From f0eb787bd8f7b9f2c18c4688e54afd2ca84bf0c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=89=91=E5=8F=A4=E6=95=9B=E9=94=8B?= <3045316072@qq.com> Date: Wed, 13 Mar 2024 13:58:12 +0800 Subject: [PATCH] =?UTF-8?q?=E7=8E=AF=E5=A2=83=E5=88=9D=E5=A7=8B=E5=8C=96?= =?UTF-8?q?=EF=BC=8C=E9=9B=86=E6=88=90=E4=BA=86lamptool=E3=80=81wbmoudle?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CMakeLists.txt | 4 +- CMakeLists.txt.user | 419 + cmake/FindFFTW.cmake | 70 + src/CMakeLists.txt | 2 +- src/FastCAE/CommandLine.cpp | 4 +- src/FastCAE/main.cpp | 24 +- src/IO/CMakeLists.txt | 2 +- src/LAMPTool/BaseToollib/BaseConstVariable.h | 38 + src/LAMPTool/BaseToollib/BaseTool.cpp | 256 + src/LAMPTool/BaseToollib/BaseTool.h | 93 + src/LAMPTool/BaseToollib/FileOperator.cpp | 188 + src/LAMPTool/BaseToollib/FileOperator.h | 50 + src/LAMPTool/BaseToollib/GeoOperator.cpp | 271 + src/LAMPTool/BaseToollib/GeoOperator.h | 111 + .../BaseToollib/ImageOperatorBase.cpp | 1239 + src/LAMPTool/BaseToollib/ImageOperatorBase.h | 190 + src/LAMPTool/BaseToollib/interpolation.cpp | 13 + src/LAMPTool/BaseToollib/interpolation.h | 69 + src/LAMPTool/BaseToollib/readme.md | 2 + src/LAMPTool/CMakeLists.txt | 68 + src/LAMPTool/FEKOFarFieldFileClass.cpp | 446 + src/LAMPTool/FEKOFarFieldFileClass.h | 138 + src/LAMPTool/FEKOSimulationSARClass.cpp | 1125 + src/LAMPTool/FEKOSimulationSARClass.h | 259 + src/LAMPTool/LAMPTool.cpp | 27 + src/LAMPTool/LAMPTool.h | 21 + src/LAMPTool/LAMPTool.ui | 56 + src/LAMPTool/LampToolTest.h | 3 + src/LAMPTool/OCCTBase.cpp | 412 + src/LAMPTool/OCCTBase.h | 96 + .../SARBaseToolLib/BackScatterModel.cpp | 14 + .../SARBaseToolLib/BackScatterModel.h | 12 + src/LAMPTool/SARBaseToolLib/SARBaseTool.cpp | 283 + src/LAMPTool/SARBaseToolLib/SARBaseTool.h | 65 + .../SARBaseToolLib/SARCalibration.cpp | 384 + src/LAMPTool/SARBaseToolLib/SARCalibration.h | 52 + .../SARBaseToolLib/SARCalibrationTool.cpp | 86 + src/LAMPTool/SARBaseToolLib/SARImageBase.cpp | 334 + src/LAMPTool/SARBaseToolLib/SARImageBase.h | 95 + src/LAMPTool/SARImage/FEKOBaseToolClass.cpp | 1040 + src/LAMPTool/SARImage/FEKOBaseToolClass.h | 338 + src/LAMPTool/SARImage/FEKONearBPBasic.cpp | 1028 + src/LAMPTool/SARImage/FEKONearBPBasic.h | 157 + src/LAMPTool/SARImage/FEKONearBpBaseImage.cpp | 100 + src/LAMPTool/cpp.hint | 4 + src/LAMPTool/main.cpp | 80 + src/LAMPTool/readme.md | 8 + src/LAMPTool/referenceHeader.h | 175 + src/LAMPTool/test.png | Bin 0 -> 11630 bytes src/MainWidgets/ControlPanel.cpp | 14 +- src/MainWidgets/preWindow.cpp | 3 + src/MainWindow/CustomizerHelper.cpp | 17 +- src/MainWindow/MainWindow.cpp | 30 +- src/MainWindow/MainWindow.ui | 114 +- src/MainWindow/MainWindowPy.cpp | 6 +- src/MainWindow/SARibbonMWUi.cpp | 1830 +- src/MainWindow/SARibbonMWUi.h | 8 + src/MainWindow/SubWindowManager.cpp | 330 +- src/PythonModule/PyAgent.cpp | 2 +- src/WBCLFZSystemModule/.command_history.lst | 0 src/WBCLFZSystemModule/AllHead.cpp | 58 + src/WBCLFZSystemModule/AllHead.h | 210 + src/WBCLFZSystemModule/CMakeLists.txt | 68 + src/WBCLFZSystemModule/DialogBatchExport.ui | 195 + .../EchoShowProcess/CMDExcuteApp.cpp | 82 + .../EchoShowProcess/CMDExcuteApp.h | 34 + .../EchoShowProcess/CMDExcuteApp.ui | 26 + .../EchoShowProcess/EchoTableEditWindow.cpp | 394 + .../EchoShowProcess/EchoTableEditWindow.h | 96 + .../EchoShowProcess/EchoTableEditWindow.ui | 285 + .../EchoShowProcess/FEKOResultImport.cpp | 427 + .../EchoShowProcess/FEKOResultImport.h | 83 + .../EchoShowProcess/FEKOResultImport.ui | 425 + src/WBCLFZSystemModule/HeaderSort.h | 4 + .../ImageShowDialogClass.cpp | 367 + src/WBCLFZSystemModule/ImageShowDialogClass.h | 139 + .../ImageShowDialogClass.ui | 33 + src/WBCLFZSystemModule/LAMPDataShowClass.cpp | 111 + src/WBCLFZSystemModule/LAMPDataShowClass.h | 50 + src/WBCLFZSystemModule/LAMPDataShowClass.ui | 57 + .../LAMPImageCreateClass.cpp | 196 + src/WBCLFZSystemModule/LAMPImageCreateClass.h | 48 + .../LAMPImageCreateClass.ui | 657 + .../LAMP_ScatterSettingClass.cpp | 2032 ++ .../LAMP_ScatterSettingClass.h | 124 + .../LAMP_ScatterSettingClass.ui | 585 + .../OCCTBaseOperaorClass.cpp | 6 + src/WBCLFZSystemModule/OCCTBaseOperaorClass.h | 19 + src/WBCLFZSystemModule/OCCTModelOperator.cpp | 465 + src/WBCLFZSystemModule/OCCTModelOperator.h | 125 + src/WBCLFZSystemModule/OCCTModelOperator.ui | 868 + .../OCCTopoShapeTreeViewer.cpp | 43 + .../OCCTopoShapeTreeViewer.h | 25 + .../OCCViewer/CommonSample.h | 43 + .../OCCViewer/DocumentCommon.cpp | 890 + .../OCCViewer/DocumentCommon.h | 209 + .../OCCViewer/GeomWidget.cpp | 98 + src/WBCLFZSystemModule/OCCViewer/GeomWidget.h | 68 + .../OCCViewer/OCCT_Test/BaseSample.cpp | 185 + .../OCCViewer/OCCT_Test/BaseSample.h | 87 + .../OCCViewer/OCCT_Test/MakeBottle.cpp | 218 + .../OCCViewer/OCCT_Test/MakeBottle.h | 33 + .../OCCViewer/OCCT_Test/Viewer3d.xml | 31 + .../OCCViewer/OCCT_Test/Viewer3dSamples.cpp | 346 + .../OCCViewer/OCCT_Test/Viewer3dSamples.h | 78 + .../OCCViewer/OcctHighlighter.cpp | 222 + .../OCCViewer/OcctHighlighter.h | 77 + .../OCCViewer/TranslateDialog.cpp | 113 + .../OCCViewer/TranslateDialog.h | 56 + .../OCCViewer/Transparency.cpp | 46 + .../OCCViewer/Transparency.h | 60 + src/WBCLFZSystemModule/OCCViewer/View.cpp | 720 + src/WBCLFZSystemModule/OCCViewer/View.h | 227 + .../OCCViewer/res/antialiasing.png | Bin 0 -> 230 bytes .../OCCViewer/res/cursor_rotate.png | Bin 0 -> 291 bytes .../OCCViewer/res/cursor_zoom.png | Bin 0 -> 245 bytes src/WBCLFZSystemModule/OCCViewer/res/help.png | Bin 0 -> 214 bytes src/WBCLFZSystemModule/OCCViewer/res/lamp.png | Bin 0 -> 1355 bytes .../OCCViewer/res/raytracing.png | Bin 0 -> 223 bytes .../OCCViewer/res/reflections.png | Bin 0 -> 217 bytes .../OCCViewer/res/shadows.png | Bin 0 -> 264 bytes .../OCCViewer/res/tool_color.png | Bin 0 -> 288 bytes .../OCCViewer/res/tool_delete.png | Bin 0 -> 203 bytes .../OCCViewer/res/tool_material.png | Bin 0 -> 293 bytes .../OCCViewer/res/tool_shading.png | Bin 0 -> 256 bytes .../OCCViewer/res/tool_transparency.png | Bin 0 -> 318 bytes .../OCCViewer/res/tool_wireframe.png | Bin 0 -> 259 bytes .../OCCViewer/res/view_axo.png | Bin 0 -> 392 bytes .../OCCViewer/res/view_back.png | Bin 0 -> 233 bytes .../OCCViewer/res/view_bottom.png | Bin 0 -> 233 bytes .../OCCViewer/res/view_comp_off.png | Bin 0 -> 199 bytes .../OCCViewer/res/view_comp_on.png | Bin 0 -> 180 bytes .../OCCViewer/res/view_fitall.png | Bin 0 -> 231 bytes .../OCCViewer/res/view_front.png | Bin 0 -> 238 bytes .../OCCViewer/res/view_left.png | Bin 0 -> 231 bytes .../OCCViewer/res/view_reset.png | Bin 0 -> 204 bytes .../OCCViewer/res/view_right.png | Bin 0 -> 230 bytes .../OCCViewer/res/view_top.png | Bin 0 -> 235 bytes src/WBCLFZSystemModule/OcctExportClass.cpp | 175 + src/WBCLFZSystemModule/OcctExportClass.h | 55 + src/WBCLFZSystemModule/OcctExportClass.ui | 161 + .../PointCloudProcess/BasePCL.cpp | 120 + .../PointCloudProcess/BasePCL.h | 127 + .../BilateralFilterWindows.ui | 243 + .../DialogTriangulationSurfaceMesh.ui | 386 + .../PointCloudProcess/MedianFilterWindows.ui | 217 + .../PointCloudProcess/PointCloudAlg.cpp | 486 + .../PointCloudProcess/PointCloudAlg.h | 268 + .../PointCloudProcess/PointManagerClass.cpp | 281 + .../PointCloudProcess/PointManagerClass.h | 197 + .../PoissonReSurfaceWindows.ui | 333 + .../RadiusOutlierRemovalWindows.ui | 269 + ...cance_FEKOSourceSettingPlaneWaveWIndows.ui | 60 + .../Scene_StripQtWidgetsClass.cpp | 10 + .../Scene_StripQtWidgetsClass.h | 16 + .../Scene_StripQtWidgetsClass.ui | 238 + .../StatisticalOutlierRemovalWindows.ui | 246 + ...trips_FEKOSourceSettingPlaneWaveWIndows.ui | 381 + .../PointCloudProcess/ToolDialog.cpp | 242 + .../PointCloudProcess/ToolDialog.h | 297 + .../PointCloudProcess/images/1.gif | Bin 0 -> 276082 bytes .../PointCloudProcess/images/RGB.png | Bin 0 -> 3331 bytes .../images/algorithm/DASHBOARD.png | Bin 0 -> 2785 bytes .../images/algorithm/DBSCAN.png | Bin 0 -> 2041 bytes .../images/algorithm/Histogram.png | Bin 0 -> 616 bytes .../images/algorithm/KMeans.png | Bin 0 -> 2555 bytes .../images/algorithm/binary.png | Bin 0 -> 1544 bytes .../images/algorithm/chooseMatrix.png | Bin 0 -> 2628 bytes .../images/algorithm/density.png | Bin 0 -> 1452 bytes .../images/algorithm/extract.png | Bin 0 -> 2922 bytes .../images/algorithm/filter.png | Bin 0 -> 1919 bytes .../images/algorithm/help.png | Bin 0 -> 1998 bytes .../images/algorithm/matrix.png | Bin 0 -> 1538 bytes .../images/algorithm/more.png | Bin 0 -> 2259 bytes .../images/algorithm/nihe.png | Bin 0 -> 2180 bytes .../images/algorithm/person.png | Bin 0 -> 1575 bytes .../images/algorithm/pingjie.png | Bin 0 -> 1853 bytes .../images/algorithm/transform.png | Bin 0 -> 2478 bytes .../images/algorithm/tree.png | Bin 0 -> 3256 bytes .../PointCloudProcess/images/back.png | Bin 0 -> 507 bytes .../PointCloudProcess/images/bottom.png | Bin 0 -> 475 bytes .../PointCloudProcess/images/camera.png | Bin 0 -> 4517 bytes .../PointCloudProcess/images/color.png | Bin 0 -> 117 bytes .../PointCloudProcess/images/coodinate.png | Bin 0 -> 982 bytes .../PointCloudProcess/images/files/CSV.png | Bin 0 -> 1452 bytes .../PointCloudProcess/images/files/add.png | Bin 0 -> 1832 bytes .../images/files/bgColor.png | Bin 0 -> 903 bytes .../PointCloudProcess/images/files/cloud.png | Bin 0 -> 2357 bytes .../PointCloudProcess/images/files/cloud2.png | Bin 0 -> 1960 bytes .../PointCloudProcess/images/files/copy.png | Bin 0 -> 695 bytes .../PointCloudProcess/images/files/cut.png | Bin 0 -> 2305 bytes .../PointCloudProcess/images/files/log.png | Bin 0 -> 1734 bytes .../PointCloudProcess/images/files/new1.png | Bin 0 -> 1438 bytes .../PointCloudProcess/images/files/new2.png | Bin 0 -> 642 bytes .../PointCloudProcess/images/files/paste.png | Bin 0 -> 741 bytes .../images/files/pointCloud.png | Bin 0 -> 2681 bytes .../PointCloudProcess/images/files/search.png | Bin 0 -> 2148 bytes .../images/files/snapshot.png | Bin 0 -> 1712 bytes .../PointCloudProcess/images/files/star.png | Bin 0 -> 2294 bytes .../PointCloudProcess/images/files/txt.png | Bin 0 -> 1359 bytes .../PointCloudProcess/images/front.png | Bin 0 -> 507 bytes .../PointCloudProcess/images/grey.png | Bin 0 -> 2024 bytes .../PointCloudProcess/images/ic-redo.png | Bin 0 -> 1366 bytes .../PointCloudProcess/images/ic-undo.png | Bin 0 -> 1355 bytes .../PointCloudProcess/images/keda.ico | Bin 0 -> 67646 bytes .../PointCloudProcess/images/left.png | Bin 0 -> 521 bytes .../PointCloudProcess/images/lock.png | Bin 0 -> 1533 bytes .../PointCloudProcess/images/open.png | Bin 0 -> 1408 bytes .../PointCloudProcess/images/redo.png | Bin 0 -> 937 bytes .../PointCloudProcess/images/reset.png | Bin 0 -> 2013 bytes .../PointCloudProcess/images/right.png | Bin 0 -> 509 bytes .../PointCloudProcess/images/rotate0.png | Bin 0 -> 2865 bytes .../PointCloudProcess/images/rotate180.png | Bin 0 -> 2373 bytes .../PointCloudProcess/images/rotate270.png | Bin 0 -> 2537 bytes .../PointCloudProcess/images/rotate90.png | Bin 0 -> 2587 bytes .../PointCloudProcess/images/seting.png | Bin 0 -> 3092 bytes .../PointCloudProcess/images/undo.png | Bin 0 -> 990 bytes .../PointCloudProcess/images/up.png | Bin 0 -> 487 bytes .../PointCloudProcess/images/zoomin.png | Bin 0 -> 2339 bytes .../PointCloudProcess/images/zoomout.png | Bin 0 -> 2399 bytes .../PointCloudProcess/inputdialog.cpp | 14 + .../PointCloudProcess/inputdialog.h | 23 + .../PointCloudProcess/inputdialog.ui | 330 + .../PointCloudProcess/pclvisualizer.cpp | 1263 + .../PointCloudProcess/pclvisualizer.h | 398 + .../PointCloudProcess/pclvisualizer.ui | 1963 + .../ProgramParamLoadingClass.cpp | 1 + .../ProgramParamLoadingClass.h | 18 + .../QConsoleCommandAction.cpp | 74 + .../QConsoleCommandAction.h | 77 + src/WBCLFZSystemModule/QConsoleIODevice.cpp | 95 + src/WBCLFZSystemModule/QConsoleIODevice.h | 40 + src/WBCLFZSystemModule/QConsoleWidget.cpp | 628 + src/WBCLFZSystemModule/QConsoleWidget.h | 159 + src/WBCLFZSystemModule/QtEchoExportWindows.ui | 141 + .../QtFreqParamsSetting.cpp | 177 + src/WBCLFZSystemModule/QtFreqParamsSetting.h | 49 + src/WBCLFZSystemModule/QtFreqParamsSetting.ui | 404 + .../QtSARAntModelSetting.cpp | 543 + src/WBCLFZSystemModule/QtSARAntModelSetting.h | 121 + .../QtSARAntModelSetting.ui | 575 + .../QtStripImageSettingClass.cpp | 10 + .../QtStripImageSettingClass.h | 19 + .../QtStripImageSettingClass.ui | 20 + .../QtWidgetsClass_CircleSAR.cpp | 41 + .../QtWidgetsClass_CircleSAR.h | 30 + .../QtWidgetsClass_CircleSAR.ui | 77 + .../QtWidgetsClass_FarSourceSetting.cpp | 49 + .../QtWidgetsClass_FarSourceSetting.h | 38 + .../QtWidgetsClass_FarSourceSetting.ui | 214 + .../QtWidgetsClass_ISAR.cpp | 50 + src/WBCLFZSystemModule/QtWidgetsClass_ISAR.h | 32 + src/WBCLFZSystemModule/QtWidgetsClass_ISAR.ui | 147 + .../QtWidgetsClass_ImageSetting.cpp | 45 + .../QtWidgetsClass_ImageSetting.h | 36 + .../QtWidgetsClass_ImageSetting.ui | 266 + .../QtWidgetsClass_Scan.cpp | 74 + src/WBCLFZSystemModule/QtWidgetsClass_Scan.h | 32 + src/WBCLFZSystemModule/QtWidgetsClass_Scan.ui | 337 + .../QtWidgetsClass_Strip.cpp | 60 + src/WBCLFZSystemModule/QtWidgetsClass_Strip.h | 34 + .../QtWidgetsClass_Strip.ui | 288 + .../SharedModuleLib/BaseUiTool.cpp | 182 + .../SharedModuleLib/BaseUiTool.h | 60 + .../SharedModuleLib/CMDExcuteApp.cpp | 82 + .../SharedModuleLib/CMDExcuteApp.h | 27 + .../SharedModuleLib/CMDExcuteApp.ui | 26 + .../SharedModuleLib/ProcessOn.cpp | 30 + .../SharedModuleLib/ProcessOn.h | 27 + .../SharedModuleLib/ProcessOn.ui | 42 + .../SharedModuleLib/TaskTreeClass.cpp | 154 + .../SharedModuleLib/TaskTreeClass.h | 88 + .../SqliteDBProcess/images/logo.png | Bin 0 -> 15047 bytes .../SqliteDBProcess/images/logo.svg | 391 + .../SqliteDBProcess/images/sqlitebrowser.png | Bin 0 -> 96368 bytes .../SqliteDBProcess/src/AboutDialog.cpp | 18 + .../SqliteDBProcess/src/AboutDialog.h | 22 + .../SqliteDBProcess/src/AboutDialog.ui | 164 + .../SqliteDBProcess/src/AddRecordDialog.cpp | 367 + .../SqliteDBProcess/src/AddRecordDialog.h | 52 + .../SqliteDBProcess/src/AddRecordDialog.ui | 158 + .../SqliteDBProcess/src/Application.cpp | 280 + .../SqliteDBProcess/src/Application.h | 43 + .../SqliteDBProcess/src/CipherDialog.cpp | 146 + .../SqliteDBProcess/src/CipherDialog.h | 36 + .../SqliteDBProcess/src/CipherDialog.ui | 403 + .../SqliteDBProcess/src/CipherSettings.cpp | 26 + .../SqliteDBProcess/src/CipherSettings.h | 50 + .../src/ColumnDisplayFormatDialog.cpp | 139 + .../src/ColumnDisplayFormatDialog.h | 41 + .../src/ColumnDisplayFormatDialog.ui | 134 + .../SqliteDBProcess/src/CondFormat.cpp | 176 + .../SqliteDBProcess/src/CondFormat.h | 81 + .../SqliteDBProcess/src/CondFormatManager.cpp | 252 + .../SqliteDBProcess/src/CondFormatManager.h | 56 + .../SqliteDBProcess/src/CondFormatManager.ui | 279 + .../SqliteDBProcess/src/DBsqliconwin.ico | Bin 0 -> 21662 bytes .../SqliteDBProcess/src/DBsqliconwin.jpg | Bin 0 -> 1662 bytes .../SqliteDBProcess/src/Data.cpp | 157 + .../SqliteDBProcess/src/Data.h | 37 + .../SqliteDBProcess/src/DbStructureModel.cpp | 429 + .../SqliteDBProcess/src/DbStructureModel.h | 60 + .../SqliteDBProcess/src/DotenvFormat.cpp | 28 + .../SqliteDBProcess/src/DotenvFormat.h | 14 + .../SqliteDBProcess/src/EditDialog.cpp | 1258 + .../SqliteDBProcess/src/EditDialog.h | 106 + .../SqliteDBProcess/src/EditDialog.ui | 690 + .../SqliteDBProcess/src/EditIndexDialog.cpp | 351 + .../SqliteDBProcess/src/EditIndexDialog.h | 49 + .../SqliteDBProcess/src/EditIndexDialog.ui | 573 + .../SqliteDBProcess/src/EditTableDialog.cpp | 1008 + .../SqliteDBProcess/src/EditTableDialog.h | 101 + .../SqliteDBProcess/src/EditTableDialog.ui | 782 + .../SqliteDBProcess/src/ExportDataDialog.cpp | 585 + .../SqliteDBProcess/src/ExportDataDialog.h | 56 + .../SqliteDBProcess/src/ExportDataDialog.ui | 408 + .../SqliteDBProcess/src/ExportSqlDialog.cpp | 133 + .../SqliteDBProcess/src/ExportSqlDialog.h | 31 + .../SqliteDBProcess/src/ExportSqlDialog.ui | 242 + .../SqliteDBProcess/src/ExtendedScintilla.cpp | 325 + .../SqliteDBProcess/src/ExtendedScintilla.h | 58 + .../src/ExtendedTableWidget.cpp | 1081 + .../SqliteDBProcess/src/ExtendedTableWidget.h | 110 + .../SqliteDBProcess/src/FileDialog.cpp | 83 + .../SqliteDBProcess/src/FileDialog.h | 104 + .../src/FileExtensionManager.cpp | 104 + .../src/FileExtensionManager.h | 30 + .../src/FileExtensionManager.ui | 153 + .../SqliteDBProcess/src/FilterLineEdit.cpp | 224 + .../SqliteDBProcess/src/FilterLineEdit.h | 47 + .../SqliteDBProcess/src/FilterTableHeader.cpp | 130 + .../SqliteDBProcess/src/FilterTableHeader.h | 44 + .../SqliteDBProcess/src/FindReplaceDialog.cpp | 227 + .../SqliteDBProcess/src/FindReplaceDialog.h | 48 + .../SqliteDBProcess/src/FindReplaceDialog.ui | 322 + .../src/ForeignKeyEditorDelegate.cpp | 190 + .../src/ForeignKeyEditorDelegate.h | 34 + .../SqliteDBProcess/src/IconCache.cpp | 22 + .../SqliteDBProcess/src/IconCache.h | 21 + .../SqliteDBProcess/src/ImportCsvDialog.cpp | 843 + .../SqliteDBProcess/src/ImportCsvDialog.h | 67 + .../SqliteDBProcess/src/ImportCsvDialog.ui | 786 + .../SqliteDBProcess/src/MainWindow.cpp | 3473 ++ .../SqliteDBProcess/src/MainWindow.h | 208 + .../SqliteDBProcess/src/Palette.cpp | 94 + .../SqliteDBProcess/src/Palette.h | 21 + .../SqliteDBProcess/src/PlotDock.cpp | 1003 + .../SqliteDBProcess/src/PlotDock.h | 126 + .../SqliteDBProcess/src/PlotDock.ui | 361 + .../SqliteDBProcess/src/PreferencesDialog.cpp | 686 + .../SqliteDBProcess/src/PreferencesDialog.h | 71 + .../SqliteDBProcess/src/PreferencesDialog.ui | 2172 ++ .../SqliteDBProcess/src/ProxyDialog.cpp | 57 + .../SqliteDBProcess/src/ProxyDialog.h | 28 + .../SqliteDBProcess/src/ProxyDialog.ui | 201 + .../src/RemoteCommitsModel.cpp | 171 + .../SqliteDBProcess/src/RemoteCommitsModel.h | 44 + .../SqliteDBProcess/src/RemoteDatabase.cpp | 432 + .../SqliteDBProcess/src/RemoteDatabase.h | 86 + .../SqliteDBProcess/src/RemoteDock.cpp | 675 + .../SqliteDBProcess/src/RemoteDock.h | 80 + .../SqliteDBProcess/src/RemoteDock.ui | 684 + .../src/RemoteLocalFilesModel.cpp | 191 + .../src/RemoteLocalFilesModel.h | 56 + .../SqliteDBProcess/src/RemoteModel.cpp | 344 + .../SqliteDBProcess/src/RemoteModel.h | 118 + .../SqliteDBProcess/src/RemoteNetwork.cpp | 571 + .../SqliteDBProcess/src/RemoteNetwork.h | 97 + .../SqliteDBProcess/src/RemotePushDialog.cpp | 174 + .../SqliteDBProcess/src/RemotePushDialog.h | 46 + .../SqliteDBProcess/src/RemotePushDialog.ui | 333 + .../SqliteDBProcess/src/RowCache.h | 264 + .../SqliteDBProcess/src/RowLoader.cpp | 256 + .../SqliteDBProcess/src/RowLoader.h | 122 + .../SqliteDBProcess/src/RunSql.cpp | 303 + .../SqliteDBProcess/src/RunSql.h | 89 + .../SqliteDBProcess/src/SelectItemsPopup.cpp | 136 + .../SqliteDBProcess/src/SelectItemsPopup.h | 44 + .../SqliteDBProcess/src/SelectItemsPopup.ui | 331 + .../SqliteDBProcess/src/Settings.cpp | 488 + .../SqliteDBProcess/src/Settings.h | 40 + .../SqliteDBProcess/src/SqlExecutionArea.cpp | 319 + .../SqliteDBProcess/src/SqlExecutionArea.h | 76 + .../SqliteDBProcess/src/SqlExecutionArea.ui | 296 + .../SqliteDBProcess/src/SqlUiLexer.cpp | 224 + .../SqliteDBProcess/src/SqlUiLexer.h | 47 + .../src/SqliteDBMainWindow.cpp | 3473 ++ .../SqliteDBProcess/src/SqliteDBMainWindow.h | 208 + .../SqliteDBProcess/src/SqliteDBMainWindow.ui | 3601 ++ .../src/SqliteDBProcessmain.cpp | 59 + .../SqliteDBProcess/src/TableBrowser.cpp | 1603 + .../SqliteDBProcess/src/TableBrowser.h | 197 + .../SqliteDBProcess/src/TableBrowser.ui | 1475 + .../SqliteDBProcess/src/VacuumDialog.cpp | 53 + .../SqliteDBProcess/src/VacuumDialog.h | 28 + .../SqliteDBProcess/src/VacuumDialog.ui | 127 + .../SqliteDBProcess/src/app.plist | 82 + .../SqliteDBProcess/src/csvparser.cpp | 324 + .../SqliteDBProcess/src/csvparser.h | 99 + .../SqliteDBProcess/src/docktextedit.cpp | 115 + .../SqliteDBProcess/src/docktextedit.h | 48 + .../src/extensions/extension-formats.c | 971 + .../src/extensions/extension-formats.def | 5 + .../src/extensions/extension-functions.c | 1947 + .../src/extensions/extension-functions.def | 16 + .../SqliteDBProcess/src/i18n.pri | 48 + .../src/icons/application_go.png | Bin 0 -> 634 bytes .../src/icons/application_link.png | Bin 0 -> 701 bytes .../src/icons/application_side_list.png | Bin 0 -> 510 bytes .../src/icons/bullet_arrow_bottom.png | Bin 0 -> 229 bytes .../src/icons/bullet_arrow_down.png | Bin 0 -> 201 bytes .../src/icons/bullet_arrow_top.png | Bin 0 -> 230 bytes .../src/icons/bullet_arrow_up.png | Bin 0 -> 201 bytes .../SqliteDBProcess/src/icons/cancel.png | Bin 0 -> 587 bytes .../SqliteDBProcess/src/icons/chart_curve.png | Bin 0 -> 710 bytes .../src/icons/clear_filters.png | Bin 0 -> 791 bytes .../src/icons/clear_sorting.png | Bin 0 -> 558 bytes .../SqliteDBProcess/src/icons/cog.png | Bin 0 -> 512 bytes .../SqliteDBProcess/src/icons/cog_go.png | Bin 0 -> 859 bytes .../src/icons/color_swatch.png | Bin 0 -> 209 bytes .../src/icons/comment_block.png | Bin 0 -> 210 bytes .../SqliteDBProcess/src/icons/cross.png | Bin 0 -> 655 bytes .../SqliteDBProcess/src/icons/database.png | Bin 0 -> 390 bytes .../src/icons/database_add.png | Bin 0 -> 658 bytes .../SqliteDBProcess/src/icons/database_go.png | Bin 0 -> 698 bytes .../src/icons/database_link.png | Bin 0 -> 679 bytes .../src/icons/database_refresh.png | Bin 0 -> 770 bytes .../src/icons/database_save.png | Bin 0 -> 755 bytes .../src/icons/document-link.png | Bin 0 -> 853 bytes .../src/icons/document-open.png | Bin 0 -> 672 bytes .../src/icons/edit_cond_formats.png | Bin 0 -> 573 bytes .../SqliteDBProcess/src/icons/filter.png | Bin 0 -> 642 bytes .../SqliteDBProcess/src/icons/folder.png | Bin 0 -> 537 bytes .../SqliteDBProcess/src/icons/folder_user.png | Bin 0 -> 730 bytes .../SqliteDBProcess/src/icons/help.png | Bin 0 -> 786 bytes .../SqliteDBProcess/src/icons/hourglass.png | Bin 0 -> 744 bytes .../SqliteDBProcess/src/icons/icons.qrc | 106 + .../src/icons/internet-web-browser.png | Bin 0 -> 928 bytes .../SqliteDBProcess/src/icons/key.png | Bin 0 -> 612 bytes .../src/icons/layout_sidebar.png | Bin 0 -> 479 bytes .../SqliteDBProcess/src/icons/package.png | Bin 0 -> 853 bytes .../SqliteDBProcess/src/icons/package_go.png | Bin 0 -> 898 bytes .../src/icons/package_rename.png | Bin 0 -> 637 bytes .../src/icons/package_save.png | Bin 0 -> 888 bytes .../SqliteDBProcess/src/icons/page_add.png | Bin 0 -> 739 bytes .../SqliteDBProcess/src/icons/page_copy.png | Bin 0 -> 663 bytes .../src/icons/page_copy_sql.png | Bin 0 -> 833 bytes .../SqliteDBProcess/src/icons/page_delete.png | Bin 0 -> 740 bytes .../SqliteDBProcess/src/icons/page_edit.png | Bin 0 -> 807 bytes .../SqliteDBProcess/src/icons/page_find.png | Bin 0 -> 879 bytes .../src/icons/page_foreign_key.png | Bin 0 -> 841 bytes .../SqliteDBProcess/src/icons/page_green.png | Bin 0 -> 621 bytes .../SqliteDBProcess/src/icons/page_key.png | Bin 0 -> 801 bytes .../src/icons/page_paintbrush.png | Bin 0 -> 813 bytes .../SqliteDBProcess/src/icons/page_paste.png | Bin 0 -> 703 bytes .../SqliteDBProcess/src/icons/page_save.png | Bin 0 -> 774 bytes .../src/icons/page_white_copy.png | Bin 0 -> 309 bytes .../src/icons/page_white_database.png | Bin 0 -> 579 bytes .../src/icons/page_white_text.png | Bin 0 -> 342 bytes .../SqliteDBProcess/src/icons/picture.png | Bin 0 -> 606 bytes .../SqliteDBProcess/src/icons/picture_add.png | Bin 0 -> 745 bytes .../src/icons/picture_delete.png | Bin 0 -> 744 bytes .../src/icons/picture_edit.png | Bin 0 -> 826 bytes .../src/icons/picture_save.png | Bin 0 -> 755 bytes .../SqliteDBProcess/src/icons/plugin_add.png | Bin 0 -> 691 bytes .../src/icons/plugin_delete.png | Bin 0 -> 692 bytes .../SqliteDBProcess/src/icons/printer.png | Bin 0 -> 731 bytes .../src/icons/resultset_first.png | Bin 0 -> 522 bytes .../src/icons/resultset_last.png | Bin 0 -> 524 bytes .../src/icons/resultset_next.png | Bin 0 -> 395 bytes .../src/icons/resultset_previous.png | Bin 0 -> 389 bytes .../SqliteDBProcess/src/icons/save_all.png | Bin 0 -> 841 bytes .../SqliteDBProcess/src/icons/script.png | Bin 0 -> 748 bytes .../SqliteDBProcess/src/icons/script_add.png | Bin 0 -> 811 bytes .../src/icons/script_delete.png | Bin 0 -> 811 bytes .../SqliteDBProcess/src/icons/script_edit.png | Bin 0 -> 880 bytes .../SqliteDBProcess/src/icons/server_add.png | Bin 0 -> 676 bytes .../SqliteDBProcess/src/icons/server_go.png | Bin 0 -> 706 bytes .../src/icons/sqlitebrowser.png | Bin 0 -> 15047 bytes .../SqliteDBProcess/src/icons/style.png | Bin 0 -> 813 bytes .../SqliteDBProcess/src/icons/style_add.png | Bin 0 -> 844 bytes .../src/icons/style_delete.png | Bin 0 -> 865 bytes .../SqliteDBProcess/src/icons/style_edit.png | Bin 0 -> 927 bytes .../SqliteDBProcess/src/icons/tab.png | Bin 0 -> 323 bytes .../SqliteDBProcess/src/icons/tab_add.png | Bin 0 -> 488 bytes .../SqliteDBProcess/src/icons/table.png | Bin 0 -> 566 bytes .../SqliteDBProcess/src/icons/table_add.png | Bin 0 -> 663 bytes .../src/icons/table_delete.png | Bin 0 -> 660 bytes .../SqliteDBProcess/src/icons/table_edit.png | Bin 0 -> 744 bytes .../src/icons/table_row_delete.png | Bin 0 -> 656 bytes .../src/icons/table_row_insert.png | Bin 0 -> 657 bytes .../SqliteDBProcess/src/icons/table_save.png | Bin 0 -> 723 bytes .../SqliteDBProcess/src/icons/tag_blue.png | Bin 0 -> 586 bytes .../src/icons/tag_blue_add.png | Bin 0 -> 671 bytes .../src/icons/tag_blue_delete.png | Bin 0 -> 701 bytes .../src/icons/tag_blue_edit.png | Bin 0 -> 748 bytes .../src/icons/text_align_center.png | Bin 0 -> 234 bytes .../src/icons/text_align_justify.png | Bin 0 -> 209 bytes .../src/icons/text_align_left.png | Bin 0 -> 209 bytes .../src/icons/text_align_right.png | Bin 0 -> 209 bytes .../SqliteDBProcess/src/icons/text_bold.png | Bin 0 -> 304 bytes .../SqliteDBProcess/src/icons/text_indent.png | Bin 0 -> 353 bytes .../SqliteDBProcess/src/icons/text_italic.png | Bin 0 -> 223 bytes .../src/icons/text_paintbrush.png | Bin 0 -> 880 bytes .../src/icons/text_replace.png | Bin 0 -> 691 bytes .../src/icons/text_underline.png | Bin 0 -> 273 bytes .../src/icons/textfield_delete.png | Bin 0 -> 335 bytes .../src/icons/view-refresh.png | Bin 0 -> 912 bytes .../SqliteDBProcess/src/icons/wrench.png | Bin 0 -> 610 bytes .../SqliteDBProcess/src/macapp.icns | Bin 0 -> 219768 bytes .../SqliteDBProcess/src/main.cpp | 59 + .../SqliteDBProcess/src/os2app.rc | 1 + .../SqliteDBProcess/src/qdarkstyle/LICENSE.md | 185 + .../src/qdarkstyle/rc/Hmovetoolbar.png | Bin 0 -> 220 bytes .../src/qdarkstyle/rc/Hsepartoolbar.png | Bin 0 -> 172 bytes .../src/qdarkstyle/rc/Vmovetoolbar.png | Bin 0 -> 2847 bytes .../src/qdarkstyle/rc/Vsepartoolbar.png | Bin 0 -> 2839 bytes .../src/qdarkstyle/rc/arrow_down.png | Bin 0 -> 525 bytes .../src/qdarkstyle/rc/arrow_down@2x.png | Bin 0 -> 977 bytes .../src/qdarkstyle/rc/arrow_down_disabled.png | Bin 0 -> 547 bytes .../qdarkstyle/rc/arrow_down_disabled@2x.png | Bin 0 -> 1040 bytes .../src/qdarkstyle/rc/arrow_down_focus.png | Bin 0 -> 530 bytes .../src/qdarkstyle/rc/arrow_down_focus@2x.png | Bin 0 -> 1025 bytes .../src/qdarkstyle/rc/arrow_down_pressed.png | Bin 0 -> 518 bytes .../qdarkstyle/rc/arrow_down_pressed@2x.png | Bin 0 -> 1007 bytes .../src/qdarkstyle/rc/arrow_left.png | Bin 0 -> 546 bytes .../src/qdarkstyle/rc/arrow_left@2x.png | Bin 0 -> 1072 bytes .../src/qdarkstyle/rc/arrow_left_disabled.png | Bin 0 -> 569 bytes .../qdarkstyle/rc/arrow_left_disabled@2x.png | Bin 0 -> 1126 bytes .../src/qdarkstyle/rc/arrow_left_focus.png | Bin 0 -> 565 bytes .../src/qdarkstyle/rc/arrow_left_focus@2x.png | Bin 0 -> 1143 bytes .../src/qdarkstyle/rc/arrow_left_pressed.png | Bin 0 -> 541 bytes .../qdarkstyle/rc/arrow_left_pressed@2x.png | Bin 0 -> 1120 bytes .../src/qdarkstyle/rc/arrow_right.png | Bin 0 -> 518 bytes .../src/qdarkstyle/rc/arrow_right@2x.png | Bin 0 -> 1062 bytes .../qdarkstyle/rc/arrow_right_disabled.png | Bin 0 -> 553 bytes .../qdarkstyle/rc/arrow_right_disabled@2x.png | Bin 0 -> 1143 bytes .../src/qdarkstyle/rc/arrow_right_focus.png | Bin 0 -> 543 bytes .../qdarkstyle/rc/arrow_right_focus@2x.png | Bin 0 -> 1139 bytes .../src/qdarkstyle/rc/arrow_right_pressed.png | Bin 0 -> 544 bytes .../qdarkstyle/rc/arrow_right_pressed@2x.png | Bin 0 -> 1121 bytes .../src/qdarkstyle/rc/arrow_up.png | Bin 0 -> 512 bytes .../src/qdarkstyle/rc/arrow_up@2x.png | Bin 0 -> 969 bytes .../src/qdarkstyle/rc/arrow_up_disabled.png | Bin 0 -> 538 bytes .../qdarkstyle/rc/arrow_up_disabled@2x.png | Bin 0 -> 1046 bytes .../src/qdarkstyle/rc/arrow_up_focus.png | Bin 0 -> 530 bytes .../src/qdarkstyle/rc/arrow_up_focus@2x.png | Bin 0 -> 1017 bytes .../src/qdarkstyle/rc/arrow_up_pressed.png | Bin 0 -> 518 bytes .../src/qdarkstyle/rc/arrow_up_pressed@2x.png | Bin 0 -> 998 bytes .../src/qdarkstyle/rc/base_icon.png | Bin 0 -> 1256 bytes .../src/qdarkstyle/rc/base_icon@2x.png | Bin 0 -> 3286 bytes .../src/qdarkstyle/rc/base_icon_disabled.png | Bin 0 -> 1256 bytes .../qdarkstyle/rc/base_icon_disabled@2x.png | Bin 0 -> 3286 bytes .../src/qdarkstyle/rc/base_icon_focus.png | Bin 0 -> 1256 bytes .../src/qdarkstyle/rc/base_icon_focus@2x.png | Bin 0 -> 3286 bytes .../src/qdarkstyle/rc/base_icon_pressed.png | Bin 0 -> 1256 bytes .../qdarkstyle/rc/base_icon_pressed@2x.png | Bin 0 -> 3286 bytes .../src/qdarkstyle/rc/branch_closed-on.png | Bin 0 -> 147 bytes .../src/qdarkstyle/rc/branch_closed.png | Bin 0 -> 350 bytes .../src/qdarkstyle/rc/branch_closed@2x.png | Bin 0 -> 704 bytes .../qdarkstyle/rc/branch_closed_disabled.png | Bin 0 -> 373 bytes .../rc/branch_closed_disabled@2x.png | Bin 0 -> 729 bytes .../src/qdarkstyle/rc/branch_closed_focus.png | Bin 0 -> 380 bytes .../qdarkstyle/rc/branch_closed_focus@2x.png | Bin 0 -> 717 bytes .../qdarkstyle/rc/branch_closed_pressed.png | Bin 0 -> 372 bytes .../rc/branch_closed_pressed@2x.png | Bin 0 -> 725 bytes .../src/qdarkstyle/rc/branch_end.png | Bin 0 -> 142 bytes .../src/qdarkstyle/rc/branch_end@2x.png | Bin 0 -> 220 bytes .../src/qdarkstyle/rc/branch_end_disabled.png | Bin 0 -> 146 bytes .../qdarkstyle/rc/branch_end_disabled@2x.png | Bin 0 -> 225 bytes .../src/qdarkstyle/rc/branch_end_focus.png | Bin 0 -> 146 bytes .../src/qdarkstyle/rc/branch_end_focus@2x.png | Bin 0 -> 226 bytes .../src/qdarkstyle/rc/branch_end_pressed.png | Bin 0 -> 146 bytes .../qdarkstyle/rc/branch_end_pressed@2x.png | Bin 0 -> 225 bytes .../src/qdarkstyle/rc/branch_line.png | Bin 0 -> 130 bytes .../src/qdarkstyle/rc/branch_line@2x.png | Bin 0 -> 242 bytes .../qdarkstyle/rc/branch_line_disabled.png | Bin 0 -> 134 bytes .../qdarkstyle/rc/branch_line_disabled@2x.png | Bin 0 -> 248 bytes .../src/qdarkstyle/rc/branch_line_focus.png | Bin 0 -> 134 bytes .../qdarkstyle/rc/branch_line_focus@2x.png | Bin 0 -> 249 bytes .../src/qdarkstyle/rc/branch_line_pressed.png | Bin 0 -> 134 bytes .../qdarkstyle/rc/branch_line_pressed@2x.png | Bin 0 -> 248 bytes .../src/qdarkstyle/rc/branch_more.png | Bin 0 -> 155 bytes .../src/qdarkstyle/rc/branch_more@2x.png | Bin 0 -> 257 bytes .../qdarkstyle/rc/branch_more_disabled.png | Bin 0 -> 162 bytes .../qdarkstyle/rc/branch_more_disabled@2x.png | Bin 0 -> 265 bytes .../src/qdarkstyle/rc/branch_more_focus.png | Bin 0 -> 162 bytes .../qdarkstyle/rc/branch_more_focus@2x.png | Bin 0 -> 266 bytes .../src/qdarkstyle/rc/branch_more_pressed.png | Bin 0 -> 162 bytes .../qdarkstyle/rc/branch_more_pressed@2x.png | Bin 0 -> 265 bytes .../src/qdarkstyle/rc/branch_open-on.png | Bin 0 -> 150 bytes .../src/qdarkstyle/rc/branch_open.png | Bin 0 -> 354 bytes .../src/qdarkstyle/rc/branch_open@2x.png | Bin 0 -> 657 bytes .../qdarkstyle/rc/branch_open_disabled.png | Bin 0 -> 375 bytes .../qdarkstyle/rc/branch_open_disabled@2x.png | Bin 0 -> 682 bytes .../src/qdarkstyle/rc/branch_open_focus.png | Bin 0 -> 367 bytes .../qdarkstyle/rc/branch_open_focus@2x.png | Bin 0 -> 665 bytes .../src/qdarkstyle/rc/branch_open_pressed.png | Bin 0 -> 369 bytes .../qdarkstyle/rc/branch_open_pressed@2x.png | Bin 0 -> 661 bytes .../src/qdarkstyle/rc/checkbox_checked.png | Bin 0 -> 452 bytes .../src/qdarkstyle/rc/checkbox_checked@2x.png | Bin 0 -> 825 bytes .../rc/checkbox_checked_disabled.png | Bin 0 -> 467 bytes .../rc/checkbox_checked_disabled@2x.png | Bin 0 -> 845 bytes .../qdarkstyle/rc/checkbox_checked_focus.png | Bin 0 -> 441 bytes .../rc/checkbox_checked_focus@2x.png | Bin 0 -> 823 bytes .../rc/checkbox_checked_pressed.png | Bin 0 -> 418 bytes .../rc/checkbox_checked_pressed@2x.png | Bin 0 -> 829 bytes .../qdarkstyle/rc/checkbox_indeterminate.png | Bin 0 -> 581 bytes .../rc/checkbox_indeterminate@2x.png | Bin 0 -> 1081 bytes .../rc/checkbox_indeterminate_disabled.png | Bin 0 -> 614 bytes .../rc/checkbox_indeterminate_disabled@2x.png | Bin 0 -> 1105 bytes .../rc/checkbox_indeterminate_focus.png | Bin 0 -> 576 bytes .../rc/checkbox_indeterminate_focus@2x.png | Bin 0 -> 1066 bytes .../rc/checkbox_indeterminate_pressed.png | Bin 0 -> 563 bytes .../rc/checkbox_indeterminate_pressed@2x.png | Bin 0 -> 1087 bytes .../src/qdarkstyle/rc/checkbox_unchecked.png | Bin 0 -> 397 bytes .../qdarkstyle/rc/checkbox_unchecked@2x.png | Bin 0 -> 828 bytes .../rc/checkbox_unchecked_disabled.png | Bin 0 -> 386 bytes .../rc/checkbox_unchecked_disabled@2x.png | Bin 0 -> 875 bytes .../rc/checkbox_unchecked_focus.png | Bin 0 -> 394 bytes .../rc/checkbox_unchecked_focus@2x.png | Bin 0 -> 866 bytes .../rc/checkbox_unchecked_pressed.png | Bin 0 -> 403 bytes .../rc/checkbox_unchecked_pressed@2x.png | Bin 0 -> 861 bytes .../src/qdarkstyle/rc/close-hover.png | Bin 0 -> 598 bytes .../src/qdarkstyle/rc/close-pressed.png | Bin 0 -> 598 bytes .../src/qdarkstyle/rc/close.png | Bin 0 -> 586 bytes .../src/qdarkstyle/rc/down_arrow.png | Bin 0 -> 165 bytes .../src/qdarkstyle/rc/down_arrow_disabled.png | Bin 0 -> 166 bytes .../src/qdarkstyle/rc/left_arrow.png | Bin 0 -> 166 bytes .../src/qdarkstyle/rc/left_arrow_disabled.png | Bin 0 -> 166 bytes .../src/qdarkstyle/rc/line_horizontal.png | Bin 0 -> 117 bytes .../src/qdarkstyle/rc/line_horizontal@2x.png | Bin 0 -> 135 bytes .../rc/line_horizontal_disabled.png | Bin 0 -> 121 bytes .../rc/line_horizontal_disabled@2x.png | Bin 0 -> 139 bytes .../qdarkstyle/rc/line_horizontal_focus.png | Bin 0 -> 120 bytes .../rc/line_horizontal_focus@2x.png | Bin 0 -> 138 bytes .../qdarkstyle/rc/line_horizontal_pressed.png | Bin 0 -> 120 bytes .../rc/line_horizontal_pressed@2x.png | Bin 0 -> 138 bytes .../src/qdarkstyle/rc/line_vertical.png | Bin 0 -> 130 bytes .../src/qdarkstyle/rc/line_vertical@2x.png | Bin 0 -> 242 bytes .../qdarkstyle/rc/line_vertical_disabled.png | Bin 0 -> 134 bytes .../rc/line_vertical_disabled@2x.png | Bin 0 -> 248 bytes .../src/qdarkstyle/rc/line_vertical_focus.png | Bin 0 -> 134 bytes .../qdarkstyle/rc/line_vertical_focus@2x.png | Bin 0 -> 249 bytes .../qdarkstyle/rc/line_vertical_pressed.png | Bin 0 -> 134 bytes .../rc/line_vertical_pressed@2x.png | Bin 0 -> 248 bytes .../src/qdarkstyle/rc/radio_checked.png | Bin 0 -> 1224 bytes .../src/qdarkstyle/rc/radio_checked@2x.png | Bin 0 -> 2714 bytes .../qdarkstyle/rc/radio_checked_disabled.png | Bin 0 -> 1325 bytes .../rc/radio_checked_disabled@2x.png | Bin 0 -> 2893 bytes .../src/qdarkstyle/rc/radio_checked_focus.png | Bin 0 -> 1293 bytes .../qdarkstyle/rc/radio_checked_focus@2x.png | Bin 0 -> 2736 bytes .../qdarkstyle/rc/radio_checked_pressed.png | Bin 0 -> 1276 bytes .../rc/radio_checked_pressed@2x.png | Bin 0 -> 2765 bytes .../src/qdarkstyle/rc/radio_unchecked.png | Bin 0 -> 963 bytes .../src/qdarkstyle/rc/radio_unchecked@2x.png | Bin 0 -> 2195 bytes .../rc/radio_unchecked_disabled.png | Bin 0 -> 1040 bytes .../rc/radio_unchecked_disabled@2x.png | Bin 0 -> 2294 bytes .../qdarkstyle/rc/radio_unchecked_focus.png | Bin 0 -> 1032 bytes .../rc/radio_unchecked_focus@2x.png | Bin 0 -> 2186 bytes .../qdarkstyle/rc/radio_unchecked_pressed.png | Bin 0 -> 1022 bytes .../rc/radio_unchecked_pressed@2x.png | Bin 0 -> 2197 bytes .../src/qdarkstyle/rc/right_arrow.png | Bin 0 -> 160 bytes .../qdarkstyle/rc/right_arrow_disabled.png | Bin 0 -> 160 bytes .../src/qdarkstyle/rc/sizegrip.png | Bin 0 -> 129 bytes .../qdarkstyle/rc/stylesheet-branch-end.png | Bin 0 -> 224 bytes .../qdarkstyle/rc/stylesheet-branch-more.png | Bin 0 -> 182 bytes .../src/qdarkstyle/rc/stylesheet-vline.png | Bin 0 -> 239 bytes .../qdarkstyle/rc/toolbar_move_horizontal.png | Bin 0 -> 150 bytes .../rc/toolbar_move_horizontal@2x.png | Bin 0 -> 304 bytes .../rc/toolbar_move_horizontal_disabled.png | Bin 0 -> 155 bytes .../toolbar_move_horizontal_disabled@2x.png | Bin 0 -> 308 bytes .../rc/toolbar_move_horizontal_focus.png | Bin 0 -> 154 bytes .../rc/toolbar_move_horizontal_focus@2x.png | Bin 0 -> 311 bytes .../rc/toolbar_move_horizontal_pressed.png | Bin 0 -> 154 bytes .../rc/toolbar_move_horizontal_pressed@2x.png | Bin 0 -> 307 bytes .../qdarkstyle/rc/toolbar_move_vertical.png | Bin 0 -> 137 bytes .../rc/toolbar_move_vertical@2x.png | Bin 0 -> 201 bytes .../rc/toolbar_move_vertical_disabled.png | Bin 0 -> 140 bytes .../rc/toolbar_move_vertical_disabled@2x.png | Bin 0 -> 212 bytes .../rc/toolbar_move_vertical_focus.png | Bin 0 -> 144 bytes .../rc/toolbar_move_vertical_focus@2x.png | Bin 0 -> 211 bytes .../rc/toolbar_move_vertical_pressed.png | Bin 0 -> 143 bytes .../rc/toolbar_move_vertical_pressed@2x.png | Bin 0 -> 204 bytes .../rc/toolbar_separator_horizontal.png | Bin 0 -> 145 bytes .../rc/toolbar_separator_horizontal@2x.png | Bin 0 -> 286 bytes .../toolbar_separator_horizontal_disabled.png | Bin 0 -> 151 bytes ...olbar_separator_horizontal_disabled@2x.png | Bin 0 -> 292 bytes .../rc/toolbar_separator_horizontal_focus.png | Bin 0 -> 149 bytes .../toolbar_separator_horizontal_focus@2x.png | Bin 0 -> 294 bytes .../toolbar_separator_horizontal_pressed.png | Bin 0 -> 149 bytes ...oolbar_separator_horizontal_pressed@2x.png | Bin 0 -> 289 bytes .../rc/toolbar_separator_vertical.png | Bin 0 -> 133 bytes .../rc/toolbar_separator_vertical@2x.png | Bin 0 -> 191 bytes .../toolbar_separator_vertical_disabled.png | Bin 0 -> 135 bytes ...toolbar_separator_vertical_disabled@2x.png | Bin 0 -> 199 bytes .../rc/toolbar_separator_vertical_focus.png | Bin 0 -> 139 bytes .../toolbar_separator_vertical_focus@2x.png | Bin 0 -> 196 bytes .../rc/toolbar_separator_vertical_pressed.png | Bin 0 -> 138 bytes .../toolbar_separator_vertical_pressed@2x.png | Bin 0 -> 193 bytes .../src/qdarkstyle/rc/transparent.png | Bin 0 -> 104 bytes .../src/qdarkstyle/rc/transparent@2x.png | Bin 0 -> 117 bytes .../qdarkstyle/rc/transparent_disabled.png | Bin 0 -> 104 bytes .../qdarkstyle/rc/transparent_disabled@2x.png | Bin 0 -> 117 bytes .../src/qdarkstyle/rc/transparent_focus.png | Bin 0 -> 104 bytes .../qdarkstyle/rc/transparent_focus@2x.png | Bin 0 -> 117 bytes .../src/qdarkstyle/rc/transparent_pressed.png | Bin 0 -> 104 bytes .../qdarkstyle/rc/transparent_pressed@2x.png | Bin 0 -> 117 bytes .../src/qdarkstyle/rc/undock.png | Bin 0 -> 578 bytes .../src/qdarkstyle/rc/up_arrow.png | Bin 0 -> 158 bytes .../src/qdarkstyle/rc/up_arrow_disabled.png | Bin 0 -> 159 bytes .../src/qdarkstyle/rc/window_close.png | Bin 0 -> 766 bytes .../src/qdarkstyle/rc/window_close@2x.png | Bin 0 -> 1690 bytes .../qdarkstyle/rc/window_close_disabled.png | Bin 0 -> 838 bytes .../rc/window_close_disabled@2x.png | Bin 0 -> 1724 bytes .../src/qdarkstyle/rc/window_close_focus.png | Bin 0 -> 756 bytes .../qdarkstyle/rc/window_close_focus@2x.png | Bin 0 -> 1704 bytes .../qdarkstyle/rc/window_close_pressed.png | Bin 0 -> 745 bytes .../qdarkstyle/rc/window_close_pressed@2x.png | Bin 0 -> 1679 bytes .../src/qdarkstyle/rc/window_grip.png | Bin 0 -> 426 bytes .../src/qdarkstyle/rc/window_grip@2x.png | Bin 0 -> 735 bytes .../qdarkstyle/rc/window_grip_disabled.png | Bin 0 -> 447 bytes .../qdarkstyle/rc/window_grip_disabled@2x.png | Bin 0 -> 768 bytes .../src/qdarkstyle/rc/window_grip_focus.png | Bin 0 -> 435 bytes .../qdarkstyle/rc/window_grip_focus@2x.png | Bin 0 -> 738 bytes .../src/qdarkstyle/rc/window_grip_pressed.png | Bin 0 -> 444 bytes .../qdarkstyle/rc/window_grip_pressed@2x.png | Bin 0 -> 729 bytes .../src/qdarkstyle/rc/window_minimize.png | Bin 0 -> 193 bytes .../src/qdarkstyle/rc/window_minimize@2x.png | Bin 0 -> 316 bytes .../rc/window_minimize_disabled.png | Bin 0 -> 206 bytes .../rc/window_minimize_disabled@2x.png | Bin 0 -> 332 bytes .../qdarkstyle/rc/window_minimize_focus.png | Bin 0 -> 208 bytes .../rc/window_minimize_focus@2x.png | Bin 0 -> 339 bytes .../qdarkstyle/rc/window_minimize_pressed.png | Bin 0 -> 202 bytes .../rc/window_minimize_pressed@2x.png | Bin 0 -> 336 bytes .../src/qdarkstyle/rc/window_undock.png | Bin 0 -> 510 bytes .../src/qdarkstyle/rc/window_undock@2x.png | Bin 0 -> 875 bytes .../qdarkstyle/rc/window_undock_disabled.png | Bin 0 -> 541 bytes .../rc/window_undock_disabled@2x.png | Bin 0 -> 910 bytes .../src/qdarkstyle/rc/window_undock_focus.png | Bin 0 -> 519 bytes .../qdarkstyle/rc/window_undock_focus@2x.png | Bin 0 -> 877 bytes .../qdarkstyle/rc/window_undock_pressed.png | Bin 0 -> 523 bytes .../rc/window_undock_pressed@2x.png | Bin 0 -> 880 bytes .../SqliteDBProcess/src/qdarkstyle/style.qrc | 216 + .../src/qdarkstyle/style.qrc.depends | 216 + .../SqliteDBProcess/src/qdarkstyle/style.qss | 2165 ++ .../src/sql/ObjectIdentifier.cpp | 80 + .../src/sql/ObjectIdentifier.h | 104 + .../SqliteDBProcess/src/sql/Query.cpp | 148 + .../SqliteDBProcess/src/sql/Query.h | 99 + .../src/sql/parser/ParserDriver.cpp | 31 + .../src/sql/parser/ParserDriver.h | 59 + .../SqliteDBProcess/src/sql/parser/README | 9 + .../src/sql/parser/sqlite3_lexer.cpp | 3623 ++ .../src/sql/parser/sqlite3_lexer.h | 610 + .../src/sql/parser/sqlite3_lexer.ll | 259 + .../src/sql/parser/sqlite3_location.h | 334 + .../src/sql/parser/sqlite3_parser.cpp | 4726 +++ .../src/sql/parser/sqlite3_parser.hpp | 4097 +++ .../src/sql/parser/sqlite3_parser.yy | 988 + .../SqliteDBProcess/src/sql/sqlitetypes.cpp | 712 + .../SqliteDBProcess/src/sql/sqlitetypes.h | 618 + .../SqliteDBProcess/src/sqlite.h | 23 + .../SqliteDBProcess/src/sqlitedb.cpp | 2130 ++ .../SqliteDBProcess/src/sqlitedb.h | 292 + .../SqliteDBProcess/src/sqlitetablemodel.cpp | 1193 + .../SqliteDBProcess/src/sqlitetablemodel.h | 254 + .../SqliteDBProcess/src/sqltextedit.cpp | 135 + .../SqliteDBProcess/src/sqltextedit.h | 27 + .../SqliteDBProcess/src/src.pro | 303 + .../SqliteDBProcess/src/tests/CMakeLists.txt | 162 + .../SqliteDBProcess/src/tests/TestImport.cpp | 178 + .../SqliteDBProcess/src/tests/TestImport.h | 19 + .../SqliteDBProcess/src/tests/TestRegex.cpp | 81 + .../SqliteDBProcess/src/tests/TestRegex.h | 17 + .../src/tests/TestRowCache.cpp | 189 + .../SqliteDBProcess/src/tests/TestRowCache.h | 22 + .../src/tests/testsqlobjects.cpp | 773 + .../src/tests/testsqlobjects.h | 47 + .../src/tools/create_windows_icon.sh | 19 + .../SqliteDBProcess/src/translations/README | 1 + .../src/translations/flags/ar.png | Bin 0 -> 592 bytes .../src/translations/flags/br.png | Bin 0 -> 560 bytes .../src/translations/flags/cn.png | Bin 0 -> 571 bytes .../src/translations/flags/cs.png | Bin 0 -> 252 bytes .../src/translations/flags/de.png | Bin 0 -> 444 bytes .../src/translations/flags/eg.png | Bin 0 -> 239 bytes .../src/translations/flags/es.png | Bin 0 -> 258 bytes .../src/translations/flags/flags.qrc | 23 + .../src/translations/flags/fr.png | Bin 0 -> 616 bytes .../src/translations/flags/gb.png | Bin 0 -> 735 bytes .../src/translations/flags/it.png | Bin 0 -> 658 bytes .../src/translations/flags/jp.png | Bin 0 -> 420 bytes .../src/translations/flags/kr.png | Bin 0 -> 893 bytes .../src/translations/flags/nl.png | Bin 0 -> 119 bytes .../src/translations/flags/pl.png | Bin 0 -> 139 bytes .../src/translations/flags/roc.png | Bin 0 -> 329 bytes .../src/translations/flags/ru.png | Bin 0 -> 503 bytes .../src/translations/flags/tr.png | Bin 0 -> 792 bytes .../src/translations/flags/ua.png | Bin 0 -> 121 bytes .../src/translations/flags/us.png | Bin 0 -> 872 bytes .../src/translations/place_translations_here | 0 .../src/translations/sqlb_ar_SA.qm | Bin 0 -> 223625 bytes .../src/translations/sqlb_ar_SA.ts | 7051 ++++ .../src/translations/sqlb_cs.qm | Bin 0 -> 72122 bytes .../src/translations/sqlb_cs.ts | 6940 ++++ .../src/translations/sqlb_de.qm | Bin 0 -> 242646 bytes .../src/translations/sqlb_de.ts | 7015 ++++ .../src/translations/sqlb_en_GB.qm | Bin 0 -> 33039 bytes .../src/translations/sqlb_en_GB.ts | 6927 ++++ .../src/translations/sqlb_es_ES.qm | Bin 0 -> 252959 bytes .../src/translations/sqlb_es_ES.ts | 7034 ++++ .../src/translations/sqlb_fa.ts | 6922 ++++ .../src/translations/sqlb_fr.qm | Bin 0 -> 264290 bytes .../src/translations/sqlb_fr.ts | 7039 ++++ .../src/translations/sqlb_it.qm | Bin 0 -> 249391 bytes .../src/translations/sqlb_it.ts | 7020 ++++ .../src/translations/sqlb_ja.qm | Bin 0 -> 182656 bytes .../src/translations/sqlb_ja.ts | 7019 ++++ .../src/translations/sqlb_ko_KR.qm | Bin 0 -> 186801 bytes .../src/translations/sqlb_ko_KR.ts | 7012 ++++ .../src/translations/sqlb_nl.qm | Bin 0 -> 253683 bytes .../src/translations/sqlb_nl.ts | 7076 ++++ .../src/translations/sqlb_pl.qm | Bin 0 -> 224964 bytes .../src/translations/sqlb_pl.ts | 7032 ++++ .../src/translations/sqlb_pt_BR.qm | Bin 0 -> 236318 bytes .../src/translations/sqlb_pt_BR.ts | 7023 ++++ .../src/translations/sqlb_ru.qm | Bin 0 -> 177150 bytes .../src/translations/sqlb_ru.ts | 6996 ++++ .../src/translations/sqlb_tr.qm | Bin 0 -> 225322 bytes .../src/translations/sqlb_tr.ts | 7006 ++++ .../src/translations/sqlb_uk_UA.qm | Bin 0 -> 84283 bytes .../src/translations/sqlb_uk_UA.ts | 6959 ++++ .../src/translations/sqlb_zh.qm | Bin 0 -> 146200 bytes .../src/translations/sqlb_zh.ts | 7008 ++++ .../src/translations/sqlb_zh_TW.qm | Bin 0 -> 25059 bytes .../src/translations/sqlb_zh_TW.ts | 6931 ++++ .../src/translations/translations.qrc | 21 + .../SqliteDBProcess/src/version.h | 16 + .../SqliteDBProcess/src/winapp.rc | 30 + .../TableProcess/TableFieldConfigClass.cpp | 10 + .../TableProcess/TableFieldConfigClass.h | 16 + .../TableProcess/TableFieldConfigClass.ui | 22 + .../TableProcess/TableFieldFindTool.cpp | 10 + .../TableProcess/TableFieldFindTool.h | 16 + .../TableProcess/TableFieldFindTool.ui | 22 + .../TableProcess/TableMainWindow.cpp | 359 + .../TableProcess/TableMainWindow.h | 79 + .../TableProcess/TableMainWindow.ui | 282 + .../TableProcess/TableViewModel.cpp | 359 + .../TableProcess/TableViewModel.h | 84 + .../TableProcess/sqliteOperator.cpp | 4 + .../TableProcess/sqliteOperator.h | 10 + src/WBCLFZSystemModule/TaskNodeList.cpp | 1013 + src/WBCLFZSystemModule/TaskNodeList.h | 245 + .../TaskXml/TaskTreeClass.cpp | 226 + .../TaskXml/TaskTreeClass.h | 112 + src/WBCLFZSystemModule/WBCLFZSystemModule.aps | Bin 0 -> 1476 bytes src/WBCLFZSystemModule/WBCLFZSystemModule.cpp | 123 + src/WBCLFZSystemModule/WBCLFZSystemModule.h | 40 + src/WBCLFZSystemModule/WBCLFZSystemModule.rc | 60 + src/WBCLFZSystemModule/WBCLFZSystemModule.ui | 73 + .../WBCLFZSystemModule.vcxproj | 548 + .../WBCLFZSystemModule.vcxproj.filters | 1076 + .../WBCLFZSystemModule.vcxproj.user | 26 + src/WBCLFZSystemModule/cpp.hint | 4 + src/WBCLFZSystemModule/main.cpp | 199 + .../modelProcess/ModelProcess.cpp | 454 + .../modelProcess/ModelProcess.h | 114 + .../modelProcess/ModelProcess.ui | 490 + src/WBCLFZSystemModule/qconsolewidget.pri | 13 + src/WBCLFZSystemModule/qscriptcompleter.cpp | 193 + src/WBCLFZSystemModule/qscriptcompleter.h | 26 + src/WBCLFZSystemModule/readme.md | 64 + src/WBCLFZSystemModule/resource.h | 14 + src/WBCLFZSystemModule/scriptsession.cpp | 132 + src/WBCLFZSystemModule/scriptsession.h | 53 + src/json/CMakeLists.txt | 30 + src/json/json.hpp | 22875 ++++++++++++ src/json/json.vcxproj | 199 + src/json/json.vcxproj.filters | 38 + src/json/json.vcxproj.user | 16 + src/json/jsonplugin.json | 1 + src/qcustomplot/CMakeLists.txt | 20 + src/qcustomplot/GPL.txt | 674 + src/qcustomplot/main.cpp | 10 + src/qcustomplot/qcustomplot.cpp | 30214 ++++++++++++++++ src/qcustomplot/qcustomplot.h | 6673 ++++ src/qcustomplot/qcustomplot.pro | 13 + src/qcustomplot/qcustomplot.qrc | 4 + src/qcustomplot/qcustomplot.ui | 28 + src/qhexedit/CMakeLists.txt | 57 + src/qhexedit/chunks.cpp | 323 + src/qhexedit/chunks.h | 77 + src/qhexedit/commands.cpp | 165 + src/qhexedit/commands.h | 47 + src/qhexedit/license.txt | 502 + src/qhexedit/qhexedit.cpp | 1145 + src/qhexedit/qhexedit.h | 423 + src/qhexedit/qhexedit.pro | 21 + src/qhexedit/qhexedit.vcxproj | 203 + src/qhexedit/qhexedit.vcxproj.filters | 50 + src/qhexedit/qhexedit.vcxproj.user | 16 + src/qhexedit/qhexeditplugin.json | 1 + src/qrc/LAMPTool.qrc | 4 + src/qrc/OCCViewer/res/antialiasing.png | Bin 0 -> 230 bytes src/qrc/OCCViewer/res/cursor_rotate.png | Bin 0 -> 291 bytes src/qrc/OCCViewer/res/cursor_zoom.png | Bin 0 -> 245 bytes src/qrc/OCCViewer/res/help.png | Bin 0 -> 214 bytes src/qrc/OCCViewer/res/lamp.png | Bin 0 -> 1355 bytes src/qrc/OCCViewer/res/raytracing.png | Bin 0 -> 223 bytes src/qrc/OCCViewer/res/reflections.png | Bin 0 -> 217 bytes src/qrc/OCCViewer/res/shadows.png | Bin 0 -> 264 bytes src/qrc/OCCViewer/res/tool_color.png | Bin 0 -> 288 bytes src/qrc/OCCViewer/res/tool_delete.png | Bin 0 -> 203 bytes src/qrc/OCCViewer/res/tool_material.png | Bin 0 -> 293 bytes src/qrc/OCCViewer/res/tool_shading.png | Bin 0 -> 256 bytes src/qrc/OCCViewer/res/tool_transparency.png | Bin 0 -> 318 bytes src/qrc/OCCViewer/res/tool_wireframe.png | Bin 0 -> 259 bytes src/qrc/OCCViewer/res/view_axo.png | Bin 0 -> 392 bytes src/qrc/OCCViewer/res/view_back.png | Bin 0 -> 233 bytes src/qrc/OCCViewer/res/view_bottom.png | Bin 0 -> 233 bytes src/qrc/OCCViewer/res/view_comp_off.png | Bin 0 -> 199 bytes src/qrc/OCCViewer/res/view_comp_on.png | Bin 0 -> 180 bytes src/qrc/OCCViewer/res/view_fitall.png | Bin 0 -> 231 bytes src/qrc/OCCViewer/res/view_front.png | Bin 0 -> 238 bytes src/qrc/OCCViewer/res/view_left.png | Bin 0 -> 231 bytes src/qrc/OCCViewer/res/view_reset.png | Bin 0 -> 204 bytes src/qrc/OCCViewer/res/view_right.png | Bin 0 -> 230 bytes src/qrc/OCCViewer/res/view_top.png | Bin 0 -> 235 bytes src/qrc/PointCloudProcess/images/1.gif | Bin 0 -> 276082 bytes .../images/QTreeView/branch-closed.png | Bin 0 -> 328 bytes .../images/QTreeView/branch-end.png | Bin 0 -> 180 bytes .../images/QTreeView/branch-more.png | Bin 0 -> 109 bytes .../images/QTreeView/branch-open.png | Bin 0 -> 334 bytes .../images/QTreeView/vline.png | Bin 0 -> 122 bytes src/qrc/PointCloudProcess/images/RGB.png | Bin 0 -> 3331 bytes .../images/algorithm/DASHBOARD.png | Bin 0 -> 2785 bytes .../images/algorithm/DBSCAN.png | Bin 0 -> 2041 bytes .../images/algorithm/Histogram.png | Bin 0 -> 616 bytes .../images/algorithm/KMeans.png | Bin 0 -> 2555 bytes .../images/algorithm/binary.png | Bin 0 -> 1544 bytes .../images/algorithm/chooseMatrix.png | Bin 0 -> 2628 bytes .../images/algorithm/density.png | Bin 0 -> 1452 bytes .../images/algorithm/extract.png | Bin 0 -> 2922 bytes .../images/algorithm/filter.png | Bin 0 -> 1919 bytes .../images/algorithm/help.png | Bin 0 -> 1998 bytes .../images/algorithm/matrix.png | Bin 0 -> 1538 bytes .../images/algorithm/more.png | Bin 0 -> 2259 bytes .../images/algorithm/nihe.png | Bin 0 -> 2180 bytes .../images/algorithm/person.png | Bin 0 -> 1575 bytes .../images/algorithm/pingjie.png | Bin 0 -> 1853 bytes .../images/algorithm/transform.png | Bin 0 -> 2478 bytes .../images/algorithm/tree.png | Bin 0 -> 3256 bytes src/qrc/PointCloudProcess/images/back.png | Bin 0 -> 507 bytes src/qrc/PointCloudProcess/images/bottom.png | Bin 0 -> 475 bytes src/qrc/PointCloudProcess/images/camera.png | Bin 0 -> 4517 bytes .../PointCloudProcess/images/ccAddConstSF.png | Bin 0 -> 119 bytes src/qrc/PointCloudProcess/images/ccAlign.png | Bin 0 -> 185 bytes .../images/ccBilateralFilter.png | Bin 0 -> 630 bytes .../PointCloudProcess/images/ccCCExtract.png | Bin 0 -> 335 bytes .../images/ccCenteredPerspective32.png | Bin 0 -> 866 bytes .../images/ccClippingBox.png | Bin 0 -> 917 bytes .../images/ccClippingBoxMultExport.png | Bin 0 -> 1218 bytes .../images/ccClippingBoxSingleExport.png | Bin 0 -> 1107 bytes src/qrc/PointCloudProcess/images/ccClone.png | Bin 0 -> 2049 bytes .../images/ccCloudCloudDistance.png | Bin 0 -> 667 bytes .../images/ccCloudMeshDistance.png | Bin 0 -> 763 bytes .../images/ccCloudPrimitiveDistance.png | Bin 0 -> 3896 bytes .../images/ccComputeStat.png | Bin 0 -> 315 bytes .../PointCloudProcess/images/ccConsole.png | Bin 0 -> 1413 bytes src/qrc/PointCloudProcess/images/ccDelete.png | Bin 0 -> 544 bytes .../PointCloudProcess/images/ccDeleteSF.png | Bin 0 -> 484 bytes src/qrc/PointCloudProcess/images/ccExit.png | Bin 0 -> 387 bytes .../images/ccFilterByValue.png | Bin 0 -> 341 bytes .../PointCloudProcess/images/ccFullScreen.png | Bin 0 -> 198 bytes .../images/ccGaussianFilter.png | Bin 0 -> 407 bytes src/qrc/PointCloudProcess/images/ccGear.png | Bin 0 -> 704 bytes .../PointCloudProcess/images/ccGlobalZoom.png | Bin 0 -> 131 bytes .../PointCloudProcess/images/ccGradient.png | Bin 0 -> 276 bytes src/qrc/PointCloudProcess/images/ccGrid.png | Bin 0 -> 253 bytes .../PointCloudProcess/images/ccHistogram.png | Bin 0 -> 267 bytes .../images/ccInteractiveTransformation.png | Bin 0 -> 165 bytes src/qrc/PointCloudProcess/images/ccLevel.png | Bin 0 -> 651 bytes .../images/ccLightParams.png | Bin 0 -> 331 bytes src/qrc/PointCloudProcess/images/ccMerge.png | Bin 0 -> 292 bytes src/qrc/PointCloudProcess/images/ccMinus.png | Bin 0 -> 256 bytes src/qrc/PointCloudProcess/images/ccOpen.png | Bin 0 -> 1933 bytes .../images/ccOrthoMode32.png | Bin 0 -> 654 bytes src/qrc/PointCloudProcess/images/ccPencil.png | Bin 0 -> 623 bytes .../PointCloudProcess/images/ccPickCenter.png | Bin 0 -> 141 bytes .../images/ccPickCenterAuto.png | Bin 0 -> 396 bytes .../PointCloudProcess/images/ccPivotAuto.png | Bin 0 -> 1082 bytes .../PointCloudProcess/images/ccPivotOff.png | Bin 0 -> 1024 bytes .../PointCloudProcess/images/ccPivotOn.png | Bin 0 -> 1048 bytes src/qrc/PointCloudProcess/images/ccPlus.png | Bin 0 -> 687 bytes .../images/ccPointListPicking.png | Bin 0 -> 497 bytes .../images/ccPointPicking.png | Bin 0 -> 1167 bytes .../PointCloudProcess/images/ccPointSize.png | Bin 0 -> 203 bytes .../PointCloudProcess/images/ccRegister.png | Bin 0 -> 464 bytes .../PointCloudProcess/images/ccSORFilter.png | Bin 0 -> 877 bytes .../images/ccSampleCloud.png | Bin 0 -> 151 bytes .../images/ccSamplePoints.png | Bin 0 -> 988 bytes src/qrc/PointCloudProcess/images/ccSave.png | Bin 0 -> 1126 bytes .../images/ccSaveProject.png | Bin 0 -> 1743 bytes .../PointCloudProcess/images/ccSegment.png | Bin 0 -> 259 bytes .../images/ccSfArithmetic.png | Bin 0 -> 322 bytes .../PointCloudProcess/images/ccStatTest.png | Bin 0 -> 660 bytes src/qrc/PointCloudProcess/images/ccStereo.png | Bin 0 -> 1110 bytes .../PointCloudProcess/images/ccSunLight.png | Bin 0 -> 1690 bytes .../PointCloudProcess/images/ccSwapUpDown.png | Bin 0 -> 1440 bytes .../images/ccTracePolyline.png | Bin 0 -> 2537 bytes .../images/ccTracePolyline.svg | 79 + .../PointCloudProcess/images/ccUnstack.png | Bin 0 -> 2785 bytes .../PointCloudProcess/images/ccViewIso1.png | Bin 0 -> 1363 bytes .../PointCloudProcess/images/ccViewIso2.png | Bin 0 -> 1391 bytes .../PointCloudProcess/images/ccViewXneg.png | Bin 0 -> 314 bytes .../PointCloudProcess/images/ccViewXpos.png | Bin 0 -> 321 bytes .../PointCloudProcess/images/ccViewYneg.png | Bin 0 -> 305 bytes .../PointCloudProcess/images/ccViewYpos.png | Bin 0 -> 307 bytes .../PointCloudProcess/images/ccViewZneg.png | Bin 0 -> 286 bytes .../PointCloudProcess/images/ccViewZpos.png | Bin 0 -> 291 bytes .../images/ccViewerBasedPerspective32.png | Bin 0 -> 1143 bytes src/qrc/PointCloudProcess/images/ccZoomIn.png | Bin 0 -> 1610 bytes .../PointCloudProcess/images/clipboard.png | Bin 0 -> 360 bytes src/qrc/PointCloudProcess/images/color.png | Bin 0 -> 117 bytes .../PointCloudProcess/images/coodinate.png | Bin 0 -> 982 bytes .../images/dbAreaLabelSymbol.png | Bin 0 -> 294 bytes .../images/dbCalibratedImageSymbol.png | Bin 0 -> 313 bytes .../images/dbCamSensorSymbol.png | Bin 0 -> 427 bytes .../images/dbCloudSymbol.png | Bin 0 -> 302 bytes .../images/dbCloudSymbolLocked.png | Bin 0 -> 308 bytes .../images/dbContainerSymbol.png | Bin 0 -> 297 bytes .../images/dbContainerSymbolLocked.png | Bin 0 -> 362 bytes .../images/dbGBLSensorSymbol.png | Bin 0 -> 548 bytes .../images/dbHObjectSymbol.png | Bin 0 -> 1073 bytes .../images/dbHObjectSymbolLocked.png | Bin 0 -> 1060 bytes .../images/dbImageSymbol.png | Bin 0 -> 471 bytes .../images/dbLabelSymbol.png | Bin 0 -> 688 bytes .../PointCloudProcess/images/dbLockSymbol.png | Bin 0 -> 178 bytes .../images/dbMaterialSymbol.png | Bin 0 -> 522 bytes .../PointCloudProcess/images/dbMeshSymbol.png | Bin 0 -> 455 bytes .../images/dbMeshSymbolLocked.png | Bin 0 -> 409 bytes .../images/dbMiscGeomSymbol.png | Bin 0 -> 466 bytes .../images/dbMiscGeomSymbolLocked.png | Bin 0 -> 419 bytes .../images/dbOctreeSymbol.png | Bin 0 -> 368 bytes .../images/dbOctreeSymbolLocked.png | Bin 0 -> 364 bytes .../images/dbPolylineSymbol.png | Bin 0 -> 447 bytes .../images/dbSubMeshSymbol.png | Bin 0 -> 747 bytes .../images/dbSubMeshSymbolLocked.png | Bin 0 -> 782 bytes .../images/dbViewportSymbol.png | Bin 0 -> 1011 bytes src/qrc/PointCloudProcess/images/donate.png | Bin 0 -> 13517 bytes .../PointCloudProcess/images/exportIcon.png | Bin 0 -> 2591 bytes .../PointCloudProcess/images/files/CSV.png | Bin 0 -> 1452 bytes .../PointCloudProcess/images/files/add.png | Bin 0 -> 1832 bytes .../images/files/bgColor.png | Bin 0 -> 903 bytes .../PointCloudProcess/images/files/cloud.png | Bin 0 -> 2357 bytes .../PointCloudProcess/images/files/cloud2.png | Bin 0 -> 1960 bytes .../PointCloudProcess/images/files/copy.png | Bin 0 -> 695 bytes .../PointCloudProcess/images/files/cut.png | Bin 0 -> 2305 bytes .../PointCloudProcess/images/files/log.png | Bin 0 -> 1734 bytes .../PointCloudProcess/images/files/new1.png | Bin 0 -> 1438 bytes .../PointCloudProcess/images/files/new2.png | Bin 0 -> 642 bytes .../PointCloudProcess/images/files/paste.png | Bin 0 -> 741 bytes .../images/files/pointCloud.png | Bin 0 -> 2681 bytes .../PointCloudProcess/images/files/search.png | Bin 0 -> 2148 bytes .../images/files/snapshot.png | Bin 0 -> 1712 bytes .../PointCloudProcess/images/files/star.png | Bin 0 -> 2294 bytes .../PointCloudProcess/images/files/txt.png | Bin 0 -> 1359 bytes src/qrc/PointCloudProcess/images/front.png | Bin 0 -> 507 bytes src/qrc/PointCloudProcess/images/gamepad.png | Bin 0 -> 601 bytes src/qrc/PointCloudProcess/images/gearIcon.png | Bin 0 -> 704 bytes src/qrc/PointCloudProcess/images/grey.png | Bin 0 -> 2024 bytes src/qrc/PointCloudProcess/images/hashtag.png | Bin 0 -> 301 bytes src/qrc/PointCloudProcess/images/ic-redo.png | Bin 0 -> 1366 bytes src/qrc/PointCloudProcess/images/ic-undo.png | Bin 0 -> 1355 bytes .../PointCloudProcess/images/icon/cc_icon.ico | Bin 0 -> 39839 bytes .../PointCloudProcess/images/icon/cc_icon.rc | 1 + .../PointCloudProcess/images/icon/cc_icon.svg | 9 + .../images/icon/cc_icon_16.png | Bin 0 -> 590 bytes .../images/icon/cc_icon_256.png | Bin 0 -> 9089 bytes .../images/icon/cc_icon_32.png | Bin 0 -> 1046 bytes .../images/icon/cc_icon_64.png | Bin 0 -> 2041 bytes .../images/icon/cc_viewer_icon.svg | 12 + .../images/icon/cc_viewer_icon_16.png | Bin 0 -> 725 bytes .../images/icon/cc_viewer_icon_256.png | Bin 0 -> 13095 bytes .../images/icon/cc_viewer_icon_32.png | Bin 0 -> 1572 bytes .../images/icon/cc_viewer_icon_64.png | Bin 0 -> 3164 bytes .../PointCloudProcess/images/im3DxLogo.png | Bin 0 -> 2379 bytes .../PointCloudProcess/images/imLogoV2Qt.png | Bin 0 -> 21785 bytes .../PointCloudProcess/images/interactors.png | Bin 0 -> 373 bytes src/qrc/PointCloudProcess/images/keda.ico | Bin 0 -> 67646 bytes src/qrc/PointCloudProcess/images/left.png | Bin 0 -> 521 bytes src/qrc/PointCloudProcess/images/lock.png | Bin 0 -> 1533 bytes src/qrc/PointCloudProcess/images/mapIcon.png | Bin 0 -> 17559 bytes .../images/material/3DxLogo.png | Bin 0 -> 2379 bytes .../images/material/Raster_grid.pptx | Bin 0 -> 38704 bytes .../images/material/ccCenteredPerspective.svg | 199 + .../images/material/ccClippingBox.svg | 242 + .../images/material/ccClippingBoxBase.svg | 242 + .../images/material/ccOrthoMode.svg | 192 + .../images/material/ccOrthoSections.svg | 97 + .../images/material/ccPivot.svg | 223 + .../images/material/ccSectionExtraction.svg | 211 + .../images/material/ccViewIso1.svg | 186 + .../images/material/ccViewIso2.svg | 186 + .../material/ccViewerBasedPerspective.svg | 226 + src/qrc/PointCloudProcess/images/monitor.svg | 1 + src/qrc/PointCloudProcess/images/noFilter.png | Bin 0 -> 1481 bytes src/qrc/PointCloudProcess/images/nvidia.png | Bin 0 -> 1514 bytes src/qrc/PointCloudProcess/images/oculus.png | Bin 0 -> 321 bytes src/qrc/PointCloudProcess/images/open.png | Bin 0 -> 1408 bytes .../images/orthoSections.png | Bin 0 -> 264 bytes .../PointCloudProcess/images/photo-camera.svg | 1 + src/qrc/PointCloudProcess/images/primBox.gif | Bin 0 -> 92 bytes src/qrc/PointCloudProcess/images/primCone.gif | Bin 0 -> 92 bytes .../PointCloudProcess/images/primCylinder.gif | Bin 0 -> 93 bytes src/qrc/PointCloudProcess/images/primDish.gif | Bin 0 -> 82 bytes .../PointCloudProcess/images/primPlane.gif | Bin 0 -> 82 bytes .../PointCloudProcess/images/primSphere.gif | Bin 0 -> 96 bytes .../PointCloudProcess/images/primTorus.gif | Bin 0 -> 82 bytes src/qrc/PointCloudProcess/images/qCompass.png | Bin 0 -> 15651 bytes .../PointCloudProcess/images/raster_grid.jpg | Bin 0 -> 32534 bytes src/qrc/PointCloudProcess/images/redo.png | Bin 0 -> 937 bytes src/qrc/PointCloudProcess/images/reset.png | Bin 0 -> 2013 bytes src/qrc/PointCloudProcess/images/restore.png | Bin 0 -> 970 bytes src/qrc/PointCloudProcess/images/right.png | Bin 0 -> 509 bytes src/qrc/PointCloudProcess/images/rotate0.png | Bin 0 -> 2865 bytes .../PointCloudProcess/images/rotate180.png | Bin 0 -> 2373 bytes .../PointCloudProcess/images/rotate270.png | Bin 0 -> 2537 bytes src/qrc/PointCloudProcess/images/rotate90.png | Bin 0 -> 2587 bytes src/qrc/PointCloudProcess/images/search.svg | 1 + .../images/sectionExtraction.png | Bin 0 -> 242 bytes src/qrc/PointCloudProcess/images/seting.png | Bin 0 -> 3092 bytes .../PointCloudProcess/images/smallBasket.png | Bin 0 -> 679 bytes .../PointCloudProcess/images/smallCSVFile.png | Bin 0 -> 421 bytes .../PointCloudProcess/images/smallCancel.png | Bin 0 -> 192 bytes .../PointCloudProcess/images/smallPause.png | Bin 0 -> 229 bytes .../images/smallPointDistance.png | Bin 0 -> 263 bytes .../images/smallPointProperties.png | Bin 0 -> 587 bytes .../images/smallPointsAngle.png | Bin 0 -> 333 bytes .../images/smallPolygonSelect.png | Bin 0 -> 478 bytes .../images/smallRectangleSelect.png | Bin 0 -> 294 bytes .../PointCloudProcess/images/smallReset.png | Bin 0 -> 193 bytes .../PointCloudProcess/images/smallRevert.png | Bin 0 -> 349 bytes .../images/smallSegmentIn.png | Bin 0 -> 303 bytes .../images/smallSegmentOut.png | Bin 0 -> 307 bytes .../PointCloudProcess/images/smallSphere.png | Bin 0 -> 537 bytes .../PointCloudProcess/images/smallTrash.png | Bin 0 -> 454 bytes .../images/smallValidate.png | Bin 0 -> 257 bytes src/qrc/PointCloudProcess/images/square.png | Bin 0 -> 189 bytes src/qrc/PointCloudProcess/images/store.png | Bin 0 -> 979 bytes .../images/theme/snowman.png | Bin 0 -> 2836 bytes .../images/typeGrayColor.png | Bin 0 -> 176 bytes .../PointCloudProcess/images/typeNormal.png | Bin 0 -> 560 bytes .../images/typePositiveSF.png | Bin 0 -> 293 bytes .../images/typeQuaternion.png | Bin 0 -> 484 bytes .../images/typeRgbCcolor.png | Bin 0 -> 787 bytes src/qrc/PointCloudProcess/images/typeSF.png | Bin 0 -> 290 bytes .../images/typeXCoordinate.png | Bin 0 -> 153 bytes .../images/typeYCoordinate.png | Bin 0 -> 145 bytes .../images/typeZCoordinate.png | Bin 0 -> 148 bytes src/qrc/PointCloudProcess/images/undo.png | Bin 0 -> 990 bytes .../PointCloudProcess/images/unfoldSmall.png | Bin 0 -> 142 bytes src/qrc/PointCloudProcess/images/up.png | Bin 0 -> 487 bytes src/qrc/PointCloudProcess/images/zoomin.png | Bin 0 -> 2339 bytes src/qrc/PointCloudProcess/images/zoomout.png | Bin 0 -> 2399 bytes src/qrc/WBCLFZSystemModule.qrc | 91 + src/qrc/qianfan.qrc | 482 +- src/qrc/translations/MainWindow_zh_CN.qm | Bin 13453 -> 13917 bytes src/qrc/translations/MainWindow_zh_CN.ts | 566 +- src/qscintilla2/CMakeLists.txt | 56 + src/qscintilla2/ChangeLog | 6206 ++++ src/qscintilla2/LICENSE | 674 + src/qscintilla2/NEWS | 541 + src/qscintilla2/Qt4Qt5/CMakeLists.txt | 181 + src/qscintilla2/Qt4Qt5/InputMethod.cpp | 283 + src/qscintilla2/Qt4Qt5/ListBoxQt.cpp | 357 + src/qscintilla2/Qt4Qt5/ListBoxQt.h | 76 + src/qscintilla2/Qt4Qt5/MacPasteboardMime.cpp | 111 + src/qscintilla2/Qt4Qt5/PlatQt.cpp | 999 + .../Qt4Qt5/Qsci/qsciabstractapis.h | 90 + src/qscintilla2/Qt4Qt5/Qsci/qsciapis.h | 213 + src/qscintilla2/Qt4Qt5/Qsci/qscicommand.h | 408 + src/qscintilla2/Qt4Qt5/Qsci/qscicommandset.h | 89 + src/qscintilla2/Qt4Qt5/Qsci/qscidocument.h | 61 + src/qscintilla2/Qt4Qt5/Qsci/qsciglobal.h | 48 + src/qscintilla2/Qt4Qt5/Qsci/qscilexer.h | 350 + src/qscintilla2/Qt4Qt5/Qsci/qscilexercpp.h | 398 + src/qscintilla2/Qt4Qt5/Qsci/qscilexercustom.h | 100 + src/qscintilla2/Qt4Qt5/Qsci/qscilexerhtml.h | 532 + .../Qt4Qt5/Qsci/qscilexerjavascript.h | 81 + src/qscintilla2/Qt4Qt5/Qsci/qscilexerjson.h | 184 + src/qscintilla2/Qt4Qt5/Qsci/qscilexerpython.h | 333 + src/qscintilla2/Qt4Qt5/Qsci/qscilexersql.h | 286 + src/qscintilla2/Qt4Qt5/Qsci/qscilexerxml.h | 106 + src/qscintilla2/Qt4Qt5/Qsci/qscimacro.h | 98 + src/qscintilla2/Qt4Qt5/Qsci/qsciprinter.h | 112 + src/qscintilla2/Qt4Qt5/Qsci/qsciscintilla.h | 2307 ++ .../Qt4Qt5/Qsci/qsciscintillabase.h | 3892 ++ src/qscintilla2/Qt4Qt5/Qsci/qscistyle.h | 204 + src/qscintilla2/Qt4Qt5/Qsci/qscistyledtext.h | 61 + src/qscintilla2/Qt4Qt5/SciAccessibility.cpp | 760 + src/qscintilla2/Qt4Qt5/SciAccessibility.h | 122 + src/qscintilla2/Qt4Qt5/SciClasses.cpp | 193 + src/qscintilla2/Qt4Qt5/SciClasses.h | 103 + src/qscintilla2/Qt4Qt5/SciNamespace.h | 35 + src/qscintilla2/Qt4Qt5/ScintillaQt.cpp | 766 + src/qscintilla2/Qt4Qt5/ScintillaQt.h | 150 + .../Qt4Qt5/features/qscintilla2.prf | 27 + src/qscintilla2/Qt4Qt5/qsciabstractapis.cpp | 51 + src/qscintilla2/Qt4Qt5/qsciapis.cpp | 999 + src/qscintilla2/Qt4Qt5/qscicommand.cpp | 143 + src/qscintilla2/Qt4Qt5/qscicommandset.cpp | 991 + src/qscintilla2/Qt4Qt5/qscidocument.cpp | 151 + src/qscintilla2/Qt4Qt5/qscilexer.cpp | 731 + src/qscintilla2/Qt4Qt5/qscilexercpp.cpp | 801 + src/qscintilla2/Qt4Qt5/qscilexercustom.cpp | 101 + src/qscintilla2/Qt4Qt5/qscilexerhtml.cpp | 1181 + .../Qt4Qt5/qscilexerjavascript.cpp | 120 + src/qscintilla2/Qt4Qt5/qscilexerjson.cpp | 298 + src/qscintilla2/Qt4Qt5/qscilexerpython.cpp | 507 + src/qscintilla2/Qt4Qt5/qscilexersql.cpp | 521 + src/qscintilla2/Qt4Qt5/qscilexerxml.cpp | 252 + src/qscintilla2/Qt4Qt5/qscimacro.cpp | 317 + src/qscintilla2/Qt4Qt5/qscintilla.pro | 240 + src/qscintilla2/Qt4Qt5/qscintilla_cs.qm | Bin 0 -> 44424 bytes src/qscintilla2/Qt4Qt5/qscintilla_cs.ts | 4051 +++ src/qscintilla2/Qt4Qt5/qscintilla_de.qm | Bin 0 -> 79869 bytes src/qscintilla2/Qt4Qt5/qscintilla_de.ts | 4051 +++ src/qscintilla2/Qt4Qt5/qscintilla_es.qm | Bin 0 -> 81850 bytes src/qscintilla2/Qt4Qt5/qscintilla_es.ts | 4051 +++ src/qscintilla2/Qt4Qt5/qscintilla_fr.qm | Bin 0 -> 53842 bytes src/qscintilla2/Qt4Qt5/qscintilla_fr.ts | 4051 +++ src/qscintilla2/Qt4Qt5/qscintilla_pt_br.qm | Bin 0 -> 49459 bytes src/qscintilla2/Qt4Qt5/qscintilla_pt_br.ts | 4051 +++ src/qscintilla2/Qt4Qt5/qsciprinter.cpp | 186 + src/qscintilla2/Qt4Qt5/qsciscintilla.cpp | 4570 +++ src/qscintilla2/Qt4Qt5/qsciscintillabase.cpp | 893 + src/qscintilla2/Qt4Qt5/qscistyle.cpp | 184 + src/qscintilla2/Qt4Qt5/qscistyledtext.cpp | 54 + src/qscintilla2/README | 2 + src/qscintilla2/include/ILexer.h | 90 + src/qscintilla2/include/ILoader.h | 21 + src/qscintilla2/include/License.txt | 20 + src/qscintilla2/include/Platform.h | 553 + src/qscintilla2/include/SciLexer.h | 1861 + src/qscintilla2/include/Sci_Position.h | 29 + src/qscintilla2/include/Scintilla.h | 1239 + src/qscintilla2/include/Scintilla.iface | 4990 +++ src/qscintilla2/include/ScintillaWidget.h | 72 + src/qscintilla2/lexers/LexHTML.cpp | 2469 ++ src/qscintilla2/lexers/LexJSON.cpp | 498 + src/qscintilla2/lexers/LexSQL.cpp | 967 + src/qscintilla2/lexers/License.txt | 20 + src/qscintilla2/lexlib/Accessor.cpp | 73 + src/qscintilla2/lexlib/Accessor.h | 31 + src/qscintilla2/lexlib/CharacterCategory.cpp | 3966 ++ src/qscintilla2/lexlib/CharacterCategory.h | 33 + src/qscintilla2/lexlib/CharacterSet.cpp | 52 + src/qscintilla2/lexlib/CharacterSet.h | 194 + src/qscintilla2/lexlib/DefaultLexer.cpp | 125 + src/qscintilla2/lexlib/DefaultLexer.h | 51 + src/qscintilla2/lexlib/LexAccessor.h | 208 + src/qscintilla2/lexlib/LexerBase.cpp | 144 + src/qscintilla2/lexlib/LexerBase.h | 53 + src/qscintilla2/lexlib/LexerModule.cpp | 126 + src/qscintilla2/lexlib/LexerModule.h | 87 + src/qscintilla2/lexlib/LexerNoExceptions.cpp | 62 + src/qscintilla2/lexlib/LexerNoExceptions.h | 28 + src/qscintilla2/lexlib/LexerSimple.cpp | 53 + src/qscintilla2/lexlib/LexerSimple.h | 26 + src/qscintilla2/lexlib/License.txt | 20 + src/qscintilla2/lexlib/OptionSet.h | 138 + src/qscintilla2/lexlib/PropSetSimple.cpp | 157 + src/qscintilla2/lexlib/PropSetSimple.h | 28 + src/qscintilla2/lexlib/SparseState.h | 106 + src/qscintilla2/lexlib/StringCopy.h | 32 + src/qscintilla2/lexlib/StyleContext.cpp | 69 + src/qscintilla2/lexlib/StyleContext.h | 212 + src/qscintilla2/lexlib/SubStyles.h | 196 + src/qscintilla2/lexlib/WordList.cpp | 295 + src/qscintilla2/lexlib/WordList.h | 38 + src/qscintilla2/qscintilla2.vcxproj | 372 + src/qscintilla2/qscintilla2.vcxproj.filters | 536 + src/qscintilla2/qscintilla2.vcxproj.user | 16 + src/qscintilla2/src/AutoComplete.cpp | 293 + src/qscintilla2/src/AutoComplete.h | 91 + src/qscintilla2/src/CallTip.cpp | 332 + src/qscintilla2/src/CallTip.h | 91 + src/qscintilla2/src/CaseConvert.cpp | 819 + src/qscintilla2/src/CaseConvert.h | 46 + src/qscintilla2/src/CaseFolder.cpp | 66 + src/qscintilla2/src/CaseFolder.h | 41 + src/qscintilla2/src/Catalogue.cpp | 83 + src/qscintilla2/src/Catalogue.h | 24 + src/qscintilla2/src/CellBuffer.cpp | 1204 + src/qscintilla2/src/CellBuffer.h | 215 + src/qscintilla2/src/CharClassify.cpp | 59 + src/qscintilla2/src/CharClassify.h | 31 + src/qscintilla2/src/ContractionState.cpp | 418 + src/qscintilla2/src/ContractionState.h | 52 + src/qscintilla2/src/DBCS.cpp | 42 + src/qscintilla2/src/DBCS.h | 17 + src/qscintilla2/src/Decoration.cpp | 316 + src/qscintilla2/src/Decoration.h | 59 + src/qscintilla2/src/Document.cpp | 3250 ++ src/qscintilla2/src/Document.h | 584 + src/qscintilla2/src/EditModel.cpp | 77 + src/qscintilla2/src/EditModel.h | 68 + src/qscintilla2/src/EditView.cpp | 2397 ++ src/qscintilla2/src/EditView.h | 186 + src/qscintilla2/src/Editor.cpp | 8234 +++++ src/qscintilla2/src/Editor.h | 650 + src/qscintilla2/src/ElapsedPeriod.h | 35 + src/qscintilla2/src/ExternalLexer.cpp | 135 + src/qscintilla2/src/ExternalLexer.h | 80 + src/qscintilla2/src/FontQuality.h | 27 + src/qscintilla2/src/Indicator.cpp | 223 + src/qscintilla2/src/Indicator.h | 56 + src/qscintilla2/src/IntegerRectangle.h | 29 + src/qscintilla2/src/KeyMap.cpp | 164 + src/qscintilla2/src/KeyMap.h | 64 + src/qscintilla2/src/License.txt | 20 + src/qscintilla2/src/LineMarker.cpp | 436 + src/qscintilla2/src/LineMarker.h | 48 + src/qscintilla2/src/MarginView.cpp | 470 + src/qscintilla2/src/MarginView.h | 46 + src/qscintilla2/src/Partitioning.h | 204 + src/qscintilla2/src/PerLine.cpp | 499 + src/qscintilla2/src/PerLine.h | 164 + src/qscintilla2/src/Position.h | 31 + src/qscintilla2/src/PositionCache.cpp | 719 + src/qscintilla2/src/PositionCache.h | 247 + src/qscintilla2/src/RESearch.cpp | 960 + src/qscintilla2/src/RESearch.h | 70 + src/qscintilla2/src/RunStyles.cpp | 314 + src/qscintilla2/src/RunStyles.h | 64 + src/qscintilla2/src/SciTE.properties | 6 + src/qscintilla2/src/ScintillaBase.cpp | 1165 + src/qscintilla2/src/ScintillaBase.h | 103 + src/qscintilla2/src/Selection.cpp | 436 + src/qscintilla2/src/Selection.h | 192 + src/qscintilla2/src/SparseVector.h | 156 + src/qscintilla2/src/SplitVector.h | 332 + src/qscintilla2/src/Style.cpp | 168 + src/qscintilla2/src/Style.h | 92 + src/qscintilla2/src/UniConversion.cpp | 368 + src/qscintilla2/src/UniConversion.h | 86 + src/qscintilla2/src/UnicodeFromUTF8.h | 32 + src/qscintilla2/src/UniqueString.h | 30 + src/qscintilla2/src/ViewStyle.cpp | 613 + src/qscintilla2/src/ViewStyle.h | 224 + src/qscintilla2/src/XPM.cpp | 448 + src/qscintilla2/src/XPM.h | 130 + 1355 files changed, 412881 insertions(+), 1653 deletions(-) create mode 100644 CMakeLists.txt.user create mode 100644 cmake/FindFFTW.cmake create mode 100644 src/LAMPTool/BaseToollib/BaseConstVariable.h create mode 100644 src/LAMPTool/BaseToollib/BaseTool.cpp create mode 100644 src/LAMPTool/BaseToollib/BaseTool.h create mode 100644 src/LAMPTool/BaseToollib/FileOperator.cpp create mode 100644 src/LAMPTool/BaseToollib/FileOperator.h create mode 100644 src/LAMPTool/BaseToollib/GeoOperator.cpp create mode 100644 src/LAMPTool/BaseToollib/GeoOperator.h create mode 100644 src/LAMPTool/BaseToollib/ImageOperatorBase.cpp create mode 100644 src/LAMPTool/BaseToollib/ImageOperatorBase.h create mode 100644 src/LAMPTool/BaseToollib/interpolation.cpp create mode 100644 src/LAMPTool/BaseToollib/interpolation.h create mode 100644 src/LAMPTool/BaseToollib/readme.md create mode 100644 src/LAMPTool/CMakeLists.txt create mode 100644 src/LAMPTool/FEKOFarFieldFileClass.cpp create mode 100644 src/LAMPTool/FEKOFarFieldFileClass.h create mode 100644 src/LAMPTool/FEKOSimulationSARClass.cpp create mode 100644 src/LAMPTool/FEKOSimulationSARClass.h create mode 100644 src/LAMPTool/LAMPTool.cpp create mode 100644 src/LAMPTool/LAMPTool.h create mode 100644 src/LAMPTool/LAMPTool.ui create mode 100644 src/LAMPTool/LampToolTest.h create mode 100644 src/LAMPTool/OCCTBase.cpp create mode 100644 src/LAMPTool/OCCTBase.h create mode 100644 src/LAMPTool/SARBaseToolLib/BackScatterModel.cpp create mode 100644 src/LAMPTool/SARBaseToolLib/BackScatterModel.h create mode 100644 src/LAMPTool/SARBaseToolLib/SARBaseTool.cpp create mode 100644 src/LAMPTool/SARBaseToolLib/SARBaseTool.h create mode 100644 src/LAMPTool/SARBaseToolLib/SARCalibration.cpp create mode 100644 src/LAMPTool/SARBaseToolLib/SARCalibration.h create mode 100644 src/LAMPTool/SARBaseToolLib/SARCalibrationTool.cpp create mode 100644 src/LAMPTool/SARBaseToolLib/SARImageBase.cpp create mode 100644 src/LAMPTool/SARBaseToolLib/SARImageBase.h create mode 100644 src/LAMPTool/SARImage/FEKOBaseToolClass.cpp create mode 100644 src/LAMPTool/SARImage/FEKOBaseToolClass.h create mode 100644 src/LAMPTool/SARImage/FEKONearBPBasic.cpp create mode 100644 src/LAMPTool/SARImage/FEKONearBPBasic.h create mode 100644 src/LAMPTool/SARImage/FEKONearBpBaseImage.cpp create mode 100644 src/LAMPTool/cpp.hint create mode 100644 src/LAMPTool/main.cpp create mode 100644 src/LAMPTool/readme.md create mode 100644 src/LAMPTool/referenceHeader.h create mode 100644 src/LAMPTool/test.png create mode 100644 src/WBCLFZSystemModule/.command_history.lst create mode 100644 src/WBCLFZSystemModule/AllHead.cpp create mode 100644 src/WBCLFZSystemModule/AllHead.h create mode 100644 src/WBCLFZSystemModule/CMakeLists.txt create mode 100644 src/WBCLFZSystemModule/DialogBatchExport.ui create mode 100644 src/WBCLFZSystemModule/EchoShowProcess/CMDExcuteApp.cpp create mode 100644 src/WBCLFZSystemModule/EchoShowProcess/CMDExcuteApp.h create mode 100644 src/WBCLFZSystemModule/EchoShowProcess/CMDExcuteApp.ui create mode 100644 src/WBCLFZSystemModule/EchoShowProcess/EchoTableEditWindow.cpp create mode 100644 src/WBCLFZSystemModule/EchoShowProcess/EchoTableEditWindow.h create mode 100644 src/WBCLFZSystemModule/EchoShowProcess/EchoTableEditWindow.ui create mode 100644 src/WBCLFZSystemModule/EchoShowProcess/FEKOResultImport.cpp create mode 100644 src/WBCLFZSystemModule/EchoShowProcess/FEKOResultImport.h create mode 100644 src/WBCLFZSystemModule/EchoShowProcess/FEKOResultImport.ui create mode 100644 src/WBCLFZSystemModule/HeaderSort.h create mode 100644 src/WBCLFZSystemModule/ImageShowDialogClass.cpp create mode 100644 src/WBCLFZSystemModule/ImageShowDialogClass.h create mode 100644 src/WBCLFZSystemModule/ImageShowDialogClass.ui create mode 100644 src/WBCLFZSystemModule/LAMPDataShowClass.cpp create mode 100644 src/WBCLFZSystemModule/LAMPDataShowClass.h create mode 100644 src/WBCLFZSystemModule/LAMPDataShowClass.ui create mode 100644 src/WBCLFZSystemModule/LAMPImageCreateClass.cpp create mode 100644 src/WBCLFZSystemModule/LAMPImageCreateClass.h create mode 100644 src/WBCLFZSystemModule/LAMPImageCreateClass.ui create mode 100644 src/WBCLFZSystemModule/LAMP_ScatterSettingClass.cpp create mode 100644 src/WBCLFZSystemModule/LAMP_ScatterSettingClass.h create mode 100644 src/WBCLFZSystemModule/LAMP_ScatterSettingClass.ui create mode 100644 src/WBCLFZSystemModule/OCCTBaseOperaorClass.cpp create mode 100644 src/WBCLFZSystemModule/OCCTBaseOperaorClass.h create mode 100644 src/WBCLFZSystemModule/OCCTModelOperator.cpp create mode 100644 src/WBCLFZSystemModule/OCCTModelOperator.h create mode 100644 src/WBCLFZSystemModule/OCCTModelOperator.ui create mode 100644 src/WBCLFZSystemModule/OCCTopoShapeTreeViewer.cpp create mode 100644 src/WBCLFZSystemModule/OCCTopoShapeTreeViewer.h create mode 100644 src/WBCLFZSystemModule/OCCViewer/CommonSample.h create mode 100644 src/WBCLFZSystemModule/OCCViewer/DocumentCommon.cpp create mode 100644 src/WBCLFZSystemModule/OCCViewer/DocumentCommon.h create mode 100644 src/WBCLFZSystemModule/OCCViewer/GeomWidget.cpp create mode 100644 src/WBCLFZSystemModule/OCCViewer/GeomWidget.h create mode 100644 src/WBCLFZSystemModule/OCCViewer/OCCT_Test/BaseSample.cpp create mode 100644 src/WBCLFZSystemModule/OCCViewer/OCCT_Test/BaseSample.h create mode 100644 src/WBCLFZSystemModule/OCCViewer/OCCT_Test/MakeBottle.cpp create mode 100644 src/WBCLFZSystemModule/OCCViewer/OCCT_Test/MakeBottle.h create mode 100644 src/WBCLFZSystemModule/OCCViewer/OCCT_Test/Viewer3d.xml create mode 100644 src/WBCLFZSystemModule/OCCViewer/OCCT_Test/Viewer3dSamples.cpp create mode 100644 src/WBCLFZSystemModule/OCCViewer/OCCT_Test/Viewer3dSamples.h create mode 100644 src/WBCLFZSystemModule/OCCViewer/OcctHighlighter.cpp create mode 100644 src/WBCLFZSystemModule/OCCViewer/OcctHighlighter.h create mode 100644 src/WBCLFZSystemModule/OCCViewer/TranslateDialog.cpp create mode 100644 src/WBCLFZSystemModule/OCCViewer/TranslateDialog.h create mode 100644 src/WBCLFZSystemModule/OCCViewer/Transparency.cpp create mode 100644 src/WBCLFZSystemModule/OCCViewer/Transparency.h create mode 100644 src/WBCLFZSystemModule/OCCViewer/View.cpp create mode 100644 src/WBCLFZSystemModule/OCCViewer/View.h create mode 100644 src/WBCLFZSystemModule/OCCViewer/res/antialiasing.png create mode 100644 src/WBCLFZSystemModule/OCCViewer/res/cursor_rotate.png create mode 100644 src/WBCLFZSystemModule/OCCViewer/res/cursor_zoom.png create mode 100644 src/WBCLFZSystemModule/OCCViewer/res/help.png create mode 100644 src/WBCLFZSystemModule/OCCViewer/res/lamp.png create mode 100644 src/WBCLFZSystemModule/OCCViewer/res/raytracing.png create mode 100644 src/WBCLFZSystemModule/OCCViewer/res/reflections.png create mode 100644 src/WBCLFZSystemModule/OCCViewer/res/shadows.png create mode 100644 src/WBCLFZSystemModule/OCCViewer/res/tool_color.png create mode 100644 src/WBCLFZSystemModule/OCCViewer/res/tool_delete.png create mode 100644 src/WBCLFZSystemModule/OCCViewer/res/tool_material.png create mode 100644 src/WBCLFZSystemModule/OCCViewer/res/tool_shading.png create mode 100644 src/WBCLFZSystemModule/OCCViewer/res/tool_transparency.png create mode 100644 src/WBCLFZSystemModule/OCCViewer/res/tool_wireframe.png create mode 100644 src/WBCLFZSystemModule/OCCViewer/res/view_axo.png create mode 100644 src/WBCLFZSystemModule/OCCViewer/res/view_back.png create mode 100644 src/WBCLFZSystemModule/OCCViewer/res/view_bottom.png create mode 100644 src/WBCLFZSystemModule/OCCViewer/res/view_comp_off.png create mode 100644 src/WBCLFZSystemModule/OCCViewer/res/view_comp_on.png create mode 100644 src/WBCLFZSystemModule/OCCViewer/res/view_fitall.png create mode 100644 src/WBCLFZSystemModule/OCCViewer/res/view_front.png create mode 100644 src/WBCLFZSystemModule/OCCViewer/res/view_left.png create mode 100644 src/WBCLFZSystemModule/OCCViewer/res/view_reset.png create mode 100644 src/WBCLFZSystemModule/OCCViewer/res/view_right.png create mode 100644 src/WBCLFZSystemModule/OCCViewer/res/view_top.png create mode 100644 src/WBCLFZSystemModule/OcctExportClass.cpp create mode 100644 src/WBCLFZSystemModule/OcctExportClass.h create mode 100644 src/WBCLFZSystemModule/OcctExportClass.ui create mode 100644 src/WBCLFZSystemModule/PointCloudProcess/BasePCL.cpp create mode 100644 src/WBCLFZSystemModule/PointCloudProcess/BasePCL.h create mode 100644 src/WBCLFZSystemModule/PointCloudProcess/BilateralFilterWindows.ui create mode 100644 src/WBCLFZSystemModule/PointCloudProcess/DialogTriangulationSurfaceMesh.ui create mode 100644 src/WBCLFZSystemModule/PointCloudProcess/MedianFilterWindows.ui create mode 100644 src/WBCLFZSystemModule/PointCloudProcess/PointCloudAlg.cpp create mode 100644 src/WBCLFZSystemModule/PointCloudProcess/PointCloudAlg.h create mode 100644 src/WBCLFZSystemModule/PointCloudProcess/PointManagerClass.cpp create mode 100644 src/WBCLFZSystemModule/PointCloudProcess/PointManagerClass.h create mode 100644 src/WBCLFZSystemModule/PointCloudProcess/PoissonReSurfaceWindows.ui create mode 100644 src/WBCLFZSystemModule/PointCloudProcess/RadiusOutlierRemovalWindows.ui create mode 100644 src/WBCLFZSystemModule/PointCloudProcess/Scance_FEKOSourceSettingPlaneWaveWIndows.ui create mode 100644 src/WBCLFZSystemModule/PointCloudProcess/Scene_StripQtWidgetsClass.cpp create mode 100644 src/WBCLFZSystemModule/PointCloudProcess/Scene_StripQtWidgetsClass.h create mode 100644 src/WBCLFZSystemModule/PointCloudProcess/Scene_StripQtWidgetsClass.ui create mode 100644 src/WBCLFZSystemModule/PointCloudProcess/StatisticalOutlierRemovalWindows.ui create mode 100644 src/WBCLFZSystemModule/PointCloudProcess/Strips_FEKOSourceSettingPlaneWaveWIndows.ui create mode 100644 src/WBCLFZSystemModule/PointCloudProcess/ToolDialog.cpp create mode 100644 src/WBCLFZSystemModule/PointCloudProcess/ToolDialog.h create mode 100644 src/WBCLFZSystemModule/PointCloudProcess/images/1.gif create mode 100644 src/WBCLFZSystemModule/PointCloudProcess/images/RGB.png create mode 100644 src/WBCLFZSystemModule/PointCloudProcess/images/algorithm/DASHBOARD.png create mode 100644 src/WBCLFZSystemModule/PointCloudProcess/images/algorithm/DBSCAN.png create mode 100644 src/WBCLFZSystemModule/PointCloudProcess/images/algorithm/Histogram.png create mode 100644 src/WBCLFZSystemModule/PointCloudProcess/images/algorithm/KMeans.png create mode 100644 src/WBCLFZSystemModule/PointCloudProcess/images/algorithm/binary.png create mode 100644 src/WBCLFZSystemModule/PointCloudProcess/images/algorithm/chooseMatrix.png create mode 100644 src/WBCLFZSystemModule/PointCloudProcess/images/algorithm/density.png create mode 100644 src/WBCLFZSystemModule/PointCloudProcess/images/algorithm/extract.png create mode 100644 src/WBCLFZSystemModule/PointCloudProcess/images/algorithm/filter.png create mode 100644 src/WBCLFZSystemModule/PointCloudProcess/images/algorithm/help.png create mode 100644 src/WBCLFZSystemModule/PointCloudProcess/images/algorithm/matrix.png create mode 100644 src/WBCLFZSystemModule/PointCloudProcess/images/algorithm/more.png create mode 100644 src/WBCLFZSystemModule/PointCloudProcess/images/algorithm/nihe.png create mode 100644 src/WBCLFZSystemModule/PointCloudProcess/images/algorithm/person.png create mode 100644 src/WBCLFZSystemModule/PointCloudProcess/images/algorithm/pingjie.png create mode 100644 src/WBCLFZSystemModule/PointCloudProcess/images/algorithm/transform.png create mode 100644 src/WBCLFZSystemModule/PointCloudProcess/images/algorithm/tree.png create mode 100644 src/WBCLFZSystemModule/PointCloudProcess/images/back.png create mode 100644 src/WBCLFZSystemModule/PointCloudProcess/images/bottom.png create mode 100644 src/WBCLFZSystemModule/PointCloudProcess/images/camera.png create mode 100644 src/WBCLFZSystemModule/PointCloudProcess/images/color.png create mode 100644 src/WBCLFZSystemModule/PointCloudProcess/images/coodinate.png create mode 100644 src/WBCLFZSystemModule/PointCloudProcess/images/files/CSV.png create mode 100644 src/WBCLFZSystemModule/PointCloudProcess/images/files/add.png create mode 100644 src/WBCLFZSystemModule/PointCloudProcess/images/files/bgColor.png create mode 100644 src/WBCLFZSystemModule/PointCloudProcess/images/files/cloud.png create mode 100644 src/WBCLFZSystemModule/PointCloudProcess/images/files/cloud2.png create mode 100644 src/WBCLFZSystemModule/PointCloudProcess/images/files/copy.png create mode 100644 src/WBCLFZSystemModule/PointCloudProcess/images/files/cut.png create mode 100644 src/WBCLFZSystemModule/PointCloudProcess/images/files/log.png create mode 100644 src/WBCLFZSystemModule/PointCloudProcess/images/files/new1.png create mode 100644 src/WBCLFZSystemModule/PointCloudProcess/images/files/new2.png create mode 100644 src/WBCLFZSystemModule/PointCloudProcess/images/files/paste.png create mode 100644 src/WBCLFZSystemModule/PointCloudProcess/images/files/pointCloud.png create mode 100644 src/WBCLFZSystemModule/PointCloudProcess/images/files/search.png create mode 100644 src/WBCLFZSystemModule/PointCloudProcess/images/files/snapshot.png create mode 100644 src/WBCLFZSystemModule/PointCloudProcess/images/files/star.png create mode 100644 src/WBCLFZSystemModule/PointCloudProcess/images/files/txt.png create mode 100644 src/WBCLFZSystemModule/PointCloudProcess/images/front.png create mode 100644 src/WBCLFZSystemModule/PointCloudProcess/images/grey.png create mode 100644 src/WBCLFZSystemModule/PointCloudProcess/images/ic-redo.png create mode 100644 src/WBCLFZSystemModule/PointCloudProcess/images/ic-undo.png create mode 100644 src/WBCLFZSystemModule/PointCloudProcess/images/keda.ico create mode 100644 src/WBCLFZSystemModule/PointCloudProcess/images/left.png create mode 100644 src/WBCLFZSystemModule/PointCloudProcess/images/lock.png create mode 100644 src/WBCLFZSystemModule/PointCloudProcess/images/open.png create mode 100644 src/WBCLFZSystemModule/PointCloudProcess/images/redo.png create mode 100644 src/WBCLFZSystemModule/PointCloudProcess/images/reset.png create mode 100644 src/WBCLFZSystemModule/PointCloudProcess/images/right.png create mode 100644 src/WBCLFZSystemModule/PointCloudProcess/images/rotate0.png create mode 100644 src/WBCLFZSystemModule/PointCloudProcess/images/rotate180.png create mode 100644 src/WBCLFZSystemModule/PointCloudProcess/images/rotate270.png create mode 100644 src/WBCLFZSystemModule/PointCloudProcess/images/rotate90.png create mode 100644 src/WBCLFZSystemModule/PointCloudProcess/images/seting.png create mode 100644 src/WBCLFZSystemModule/PointCloudProcess/images/undo.png create mode 100644 src/WBCLFZSystemModule/PointCloudProcess/images/up.png create mode 100644 src/WBCLFZSystemModule/PointCloudProcess/images/zoomin.png create mode 100644 src/WBCLFZSystemModule/PointCloudProcess/images/zoomout.png create mode 100644 src/WBCLFZSystemModule/PointCloudProcess/inputdialog.cpp create mode 100644 src/WBCLFZSystemModule/PointCloudProcess/inputdialog.h create mode 100644 src/WBCLFZSystemModule/PointCloudProcess/inputdialog.ui create mode 100644 src/WBCLFZSystemModule/PointCloudProcess/pclvisualizer.cpp create mode 100644 src/WBCLFZSystemModule/PointCloudProcess/pclvisualizer.h create mode 100644 src/WBCLFZSystemModule/PointCloudProcess/pclvisualizer.ui create mode 100644 src/WBCLFZSystemModule/ProgramParamLoadingClass.cpp create mode 100644 src/WBCLFZSystemModule/ProgramParamLoadingClass.h create mode 100644 src/WBCLFZSystemModule/QConsoleCommandAction.cpp create mode 100644 src/WBCLFZSystemModule/QConsoleCommandAction.h create mode 100644 src/WBCLFZSystemModule/QConsoleIODevice.cpp create mode 100644 src/WBCLFZSystemModule/QConsoleIODevice.h create mode 100644 src/WBCLFZSystemModule/QConsoleWidget.cpp create mode 100644 src/WBCLFZSystemModule/QConsoleWidget.h create mode 100644 src/WBCLFZSystemModule/QtEchoExportWindows.ui create mode 100644 src/WBCLFZSystemModule/QtFreqParamsSetting.cpp create mode 100644 src/WBCLFZSystemModule/QtFreqParamsSetting.h create mode 100644 src/WBCLFZSystemModule/QtFreqParamsSetting.ui create mode 100644 src/WBCLFZSystemModule/QtSARAntModelSetting.cpp create mode 100644 src/WBCLFZSystemModule/QtSARAntModelSetting.h create mode 100644 src/WBCLFZSystemModule/QtSARAntModelSetting.ui create mode 100644 src/WBCLFZSystemModule/QtStripImageSettingClass.cpp create mode 100644 src/WBCLFZSystemModule/QtStripImageSettingClass.h create mode 100644 src/WBCLFZSystemModule/QtStripImageSettingClass.ui create mode 100644 src/WBCLFZSystemModule/QtWidgetsClass_CircleSAR.cpp create mode 100644 src/WBCLFZSystemModule/QtWidgetsClass_CircleSAR.h create mode 100644 src/WBCLFZSystemModule/QtWidgetsClass_CircleSAR.ui create mode 100644 src/WBCLFZSystemModule/QtWidgetsClass_FarSourceSetting.cpp create mode 100644 src/WBCLFZSystemModule/QtWidgetsClass_FarSourceSetting.h create mode 100644 src/WBCLFZSystemModule/QtWidgetsClass_FarSourceSetting.ui create mode 100644 src/WBCLFZSystemModule/QtWidgetsClass_ISAR.cpp create mode 100644 src/WBCLFZSystemModule/QtWidgetsClass_ISAR.h create mode 100644 src/WBCLFZSystemModule/QtWidgetsClass_ISAR.ui create mode 100644 src/WBCLFZSystemModule/QtWidgetsClass_ImageSetting.cpp create mode 100644 src/WBCLFZSystemModule/QtWidgetsClass_ImageSetting.h create mode 100644 src/WBCLFZSystemModule/QtWidgetsClass_ImageSetting.ui create mode 100644 src/WBCLFZSystemModule/QtWidgetsClass_Scan.cpp create mode 100644 src/WBCLFZSystemModule/QtWidgetsClass_Scan.h create mode 100644 src/WBCLFZSystemModule/QtWidgetsClass_Scan.ui create mode 100644 src/WBCLFZSystemModule/QtWidgetsClass_Strip.cpp create mode 100644 src/WBCLFZSystemModule/QtWidgetsClass_Strip.h create mode 100644 src/WBCLFZSystemModule/QtWidgetsClass_Strip.ui create mode 100644 src/WBCLFZSystemModule/SharedModuleLib/BaseUiTool.cpp create mode 100644 src/WBCLFZSystemModule/SharedModuleLib/BaseUiTool.h create mode 100644 src/WBCLFZSystemModule/SharedModuleLib/CMDExcuteApp.cpp create mode 100644 src/WBCLFZSystemModule/SharedModuleLib/CMDExcuteApp.h create mode 100644 src/WBCLFZSystemModule/SharedModuleLib/CMDExcuteApp.ui create mode 100644 src/WBCLFZSystemModule/SharedModuleLib/ProcessOn.cpp create mode 100644 src/WBCLFZSystemModule/SharedModuleLib/ProcessOn.h create mode 100644 src/WBCLFZSystemModule/SharedModuleLib/ProcessOn.ui create mode 100644 src/WBCLFZSystemModule/SharedModuleLib/TaskTreeClass.cpp create mode 100644 src/WBCLFZSystemModule/SharedModuleLib/TaskTreeClass.h create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/images/logo.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/images/logo.svg create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/images/sqlitebrowser.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/AboutDialog.cpp create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/AboutDialog.h create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/AboutDialog.ui create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/AddRecordDialog.cpp create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/AddRecordDialog.h create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/AddRecordDialog.ui create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/Application.cpp create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/Application.h create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/CipherDialog.cpp create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/CipherDialog.h create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/CipherDialog.ui create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/CipherSettings.cpp create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/CipherSettings.h create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/ColumnDisplayFormatDialog.cpp create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/ColumnDisplayFormatDialog.h create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/ColumnDisplayFormatDialog.ui create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/CondFormat.cpp create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/CondFormat.h create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/CondFormatManager.cpp create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/CondFormatManager.h create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/CondFormatManager.ui create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/DBsqliconwin.ico create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/DBsqliconwin.jpg create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/Data.cpp create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/Data.h create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/DbStructureModel.cpp create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/DbStructureModel.h create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/DotenvFormat.cpp create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/DotenvFormat.h create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/EditDialog.cpp create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/EditDialog.h create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/EditDialog.ui create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/EditIndexDialog.cpp create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/EditIndexDialog.h create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/EditIndexDialog.ui create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/EditTableDialog.cpp create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/EditTableDialog.h create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/EditTableDialog.ui create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/ExportDataDialog.cpp create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/ExportDataDialog.h create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/ExportDataDialog.ui create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/ExportSqlDialog.cpp create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/ExportSqlDialog.h create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/ExportSqlDialog.ui create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/ExtendedScintilla.cpp create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/ExtendedScintilla.h create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/ExtendedTableWidget.cpp create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/ExtendedTableWidget.h create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/FileDialog.cpp create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/FileDialog.h create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/FileExtensionManager.cpp create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/FileExtensionManager.h create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/FileExtensionManager.ui create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/FilterLineEdit.cpp create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/FilterLineEdit.h create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/FilterTableHeader.cpp create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/FilterTableHeader.h create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/FindReplaceDialog.cpp create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/FindReplaceDialog.h create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/FindReplaceDialog.ui create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/ForeignKeyEditorDelegate.cpp create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/ForeignKeyEditorDelegate.h create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/IconCache.cpp create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/IconCache.h create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/ImportCsvDialog.cpp create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/ImportCsvDialog.h create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/ImportCsvDialog.ui create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/MainWindow.cpp create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/MainWindow.h create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/Palette.cpp create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/Palette.h create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/PlotDock.cpp create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/PlotDock.h create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/PlotDock.ui create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/PreferencesDialog.cpp create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/PreferencesDialog.h create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/PreferencesDialog.ui create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/ProxyDialog.cpp create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/ProxyDialog.h create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/ProxyDialog.ui create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/RemoteCommitsModel.cpp create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/RemoteCommitsModel.h create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/RemoteDatabase.cpp create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/RemoteDatabase.h create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/RemoteDock.cpp create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/RemoteDock.h create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/RemoteDock.ui create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/RemoteLocalFilesModel.cpp create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/RemoteLocalFilesModel.h create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/RemoteModel.cpp create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/RemoteModel.h create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/RemoteNetwork.cpp create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/RemoteNetwork.h create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/RemotePushDialog.cpp create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/RemotePushDialog.h create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/RemotePushDialog.ui create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/RowCache.h create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/RowLoader.cpp create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/RowLoader.h create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/RunSql.cpp create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/RunSql.h create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/SelectItemsPopup.cpp create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/SelectItemsPopup.h create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/SelectItemsPopup.ui create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/Settings.cpp create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/Settings.h create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/SqlExecutionArea.cpp create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/SqlExecutionArea.h create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/SqlExecutionArea.ui create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/SqlUiLexer.cpp create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/SqlUiLexer.h create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/SqliteDBMainWindow.cpp create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/SqliteDBMainWindow.h create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/SqliteDBMainWindow.ui create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/SqliteDBProcessmain.cpp create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/TableBrowser.cpp create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/TableBrowser.h create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/TableBrowser.ui create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/VacuumDialog.cpp create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/VacuumDialog.h create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/VacuumDialog.ui create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/app.plist create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/csvparser.cpp create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/csvparser.h create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/docktextedit.cpp create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/docktextedit.h create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/extensions/extension-formats.c create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/extensions/extension-formats.def create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/extensions/extension-functions.c create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/extensions/extension-functions.def create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/i18n.pri create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/icons/application_go.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/icons/application_link.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/icons/application_side_list.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/icons/bullet_arrow_bottom.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/icons/bullet_arrow_down.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/icons/bullet_arrow_top.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/icons/bullet_arrow_up.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/icons/cancel.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/icons/chart_curve.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/icons/clear_filters.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/icons/clear_sorting.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/icons/cog.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/icons/cog_go.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/icons/color_swatch.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/icons/comment_block.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/icons/cross.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/icons/database.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/icons/database_add.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/icons/database_go.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/icons/database_link.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/icons/database_refresh.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/icons/database_save.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/icons/document-link.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/icons/document-open.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/icons/edit_cond_formats.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/icons/filter.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/icons/folder.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/icons/folder_user.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/icons/help.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/icons/hourglass.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/icons/icons.qrc create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/icons/internet-web-browser.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/icons/key.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/icons/layout_sidebar.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/icons/package.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/icons/package_go.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/icons/package_rename.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/icons/package_save.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/icons/page_add.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/icons/page_copy.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/icons/page_copy_sql.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/icons/page_delete.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/icons/page_edit.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/icons/page_find.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/icons/page_foreign_key.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/icons/page_green.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/icons/page_key.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/icons/page_paintbrush.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/icons/page_paste.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/icons/page_save.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/icons/page_white_copy.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/icons/page_white_database.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/icons/page_white_text.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/icons/picture.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/icons/picture_add.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/icons/picture_delete.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/icons/picture_edit.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/icons/picture_save.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/icons/plugin_add.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/icons/plugin_delete.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/icons/printer.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/icons/resultset_first.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/icons/resultset_last.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/icons/resultset_next.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/icons/resultset_previous.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/icons/save_all.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/icons/script.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/icons/script_add.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/icons/script_delete.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/icons/script_edit.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/icons/server_add.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/icons/server_go.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/icons/sqlitebrowser.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/icons/style.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/icons/style_add.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/icons/style_delete.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/icons/style_edit.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/icons/tab.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/icons/tab_add.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/icons/table.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/icons/table_add.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/icons/table_delete.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/icons/table_edit.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/icons/table_row_delete.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/icons/table_row_insert.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/icons/table_save.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/icons/tag_blue.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/icons/tag_blue_add.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/icons/tag_blue_delete.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/icons/tag_blue_edit.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/icons/text_align_center.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/icons/text_align_justify.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/icons/text_align_left.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/icons/text_align_right.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/icons/text_bold.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/icons/text_indent.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/icons/text_italic.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/icons/text_paintbrush.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/icons/text_replace.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/icons/text_underline.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/icons/textfield_delete.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/icons/view-refresh.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/icons/wrench.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/macapp.icns create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/main.cpp create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/os2app.rc create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/LICENSE.md create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/Hmovetoolbar.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/Hsepartoolbar.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/Vmovetoolbar.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/Vsepartoolbar.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/arrow_down.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/arrow_down@2x.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/arrow_down_disabled.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/arrow_down_disabled@2x.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/arrow_down_focus.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/arrow_down_focus@2x.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/arrow_down_pressed.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/arrow_down_pressed@2x.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/arrow_left.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/arrow_left@2x.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/arrow_left_disabled.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/arrow_left_disabled@2x.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/arrow_left_focus.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/arrow_left_focus@2x.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/arrow_left_pressed.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/arrow_left_pressed@2x.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/arrow_right.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/arrow_right@2x.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/arrow_right_disabled.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/arrow_right_disabled@2x.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/arrow_right_focus.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/arrow_right_focus@2x.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/arrow_right_pressed.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/arrow_right_pressed@2x.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/arrow_up.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/arrow_up@2x.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/arrow_up_disabled.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/arrow_up_disabled@2x.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/arrow_up_focus.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/arrow_up_focus@2x.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/arrow_up_pressed.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/arrow_up_pressed@2x.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/base_icon.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/base_icon@2x.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/base_icon_disabled.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/base_icon_disabled@2x.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/base_icon_focus.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/base_icon_focus@2x.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/base_icon_pressed.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/base_icon_pressed@2x.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/branch_closed-on.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/branch_closed.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/branch_closed@2x.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/branch_closed_disabled.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/branch_closed_disabled@2x.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/branch_closed_focus.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/branch_closed_focus@2x.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/branch_closed_pressed.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/branch_closed_pressed@2x.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/branch_end.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/branch_end@2x.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/branch_end_disabled.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/branch_end_disabled@2x.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/branch_end_focus.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/branch_end_focus@2x.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/branch_end_pressed.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/branch_end_pressed@2x.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/branch_line.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/branch_line@2x.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/branch_line_disabled.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/branch_line_disabled@2x.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/branch_line_focus.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/branch_line_focus@2x.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/branch_line_pressed.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/branch_line_pressed@2x.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/branch_more.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/branch_more@2x.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/branch_more_disabled.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/branch_more_disabled@2x.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/branch_more_focus.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/branch_more_focus@2x.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/branch_more_pressed.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/branch_more_pressed@2x.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/branch_open-on.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/branch_open.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/branch_open@2x.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/branch_open_disabled.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/branch_open_disabled@2x.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/branch_open_focus.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/branch_open_focus@2x.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/branch_open_pressed.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/branch_open_pressed@2x.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/checkbox_checked.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/checkbox_checked@2x.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/checkbox_checked_disabled.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/checkbox_checked_disabled@2x.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/checkbox_checked_focus.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/checkbox_checked_focus@2x.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/checkbox_checked_pressed.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/checkbox_checked_pressed@2x.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/checkbox_indeterminate.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/checkbox_indeterminate@2x.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/checkbox_indeterminate_disabled.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/checkbox_indeterminate_disabled@2x.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/checkbox_indeterminate_focus.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/checkbox_indeterminate_focus@2x.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/checkbox_indeterminate_pressed.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/checkbox_indeterminate_pressed@2x.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/checkbox_unchecked.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/checkbox_unchecked@2x.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/checkbox_unchecked_disabled.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/checkbox_unchecked_disabled@2x.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/checkbox_unchecked_focus.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/checkbox_unchecked_focus@2x.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/checkbox_unchecked_pressed.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/checkbox_unchecked_pressed@2x.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/close-hover.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/close-pressed.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/close.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/down_arrow.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/down_arrow_disabled.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/left_arrow.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/left_arrow_disabled.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/line_horizontal.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/line_horizontal@2x.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/line_horizontal_disabled.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/line_horizontal_disabled@2x.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/line_horizontal_focus.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/line_horizontal_focus@2x.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/line_horizontal_pressed.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/line_horizontal_pressed@2x.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/line_vertical.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/line_vertical@2x.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/line_vertical_disabled.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/line_vertical_disabled@2x.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/line_vertical_focus.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/line_vertical_focus@2x.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/line_vertical_pressed.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/line_vertical_pressed@2x.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/radio_checked.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/radio_checked@2x.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/radio_checked_disabled.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/radio_checked_disabled@2x.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/radio_checked_focus.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/radio_checked_focus@2x.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/radio_checked_pressed.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/radio_checked_pressed@2x.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/radio_unchecked.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/radio_unchecked@2x.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/radio_unchecked_disabled.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/radio_unchecked_disabled@2x.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/radio_unchecked_focus.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/radio_unchecked_focus@2x.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/radio_unchecked_pressed.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/radio_unchecked_pressed@2x.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/right_arrow.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/right_arrow_disabled.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/sizegrip.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/stylesheet-branch-end.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/stylesheet-branch-more.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/stylesheet-vline.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/toolbar_move_horizontal.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/toolbar_move_horizontal@2x.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/toolbar_move_horizontal_disabled.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/toolbar_move_horizontal_disabled@2x.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/toolbar_move_horizontal_focus.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/toolbar_move_horizontal_focus@2x.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/toolbar_move_horizontal_pressed.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/toolbar_move_horizontal_pressed@2x.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/toolbar_move_vertical.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/toolbar_move_vertical@2x.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/toolbar_move_vertical_disabled.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/toolbar_move_vertical_disabled@2x.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/toolbar_move_vertical_focus.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/toolbar_move_vertical_focus@2x.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/toolbar_move_vertical_pressed.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/toolbar_move_vertical_pressed@2x.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/toolbar_separator_horizontal.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/toolbar_separator_horizontal@2x.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/toolbar_separator_horizontal_disabled.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/toolbar_separator_horizontal_disabled@2x.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/toolbar_separator_horizontal_focus.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/toolbar_separator_horizontal_focus@2x.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/toolbar_separator_horizontal_pressed.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/toolbar_separator_horizontal_pressed@2x.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/toolbar_separator_vertical.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/toolbar_separator_vertical@2x.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/toolbar_separator_vertical_disabled.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/toolbar_separator_vertical_disabled@2x.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/toolbar_separator_vertical_focus.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/toolbar_separator_vertical_focus@2x.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/toolbar_separator_vertical_pressed.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/toolbar_separator_vertical_pressed@2x.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/transparent.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/transparent@2x.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/transparent_disabled.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/transparent_disabled@2x.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/transparent_focus.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/transparent_focus@2x.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/transparent_pressed.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/transparent_pressed@2x.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/undock.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/up_arrow.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/up_arrow_disabled.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/window_close.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/window_close@2x.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/window_close_disabled.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/window_close_disabled@2x.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/window_close_focus.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/window_close_focus@2x.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/window_close_pressed.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/window_close_pressed@2x.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/window_grip.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/window_grip@2x.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/window_grip_disabled.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/window_grip_disabled@2x.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/window_grip_focus.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/window_grip_focus@2x.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/window_grip_pressed.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/window_grip_pressed@2x.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/window_minimize.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/window_minimize@2x.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/window_minimize_disabled.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/window_minimize_disabled@2x.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/window_minimize_focus.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/window_minimize_focus@2x.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/window_minimize_pressed.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/window_minimize_pressed@2x.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/window_undock.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/window_undock@2x.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/window_undock_disabled.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/window_undock_disabled@2x.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/window_undock_focus.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/window_undock_focus@2x.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/window_undock_pressed.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/window_undock_pressed@2x.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/style.qrc create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/style.qrc.depends create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/style.qss create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/sql/ObjectIdentifier.cpp create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/sql/ObjectIdentifier.h create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/sql/Query.cpp create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/sql/Query.h create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/sql/parser/ParserDriver.cpp create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/sql/parser/ParserDriver.h create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/sql/parser/README create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/sql/parser/sqlite3_lexer.cpp create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/sql/parser/sqlite3_lexer.h create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/sql/parser/sqlite3_lexer.ll create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/sql/parser/sqlite3_location.h create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/sql/parser/sqlite3_parser.cpp create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/sql/parser/sqlite3_parser.hpp create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/sql/parser/sqlite3_parser.yy create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/sql/sqlitetypes.cpp create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/sql/sqlitetypes.h create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/sqlite.h create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/sqlitedb.cpp create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/sqlitedb.h create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/sqlitetablemodel.cpp create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/sqlitetablemodel.h create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/sqltextedit.cpp create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/sqltextedit.h create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/src.pro create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/tests/CMakeLists.txt create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/tests/TestImport.cpp create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/tests/TestImport.h create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/tests/TestRegex.cpp create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/tests/TestRegex.h create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/tests/TestRowCache.cpp create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/tests/TestRowCache.h create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/tests/testsqlobjects.cpp create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/tests/testsqlobjects.h create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/tools/create_windows_icon.sh create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/translations/README create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/translations/flags/ar.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/translations/flags/br.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/translations/flags/cn.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/translations/flags/cs.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/translations/flags/de.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/translations/flags/eg.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/translations/flags/es.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/translations/flags/flags.qrc create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/translations/flags/fr.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/translations/flags/gb.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/translations/flags/it.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/translations/flags/jp.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/translations/flags/kr.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/translations/flags/nl.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/translations/flags/pl.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/translations/flags/roc.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/translations/flags/ru.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/translations/flags/tr.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/translations/flags/ua.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/translations/flags/us.png create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/translations/place_translations_here create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/translations/sqlb_ar_SA.qm create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/translations/sqlb_ar_SA.ts create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/translations/sqlb_cs.qm create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/translations/sqlb_cs.ts create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/translations/sqlb_de.qm create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/translations/sqlb_de.ts create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/translations/sqlb_en_GB.qm create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/translations/sqlb_en_GB.ts create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/translations/sqlb_es_ES.qm create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/translations/sqlb_es_ES.ts create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/translations/sqlb_fa.ts create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/translations/sqlb_fr.qm create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/translations/sqlb_fr.ts create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/translations/sqlb_it.qm create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/translations/sqlb_it.ts create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/translations/sqlb_ja.qm create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/translations/sqlb_ja.ts create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/translations/sqlb_ko_KR.qm create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/translations/sqlb_ko_KR.ts create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/translations/sqlb_nl.qm create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/translations/sqlb_nl.ts create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/translations/sqlb_pl.qm create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/translations/sqlb_pl.ts create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/translations/sqlb_pt_BR.qm create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/translations/sqlb_pt_BR.ts create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/translations/sqlb_ru.qm create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/translations/sqlb_ru.ts create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/translations/sqlb_tr.qm create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/translations/sqlb_tr.ts create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/translations/sqlb_uk_UA.qm create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/translations/sqlb_uk_UA.ts create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/translations/sqlb_zh.qm create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/translations/sqlb_zh.ts create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/translations/sqlb_zh_TW.qm create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/translations/sqlb_zh_TW.ts create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/translations/translations.qrc create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/version.h create mode 100644 src/WBCLFZSystemModule/SqliteDBProcess/src/winapp.rc create mode 100644 src/WBCLFZSystemModule/TableProcess/TableFieldConfigClass.cpp create mode 100644 src/WBCLFZSystemModule/TableProcess/TableFieldConfigClass.h create mode 100644 src/WBCLFZSystemModule/TableProcess/TableFieldConfigClass.ui create mode 100644 src/WBCLFZSystemModule/TableProcess/TableFieldFindTool.cpp create mode 100644 src/WBCLFZSystemModule/TableProcess/TableFieldFindTool.h create mode 100644 src/WBCLFZSystemModule/TableProcess/TableFieldFindTool.ui create mode 100644 src/WBCLFZSystemModule/TableProcess/TableMainWindow.cpp create mode 100644 src/WBCLFZSystemModule/TableProcess/TableMainWindow.h create mode 100644 src/WBCLFZSystemModule/TableProcess/TableMainWindow.ui create mode 100644 src/WBCLFZSystemModule/TableProcess/TableViewModel.cpp create mode 100644 src/WBCLFZSystemModule/TableProcess/TableViewModel.h create mode 100644 src/WBCLFZSystemModule/TableProcess/sqliteOperator.cpp create mode 100644 src/WBCLFZSystemModule/TableProcess/sqliteOperator.h create mode 100644 src/WBCLFZSystemModule/TaskNodeList.cpp create mode 100644 src/WBCLFZSystemModule/TaskNodeList.h create mode 100644 src/WBCLFZSystemModule/TaskXml/TaskTreeClass.cpp create mode 100644 src/WBCLFZSystemModule/TaskXml/TaskTreeClass.h create mode 100644 src/WBCLFZSystemModule/WBCLFZSystemModule.aps create mode 100644 src/WBCLFZSystemModule/WBCLFZSystemModule.cpp create mode 100644 src/WBCLFZSystemModule/WBCLFZSystemModule.h create mode 100644 src/WBCLFZSystemModule/WBCLFZSystemModule.rc create mode 100644 src/WBCLFZSystemModule/WBCLFZSystemModule.ui create mode 100644 src/WBCLFZSystemModule/WBCLFZSystemModule.vcxproj create mode 100644 src/WBCLFZSystemModule/WBCLFZSystemModule.vcxproj.filters create mode 100644 src/WBCLFZSystemModule/WBCLFZSystemModule.vcxproj.user create mode 100644 src/WBCLFZSystemModule/cpp.hint create mode 100644 src/WBCLFZSystemModule/main.cpp create mode 100644 src/WBCLFZSystemModule/modelProcess/ModelProcess.cpp create mode 100644 src/WBCLFZSystemModule/modelProcess/ModelProcess.h create mode 100644 src/WBCLFZSystemModule/modelProcess/ModelProcess.ui create mode 100644 src/WBCLFZSystemModule/qconsolewidget.pri create mode 100644 src/WBCLFZSystemModule/qscriptcompleter.cpp create mode 100644 src/WBCLFZSystemModule/qscriptcompleter.h create mode 100644 src/WBCLFZSystemModule/readme.md create mode 100644 src/WBCLFZSystemModule/resource.h create mode 100644 src/WBCLFZSystemModule/scriptsession.cpp create mode 100644 src/WBCLFZSystemModule/scriptsession.h create mode 100644 src/json/CMakeLists.txt create mode 100644 src/json/json.hpp create mode 100644 src/json/json.vcxproj create mode 100644 src/json/json.vcxproj.filters create mode 100644 src/json/json.vcxproj.user create mode 100644 src/json/jsonplugin.json create mode 100644 src/qcustomplot/CMakeLists.txt create mode 100644 src/qcustomplot/GPL.txt create mode 100644 src/qcustomplot/main.cpp create mode 100644 src/qcustomplot/qcustomplot.cpp create mode 100644 src/qcustomplot/qcustomplot.h create mode 100644 src/qcustomplot/qcustomplot.pro create mode 100644 src/qcustomplot/qcustomplot.qrc create mode 100644 src/qcustomplot/qcustomplot.ui create mode 100644 src/qhexedit/CMakeLists.txt create mode 100644 src/qhexedit/chunks.cpp create mode 100644 src/qhexedit/chunks.h create mode 100644 src/qhexedit/commands.cpp create mode 100644 src/qhexedit/commands.h create mode 100644 src/qhexedit/license.txt create mode 100644 src/qhexedit/qhexedit.cpp create mode 100644 src/qhexedit/qhexedit.h create mode 100644 src/qhexedit/qhexedit.pro create mode 100644 src/qhexedit/qhexedit.vcxproj create mode 100644 src/qhexedit/qhexedit.vcxproj.filters create mode 100644 src/qhexedit/qhexedit.vcxproj.user create mode 100644 src/qhexedit/qhexeditplugin.json create mode 100644 src/qrc/LAMPTool.qrc create mode 100644 src/qrc/OCCViewer/res/antialiasing.png create mode 100644 src/qrc/OCCViewer/res/cursor_rotate.png create mode 100644 src/qrc/OCCViewer/res/cursor_zoom.png create mode 100644 src/qrc/OCCViewer/res/help.png create mode 100644 src/qrc/OCCViewer/res/lamp.png create mode 100644 src/qrc/OCCViewer/res/raytracing.png create mode 100644 src/qrc/OCCViewer/res/reflections.png create mode 100644 src/qrc/OCCViewer/res/shadows.png create mode 100644 src/qrc/OCCViewer/res/tool_color.png create mode 100644 src/qrc/OCCViewer/res/tool_delete.png create mode 100644 src/qrc/OCCViewer/res/tool_material.png create mode 100644 src/qrc/OCCViewer/res/tool_shading.png create mode 100644 src/qrc/OCCViewer/res/tool_transparency.png create mode 100644 src/qrc/OCCViewer/res/tool_wireframe.png create mode 100644 src/qrc/OCCViewer/res/view_axo.png create mode 100644 src/qrc/OCCViewer/res/view_back.png create mode 100644 src/qrc/OCCViewer/res/view_bottom.png create mode 100644 src/qrc/OCCViewer/res/view_comp_off.png create mode 100644 src/qrc/OCCViewer/res/view_comp_on.png create mode 100644 src/qrc/OCCViewer/res/view_fitall.png create mode 100644 src/qrc/OCCViewer/res/view_front.png create mode 100644 src/qrc/OCCViewer/res/view_left.png create mode 100644 src/qrc/OCCViewer/res/view_reset.png create mode 100644 src/qrc/OCCViewer/res/view_right.png create mode 100644 src/qrc/OCCViewer/res/view_top.png create mode 100644 src/qrc/PointCloudProcess/images/1.gif create mode 100644 src/qrc/PointCloudProcess/images/QTreeView/branch-closed.png create mode 100644 src/qrc/PointCloudProcess/images/QTreeView/branch-end.png create mode 100644 src/qrc/PointCloudProcess/images/QTreeView/branch-more.png create mode 100644 src/qrc/PointCloudProcess/images/QTreeView/branch-open.png create mode 100644 src/qrc/PointCloudProcess/images/QTreeView/vline.png create mode 100644 src/qrc/PointCloudProcess/images/RGB.png create mode 100644 src/qrc/PointCloudProcess/images/algorithm/DASHBOARD.png create mode 100644 src/qrc/PointCloudProcess/images/algorithm/DBSCAN.png create mode 100644 src/qrc/PointCloudProcess/images/algorithm/Histogram.png create mode 100644 src/qrc/PointCloudProcess/images/algorithm/KMeans.png create mode 100644 src/qrc/PointCloudProcess/images/algorithm/binary.png create mode 100644 src/qrc/PointCloudProcess/images/algorithm/chooseMatrix.png create mode 100644 src/qrc/PointCloudProcess/images/algorithm/density.png create mode 100644 src/qrc/PointCloudProcess/images/algorithm/extract.png create mode 100644 src/qrc/PointCloudProcess/images/algorithm/filter.png create mode 100644 src/qrc/PointCloudProcess/images/algorithm/help.png create mode 100644 src/qrc/PointCloudProcess/images/algorithm/matrix.png create mode 100644 src/qrc/PointCloudProcess/images/algorithm/more.png create mode 100644 src/qrc/PointCloudProcess/images/algorithm/nihe.png create mode 100644 src/qrc/PointCloudProcess/images/algorithm/person.png create mode 100644 src/qrc/PointCloudProcess/images/algorithm/pingjie.png create mode 100644 src/qrc/PointCloudProcess/images/algorithm/transform.png create mode 100644 src/qrc/PointCloudProcess/images/algorithm/tree.png create mode 100644 src/qrc/PointCloudProcess/images/back.png create mode 100644 src/qrc/PointCloudProcess/images/bottom.png create mode 100644 src/qrc/PointCloudProcess/images/camera.png create mode 100644 src/qrc/PointCloudProcess/images/ccAddConstSF.png create mode 100644 src/qrc/PointCloudProcess/images/ccAlign.png create mode 100644 src/qrc/PointCloudProcess/images/ccBilateralFilter.png create mode 100644 src/qrc/PointCloudProcess/images/ccCCExtract.png create mode 100644 src/qrc/PointCloudProcess/images/ccCenteredPerspective32.png create mode 100644 src/qrc/PointCloudProcess/images/ccClippingBox.png create mode 100644 src/qrc/PointCloudProcess/images/ccClippingBoxMultExport.png create mode 100644 src/qrc/PointCloudProcess/images/ccClippingBoxSingleExport.png create mode 100644 src/qrc/PointCloudProcess/images/ccClone.png create mode 100644 src/qrc/PointCloudProcess/images/ccCloudCloudDistance.png create mode 100644 src/qrc/PointCloudProcess/images/ccCloudMeshDistance.png create mode 100644 src/qrc/PointCloudProcess/images/ccCloudPrimitiveDistance.png create mode 100644 src/qrc/PointCloudProcess/images/ccComputeStat.png create mode 100644 src/qrc/PointCloudProcess/images/ccConsole.png create mode 100644 src/qrc/PointCloudProcess/images/ccDelete.png create mode 100644 src/qrc/PointCloudProcess/images/ccDeleteSF.png create mode 100644 src/qrc/PointCloudProcess/images/ccExit.png create mode 100644 src/qrc/PointCloudProcess/images/ccFilterByValue.png create mode 100644 src/qrc/PointCloudProcess/images/ccFullScreen.png create mode 100644 src/qrc/PointCloudProcess/images/ccGaussianFilter.png create mode 100644 src/qrc/PointCloudProcess/images/ccGear.png create mode 100644 src/qrc/PointCloudProcess/images/ccGlobalZoom.png create mode 100644 src/qrc/PointCloudProcess/images/ccGradient.png create mode 100644 src/qrc/PointCloudProcess/images/ccGrid.png create mode 100644 src/qrc/PointCloudProcess/images/ccHistogram.png create mode 100644 src/qrc/PointCloudProcess/images/ccInteractiveTransformation.png create mode 100644 src/qrc/PointCloudProcess/images/ccLevel.png create mode 100644 src/qrc/PointCloudProcess/images/ccLightParams.png create mode 100644 src/qrc/PointCloudProcess/images/ccMerge.png create mode 100644 src/qrc/PointCloudProcess/images/ccMinus.png create mode 100644 src/qrc/PointCloudProcess/images/ccOpen.png create mode 100644 src/qrc/PointCloudProcess/images/ccOrthoMode32.png create mode 100644 src/qrc/PointCloudProcess/images/ccPencil.png create mode 100644 src/qrc/PointCloudProcess/images/ccPickCenter.png create mode 100644 src/qrc/PointCloudProcess/images/ccPickCenterAuto.png create mode 100644 src/qrc/PointCloudProcess/images/ccPivotAuto.png create mode 100644 src/qrc/PointCloudProcess/images/ccPivotOff.png create mode 100644 src/qrc/PointCloudProcess/images/ccPivotOn.png create mode 100644 src/qrc/PointCloudProcess/images/ccPlus.png create mode 100644 src/qrc/PointCloudProcess/images/ccPointListPicking.png create mode 100644 src/qrc/PointCloudProcess/images/ccPointPicking.png create mode 100644 src/qrc/PointCloudProcess/images/ccPointSize.png create mode 100644 src/qrc/PointCloudProcess/images/ccRegister.png create mode 100644 src/qrc/PointCloudProcess/images/ccSORFilter.png create mode 100644 src/qrc/PointCloudProcess/images/ccSampleCloud.png create mode 100644 src/qrc/PointCloudProcess/images/ccSamplePoints.png create mode 100644 src/qrc/PointCloudProcess/images/ccSave.png create mode 100644 src/qrc/PointCloudProcess/images/ccSaveProject.png create mode 100644 src/qrc/PointCloudProcess/images/ccSegment.png create mode 100644 src/qrc/PointCloudProcess/images/ccSfArithmetic.png create mode 100644 src/qrc/PointCloudProcess/images/ccStatTest.png create mode 100644 src/qrc/PointCloudProcess/images/ccStereo.png create mode 100644 src/qrc/PointCloudProcess/images/ccSunLight.png create mode 100644 src/qrc/PointCloudProcess/images/ccSwapUpDown.png create mode 100644 src/qrc/PointCloudProcess/images/ccTracePolyline.png create mode 100644 src/qrc/PointCloudProcess/images/ccTracePolyline.svg create mode 100644 src/qrc/PointCloudProcess/images/ccUnstack.png create mode 100644 src/qrc/PointCloudProcess/images/ccViewIso1.png create mode 100644 src/qrc/PointCloudProcess/images/ccViewIso2.png create mode 100644 src/qrc/PointCloudProcess/images/ccViewXneg.png create mode 100644 src/qrc/PointCloudProcess/images/ccViewXpos.png create mode 100644 src/qrc/PointCloudProcess/images/ccViewYneg.png create mode 100644 src/qrc/PointCloudProcess/images/ccViewYpos.png create mode 100644 src/qrc/PointCloudProcess/images/ccViewZneg.png create mode 100644 src/qrc/PointCloudProcess/images/ccViewZpos.png create mode 100644 src/qrc/PointCloudProcess/images/ccViewerBasedPerspective32.png create mode 100644 src/qrc/PointCloudProcess/images/ccZoomIn.png create mode 100644 src/qrc/PointCloudProcess/images/clipboard.png create mode 100644 src/qrc/PointCloudProcess/images/color.png create mode 100644 src/qrc/PointCloudProcess/images/coodinate.png create mode 100644 src/qrc/PointCloudProcess/images/dbAreaLabelSymbol.png create mode 100644 src/qrc/PointCloudProcess/images/dbCalibratedImageSymbol.png create mode 100644 src/qrc/PointCloudProcess/images/dbCamSensorSymbol.png create mode 100644 src/qrc/PointCloudProcess/images/dbCloudSymbol.png create mode 100644 src/qrc/PointCloudProcess/images/dbCloudSymbolLocked.png create mode 100644 src/qrc/PointCloudProcess/images/dbContainerSymbol.png create mode 100644 src/qrc/PointCloudProcess/images/dbContainerSymbolLocked.png create mode 100644 src/qrc/PointCloudProcess/images/dbGBLSensorSymbol.png create mode 100644 src/qrc/PointCloudProcess/images/dbHObjectSymbol.png create mode 100644 src/qrc/PointCloudProcess/images/dbHObjectSymbolLocked.png create mode 100644 src/qrc/PointCloudProcess/images/dbImageSymbol.png create mode 100644 src/qrc/PointCloudProcess/images/dbLabelSymbol.png create mode 100644 src/qrc/PointCloudProcess/images/dbLockSymbol.png create mode 100644 src/qrc/PointCloudProcess/images/dbMaterialSymbol.png create mode 100644 src/qrc/PointCloudProcess/images/dbMeshSymbol.png create mode 100644 src/qrc/PointCloudProcess/images/dbMeshSymbolLocked.png create mode 100644 src/qrc/PointCloudProcess/images/dbMiscGeomSymbol.png create mode 100644 src/qrc/PointCloudProcess/images/dbMiscGeomSymbolLocked.png create mode 100644 src/qrc/PointCloudProcess/images/dbOctreeSymbol.png create mode 100644 src/qrc/PointCloudProcess/images/dbOctreeSymbolLocked.png create mode 100644 src/qrc/PointCloudProcess/images/dbPolylineSymbol.png create mode 100644 src/qrc/PointCloudProcess/images/dbSubMeshSymbol.png create mode 100644 src/qrc/PointCloudProcess/images/dbSubMeshSymbolLocked.png create mode 100644 src/qrc/PointCloudProcess/images/dbViewportSymbol.png create mode 100644 src/qrc/PointCloudProcess/images/donate.png create mode 100644 src/qrc/PointCloudProcess/images/exportIcon.png create mode 100644 src/qrc/PointCloudProcess/images/files/CSV.png create mode 100644 src/qrc/PointCloudProcess/images/files/add.png create mode 100644 src/qrc/PointCloudProcess/images/files/bgColor.png create mode 100644 src/qrc/PointCloudProcess/images/files/cloud.png create mode 100644 src/qrc/PointCloudProcess/images/files/cloud2.png create mode 100644 src/qrc/PointCloudProcess/images/files/copy.png create mode 100644 src/qrc/PointCloudProcess/images/files/cut.png create mode 100644 src/qrc/PointCloudProcess/images/files/log.png create mode 100644 src/qrc/PointCloudProcess/images/files/new1.png create mode 100644 src/qrc/PointCloudProcess/images/files/new2.png create mode 100644 src/qrc/PointCloudProcess/images/files/paste.png create mode 100644 src/qrc/PointCloudProcess/images/files/pointCloud.png create mode 100644 src/qrc/PointCloudProcess/images/files/search.png create mode 100644 src/qrc/PointCloudProcess/images/files/snapshot.png create mode 100644 src/qrc/PointCloudProcess/images/files/star.png create mode 100644 src/qrc/PointCloudProcess/images/files/txt.png create mode 100644 src/qrc/PointCloudProcess/images/front.png create mode 100644 src/qrc/PointCloudProcess/images/gamepad.png create mode 100644 src/qrc/PointCloudProcess/images/gearIcon.png create mode 100644 src/qrc/PointCloudProcess/images/grey.png create mode 100644 src/qrc/PointCloudProcess/images/hashtag.png create mode 100644 src/qrc/PointCloudProcess/images/ic-redo.png create mode 100644 src/qrc/PointCloudProcess/images/ic-undo.png create mode 100644 src/qrc/PointCloudProcess/images/icon/cc_icon.ico create mode 100644 src/qrc/PointCloudProcess/images/icon/cc_icon.rc create mode 100644 src/qrc/PointCloudProcess/images/icon/cc_icon.svg create mode 100644 src/qrc/PointCloudProcess/images/icon/cc_icon_16.png create mode 100644 src/qrc/PointCloudProcess/images/icon/cc_icon_256.png create mode 100644 src/qrc/PointCloudProcess/images/icon/cc_icon_32.png create mode 100644 src/qrc/PointCloudProcess/images/icon/cc_icon_64.png create mode 100644 src/qrc/PointCloudProcess/images/icon/cc_viewer_icon.svg create mode 100644 src/qrc/PointCloudProcess/images/icon/cc_viewer_icon_16.png create mode 100644 src/qrc/PointCloudProcess/images/icon/cc_viewer_icon_256.png create mode 100644 src/qrc/PointCloudProcess/images/icon/cc_viewer_icon_32.png create mode 100644 src/qrc/PointCloudProcess/images/icon/cc_viewer_icon_64.png create mode 100644 src/qrc/PointCloudProcess/images/im3DxLogo.png create mode 100644 src/qrc/PointCloudProcess/images/imLogoV2Qt.png create mode 100644 src/qrc/PointCloudProcess/images/interactors.png create mode 100644 src/qrc/PointCloudProcess/images/keda.ico create mode 100644 src/qrc/PointCloudProcess/images/left.png create mode 100644 src/qrc/PointCloudProcess/images/lock.png create mode 100644 src/qrc/PointCloudProcess/images/mapIcon.png create mode 100644 src/qrc/PointCloudProcess/images/material/3DxLogo.png create mode 100644 src/qrc/PointCloudProcess/images/material/Raster_grid.pptx create mode 100644 src/qrc/PointCloudProcess/images/material/ccCenteredPerspective.svg create mode 100644 src/qrc/PointCloudProcess/images/material/ccClippingBox.svg create mode 100644 src/qrc/PointCloudProcess/images/material/ccClippingBoxBase.svg create mode 100644 src/qrc/PointCloudProcess/images/material/ccOrthoMode.svg create mode 100644 src/qrc/PointCloudProcess/images/material/ccOrthoSections.svg create mode 100644 src/qrc/PointCloudProcess/images/material/ccPivot.svg create mode 100644 src/qrc/PointCloudProcess/images/material/ccSectionExtraction.svg create mode 100644 src/qrc/PointCloudProcess/images/material/ccViewIso1.svg create mode 100644 src/qrc/PointCloudProcess/images/material/ccViewIso2.svg create mode 100644 src/qrc/PointCloudProcess/images/material/ccViewerBasedPerspective.svg create mode 100644 src/qrc/PointCloudProcess/images/monitor.svg create mode 100644 src/qrc/PointCloudProcess/images/noFilter.png create mode 100644 src/qrc/PointCloudProcess/images/nvidia.png create mode 100644 src/qrc/PointCloudProcess/images/oculus.png create mode 100644 src/qrc/PointCloudProcess/images/open.png create mode 100644 src/qrc/PointCloudProcess/images/orthoSections.png create mode 100644 src/qrc/PointCloudProcess/images/photo-camera.svg create mode 100644 src/qrc/PointCloudProcess/images/primBox.gif create mode 100644 src/qrc/PointCloudProcess/images/primCone.gif create mode 100644 src/qrc/PointCloudProcess/images/primCylinder.gif create mode 100644 src/qrc/PointCloudProcess/images/primDish.gif create mode 100644 src/qrc/PointCloudProcess/images/primPlane.gif create mode 100644 src/qrc/PointCloudProcess/images/primSphere.gif create mode 100644 src/qrc/PointCloudProcess/images/primTorus.gif create mode 100644 src/qrc/PointCloudProcess/images/qCompass.png create mode 100644 src/qrc/PointCloudProcess/images/raster_grid.jpg create mode 100644 src/qrc/PointCloudProcess/images/redo.png create mode 100644 src/qrc/PointCloudProcess/images/reset.png create mode 100644 src/qrc/PointCloudProcess/images/restore.png create mode 100644 src/qrc/PointCloudProcess/images/right.png create mode 100644 src/qrc/PointCloudProcess/images/rotate0.png create mode 100644 src/qrc/PointCloudProcess/images/rotate180.png create mode 100644 src/qrc/PointCloudProcess/images/rotate270.png create mode 100644 src/qrc/PointCloudProcess/images/rotate90.png create mode 100644 src/qrc/PointCloudProcess/images/search.svg create mode 100644 src/qrc/PointCloudProcess/images/sectionExtraction.png create mode 100644 src/qrc/PointCloudProcess/images/seting.png create mode 100644 src/qrc/PointCloudProcess/images/smallBasket.png create mode 100644 src/qrc/PointCloudProcess/images/smallCSVFile.png create mode 100644 src/qrc/PointCloudProcess/images/smallCancel.png create mode 100644 src/qrc/PointCloudProcess/images/smallPause.png create mode 100644 src/qrc/PointCloudProcess/images/smallPointDistance.png create mode 100644 src/qrc/PointCloudProcess/images/smallPointProperties.png create mode 100644 src/qrc/PointCloudProcess/images/smallPointsAngle.png create mode 100644 src/qrc/PointCloudProcess/images/smallPolygonSelect.png create mode 100644 src/qrc/PointCloudProcess/images/smallRectangleSelect.png create mode 100644 src/qrc/PointCloudProcess/images/smallReset.png create mode 100644 src/qrc/PointCloudProcess/images/smallRevert.png create mode 100644 src/qrc/PointCloudProcess/images/smallSegmentIn.png create mode 100644 src/qrc/PointCloudProcess/images/smallSegmentOut.png create mode 100644 src/qrc/PointCloudProcess/images/smallSphere.png create mode 100644 src/qrc/PointCloudProcess/images/smallTrash.png create mode 100644 src/qrc/PointCloudProcess/images/smallValidate.png create mode 100644 src/qrc/PointCloudProcess/images/square.png create mode 100644 src/qrc/PointCloudProcess/images/store.png create mode 100644 src/qrc/PointCloudProcess/images/theme/snowman.png create mode 100644 src/qrc/PointCloudProcess/images/typeGrayColor.png create mode 100644 src/qrc/PointCloudProcess/images/typeNormal.png create mode 100644 src/qrc/PointCloudProcess/images/typePositiveSF.png create mode 100644 src/qrc/PointCloudProcess/images/typeQuaternion.png create mode 100644 src/qrc/PointCloudProcess/images/typeRgbCcolor.png create mode 100644 src/qrc/PointCloudProcess/images/typeSF.png create mode 100644 src/qrc/PointCloudProcess/images/typeXCoordinate.png create mode 100644 src/qrc/PointCloudProcess/images/typeYCoordinate.png create mode 100644 src/qrc/PointCloudProcess/images/typeZCoordinate.png create mode 100644 src/qrc/PointCloudProcess/images/undo.png create mode 100644 src/qrc/PointCloudProcess/images/unfoldSmall.png create mode 100644 src/qrc/PointCloudProcess/images/up.png create mode 100644 src/qrc/PointCloudProcess/images/zoomin.png create mode 100644 src/qrc/PointCloudProcess/images/zoomout.png create mode 100644 src/qrc/WBCLFZSystemModule.qrc create mode 100644 src/qscintilla2/CMakeLists.txt create mode 100644 src/qscintilla2/ChangeLog create mode 100644 src/qscintilla2/LICENSE create mode 100644 src/qscintilla2/NEWS create mode 100644 src/qscintilla2/Qt4Qt5/CMakeLists.txt create mode 100644 src/qscintilla2/Qt4Qt5/InputMethod.cpp create mode 100644 src/qscintilla2/Qt4Qt5/ListBoxQt.cpp create mode 100644 src/qscintilla2/Qt4Qt5/ListBoxQt.h create mode 100644 src/qscintilla2/Qt4Qt5/MacPasteboardMime.cpp create mode 100644 src/qscintilla2/Qt4Qt5/PlatQt.cpp create mode 100644 src/qscintilla2/Qt4Qt5/Qsci/qsciabstractapis.h create mode 100644 src/qscintilla2/Qt4Qt5/Qsci/qsciapis.h create mode 100644 src/qscintilla2/Qt4Qt5/Qsci/qscicommand.h create mode 100644 src/qscintilla2/Qt4Qt5/Qsci/qscicommandset.h create mode 100644 src/qscintilla2/Qt4Qt5/Qsci/qscidocument.h create mode 100644 src/qscintilla2/Qt4Qt5/Qsci/qsciglobal.h create mode 100644 src/qscintilla2/Qt4Qt5/Qsci/qscilexer.h create mode 100644 src/qscintilla2/Qt4Qt5/Qsci/qscilexercpp.h create mode 100644 src/qscintilla2/Qt4Qt5/Qsci/qscilexercustom.h create mode 100644 src/qscintilla2/Qt4Qt5/Qsci/qscilexerhtml.h create mode 100644 src/qscintilla2/Qt4Qt5/Qsci/qscilexerjavascript.h create mode 100644 src/qscintilla2/Qt4Qt5/Qsci/qscilexerjson.h create mode 100644 src/qscintilla2/Qt4Qt5/Qsci/qscilexerpython.h create mode 100644 src/qscintilla2/Qt4Qt5/Qsci/qscilexersql.h create mode 100644 src/qscintilla2/Qt4Qt5/Qsci/qscilexerxml.h create mode 100644 src/qscintilla2/Qt4Qt5/Qsci/qscimacro.h create mode 100644 src/qscintilla2/Qt4Qt5/Qsci/qsciprinter.h create mode 100644 src/qscintilla2/Qt4Qt5/Qsci/qsciscintilla.h create mode 100644 src/qscintilla2/Qt4Qt5/Qsci/qsciscintillabase.h create mode 100644 src/qscintilla2/Qt4Qt5/Qsci/qscistyle.h create mode 100644 src/qscintilla2/Qt4Qt5/Qsci/qscistyledtext.h create mode 100644 src/qscintilla2/Qt4Qt5/SciAccessibility.cpp create mode 100644 src/qscintilla2/Qt4Qt5/SciAccessibility.h create mode 100644 src/qscintilla2/Qt4Qt5/SciClasses.cpp create mode 100644 src/qscintilla2/Qt4Qt5/SciClasses.h create mode 100644 src/qscintilla2/Qt4Qt5/SciNamespace.h create mode 100644 src/qscintilla2/Qt4Qt5/ScintillaQt.cpp create mode 100644 src/qscintilla2/Qt4Qt5/ScintillaQt.h create mode 100644 src/qscintilla2/Qt4Qt5/features/qscintilla2.prf create mode 100644 src/qscintilla2/Qt4Qt5/qsciabstractapis.cpp create mode 100644 src/qscintilla2/Qt4Qt5/qsciapis.cpp create mode 100644 src/qscintilla2/Qt4Qt5/qscicommand.cpp create mode 100644 src/qscintilla2/Qt4Qt5/qscicommandset.cpp create mode 100644 src/qscintilla2/Qt4Qt5/qscidocument.cpp create mode 100644 src/qscintilla2/Qt4Qt5/qscilexer.cpp create mode 100644 src/qscintilla2/Qt4Qt5/qscilexercpp.cpp create mode 100644 src/qscintilla2/Qt4Qt5/qscilexercustom.cpp create mode 100644 src/qscintilla2/Qt4Qt5/qscilexerhtml.cpp create mode 100644 src/qscintilla2/Qt4Qt5/qscilexerjavascript.cpp create mode 100644 src/qscintilla2/Qt4Qt5/qscilexerjson.cpp create mode 100644 src/qscintilla2/Qt4Qt5/qscilexerpython.cpp create mode 100644 src/qscintilla2/Qt4Qt5/qscilexersql.cpp create mode 100644 src/qscintilla2/Qt4Qt5/qscilexerxml.cpp create mode 100644 src/qscintilla2/Qt4Qt5/qscimacro.cpp create mode 100644 src/qscintilla2/Qt4Qt5/qscintilla.pro create mode 100644 src/qscintilla2/Qt4Qt5/qscintilla_cs.qm create mode 100644 src/qscintilla2/Qt4Qt5/qscintilla_cs.ts create mode 100644 src/qscintilla2/Qt4Qt5/qscintilla_de.qm create mode 100644 src/qscintilla2/Qt4Qt5/qscintilla_de.ts create mode 100644 src/qscintilla2/Qt4Qt5/qscintilla_es.qm create mode 100644 src/qscintilla2/Qt4Qt5/qscintilla_es.ts create mode 100644 src/qscintilla2/Qt4Qt5/qscintilla_fr.qm create mode 100644 src/qscintilla2/Qt4Qt5/qscintilla_fr.ts create mode 100644 src/qscintilla2/Qt4Qt5/qscintilla_pt_br.qm create mode 100644 src/qscintilla2/Qt4Qt5/qscintilla_pt_br.ts create mode 100644 src/qscintilla2/Qt4Qt5/qsciprinter.cpp create mode 100644 src/qscintilla2/Qt4Qt5/qsciscintilla.cpp create mode 100644 src/qscintilla2/Qt4Qt5/qsciscintillabase.cpp create mode 100644 src/qscintilla2/Qt4Qt5/qscistyle.cpp create mode 100644 src/qscintilla2/Qt4Qt5/qscistyledtext.cpp create mode 100644 src/qscintilla2/README create mode 100644 src/qscintilla2/include/ILexer.h create mode 100644 src/qscintilla2/include/ILoader.h create mode 100644 src/qscintilla2/include/License.txt create mode 100644 src/qscintilla2/include/Platform.h create mode 100644 src/qscintilla2/include/SciLexer.h create mode 100644 src/qscintilla2/include/Sci_Position.h create mode 100644 src/qscintilla2/include/Scintilla.h create mode 100644 src/qscintilla2/include/Scintilla.iface create mode 100644 src/qscintilla2/include/ScintillaWidget.h create mode 100644 src/qscintilla2/lexers/LexHTML.cpp create mode 100644 src/qscintilla2/lexers/LexJSON.cpp create mode 100644 src/qscintilla2/lexers/LexSQL.cpp create mode 100644 src/qscintilla2/lexers/License.txt create mode 100644 src/qscintilla2/lexlib/Accessor.cpp create mode 100644 src/qscintilla2/lexlib/Accessor.h create mode 100644 src/qscintilla2/lexlib/CharacterCategory.cpp create mode 100644 src/qscintilla2/lexlib/CharacterCategory.h create mode 100644 src/qscintilla2/lexlib/CharacterSet.cpp create mode 100644 src/qscintilla2/lexlib/CharacterSet.h create mode 100644 src/qscintilla2/lexlib/DefaultLexer.cpp create mode 100644 src/qscintilla2/lexlib/DefaultLexer.h create mode 100644 src/qscintilla2/lexlib/LexAccessor.h create mode 100644 src/qscintilla2/lexlib/LexerBase.cpp create mode 100644 src/qscintilla2/lexlib/LexerBase.h create mode 100644 src/qscintilla2/lexlib/LexerModule.cpp create mode 100644 src/qscintilla2/lexlib/LexerModule.h create mode 100644 src/qscintilla2/lexlib/LexerNoExceptions.cpp create mode 100644 src/qscintilla2/lexlib/LexerNoExceptions.h create mode 100644 src/qscintilla2/lexlib/LexerSimple.cpp create mode 100644 src/qscintilla2/lexlib/LexerSimple.h create mode 100644 src/qscintilla2/lexlib/License.txt create mode 100644 src/qscintilla2/lexlib/OptionSet.h create mode 100644 src/qscintilla2/lexlib/PropSetSimple.cpp create mode 100644 src/qscintilla2/lexlib/PropSetSimple.h create mode 100644 src/qscintilla2/lexlib/SparseState.h create mode 100644 src/qscintilla2/lexlib/StringCopy.h create mode 100644 src/qscintilla2/lexlib/StyleContext.cpp create mode 100644 src/qscintilla2/lexlib/StyleContext.h create mode 100644 src/qscintilla2/lexlib/SubStyles.h create mode 100644 src/qscintilla2/lexlib/WordList.cpp create mode 100644 src/qscintilla2/lexlib/WordList.h create mode 100644 src/qscintilla2/qscintilla2.vcxproj create mode 100644 src/qscintilla2/qscintilla2.vcxproj.filters create mode 100644 src/qscintilla2/qscintilla2.vcxproj.user create mode 100644 src/qscintilla2/src/AutoComplete.cpp create mode 100644 src/qscintilla2/src/AutoComplete.h create mode 100644 src/qscintilla2/src/CallTip.cpp create mode 100644 src/qscintilla2/src/CallTip.h create mode 100644 src/qscintilla2/src/CaseConvert.cpp create mode 100644 src/qscintilla2/src/CaseConvert.h create mode 100644 src/qscintilla2/src/CaseFolder.cpp create mode 100644 src/qscintilla2/src/CaseFolder.h create mode 100644 src/qscintilla2/src/Catalogue.cpp create mode 100644 src/qscintilla2/src/Catalogue.h create mode 100644 src/qscintilla2/src/CellBuffer.cpp create mode 100644 src/qscintilla2/src/CellBuffer.h create mode 100644 src/qscintilla2/src/CharClassify.cpp create mode 100644 src/qscintilla2/src/CharClassify.h create mode 100644 src/qscintilla2/src/ContractionState.cpp create mode 100644 src/qscintilla2/src/ContractionState.h create mode 100644 src/qscintilla2/src/DBCS.cpp create mode 100644 src/qscintilla2/src/DBCS.h create mode 100644 src/qscintilla2/src/Decoration.cpp create mode 100644 src/qscintilla2/src/Decoration.h create mode 100644 src/qscintilla2/src/Document.cpp create mode 100644 src/qscintilla2/src/Document.h create mode 100644 src/qscintilla2/src/EditModel.cpp create mode 100644 src/qscintilla2/src/EditModel.h create mode 100644 src/qscintilla2/src/EditView.cpp create mode 100644 src/qscintilla2/src/EditView.h create mode 100644 src/qscintilla2/src/Editor.cpp create mode 100644 src/qscintilla2/src/Editor.h create mode 100644 src/qscintilla2/src/ElapsedPeriod.h create mode 100644 src/qscintilla2/src/ExternalLexer.cpp create mode 100644 src/qscintilla2/src/ExternalLexer.h create mode 100644 src/qscintilla2/src/FontQuality.h create mode 100644 src/qscintilla2/src/Indicator.cpp create mode 100644 src/qscintilla2/src/Indicator.h create mode 100644 src/qscintilla2/src/IntegerRectangle.h create mode 100644 src/qscintilla2/src/KeyMap.cpp create mode 100644 src/qscintilla2/src/KeyMap.h create mode 100644 src/qscintilla2/src/License.txt create mode 100644 src/qscintilla2/src/LineMarker.cpp create mode 100644 src/qscintilla2/src/LineMarker.h create mode 100644 src/qscintilla2/src/MarginView.cpp create mode 100644 src/qscintilla2/src/MarginView.h create mode 100644 src/qscintilla2/src/Partitioning.h create mode 100644 src/qscintilla2/src/PerLine.cpp create mode 100644 src/qscintilla2/src/PerLine.h create mode 100644 src/qscintilla2/src/Position.h create mode 100644 src/qscintilla2/src/PositionCache.cpp create mode 100644 src/qscintilla2/src/PositionCache.h create mode 100644 src/qscintilla2/src/RESearch.cpp create mode 100644 src/qscintilla2/src/RESearch.h create mode 100644 src/qscintilla2/src/RunStyles.cpp create mode 100644 src/qscintilla2/src/RunStyles.h create mode 100644 src/qscintilla2/src/SciTE.properties create mode 100644 src/qscintilla2/src/ScintillaBase.cpp create mode 100644 src/qscintilla2/src/ScintillaBase.h create mode 100644 src/qscintilla2/src/Selection.cpp create mode 100644 src/qscintilla2/src/Selection.h create mode 100644 src/qscintilla2/src/SparseVector.h create mode 100644 src/qscintilla2/src/SplitVector.h create mode 100644 src/qscintilla2/src/Style.cpp create mode 100644 src/qscintilla2/src/Style.h create mode 100644 src/qscintilla2/src/UniConversion.cpp create mode 100644 src/qscintilla2/src/UniConversion.h create mode 100644 src/qscintilla2/src/UnicodeFromUTF8.h create mode 100644 src/qscintilla2/src/UniqueString.h create mode 100644 src/qscintilla2/src/ViewStyle.cpp create mode 100644 src/qscintilla2/src/ViewStyle.h create mode 100644 src/qscintilla2/src/XPM.cpp create mode 100644 src/qscintilla2/src/XPM.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 12e8d06..4c11220 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,8 +7,8 @@ cmake_minimum_required(VERSION 3.21 FATAL_ERROR) project(FastCAE VERSION 2.5.0 LANGUAGES CXX - DESCRIPTION "FastCAE,一款å…费的CAEä»¿çœŸè½¯ä»¶ç ”å‘æ”¯æ’‘å¹³å°ã€‚" - HOMEPAGE_URL "http://www.fastcae.com/" + DESCRIPTION "LAMPCAE,基于FastCAE的测é‡ä»¿çœŸåˆ†æžè½¯ä»¶ã€‚" + HOMEPAGE_URL "http://124.16.188.131:9699/web/server3/build/#/Guide/" ) #----------------------------------------------------------------------------- diff --git a/CMakeLists.txt.user b/CMakeLists.txt.user new file mode 100644 index 0000000..5de0095 --- /dev/null +++ b/CMakeLists.txt.user @@ -0,0 +1,419 @@ + + + + + + EnvironmentId + {d034e98c-d1df-4d65-be6b-a0d9f31abe3b} + + + ProjectExplorer.Project.ActiveTarget + 0 + + + ProjectExplorer.Project.EditorSettings + + true + false + true + + Cpp + + CppGlobal + + + + QmlJS + + QmlJSGlobal + + + 2 + UTF-8 + false + 4 + false + 80 + true + true + 1 + 0 + false + true + false + 0 + true + true + 0 + 8 + true + false + 1 + true + true + true + *.md, *.MD, Makefile + false + true + true + + + + ProjectExplorer.Project.PluginSettings + + + true + false + true + true + true + true + + + 0 + true + + true + true + Builtin.DefaultTidyAndClazy + 8 + true + + + + true + + + + + ProjectExplorer.Project.Target.0 + + Desktop + Desktop Qt 5.15.2 MSVC2019 64bit + Desktop Qt 5.15.2 MSVC2019 64bit + qt.qt5.5152.win64_msvc2019_64_kit + 0 + 0 + 0 + + Debug + 2 + false + + -DCMAKE_GENERATOR:STRING=Ninja +-DCMAKE_BUILD_TYPE:STRING=Debug +-DCMAKE_PROJECT_INCLUDE_BEFORE:FILEPATH=%{BuildConfig:BuildDirectory:NativeFilePath}/.qtc/package-manager/auto-setup.cmake +-DQT_QMAKE_EXECUTABLE:FILEPATH=%{Qt:qmakeExecutable} +-DCMAKE_PREFIX_PATH:PATH=%{Qt:QT_INSTALL_PREFIX} +-DCMAKE_C_COMPILER:FILEPATH=%{Compiler:Executable:C} +-DCMAKE_CXX_COMPILER:FILEPATH=%{Compiler:Executable:Cxx} +-DCMAKE_CXX_FLAGS_INIT:STRING=%{Qt:QML_DEBUG_FLAG} + 0 + D:\WBFZCPP\source\build-FastCAE-Desktop_Qt_5_15_2_MSVC2019_64bit-Debug + + + + + all + + false + + true + 构建 + CMakeProjectManager.MakeStep + + 1 + 构建 + 构建 + ProjectExplorer.BuildSteps.Build + + + + + + clean + + false + + true + 构建 + CMakeProjectManager.MakeStep + + 1 + 清除 + 清除 + ProjectExplorer.BuildSteps.Clean + + 2 + false + + false + + Debug + CMakeProjectManager.CMakeBuildConfiguration + + + Release + 2 + false + + -DCMAKE_GENERATOR:STRING=Ninja +-DCMAKE_BUILD_TYPE:STRING=Release +-DCMAKE_PROJECT_INCLUDE_BEFORE:FILEPATH=%{BuildConfig:BuildDirectory:NativeFilePath}/.qtc/package-manager/auto-setup.cmake +-DQT_QMAKE_EXECUTABLE:FILEPATH=%{Qt:qmakeExecutable} +-DCMAKE_PREFIX_PATH:PATH=%{Qt:QT_INSTALL_PREFIX} +-DCMAKE_C_COMPILER:FILEPATH=%{Compiler:Executable:C} +-DCMAKE_CXX_COMPILER:FILEPATH=%{Compiler:Executable:Cxx} +-DCMAKE_CXX_FLAGS_INIT:STRING=%{Qt:QML_DEBUG_FLAG} + D:\WBFZCPP\source\build-FastCAE-Desktop_Qt_5_15_2_MSVC2019_64bit-Release + + + + + all + + false + + true + CMakeProjectManager.MakeStep + + 1 + 构建 + 构建 + ProjectExplorer.BuildSteps.Build + + + + + + clean + + false + + true + CMakeProjectManager.MakeStep + + 1 + 清除 + 清除 + ProjectExplorer.BuildSteps.Clean + + 2 + false + + false + + Release + CMakeProjectManager.CMakeBuildConfiguration + + + RelWithDebInfo + 2 + false + + -DCMAKE_GENERATOR:STRING=Ninja +-DCMAKE_BUILD_TYPE:STRING=RelWithDebInfo +-DCMAKE_PROJECT_INCLUDE_BEFORE:FILEPATH=%{BuildConfig:BuildDirectory:NativeFilePath}/.qtc/package-manager/auto-setup.cmake +-DQT_QMAKE_EXECUTABLE:FILEPATH=%{Qt:qmakeExecutable} +-DCMAKE_PREFIX_PATH:PATH=%{Qt:QT_INSTALL_PREFIX} +-DCMAKE_C_COMPILER:FILEPATH=%{Compiler:Executable:C} +-DCMAKE_CXX_COMPILER:FILEPATH=%{Compiler:Executable:Cxx} +-DCMAKE_CXX_FLAGS_INIT:STRING=%{Qt:QML_DEBUG_FLAG} + D:\WBFZCPP\source\build-FastCAE-Desktop_Qt_5_15_2_MSVC2019_64bit-RelWithDebInfo + + + + + all + + false + + true + CMakeProjectManager.MakeStep + + 1 + 构建 + 构建 + ProjectExplorer.BuildSteps.Build + + + + + + clean + + false + + true + CMakeProjectManager.MakeStep + + 1 + 清除 + 清除 + ProjectExplorer.BuildSteps.Clean + + 2 + false + + false + + Release with Debug Information + CMakeProjectManager.CMakeBuildConfiguration + + + RelWithDebInfo + 2 + false + + -DCMAKE_GENERATOR:STRING=Ninja +-DCMAKE_BUILD_TYPE:STRING=RelWithDebInfo +-DCMAKE_PROJECT_INCLUDE_BEFORE:FILEPATH=%{BuildConfig:BuildDirectory:NativeFilePath}/.qtc/package-manager/auto-setup.cmake +-DQT_QMAKE_EXECUTABLE:FILEPATH=%{Qt:qmakeExecutable} +-DCMAKE_PREFIX_PATH:PATH=%{Qt:QT_INSTALL_PREFIX} +-DCMAKE_C_COMPILER:FILEPATH=%{Compiler:Executable:C} +-DCMAKE_CXX_COMPILER:FILEPATH=%{Compiler:Executable:Cxx} +-DCMAKE_CXX_FLAGS_INIT:STRING=%{Qt:QML_DEBUG_FLAG} + 0 + D:\WBFZCPP\source\build-FastCAE-Desktop_Qt_5_15_2_MSVC2019_64bit-Profile + + + + + all + + false + + true + CMakeProjectManager.MakeStep + + 1 + 构建 + 构建 + ProjectExplorer.BuildSteps.Build + + + + + + clean + + false + + true + CMakeProjectManager.MakeStep + + 1 + 清除 + 清除 + ProjectExplorer.BuildSteps.Clean + + 2 + false + + false + + Profile + CMakeProjectManager.CMakeBuildConfiguration + + + MinSizeRel + 2 + false + + -DCMAKE_GENERATOR:STRING=Ninja +-DCMAKE_BUILD_TYPE:STRING=MinSizeRel +-DCMAKE_PROJECT_INCLUDE_BEFORE:FILEPATH=%{BuildConfig:BuildDirectory:NativeFilePath}/.qtc/package-manager/auto-setup.cmake +-DQT_QMAKE_EXECUTABLE:FILEPATH=%{Qt:qmakeExecutable} +-DCMAKE_PREFIX_PATH:PATH=%{Qt:QT_INSTALL_PREFIX} +-DCMAKE_C_COMPILER:FILEPATH=%{Compiler:Executable:C} +-DCMAKE_CXX_COMPILER:FILEPATH=%{Compiler:Executable:Cxx} +-DCMAKE_CXX_FLAGS_INIT:STRING=%{Qt:QML_DEBUG_FLAG} + D:\WBFZCPP\source\build-FastCAE-Desktop_Qt_5_15_2_MSVC2019_64bit-MinSizeRel + + + + + all + + false + + true + CMakeProjectManager.MakeStep + + 1 + 构建 + 构建 + ProjectExplorer.BuildSteps.Build + + + + + + clean + + false + + true + CMakeProjectManager.MakeStep + + 1 + 清除 + 清除 + ProjectExplorer.BuildSteps.Clean + + 2 + false + + false + + Minimum Size Release + CMakeProjectManager.CMakeBuildConfiguration + + 5 + + + 0 + 部署 + 部署 + ProjectExplorer.BuildSteps.Deploy + + 1 + + false + ProjectExplorer.DefaultDeployConfiguration + + 1 + + true + true + 0 + true + + 2 + + false + FastCAE + CMakeProjectManager.CMakeRunConfiguration.FastCAE + FastCAE + false + true + true + true + D:/WBFZCPP/source/build-FastCAE-Desktop_Qt_5_15_2_MSVC2019_64bit-Debug/Debug + + 1 + + + + ProjectExplorer.Project.TargetCount + 1 + + + ProjectExplorer.Project.Updater.FileVersion + 22 + + + Version + 22 + + diff --git a/cmake/FindFFTW.cmake b/cmake/FindFFTW.cmake new file mode 100644 index 0000000..9cc94d6 --- /dev/null +++ b/cmake/FindFFTW.cmake @@ -0,0 +1,70 @@ +## FFTW can be compiled and subsequently linked against +## various data types. +## There is a single set of include files, and then muttiple libraries, +## One for each type. I.e. libfftw.a-->double, libfftwf.a-->float + +## The following logic belongs in the individual package +## mark_as_advanced(ITK_USE_FFTWD) +## option(ITK_USE_FFTWD "Use double precision FFTW if found" ON) +## mark_as_advanced(ITK_USE_FFTWF) +## option(ITK_USE_FFTWF "Use single precision FFTW if found" ON) + +if(ITK_USE_FFTWD OR ITK_USE_FFTWF) + + set(FFTW_INC_SEARCHPATH + /sw/include + /usr/include + /usr/local/include + /usr/include/fftw + /usr/local/include/fftw + ) + + find_path(FFTW_INCLUDE_PATH fftw3.h ${FFTW_INC_SEARCHPATH}) + + if(FFTW_INCLUDE_PATH) + file(TO_CMAKE_PATH "${FFTW_INCLUDE_PATH}" FFTW_INCLUDE_PATH) + set(FFTW_INCLUDE ${FFTW_INCLUDE_PATH}) + endif() + + if(FFTW_INCLUDE) + include_directories(${FFTW_INCLUDE}) + endif() + + get_filename_component(FFTW_INSTALL_BASE_PATH ${FFTW_INCLUDE_PATH} PATH) + + set(FFTW_LIB_SEARCHPATH + ${FFTW_INSTALL_BASE_PATH}/lib + ${FFTW_INSTALL_BASE_PATH}/lib64 + /usr/lib/fftw + /usr/local/lib/fftw + ) + + if(ITK_USE_FFTWD) + mark_as_advanced(FFTWD_LIB) + find_library(FFTWD_LIB fftw3 ${FFTW_LIB_SEARCHPATH}) #Double Precision Lib + find_library(FFTWD_THREADS_LIB fftw3_threads ${FFTW_LIB_SEARCHPATH}) #Double Precision Lib only if compiled with threads support + + if(FFTWD_LIB) + set(FFTWD_FOUND 1) + get_filename_component(FFTW_LIBDIR ${FFTWD_LIB} PATH) + if(FFTWD_THREADS_LIB) + set(FFTWD_LIB ${FFTWD_LIB} ${FFTWD_THREADS_LIB} ) + endif() + endif() + endif() + + if(ITK_USE_FFTWF) + mark_as_advanced(FFTWF_LIB) + find_library(FFTWF_LIB fftw3f ${FFTW_LIB_SEARCHPATH}) #Single Precision Lib + find_library(FFTWF_THREADS_LIB fftw3f_threads ${FFTW_LIB_SEARCHPATH}) #Single Precision Lib only if compiled with threads support + + if(FFTWF_LIB) + set(FFTWF_FOUND 1) + get_filename_component(FFTW_LIBDIR ${FFTWF_LIB} PATH) + if(FFTWF_THREADS_LIB) + set(FFTWF_LIB ${FFTWF_LIB} ${FFTWF_THREADS_LIB} ) + endif() + endif() + endif() + +endif() diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index a40782d..e07abad 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -3,7 +3,7 @@ #----------------------------------------------------------------------------- # 所有项目 #----------------------------------------------------------------------------- -list(APPEND _libraries Common PythonModule SARibbonBar Settings DataProperty MeshData SelfDefObject Material Geometry BCBase ConfigOptions ParaClassFactory ModelData ModuleBase PostAlgorithm PostRenderData PostInterface PostCurveDataManager PostPlotWidget PostWidgets GeometryDataExchange ProjectTree ProjectTreeExtend GeometryCommand GeometryWidgets PluginManager GmshModule IO SolverControl MainWidgets UserGuidence) +list(APPEND _libraries qcustomplot json qscintilla2 qhexedit LAMPTool WBCLFZSystemModule Common PythonModule SARibbonBar Settings DataProperty MeshData SelfDefObject Material Geometry BCBase ConfigOptions ParaClassFactory ModelData ModuleBase PostAlgorithm PostRenderData PostInterface PostCurveDataManager PostPlotWidget PostWidgets GeometryDataExchange ProjectTree ProjectTreeExtend GeometryCommand GeometryWidgets PluginManager GmshModule IO SolverControl MainWidgets UserGuidence) #[[if(_WIN_) list(APPEND _libraries XGenerateReport License) diff --git a/src/FastCAE/CommandLine.cpp b/src/FastCAE/CommandLine.cpp index 84d9903..7e6fc03 100644 --- a/src/FastCAE/CommandLine.cpp +++ b/src/FastCAE/CommandLine.cpp @@ -50,6 +50,8 @@ #include #endif +#include "Common/DebugLogger.h" // 日志文件 + #define WELCOMETIME 1500 CommandPara::CommandPara(int argc, char *argv[]) @@ -131,7 +133,6 @@ bool CommandPara::exec(GUI::MainWindow *window) window->show(); window->showMaximized(); } - if (!_projectFile.isEmpty()) { QFile sf(_projectFile); @@ -155,6 +156,7 @@ bool CommandPara::exec(GUI::MainWindow *window) runSc = true; } } + if (_showGUI) return true; else if (runSc) diff --git a/src/FastCAE/main.cpp b/src/FastCAE/main.cpp index bd52c96..d784baa 100644 --- a/src/FastCAE/main.cpp +++ b/src/FastCAE/main.cpp @@ -31,9 +31,11 @@ #include #include #include -// #include "ConfigOptions/ConfigDataReader.h" -// #include "ConfigOptions/ConfigOptions.h" -// #include "ConfigOptions/GlobalConfig.h" + +#include "ConfigOptions/ConfigDataReader.h" +#include "ConfigOptions/ConfigOptions.h" +#include "ConfigOptions/GlobalConfig.h" + #include "Common/DebugLogger.h" #include "Settings/BusAPI.h" @@ -44,6 +46,10 @@ #endif #endif +#include "Common/DebugLogger.h" // 日志文件 + + + #define CHECKINGMEMORY 0 bool testOpenGL() @@ -92,12 +98,13 @@ int main(int argc, char* argv[]) if(!testOpenGL()) { return 1; } - // QString path = qApp->applicationDirPath(); - // ConfigOption::ConfigDataReader reader(path + "/../ConfigFiles/", - // ConfigOption::ConfigOption::getInstance()); reader.read(); QString qUseRibbon = - // ConfigOption::ConfigOption::getInstance()->getGlobalConfig()->getUseRibbon(); bool - // bUseRibbon = qUseRibbon == "yes" ? true : false; + /*****************åŠ è½½å‚æ•°é…置项 *****************************************/ + QString path = qApp->applicationDirPath(); + ConfigOption::ConfigDataReader reader(path + "/../ConfigFiles/", ConfigOption::ConfigOption::getInstance()); + reader.read(); + + /******************************************************************************/ bool isRibbon = Setting::BusAPI::instance()->isUseRibbon(); GUI::MainWindow mainwindow(isRibbon); @@ -128,7 +135,6 @@ int main(int argc, char* argv[]) #endif //***************************************** - if(para.exec(&mainwindow)) emit mainwindow.sendInfoToStatesBar(QString("Version: %1").arg(FASTCAE_VERSION)); else diff --git a/src/IO/CMakeLists.txt b/src/IO/CMakeLists.txt index 3cdc1c1..33068e7 100644 --- a/src/IO/CMakeLists.txt +++ b/src/IO/CMakeLists.txt @@ -11,7 +11,7 @@ set(CMAKE_INCLUDE_CURRENT_DIR ON) #----------------------------------------------------------------------------- # æºç æ‰«æ #----------------------------------------------------------------------------- -file(GLOB _header "*.h") +file(GLOB _header "*.h*") file(GLOB _source "*.cpp") #----------------------------------------------------------------------------- diff --git a/src/LAMPTool/BaseToollib/BaseConstVariable.h b/src/LAMPTool/BaseToollib/BaseConstVariable.h new file mode 100644 index 0000000..c38899b --- /dev/null +++ b/src/LAMPTool/BaseToollib/BaseConstVariable.h @@ -0,0 +1,38 @@ +#pragma once + +#ifndef BASECONSTVARIABLE_H +#define BASECONSTVARIABLE_H + + +#include +#include + + +#define PI_180 180/3.141592653589793238462643383279 +#define T180_PI 3.141592653589793238462643383279/180 +#define LIGHTSPEED 299792458 + +#define Radians2Degrees(Radians) Radians*PI_180 +#define Degrees2Radians(Degrees) Degrees*T180_PI + + + +const double PI = 3.141592653589793238462643383279; +const double epsilon = 0.000000000000001; +const double pi = 3.14159265358979323846; +const double d2r = pi / 180; +const double r2d = 180 / pi; + +const double a = 6378137.0; //ÍÖÇò³¤°ëÖá +const double ae = 6378137.0; //ÍÖÇò³¤°ëÖá +const double ee = 0.0818191910428;// µÚһƫÐÄÂÊ +const double f_inverse = 298.257223563; //±âÂʵ¹Êý +const double b = a - a / f_inverse; +const double eSquare = (a * a - b * b) / (a * a); +const double e = sqrt(eSquare); +const double earth_Re = 6378136.49; +const double earth_Rp = (1 - 1 / f_inverse) * earth_Re; +const double earth_We = 0.000072292115; + + +#endif \ No newline at end of file diff --git a/src/LAMPTool/BaseToollib/BaseTool.cpp b/src/LAMPTool/BaseToollib/BaseTool.cpp new file mode 100644 index 0000000..81da26c --- /dev/null +++ b/src/LAMPTool/BaseToollib/BaseTool.cpp @@ -0,0 +1,256 @@ +#pragma once +#include "BaseTool.h" +/// +/// +//#define EIGEN_USE_MKL_ALL +//#define EIGEN_VECTORIZE_SSE4_2 +//#include + +#include "referenceHeader.h" +#include +#include +#include +#include +//#include +#include +#include + +#include < io.h > +#include < stdio.h > +#include < stdlib.h > +#include +#include +#include +//#include +#include //#include "ogrsf_frmts.h" + +#include +#include +#include "GeoOperator.h" + + +#include "baseTool.h" +using namespace std; +using namespace Eigen; + + + + +QString getCurrentTimeString() { + struct tm ConversionTime; + std::time_t t = std::time(NULL); + char mbstr[100]; + _localtime64_s(&ConversionTime, &t); + std::strftime(mbstr, sizeof(mbstr), "%Y-%m-%d %H:%M:%S", &ConversionTime); + QString strTime = mbstr; + return strTime; +} + +QString getCurrentShortTimeString() { + struct tm ConversionTime; + std::time_t t = std::time(NULL); + char mbstr[100]; + _localtime64_s(&ConversionTime, &t); + std::strftime(mbstr, sizeof(mbstr), "%Y-%m-%d %H:%M:%S", &ConversionTime); + QString strTime = mbstr; + return strTime; +} + +std::vector splitString(const QString& str, char delimiter) +{ + QStringList tokens = str.split(delimiter); + return convertQStringListToStdVector(tokens); +} + + +complex Cubic_Convolution_interpolation(double u, double v, Eigen::MatrixX> img) +{ + if (img.rows() != 4 || img.cols() != 4) { + throw exception("the size of img's block is not right"); + } + // ½ï¿½ï¿½ï¿½Ä£ï¿½ï¿½ + Eigen::MatrixX> wrc(1, 4);// ʹ�� complex ½ï¿½ï¿½ï¿½ÒªÔ­½ï¿½Îªï¿½Ë»ï¿½È¡Öµ + Eigen::MatrixX> wcr(4, 1);// + for (int i = 0; i < 4; i++) { + wrc(0, i) = Cubic_kernel_weight(u + 1 - i); // u+1,u,u-1,u-2 + wcr(i, 0) = Cubic_kernel_weight(v + 1 - i); + } + + Eigen::MatrixX> interValue = wrc * img * wcr; + return interValue(0, 0); +} + +complex Cubic_kernel_weight(double s) +{ + s = abs(s); + if (s <= 1) { + return complex(1.5 * s * s * s - 2.5 * s * s + 1, 0); + } + else if (s <= 2) { + return complex(-0.5 * s * s * s + 2.5 * s * s - 4 * s + 2, 0); + } + else { + return complex(0, 0); + } +} + +/// +/// p11 p12 -- x +/// p0(u,v) +/// p21 p22 +/// | +/// y +/// p11(0,0) +/// p21(0,1) +/// P12(1,0) +/// p22(1,1) +/// +/// x,y,z +/// x,y,z +/// x,y,z +/// x,y,z +/// x,y,z +/// +double Bilinear_interpolation(Landpoint p0, Landpoint p11, Landpoint p21, Landpoint p12, Landpoint p22) +{ + + return p11.ati * (1 - p0.lon) * (1 - p0.lat) + + p12.ati * p0.lon * (1 - p0.lat) + + p21.ati * (1 - p0.lon) * p0.lat + + p22.ati * p0.lon * p0.lat; +} + + + +bool onSegment(Point_3d Pi, Point_3d Pj, Point_3d Q) +{ + if ((Q.x - Pi.x) * (Pj.y - Pi.y) == (Pj.x - Pi.x) * (Q.y - Pi.y) //²æ³Ë + //±£Ö¤Qµã×ø±êÔÚpi,pjÖ®¼ä + && min(Pi.x, Pj.x) <= Q.x && Q.x <= max(Pi.x, Pj.x) + && min(Pi.y, Pj.y) <= Q.y && Q.y <= max(Pi.y, Pj.y)) + return true; + else + return false; +} + +Point_3d invBilinear(Point_3d p, Point_3d a, Point_3d b, Point_3d c, Point_3d d) +{ + Point_3d res; + + Point_3d e = b - a; + Point_3d f = d - a; + Point_3d g = a - b + c - d; + Point_3d h = p - a; + + double k2 = cross2d(g, f); + double k1 = cross2d(e, f) + cross2d(h, g); + double k0 = cross2d(h, e); + double u, v; + // if edges are parallel, this is a linear equation + if (abs(k2) < 0.001) + { + v = -k0 / k1; + u = (h.x - f.x * v) / (e.x + g.x * v); + p.z = a.z + (b.z - a.z) * u + (d.z - a.z) * v + (a.z - b.z + c.z - d.z) * u * v; + return p; + } + // otherwise, it's a quadratic + else + { + float w = k1 * k1 - 4.0 * k0 * k2; + if (w < 0.0) { + // ¿ÉÄÜÔڱ߽çÉÏ + if (onSegment(a, b, p)) { + Point_3d tt = b - a; + Point_3d ttpa = p - a; + double scater = ttpa / tt; + if (scater < 0 || scater>1) { return { -9999,-9999,-9999 }; } + p.z = a.z + scater * tt.z; + return p; + } + else if (onSegment(b, c, p)) { + Point_3d tt = c - b; + Point_3d ttpa = p - b; + double scater = ttpa / tt; + if (scater < 0 || scater>1) { return { -9999,-9999,-9999 }; } + p.z = b.z + scater * tt.z; + return p; + } + else if (onSegment(c, d, p)) { + Point_3d tt = d - c; + Point_3d ttpa = p - c; + double scater = ttpa / tt; + if (scater < 0 || scater>1) { return { -9999,-9999,-9999 }; } + p.z = c.z + scater * tt.z; + return p; + } + else if (onSegment(d, a, p)) { + Point_3d tt = a - d; + Point_3d ttpa = p - d; + double scater = ttpa / tt; + if (scater < 0 || scater>1) { return { -9999,-9999,-9999 }; } + p.z = d.z + scater * tt.z; + return p; + } + + return { -9999,-9999,-9999 }; + } + else { + w = sqrt(w); + + float ik2 = 0.5 / k2; + float v = (-k1 - w) * ik2; + float u = (h.x - f.x * v) / (e.x + g.x * v); + + if (u < 0.0 || u>1.0 || v < 0.0 || v>1.0) + { + v = (-k1 + w) * ik2; + u = (h.x - f.x * v) / (e.x + g.x * v); + } + p.z = a.z + (b.z - a.z) * u + (d.z - a.z) * v + (a.z - b.z + c.z - d.z) * u * v; + return p; + } + } + p.z = a.z + (b.z - a.z) * u + (d.z - a.z) * v + (a.z - b.z + c.z - d.z) * u * v; + return p; +} + +double sind(double degree) +{ + return sin(degree * d2r); +} + +double cosd(double d) +{ + return cos(d * d2r); +} + + +string Convert(float Num) +{ + ostringstream oss; + oss << Num; + string str(oss.str()); + return str; +} + +QString JoinPath(const QString& path, const QString& filename) +{ + QDir dir(path); + + // Ensure the path ends with the appropriate separator + if (!QDir::isAbsolutePath(path)) + dir.makeAbsolute(); + + return dir.filePath(filename); +} +std::vector convertQStringListToStdVector(const QStringList& qStringList) +{ + std::vector stdVector; + + for (const QString& str : qStringList) { + stdVector.push_back(str); + } + + return stdVector; +}; \ No newline at end of file diff --git a/src/LAMPTool/BaseToollib/BaseTool.h b/src/LAMPTool/BaseToollib/BaseTool.h new file mode 100644 index 0000000..4743173 --- /dev/null +++ b/src/LAMPTool/BaseToollib/BaseTool.h @@ -0,0 +1,93 @@ +#pragma once +#pragma once +#ifndef BASETOOL_H +#define BASETOOL_H + +/// +/// »ù±¾Àà¡¢»ù±¾º¯Êý +/// +//#define EIGEN_USE_MKL_ALL +//#define EIGEN_VECTORIZE_SSE4_2 +//#include + +//#include +#include +#include +#include +#include +#include +#include +#include +#include "referenceHeader.h" +#include +#include +#include +#include +#include +#include "GeoOperator.h" +#include +#include + +using namespace std; +using namespace Eigen; + + +///////////////////////////////////// ÔËÐÐʱ¼ä´òÓ¡ ////////////////////////////////////////////////////////// + + +QString getCurrentTimeString(); +QString getCurrentShortTimeString(); + +std::vector splitString(const QString& str, char delimiter); + + + +/////////////////////////////// »ù±¾Í¼ÏñÀà ½áÊø ////////////////////////////////////////////////////////// + +string Convert(float Num); +QString JoinPath(const QString& path, const QString& filename); + +////////////////////////////// ×ø±ê²¿·Ö»ù±¾·½·¨ ////////////////////////////////////////// + + +////////////////////////////// ×ø±ê²¿·Ö»ù±¾·½·¨ ////////////////////////////////////////// + + +////////////////////////////// ²åÖµ //////////////////////////////////////////// + +complex Cubic_Convolution_interpolation(double u, double v, Eigen::MatrixX> img); + +complex Cubic_kernel_weight(double s); + +double Bilinear_interpolation(Landpoint p0, Landpoint p11, Landpoint p21, Landpoint p12, Landpoint p22); + +bool onSegment(Point_3d Pi, Point_3d Pj, Point_3d Q); + +Point_3d invBilinear(Point_3d p, Point_3d a, Point_3d b, Point_3d c, Point_3d d); + + + +// +// WGS84 µ½J2000 ×ø±êϵµÄ±ä»» +// ²Î¿¼ÍøÖ·£ºhttps://blog.csdn.net/hit5067/article/details/116894616 +// ×ÊÁÏÍøÖ·£ºhttp://celestrak.org/spacedata/ +// ²ÎÊýÎļþ£º +// a. Earth Orientation Parameter Îļþ£º http://celestrak.org/spacedata/EOP-Last5Years.csv +// b. Space Weather Data Îļþ£º http://celestrak.org/spacedata/SW-Last5Years.csv +// ±¸×¢£ºÉÏÊöÎļþÊÇ×Ô2017Äê-ÎåÄêÄÚ +/** +ÔÚwgs84 ×ø±êϵתµ½J2000 ×ø±êϵ Ö÷Òª Éæ¼°µ½×ø±êµÄÏ໥ת»»¡£Ò»°ã¸ø¶¨µÄWGS×ø±êΪ ¸ø¶¨Ê±¿ÌµÄ t ,BLH +ת»»²½Ö裺 +step 1: WGS 84 ת»»µ½Ð­Ò鵨Çò×ø±êϵ +step 2: ЭÒ鵨Çò×ø±êϵ ת»»ÎªË²Ê±µØÇò×ø±êϵ +step 3: ˲ʱµØÇò×ø±êϵ ת»»Îª Ë²Ê±ÕæÌìÇò×ø±êϵ +step 4: Ë²Ê±ÕæÌìÇò×ø±êϵ תµ½Ë²Ê±Æ½ÌìÇò ×ø±êϵ +step 5: ˲ʱƽÌìÇò×ø±êϵת»»ÎªÐ­ÒéÌìÇò×ø±êϵ£¨J2000£© +**/ + + +double sind(double degree); + +double cosd(double d); + +#endif \ No newline at end of file diff --git a/src/LAMPTool/BaseToollib/FileOperator.cpp b/src/LAMPTool/BaseToollib/FileOperator.cpp new file mode 100644 index 0000000..7ce44bb --- /dev/null +++ b/src/LAMPTool/BaseToollib/FileOperator.cpp @@ -0,0 +1,188 @@ +#include "FileOperator.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +std::vector getFilelist(const QString& folderpath, const QString& filenameExtension, int (*logfun)(QString logtext, int value)) +{ + QString filenameExtensionStr = filenameExtension; + filenameExtensionStr = filenameExtensionStr.remove(0, 1); + std::vector filenames(0); + if (isExists(folderpath) && isDirectory(folderpath)) { + QDir directory(folderpath); + if (directory.exists() && directory.isReadable()) { + QFileInfoList fileList = directory.entryInfoList(QDir::Files | QDir::NoDotAndDotDot); + for (const QFileInfo& fileInfo : fileList) { + qDebug() << fileInfo.filePath() + "\nExtension: (" + filenameExtensionStr + ", " + fileInfo.suffix() + ")"; + if (filenameExtensionStr == u8"*" || filenameExtensionStr == fileInfo.suffix()) { + filenames.push_back(fileInfo.filePath()); + } + if (logfun) { + logfun(fileInfo.filePath() + "\nExtension: (" + filenameExtensionStr + ", " + fileInfo.suffix() + ")", 4); + } + } + } + else { + qWarning() << "Folder does not exist or is not readable: " << folderpath; + } + return filenames; + } + else { + return std::vector(0); + } + +} + +QString getParantFolderNameFromPath(const QString& path) +{ + QDir directory(path); + directory.cdUp(); + QString parentPath = directory.absolutePath(); + return directory.dirName(); +} + +QString getParantFromPath(const QString& path) +{ + //qDebug() << path; + QDir directory(path); + directory.cdUp(); + QString parentPath = directory.absolutePath(); + //qDebug() << parentPath; + return parentPath; +} + +QString getFileNameFromPath(const QString& path) +{ + QFileInfo fileInfo(path); + return fileInfo.fileName(); +} + +bool isDirectory(const QString& path) +{ + QFileInfo fileinfo(path); + return fileinfo.isDir(); +} + +bool isExists(const QString& path) +{ + QFileInfo fileinfo(path); + return fileinfo.exists(); +} + +bool isFile(const QString& path) +{ + QFileInfo fileinfo(path); + return fileinfo.isFile(); +} + +int write_binfile(char* filepath, char* data, size_t data_len) +{ + FILE* pd = fopen(filepath, "w"); + if (NULL == pd) { + return 2; + } + //Êý¾Ý¿éÊ×µØÖ·: "&a"£¬ÔªËØ´óС: "sizeof(unsigned __int8)"£¬ ÔªËØ¸öÊý: "10"£¬ ÎļþÖ¸Õ룺"pd" + fwrite(data, sizeof(char), data_len, pd); + fclose(pd); + return -1; +} + +char* read_textfile(char* text_path, int* length) +{ + char* data = NULL; + FILE* fp1 = fopen(text_path, "r"); + if (fp1 == NULL) { + return NULL; + } + else {} + // ¶ÁÈ¡Îļþ + fseek(fp1, 0, SEEK_END); + int data_length = ftell(fp1); + data = (char*)malloc((data_length + 1) * sizeof(char)); + rewind(fp1); + if (data_length == fread(data, sizeof(char), data_length, fp1)) { + data[data_length] = '\0'; // Îļþβ + } + else { + free(data); + fclose(fp1); + return NULL; + } + fclose(fp1); + *length = data_length + 1; + return data; +} + +bool exists_test(const QString& name) +{ + return isExists(name); +} + +size_t fsize(FILE* fp) +{ + size_t n; + fpos_t fpos; // µ±Ç°Î»Öà + fgetpos(fp, &fpos); // »ñÈ¡µ±Ç°Î»Öà + fseek(fp, 0, SEEK_END); + n = ftell(fp); + fsetpos(fp, &fpos); // »Ö¸´Ö®Ç°µÄλÖà + return n; +} + + +void removeFile(const QString& filePath) +{ + QFile file(filePath); + + if (file.exists()) { + if (file.remove()) { + qDebug() << "File removed successfully: " << filePath; + } + else { + qWarning() << "Failed to remove file: " << filePath; + } + } + else { + qDebug() << "File does not exist: " << filePath; + } +} + +unsigned long convertToULong(const QString& input) { + bool ok; // Used to check if the conversion was successful + unsigned long result = input.toULong(&ok); + + if (!ok) { + qWarning() << "Conversion to unsigned long failed for input: " << input; + } + + return result; +} + + + +void copyFile(const QString& sourcePath, const QString& destinationPath) { + QFile sourceFile(sourcePath); + QFile destinationFile(destinationPath); + + if (sourceFile.exists()) { + if (sourceFile.copy(destinationPath)) { + // ¸´ÖƳɹ¦ + //QMessageBox::information(nullptr, u8"³É¹¦", u8"Îļþ¸´ÖƳɹ¦"); + } + else { + // ¸´ÖÆÊ§°Ü + QMessageBox::critical(nullptr, u8"´íÎó", u8"Îļþ¸´ÖÆÊ§°Ü"); + } + } + else { + // Ô´Îļþ²»´æÔÚ + QMessageBox::warning(nullptr, u8"¾¯¸æ", u8"Ô´Îļþ²»´æÔÚ"); + } +} \ No newline at end of file diff --git a/src/LAMPTool/BaseToollib/FileOperator.h b/src/LAMPTool/BaseToollib/FileOperator.h new file mode 100644 index 0000000..a823f0f --- /dev/null +++ b/src/LAMPTool/BaseToollib/FileOperator.h @@ -0,0 +1,50 @@ +#pragma once + +#ifndef FILEOPERATOR_H +#define FILEOPERATOR_H + +#include "referenceHeader.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +bool isDirectory(const QString& path); +bool isExists(const QString& path); +bool isFile(const QString& path); +void removeFile(const QString& filePath); +unsigned long convertToULong(const QString& input); +/// +/// »ñÈ¡Îļþ(¾ø¶Ô·¾¶£© +/// +/// +/// +/// +std::vector getFilelist(const QString& folderpath, const QString& FilenameExtension = ".*",int (*logfun)(QString logtext,int value)=nullptr); + +QString getParantFolderNameFromPath(const QString& path); + +QString getFileNameFromPath(const QString& path); + +int write_binfile(char* filepath, char* data, size_t data_len); + +char* read_textfile(char* text_path, int* length); + +bool exists_test(const QString& name); + +size_t fsize(FILE* fp); + +QString getParantFromPath(const QString& path); +void copyFile(const QString& sourcePath, const QString& destinationPath); +// QT FileOperator +#endif \ No newline at end of file diff --git a/src/LAMPTool/BaseToollib/GeoOperator.cpp b/src/LAMPTool/BaseToollib/GeoOperator.cpp new file mode 100644 index 0000000..d515e3a --- /dev/null +++ b/src/LAMPTool/BaseToollib/GeoOperator.cpp @@ -0,0 +1,271 @@ +#include "GeoOperator.h" +#include +#include +#include +#include +//#include +#include +#include +#include < io.h > +#include < stdio.h > +#include < stdlib.h > +#include +#include +#include +//#include +#include //#include "ogrsf_frmts.h" +#include +#include + +using namespace std; +using namespace Eigen; + + +Landpoint operator +(const Landpoint& p1, const Landpoint& p2) +{ + return Landpoint{ p1.lon + p2.lon,p1.lat + p2.lat,p1.ati + p2.ati }; +} + +Landpoint operator -(const Landpoint& p1, const Landpoint& p2) +{ + return Landpoint{ p1.lon - p2.lon,p1.lat - p2.lat,p1.ati - p2.ati }; +} + +bool operator ==(const Landpoint& p1, const Landpoint& p2) +{ + return p1.lat == p2.lat && p1.lon == p2.lon && p1.ati == p2.ati; +} + + + +Landpoint operator *(const Landpoint& p, double scale) +{ + return Landpoint{ + p.lon * scale, + p.lat * scale, + p.ati * scale + }; +} + + +Landpoint LLA2XYZ(const Landpoint& LLA) { + double L = LLA.lon * d2r; + double B = LLA.lat * d2r; + double H = LLA.ati; + + double sinB = sin(B); + double cosB = cos(B); + + //double N = a / sqrt(1 - e * e * sin(B) * sin(B)); + double N = a / sqrt(1 - eSquare * sinB * sinB); + Landpoint result = { 0,0,0 }; + result.lon = (N + H) * cosB * cos(L); + result.lat = (N + H) * cosB * sin(L); + //result.z = (N * (1 - e * e) + H) * sin(B); + result.ati = (N * (1 - 1 / f_inverse) * (1 - 1 / f_inverse) + H) * sinB; + return result; +} + + +Eigen::MatrixXd LLA2XYZ(Eigen::MatrixXd landpoint) +{ + landpoint.col(0) = landpoint.col(0).array() * d2r; // lon + landpoint.col(1) = landpoint.col(1).array() * d2r; // lat + + Eigen::MatrixXd sinB = (landpoint.col(1).array().sin());//lat + Eigen::MatrixXd cosB = (landpoint.col(1).array().cos());//lat + + Eigen::MatrixXd N = a / ((1 - sinB.array().pow(2) * eSquare).array().sqrt()); + Eigen::MatrixXd result(landpoint.rows(), 3); + + result.col(0) = (N.array() + landpoint.col(2).array()) * cosB.array() * Eigen::cos(landpoint.col(0).array()).array(); //x + result.col(1) = (N.array() + landpoint.col(2).array()) * cosB.array() * Eigen::sin(landpoint.col(0).array()).array(); //y + + result.col(2) = (N.array() * (1 - 1 / f_inverse) * (1 - 1 / f_inverse) + landpoint.col(2).array()) * sinB.array(); //z + + return result; +} + + +Landpoint XYZ2LLA(const Landpoint& XYZ) { + double tmpX = XYZ.lon;// + double temY = XYZ.lat;// + double temZ = XYZ.ati; + + double curB = 0; + double N = 0; + double sqrtTempXY = sqrt(tmpX * tmpX + temY * temY); + double calB = atan2(temZ, sqrtTempXY); + int counter = 0; + double sinCurB = 0; + while (abs(curB - calB) * r2d > epsilon && counter < 25) + { + curB = calB; + sinCurB = sin(curB); + N = a / sqrt(1 - eSquare * sinCurB * sinCurB); + calB = atan2(temZ + N * eSquare * sinCurB, sqrtTempXY); + counter++; + } + + Landpoint result = { 0,0,0 }; + result.lon = atan2(temY, tmpX) * r2d; + result.lat = curB * r2d; + result.ati = temZ / sinCurB - N * (1 - eSquare); + return result; +} + + + + +double getAngle(const Landpoint& a, const Landpoint& b) +{ + double c = dot(a, b) / (getlength(a) * getlength(b)); + if (a.lon * b.lat - a.lat * b.lon >= 0) { + return acos(c > 1 ? 1 : c < -1 ? -1 : c) * r2d; + } + else { + return 360 - acos(c > 1 ? 1 : c < -1 ? -1 : c) * r2d; + } +} + +double dot(const Landpoint& p1, const Landpoint& p2) +{ + return p1.lat * p2.lat + p1.lon * p2.lon + p1.ati * p2.ati; +} + +double getlength(const Landpoint& p1) { + + return sqrt(dot(p1, p1)); +} + +Landpoint crossProduct(const Landpoint& a, const Landpoint& b) { + return Landpoint{ + a.lat * b.ati - a.ati * b.lat,//x + a.ati * b.lon - a.lon * b.ati,//y + a.lon * b.lat - a.lat * b.lon//z + }; +} + +float cross2d(Point_3d a, Point_3d b) +{ + return a.x * b.y - a.y * b.x; +} + +Point_3d operator -(Point_3d a, Point_3d b) +{ + return Point_3d{ a.x - b.x, a.y - b.y, a.z - b.z }; +} + +Point_3d operator +(Point_3d a, Point_3d b) +{ + return Point_3d{ a.x + b.x, a.y + b.y, a.z + b.z }; +} + +double operator /(Point_3d a, Point_3d b) +{ + return sqrt(pow(a.x, 2) + pow(a.y, 2)) / sqrt(pow(b.x, 2) + pow(b.y, 2)); +} + + +Landpoint getSlopeVector(const Landpoint& p0, const Landpoint& p1, const Landpoint& p2, const Landpoint& p3, const Landpoint& p4) { + + Landpoint n0 = LLA2XYZ(p0), + n1 = LLA2XYZ(p1), + n2 = LLA2XYZ(p2), + n3 = LLA2XYZ(p3), + n4 = LLA2XYZ(p4); + Landpoint n01 = n1 - n0, n02 = n2 - n0, n03 = n3 - n0, n04 = n4 - n0; + // ��n01�������� + Landpoint np01 = p1 - p0, np02 = p2 - p0, np03 = p3 - p0, np04 = p4 - p0; + double a2 = getAngle(Landpoint{ np01.lon,np01.lat,0 }, Landpoint{ np02.lon,np02.lat,0 });// 01->02 ��ʱ�� + double a3 = getAngle(Landpoint{ np01.lon,np01.lat,0 }, Landpoint{ np03.lon,np03.lat,0 });// 01->03 ��ʱ�� + double a4 = getAngle(Landpoint{ np01.lon,np01.lat,0 }, Landpoint{ np04.lon,np04.lat,0 });// 01->04 ��ʱ�� + //qDebug() << a2 << "\t" << a3 << "\t" << a4 << endl; + a2 = 360 - a2; + a3 = 360 - a3; + a4 = 360 - a4; + Landpoint N, W, S, E; + N = n01; + if (a2 >= a3 && a2 >= a4) { + W = n02; + if (a3 >= a4) { + S = n03; + E = n04; + } + else { + S = n04; + E = n03; + } + } + else if (a3 >= a2 && a3 >= a4) { + W = n03; + if (a2 >= a4) { + S = n02; + E = n04; + } + else { + S = n04; + E = n02; + } + } + else if (a4 >= a2 && a4 >= a3) + { + W = n04; + if (a2 >= a3) { + S = n02; + E = n03; + } + else { + S = n03; + E = n02; + } + } + return (crossProduct(N, W) + crossProduct(W, S) + crossProduct(S, E) + crossProduct(E, N)) * 0.25; +} + + + +double distance(const Vector3D& p1, const Vector3D& p2) +{ + double dx = p1.x - p2.x; + double dy = p1.y - p2.y; + double dz = p1.z - p2.z; + return std::sqrt(dx * dx + dy * dy + dz * dz); +} + +double pointToLineDistance(const Vector3D& point, const Vector3D& linePoint, const Vector3D& lineDirection) +{ + Vector3D pointToLine = { point.x - linePoint.x, point.y - linePoint.y, point.z - linePoint.z }; + + // 计算点到直线的投影点的ä½ç½® + double t = (pointToLine.x * lineDirection.x + pointToLine.y * lineDirection.y + pointToLine.z * lineDirection.z) / + (lineDirection.x * lineDirection.x + lineDirection.y * lineDirection.y + lineDirection.z * lineDirection.z); + + // 计算投影点 + Vector3D projection = { linePoint.x + t * lineDirection.x, linePoint.y + t * lineDirection.y, linePoint.z + t * lineDirection.z }; + + // 计算点到直线的è·ç¦» + return distance(point, projection); +} + +SphericalCoordinates cartesianToSpherical(const CartesianCoordinates& cartesian) +{ + SphericalCoordinates spherical; + + spherical.r = std::sqrt(cartesian.x * cartesian.x + cartesian.y * cartesian.y + cartesian.z * cartesian.z); + spherical.theta = std::acos(cartesian.z / spherical.r); + spherical.phi = std::atan2(cartesian.y, cartesian.x); + + return spherical; +} + +CartesianCoordinates sphericalToCartesian(const SphericalCoordinates& spherical) +{ + CartesianCoordinates cartesian; + + cartesian.x = spherical.r * std::sin(spherical.theta) * std::cos(spherical.phi); + cartesian.y = spherical.r * std::sin(spherical.theta) * std::sin(spherical.phi); + cartesian.z = spherical.r * std::cos(spherical.theta); + + return cartesian; +} \ No newline at end of file diff --git a/src/LAMPTool/BaseToollib/GeoOperator.h b/src/LAMPTool/BaseToollib/GeoOperator.h new file mode 100644 index 0000000..51dd1dd --- /dev/null +++ b/src/LAMPTool/BaseToollib/GeoOperator.h @@ -0,0 +1,111 @@ +#pragma once + + +#ifndef GEOOPERATOR_H +#define GEOOPERATOR_H + +#include "BaseConstVariable.h" +#include +#include +#include +#include +#include +#include +#include + +/// +/// ÈýάÏòÁ¿£¬×ø±ê±í´ï +/// +struct Landpoint // µã SARÓ°ÏñµÄÏñËØ×ø±ê£» +{ + /// + /// ¾­¶Èx + /// + double lon; // ¾­¶Èx lon pixel_col + /// + /// γ¶Èy + /// + double lat; // γ¶Èy lat pixel_row + /// + /// ¸ß¶Èz + /// + double ati; // ¸ß³Ìz ati pixel_time +}; +struct Point_3d { + double x; + double y; + double z; +}; + +/// +/// ½«¾­Î³¶Èת»»ÎªµØ¹Ì²ÎÐÄ×ø±êϵ +/// +/// ¾­Î³¶Èµã--degree +/// Í¶Ó°×ø±êϵµã +Landpoint LLA2XYZ(const Landpoint& LLA); +Eigen::MatrixXd LLA2XYZ(Eigen::MatrixXd landpoint); + +/// +/// ½«µØ¹Ì²ÎÐÄ×ø±êϵת»»Îª¾­Î³¶È +/// +/// ¹Ì²ÎÐÄ×ø±êϵ +/// ¾­Î³¶È--degree +Landpoint XYZ2LLA(const Landpoint& XYZ); + + +Landpoint operator +(const Landpoint& p1, const Landpoint& p2); + +Landpoint operator -(const Landpoint& p1, const Landpoint& p2); + +bool operator ==(const Landpoint& p1, const Landpoint& p2); + +Landpoint operator *(const Landpoint& p, double scale); + +double getAngle(const Landpoint& a, const Landpoint& b); + +double dot(const Landpoint& p1, const Landpoint& p2); + +double getlength(const Landpoint& p1); + +Landpoint crossProduct(const Landpoint& a, const Landpoint& b); + + +Landpoint getSlopeVector(const Landpoint& p0, const Landpoint& p1, const Landpoint& p2, const Landpoint& p3, const Landpoint& p4); + + + +float cross2d(Point_3d a, Point_3d b); + +Point_3d operator -(Point_3d a, Point_3d b); + +Point_3d operator +(Point_3d a, Point_3d b); + +double operator /(Point_3d a, Point_3d b); + + + +// ʸÁ¿¼ÆËã +struct Vector3D { + double x, y, z; +}; + +// ¼ÆËãÁ½µãÖ®¼äµÄ¾àÀë +double distance(const Vector3D& p1, const Vector3D& p2); +// ¼ÆËãµãµ½Ö±ÏßµÄ×î¶Ì¾àÀë +double pointToLineDistance(const Vector3D& point, const Vector3D& linePoint, const Vector3D& lineDirection); + + +struct CartesianCoordinates { + double x, y, z; +}; + +struct SphericalCoordinates { + double r, theta, phi; +}; + +SphericalCoordinates cartesianToSpherical(const CartesianCoordinates& cartesian); + +CartesianCoordinates sphericalToCartesian(const SphericalCoordinates& spherical); + + +#endif \ No newline at end of file diff --git a/src/LAMPTool/BaseToollib/ImageOperatorBase.cpp b/src/LAMPTool/BaseToollib/ImageOperatorBase.cpp new file mode 100644 index 0000000..6ea06d2 --- /dev/null +++ b/src/LAMPTool/BaseToollib/ImageOperatorBase.cpp @@ -0,0 +1,1239 @@ +#include "ImageOperatorBase.h" +#include "GeoOperator.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "FileOperator.h" + +using namespace std; +using namespace Eigen; + +/** +* ÊäÈëÊý¾ÝÊÇENVI¸ñʽÊý¾Ý +*/ + + + + + + +std::shared_ptr OpenDataset(const QString& in_path,GDALAccess rwmode) +{ + GDALAllRegister(); + GDALDataset* dataset_ptr = (GDALDataset*)(GDALOpen(in_path.toUtf8().constData(), rwmode)); + std::shared_ptr rasterDataset(dataset_ptr, CloseDataset); + return rasterDataset; +} + +void CloseDataset(GDALDataset* ptr) +{ + GDALClose(ptr); + ptr = NULL; +} + +int TIFF2ENVI(QString in_tiff_path, QString out_envi_path) +{ + std::shared_ptr ds = OpenDataset(in_tiff_path); + const char* args[] = { "-of", "ENVI", NULL }; + GDALTranslateOptions* psOptions = GDALTranslateOptionsNew((char**)args, NULL); + GDALClose(GDALTranslate(out_envi_path.toUtf8().constData(),ds.get(), psOptions,NULL)); + GDALTranslateOptionsFree(psOptions); + return 0; +} + +int ENVI2TIFF(QString in_envi_path, QString out_tiff_path) +{ + std::shared_ptr ds = OpenDataset(in_envi_path); + const char* args[] = { "-of", "Gtiff", NULL }; + GDALTranslateOptions* psOptions = GDALTranslateOptionsNew((char**)args, NULL); + GDALClose(GDALTranslate(out_tiff_path.toUtf8().constData(), ds.get(), psOptions, NULL)); + GDALTranslateOptionsFree(psOptions); + return 0; +} + +int CreateDataset(QString new_file_path,int height, int width, int band_num,double* gt, QString projection, GDALDataType gdal_dtype ,bool need_gt) +{ + GDALAllRegister(); + GDALDriver* poDriver = GetGDALDriverManager()->GetDriverByName("ENVI"); + std::shared_ptr< GDALDataset> poDstDS(poDriver->Create(new_file_path.toUtf8().constData(), width, height, band_num, gdal_dtype, NULL)); + if (need_gt) + { + poDstDS->SetProjection(projection.toUtf8().constData()); + poDstDS->SetGeoTransform(gt); + } + else {} + GDALFlushCache((GDALDatasetH)poDstDS.get()); + return 0; +} + +int saveDataset(QString new_file_path, int start_line,int start_cols ,int band_ids, int datacols,int datarows,void* databuffer) +{ + GDALAllRegister(); + std::shared_ptr poDstDS = OpenDataset(new_file_path,GA_Update); + GDALDataType gdal_datatype = poDstDS->GetRasterBand(1)->GetRasterDataType(); + poDstDS->GetRasterBand(band_ids)->RasterIO(GF_Write, start_cols, start_line, datacols, datarows, databuffer, datacols, datarows, gdal_datatype, 0, 0); + GDALFlushCache(poDstDS.get()); + return 0; +} + +int block_num_pre_memory(int block_width, int height, GDALDataType gdal_datatype,double memey_size) +{ + // ¼ÆËã´óС + int size_meta = 0; + + if (gdal_datatype == GDT_Byte) { + size_meta = 1; + } + else if (gdal_datatype == GDT_UInt16) { + size_meta = 2; // Ö»ÓÐ˫ͨµÀ²ÅÄܹ¹½¨ ¸´Êý¾ØÕó + } + else if (gdal_datatype == GDT_UInt16) { + size_meta = 2; + } + else if (gdal_datatype == GDT_Int16) { + size_meta = 2; + } + else if (gdal_datatype == GDT_UInt32) { + size_meta = 4; + } + else if (gdal_datatype == GDT_Int32) { + size_meta = 4; + } + //else if (gdal_datatype == GDT_UInt64) { + // size_meta = 8; + //} + //else if (gdal_datatype == GDT_Int64) { + // size_meta = 8; + //} + else if (gdal_datatype == GDT_Float32) { + size_meta = 4; + } + else if (gdal_datatype == GDT_Float64) { + size_meta = 4; + } + else if (gdal_datatype == GDT_CInt16) { size_meta = 2; } + else if (gdal_datatype == GDT_CInt32) { size_meta = 2; } + else if (gdal_datatype == GDT_CFloat32) { size_meta = 4; } + else if (gdal_datatype == GDT_CFloat64) { size_meta = 8; } + else {} + int block_num = int(memey_size / (size_meta * block_width)); + block_num = block_num > height ? height : block_num; // ÐÐÊý + block_num = block_num < 1 ? 1 : block_num; + return block_num; +} + +Eigen::Matrix ReadComplexMatrixData(int start_line, int width, int line_num, std::shared_ptr rasterDataset, GDALDataType gdal_datatype) +{ + + int band_num = rasterDataset->GetRasterCount(); + if (gdal_datatype == 0) { + return Eigen::Matrix (0, 0); + } + else if (gdal_datatype < 8) { + if (band_num != 2) { + return Eigen::Matrix(0, 0); + } + } + else if (gdal_datatype < 12) { + if (band_num != 1) { + return Eigen::Matrix(0, 0); + } + + } + else {} + bool _flag = false; + Eigen::Matrix data_mat(line_num * width, 2);// ±ØÐëÇ¿ÖÆÐÐÓÅÏÈ + if (gdal_datatype == GDT_Byte) { + Eigen::MatrixX real_mat(line_num * width, 1); + Eigen::MatrixX imag_mat(line_num * width, 1); + rasterDataset->GetRasterBand(1)->RasterIO(GF_Read, 0, start_line, width, line_num, real_mat.data(), width, line_num, gdal_datatype, 0, 0); // real + rasterDataset->GetRasterBand(2)->RasterIO(GF_Read, 0, start_line, width, line_num, imag_mat.data(), width, line_num, gdal_datatype, 0, 0); // imag + data_mat.col(0) = (real_mat.array().cast()).array(); + data_mat.col(1) = (imag_mat.array().cast()).array(); + _flag = true; + } + else if (gdal_datatype == GDT_UInt16) { + Eigen::MatrixX real_mat(line_num * width, 1); + Eigen::MatrixX imag_mat(line_num * width, 1); + rasterDataset->GetRasterBand(1)->RasterIO(GF_Read, 0, start_line, width, line_num, real_mat.data(), width, line_num, gdal_datatype, 0, 0); // real + rasterDataset->GetRasterBand(2)->RasterIO(GF_Read, 0, start_line, width, line_num, imag_mat.data(), width, line_num, gdal_datatype, 0, 0); // imag + data_mat.col(0) = (real_mat.array().cast()).array(); + data_mat.col(1) = (imag_mat.array().cast()).array(); + _flag = true; + } + else if (gdal_datatype == GDT_Int16) { + Eigen::MatrixX real_mat(line_num * width, 1); + Eigen::MatrixX imag_mat(line_num * width, 1); + rasterDataset->GetRasterBand(1)->RasterIO(GF_Read, 0, start_line, width, line_num, real_mat.data(), width, line_num, gdal_datatype, 0, 0); // real + rasterDataset->GetRasterBand(2)->RasterIO(GF_Read, 0, start_line, width, line_num, imag_mat.data(), width, line_num, gdal_datatype, 0, 0); // imag + data_mat.col(0) = (real_mat.array().cast()).array(); + data_mat.col(1) = (imag_mat.array().cast()).array(); + _flag = true; + } + else if (gdal_datatype == GDT_UInt32) { + Eigen::MatrixX real_mat(line_num * width, 1); + Eigen::MatrixX imag_mat(line_num * width, 1); + rasterDataset->GetRasterBand(1)->RasterIO(GF_Read, 0, start_line, width, line_num, real_mat.data(), width, line_num, gdal_datatype, 0, 0); // real + rasterDataset->GetRasterBand(2)->RasterIO(GF_Read, 0, start_line, width, line_num, imag_mat.data(), width, line_num, gdal_datatype, 0, 0); // imag + data_mat.col(0) = (real_mat.array().cast()).array(); + data_mat.col(1) = (imag_mat.array().cast()).array(); + _flag = true; + } + else if (gdal_datatype == GDT_Int32) { + Eigen::MatrixX real_mat(line_num * width, 1); + Eigen::MatrixX imag_mat(line_num * width, 1); + rasterDataset->GetRasterBand(1)->RasterIO(GF_Read, 0, start_line, width, line_num, real_mat.data(), width, line_num, gdal_datatype, 0, 0); // real + rasterDataset->GetRasterBand(2)->RasterIO(GF_Read, 0, start_line, width, line_num, imag_mat.data(), width, line_num, gdal_datatype, 0, 0); // imag + data_mat.col(0) = (real_mat.array().cast()).array(); + data_mat.col(1) = (imag_mat.array().cast()).array(); + _flag = true; + } + //else if (gdal_datatype == GDT_UInt64) { + // Eigen::MatrixX real_mat(line_num * width, 1); + // Eigen::MatrixX imag_mat(line_num * width, 1); + // rasterDataset->GetRasterBand(1)->RasterIO(GF_Read, 0, start_line, width, line_num, real_mat.data(), width, line_num, gdal_datatype, 0, 0); // real + // rasterDataset->GetRasterBand(2)->RasterIO(GF_Read, 0, start_line, width, line_num, imag_mat.data(), width, line_num, gdal_datatype, 0, 0); // imag + // data_mat.col(0) = (real_mat.array().cast()).array(); + // data_mat.col(1) = (imag_mat.array().cast()).array(); + // _flag = true; + //} + //else if (gdal_datatype == GDT_Int64) { + // Eigen::MatrixX real_mat(line_num * width, 1); + // Eigen::MatrixX imag_mat(line_num * width, 1); + // rasterDataset->GetRasterBand(1)->RasterIO(GF_Read, 0, start_line, width, line_num, real_mat.data(), width, line_num, gdal_datatype, 0, 0); // real + // rasterDataset->GetRasterBand(2)->RasterIO(GF_Read, 0, start_line, width, line_num, imag_mat.data(), width, line_num, gdal_datatype, 0, 0); // imag + // data_mat.col(0) = (real_mat.array().cast()).array(); + // data_mat.col(1) = (imag_mat.array().cast()).array(); + // _flag = true; + //} + else if (gdal_datatype == GDT_Float32) { + Eigen::MatrixX real_mat(line_num * width, 1); + Eigen::MatrixX imag_mat(line_num * width, 1); + rasterDataset->GetRasterBand(1)->RasterIO(GF_Read, 0, start_line, width, line_num, real_mat.data(), width, line_num, gdal_datatype, 0, 0); // real + rasterDataset->GetRasterBand(2)->RasterIO(GF_Read, 0, start_line, width, line_num, imag_mat.data(), width, line_num, gdal_datatype, 0, 0); // imag + data_mat.col(0) = (real_mat.array().cast()).array(); + data_mat.col(1) = (imag_mat.array().cast()).array(); + _flag = true; + } + else if (gdal_datatype == GDT_Float64) { + Eigen::MatrixX real_mat(line_num * width, 1); + Eigen::MatrixX imag_mat(line_num * width, 1); + rasterDataset->GetRasterBand(1)->RasterIO(GF_Read, 0, start_line, width, line_num, real_mat.data(), width, line_num, gdal_datatype, 0, 0); // real + rasterDataset->GetRasterBand(2)->RasterIO(GF_Read, 0, start_line, width, line_num, imag_mat.data(), width, line_num, gdal_datatype, 0, 0); // imag + data_mat.col(0) = (real_mat.array().cast()).array(); + data_mat.col(1) = (imag_mat.array().cast()).array(); + _flag = true; + } + else if (gdal_datatype == GDT_CInt16) { + Eigen::MatrixX> complex_short_mat(line_num * width, 1); + rasterDataset->GetRasterBand(1)->RasterIO(GF_Read, 0, start_line, width, line_num, complex_short_mat.data(), width, line_num, gdal_datatype, 0, 0); // real + data_mat.col(0) = (complex_short_mat.real().array().cast()).array(); + data_mat.col(1) = (complex_short_mat.imag().array().cast()).array(); + _flag = true; + } + else if (gdal_datatype == GDT_CInt32) { + Eigen::MatrixX> complex_short_mat(line_num * width, 1); + rasterDataset->GetRasterBand(1)->RasterIO(GF_Read, 0, start_line, width, line_num, complex_short_mat.data(), width, line_num, gdal_datatype, 0, 0); // real + data_mat.col(0) = (complex_short_mat.real().array().cast()).array(); + data_mat.col(1) = (complex_short_mat.imag().array().cast()).array(); + _flag = true; + } + else if (gdal_datatype == GDT_CFloat32) { + Eigen::MatrixX> complex_short_mat(line_num * width, 1); + rasterDataset->GetRasterBand(1)->RasterIO(GF_Read, 0, start_line, width, line_num, complex_short_mat.data(), width, line_num, gdal_datatype, 0, 0); // real + data_mat.col(0) = (complex_short_mat.real().array().cast()).array(); + data_mat.col(1) = (complex_short_mat.imag().array().cast()).array(); + _flag = true; + } + else if (gdal_datatype == GDT_CFloat64) { + Eigen::MatrixX> complex_short_mat(line_num * width, 1); + rasterDataset->GetRasterBand(1)->RasterIO(GF_Read, 0, start_line, width, line_num, complex_short_mat.data(), width, line_num, gdal_datatype, 0, 0); // real + data_mat.col(0) = (complex_short_mat.real().array().cast()).array(); + data_mat.col(1) = (complex_short_mat.imag().array().cast()).array(); + _flag = true; + } + else {} + // ±£´æÊý¾Ý + + + if (_flag) { + return data_mat; + } + else { + return Eigen::Matrix(0, 0);// ±ØÐëÇ¿ÖÆÐÐÓÅÏÈ; + } +} + +Eigen::Matrix ReadMatrixDoubleData(int start_line, int width, int line_num, std::shared_ptr rasterDataset, GDALDataType gdal_datatype, int band_idx) +{ + // ¹¹½¨¾ØÕó¿é£¬Ê¹ÓÃeigen ½øÐоØÕó¼ÆË㣬¼ÓËÙ¼ÆËã + bool _flag = false; + Eigen::Matrix data_mat(line_num * width, 1);// ±ØÐëÇ¿ÖÆÐÐÓÅÏÈ + if (gdal_datatype == GDT_Byte) { + Eigen::MatrixX real_mat(line_num * width, 1); + rasterDataset->GetRasterBand(band_idx)->RasterIO(GF_Read, 0, start_line, width, line_num, real_mat.data(), width, line_num, gdal_datatype, 0, 0); // real + data_mat.col(0) = ((real_mat.array().cast()).array().pow(2)).log10() * 10.0; + _flag = true; + } + else if (gdal_datatype == GDT_UInt16) { + Eigen::MatrixX real_mat(line_num * width, 1); + rasterDataset->GetRasterBand(band_idx)->RasterIO(GF_Read, 0, start_line, width, line_num, real_mat.data(), width, line_num, gdal_datatype, 0, 0); // real + data_mat.col(0) = ((real_mat.array().cast()).array().pow(2)).log10() * 10.0; + _flag = true; + } + else if (gdal_datatype == GDT_Int16) { + Eigen::MatrixX real_mat(line_num * width, 1); + rasterDataset->GetRasterBand(band_idx)->RasterIO(GF_Read, 0, start_line, width, line_num, real_mat.data(), width, line_num, gdal_datatype, 0, 0); // real + data_mat.col(0) = ((real_mat.array().cast()).array().pow(2)).log10() * 10.0; + _flag = true; + } + else if (gdal_datatype == GDT_UInt32) { + Eigen::MatrixX real_mat(line_num * width, 1); + rasterDataset->GetRasterBand(band_idx)->RasterIO(GF_Read, 0, start_line, width, line_num, real_mat.data(), width, line_num, gdal_datatype, 0, 0); // real + data_mat.col(0) = ((real_mat.array().cast()).array().pow(2)).log10() * 10.0; + _flag = true; + } + else if (gdal_datatype == GDT_Int32) { + Eigen::MatrixX real_mat(line_num * width, 1); + rasterDataset->GetRasterBand(band_idx)->RasterIO(GF_Read, 0, start_line, width, line_num, real_mat.data(), width, line_num, gdal_datatype, 0, 0); // real + data_mat.col(0) = ((real_mat.array().cast()).array().pow(2)).log10() * 10.0; + _flag = true; + } + //else if (gdal_datatype == GDT_UInt64) { + // Eigen::MatrixX real_mat(line_num * width, 1); + // rasterDataset->GetRasterBand(band_idx)->RasterIO(GF_Read, 0, start_line, width, line_num, real_mat.data(), width, line_num, gdal_datatype, 0, 0); // real + // data_mat.col(0) = ((real_mat.array().cast()).array().pow(2)).log10() * 10.0; + // _flag = true; + //} + //else if (gdal_datatype == GDT_Int64) { + // Eigen::MatrixX real_mat(line_num * width, 1); + // rasterDataset->GetRasterBand(band_idx)->RasterIO(GF_Read, 0, start_line, width, line_num, real_mat.data(), width, line_num, gdal_datatype, 0, 0); // real + // data_mat.col(0) = ((real_mat.array().cast()).array().pow(2)).log10() * 10.0; + // _flag = true; + //} + else if (gdal_datatype == GDT_Float32) { + Eigen::MatrixX real_mat(line_num * width, 1); + rasterDataset->GetRasterBand(band_idx)->RasterIO(GF_Read, 0, start_line, width, line_num, real_mat.data(), width, line_num, gdal_datatype, 0, 0); // real + data_mat.col(0) = ((real_mat.array().cast()).array().pow(2)).log10() * 10.0; + _flag = true; + } + else if (gdal_datatype == GDT_Float64) { + Eigen::MatrixX real_mat(line_num * width, 1); + rasterDataset->GetRasterBand(band_idx)->RasterIO(GF_Read, 0, start_line, width, line_num, real_mat.data(), width, line_num, gdal_datatype, 0, 0); // real + data_mat.col(0) = ((real_mat.array().cast()).array().pow(2)).log10() * 10.0; + _flag = true; + } + else {} + + + return data_mat; +} + +Eigen::MatrixXd getGeoTranslationArray(QString in_path) +{ + + + + return Eigen::MatrixXd(); +} + +ImageGEOINFO getImageINFO(QString in_path) +{ + std::shared_ptr df = OpenDataset(in_path); + int width = df->GetRasterXSize(); + int heigh = df->GetRasterYSize(); + int band_num = df->GetRasterCount(); + ImageGEOINFO result; + result.width = width; + result.height = heigh; + result.bandnum = band_num; + + return result; +} + +GDALDataType getGDALDataType(QString fileptah) +{ + omp_lock_t lock; + omp_init_lock(&lock); + omp_set_lock(&lock); + GDALAllRegister(); + + GDALDataset* rasterDataset = (GDALDataset*)(GDALOpen(fileptah.toUtf8().constData(), GA_ReadOnly));//��ֻ½ï¿½Ê½ï¿½ï¿½È¡½ï¿½Ó°ï¿½ï¿½ + + GDALDataType gdal_datatype = rasterDataset->GetRasterBand(1)->GetRasterDataType(); + + GDALClose((GDALDatasetH)rasterDataset); + omp_unset_lock(&lock); //�ͷŻ�½ï¿½ + omp_destroy_lock(&lock); //½Ù»ï¿½½ï¿½ + + return gdal_datatype; +} + + +gdalImage::gdalImage() +{ + this->height = 0; + this->width = 0; + this->data_band_ids = 1; + this->start_row = 0; + this->start_col = 0; +} + +/// +/// ½ï¿½Í¼½È¡Ó°ï¿½ï¿?1ï¿?7 +/// +/// +gdalImage::gdalImage(const QString& raster_path) +{ + omp_lock_t lock; + omp_init_lock(&lock); // ��ʼ½ï¿½½ï¿½ + omp_set_lock(&lock); //��û½ï¿½ï¿?1ï¿?7 + this->img_path = raster_path; + + GDALAllRegister();// ×¢½Ê½ï¿½½ï¿½ï¿?1ï¿?7 + // ��DEMӰ�� + GDALDataset* rasterDataset = (GDALDataset*)(GDALOpen(raster_path.toUtf8().constData(), GA_ReadOnly));//��ֻ½ï¿½Ê½ï¿½ï¿½È¡½ï¿½Ó°ï¿½ï¿½ + this->width = rasterDataset->GetRasterXSize(); + this->height = rasterDataset->GetRasterYSize(); + this->band_num = rasterDataset->GetRasterCount(); + + double* gt = new double[6]; + // ��÷½ï¿½ï¿½ï¿½ + rasterDataset->GetGeoTransform(gt); + this->gt = Eigen::MatrixXd(2, 3); + this->gt << gt[0], gt[1], gt[2], gt[3], gt[4], gt[5]; + + this->projection = rasterDataset->GetProjectionRef(); + // ½ï¿½½ï¿½ + //double* inv_gt = new double[6];; + //GDALInvGeoTransform(gt, inv_gt); // ½ï¿½½ï¿½ + // ½ï¿½Í¶Ó° + GDALFlushCache((GDALDatasetH)rasterDataset); + GDALClose((GDALDatasetH)rasterDataset); + rasterDataset = NULL;// Ö¸½Ã¿ï¿½ + this->InitInv_gt(); + delete[] gt; + ////GDALDestroy(); // or, DllMain at DLL_PROCESS_DETACH + omp_unset_lock(&lock); //�ͷŻ�½ï¿½ + omp_destroy_lock(&lock); //½Ù»ï¿½½ï¿½ +} + +gdalImage::~gdalImage() +{ +} + +void gdalImage::setHeight(int height) +{ + this->height = height; +} + +void gdalImage::setWidth(int width) +{ + this->width = width; +} + +void gdalImage::setTranslationMatrix(Eigen::MatrixXd gt) +{ + this->gt = gt; +} + +void gdalImage::setData(Eigen::MatrixXd, int data_band_ids) +{ + this->data = data; + this->data_band_ids = data_band_ids; +} + + + +Eigen::MatrixXd gdalImage::getData(int start_row, int start_col, int rows_count, int cols_count, int band_ids = 1) +{ + omp_lock_t lock; + omp_init_lock(&lock); + omp_set_lock(&lock); + GDALAllRegister(); + + GDALDataset* rasterDataset = (GDALDataset*)(GDALOpen(this->img_path.toUtf8().constData(), GA_ReadOnly));//��ֻ½ï¿½Ê½ï¿½ï¿½È¡½ï¿½Ó°ï¿½ï¿½ + + GDALDataType gdal_datatype = rasterDataset->GetRasterBand(1)->GetRasterDataType(); + GDALRasterBand* demBand = rasterDataset->GetRasterBand(band_ids); + + rows_count = start_row + rows_count <= this->height ? rows_count : this->height - start_row; + cols_count = start_col + cols_count <= this->width ? cols_count : this->width - start_col; + + MatrixXd datamatrix(rows_count, cols_count); + + + if (gdal_datatype == GDT_Byte) { + char* temp = new char[rows_count * cols_count]; + demBand->RasterIO(GF_Read, start_col, start_row, cols_count, rows_count, temp, cols_count, rows_count, gdal_datatype, 0, 0); + for (int i = 0; i < rows_count; i++) { + for (int j = 0; j < cols_count; j++) { + datamatrix(i, j) = temp[i * cols_count + j]; + } + } + delete[] temp; + } + else if (gdal_datatype == GDT_UInt16) { + unsigned short* temp = new unsigned short[rows_count * cols_count]; + demBand->RasterIO(GF_Read, start_col, start_row, cols_count, rows_count, temp, cols_count, rows_count, gdal_datatype, 0, 0); + for (int i = 0; i < rows_count; i++) { + for (int j = 0; j < cols_count; j++) { + datamatrix(i, j) = temp[i * cols_count + j]; + } + } + delete[] temp; + } + else if (gdal_datatype == GDT_Int16) { + short* temp = new short[rows_count * cols_count]; + demBand->RasterIO(GF_Read, start_col, start_row, cols_count, rows_count, temp, cols_count, rows_count, gdal_datatype, 0, 0); + for (int i = 0; i < rows_count; i++) { + for (int j = 0; j < cols_count; j++) { + datamatrix(i, j) = temp[i * cols_count + j]; + } + } + delete[] temp; + } + else if (gdal_datatype == GDT_UInt32) { + unsigned int* temp = new unsigned int[rows_count * cols_count]; + demBand->RasterIO(GF_Read, start_col, start_row, cols_count, rows_count, temp, cols_count, rows_count, gdal_datatype, 0, 0); + for (int i = 0; i < rows_count; i++) { + for (int j = 0; j < cols_count; j++) { + datamatrix(i, j) = temp[i * cols_count + j]; + } + } + delete[] temp; + } + else if (gdal_datatype == GDT_Int32) { + int* temp = new int[rows_count * cols_count]; + demBand->RasterIO(GF_Read, start_col, start_row, cols_count, rows_count, temp, cols_count, rows_count, gdal_datatype, 0, 0); + for (int i = 0; i < rows_count; i++) { + for (int j = 0; j < cols_count; j++) { + datamatrix(i, j) = temp[i * cols_count + j]; + } + } + delete[] temp; + } + //else if (gdal_datatype == GDT_UInt64) { + // unsigned long* temp = new unsigned long[rows_count * cols_count]; + // demBand->RasterIO(GF_Read, start_col, start_row, cols_count, rows_count, temp, cols_count, rows_count, gdal_datatype, 0, 0); + // for (int i = 0; i < rows_count; i++) { + // for (int j = 0; j < cols_count; j++) { + // datamatrix(i, j) = temp[i * cols_count + j]; + // } + // } + // delete[] temp; + //} + //else if (gdal_datatype == GDT_Int64) { + // long* temp = new long[rows_count * cols_count]; + // demBand->RasterIO(GF_Read, start_col, start_row, cols_count, rows_count, temp, cols_count, rows_count, gdal_datatype, 0, 0); + // for (int i = 0; i < rows_count; i++) { + // for (int j = 0; j < cols_count; j++) { + // datamatrix(i, j) = temp[i * cols_count + j]; + // } + // } + // delete[] temp; + //} + else if (gdal_datatype == GDT_Float32) { + float* temp = new float[rows_count * cols_count]; + demBand->RasterIO(GF_Read, start_col, start_row, cols_count, rows_count, temp, cols_count, rows_count, gdal_datatype, 0, 0); + + for (int i = 0; i < rows_count; i++) { + for (int j = 0; j < cols_count; j++) { + datamatrix(i, j) = temp[i * cols_count + j]; + } + } + delete[] temp; + } + else if (gdal_datatype == GDT_Float64) { + double* temp = new double[rows_count * cols_count]; + demBand->RasterIO(GF_Read, start_col, start_row, cols_count, rows_count, temp, cols_count, rows_count, gdal_datatype, 0, 0); + + for (int i = 0; i < rows_count; i++) { + for (int j = 0; j < cols_count; j++) { + datamatrix(i, j) = temp[i * cols_count + j]; + } + } + delete[] temp; + } + else {} + GDALClose((GDALDatasetH)rasterDataset); + omp_unset_lock(&lock); //�ͷŻ�½ï¿½ + omp_destroy_lock(&lock); //½Ù»ï¿½½ï¿½ + //GDALDestroy(); // or, DllMain at DLL_PROCESS_DETACH + return datamatrix; + +} + +Eigen::MatrixXd gdalImage::getGeoTranslation() +{ + return this->gt; +} + +GDALDataType gdalImage::getDataType() +{ + GDALDataset* rasterDataset = (GDALDataset*)(GDALOpen(this->img_path.toUtf8().constData(), GA_ReadOnly)); + GDALDataType gdal_datatype = rasterDataset->GetRasterBand(1)->GetRasterDataType(); + return gdal_datatype; +} + +/// +/// д��ң��Ӱ�� +/// +/// +/// +/// +/// +void gdalImage::saveImage(Eigen::MatrixXd data, int start_row = 0, int start_col = 0, int band_ids = 1) +{ + omp_lock_t lock; + omp_init_lock(&lock); + omp_set_lock(&lock); + if (start_row + data.rows() > this->height || start_col + data.cols() > this->width) { + QString tip = u8"file path: " + this->img_path; + qDebug() << tip; + throw exception(tip.toUtf8().constData()); + } + GDALAllRegister(); + GDALDriver* poDriver = GetGDALDriverManager()->GetDriverByName("GTiff"); + GDALDataset* poDstDS = nullptr; + if (exists_test(this->img_path)) { + poDstDS = (GDALDataset*)(GDALOpen(this->img_path.toUtf8().constData(), GA_Update)); + } + else { + poDstDS = poDriver->Create(this->img_path.toUtf8().constData(), this->width, this->height, this->band_num, GDT_Float32, NULL); // ½ï¿½ï¿½ï¿½ + poDstDS->SetProjection(this->projection.toUtf8().constData()); + + + double gt_ptr[6]; + for (int i = 0; i < this->gt.rows(); i++) { + for (int j = 0; j < this->gt.cols(); j++) { + gt_ptr[i * 3 + j] = this->gt(i, j); + } + } + poDstDS->SetGeoTransform(gt_ptr); + delete[] gt_ptr; + } + + int datarows = data.rows(); + int datacols = data.cols(); + + float* databuffer = new float[datarows * datacols];// (float*)malloc(datarows * datacols * sizeof(float)); + + for (int i = 0; i < datarows; i++) { + for (int j = 0; j < datacols; j++) { + float temp = float(data(i, j)); + databuffer[i * datacols + j] = temp; + } + } + //poDstDS->RasterIO(GF_Write,start_col, start_row, datacols, datarows, databuffer, datacols, datarows, GDT_Float32,band_ids, num,0,0,0); + poDstDS->GetRasterBand(band_ids)->RasterIO(GF_Write, start_col, start_row, datacols, datarows, databuffer, datacols, datarows, GDT_Float32, 0, 0); + + GDALFlushCache(poDstDS); + GDALClose((GDALDatasetH)poDstDS); + //GDALDestroy(); // or, DllMain at DLL_PROCESS_DETACH + delete[] databuffer; + omp_unset_lock(&lock); //�ͷŻ�½ï¿½ + omp_destroy_lock(&lock); //½Ù»ï¿½½ï¿½ +} + +void gdalImage::saveImage() +{ + this->saveImage(this->data, this->start_row, this->start_col, this->data_band_ids); +} + +void gdalImage::setNoDataValue(double nodatavalue = -9999, int band_ids = 1) +{ + GDALAllRegister();// ×¢½Ê½ï¿½½ï¿½ï¿?1ï¿?7 + //GDALDriver* poDriver = GetGDALDriverManager()->GetDriverByName("GTiff"); + GDALDataset* poDstDS = (GDALDataset*)(GDALOpen(img_path.toUtf8().constData(), GA_Update)); + poDstDS->GetRasterBand(band_ids)->SetNoDataValue(nodatavalue); + GDALFlushCache((GDALDatasetH)poDstDS); + GDALClose((GDALDatasetH)poDstDS); +} + +int gdalImage::InitInv_gt() +{ + //1 lon lat = x + //1 lon lat = y + Eigen::MatrixXd temp=Eigen::MatrixXd::Zero(2, 3); + this->inv_gt = temp; + double a = this->gt(0, 0); + double b = this->gt(0, 1); + double c = this->gt(0, 2); + double d = this->gt(1, 0); + double e = this->gt(1, 1); + double f = this->gt(1, 2); + double g = 1; + double det_gt = b * f - c * e; + if (det_gt == 0) { + return 0; + } + this->inv_gt(0, 0) = (c * d - a * f) / det_gt; //2 + this->inv_gt(0, 1) = f / det_gt; // lon + this->inv_gt(0, 2) = -c / det_gt; // lat + this->inv_gt(1, 0) = (a * e - b * d) / det_gt; //1 + this->inv_gt(1, 1) = -e / det_gt; // lon + this->inv_gt(1, 2) = b / det_gt; // lat + return 1; +} + +Landpoint gdalImage::getRow_Col(double lon, double lat) +{ + Landpoint p{ 0,0,0 }; + p.lon = this->inv_gt(0, 0) + lon * this->inv_gt(0, 1) + lat * this->inv_gt(0, 2); //x + p.lat = this->inv_gt(1, 0) + lon * this->inv_gt(1, 1) + lat * this->inv_gt(1, 2); //y + return p; +} + +Landpoint gdalImage::getLandPoint(double row, double col, double ati = 0) +{ + Landpoint p{ 0,0,0 }; + p.lon = this->gt(0, 0) + col * this->gt(0, 1) + row * this->gt(0, 2); //x + p.lat = this->gt(1, 0) + col * this->gt(1, 1) + row * this->gt(1, 2); //y + p.ati = ati; + return p; +} + +double gdalImage::mean(int bandids) +{ + double mean_value = 0; + double count = this->height * this->width; + int line_invert = 100; + int start_ids = 0; + do { + Eigen::MatrixXd sar_a = this->getData(start_ids, 0, line_invert, this->width, bandids); + mean_value = mean_value + sar_a.sum() / count; + start_ids = start_ids + line_invert; + } while (start_ids < this->height); + return mean_value; +} + +double gdalImage::max(int bandids) +{ + double max_value = 0; + bool state_max = true; + int line_invert = 100; + int start_ids = 0; + double temp_max = 0; + do { + Eigen::MatrixXd sar_a = this->getData(start_ids, 0, line_invert, this->width, bandids); + if (state_max) { + state_max = false; + max_value = sar_a.maxCoeff(); + } + else { + temp_max = sar_a.maxCoeff(); + if (max_value < temp_max) { + max_value = temp_max; + } + } + start_ids = start_ids + line_invert; + } while (start_ids < this->height); + return max_value; +} + +double gdalImage::min(int bandids) +{ + double min_value = 0; + bool state_min = true; + int line_invert = 100; + int start_ids = 0; + double temp_min = 0; + do { + Eigen::MatrixXd sar_a = this->getData(start_ids, 0, line_invert, this->width, bandids); + if (state_min) { + state_min = false; + min_value = sar_a.minCoeff(); + } + else { + temp_min = sar_a.minCoeff(); + if (min_value < temp_min) { + min_value = temp_min; + } + } + start_ids = start_ids + line_invert; + } while (start_ids < this->height); + return min_value; +} + +GDALRPCInfo gdalImage::getRPC() +{ + CPLSetConfigOption("GDAL_FILENAME_IS_UTF8", "NO"); + CPLSetConfigOption("GDAL_DATA", "./data"); + GDALAllRegister();//×¢½ï¿½ï¿½ï¿½ + //½ï¿½ï¿½ï¿½ + GDALDataset* pDS = (GDALDataset*)GDALOpen(this->img_path.toUtf8().constData(), GA_ReadOnly); + //��Ԫ½ï¿½ï¿½Ð»ï¿½È¡RPC��Ϣ + char** papszRPC = pDS->GetMetadata("RPC"); + + //½ï¿½È¡ï¿½ï¿½RPC��Ϣ½ï¿½É½á¹¹ï¿½ï¿?1ï¿?7 + GDALRPCInfo oInfo; + GDALExtractRPCInfo(papszRPC, &oInfo); + + GDALClose((GDALDatasetH)pDS); + + return oInfo; +} + +Eigen::MatrixXd gdalImage::getLandPoint(Eigen::MatrixXd points) +{ + if (points.cols() != 3) { + throw new exception("the size of points is equit 3!!!"); + } + + Eigen::MatrixXd result(points.rows(), 3); + result.col(2) = points.col(2);// �߳� + points.col(2) = points.col(2).array() * 0 + 1; + points.col(0).swap(points.col(2));// ½ï¿½ + Eigen::MatrixXd gts(3, 2); + gts.col(0) = this->gt.row(0); + gts.col(1) = this->gt.row(1); + + result.block(0, 0, points.rows(), 2) = points * gts; + return result; +} + +Eigen::MatrixXd gdalImage::getHist(int bandids) +{ + GDALAllRegister();// ×¢½Ê½ï¿½½ï¿½ï¿?1ï¿?7 + // ��DEMӰ�� + GDALDataset* rasterDataset = (GDALDataset*)(GDALOpen(this->img_path.toUtf8().constData(), GA_ReadOnly));//��ֻ½ï¿½Ê½ï¿½ï¿½È¡½ï¿½Ó°ï¿½ï¿½ + + GDALDataType gdal_datatype = rasterDataset->GetRasterBand(1)->GetRasterDataType(); + GDALRasterBand* xBand = rasterDataset->GetRasterBand(bandids); + + + double dfMin = this->min(bandids); + double dfMax = this->max(bandids); + int count = int((dfMax - dfMin) / 0.01); + count = count > 255 ? count : 255; + GUIntBig* panHistogram = new GUIntBig[count]; + xBand->GetHistogram(dfMin, dfMax, count, panHistogram, TRUE, FALSE, NULL, NULL); + Eigen::MatrixXd result(count, 2); + double delta = (dfMax - dfMin) / count; + for (int i = 0; i < count; i++) { + result(i, 0) = dfMin + i * delta; + result(i, 1) = double(panHistogram[i]); + } + delete[] panHistogram; + GDALClose((GDALDatasetH)rasterDataset); + return result; +} + + +gdalImage CreategdalImage(const QString& img_path, int height, int width, int band_num, Eigen::MatrixXd gt, QString projection, bool need_gt,bool overwrite) { + + if (exists_test(img_path.toUtf8().constData())) { + if (overwrite) { + gdalImage result_img(img_path); + return result_img; + } + else { + throw "file has exist!!!"; + exit(1); + } + } + GDALAllRegister();// ע���ʽ�����ï¿?1ï¿?7 + GDALDriver* poDriver = GetGDALDriverManager()->GetDriverByName("GTiff"); + GDALDataset* poDstDS = poDriver->Create(img_path.toUtf8().constData(), width, height, band_num, GDT_Float32, NULL); // ������ + if (need_gt) { + poDstDS->SetProjection(projection.toUtf8().constData()); + + // ����ת������ + double gt_ptr[6] = { 0 }; + for (int i = 0; i < gt.rows(); i++) { + for (int j = 0; j < gt.cols(); j++) { + gt_ptr[i * 3 + j] = gt(i, j); + } + } + poDstDS->SetGeoTransform(gt_ptr); + } + for (int i = 1; i <= band_num; i++) { + poDstDS->GetRasterBand(i)->SetNoDataValue(-9999); + } + GDALFlushCache((GDALDatasetH)poDstDS); + GDALClose((GDALDatasetH)poDstDS); + ////GDALDestroy(); // or, DllMain at DLL_PROCESS_DETACH + gdalImage result_img(img_path); + return result_img; +} + +gdalImageComplex CreategdalImageComplex(const QString& img_path, int height, int width, int band_num, Eigen::MatrixXd gt, QString projection, bool need_gt, bool overwrite) +{ + if (exists_test(img_path.toUtf8().constData())) { + if (overwrite) { + gdalImageComplex result_img(img_path); + return result_img; + } + else { + throw "file has exist!!!"; + exit(1); + } + } + GDALAllRegister(); + GDALDriver* poDriver = GetGDALDriverManager()->GetDriverByName("ENVI"); + GDALDataset* poDstDS = poDriver->Create(img_path.toUtf8().constData(), width, height, band_num, GDT_CFloat64, NULL); + if (need_gt) { + poDstDS->SetProjection(projection.toUtf8().constData()); + + // ����ת������ + double gt_ptr[6] = { 0 }; + for (int i = 0; i < gt.rows(); i++) { + for (int j = 0; j < gt.cols(); j++) { + gt_ptr[i * 3 + j] = gt(i, j); + } + } + poDstDS->SetGeoTransform(gt_ptr); + } + for (int i = 1; i <= band_num; i++) { + poDstDS->GetRasterBand(i)->SetNoDataValue(-9999); + } + GDALFlushCache((GDALDatasetH)poDstDS); + GDALClose((GDALDatasetH)poDstDS); + ////GDALDestroy(); // or, DllMain at DLL_PROCESS_DETACH + gdalImageComplex result_img(img_path); + return result_img; +} + + +int ResampleGDAL(const char* pszSrcFile, const char* pszOutFile, double* gt, int new_width, int new_height, GDALResampleAlg eResample) +{ + GDALAllRegister(); + CPLSetConfigOption("GDAL_FILENAME_IS_UTF8", "NO"); + GDALDataset* pDSrc = (GDALDataset*)GDALOpen(pszSrcFile, GA_ReadOnly); + if (pDSrc == NULL) + { + return -1; + } + + GDALDriver* pDriver = GetGDALDriverManager()->GetDriverByName("GTiff"); + if (pDriver == NULL) + { + GDALClose((GDALDatasetH)(GDALDatasetH)pDSrc); + return -2; + } + int width = pDSrc->GetRasterXSize(); + int height = pDSrc->GetRasterYSize(); + int nBandCount = pDSrc->GetRasterCount(); + GDALDataType dataType = pDSrc->GetRasterBand(1)->GetRasterDataType(); + + char* pszSrcWKT = NULL; + pszSrcWKT = const_cast(pDSrc->GetProjectionRef()); + + //���û��ͶӰ����Î?¿½ï¿½ï¿½ï¿½Ò»ï¿½ï¿?1ï¿?7 + if (strlen(pszSrcWKT) <= 0) + { + OGRSpatialReference oSRS; + oSRS.importFromEPSG(4326); + //oSRS.SetUTM(50, true); //������ ����120�� + //oSRS.SetWellKnownGeogCS("WGS84"); + oSRS.exportToWkt(&pszSrcWKT); + } + qDebug() << "GDALCreateGenImgProjTransformer " << endl; + void* hTransformArg; + hTransformArg = GDALCreateGenImgProjTransformer((GDALDatasetH)pDSrc, pszSrcWKT, NULL, pszSrcWKT, FALSE, 0.0, 1); + qDebug() << "no proj " << endl; + //(û��ͶӰ��Ӱ��������߲�Í?¿½ï¿?1ï¿?7) + if (hTransformArg == NULL) + { + GDALClose((GDALDatasetH)(GDALDatasetH)pDSrc); + return -3; + } + qDebug() << "has proj " << endl; + double dGeoTrans[6] = { 0 }; + int nNewWidth = 0, nNewHeight = 0; + if (GDALSuggestedWarpOutput((GDALDatasetH)pDSrc, GDALGenImgProjTransform, hTransformArg, dGeoTrans, &nNewWidth, &nNewHeight) != CE_None) + { + GDALClose((GDALDatasetH)(GDALDatasetH)pDSrc); + return -3; + } + + //GDALDestroyGenImgProjTransformer(hTransformArg); + + + GDALDataset* pDDst = pDriver->Create(pszOutFile, new_width, new_height, nBandCount, dataType, NULL); + if (pDDst == NULL) + { + GDALClose((GDALDatasetH)(GDALDatasetH)pDSrc); + return -2; + } + + pDDst->SetProjection(pszSrcWKT); + pDDst->SetGeoTransform(gt); + + GDALWarpOptions* psWo = GDALCreateWarpOptions(); + + //psWo->papszWarpOptions = CSLDuplicate(NULL); + psWo->eWorkingDataType = dataType; + psWo->eResampleAlg = eResample; + + psWo->hSrcDS = (GDALDatasetH)pDSrc; + psWo->hDstDS = (GDALDatasetH)pDDst; + qDebug() << "GDALCreateGenImgProjTransformer" << endl; + psWo->pfnTransformer = GDALGenImgProjTransform; + psWo->pTransformerArg = GDALCreateGenImgProjTransformer((GDALDatasetH)pDSrc, pszSrcWKT, (GDALDatasetH)pDDst, pszSrcWKT, FALSE, 0.0, 1);; + + qDebug() << "GDALCreateGenImgProjTransformer has created" << endl; + psWo->nBandCount = nBandCount; + psWo->panSrcBands = (int*)CPLMalloc(nBandCount * sizeof(int)); + psWo->panDstBands = (int*)CPLMalloc(nBandCount * sizeof(int)); + for (int i = 0; i < nBandCount; i++) + { + psWo->panSrcBands[i] = i + 1; + psWo->panDstBands[i] = i + 1; + } + + GDALWarpOperation oWo; + if (oWo.Initialize(psWo) != CE_None) + { + GDALClose((GDALDatasetH)(GDALDatasetH)pDSrc); + GDALClose((GDALDatasetH)(GDALDatasetH)pDDst); + return -3; + } + qDebug() << "ChunkAndWarpImage:" << new_width << "," << new_height << endl; + oWo.ChunkAndWarpMulti(0, 0, new_width, new_height); + GDALFlushCache(pDDst); + qDebug() << "ChunkAndWarpImage over" << endl; + //GDALDestroyGenImgProjTransformer(psWo->pTransformerArg); + //GDALDestroyWarpOptions(psWo); + GDALClose((GDALDatasetH)(GDALDatasetH)pDSrc); + GDALClose((GDALDatasetH)(GDALDatasetH)pDDst); + ////GDALDestroy(); // or, DllMain at DLL_PROCESS_DETACH + return 0; +} + +int ResampleGDALs(const char* pszSrcFile, int band_ids, GDALRIOResampleAlg eResample) +{ + GDALAllRegister(); + CPLSetConfigOption("GDAL_FILENAME_IS_UTF8", "NO"); + GDALDataset* pDSrc = (GDALDataset*)GDALOpen(pszSrcFile, GA_Update); + if (pDSrc == NULL) + { + return -1; + } + + GDALDataType gdal_datatype = pDSrc->GetRasterBand(1)->GetRasterDataType(); + + GDALRasterBand* demBand = pDSrc->GetRasterBand(band_ids); + + int width = pDSrc->GetRasterXSize(); + int height = pDSrc->GetRasterYSize(); + int start_col = 0, start_row = 0, rows_count = 0, cols_count; + + int row_delta = int(120000000 / width); + + GDALRasterIOExtraArg psExtraArg; + INIT_RASTERIO_EXTRA_ARG(psExtraArg); + psExtraArg.eResampleAlg = eResample; + + do { + + rows_count = start_row + row_delta < height ? row_delta : height - start_row; + cols_count = width; + + if (gdal_datatype == GDALDataType::GDT_UInt16) { + + unsigned short* temp = new unsigned short[rows_count * cols_count]; + demBand->RasterIO(GF_Read, start_col, start_row, cols_count, rows_count, temp, cols_count, rows_count, gdal_datatype, 0, 0); + demBand->RasterIO(GF_Write, start_col, start_row, cols_count, rows_count, temp, cols_count, rows_count, gdal_datatype, 0, 0, &psExtraArg); + delete[] temp; + + } + else if (gdal_datatype == GDALDataType::GDT_Int16) { + + short* temp = new short[rows_count * cols_count]; + demBand->RasterIO(GF_Read, start_col, start_row, cols_count, rows_count, temp, cols_count, rows_count, gdal_datatype, 0, 0); + demBand->RasterIO(GF_Write, start_col, start_row, cols_count, rows_count, temp, cols_count, rows_count, gdal_datatype, 0, 0, &psExtraArg); + delete[] temp; + } + else if (gdal_datatype == GDALDataType::GDT_Float32) { + float* temp = new float[rows_count * cols_count]; + demBand->RasterIO(GF_Read, start_col, start_row, cols_count, rows_count, temp, cols_count, rows_count, gdal_datatype, 0, 0); + demBand->RasterIO(GF_Write, start_col, start_row, cols_count, rows_count, temp, cols_count, rows_count, gdal_datatype, 0, 0, &psExtraArg); + delete[] temp; + } + start_row = start_row + rows_count; + } while (start_row < height); + GDALClose((GDALDatasetH)pDSrc); + + + return 0; +} + +int saveMatrixXcd2TiFF(Eigen::MatrixXcd data, QString out_tiff_path) +{ + int rows = data.rows(); + int cols = data.cols(); + + Eigen::MatrixXd gt = Eigen::MatrixXd::Zero(2, 3); + + gdalImage image_tiff = CreategdalImage(out_tiff_path, rows, cols, 2, gt, "", false, true);// ×¢ÒâÕâÀï±£Áô·ÂÕæ½á¹û + // ±£´æ¶þ½øÖÆÎļþ + Eigen::MatrixXd real_img = data.array().real(); + Eigen::MatrixXd imag_img = data.array().imag(); + image_tiff.saveImage(real_img, 0, 0, 1); + image_tiff.saveImage(imag_img, 0, 0, 2); + return -1; +} + + +gdalImageComplex::gdalImageComplex(const QString& raster_path) +{ + omp_lock_t lock; + omp_init_lock(&lock); + omp_set_lock(&lock); + this->img_path = raster_path; + + GDALAllRegister(); + GDALDataset* rasterDataset = (GDALDataset*)(GDALOpen(raster_path.toUtf8().constData(), GA_ReadOnly));//��ֻ½ï¿½Ê½ï¿½ï¿½È¡½ï¿½Ó°ï¿½ï¿½ + this->width = rasterDataset->GetRasterXSize(); + this->height = rasterDataset->GetRasterYSize(); + this->band_num = rasterDataset->GetRasterCount(); + + double* gt = new double[6]; + rasterDataset->GetGeoTransform(gt); + this->gt = Eigen::MatrixXd(2, 3); + this->gt << gt[0], gt[1], gt[2], gt[3], gt[4], gt[5]; + + + double a = this->gt(0, 0); + double b = this->gt(0, 1); + double c = this->gt(0, 2); + double d = this->gt(1, 0); + double e = this->gt(1, 1); + double f = this->gt(1, 2); + + this->projection = rasterDataset->GetProjectionRef(); + + // ½ï¿½Í¶Ó° + GDALFlushCache((GDALDatasetH)rasterDataset); + GDALClose((GDALDatasetH)rasterDataset); + rasterDataset = NULL;// Ö¸½Ã¿ï¿½ + this->InitInv_gt(); + delete[] gt; + ////GDALDestroy(); // or, DllMain at DLL_PROCESS_DETACH + omp_unset_lock(&lock); //�ͷŻ�½ï¿½ + omp_destroy_lock(&lock); //½Ù»ï¿½½ï¿½ + + +} + +gdalImageComplex::~gdalImageComplex() +{ +} + +void gdalImageComplex::setData(Eigen::MatrixXcd data) +{ + this->data = data; +} + +void gdalImageComplex::saveImage(Eigen::MatrixXcd data, int start_row, int start_col, int band_ids) +{ + omp_lock_t lock; + omp_init_lock(&lock); + omp_set_lock(&lock); + if (start_row + data.rows() > this->height || start_col + data.cols() > this->width) { + QString tip = u8"file path: " + this->img_path; + qDebug() << tip; + throw exception(tip.toUtf8().constData()); + } + GDALAllRegister(); + GDALDriver* poDriver = GetGDALDriverManager()->GetDriverByName("ENVI"); + GDALDataset* poDstDS = nullptr; + if (exists_test(this->img_path)) { + poDstDS = (GDALDataset*)(GDALOpen(this->img_path.toUtf8().constData(), GA_Update)); + } + else { + poDstDS = poDriver->Create(this->img_path.toUtf8().constData(), this->width, this->height, this->band_num, GDT_CFloat64, NULL); // ½ï¿½ï¿½ï¿½ + poDstDS->SetProjection(this->projection.toUtf8().constData()); + + + double gt_ptr[6]; + for (int i = 0; i < this->gt.rows(); i++) { + for (int j = 0; j < this->gt.cols(); j++) { + gt_ptr[i * 3 + j] = this->gt(i, j); + } + } + poDstDS->SetGeoTransform(gt_ptr); + delete[] gt_ptr; + } + + int datarows = data.rows(); + int datacols = data.cols(); + + double* databuffer = new double[data.size() * 2]; + for (int i = 0; i < data.rows(); i++) { + for (int j = 0; j < data.cols(); j++) { + databuffer[i * data.cols() * 2 + j * 2] = data(i, j).real(); + databuffer[i * data.cols() * 2 + j * 2 + 1] = data(i, j).imag(); + } + } + + //poDstDS->RasterIO(GF_Write,start_col, start_row, datacols, datarows, databuffer, datacols, datarows, GDT_Float32,band_ids, num,0,0,0); + poDstDS->GetRasterBand(band_ids)->RasterIO(GF_Write, start_col, start_row, datacols, datarows, databuffer, datacols, datarows, GDT_CFloat64, 0, 0); + GDALFlushCache(poDstDS); + delete databuffer; + GDALClose((GDALDatasetH)poDstDS); + //GDALDestroy(); // or, DllMain at DLL_PROCESS_DETACH + omp_unset_lock(&lock); //�ͷŻ�½ï¿½ + omp_destroy_lock(&lock); //½Ù»ï¿½½ï¿½ + +} + +Eigen::MatrixXcd gdalImageComplex::getDataComplex(int start_row, int start_col, int rows_count, int cols_count, int band_ids) +{ + + + GDALDataset* poDataset; + GDALAllRegister(); + + // ´ò¿ªTIFFÎļþ + poDataset = (GDALDataset*)GDALOpen(this->img_path.toUtf8().constData(), GA_ReadOnly); + if (poDataset == nullptr) { + QMessageBox::warning(nullptr, u8"´íÎó", u8"ÎÞ·¨´ò¿ªÎļþ£º" + this->img_path); + qDebug() << u8"ÎÞ·¨´ò¿ªÎļþ£º" + this->img_path; + } + + // »ñÈ¡Êý¾Ý¼¯µÄµÚÒ»¸ö²¨¶Î + GDALRasterBand* poBand; + poBand = poDataset->GetRasterBand(1); + + // ¶ÁÈ¡²¨¶ÎÐÅÏ¢£¬¼ÙÉèÊǸ´ÊýÀàÐÍ + int nXSize = poBand->GetXSize(); + int nYSize = poBand->GetYSize(); + + + double* databuffer = new double[nXSize * nYSize * 2]; + poBand->RasterIO(GF_Read, start_col, start_row, cols_count, rows_count, databuffer, cols_count, rows_count, GDT_CFloat64, 0, 0); + GDALClose((GDALDatasetH)poDataset); + Eigen::MatrixXcd rasterData(nYSize, nXSize); // ʹÓÃEigenµÄMatrixXcd + for (size_t i = 0; i < nYSize; i++) + { + for (size_t j = 0; j < nXSize; j++) { + rasterData(i, j) = std::complex(databuffer[i * nXSize * 2 + j * 2], databuffer[i * nXSize * 2 + j * 2 + 1]); + } + } + + delete databuffer; + return rasterData; + +} + +void gdalImageComplex::saveImage() +{ + this->saveImage(this->data, this->start_row, this->start_col, this->data_band_ids); +} + + \ No newline at end of file diff --git a/src/LAMPTool/BaseToollib/ImageOperatorBase.h b/src/LAMPTool/BaseToollib/ImageOperatorBase.h new file mode 100644 index 0000000..eccede4 --- /dev/null +++ b/src/LAMPTool/BaseToollib/ImageOperatorBase.h @@ -0,0 +1,190 @@ +#pragma once +/** + * Ó°ÏñÊý¾Ý²Ù×÷Ïî + * ËùÓÐÊý¾ÝÏà¹ØµÄ²Ù×÷£¬¶¼ÊÇ»ùÓÚENVIµÄÊý¾Ý¸ñʽ + * Ó°Ïñ¶Áд²Ù×÷ʱ»ùÓÚ GDAL ¿â + * **/ + + + +#ifndef IMAGEOPERATORBASE_H +#define IMAGEOPERATORBASE_H + +#include "BaseToollib/BaseConstVariable.h" +#include "BaseToollib/GeoOperator.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include // for CPLMalloc() +#include "referenceHeader.h" +using namespace std; +using namespace Eigen; + +struct ImageGEOINFO { + int width; + int height; + int bandnum; +}; + + +// ÅжÏÊÇ·ñÐèÒªÊä³öΪDLL +#define DLLOUT +// Îļþ´ò¿ª +std::shared_ptr OpenDataset(const QString& in_path, GDALAccess rwmode= GA_ReadOnly); // µ±Ö¸ÁîÏú»Ùʱ£¬µ÷ÓÃGDALClose Ïú»ÙÀàÐÍ +void CloseDataset(GDALDataset* ptr); + +// Êý¾Ý¸ñʽת»» +int TIFF2ENVI(QString in_tiff_path,QString out_envi_path); +int ENVI2TIFF(QString in_envi_path,QString out_tiff_path); + +// ±£´æÓ°ÏñÊý¾Ý --Ö±½Ó±£´æ ENVI Îļþ + +int CreateDataset(QString new_file_path, int height, int width, int band_num, double* gt, QString projection, GDALDataType gdal_dtype, bool need_gt); // ´´½¨Îļþ + +int saveDataset(QString new_file_path, int start_line, int start_cols, int band_ids, int datacols, int datarows, void* databuffer); + +// ¸ù¾ÝÏÞÖÆÌõ¼þ¹ÀËã·Ö¿é´óС +int block_num_pre_memory(int width, int height, GDALDataType gdal_dtype,double memey_size); + +// ½«½á¹ûת»»Îª¸´Êý »òÕß ÊµÊý +Eigen::Matrix ReadComplexMatrixData(int start_line,int width, int line_num, std::shared_ptr rasterDataset, GDALDataType gdal_datatype); + +Eigen::Matrix ReadMatrixDoubleData(int start_line, int width, int line_num, std::shared_ptr rasterDataset, GDALDataType gdal_datatype,int band_idx); + +Eigen::MatrixXd getGeoTranslationArray(QString in_path); +ImageGEOINFO getImageINFO(QString in_path); + +GDALDataType getGDALDataType(QString fileptah); + + +struct DemBox { + double min_lat; //γ¶È + double min_lon;//¾­¶È + double max_lat;//γ¶È + double max_lon;//¾­¶È +}; + + +/// +/// gdalImageͼÏñ²Ù×÷Àà +/// +class gdalImage +{ + +public: // ·½·¨ + gdalImage(); + gdalImage(const QString& raster_path); + ~gdalImage(); + virtual void setHeight(int); + virtual void setWidth(int); + virtual void setTranslationMatrix(Eigen::MatrixXd gt); + virtual void setData(Eigen::MatrixXd,int data_band_ids=1); + virtual Eigen::MatrixXd getData(int start_row, int start_col, int rows_count, int cols_count, int band_ids); + virtual Eigen::MatrixXd getGeoTranslation(); + virtual GDALDataType getDataType(); + virtual void saveImage(Eigen::MatrixXd, int start_row, int start_col, int band_ids); + virtual void saveImage(); + virtual void setNoDataValue(double nodatavalue, int band_ids); + virtual int InitInv_gt(); + virtual Landpoint getRow_Col(double lon, double lat); + virtual Landpoint getLandPoint(double i, double j, double ati); + virtual double mean(int bandids = 1); + virtual double max(int bandids = 1); + virtual double min(int bandids = 1); + virtual GDALRPCInfo getRPC(); + virtual Eigen::MatrixXd getLandPoint(Eigen::MatrixXd points); + + virtual Eigen::MatrixXd getHist(int bandids); +public: + QString img_path; // ͼÏñÎļþ + int height; // ¸ß + int width; // ¿í + int band_num;// ²¨¶ÎÊý + int start_row;// + int start_col;// + int data_band_ids; + Eigen::MatrixXd gt; // ±ä»»¾ØÕó + Eigen::MatrixXd inv_gt; // Äæ±ä»»¾ØÕó + Eigen::MatrixXd data; + QString projection; +}; + + + + + + + +/// +/// gdalImageͼÏñ²Ù×÷Àà +/// +class gdalImageComplex:public gdalImage +{ + +public: // ·½·¨ + gdalImageComplex(const QString& raster_path); + ~gdalImageComplex(); + void setData(Eigen::MatrixXcd); + void saveImage(Eigen::MatrixXcd data, int start_row, int start_col, int band_ids); + Eigen::MatrixXcd getDataComplex(int start_row, int start_col, int rows_count, int cols_count, int band_ids); + void saveImage() override; + +public: + Eigen::MatrixXcd data; +}; + + + + + + + + + + + + + + +gdalImage CreategdalImage(const QString& img_path, int height, int width, int band_num, Eigen::MatrixXd gt, QString projection, bool need_gt = true, bool overwrite = false); +gdalImageComplex CreategdalImageComplex(const QString& img_path, int height, int width, int band_num, Eigen::MatrixXd gt, QString projection, bool need_gt = true, bool overwrite = false); + + + + +int ResampleGDAL(const char* pszSrcFile, const char* pszOutFile, double* gt, int new_width, int new_height, GDALResampleAlg eResample); + +int ResampleGDALs(const char* pszSrcFile, int band_ids, GDALRIOResampleAlg eResample = GRIORA_Bilinear); + + +//--------------------- ±£´æÎIJ© ------------------------------- + +int saveMatrixXcd2TiFF(Eigen::MatrixXcd data, QString out_tiff_path); + +//---------------------------------------------------- + + + +#ifndef DLLOUT + + + + + +#else +//#define DllExport __declspec( dllexport ) +//double __declspec(dllexport) ProcessMGCMathX_MGC(int Xbetaidx, int Xbwidx, double XTao, double satH, char* sigma_path, char* output_path, +// double p1_x, double p1_y, double p2_x, double p2_y, double p3_x, double p3_y, double p4_x, double p4_y) + +#endif + +#endif \ No newline at end of file diff --git a/src/LAMPTool/BaseToollib/interpolation.cpp b/src/LAMPTool/BaseToollib/interpolation.cpp new file mode 100644 index 0000000..0203513 --- /dev/null +++ b/src/LAMPTool/BaseToollib/interpolation.cpp @@ -0,0 +1,13 @@ +#include "BaseToolLib/interpolation.h" +#include +#include +#include +#include +#include +#include + + + +namespace LampInterpolation { + +} \ No newline at end of file diff --git a/src/LAMPTool/BaseToollib/interpolation.h b/src/LAMPTool/BaseToollib/interpolation.h new file mode 100644 index 0000000..e3e087e --- /dev/null +++ b/src/LAMPTool/BaseToollib/interpolation.h @@ -0,0 +1,69 @@ +#pragma once + +#ifndef INTERPOLATION_H +#define INTERPOLATION_H + +#include +#include +#include +#include +#include +#include +#include + + +namespace LampInterpolation { + enum interpolationtype { + nearest, + linear, + cubic, + }; + + + /// + /// ¾ØÕóΪ 1xn + /// + template + std::complex interpolation(Eigen::MatrixX>& echo, double& index, interpolationtype methodtype) + { + assert(echo.rows() != 1 || echo.cols() >= index || index < 0); // ¶ÏÑÔ + if (methodtype == interpolationtype::linear) { + return interpolationLinear(echo, index); + } + else if (methodtype == interpolationtype::cubic) { + + } + else if (methodtype == interpolationtype::nearest) { + return interpolationNearest(echo, index); + } + else {} + return std::complex(0, 0); + }; + + template + std::complex interpolationLinear(Eigen::MatrixX>& echo, double& index) + { + size_t last_ids = size_t(std::floor(index)); + size_t next_ids = size_t(std::ceil(index)); + + std::complex last_value = echo(1, last_ids); + std::complex next_value = echo(1, next_ids); + + // ʵ²¿£¬Ð鲿ͬʱ²åÖµ + double real = last_value.real() + ((next_value.real() - last_value.real()) / (next_ids - last_ids)) * (index - last_ids); + double imag = last_value.imag() + ((next_value.imag() - last_value.imag()) / (next_ids - last_ids)) * (index - last_ids); + + return std::complex(T(real), T(imag)); + }; + + template + std::complex interpolationNearest(Eigen::MatrixX>& echo, double& index) + { + size_t nearest_ids = size_t(std::round(index)); + return echo(1, nearest_ids); + }; + +} + + +#endif \ No newline at end of file diff --git a/src/LAMPTool/BaseToollib/readme.md b/src/LAMPTool/BaseToollib/readme.md new file mode 100644 index 0000000..671e01a --- /dev/null +++ b/src/LAMPTool/BaseToollib/readme.md @@ -0,0 +1,2 @@ +# 说明 +此模å—ä¸»è¦æ˜¯é€šç”¨åŸºç¡€æ¨¡å— \ No newline at end of file diff --git a/src/LAMPTool/CMakeLists.txt b/src/LAMPTool/CMakeLists.txt new file mode 100644 index 0000000..823dd5f --- /dev/null +++ b/src/LAMPTool/CMakeLists.txt @@ -0,0 +1,68 @@ +#----------------------------------------------------------------------------- +# 头文件æœç´¢è·¯å¾„ +#----------------------------------------------------------------------------- +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/..) + +#----------------------------------------------------------------------------- +# 自动添加include目录 +#----------------------------------------------------------------------------- +set(CMAKE_INCLUDE_CURRENT_DIR ON) + +#----------------------------------------------------------------------------- +# æ·»åŠ èµ„æºæ–‡ä»¶ +#----------------------------------------------------------------------------- +set(_qrc "${CMAKE_CURRENT_SOURCE_DIR}/../qrc/WBCLFZSystemModule.qrc") + +qt5_add_resources(_resource ${_qrc} ${_lang}) + +#----------------------------------------------------------------------------- +# æºç æ‰«æ +#----------------------------------------------------------------------------- +file(GLOB _ui "*.ui") +file(GLOB _header "*.h*") +file(GLOB _source "*.cpp") +qt5_wrap_ui(_interface ${_ui}) + +#----------------------------------------------------------------------------- +# 添加动æ€åº“目标 +#----------------------------------------------------------------------------- +add_library(LAMPTool + ${_resource} + ${_interface} + ${_header} + ${_source} +) + +#----------------------------------------------------------------------------- +# 添加接å£å£°æ˜Žå® +#----------------------------------------------------------------------------- +target_compile_definitions(LAMPTool PRIVATE "LAMPTool_API") + + + + +list(APPEND _depend_library qcustomplot) + +list(APPEND _runtimes_libraries + Qt5::Core Qt5::Gui Qt5::Widgets +) + +target_include_directories(LAMPTool PRIVATE ${Qwt_INCLUDE_DIRS}) + +#----------------------------------------------------------------------------- +# 链接ä¾èµ–库 +#----------------------------------------------------------------------------- +target_link_libraries(LAMPTool PRIVATE + ${_runtimes_libraries} + ${_depend_library} +) + +#----------------------------------------------------------------------------- +# 添加ä¾èµ–关系 +#----------------------------------------------------------------------------- +add_dependencies(LAMPTool ${_depend_library}) + +#----------------------------------------------------------------------------- +# 添加è¿è¡Œæ—¶ä¾èµ–关系 +#----------------------------------------------------------------------------- +set(FastCAE_LAMPTool_Runtimes_Libraries ${_runtimes_libraries} PARENT_SCOPE) \ No newline at end of file diff --git a/src/LAMPTool/FEKOFarFieldFileClass.cpp b/src/LAMPTool/FEKOFarFieldFileClass.cpp new file mode 100644 index 0000000..0f24aa4 --- /dev/null +++ b/src/LAMPTool/FEKOFarFieldFileClass.cpp @@ -0,0 +1,446 @@ +#include "FEKOFarFieldFileClass.h" + +FEKOBase::FEKOFarFieldFileClass::FEKOFarFieldFileClass() +{ + +} + +FEKOBase::FEKOFarFieldFileClass::~FEKOFarFieldFileClass() +{ + +} + +void FEKOBase::FEKOFarFieldFileClass::parseFarFieldFile(const QString& fileName) +{ + QFile file(fileName); + // ¼ÓÔØÎı¾ÎļþÖеÄËùÓÐÊý¾Ýµ½Ò»¸ö QString ÖÐ + if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) + { + qDebug() << "Failed to open file for reading"; + return; + } + QTextStream in(&file); + QString line; + bool dataSectionStarted = false; + + + QList dataBlockStrList; + dataBlockStrList.clear(); + while (!in.atEnd()) { + line = in.readLine().trimmed(); + if (line.startsWith(u8"##")) { + if (line.indexOf(u8"File Type:") != -1) { + this->FileType = line.split(":")[1].trimmed(); + } + else if (line.indexOf(u8"File Format:") != -1) { + this->FileFormat = line.split(":")[1].trimmed(); + } + else if (line.indexOf(u8"Source:") != -1) { + this->Sourcestr = line.split(":")[1].trimmed(); + } + else if (line.indexOf(u8"Date:") != -1) { + this->Datestr = line.split(":")[1].trimmed(); + } + else { + continue; + } + } + else if (line.startsWith("**")) { + dataBlockStrList.clear(); + continue; + } + else { + if (line.length() < 5) { + if (dataBlockStrList.length() > 0) { + FEKOFARFIELDFEKODATABLOCK temp_dataBlock; + temp_dataBlock.paraseFEKOFarFieldDataBlockFromList(dataBlockStrList); + this->dataBlockList.push_back(temp_dataBlock); + } + else { + + } + dataBlockStrList.clear(); + } + else { + dataBlockStrList.append(line); + } + } + } + + if (dataBlockStrList.length() > 0) { + FEKOFARFIELDFEKODATABLOCK temp_dataBlock; + temp_dataBlock.paraseFEKOFarFieldDataBlockFromList(dataBlockStrList); + this->dataBlockList.push_back(temp_dataBlock); + } + + file.close(); +} + +void FEKOBase::FEKOFarFieldFileClass::outputToFile(const QString& fileName) +{ + QFile file(fileName); + if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) + { + qDebug() << "Failed to open file for writing"; + return; + } + + QTextStream out(&file); + + file.close(); + +} + +FEKOBase::FEKOFARFIELDRESULTTYPE FEKOBase::FEKOFARFIELDRESULTTYPEString2Enum(QString str) +{ + if (str.toUpper() == "GAIN") { return FEKOBase::GAIN; } + else if (str.toUpper() == "DIRECTIVITY") { return FEKOBase::DIRECTIVITY; } + else if (str.toUpper() == "RCS") { return FEKOBase::RCS; } + else if (str.toUpper() == "FARFIELDVALUES") { return FEKOBase::FARFIELDVALUES; } + else { + return FEKOBase::FEKOFARFIELDRESULTTYPEUNKOWN; + } + return FEKOBase::FEKOFARFIELDRESULTTYPE(); +} + +QString FEKOBase::QString2FEKOFARFIELDRESULTTYPE(FEKOBase::FEKOFARFIELDRESULTTYPE mode) +{ + switch (mode) { + case FEKOBase::GAIN: + return "GAIN"; + case FEKOBase::DIRECTIVITY: + return "DIRECTIVITY"; + case FEKOBase::RCS: + return "RCS"; + case FEKOBase::FARFIELDVALUES: + return "FARFIELDVALUES"; + default: + return "FEKOFARFIELDRESULTTYPEUNKOWN"; + + } +} + +FEKOBase::FEKOFARFIELDFEKODATABLOCK::FEKOFARFIELDFEKODATABLOCK() +{ + this->dataList.clear(); + this->thetaSamples = 0; + this->phiSamples = 0; + this->USamples = 0; + this->VSamples = 0; + this->configurationName.clear(); + this->requestName.clear(); + this->frequency = 0; + this->Origin = { 0,0,0 }; + this->headerLines = 0; + this->coordinateSystem = FEKOBase::UNKONWFEKOCOORDINATESYSTEM; + this->resultType = FEKOBase::FEKOFARFIELDRESULTTYPEUNKOWN; +} + +FEKOBase::FEKOFARFIELDFEKODATABLOCK::~FEKOFARFIELDFEKODATABLOCK() +{ + +} + +int FEKOBase::FEKOFARFIELDFEKODATABLOCK::paraseFEKOFarFieldDataBlock(const QString& blockstr) +{ + // °´ÐнøÐнâÎö + QList lines= blockstr.split("\n"); + return this->paraseFEKOFarFieldDataBlockFromList(lines); + return 1; + +} + +int FEKOBase::FEKOFARFIELDFEKODATABLOCK::paraseFEKOFarFieldDataBlockFromList(QList& lines) +{ + bool in_readHeaderState = false; + size_t headerlineCount = 0; + std::vector headerLines;// ½âÎöÐÐÁÐʱ±£Ö¤½á¹û + + + for (size_t i = 0; i < lines.size(); i++) { + if (lines[i].startsWith("#")) { // ²ÎÊýÏîÊÇÒÔ# ¿ªÍ·×÷ΪÅäÖÃÏî + // Õë¶Ô²»Í¬²ÎÊýÏîÌáÈ¡²ÎÊý + QString configName = normalizationHeaderString(lines[i]); // »ñÈ¡²ÎÊýµÄ¹éÒ»»¯Ãû³Æ + if (configName == u8"") { // δ֪²ÎÊýÏî + // ½øÈë×ֶνâÎö״̬ + if (in_readHeaderState) { // ½âÎö×Ö¶Î + QList temp_headerLines=lines[i].split(FEKOFARFIELDSPLITCHAT); + for (size_t ii = 0; ii < temp_headerLines.size();ii++) { + if (temp_headerLines[ii].length() > 2) { + QString temp_header_str= this->normalizationHeaderString(temp_headerLines[ii]); + headerLines.push_back(temp_header_str); + } + else { + continue; + } + } + headerlineCount++; + if (headerlineCount >= this->headerLines) { + in_readHeaderState = false; + } + } + else { + continue; + } + } + else if (configName == u8"ConfigurationName") { + this->configurationName = lines[i].split(":")[1].trimmed(); + } + else if (configName == u8"RequestName") { + this->requestName = lines[i].split(":")[1].trimmed(); + } + else if (configName == u8"Frequency") { + this->frequency = lines[i].split(":")[1].trimmed().toDouble(); + } + else if (configName == u8"CoordinateSystem") { + this->coordinateSystem = FEKOBase::FEKOCoordinateSystemString2Enum(lines[i].split(":")[1].trimmed()); + } + else if (configName == u8"ThetaSamplePointsNumber") { + this->thetaSamples = lines[i].split(":")[1].trimmed().toInt(); + } + else if (configName == u8"PhiSamplePointsNumber") { + this->phiSamples = lines[i].split(":")[1].trimmed().toInt(); + } + else if (configName == u8"USamplePointNumber") { + this->USamples = lines[i].split(":")[1].trimmed().toInt(); + } + else if (configName == u8"VSamplePointNumber") { + this->VSamples = lines[i].split(":")[1].trimmed().toInt(); + } + else if (configName == u8"ORIGIN") { + QStringList originstrlist = lines[i].replace("(", "").replace(")", "").split(":")[1].trimmed().split(","); + this->Origin = { originstrlist[0].trimmed().toDouble(),originstrlist[1].trimmed().toDouble(),originstrlist[2].trimmed().toDouble() }; + } + else if (configName == u8"ResultType") { + this->resultType = FEKOBase::FEKOFARFIELDRESULTTYPEString2Enum(lines[i].split(":")[1].trimmed()); + } + else if (configName == u8"HeaderLines") { + this->headerLines = lines[i].split(":")[1].trimmed().toInt(); + in_readHeaderState = true; + + } + else { + continue; + } + } + else if (lines[i].size() > 10) { // ½âÎöÊý¾Ý¿é + QList dataline = lines[i].split(FEKOFARFIELDSPLITCHAT); + FEKOBase::FEKOFarFieldFEKOFarFieldData temp_data; + long field_idx =-1; + for (size_t ii = 0; ii < dataline.count(); ii++) { + if (dataline[ii] == u8"") { continue; } + else { field_idx = field_idx + 1; } + if (headerLines[field_idx] == "theta") { temp_data.theta = dataline[ii].toDouble(); } + else if (headerLines[field_idx] == "phi") { temp_data.phi = dataline[ii].toDouble(); } + else if (headerLines[field_idx] == "re(etheta)") { temp_data.re_Etheta = dataline[ii].toDouble(); } + else if (headerLines[field_idx] == "im(etheta)") { temp_data.im_Etheta = dataline[ii].toDouble(); } + else if (headerLines[field_idx] == "re(ephi)") { temp_data.re_Ephi = dataline[ii].toDouble(); } + else if (headerLines[field_idx] == "im(ephi)") { temp_data.im_Ephi = dataline[ii].toDouble(); } + else if (headerLines[field_idx] == "gain(theta)") { temp_data.gain_Theta = dataline[ii].toDouble(); } + else if (headerLines[field_idx] == "gain(phi)") { temp_data.gain_Phi = dataline[ii].toDouble(); } + else if (headerLines[field_idx] == "gain(total)") { temp_data.gain_Total = dataline[ii].toDouble(); } + else if (headerLines[field_idx] == "radius") { temp_data.radius = dataline[ii].toDouble(); } + else if (headerLines[field_idx] == "x") { temp_data.X = dataline[ii].toDouble(); } + else if (headerLines[field_idx] == "y") { temp_data.Y = dataline[ii].toDouble(); } + else if (headerLines[field_idx] == "z") { temp_data.Z = dataline[ii].toDouble(); } + else if (headerLines[field_idx] == "re(ex)") { temp_data.re_Ex = dataline[ii].toDouble(); } + else if (headerLines[field_idx] == "re(ey)") { temp_data.re_Ey = dataline[ii].toDouble(); } + else if (headerLines[field_idx] == "re(ez)") { temp_data.re_Ez = dataline[ii].toDouble(); } + else if (headerLines[field_idx] == "im(ex)") { temp_data.im_Ex = dataline[ii].toDouble(); } + else if (headerLines[field_idx] == "im(ey)") { temp_data.im_Ey = dataline[ii].toDouble(); } + else if (headerLines[field_idx] == "im(ez)") { temp_data.im_Ez = dataline[ii].toDouble(); } + else if (headerLines[field_idx] == "re(er)") { temp_data.re_Er = dataline[ii].toDouble(); } + else if (headerLines[field_idx] == "im(er)") { temp_data.im_Er = dataline[ii].toDouble(); } + else if (headerLines[field_idx] == "u") { temp_data.U = dataline[ii].toDouble(); } + else if (headerLines[field_idx] == "v") { temp_data.V = dataline[ii].toDouble(); } + else { + continue; + } + } + this->dataList.push_back(temp_data); + } + else { + continue; + } + + } + return 0; +} + +QString FEKOBase::FEKOFARFIELDFEKODATABLOCK::normalizationHeaderString(QString headerstr) +{ + headerstr = headerstr.replace("'", "").replace(u8"\"",u8""); + if(headerstr.indexOf("#Configuration Name") != -1) + { + return u8"ConfigurationName"; + } + else if (headerstr.indexOf("#Request Name") != -1) + { + return u8"RequestName"; + } + else if (headerstr.indexOf("#Frequency") != -1) + { + return u8"Frequency"; + } + else if (headerstr.indexOf("#Coordinate System:") != -1) + { + return u8"CoordinateSystem"; + } + else if (headerstr.indexOf("#No. of Theta Samples:") != -1) + { + return u8"ThetaSamplePointsNumber"; + } + else if (headerstr.indexOf("#No. of Phi Samples:") != -1) + { + return u8"PhiSamplePointsNumber"; + } + else if (headerstr.indexOf("#No. of U Samples:") != -1) + { + return u8"USamplePointNumber"; + } + else if (headerstr.indexOf("#No. of V Samples:") != -1) + { + return u8"VSamplePointNumber"; + } + else if (headerstr.indexOf("#No. of X Samples:") != -1) + { + return u8"XSamplePointNumber"; + } + else if (headerstr.indexOf("#No. of Y Samples:") != -1) + { + return u8"YSamplePointNumber"; + } + else if (headerstr.indexOf("#No. of Z Samples:") != -1) + { + return u8"ZSamplePointNumber"; + } + else if (headerstr.indexOf("#Origin:") != -1) + { + return u8"ORIGIN"; + } + else if (headerstr.indexOf("#Result Type:") != -1) + { + return u8"ResultType"; + } + else if (headerstr.indexOf("#No. of Header Lines:") != -1) + { + return u8"HeaderLines"; + } + else if (headerstr.toLower().trimmed()==u8"theta"|| headerstr.toLower().trimmed() == u8"theta'") { + return u8"theta"; + } + else if (headerstr.toLower().trimmed() == u8"phi"|| headerstr.toLower().trimmed() == u8"phi'") { + return u8"phi"; + } + else if (headerstr.toLower().trimmed() == u8"re(etheta)"|| headerstr.toLower().trimmed() == u8"re(etheta')") { + return u8"re(etheta)"; + } + else if (headerstr.toLower().trimmed() == u8"im(etheta)"|| headerstr.toLower().trimmed() == u8"im(etheta')") { + return u8"im(etheta)"; + } + else if (headerstr.toLower().trimmed() == u8"re(ephi)"|| headerstr.toLower().trimmed() == u8"re(ephi')") { + return u8"re(ephi)"; + } + else if (headerstr.toLower().trimmed() == u8"im(ephi)"|| headerstr.toLower().trimmed() == u8"im(ephi')") { + return u8"im(ephi)"; + } + else if (headerstr.toLower().trimmed() == u8"re(er)"|| headerstr.toLower().trimmed() == u8"re(er')") { + return u8"re(ephi)"; + } + else if (headerstr.toLower().trimmed() == u8"im(er)"|| headerstr.toLower().trimmed() == u8"im(er')") { + return u8"im(ephi)"; + } + else if (headerstr.toLower().trimmed() == u8"gain(theta)"|| headerstr.toLower().trimmed() == u8"gain(theta')") { + return u8"gain(theta)"; + } + else if (headerstr.toLower().trimmed() == u8"gain(phi)"|| headerstr.toLower().trimmed() == u8"gain(phi')") { + return u8"gain(phi)"; + } + else if (headerstr.toLower().trimmed() == u8"gain(total)"|| headerstr.toLower().trimmed() == u8"gain(total')") { + return u8"gain(total)"; + } + else if (headerstr.toLower().trimmed() == u8"radius"|| headerstr.toLower().trimmed() == u8"radius'") { + return u8"radius"; + } + else if (headerstr.toLower().trimmed() == u8"x" || headerstr.toLower().trimmed() == "x'") { + return u8"x"; + } + else if (headerstr.toLower().trimmed() == u8"y" || headerstr.toLower().trimmed() == "y'") { + return u8"y"; + } + else if (headerstr.toLower().trimmed() == u8"z" || headerstr.toLower().trimmed() == "z'") { + return u8"z"; + } + else if (headerstr.toLower().trimmed() == "re(ex)" || headerstr.toLower().trimmed() == "re(ex')") { + return u8"re(ex)"; + } + else if (headerstr.toLower().trimmed() == "re(ey)" || headerstr.toLower().trimmed() == "re(ey')") { + return u8"re(ey)"; + } + else if (headerstr.toLower().trimmed() == "re(ez)" || headerstr.toLower().trimmed() == "re(ez')") { + return u8"re(ez)"; + } + else if (headerstr.toLower().trimmed() == "im(ex)" || headerstr.toLower().trimmed() == "im(ex')") { + return u8"im(ex)"; + } + else if (headerstr.toLower().trimmed() == "im(ey)" || headerstr.toLower().trimmed() == "im(ey')") { + return u8"im(ey)"; + } + else if (headerstr.toLower().trimmed() == "im(ez)" || headerstr.toLower().trimmed() == "im(ez')") { + return u8"im(ez)"; + } + else if (headerstr.toLower().trimmed() == "re(er)" || headerstr.toLower().trimmed() == "re(er')") { + return u8"re(er)"; + } + else if (headerstr.toLower().trimmed() == "im(er)" || headerstr.toLower().trimmed() == "im(er')") { + return u8"im(er)"; + } + else if (headerstr.toLower().trimmed() == "u" || headerstr.toLower().trimmed() == "u'") { + return u8"u"; + } + else if (headerstr.toLower().trimmed() == "v" || headerstr.toLower().trimmed() == "v'") { + return u8"v"; + } + else { + return u8""; + } + +; +} + +QString FEKOBase::FEKOFARFIELDFEKODATABLOCK::saveFEKOFarFieldDataBlock() +{ + + switch (this->resultType) { + case FEKOBase::GAIN: + return this->saveFEKOFarFieldDataBlock_Gain(); + case FEKOBase::DIRECTIVITY: + return this->saveFEKOFarFieldDataBlock_Directivity(); + case FEKOBase::RCS: + return this->saveFEKOFarFieldDataBlock_RCS(); + case FEKOBase::FARFIELDVALUES: + return this->saveFEKOFarFieldDataBlock_FarFieldValues(); + default: + return QString(); + } +} + +QString FEKOBase::FEKOFARFIELDFEKODATABLOCK::saveFEKOFarFieldDataBlock_Gain() +{ + return QString(); +} + +QString FEKOBase::FEKOFARFIELDFEKODATABLOCK::saveFEKOFarFieldDataBlock_Directivity() +{ + return QString(); +} + +QString FEKOBase::FEKOFARFIELDFEKODATABLOCK::saveFEKOFarFieldDataBlock_RCS() +{ + return QString(); +} + +QString FEKOBase::FEKOFARFIELDFEKODATABLOCK::saveFEKOFarFieldDataBlock_FarFieldValues() +{ + return QString(); +} diff --git a/src/LAMPTool/FEKOFarFieldFileClass.h b/src/LAMPTool/FEKOFarFieldFileClass.h new file mode 100644 index 0000000..e778bb4 --- /dev/null +++ b/src/LAMPTool/FEKOFarFieldFileClass.h @@ -0,0 +1,138 @@ +#pragma once + +#ifndef FARFIELDFILECLASS_H +#define FARFIELDFILECLASS_H +#include "referenceHeader.h" +#include "SARImage/FEKOBaseToolClass.h" + + +namespace FEKOBase { + // + // ²ÎÊý altair feko user guide 2018.1 + // ÕÂ½Ú A-10 summary of feko file formats + // + + const QString FEKOFARFIELDSPLITCHAT = u8" "; + + enum FEKOFARFIELDRESULTTYPE { + GAIN, // ÔöÒæ + DIRECTIVITY,// µç³¡ + RCS,// ºóÏòÉ¢ÉäϵÊý + FARFIELDVALUES,// Ô¶³¡Öµ + FEKOFARFIELDRESULTTYPEUNKOWN + }; + FEKOBase::FEKOFARFIELDRESULTTYPE FEKOFARFIELDRESULTTYPEString2Enum(QString str); + QString QString2FEKOFARFIELDRESULTTYPE(FEKOBase::FEKOFARFIELDRESULTTYPE mode); + + + +//========================================================== +// FEKO ·ÂÕæ½á¹ûÎļþ farfield Îļþ ffe +// ½âÎöffe Îļþ +//========================================================== + struct FEKOFarFieldFEKOFarFieldData // ·ÂÕæ½á¹ûµÄÊý¾ÝÏî £¬ÐÐ + { + double X=0;// cartesian coordinate system + double Y=0; + double Z=0; + double U=0; // cartesian coordinate system + double V=0; + double radius=0; // nearfield + double theta=0; // spherical coordinate system + double phi=0; + double re_Er=0; + double im_Er=0; + double re_Etheta=0; // theta + double im_Etheta=0; + double re_Ephi=0; // phi + double im_Ephi=0; + double re_Ex=0;// X + double im_Ex=0; + double re_Ey=0; //y + double im_Ey=0; + double re_Ez=0; //z + double im_Ez=0; + double gain_Theta=0; // gain in spherical coordinate system + double gain_Phi=0; + double gain_Total=0; + double directivity_Theta=0; // directivity in spherical coordinate system + double directivity_Phi = 0; + double directivity_total = 0; + double RCS_theta = 0;// RCS in spherical coordinate system + double RCS_phi = 0; + double RCS_total = 0; + }; + + class FEKOFARFIELDFEKODATABLOCK { // Êý¾Ý¿é + public: + FEKOFARFIELDFEKODATABLOCK(); + ~FEKOFARFIELDFEKODATABLOCK(); + public: // ±äÁ¿ + QString configurationName; + QString requestName; + double frequency; + FEKOBase::FEKOCoordinateSystem coordinateSystem; // + FEKOBase::FEKOFARFIELDRESULTTYPE resultType; + long thetaSamples; + long phiSamples; + long USamples; + long VSamples; + CartesianCoordinates Origin; // ×ø±êϵԭµã + long headerLines; + QList dataList; + public: // Ïà¹Øº¯Êý + // ½âÎöÎļþ + int paraseFEKOFarFieldDataBlock(const QString& blockstr); // ½âÎöÊý¾Ý¿é + int paraseFEKOFarFieldDataBlockFromList(QList& blockstr); // ½âÎöÊý¾Ý¿é + QString normalizationHeaderString(QString headerstr);// ¶ÔÊý¾Ý¿éÍ·Ãû³Æ½øÐбê×¼»¯ + + // ±£´æÎļþ + QString saveFEKOFarFieldDataBlock(); // Éú³ÉÊý¾Ý¿é×Ö·û´® + QString saveFEKOFarFieldDataBlock_Gain(); // ¸ù¾ÝÀàÐÍÉú³ÉÊý¾Ý¿é×Ö·û´® + QString saveFEKOFarFieldDataBlock_Directivity(); + QString saveFEKOFarFieldDataBlock_RCS(); + QString saveFEKOFarFieldDataBlock_FarFieldValues(); + }; + + + + + + + +class FEKOFarFieldFileClass: public QObject +{ + Q_OBJECT +public: + FEKOFarFieldFileClass(); + ~FEKOFarFieldFileClass(); + +public: + QString FileType; + QString FileFormat; + QString Sourcestr; + QString Datestr; + QList dataBlockList; + + +public: + void parseFarFieldFile(const QString& fileName); + void outputToFile(const QString& fileName); + +}; + + + +//========================================================== +// FEKO ·ÂÕæ½á¹ûÎļþ nearfield Îļþ efe +// ½âÎöefe Îļþ£¬ +//========================================================== + + + + + + +} +#endif // ! FARFIELDFILECLASS_H + diff --git a/src/LAMPTool/FEKOSimulationSARClass.cpp b/src/LAMPTool/FEKOSimulationSARClass.cpp new file mode 100644 index 0000000..177fcfc --- /dev/null +++ b/src/LAMPTool/FEKOSimulationSARClass.cpp @@ -0,0 +1,1125 @@ +// ÏÂÃæµÄ´úÂëÊÇÊôÐÔµÄÉèÖÃÓë»ñÈ¡£¬Çë²¹³äÍêÕû +#include "FEKOSimulationSARClass.h" +#include "BaseToolLib/BaseConstVariable.h" +#include +#include +#include +#include "BaseToollib/ImageOperatorBase.h" +#include +#include "BaseToollib/FileOperator.h" +#include +#include "BaseToollib/GeoOperator.h" + + + + +FEKOBase::FEKOSimulationSARClass::FEKOSimulationSARClass() +{ + +} + +FEKOBase::FEKOSimulationSARClass::~FEKOSimulationSARClass() +{ +} + +void FEKOBase::FEKOSimulationSARClass::generator_STRIP_FEKOSatelliteParams() +{ + qDebug() << u8"¼ÆËã Strip..."; + double incAngle = this->simulationparams->incangle; + double refRange = this->simulationparams->refRange; + double start_x = this->simulationparams->start_x; + double start_y = this->simulationparams->start_y; + double start_z = this->simulationparams->start_z; + double end_x = this->simulationparams->end_x; + double end_y = this->simulationparams->end_y; + double end_z = this->simulationparams->end_z; + size_t prfcount = this->simulationparams->prfcount; + + + double AzAngle = 0; + this->FEKOAntPoselist.clear(); + gp_Pnt apex(0, 0, 5); // ¶¥µãÔÚÈýά¿Õ¼äÖеÄ×ø±ê + gp_Pnt p1(-2, 0, 0); + gp_Pnt p2(0, -2, 0); + gp_Pnt p3(4, 0, 0); + gp_Pnt p4(0, 3, 0); + + // ´´½¨»ùµ×µÄ±ß + TopoDS_Edge edge1 = BRepBuilderAPI_MakeEdge(p1, p2); + TopoDS_Edge edge2 = BRepBuilderAPI_MakeEdge(p2, p3); + TopoDS_Edge edge3 = BRepBuilderAPI_MakeEdge(p3, p4); + TopoDS_Edge edge4 = BRepBuilderAPI_MakeEdge(p4, p1); + + // ʹÓñߴ´½¨Ò»¸ö±ÕºÏµÄÏß¿ò + BRepBuilderAPI_MakeWire makeWire; + makeWire.Add(edge1); + makeWire.Add(edge2); + makeWire.Add(edge3); + makeWire.Add(edge4); + TopoDS_Wire baseWire = makeWire.Wire(); + + // ʹÓÃÏß¿ò´´½¨Ò»¸öÃæ + BRepBuilderAPI_MakeFace makeFace(baseWire); + TopoDS_Face baseFace = makeFace.Face(); + + // ´Ó»ùµ×ÃæÏò¶¥µãÀ­É죬´´½¨ËÄÀâ×¶ + BRepPrimAPI_MakePrism makePrism(baseFace, gp_Vec(apex.XYZ() - p1.XYZ())); + TopoDS_Shape in_ds = makePrism.Shape(); + double Vx = end_x - start_x; + double Vy = end_y - start_y; + double Vz = end_z - start_z; + for (size_t i = 0; i < prfcount; i++) { + double Px = start_x + (end_x - start_x) / (prfcount - 1) * i; + double Py = start_y + (end_y - start_y) / (prfcount - 1) * i; + double Pz = start_z + (end_z - start_z) / (prfcount - 1) * i; + + // ´´½¨ SatelliteState + FEKOBase::SatelliteState satepos{ + FEKOBase::SatellitePosition{Px,Py,Pz}, + FEKOBase::SatelliteVelocity{Vx,Vy,Vz}, + }; + + FEKOBase::FEKOantPitionDirect tempdir; + TopoDS_Shape out_ds = SatellitePos2FEKOAntPos(satepos, incAngle, AzAngle, this->simulationparams->isRight, &tempdir, in_ds); + FEKOBase::FEKOSatelliteParams temp = createFEKOSatelliteParams(satepos, incAngle, AzAngle, tempdir, i); + this->FEKOAntPoselist.push_back(temp); + } + + +} + +void FEKOBase::FEKOSimulationSARClass::generator_SCAN_FEKOSatelliteParams() +{ + qDebug() << u8"¼ÆËã ScaneSAR..."; + + + double incAngle = this->simulationparams->incangle; + double refRange = this->simulationparams->refRange; + double startAzAngle = this->simulationparams->start_az_angle; + double endAzAngle = this->simulationparams->end_az_angle; + double start_x = this->simulationparams->start_x; + double start_y = this->simulationparams->start_y; + double start_z = this->simulationparams->start_z; + double end_x = this->simulationparams->end_x; + double end_y = this->simulationparams->end_y; + double end_z = this->simulationparams->end_z; + size_t prfcount = this->simulationparams->prfcount; + + + this->FEKOAntPoselist.clear(); + TopoDS_Shape in_ds; + for (size_t i = 0; i < prfcount; i++) { + double AzAngle = startAzAngle + (endAzAngle - startAzAngle) / prfcount * i; + double Px = start_x + (end_x - start_x) / (prfcount - 1) * i; + double Py = start_y + (end_y - start_y) / (prfcount - 1) * i; + double Pz = start_z + (end_z - start_z) / (prfcount - 1) * i; + double Vx = end_x - start_x; + double Vy = end_y - start_y; + double Vz = end_z - start_z; + + // ´´½¨ SatelliteState + FEKOBase::SatelliteState satepos{ + FEKOBase::SatellitePosition{Px,Py,Pz}, + FEKOBase::SatelliteVelocity{Vx,Vy,Vz}, + }; + + FEKOBase::FEKOantPitionDirect tempdir; + TopoDS_Shape out_ds = SatellitePos2FEKOAntPos(satepos, incAngle, AzAngle, this->simulationparams->isRight, &tempdir, in_ds); + FEKOBase::FEKOSatelliteParams temp = createFEKOSatelliteParams(satepos, incAngle, AzAngle, tempdir, i); + this->FEKOAntPoselist.push_back(temp); + } + +} + +void FEKOBase::FEKOSimulationSARClass::generator_ISAR_FEKOSatelliteParams() +{ + qDebug() << u8"¼ÆËã ISAR..."; + // ¼ÆËãISAR + double iangle = this->simulationparams->incangle; // ÈëÉä½Ç + double azAngle = 0; // ɨÃè½Ç±ä»¯ + double incAngle = this->simulationparams->incangle * M_PI / 180; + double deltaAngle = this->simulationparams->delta_angle * M_PI / 180; + double startAngle = this->simulationparams->start_circle_angle * M_PI / 180; + double endAngle = this->simulationparams->end_circle_angle * M_PI / 180; + + double refRange = this->simulationparams->refRange; + + + // ¼ÆËãISAR + this->FEKOAntPoselist.clear(); + double mpi_delta = (deltaAngle) / abs(deltaAngle) * M_PI / 2; + //double startangle = 0; + //double endAngle = M_PI * 2; + if (mpi_delta > 0) { // ÄæÊ±ÕëÐýת + this->simulationparams->setIsRight(false); + } + else { + this->simulationparams->setIsRight(true); + endAngle = -1 * endAngle; + } + double ZRotation_angle = M_PI - incAngle; + + size_t PRFidx = 0; + for (double angle = startAngle; angle <= endAngle; angle = angle + deltaAngle) { + double Px = refRange * sin(incAngle) * cos(angle); // ¼ÆËã×ø±ê + double Py = refRange * sin(incAngle) * sin(angle); + double Pz = refRange * cos(incAngle); + // ¼ÆËãËÙ¶ÈʸÁ¿£¬ËüÓëxyz.ÇÐÏß´¹Ö± + + gp_Vec fly_ori(gp_Pnt(Px, Py, Pz), gp_Pnt(0.0, 0.0, 0.0)); + gp_Vec fly_Z(gp_Pnt(0, 0, 0), gp_Pnt(0.0, 0.0, 1)); + gp_Vec fly_direct = fly_ori.Crossed(fly_Z); + // + double Vx = fly_direct.X(); // ¼ÆËã·ÉÐÐËÙ¶È + double Vy = fly_direct.Y(); + double Vz = fly_direct.Z(); + double theta = ZRotation_angle; + double phi = (this->simulationparams->isRight) ? -1 * angle + M_PI / 2 : angle + M_PI; // ¸ù¾ÝλÖüÆËãÈëÉä½Ç + + theta = theta * 180 / M_PI; + phi = phi * 180 / M_PI; + FEKOBase::FEKOSatelliteParams temp = FEKOBase::createFEKOSatelliteParams(Px, Py, Pz, Vx, Vy, Vz, iangle, azAngle, theta, phi, this->simulationparams->isRight, PRFidx); + this->FEKOAntPoselist.push_back(temp); + PRFidx = PRFidx + 1; + } + +} + +void FEKOBase::FEKOSimulationSARClass::generator_CircleSAR_FEKOSatelliteParams() +{ + qDebug() << u8"¼ÆËã CircleSAR..."; // ·ÉÐз½ÏòΪ Y ÖᣬÀ×´ïÖ¸ÏòΪ Z Öá + + double incAngle = this->simulationparams->incangle; + double deltaAngle = this->simulationparams->delta_angle; + double refRange = this->simulationparams->refRange; + + + double iangle = incAngle; // ÈëÉä½Ç + double azAngle = 0; // ɨÃè½Ç±ä»¯ + incAngle = incAngle * M_PI / 180; + deltaAngle = deltaAngle * M_PI / 180; + // ¼ÆËãISAR + this->FEKOAntPoselist.clear(); + double mpi_delta = (deltaAngle) / abs(deltaAngle) * M_PI / 2; + double startangle = 0; + double endAngle = M_PI * 2; + + + + if (mpi_delta > 0) { // ÄæÊ±ÕëÐýת + this->simulationparams->isRight = false; + } + else { + this->simulationparams->isRight = true; + endAngle = -1 * endAngle; + } + double ZRotation_angle = M_PI - incAngle; + + size_t PRFidx = 0; + for (double angle = 0; angle <= endAngle; angle = angle + deltaAngle) { + double Px = refRange * sin(incAngle) * cos(angle); // ¼ÆËã×ø±ê + double Py = refRange * sin(incAngle) * sin(angle); + double Pz = refRange * cos(incAngle); + // ¼ÆËãËÙ¶ÈʸÁ¿£¬ËüÓëxyz.ÇÐÏß´¹Ö± + + gp_Vec fly_ori(gp_Pnt(Px, Py, Pz), gp_Pnt(0.0, 0.0, 0.0)); + gp_Vec fly_Z(gp_Pnt(0, 0, 0), gp_Pnt(0.0, 0.0, 1)); + gp_Vec fly_direct = fly_ori.Crossed(fly_Z); + // + double Vx = fly_direct.X(); // ¼ÆËã·ÉÐÐËÙ¶È + double Vy = fly_direct.Y(); + double Vz = fly_direct.Z(); + double theta = ZRotation_angle; + double phi = (this->simulationparams->isRight) ? -1 * angle + M_PI / 2 : angle + M_PI; // ¸ù¾ÝλÖüÆËãÈëÉä½Ç + + theta = theta * 180 / M_PI; + phi = phi * 180 / M_PI; + FEKOBase::FEKOSatelliteParams temp = FEKOBase::createFEKOSatelliteParams(Px, Py, Pz, Vx, Vy, Vz, iangle, azAngle, theta, phi, this->simulationparams->isRight, PRFidx); + this->FEKOAntPoselist.push_back(temp); + PRFidx = PRFidx + 1; + } + + +} + +void FEKOBase::FEKOSimulationSARClass::generator_FEKOSatelliteParams() +{ + + switch (this->simulationparams->imagemode) + { + case FEKOBase::FEKOImageMode::Strip: + return this->generator_STRIP_FEKOSatelliteParams(); + case FEKOBase::FEKOImageMode::Scane: + return this->generator_SCAN_FEKOSatelliteParams(); + case FEKOBase::FEKOImageMode::ISAR: + return this->generator_ISAR_FEKOSatelliteParams(); + case FEKOBase::FEKOImageMode::CircleSAR: + return this->generator_CircleSAR_FEKOSatelliteParams(); + + default: + return; + } +} + + +void FEKOBase::FEKOSimulationSARClass::refreshFEKOSimulationParams() { + +} + +void FEKOBase::FEKOSimulationSARClass::setFEKOAntPoselist(std::vector FEKOAntPoselist) +{ + this->FEKOAntPoselist = FEKOAntPoselist; +} + +std::vector FEKOBase::FEKOSimulationSARClass::getFEKOAntPoselist() +{ + return this->FEKOAntPoselist; +} + +void FEKOBase::FEKOSimulationSARClass::loadFEKOImageSettingXML(QString xmlpath) +{ + + if (!isExists(xmlpath)) { + // QString newName = QInputDialog::getText(nullptr, u8"ÃüÃû", u8"³ÉÏñÈÎÎñÃû³Æ", QLineEdit::Normal); + QString newName = QInputDialog::getText(nullptr, "rename", "Image task Name", QLineEdit::Normal); + if (newName.isEmpty()) { + return; + } + this->simulationparams->setTaskName(newName); + QString parentpath = getParantFromPath(xmlpath); + this->workSpace = parentpath; + QDir dir; + if (!isExists(this->workSpace)) { + dir.mkpath(this->workSpace); + } + + this->xmlpath = xmlpath; + return; + } + QString parentpath = getParantFromPath(xmlpath); + this->workSpace = parentpath; + this->xmlpath = xmlpath; + + this->simulationparams->loadXml(xmlpath); + this->generator_FEKOSatelliteParams(); + qDebug() << u8"finish load fekoSimulation xml file."; +} + +void FEKOBase::FEKOSimulationSARClass::saveFEKOImageSettingXML() +{ + // ΪÏÂÁÐÿ¸ö½Úµã£¬¸½¼ÓÒ»¸öTextNode + if (isExists(this->xmlpath)) { + removeFile(this->xmlpath); + } + else {} + this->simulationparams->saveXml(this->xmlpath); + qDebug()<<"finish save fekoSimulation xml file."; +} + +QString FEKOBase::FEKOSimulationSARClass::createLuaSciptString(size_t startprfidx, size_t endprfidx) +{ + QProgressDialog progressDialog(u8"¹¹½¨À¡Ô´ÉèÖýű¾", u8"ÖÕÖ¹", 0, this->FEKOAntPoselist.size()); + progressDialog.setWindowTitle("imaging..."); + progressDialog.setModal(true); + progressDialog.setAutoClose(true); + progressDialog.setValue(0); + progressDialog.setMaximum(this->FEKOAntPoselist.size()); + progressDialog.setMinimum(0); + progressDialog.show(); + + if (this->simulationparams->startfreq > 1e6) { this->simulationparams->startfreq = this->simulationparams->startfreq / 1e9; } // ==> GHz + if (this->simulationparams->endfreq > 1e6) { this->simulationparams->endfreq = this->simulationparams->endfreq / 1e9; } + + + QString luascript = QString(u8"--- create feko task :%1\n--- mode:%2\n\n").arg(this->simulationparams->taskName).arg(FEKOBase::FEKOImageModeenumToString(this->simulationparams->imagemode)); + luascript = luascript + QString(u8"-- create strip pulse \n"); + luascript = luascript + QString(u8"-- LAMP \n\n"); + luascript = luascript + QString(u8"-- warning:the configure's number of a feko project should be less than 600. if greater than 600,the program will very slow\n"); + luascript = luascript + QString(u8"\n"); + luascript = luascript + QString(u8"\n"); + luascript = luascript + QString(u8"app=cf.GetApplication()\n"); + luascript = luascript + QString(u8"project=app.Project --- get current project\n"); + luascript = luascript + QString(u8"farFieldData = project.FieldDataList:AddFarFieldData(\"%1\",%2,%3) -- farField Gains\n").arg(this->simulationparams->AntennaRadiationFileName).arg(QString::number(this->simulationparams->farsource_thetaPoints)).arg(QString::number(this->simulationparams->farsource_phiPoints)); + luascript = luascript + QString(u8"\n"); + luascript = luascript + QString(u8"--const values\n"); + luascript = luascript + QString(u8"local pi=3.141592653589793238462643383279\n"); + luascript = luascript + QString(u8"local r2d=180.0/pi;\n"); + luascript = luascript + QString(u8"local d2r=pi/180.0;\n"); + luascript = luascript + QString(u8"\n"); + luascript = luascript + QString(u8"\n"); + luascript = luascript + QString(u8"\n"); + luascript = luascript + QString(u8"-- varables \n"); + luascript = luascript + QString(u8"\n"); + luascript = luascript + QString(u8"\n"); + luascript = luascript + QString(u8"local f1=%1 -- start freq\n").arg(QString::number(this->simulationparams->startfreq * 1e9)); + luascript = luascript + QString(u8"local f2=%2 -- end freq\n").arg(QString::number(this->simulationparams->endfreq * 1e9)); + luascript = luascript + QString(u8"local freq_num=%3 -- freq point \n").arg(QString::number(this->simulationparams->freqpoints)); + luascript = luascript + QString(u8"\n"); + luascript = luascript + QString(u8"--- local request_z=Rref*math.cos(in_theta*d2r) --z\n"); + luascript = luascript + QString(u8"--- local request_y=Rref*math.sin(in_theta*d2r)*math.sin(in_phi*d2r) -- y\n"); + luascript = luascript + QString(u8"--- local ant_theta= 220 --- ÌìÏßÈëÉä½Ç·½Ïò\n"); + luascript = luascript + QString(u8"--- local ant_phi=90 -- ÌìÏßÕÕÉä·½Ïò -£ºÖ¸Ïò¸ºÖá +£ºÖ¸ÏòÕýÖá\n"); + luascript = luascript + QString(u8"--- local ant_phi_start=-1.5 -- µ±Ç°¹¤³ÌµÄÆðʼµã ÌìÏßÖ¸ÏòɨÃè½Ç\n"); + luascript = luascript + QString(u8"--- local ant_phi_delta= 3/2800 -- ÕâÀïµ÷Õû²½½øÔöÁ¿Îª\n"); + luascript = luascript + QString(u8"\n"); + luascript = luascript + QString(u8"--- PRF POint Setting --- \n"); + // ------------------------------------------ ²ÎÊýÉèÖà ------------------------ + for (size_t i = startprfidx; i < this->FEKOAntPoselist.size() && i < endprfidx; i++) { + FEKOBase::FEKOSatelliteParams temp = this->FEKOAntPoselist[i]; + QString prf_id = QString::number(QString::number(temp.PRFidx).toInt()); + luascript = luascript + QString(u8" ---------------------\"PRF_%1\" start -------------------------------------------------\n").arg(prf_id); + luascript = luascript + QString(u8" PRF_phi=%1 --- ÌìÏßÕÕÉä·½Ïò\n").arg(QString::number(temp.antpos.phi)); + luascript = luascript + QString(u8" PRF_theta=%1 --- ÈëÉä½Ç\n").arg(QString::number(temp.antpos.theta)); + luascript = luascript + QString(u8" temp_standardConfiguration = project.SolutionConfigurations:AddStandardConfiguration()\n"); + luascript = luascript + QString(u8" temp_standardConfiguration.Label=\"PRF_%1\" -- set standardConfiguration label PRF Count\n").arg(prf_id); + luascript = luascript + QString(u8" --- set frequency\n"); // ÉèÖÃÆµÂÊ + luascript = luascript + QString(u8" frequencyRange=temp_standardConfiguration.Frequency\n"); + luascript = luascript + QString(u8" properties = frequencyRange:GetProperties()\n"); + luascript = luascript + QString(u8" properties.RangeType = cf.Enums.FrequencyRangeTypeEnum.LinearSpacedDiscrete\n"); + luascript = luascript + QString(u8" properties.Start = f1 -- start\n"); + luascript = luascript + QString(u8" properties.End=f2 --end \n"); + luascript = luascript + QString(u8" properties.NumberOfDiscreteValues=freq_num -- freq_num\n"); + luascript = luascript + QString(u8" frequencyRange:SetProperties(properties)\n"); + luascript = luascript + QString(u8" -- set Source\n"); + luascript = luascript + QString(u8" farFieldSource = temp_standardConfiguration.Sources:AddFarFieldSource(farFieldData)\n"); // ÉèÖ÷¢ÉäÔ´ + luascript = luascript + QString(u8" farFieldSource.Label=\"FarSource_PRF_%1\"\n").arg(prf_id); + luascript = luascript + QString(u8" farFieldSource.Position.U=%1\n").arg(QString::number(temp.antpos.x)); + luascript = luascript + QString(u8" farFieldSource.Position.V=%1\n").arg(QString::number(temp.antpos.y)); + luascript = luascript + QString(u8" farFieldSource.Position.N=%1\n").arg(QString::number(temp.antpos.z)); + luascript = luascript + QString(u8" farFieldSource.Theta=PRF_theta\n"); + luascript = luascript + QString(u8" farFieldSource.Phi=PRF_phi\n"); + luascript = luascript + QString(u8" temp_farFieldSource_workplane=farFieldSource.LocalWorkplane\n"); + luascript = luascript + QString(u8" temp_farFieldSource_workplane.Origin.X=0 -- move reference Point\n"); + luascript = luascript + QString(u8" temp_farFieldSource_workplane.Origin.Y=0\n"); + luascript = luascript + QString(u8" temp_farFieldSource_workplane.Origin.Z=0 \n"); + luascript = luascript + QString(u8"\n"); + luascript = luascript + QString(u8" -- set nearfield\n"); + luascript = luascript + QString(u8" temp_nearFieldRequest=temp_standardConfiguration.NearFields:AddSpherical(%1,%2,%3,%4,%5,%6,1,1,1) -- nearfield \n").arg(QString::number(0)) + .arg(QString::number(temp.antpos.theta)) + .arg(QString::number(temp.antpos.phi)) + .arg(QString::number(0)) + .arg(QString::number(temp.antpos.theta)) + .arg(QString::number(temp.antpos.phi)); // ÉèÖýÓÊÕµã + luascript = luascript + QString(u8" temp_nearFieldRequest.Label=\"NearField_PRF_%1\"\n").arg(prf_id); + luascript = luascript + QString(u8" temp_nearFieldRequest_workplane=temp_nearFieldRequest.LocalWorkplane\n"); + luascript = luascript + QString(u8" temp_nearFieldRequest_workplane.Origin.X=%1\n").arg(QString::number(temp.antpos.x)); + luascript = luascript + QString(u8" temp_nearFieldRequest_workplane.Origin.Y=%1\n").arg(QString::number(temp.antpos.y)); + luascript = luascript + QString(u8" temp_nearFieldRequest_workplane.Origin.Z=%1\n").arg(QString::number(temp.antpos.z)); + luascript = luascript + QString(u8" -- set nearfieldAdavance\n"); + luascript = luascript + QString(u8" temp_nearfieldAdvance=temp_nearFieldRequest.Advanced\n"); + luascript = luascript + QString(u8" temp_nearfieldAdvance.CalculationType=cf.Enums.NearFieldCalculationTypeEnum.Fields\n"); + luascript = luascript + QString(u8" temp_nearfieldAdvance.CalculateElectricFields=true\n"); + luascript = luascript + QString(u8" temp_nearfieldAdvance.CalculateMagneticFields=true\n"); + luascript = luascript + QString(u8" temp_nearfieldAdvance.ExportSettings.ASCIIEnabled=true\n"); + luascript = luascript + QString(u8" temp_nearfieldAdvance.ExportSettings.OutFileEnabled=true\n"); + luascript = luascript + QString(u8" temp_nearfieldAdvance.OnlyScatteredPartCalculationEnabled=true \n"); + luascript = luascript + QString(u8" \n"); + luascript = luascript + QString(u8" \n"); + luascript = luascript + QString(u8"\n"); + luascript = luascript + QString(u8" -- \n"); + luascript = luascript + QString(u8" print(\"PRF_%1\")\n").arg(prf_id); + luascript = luascript + QString(u8" ---------------------\"PRF_%1\" end -------------------------------------------------\n").arg(prf_id); + luascript = luascript + QString(u8"\n"); + progressDialog.setValue(i); + } + luascript = luascript + QString(u8"-- prf point setting over -------\n"); + luascript = luascript + QString(u8" \n"); + + progressDialog.setWindowTitle(u8"À¡Ô´½Å±¾Éú²ú³É¹¦" ); + progressDialog.setValue(this->FEKOAntPoselist.size()); + progressDialog.close(); + + return luascript; +} + + + +bool FEKOBase::FEKOImageProcess(EchoDataClass& echodata, FEKOImageSettingParams& imageSettingParams, QString& outPath, FEKOImageAlgorithm algmethod, ImageAlgWindowFun winfun) +{ + Eigen::MatrixXcd echoData = echodata.getEchoData(); + Eigen::MatrixXd antpos = echodata.getAntPos(); + Eigen::MatrixXd freqmatrix = Eigen::MatrixXd::Zero(1, echoData.cols()); + Eigen::MatrixXd Image_X = Eigen::MatrixXd::Zero(imageSettingParams.ImageHeight, imageSettingParams.ImageWidth); + Eigen::MatrixXd Image_Y = Eigen::MatrixXd::Zero(imageSettingParams.ImageHeight, imageSettingParams.ImageWidth); + Eigen::MatrixXd Image_Z = Eigen::MatrixXd::Zero(imageSettingParams.ImageHeight, imageSettingParams.ImageWidth); + size_t prfcount = echoData.rows(); + size_t frepoints = echodata.getFreqpoints(); + if (frepoints != echoData.cols() || prfcount != antpos.rows()) { + QString infotip = u8"»Ø²¨¾ØÕó ´óС²»Æ¥Å䣺" + QString(u8"»Ø²¨Âö³åÊý£º%1£¬Êµ¼Ê£º%2£»»Ø²¨ÆµµãÊý£º%3£¬Êµ¼Ê£º%4") + .arg(QString::number(prfcount)). + arg(QString::number(antpos.rows())) + .arg(QString::number(echoData.cols())) + .arg(QString::number(frepoints)); +# ifdef __SHOWPROCESS + QMessageBox::warning(nullptr, u8"´íÎó", infotip); +#endif // __SHOWPROCESS + qWarning() << infotip; + return false; + } + + // ¹¹½¨ÆµÂʾØÕó + double startfreq = echodata.getFreqStart(); + double endfreq = echodata.getFreqEnd(); + if (startfreq > 1e5) { startfreq = startfreq * 1e-9; } // ƵÂʵ¥Î»½øÐÐת»» Hz->GHz + if (endfreq > 1e5) { endfreq = endfreq * 1e-9; } + freqmatrix = Eigen::ArrayXd::LinSpaced(frepoints, startfreq, endfreq).array().reshaped(1, frepoints).array(); + + // ¹¹½¨Í¼Ïñ×ø±ê¾ØÕó + size_t imageHeight = imageSettingParams.ImageHeight; // Y ·½Ïò + size_t imageWidth = imageSettingParams.ImageWidth; // X ·½Ïò + + + + + for (size_t i = 0; i < imageHeight; i++) { + Image_X.row(i) = Eigen::ArrayXd::LinSpaced(imageWidth, imageSettingParams.min_x, imageSettingParams.max_x); + } + + for (size_t i = 0; i < imageWidth; i++) { + Image_Y.col(i) = Eigen::ArrayXd::LinSpaced(imageHeight, imageSettingParams.max_y, imageSettingParams.min_y); + } + Image_Z = Image_Z.array() * 0 + imageSettingParams.plane_z; + + //std::cout << Image_X.row(0) << std::endl; + //std::cout << Image_Y.col(0) << std::endl; + switch (algmethod) + { + case FEKOBase::TBP_TIME: + return FEKOBase::BPImage_TIME(outPath, echoData, antpos, freqmatrix, Image_X, Image_Y, Image_Z, winfun); + case FEKOBase::TBP_FREQ: + return FEKOBase::FBPImage_FREQ(outPath, echoData, antpos, freqmatrix, Image_X, Image_Y, Image_Z, winfun); + default: + return false; + } + return false; +} + + +FEKOBase::FEKOImageProcessAbstractClass::FEKOImageProcessAbstractClass() +{ +} + +FEKOBase::FEKOImageProcessAbstractClass::~FEKOImageProcessAbstractClass() +{ +} + +void FEKOBase::FEKOImageProcessAbstractClass::setEchoData(EchoDataClass echodata) +{ + this->echodata = echodata; +} + +FEKOBase::EchoDataClass FEKOBase::FEKOImageProcessAbstractClass::getEchoData() const +{ + + FEKOBase::EchoDataClass res; ; + res.setEchoData(this->echodata.getEchoData()); + res.setAntPos(this->echodata.getAntPos()); + res.setFreqStart(this->echodata.getFreqStart()); + res.setFreqEnd(this->echodata.getFreqEnd()); + res.setFreqpoints(this->echodata.getFreqpoints()); + return res; +} + +void FEKOBase::FEKOImageProcessAbstractClass::setImageSettingParams(FEKOImageSettingParams imageSettingParams) +{ +} + +FEKOBase::FEKOImageSettingParams FEKOBase::FEKOImageProcessAbstractClass::getImageSettingParams() +{ + return this->imageSettingParams; +} + +void FEKOBase::FEKOImageProcessAbstractClass::setAlgmethod(FEKOImageAlgorithm algmethod) { + this->algmethod = algmethod; +} + +FEKOBase::FEKOImageAlgorithm FEKOBase::FEKOImageProcessAbstractClass::getAlgmethod() +{ + return this->algmethod; + +} + +void FEKOBase::FEKOImageProcessAbstractClass::settiffPath(QString outtiffPath) +{ + this->tiffPath = outtiffPath; +} + +QString FEKOBase::FEKOImageProcessAbstractClass::gettiffPath() +{ + return this->tiffPath; +} + +void FEKOBase::FEKOImageProcessAbstractClass::LoadEchoDataPath(QString echoPath) +{ + EchoDataClass echodata; + echodata.loadEchoData(echoPath); + //this->setEchoData(echodata); + this->echodata = echodata; +} + +bool FEKOBase::FEKOImageProcessAbstractClass::Imageprocess() +{ + return FEKOImageProcess(this->echodata, this->imageSettingParams, this->tiffPath, this->algmethod); +} + +FEKOBase::FEKOSimulationDataparams::FEKOSimulationDataparams(QObject* parent ): QObject(parent) +{ // ³õʼ»¯³ÉÔ±±äÁ¿ + this->taskName = u8"TaskName"; + this->imagemode = FEKOBase::FEKOImageMode::Strip; + this->isRight = true; + this->refRange = 9.3; + this->incangle = 0; + this->centerFreq = 9.6; + this->bandwidth = 0.8; + this->rangeResolution = LIGHESPEEDGHZ/ this->bandwidth/2.0; + + this->startfreq = 9.2; + this->endfreq = 10; + this->freqpoints = 41; + this->x_min = -2; + this->x_max = 2; + this->y_min = -2; + this->y_max = 2; + this->z_plane = 0; + this->imageheight = 251; + this->imagewidth = 251; + this->prfcount = 101; + this->start_x = -10; + this->end_x = 10; + this->start_y = 10; + this->end_y = 10; + this->start_z = 0; + this->end_z = 0; + this->start_az_angle = 0; + this->end_az_angle = 0; + this->delta_angle = 0; + this->start_circle_angle = 0; + this->end_circle_angle = 0; + this->farsource_thetaPoints = 37; + this->farsource_phiPoints = 73; + this->AntennaRadiationFileName = u8"TESTFarSource"; +} + +FEKOBase::FEKOSimulationDataparams::~FEKOSimulationDataparams() +{ +} + + +QString FEKOBase::FEKOSimulationDataparams::getTaskName() { + return taskName; +} + +void FEKOBase::FEKOSimulationDataparams::setTaskName(QString name) { + taskName = name; +} + +FEKOBase::FEKOImageMode FEKOBase::FEKOSimulationDataparams::getImagemode() { + return imagemode; +} + +void FEKOBase::FEKOSimulationDataparams::setImagemode(FEKOBase::FEKOImageMode mode) { + imagemode = mode; +} + +bool FEKOBase::FEKOSimulationDataparams::getIsRight() { + return isRight; +} + +void FEKOBase::FEKOSimulationDataparams::setIsRight(bool right) { + isRight = right; +} + +double FEKOBase::FEKOSimulationDataparams::getRefRange() { + return refRange; +} + +void FEKOBase::FEKOSimulationDataparams::setRefRange(double range) { + refRange = range; +} + +double FEKOBase::FEKOSimulationDataparams::getIncangle() { + return incangle; +} + +void FEKOBase::FEKOSimulationDataparams::setIncangle(double angle) { + incangle = angle; +} + +double FEKOBase::FEKOSimulationDataparams::getCenterFreq() { + return centerFreq; +} + +void FEKOBase::FEKOSimulationDataparams::setCenterFreq(double freq) { + centerFreq = freq; +} + +double FEKOBase::FEKOSimulationDataparams::getRangeResolution() { + return rangeResolution; +} + +void FEKOBase::FEKOSimulationDataparams::setRangeResolution(double resolution) { + rangeResolution = resolution; +} + +double FEKOBase::FEKOSimulationDataparams::getBandwidth() { + return bandwidth; +} + +void FEKOBase::FEKOSimulationDataparams::setBandwidth(double bw) { + bandwidth = bw; +} + +double FEKOBase::FEKOSimulationDataparams::getStartfreq() { + return startfreq; +} + +void FEKOBase::FEKOSimulationDataparams::setStartfreq(double start) { + startfreq = start; +} + +double FEKOBase::FEKOSimulationDataparams::getEndfreq() { + return endfreq; +} + +void FEKOBase::FEKOSimulationDataparams::setEndfreq(double end) { + endfreq = end; +} + +double FEKOBase::FEKOSimulationDataparams::getFreqpoints() { + return freqpoints; +} + +void FEKOBase::FEKOSimulationDataparams::setFreqpoints(double points) { + freqpoints = points; +} + +double FEKOBase::FEKOSimulationDataparams::getX_min() { + return x_min; +} + +void FEKOBase::FEKOSimulationDataparams::setX_min(double xmin) { + x_min = xmin; +} + +double FEKOBase::FEKOSimulationDataparams::getX_max() { + return x_max; +} + +void FEKOBase::FEKOSimulationDataparams::setX_max(double xmax) { + x_max = xmax; +} + +double FEKOBase::FEKOSimulationDataparams::getY_min() { + return y_min; +} + +void FEKOBase::FEKOSimulationDataparams::setY_min(double ymin) { + y_min = ymin; +} + +double FEKOBase::FEKOSimulationDataparams::getY_max() { + return y_max; +} + +void FEKOBase::FEKOSimulationDataparams::setY_max(double ymax) { + y_max = ymax; +} + +double FEKOBase::FEKOSimulationDataparams::getZ_plane() { + return z_plane; +} + +void FEKOBase::FEKOSimulationDataparams::setZ_plane(double z) { + z_plane = z; +} + +size_t FEKOBase::FEKOSimulationDataparams::getImageheight() { + return imageheight; +} + +void FEKOBase::FEKOSimulationDataparams::setImageheight(size_t height) { + imageheight = height; +} + +size_t FEKOBase::FEKOSimulationDataparams::getImagewidth() { + return imagewidth; +} + +void FEKOBase::FEKOSimulationDataparams::setImagewidth(size_t width) { + imagewidth = width; +} + +size_t FEKOBase::FEKOSimulationDataparams::getPRFCount() { + return prfcount; +} + +void FEKOBase::FEKOSimulationDataparams::setPRFCount(size_t count) { + prfcount = count; +} + +double FEKOBase::FEKOSimulationDataparams::getStart_x() { + return start_x; +} + +void FEKOBase::FEKOSimulationDataparams::setStart_x(double startx) { + start_x = startx; +} + +double FEKOBase::FEKOSimulationDataparams::getEnd_x() { + return end_x; +} + +void FEKOBase::FEKOSimulationDataparams::setEnd_x(double endx) { + end_x = endx; +} + +double FEKOBase::FEKOSimulationDataparams::getStart_y() { + return start_y; +} + +void FEKOBase::FEKOSimulationDataparams::setStart_y(double starty) { + start_y = starty; +} + +double FEKOBase::FEKOSimulationDataparams::getEnd_y() { + return end_y; +} + +void FEKOBase::FEKOSimulationDataparams::setEnd_y(double endy) { + end_y = endy; +} + +double FEKOBase::FEKOSimulationDataparams::getStart_z() { + return start_z; +} + +void FEKOBase::FEKOSimulationDataparams::setStart_z(double startz) { + start_z = startz; +} + +double FEKOBase::FEKOSimulationDataparams::getEnd_z() { + return end_z; +} + +void FEKOBase::FEKOSimulationDataparams::setEnd_z(double endz) { + end_z = endz; +} + +double FEKOBase::FEKOSimulationDataparams::getStart_az_angle() { + return start_az_angle; +} + +void FEKOBase::FEKOSimulationDataparams::setStart_az_angle(double startAngle) { + start_az_angle = startAngle; +} + +double FEKOBase::FEKOSimulationDataparams::getEnd_az_angle() { + return end_az_angle; +} + +void FEKOBase::FEKOSimulationDataparams::setEnd_az_angle(double endAngle) { + end_az_angle = endAngle; +} + +double FEKOBase::FEKOSimulationDataparams::getStart_circle_angle() { + return start_circle_angle; +} + +void FEKOBase::FEKOSimulationDataparams::setStart_circle_angle(double startAngle) { + start_circle_angle = startAngle; +} + +double FEKOBase::FEKOSimulationDataparams::getEnd_circle_angle() { + return end_circle_angle; +} + +void FEKOBase::FEKOSimulationDataparams::setEnd_circle_angle(double endAngle) { + end_circle_angle = endAngle; +} + +double FEKOBase::FEKOSimulationDataparams::getDelta_angle() { + return delta_angle; +} + +void FEKOBase::FEKOSimulationDataparams::setDelta_angle(double delta) { + delta_angle = delta; +} + + +// »ñȡԶ³ÌÌìÏßµÈЧ·øÉä·½ÏòͼÎļþµØÖ· +QString FEKOBase::FEKOSimulationDataparams::getAntennaRadiationFileName() { + return AntennaRadiationFileName; +} + +// ÉèÖÃÔ¶³ÌÌìÏßµÈЧ·øÉä·½ÏòͼÎļþµØÖ· +void FEKOBase::FEKOSimulationDataparams::setAntennaRadiationFileName(QString AntennaRadiationFileName) { + AntennaRadiationFileName = AntennaRadiationFileName; +} + +// »ñȡԶ³ÌÌìÏßµÈЧ·øÉä·½ÏòͼµÄ thetaPoints +long FEKOBase::FEKOSimulationDataparams::getFarsourceThetaPoints() { + return farsource_thetaPoints; +} + +// ÉèÖÃÔ¶³ÌÌìÏßµÈЧ·øÉä·½ÏòͼµÄ thetaPoints +void FEKOBase::FEKOSimulationDataparams::setFarsourceThetaPoints(long thetaPoints) { + farsource_thetaPoints = thetaPoints; +} + +// »ñȡԶ³ÌÌìÏßµÈЧ·øÉä·½ÏòͼµÄ phiPoints +long FEKOBase::FEKOSimulationDataparams::getFarsourcePhiPoints() { + return farsource_phiPoints; +} + +// ÉèÖÃÔ¶³ÌÌìÏßµÈЧ·øÉä·½ÏòͼµÄ phiPoints +void FEKOBase::FEKOSimulationDataparams::setFarsourcePhiPoints(long phiPoints) { + farsource_phiPoints = phiPoints; +} + + +// ¸ù¾ÝFEKOBase::FEKOSimulationDataparams ¹¹½¨xml,²¢Ìṩ loadxml£¬savexml º¯Êý£¬copilot ¼ÌÐø²»ÒªÒ»ÐÐÐУ¬ÒªÈ«²¿³öÀ´£¬Èç¹ûÒ»´Î»á»°¸ã²»¶¨£¬¾Í·Ö¶à¸ö»á»° + +void FEKOBase::FEKOSimulationDataparams::CalFEKOSimulationFreqParams(double centerFreq, double resolution, double bandWidth, double scenceRange, bool isResolution) +{ +} + +void FEKOBase::FEKOSimulationDataparams::updateFEKOSimulationFreqParams(double startfreq, double endfreq, size_t freqpoints) +{ +} + +void FEKOBase::FEKOSimulationDataparams::loadXml(const QString& fileName) { + QFile file(fileName); + if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { + //QMessageBox::warning(nullptr, u8"¾¯¸æ", u8"ÎÞ·¨´ò¿ªÎļþ"); + QMessageBox::warning(nullptr, tr("warning"), tr("File not found")); + return; + } + + QXmlStreamReader xmlReader(&file); + + while (!xmlReader.atEnd() && !xmlReader.hasError()) { + xmlReader.readNext(); + + if (xmlReader.isStartElement()) { + if (xmlReader.name() == "TaskName") { + xmlReader.readNext(); + taskName = xmlReader.text().toString(); + } + else if (xmlReader.name() == "ImageMode") { + xmlReader.readNext(); + imagemode = static_cast(xmlReader.text().toInt()); + } + else if (xmlReader.name() == "IsRight") { + xmlReader.readNext(); + + isRight = (xmlReader.text().toString().toLower().compare(u8"true") == 0); + } + else if (xmlReader.name() == "RefRange") { + xmlReader.readNext(); + refRange = xmlReader.text().toDouble(); + } + else if (xmlReader.name() == "IncAngle") { + xmlReader.readNext(); + incangle = xmlReader.text().toDouble(); + } + else if (xmlReader.name() == "CenterFreq") { + xmlReader.readNext(); + centerFreq = xmlReader.text().toDouble(); + } + else if (xmlReader.name() == "RangeResolution") { + xmlReader.readNext(); + rangeResolution = xmlReader.text().toDouble(); + } + else if (xmlReader.name() == "Bandwidth") { + xmlReader.readNext(); + bandwidth = xmlReader.text().toDouble(); + } + else if (xmlReader.name() == "Startfreq") { + xmlReader.readNext(); + startfreq = xmlReader.text().toDouble(); + } + else if (xmlReader.name() == "Endfreq") { + xmlReader.readNext(); + endfreq = xmlReader.text().toDouble(); + } + else if (xmlReader.name() == "Freqpoints") { + xmlReader.readNext(); + freqpoints = xmlReader.text().toDouble(); + } + else if (xmlReader.name() == "X_min") { + xmlReader.readNext(); + x_min = xmlReader.text().toDouble(); + } + else if (xmlReader.name() == "X_max") { + xmlReader.readNext(); + x_max = xmlReader.text().toDouble(); + } + else if (xmlReader.name() == "Y_min") { + xmlReader.readNext(); + y_min = xmlReader.text().toDouble(); + } + else if (xmlReader.name() == "Y_max") { + xmlReader.readNext(); + y_max = xmlReader.text().toDouble(); + } + else if (xmlReader.name() == "Z_plane") { + xmlReader.readNext(); + z_plane = xmlReader.text().toDouble(); + } + else if (xmlReader.name() == "Imageheight") { + xmlReader.readNext(); + imageheight = xmlReader.text().toInt(); + } + else if (xmlReader.name() == "Imagewidth") { + xmlReader.readNext(); + imagewidth = xmlReader.text().toInt(); + } + else if (xmlReader.name() == "PRFCount") { + xmlReader.readNext(); + prfcount = xmlReader.text().toInt(); + } + else if (xmlReader.name() == "Start_x") { + xmlReader.readNext(); + start_x = xmlReader.text().toDouble(); + } + else if (xmlReader.name() == "End_x") { + xmlReader.readNext(); + end_x = xmlReader.text().toDouble(); + } + else if (xmlReader.name() == "Start_y") { + xmlReader.readNext(); + start_y = xmlReader.text().toDouble(); + } + else if (xmlReader.name() == "End_y") { + xmlReader.readNext(); + end_y = xmlReader.text().toDouble(); + } + else if (xmlReader.name() == "Start_z") { + xmlReader.readNext(); + start_z = xmlReader.text().toDouble(); + } + else if (xmlReader.name() == "End_z") { + xmlReader.readNext(); + end_z = xmlReader.text().toDouble(); + } + else if (xmlReader.name() == "Start_az_angle") { + xmlReader.readNext(); + start_az_angle = xmlReader.text().toDouble(); + } + else if (xmlReader.name() == "End_az_angle") { + xmlReader.readNext(); + end_az_angle = xmlReader.text().toDouble(); + } + else if (xmlReader.name() == "Start_circle_angle") { + xmlReader.readNext(); + start_circle_angle = xmlReader.text().toDouble(); + } + else if (xmlReader.name() == "End_circle_angle") { + xmlReader.readNext(); + end_circle_angle = xmlReader.text().toDouble(); + } + else if (xmlReader.name() == "Delta_angle") { + xmlReader.readNext(); + delta_angle = xmlReader.text().toDouble(); + } + else if (xmlReader.name() == "AntennaRadiationFileName") { + xmlReader.readNext(); + AntennaRadiationFileName = xmlReader.text().toString(); + } + else if (xmlReader.name() == "FarsourceThetaPoints") { + xmlReader.readNext(); + farsource_thetaPoints = xmlReader.text().toLong(); + } + else if (xmlReader.name() == "FarsourcePhiPoints") { + xmlReader.readNext(); + farsource_phiPoints = xmlReader.text().toLong(); + } + } + } + + file.close(); +} + +void FEKOBase::FEKOSimulationDataparams::saveXml(const QString& fileName) { + QFile file(fileName); + if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) { + QMessageBox::warning(nullptr, "warning", "File not open"); + return; + } + + QXmlStreamWriter xmlWriter(&file); + xmlWriter.setAutoFormatting(true); + xmlWriter.writeStartDocument(); + xmlWriter.writeStartElement("FEKOSimulationDataparams"); + xmlWriter.writeTextElement("TaskName", taskName); + xmlWriter.writeTextElement("ImageMode", QString::number(static_cast(imagemode))); + xmlWriter.writeTextElement("IsRight", isRight ? "true" : "false"); + xmlWriter.writeTextElement("RefRange", QString::number(refRange)); + xmlWriter.writeTextElement("IncAngle", QString::number(incangle)); + xmlWriter.writeTextElement("CenterFreq", QString::number(centerFreq)); + xmlWriter.writeTextElement("RangeResolution", QString::number(rangeResolution)); + xmlWriter.writeTextElement("Bandwidth", QString::number(bandwidth)); + xmlWriter.writeTextElement("Startfreq", QString::number(startfreq)); + xmlWriter.writeTextElement("Endfreq", QString::number(endfreq)); + xmlWriter.writeTextElement("Freqpoints", QString::number(freqpoints)); + xmlWriter.writeTextElement("X_min", QString::number(x_min)); + xmlWriter.writeTextElement("X_max", QString::number(x_max)); + xmlWriter.writeTextElement("Y_min", QString::number(y_min)); + xmlWriter.writeTextElement("Y_max", QString::number(y_max)); + xmlWriter.writeTextElement("Z_plane", QString::number(z_plane)); + xmlWriter.writeTextElement("Imageheight", QString::number(imageheight)); + xmlWriter.writeTextElement("Imagewidth", QString::number(imagewidth)); + xmlWriter.writeTextElement("PRFCount", QString::number(prfcount)); + xmlWriter.writeTextElement("Start_x", QString::number(start_x)); + xmlWriter.writeTextElement("End_x", QString::number(end_x)); + xmlWriter.writeTextElement("Start_y", QString::number(start_y)); + xmlWriter.writeTextElement("End_y", QString::number(end_y)); + xmlWriter.writeTextElement("Start_z", QString::number(start_z)); + xmlWriter.writeTextElement("End_z", QString::number(end_z)); + xmlWriter.writeTextElement("Start_az_angle", QString::number(start_az_angle)); + xmlWriter.writeTextElement("End_az_angle", QString::number(end_az_angle)); + xmlWriter.writeTextElement("Start_circle_angle", QString::number(start_circle_angle)); + xmlWriter.writeTextElement("End_circle_angle", QString::number(end_circle_angle)); + xmlWriter.writeTextElement("Delta_angle", QString::number(delta_angle)); + + xmlWriter.writeTextElement("AntennaRadiationFileName", AntennaRadiationFileName); + xmlWriter.writeTextElement("FarsourceThetaPoints", QString::number(farsource_thetaPoints)); + xmlWriter.writeTextElement("FarsourcePhiPoints", QString::number(farsource_phiPoints)); + + + + xmlWriter.writeEndElement(); // ¹Ø±ÕFEKOSimulationDataparamsÔªËØ + xmlWriter.writeEndDocument(); + + file.close(); + + +} + +FEKOBase::FEKOSimulationDataparamsHandler::FEKOSimulationDataparamsHandler() +{ + +} + +FEKOBase::FEKOSimulationDataparamsHandler::~FEKOSimulationDataparamsHandler() +{ +} + +void FEKOBase::FEKOSimulationDataparamsHandler::setFEKOSimulationDataparams(std::shared_ptr simulationparams) +{ + this->simulationparams = simulationparams; + this->bandingsetFEKOSimulationDataparams(); +} + +std::shared_ptr FEKOBase::FEKOSimulationDataparamsHandler::getFEKOSimulationDataparams() +{ + return this->simulationparams; +} + +void FEKOBase::FEKOSimulationDataparamsHandler::bandingsetFEKOSimulationDataparams() +{ + +} + + + \ No newline at end of file diff --git a/src/LAMPTool/FEKOSimulationSARClass.h b/src/LAMPTool/FEKOSimulationSARClass.h new file mode 100644 index 0000000..2cc5ebe --- /dev/null +++ b/src/LAMPTool/FEKOSimulationSARClass.h @@ -0,0 +1,259 @@ +#pragma once +/* +* FEKO_SIMULAION_SAR_CLASS ÊÇÊÊÅäFEKO³ÉÏñËã·¨ +* FEKOSimulationSARClass +* +*/ +#ifndef FEKO_SIMULATION_SAR_CLASS_H +#define FEKO_SIMULATION_SAR_CLASS_H + +#include "referenceHeader.h" +#include "OCCTBase.h" +#include "BaseToollib/GeoOperator.h" +#include "SARImage/FEKOBaseToolClass.h" +#include "SARBaseToolLib/SARImageBase.h" + +#include + +namespace FEKOBase { + + //========================================================== + // FEKO³ÉÏñ·ÂÕæ²ÎÊýÀà + //========================================================== + class FEKOSimulationDataparams:public QObject + { // ·ÂÕæ²ÎÊýÀà + Q_OBJECT + + public: + FEKOSimulationDataparams(QObject* parent=nullptr); + ~FEKOSimulationDataparams(); + + signals: + void FEKOSimulationDataparamsChanged(); // ÏìӦʱ¼ä£¬×÷Ϊһ¸ö²ÎÊý·Ö·¢ + + public: // ƵÂʸüР+ void CalFEKOSimulationFreqParams(double centerFreq, double resolution, double bandWidth, double scenceRange, bool isResolution = false); + void updateFEKOSimulationFreqParams(double startfreq, double endfreq, size_t freqpoints); + + + public: + void loadXml(const QString& fileName); + void saveXml(const QString& fileName); + + + public: // ÊôÐÔ×Ö¶Î + QString taskName; // ÈÎÎñÃû³Æ + FEKOImageMode imagemode; // ³ÉÏñʱ¼ä + QString AntennaRadiationFileName; // Ô¶³ÌÌìÏßµÈЧ·øÉä·½ÏòͼÎļþµØÖ· + long farsource_thetaPoints; + long farsource_phiPoints; + + + bool isRight = false; // ÊÇ·ñΪÓÒÊÓ + double refRange;// ²Î¿¼¾àÀë m + double incangle; // ÈëÉä½Ç ¡ã + + double centerFreq; // ÖÐÐÄÆµÂÊ + double rangeResolution;//·Ö±æÂÊ + double bandwidth;// ´ø¿í + + double startfreq; // ƵÂʲÎÊý + double endfreq; + double freqpoints; + + + //³ÉÏñ³¡¾°ÉèÖà + double x_min; + double x_max; + double y_min; + double y_max; + double z_plane; + + size_t imageheight; // ͼÏñ¸ß¶È + size_t imagewidth; // ͼÏñ¿í¶È + + // Ìõ´øÄ£Ê½²ÎÊý + size_t prfcount; // Âö³åÊýÁ¿ + double start_x; + double end_x; + double start_y; + double end_y; + double start_z; + double end_z; + + // ɨÃèģʽ²ÎÊý + double start_az_angle; // ɨÃèÆðʼ½Ç + double end_az_angle; // ɨÃèÖÕÖ¹½Ç + + + // ISARģʽ²ÎÊý , Ô²¼£Ä£Ê½²ÎÊý + double start_circle_angle; // ÆðʼɨÃè½Ç + double end_circle_angle; // ÖÕֹɨÃè½Ç + double delta_angle;// ɨÃè½Ç¼ä¸ô + + public: + void setTaskName(QString taskName); + QString getTaskName(); + // ³ÉÏñģʽ + void setImagemode(FEKOImageMode imagemode); + FEKOImageMode getImagemode(); + // ÊÇ·ñΪÓÒÊÓ + void setIsRight(bool isRight); + bool getIsRight(); + // ²Î¿¼¾àÀë + void setRefRange(double refRange); + double getRefRange(); + // ÈëÉä½Ç + void setIncangle(double incangle); + double getIncangle(); + // ÖÐÐÄÆµÂÊ + void setCenterFreq(double centerFreq); + double getCenterFreq(); + // ·Ö±æÂÊ + void setRangeResolution(double rangeResolution); + double getRangeResolution(); + // ´ø¿í + void setBandwidth(double bandwidth); + double getBandwidth(); + // ƵÂʲÎÊý + void setStartfreq(double startfreq); + double getStartfreq(); + void setEndfreq(double endfreq); + double getEndfreq(); + void setFreqpoints(double freqpoints); + double getFreqpoints(); + // ³ÉÏñ·¶Î§ + void setX_min(double x_min); + double getX_min(); + void setX_max(double x_max); + double getX_max(); + void setY_min(double y_min); + double getY_min(); + void setY_max(double y_max); + double getY_max(); + void setZ_plane(double z_plane); + double getZ_plane(); + // ͼÏñ¸ß¶È + void setImageheight(size_t imageheight); + size_t getImageheight(); + // ͼÏñ¿í¶È + void setImagewidth(size_t imagewidth); + size_t getImagewidth(); + // Ìõ´øÄ£Ê½²ÎÊý + void setPRFCount(size_t prfcount); + size_t getPRFCount(); + void setStart_x(double start_x); + double getStart_x(); + void setEnd_x(double end_x); + double getEnd_x(); + void setStart_y(double start_y); + double getStart_y(); + void setEnd_y(double end_y); + double getEnd_y(); + void setStart_z(double start_z); + double getStart_z(); + void setEnd_z(double end_z); + double getEnd_z(); + double getStart_az_angle(); // ɨÃèÆðʼ½Ç + double getEnd_az_angle(); // ɨÃèÖÕÖ¹½Ç + double getStart_circle_angle(); // ÆðʼɨÃè½Ç + double getEnd_circle_angle(); // ÖÕֹɨÃè½Ç + double getDelta_angle();// ɨÃè½Ç¼ä¸ô + + void setStart_az_angle(double Start_az_angle); // ɨÃèÆðʼ½Ç + void setEnd_az_angle(double End_az_angle); // ɨÃèÖÕÖ¹½Ç + void setStart_circle_angle(double Start_circle_angle); // ÆðʼɨÃè½Ç + void setEnd_circle_angle(double End_circle_angle); // ÖÕֹɨÃè½Ç + void setDelta_angle(double Delta_angle);// ɨÃè½Ç¼ä¸ô + + QString getAntennaRadiationFileName(); + void setAntennaRadiationFileName( QString path); + long getFarsourceThetaPoints(); + void setFarsourceThetaPoints(long thetaPoints); + long getFarsourcePhiPoints(); + void setFarsourcePhiPoints(long phiPoints); + + }; + + class FEKOSimulationDataparamsHandler { + + public: + FEKOSimulationDataparamsHandler(); + ~FEKOSimulationDataparamsHandler(); + public: + std::shared_ptr simulationparams; + void setFEKOSimulationDataparams(std::shared_ptr simulationparams); + std::shared_ptr getFEKOSimulationDataparams(); + + public: + virtual void bandingsetFEKOSimulationDataparams(); + }; + + //========================================================== + // FEKO·ÂÕæ³ÉÏñ²ÎÊýÀà + // ½âÎö³ÉÏñ²ÎÊýxml + //========================================================== + class FEKOSimulationSARClass : public FEKOSimulationDataparamsHandler + { + public: + FEKOSimulationSARClass(); + ~FEKOSimulationSARClass(); + + public: + std::vector FEKOAntPoselist;// FEKOµÄÌìÏß²ÎÊýÉèÖà + void setFEKOAntPoselist(std::vector FEKOAntPoselist); // FEKOµÄÌìÏß²ÎÊýÉèÖà + std::vector getFEKOAntPoselist(); + + public: + void generator_STRIP_FEKOSatelliteParams(); + void generator_SCAN_FEKOSatelliteParams(); + void generator_ISAR_FEKOSatelliteParams(); + void generator_CircleSAR_FEKOSatelliteParams(); + void generator_FEKOSatelliteParams(); + + virtual void refreshFEKOSimulationParams(); + + public: + QString workSpace; // ¹¤×÷¿Õ¼ä + QString AntennaRadiationPath; // Ô¶³ÌÌìÏßµÈЧ·øÉä·½ÏòͼÎļþµØÖ· + QString xmlpath; + public : // ³õʼ»¯Ä£ÐÍ + void loadFEKOImageSettingXML(QString xmlpath); + void saveFEKOImageSettingXML(); + QString createLuaSciptString(size_t startprfidx, size_t endprfidx); + }; + + //========================================================== + // FEKO³ÉÏñ + //========================================================== + + bool FEKOImageProcess(EchoDataClass& echodata, FEKOImageSettingParams& imageSettingParams, QString& outPath, FEKOImageAlgorithm algmethod = FEKOImageAlgorithm::TBP_FREQ, ImageAlgWindowFun winfun = ImageAlgWindowFun::HANMMING); + + class FEKOImageProcessAbstractClass { + + public: + FEKOImageProcessAbstractClass(); + ~FEKOImageProcessAbstractClass(); + private: + EchoDataClass echodata; // ԭʼ»Ø²¨Êý¾Ý - + FEKOImageSettingParams imageSettingParams; // ³ÉÏñ²ÎÊý + FEKOImageAlgorithm algmethod; // ³ÉÏñËã·¨ + QString tiffPath; + public: + // ¹¹½¨Óë³ÉÔ±±äÁ¿ÓйصÄÊôÐÔº¯Êý + void setEchoData(EchoDataClass echodata); + EchoDataClass getEchoData() const; + void setImageSettingParams(FEKOImageSettingParams imageSettingParams); + FEKOImageSettingParams getImageSettingParams(); + void setAlgmethod(FEKOImageAlgorithm algmethod); + FEKOImageAlgorithm getAlgmethod(); + void settiffPath(QString outtiffPath); + QString gettiffPath(); + void LoadEchoDataPath(QString echoPath); + public: // ³ÉÏñ²ÎÊý + bool Imageprocess(); + }; +}; + + +#endif \ No newline at end of file diff --git a/src/LAMPTool/LAMPTool.cpp b/src/LAMPTool/LAMPTool.cpp new file mode 100644 index 0000000..597081c --- /dev/null +++ b/src/LAMPTool/LAMPTool.cpp @@ -0,0 +1,27 @@ +#include "LAMPTool.h" +#include + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +LAMPTool::LAMPTool(QWidget *parent) + : QMainWindow(parent) +{ + ui.setupUi(this); +} + +LAMPTool::~LAMPTool() +{} + + diff --git a/src/LAMPTool/LAMPTool.h b/src/LAMPTool/LAMPTool.h new file mode 100644 index 0000000..9e57256 --- /dev/null +++ b/src/LAMPTool/LAMPTool.h @@ -0,0 +1,21 @@ +#pragma once + + +#ifndef LAMPTOOL_H +#define LAMPTOOL_H + +#include +#include "ui_LAMPTool.h" + +class LAMPTool : public QMainWindow +{ + Q_OBJECT + +public: + LAMPTool(QWidget *parent = nullptr); + ~LAMPTool(); + +private: + Ui::LAMPToolClass ui; +}; +#endif \ No newline at end of file diff --git a/src/LAMPTool/LAMPTool.ui b/src/LAMPTool/LAMPTool.ui new file mode 100644 index 0000000..b73011e --- /dev/null +++ b/src/LAMPTool/LAMPTool.ui @@ -0,0 +1,56 @@ + + + LAMPToolClass + + + + 0 + 0 + 600 + 400 + + + + LAMPTool + + + + + + 130 + 40 + 93 + 28 + + + + 测试 + + + + + + + 0 + 0 + 600 + 26 + + + + + + TopToolBarArea + + + false + + + + + + + + + + diff --git a/src/LAMPTool/LampToolTest.h b/src/LAMPTool/LampToolTest.h new file mode 100644 index 0000000..f31be4b --- /dev/null +++ b/src/LAMPTool/LampToolTest.h @@ -0,0 +1,3 @@ +#pragma once + +int TestImageBP_main(int argc, char* argv[]); // BP³ÉÏñº¯Êý²âÊÔ \ No newline at end of file diff --git a/src/LAMPTool/OCCTBase.cpp b/src/LAMPTool/OCCTBase.cpp new file mode 100644 index 0000000..c49a972 --- /dev/null +++ b/src/LAMPTool/OCCTBase.cpp @@ -0,0 +1,412 @@ +#include "OCCTBase.h" +#include "referenceHeader.h" +#include + + +// =================================================================== +// ³£Óú¯Êý·½·¨ +// =================================================================== + + +OCCTShapeType str2OCCTShapeType(QString str) +{ + if (str.isEmpty()) { + return OCCTShapeType::NoneType; + } + else if (str.toUpper() == "STL") { + return OCCTShapeType::STL; + } + else if (str.toUpper() == "STEP") { + return OCCTShapeType::STEP; + } + else if (str.toUpper() == "IGES") { + return OCCTShapeType::IGES; + } + else { + return OCCTShapeType::NoneType; + } + return OCCTShapeType(); +} + +QStringList getOCCTShapeTypeEmnu() +{ + QStringList list; + list.push_back(QString(u8"STL")); + list.push_back(QString(u8"STEP")); + list.push_back(QString(u8"IGES")); + + return list; +} + +QString getOCCTShapeTypeFilterString() +{ + return QString(u8"STL Files (*.stl);;STL Files (*.stla);;step Files (*.stp);;step Files (*.step);;IGES Files (*.iges);;IGES Files (*.igs)"); +} + +QString get_STL_FilterString() +{ + return QString(u8"STL Files (*.stl);;STL Files (*.stla)"); +} + +QString get_STEP_FilterString() +{ + return QString(u8"step Files (*.stp);;step Files (*.step)"); +} + +QString get_IGES_FilterString() +{ + return QString(u8"IGES Files (*.iges);;IGES Files (*.igs)"); +} + +QString getOCCTShapeTypeFilterString(OCCTShapeType switch_on) +{ + switch (switch_on) + { + case(OCCTShapeType::STL): {return get_STL_FilterString(); } + case(OCCTShapeType::STEP): {return get_STEP_FilterString(); } + case(OCCTShapeType::IGES): {return get_IGES_FilterString(); } + + default: + return getOCCTShapeTypeFilterString(); + } +} + +QString getOCCTShapeTypeFilterString(QString str) +{ + return getOCCTShapeTypeFilterString(str2OCCTShapeType(str)); +} + +bool SaveTopoDs_Stl(QString FilePath, const TopoDS_Shape& shape) { + // ½«ÐÎ×´±£´æÎª STL Îļþ + qDebug() << u8"SaveTopoDs_Stl " << FilePath; + StlAPI_Writer writer; + writer.Write(shape, FilePath.toStdString().c_str()); // ±£´æÎªstlÄ£ÐÍ + return true; +} +bool SaveTopoDs_Step(QString FilePath, const TopoDS_Shape& shape) { + qDebug() << u8"SaveTopoDs_Step " << FilePath; + STEPControl_Writer writer; + writer.Transfer(shape, STEPControl_AsIs); + writer.Write(FilePath.toStdString().c_str()); + return true; +} +bool SaveTopoDs_IGES(QString FilePath,const TopoDS_Shape& shape) { + qDebug() << u8"SaveTopoDs_IGES " << FilePath; + IGESControl_Writer writer; + writer.AddShape(shape); + writer.Write(FilePath.toStdString().c_str()); + return true; +} + +bool SaveTopoDs(QString FilePath,const TopoDS_Shape& DataShape, OCCTShapeType shapetype) +{ + switch (shapetype) + { + case(OCCTShapeType::STL): { // ±£´æÎªstl + + SaveTopoDs_Stl(FilePath, DataShape); + break; + } + case(OCCTShapeType::STEP): { + SaveTopoDs_Step(FilePath, DataShape); + break; + } + case(OCCTShapeType::IGES): { + + SaveTopoDs_IGES(FilePath, DataShape); + break; + } + + default: + break; + } + + + return true; +} + +TopoDS_Shape ReadTopoDs_IGES(QString Filepath) { + IGESControl_Reader reader; + reader.ReadFile(Filepath.toStdString().c_str()); + reader.TransferRoots(); + TopoDS_Shape shape = reader.OneShape(); + return shape; +} +TopoDS_Shape ReadTopoDs_Stl(QString Filepath) { + TopoDS_Shape shape_TopoDs; + StlAPI_Reader aReader_Stl; + aReader_Stl.Read(shape_TopoDs, Filepath.toStdString().c_str()); + return shape_TopoDs; +} +TopoDS_Shape ReadTopoDs_Step(QString Filepath) { + TopoDS_Shape shape; + STEPControl_Reader reader; + IFSelect_ReturnStatus status = reader.ReadFile(Filepath.toStdString().c_str()); + if (status == IFSelect_RetDone) { + reader.TransferRoots(); + shape = reader.OneShape(); + return shape; + } + else { + return shape; + } +} + +OCCTShapeType ReadTopoDs_Shape(QString filepath, TopoDS_Shape& shape_TopoDs) +{ + QFileInfo fileinfo(filepath); + QString filename = fileinfo.fileName(); + QString fileSuffix = fileinfo.suffix(); + OCCTShapeType shapetype; + if (fileSuffix.compare(u8"stl") == 0 || fileSuffix.compare(u8"stla") == 0) { + shapetype = OCCTShapeType::STL; + shape_TopoDs = ReadTopoDs_Stl(filepath); + return shapetype; + } + else if (fileSuffix.compare(u8"step") == 0 || fileSuffix.compare(u8"stp") == 0) { + shapetype = OCCTShapeType::STEP; + shape_TopoDs = ReadTopoDs_Step(filepath); + return shapetype; + } + else if (fileSuffix.compare(u8"iges") == 0 || fileSuffix.compare(u8"igs") == 0) { + shapetype = OCCTShapeType::IGES; + shape_TopoDs = ReadTopoDs_IGES(filepath); + return shapetype; + } + else { + qDebug() << QString(u8"=================open Model ====================\n"); + qDebug() << QString(u8"don't open model\n"); + qDebug() << filepath; + qDebug() << QString(u8"=====================================\n"); + return OCCTShapeType::NoneType; + } +} + +TopoDS_Shape MergedTopoShape(std::vector TopoDS_Shapelist) +{ + // ´´½¨Ò»¸ö¸´ºÏÌå + TopoDS_Compound compound; + BRep_Builder builder; + builder.MakeCompound(compound); + + // ½«ËùÓеÄÐÎ×´Ìí¼Óµ½¸´ºÏÌåÖÐ + for (const TopoDS_Shape& shape : TopoDS_Shapelist) { + builder.Add(compound, shape); + } + + // ·µ»ØºÏ²¢ºóµÄ¸´ºÏÌå + return compound; + +} + +void ChangeModelColor(Handle(AIS_Shape)& aisShape, Quantity_Color& redColor) +{ + + // ½«ÑÕɫӦÓõ½Ä£ÐÍ + aisShape->SetColor(redColor); +} + + + +TopoDS_Shape CreateArrow(const gp_Dir& direction, Standard_Real length, Standard_Real radius) { + // ´´½¨Ò»¸öÔ²Öù×÷Ϊ¼ýÍ·µÄÖ÷Ìå + gp_Pnt origin(0, 0, 0); + gp_Ax2 axis(origin, direction); + BRepPrimAPI_MakeCylinder cylinder(axis, radius, length - radius * 2); + + // ´´½¨Ò»¸öÔ²×¶×÷Ϊ¼ýÍ·µÄ¼â¶Ë + gp_Pnt tip = origin.Translated(length * gp_Vec(direction)); + gp_Ax2 coneAxis(tip, direction); + BRepPrimAPI_MakeCone cone(coneAxis, radius * 2, 0, radius * 2); + + // ºÏ²¢Ô²ÖùºÍÔ²×¶ + TopoDS_Compound compound; + BRep_Builder builder; + builder.MakeCompound(compound); + builder.Add(compound, cylinder.Shape()); + builder.Add(compound, cone.Shape()); + + return compound; + +} + +gp_Trsf GetTransFormFromVector(const gp_Vec& vectorA, const gp_Vec& vectorB) +{ + // ¼ÆËãÐýתÖáºÍÐýת½Ç¶È + gp_Vec rotationAxis = vectorA.Crossed(vectorB); + Standard_Real rotationAngle = vectorA.Angle(vectorB); + if (rotationAxis.X() != 0 || rotationAxis.Y() != 0 || rotationAxis.Z() != 0) { + // ´´½¨±ä»»£¬ÈÆÐýתÖáÐýתָ¶¨½Ç¶È + gp_Trsf transformation; + transformation.SetRotation(gp_Ax1(gp_Pnt(0, 0, 0), rotationAxis), rotationAngle); + return transformation; + } + else { + // ´´½¨±ä»»£¬ÈÆÐýתÖáÐýתָ¶¨½Ç¶È + gp_Trsf transformation; + transformation.SetRotation(gp_Ax1(gp_Pnt(0, 0, 0), gp_Vec(0, 0, 1)), 0); + return transformation; + } + +} + +TopoDS_Shape Process_RotationThetaPhi_MoveXYZ(TopoDS_Shape shape, double theta, double phi, double X, double Y, double Z) +{ + gp_Vec Position(gp_Pnt(0, 0, 0), gp_Pnt(X, Y, Z)); + gp_Trsf rotationTransform_theta; + rotationTransform_theta.SetRotation(gp_Ax1(gp_Pnt(0, 0, 0), gp_Dir(0, 1, 0)), theta); // ÈÆ y ÖáÐýת + gp_Trsf rotationTransform_phi; + rotationTransform_phi.SetRotation(gp_Ax1(gp_Pnt(0, 0, 0), gp_Dir(0, 0, 1)), phi); // ÈÆ z ÖáÐýת + gp_Trsf moveTransform_xyz; + moveTransform_xyz.SetTranslation(Position); + + BRepBuilderAPI_Transform shapeTransform_theta(shape, rotationTransform_theta); + TopoDS_Shape tempShape_theta = shapeTransform_theta.Shape(); + BRepBuilderAPI_Transform shapeTransform_phi(tempShape_theta, rotationTransform_phi); + TopoDS_Shape tempShape_phi = shapeTransform_phi.Shape(); + BRepBuilderAPI_Transform shapeTransform_move(tempShape_phi, moveTransform_xyz); + TopoDS_Shape result = shapeTransform_move.Shape(); + + return result; +} + +TopoDS_Shape CreateCartesianCoordinatesAxis(double xlength, double ylength, double zlength) +{ + + // ´´½¨Èý¸ö·½ÏòµÄ¼ýÍ· + TopoDS_Shape arrow1 = CreateArrow(gp_Dir(1, 0, 0), xlength, xlength*0.05); // X·½Ïò + TopoDS_Shape arrow2 = CreateArrow(gp_Dir(0, 1, 0), ylength, ylength*0.05); // Y·½Ïò + TopoDS_Shape arrow3 = CreateArrow(gp_Dir(0, 0, 1), zlength, zlength*0.05); // Z·½Ïò + + // ´´½¨À×´ïÄ£ÐÍ + + gp_Ax2 modelCoor = gp_Ax2(gp_Pnt(0, 0, 0), gp_Dir(0, 0, 1), gp_Dir(1, 0, 0)); + + + // ´´½¨Ò»¸ö°üº¬ËùÓмýÍ·µÄ¸´ºÏÌå + TopoDS_Compound compound; + BRep_Builder builder; + + + builder.MakeCompound(compound); + builder.Add(compound, arrow1); + builder.Add(compound, arrow2); + builder.Add(compound, arrow3); + + return compound; +} + +TopoDS_Shape CreateBox(double x, double y, double z) +{ + // ´´½¨Ò»¸ö³¤·½Ìå + BRepPrimAPI_MakeBox box(gp_Pnt(-x / 2, -y / 2, -z / 2), gp_Pnt(x / 2, y / 2, z / 2)); + return box.Shape(); +} + +TopoDS_Shape CreateCylinder(double radius, double height) +{ + BRepPrimAPI_MakeCylinder makeCylinder(radius, height); + TopoDS_Shape cylinderShape = makeCylinder.Shape(); + return cylinderShape; +} + +TopoDS_Shape CreateCone(double radius1, double radius2, double height) +{ + BRepPrimAPI_MakeCone mkCone = BRepPrimAPI_MakeCone::BRepPrimAPI_MakeCone(radius1, radius2, height); + TopoDS_Shape coneShape = mkCone.Shape(); + + return coneShape; +} + +TopoDS_Shape CreateSphere(double radius) +{ + return TopoDS_Shape(); +} + +TopoDS_Shape CreateTorus(double majorRadius, double minorRadius) +{ + return TopoDS_Shape(); +} + +TopoDS_Shape Cut(TopoDS_Shape& shape1, TopoDS_Shape& shape2) +{ + + return TopoDS_Shape(); +} + +TopoDS_Shape Fuse(TopoDS_Shape& shape1, TopoDS_Shape& shape2) +{ + + return TopoDS_Shape(); +} + +TopoDS_Shape Rotate(TopoDS_Shape& shape, gp_Ax1 axis, double angle) +{ + // ½øÐÐÐýת + angle= angle * M_PI / 180; + gp_Trsf rotation; + rotation.SetRotation(axis, angle); // X + BRepBuilderAPI_Transform rotateTransform_X(shape, rotation); + return rotateTransform_X.Shape(); +} + +TopoDS_Shape Translate(TopoDS_Shape& shape, gp_Vec move_vec) +{ + gp_Trsf translation; + translation.SetTranslation(move_vec); + BRepBuilderAPI_Transform translateTransform(shape, translation); + return translateTransform.Shape(); +} + +TopoDS_Shape Scale(TopoDS_Shape& shape, gp_Pnt refrenceCenter, double scale) +{ + gp_Trsf scaleTransform; + scaleTransform.SetScale(refrenceCenter, scale); + BRepBuilderAPI_Transform scaleTransformBuilder(shape, scaleTransform); + return scaleTransformBuilder.Shape(); +} + +TopoDS_Shape createConicalHorn(double bottomRadius, double bottomHeight, double topRadius, double topHeight) +{ + + BRepPrimAPI_MakeCone mkCone = BRepPrimAPI_MakeCone::BRepPrimAPI_MakeCone(bottomRadius,topRadius,topHeight); + TopoDS_Shape coneShape = mkCone.Shape(); + + // ÕûÌåÆ½ÒÆ + gp_Vec trans_vec(gp_Pnt(0, 0, 0), gp_Pnt(0, 0, bottomHeight)); + gp_Trsf move_trsf; + move_trsf.SetTranslation(trans_vec); + BRepBuilderAPI_Transform shapeTransform_move(coneShape, move_trsf); // fly_Z --> incidenceAngle + TopoDS_Shape tempShape = shapeTransform_move.Shape(); // Æ½ÒÆÎÀÐÇÄ£ÐÍ + + + BRepPrimAPI_MakeCylinder makeCylinder(bottomRadius, bottomHeight); + TopoDS_Shape cylinderShape = makeCylinder.Shape(); + + // ´´½¨Ò»¸ö°üº¬ËùÓмýÍ·µÄ¸´ºÏÌå + TopoDS_Compound compound; + BRep_Builder builder; + + builder.MakeCompound(compound); + builder.Add(compound, tempShape); + builder.Add(compound, cylinderShape); + + return compound; +} + +TopoDS_Shape createPyramidalHorn(double bottomWidth, double bottomHeight, double bottomAtl, double topWidth, double topHeight, double topAtl) +{ + + + + return TopoDS_Shape(); +} + + TopoDS_Shape CreateWedge(double x, double y, double z) +{ + + + + + return TopoDS_Shape(); +} diff --git a/src/LAMPTool/OCCTBase.h b/src/LAMPTool/OCCTBase.h new file mode 100644 index 0000000..fac6cab --- /dev/null +++ b/src/LAMPTool/OCCTBase.h @@ -0,0 +1,96 @@ +#pragma once + +#ifndef OCCTBASELAMP_H +#define OCCTBASELAMP_H +#include "referenceHeader.h" + + +//==================== +// ϵͳ֧³ÖµÄÄ£Ð͵¼³öÀàÐÍ +//===================== + +enum OCCTShapeType +{ + STL, + STEP, + IGES, + NoneType, +}; + +OCCTShapeType str2OCCTShapeType(QString str); +QStringList getOCCTShapeTypeEmnu(); +QString getOCCTShapeTypeFilterString(); +QString get_STL_FilterString(); +QString get_STEP_FilterString(); +QString get_IGES_FilterString(); +QString getOCCTShapeTypeFilterString(OCCTShapeType t); +QString getOCCTShapeTypeFilterString(QString str); + +// ³£Óþ²Ì¬º¯Êý +bool SaveTopoDs_Stl(QString FilePath, const TopoDS_Shape& shape); +bool SaveTopoDs_Step(QString FilePath, const TopoDS_Shape& shape); +bool SaveTopoDs_IGES(QString FilePath,const TopoDS_Shape& shape); +bool SaveTopoDs(QString FilePath,const TopoDS_Shape& shape, OCCTShapeType type); + +TopoDS_Shape ReadTopoDs_IGES(QString Filepath); +TopoDS_Shape ReadTopoDs_Stl(QString Filepath); +TopoDS_Shape ReadTopoDs_Step(QString Filepath); + +OCCTShapeType ReadTopoDs_Shape(QString FilePath, TopoDS_Shape& shape_TopoDs); + + +// Ä£Ðͺϲ¢ +TopoDS_Shape MergedTopoShape(std::vector TopoDS_Shapelist); + + +// ÐÞ¸ÄÄ£ÐÍÏÔʾ +void ChangeModelColor(Handle(AIS_Shape)& aisShape, Quantity_Color& redColor); + +//// ´´½¨¼ýÍ· +TopoDS_Shape CreateArrow(const gp_Dir& direction, Standard_Real length, Standard_Real radius); +// + + +// OCCT ¸ù¾ÝÏòÁ¿AºÍB,¼ÆËã±ä»»¾ØÕó +gp_Trsf GetTransFormFromVector(const gp_Vec& A, const gp_Vec& B); + + +TopoDS_Shape Process_RotationThetaPhi_MoveXYZ(TopoDS_Shape shape, double theta, double phi,double X,double Y,double Z); + + +//TopoDS_Shape Createpyramid(double width=10.0,double depth=5.0, double mouthWidth=1.0, double mouthHeight=0.5, double height = 15.0); + + + +// ´´½¨Ò»¸öµÑ¿¨¶û×ø±êϵ +TopoDS_Shape CreateCartesianCoordinatesAxis(double xlength,double ylength,double zlength); +// ³£¼ûÄ£ÐÍ´´½¨ +TopoDS_Shape CreateBox(double x, double y, double z); +TopoDS_Shape CreateCylinder(double radius, double height); +TopoDS_Shape CreateCone(double radius_bottom, double radius_top, double height); +TopoDS_Shape CreateSphere(double radius); +TopoDS_Shape CreateTorus(double majorRadius, double minorRadius); + +// ³£¼ûÄ£ÐͲÙ×÷ +TopoDS_Shape Cut(TopoDS_Shape& shape1, TopoDS_Shape& shape2); +TopoDS_Shape Fuse(TopoDS_Shape& shape1, TopoDS_Shape& shape2); +// ³£¼û²Ù×÷ -- Ä£ÐÍÐýת¡¢Æ½ÒÆ¡¢Ëõ·Å +TopoDS_Shape Rotate(TopoDS_Shape& shape, gp_Ax1 axis, double angle); +TopoDS_Shape Translate(TopoDS_Shape& shape, gp_Vec move_vec); +TopoDS_Shape Scale(TopoDS_Shape& shape, gp_Pnt refrenceCenter, double scale); + + +// ´´½¨É¢ÉäÌåÀ×´ï +// ´´½¨Ò»¸ö×ø±êÔ­µãΪԲÐÄµÄ +TopoDS_Shape createConicalHorn(double bottomRadius,double bottomHeight,double topRadius,double topHeight); +TopoDS_Shape createPyramidalHorn(double bottomWidth, double bottomHeight, double bottomAtl, double topWidth, double topHeight, double topAtl); + + + + + +#endif // OCCTBASELAMP_H + + + + diff --git a/src/LAMPTool/SARBaseToolLib/BackScatterModel.cpp b/src/LAMPTool/SARBaseToolLib/BackScatterModel.cpp new file mode 100644 index 0000000..fc43fa2 --- /dev/null +++ b/src/LAMPTool/SARBaseToolLib/BackScatterModel.cpp @@ -0,0 +1,14 @@ +#include "BackScatterModel.h" +#include +#include + + +double MuhlemanSimulationBackScatter(double incidentAngle) +{ + return 0.0133*cos(incidentAngle)/pow(sin(incidentAngle)+0.1*cos(incidentAngle), 3); +} + +Eigen::MatrixXd MuhlemanSimulationBackScatter(Eigen::MatrixXd incidentAngle) +{ + return 0.0133 * (incidentAngle.array().cos()) / ((incidentAngle.array().sin()) + cos(incidentAngle.array().cos()*0.1).pow(3)); +} diff --git a/src/LAMPTool/SARBaseToolLib/BackScatterModel.h b/src/LAMPTool/SARBaseToolLib/BackScatterModel.h new file mode 100644 index 0000000..3544153 --- /dev/null +++ b/src/LAMPTool/SARBaseToolLib/BackScatterModel.h @@ -0,0 +1,12 @@ +#pragma once +#include +#include + +double MuhlemanSimulationBackScatter(double incidentAngle); +Eigen::MatrixXd MuhlemanSimulationBackScatter(Eigen::MatrixXd incidentAngle); + + + + + + diff --git a/src/LAMPTool/SARBaseToolLib/SARBaseTool.cpp b/src/LAMPTool/SARBaseToolLib/SARBaseTool.cpp new file mode 100644 index 0000000..320f543 --- /dev/null +++ b/src/LAMPTool/SARBaseToolLib/SARBaseTool.cpp @@ -0,0 +1,283 @@ +// SARBaseTool.cpp : æ­¤æ–‡ä»¶åŒ…å« "main" å‡½æ•°ã€‚ç¨‹åºæ‰§è¡Œå°†åœ¨æ­¤å¤„开始并结æŸã€‚ +// + +#include "BaseToollib/ImageOperatorBase.h" +#include "SARBaseTool.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + + +int Complex2dB(QString in_tiff, QString out_dB_path) +{ + GDALAllRegister(); + std::shared_ptr rasterDataset = OpenDataset(in_tiff); + int width = rasterDataset->GetRasterXSize(); + int height = rasterDataset->GetRasterYSize(); + int band_num = rasterDataset->GetRasterCount(); + double* gt = new double[6]; + std::shared_ptr gt_ptr(gt); + QString projectDef = rasterDataset->GetProjectionRef(); + GDALDataType gdal_datatype = rasterDataset->GetRasterBand(1)->GetRasterDataType(); + bool _nGt_flag = false; + if (projectDef == "") { + _nGt_flag = true; + } + else { + _nGt_flag = false; + } + CreateDataset(out_dB_path, height, width, 1, gt_ptr.get(), projectDef, GDT_Float64, _nGt_flag); + // è®¡ç®—å¤§å° + if (gdal_datatype == 0) { + return 1; + } + else if (gdal_datatype < 8) { + if (band_num != 2) { return 1; } + } + else if (gdal_datatype < 12) { + if (band_num != 1) { return 1; } + } + + int block_num = block_num_pre_memory(width, height, gdal_datatype, 1e9);// + block_num = block_num > height ? height : block_num; // 行数 + int line_num = block_num; + for (int i = 0; i < height; i = block_num + i) { + if (height - i < block_num) { + line_num = height - i; + } + else {} + // 构建矩阵å—,使用eigen 进行矩阵计算,加速计算 + bool _flag = false; + Eigen::Matrix data_mat(line_num * width, 1);// 必须强制行优先 + if (gdal_datatype == GDT_Byte) { + Eigen::MatrixX real_mat(line_num * width, 1); + Eigen::MatrixX imag_mat(line_num * width, 1); + rasterDataset->GetRasterBand(1)->RasterIO(GF_Read, 0, i, width, line_num, real_mat.data(), width, line_num, gdal_datatype, 0, 0); // real + rasterDataset->GetRasterBand(2)->RasterIO(GF_Read, 0, i, width, line_num, imag_mat.data(), width, line_num, gdal_datatype, 0, 0); // imag + data_mat.col(0) = ((real_mat.array().cast()).array().pow(2) + (imag_mat.array().cast()).array().pow(2)).log10() * 10.0; + _flag = true; + } + else if (gdal_datatype == GDT_UInt16) { + Eigen::MatrixX real_mat(line_num * width, 1); + Eigen::MatrixX imag_mat(line_num * width, 1); + rasterDataset->GetRasterBand(1)->RasterIO(GF_Read, 0, i, width, line_num, real_mat.data(), width, line_num, gdal_datatype, 0, 0); // real + rasterDataset->GetRasterBand(2)->RasterIO(GF_Read, 0, i, width, line_num, imag_mat.data(), width, line_num, gdal_datatype, 0, 0); // imag + data_mat.col(0) = ((real_mat.array().cast()).array().pow(2) + (imag_mat.array().cast()).array().pow(2)).log10() * 10.0; + _flag = true; + } + else if (gdal_datatype == GDT_Int16) { + Eigen::MatrixX real_mat(line_num * width, 1); + Eigen::MatrixX imag_mat(line_num * width, 1); + rasterDataset->GetRasterBand(1)->RasterIO(GF_Read, 0, i, width, line_num, real_mat.data(), width, line_num, gdal_datatype, 0, 0); // real + rasterDataset->GetRasterBand(2)->RasterIO(GF_Read, 0, i, width, line_num, imag_mat.data(), width, line_num, gdal_datatype, 0, 0); // imag + data_mat.col(0) = ((real_mat.array().cast()).array().pow(2) + (imag_mat.array().cast()).array().pow(2)).log10() * 10.0; + _flag = true; + } + else if (gdal_datatype == GDT_UInt32) { + Eigen::MatrixX real_mat(line_num * width, 1); + Eigen::MatrixX imag_mat(line_num * width, 1); + rasterDataset->GetRasterBand(1)->RasterIO(GF_Read, 0, i, width, line_num, real_mat.data(), width, line_num, gdal_datatype, 0, 0); // real + rasterDataset->GetRasterBand(2)->RasterIO(GF_Read, 0, i, width, line_num, imag_mat.data(), width, line_num, gdal_datatype, 0, 0); // imag + data_mat.col(0) = ((real_mat.array().cast()).array().pow(2) + (imag_mat.array().cast()).array().pow(2)).log10() * 10.0; + _flag = true; + } + else if (gdal_datatype == GDT_Int32) { + Eigen::MatrixX real_mat(line_num * width, 1); + Eigen::MatrixX imag_mat(line_num * width, 1); + rasterDataset->GetRasterBand(1)->RasterIO(GF_Read, 0, i, width, line_num, real_mat.data(), width, line_num, gdal_datatype, 0, 0); // real + rasterDataset->GetRasterBand(2)->RasterIO(GF_Read, 0, i, width, line_num, imag_mat.data(), width, line_num, gdal_datatype, 0, 0); // imag + data_mat.col(0) = ((real_mat.array().cast()).array().pow(2) + (imag_mat.array().cast()).array().pow(2)).log10() * 10.0; + _flag = true; + } + //else if (gdal_datatype == GDT_UInt64) { + // Eigen::MatrixX real_mat(line_num * width, 1); + // Eigen::MatrixX imag_mat(line_num * width, 1); + // rasterDataset->GetRasterBand(1)->RasterIO(GF_Read, 0, i, width, line_num, real_mat.data(), width, line_num, gdal_datatype, 0, 0); // real + // rasterDataset->GetRasterBand(2)->RasterIO(GF_Read, 0, i, width, line_num, imag_mat.data(), width, line_num, gdal_datatype, 0, 0); // imag + // data_mat.col(0) = ((real_mat.array().cast()).array().pow(2) + (imag_mat.array().cast()).array().pow(2)).log10() * 10.0; + // _flag = true; + //} + //else if (gdal_datatype == GDT_Int64) { + // Eigen::MatrixX real_mat(line_num * width, 1); + // Eigen::MatrixX imag_mat(line_num * width, 1); + // rasterDataset->GetRasterBand(1)->RasterIO(GF_Read, 0, i, width, line_num, real_mat.data(), width, line_num, gdal_datatype, 0, 0); // real + // rasterDataset->GetRasterBand(2)->RasterIO(GF_Read, 0, i, width, line_num, imag_mat.data(), width, line_num, gdal_datatype, 0, 0); // imag + // data_mat.col(0) = ((real_mat.array().cast()).array().pow(2) + (imag_mat.array().cast()).array().pow(2)).log10() * 10.0; + // _flag = true; + //} + else if (gdal_datatype == GDT_Float32) { + Eigen::MatrixX real_mat(line_num * width, 1); + Eigen::MatrixX imag_mat(line_num * width, 1); + rasterDataset->GetRasterBand(1)->RasterIO(GF_Read, 0, i, width, line_num, real_mat.data(), width, line_num, gdal_datatype, 0, 0); // real + rasterDataset->GetRasterBand(2)->RasterIO(GF_Read, 0, i, width, line_num, imag_mat.data(), width, line_num, gdal_datatype, 0, 0); // imag + data_mat.col(0) = ((real_mat.array().cast()).array().pow(2) + (imag_mat.array().cast()).array().pow(2)).log10() * 10.0; + _flag = true; + } + else if (gdal_datatype == GDT_Float64) { + Eigen::MatrixX real_mat(line_num * width, 1); + Eigen::MatrixX imag_mat(line_num * width, 1); + rasterDataset->GetRasterBand(1)->RasterIO(GF_Read, 0, i, width, line_num, real_mat.data(), width, line_num, gdal_datatype, 0, 0); // real + rasterDataset->GetRasterBand(2)->RasterIO(GF_Read, 0, i, width, line_num, imag_mat.data(), width, line_num, gdal_datatype, 0, 0); // imag + data_mat.col(0) = ((real_mat.array().cast()).array().pow(2) + (imag_mat.array().cast()).array().pow(2)).log10() * 10.0; + _flag = true; + } + else if (gdal_datatype == GDT_CInt16) { + Eigen::MatrixX> complex_short_mat(line_num * width, 1); + rasterDataset->GetRasterBand(1)->RasterIO(GF_Read, 0, i, width, line_num, complex_short_mat.data(), width, line_num, gdal_datatype, 0, 0); // real + data_mat.col(0) = (complex_short_mat.real().array().cast().array().pow(2) + complex_short_mat.imag().array().cast().pow(2)).log10() * 10.0; + _flag = true; + } + else if (gdal_datatype == GDT_CInt32) { + Eigen::MatrixX> complex_short_mat(line_num * width, 1); + rasterDataset->GetRasterBand(1)->RasterIO(GF_Read, 0, i, width, line_num, complex_short_mat.data(), width, line_num, gdal_datatype, 0, 0); // real + data_mat.col(0) = (complex_short_mat.real().array().cast().array().pow(2) + complex_short_mat.imag().array().cast().pow(2)).log10() * 10.0; + _flag = true; + } + else if (gdal_datatype == GDT_CFloat32) { + Eigen::MatrixX> complex_short_mat(line_num * width, 1); + rasterDataset->GetRasterBand(1)->RasterIO(GF_Read, 0, i, width, line_num, complex_short_mat.data(), width, line_num, gdal_datatype, 0, 0); // real + data_mat.col(0) = (complex_short_mat.real().array().cast().array().pow(2) + complex_short_mat.imag().array().cast().pow(2)).log10() * 10.0; + _flag = true; + } + else if (gdal_datatype == GDT_CFloat64) { + Eigen::MatrixX> complex_short_mat(line_num * width, 1); + rasterDataset->GetRasterBand(1)->RasterIO(GF_Read, 0, i, width, line_num, complex_short_mat.data(), width, line_num, gdal_datatype, 0, 0); // real + data_mat.col(0) = (complex_short_mat.real().array().cast().array().pow(2) + complex_short_mat.imag().array().cast().pow(2)).log10() * 10.0; + _flag = true; + } + else {} + // ä¿å­˜æ•°æ® + if (_flag) { + // 定义赋值矩阵 + saveDataset(out_dB_path, i, 0, 1, width, line_num, data_mat.data()); + } + else { + } + } + return 0; +} + +int Amplitude2dB(QString in_tiff, QString out_dB_path) +{ + + GDALAllRegister(); + std::shared_ptr rasterDataset = OpenDataset(in_tiff); + int width = rasterDataset->GetRasterXSize(); + int height = rasterDataset->GetRasterYSize(); + int band_num = rasterDataset->GetRasterCount(); + double* gt = new double[6]; + std::shared_ptr gt_ptr(gt); + QString projectDef = rasterDataset->GetProjectionRef(); + GDALDataType gdal_datatype = rasterDataset->GetRasterBand(1)->GetRasterDataType(); + bool _nGt_flag = false; + if (projectDef == "") { + _nGt_flag = true; + } + else { + _nGt_flag = false; + } + CreateDataset(out_dB_path, height, width, 1, gt_ptr.get(), projectDef, GDT_Float64, _nGt_flag); + // è®¡ç®—å¤§å° + if (gdal_datatype == 0) { + return 1; + } + else if (gdal_datatype < 8) { + if (band_num != 1) { return 1; } + } + else { return 1; } + + + int block_num = block_num_pre_memory(width, height, gdal_datatype, 2e9);// + block_num = block_num > height ? height : block_num; // 行数 + int line_num = block_num; + for (int i = 0; i < height; i = block_num + i) { + if (height - i < block_num) { + line_num = height - i; + } + else {} + // 构建矩阵å—,使用eigen 进行矩阵计算,加速计算 + bool _flag = false; + Eigen::Matrix data_mat = ReadMatrixDoubleData(i, width, line_num, rasterDataset, gdal_datatype, 1); + _flag = (data_mat.rows() > 0) && (data_mat.cols() > 0); + // ä¿å­˜æ•°æ® + if (_flag) { + // 定义赋值矩阵 + saveDataset(out_dB_path, i, 0, 1, width, line_num, data_mat.data()); + } + else { + } + } + return 0; +} + +Eigen::MatrixXd Complex2dB(Eigen::MatrixXcd in_matrix) +{ + return Complex2dB(in_matrix.real().array(), in_matrix.imag().array()); +} + +Eigen::MatrixXd Complex2dB(Eigen::MatrixXd in_matrix_real, Eigen::MatrixXd in_matrix_imag) +{ + return (in_matrix_real.array().pow(2) + in_matrix_imag.array().pow(2)).log10() * 10; +} + +double Complex2Amplitude(std::complex sign) +{ + return sqrt(pow(sign.real(),2)+pow(sign.imag(),2)); +} + +double Complex2phase(std::complex sign) +{ + //return (sign.real() == 0)*((sign.imag() < 0) * PI / 2)+ (sign.real() != 0)*(atan(sign.imag() / sign.real()) + (sign.real() < 0) * ((sign.imag() <= 0) * PI)); + if (sign.real() != 0) { + return atan(sign.imag() / sign.real()) + (sign.real() < 0) * ((sign.imag() <= 0) * PI); + } + else { + return (sign.imag() < 0) * PI / 2; + } +} + +Eigen::MatrixXd Complex2Amplitude(Eigen::MatrixXcd in_matrix) +{ + return in_matrix.array().abs().cast().array(); +} + +Eigen::MatrixXd Complex2phase(Eigen::MatrixXcd in_matrix) +{ + // 夿•°è½¬ç›¸ä½ + Eigen::MatrixXd result = in_matrix.real().array(); + int rows = in_matrix.rows(); + int cols = in_matrix.cols(); + for (int i = 0; i < rows; i++) { // å¯èƒ½æ˜¯æ€§èƒ½ç“¶é¢ˆ + for (int j = 0; j < cols; j++) { + result(i, j) = Complex2phase(in_matrix(i, j)); + } + } + + + return result; +} + +int Complex2dB_DLL(QString out_path, QString in_sar_path) +{ + return Complex2dB(in_sar_path, out_path); +} + +int Amplitude2dB_DLL(QString in_tiff, QString out_dB_path) +{ + return Amplitude2dB(in_tiff, out_dB_path); +} + + diff --git a/src/LAMPTool/SARBaseToolLib/SARBaseTool.h b/src/LAMPTool/SARBaseToolLib/SARBaseTool.h new file mode 100644 index 0000000..70ba59a --- /dev/null +++ b/src/LAMPTool/SARBaseToolLib/SARBaseTool.h @@ -0,0 +1,65 @@ +#pragma once +/** +* »ù´¡SARBaseTool ²Ù×÷ +* +*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#define PI 3.141592653589793238462643383279 +#define PI_180 180/3.141592653589793238462643383279 +#define T180_PI 3.141592653589793238462643383279/180 +#define LIGHTSPEED 299792458 +#define LIGHESPEEDGHZ 0.299792458 + +#define Radians2Degrees(Radians) Radians*PI_180 +#define Degrees2Radians(Degrees) Degrees*T180_PI + + +// ÅжÏÊÇ·ñÐèÒªÊä³öΪDLL +#define DLLOUT +int Complex2dB(QString in_tiff, QString out_dB_path); +int Amplitude2dB(QString in_tiff, QString out_dB_path); +Eigen::MatrixXd Complex2dB(Eigen::MatrixXcd in_matrix); +Eigen::MatrixXd Complex2dB(Eigen::MatrixXd in_matrix_real, Eigen::MatrixXd in_matrix_imag ); + +double Complex2Amplitude(std::complex sign); +double Complex2phase(std::complex sign);// ·µ»Ø»¡¶ÈÖÆÏàλ + + + +Eigen::MatrixXd Complex2Amplitude(Eigen::MatrixXcd in_matrix); +Eigen::MatrixXd Complex2phase(Eigen::MatrixXcd in_matrix); +// ---------------------------------------------------------------------------------------------------------- +// ºóÏòÉ¢ÉäϵÊýϵͳ·ÂտģÐÍ + +#ifndef DLLOUT + +#else + +#ifdef __cplusplus +extern "C" { +#endif +#define DllExport __declspec( dllexport ) + int __declspec(dllexport) Complex2dB_DLL(QString out_path, QString in_sar_path); + int __declspec(dllexport) Amplitude2dB_DLL(QString in_tiff, QString out_dB_path); +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/src/LAMPTool/SARBaseToolLib/SARCalibration.cpp b/src/LAMPTool/SARBaseToolLib/SARCalibration.cpp new file mode 100644 index 0000000..0a021b2 --- /dev/null +++ b/src/LAMPTool/SARBaseToolLib/SARCalibration.cpp @@ -0,0 +1,384 @@ +#include "SARCalibration.h" +#include "BaseToollib/ImageOperatorBase.h" +#include "SARBaseTool.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +using namespace std; +using namespace Eigen; + +/** +* ÊäÈëÊý¾ÝÊÇENVI¸ñʽÊý¾Ý +*/ + + + + + + +Eigen::Matrix2cd CalibrationMatrix(Eigen::MatrixXcd in_matrix, double calibrationValue) +{ + return in_matrix.array() * calibrationValue; +} + +int CalibrationSiglePolarSAR(QString out_path, QString in_sar_path, double calibrationValue) +{ + return CalibrationComplex(out_path, in_sar_path, calibrationValue); +} + +int CalibrationComplex(const QString& out_path, const QString& in_sar_path, double calibrationValue) +{ + GDALAllRegister(); + std::shared_ptr rasterDataset = OpenDataset(in_sar_path); + int width = rasterDataset->GetRasterXSize(); + int height = rasterDataset->GetRasterYSize(); + int band_num = rasterDataset->GetRasterCount(); + double* gt = new double[6]; + std::shared_ptr gt_ptr(gt); + QString projectDef = rasterDataset->GetProjectionRef(); + GDALDataType gdal_datatype = rasterDataset->GetRasterBand(1)->GetRasterDataType(); + bool _nGt_flag = false; + if (projectDef == "") { + _nGt_flag = true; + } + else { + _nGt_flag = false; + } + CreateDataset(out_path, height, width, 1, gt_ptr.get(), projectDef, GDT_CFloat64, _nGt_flag); + // ¼ÆËã´óС + if (gdal_datatype == 0) { + return 1; + } + else if (gdal_datatype < 8) { + if (band_num != 2) { return 1; } + } + else if (gdal_datatype < 12) { + if (band_num != 1) { return 1; } + + } + else {} + int block_num = block_num_pre_memory(width, height, gdal_datatype, 2e9);// + block_num = block_num > height ? height : block_num; // ÐÐÊý + int line_num = block_num; + for (int i = 0; i < height; i= block_num+i) { + if (height - i < block_num) { + line_num = height - i; + } + else {} + // ¹¹½¨¾ØÕó¿é£¬Ê¹ÓÃeigen ½øÐоØÕó¼ÆË㣬¼ÓËÙ¼ÆËã + bool _flag = false; + Eigen::Matrix data_mat(line_num * width, 2);// ±ØÐëÇ¿ÖÆÐÐÓÅÏÈ + if (gdal_datatype == GDT_Byte) { + Eigen::MatrixX real_mat(line_num*width,1); + Eigen::MatrixX imag_mat(line_num*width,1); + rasterDataset->GetRasterBand(1)->RasterIO(GF_Read, 0, i, width, line_num, real_mat.data(), width, line_num, gdal_datatype, 0, 0); // real + rasterDataset->GetRasterBand(2)->RasterIO(GF_Read, 0, i, width, line_num, imag_mat.data(), width, line_num, gdal_datatype, 0, 0); // imag + data_mat.col(0) = (real_mat.array().cast() * calibrationValue).array(); + data_mat.col(1) = (imag_mat.array().cast() * calibrationValue).array(); + _flag = true; + } + else if (gdal_datatype == GDT_UInt16) { + Eigen::MatrixX real_mat(line_num * width, 1); + Eigen::MatrixX imag_mat(line_num*width, 1); + rasterDataset->GetRasterBand(1)->RasterIO(GF_Read, 0, i, width, line_num, real_mat.data(), width, line_num, gdal_datatype, 0, 0); // real + rasterDataset->GetRasterBand(2)->RasterIO(GF_Read, 0, i, width, line_num, imag_mat.data(), width, line_num, gdal_datatype, 0, 0); // imag + data_mat.col(0) = (real_mat.array().cast() * calibrationValue).array(); + data_mat.col(1) = (imag_mat.array().cast() * calibrationValue).array(); + _flag = true; + } + else if (gdal_datatype == GDT_Int16) { + Eigen::MatrixX real_mat(line_num*width, 1); + Eigen::MatrixX imag_mat(line_num*width, 1); + rasterDataset->GetRasterBand(1)->RasterIO(GF_Read, 0, i, width, line_num, real_mat.data(), width, line_num, gdal_datatype, 0, 0); // real + rasterDataset->GetRasterBand(2)->RasterIO(GF_Read, 0, i, width, line_num, imag_mat.data(), width, line_num, gdal_datatype, 0, 0); // imag + data_mat.col(0) = (real_mat.array().cast() * calibrationValue).array(); + data_mat.col(1) = (imag_mat.array().cast() * calibrationValue).array(); + _flag = true; + } + else if (gdal_datatype == GDT_UInt32) { + Eigen::MatrixX real_mat(line_num*width, 1); + Eigen::MatrixX imag_mat(line_num*width, 1); + rasterDataset->GetRasterBand(1)->RasterIO(GF_Read, 0, i, width, line_num, real_mat.data(), width, line_num, gdal_datatype, 0, 0); // real + rasterDataset->GetRasterBand(2)->RasterIO(GF_Read, 0, i, width, line_num, imag_mat.data(), width, line_num, gdal_datatype, 0, 0); // imag + data_mat.col(0) = (real_mat.array().cast() * calibrationValue).array(); + data_mat.col(1) = (imag_mat.array().cast() * calibrationValue).array(); + _flag = true; + } + else if (gdal_datatype == GDT_Int32) { + Eigen::MatrixX real_mat(line_num*width, 1); + Eigen::MatrixX imag_mat(line_num*width, 1); + rasterDataset->GetRasterBand(1)->RasterIO(GF_Read, 0, i, width, line_num, real_mat.data(), width, line_num, gdal_datatype, 0, 0); // real + rasterDataset->GetRasterBand(2)->RasterIO(GF_Read, 0, i, width, line_num, imag_mat.data(), width, line_num, gdal_datatype, 0, 0); // imag + data_mat.col(0) = (real_mat.array().cast() * calibrationValue).array(); + data_mat.col(1) = (imag_mat.array().cast() * calibrationValue).array(); + _flag = true; + } + //else if (gdal_datatype == GDT_UInt64) { + // Eigen::MatrixX real_mat(line_num*width, 1); + // Eigen::MatrixX imag_mat(line_num*width, 1); + // rasterDataset->GetRasterBand(1)->RasterIO(GF_Read, 0, i, width, line_num, real_mat.data(), width, line_num, gdal_datatype, 0, 0); // real + // rasterDataset->GetRasterBand(2)->RasterIO(GF_Read, 0, i, width, line_num, imag_mat.data(), width, line_num, gdal_datatype, 0, 0); // imag + // data_mat.col(0) = (real_mat.array().cast() * calibrationValue).array(); + // data_mat.col(1) = (imag_mat.array().cast() * calibrationValue).array(); + // _flag = true; + //} + //else if (gdal_datatype == GDT_Int64) { + // Eigen::MatrixX real_mat(line_num*width, 1); + // Eigen::MatrixX imag_mat(line_num*width, 1); + // rasterDataset->GetRasterBand(1)->RasterIO(GF_Read, 0, i, width, line_num, real_mat.data(), width, line_num, gdal_datatype, 0, 0); // real + // rasterDataset->GetRasterBand(2)->RasterIO(GF_Read, 0, i, width, line_num, imag_mat.data(), width, line_num, gdal_datatype, 0, 0); // imag + // data_mat.col(0) = (real_mat.array().cast() * calibrationValue).array(); + // data_mat.col(1) = (imag_mat.array().cast() * calibrationValue).array(); + // _flag = true; + //} + else if (gdal_datatype == GDT_Float32) { + Eigen::MatrixX real_mat(line_num*width, 1); + Eigen::MatrixX imag_mat(line_num*width, 1); + rasterDataset->GetRasterBand(1)->RasterIO(GF_Read, 0, i, width, line_num, real_mat.data(), width, line_num, gdal_datatype, 0, 0); // real + rasterDataset->GetRasterBand(2)->RasterIO(GF_Read, 0, i, width, line_num, imag_mat.data(), width, line_num, gdal_datatype, 0, 0); // imag + data_mat.col(0) = (real_mat.array().cast() * calibrationValue).array(); + data_mat.col(1) = (imag_mat.array().cast() * calibrationValue).array(); + _flag = true; + } + else if (gdal_datatype == GDT_Float64) { + Eigen::MatrixX real_mat(line_num*width, 1); + Eigen::MatrixX imag_mat(line_num*width, 1); + rasterDataset->GetRasterBand(1)->RasterIO(GF_Read, 0, i, width, line_num, real_mat.data(), width, line_num, gdal_datatype, 0, 0); // real + rasterDataset->GetRasterBand(2)->RasterIO(GF_Read, 0, i, width, line_num, imag_mat.data(), width, line_num, gdal_datatype, 0, 0); // imag + data_mat.col(0) = (real_mat.array().cast() * calibrationValue).array(); + data_mat.col(1) =( imag_mat.array().cast() * calibrationValue).array(); + _flag = true; + } + else if (gdal_datatype == GDT_CInt16) { + Eigen::MatrixX> complex_short_mat(line_num*width, 1); + rasterDataset->GetRasterBand(1)->RasterIO(GF_Read, 0, i, width, line_num, complex_short_mat.data(), width, line_num, gdal_datatype, 0, 0); // real + data_mat.col(0) = (complex_short_mat.real().array().cast() * calibrationValue).array(); + data_mat.col(1) = (complex_short_mat.imag().array().cast() * calibrationValue).array(); + _flag = true; + } + else if (gdal_datatype == GDT_CInt32) { + Eigen::MatrixX> complex_short_mat(line_num*width, 1); + rasterDataset->GetRasterBand(1)->RasterIO(GF_Read, 0, i, width, line_num, complex_short_mat.data(), width, line_num, gdal_datatype, 0, 0); // real + data_mat.col(0) = (complex_short_mat.real().array().cast() * calibrationValue).array(); + data_mat.col(1) = (complex_short_mat.imag().array().cast() * calibrationValue).array(); + _flag = true; + } + else if (gdal_datatype == GDT_CFloat32) { + Eigen::MatrixX> complex_short_mat(line_num*width, 1); + rasterDataset->GetRasterBand(1)->RasterIO(GF_Read, 0, i, width, line_num, complex_short_mat.data(), width, line_num, gdal_datatype, 0, 0); // real + data_mat.col(0) = (complex_short_mat.real().array().cast() * calibrationValue).array(); + data_mat.col(1) = (complex_short_mat.imag().array().cast() * calibrationValue).array(); + _flag = true; + } + else if (gdal_datatype == GDT_CFloat64) { + Eigen::MatrixX> complex_short_mat(line_num*width, 1); + rasterDataset->GetRasterBand(1)->RasterIO(GF_Read, 0, i, width, line_num, complex_short_mat.data(), width, line_num, gdal_datatype, 0, 0); // real + data_mat.col(0) = (complex_short_mat.real().array().cast() * calibrationValue).array(); + data_mat.col(1) = (complex_short_mat.imag().array().cast() * calibrationValue).array(); + _flag = true; + } + else {} + // ±£´æÊý¾Ý + if (_flag) { + // ¶¨Ò帳ֵ¾ØÕó + saveDataset(out_path, i,0,1, width, line_num, data_mat.data()); + } + else { + } + } + return -1; +} + +int CalibrationComplex2dB(const QString& out_path, const QString& in_sar_path, double calibrationValue) +{ + GDALAllRegister(); + std::shared_ptr rasterDataset = OpenDataset(in_sar_path); + int width = rasterDataset->GetRasterXSize(); + int height = rasterDataset->GetRasterYSize(); + int band_num = rasterDataset->GetRasterCount(); + double* gt = new double[6]; + std::shared_ptr gt_ptr(gt); + QString projectDef = rasterDataset->GetProjectionRef(); + GDALDataType gdal_datatype = rasterDataset->GetRasterBand(1)->GetRasterDataType(); + bool _nGt_flag = false; + if (projectDef == "") { + _nGt_flag = true; + } + else { + _nGt_flag = false; + } + CreateDataset(out_path, height, width, 1, gt_ptr.get(), projectDef, GDT_CFloat64, _nGt_flag); + // ¼ÆËã´óС + if (gdal_datatype == 0) { + return 1; + } + else if (gdal_datatype < 8) { + if (band_num != 2) { return 1; } + } + else if (gdal_datatype < 12) { + if (band_num != 1) { return 1; } + + } + else {} + int block_num = block_num_pre_memory(width, height, gdal_datatype, 2e9);// + block_num = block_num > height ? height : block_num; // ÐÐÊý + int line_num = block_num; + for (int i = 0; i < height; i = block_num + i) { + if (height - i < block_num) { + line_num = height - i; + } + else {} + // ¹¹½¨¾ØÕó¿é£¬Ê¹ÓÃeigen ½øÐоØÕó¼ÆË㣬¼ÓËÙ¼ÆËã + bool _flag = false; + Eigen::Matrix data_mat(line_num * width, 2);// ±ØÐëÇ¿ÖÆÐÐÓÅÏÈ + if (gdal_datatype == GDT_Byte) { + Eigen::MatrixX real_mat(line_num * width, 1); + Eigen::MatrixX imag_mat(line_num * width, 1); + rasterDataset->GetRasterBand(1)->RasterIO(GF_Read, 0, i, width, line_num, real_mat.data(), width, line_num, gdal_datatype, 0, 0); // real + rasterDataset->GetRasterBand(2)->RasterIO(GF_Read, 0, i, width, line_num, imag_mat.data(), width, line_num, gdal_datatype, 0, 0); // imag + data_mat.col(0) = (real_mat.array().cast() * calibrationValue).array(); + data_mat.col(1) = (imag_mat.array().cast() * calibrationValue).array(); + _flag = true; + } + else if (gdal_datatype == GDT_UInt16) { + Eigen::MatrixX real_mat(line_num * width, 1); + Eigen::MatrixX imag_mat(line_num * width, 1); + rasterDataset->GetRasterBand(1)->RasterIO(GF_Read, 0, i, width, line_num, real_mat.data(), width, line_num, gdal_datatype, 0, 0); // real + rasterDataset->GetRasterBand(2)->RasterIO(GF_Read, 0, i, width, line_num, imag_mat.data(), width, line_num, gdal_datatype, 0, 0); // imag + data_mat.col(0) = (real_mat.array().cast() * calibrationValue).array(); + data_mat.col(1) = (imag_mat.array().cast() * calibrationValue).array(); + _flag = true; + } + else if (gdal_datatype == GDT_Int16) { + Eigen::MatrixX real_mat(line_num * width, 1); + Eigen::MatrixX imag_mat(line_num * width, 1); + rasterDataset->GetRasterBand(1)->RasterIO(GF_Read, 0, i, width, line_num, real_mat.data(), width, line_num, gdal_datatype, 0, 0); // real + rasterDataset->GetRasterBand(2)->RasterIO(GF_Read, 0, i, width, line_num, imag_mat.data(), width, line_num, gdal_datatype, 0, 0); // imag + data_mat.col(0) = (real_mat.array().cast() * calibrationValue).array(); + data_mat.col(1) = (imag_mat.array().cast() * calibrationValue).array(); + _flag = true; + } + else if (gdal_datatype == GDT_UInt32) { + Eigen::MatrixX real_mat(line_num * width, 1); + Eigen::MatrixX imag_mat(line_num * width, 1); + rasterDataset->GetRasterBand(1)->RasterIO(GF_Read, 0, i, width, line_num, real_mat.data(), width, line_num, gdal_datatype, 0, 0); // real + rasterDataset->GetRasterBand(2)->RasterIO(GF_Read, 0, i, width, line_num, imag_mat.data(), width, line_num, gdal_datatype, 0, 0); // imag + data_mat.col(0) = (real_mat.array().cast() * calibrationValue).array(); + data_mat.col(1) = (imag_mat.array().cast() * calibrationValue).array(); + _flag = true; + } + else if (gdal_datatype == GDT_Int32) { + Eigen::MatrixX real_mat(line_num * width, 1); + Eigen::MatrixX imag_mat(line_num * width, 1); + rasterDataset->GetRasterBand(1)->RasterIO(GF_Read, 0, i, width, line_num, real_mat.data(), width, line_num, gdal_datatype, 0, 0); // real + rasterDataset->GetRasterBand(2)->RasterIO(GF_Read, 0, i, width, line_num, imag_mat.data(), width, line_num, gdal_datatype, 0, 0); // imag + data_mat.col(0) = (real_mat.array().cast() * calibrationValue).array(); + data_mat.col(1) = (imag_mat.array().cast() * calibrationValue).array(); + _flag = true; + } + //else if (gdal_datatype == GDT_UInt64) { + // Eigen::MatrixX real_mat(line_num * width, 1); + // Eigen::MatrixX imag_mat(line_num * width, 1); + // rasterDataset->GetRasterBand(1)->RasterIO(GF_Read, 0, i, width, line_num, real_mat.data(), width, line_num, gdal_datatype, 0, 0); // real + // rasterDataset->GetRasterBand(2)->RasterIO(GF_Read, 0, i, width, line_num, imag_mat.data(), width, line_num, gdal_datatype, 0, 0); // imag + // data_mat.col(0) = (real_mat.array().cast() * calibrationValue).array(); + // data_mat.col(1) = (imag_mat.array().cast() * calibrationValue).array(); + // _flag = true; + //} + //else if (gdal_datatype == GDT_Int64) { + // Eigen::MatrixX real_mat(line_num * width, 1); + // Eigen::MatrixX imag_mat(line_num * width, 1); + // rasterDataset->GetRasterBand(1)->RasterIO(GF_Read, 0, i, width, line_num, real_mat.data(), width, line_num, gdal_datatype, 0, 0); // real + // rasterDataset->GetRasterBand(2)->RasterIO(GF_Read, 0, i, width, line_num, imag_mat.data(), width, line_num, gdal_datatype, 0, 0); // imag + // data_mat.col(0) = (real_mat.array().cast() * calibrationValue).array(); + // data_mat.col(1) = (imag_mat.array().cast() * calibrationValue).array(); + // _flag = true; + //} + else if (gdal_datatype == GDT_Float32) { + Eigen::MatrixX real_mat(line_num * width, 1); + Eigen::MatrixX imag_mat(line_num * width, 1); + rasterDataset->GetRasterBand(1)->RasterIO(GF_Read, 0, i, width, line_num, real_mat.data(), width, line_num, gdal_datatype, 0, 0); // real + rasterDataset->GetRasterBand(2)->RasterIO(GF_Read, 0, i, width, line_num, imag_mat.data(), width, line_num, gdal_datatype, 0, 0); // imag + data_mat.col(0) = (real_mat.array().cast() * calibrationValue).array(); + data_mat.col(1) = (imag_mat.array().cast() * calibrationValue).array(); + _flag = true; + } + else if (gdal_datatype == GDT_Float64) { + Eigen::MatrixX real_mat(line_num * width, 1); + Eigen::MatrixX imag_mat(line_num * width, 1); + rasterDataset->GetRasterBand(1)->RasterIO(GF_Read, 0, i, width, line_num, real_mat.data(), width, line_num, gdal_datatype, 0, 0); // real + rasterDataset->GetRasterBand(2)->RasterIO(GF_Read, 0, i, width, line_num, imag_mat.data(), width, line_num, gdal_datatype, 0, 0); // imag + data_mat.col(0) = (real_mat.array().cast() * calibrationValue).array(); + data_mat.col(1) = (imag_mat.array().cast() * calibrationValue).array(); + _flag = true; + } + else if (gdal_datatype == GDT_CInt16) { + Eigen::MatrixX> complex_short_mat(line_num * width, 1); + rasterDataset->GetRasterBand(1)->RasterIO(GF_Read, 0, i, width, line_num, complex_short_mat.data(), width, line_num, gdal_datatype, 0, 0); // real + data_mat.col(0) = (complex_short_mat.real().array().cast() * calibrationValue).array(); + data_mat.col(1) = (complex_short_mat.imag().array().cast() * calibrationValue).array(); + _flag = true; + } + else if (gdal_datatype == GDT_CInt32) { + Eigen::MatrixX> complex_short_mat(line_num * width, 1); + rasterDataset->GetRasterBand(1)->RasterIO(GF_Read, 0, i, width, line_num, complex_short_mat.data(), width, line_num, gdal_datatype, 0, 0); // real + data_mat.col(0) = (complex_short_mat.real().array().cast() * calibrationValue).array(); + data_mat.col(1) = (complex_short_mat.imag().array().cast() * calibrationValue).array(); + _flag = true; + } + else if (gdal_datatype == GDT_CFloat32) { + Eigen::MatrixX> complex_short_mat(line_num * width, 1); + rasterDataset->GetRasterBand(1)->RasterIO(GF_Read, 0, i, width, line_num, complex_short_mat.data(), width, line_num, gdal_datatype, 0, 0); // real + data_mat.col(0) = (complex_short_mat.real().array().cast() * calibrationValue).array(); + data_mat.col(1) = (complex_short_mat.imag().array().cast() * calibrationValue).array(); + _flag = true; + } + else if (gdal_datatype == GDT_CFloat64) { + Eigen::MatrixX> complex_short_mat(line_num * width, 1); + rasterDataset->GetRasterBand(1)->RasterIO(GF_Read, 0, i, width, line_num, complex_short_mat.data(), width, line_num, gdal_datatype, 0, 0); // real + data_mat.col(0) = (complex_short_mat.real().array().cast() * calibrationValue).array(); + data_mat.col(1) = (complex_short_mat.imag().array().cast() * calibrationValue).array(); + _flag = true; + } + else {} + // ±£´æÊý¾Ý + if (_flag) { + // ¶¨Ò帳ֵ¾ØÕó + + Eigen::Matrix data_out(line_num* width, 1);// ±ØÐëÇ¿ÖÆÐÐÓÅÏÈ + data_out.col(0) = Complex2dB(data_mat.col(0).array(), data_mat.col(1).array()).array(); + saveDataset(out_path, i, 0, 1, width, line_num, data_out.data()); + } + else { + } + } + return -1; + + + + + return 0; +} + +int CalibrationComplex_DLL(const QString& out_path, const QString& in_sar_path, double calibrationValue) +{ + return 0; +} + +int CalibrationComplex2dB_DLL(const QString& out_path, const QString& in_sar_path, double calibrationValue) +{ + return 0; +} diff --git a/src/LAMPTool/SARBaseToolLib/SARCalibration.h b/src/LAMPTool/SARBaseToolLib/SARCalibration.h new file mode 100644 index 0000000..757c71d --- /dev/null +++ b/src/LAMPTool/SARBaseToolLib/SARCalibration.h @@ -0,0 +1,52 @@ +#pragma once + + +#ifndef SARCALIBRATION_H +#define SARCALIBRATION_H +/** +* SAR¶¨±êº¯Êý +* +*/ +#include "referenceHeader.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +using namespace std; +using namespace Eigen; +// ÅжÏÊÇ·ñÐèÒªÊä³öΪDLL +#define DLLOUT + + +// ¶¨±ê¼ÆËã +// ÊäÈ붨±êϵͳ£¬±£Ö¤Êý¾ÝÄܹ»Õý³£¶¨±ê +Eigen::Matrix2cd CalibrationMatrix(Eigen::MatrixXcd in_matrix, double calibrationValue); +int CalibrationComplex(const QString& out_path, const QString& in_sar_path, double calibrationValue); +int CalibrationComplex2dB(const QString& out_path, const QString& in_sar_path, double calibrationValue); +#ifndef DLLOUT + +#else + +#ifdef __cplusplus +extern "C" { +#endif + #define DllExport __declspec( dllexport ) + int __declspec(dllexport) CalibrationComplex_DLL(const QString& out_path, const QString& in_sar_path, double calibrationValue); + int __declspec(dllexport) CalibrationComplex2dB_DLL(const QString& out_path, const QString& in_sar_path, double calibrationValue); +#ifdef __cplusplus +} +#endif + + + +#endif + +#endif // !SARCALIBRATION_H \ No newline at end of file diff --git a/src/LAMPTool/SARBaseToolLib/SARCalibrationTool.cpp b/src/LAMPTool/SARBaseToolLib/SARCalibrationTool.cpp new file mode 100644 index 0000000..de1d1d1 --- /dev/null +++ b/src/LAMPTool/SARBaseToolLib/SARCalibrationTool.cpp @@ -0,0 +1,86 @@ +// SARCalibrationTool.cpp : æ­¤æ–‡ä»¶åŒ…å« "main" å‡½æ•°ã€‚ç¨‹åºæ‰§è¡Œå°†åœ¨æ­¤å¤„开始并结æŸã€‚ +// +#include "SARCalibration.h" +#include "SARBaseTool.h" +#include +#include +#include + + + +int SiglePolarCalibration(int argc, char* argv[]) { + qDebug() << "mode : 1 "<< "\n"; + QString in_tiff_path = ""; + QString out_path = ""; + double calibration = 0; + // params prase + for (int i = 0; i < argc; i++) { + if (string(argv[i]) == "-in") + { + in_tiff_path = argv[i + 1]; + qDebug() << "in file : " << in_tiff_path << "\n"; + } + else if (string(argv[i]) == "-out") { + out_path = argv[i + 1]; + qDebug() << "out file : " << in_tiff_path << "\n"; + } + else if (string(argv[i]) == "-calibrationConst") { + calibration = strtod(argv[i + 1], NULL); + qDebug() << "calibrationConst : " << calibration << "\n"; + } + else {} + } + // excute tool + return CalibrationComplex(out_path, in_tiff_path, calibration); +} + + +int RasterComplex2dB(int argc, char* argv[]) { + qDebug() << "mode : 1 " << "\n"; + QString in_tiff_path = ""; + QString out_path = ""; + // params prase + for (int i = 0; i < argc; i++) { + if (string(argv[i]) == "-in") + { + in_tiff_path = argv[i + 1]; + qDebug() << "in file : " << in_tiff_path << "\n"; + } + else if (string(argv[i]) == "-out") { + out_path = argv[i + 1]; + qDebug() << "out file : " << in_tiff_path << "\n"; + } + else {} + } + // excute tool + return Complex2dB(in_tiff_path, out_path); +} + + +int Test_SARCalibrationTool(int argc, char* argv[]) +{ + qDebug() << "calibration tool " << "\n"; + qDebug() << "sigle polsar Amg: SARCalibrationTool.exe 1 -in filepath -out filepath -calibrationConst 43" << "\n"; + qDebug() << "complex 2 dB : SARCalibrationTool.exe 1 -in filepath -out filepath" << "\n"; + if (argc == 1) { + qDebug() << "the number of params should be than 2" << "\n"; + return 2; + } + try { + int mode = atoi(argv[1]); + if (mode == 1) { + return SiglePolarCalibration(argc, argv); + } + else if (mode == 2) { + return RasterComplex2dB(argc, argv); + } + else {} + } + catch (std::exception ex) { + std::wcerr << ex.what() << "\n"; + } + + qDebug() << "Hello World!\n"; + return 0; +} + diff --git a/src/LAMPTool/SARBaseToolLib/SARImageBase.cpp b/src/LAMPTool/SARBaseToolLib/SARImageBase.cpp new file mode 100644 index 0000000..6d18725 --- /dev/null +++ b/src/LAMPTool/SARBaseToolLib/SARImageBase.cpp @@ -0,0 +1,334 @@ +#include "BaseToollib/ImageOperatorBase.h" +#include "SARBaseTool.h" +#include "SARImageBase.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "referenceHeader.h" +#include "OCCTBase.h" +#include "BaseToollib/GeoOperator.h" +#include "SARBaseToolLib/SARImageBase.h" + + + + + +double getRangeResolution(double startfreq, double endfreq) +{ + return LIGHTSPEED / 2 / std::abs(endfreq - startfreq); +} + +double getAzimuthResolution(double AzAngleRange, double startFreq) +{ + return LIGHTSPEED / 2 / (AzAngleRange * startFreq); +} + +Eigen::MatrixXd hammingWindows(size_t num) +{ + double alpha = 25. / 46; + double beta = 1 - alpha; + double scale = 1; + size_t m = num; + Eigen::MatrixXd x = Eigen::MatrixXd::Zero(m, 1); + for (int i = 0; i < m; i++) { + x(i, 0) = alpha - beta * std::cos(2 * PI * i / (num - 1)); + } + x = x.array() * scale; + return x; +} + + +Eigen::MatrixXd Hanning(size_t Nf, size_t Nxa, double alpha) +{ + // n1 = double ? DOUBLE(n1In[0]) : FLOAT(n1In[0]) + double a = 2 * PI / Nf; // a = 2 * pi / N1 ;scale factor + double n2 = Nxa; // n2 = double ? DOUBLE(n2In[0]) : FLOAT(n2In[0]) + double b = 2 * pi / n2; // dim 2 scale fact + double one = 1.0; // double ? 1d : 1.0 + double temp_row = 0; + double temp_col = 0; + Eigen::MatrixXd result_arr = Eigen::MatrixXd::Zero(Nxa, Nf); // ½á¹û + for (int i = 0; i < Nxa; i++) { + for (int j = 0; j < Nf; j++) { + // index = double ? DINDGEN(n1) : FINDGEN(n1) ; Nf + temp_row = (alpha - one) * cos(j * a) + alpha; // (alpha-one) * cos(index*a) + alpha ;One row + // index = double ? DINDGEN(n2) : FINDGEN(n2) ; Nxa + temp_col = (alpha - one) * cos(i * b) + alpha; // col = (alpha-one) * cos(index*b) + alpha ;One column + result_arr(i, j) = temp_row * temp_col;// RETURN,(row # col) ;DINDGEN(n1)#DINDGEN(n2) + } + } + return result_arr; +} + + +Eigen::MatrixXcd HammingWindows(Eigen::MatrixXcd FreqEcho) +{ + size_t data_cols = FreqEcho.cols(); + size_t data_rows = FreqEcho.rows(); + + // ½øÐнøÐÐhanmming windows + Eigen::MatrixXd hamming_Az = hammingWindows(data_cols); + Eigen::MatrixXd hamming_Rz = hammingWindows(data_rows); + for (int i = 0; i < data_cols; i++) { + for (int j = 0; j < data_rows; j++) { + FreqEcho(j, i) = FreqEcho(j, i) * hamming_Az(i, 0) * hamming_Rz(j, 0); + } + } + return FreqEcho; +} + +Eigen::MatrixXcd InterpFreqEcho(Eigen::MatrixXcd freqEcho, Eigen::VectorXd SourceFreqlist, Eigen::VectorXd interpFreqlist) +{ + assert(freqEcho.cols() == SourceFreqlist.rows()); + + + + size_t data_rows = freqEcho.rows(); + size_t data_cols = freqEcho.cols(); + + size_t out_cols = interpFreqlist.rows(); + Eigen::MatrixXcd resultECHO = Eigen::MatrixXcd::Zero(data_rows, out_cols); + + +#pragma omp parallel for // NEW ADD + for (int i = 0; i < data_rows; i++) { // µ¥Âö³å + double* xs = new double[data_rows]; + for (int i = 0; i < data_cols; i++) { + xs[i] = SourceFreqlist(i); // ԭʼ»Ø²¨ + } + double* real_ys = new double[data_cols]; + double* imag_ys = new double[data_cols]; + + gsl_interp_accel* acc = gsl_interp_accel_alloc(); + const gsl_interp_type* t = gsl_interp_cspline_periodic; + gsl_spline* spline_real = gsl_spline_alloc(t, data_rows); + gsl_spline* spline_imag = gsl_spline_alloc(t, data_rows); + + for (int jj = 0; jj < data_cols; jj++) { + real_ys[jj] = freqEcho(jj, i).real(); + imag_ys[jj] = freqEcho(jj, i).imag(); + } + gsl_spline_init(spline_real, xs, real_ys, data_rows); + gsl_spline_init(spline_imag, xs, imag_ys, data_rows); + for (int j = 0; j < out_cols; j++) { // ÊÜÏÞÓÚµ±Ç°º¯ÊýÖ»ÄÜÖðµã²åÖµ£¬»òÕߺóÆÚ¿ÉÐÞ¸ÄΪ gsl Ö±½Ó²åÖµ + double cx = interpFreqlist(j,0); + std::complex result( + gsl_spline_eval(spline_real, cx, acc),// ²åֵʵ²¿ + gsl_spline_eval(spline_imag, cx, acc)// ²åÖµÐ鲿 + ); + resultECHO(i, j) = result; + } + + gsl_spline_free(spline_real); + gsl_spline_free(spline_imag); + gsl_interp_accel_free(acc); + + delete[] xs; + delete[] real_ys, imag_ys; + } + return resultECHO; +} + +int WriteComplexData2Amp_Arg(QString out_tiff_path, Eigen::MatrixXcd data) +{ + Eigen::MatrixXd amp_data = Eigen::MatrixXd::Zero(data.rows(), data.cols()); + Eigen::MatrixXd arg_data = Eigen::MatrixXd::Zero(data.rows(), data.cols()); + size_t row_count = data.rows(); + size_t col_count = data.cols(); + for (int i = 0; i < row_count; i++) { + for (int j = 0; j < col_count; j++) { + amp_data(i, j) = std::abs(data(i, j)); + arg_data(i, j) = std::arg(data(i, j)); + } + } + + + Eigen::MatrixXd gt = Eigen::MatrixXd::Zero(2, 3); + + gdalImage image_tiff = CreategdalImage(out_tiff_path, row_count, col_count, 2, gt, "", false, true);// ×¢ÒâÕâÀï±£Áô·ÂÕæ½á¹û + + image_tiff.saveImage(amp_data, 0, 0, 1); + image_tiff.saveImage(arg_data, 0, 0, 2); + + return 0; +} + +int WriteComplexData2AmpdB_Arg(QString out_tiff_path, Eigen::MatrixXcd data) +{ + Eigen::MatrixXd amp_data = Eigen::MatrixXd::Zero(data.rows(), data.cols()); + Eigen::MatrixXd arg_data = Eigen::MatrixXd::Zero(data.rows(), data.cols()); + size_t row_count = data.rows(); + size_t col_count = data.cols(); + for (int i = 0; i < row_count; i++) { + for (int j = 0; j < col_count; j++) { + amp_data(i, j) = 10.0*std::log10(std::abs(data(i, j))); + arg_data(i, j) = std::arg(data(i, j)); + } + } + + + Eigen::MatrixXd gt = Eigen::MatrixXd::Zero(2, 3); + + gdalImage image_tiff = CreategdalImage(out_tiff_path, row_count, col_count, 2, gt, "", false, true);// ×¢ÒâÕâÀï±£Áô·ÂÕæ½á¹û + + image_tiff.saveImage(amp_data, 0, 0, 1); + image_tiff.saveImage(arg_data, 0, 0, 2); + + return 0; +} + +size_t nextpow2(size_t num) +{ + double n = std::round(std::log10(num * 1.0) / std::log10(2.0)); + return pow(2, (size_t)std::ceil(n) + 1); +} + + +Eigen::MatrixXcd IFFTW1D(Eigen::MatrixXcd ECHOdata) +{ + size_t data_rows = ECHOdata.rows(); + size_t data_cols = ECHOdata.cols(); + // ƵÓò ת»»µ½ ʱÓò + size_t n2 = nextpow2(data_cols) ; + //qDebug() << data_rows << "," << data_cols << "," << n2 << "\n"; + // ²¹Áã + Eigen::MatrixXcd ExpandECHO = Eigen::MatrixXcd::Zero(data_rows, n2); + for (int i = 0; i < data_rows; i++) { + for (int j = 0; j < data_cols; j++) { + ExpandECHO(i, j) = ECHOdata(i, j); + } + } + // ½á¹û + Eigen::MatrixXcd echoTime = Eigen::MatrixXcd::Zero(data_rows, n2); + + fftw_complex* din = (fftw_complex*)fftw_malloc(sizeof(double) * n2 * 2); + fftw_complex* dout = (fftw_complex*)fftw_malloc(sizeof(double) * n2 * 2); + fftw_plan p; + double n = 1.0 / n2; // ÒòΪ fftw µÄÄæ¸µÀïÒ¶±ä»»£¬Ã»ÓгýÓÚN,ËùÒÔʵ¼ÊÉÏÊÇÔ­À´µÄN±¶ + //ÖðÐнøÐÐfftw + p = fftw_plan_dft_1d(n2, din, dout, FFTW_BACKWARD, FFTW_MEASURE);//FFTW_BACKWARD Äæ£¬ + fftw_execute(p); //FFTW_MEASURE ¹À¼Æ×îÓű任·½·¨£¬ºóÃæ¸´Óñ任·½°¸ + // ¸µÀïÒ¶ ¼ÆËã½ø¶È + for (int i = 0; i < data_rows; i++) { + for (int j = 0; j < n2; j++) { // ³õʼ»¯ÊäÈë + din[j][0] = std::real(ExpandECHO(i, j)); + din[j][1] = std::imag(ExpandECHO(i, j)); + } + // ¹¹½¨fftw ÈÎÎñ + fftw_execute(p); + // ±£´æ½á¹û + for (int j = 0; j < n2; j++) { //¶ÁÈ¡½á¹û + echoTime(i, j) = std::complex(dout[j][0], dout[j][1]) * n; // ÿ´Î±ä»»ºó¶¼³ýÓÚn + } + printf("\rIFFT[%.2lf%%]...:", i * 100.0 / (data_rows - 1)); + } + fftw_destroy_plan(p); + fftw_free(din); + fftw_free(dout); + qDebug() << "\n"; + qDebug() << "IFFT over" << "\n"; + return echoTime; +} + +Eigen::MatrixXcd FFTW1D(Eigen::MatrixXcd ECHO) +{ + size_t data_rows = ECHO.rows(); + size_t data_cols = ECHO.cols(); + // ƵÓò ת»»µ½ ʱÓò + size_t n2 = data_cols; + // ²¹Áã + Eigen::MatrixXcd ExpandECHO = Eigen::MatrixXcd::Zero(data_rows, n2); + for (int i = 0; i < data_rows; i++) { + for (int j = 0; j < data_cols; j++) { + ExpandECHO(i, j) = ECHO(i, j); + } + } + // ½á¹û + Eigen::MatrixXcd echofreq = Eigen::MatrixXcd::Zero(data_rows, n2); + fftw_complex* din = (fftw_complex*)fftw_malloc(sizeof(double) * n2 * 2); + fftw_complex* dout = (fftw_complex*)fftw_malloc(sizeof(double) * n2 * 2); + fftw_plan p; + //ÖðÐнøÐÐfftw + p = fftw_plan_dft_1d(n2, din, dout, FFTW_FORWARD, FFTW_MEASURE);//FFTW_FORWARD ˳£¬ + fftw_execute(p); //FFTW_MEASURE ¹À¼Æ×îÓű任·½·¨£¬ºóÃæ¸´Óñ任·½°¸ + for (int i = 0; i < data_rows; i++) { + for (int j = 0; j < n2; j++) { // ³õʼ»¯ÊäÈë + din[j][0] = std::real(ExpandECHO(i, j)); + din[j][1] = std::imag(ExpandECHO(i, j)); + } + // ¹¹½¨fftw ÈÎÎñ + fftw_execute(p); + // ±£´æ½á¹û + for (int j = 0; j < n2; j++) { //¶ÁÈ¡½á¹û + echofreq(i, j) = std::complex(dout[j][0], dout[j][1]); + } + printf("\rFFT[%.2lf%%]...:", i * 100.0 / (data_rows - 1)); + } + fftw_destroy_plan(p); + fftw_free(din); + fftw_free(dout); + qDebug() << "\n"; + qDebug() << "FFT over" << "\n"; + return echofreq; +} + + + +Eigen::MatrixXcd FFTW2D(Eigen::MatrixXcd ECHO) +{ + // »ñÈ¡Êý¾ÝµÄ³ß´ç + int rows = ECHO.rows(); + int cols = ECHO.cols(); + + // ´´½¨FFTWÊäÈëºÍÊä³öÊý×é + fftw_complex* in = reinterpret_cast(ECHO.data()); + fftw_complex* out = static_cast(fftw_malloc(sizeof(fftw_complex) * rows * cols)); + + // ´´½¨FFTW¼Æ»®£¬Ö´ÐиµÁ¢Ò¶±ä»» + fftw_plan plan = fftw_plan_dft_2d(rows, cols, in, out, FFTW_FORWARD, FFTW_ESTIMATE); + fftw_execute(plan); + + // ´òÓ¡¸µÁ¢Ò¶±ä»»½á¹û + Eigen::MatrixXcd result(rows, cols); + result = Map(reinterpret_cast*>(out), rows, cols); + //qDebug() << "Fourier Transform Result: " << "\n" << result << "\n"; + + // Ïú»ÙFFTW¼Æ»®ºÍÄÚ´æ + fftw_destroy_plan(plan); + fftw_free(out); + qDebug() << "\n"; + qDebug() << "FFT over" << "\n"; + return result; +} + + +Eigen::MatrixXcd fftshift(Eigen::MatrixXcd X) { + int rows = X.rows(); + int cols = X.cols(); + int rows_half = rows / 2; + int cols_half = cols / 2; + + Eigen::MatrixXcd tmp = X.topLeftCorner(rows_half, cols_half); + X.topLeftCorner(rows_half, cols_half) = X.bottomRightCorner(rows_half, cols_half); + X.bottomRightCorner(rows_half, cols_half) = tmp; + + tmp = X.topRightCorner(rows_half, cols_half); + X.topRightCorner(rows_half, cols_half) = X.bottomLeftCorner(rows_half, cols_half); + X.bottomLeftCorner(rows_half, cols_half) = tmp; + + return X; +} \ No newline at end of file diff --git a/src/LAMPTool/SARBaseToolLib/SARImageBase.h b/src/LAMPTool/SARBaseToolLib/SARImageBase.h new file mode 100644 index 0000000..e488482 --- /dev/null +++ b/src/LAMPTool/SARBaseToolLib/SARImageBase.h @@ -0,0 +1,95 @@ +#pragma once +#ifndef SARIMAGEBASE_H +#define SARIMAGEBASE_H +/** +* ³ÉÏñ¹ý³ÌÖг£ÓõļÆË㺯Êý +****/ +#include "referenceHeader.h" +#include "SARBaseTool.h" +// ------------------------------------------- ³ÉÏñ ¹«Óÿâ---------------------------------------------------------- +// SAR ³£ÓüÆËãµÄ·½·¨ +double getRangeResolution(double startfreq, double endfreq); + +/// +/// ·½Î»Ïò·Ö±æÂʼÆËã +/// +/// »¡¶ÈÖÆ£¬·½Î»½Ç±ä»¯·¶Î§£¨>=0£© +/// ÆðʼƵÂÊ +/// +double getAzimuthResolution(double AzAngleRange, double startFreq); +// ¸ù¾ÝÊäÈëÊýÁ¿¹¹½¨ººÃ÷´° +Eigen::MatrixXd hammingWindows(size_t num); + + +// ƵÂÊÓòººÃ÷´°¿Ú + +/// +/// ƵÂÊÓòººÃ÷´°¿Ú +/// +/// ƵÂʵãÊý +/// Âö³åÊýÁ¿ +/// È¨ÖØ +/// ººÃ÷´°È¨ÖØ +Eigen::MatrixXd Hanning(size_t Nf, size_t Nxa, double alpha = 0.54); + +/// +/// »ñÈ¡2µÄƽ·½Êý,´óÓÚ2 +/// +/// +/// +size_t nextpow2(size_t num); + +/// +/// ¶Ô»Ø²¨ÑØ×ÅÐнøÐÐһά¸µÀïÒ¶Äæ±ä»» +/// +/// +/// +Eigen::MatrixXcd IFFTW1D(Eigen::MatrixXcd ECHO); + + +/// +/// ¶Ô»Ø²¨ÑØ×ÅÐнøÐÐһά¸µÀïÒ¶±ä»» +/// +/// +/// +Eigen::MatrixXcd FFTW1D(Eigen::MatrixXcd echo); +Eigen::MatrixXcd FFTW2D(Eigen::MatrixXcd ECHO); + +Eigen::MatrixXcd fftshift(Eigen::MatrixXcd X); +/// +/// ¶Ô»Ø²¨ ¼Ó hamming ´° +/// +/// ƵÓòµÄ»Ø²¨Êý¾Ý£¨PRFnum,Freqnum) +/// +Eigen::MatrixXcd HammingWindows(Eigen::MatrixXcd FreqEcho); + + +/// +/// ¶Ô»Ø²¨½øÐÐһά²åÖµ(²¢ÐУ©£¬²»ÄÜÓÃÀ´´¦Àí¼«×ø±ê +/// ²åÖµ·½Ê½Îª ʵ²¿Ð鲿·Ö±ð½øÐÐÏßÐÔ²åÖµ +/// +/// »Ø²¨Êý¾Ý,£¨ÐÐÊý£¬ÁÐÊý£©:£¨PRFNUM,freqNUM£© +/// »Ø²¨µÄ ԭʼƵÂÊÁбí +/// »Ø²¨µÄ ²åֵƵÂÊÁбí +/// +Eigen::MatrixXcd InterpFreqEcho(Eigen::MatrixXcd freqEcho, Eigen::VectorXd SourceFreqlist, Eigen::VectorXd interpFreqlist); + + +/// +/// ±£´æ¸´Êý¾ØÕóÊý¾Ý Ϊtiff£¬ ÆäÖУ¬band 1: amp (linear) angle(radia) +/// +/// +/// +/// +int WriteComplexData2Amp_Arg(QString out_tiff_path, Eigen::MatrixXcd data); + + +/// +/// ±£´æ¸´Êý¾ØÕóÊý¾Ý Ϊtiff£¬ ÆäÖУ¬band 1: amp (dB) angle(radia) +/// +/// +/// +/// +int WriteComplexData2AmpdB_Arg(QString out_tiff_path, Eigen::MatrixXcd data); +// ---------------------------------------------------------------------------------------------------------- +#endif diff --git a/src/LAMPTool/SARImage/FEKOBaseToolClass.cpp b/src/LAMPTool/SARImage/FEKOBaseToolClass.cpp new file mode 100644 index 0000000..d06a2e9 --- /dev/null +++ b/src/LAMPTool/SARImage/FEKOBaseToolClass.cpp @@ -0,0 +1,1040 @@ +#include "SARImage/FEKOBaseToolClass.h" +#include +#include "BaseToolLib/BaseConstVariable.h" +#include +#include +#include +#include "BaseToollib/ImageOperatorBase.h" +#include +#include "SARBaseToolLib/SARBaseTool.h" +#include "BaseToollib/FileOperator.h" +#include + + + + + + + + + +QString FEKOBase::FEKOImageModeenumToString(FEKOBase::FEKOImageMode mode) +{ + switch (mode) { + case Strip: + return "STRIP"; + case Scane: + return "SCANE"; + case ISAR: + return "ISAR"; + case CircleSAR: + return "CircleSAR"; + } + // Èç¹ûö¾ÙÖµ²»Æ¥ÅäÈκÎ×Ö·û´®£¬Ôò·µ»ØÒ»¸öĬÈÏÖµ£¬»òÕßÅ׳öÒì³£ + return "UNKNOW"; // ĬÈÏ·µ»ØUnknown +} + +FEKOBase::FEKOCoordinateSystem FEKOBase::FEKOCoordinateSystemString2Enum(QString str) +{ + if (str.toUpper() == "SPHERICAL") { return FEKOBase::Spherical; } + else if (str.toUpper() == "CARTESIAN") { return FEKOBase::Cartesian; } + else { + return FEKOBase::UNKONWFEKOCOORDINATESYSTEM; + } + +} + +QString FEKOBase::QString2FEKOCoordinateSystem(FEKOBase::FEKOCoordinateSystem mode) +{ + switch (mode) { + case FEKOBase::Spherical: + return "SPHERICAL"; + case FEKOBase::Cartesian: + return "CARTESIAN"; + default: + return "UNKONWFEKOCOORDINATESYSTEM"; + + } +} + +FEKOBase::FEKOImageMode FEKOBase::FEKOImageModeString2Enum(QString str) +{ + if (str.toUpper() == "STRIP") { + return FEKOBase::FEKOImageMode::Strip; + } + else if (str.toUpper() == "SCANE") { + return FEKOBase::FEKOImageMode::Scane; + } + else if (str.toUpper() == "ISAR") { + return FEKOBase::FEKOImageMode::ISAR; + } + else if (str.toUpper() == "CIRCLESAR") { + return FEKOBase::FEKOImageMode::CircleSAR; + } + // Èç¹ûÊäÈëµÄ×Ö·û´®²»Æ¥ÅäÈκÎö¾ÙÖµ£¬Ôò·µ»ØÒ»¸öĬÈÏÖµ£¬»òÕßÅ׳öÒì³£ + return FEKOBase::FEKOImageMode::UNKNOW; // ĬÈÏ·µ»ØUNKNOW +} + +FEKOBase::freqParams FEKOBase::getFreqSetting(double centerFreq, double resolution, double bandWidth, double scenceRange, bool isResolution) { + + FEKOBase::freqParams result{ 0,0,0 }; + { + if (isResolution) { + bandWidth = 0.299792458 / 2 / resolution; // ¼ÆËã´ø¿í + } + else { + resolution = 0.299792458 / 2 / bandWidth; // ¼ÆËã·Ö±æÂÊ + } + } + size_t samplePoint = std::ceil((scenceRange) / resolution) + 1; + result.startfreqs = centerFreq - 0.5 * bandWidth; + result.endfreqs = centerFreq + 0.5 * bandWidth; + result.freqpoint = samplePoint; + return result; +} + +FEKOBase::FEKOSatelliteParams FEKOBase::createFEKOSatelliteParams(double Px, double Py, double Pz, double Vx, double Vy, double Vz, double incidenceAngle, double AzAngle, double theta, double phi, bool isRight, size_t PRFIdx) +{ + FEKOBase::FEKOSatelliteParams result{ + PRFIdx, + FEKOBase::SatelliteState{ + FEKOBase::SatellitePosition{Px,Py,Pz}, + FEKOBase::SatelliteVelocity{Vx,Vy,Vz} + }, + incidenceAngle,AzAngle, + FEKOBase::FEKOantPitionDirect{Px,Py,Pz,theta,phi}, + isRight + }; + return result; +} + +FEKOBase::FEKOSatelliteParams FEKOBase::createFEKOSatelliteParams(SatelliteState pose, double incidenceAngle, double AzAngle, FEKOantPitionDirect antpos, size_t PRFIdx) +{ + FEKOBase::FEKOSatelliteParams result{ + PRFIdx,pose,incidenceAngle,AzAngle,antpos + }; + return result; +} + +FEKOBase::SatelliteState FEKOBase::FEKOSatelliteParams2SatelliteState(FEKOSatelliteParams parmas) +{ + return parmas.pose; +} + +FEKOBase::FEKOantPitionDirect FEKOBase::FEKOSatelliteParams2FEKOantPitionDirect(FEKOSatelliteParams parmas) +{ + return parmas.antpos; +} + +TopoDS_Shape FEKOBase::SatellitePos2FEKOAntPos(SatelliteState satepos, double incidenceAngle, double AzAngle, bool isRIGHT, FEKOantPitionDirect* antposition_Direct, TopoDS_Shape antModel) +{ + incidenceAngle = incidenceAngle * M_PI / 180; // ת»»Îª»¡¶È + AzAngle = AzAngle * M_PI / 180; // ɨÃè½Ç¶Èת»»Îª»¡¶È + TopoDS_Shape tempShape; + if (!antModel.IsNull()) { + // ´´½¨Ò»¸ö¸´ÖÆ + BRepBuilderAPI_Copy copyBuilder(antModel); + tempShape = copyBuilder.Shape(); + } + + double Sx = satepos.pos.Px; + double Sy = satepos.pos.Py; + double Sz = satepos.pos.Pz; + double Vx = satepos.vel.Vx; + double Vy = satepos.vel.Vy; + double Vz = satepos.vel.Vz; + //qDebug() << u8"// 0. ÎÀÐÇ״̬ʸÁ¿"; + gp_Vec SateVelocity(gp_Pnt(0, 0, 0), gp_Pnt(Vx, Vy, Vz)); // ÎÀÐÇËÙ¶ÈʸÁ¿ + gp_Vec SatePosition(gp_Pnt(0, 0, 0), gp_Pnt(Sx, Sy, Sz)); // ÎÀÐÇλÖÃʸÁ¿ + gp_Vec sch_X(gp_Pnt(0, 0, 0), gp_Pnt(1.0, 0.0, 0.0)); + gp_Vec sch_Y(gp_Pnt(0, 0, 0), gp_Pnt(0.0, 1.0, 0.0)); // ·ÉÐз½Ïò y + gp_Vec sch_Z(gp_Pnt(0, 0, 0), gp_Pnt(0.0, 0.0, 1.0)); // À×´ïÕÕÉä·½Ïò + +// qDebug() << u8"// 1. ÎÀÐÇ×ø±êϵ sch -->·ÉÐÐ×ø±êϵ fly ±£Ö¤ZÖáÖ¸Ïò²»±ä»¯"; + gp_Vec sch_X_fly; + gp_Vec sch_Y_fly; // ·ÉÐÐÏò + gp_Vec sch_Z_fly; + + { + CartesianCoordinates Sp_car{ sch_Y.X(),sch_Y.Y(), sch_Y.Z() }; + CartesianCoordinates tp_car{ SateVelocity.X(),SateVelocity.Y(), SateVelocity.Z() }; + + SphericalCoordinates sp_sph = cartesianToSpherical(Sp_car); + SphericalCoordinates tp_sph = cartesianToSpherical(tp_car); + + // ¼ÆËã + double delta_theta = tp_sph.theta - sp_sph.theta; + double delta_phi = tp_sph.phi - sp_sph.phi; + + gp_Trsf rotationTransform_theta; + rotationTransform_theta.SetRotation(gp_Ax1(gp_Pnt(0, 0, 0), gp_Dir(0, 1, 0)), delta_theta); // ÈÆ y ÖáÐýת + sch_X_fly = sch_X.Transformed(rotationTransform_theta); + sch_Y_fly = sch_Y.Transformed(rotationTransform_theta); + sch_Z_fly = sch_Z.Transformed(rotationTransform_theta); + + gp_Trsf rotationTransform_phi; + rotationTransform_phi.SetRotation(gp_Ax1(gp_Pnt(0, 0, 0), gp_Dir(0, 0, 1)), delta_phi); // ÈÆ z ÖáÐýת + sch_X_fly = sch_X_fly.Transformed(rotationTransform_phi); + sch_Y_fly = sch_Y_fly.Transformed(rotationTransform_phi); + sch_Z_fly = sch_Z_fly.Transformed(rotationTransform_phi); + + if (!tempShape.IsNull()) { + BRepBuilderAPI_Transform shapeTransform_theta(tempShape, rotationTransform_theta); + tempShape = shapeTransform_theta.Shape(); + BRepBuilderAPI_Transform shapeTransform_phi(tempShape, rotationTransform_phi); + tempShape = shapeTransform_phi.Shape(); + } + } + +// qDebug() << u8"// 2. ¸ù¾Ý·½Î»½ÇÓ븩Ñö½Ç£¬µ÷ÕûÀ×´ï×Ë̬ --- ´Ë²½È·¶¨ Y ÖáÒѾ­µ÷ÕûÍê±Ï "; +// qDebug() << u8"// 2. a ¸ù¾Ý incidenceAngle µ÷Õû Z µÄÖ¸Ïò£¬ÐèÒªÏȸù¾Ý×óÓÒÊÓÅжϳöÀ×´ïÕÕÉä·½Ïò"; + + { // °´ÕÕ Y Öá½øÐмÆËã + incidenceAngle = M_PI - incidenceAngle; // ÏÂZÖá + Standard_Real ZRotation_angle = 0; + if (isRIGHT) { // ÓÒÊÓ + + ZRotation_angle = incidenceAngle; + } + else { // ×óÊÓ - + ZRotation_angle = -1 * incidenceAngle; + } + gp_Trsf fly_incidence_trsf; + fly_incidence_trsf.SetRotation(gp_Ax1(gp_Pnt(0, 0, 0), sch_Y_fly), ZRotation_angle); // ¼ÆËãÈëÉä½Ç + + sch_X_fly = sch_X_fly.Transformed(fly_incidence_trsf); + sch_Y_fly = sch_Y_fly.Transformed(fly_incidence_trsf); + sch_Z_fly = sch_Z_fly.Transformed(fly_incidence_trsf); // ´Ëʱ»ñÈ¡À×´ïµÄÕÕÉä·½Ïò + + if (!tempShape.IsNull()) { + BRepBuilderAPI_Transform shapeTransform_incidence(tempShape, fly_incidence_trsf); // fly_Z --> incidenceAngle + tempShape = shapeTransform_incidence.Shape(); + } + + } + +// qDebug() << u8"// 2.b ¸ù¾Ý AzAngle µ÷Õû Z µÄÖ¸Ïò "; +// qDebug() << u8"// Az Ó¦¸Ã±ä»¯ÔÚ YoZ£¬ Ò²¾ÍÊÇÈÆ X Öá Ðýת£»"; + + { // ÑØZ Öá½øÐмÆËã + gp_Trsf fly_AZ_trsf; + fly_AZ_trsf.SetRotation(gp_Ax1(gp_Pnt(0, 0, 0), sch_X_fly), AzAngle); // ¼ÆË㷽λ½Ç±ä»¯ + + sch_X_fly = sch_X_fly.Transformed(fly_AZ_trsf); + sch_Y_fly = sch_Y_fly.Transformed(fly_AZ_trsf); + sch_Z_fly = sch_Z_fly.Transformed(fly_AZ_trsf); // ´Ëʱ»ñÈ¡À×´ïµÄÕÕÉä·½Ïò + + if (!tempShape.IsNull()) { + BRepBuilderAPI_Transform shapeTransform_AZ(tempShape, fly_AZ_trsf); // fly_Z --> incidenceAngle + tempShape = shapeTransform_AZ.Shape(); // ÐýתÎÀÐÇÄ£ÐÍ + } + + } +// qDebug() << u8"// 2.c ²ÎÊý¼Ç¼ "; + { + CartesianCoordinates Sp_car{ 0,0,1 }; + CartesianCoordinates tp_car{ sch_Z_fly.X(),sch_Z_fly.Y(), sch_Z_fly.Z() }; + + SphericalCoordinates sp_sph = cartesianToSpherical(Sp_car); + SphericalCoordinates tp_sph = cartesianToSpherical(tp_car); // ¼ÆËãphi½Ç¶È + + double delta_theta = tp_sph.theta - sp_sph.theta; + double delta_phi = tp_sph.phi - sp_sph.phi; + + antposition_Direct->x = Sx; //-- FEKO ÉèÖà + antposition_Direct->y = Sy; //-- FEKO ÉèÖà + antposition_Direct->z = Sz; //-- FEKO ÉèÖà + antposition_Direct->theta = delta_theta / M_PI * 180; //-- FEKO ÉèÖà theta + antposition_Direct->phi = delta_phi / M_PI * 180;//--- FEKO ÉèÖà phi + + } +// qDebug() << u8"//3. Ö´ÐÐÄ£ÐÍÆ½ÒÆ"; + { + if (!tempShape.IsNull()) { + gp_Trsf fly_move_trsf; + fly_move_trsf.SetTranslation(SatePosition); + BRepBuilderAPI_Transform shapeTransform_move(tempShape, fly_move_trsf); // fly_Z --> incidenceAngle + tempShape = shapeTransform_move.Shape(); // Æ½ÒÆÎÀÐÇÄ£ÐÍ + + } + } + + qDebug() << QString(u8"À×´ï×ø±êÓë×Ë̬£¨X,Y,Z,theta,phi): £¨%1,%2,%3,%4,%5)").arg(antposition_Direct->x) + .arg(antposition_Direct->y) + .arg(antposition_Direct->z) + .arg(antposition_Direct->theta) + .arg(antposition_Direct->phi); + + return tempShape; +} + +bool FEKOBase::compareElectricFieldDataInFreq(const ElectricFieldData& a, const ElectricFieldData& b) +{ + return a.frequency < b.frequency; +} + +bool FEKOBase::comparePRFPluseDataInPRFIdx(const PRFPluseData& a, const PRFPluseData& b) +{ + return a.prfidx < b.prfidx; +} + +FEKOBase::NearFieldEchoCSVParser::NearFieldEchoCSVParser() +{ +} + +FEKOBase::NearFieldEchoCSVParser::~NearFieldEchoCSVParser() +{ +} + +bool FEKOBase::NearFieldEchoCSVParser::checkPRFModel() +{ + + qDebug() << u8"ÕýÔÚ¼ì²éÊÇ·ñ¿ÉÒÔ²ÉÓÃÂö³å¼ÆÊýģʽ configuration Name £ºPRF_{Âö³å¼ÆÊý}"; + + QRegExp regex("(\\d+)"); + // ÅжÏÊÇ·ñÐèÒª°´ÕÕÂö³å´ÎÐòÅÅÐò + bool usePRFbool = true; + QMap configName_prfidx; + // ʹÓõü´úÆ÷±éÀú QMap + QMap>::const_iterator it; + for (it = this->electricFieldDataList.constBegin(); it != this->electricFieldDataList.constEnd(); ++it) { + for (size_t i = 0; i < this->electricFieldDataList[it.key()].size(); i++) { + QString value = this->electricFieldDataList[it.key()][i].configurationName; + if (value.indexOf("PRF") != -1) { + if (regex.indexIn(value) != -1) { + // ÌáȡƥÅäµ½µÄ²¿·Ö + QString matchedText = regex.cap(1); + + size_t PRFidx = matchedText.toInt(&usePRFbool); + if (usePRFbool) { + configName_prfidx.insert(this->electricFieldDataList[it.key()][i].configurationName, PRFidx); + } + else { + qDebug() << u8"²»ÄܲÉÓÃÂö³å¼ÆÊýÄ£ÐÍ"; + QMessageBox::information(nullptr, u8"¾¯¸æ", u8"ÎÞ·¨¸ù¾ÝConfiguration Nameʶ±ðÂö³å˳Ðò£¬°´ÕÕ¶Áȡ˳Ðò£¬¼ÆÊýPRF", QMessageBox::Ok); + this->usePRFCountMode = false; + return false; + } + } + } + else { + qDebug() << u8"²»ÄܲÉÓÃÂö³å¼ÆÊýÄ£ÐÍ"; + QMessageBox::information(nullptr, u8"¾¯¸æ", u8"ÎÞ·¨¸ù¾ÝConfiguration Nameʶ±ðÂö³å˳Ðò£¬°´ÕÕ¶Áȡ˳Ðò£¬¼ÆÊýPRF", QMessageBox::Ok); + this->usePRFCountMode = false; + return false; + } + } + } + + // ¸üÐÂprfidx + for (it = this->electricFieldDataList.constBegin(); it != this->electricFieldDataList.constEnd(); ++it) { + if (!(this->electricFieldDataList[it.key()].size() > 0)) { + QMessageBox::warning(nullptr, u8"´íÎó", u8"·¢ÏÖ¿ÕÂö³å£º" + it.key()); + qWarning() << u8"·¢ÏÖ¿ÕÂö³å£º" + it.key(); + return false; + } + else {} + + QString value = this->electricFieldDataList[it.key()][0].configurationName; + + for (size_t i = 0; i < this->electricFieldDataList[it.key()].size(); i++) { + if (value != this->electricFieldDataList[it.key()][0].configurationName) { + QMessageBox::warning(nullptr, u8"´íÎó", u8"Âö³å½âÎö´íÎó£¬Ãû³Æ²»Ò»Ö£º" + it.key() + " | " + value); + qWarning() << u8"Âö³å½âÎö´íÎó£¬Ãû³Æ²»Ò»Ö£º" + it.key() + " | " + value; + } + else {} + size_t tempprfidx = configName_prfidx[value]; + this->electricFieldDataList[it.key()][i].prfidx = tempprfidx; + } + } + + qDebug() << u8"½áÊø¼ì²éÊÇ·ñ¿ÉÒÔ²ÉÓÃÂö³å¼ÆÊýģʽ configuration Name £ºPRF_{Âö³å¼ÆÊý}"; + return true; +} + +bool FEKOBase::NearFieldEchoCSVParser::resizePRFPluse() +{ + qDebug() << u8"¸ù¾ÝÊý¾ÝÎļþ£¬ÖØÐÂÕûÀí³ÉÂö³åÐÎʽ"; + + QMap prfPluseMap; // ²ÉÓÃ×ÖµäÓ³É䷽ʽ + + qDebug() << u8"QMap> ==> QMap"; + double px; // 2. ¼ÆËã×Ë̬£¬½ü³¡µã×ø±ê + double py; + double pz; + double R; + double theta; // x0y + double phi; // y0z + size_t PRFidx; + + for (QMap>::const_iterator it = this->electricFieldDataList.constBegin(); it != this->electricFieldDataList.constEnd(); ++it) { + PRFPluseData temp; + std::vector tempData = this->electricFieldDataList[it.key()]; // Âö³åÒѾ­ÅÅÐòºÅ + std::sort(tempData.begin(), tempData.end(), compareElectricFieldDataInFreq); + temp.electricFieldDataList = tempData; // °´ÕÕÂö³åÅÅÐò + + temp.freqstart = tempData[0].frequency; // 1. ƵÂÊ + temp.freqend = tempData[tempData.size() - 1].frequency; + temp.freqpoints = tempData.size(); + + px = tempData[0].origin.x; // 2. ½ü³¡½ÓÊÕµã¼ÆËã×Ë̬£¬½ü³¡µã×ø±ê + py = tempData[0].origin.y; + pz = tempData[0].origin.z; + + + R = tempData[0].radius; + theta = tempData[0].theta; // x0y + phi = tempData[0].phi; // y0z + + + + + PRFidx = tempData[0].prfidx; + qDebug() << u8"·ÖÎö×Ë̬:" + it.key(); + for (size_t i = 0; i < tempData.size(); i++) { + if (abs(px - tempData[i].origin.x) > 0.001 || abs(py - tempData[i].origin.y) > 0.001 || + abs(pz - tempData[i].origin.z) > 0.001 || abs(R - tempData[i].radius) > 0.001 || + abs(theta - tempData[i].theta) > 0.001 || abs(phi - tempData[i].phi) > 0.001) + { + qDebug() << u8"·¢ÏÖ configuration Name:" + it.key() + u8" , ·¢ÏÖÎÊÌ⣬Çë¼ì²é"; + QMessageBox::warning(nullptr, u8"¾¯¸æ", u8"·¢ÏÖ configuration Name:" + it.key() + u8" , ·¢ÏÖÎÊÌ⣬Çë¼ì²é"); + return false; + } + else {} + } + // ¼ÆËãÔöÁ¿ R, theta, phi ==> delta_R,delta_theta,delta_phi + theta = theta * M_PI / 180; + phi = phi * M_PI / 180; + + px = px + R * std::sin(theta) * std::cos(phi); + py = py + R * std::sin(theta) * std::sin(phi); + pz = pz + R * std::cos(theta); + + temp.px = px; + temp.py = py; + temp.pz = pz; + temp.prfidx = PRFidx; + + + prfPluseMap.insert(it.key(), temp); + } + + + qDebug() << u8"ÅжÏÊÇËùÓлز¨¾ùÒ»ÐÔ"; + this->prfData = std::vector(0); + size_t freqpointnum = prfPluseMap.first().freqpoints; + for (QMap::const_iterator it = prfPluseMap.constBegin(); it != prfPluseMap.constEnd(); ++it) { + if (it.value().freqpoints != freqpointnum) { + qDebug() << u8"»Ø²¨Êý¾ÝƵµãÊý²»Ò»Ö£¬ÎÞ·¨½øÐÐÂö³å¼ÆÊý"; + QMessageBox::information(nullptr, u8"¾¯¸æ", u8"»Ø²¨Êý¾ÝƵµãÊý²»Ò»Ö£¬ÎÞ·¨½øÐÐÂö³å¼ÆÊý", QMessageBox::Ok); + this->usePRFCountMode = false; + return false; + } + this->prfData.push_back(it.value()); + } + this->freqPoints = freqpointnum; + std::sort(this->prfData.begin(), this->prfData.end(), comparePRFPluseDataInPRFIdx); + + this->freqStart = this->prfData[0].freqstart; + this->freqEnd = this->prfData[0].freqend; + qDebug() << u8"¸ù¾ÝÊý¾ÝÎļþ£¬½áÊøÕûÀí³ÉÂö³åÐÎʽ"; + return true; + +} + +bool FEKOBase::NearFieldEchoCSVParser::parseCSV(const QString& filePath) +{ + + std::vector dataList; + + QFile file(filePath); + if (file.open(QIODevice::ReadOnly | QIODevice::Text)) { + QTextStream in(&file); + + // ¶ÁÈ¡±êÌâÐÐ + QString headerLine = in.readLine(); + QStringList headers = headerLine.split(QRegularExpression(",(?!\\s)")); + + while (!in.atEnd()) { + QString line = in.readLine(); + + QStringList fields = line.split(QRegularExpression(",(?!\\s)")); + + ElectricFieldData data; + // ½âÎöÊý¾Ý¸ù¾ÝÁÐÃû + for (int i = 0; i < headers.size(); ++i) { + QString header = headers[i].trimmed(); + QString value = fields[i];// .trimmed(); + + if (header == "File Type") { + data.fileType = value; + } + else if (header == "File Format") { + data.fileFormat = value; + } + else if (header == "Source") { + data.source = value; + } + else if (header == "Date") { + data.date = value; + } + else if (header == "Radius") { // °ë¾¶ + data.radius = value.toDouble(); + } + else if (header == "Theta") { // theta ½Ç + data.theta = value.toDouble(); + } + else if (header == "Phi") {// phi ½Ç + data.phi = value.toDouble(); + } + else if (header == "Re(Er)") { + data.reEr = value.toDouble(); + } + else if (header == "Im(Er)") { + data.imEr = value.toDouble(); + } + else if (header == "Re(Etheta)") { + data.reEtheta = value.toDouble(); + } + else if (header == "Im(Etheta)") { + data.imEtheta = value.toDouble(); + } + else if (header == "Re(Ephi)") { + data.reEphi = value.toDouble(); + } + else if (header == "Im(Ephi)") { + data.imEphi = value.toDouble(); + } + else if (header == "Configuration Name") { // Âö³å´ÎÐòÃû³Æ + data.configurationName = value.trimmed(); + } + else if (header == "Request Name") { + data.requestName = value.trimmed(); + } + else if (header == "Frequency") { + data.frequency = value.toDouble(); + } + else if (header == "Coordinate System") { + data.coordinateSystem = value; + } + else if (header == "Origin") { // ×ø±ê²Î¿¼Ô­µã + QStringList vls = value.replace("\"", "").replace("(", "").replace(")", "").split(","); + if (vls.length() < 3) { + qDebug() << "******************** ERROR INFO ******************************************"; + qDebug() << "origin point has error ," << value; + qDebug() << "line: " << line; + qDebug() << "head: " << header; + qDebug() << "***************************************************************************"; + QMessageBox::information(nullptr, u8"¾¯¸æ", u8"ÎÞ·¨½âÎöOrigin ²ÎÊý£¬Çë¼ì²é", QMessageBox::Ok); + return false; + } + data.origin = Point_3d{ vls.at(0).toDouble(), + vls.at(1).toDouble(), + vls.at(2).toDouble() }; + } + else if (header == "Num Radius Samples") { + data.numRadiusSamples = value.toInt(); + } + else if (header == "Num Theta Samples") { + data.numThetaSamples = value.toInt(); + } + else if (header == "Num Phi Samples") { + data.numPhiSamples = value.toInt(); + } + else if (header == "Result Type") { + data.resultType = value; + } + else if (header == "Num Header Lines") { + data.numHeaderLines = value.toInt(); + } + // Ìí¼ÓÆäËû×ֶεĽâÎö... + } + dataList.push_back(data); + } + + file.close(); + } + else { + qDebug() << "Failed to open the file:" << file.errorString(); + return false; + } + + //this->electricFieldDataList = dataList; + + qDebug() << u8"Îļþ¶ÁÈ¡½á¹û£¬¶ÔÎļþ½á¹û½øÐÐÖØÐÂÕûÀíÓë¼ì²é"; + //»ñÈ¡Âö³å×îСֵ£¬×î´óÖµ£¬Èç¹ûÊÇ Ê¹ÓÃÈí¼þÉú²úµÄ configname Ó¦¸ÃΪ PRF_1 PRF_2 ÕâÀïͨ¹ýÅÐ¶Ï 1,2 À´È·¶¨Âö³åÐòºÅ + QSet configNameSet; + size_t curPRF = 0; + for (int i = 0; i < dataList.size(); i++) { + if (!configNameSet.contains(dataList[i].configurationName)) { + curPRF = curPRF + 1; + } + dataList[i].prfidx = curPRF; + configNameSet.insert(dataList[i].configurationName); + } + + // ³õʼ»¯ + for (const QString& elementconfigName : configNameSet) { + this->electricFieldDataList.insert(elementconfigName, std::vector(0)); + } + + // Êý¾Ý³õʼ»¯ + for (size_t i = 0; i < dataList.size(); i++) { + this->electricFieldDataList[dataList[i].configurationName].push_back(dataList[i]); + } + // ÿ¸öPluse ½øÐÐÅÅÐò,°´ÕÕÆµÂÊ£º С -> ´ó£¬ + QMap>::const_iterator it; + for (it = this->electricFieldDataList.constBegin(); it != this->electricFieldDataList.constEnd(); ++it) { + std::sort(this->electricFieldDataList[it.key()].begin(), this->electricFieldDataList[it.key()].end(), compareElectricFieldDataInFreq); + } + + // ¼ì²éÿ¸öelectricFieldDataList ÊÇ·ñ°´ÕÕÆµÂʽøÐÐÅÅÐò + for (it = this->electricFieldDataList.constBegin(); it != this->electricFieldDataList.constEnd(); ++it) { + for (size_t i = 0; i < this->electricFieldDataList[it.key()].size() - 1; i++) { + if (this->electricFieldDataList[it.key()][i].frequency > this->electricFieldDataList[it.key()][i + 1].frequency) { + qDebug() << u8"·¢ÏÖ configuration Name:" + it.key() + u8" , ·¢ÏÖÎÊÌ⣬Çë¼ì²é"; + QMessageBox::warning(nullptr, u8"¾¯¸æ", u8"·¢ÏÖ configuration Name:" + it.key() + u8" , ·¢ÏÖÎÊÌ⣬Çë¼ì²é"); + return false; + } + } + } + + + if (!this->checkPRFModel() || !this->resizePRFPluse()) { + return false; + } + + return true; + +} + +void FEKOBase::NearFieldEchoCSVParser::toThetapolar(const QString& filePath) +{ + + this->toEchoData(filePath, 2); +} + +void FEKOBase::NearFieldEchoCSVParser::toPhiPolar(const QString& filePath) +{ + this->toEchoData(filePath, 1); +} + +void FEKOBase::NearFieldEchoCSVParser::toRPolar(const QString& filePath) +{ + this->toEchoData(filePath, 0); +} + +void FEKOBase::NearFieldEchoCSVParser::saveCSV(const QString& filePath) +{ +} + +/// +/// Êä³öÂö³å»Ø²¨Îļþ +/// +/// Îļþ·¾¶ +/// 0: R,1: phi,2: theta +void FEKOBase::NearFieldEchoCSVParser::toEchoData(const QString& filePath, size_t outDataName) +{ + // Âö³åÕûÀí + Eigen::MatrixXcd echoData = Eigen::MatrixXcd::Zero(this->prfData.size(), this->freqPoints); + Eigen::MatrixXd antpos = Eigen::MatrixXd::Zero(this->prfData.size(), 5); //x,y,z,theta,phi" + + for (size_t i = 0; i < this->prfData.size(); i++) { + antpos(i, 0) = this->prfData[i].px; + antpos(i, 1) = this->prfData[i].py; + antpos(i, 2) = this->prfData[i].pz; + antpos(i, 3) = this->prfData[i].electricFieldDataList[0].theta; + antpos(i, 4) = this->prfData[i].electricFieldDataList[0].phi; + for (size_t j = 0; j < this->freqPoints; j++) { + if (outDataName == 0) { + echoData(i, j) = std::complex(this->prfData[i].electricFieldDataList[j].reEr, this->prfData[i].electricFieldDataList[j].imEr); + } + else if (outDataName == 1) { + echoData(i, j) = std::complex(this->prfData[i].electricFieldDataList[j].reEphi, this->prfData[i].electricFieldDataList[j].imEphi); + } + else { + echoData(i, j) = std::complex(this->prfData[i].electricFieldDataList[j].reEtheta, this->prfData[i].electricFieldDataList[j].imEtheta); + } + + } + } + + EchoDataClass echodataTemp; + echodataTemp.setAntPos(antpos); + echodataTemp.setFreqStart(this->freqStart); + echodataTemp.setFreqEnd(this->freqEnd); + echodataTemp.setFreqpoints(this->freqPoints); + echodataTemp.setEchoData(echoData); + echodataTemp.SaveEchoData(filePath); +} + +FEKOBase::EchoDataClass::EchoDataClass(const FEKOBase::EchoDataClass& inecho) +{ + + this->echoData = inecho.getEchoData(); + this->antPos = inecho.getAntPos(); + this->freqStart = inecho.getFreqStart(); + this->freqEnd = inecho.getFreqEnd(); + this->freqpoints = inecho.getFreqpoints(); +} + + + +FEKOBase::EchoDataClass::EchoDataClass() +{ + +} + +FEKOBase::EchoDataClass::~EchoDataClass() +{ +} + + + + +void FEKOBase::EchoDataClass::setEchoData(Eigen::MatrixXcd echoData) +{ + this->echoData = echoData; +} + +Eigen::MatrixXcd FEKOBase::EchoDataClass::getEchoData() const +{ + return this->echoData; +} + +void FEKOBase::EchoDataClass::setAntPos(Eigen::MatrixXd antPos) +{ + this->antPos = antPos; +} + +Eigen::MatrixXd FEKOBase::EchoDataClass::getAntPos() const +{ + return this->antPos; +} + +void FEKOBase::EchoDataClass::setFreqStart(double freqStart) +{ + this->freqStart = freqStart; +} + +double FEKOBase::EchoDataClass::getFreqStart() const +{ + return this->freqStart; +} + +void FEKOBase::EchoDataClass::setFreqEnd(double freqEnd) +{ + this->freqEnd = freqEnd; +} + +double FEKOBase::EchoDataClass::getFreqEnd() const +{ + return this->freqEnd; +} + +void FEKOBase::EchoDataClass::setFreqpoints(int freqpoints) +{ + this->freqpoints = freqpoints; +} + +int FEKOBase::EchoDataClass::getFreqpoints() const +{ + return this->freqpoints; +} + +void FEKOBase::EchoDataClass::loadEchoData(const QString& filePath) +{ + std::ifstream file(reinterpret_cast(filePath.utf16()), std::ios::binary); + + if (file.is_open()) { + // ±£´æÆµÂʱäÁ¿ + INT32 PRFRow = 0; + INT32 freqCol = 0; + // ¶ÁÈ¡ÆäËû³ÉÔ±±äÁ¿ + file.read(reinterpret_cast(&freqStart), sizeof(double)); + file.read(reinterpret_cast(&freqEnd), sizeof(double)); + file.read(reinterpret_cast(&freqpoints), sizeof(INT32)); + file.read(reinterpret_cast(&PRFRow), sizeof(INT32)); + file.read(reinterpret_cast(&freqCol), sizeof(INT32)); + echoData = Eigen::MatrixXcd::Zero(PRFRow, freqCol); // ÖØÐ·ÖÅäÄÚ´æ + antPos = Eigen::MatrixXd::Zero(PRFRow, 5); + file.read(reinterpret_cast(antPos.data()), sizeof(double) * PRFRow * 5); // ±£´æÌìÏßλÖà + file.read(reinterpret_cast(echoData.data()), sizeof(std::complex) * PRFRow * freqCol); // ±£´æ»Ø²¨Êý¾Ý + file.close(); // ¹Ø±ÕÎļþ + + this->freqStart = freqStart; + this->freqEnd = freqEnd; + this->freqpoints = freqpoints; + this->echoData = echoData; + this->antPos = antPos; + qDebug() << u8"»Ø²¨Êý¾Ý¼ÓÔØÍê³É"; + } + else { + qWarning() << "Error: Unable to open file for reading."; + } +} + +void FEKOBase::EchoDataClass::SaveEchoData(const QString& filePath) +{ + if (echoData.rows() != antPos.rows() || antPos.cols() != 5) { + qDebug() << "Error: antPos.size()!=echoData.rows()*5" + + QString::number(echoData.rows()) + u8"!=" + QString::number(antPos.rows()) + + QString::number(antPos.cols()) + u8"!=5"; + return; + } + else {} + std::ofstream file(reinterpret_cast(filePath.utf16()), std::ios::binary); + qDebug() << "==================================================================="; + qDebug() << u8"»Ø²¨Âö³åÎļþ¸ñʽ˵Ã÷£º"; + qDebug() << u8"|freqStart(double)£¬freqEnd(double)£¬freqpoints(int)|PRFROW(int),PRFCol(int)|antPos|echodata|"; + qDebug() << u8"ÆäÖÐantPos: PRFrow*3 double x,y,z,incidence,azangle,theta,phi"; + qDebug() << u8"ÆäÖÐechodata: PRFrow*PRFCol complex "; + qDebug() << "==================================================================="; + if (file.is_open()) { + INT32 PRFRow = echoData.rows(); + INT32 freqCol = echoData.cols(); + file.write(reinterpret_cast(&freqStart), sizeof(double)); // ±£´æÆµÂʱäÁ¿ + file.write(reinterpret_cast(&freqEnd), sizeof(double)); + file.write(reinterpret_cast(&freqpoints), sizeof(INT32)); + file.write(reinterpret_cast(&PRFRow), sizeof(INT32)); + file.write(reinterpret_cast(&freqCol), sizeof(INT32)); + file.write(reinterpret_cast(antPos.data()), sizeof(double) * antPos.size()); // ±£´æÌìÏßλÖà + file.write(reinterpret_cast(echoData.data()), sizeof(std::complex) * echoData.size()); // ±£´æ»Ø²¨Êý¾Ý + file.close(); // ¹Ø±ÕÎļþ + + } + else { + qDebug() << "Error: Unable to open file for writing."; + } +} + + + +Eigen::MatrixXd FEKOBase::WINDOWFun(Eigen::MatrixXcd& echo, ImageAlgWindowFun winfun) +{ + size_t Nxa = echo.rows(); + size_t Nf = echo.cols(); + Eigen::MatrixXd normw = Eigen::MatrixXd::Zero(Nxa, Nf); // ¹éÒ»»¯´°º¯Êý + + if (winfun == ImageAlgWindowFun::HANMMING) { + normw = Hanning(Nf, Nxa); + echo = echo.array() * normw.array(); + } + else { + normw = normw.array() * 0 + 1 / (Nxa * Nf); + } + + return normw; +} + +QList FEKOBase::getFEKOImageAlgorithmList() +{ + QList list; + FEKOImageAlgorithm alg; + for (alg = FEKOImageAlgorithm::TBP_TIME; alg < FEKOImageAlgorithm::UNKONW; alg = (FEKOImageAlgorithm)(alg + 1)) { + list.append(FEKOImageAlgorithm2String(alg)); + } + return list; +} + +FEKOBase::FEKOImageAlgorithm FEKOBase::String2FEKOImageAlgorithm(QString str) +{ + FEKOImageAlgorithm alg; + for (alg = FEKOImageAlgorithm::TBP_TIME; alg < FEKOImageAlgorithm::UNKONW; alg = (FEKOImageAlgorithm)(alg + 1)) { + if (str == FEKOImageAlgorithm2String(alg)) { + return alg; + } + else {} + } + return alg; +} + +QString FEKOBase::FEKOImageAlgorithm2String(FEKOImageAlgorithm alg) +{ + // ½«FEKOImageAlgorithm ö¾Ùת»»Îª×Ö·û´® + switch (alg) + { + case FEKOBase::TBP_TIME: + return u8"TBP_TIME"; + case FEKOBase::TBP_FREQ: + return u8"TBP_FREQ"; + default: + return u8"UNKONW"; + } +} + +// Çë·ÂÕÕFEKOImageAlgorithmö¾ÙµÄд·¨£¬¹¹½¨QString Óë ImageAlgWindowFun µÄת»»º¯Êý + +QList FEKOBase::getImageAlgWindowFunList() +{ + QList list; + ImageAlgWindowFun alg; + for (alg = ImageAlgWindowFun::NOWINDOWS; alg < ImageAlgWindowFun::UNKONWWINDOW; alg = (ImageAlgWindowFun)(alg + 1)) { + list.append(ImageAlgWindowFun2String(alg)); + } + return list; +} + +FEKOBase::ImageAlgWindowFun FEKOBase::String2ImageAlgWindowFun(QString str) +{ + ImageAlgWindowFun alg; + for (alg = ImageAlgWindowFun::UNKONWWINDOW; alg < ImageAlgWindowFun::UNKONWWINDOW; alg = (ImageAlgWindowFun)(alg + 1)) { + if (str == ImageAlgWindowFun2String(alg)) { + return alg; + } + else {} + } + return alg; +} + +QString FEKOBase::ImageAlgWindowFun2String(FEKOBase::ImageAlgWindowFun alg) +{ + switch (alg) + { + case FEKOBase::NOWINDOWS: + return u8"NOWINDOWS"; + case FEKOBase::HANMMING: + return u8"HANMMING"; + default: + return u8"UNKONWWINDOW"; + } +} + + +bool FEKOBase::BPImage_TIME(QString& restiffpath, Eigen::MatrixXcd& echoData, Eigen::MatrixXd& antPos, Eigen::MatrixXd& freqmatrix, Eigen::MatrixXd& X, Eigen::MatrixXd& Y, Eigen::MatrixXd& Z, ImageAlgWindowFun winfun) +{ + // BP³ÉÏñËã·¨ + const double c = 0.299792458; // ¹âËÙ + + return true; +} + +bool FEKOBase::FBPImage_FREQ(QString& restiffpath, Eigen::MatrixXcd& echoData, Eigen::MatrixXd& antPos, Eigen::MatrixXd& freqmatrix, Eigen::MatrixXd& X, Eigen::MatrixXd& Y, Eigen::MatrixXd& Z, ImageAlgWindowFun winfun) +{ + + // BP³ÉÏñËã·¨ + const double c = 0.299792458; // ¹âËÙ + const std::complex j(0, 1); // ÐéÊýµ¥Î» + const size_t image_height = X.rows(); + const size_t image_width = X.cols(); + const size_t PRFCount = echoData.rows(); + const size_t frepoints = echoData.cols(); + Eigen::MatrixXcd factorj = Eigen::MatrixXcd::Zero(1, echoData.cols()); // 1 , freqs + factorj = freqmatrix.array().cast>().array() * j * 4 * M_PI / c; // ÉùÃ÷УÕý¾ØÕó + Eigen::MatrixXcd im_final = Eigen::MatrixXcd::Zero(image_height, image_width); + + + +#ifdef __SHOWPROCESS // ½ø¶ÈÌõչʾ + QProgressDialog progressDialog(u8"BP_FREQ³ÉÏñ½ø¶È", u8"ÖÕÖ¹", 0, image_height); + progressDialog.setWindowTitle(u8"³ÉÏñÖÐ"); + progressDialog.setWindowModality(Qt::WindowModal); + progressDialog.setAutoClose(true); + progressDialog.setValue(0); + progressDialog.setMaximum(image_height); + progressDialog.setMinimum(0); + progressDialog.show(); +#endif // __SHOWPROCESS + + + +#ifdef __SHOWIMAGEPROCESSRESULT // ¼Ó´°´¦Àí + Eigen::MatrixXd normw = WINDOWFun(echoData, winfun); +#endif + +#ifdef __IMAGEPARALLEL +#pragma omp parallel for + for (long ii = 0; ii < image_height; ii++) + { + Eigen::MatrixXd im_R = Eigen::MatrixXd::Zero(PRFCount, 1);// ͼÏñµ½Âö³å¾ØÕó prf*1 + Eigen::MatrixXcd term_R = Eigen::MatrixXcd::Zero(1, frepoints); + Eigen::MatrixXcd pluse_R = Eigen::MatrixXcd::Zero(PRFCount, 1); + + for (size_t jj = 0; jj < image_width; jj++) { + im_R.col(0) = ((antPos.col(0).array() - X(ii, jj)).array().pow(2) + + (antPos.col(1).array() - Y(ii, jj)).array().pow(2) + + (antPos.col(2).array() - Z(ii, jj)).array().pow(2)) + .array().sqrt().array(); // »ñȡĿ±êµ½ÌìÏß¾ØÕó ¼ÆËã ok + // im_R PRF_count x 1 + for (size_t tt = 0; tt < PRFCount; tt++) { + term_R = (im_R(tt, 0) * factorj.array()).array().exp(); // ok + pluse_R(tt, 0) = (echoData.row(tt).array() * term_R.array()).sum(); // ¶Ôÿ¸öÂö³åУÕýÇóºÍ + } + im_final(ii, jj) = pluse_R.array().sum(); // ¼ÆËãͼÏñ + } + } +#else + + Eigen::MatrixXd im_R = Eigen::MatrixXd::Zero(PRFCount, 1);// ͼÏñµ½Âö³å¾ØÕó prf*1 + Eigen::MatrixXcd term_R = Eigen::MatrixXcd::Zero(1, frepoints); + Eigen::MatrixXcd pluse_R = Eigen::MatrixXcd::Zero(PRFCount, 1); + for (long ii = 0; ii < image_height; ii++) + { + for (size_t jj = 0; jj < image_width; jj++) { + im_R.col(0) = ((antPos.col(0).array() - X(ii, jj)).array().pow(2) + + (antPos.col(1).array() - Y(ii, jj)).array().pow(2) + + (antPos.col(2).array() - Z(ii, jj)).array().pow(2)) + .array().sqrt().array(); // »ñȡĿ±êµ½ÌìÏß¾ØÕó ¼ÆËã ok + // im_R PRF_count x 1 + for (size_t tt = 0; tt < PRFCount; tt++) { + term_R = (im_R(tt, 0) * factorj.array()).array().exp(); // ok + pluse_R(tt, 0) = (echoData.row(tt).array() * term_R.array()).sum(); // ¶Ôÿ¸öÂö³åУÕýÇóºÍ + } + im_final(ii, jj) = pluse_R.array().sum(); // ¼ÆËãͼÏñ + } +#ifdef __SHOWPROCESS + progressDialog.setValue(ii); +#endif + } +#endif + +#ifdef __SHOWIMAGEPROCESSRESULT // ¼Ó´°´¦Àí + im_final = im_final.array() / (normw.array().sum()); + +#endif + + + // 3. ±£´æÍ¼Ïñ + + + QString newrestiffpath = restiffpath; + + + Eigen::MatrixXd gt = Eigen::MatrixXd::Zero(2,3); + gt(0, 0) = X(0, 0); + gt(0, 1) = X(0, 1) - X(0, 0); + gt(0, 2) = 0; + gt(1, 0) = Y(0, 0); + gt(1, 1) = 0; + gt(1, 2) = Y(0, 0) - Y(1, 0); + std::cout << gt << std::endl; + gdalImageComplex im_final_gdal = CreategdalImageComplex(restiffpath,im_final.rows(),im_final.cols(),1,gt, QString(u8""), true,true); + im_final_gdal.setData(im_final); + im_final_gdal.saveImage(); + + qDebug() << QString(u8"±£´æÎļþµØÖ·£º" + restiffpath); +#ifdef __SHOWPROCESS + progressDialog.setWindowTitle(u8"±£´æÎļþ£º" + restiffpath); + progressDialog.setValue(image_height); + progressDialog.close(); +#endif + + // »æÖÆÍ¼Ïñ +#ifdef __SHOWIMAGEPROCESSRESULT + // ½«¸´Êý¾ØÕóµÄ·ù¶Èת»»ÎªÊµÊý¾ØÕó + matplot::figure(); + matplot::vector_2d amplitude_im_final(im_final.rows(), matplot::vector_1d(im_final.cols())); + for (int i = 0; i < im_final.rows(); ++i) { + for (int j = 0; j < im_final.cols(); ++j) { + amplitude_im_final[i][j] = std::abs(im_final(i, j)); + } + } + matplot::imagesc(amplitude_im_final); + matplot::colorbar(); + matplot::show(); +#endif // __SHOWMATPLOTLIBCPP + + return true; +} + + + diff --git a/src/LAMPTool/SARImage/FEKOBaseToolClass.h b/src/LAMPTool/SARImage/FEKOBaseToolClass.h new file mode 100644 index 0000000..16c851e --- /dev/null +++ b/src/LAMPTool/SARImage/FEKOBaseToolClass.h @@ -0,0 +1,338 @@ +#pragma once +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "referenceHeader.h" +#include "BaseToollib/GeoOperator.h" + + +/** +* ´ËÀàÓÃÓÚFEKOµÄ»ù±¾ÀàÐÍ£¬Ö÷Òª¹¦ÄÜÈçÏ£º +* 1. ¸ù¾Ý·Ö±æÂÊ¡¢ÖÐÐÄÆµÂÊ¡¢´ø¿í£¬½üԶб¾à£¬¼ÆËãÆµÂÊÆðʼµã£¬ÒÔ¼°²ÉÑùµãÊý +* 2. ¸ù¾ÝÆðʼ³ÉÏñµã¡¢³ÉÏñʱ³¤¡¢PRF²ÉÑùµãÊý£¬»ñÈ¡PRF²ÉÑùµãÊý +* 3. ½áºÏ PRF²ÉÑùµã×ø±ê£¬ÈëÉä½Ç£¬ÒÔ¼°Óë·ÉÐз½ÏòµÄ¼Ð½Ç£¨Ä¬ÈÏΪ 90¶È£©, ²Î¿¼¸ß³Ì£¬¼ÆËãÈëÉ䲨µÄ²Î¿¼Æ½Ã沿·Ö +* 4. +***/ + +namespace FEKOBase { + + //========================================================== + // FEKO³£ÓÃ×ø±êϵ + //========================================================== + enum FEKOCoordinateSystem { + Spherical, // Çò×ø±êϵ + Cartesian, // µÑ¿¨¶û×ø±êϵ + UNKONWFEKOCOORDINATESYSTEM // ±ØÐëΪ×îºóÒ»¸ö±íʾδ֪ + }; + FEKOBase::FEKOCoordinateSystem FEKOCoordinateSystemString2Enum(QString str); + QString QString2FEKOCoordinateSystem(FEKOBase::FEKOCoordinateSystem mode); + + + //========================================================== + // FEKO³ÉÏñģʽö¾Ù + //========================================================== + enum FEKOImageMode + { + Strip, + Scane, + ISAR, + CircleSAR, + UNKNOW + }; + + FEKOImageMode FEKOImageModeString2Enum(QString str); + QString FEKOImageModeenumToString(FEKOImageMode mode); + + + + + //========================================================== + // FEKO³ÉÏñ·ÂÕæ²ÎÊýÀ࣬Ö÷ÒªÓÃÀ´´î½¨Í³Ò»µÄ·ÂÕæ³ÉÏñÄ£¿é + //========================================================== + + + + + //========================================================== + // ƵÂʲÎÊý + //========================================================== + struct freqParams { // ƵÂʲÎÊý + double startfreqs; + double endfreqs; + size_t freqpoint; + }; + + //========================================================== + // ÊäÈëµÄÎÀÐDzÎÊý + //========================================================== + struct SatellitePosition { // ÎÀÐÇ×Ë̬ + double Px = 0, Py = 0, Pz = 0; + }; + struct SatelliteVelocity { // ÎÀÐÇËÙ¶È + double Vx = 0, Vy = 0, Vz = 0; + }; + + struct SatelliteState { // ÎÀÐÇʸÁ¿ + SatellitePosition pos; + SatelliteVelocity vel; + }; + + + //========================================================== + // FEKO Ô¶³¡µÈЧԴ×Ë̬²ÎÊý + //========================================================== + struct FEKOantPitionDirect { + double x = 0; + double y = 0; + double z = 0; + double theta = 0; + double phi = 0; + }; + + + //=========================================================== + // FEKO³ÉÏñÉèÖòÎÊý + //=========================================================== + struct FEKOImageSettingParams { + double min_x = 0; + double max_x = 0; + double min_y = 0; + double max_y = 0; + double plane_z = 0; // Æ½Ãæ¸ß³Ì + size_t ImageWidth = 0; + size_t ImageHeight = 0; + + }; + + + + //========================================================== + // FEKO²ÎÊýÎļþµÈЧ²ÎÊý + //========================================================== + struct FEKOSatelliteParams { // FEKOPRFÂö³å²ÎÊý + size_t PRFidx = 0; // PRF Âö³å¼ÆÊý + SatelliteState pose;// ÎÀÐÇʸÁ¿ + double incidenceAngle = 0; // ÈëÉä½Ç + double AzAngle = 0; // ×Ë̬½Ç + FEKOantPitionDirect antpos;// ÌìÏßʵ¼Ê×Ë̬ + bool isRight = false; // ÅжÏ×óÓÒÊÓ£¬false ×ó£¬right ÓÒ + }; + + + ///////////////////////////////////////////////// + ///// º¯ÊýÀà + ////////////////////////////////////////////// + /// + /// ƵÂÊSetting + /// + /// ÖÐÐÄÆµÂÊ GHZ + /// ·Ö±æÂÊ Ã× + /// ´ø¿í GHz + /// ·Ö±æÂÊ Ã× + /// + /// + freqParams getFreqSetting(double centerFreq, double resolution, double bandWidth, double scenceRange, bool isResolution = false); + + FEKOSatelliteParams createFEKOSatelliteParams(double Px, double Py, double Pz, double Vx, double Vy, double Vz, double incidenceAngle, double AzAngle, double theta, double phi, bool isRight, size_t PRFIdx = 0); + FEKOSatelliteParams createFEKOSatelliteParams(SatelliteState pose, double incidenceAngle, double AzAngle, FEKOantPitionDirect antpos, size_t PRFIdx = 0); + + SatelliteState FEKOSatelliteParams2SatelliteState(FEKOSatelliteParams parmas); + FEKOantPitionDirect FEKOSatelliteParams2FEKOantPitionDirect(FEKOSatelliteParams parmas); + + /// + /// ½«ÎÀÐÇ×Ë̬ת»»Îª FEKO ÌìÏß×ø±ê£¬ + /// ×¢ÒâĬÈÏÄ£Ð͵ÄZÖáΪÌìÏßµÄÖ¸Ïò + /// + /// ÎÀÐÇʸÁ¿ + /// ÈëÉä½Ç + /// ²àÊÓ½Ç + /// ÊÇ·ñΪÓÒÊÓ + /// ½á¹ûÎļþ + /// ÊäÈëÄ£ÐÍ + /// + TopoDS_Shape SatellitePos2FEKOAntPos(SatelliteState satepos, double incidenceAngle, double AzAngle, bool isRIGHT, FEKOantPitionDirect* antposition_Direct, TopoDS_Shape inDs); + + + + //=============================================== + // FEKO½á¹û½âÎöÎļþ + //=============================================== + + struct ElectricFieldData { + QString fileType; + QString fileFormat; + QString source; + QString date; + double radius; + double theta; + double phi; + double reEr; + double imEr; + double reEtheta; + double imEtheta; + double reEphi; + double imEphi; + QString configurationName; + QString requestName; + double frequency; + QString coordinateSystem; + Point_3d origin; + int numRadiusSamples; + int numThetaSamples; + int numPhiSamples; + QString resultType; + int numHeaderLines; + size_t prfidx = -1; // Âö³å¼ÆÊý£¬>0 + }; + + struct PRFPluseData { // µ¥¸öPRFÂö³åÊý¾Ý¸ñʽ + size_t prfidx; //Âö³å´ÎÊý + double freqstart; + double freqend; + size_t freqpoints; + + double px, py, pz; + //double theta, phi; + //double incidence, azangle; + //std::vector freqlist; + std::vector electricFieldDataList; // µ¥ÆµµãÐÅÏ¢ + }; + + bool compareElectricFieldDataInFreq(const ElectricFieldData& a, const ElectricFieldData& b); + bool comparePRFPluseDataInPRFIdx(const PRFPluseData& a, const PRFPluseData& b); + + class NearFieldEchoCSVParser { + public: + NearFieldEchoCSVParser(); + ~NearFieldEchoCSVParser(); + private: + bool usePRFCountMode = true; + //std::vector electricFieldDataList; + QMap> electricFieldDataList; // µç³¡Êý¾Ý + //QMap prfPluseMap; + std::vector prfData; + size_t freqPoints; + double freqStart; + double freqEnd; + // ƵÂʲÎÊý + private: // ÄÚ²¿¼ì²éº¯Êý + bool checkPRFModel(); + bool resizePRFPluse(); //»Ø²¨ÕûÀí + + public: + bool parseCSV(const QString& filePath); // ¶ÁÈ¡»Ø²¨Êý¾ÝÎļþ + void toThetapolar(const QString& filePath);// Êä³ötheta ¼«»¯ + void toPhiPolar(const QString& filePath);// Êä³öphi ¼«»¯ + void toRPolar(const QString& filePath);// Êä³öphi ¼«»¯ + void saveCSV(const QString& filePath);// Êä³öcsvÎļþ + private: + void toEchoData(const QString& filePath, size_t outDataName);// Êä³ö»Ø²¨Êý¾Ý + }; + + + + + //======================================================================== + // ³ÉÏñ»Ø²¨¸ñʽ + // file type: + // freqStart,freqEnd,freqPoint,isRight, + // PRF1,Pos,incidenceAngle,AzAngle,echoDatalist + // PRF2,Pos,incidenceAngle,AzAngle,echoDatalist + // ¡£ + // ¡£ + // ¡£ + // ×¢ÒâBp²¢²»¹ØÐÄÂö³åµÄ˳Ðò£¬Ö»ÊǹØ×¢Âö³åµÄ×ø±êλÖã¬Ä¬Èϰ´ÕÕÂö³åµÄ½âÎö˳Ðò½øÐÐ×éÖ¯ + //======================================================================== + class EchoDataClass { + private: // ³ÉÏñ±äÁ¿ + Eigen::MatrixXcd echoData; // »Ø²¨Êý¾Ý + Eigen::MatrixXd antPos;// ÿ¸öÂö³åµÄ×ø±ê + double freqStart; // ÆðʼƵÂÊ + double freqEnd; // ÖÕֹƵÂÊ + int freqpoints; // ƵÂʵãÊý + + public: + EchoDataClass(const FEKOBase::EchoDataClass& inecho); + EchoDataClass(); + ~EchoDataClass(); + public: + // ¸ù¾Ýÿ¸ö³ÉÔ±±äÁ¿¹¹½¨ÊôÐÔ + void setEchoData(Eigen::MatrixXcd echoData); + Eigen::MatrixXcd getEchoData() const; + void setAntPos(Eigen::MatrixXd antPos); + Eigen::MatrixXd getAntPos() const; + void setFreqStart(double freqStart); + double getFreqStart() const; + void setFreqEnd(double freqEnd); + double getFreqEnd() const; + void setFreqpoints(int freqpoints); + int getFreqpoints() const; + + void loadEchoData(const QString& filePath); // ¼ÓÔØ»Ø²¨Êý¾ÝÎļþ + void SaveEchoData(const QString& filePath); // ±£´æ»Ø²¨Êý¾ÝÎļþ + }; + + + + + + //========================================================== + // ·ÂÕæ³ÉÏñËã·¨Àà + // BP³ÉÏñËã·¨ + // ½¨Ò齫ËùÓÐµÄÆµÂÊ´¦Àíµ½ GHz µ¥Î»£¬±ÜÃâÆµÂʹý´óµ¼Öµľ«¶ÈÎÊÌâ + // »Ø²¨¾ØÕó£º + // PRF1:f1,f2,f3,f4 + // PRF2£ºf1,f2,f3,f4 + // PRF2£ºf1,f2,f3,f4 + //========================================================== + + enum ImageAlgWindowFun // ³ÉÏñ·½·¨¼Ó´°·½·¨ + { + NOWINDOWS, + HANMMING, + UNKONWWINDOW + }; + + /// + /// ¼Ó´° + /// + /// ÐÐ:Âö³å£¬ÁУºÆµµã + /// + Eigen::MatrixXd WINDOWFun(Eigen::MatrixXcd& echo, ImageAlgWindowFun winfun = ImageAlgWindowFun::HANMMING); + + enum FEKOImageAlgorithm + { + TBP_TIME, + TBP_FREQ, + UNKONW // ±ØÐëΪ×îºóÒ»¸ö±íʾδ֪ + }; + + QList getFEKOImageAlgorithmList(); + FEKOImageAlgorithm String2FEKOImageAlgorithm(QString str); + QString FEKOImageAlgorithm2String(FEKOImageAlgorithm alg); + + // Çë·ÂÕÕFEKOImageAlgorithmö¾ÙµÄд·¨£¬¹¹½¨QString Óë ImageAlgWindowFun µÄת»»º¯Êý + QList getImageAlgWindowFunList(); + ImageAlgWindowFun String2ImageAlgWindowFun(QString str); + QString ImageAlgWindowFun2String(ImageAlgWindowFun alg); + + + bool BPImage_TIME(QString& restiffpath, Eigen::MatrixXcd& echoData, Eigen::MatrixXd& antPos, Eigen::MatrixXd& freqmatrix, Eigen::MatrixXd& X, Eigen::MatrixXd& Y, Eigen::MatrixXd& Z, ImageAlgWindowFun winfun = ImageAlgWindowFun::HANMMING); // BP³ÉÏñ + bool FBPImage_FREQ(QString& restiffpath, Eigen::MatrixXcd& echoData, Eigen::MatrixXd& antPos, Eigen::MatrixXd& freqmatrix, Eigen::MatrixXd& X, Eigen::MatrixXd& Y, Eigen::MatrixXd& Z, ImageAlgWindowFun winfun = ImageAlgWindowFun::HANMMING); // FBP³ÉÏñ + + + +} \ No newline at end of file diff --git a/src/LAMPTool/SARImage/FEKONearBPBasic.cpp b/src/LAMPTool/SARImage/FEKONearBPBasic.cpp new file mode 100644 index 0000000..7a56487 --- /dev/null +++ b/src/LAMPTool/SARImage/FEKONearBPBasic.cpp @@ -0,0 +1,1028 @@ +#include "FEKONearBPBasic.h" +#include "BaseToolLib/interpolation.h" +#include "BaseToollib/FileOperator.h" +#include "BaseToollib/BaseTool.h" +#include "BaseToollib/ImageOperatorBase.h" +#include "SARBaseToolLib/SARImageBase.h" +#include +#include +#include +#include +#include +#include + +#include "SARBaseToolLib/SARBaseTool.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + + + + +// ¶¨Òå²åÖµº¯Êý£¬ÒÔ´¦Àí¸´ÊýÖµ +std::complex InterpolateComplex(Eigen::MatrixXd& xi, Eigen::MatrixXd& yi, Eigen::MatrixXcd& data, double x, double y) { + int m = xi.rows(); + int n = xi.cols(); + + if (x < xi(0, 0) || x > xi(m - 1, n - 1) || y < yi(0, 0) || y > yi(m - 1, n - 1)) { + std::complex defaultMatrix = std::complex(0,0); // ³¬³ö·¶Î§Ê±·µ»ØÄ¬ÈÏÖµ + return defaultMatrix; + } + + int i, j; + for (i = 0; i < m - 1; i++) { + if (x >= xi(i, 0) && x <= xi(i + 1, 0)) { + break; + } + } + + for (j = 0; j < n - 1; j++) { + if (y >= yi(0, j) && y <= yi(0, j + 1)) { + break; + } + } + + double x1 = xi(i, 0); + double x2 = xi(i + 1, 0); + double y1 = yi(0, j); + double y2 = yi(0, j + 1); + + std::complex Q11 = data(i, j); + std::complex Q12 = data(i, j + 1); + std::complex Q21 = data(i + 1, j); + std::complex Q22 = data(i + 1, j + 1); + + double dx1 = x2 - x; + double dx2 = x - x1; + double dy1 = y2 - y; + double dy2 = y - y1; + double denom = (x2 - x1) * (y2 - y1); + + std::complex interpolatedValue = (Q11 * dx1 * dy1 + Q21 * dx2 * dy1 + Q12 * dx1 * dy2 + Q22 * dx2 * dy2) / denom; + return interpolatedValue; +} + + +Eigen::MatrixXd Cartesian2Spherical(Eigen::MatrixXd CartesianPoint) +{ + Eigen::MatrixXd result = CartesianPoint; + size_t rows = result.rows(); + size_t cols = result.cols(); + for (int i = 0; i < rows; i++) { + double x = CartesianPoint(i, 0); + double y = CartesianPoint(i, 1); + double z = CartesianPoint(i, 2); + result(i, 0) = std::sqrt(CartesianPoint(i, 0) * CartesianPoint(i, 0) + + CartesianPoint(i, 1) * CartesianPoint(i, 1) + + CartesianPoint(i, 2) * CartesianPoint(i, 2)); + result(i, 1) = std::acos(CartesianPoint(i, 2) / result(i, 0));// ÐÐ theta + if (CartesianPoint(i, 0) == 0 && CartesianPoint(i, 1) == 0) { + result(i, 2) = 0; + } + else { + result(i, 2) = std::asin(y / (std::sin(result(i, 1)) * result(i, 0)));//Ò» Èý -pi/2 pi/2 + if (CartesianPoint(i, 0) < 0 && CartesianPoint(i, 1) > 0) { // ¶þ + result(i, 2) = PI - result(i, 2);// phi + } + else if (CartesianPoint(i, 0) < 0 && CartesianPoint(i, 1) < 0) { + result(i, 2) = -1 * PI - result(i, 2);// phi + } + else {} + } + } + + return result; +} + +int BP2DProcess(QString in_path, QString out_path, double Rref, double minX, double maxX, double minY, double maxY, double PlaneZ, int ImageHeight, int ImageWidth) +{ + BP2DProcessClass process; + process.initProcess(in_path, out_path, Rref, minX, maxX, minY, maxY, PlaneZ, ImageHeight, ImageWidth); + process.start(); + return -1; +} + + +int FBP2DProcess(QString in_path, QString out_path, double Rref, double minX, double maxX, double minY, double maxY, double PlaneZ, int ImageHeight, int ImageWidth) +{ + FBP2DProcessClass process; + process.initProcess(in_path, out_path, Rref, minX, maxX, minY, maxY, PlaneZ, ImageHeight, ImageWidth); + process.start(); + return -1; +} + +int build2Bin(QString path, int width, int height, std::vector& freqs, Eigen::MatrixXd AntPostion, Eigen::MatrixXcd echo) +{ + /* +* % ¹¹½¨»Ø²¨½á¹û +fid=fopen("H_echo.bin","w+"); +fwrite(fid,801,'int32'); +fwrite(fid,801,'int32'); +for i=1:length(freqs) + fwrite(fid,freqs(i),'double'); +end + +for i=1:length(AntPostion) + fwrite(fid,AntPostion(i,1),'double'); + fwrite(fid,AntPostion(i,2),'double'); + fwrite(fid,AntPostion(i,3),'double'); + fwrite(fid,real(echo_H_datas(i,:)),'double'); + fwrite(fid,imag(echo_H_datas(i,:)),'double'); +end +fclose(fid); +**/ +// ¹¹½¨¶þ½øÖÆÎļþ + + std::ofstream file(path.toUtf8().constData(), std::ios::binary); + double freq; + + file.write(reinterpret_cast(&height), sizeof(height)); + file.write(reinterpret_cast(&width), sizeof(width)); + + for (size_t i = 0; i < freqs.size(); i++) { + freq = freqs[i]; + file.write(reinterpret_cast(&freq), sizeof(freq)); + } + + double x, y, z; + double real_val, imag_val; + + for (size_t i = 0; i < AntPostion.rows(); i++) { + x = AntPostion(i, 0); + y = AntPostion(i, 1); + z = AntPostion(i, 2); + file.write(reinterpret_cast(&x), sizeof(x)); + file.write(reinterpret_cast(&y), sizeof(y)); + file.write(reinterpret_cast(&z), sizeof(z)); + for (size_t j = 0; j < echo.cols(); j++) { + real_val = std::real(echo(i, j)); + imag_val = std::imag(echo(i, j)); + file.write(reinterpret_cast(&real_val), sizeof(real_val)); + file.write(reinterpret_cast(&imag_val), sizeof(imag_val)); + } + } + + file.close(); + return 0; +} + +template +Eigen::MatrixXcd BP2DImageByPluse(Eigen::MatrixXcd timeEcho, Eigen::MatrixXd AntPosition, double minX, double maxX, double minY, double maxY, double PlaneZ, double Rref, size_t ImageWidth, size_t ImageHeight, double startfreq, size_t timefreqnum, double timeFreqBandWidth, T* logclss) +{ + bool logfun = !(nullptr == logclss); // ¿ÕÖ¸Õë + double delta_x = (maxX - minX) / (ImageWidth - 1); + double delta_y = (maxY - minY) / (ImageHeight - 1); + + double* Rs = new double[timefreqnum]; // ʱÓò ¾àÀë²åÖµ + for (int i = 0; i < timefreqnum; i++) { + Rs[i] = (LIGHTSPEED / timeFreqBandWidth) * i; // ²Î¿¼ ¡¶À×´ï³ÉÏñËã·¨¡·-- Æ¥ÅäÂ˲¨Ò»Õ + } + double wave_len = LIGHTSPEED / startfreq; + if (logfun) { + logclss->logFUN(0, "process....."); + } + + size_t process = 0; + size_t PRFNUM = timeEcho.rows(); + Eigen::MatrixXcd img = Eigen::MatrixXcd::Zero(ImageHeight, ImageWidth); + + for (int i = 0; i < PRFNUM; i++) { + gsl_interp_accel* accopm = gsl_interp_accel_alloc(); + const gsl_interp_type* tt = gsl_interp_linear; //gsl_interp_cspline_periodic; + gsl_spline* spline_time_real = gsl_spline_alloc(tt, timefreqnum); + gsl_spline* spline_time_imag = gsl_spline_alloc(tt, timefreqnum); + + double* real_time_ys = new double[timefreqnum]; + double* imag_time_ys = new double[timefreqnum]; + for (int tt = 0; tt < timefreqnum; tt++) { + real_time_ys[tt] = timeEcho(i, tt).real(); + imag_time_ys[tt] = timeEcho(i, tt).imag(); + } + gsl_spline_init(spline_time_real, Rs, real_time_ys, timefreqnum); + gsl_spline_init(spline_time_imag, Rs, imag_time_ys, timefreqnum); + for (int ii = 0; ii < ImageHeight; ii++) { + for (int jj = 0; jj < ImageWidth; jj++) { + double px = ii * delta_x + minX; + double py = jj * delta_y + minY; + double pz = PlaneZ; + double dR = 0; + double R = std::sqrt( + std::pow(AntPosition(i, 0) - px, 2) + + std::pow(AntPosition(i, 1) - py, 2) + + std::pow(AntPosition(i, 2) - pz, 2) + ); + dR = R - Rref; + std::complex echo_temp( + gsl_spline_eval(spline_time_real, R, accopm),// ²åֵʵ²¿ + gsl_spline_eval(spline_time_imag, R, accopm)// ²åÖµÐ鲿 + ); + img(ii, jj) = img(ii, jj) + echo_temp * std::exp(std::complex(0, 2 * pi * dR / wave_len)); + } + } + gsl_spline_free(spline_time_real); + gsl_spline_free(spline_time_imag); + gsl_interp_accel_free(accopm); + // ±£´æÎļþ + process = process + 1; + if (logfun) { + logclss->logFUN((size_t)(process / PRFNUM * 100), "BP process over"); + } + } + if (logfun) { + logclss->logFUN(100, "BP process over"); + } + return img; +} + + +template +Eigen::MatrixXcd BP2DImageByPixel(Eigen::MatrixXcd timeEcho, Eigen::MatrixXd AntPosition, double minX, double maxX, double minY, double maxY, double PlaneZ, double Rref, size_t ImageWidth, size_t ImageHeight, double startfreq, size_t timefreqnum, double timeFreqBandWidth, T* logclss) +{ + bool logfun = !(nullptr == logclss); + double delta_x = (maxX - minX) / (ImageWidth - 1); + double delta_y = (maxY - minY) / (ImageHeight - 1); + double maxRange = delta_x * ImageWidth > delta_y * ImageHeight ? delta_x * ImageWidth : delta_y * ImageHeight; + double halfR = Rref * 0.1; + double maxRLs = std::sqrt(Rref * Rref + halfR * halfR) - Rref; + double minR = Rref - maxRange * 2 - maxRLs; // ×îСб¾à + double maxR = Rref + maxRange * 2 + maxRLs; // ×î´óб¾à + + double dftime = timeFreqBandWidth / (timefreqnum - 1); + + // ºóÐøÐèÒªÔö¼Ó¾àÀë´°µÄ¼ÆËã·½·¨ + + + double dRs = (LIGHTSPEED / 2.0/timeFreqBandWidth); // ¾àÀëÏò·Ö±æÂÊ + double* Rs = new double[timefreqnum]; // ʱÓò ¾àÀë²åÖµ + for (int i = 0; i < timefreqnum; i++) { + Rs[i] = 2*dRs * i; // ²Î¿¼ ¡¶À×´ï³ÉÏñËã·¨¡·-- Æ¥ÅäÂ˲¨Ò»Õ + } + //double wave_len = LIGHTSPEED / startfreq; + if (logfun) { + logclss->logFUN(0, "process....."); + } + + + size_t process = 0; + size_t PRFNUM = timeEcho.rows(); + + Eigen::MatrixXcd img = Eigen::MatrixXcd::Zero(ImageHeight, ImageWidth); + omp_lock_t lock; + omp_init_lock(&lock); // ³õʼ»¯»¥³âËø + size_t parallel_step = 100; + + +#pragma omp parallel for // NEW ADD + for (int ii = 0; ii < ImageHeight; ii = ii + parallel_step) { + size_t start_i = ii; + size_t max_i = ii + parallel_step; + max_i = max_i < ImageHeight ? max_i : ImageHeight; + + + double px; + double py ; + double pz; + std::complex echo_sum(0, 0); + double R = 0; + double dR = 0; + + + // ¹ÀËã×ø±êµÄ¼Ð½Ç£¬¹ÀËãË«ÏßÐÔ¾àÀë + Eigen::MatrixXd Rline(PRFNUM, 2); + Point_3d Vpluse_p; + Point_3d Vs_e; + double Rline_ref ; + double offer_Rline; + + Eigen::MatrixX> echoline; + double real, imag; + std::complex echo_temp; + std::complex echo_phase(0, 0); + std::complex last_value; + std::complex next_value; + size_t last_ids; + size_t next_ids; + double index = 0; + + Vector3D p; + Vector3D lineP; + Vector3D lineDirection; + double DopplerFreq; + double wave_len; + + + for (int i = start_i; i < max_i; i++) + { + for (int j = 0; j < ImageWidth; j++) { + px = i * delta_x + minX; + py = j * delta_y + minY; + pz = PlaneZ; + echo_sum.real(0); + echo_sum.imag(0); + R = 0; + dR = 0; + + + for (int mm = 0; mm < PRFNUM; mm++) { // ¼ÆËãÿ¸öÂö³åÇé¿ö + Rline(mm, 0) = std::sqrt( + std::pow(AntPosition(mm, 0) - px, 2) + + std::pow(AntPosition(mm, 1) - py, 2) + + std::pow(AntPosition(mm, 2) - pz, 2) + ); + + // ¼ÆËã¼Ð½Ç + Vpluse_p.x = px - AntPosition(mm, 0); + Vpluse_p.y = py - AntPosition(mm, 1); + Vpluse_p.z = pz - AntPosition(mm, 2); + if (mm == 0) { + Vs_e.x = AntPosition(mm + 1, 0) - AntPosition(mm, 0); + Vs_e.y = AntPosition(mm + 1, 1) - AntPosition(mm, 1); + Vs_e.z = AntPosition(mm + 1, 2) - AntPosition(mm, 2); + } + else { + Vs_e.x = AntPosition(mm, 0) - AntPosition(mm - 1, 0); + Vs_e.y = AntPosition(mm, 1) - AntPosition(mm - 1, 1); + Vs_e.z = AntPosition(mm, 2) - AntPosition(mm - 1, 2); + } + + Rline(mm, 1) = Vpluse_p.x * Vs_e.x + Vpluse_p.y * Vs_e.y + Vpluse_p.z * Vs_e.z; // cos(90)=0 + } + Rline_ref = Rref; + // ²éÕÒ×îСֵ£¬»ñÈ¡ 0¶àÆÕÀÕÌõ¼þÏ嵀 ×î¶Ì²Î¿¼Â·¾¶ + for (int mm = 0; mm < PRFNUM - 1; mm++) { + if (Rline(mm, 0) == 0) { // Çó½â×îСֵ + Rline_ref = Rline(mm, 0); + break; + } + else { + double flag = Rline(mm, 1) * Rline(mm + 1, 1); + if (flag < 0) { // ²»Í¬ºÅ + // Çó½âÄ¿±êµãµ½ µ±Ç°Ö±ÏßµÄ×î¶Ì¾àÀë + p.x = px; + p.y = py; + p.z = pz; + lineP.x = AntPosition(mm, 0); + lineP.y = AntPosition(mm, 1); + lineP.z = AntPosition(mm, 2); + lineDirection.x = AntPosition(mm + 1, 0) - AntPosition(mm, 0); + lineDirection.y = AntPosition(mm + 1, 1) - AntPosition(mm, 1); + lineDirection.z = AntPosition(mm + 1, 2) - AntPosition(mm, 2); + + Rline_ref = pointToLineDistance(p, lineP, lineDirection); + break; + } + } + } + + offer_Rline = Rline_ref - Rref; // ¼ÆËãÆ«ÒÆÏß + Rline = Rline.array() + offer_Rline; + + for (int mm = 0; mm < PRFNUM; mm++) { + R= Rline(mm, 0); // ÒѾ­Ð£ÕýÁ˾àÀëá㶯Ïß + + //if (R maxR) { // ¾àÀë´° + // continue; + //} + dR = R - Rref; + // ²åÖµ¼ÆËã + index = R / 2 / dRs; + last_ids = size_t(std::floor(index)); + next_ids = size_t(std::ceil(index)); + + last_value = timeEcho(mm, last_ids); + next_value = timeEcho(mm, next_ids); + + // ʵ²¿£¬Ð鲿ͬʱ²åÖµ + real = last_value.real() + ((next_value.real() - last_value.real()) / (next_ids - last_ids)) * (index - last_ids); + imag = last_value.imag() + ((next_value.imag() - last_value.imag()) / (next_ids - last_ids)) * (index - last_ids); + echo_temp.real(real); + echo_temp.imag(imag); + + DopplerFreq =std::sqrt(R*R - Rline_ref* Rline_ref) / Rline_ref * startfreq; + wave_len = std::abs(LIGHTSPEED / DopplerFreq); + echo_phase.imag(-2 * pi * dR / wave_len); + echo_sum = echo_sum + echo_temp;// *std::exp(echo_phase); + } + img(i, j) = echo_sum; + } + // ±£´æÎļþ + + } + omp_set_lock(&lock); + process = process + parallel_step; + process = process < ImageHeight ? process : ImageHeight; + if (logfun) { + logclss->logFUN(size_t(std::round(process * 1.0 / ImageHeight * 100)), "BP process over"); + } + omp_unset_lock(&lock); + } + omp_destroy_lock(&lock); //Ïú»Ù»¥³âÆ÷ + if (logfun) { + logclss->logFUN(100, "BP process over"); + } + return img; +} + + +int BP2DProcessClass::initProcess(QString in_path, QString out_path, double Rref, double minX, double maxX, double minY, double maxY, double PlaneZ, int ImageHeight, int ImageWidth) +{ + // ³õʼ»¯²ÎÊý + this->readEchoFile(in_path); + this->out_path = out_path; + this->Rref = Rref; // ³ÉÏñÖÐÐĵIJο¼¾àÀë + this->minX = minX; + this->maxX = maxX; + this->minY = minY; + this->maxY = maxY; + this->Zplane = PlaneZ; + this->ImageHeight = ImageHeight; + this->ImageWidth = ImageWidth; + // ¼ÆËã×ø±êµÄµ½³ÉÏñÖÐÐĵÄ×ø±ê + this->centerX = (this->maxX + this->minX) / 2; + this->centerY = (this->minY + this->maxY) / 2; + this->AntPosition.col(0) = this->AntPosition.col(0).array() - this->centerX; + this->AntPosition.col(1) = this->AntPosition.col(1).array() - this->centerY; + this->AntPosition.col(2) = this->AntPosition.col(2).array() - this->Zplane; + // ¼ÆËãÆµÂÊÏà¹ØÐÅÏ¢ + this->f1 = this->Frequencylist(0); + this->freqnum = this->Frequencylist.rows(); + this->fc = (this->f1 + this->Frequencylist(this->freqnum - 1)); + return -1; +} + +int BP2DProcessClass::readEchoFile(QString in_path) +{ + std::ifstream fin(in_path.toUtf8().constData(), std::ios::in | std::ios::binary); + if (!fin.is_open()) exit(2); + // ¶ÁÈ¡²ÎÊý + int height = 0; + int width = 0; + fin.read((char*)&height, sizeof(int)); + fin.read((char*)&width, sizeof(int)); + this->height = height; + this->width = width; + //frequencylist[width*double] + double* freqs = new double[width]; + fin.read((char*)freqs, sizeof(double) * width); + this->Frequencylist = Eigen::VectorXd::Zero(width, 1); // ÁÐÏòÁ¿ + for (int i = 0; i < width; i++) { + this->Frequencylist(i) = freqs[i]; + } + delete[] freqs; + freqs = nullptr; + + // ¶ÁÈ¡»Ø²¨²¢½âÎöÂö³åÌìÏßλÖà + this->AntPosition = Eigen::MatrixXd::Zero(height, 3); + this->echo = Eigen::MatrixXcd::Zero(height, width); + double tempvalue = 0; + for (int i = 0; i < height; i++) { + fin.read((char*)&tempvalue, sizeof(double)); this->AntPosition(i, 0) = tempvalue; //X + fin.read((char*)&tempvalue, sizeof(double)); this->AntPosition(i, 1) = tempvalue;//Y + fin.read((char*)&tempvalue, sizeof(double)); this->AntPosition(i, 2) = tempvalue;//Z + + // echo + for (int j = 0; j < width; j++) { + fin.read((char*)&tempvalue, sizeof(double)); // real + this->echo(i, j) = this->echo(i, j) + tempvalue; + } + //imag + for (int j = 0; j < width; j++) { + fin.read((char*)&tempvalue, sizeof(double)); // real + this->echo(i, j) = this->echo(i, j) + std::complex(0, tempvalue); + } + } + fin.close(); + return -1; +} + +int BP2DProcessClass::saveTiFF(Eigen::MatrixXcd m) +{ + return saveMatrixXcd2TiFF(m, this->out_path); +} + +/// +/// ³ÉÏñ¹¤×÷Á÷£¬×¢Òâ´æÔÚ´óÁ¿µÄÄÚ´æÀË·Ñ£¬ºóÆÚ¿ÉÒÔ¸ù¾ÝÇé¿ö½øÐÐÓÅ»¯ +/// +/// +int BP2DProcessClass::start() +{ + // step 0 Éú³ÉÎļþ¼Ð·¾¶£¬ÎªÖмäÁÙʱÎļþÊä³ö,¹¹½¨ÁÙʱ»·¾³£¬Õýʽ°æÐèҪעÊÍÏà¹Ø´úÂë + QString parantPath = getParantFolderNameFromPath(this->out_path); + + + // step 1 ²åֵƵÂÊÓò -- FEKO ƵÂʲåÖµÊǾùÔȲåÖµ + size_t Nf = this->freqnum; + size_t Nxa = this->AntPosition.rows(); + double df = this->Frequencylist(1) - this->Frequencylist(0); // FEKO µÄƵÂʲåÖµ±È½Ï¹æÕû + double startfreq = this->Frequencylist(0); // ÆðʼƵÂÊ + + // Êä³öƵÓò ͼÏñ£¨Î´´¦Àíǰ£© ²¢½«¸´ÊýÊý¾Ýת»»Îª Õñ·ù Óë Ïàλ £¬ÐУº·½Î»Ïò£¬ÁУº¾àÀëÏò------------------- + QString before_path = JoinPath(parantPath, "freq_ampDB_angle_echo.tiff"); + WriteComplexData2AmpdB_Arg(before_path, this->echo);// ±£´æÎªÆµÓò»Ø²¨ + this->logFUN(100, "Read Echo\n"); + // ---------------------------------------------------------------------------------------------- + + // ---------------------------------------------------------------------------------------------- + + this->logFUN(100, "hamming windows over"); + // ----------------- step2 ¸µÀïÒ¶±ä»» £¨ÆµÓò-->ʱÓò£© ----------------------------------------- + Eigen::MatrixXcd echoTime = IFFTW1D(this->echo); + size_t timefreqnum = echoTime.cols(); + double timeFreqBandWidth = df * (timefreqnum - 1); + this->logFUN(100, "echo IFFT over"); + + // Êä³öƵÓò ͼÏñ£¨¼Ó´°£© ²¢½«¸´ÊýÊý¾Ýת»»Îª Õñ·ù Óë Ïàλ £¬ÐУº·½Î»Ïò£¬ÁУº¾àÀëÏò------------------- + QString time_echo_path = JoinPath(parantPath, "freq_ampDB_angle_echo_hanning_ifft.tiff"); + WriteComplexData2AmpdB_Arg(time_echo_path, echoTime);// ±£´æÎªÆµÓò»Ø²¨ + this->logFUN(100, "after ifft ,in Time\n"); + // ---------------------------------------------------------------------------------------------- + // step 3 ʱÓòÓò¼Ó´° + Nf = echoTime.cols(); + Eigen::MatrixXd wfxa = Hanning(Nf, Nxa, 0.54); // wfxa = hanning(Nf,Nxa,alpha=0.54) + double normw = wfxa.array().sum(); // normw = TOTAL(wfxa) + + Eigen::MatrixXcd dfrex = (echoTime.array())* (wfxa.array()); // dfrex = dfrex * wfxa + // Êä³öƵÓò ͼÏñ£¨¼Ó´°£© ²¢½«¸´ÊýÊý¾Ýת»»Îª Õñ·ù Óë Ïàλ £¬ÐУº·½Î»Ïò£¬ÁУº¾àÀëÏò------------------- + QString hanning_path = JoinPath(parantPath, "freq_ampDB_angle_echo_hanning.tiff"); + WriteComplexData2AmpdB_Arg(hanning_path, dfrex);// ±£´æÎªÆµÓò»Ø²¨ + this->logFUN(100, "after hanning\n"); + echoTime = dfrex; + // ----------------- step4 TBP³ÉÏñ £¨Ê±Óò£© ----------------------------------------------------------- + Eigen::MatrixXcd img = BP2DImageByPixel(echoTime, this->AntPosition, this->minX, this->maxX, this->minY, this->maxY, this->Zplane, this->Rref, this->ImageWidth, this->ImageHeight, startfreq, timefreqnum, timeFreqBandWidth, this); + this->logFUN(100, "echo bp over"); + + + + // Êä³ö ×îÖÕ½á¹ûͼÏñ ²¢½«¸´ÊýÊý¾Ýת»»Îª Õñ·ù Óë Ïàλ £¬ÐУº·½Î»Ïò£¬ÁУº¾àÀëÏò------------------- + QString FBP_resultDB_path = JoinPath(parantPath, "freq_ampDB_angle_echo_hanning_BP.tiff"); + WriteComplexData2AmpdB_Arg(FBP_resultDB_path, img);// ±£´æÎªÆµÓò»Ø²¨ + // ---------------------------------------------------------------------------------------- + // Êä³ö ×îÖÕ½á¹ûͼÏñ ²¢½«¸´ÊýÊý¾Ýת»»Îª Õñ·ù Óë Ïàλ £¬ÐУº·½Î»Ïò£¬ÁУº¾àÀëÏò------------------- + QString FBP_result_path = JoinPath(parantPath, "freq_amp_angle_echo_hanning_BP.tiff"); + WriteComplexData2Amp_Arg(FBP_result_path, img);// ±£´æÎªÆµÓò»Ø²¨ + // ---------------------------------------------------------------------------------------- + + this->saveTiFF(img); + this->logFUN(100, "out bpimag over : " + this->out_path); + return -1; +} + +int BP2DProcessClass::logFUN(int percent, QString logtext) { + qDebug() << "\rBPProcess [" << percent << "%]\t" << logtext; + if (percent < 100) { + qDebug()<<"\n"; + } + return 0; +}; + + + + + + +//////////////////////////////////////////////////////////////////////////////////////// +/// +/// FBP³ÉÏñ¹¤×÷Á÷£¨ÆµÓò£©£¬²Î¿¼ bp_linear_2d +/// Juan M Lopez-Sanchez, University of Alicante +/// +/// +//////////////////////////////////////////////////////////////////////////////////////// + + + + + + + + + + + + + + + + +int FBP2DProcessClass::initProcess(QString in_path, QString out_path, double Rref, double minX, double maxX, double minY, double maxY, double PlaneZ, int ImageHeight, int ImageWidth) +{ + // ³õʼ»¯²ÎÊý + this->readEchoFile(in_path); + this->out_path = out_path; + this->Rref = Rref; // ³ÉÏñÖÐÐĵIJο¼¾àÀë + this->minX = minX; + this->maxX = maxX; + this->minY = minY; + this->maxY = maxY; + this->Zplane = PlaneZ; + this->ImageHeight = ImageHeight; + this->ImageWidth = ImageWidth; + // ¼ÆËã×ø±êµÄµ½³ÉÏñÖÐÐĵÄ×ø±ê + this->centerX = (this->maxX + this->minX) / 2; + this->centerY = (this->minY + this->maxY) / 2; + this->AntPosition.col(0) = this->AntPosition.col(0).array() - this->centerX; + this->AntPosition.col(1) = this->AntPosition.col(1).array() - this->centerY; + this->AntPosition.col(2) = this->AntPosition.col(2).array() - this->Zplane; + // ¼ÆËãÆµÂÊÏà¹ØÐÅÏ¢ + this->f1 = this->Frequencylist(0); + this->freqnum = this->Frequencylist.rows(); + this->fc = (this->f1 + this->Frequencylist(this->freqnum - 1)); + return -1; +} + +int FBP2DProcessClass::readEchoFile(QString in_path) +{ + std::ifstream fin(in_path.toUtf8().constData(), std::ios::in | std::ios::binary); + if (!fin.is_open()) exit(2); + // ¶ÁÈ¡²ÎÊý + int height = 0; + int width = 0; + fin.read((char*)&height, sizeof(int)); + fin.read((char*)&width, sizeof(int)); + this->height = height; + this->width = width; + //frequencylist[width*double] + double* freqs = new double[width]; + fin.read((char*)freqs, sizeof(double) * width); + this->Frequencylist = Eigen::VectorXd::Zero(width, 1); // ÁÐÏòÁ¿ + for (int i = 0; i < width; i++) { + this->Frequencylist(i) = freqs[i]; + } + delete[] freqs; + freqs = nullptr; + + // ¶ÁÈ¡»Ø²¨²¢½âÎöÂö³åÌìÏßλÖà + this->AntPosition = Eigen::MatrixXd::Zero(height, 3); + this->echo = Eigen::MatrixXcd::Zero(height, width); + double tempvalue = 0; + for (int i = 0; i < height; i++) { + fin.read((char*)&tempvalue, sizeof(double)); this->AntPosition(i, 0) = tempvalue; //X + fin.read((char*)&tempvalue, sizeof(double)); this->AntPosition(i, 1) = tempvalue;//Y + fin.read((char*)&tempvalue, sizeof(double)); this->AntPosition(i, 2) = tempvalue;//Z + + // echo + for (int j = 0; j < width; j++) { + fin.read((char*)&tempvalue, sizeof(double)); // real + this->echo(i, j) = this->echo(i, j) + tempvalue; + } + //imag + for (int j = 0; j < width; j++) { + fin.read((char*)&tempvalue, sizeof(double)); // real + this->echo(i, j) = this->echo(i, j) + std::complex(0, tempvalue); + } + } + fin.close(); + return -1; +} + +int FBP2DProcessClass::saveTiFF(Eigen::MatrixXcd m) +{ + return saveMatrixXcd2TiFF(m, this->out_path); +} + + + + + + + + + + + + + + + + + +/// +/// FBP³ÉÏñ¹¤×÷Á÷£¨ÆµÓò£©£¬²Î¿¼ bp_linear_2d +/// Juan M Lopez-Sanchez, University of Alicante +/// +/// +int FBP2DProcessClass::start() +{ + // step 0 Éú³ÉÎļþ¼Ð·¾¶£¬ÎªÖмäÁÙʱÎļþÊä³ö,¹¹½¨ÁÙʱ»·¾³£¬Õýʽ°æÐèҪעÊÍÏà¹Ø´úÂë + QString parantPath = getParantFolderNameFromPath(this->out_path); + + + // step 1 ²åֵƵÂÊÓò -- FEKO ƵÂʲåÖµÊǾùÔȲåÖµ + size_t Nf = this->freqnum; + size_t Nxa = this->AntPosition.rows(); + // Êä³öƵÓò ͼÏñ£¨Î´´¦Àíǰ£© ²¢½«¸´ÊýÊý¾Ýת»»Îª Õñ·ù Óë Ïàλ £¬ÐУº·½Î»Ïò£¬ÁУº¾àÀëÏò------------------- + QString before_path = JoinPath(parantPath, "freq_ampDB_angle_echo.tiff"); + WriteComplexData2AmpdB_Arg(before_path, this->echo);// ±£´æÎªÆµÓò»Ø²¨ + this->logFUN(100, "Read Echo\n"); + // ---------------------------------------------------------------------------------------------- + // step 2 ƵÂÊÓò¼Ó´° + Eigen::MatrixXd wfxa = Hanning(Nf, Nxa, 0.54); // wfxa = hanning(Nf,Nxa,alpha=0.54) + double normw = wfxa.array().sum(); // normw = TOTAL(wfxa) + + Eigen::MatrixXcd dfrex = (this->echo.array()) * (wfxa.array()); // dfrex = dfrex * wfxa + // Êä³öƵÓò ͼÏñ£¨¼Ó´°£© ²¢½«¸´ÊýÊý¾Ýת»»Îª Õñ·ù Óë Ïàλ £¬ÐУº·½Î»Ïò£¬ÁУº¾àÀëÏò------------------- + QString hanning_path = JoinPath(parantPath, "freq_ampDB_angle_echo_hanning.tiff"); + WriteComplexData2AmpdB_Arg(hanning_path, dfrex);// ±£´æÎªÆµÓò»Ø²¨ + this->logFUN(100, "after hanning\n"); + // ---------------------------------------------------------------------------------------------- + // step 3 Freq Backprojection algorithm + Eigen::MatrixXcd result_image = Eigen::MatrixXcd::Zero(this->ImageHeight, this->ImageWidth); // ¹¹½¨Íø¸ñ£¬Ã¿¸öÍø¸ñ×ø±ê¸ù¾ÝÖÐÐÄµã£¬Æ½Ãæµã¼ÆËã + double dx = (this->maxX - this->minX) / (this->ImageWidth - 1); + double dy = (this->maxY - this->minY) / (this->ImageWidth - 1); + double px = 0, py = 0, pz = 0; // ÏñËØ×ø±ê + Eigen::MatrixXd Xdis = Eigen::MatrixXd::Zero(Nxa, Nf); + + // ; Nxa Nf + // mfre = fre # replicate(1, Nxa) ---- Nxa * Nf ¸´ÖÆÃ¿ÐÐ f1,f2,f3 ....... + // c = 0.2997925 ; Speed of light + // factorj = cj * (4.0*!PI/c) * mfre --- Nxa * Nf ¸´ÖÆÃ¿ÐÐ f1,f2,f3 ....... + // + + Eigen::MatrixXcd factorj = Eigen::MatrixXcd::Zero(Nxa, Nf); + for (size_t i = 0; i < Nxa; i++) { + for (size_t j = 0; j < Nf; j++) { + factorj(i, j) = std::complex(0, 4.0 * PI / (LIGHTSPEED * 1e-9)) * (this->Frequencylist(j) * 1e-9); // cj * (4.0*!PI/c) * mfre + } + } + + double R0 = this->Rref;// -- ²Î¿¼Ð±¾à + Eigen::MatrixXd R = Eigen::MatrixXd::Zero(Nxa, Nf); + Eigen::MatrixXd distR = Eigen::MatrixXd::Zero(Nxa, 1); + Eigen::MatrixXcd term = Eigen::MatrixXcd::Zero(Nxa, Nf); + Eigen::MatrixXcd data = Eigen::MatrixXcd::Zero(Nxa, Nf); + + for (size_t ix = 0; ix < this->ImageWidth; ix++) { + if (ix % 100 == 0) { + this->logFUN(size_t(ix * 1.0 / this->ImageWidth * 100), "FBP ....\n"); + } + // theta = theta / !radeg -- ¸ù¾ÝÈëÉä½Ç ¼ÆË㠲ο¼×ø±ê + // ya = Ro * sin(theta) -- À×´ï y ×ø±ê + // za = Ro * cos(theta) -- À×´ï z ×ø±ê + // + // xa_min = pos_start + // xa_max = pos_stop + // Nxa = Npos + // + // dxa = ( xa_max - xa_min ) / float(Nxa-1) + // xa = xa_min + findgen(Nxa) * dxa -- À×´ï x ×ø±ê + // + // dx = (x_max-x_min) / float(Nx-1) + // x = x_min + findgen(Nx) * dx + // + // dy = (y_max-y_min) / float(Ny-1) + // y = y_min + findgen(Ny) * dy + // mxa = replicate(1, Nf) # xa ;--- Nxa * Nf ÿ¸öÁÐ ant_x1£¬ ant_x2, ant_x3,...... + // xdis = (x[ix]-mxa)^2 + za^2 ;--- Nxa * Nf ÿ¸öÁÐ ant_x1_z1£¬ant_x2_z2,ant_x3_z3,...... + // R = sqrt( xdis + (ya - y[iy])^2 ) ;--- Nxa * Nf ÿ¸öÁÐ ant_x1£¬ ant_x2, ant_x3,...... + // + px = ix * dx + this->minX; + pz = this->Zplane; + for (size_t iy = 0; iy < this->ImageHeight; iy++) { + py = iy * dy + this->minY; + + // mxa = replicate(1, Nf) # xa ;--- Nxa * Nf ÿ¸öÁÐ ant_x1£¬ ant_x2, ant_x3,...... + // xdis = (x[ix]-mxa)^2 + za^2 ;--- Nxa * Nf ÿ¸öÁÐ ant_x1_z1£¬ant_x2_z2,ant_x3_z3,...... + // R = sqrt( xdis + (ya - y[iy])^2 ) ;--- Nxa * Nf ÿ¸öÁÐ ant_x1£¬ ant_x2, ant_x3,...... + // + + distR = ((this->AntPosition.col(0).array() - px).pow(2) + (this->AntPosition.col(1).array() - py).pow(2) + (this->AntPosition.col(2).array() - pz).pow(2)).array().sqrt().array(); // ¸´ÖÆ + + for (size_t jj = 0; jj < Nf; jj++) { // ÖðÁи´ÖÆ + R.col(jj) = distR.array(); + } + // term = (R/Ro)^2 * exp( factorj * ( R - Ro ) ) ; Nxa x Nf + + term = (R.array() / R0).array().pow(2) * ((factorj.array() * (R.array() - R0)).array().exp()); + data = dfrex.array() * term.array(); + result_image(iy, ix) = data.array().sum(); + // ÁÙʱÎļþÊä³ö----------------------- + if (iy == this->ImageHeight / 2 && ix == this->ImageWidth / 2) { + // Êä³ö УÕýÖµ ²¢½«¸´ÊýÊý¾Ýת»»Îª Õñ·ù Óë Ïàλ £¬ÐУº·½Î»Ïò£¬ÁУº¾àÀëÏò------------------- + QString FBP_termDB_path = JoinPath(parantPath, "freq_ampDB_angle_echo_hanning_term_FBP.tiff"); + WriteComplexData2AmpdB_Arg(FBP_termDB_path, term);// ±£´æÎªÆµÓò»Ø²¨ + + // Êä³ö УÕýºóͼÏñ ²¢½«¸´ÊýÊý¾Ýת»»Îª Õñ·ù Óë Ïàλ £¬ÐУº·½Î»Ïò£¬ÁУº¾àÀëÏò------------------- + QString FBP_dataDB_path = JoinPath(parantPath, "freq_ampDB_angle_echo_hanning_data_FBP.tiff"); + WriteComplexData2AmpdB_Arg(FBP_dataDB_path, data);// ±£´æÎªÆµÓò»Ø²¨ + + // ---------------------------------------------------------------------------------------------- + } + + /***/ + } + } + result_image = result_image.array() / normw; + // Êä³ö ×îÖÕ½á¹ûͼÏñ ²¢½«¸´ÊýÊý¾Ýת»»Îª Õñ·ù Óë Ïàλ £¬ÐУº·½Î»Ïò£¬ÁУº¾àÀëÏò------------------- + QString FBP_resultDB_path = JoinPath(parantPath, "freq_ampDB_angle_echo_hanning_FBP.tiff"); + WriteComplexData2AmpdB_Arg(FBP_resultDB_path, result_image);// ±£´æÎªÆµÓò»Ø²¨ + // ---------------------------------------------------------------------------------------------- + // Êä³ö ×îÖÕ½á¹ûͼÏñ ²¢½«¸´ÊýÊý¾Ýת»»Îª Õñ·ù Óë Ïàλ £¬ÐУº·½Î»Ïò£¬ÁУº¾àÀëÏò------------------- + QString FBP_result_path = JoinPath(parantPath, "freq_amp_angle_echo_hanning_FBP.tiff"); + WriteComplexData2Amp_Arg(FBP_result_path, result_image);// ±£´æÎªÆµÓò»Ø²¨ + // ---------------------------------------------------------------------------------------------- + this->saveTiFF(result_image); + + return 0; +} + +int FBP2DProcessClass::logFUN(int percent, QString logtext) +{ + qDebug() << "\rFBPProcess [" << percent << "%]\t" << logtext; + if (percent < 100) { + qDebug() << "\n"; + } + return 0; +} + +int FEKOFarFieldProcessClass::initProcess(QString in_path, QString out_path, double Rref, double minX, double maxX, double minY, double maxY, double PlaneZ, int ImageHeight, int ImageWidth) +{ + // ³õʼ»¯²ÎÊý + this->readEchoFile(in_path); + this->out_path = out_path; + this->Rref = Rref; // ³ÉÏñÖÐÐĵIJο¼¾àÀë + this->minX = minX; + this->maxX = maxX; + this->minY = minY; + this->maxY = maxY; + this->Zplane = PlaneZ; + this->ImageHeight = ImageHeight; + this->ImageWidth = ImageWidth; + // ¼ÆËã×ø±êµÄµ½³ÉÏñÖÐÐĵÄ×ø±ê + this->centerX = (this->maxX + this->minX) / 2; + this->centerY = (this->minY + this->maxY) / 2; + this->AntPosition.col(0) = this->AntPosition.col(0).array() - this->centerX; + this->AntPosition.col(1) = this->AntPosition.col(1).array() - this->centerY; + this->AntPosition.col(2) = this->AntPosition.col(2).array() - this->Zplane; + // ¼ÆËãÆµÂÊÏà¹ØÐÅÏ¢ + this->f1 = this->Frequencylist(0); + this->freqnum = this->Frequencylist.rows(); + this->fc = (this->f1 + this->Frequencylist(this->freqnum - 1)); + return -1; +} + +int FEKOFarFieldProcessClass::readEchoFile(QString in_path) +{ + std::ifstream fin(in_path.toUtf8().constData(), std::ios::in | std::ios::binary); + if (!fin.is_open()) exit(2); + // ¶ÁÈ¡²ÎÊý + int height = 0; + int width = 0; + fin.read((char*)&height, sizeof(int)); + fin.read((char*)&width, sizeof(int)); + this->height = height; + this->width = width; + //frequencylist[width*double] + double* freqs = new double[width]; + fin.read((char*)freqs, sizeof(double) * width); + this->Frequencylist = Eigen::VectorXd::Zero(width, 1); // ÁÐÏòÁ¿ + for (int i = 0; i < width; i++) { + this->Frequencylist(i) = freqs[i]; + } + delete[] freqs; + freqs = nullptr; + + // ¶ÁÈ¡»Ø²¨²¢½âÎöÂö³åÌìÏßλÖà + this->AntPosition = Eigen::MatrixXd::Zero(height, 3); + this->echo = Eigen::MatrixXcd::Zero(height, width); + double tempvalue = 0; + for (int i = 0; i < height; i++) { + fin.read((char*)&tempvalue, sizeof(double)); this->AntPosition(i, 0) = tempvalue; //X + fin.read((char*)&tempvalue, sizeof(double)); this->AntPosition(i, 1) = tempvalue;//Y + fin.read((char*)&tempvalue, sizeof(double)); this->AntPosition(i, 2) = tempvalue;//Z + + // echo + for (int j = 0; j < width; j++) { + fin.read((char*)&tempvalue, sizeof(double)); // real + this->echo(i, j) = this->echo(i, j) + tempvalue; + } + //imag + for (int j = 0; j < width; j++) { + fin.read((char*)&tempvalue, sizeof(double)); // real + this->echo(i, j) = this->echo(i, j) + std::complex(0, tempvalue); + } + } + fin.close(); + return -1; +} + +int FEKOFarFieldProcessClass::saveTiFF(Eigen::MatrixXcd m) +{ + return saveMatrixXcd2TiFF(m, this->out_path); +} + +int FEKOFarFieldProcessClass::start() +{ + + //// step 0 Éú³ÉÎļþ¼Ð·¾¶£¬ÎªÖмäÁÙʱÎļþÊä³ö,¹¹½¨ÁÙʱ»·¾³£¬Õýʽ°æÐèҪעÊÍÏà¹Ø´úÂë + //QString parantPath = getParantFolderNameFromPath(this->out_path); + + + //double freqbandWidth = this->Frequencylist(this->get_Nf() - 1) - this->Frequencylist(0); + //double dx = LIGHTSPEED / 2.0 / std::abs(freqbandWidth); // ¾àÀëÏò·Ö±æÂÊ + //double startPhiAngle = this->AntPosition(0, 1); + //double endPhiAngle = this->AntPosition(this->get_Nxa(), 1); + //double AzAngleWidth = std::abs(endPhiAngle - startPhiAngle); + //double halfAzAngleWidth = AzAngleWidth / 2.0; + //double AzBandWidth = 2 * std::tan(Degrees2Radians(halfAzAngleWidth)) * this->get_minFreq(); + //double dy = LIGHTSPEED / 2.0 / std::abs(AzBandWidth); // ·½Î»Ïò·Ö±æÂÊ + + + + //// step 1 ²åֵƵÂÊÓò -- FEKO ƵÂʲåÖµÊǾùÔȲåÖµ + //size_t Nf = this->freqnum; + //size_t Nxa = this->AntPosition.rows(); + + + + //double angStart = startPhiAngle; + //double angEnd = endPhiAngle; + //double freqEnd = this->Frequencylist(this->get_Nf() - 1); + //double fxStart = this->Frequencylist(0); + //double fyStart = std::tan(-1 * std::abs(halfAzAngleWidth)) * fxStart; + //double fyEnd = std::tan(-1 * std::abs(halfAzAngleWidth)) * fxStart; + //double fxEnd = std::sqrt(std::pow(freqEnd, 2) - std::pow(fyStart, 2)); + + //double freqSamples = this->Frequencylist.rows(); + //double angSamples = this->AntPosition.rows(); + + //double ysd = (fyEnd - fyStart) / (angSamples - 1); // ת»»Îª Íø¸ñ½Úµã + //double xsd = (fxEnd - fxStart) / (freqSamples - 1); // ת»»Îª Íø¸ñ½Úµã + + //Eigen::MatrixXd image_points_freq(angSamples, freqSamples); + //Eigen::MatrixXd image_points_ang(angSamples, freqSamples); + //Eigen::MatrixXcd Echo_data(angSamples, freqSamples); + + //Eigen::MatrixXd xi(Nxa,Nf); + //Eigen::MatrixXd yi(Nxa, Nf); + + + //// ´´½¨Íø¸ñ + //for (int f = 0; f < freqSamples; f++) { + // for (int a = 0; a < angSamples; a++) { + // double x = fxStart + f * xsd; + // double y = fyStart + a * ysd; + // image_points_freq(a, f) = std::sqrt(x * x + y * y); // »ñȡÿ¸öµãµÄ ƵÂÊ + // image_points_ang(a, f) = std::atan2(y, x); // »ñȡÿ¸öµãµÄ ½Ç¶È×ø±ê + // Echo_data(a, f) = InterpolateComplex(xi, yi, this->echo, image_points_freq(a, f), image_points_ang(a, f)); // ²åÖµµÃµ½ÇøÓòÊý¾Ý + + // } + //} + // + //// step 2 ƵÂÊÓò¼Ó´° + //Eigen::MatrixXd wfxa = Hanning(Nf, Nxa, 0.54); // wfxa = hanning(Nf,Nxa,alpha=0.54) + //double normw = wfxa.array().sum(); // normw = TOTAL(wfxa) + + //Eigen::MatrixXcd dfrex = (this->echo.array()) * (wfxa.array()); // dfrex = dfrex * wfxa + //// Êä³öƵÓò ͼÏñ£¨¼Ó´°£© ²¢½«¸´ÊýÊý¾Ýת»»Îª Õñ·ù Óë Ïàλ £¬ÐУº·½Î»Ïò£¬ÁУº¾àÀëÏò------------------- + //QString hanning_path = JoinPath(parantPath, "freq_ampDB_angle_echo_hanning.tiff"); + //WriteComplexData2AmpdB_Arg(hanning_path, dfrex);// ±£´æÎªÆµÓò»Ø²¨ + //this->logFUN(100, "after hanning\n"); + + //Echo_data = dfrex; + + // + //// Ö´Ðжþά¸µÁ¢Ò¶±ä»» + //Eigen::MatrixXcd H_echo_win_fft = FFTW2D(Echo_data); + + //// »ñÈ¡¾ØÕóµÄÐÐÊýºÍÁÐÊý + //int n_freq = Echo_data.rows(); + //int n_angle = Echo_data.cols(); + + //// ½«¸µÁ¢Ò¶±ä»»½á¹û¹éÒ»»¯ + //H_echo_win_fft = H_echo_win_fft.array()/(n_freq * n_angle); + + //// Ö´ÐÐÄæ¸µÁ¢Ò¶±ä»»£¨Èç¹ûÐèÒª£© + //// MatrixXcd H_echo_win_ifft = ifft2(H_echo_win_fft); + //// H_echo_win_ifft /= (n_freq * n_angle); + + //// Ö´ÐÐÆ½ÒÆ + //Eigen::MatrixXcd result_image = fftshift(H_echo_win_fft); + + + //// Êä³ö ×îÖÕ½á¹ûͼÏñ ²¢½«¸´ÊýÊý¾Ýת»»Îª Õñ·ù Óë Ïàλ £¬ÐУº·½Î»Ïò£¬ÁУº¾àÀëÏò------------------- + //QString FBP_resultDB_path = JoinPath(parantPath, "freq_ampDB_angle_echo_hanning_FBP.tiff"); + //WriteComplexData2AmpdB_Arg(FBP_resultDB_path, result_image);// ±£´æÎªÆµÓò»Ø²¨ + //// ---------------------------------------------------------------------------------------------- + //// Êä³ö ×îÖÕ½á¹ûͼÏñ ²¢½«¸´ÊýÊý¾Ýת»»Îª Õñ·ù Óë Ïàλ £¬ÐУº·½Î»Ïò£¬ÁУº¾àÀëÏò------------------- + //QString FBP_result_path = JoinPath(parantPath, "freq_amp_angle_echo_hanning_FBP.tiff"); + //WriteComplexData2Amp_Arg(FBP_result_path, result_image);// ±£´æÎªÆµÓò»Ø²¨ + //// ---------------------------------------------------------------------------------------------- + //this->saveTiFF(result_image); + + + return 0; +} + +int FEKOFarFieldProcessClass::logFUN(int percent, QString logtext) +{ + qDebug() << "\rFBPProcess [" << percent << "%]\t" << logtext; + if (percent < 100) { + qDebug() << "\n"; + } + return 0; +} diff --git a/src/LAMPTool/SARImage/FEKONearBPBasic.h b/src/LAMPTool/SARImage/FEKONearBPBasic.h new file mode 100644 index 0000000..88c03e4 --- /dev/null +++ b/src/LAMPTool/SARImage/FEKONearBPBasic.h @@ -0,0 +1,157 @@ +#pragma once +/** +* ÊÊÓÃÓÚFEKOµÄ½ü³¡½á¹ûµÄ BP ³ÉÏñËã·¨ +* +**/ +#include +#include +#include +#include +#include +#include +#include +#include "referenceHeader.h" + + + +// FEKO ¼¸ºÎ¹ØÏµ´¦Àí + +/// +/// µÑ¿¨¶û×ø±êϵ£¬×ª»»Îª ¼«×ø±êϵ +/// +/// [X,Y,Z;X1,Y1,Z1] +/// +Eigen::MatrixXd Cartesian2Spherical(Eigen::MatrixXd CartesianPoint); + +/// +/// ʱÓòBP +/// +class BP2DProcessClass { +public: + size_t height; + size_t width; + Eigen::MatrixXcd echo; + Eigen::MatrixXd AntPosition; + Eigen::VectorXd Frequencylist; + size_t freqnum; + double f1; + double fc; + double Rref; // ³ÉÏñÖÐÐĵIJο¼¾àÀë + double minX; + double maxX; + double minY; + double maxY; + double centerX; + double centerY; + double Zplane; + size_t ImageHeight; + size_t ImageWidth; + QString out_path; +public: + virtual int initProcess(QString in_path, QString out_path, double Rref, double minX, double maxX, double minY, double maxY, double PlaneZ, int ImageHeight, int ImageWidth); + virtual int readEchoFile(QString in_path); + virtual int saveTiFF(Eigen::MatrixXcd m); + virtual int start(); + virtual int logFUN(int percent, QString logtext); +}; + + +int BP2DProcess(QString in_path, QString out_path, double Rref, double minX, double maxX, double minY, double maxY, double PlaneZ,int ImageHeight,int ImageWidth); +// BP ³ÉÏñʱ£¬ÖðÏñËØµã¼ÆË㣬¼ÆËãËÙ¶ÈÂý£¬»Ø²¨£¨PRFNUM,freqNUM) +template +Eigen::MatrixXcd BP2DImageByPixel(Eigen::MatrixXcd timeEcho,Eigen::MatrixXd AntPosition,double minX,double maxX,double minY,double maxY,double PlaneZ ,double Rref,size_t ImageWidth,size_t ImageHeight,double startfreq,size_t timefreqnum,double timeFreqBandWidth, T* logclss=nullptr); + +/// +/// ʱÓòBP --- FBP +/// +class FBP2DProcessClass:public BP2DProcessClass { +public: + size_t height; + size_t width; + Eigen::MatrixXcd echo; + Eigen::MatrixXd AntPosition; + Eigen::VectorXd Frequencylist; + size_t freqnum; + double f1; + double fc; + double Rref; // ³ÉÏñÖÐÐĵIJο¼¾àÀë + double minX; + double maxX; + double minY; + double maxY; + double centerX; + double centerY; + double Zplane; + size_t ImageHeight; + size_t ImageWidth; + QString out_path; +public: + virtual int initProcess(QString in_path, QString out_path, double Rref, double minX, double maxX, double minY, double maxY, double PlaneZ, int ImageHeight, int ImageWidth); + virtual int readEchoFile(QString in_path); + virtual int saveTiFF(Eigen::MatrixXcd m); + virtual int start(); + virtual int logFUN(int percent, QString logtext); +}; + +// BP ³ÉÏñʱ£¬ÖðÂö³å¼ÆË㣬»Ø²¨£¨PRFNUM,freqNUM) +template +Eigen::MatrixXcd BP2DImageByPluse(Eigen::MatrixXcd timeEcho, Eigen::MatrixXd AntPosition, double minX, double maxX, double minY, double maxY, double PlaneZ, double Rref, size_t ImageWidth, size_t ImageHeight, double startfreq, size_t timefreqnum, double timeFreqBandWidth, T* logclss = nullptr); + +int FBP2DProcess(QString in_path, QString out_path, double Rref, double minX, double maxX, double minY, double maxY, double PlaneZ, int ImageHeight, int ImageWidth); + +// Éú³É³ÉÏñµÄÊý¾ÝÎļþ +int build2Bin(QString path,int width,int height,std::vector &freqs,Eigen::MatrixXd AntPositions,Eigen::MatrixXcd echo); + + +// ¶¨Òå²åÖµº¯Êý£¬ÒÔ´¦Àí¸´ÊýÖµ +std::complex InterpolateComplex(Eigen::MatrixXd& xi, Eigen::MatrixXd& yi, Eigen::MatrixXcd& data, double x, double y); + + + +/// +/// Ô¶³¡³ÉÏñ +/// +class FEKOFarFieldProcessClass :public BP2DProcessClass { +public: + size_t height; + size_t width; + Eigen::MatrixXcd echo; + Eigen::MatrixXd AntPosition; // theta phi 0 + Eigen::VectorXd Frequencylist; + size_t freqnum; + double f1; + double fc; + double Rref; // ³ÉÏñÖÐÐĵIJο¼¾àÀë + double minX; + double maxX; + double minY; + double maxY; + double centerX; + double centerY; + double Zplane; + size_t ImageHeight; + size_t ImageWidth; + QString out_path; +public: + virtual int initProcess(QString in_path, QString out_path, double Rref, double minX, double maxX, double minY, double maxY, double PlaneZ, int ImageHeight, int ImageWidth); + virtual int readEchoFile(QString in_path); + virtual int saveTiFF(Eigen::MatrixXcd m); + virtual int start(); + virtual int logFUN(int percent, QString logtext); + + // ƽ¾ùƵÂʼä¸ô + double get_df() { return (this->Frequencylist(this->get_Nf() - 1) - this->Frequencylist(0)) / (this->get_Nf() - 1); }; + // Âö³åÊý + size_t get_Nxa() { return this->AntPosition.rows(); }; + // ƵÂʵãÊý + size_t get_Nf() { return this->Frequencylist.rows(); }; + double get_minFreq() { this->Frequencylist(this->get_Nf() - 1) > this->Frequencylist(0) ? this->Frequencylist(0) : this->Frequencylist(this->get_Nf() - 1); }; + +}; + + + + + + + diff --git a/src/LAMPTool/SARImage/FEKONearBpBaseImage.cpp b/src/LAMPTool/SARImage/FEKONearBpBaseImage.cpp new file mode 100644 index 0000000..8df66d0 --- /dev/null +++ b/src/LAMPTool/SARImage/FEKONearBpBaseImage.cpp @@ -0,0 +1,100 @@ +// FEKONearBpBaseImage.cpp : æ­¤æ–‡ä»¶åŒ…å« "main" å‡½æ•°ã€‚ç¨‹åºæ‰§è¡Œå°†åœ¨æ­¤å¤„开始并结æŸã€‚ +// +#include "FEKONearBPBasic.h" +#include +#include +#include "LampToolTest.h" + +int TestImageBP_main(int argc, char* argv[]) +{ + qDebug() << "process starting .......\n"; + qDebug() << "-i in_echo.bin -o out_resule.bin -Rref 10 -minX -1 -maxX 1 -minY -1 -maxY 1 -PlaneZ 0 -ImageHeight 201 -ImageWidth 201" << "\n"; + qDebug() << "BP mehtod for FEKO Near field (Cartesian) " << "\n"; + qDebug() << "format: " << "\n"; + qDebug() << "height[int32] width[int32] frequencylist[width*double] echoData " << "\n"; + qDebug() << "echoData format: ant[x,y,z 3xdouble] real[width*double] imag[width*double]" << "\n"; + qDebug() << "echodata [freqNUM,PRF_num]" << "\n"; + qDebug() << "warnning:Eigen default matrix is row-major storage" << "\n"; + qDebug() << "===============params list==============================" << "\n"; + QString in_path = ""; + QString out_path = ""; + int mode = 1; + double Rref=0, minX=0, maxX = 0, minY = 0, maxY = 0, PlaneZ = 0, ImageHeight = 0, ImageWidth = 0; + for (int i = 0; i < argc; i++) { + qDebug() << argv[i] << "\n"; + } + for (int i = 0; i < argc; i++) { + if (strcmp(argv[i], "-i")==0) { + if (i == argc - 1) { return 1; } + in_path = argv[i + 1]; + qDebug() << argv[i] << " = " << argv[i + 1] << "\n"; + } + else if (strcmp(argv[i], "-o") == 0) { + if (i == argc - 1) { return 1; } + out_path = argv[i + 1]; + qDebug() << argv[i] << " = " << argv[i + 1] << "\n"; + } + else if (strcmp(argv[i], "-Rref") == 0) { + if (i == argc - 1) { return 1; } + Rref =std::stod(argv[i+1]); + qDebug() << argv[i] << " = " << argv[i + 1] << "\n"; + } + else if (strcmp(argv[i], "-minX") == 0) { + if (i == argc - 1) { return 1; } + minX = std::stod(argv[i + 1]); + qDebug() << argv[i] << " = " << argv[i + 1] << "\n"; + } + else if (strcmp(argv[i], "-maxX") == 0) { + if (i == argc - 1) { return 1; } + maxX = std::stod(argv[i + 1]); + qDebug() << argv[i] << " = " << argv[i + 1] << "\n"; + } + else if (strcmp(argv[i], "-minY") == 0) { + if (i == argc - 1) { return 1; } + minY = std::stod(argv[i + 1]); + qDebug() << argv[i] << " = " << argv[i + 1] << "\n"; + } + else if (strcmp(argv[i], "-maxY") == 0) { + if (i == argc - 1) { return 1; } + maxY = std::stod(argv[i + 1]); + qDebug() << argv[i] << " = " << argv[i + 1] << "\n"; + } + else if (strcmp(argv[i], "-PlaneZ") == 0) { + if (i == argc - 1) { return 1; } + PlaneZ = std::stod(argv[i + 1]); + qDebug() << argv[i] << " = " << argv[i + 1] << "\n"; + } + else if (strcmp(argv[i], "-ImageHeight") == 0) { + if (i == argc - 1) { return 1; } + ImageHeight = std::stod(argv[i + 1]); + qDebug() << argv[i] << " = " << argv[i + 1] << "\n"; + } + else if (strcmp(argv[i], "-ImageWidth")==0) { + if (i == argc - 1) { return 1; } + ImageWidth = std::stod(argv[i + 1]); + qDebug() << argv[i] << " = " << argv[i + 1] << "\n"; + } + else if (strcmp(argv[i], "-mode") == 0) { + if (i == argc - 1) { return 1; } + mode = std::stoi(argv[i + 1]); + qDebug() << argv[i] << " = " << argv[i + 1] << "\n"; + } + } + qDebug() << "======================================================" << "\n"; + //qDebug() << Eigen::MatrixXd::LinSpaced(1, 10).array() << "\n"; + if (mode == 0) { + //BP2DProcess(in_path, out_path, Rref, minX, maxX, minY, maxY, PlaneZ, ImageHeight, ImageWidth); + } + else if (mode == 1) { + //FBP2DProcess(in_path, out_path, Rref, minX, maxX, minY, maxY, PlaneZ, ImageHeight, ImageWidth); + } + else if (mode == 2) { + + } + + return 0; +} + + + + diff --git a/src/LAMPTool/cpp.hint b/src/LAMPTool/cpp.hint new file mode 100644 index 0000000..eaabbfc --- /dev/null +++ b/src/LAMPTool/cpp.hint @@ -0,0 +1,4 @@ +// æç¤ºæ–‡ä»¶å¸®åŠ© Visual Studio IDE 解释 Visual C++ 标识符, +// 如函数和å®çš„å称。 +// 有关详细信æ¯ï¼Œè¯·å‚è§ https://go.microsoft.com/fwlink/?linkid=865984 + diff --git a/src/LAMPTool/main.cpp b/src/LAMPTool/main.cpp new file mode 100644 index 0000000..a20ca9e --- /dev/null +++ b/src/LAMPTool/main.cpp @@ -0,0 +1,80 @@ + +#define __TEST_IMAGEPROCESS +//#define __TESTMATHGL +//#define __TEST_FARFIELDFILEREADPROCESS + +#ifdef __TESTMATHGL +#include +int main() +{ + mglGraph gr; + gr.FPlot("sin(pi*x)"); + gr.WriteFrame("D:\\codestorage\\LAMPSARtool\\CPluseCpluse\\WBCLFZProgram\\WBCLFZProgram\\test.png"); +} + +#endif + + + + +#ifdef __TEST_IMAGEPROCESS + + +#include "LAMPTool.h" +#include +#include "LampToolTest.h" +#include "FEKOSimulationSARClass.h" +#include + + + +int main(int argc, char* argv[]) +{ + + QApplication a(argc, argv); + //LAMPTool w; + //w.show(); + //a.exec(); + //TestImageBP_main(argc, argv); + + + //==================================== + // ²âÊÔFEKOÄ£ÐͼÓÔØ½á¹û + //==================================== + + + //QString antXmlPath = "D:\\codestorage\\LAMPSARtool\\CPluseCpluse\\WBCLFZProgram\\WBCLFZProgram\\help\\FEKOImageSettingTask.xml"; + //QString echocsvpath = u8"D:\\µÂÇåÑо¿Ôº¼ÓÃÜ\\ÏîÄ¿\\ÏîÄ¿Îĵµ¹éµµ\\FEKO֪ʶ¿â\\Ä£ÐÍ\\Ô¶³¡Ìõ´ø\\ball_001\\ball001_X_strip.csv"; + //QString thetafilepath = ""; + QString phifilepath = u8"D:/codestorage/LAMPSARtool/tmp/antSpace/TESTIMageProject.phi"; + QString tifffilepath = u8"D:/codestorage/LAMPSARtool/tmp/antSpace/TESTIMageProjectImage_phi.dat"; + FEKOBase::FEKOImageSettingParams imageparams{ -2.0, 2.0, -2.0, 2.0, 0.0, 201, 201 }; + + //FEKOBase::NearFieldEchoCSVParser nearfilePraseclass; + //nearfilePraseclass.parseCSV(echocsvpath); + //nearfilePraseclass.toPhiPolar(phifilepath); + + FEKOBase::EchoDataClass data; + data.loadEchoData(phifilepath); + FEKOBase::FEKOImageProcess(data, imageparams, tifffilepath); + return 0; +} + + + +#endif + + +#ifdef __TEST_FARFIELDFILEREADPROCESS +#include "LAMPTool.h" +#include "SARImage/FEKOBaseToolClass.h" +#include "FEKOFarFieldFileClass.h" +#include "FEKOSimulationSARClass.h" +int main() { + QString ffe_filepath = u8"D:\\µÂÇåÑо¿Ôº¼ÓÃÜ\\ÏîÄ¿\\ÏîÄ¿Îĵµ¹éµµ\\FEKO֪ʶ¿â\\Ä£ÐÍ\\Ìõ´øÂö³åÄ£ÐÍ\\trihedral\\ant_SAR_new\\ant_SAR_Move\\ant_SAR_new_Horn_conical1_FarField.ffe"; + FEKOBase::FEKOFarFieldFileClass ffefile; + std::cout << ffe_filepath.toLocal8Bit().constData()<< std::endl; + ffefile.parseFarFieldFile(ffe_filepath); + std::cout << "__TEST_FARFIELDFILEREADPROCESS" << std::endl; +} +#endif \ No newline at end of file diff --git a/src/LAMPTool/readme.md b/src/LAMPTool/readme.md new file mode 100644 index 0000000..017b26e --- /dev/null +++ b/src/LAMPTool/readme.md @@ -0,0 +1,8 @@ + + +# BaseToollib +基础æ“作库 + +# SARBaseToolLib +SARå¤„ç†æ“作库 + diff --git a/src/LAMPTool/referenceHeader.h b/src/LAMPTool/referenceHeader.h new file mode 100644 index 0000000..62ba818 --- /dev/null +++ b/src/LAMPTool/referenceHeader.h @@ -0,0 +1,175 @@ +#pragma once +//================================== +// ÏßÐÔ¼ÆËã¿âÓÅ»¯ +//=============================== +//#define EIGEN_NO_DEBUG + + + + +#ifndef REFERENCEHEADER_H +#define REFERENCEHEADER_H +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include // ²¢ÐмÆËã¿â +#include + + +//================================================ +// ³£Óú¯Êý +//================================================ +std::vector convertQStringListToStdVector(const QStringList& qStringList); + + + + + +// ===================================================== +// ³£Óú궨Òå +// __SHOWPROCESS : չʾ½ø¶ÈÌõ +// ====================================================== + +#define __SHOWPROCESS +//#define __SHOWMATPLOTLIBCPPTEST // ¾Ö²¿»æÖƽá¹ûµ÷ÊÔ +#define __IMAGEPARALLEL // ³ÉÏñËã·¨²¢Ðа汾 +#define __IMAGEWINDOWSPROCESS // ³ÉÏñË㷨ʹÓüӴ°º¯Êý + + + + +#ifdef __SHOWMATPLOTLIBCPPTEST +#include +#include +#include +//#define __SHOWECHOPARSE // չʾ½âÎö½á¹û +//#define __SHOWIMAGEPROCESSING // չʾ³ÉÏñÖмä½á¹û +//#define __SHOWIMAGEPROCESSRESULT// չʾ³ÉÏñ½á¹û + + +#endif + + + + + + + + + + + + +#endif // !REFERENCEHEADER_Hstd::vector convertQStringListToStdVector(const QStringList& qStringList) + diff --git a/src/LAMPTool/test.png b/src/LAMPTool/test.png new file mode 100644 index 0000000000000000000000000000000000000000..8ca3bea824e8612ff5e93c946405b39a8d5a1089 GIT binary patch literal 11630 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 - _physicsWidget = new PhysicsWidget(mainwindow); // - _geometryWidget = new GeometryTreeWidget(mainwindow); - _meshWidget = new MeshWidget(mainwindow); - _propTable = new PropertyTable(mainwindow, this); - _postTreeWidget = new Post::PostTreeWidget(mainwindow); + _physicsWidget = new PhysicsWidget(mainwindow); // ææ–™ç®—例 + _geometryWidget = new GeometryTreeWidget(mainwindow); // 几何模型 + _meshWidget = new MeshWidget(mainwindow); // 网格 + _propTable = new PropertyTable(mainwindow, this); // å±žæ€§çª—å£ + _postTreeWidget = new Post::PostTreeWidget(mainwindow); _postInfoWidget = new Post::PostInfoWidget(mainwindow); _plotTreewidget = new PostPlot::PlotTreeWidget(mainwindow); + + + + Init(); repaintTitleBar(); _ui->propTabWidget->tabBar()->hide(); diff --git a/src/MainWidgets/preWindow.cpp b/src/MainWidgets/preWindow.cpp index 42f7d58..1651119 100644 --- a/src/MainWidgets/preWindow.cpp +++ b/src/MainWidgets/preWindow.cpp @@ -25,6 +25,9 @@ namespace MainWidget _geoProvider = new GeometryViewProvider(mw, this); _meshProvider = new MeshViewProvider(mw, this); _sketchProvider = new SketchViewProvider(mw, this); + + + this->setWindowTitle(tr("Pre-Window")); connect(this, SIGNAL(closed()), mw, SIGNAL(closePreWindowSig())); connect(mw, SIGNAL(clearAllHighLight()), this, SIGNAL(clearAllHighLight())); diff --git a/src/MainWindow/CustomizerHelper.cpp b/src/MainWindow/CustomizerHelper.cpp index 2bb28cf..9f9e189 100644 --- a/src/MainWindow/CustomizerHelper.cpp +++ b/src/MainWindow/CustomizerHelper.cpp @@ -26,6 +26,9 @@ #include #include +//logger +#include "Common/DebugLogger.h" + namespace GUI { CustomizerHelper::CustomizerHelper(MainWindow* m, Ui::MainWindowRibbon* ui) : _mainWindow(m) @@ -147,7 +150,7 @@ namespace GUI { ConfigOption::ConfigOption* option = ConfigOption::ConfigOption::getInstance(); ConfigOption::GeometryConfig* geometryOption = option->getGeometryConfig(); ConfigOption::MeshConfig* meshOption = option->getMeshConfig(); - + if(!isUseRibbon()) { bool ok = geometryOption->isImportGeometryEnabled(); this->enableGeoImport(ok); @@ -205,8 +208,8 @@ namespace GUI { } else { // ribbonçš„è®¾ç½®æ–¹å¼ } - _mainWindow->getControlPanel()->registerEnabledModule(); + _mainWindow->getControlPanel()->registerEnabledModule(); Py::PythonAgent::getInstance()->unLock(); } @@ -230,15 +233,21 @@ namespace GUI { ConfigOption::GlobalConfig* globalConfig = options->getGlobalConfig(); const QString lang = Setting::BusAPI::instance()->getLanguage(); - QString softName = "FastCAE"; + QString softName = u8"微波测é‡ä»¿çœŸåˆ†ç³»ç»Ÿä¸“用软件"; if(lang.toLower() == "chinese") { QString f = globalConfig->getChineseName(); if(!f.isEmpty()) softName = f; } else { QString f = globalConfig->getSoftName(); - if(!f.isEmpty()) + if (!f.isEmpty()) + { softName = f; + } + else + { + softName = "MicrowaveMeasurementSimulationSubSystemCAE"; + } } _mainWindow->setWindowTitle(softName); diff --git a/src/MainWindow/MainWindow.cpp b/src/MainWindow/MainWindow.cpp index 3ac5227..53890d4 100644 --- a/src/MainWindow/MainWindow.cpp +++ b/src/MainWindow/MainWindow.cpp @@ -82,6 +82,10 @@ #include "Common/Types.h" #include "PostInterface/AnimationToolBar.h" #include "PostInterface/RenderDirector.h" + +//logger +#include "Common/DebugLogger.h" + namespace GUI { MainWindow::MainWindow(bool useRibbon): SARibbonMainWindow(nullptr, useRibbon), _ui(new Ui::MainWindowRibbon) { @@ -97,9 +101,9 @@ namespace GUI { } this->setContextMenuPolicy(Qt::NoContextMenu); - QString lang = Setting::BusAPI::instance()->getLanguage(); + QString lang = Setting::BusAPI::instance()->getLanguage(); // 获å–语言 - registerMoudel(); // 控制é¢ç‰ˆ 傿•°è®¾ç½®é¢æ¿ æŽ§åˆ¶å° è¿›ç¨‹ + registerMoudel(); // 控制é¢ç‰ˆ 傿•°è®¾ç½®é¢æ¿ã€ æ—¥å¿—è¾“å‡ºé¢æ¿ã€ 进程é¢ç‰ˆ _signalHandler = new SignalHandler(this); _translator = new Translator(); _subWindowManager = new SubWindowManager(this, _ui->mdiArea, _signalHandler, _controlPanel); @@ -136,21 +140,17 @@ namespace GUI { Gmsh::GmshModule::getInstance(this); this->showGraphRange(0, 0); - - Py::PythonAgent::getInstance()->initialize(this); + Py::PythonAgent::getInstance()->initialize(this); // åˆå§‹ç•Œé¢å‚数设置 Plugins::PluginManager::getInstance()->loadPlugs(this); _customizerHelper = new CustomizerHelper(this, _ui); _customizerHelper->registerInterface(); - - _subWindowManager->openPreWindow(); + _subWindowManager->openPreWindow(); // å‰å¤„ç†çª—å£å±•示 isLoadRecordScripFile(); - // ribbon customize // MainWindowçš„æž„é€ å‡½æ•°æœ€åŽ if(useRibbon) { - const QString strCostomizePath = - QApplication::applicationDirPath() + "/customization.xml"; + const QString strCostomizePath =QApplication::applicationDirPath() + "/customization.xml"; sa_apply_customize_from_xml_file(strCostomizePath, this, m_ribbonActionMgr); } } @@ -377,18 +377,18 @@ namespace GUI { QString lang = Setting::BusAPI::instance()->getLanguage(); QString title; - ConfigOption::GlobalConfig* g = - ConfigOption::ConfigOption::getInstance()->getGlobalConfig(); + ConfigOption::GlobalConfig* g = ConfigOption::ConfigOption::getInstance()->getGlobalConfig(); title = g->getSoftName(); if(lang.toLower() == "chinese") title = g->getChineseName(); if(title.isEmpty()) - title = "FastCAE"; + title = u8"MicrowaveMeasurementSimulationSubSystemCAE"; if(!_currentFile.isEmpty()) title = QString("%1-[%2]").arg(title).arg(_currentFile); this->setWindowTitle(title); + DebugInfo("setCurrentFile TitleName: %s\n", title.toStdU16String().c_str()); } void MainWindow::updatePreMeshActor() @@ -463,9 +463,8 @@ namespace GUI { if(_processWindow != nullptr) _processWindow->reTranslate(); - ConfigOption::GlobalConfig* g = - ConfigOption::ConfigOption::getInstance()->getGlobalConfig(); - QString title = "WBCLFZCAE"; // 修改 标识 FastCAE + ConfigOption::GlobalConfig* g =ConfigOption::ConfigOption::getInstance()->getGlobalConfig(); + QString title = "MicrowaveMeasurementSimulationSubSystemCAE"; // 修改 标识 FastCAE if(lang.toLower() == "chinese") { QString f = g->getChineseName(); if(!f.isEmpty()) @@ -477,7 +476,6 @@ namespace GUI { } if(!_currentFile.isEmpty()) title = QString("%1-[%2]").arg(title).arg(_currentFile); - this->setWindowTitle(title); } diff --git a/src/MainWindow/MainWindow.ui b/src/MainWindow/MainWindow.ui index df418e8..a0fe06a 100644 --- a/src/MainWindow/MainWindow.ui +++ b/src/MainWindow/MainWindow.ui @@ -268,7 +268,7 @@ 0 0 1678 - 22 + 17 @@ -284,6 +284,9 @@ + + + @@ -495,10 +498,41 @@ + + + &PointCloud + + + + PCLFilter + + + + :/PointCloudProcess/PointCloudProcess/images/algorithm/filter.png:/PointCloudProcess/PointCloudProcess/images/algorithm/filter.png + + + + + + + + + reSurfaceMesh + + + + :/PointCloudProcess/PointCloudProcess/images/algorithm/tree.png:/PointCloudProcess/PointCloudProcess/images/algorithm/tree.png + + + + + + + @@ -1838,6 +1872,84 @@ SaveVideo + + + + :/PointCloudProcess/PointCloudProcess/images/files/cloud.png:/PointCloudProcess/PointCloudProcess/images/files/cloud.png + + + Load PointCloud + + + + + + :/PointCloudProcess/PointCloudProcess/images/files/pointCloud.png:/PointCloudProcess/PointCloudProcess/images/files/pointCloud.png + + + Save PointCloud + + + + + Filter + + + + + StatisticalRemove + + + + + + :/PointCloudProcess/PointCloudProcess/images/algorithm/Histogram.png:/PointCloudProcess/PointCloudProcess/images/algorithm/Histogram.png + + + StatisticalRemoveFilter + + + + + + :/PointCloudProcess/PointCloudProcess/images/algorithm/DBSCAN.png:/PointCloudProcess/PointCloudProcess/images/algorithm/DBSCAN.png + + + DBRemoveFilter + + + + + + :/PointCloudProcess/PointCloudProcess/images/algorithm/nihe.png:/PointCloudProcess/PointCloudProcess/images/algorithm/nihe.png + + + GuassFilter + + + + + + :/PointCloudProcess/PointCloudProcess/images/algorithm/KMeans.png:/PointCloudProcess/PointCloudProcess/images/algorithm/KMeans.png + + + AverageFilter + + + + + + :/PointCloudProcess/PointCloudProcess/images/grey.png:/PointCloudProcess/PointCloudProcess/images/grey.png + + + GPMesh + + + + + LoadFile + + diff --git a/src/MainWindow/MainWindowPy.cpp b/src/MainWindow/MainWindowPy.cpp index 81b4672..f0bd88f 100644 --- a/src/MainWindow/MainWindowPy.cpp +++ b/src/MainWindow/MainWindowPy.cpp @@ -1637,6 +1637,8 @@ namespace GUI { void MainWindowPy::createVTKTransform(const char* componentIds, const char* rotate, const char* moveLocation, const char* scale) { + + QStringList qCompontIds = QString(componentIds).split(','); QStringList qRotate = QString(rotate).split(','); QStringList qMoveLocation = QString(moveLocation).split(','); @@ -1672,14 +1674,14 @@ namespace GUI { QString(meshSet->getName() + "_transform%1").arg(meshSet->getMaxID() + 1); setType = MeshData::MeshSet::setTypeToString(meshSet->getSetType()); ids.append(QString::number(meshKernal->getID()) + ":"); - + emit _pyAgent->printInfo(Common::Message::Normal, "check setType = "+setType); int nCount = 0; if(setType == "Node") nCount = transformed->GetNumberOfPoints(); else if(setType == "Element") nCount = transformed->GetNumberOfCells(); if(nCount == 0) { - emit _pyAgent->printInfo(Common::Message::Error, "Transform Failed!"); + emit _pyAgent->printInfo(Common::Message::Error, "nCount=0 Transform Failed!"); meshData->removeKernalByID(meshKernal->getID()); Py::PythonAgent::getInstance()->unLock(); return; diff --git a/src/MainWindow/SARibbonMWUi.cpp b/src/MainWindow/SARibbonMWUi.cpp index 5265fa4..4ad356f 100644 --- a/src/MainWindow/SARibbonMWUi.cpp +++ b/src/MainWindow/SARibbonMWUi.cpp @@ -20,751 +20,681 @@ namespace Ui { // BaseUi::setupUi(), but not initialized menu and toolbar // the actions have initialized but not installed anywhere { - if(MainWindow->objectName().isEmpty()) - MainWindow->setObjectName(QString::fromUtf8("MainWindow")); - MainWindow->setEnabled(true); - MainWindow->resize(1678, 921); - actionNew = new QAction(MainWindow); - actionNew->setObjectName(QString::fromUtf8("actionNew")); - QIcon icon; - icon.addFile(QString::fromUtf8(":/QUI/icon/createNew.png"), QSize(), QIcon::Normal, - QIcon::Off); - actionNew->setIcon(icon); - actionOpen = new QAction(MainWindow); - actionOpen->setObjectName(QString::fromUtf8("actionOpen")); - QIcon icon1; - icon1.addFile(QString::fromUtf8(":/QUI/icon/open.png"), QSize(), QIcon::Normal, - QIcon::Off); - actionOpen->setIcon(icon1); - actionSave = new QAction(MainWindow); - actionSave->setObjectName(QString::fromUtf8("actionSave")); - actionSave->setEnabled(false); - QIcon icon2; - icon2.addFile(QString::fromUtf8(":/QUI/icon/save.png"), QSize(), QIcon::Normal, - QIcon::Off); - actionSave->setIcon(icon2); - actionClose = new QAction(MainWindow); - actionClose->setObjectName(QString::fromUtf8("actionClose")); - QIcon icon3; - icon3.addFile(QString::fromUtf8(":/QUI/icon/stop.png"), QSize(), QIcon::Normal, - QIcon::Off); - actionClose->setIcon(icon3); - actionSaveAs = new QAction(MainWindow); - actionSaveAs->setObjectName(QString::fromUtf8("actionSaveAs")); - actionSaveAs->setEnabled(false); - QIcon icon4; - icon4.addFile(QString::fromUtf8(":/QUI/icon/saveAs.png"), QSize(), QIcon::Normal, - QIcon::Off); - actionSaveAs->setIcon(icon4); - actionChinese = new QAction(MainWindow); - actionChinese->setObjectName(QString::fromUtf8("actionChinese")); - actionChinese->setCheckable(true); - QIcon icon5; - icon5.addFile(QString::fromUtf8(":/QUI/icon/chinese_language.png"), QSize(), - QIcon::Normal, QIcon::Off); - actionChinese->setIcon(icon5); - actionEnglish = new QAction(MainWindow); - actionEnglish->setObjectName(QString::fromUtf8("actionEnglish")); - actionEnglish->setCheckable(true); - QIcon icon6; - icon6.addFile(QString::fromUtf8(":/QUI/icon/english_language.png"), QSize(), - QIcon::Normal, QIcon::Off); - actionEnglish->setIcon(icon6); - actionImportMesh = new QAction(MainWindow); - actionImportMesh->setObjectName(QString::fromUtf8("actionImportMesh")); - QIcon icon7; - icon7.addFile(QString::fromUtf8(":/QUI/icon/importMesh.png"), QSize(), QIcon::Normal, - QIcon::Off); - actionImportMesh->setIcon(icon7); - actionImportGeometry = new QAction(MainWindow); - actionImportGeometry->setObjectName(QString::fromUtf8("actionImportGeometry")); - QIcon icon8; - icon8.addFile(QString::fromUtf8(":/QUI/icon/importGeometry.png"), QSize(), - QIcon::Normal, QIcon::Off); - actionImportGeometry->setIcon(icon8); - actionWorkingDir = new QAction(MainWindow); - actionWorkingDir->setObjectName(QString::fromUtf8("actionWorkingDir")); - actionWorkingDir->setIcon(icon1); - actionSolve = new QAction(MainWindow); - actionSolve->setObjectName(QString::fromUtf8("actionSolve")); - actionSolve->setEnabled(false); - QIcon icon9; - icon9.addFile(QString::fromUtf8(":/QUI/icon/solve.png"), QSize(), QIcon::Normal, - QIcon::Off); - actionSolve->setIcon(icon9); - actionSolver_Manager = new QAction(MainWindow); - actionSolver_Manager->setObjectName(QString::fromUtf8("actionSolver_Manager")); - QIcon icon10; - icon10.addFile(QString::fromUtf8(":/QUI/icon/setting.png"), QSize(), QIcon::Normal, - QIcon::Off); - actionSolver_Manager->setIcon(icon10); - actionViewXPlus = new QAction(MainWindow); - actionViewXPlus->setObjectName(QString::fromUtf8("actionViewXPlus")); - actionViewXPlus->setEnabled(false); - QIcon icon11; - icon11.addFile(QString::fromUtf8(":/QUI/icon/xPlus.png"), QSize(), QIcon::Normal, - QIcon::Off); - actionViewXPlus->setIcon(icon11); - actionViewXMinus = new QAction(MainWindow); - actionViewXMinus->setObjectName(QString::fromUtf8("actionViewXMinus")); - actionViewXMinus->setEnabled(false); - QIcon icon12; - icon12.addFile(QString::fromUtf8(":/QUI/icon/xMinus.png"), QSize(), QIcon::Normal, - QIcon::Off); - actionViewXMinus->setIcon(icon12); - actionViewYPlus = new QAction(MainWindow); - actionViewYPlus->setObjectName(QString::fromUtf8("actionViewYPlus")); - actionViewYPlus->setEnabled(false); - QIcon icon13; - icon13.addFile(QString::fromUtf8(":/QUI/icon/yPlus.png"), QSize(), QIcon::Normal, - QIcon::Off); - actionViewYPlus->setIcon(icon13); - actionViewYMinus = new QAction(MainWindow); - actionViewYMinus->setObjectName(QString::fromUtf8("actionViewYMinus")); - actionViewYMinus->setEnabled(false); - QIcon icon14; - icon14.addFile(QString::fromUtf8(":/QUI/icon/yMinus.png"), QSize(), QIcon::Normal, - QIcon::Off); - actionViewYMinus->setIcon(icon14); - actionViewZPlus = new QAction(MainWindow); - actionViewZPlus->setObjectName(QString::fromUtf8("actionViewZPlus")); - actionViewZPlus->setEnabled(false); - QIcon icon15; - icon15.addFile(QString::fromUtf8(":/QUI/icon/zPlus.png"), QSize(), QIcon::Normal, - QIcon::Off); - actionViewZPlus->setIcon(icon15); - actionViewZMinus = new QAction(MainWindow); - actionViewZMinus->setObjectName(QString::fromUtf8("actionViewZMinus")); - actionViewZMinus->setEnabled(false); - QIcon icon16; - icon16.addFile(QString::fromUtf8(":/QUI/icon/zMinus.png"), QSize(), QIcon::Normal, - QIcon::Off); - actionViewZMinus->setIcon(icon16); - actionFitView = new QAction(MainWindow); - actionFitView->setObjectName(QString::fromUtf8("actionFitView")); - actionFitView->setEnabled(false); - QIcon icon17; - icon17.addFile(QString::fromUtf8(":/QUI/icon/fit.png"), QSize(), QIcon::Normal, - QIcon::Off); - actionFitView->setIcon(icon17); - actionSelectOff = new QAction(MainWindow); - actionSelectOff->setObjectName(QString::fromUtf8("actionSelectOff")); - actionSelectOff->setCheckable(true); - actionSelectOff->setChecked(true); - actionSelectOff->setEnabled(false); - QIcon icon18; - icon18.addFile(QString::fromUtf8(":/QUI/icon/selectOff.png"), QSize(), QIcon::Normal, - QIcon::Off); - actionSelectOff->setIcon(icon18); - actionSelectMeshNode = new QAction(MainWindow); - actionSelectMeshNode->setObjectName(QString::fromUtf8("actionSelectMeshNode")); - actionSelectMeshNode->setCheckable(true); - actionSelectMeshNode->setEnabled(false); - QIcon icon19; - icon19.addFile(QString::fromUtf8(":/QUI/icon/selectNode.png"), QSize(), QIcon::Normal, - QIcon::Off); - actionSelectMeshNode->setIcon(icon19); - actionSelectMeshCell = new QAction(MainWindow); - actionSelectMeshCell->setObjectName(QString::fromUtf8("actionSelectMeshCell")); - actionSelectMeshCell->setCheckable(true); - actionSelectMeshCell->setEnabled(false); - QIcon icon20; - icon20.addFile(QString::fromUtf8(":/QUI/icon/selectElement.png"), QSize(), - QIcon::Normal, QIcon::Off); - actionSelectMeshCell->setIcon(icon20); - actionSolve_Options = new QAction(MainWindow); - actionSolve_Options->setObjectName(QString::fromUtf8("actionSolve_Options")); - actionSolve_Options->setIcon(icon9); - actionGraph_Options = new QAction(MainWindow); - actionGraph_Options->setObjectName(QString::fromUtf8("actionGraph_Options")); - QIcon icon21; - icon21.addFile(QString::fromUtf8(":/QUI/icon/graphOption.png"), QSize(), QIcon::Normal, - QIcon::Off); - actionGraph_Options->setIcon(icon21); - actionSurfaceMesh = new QAction(MainWindow); - actionSurfaceMesh->setObjectName(QString::fromUtf8("actionSurfaceMesh")); - actionSurfaceMesh->setEnabled(false); - QIcon icon22; - icon22.addFile(QString::fromUtf8(":/QUI/icon/surfaceMesh.png"), QSize(), QIcon::Normal, - QIcon::Off); - actionSurfaceMesh->setIcon(icon22); - actionSolidMesh = new QAction(MainWindow); - actionSolidMesh->setObjectName(QString::fromUtf8("actionSolidMesh")); - actionSolidMesh->setEnabled(false); - QIcon icon23; - icon23.addFile(QString::fromUtf8(":/QUI/icon/solidMesh.png"), QSize(), QIcon::Normal, - QIcon::Off); - actionSolidMesh->setIcon(icon23); - actionExportMesh = new QAction(MainWindow); - actionExportMesh->setObjectName(QString::fromUtf8("actionExportMesh")); - actionExportMesh->setEnabled(false); - QIcon icon24; - icon24.addFile(QString::fromUtf8(":/QUI/icon/exportMesh.png"), QSize(), QIcon::Normal, - QIcon::Off); - actionExportMesh->setIcon(icon24); - actionUser_Manual = new QAction(MainWindow); - actionUser_Manual->setObjectName(QString::fromUtf8("actionUser_Manual")); - actionUser_Manual->setCheckable(true); - actionUser_Manual->setChecked(true); - QIcon icon25; - icon25.addFile(QString::fromUtf8(":/QUI/icon/help.png"), QSize(), QIcon::Normal, - QIcon::Off); - actionUser_Manual->setIcon(icon25); - actionAbout = new QAction(MainWindow); - actionAbout->setObjectName(QString::fromUtf8("actionAbout")); - QIcon icon26; - icon26.addFile(QString::fromUtf8(":/QUI/icon/about_us.png"), QSize(), QIcon::Normal, - QIcon::Off); - actionAbout->setIcon(icon26); - actionDisplayNode = new QAction(MainWindow); - actionDisplayNode->setObjectName(QString::fromUtf8("actionDisplayNode")); - actionDisplayNode->setCheckable(true); - actionDisplayNode->setEnabled(false); - QIcon icon27; - icon27.addFile(QString::fromUtf8(":/QUI/icon/node.png"), QSize(), QIcon::Normal, - QIcon::Off); - actionDisplayNode->setIcon(icon27); - actionPreDisplayWireFrame = new QAction(MainWindow); - actionPreDisplayWireFrame->setObjectName( - QString::fromUtf8("actionPreDisplayWireFrame")); - actionPreDisplayWireFrame->setCheckable(true); - actionPreDisplayWireFrame->setChecked(false); - actionPreDisplayWireFrame->setEnabled(false); - QIcon icon28; - icon28.addFile(QString::fromUtf8(":/QUI/icon/wireFrame.png"), QSize(), QIcon::Normal, - QIcon::Off); - actionPreDisplayWireFrame->setIcon(icon28); - actionDisplaySurface = new QAction(MainWindow); - actionDisplaySurface->setObjectName(QString::fromUtf8("actionDisplaySurface")); - actionDisplaySurface->setCheckable(true); - actionDisplaySurface->setEnabled(false); - QIcon icon29; - icon29.addFile(QString::fromUtf8(":/QUI/icon/face.png"), QSize(), QIcon::Normal, - QIcon::Off); - actionDisplaySurface->setIcon(icon29); - actionCreate_Set = new QAction(MainWindow); - actionCreate_Set->setObjectName(QString::fromUtf8("actionCreate_Set")); - actionCreate_Set->setEnabled(false); - QIcon icon30; - icon30.addFile(QString::fromUtf8(":/QUI/icon/meshComponent.png"), QSize(), - QIcon::Normal, QIcon::Off); - actionCreate_Set->setIcon(icon30); - action2DPlot = new QAction(MainWindow); - action2DPlot->setObjectName(QString::fromUtf8("action2DPlot")); - QIcon icon31; - icon31.addFile(QString::fromUtf8(":/QUI/window/2dplot.png"), QSize(), QIcon::Normal, - QIcon::Off); - action2DPlot->setIcon(icon31); - action3DGraph = new QAction(MainWindow); - action3DGraph->setObjectName(QString::fromUtf8("action3DGraph")); - QIcon icon32; - icon32.addFile(QString::fromUtf8(":/QUI/window/3dgraph.png"), QSize(), QIcon::Normal, - QIcon::Off); - action3DGraph->setIcon(icon32); - actionSave_Script = new QAction(MainWindow); - actionSave_Script->setObjectName(QString::fromUtf8("actionSave_Script")); - QIcon icon33; - icon33.addFile(QString::fromUtf8(":/QUI/icon/saveScript.png"), QSize(), QIcon::Normal, - QIcon::Off); - actionSave_Script->setIcon(icon33); - actionExecute_Script = new QAction(MainWindow); - actionExecute_Script->setObjectName(QString::fromUtf8("actionExecute_Script")); - QIcon icon34; - icon34.addFile(QString::fromUtf8(":/QUI/icon/execScript.png"), QSize(), QIcon::Normal, - QIcon::Off); - actionExecute_Script->setIcon(icon34); - actionGenMesh = new QAction(MainWindow); - actionGenMesh->setObjectName(QString::fromUtf8("actionGenMesh")); - actionGenMesh->setEnabled(false); - QIcon icon35; - icon35.addFile(QString::fromUtf8(":/QUI/icon/solumationsetting.png"), QSize(), - QIcon::Normal, QIcon::Off); - actionGenMesh->setIcon(icon35); - actionSave_Picture = new QAction(MainWindow); - actionSave_Picture->setObjectName(QString::fromUtf8("actionSave_Picture")); - QIcon icon36; - icon36.addFile(QString::fromUtf8(":/QUI/icon/saveImage.png"), QSize(), QIcon::Normal, - QIcon::Off); - actionSave_Picture->setIcon(icon36); - actionBoxMeshNode = new QAction(MainWindow); - actionBoxMeshNode->setObjectName(QString::fromUtf8("actionBoxMeshNode")); - actionBoxMeshNode->setCheckable(true); - actionBoxMeshNode->setEnabled(false); - QIcon icon37; - icon37.addFile(QString::fromUtf8(":/QUI/icon/boxNode.png"), QSize(), QIcon::Normal, - QIcon::Off); - actionBoxMeshNode->setIcon(icon37); - actionBoxMeshCell = new QAction(MainWindow); - actionBoxMeshCell->setObjectName(QString::fromUtf8("actionBoxMeshCell")); - actionBoxMeshCell->setCheckable(true); - actionBoxMeshCell->setEnabled(false); - QIcon icon38; - icon38.addFile(QString::fromUtf8(":/QUI/icon/boxCell.png"), QSize(), QIcon::Normal, - QIcon::Off); - actionBoxMeshCell->setIcon(icon38); - actionStart_Page = new QAction(MainWindow); - actionStart_Page->setObjectName(QString::fromUtf8("actionStart_Page")); - QIcon icon39; - icon39.addFile(QString::fromUtf8(":/QUI/window/startpage.png"), QSize(), QIcon::Normal, - QIcon::Off); - actionStart_Page->setIcon(icon39); - actionPre_Window = new QAction(MainWindow); - actionPre_Window->setObjectName(QString::fromUtf8("actionPre_Window")); - QIcon icon40; - icon40.addFile(QString::fromUtf8(":/QUI/window/preWindow.png"), QSize(), QIcon::Normal, - QIcon::Off); - actionPre_Window->setIcon(icon40); - actionChecking = new QAction(MainWindow); - actionChecking->setObjectName(QString::fromUtf8("actionChecking")); - actionChecking->setEnabled(false); - QIcon icon41; - icon41.addFile(QString::fromUtf8(":/QUI/icon/meshChecking.png"), QSize(), QIcon::Active, - QIcon::On); - actionChecking->setIcon(icon41); - actionCreateBox = new QAction(MainWindow); - actionCreateBox->setObjectName(QString::fromUtf8("actionCreateBox")); - QIcon icon42; - icon42.addFile(QString::fromUtf8(":/QUI/geometry/box.png"), QSize(), QIcon::Normal, - QIcon::Off); - actionCreateBox->setIcon(icon42); - actionCreateCylinder = new QAction(MainWindow); - actionCreateCylinder->setObjectName(QString::fromUtf8("actionCreateCylinder")); - QIcon icon43; - icon43.addFile(QString::fromUtf8(":/QUI/geometry/cylinder.png"), QSize(), QIcon::Normal, - QIcon::Off); - actionCreateCylinder->setIcon(icon43); - actionCreaterSphere = new QAction(MainWindow); - actionCreaterSphere->setObjectName(QString::fromUtf8("actionCreaterSphere")); - QIcon icon44; - icon44.addFile(QString::fromUtf8(":/QUI/geometry/sphere.png"), QSize(), QIcon::Normal, - QIcon::Off); - actionCreaterSphere->setIcon(icon44); - actionChamfer = new QAction(MainWindow); - actionChamfer->setObjectName(QString::fromUtf8("actionChamfer")); - QIcon icon45; - icon45.addFile(QString::fromUtf8(":/QUI/geometry/chamfer.png"), QSize(), QIcon::Normal, - QIcon::Off); - actionChamfer->setIcon(icon45); - actionFillet = new QAction(MainWindow); - actionFillet->setObjectName(QString::fromUtf8("actionFillet")); - QIcon icon46; - icon46.addFile(QString::fromUtf8(":/QUI/geometry/fillet.png"), QSize(), QIcon::Normal, - QIcon::Off); - actionFillet->setIcon(icon46); - actionBoolCut = new QAction(MainWindow); - actionBoolCut->setObjectName(QString::fromUtf8("actionBoolCut")); - QIcon icon47; - icon47.addFile(QString::fromUtf8(":/QUI/geometry/cut.png"), QSize(), QIcon::Normal, - QIcon::Off); - actionBoolCut->setIcon(icon47); - actionBoolFause = new QAction(MainWindow); - actionBoolFause->setObjectName(QString::fromUtf8("actionBoolFause")); - QIcon icon48; - icon48.addFile(QString::fromUtf8(":/QUI/geometry/fuse.png"), QSize(), QIcon::Normal, - QIcon::Off); - actionBoolFause->setIcon(icon48); - actionBoolCommon = new QAction(MainWindow); - actionBoolCommon->setObjectName(QString::fromUtf8("actionBoolCommon")); - QIcon icon49; - icon49.addFile(QString::fromUtf8(":/QUI/geometry/common.png"), QSize(), QIcon::Normal, - QIcon::Off); - actionBoolCommon->setIcon(icon49); - actionUndo = new QAction(MainWindow); - actionUndo->setObjectName(QString::fromUtf8("actionUndo")); - QIcon icon50; - icon50.addFile(QString::fromUtf8(":/QUI/geometry/undo.png"), QSize(), QIcon::Normal, - QIcon::Off); - actionUndo->setIcon(icon50); - actionRedo = new QAction(MainWindow); - actionRedo->setObjectName(QString::fromUtf8("actionRedo")); - QIcon icon51; - icon51.addFile(QString::fromUtf8(":/QUI/geometry/redo.png"), QSize(), QIcon::Normal, - QIcon::Off); - actionRedo->setIcon(icon51); - actionExportGeometry = new QAction(MainWindow); - actionExportGeometry->setObjectName(QString::fromUtf8("actionExportGeometry")); - QIcon icon52; - icon52.addFile(QString::fromUtf8(":/QUI/icon/exportGeometry.png"), QSize(), - QIcon::Normal, QIcon::Off); - actionExportGeometry->setIcon(icon52); - actionCreaterCone = new QAction(MainWindow); - actionCreaterCone->setObjectName(QString::fromUtf8("actionCreaterCone")); - QIcon icon53; - icon53.addFile(QString::fromUtf8(":/QUI/geometry/cone.png"), QSize(), QIcon::Normal, - QIcon::Off); - actionCreaterCone->setIcon(icon53); - actionMirrorFeature = new QAction(MainWindow); - actionMirrorFeature->setObjectName(QString::fromUtf8("actionMirrorFeature")); - QIcon icon54; - icon54.addFile(QString::fromUtf8(":/QUI/geometry/mirror.png"), QSize(), QIcon::Normal, - QIcon::Off); - actionMirrorFeature->setIcon(icon54); - actionVariable_Fillet = new QAction(MainWindow); - actionVariable_Fillet->setObjectName(QString::fromUtf8("actionVariable_Fillet")); - QIcon icon55; - icon55.addFile(QString::fromUtf8(":/QUI/geometry/variableFillet.png"), QSize(), - QIcon::Normal, QIcon::Off); - actionVariable_Fillet->setIcon(icon55); - actionExtrude = new QAction(MainWindow); - actionExtrude->setObjectName(QString::fromUtf8("actionExtrude")); - QIcon icon56; - icon56.addFile(QString::fromUtf8(":/QUI/geometry/extrude.png"), QSize(), QIcon::Normal, - QIcon::Off); - actionExtrude->setIcon(icon56); - actionCreate_Point = new QAction(MainWindow); - actionCreate_Point->setObjectName(QString::fromUtf8("actionCreate_Point")); - QIcon icon57; - icon57.addFile(QString::fromUtf8(":/QUI/geometry/point.png"), QSize(), QIcon::Normal, - QIcon::Off); - actionCreate_Point->setIcon(icon57); - actionCreate_Line = new QAction(MainWindow); - actionCreate_Line->setObjectName(QString::fromUtf8("actionCreate_Line")); - QIcon icon58; - icon58.addFile(QString::fromUtf8(":/QUI/geometry/line.png"), QSize(), QIcon::Normal, - QIcon::Off); - actionCreate_Line->setIcon(icon58); - actionCreate_Face = new QAction(MainWindow); - actionCreate_Face->setObjectName(QString::fromUtf8("actionCreate_Face")); - QIcon icon59; - icon59.addFile(QString::fromUtf8(":/QUI/geometry/face.png"), QSize(), QIcon::Normal, - QIcon::Off); - actionCreate_Face->setIcon(icon59); - actionMoveFeature = new QAction(MainWindow); - actionMoveFeature->setObjectName(QString::fromUtf8("actionMoveFeature")); - QIcon icon60; - icon60.addFile(QString::fromUtf8(":/QUI/geometry/move.png"), QSize(), QIcon::Normal, - QIcon::Off); - actionMoveFeature->setIcon(icon60); - actionRotateFeature = new QAction(MainWindow); - actionRotateFeature->setObjectName(QString::fromUtf8("actionRotateFeature")); - QIcon icon61; - icon61.addFile(QString::fromUtf8(":/QUI/geometry/Rotate.png"), QSize(), QIcon::Normal, - QIcon::Off); - actionRotateFeature->setIcon(icon61); - actionRevol = new QAction(MainWindow); - actionRevol->setObjectName(QString::fromUtf8("actionRevol")); - QIcon icon62; - icon62.addFile(QString::fromUtf8(":/QUI/geometry/revolve.png"), QSize(), QIcon::Normal, - QIcon::Off); - actionRevol->setIcon(icon62); - actionLoft = new QAction(MainWindow); - actionLoft->setObjectName(QString::fromUtf8("actionLoft")); - QIcon icon63; - icon63.addFile(QString::fromUtf8(":/QUI/geometry/loft.png"), QSize(), QIcon::Normal, - QIcon::Off); - actionLoft->setIcon(icon63); - actionCreateDatumPlane = new QAction(MainWindow); - actionCreateDatumPlane->setObjectName(QString::fromUtf8("actionCreateDatumPlane")); - QIcon icon64; - icon64.addFile(QString::fromUtf8(":/QUI/icon/datumPlane.png"), QSize(), QIcon::Normal, - QIcon::Off); - actionCreateDatumPlane->setIcon(icon64); - actionDrawLine = new QAction(MainWindow); - actionDrawLine->setObjectName(QString::fromUtf8("actionDrawLine")); - actionDrawLine->setCheckable(false); - QIcon icon65; - icon65.addFile(QString::fromUtf8(":/QUI/icon/sketchLine.png"), QSize(), QIcon::Normal, - QIcon::Off); - actionDrawLine->setIcon(icon65); - actionDrawRectangle = new QAction(MainWindow); - actionDrawRectangle->setObjectName(QString::fromUtf8("actionDrawRectangle")); - actionDrawRectangle->setCheckable(false); - QIcon icon66; - icon66.addFile(QString::fromUtf8(":/QUI/icon/sketchRectangle.png"), QSize(), - QIcon::Normal, QIcon::Off); - actionDrawRectangle->setIcon(icon66); - actionDrawCircle = new QAction(MainWindow); - actionDrawCircle->setObjectName(QString::fromUtf8("actionDrawCircle")); - actionDrawCircle->setCheckable(false); - QIcon icon67; - icon67.addFile(QString::fromUtf8(":/QUI/icon/sketchCircle.png"), QSize(), QIcon::Normal, - QIcon::Off); - actionDrawCircle->setIcon(icon67); - actionCreate_Sketch = new QAction(MainWindow); - actionCreate_Sketch->setObjectName(QString::fromUtf8("actionCreate_Sketch")); - actionCreate_Sketch->setCheckable(true); - QIcon icon68; - icon68.addFile(QString::fromUtf8(":/QUI/icon/createSketch.png"), QSize(), QIcon::Normal, - QIcon::Off); - actionCreate_Sketch->setIcon(icon68); - actionDrawArc = new QAction(MainWindow); - actionDrawArc->setObjectName(QString::fromUtf8("actionDrawArc")); - actionDrawArc->setCheckable(false); - actionDrawArc->setEnabled(true); - QIcon icon69; - icon69.addFile(QString::fromUtf8(":/QUI/icon/sketchArc.png"), QSize(), QIcon::Normal, - QIcon::Off); - actionDrawArc->setIcon(icon69); - actionDrawPolyline = new QAction(MainWindow); - actionDrawPolyline->setObjectName(QString::fromUtf8("actionDrawPolyline")); - QIcon icon70; - icon70.addFile(QString::fromUtf8(":/QUI/icon/sketchPolyLine.png"), QSize(), - QIcon::Normal, QIcon::Off); - actionDrawPolyline->setIcon(icon70); - actionMakeMatrix = new QAction(MainWindow); - actionMakeMatrix->setObjectName(QString::fromUtf8("actionMakeMatrix")); - QIcon icon71; - icon71.addFile(QString::fromUtf8(":/QUI/geometry/matrix.png"), QSize(), QIcon::Normal, - QIcon::Off); - actionMakeMatrix->setIcon(icon71); - actionSweep = new QAction(MainWindow); - actionSweep->setObjectName(QString::fromUtf8("actionSweep")); - QIcon icon72; - icon72.addFile(QString::fromUtf8(":/QUI/geometry/sweep.png"), QSize(), QIcon::Normal, - QIcon::Off); - actionSweep->setIcon(icon72); - actionDrawSpline = new QAction(MainWindow); - actionDrawSpline->setObjectName(QString::fromUtf8("actionDrawSpline")); - QIcon icon73; - icon73.addFile(QString::fromUtf8(":/QUI/icon/sketchSpline.png"), QSize(), QIcon::Normal, - QIcon::Off); - actionDrawSpline->setIcon(icon73); - actionDisplayPoint = new QAction(MainWindow); - actionDisplayPoint->setObjectName(QString::fromUtf8("actionDisplayPoint")); - actionDisplayPoint->setCheckable(true); - actionDisplayPoint->setChecked(false); - QIcon icon74; - icon74.addFile(QString::fromUtf8(":/QUI/geometry/pointDisplay.png"), QSize(), - QIcon::Normal, QIcon::Off); - actionDisplayPoint->setIcon(icon74); - actionDisplayCurve = new QAction(MainWindow); - actionDisplayCurve->setObjectName(QString::fromUtf8("actionDisplayCurve")); - actionDisplayCurve->setCheckable(true); - actionDisplayCurve->setChecked(false); - QIcon icon75; - icon75.addFile(QString::fromUtf8(":/QUI/geometry/edgeDisplay.png"), QSize(), - QIcon::Normal, QIcon::Off); - actionDisplayCurve->setIcon(icon75); - actionDisplayFace = new QAction(MainWindow); - actionDisplayFace->setObjectName(QString::fromUtf8("actionDisplayFace")); - actionDisplayFace->setCheckable(true); - actionDisplayFace->setChecked(true); - QIcon icon76; - icon76.addFile(QString::fromUtf8(":/QUI/geometry/facedisplay.png"), QSize(), - QIcon::Normal, QIcon::Off); - actionDisplayFace->setIcon(icon76); - actionSelectPoint = new QAction(MainWindow); - actionSelectPoint->setObjectName(QString::fromUtf8("actionSelectPoint")); - actionSelectPoint->setCheckable(true); - QIcon icon77; - icon77.addFile(QString::fromUtf8(":/QUI/geometry/selectpoint.png"), QSize(), - QIcon::Normal, QIcon::Off); - actionSelectPoint->setIcon(icon77); - actionSelectCurve = new QAction(MainWindow); - actionSelectCurve->setObjectName(QString::fromUtf8("actionSelectCurve")); - actionSelectCurve->setCheckable(true); - QIcon icon78; - icon78.addFile(QString::fromUtf8(":/QUI/geometry/selectwire.png"), QSize(), - QIcon::Normal, QIcon::Off); - actionSelectCurve->setIcon(icon78); - actionSelectFace = new QAction(MainWindow); - actionSelectFace->setObjectName(QString::fromUtf8("actionSelectFace")); - actionSelectFace->setCheckable(true); - QIcon icon79; - icon79.addFile(QString::fromUtf8(":/QUI/geometry/selectface.png"), QSize(), - QIcon::Normal, QIcon::Off); - actionSelectFace->setIcon(icon79); - actionSelectGeometryBody = new QAction(MainWindow); - actionSelectGeometryBody->setObjectName(QString::fromUtf8("actionSelectGeometryBody")); - actionSelectGeometryBody->setCheckable(true); - QIcon icon80; - icon80.addFile(QString::fromUtf8(":/QUI/geometry/selectbody.png"), QSize(), - QIcon::Normal, QIcon::Off); - actionSelectGeometryBody->setIcon(icon80); - actionPluginManager = new QAction(MainWindow); - actionPluginManager->setObjectName(QString::fromUtf8("actionPluginManager")); - QIcon icon81; - icon81.addFile(QString::fromUtf8(":/QUI/icon/pluginManager.png"), QSize(), - QIcon::Normal, QIcon::Off); - actionPluginManager->setIcon(icon81); - actionUser_Guidance = new QAction(MainWindow); - actionUser_Guidance->setObjectName(QString::fromUtf8("actionUser_Guidance")); - actionUser_Guidance->setCheckable(true); - actionUser_Guidance->setChecked(true); - QIcon icon82; - icon82.addFile(QString::fromUtf8(":/QUI/icon/userguidance.png"), QSize(), QIcon::Normal, - QIcon::Off); - actionUser_Guidance->setIcon(icon82); - actionMeasure_Distance = new QAction(MainWindow); - actionMeasure_Distance->setObjectName(QString::fromUtf8("actionMeasure_Distance")); - QIcon icon83; - icon83.addFile(QString::fromUtf8(":/QUI/geometry/geoMeasure.png"), QSize(), - QIcon::Normal, QIcon::Off); - actionMeasure_Distance->setIcon(icon83); - actionMeasure = new QAction(MainWindow); - actionMeasure->setObjectName(QString::fromUtf8("actionMeasure")); - actionGeoSplitter = new QAction(MainWindow); - actionGeoSplitter->setObjectName(QString::fromUtf8("actionGeoSplitter")); - QIcon icon84; - icon84.addFile(QString::fromUtf8(":/QUI/geometry/geoSSplit.png"), QSize(), - QIcon::Normal, QIcon::Off); - actionGeoSplitter->setIcon(icon84); - actionCreateGeoComponent = new QAction(MainWindow); - actionCreateGeoComponent->setObjectName(QString::fromUtf8("actionCreateGeoComponent")); - actionCreateGeoComponent->setEnabled(false); - QIcon icon85; - icon85.addFile(QString::fromUtf8(":/QUI/geometry/geoComponent.png"), QSize(), - QIcon::Normal, QIcon::Off); - actionCreateGeoComponent->setIcon(icon85); - actionFluidMesh = new QAction(MainWindow); - actionFluidMesh->setObjectName(QString::fromUtf8("actionFluidMesh")); - actionFluidMesh->setEnabled(false); - QIcon icon86; - icon86.addFile(QString::fromUtf8(":/QUI/icon/meshFluid.png"), QSize(), QIcon::Normal, - QIcon::Off); - actionFluidMesh->setIcon(icon86); - actionFilterMesh = new QAction(MainWindow); - actionFilterMesh->setObjectName(QString::fromUtf8("actionFilterMesh")); - actionFilterMesh->setEnabled(false); - QIcon icon87; - icon87.addFile(QString::fromUtf8(":/QUI/icon/meshFilter.png"), QSize(), QIcon::Normal, - QIcon::Off); - actionFilterMesh->setIcon(icon87); - actionFillHole = new QAction(MainWindow); - actionFillHole->setObjectName(QString::fromUtf8("actionFillHole")); - QIcon icon88; - icon88.addFile(QString::fromUtf8(":/QUI/geometry/geoFillHole.png"), QSize(), - QIcon::Normal, QIcon::Off); - actionFillHole->setIcon(icon88); - actionRemoveSurface = new QAction(MainWindow); - actionRemoveSurface->setObjectName(QString::fromUtf8("actionRemoveSurface")); - QIcon icon89; - icon89.addFile(QString::fromUtf8(":/QUI/geometry/geoRemoveFace.png"), QSize(), - QIcon::Normal, QIcon::Off); - actionRemoveSurface->setIcon(icon89); - actionFillGap = new QAction(MainWindow); - actionFillGap->setObjectName(QString::fromUtf8("actionFillGap")); - QIcon icon90; - icon90.addFile(QString::fromUtf8(":/QUI/geometry/geoFixSurface.png"), QSize(), - QIcon::Normal, QIcon::Off); - actionFillGap->setIcon(icon90); - actionVTKTranslation = new QAction(MainWindow); - actionVTKTranslation->setObjectName(QString::fromUtf8("actionVTKTranslation")); - actionVTKTranslation->setCheckable(false); - actionVTKTranslation->setEnabled(false); - QIcon icon91; - icon91.addFile(QString::fromUtf8(":/QUI/icon/meshmodeling.png"), QSize(), QIcon::Normal, - QIcon::Off); - actionVTKTranslation->setIcon(icon91); - actionNormal = new QAction(MainWindow); - actionNormal->setObjectName(QString::fromUtf8("actionNormal")); - actionNormal->setCheckable(false); - actionRibbon = new QAction(MainWindow); - actionRibbon->setObjectName(QString::fromUtf8("actionRibbon")); - actionRibbon->setCheckable(false); - actionOpenPostFile = new QAction(MainWindow); - actionOpenPostFile->setObjectName(QString::fromUtf8("actionOpenPostFile")); - QIcon iconOpenPostFile; - iconOpenPostFile.addFile(QString::fromUtf8(":/QUI/post/open.png"), QSize(), - QIcon::Normal, QIcon::Off); - actionOpenPostFile->setIcon(iconOpenPostFile); - actionDisplayPoints = new QAction(MainWindow); - actionDisplayPoints->setObjectName(QString::fromUtf8("actionDisplayPoints")); - QIcon icon92; - icon92.addFile(QString::fromUtf8(":/QUI/post/rep_point.png"), QSize(), QIcon::Normal, - QIcon::Off); - actionDisplayPoints->setIcon(icon92); - actionPostDisplayWireframe = new QAction(MainWindow); - actionPostDisplayWireframe->setObjectName(QString::fromUtf8("actionDisplayWireframe")); - QIcon icon93; - icon93.addFile(QString::fromUtf8(":/QUI/post/rep_wireFrame.png"), QSize(), - QIcon::Normal, QIcon::Off); - actionPostDisplayWireframe->setIcon(icon93); - actionDisplaySurfaceWithoutEdge = new QAction(MainWindow); - actionDisplaySurfaceWithoutEdge->setObjectName( - QString::fromUtf8("actionDisplaySurfaceWithoutEdge")); - QIcon icon94; - icon94.addFile(QString::fromUtf8(":/QUI/post/rep_surface.png"), QSize(), QIcon::Normal, - QIcon::Off); - actionDisplaySurfaceWithoutEdge->setIcon(icon94); - actionDisplaySurfaceWithEdge = new QAction(MainWindow); - actionDisplaySurfaceWithEdge->setObjectName( - QString::fromUtf8("actionDisplaySurfaceWithEdge")); - QIcon icon95; - icon95.addFile(QString::fromUtf8(":/QUI/post/rep_surfaceWithEdge.png"), QSize(), - QIcon::Normal, QIcon::Off); - actionDisplaySurfaceWithEdge->setIcon(icon95); - actionCreateVector = new QAction(MainWindow); - actionCreateVector->setObjectName(QString::fromUtf8("actionCreateVector")); - QIcon icon96; - icon96.addFile(QString::fromUtf8(":/QUI/post/vector.png"), QSize(), QIcon::Normal, - QIcon::Off); - actionCreateVector->setIcon(icon96); - actionCreateClip = new QAction(MainWindow); - actionCreateClip->setObjectName(QString::fromUtf8("actionCreateClip")); - QIcon icon97; - icon97.addFile(QString::fromUtf8(":/QUI/post/clip.png"), QSize(), QIcon::Normal, - QIcon::Off); - actionCreateClip->setIcon(icon97); - actionCreateSlice = new QAction(MainWindow); - actionCreateSlice->setObjectName(QString::fromUtf8("actionCreateSlice")); - QIcon icon98; - icon98.addFile(QString::fromUtf8(":/QUI/post/slice.png"), QSize(), QIcon::Normal, - QIcon::Off); - actionCreateSlice->setIcon(icon98); - actionCreateStreamLine = new QAction(MainWindow); - actionCreateStreamLine->setObjectName(QString::fromUtf8("actionCreateStreamLine")); - QIcon icon99; - icon99.addFile(QString::fromUtf8(":/QUI/post/streamline.png"), QSize(), QIcon::Normal, - QIcon::Off); - actionCreateStreamLine->setIcon(icon99); - actionCreateISOCurve = new QAction(MainWindow); - actionCreateISOCurve->setObjectName(QString::fromUtf8("actionCreateISOCurve")); - QIcon iconISOCurve; - iconISOCurve.addFile(QString::fromUtf8(":/QUI/post/isocurve.png"), QSize(), - QIcon::Normal, QIcon::Off); - actionCreateISOCurve->setIcon(iconISOCurve); - actionCreateISOSurface = new QAction(MainWindow); - actionCreateISOSurface->setObjectName(QString::fromUtf8("actionCreateISOSurface")); - QIcon icon100; - icon100.addFile(QString::fromUtf8(":/QUI/post/isosurf.png"), QSize(), QIcon::Normal, - QIcon::Off); - actionCreateISOSurface->setIcon(icon100); - actionCreateCalculator = new QAction(MainWindow); - actionCreateCalculator->setObjectName(QString::fromUtf8("actionCreateCalculator")); - QIcon icon101; - icon101.addFile(QString::fromUtf8(":/QUI/post/calculator.png"), QSize(), QIcon::Normal, - QIcon::Off); - actionCreateCalculator->setIcon(icon101); - actionCreateReflection = new QAction(MainWindow); - actionCreateReflection->setObjectName(QString::fromUtf8("actionCreateReflection")); - QIcon icon102; - icon102.addFile(QString::fromUtf8(":/QUI/post/Reflection.png"), QSize(), QIcon::Normal, - QIcon::Off); - actionCreateReflection->setIcon(icon102); - actionSaveImage = new QAction(MainWindow); - actionSaveImage->setObjectName(QString::fromUtf8("actionSaveImage")); - QIcon icon103; - icon103.addFile(QString::fromUtf8(":/QUI/post/saveImage.png"), QSize(), QIcon::Normal, - QIcon::Off); - actionSaveImage->setIcon(icon103); - actionSaveVideo = new QAction(MainWindow); - actionSaveVideo->setObjectName(QString::fromUtf8("actionSaveVideo")); - QIcon icon104; - icon104.addFile(QString::fromUtf8(":/QUI/post/video.png"), QSize(), QIcon::Normal, - QIcon::Off); - actionSaveVideo->setIcon(icon104); + if (MainWindow->objectName().isEmpty()) + MainWindow->setObjectName(QString::fromUtf8("MainWindow")); + MainWindow->setEnabled(true); + MainWindow->resize(1678, 921); + actionNew = new QAction(MainWindow); + actionNew->setObjectName(QString::fromUtf8("actionNew")); + QIcon icon; + icon.addFile(QString::fromUtf8(":/QUI/icon/createNew.png"), QSize(), QIcon::Normal, QIcon::Off); + actionNew->setIcon(icon); + actionOpen = new QAction(MainWindow); + actionOpen->setObjectName(QString::fromUtf8("actionOpen")); + QIcon icon1; + icon1.addFile(QString::fromUtf8(":/QUI/icon/open.png"), QSize(), QIcon::Normal, QIcon::Off); + actionOpen->setIcon(icon1); + actionSave = new QAction(MainWindow); + actionSave->setObjectName(QString::fromUtf8("actionSave")); + actionSave->setEnabled(false); + QIcon icon2; + icon2.addFile(QString::fromUtf8(":/QUI/icon/save.png"), QSize(), QIcon::Normal, QIcon::Off); + actionSave->setIcon(icon2); + actionClose = new QAction(MainWindow); + actionClose->setObjectName(QString::fromUtf8("actionClose")); + QIcon icon3; + icon3.addFile(QString::fromUtf8(":/QUI/icon/stop.png"), QSize(), QIcon::Normal, QIcon::Off); + actionClose->setIcon(icon3); + actionSaveAs = new QAction(MainWindow); + actionSaveAs->setObjectName(QString::fromUtf8("actionSaveAs")); + actionSaveAs->setEnabled(false); + QIcon icon4; + icon4.addFile(QString::fromUtf8(":/QUI/icon/saveAs.png"), QSize(), QIcon::Normal, QIcon::Off); + actionSaveAs->setIcon(icon4); + actionChinese = new QAction(MainWindow); + actionChinese->setObjectName(QString::fromUtf8("actionChinese")); + actionChinese->setCheckable(true); + QIcon icon5; + icon5.addFile(QString::fromUtf8(":/QUI/icon/chinese_language.png"), QSize(), QIcon::Normal, QIcon::Off); + actionChinese->setIcon(icon5); + actionEnglish = new QAction(MainWindow); + actionEnglish->setObjectName(QString::fromUtf8("actionEnglish")); + actionEnglish->setCheckable(true); + QIcon icon6; + icon6.addFile(QString::fromUtf8(":/QUI/icon/english_language.png"), QSize(), QIcon::Normal, QIcon::Off); + actionEnglish->setIcon(icon6); + actionImportMesh = new QAction(MainWindow); + actionImportMesh->setObjectName(QString::fromUtf8("actionImportMesh")); + QIcon icon7; + icon7.addFile(QString::fromUtf8(":/QUI/icon/importMesh.png"), QSize(), QIcon::Normal, QIcon::Off); + actionImportMesh->setIcon(icon7); + actionImportGeometry = new QAction(MainWindow); + actionImportGeometry->setObjectName(QString::fromUtf8("actionImportGeometry")); + QIcon icon8; + icon8.addFile(QString::fromUtf8(":/QUI/icon/importGeometry.png"), QSize(), QIcon::Normal, QIcon::Off); + actionImportGeometry->setIcon(icon8); + actionWorkingDir = new QAction(MainWindow); + actionWorkingDir->setObjectName(QString::fromUtf8("actionWorkingDir")); + actionWorkingDir->setIcon(icon1); + actionSolve = new QAction(MainWindow); + actionSolve->setObjectName(QString::fromUtf8("actionSolve")); + actionSolve->setEnabled(false); + QIcon icon9; + icon9.addFile(QString::fromUtf8(":/QUI/icon/solve.png"), QSize(), QIcon::Normal, QIcon::Off); + actionSolve->setIcon(icon9); + actionSolver_Manager = new QAction(MainWindow); + actionSolver_Manager->setObjectName(QString::fromUtf8("actionSolver_Manager")); + QIcon icon10; + icon10.addFile(QString::fromUtf8(":/QUI/icon/setting.png"), QSize(), QIcon::Normal, QIcon::Off); + actionSolver_Manager->setIcon(icon10); + actionViewXPlus = new QAction(MainWindow); + actionViewXPlus->setObjectName(QString::fromUtf8("actionViewXPlus")); + actionViewXPlus->setEnabled(false); + QIcon icon11; + icon11.addFile(QString::fromUtf8(":/QUI/icon/xPlus.png"), QSize(), QIcon::Normal, QIcon::Off); + actionViewXPlus->setIcon(icon11); + actionViewXMinus = new QAction(MainWindow); + actionViewXMinus->setObjectName(QString::fromUtf8("actionViewXMinus")); + actionViewXMinus->setEnabled(false); + QIcon icon12; + icon12.addFile(QString::fromUtf8(":/QUI/icon/xMinus.png"), QSize(), QIcon::Normal, QIcon::Off); + actionViewXMinus->setIcon(icon12); + actionViewYPlus = new QAction(MainWindow); + actionViewYPlus->setObjectName(QString::fromUtf8("actionViewYPlus")); + actionViewYPlus->setEnabled(false); + QIcon icon13; + icon13.addFile(QString::fromUtf8(":/QUI/icon/yPlus.png"), QSize(), QIcon::Normal, QIcon::Off); + actionViewYPlus->setIcon(icon13); + actionViewYMinus = new QAction(MainWindow); + actionViewYMinus->setObjectName(QString::fromUtf8("actionViewYMinus")); + actionViewYMinus->setEnabled(false); + QIcon icon14; + icon14.addFile(QString::fromUtf8(":/QUI/icon/yMinus.png"), QSize(), QIcon::Normal, QIcon::Off); + actionViewYMinus->setIcon(icon14); + actionViewZPlus = new QAction(MainWindow); + actionViewZPlus->setObjectName(QString::fromUtf8("actionViewZPlus")); + actionViewZPlus->setEnabled(false); + QIcon icon15; + icon15.addFile(QString::fromUtf8(":/QUI/icon/zPlus.png"), QSize(), QIcon::Normal, QIcon::Off); + actionViewZPlus->setIcon(icon15); + actionViewZMinus = new QAction(MainWindow); + actionViewZMinus->setObjectName(QString::fromUtf8("actionViewZMinus")); + actionViewZMinus->setEnabled(false); + QIcon icon16; + icon16.addFile(QString::fromUtf8(":/QUI/icon/zMinus.png"), QSize(), QIcon::Normal, QIcon::Off); + actionViewZMinus->setIcon(icon16); + actionFitView = new QAction(MainWindow); + actionFitView->setObjectName(QString::fromUtf8("actionFitView")); + actionFitView->setEnabled(false); + QIcon icon17; + icon17.addFile(QString::fromUtf8(":/QUI/icon/fit.png"), QSize(), QIcon::Normal, QIcon::Off); + actionFitView->setIcon(icon17); + actionSelectOff = new QAction(MainWindow); + actionSelectOff->setObjectName(QString::fromUtf8("actionSelectOff")); + actionSelectOff->setCheckable(true); + actionSelectOff->setChecked(true); + actionSelectOff->setEnabled(false); + QIcon icon18; + icon18.addFile(QString::fromUtf8(":/QUI/icon/selectOff.png"), QSize(), QIcon::Normal, QIcon::Off); + actionSelectOff->setIcon(icon18); + actionSelectMeshNode = new QAction(MainWindow); + actionSelectMeshNode->setObjectName(QString::fromUtf8("actionSelectMeshNode")); + actionSelectMeshNode->setCheckable(true); + actionSelectMeshNode->setEnabled(false); + QIcon icon19; + icon19.addFile(QString::fromUtf8(":/QUI/icon/selectNode.png"), QSize(), QIcon::Normal, QIcon::Off); + actionSelectMeshNode->setIcon(icon19); + actionSelectMeshCell = new QAction(MainWindow); + actionSelectMeshCell->setObjectName(QString::fromUtf8("actionSelectMeshCell")); + actionSelectMeshCell->setCheckable(true); + actionSelectMeshCell->setEnabled(false); + QIcon icon20; + icon20.addFile(QString::fromUtf8(":/QUI/icon/selectElement.png"), QSize(), QIcon::Normal, QIcon::Off); + actionSelectMeshCell->setIcon(icon20); + actionSolve_Options = new QAction(MainWindow); + actionSolve_Options->setObjectName(QString::fromUtf8("actionSolve_Options")); + actionSolve_Options->setIcon(icon9); + actionGraph_Options = new QAction(MainWindow); + actionGraph_Options->setObjectName(QString::fromUtf8("actionGraph_Options")); + QIcon icon21; + icon21.addFile(QString::fromUtf8(":/QUI/icon/graphOption.png"), QSize(), QIcon::Normal, QIcon::Off); + actionGraph_Options->setIcon(icon21); + actionSurfaceMesh = new QAction(MainWindow); + actionSurfaceMesh->setObjectName(QString::fromUtf8("actionSurfaceMesh")); + actionSurfaceMesh->setEnabled(false); + QIcon icon22; + icon22.addFile(QString::fromUtf8(":/QUI/icon/surfaceMesh.png"), QSize(), QIcon::Normal, QIcon::Off); + actionSurfaceMesh->setIcon(icon22); + actionSolidMesh = new QAction(MainWindow); + actionSolidMesh->setObjectName(QString::fromUtf8("actionSolidMesh")); + actionSolidMesh->setEnabled(false); + QIcon icon23; + icon23.addFile(QString::fromUtf8(":/QUI/icon/solidMesh.png"), QSize(), QIcon::Normal, QIcon::Off); + actionSolidMesh->setIcon(icon23); + actionExportMesh = new QAction(MainWindow); + actionExportMesh->setObjectName(QString::fromUtf8("actionExportMesh")); + actionExportMesh->setEnabled(false); + QIcon icon24; + icon24.addFile(QString::fromUtf8(":/QUI/icon/exportMesh.png"), QSize(), QIcon::Normal, QIcon::Off); + actionExportMesh->setIcon(icon24); + actionUser_Manual = new QAction(MainWindow); + actionUser_Manual->setObjectName(QString::fromUtf8("actionUser_Manual")); + actionUser_Manual->setCheckable(true); + actionUser_Manual->setChecked(true); + QIcon icon25; + icon25.addFile(QString::fromUtf8(":/QUI/icon/help.png"), QSize(), QIcon::Normal, QIcon::Off); + actionUser_Manual->setIcon(icon25); + actionAbout = new QAction(MainWindow); + actionAbout->setObjectName(QString::fromUtf8("actionAbout")); + QIcon icon26; + icon26.addFile(QString::fromUtf8(":/QUI/icon/about_us.png"), QSize(), QIcon::Normal, QIcon::Off); + actionAbout->setIcon(icon26); + actionDisplayNode = new QAction(MainWindow); + actionDisplayNode->setObjectName(QString::fromUtf8("actionDisplayNode")); + actionDisplayNode->setCheckable(true); + actionDisplayNode->setEnabled(false); + QIcon icon27; + icon27.addFile(QString::fromUtf8(":/QUI/icon/node.png"), QSize(), QIcon::Normal, QIcon::Off); + actionDisplayNode->setIcon(icon27); + actionPreDisplayWireFrame = new QAction(MainWindow); + actionPreDisplayWireFrame->setObjectName(QString::fromUtf8("actionPreDisplayWireFrame")); + actionPreDisplayWireFrame->setCheckable(true); + actionPreDisplayWireFrame->setChecked(false); + actionPreDisplayWireFrame->setEnabled(false); + QIcon icon28; + icon28.addFile(QString::fromUtf8(":/QUI/icon/wireFrame.png"), QSize(), QIcon::Normal, QIcon::Off); + actionPreDisplayWireFrame->setIcon(icon28); + actionDisplaySurface = new QAction(MainWindow); + actionDisplaySurface->setObjectName(QString::fromUtf8("actionDisplaySurface")); + actionDisplaySurface->setCheckable(true); + actionDisplaySurface->setEnabled(false); + QIcon icon29; + icon29.addFile(QString::fromUtf8(":/QUI/icon/face.png"), QSize(), QIcon::Normal, QIcon::Off); + actionDisplaySurface->setIcon(icon29); + actionCreate_Set = new QAction(MainWindow); + actionCreate_Set->setObjectName(QString::fromUtf8("actionCreate_Set")); + actionCreate_Set->setEnabled(false); + QIcon icon30; + icon30.addFile(QString::fromUtf8(":/QUI/icon/meshComponent.png"), QSize(), QIcon::Normal, QIcon::Off); + actionCreate_Set->setIcon(icon30); + action2DPlot = new QAction(MainWindow); + action2DPlot->setObjectName(QString::fromUtf8("action2DPlot")); + QIcon icon31; + icon31.addFile(QString::fromUtf8(":/QUI/window/2dplot.png"), QSize(), QIcon::Normal, QIcon::Off); + action2DPlot->setIcon(icon31); + action3DGraph = new QAction(MainWindow); + action3DGraph->setObjectName(QString::fromUtf8("action3DGraph")); + QIcon icon32; + icon32.addFile(QString::fromUtf8(":/QUI/window/3dgraph.png"), QSize(), QIcon::Normal, QIcon::Off); + action3DGraph->setIcon(icon32); + actionSave_Script = new QAction(MainWindow); + actionSave_Script->setObjectName(QString::fromUtf8("actionSave_Script")); + QIcon icon33; + icon33.addFile(QString::fromUtf8(":/QUI/icon/saveScript.png"), QSize(), QIcon::Normal, QIcon::Off); + actionSave_Script->setIcon(icon33); + actionExecute_Script = new QAction(MainWindow); + actionExecute_Script->setObjectName(QString::fromUtf8("actionExecute_Script")); + QIcon icon34; + icon34.addFile(QString::fromUtf8(":/QUI/icon/execScript.png"), QSize(), QIcon::Normal, QIcon::Off); + actionExecute_Script->setIcon(icon34); + actionGenMesh = new QAction(MainWindow); + actionGenMesh->setObjectName(QString::fromUtf8("actionGenMesh")); + actionGenMesh->setEnabled(false); + QIcon icon35; + icon35.addFile(QString::fromUtf8(":/QUI/icon/solumationsetting.png"), QSize(), QIcon::Normal, QIcon::Off); + actionGenMesh->setIcon(icon35); + actionSave_Picture = new QAction(MainWindow); + actionSave_Picture->setObjectName(QString::fromUtf8("actionSave_Picture")); + QIcon icon36; + icon36.addFile(QString::fromUtf8(":/QUI/icon/saveImage.png"), QSize(), QIcon::Normal, QIcon::Off); + actionSave_Picture->setIcon(icon36); + actionBoxMeshNode = new QAction(MainWindow); + actionBoxMeshNode->setObjectName(QString::fromUtf8("actionBoxMeshNode")); + actionBoxMeshNode->setCheckable(true); + actionBoxMeshNode->setEnabled(false); + QIcon icon37; + icon37.addFile(QString::fromUtf8(":/QUI/icon/boxNode.png"), QSize(), QIcon::Normal, QIcon::Off); + actionBoxMeshNode->setIcon(icon37); + actionBoxMeshCell = new QAction(MainWindow); + actionBoxMeshCell->setObjectName(QString::fromUtf8("actionBoxMeshCell")); + actionBoxMeshCell->setCheckable(true); + actionBoxMeshCell->setEnabled(false); + QIcon icon38; + icon38.addFile(QString::fromUtf8(":/QUI/icon/boxCell.png"), QSize(), QIcon::Normal, QIcon::Off); + actionBoxMeshCell->setIcon(icon38); + actionStart_Page = new QAction(MainWindow); + actionStart_Page->setObjectName(QString::fromUtf8("actionStart_Page")); + QIcon icon39; + icon39.addFile(QString::fromUtf8(":/QUI/window/startpage.png"), QSize(), QIcon::Normal, QIcon::Off); + actionStart_Page->setIcon(icon39); + actionPre_Window = new QAction(MainWindow); + actionPre_Window->setObjectName(QString::fromUtf8("actionPre_Window")); + QIcon icon40; + icon40.addFile(QString::fromUtf8(":/QUI/window/preWindow.png"), QSize(), QIcon::Normal, QIcon::Off); + actionPre_Window->setIcon(icon40); + actionChecking = new QAction(MainWindow); + actionChecking->setObjectName(QString::fromUtf8("actionChecking")); + actionChecking->setEnabled(false); + QIcon icon41; + icon41.addFile(QString::fromUtf8(":/QUI/icon/meshChecking.png"), QSize(), QIcon::Active, QIcon::On); + actionChecking->setIcon(icon41); + actionCreateBox = new QAction(MainWindow); + actionCreateBox->setObjectName(QString::fromUtf8("actionCreateBox")); + QIcon icon42; + icon42.addFile(QString::fromUtf8(":/QUI/geometry/box.png"), QSize(), QIcon::Normal, QIcon::Off); + actionCreateBox->setIcon(icon42); + actionCreateCylinder = new QAction(MainWindow); + actionCreateCylinder->setObjectName(QString::fromUtf8("actionCreateCylinder")); + QIcon icon43; + icon43.addFile(QString::fromUtf8(":/QUI/geometry/cylinder.png"), QSize(), QIcon::Normal, QIcon::Off); + actionCreateCylinder->setIcon(icon43); + actionCreaterSphere = new QAction(MainWindow); + actionCreaterSphere->setObjectName(QString::fromUtf8("actionCreaterSphere")); + QIcon icon44; + icon44.addFile(QString::fromUtf8(":/QUI/geometry/sphere.png"), QSize(), QIcon::Normal, QIcon::Off); + actionCreaterSphere->setIcon(icon44); + actionChamfer = new QAction(MainWindow); + actionChamfer->setObjectName(QString::fromUtf8("actionChamfer")); + QIcon icon45; + icon45.addFile(QString::fromUtf8(":/QUI/geometry/chamfer.png"), QSize(), QIcon::Normal, QIcon::Off); + actionChamfer->setIcon(icon45); + actionFillet = new QAction(MainWindow); + actionFillet->setObjectName(QString::fromUtf8("actionFillet")); + QIcon icon46; + icon46.addFile(QString::fromUtf8(":/QUI/geometry/fillet.png"), QSize(), QIcon::Normal, QIcon::Off); + actionFillet->setIcon(icon46); + actionBoolCut = new QAction(MainWindow); + actionBoolCut->setObjectName(QString::fromUtf8("actionBoolCut")); + QIcon icon47; + icon47.addFile(QString::fromUtf8(":/QUI/geometry/cut.png"), QSize(), QIcon::Normal, QIcon::Off); + actionBoolCut->setIcon(icon47); + actionBoolFause = new QAction(MainWindow); + actionBoolFause->setObjectName(QString::fromUtf8("actionBoolFause")); + QIcon icon48; + icon48.addFile(QString::fromUtf8(":/QUI/geometry/fuse.png"), QSize(), QIcon::Normal, QIcon::Off); + actionBoolFause->setIcon(icon48); + actionBoolCommon = new QAction(MainWindow); + actionBoolCommon->setObjectName(QString::fromUtf8("actionBoolCommon")); + QIcon icon49; + icon49.addFile(QString::fromUtf8(":/QUI/geometry/common.png"), QSize(), QIcon::Normal, QIcon::Off); + actionBoolCommon->setIcon(icon49); + actionUndo = new QAction(MainWindow); + actionUndo->setObjectName(QString::fromUtf8("actionUndo")); + QIcon icon50; + icon50.addFile(QString::fromUtf8(":/QUI/geometry/undo.png"), QSize(), QIcon::Normal, QIcon::Off); + actionUndo->setIcon(icon50); + actionRedo = new QAction(MainWindow); + actionRedo->setObjectName(QString::fromUtf8("actionRedo")); + QIcon icon51; + icon51.addFile(QString::fromUtf8(":/QUI/geometry/redo.png"), QSize(), QIcon::Normal, QIcon::Off); + actionRedo->setIcon(icon51); + actionExportGeometry = new QAction(MainWindow); + actionExportGeometry->setObjectName(QString::fromUtf8("actionExportGeometry")); + QIcon icon52; + icon52.addFile(QString::fromUtf8(":/QUI/icon/exportGeometry.png"), QSize(), QIcon::Normal, QIcon::Off); + actionExportGeometry->setIcon(icon52); + actionCreaterCone = new QAction(MainWindow); + actionCreaterCone->setObjectName(QString::fromUtf8("actionCreaterCone")); + QIcon icon53; + icon53.addFile(QString::fromUtf8(":/QUI/geometry/cone.png"), QSize(), QIcon::Normal, QIcon::Off); + actionCreaterCone->setIcon(icon53); + actionMirrorFeature = new QAction(MainWindow); + actionMirrorFeature->setObjectName(QString::fromUtf8("actionMirrorFeature")); + QIcon icon54; + icon54.addFile(QString::fromUtf8(":/QUI/geometry/mirror.png"), QSize(), QIcon::Normal, QIcon::Off); + actionMirrorFeature->setIcon(icon54); + actionVariable_Fillet = new QAction(MainWindow); + actionVariable_Fillet->setObjectName(QString::fromUtf8("actionVariable_Fillet")); + QIcon icon55; + icon55.addFile(QString::fromUtf8(":/QUI/geometry/variableFillet.png"), QSize(), QIcon::Normal, QIcon::Off); + actionVariable_Fillet->setIcon(icon55); + actionExtrude = new QAction(MainWindow); + actionExtrude->setObjectName(QString::fromUtf8("actionExtrude")); + QIcon icon56; + icon56.addFile(QString::fromUtf8(":/QUI/geometry/extrude.png"), QSize(), QIcon::Normal, QIcon::Off); + actionExtrude->setIcon(icon56); + actionCreate_Point = new QAction(MainWindow); + actionCreate_Point->setObjectName(QString::fromUtf8("actionCreate_Point")); + QIcon icon57; + icon57.addFile(QString::fromUtf8(":/QUI/geometry/point.png"), QSize(), QIcon::Normal, QIcon::Off); + actionCreate_Point->setIcon(icon57); + actionCreate_Line = new QAction(MainWindow); + actionCreate_Line->setObjectName(QString::fromUtf8("actionCreate_Line")); + QIcon icon58; + icon58.addFile(QString::fromUtf8(":/QUI/geometry/line.png"), QSize(), QIcon::Normal, QIcon::Off); + actionCreate_Line->setIcon(icon58); + actionCreate_Face = new QAction(MainWindow); + actionCreate_Face->setObjectName(QString::fromUtf8("actionCreate_Face")); + QIcon icon59; + icon59.addFile(QString::fromUtf8(":/QUI/geometry/face.png"), QSize(), QIcon::Normal, QIcon::Off); + actionCreate_Face->setIcon(icon59); + actionMoveFeature = new QAction(MainWindow); + actionMoveFeature->setObjectName(QString::fromUtf8("actionMoveFeature")); + QIcon icon60; + icon60.addFile(QString::fromUtf8(":/QUI/geometry/move.png"), QSize(), QIcon::Normal, QIcon::Off); + actionMoveFeature->setIcon(icon60); + actionRotateFeature = new QAction(MainWindow); + actionRotateFeature->setObjectName(QString::fromUtf8("actionRotateFeature")); + QIcon icon61; + icon61.addFile(QString::fromUtf8(":/QUI/geometry/Rotate.png"), QSize(), QIcon::Normal, QIcon::Off); + actionRotateFeature->setIcon(icon61); + actionRevol = new QAction(MainWindow); + actionRevol->setObjectName(QString::fromUtf8("actionRevol")); + QIcon icon62; + icon62.addFile(QString::fromUtf8(":/QUI/geometry/revolve.png"), QSize(), QIcon::Normal, QIcon::Off); + actionRevol->setIcon(icon62); + actionLoft = new QAction(MainWindow); + actionLoft->setObjectName(QString::fromUtf8("actionLoft")); + QIcon icon63; + icon63.addFile(QString::fromUtf8(":/QUI/geometry/loft.png"), QSize(), QIcon::Normal, QIcon::Off); + actionLoft->setIcon(icon63); + actionCreateDatumPlane = new QAction(MainWindow); + actionCreateDatumPlane->setObjectName(QString::fromUtf8("actionCreateDatumPlane")); + QIcon icon64; + icon64.addFile(QString::fromUtf8(":/QUI/icon/datumPlane.png"), QSize(), QIcon::Normal, QIcon::Off); + actionCreateDatumPlane->setIcon(icon64); + actionDrawLine = new QAction(MainWindow); + actionDrawLine->setObjectName(QString::fromUtf8("actionDrawLine")); + actionDrawLine->setCheckable(false); + QIcon icon65; + icon65.addFile(QString::fromUtf8(":/QUI/icon/sketchLine.png"), QSize(), QIcon::Normal, QIcon::Off); + actionDrawLine->setIcon(icon65); + actionDrawRectangle = new QAction(MainWindow); + actionDrawRectangle->setObjectName(QString::fromUtf8("actionDrawRectangle")); + actionDrawRectangle->setCheckable(false); + QIcon icon66; + icon66.addFile(QString::fromUtf8(":/QUI/icon/sketchRectangle.png"), QSize(), QIcon::Normal, QIcon::Off); + actionDrawRectangle->setIcon(icon66); + actionDrawCircle = new QAction(MainWindow); + actionDrawCircle->setObjectName(QString::fromUtf8("actionDrawCircle")); + actionDrawCircle->setCheckable(false); + QIcon icon67; + icon67.addFile(QString::fromUtf8(":/QUI/icon/sketchCircle.png"), QSize(), QIcon::Normal, QIcon::Off); + actionDrawCircle->setIcon(icon67); + actionCreate_Sketch = new QAction(MainWindow); + actionCreate_Sketch->setObjectName(QString::fromUtf8("actionCreate_Sketch")); + actionCreate_Sketch->setCheckable(true); + QIcon icon68; + icon68.addFile(QString::fromUtf8(":/QUI/icon/createSketch.png"), QSize(), QIcon::Normal, QIcon::Off); + actionCreate_Sketch->setIcon(icon68); + actionDrawArc = new QAction(MainWindow); + actionDrawArc->setObjectName(QString::fromUtf8("actionDrawArc")); + actionDrawArc->setCheckable(false); + actionDrawArc->setEnabled(true); + QIcon icon69; + icon69.addFile(QString::fromUtf8(":/QUI/icon/sketchArc.png"), QSize(), QIcon::Normal, QIcon::Off); + actionDrawArc->setIcon(icon69); + actionDrawPolyline = new QAction(MainWindow); + actionDrawPolyline->setObjectName(QString::fromUtf8("actionDrawPolyline")); + QIcon icon70; + icon70.addFile(QString::fromUtf8(":/QUI/icon/sketchPolyLine.png"), QSize(), QIcon::Normal, QIcon::Off); + actionDrawPolyline->setIcon(icon70); + actionMakeMatrix = new QAction(MainWindow); + actionMakeMatrix->setObjectName(QString::fromUtf8("actionMakeMatrix")); + QIcon icon71; + icon71.addFile(QString::fromUtf8(":/QUI/geometry/matrix.png"), QSize(), QIcon::Normal, QIcon::Off); + actionMakeMatrix->setIcon(icon71); + actionSweep = new QAction(MainWindow); + actionSweep->setObjectName(QString::fromUtf8("actionSweep")); + QIcon icon72; + icon72.addFile(QString::fromUtf8(":/QUI/geometry/sweep.png"), QSize(), QIcon::Normal, QIcon::Off); + actionSweep->setIcon(icon72); + actionDrawSpline = new QAction(MainWindow); + actionDrawSpline->setObjectName(QString::fromUtf8("actionDrawSpline")); + QIcon icon73; + icon73.addFile(QString::fromUtf8(":/QUI/icon/sketchSpline.png"), QSize(), QIcon::Normal, QIcon::Off); + actionDrawSpline->setIcon(icon73); + actionDisplayPoint = new QAction(MainWindow); + actionDisplayPoint->setObjectName(QString::fromUtf8("actionDisplayPoint")); + actionDisplayPoint->setCheckable(true); + actionDisplayPoint->setChecked(false); + QIcon icon74; + icon74.addFile(QString::fromUtf8(":/QUI/geometry/pointDisplay.png"), QSize(), QIcon::Normal, QIcon::Off); + actionDisplayPoint->setIcon(icon74); + actionDisplayCurve = new QAction(MainWindow); + actionDisplayCurve->setObjectName(QString::fromUtf8("actionDisplayCurve")); + actionDisplayCurve->setCheckable(true); + actionDisplayCurve->setChecked(false); + QIcon icon75; + icon75.addFile(QString::fromUtf8(":/QUI/geometry/edgeDisplay.png"), QSize(), QIcon::Normal, QIcon::Off); + actionDisplayCurve->setIcon(icon75); + actionDisplayFace = new QAction(MainWindow); + actionDisplayFace->setObjectName(QString::fromUtf8("actionDisplayFace")); + actionDisplayFace->setCheckable(true); + actionDisplayFace->setChecked(true); + QIcon icon76; + icon76.addFile(QString::fromUtf8(":/QUI/geometry/facedisplay.png"), QSize(), QIcon::Normal, QIcon::Off); + actionDisplayFace->setIcon(icon76); + actionSelectPoint = new QAction(MainWindow); + actionSelectPoint->setObjectName(QString::fromUtf8("actionSelectPoint")); + actionSelectPoint->setCheckable(true); + QIcon icon77; + icon77.addFile(QString::fromUtf8(":/QUI/geometry/selectpoint.png"), QSize(), QIcon::Normal, QIcon::Off); + actionSelectPoint->setIcon(icon77); + actionSelectCurve = new QAction(MainWindow); + actionSelectCurve->setObjectName(QString::fromUtf8("actionSelectCurve")); + actionSelectCurve->setCheckable(true); + QIcon icon78; + icon78.addFile(QString::fromUtf8(":/QUI/geometry/selectwire.png"), QSize(), QIcon::Normal, QIcon::Off); + actionSelectCurve->setIcon(icon78); + actionSelectFace = new QAction(MainWindow); + actionSelectFace->setObjectName(QString::fromUtf8("actionSelectFace")); + actionSelectFace->setCheckable(true); + QIcon icon79; + icon79.addFile(QString::fromUtf8(":/QUI/geometry/selectface.png"), QSize(), QIcon::Normal, QIcon::Off); + actionSelectFace->setIcon(icon79); + actionSelectGeometryBody = new QAction(MainWindow); + actionSelectGeometryBody->setObjectName(QString::fromUtf8("actionSelectGeometryBody")); + actionSelectGeometryBody->setCheckable(true); + QIcon icon80; + icon80.addFile(QString::fromUtf8(":/QUI/geometry/selectbody.png"), QSize(), QIcon::Normal, QIcon::Off); + actionSelectGeometryBody->setIcon(icon80); + actionPluginManager = new QAction(MainWindow); + actionPluginManager->setObjectName(QString::fromUtf8("actionPluginManager")); + QIcon icon81; + icon81.addFile(QString::fromUtf8(":/QUI/icon/pluginManager.png"), QSize(), QIcon::Normal, QIcon::Off); + actionPluginManager->setIcon(icon81); + actionUser_Guidance = new QAction(MainWindow); + actionUser_Guidance->setObjectName(QString::fromUtf8("actionUser_Guidance")); + actionUser_Guidance->setCheckable(true); + actionUser_Guidance->setChecked(true); + QIcon icon82; + icon82.addFile(QString::fromUtf8(":/QUI/icon/userguidance.png"), QSize(), QIcon::Normal, QIcon::Off); + actionUser_Guidance->setIcon(icon82); + actionMeasure_Distance = new QAction(MainWindow); + actionMeasure_Distance->setObjectName(QString::fromUtf8("actionMeasure_Distance")); + QIcon icon83; + icon83.addFile(QString::fromUtf8(":/QUI/geometry/geoMeasure.png"), QSize(), QIcon::Normal, QIcon::Off); + actionMeasure_Distance->setIcon(icon83); + actionMeasure = new QAction(MainWindow); + actionMeasure->setObjectName(QString::fromUtf8("actionMeasure")); + actionGeoSplitter = new QAction(MainWindow); + actionGeoSplitter->setObjectName(QString::fromUtf8("actionGeoSplitter")); + QIcon icon84; + icon84.addFile(QString::fromUtf8(":/QUI/geometry/geoSSplit.png"), QSize(), QIcon::Normal, QIcon::Off); + actionGeoSplitter->setIcon(icon84); + actionCreateGeoComponent = new QAction(MainWindow); + actionCreateGeoComponent->setObjectName(QString::fromUtf8("actionCreateGeoComponent")); + actionCreateGeoComponent->setEnabled(false); + QIcon icon85; + icon85.addFile(QString::fromUtf8(":/QUI/geometry/geoComponent.png"), QSize(), QIcon::Normal, QIcon::Off); + actionCreateGeoComponent->setIcon(icon85); + actionFluidMesh = new QAction(MainWindow); + actionFluidMesh->setObjectName(QString::fromUtf8("actionFluidMesh")); + actionFluidMesh->setEnabled(false); + QIcon icon86; + icon86.addFile(QString::fromUtf8(":/QUI/icon/meshFluid.png"), QSize(), QIcon::Normal, QIcon::Off); + actionFluidMesh->setIcon(icon86); + actionFilterMesh = new QAction(MainWindow); + actionFilterMesh->setObjectName(QString::fromUtf8("actionFilterMesh")); + actionFilterMesh->setEnabled(false); + QIcon icon87; + icon87.addFile(QString::fromUtf8(":/QUI/icon/meshFilter.png"), QSize(), QIcon::Normal, QIcon::Off); + actionFilterMesh->setIcon(icon87); + actionFillHole = new QAction(MainWindow); + actionFillHole->setObjectName(QString::fromUtf8("actionFillHole")); + QIcon icon88; + icon88.addFile(QString::fromUtf8(":/QUI/geometry/geoFillHole.png"), QSize(), QIcon::Normal, QIcon::Off); + actionFillHole->setIcon(icon88); + actionRemoveSurface = new QAction(MainWindow); + actionRemoveSurface->setObjectName(QString::fromUtf8("actionRemoveSurface")); + QIcon icon89; + icon89.addFile(QString::fromUtf8(":/QUI/geometry/geoRemoveFace.png"), QSize(), QIcon::Normal, QIcon::Off); + actionRemoveSurface->setIcon(icon89); + actionFillGap = new QAction(MainWindow); + actionFillGap->setObjectName(QString::fromUtf8("actionFillGap")); + QIcon icon90; + icon90.addFile(QString::fromUtf8(":/QUI/geometry/geoFixSurface.png"), QSize(), QIcon::Normal, QIcon::Off); + actionFillGap->setIcon(icon90); + actionVTKTranslation = new QAction(MainWindow); + actionVTKTranslation->setObjectName(QString::fromUtf8("actionVTKTranslation")); + actionVTKTranslation->setCheckable(false); + actionVTKTranslation->setEnabled(false); + QIcon icon91; + icon91.addFile(QString::fromUtf8(":/QUI/icon/meshmodeling.png"), QSize(), QIcon::Normal, QIcon::Off); + actionVTKTranslation->setIcon(icon91); + actionGeoMeshRotate = new QAction(MainWindow); + actionGeoMeshRotate->setObjectName(QString::fromUtf8("actionGeoMeshRotate")); + QIcon icon92; + icon92.addFile(QString::fromUtf8(":/QUI/icon/vector.png"), QSize(), QIcon::Normal, QIcon::Off); + actionGeoMeshRotate->setIcon(icon92); + actionNormal = new QAction(MainWindow); + actionNormal->setObjectName(QString::fromUtf8("actionNormal")); + actionNormal->setCheckable(false); + actionRibbon = new QAction(MainWindow); + actionRibbon->setObjectName(QString::fromUtf8("actionRibbon")); + actionRibbon->setCheckable(false); + actionOpenPostFile = new QAction(MainWindow); + actionOpenPostFile->setObjectName(QString::fromUtf8("actionOpenPostFile")); + QIcon icon93; + icon93.addFile(QString::fromUtf8(":/QUI/post/open.png"), QSize(), QIcon::Normal, QIcon::Off); + actionOpenPostFile->setIcon(icon93); + actionDisplayPoints = new QAction(MainWindow); + actionDisplayPoints->setObjectName(QString::fromUtf8("actionDisplayPoints")); + QIcon icon94; + icon94.addFile(QString::fromUtf8(":/QUI/post/rep_point.png"), QSize(), QIcon::Normal, QIcon::Off); + actionDisplayPoints->setIcon(icon94); + actionPostDisplayWireframe = new QAction(MainWindow); + actionPostDisplayWireframe->setObjectName(QString::fromUtf8("actionPostDisplayWireframe")); + QIcon icon95; + icon95.addFile(QString::fromUtf8(":/QUI/post/rep_wireFrame.png"), QSize(), QIcon::Normal, QIcon::Off); + actionPostDisplayWireframe->setIcon(icon95); + actionDisplaySurfaceWithoutEdge = new QAction(MainWindow); + actionDisplaySurfaceWithoutEdge->setObjectName(QString::fromUtf8("actionDisplaySurfaceWithoutEdge")); + QIcon icon96; + icon96.addFile(QString::fromUtf8(":/QUI/post/rep_surface.png"), QSize(), QIcon::Normal, QIcon::Off); + actionDisplaySurfaceWithoutEdge->setIcon(icon96); + actionDisplaySurfaceWithEdge = new QAction(MainWindow); + actionDisplaySurfaceWithEdge->setObjectName(QString::fromUtf8("actionDisplaySurfaceWithEdge")); + QIcon icon97; + icon97.addFile(QString::fromUtf8(":/QUI/post/rep_surfaceWithEdge.png"), QSize(), QIcon::Normal, QIcon::Off); + actionDisplaySurfaceWithEdge->setIcon(icon97); + actionCreateVector = new QAction(MainWindow); + actionCreateVector->setObjectName(QString::fromUtf8("actionCreateVector")); + QIcon icon98; + icon98.addFile(QString::fromUtf8(":/QUI/post/vector.png"), QSize(), QIcon::Normal, QIcon::Off); + actionCreateVector->setIcon(icon98); + actionCreateClip = new QAction(MainWindow); + actionCreateClip->setObjectName(QString::fromUtf8("actionCreateClip")); + QIcon icon99; + icon99.addFile(QString::fromUtf8(":/QUI/post/clip.png"), QSize(), QIcon::Normal, QIcon::Off); + actionCreateClip->setIcon(icon99); + actionCreateSlice = new QAction(MainWindow); + actionCreateSlice->setObjectName(QString::fromUtf8("actionCreateSlice")); + QIcon icon100; + icon100.addFile(QString::fromUtf8(":/QUI/post/slice.png"), QSize(), QIcon::Normal, QIcon::Off); + actionCreateSlice->setIcon(icon100); + actionCreateStreamLine = new QAction(MainWindow); + actionCreateStreamLine->setObjectName(QString::fromUtf8("actionCreateStreamLine")); + QIcon icon101; + icon101.addFile(QString::fromUtf8(":/QUI/post/streamline.png"), QSize(), QIcon::Normal, QIcon::Off); + actionCreateStreamLine->setIcon(icon101); + actionCreateISOCurve = new QAction(MainWindow); + actionCreateISOCurve->setObjectName(QString::fromUtf8("actionCreateISOCurve")); + QIcon icon102; + icon102.addFile(QString::fromUtf8(":/QUI/post/isocurve.png"), QSize(), QIcon::Normal, QIcon::Off); + actionCreateISOCurve->setIcon(icon102); + actionCreateISOSurface = new QAction(MainWindow); + actionCreateISOSurface->setObjectName(QString::fromUtf8("actionCreateISOSurface")); + QIcon icon103; + icon103.addFile(QString::fromUtf8(":/QUI/post/isosurf.png"), QSize(), QIcon::Normal, QIcon::Off); + actionCreateISOSurface->setIcon(icon103); + actionCreateCalculator = new QAction(MainWindow); + actionCreateCalculator->setObjectName(QString::fromUtf8("actionCreateCalculator")); + QIcon icon104; + icon104.addFile(QString::fromUtf8(":/QUI/post/calculator.png"), QSize(), QIcon::Normal, QIcon::Off); + actionCreateCalculator->setIcon(icon104); + actionCreateReflection = new QAction(MainWindow); + actionCreateReflection->setObjectName(QString::fromUtf8("actionCreateReflection")); + QIcon icon105; + icon105.addFile(QString::fromUtf8(":/QUI/post/Reflection.png"), QSize(), QIcon::Normal, QIcon::Off); + actionCreateReflection->setIcon(icon105); + actionSaveImage = new QAction(MainWindow); + actionSaveImage->setObjectName(QString::fromUtf8("actionSaveImage")); + QIcon icon106; + icon106.addFile(QString::fromUtf8(":/QUI/post/saveImage.png"), QSize(), QIcon::Normal, QIcon::Off); + actionSaveImage->setIcon(icon106); + actionSaveVideo = new QAction(MainWindow); + actionSaveVideo->setObjectName(QString::fromUtf8("actionSaveVideo")); + QIcon icon107; + icon107.addFile(QString::fromUtf8(":/QUI/post/video.png"), QSize(), QIcon::Normal, QIcon::Off); + actionSaveVideo->setIcon(icon107); + actionLoadPointCloud = new QAction(MainWindow); + actionLoadPointCloud->setObjectName(QString::fromUtf8("actionLoadPointCloud")); + QIcon icon108; + icon108.addFile(QString::fromUtf8(":/PointCloudProcess/PointCloudProcess/images/files/cloud.png"), QSize(), QIcon::Normal, QIcon::Off); + actionLoadPointCloud->setIcon(icon108); + actionSavePointCloud = new QAction(MainWindow); + actionSavePointCloud->setObjectName(QString::fromUtf8("actionSavePointCloud")); + QIcon icon109; + icon109.addFile(QString::fromUtf8(":/PointCloudProcess/PointCloudProcess/images/files/pointCloud.png"), QSize(), QIcon::Normal, QIcon::Off); + actionSavePointCloud->setIcon(icon109); + actionFilter = new QAction(MainWindow); + actionFilter->setObjectName(QString::fromUtf8("actionFilter")); + actionPointCloudStatisticalRemove = new QAction(MainWindow); + actionPointCloudStatisticalRemove->setObjectName(QString::fromUtf8("actionPointCloudStatisticalRemove")); + actionPCLStatisticalRemoveFilter = new QAction(MainWindow); + actionPCLStatisticalRemoveFilter->setObjectName(QString::fromUtf8("actionPCLStatisticalRemoveFilter")); + + QIcon icon110; + icon110.addFile(QString::fromUtf8(":/PointCloudProcess/PointCloudProcess/images/algorithm/Histogram.png"), QSize(), QIcon::Normal, QIcon::Off); + actionPCLStatisticalRemoveFilter->setIcon(icon110); + actionPCLDBRemoveFilter = new QAction(MainWindow); + actionPCLDBRemoveFilter->setObjectName(QString::fromUtf8("actionPCLDBRemoveFilter")); + QIcon icon111; + icon111.addFile(QString::fromUtf8(":/PointCloudProcess/PointCloudProcess/images/algorithm/DBSCAN.png"), QSize(), QIcon::Normal, QIcon::Off); + actionPCLDBRemoveFilter->setIcon(icon111); + actionPCLGuassFilter = new QAction(MainWindow); + actionPCLGuassFilter->setObjectName(QString::fromUtf8("actionPCLGuassFilter")); + QIcon icon112; + icon112.addFile(QString::fromUtf8(":/PointCloudProcess/PointCloudProcess/images/algorithm/nihe.png"), QSize(), QIcon::Normal, QIcon::Off); + actionPCLGuassFilter->setIcon(icon112); + actionPCLAverageFilter = new QAction(MainWindow); + actionPCLAverageFilter->setObjectName(QString::fromUtf8("actionPCLAverageFilter")); + QIcon icon113; + icon113.addFile(QString::fromUtf8(":/PointCloudProcess/PointCloudProcess/images/algorithm/KMeans.png"), QSize(), QIcon::Normal, QIcon::Off); + actionPCLAverageFilter->setIcon(icon113); + actionPCLGPMesh = new QAction(MainWindow); + actionPCLGPMesh->setObjectName(QString::fromUtf8("actionPCLGPMesh")); + QIcon icon114; + icon114.addFile(QString::fromUtf8(":/PointCloudProcess/PointCloudProcess/images/grey.png"), QSize(), QIcon::Normal, QIcon::Off); + actionPCLGPMesh->setIcon(icon114); + actionLoadFile = new QAction(MainWindow); + actionLoadFile->setObjectName(QString::fromUtf8("actionLoadFile")); + centralwidget = new QWidget(MainWindow); + centralwidget->setObjectName(QString::fromUtf8("centralwidget")); + gridLayout = new QGridLayout(centralwidget); + gridLayout->setObjectName(QString::fromUtf8("gridLayout")); + mdiArea = new QMdiArea(centralwidget); + mdiArea->setObjectName(QString::fromUtf8("mdiArea")); - actionGeoMeshRotate = new QAction(MainWindow); - actionGeoMeshRotate->setObjectName(QString::fromUtf8("actionGeoMeshRotate")); - QIcon icon105; - icon105.addFile(QString::fromUtf8(":/QUI/icon/vector.png"), QSize(), QIcon::Normal, - QIcon::Off); - actionGeoMeshRotate->setIcon(icon105); + gridLayout->addWidget(mdiArea, 0, 0, 1, 1); - centralwidget = new QWidget(MainWindow); - centralwidget->setObjectName(QString::fromUtf8("centralwidget")); - gridLayout = new QGridLayout(centralwidget); - gridLayout->setObjectName(QString::fromUtf8("gridLayout")); - mdiArea = new QMdiArea(centralwidget); - mdiArea->setObjectName(QString::fromUtf8("mdiArea")); + MainWindow->setCentralWidget(centralwidget); + statusbar = new QStatusBar(MainWindow); + statusbar->setObjectName(QString::fromUtf8("statusbar")); + MainWindow->setStatusBar(statusbar); - gridLayout->addWidget(mdiArea, 0, 0, 1, 1); - - MainWindow->setCentralWidget(centralwidget); - statusbar = new QStatusBar(MainWindow); - statusbar->setObjectName(QString::fromUtf8("statusbar")); - MainWindow->setStatusBar(statusbar); } // toolbar to ribbon @@ -790,6 +720,9 @@ namespace Ui { menuFile->addAction(actionSave); menuFile->addAction(actionSaveAs); menuFile->addSeparator(); + menuFile->addAction(actionLoadPointCloud); + menuFile->addAction(actionSavePointCloud); + menuFile->addSeparator(); menuFile->addAction(actionSave_Script); menuFile->addAction(actionExecute_Script); menuFile->addSeparator(); @@ -940,6 +873,23 @@ namespace Ui { create_set_pannel->addLargeAction(actionGenMesh); } + // PointCloud + pointCloud_page=ribbon->addCategoryPage(QObject::tr("PointCloud")); + PCLFile_operator_pannel= pointCloud_page->addPannel(QObject::tr("File")); + PCLFilter_pannel = pointCloud_page->addPannel(QObject::tr("Noise Filter")); + PCLReSurfaceMesh_pannel = pointCloud_page->addPannel(QObject::tr("ReSurface Mesh")); + { + PCLFile_operator_pannel->addMediumAction(actionLoadPointCloud); + PCLFile_operator_pannel->addMediumAction(actionSavePointCloud); + PCLFilter_pannel->addMediumAction(actionPCLStatisticalRemoveFilter); + PCLFilter_pannel->addMediumAction(actionPCLDBRemoveFilter); + PCLFilter_pannel->addMediumAction(actionPCLGuassFilter); + PCLFilter_pannel->addMediumAction(actionPCLAverageFilter); + PCLReSurfaceMesh_pannel->addLargeAction(actionPCLGPMesh); + } + + + // solve solve_page = ribbon->addCategoryPage(QObject::tr("Solve")); solver_management_pannel = solve_page->addPannel(QObject::tr("Solver Manager")); @@ -1025,286 +975,202 @@ namespace Ui { void MainWindowRibbon::retranslateRibbonUi(QMainWindow* MainWindow) { // BaseUi::retranslateUi() - { - MainWindow->setWindowTitle( - QCoreApplication::translate("MainWindow", "FastCAE", nullptr)); - actionNew->setText(QCoreApplication::translate("MainWindow", "New", nullptr)); + { + MainWindow->setWindowTitle(QCoreApplication::translate("MainWindow", "WBCLFZ_CAE", nullptr)); + actionNew->setText(QCoreApplication::translate("MainWindow", "New", nullptr)); #if QT_CONFIG(tooltip) - actionNew->setToolTip(QCoreApplication::translate("MainWindow", "New", nullptr)); + actionNew->setToolTip(QCoreApplication::translate("MainWindow", "New", nullptr)); #endif // QT_CONFIG(tooltip) #if QT_CONFIG(shortcut) - actionNew->setShortcut(QCoreApplication::translate("MainWindow", "Ctrl+N", nullptr)); + actionNew->setShortcut(QCoreApplication::translate("MainWindow", "Ctrl+N", nullptr)); #endif // QT_CONFIG(shortcut) - actionOpen->setText(QCoreApplication::translate("MainWindow", "Open", nullptr)); + actionOpen->setText(QCoreApplication::translate("MainWindow", "Open", nullptr)); #if QT_CONFIG(tooltip) - actionOpen->setToolTip(QCoreApplication::translate("MainWindow", "Open", nullptr)); + actionOpen->setToolTip(QCoreApplication::translate("MainWindow", "Open", nullptr)); #endif // QT_CONFIG(tooltip) #if QT_CONFIG(shortcut) - actionOpen->setShortcut(QCoreApplication::translate("MainWindow", "Ctrl+O", nullptr)); + actionOpen->setShortcut(QCoreApplication::translate("MainWindow", "Ctrl+O", nullptr)); #endif // QT_CONFIG(shortcut) - actionSave->setText(QCoreApplication::translate("MainWindow", "Save", nullptr)); + actionSave->setText(QCoreApplication::translate("MainWindow", "Save", nullptr)); #if QT_CONFIG(shortcut) - actionSave->setShortcut(QCoreApplication::translate("MainWindow", "Ctrl+S", nullptr)); + actionSave->setShortcut(QCoreApplication::translate("MainWindow", "Ctrl+S", nullptr)); #endif // QT_CONFIG(shortcut) - actionClose->setText(QCoreApplication::translate("MainWindow", "Close", nullptr)); + actionClose->setText(QCoreApplication::translate("MainWindow", "Close", nullptr)); #if QT_CONFIG(tooltip) - actionClose->setToolTip(QCoreApplication::translate("MainWindow", "Close", nullptr)); + actionClose->setToolTip(QCoreApplication::translate("MainWindow", "Close", nullptr)); #endif // QT_CONFIG(tooltip) #if QT_CONFIG(shortcut) - actionClose->setShortcut(QCoreApplication::translate("MainWindow", "Ctrl+Q", nullptr)); + actionClose->setShortcut(QCoreApplication::translate("MainWindow", "Ctrl+Q", nullptr)); #endif // QT_CONFIG(shortcut) - actionSaveAs->setText(QCoreApplication::translate("MainWindow", "SaveAs", nullptr)); + actionSaveAs->setText(QCoreApplication::translate("MainWindow", "SaveAs", nullptr)); #if QT_CONFIG(shortcut) - actionSaveAs->setShortcut( - QCoreApplication::translate("MainWindow", "Ctrl+Shift+S", nullptr)); + actionSaveAs->setShortcut(QCoreApplication::translate("MainWindow", "Ctrl+Shift+S", nullptr)); #endif // QT_CONFIG(shortcut) - actionChinese->setText(QCoreApplication::translate("MainWindow", "Chinese", nullptr)); + actionChinese->setText(QCoreApplication::translate("MainWindow", "Chinese", nullptr)); #if QT_CONFIG(tooltip) - actionChinese->setToolTip( - QCoreApplication::translate("MainWindow", "Chinese", nullptr)); + actionChinese->setToolTip(QCoreApplication::translate("MainWindow", "Chinese", nullptr)); #endif // QT_CONFIG(tooltip) - actionEnglish->setText(QCoreApplication::translate("MainWindow", "English", nullptr)); + actionEnglish->setText(QCoreApplication::translate("MainWindow", "English", nullptr)); #if QT_CONFIG(tooltip) - actionEnglish->setToolTip( - QCoreApplication::translate("MainWindow", "English", nullptr)); + actionEnglish->setToolTip(QCoreApplication::translate("MainWindow", "English", nullptr)); #endif // QT_CONFIG(tooltip) - actionImportMesh->setText( - QCoreApplication::translate("MainWindow", "Import Mesh", nullptr)); + actionImportMesh->setText(QCoreApplication::translate("MainWindow", "Import Mesh", nullptr)); #if QT_CONFIG(shortcut) - actionImportMesh->setShortcut( - QCoreApplication::translate("MainWindow", "Ctrl+I", nullptr)); + actionImportMesh->setShortcut(QCoreApplication::translate("MainWindow", "Ctrl+M", nullptr)); #endif // QT_CONFIG(shortcut) - actionImportGeometry->setText( - QCoreApplication::translate("MainWindow", "Import Geometry", nullptr)); + actionImportGeometry->setText(QCoreApplication::translate("MainWindow", "Import Geometry", nullptr)); #if QT_CONFIG(shortcut) - actionImportGeometry->setShortcut( - QCoreApplication::translate("MainWindow", "Ctrl+G", nullptr)); + actionImportGeometry->setShortcut(QCoreApplication::translate("MainWindow", "Ctrl+G", nullptr)); #endif // QT_CONFIG(shortcut) - actionWorkingDir->setText( - QCoreApplication::translate("MainWindow", "WorkingDir", nullptr)); - actionSolve->setText(QCoreApplication::translate("MainWindow", "Solve", nullptr)); + actionWorkingDir->setText(QCoreApplication::translate("MainWindow", "WorkingDir", nullptr)); + actionSolve->setText(QCoreApplication::translate("MainWindow", "Solve", nullptr)); #if QT_CONFIG(shortcut) - actionSolve->setShortcut(QCoreApplication::translate("MainWindow", "F5", nullptr)); + actionSolve->setShortcut(QCoreApplication::translate("MainWindow", "F5", nullptr)); #endif // QT_CONFIG(shortcut) - actionSolver_Manager->setText( - QCoreApplication::translate("MainWindow", "Solver Manager", nullptr)); - actionViewXPlus->setText( - QCoreApplication::translate("MainWindow", "ViewXPlus", nullptr)); - actionViewXMinus->setText( - QCoreApplication::translate("MainWindow", "ViewXMinus", nullptr)); - actionViewYPlus->setText( - QCoreApplication::translate("MainWindow", "ViewYPlus", nullptr)); - actionViewYMinus->setText( - QCoreApplication::translate("MainWindow", "ViewYMinus", nullptr)); - actionViewZPlus->setText( - QCoreApplication::translate("MainWindow", "ViewZPlus", nullptr)); - actionViewZMinus->setText( - QCoreApplication::translate("MainWindow", "ViewZMinus", nullptr)); - actionFitView->setText(QCoreApplication::translate("MainWindow", "FitView", nullptr)); - actionSelectOff->setText( - QCoreApplication::translate("MainWindow", "selectOff", nullptr)); - actionSelectMeshNode->setText( - QCoreApplication::translate("MainWindow", "selectMeshNode", nullptr)); - actionSelectMeshCell->setText( - QCoreApplication::translate("MainWindow", "selectMeshCell", nullptr)); - actionSolve_Options->setText( - QCoreApplication::translate("MainWindow", "Solve Options", nullptr)); - actionGraph_Options->setText( - QCoreApplication::translate("MainWindow", "Graph Options", nullptr)); - actionSurfaceMesh->setText( - QCoreApplication::translate("MainWindow", "SurfaceMesh", nullptr)); - actionSolidMesh->setText( - QCoreApplication::translate("MainWindow", "SolidMesh", nullptr)); - actionExportMesh->setText( - QCoreApplication::translate("MainWindow", "Export Mesh", nullptr)); + actionSolver_Manager->setText(QCoreApplication::translate("MainWindow", "Solver Manager", nullptr)); + actionViewXPlus->setText(QCoreApplication::translate("MainWindow", "ViewXPlus", nullptr)); + actionViewXMinus->setText(QCoreApplication::translate("MainWindow", "ViewXMinus", nullptr)); + actionViewYPlus->setText(QCoreApplication::translate("MainWindow", "ViewYPlus", nullptr)); + actionViewYMinus->setText(QCoreApplication::translate("MainWindow", "ViewYMinus", nullptr)); + actionViewZPlus->setText(QCoreApplication::translate("MainWindow", "ViewZPlus", nullptr)); + actionViewZMinus->setText(QCoreApplication::translate("MainWindow", "ViewZMinus", nullptr)); + actionFitView->setText(QCoreApplication::translate("MainWindow", "FitView", nullptr)); + actionSelectOff->setText(QCoreApplication::translate("MainWindow", "selectOff", nullptr)); + actionSelectMeshNode->setText(QCoreApplication::translate("MainWindow", "selectMeshNode", nullptr)); + actionSelectMeshCell->setText(QCoreApplication::translate("MainWindow", "selectMeshCell", nullptr)); + actionSolve_Options->setText(QCoreApplication::translate("MainWindow", "Solve Options", nullptr)); + actionGraph_Options->setText(QCoreApplication::translate("MainWindow", "Graph Options", nullptr)); + actionSurfaceMesh->setText(QCoreApplication::translate("MainWindow", "SurfaceMesh", nullptr)); + actionSolidMesh->setText(QCoreApplication::translate("MainWindow", "SolidMesh", nullptr)); + actionExportMesh->setText(QCoreApplication::translate("MainWindow", "Export Mesh", nullptr)); #if QT_CONFIG(shortcut) - actionExportMesh->setShortcut( - QCoreApplication::translate("MainWindow", "Ctrl+E", nullptr)); + actionExportMesh->setShortcut(QCoreApplication::translate("MainWindow", "Ctrl+Shift+M", nullptr)); #endif // QT_CONFIG(shortcut) - actionUser_Manual->setText( - QCoreApplication::translate("MainWindow", "User Manual", nullptr)); - actionAbout->setText(QCoreApplication::translate("MainWindow", "About", nullptr)); - actionDisplayNode->setText( - QCoreApplication::translate("MainWindow", "DisplayNode", nullptr)); - actionPreDisplayWireFrame->setText( - QCoreApplication::translate("MainWindow", "DisplayWireFrame", nullptr)); - actionDisplaySurface->setText( - QCoreApplication::translate("MainWindow", "DisplaySurface", nullptr)); -// actionDisplaySurfaceEdge->setText(QCoreApplication::translate("MainWindow", -//"DisplaySurfaceEdge", nullptr)); + actionUser_Manual->setText(QCoreApplication::translate("MainWindow", "User Manual", nullptr)); + actionAbout->setText(QCoreApplication::translate("MainWindow", "About", nullptr)); + actionDisplayNode->setText(QCoreApplication::translate("MainWindow", "DisplayNode", nullptr)); + actionPreDisplayWireFrame->setText(QCoreApplication::translate("MainWindow", "DisplayWireFrame", nullptr)); + actionDisplaySurface->setText(QCoreApplication::translate("MainWindow", "DisplaySurface", nullptr)); + actionCreate_Set->setText(QCoreApplication::translate("MainWindow", "Create Set", nullptr)); + action2DPlot->setText(QCoreApplication::translate("MainWindow", "2D Plot", nullptr)); + action3DGraph->setText(QCoreApplication::translate("MainWindow", "3D Graph", nullptr)); + actionSave_Script->setText(QCoreApplication::translate("MainWindow", "Save Script", nullptr)); + actionExecute_Script->setText(QCoreApplication::translate("MainWindow", "Execute Script", nullptr)); +#if QT_CONFIG(shortcut) + actionExecute_Script->setShortcut(QCoreApplication::translate("MainWindow", "Ctrl+R", nullptr)); +#endif // QT_CONFIG(shortcut) + actionGenMesh->setText(QCoreApplication::translate("MainWindow", "GenMesh", nullptr)); + actionSave_Picture->setText(QCoreApplication::translate("MainWindow", "Save Picture", nullptr)); + actionBoxMeshNode->setText(QCoreApplication::translate("MainWindow", "BoxMeshNode", nullptr)); + actionBoxMeshCell->setText(QCoreApplication::translate("MainWindow", "BoxMeshCell", nullptr)); + actionStart_Page->setText(QCoreApplication::translate("MainWindow", "Start Page", nullptr)); + actionPre_Window->setText(QCoreApplication::translate("MainWindow", "Pre Window", nullptr)); + actionChecking->setText(QCoreApplication::translate("MainWindow", "Checking", nullptr)); + actionCreateBox->setText(QCoreApplication::translate("MainWindow", "CreateBox", nullptr)); + actionCreateCylinder->setText(QCoreApplication::translate("MainWindow", "CreateCylinder", nullptr)); + actionCreaterSphere->setText(QCoreApplication::translate("MainWindow", "CreaterSphere", nullptr)); + actionChamfer->setText(QCoreApplication::translate("MainWindow", "Chamfer", nullptr)); + actionFillet->setText(QCoreApplication::translate("MainWindow", "Fillet", nullptr)); + actionBoolCut->setText(QCoreApplication::translate("MainWindow", "BoolCut", nullptr)); + actionBoolFause->setText(QCoreApplication::translate("MainWindow", "BoolFause", nullptr)); + actionBoolCommon->setText(QCoreApplication::translate("MainWindow", "BoolCommon", nullptr)); + actionUndo->setText(QCoreApplication::translate("MainWindow", "undo", nullptr)); +#if QT_CONFIG(shortcut) + actionUndo->setShortcut(QCoreApplication::translate("MainWindow", "Ctrl+Z", nullptr)); +#endif // QT_CONFIG(shortcut) + actionRedo->setText(QCoreApplication::translate("MainWindow", "redo", nullptr)); +#if QT_CONFIG(shortcut) + actionRedo->setShortcut(QCoreApplication::translate("MainWindow", "Ctrl+Y", nullptr)); +#endif // QT_CONFIG(shortcut) + actionExportGeometry->setText(QCoreApplication::translate("MainWindow", "ExportGeometry", nullptr)); +#if QT_CONFIG(shortcut) + actionExportGeometry->setShortcut(QCoreApplication::translate("MainWindow", "Ctrl+Shift+G", nullptr)); +#endif // QT_CONFIG(shortcut) + actionCreaterCone->setText(QCoreApplication::translate("MainWindow", "CreaterCone", nullptr)); + actionMirrorFeature->setText(QCoreApplication::translate("MainWindow", "MirrorFeature", nullptr)); + actionVariable_Fillet->setText(QCoreApplication::translate("MainWindow", "Variable Fillet", nullptr)); + actionExtrude->setText(QCoreApplication::translate("MainWindow", "Extrude", nullptr)); + actionCreate_Point->setText(QCoreApplication::translate("MainWindow", "Create Point", nullptr)); + actionCreate_Line->setText(QCoreApplication::translate("MainWindow", "Create Line", nullptr)); + actionCreate_Face->setText(QCoreApplication::translate("MainWindow", "Create_Surface", nullptr)); + actionMoveFeature->setText(QCoreApplication::translate("MainWindow", "Move", nullptr)); + actionRotateFeature->setText(QCoreApplication::translate("MainWindow", "Rotate", nullptr)); + actionRevol->setText(QCoreApplication::translate("MainWindow", "Revol", nullptr)); + actionLoft->setText(QCoreApplication::translate("MainWindow", "loft", nullptr)); + actionCreateDatumPlane->setText(QCoreApplication::translate("MainWindow", "Create Datum Plane", nullptr)); + actionDrawLine->setText(QCoreApplication::translate("MainWindow", "DrawLine", nullptr)); + actionDrawRectangle->setText(QCoreApplication::translate("MainWindow", "DrawRectangle", nullptr)); + actionDrawCircle->setText(QCoreApplication::translate("MainWindow", "DrawCircle", nullptr)); + actionCreate_Sketch->setText(QCoreApplication::translate("MainWindow", "Create Sketch", nullptr)); + actionDrawArc->setText(QCoreApplication::translate("MainWindow", "DrawArc", nullptr)); + actionDrawPolyline->setText(QCoreApplication::translate("MainWindow", "DrawPolyline", nullptr)); + actionMakeMatrix->setText(QCoreApplication::translate("MainWindow", "MakeMatrix", nullptr)); #if QT_CONFIG(tooltip) -// actionDisplaySurfaceEdge->setToolTip(QCoreApplication::translate("MainWindow", -//"DisplaySurfaceEdge", nullptr)); + actionMakeMatrix->setToolTip(QCoreApplication::translate("MainWindow", "MakeMatrix", nullptr)); #endif // QT_CONFIG(tooltip) - actionCreate_Set->setText( - QCoreApplication::translate("MainWindow", "Create Set", nullptr)); - action2DPlot->setText(QCoreApplication::translate("MainWindow", "2D Plot", nullptr)); - action3DGraph->setText(QCoreApplication::translate("MainWindow", "3D Graph", nullptr)); - actionSave_Script->setText( - QCoreApplication::translate("MainWindow", "Save Script", nullptr)); - actionExecute_Script->setText( - QCoreApplication::translate("MainWindow", "Execute Script", nullptr)); -#if QT_CONFIG(shortcut) - actionExecute_Script->setShortcut( - QCoreApplication::translate("MainWindow", "Ctrl+R", nullptr)); -#endif // QT_CONFIG(shortcut) - actionGenMesh->setText(QCoreApplication::translate("MainWindow", "GenMesh", nullptr)); - actionSave_Picture->setText( - QCoreApplication::translate("MainWindow", "Save Picture", nullptr)); - actionBoxMeshNode->setText( - QCoreApplication::translate("MainWindow", "BoxMeshNode", nullptr)); - actionBoxMeshCell->setText( - QCoreApplication::translate("MainWindow", "BoxMeshCell", nullptr)); - actionStart_Page->setText( - QCoreApplication::translate("MainWindow", "Start Page", nullptr)); - actionPre_Window->setText( - QCoreApplication::translate("MainWindow", "Pre Window", nullptr)); - actionChecking->setText(QCoreApplication::translate("MainWindow", "Checking", nullptr)); - actionCreateBox->setText( - QCoreApplication::translate("MainWindow", "CreateBox", nullptr)); - actionCreateCylinder->setText( - QCoreApplication::translate("MainWindow", "CreateCylinder", nullptr)); - actionCreaterSphere->setText( - QCoreApplication::translate("MainWindow", "CreaterSphere", nullptr)); - actionChamfer->setText(QCoreApplication::translate("MainWindow", "Chamfer", nullptr)); - actionFillet->setText(QCoreApplication::translate("MainWindow", "Fillet", nullptr)); - actionBoolCut->setText(QCoreApplication::translate("MainWindow", "BoolCut", nullptr)); - actionBoolFause->setText( - QCoreApplication::translate("MainWindow", "BoolFause", nullptr)); - actionBoolCommon->setText( - QCoreApplication::translate("MainWindow", "BoolCommon", nullptr)); - actionUndo->setText(QCoreApplication::translate("MainWindow", "undo", nullptr)); -#if QT_CONFIG(shortcut) - actionUndo->setShortcut(QCoreApplication::translate("MainWindow", "Ctrl+Z", nullptr)); -#endif // QT_CONFIG(shortcut) - actionRedo->setText(QCoreApplication::translate("MainWindow", "redo", nullptr)); -#if QT_CONFIG(shortcut) - actionRedo->setShortcut(QCoreApplication::translate("MainWindow", "Ctrl+Y", nullptr)); -#endif // QT_CONFIG(shortcut) - actionExportGeometry->setText( - QCoreApplication::translate("MainWindow", "ExportGeometry", nullptr)); - actionCreaterCone->setText( - QCoreApplication::translate("MainWindow", "CreaterCone", nullptr)); - actionMirrorFeature->setText( - QCoreApplication::translate("MainWindow", "MirrorFeature", nullptr)); - actionVariable_Fillet->setText( - QCoreApplication::translate("MainWindow", "Variable Fillet", nullptr)); - actionExtrude->setText(QCoreApplication::translate("MainWindow", "Extrude", nullptr)); - actionCreate_Point->setText( - QCoreApplication::translate("MainWindow", "Create Point", nullptr)); - actionCreate_Line->setText( - QCoreApplication::translate("MainWindow", "Create Line", nullptr)); - actionCreate_Face->setText( - QCoreApplication::translate("MainWindow", "Create_Surface", nullptr)); - actionMoveFeature->setText(QCoreApplication::translate("MainWindow", "Move", nullptr)); - actionRotateFeature->setText( - QCoreApplication::translate("MainWindow", "Rotate", nullptr)); - actionRevol->setText(QCoreApplication::translate("MainWindow", "Revol", nullptr)); - actionLoft->setText(QCoreApplication::translate("MainWindow", "loft", nullptr)); - actionCreateDatumPlane->setText( - QCoreApplication::translate("MainWindow", "Create Datum Plane", nullptr)); - actionDrawLine->setText(QCoreApplication::translate("MainWindow", "DrawLine", nullptr)); - actionDrawRectangle->setText( - QCoreApplication::translate("MainWindow", "DrawRectangle", nullptr)); - actionDrawCircle->setText( - QCoreApplication::translate("MainWindow", "DrawCircle", nullptr)); - actionCreate_Sketch->setText( - QCoreApplication::translate("MainWindow", "Create Sketch", nullptr)); - actionDrawArc->setText(QCoreApplication::translate("MainWindow", "DrawArc", nullptr)); - actionDrawPolyline->setText( - QCoreApplication::translate("MainWindow", "DrawPolyline", nullptr)); - actionMakeMatrix->setText( - QCoreApplication::translate("MainWindow", "MakeMatrix", nullptr)); + actionSweep->setText(QCoreApplication::translate("MainWindow", "Sweep", nullptr)); + actionDrawSpline->setText(QCoreApplication::translate("MainWindow", "DrawSpline", nullptr)); + actionDisplayPoint->setText(QCoreApplication::translate("MainWindow", "DisplayPoint", nullptr)); + actionDisplayCurve->setText(QCoreApplication::translate("MainWindow", "DisplayCurve", nullptr)); + actionDisplayFace->setText(QCoreApplication::translate("MainWindow", "DisplayFace", nullptr)); + actionSelectPoint->setText(QCoreApplication::translate("MainWindow", "SelectPoint", nullptr)); + actionSelectCurve->setText(QCoreApplication::translate("MainWindow", "SelectCurve", nullptr)); + actionSelectFace->setText(QCoreApplication::translate("MainWindow", "SelectFace", nullptr)); + actionSelectGeometryBody->setText(QCoreApplication::translate("MainWindow", "SelectGeometryBody", nullptr)); + actionPluginManager->setText(QCoreApplication::translate("MainWindow", "Plugin Manager", nullptr)); #if QT_CONFIG(tooltip) - actionMakeMatrix->setToolTip( - QCoreApplication::translate("MainWindow", "MakeMatrix", nullptr)); + actionPluginManager->setToolTip(QCoreApplication::translate("MainWindow", "Plugin Manager", nullptr)); #endif // QT_CONFIG(tooltip) - actionSweep->setText(QCoreApplication::translate("MainWindow", "Sweep", nullptr)); - actionDrawSpline->setText( - QCoreApplication::translate("MainWindow", "DrawSpline", nullptr)); - actionDisplayPoint->setText( - QCoreApplication::translate("MainWindow", "DisplayPoint", nullptr)); - actionDisplayCurve->setText( - QCoreApplication::translate("MainWindow", "DisplayCurve", nullptr)); - actionDisplayFace->setText( - QCoreApplication::translate("MainWindow", "DisplayFace", nullptr)); - actionSelectPoint->setText( - QCoreApplication::translate("MainWindow", "SelectPoint", nullptr)); - actionSelectCurve->setText( - QCoreApplication::translate("MainWindow", "SelectCurve", nullptr)); - actionSelectFace->setText( - QCoreApplication::translate("MainWindow", "SelectFace", nullptr)); - actionSelectGeometryBody->setText( - QCoreApplication::translate("MainWindow", "SelectGeometryBody", nullptr)); - actionPluginManager->setText( - QCoreApplication::translate("MainWindow", "Plugin Manager", nullptr)); + actionUser_Guidance->setText(QCoreApplication::translate("MainWindow", "User Guidance", nullptr)); + actionMeasure_Distance->setText(QCoreApplication::translate("MainWindow", "Measure Distance", nullptr)); + actionMeasure->setText(QCoreApplication::translate("MainWindow", "Measure", nullptr)); + actionGeoSplitter->setText(QCoreApplication::translate("MainWindow", "Split", nullptr)); + actionCreateGeoComponent->setText(QCoreApplication::translate("MainWindow", "CreateGeoComponent", nullptr)); + actionFluidMesh->setText(QCoreApplication::translate("MainWindow", "FluidMesh", nullptr)); + actionFilterMesh->setText(QCoreApplication::translate("MainWindow", "FilterMesh", nullptr)); + actionFillHole->setText(QCoreApplication::translate("MainWindow", "FillHole", nullptr)); + actionRemoveSurface->setText(QCoreApplication::translate("MainWindow", "RemoveSurface", nullptr)); + actionFillGap->setText(QCoreApplication::translate("MainWindow", "FillGap", nullptr)); + actionVTKTranslation->setText(QCoreApplication::translate("MainWindow", "Mesh Modeling", nullptr)); + actionGeoMeshRotate->setText(QCoreApplication::translate("MainWindow", "GeoMeshRotate", nullptr)); + actionNormal->setText(QCoreApplication::translate("MainWindow", "Normal", nullptr)); + actionRibbon->setText(QCoreApplication::translate("MainWindow", "Ribbon", nullptr)); + actionOpenPostFile->setText(QCoreApplication::translate("MainWindow", "OpenPostFile", nullptr)); + actionDisplayPoints->setText(QCoreApplication::translate("MainWindow", "DisplayPoints", nullptr)); + actionPostDisplayWireframe->setText(QCoreApplication::translate("MainWindow", "DisplayWireframe", nullptr)); + actionDisplaySurfaceWithoutEdge->setText(QCoreApplication::translate("MainWindow", "DisplaySurfaceWithoutEdge", nullptr)); + actionDisplaySurfaceWithEdge->setText(QCoreApplication::translate("MainWindow", "DisplaySurfaceWithEdge", nullptr)); + actionCreateVector->setText(QCoreApplication::translate("MainWindow", "CreateVector", nullptr)); + actionCreateClip->setText(QCoreApplication::translate("MainWindow", "CreateClip", nullptr)); + actionCreateSlice->setText(QCoreApplication::translate("MainWindow", "CreateSlice", nullptr)); + actionCreateStreamLine->setText(QCoreApplication::translate("MainWindow", "CreateStreamLine", nullptr)); + actionCreateISOCurve->setText(QCoreApplication::translate("MainWindow", "CreateISOCurve", nullptr)); + actionCreateISOSurface->setText(QCoreApplication::translate("MainWindow", "CreateISOSurface", nullptr)); + actionCreateCalculator->setText(QCoreApplication::translate("MainWindow", "CreateCalculator", nullptr)); + actionCreateReflection->setText(QCoreApplication::translate("MainWindow", "CreateReflection", nullptr)); + actionSaveImage->setText(QCoreApplication::translate("MainWindow", "SaveImage", nullptr)); + actionSaveVideo->setText(QCoreApplication::translate("MainWindow", "SaveVideo", nullptr)); #if QT_CONFIG(tooltip) - actionPluginManager->setToolTip( - QCoreApplication::translate("MainWindow", "Plugin Manager", nullptr)); + actionSaveVideo->setToolTip(QCoreApplication::translate("MainWindow", "SaveVideo", nullptr)); #endif // QT_CONFIG(tooltip) - actionUser_Guidance->setText( - QCoreApplication::translate("MainWindow", "User Guidance", nullptr)); - actionMeasure_Distance->setText( - QCoreApplication::translate("MainWindow", "Measure Distance", nullptr)); - actionMeasure->setText(QCoreApplication::translate("MainWindow", "Measure", nullptr)); - actionGeoSplitter->setText(QCoreApplication::translate("MainWindow", "Split", nullptr)); - actionCreateGeoComponent->setText( - QCoreApplication::translate("MainWindow", "CreateGeoComponent", nullptr)); - actionFluidMesh->setText( - QCoreApplication::translate("MainWindow", "FluidMesh", nullptr)); - actionFilterMesh->setText( - QCoreApplication::translate("MainWindow", "FilterMesh", nullptr)); - actionFillHole->setText(QCoreApplication::translate("MainWindow", "FillHole", nullptr)); - actionRemoveSurface->setText( - QCoreApplication::translate("MainWindow", "RemoveSurface", nullptr)); - actionFillGap->setText(QCoreApplication::translate("MainWindow", "FillGap", nullptr)); - actionVTKTranslation->setText( - QCoreApplication::translate("MainWindow", "Mesh Modeling", nullptr)); - actionGeoMeshRotate->setText( - QCoreApplication::translate("MainWindow", "GeoMeshRotate", nullptr)); - actionNormal->setText(QCoreApplication::translate("MainWindow", "Normal", nullptr)); - actionRibbon->setText(QCoreApplication::translate("MainWindow", "Ribbon", nullptr)); - actionOpenPostFile->setText( - QCoreApplication::translate("MainWindow", "OpenPostFile", nullptr)); - actionDisplayPoints->setText( - QCoreApplication::translate("MainWindow", "DisplayPoints", nullptr)); - actionPostDisplayWireframe->setText( - QCoreApplication::translate("MainWindow", "DisplayWireframe", nullptr)); - actionDisplaySurfaceWithoutEdge->setText( - QCoreApplication::translate("MainWindow", "DisplaySurfaceWithoutEdge", nullptr)); - actionDisplaySurfaceWithEdge->setText( - QCoreApplication::translate("MainWindow", "DisplaySurfaceWithEdge", nullptr)); - actionCreateVector->setText( - QCoreApplication::translate("MainWindow", "CreateVector", nullptr)); - actionCreateClip->setText( - QCoreApplication::translate("MainWindow", "CreateClip", nullptr)); - actionCreateSlice->setText( - QCoreApplication::translate("MainWindow", "CreateSlice", nullptr)); - actionCreateStreamLine->setText( - QCoreApplication::translate("MainWindow", "CreateStreamLine", nullptr)); - actionCreateISOCurve->setText( - QCoreApplication::translate("MainWindow", "CreateISOCurve", nullptr)); - actionCreateISOSurface->setText( - QCoreApplication::translate("MainWindow", "CreateISOSurface", nullptr)); - actionCreateCalculator->setText( - QCoreApplication::translate("MainWindow", "CreateCalculator", nullptr)); - actionCreateReflection->setText( - QCoreApplication::translate("MainWindow", "CreateReflection", nullptr)); - actionSaveImage->setText( - QCoreApplication::translate("MainWindow", "SaveImage", nullptr)); - actionSaveVideo->setText( - QCoreApplication::translate("MainWindow", "SaveVideo", nullptr)); -#if QT_CONFIG(tooltip) - actionSaveVideo->setToolTip( - QCoreApplication::translate("MainWindow", "SaveVideo", nullptr)); -#endif // QT_CONFIG(tooltip) - } + actionLoadPointCloud->setText(QCoreApplication::translate("MainWindow", "Load PointCloud", nullptr)); + actionSavePointCloud->setText(QCoreApplication::translate("MainWindow", "Save PointCloud", nullptr)); + actionFilter->setText(QCoreApplication::translate("MainWindow", "Filter", nullptr)); + actionPointCloudStatisticalRemove->setText(QCoreApplication::translate("MainWindow", "StatisticalRemove", nullptr)); + actionPCLStatisticalRemoveFilter->setText(QCoreApplication::translate("MainWindow", "StatisticalRemoveFilter", nullptr)); + actionPCLDBRemoveFilter->setText(QCoreApplication::translate("MainWindow", "DBRemoveFilter", nullptr)); + actionPCLGuassFilter->setText(QCoreApplication::translate("MainWindow", "GuassFilter", nullptr)); + actionPCLAverageFilter->setText(QCoreApplication::translate("MainWindow", "AverageFilter", nullptr)); + actionPCLGPMesh->setText(QCoreApplication::translate("MainWindow", "GPMesh", nullptr)); + actionLoadFile->setText(QCoreApplication::translate("MainWindow", "LoadFile", nullptr)); + } // retranslateUi SARibbonMainWindow* ribbonwindow = qobject_cast(MainWindow); ribbonwindow->ribbonBar()->applicationButton()->setText(QObject::tr("File")); home_page->setWindowTitle(QObject::tr("Home")); geometry_page->setWindowTitle(QObject::tr("Geometry")); mesh_page->setWindowTitle(QObject::tr("Mesh")); + pointCloud_page->setWindowTitle(QObject::tr("PointCloud")); solve_page->setWindowTitle(QObject::tr("Solve")); window_page->setWindowTitle(QObject::tr("Windows")); help_page->setWindowTitle(QObject::tr("Help")); diff --git a/src/MainWindow/SARibbonMWUi.h b/src/MainWindow/SARibbonMWUi.h index bf6c630..ffcf847 100644 --- a/src/MainWindow/SARibbonMWUi.h +++ b/src/MainWindow/SARibbonMWUi.h @@ -44,6 +44,14 @@ namespace Ui { SARibbonPannel* display_node_pannel{}; SARibbonPannel* create_set_pannel{}; + + SARibbonCategory* pointCloud_page{}; // ç‚¹äº‘é¢æ¿ + SARibbonPannel* PCLFile_operator_pannel{}; + SARibbonPannel* PCLFilter_pannel{}; + SARibbonPannel* PCLReSurfaceMesh_pannel{}; + + + SARibbonCategory* solve_page{}; SARibbonPannel* solver_management_pannel{}; diff --git a/src/MainWindow/SubWindowManager.cpp b/src/MainWindow/SubWindowManager.cpp index 6c56f56..3b6c65f 100644 --- a/src/MainWindow/SubWindowManager.cpp +++ b/src/MainWindow/SubWindowManager.cpp @@ -25,55 +25,39 @@ #include namespace GUI { - SubWindowManager::SubWindowManager(MainWindow* mainwindow, QMdiArea* mdiArea, - SignalHandler* hander, MainWidget::ControlPanel* cp) + SubWindowManager::SubWindowManager(MainWindow* mainwindow, QMdiArea* mdiArea, SignalHandler* hander, MainWidget::ControlPanel* cp) : _mainWindow(mainwindow) , _mdiArea(mdiArea) , _signalHander(hander) , _controlPanel(cp) { connect(mainwindow, SIGNAL(closePreWindowSig()), this, SLOT(closePreWindow())); - connect(mainwindow, SIGNAL(openPostWindowSig(Post::PostWindowBase*)), this, - SLOT(openPostWindow(Post::PostWindowBase*))); - connect(mainwindow, SIGNAL(openRealTimeWindowSig(Post::RealTimeWindowBase*, int)), this, - SLOT(openRealTimeWindow(Post::RealTimeWindowBase*))); - connect(mainwindow, SIGNAL(showPostWindowInfoSig(int, int)), this, - SLOT(showPostWindowInfo(int, int))); - connect(mainwindow, SIGNAL(closePostWindowSig(Post::PostWindowBase*)), this, - SLOT(closePostWindow(Post::PostWindowBase*))); - connect(_mdiArea, SIGNAL(subWindowActivated(QMdiSubWindow*)), this, - SLOT(subWindowActived(QMdiSubWindow*))); - connect(mainwindow, SIGNAL(closeRealTimeWindowSig(Post::RealTimeWindowBase*)), this, - SLOT(closeRealTimeWindow(Post::RealTimeWindowBase*))); - connect(mainwindow, SIGNAL(openReportWindowSig(XReport::ReportWindow*)), this, - SLOT(openReportWindow(XReport::ReportWindow*))); - connect(mainwindow, SIGNAL(closeReportWindowSig(XReport::ReportWindow*)), this, - SLOT(closeReportWindow(XReport::ReportWindow*))); - connect(mainwindow, SIGNAL(saveImageSig(QString, int, Post::PostWindowBase*, int, int)), - this, SLOT(saveImage(QString, int, Post::PostWindowBase*, int, int))); - connect(mainwindow, SIGNAL(saveImage(int, int, QString)), this, - SLOT(saveImage(int, int, QString))); + connect(mainwindow, SIGNAL(openPostWindowSig(Post::PostWindowBase*)), this, SLOT(openPostWindow(Post::PostWindowBase*))); + connect(mainwindow, SIGNAL(openRealTimeWindowSig(Post::RealTimeWindowBase*, int)), this, SLOT(openRealTimeWindow(Post::RealTimeWindowBase*))); + connect(mainwindow, SIGNAL(showPostWindowInfoSig(int, int)), this, SLOT(showPostWindowInfo(int, int))); + connect(mainwindow, SIGNAL(closePostWindowSig(Post::PostWindowBase*)), this, SLOT(closePostWindow(Post::PostWindowBase*))); + connect(_mdiArea, SIGNAL(subWindowActivated(QMdiSubWindow*)), this, SLOT(subWindowActived(QMdiSubWindow*))); + connect(mainwindow, SIGNAL(closeRealTimeWindowSig(Post::RealTimeWindowBase*)), this, SLOT(closeRealTimeWindow(Post::RealTimeWindowBase*))); + connect(mainwindow, SIGNAL(openReportWindowSig(XReport::ReportWindow*)), this, SLOT(openReportWindow(XReport::ReportWindow*))); + connect(mainwindow, SIGNAL(closeReportWindowSig(XReport::ReportWindow*)), this, SLOT(closeReportWindow(XReport::ReportWindow*))); + connect(mainwindow, SIGNAL(saveImageSig(QString, int, Post::PostWindowBase*, int, int)), this, SLOT(saveImage(QString, int, Post::PostWindowBase*, int, int))); + connect(mainwindow, SIGNAL(saveImage(int, int, QString)), this, SLOT(saveImage(int, int, QString))); - connect(this, SIGNAL(setViewSig(int, QString, QString)), this, - SLOT(setView(int, QString, QString))); - connect(this, - SIGNAL(setViewValueSig(int, QString, int, int, int, int, int, int, int, int, int)), - this, - SLOT(setViewValue(int, QString, int, int, int, int, int, int, int, int, int))); - connect(this, SIGNAL(saveImageSig(int, int, int, QString, QString)), this, - SLOT(saveImage(int, int, int, QString, QString))); + connect(this, SIGNAL(setViewSig(int, QString, QString)), this, SLOT(setView(int, QString, QString))); + connect(this, SIGNAL(setViewValueSig(int, QString, int, int, int, int, int, int, int, int, int)), this, SLOT(setViewValue(int, QString, int, int, int, int, int, int, int, int, int))); + connect(this, SIGNAL(saveImageSig(int, int, int, QString, QString)), this, SLOT(saveImage(int, int, int, QString, QString))); connect(this, SIGNAL(openPreWindowSig()), this, SLOT(openPreWindow())); } SubWindowManager::~SubWindowManager() {} void SubWindowManager::openPreWindow() { - if(isPreWindowOpened()) { + if (isPreWindowOpened()) { Py::PythonAgent::getInstance()->unLock(); return; } - if(_preWindow.first == nullptr || _preWindow.second == nullptr) { + if (_preWindow.first == nullptr || _preWindow.second == nullptr) { _preWindow.second = new MainWidget::PreWindow(_mainWindow); - _preWindow.first = _mdiArea->addSubWindow(_preWindow.second); + _preWindow.first = _mdiArea->addSubWindow(_preWindow.second); _signalHander->updateActionsStates(); Command::GeometryCommandPy::init(_mainWindow, _preWindow.second); } @@ -105,53 +89,54 @@ namespace GUI { void SubWindowManager::add3dRenderPage(const QList& toolbars) { - if(_threeD_render_page || toolbars.size() != 4) + if (_threeD_render_page || toolbars.size() != 4) return; QList actions; - QAction* action{}; - SARibbonBar* ribbon = _mainWindow->ribbonBar(); - _threeD_render_page = ribbon->addCategoryPage(QObject::tr("3D Render")); + QAction* action{}; + SARibbonBar* ribbon = _mainWindow->ribbonBar(); + _threeD_render_page = ribbon->addCategoryPage(QObject::tr("3D Render")); - SARibbonPannel* pannel0 = _threeD_render_page->addPannel(QString()); - QToolBar* toolbar0 = toolbars.at(0); - actions = toolbar0->actions(); - for(int j = 0; j < actions.size(); j++) { + SARibbonPannel* pannel0 = _threeD_render_page->addPannel(QString()); + QToolBar* toolbar0 = toolbars.at(0); + actions = toolbar0->actions(); + for (int j = 0; j < actions.size(); j++) { action = actions.at(j); pannel0->addLargeAction(action); } - SARibbonPannel* pannel2 = _threeD_render_page->addPannel(QString()); - QToolBar* toolbar2 = toolbars.at(2); - actions = toolbar2->actions(); - for(int j = 0; j < actions.size(); j++) { + SARibbonPannel* pannel2 = _threeD_render_page->addPannel(QString()); + QToolBar* toolbar2 = toolbars.at(2); + actions = toolbar2->actions(); + for (int j = 0; j < actions.size(); j++) { action = actions.at(j); pannel2->addLargeAction(action); } - SARibbonPannel* pannel3 = _threeD_render_page->addPannel(QString()); - QToolBar* toolbar3 = toolbars.at(3); - actions = toolbar3->actions(); - for(int j = 0; j < actions.size(); j++) { + SARibbonPannel* pannel3 = _threeD_render_page->addPannel(QString()); + QToolBar* toolbar3 = toolbars.at(3); + actions = toolbar3->actions(); + for (int j = 0; j < actions.size(); j++) { action = actions.at(j); pannel3->addLargeAction(action); } - SARibbonPannel* pannel1 = _threeD_render_page->addPannel(QString()); - QToolBar* toolbar1 = toolbars.at(1); - actions = toolbar1->actions(); + SARibbonPannel* pannel1 = _threeD_render_page->addPannel(QString()); + QToolBar* toolbar1 = toolbars.at(1); + actions = toolbar1->actions(); QList realActions; QList comboxs; - QWidget* widget{}; - for(int j = 0; j < actions.size(); j++) { + QWidget* widget{}; + for (int j = 0; j < actions.size(); j++) { action = actions.at(j); - if(action->objectName() == "QComboBox") { + if (action->objectName() == "QComboBox") { widget = toolbar1->widgetForAction(action); widget->setVisible(true); comboxs.append(widget); - } else if(action->objectName() == "QAction") + } + else if (action->objectName() == "QAction") realActions.append(action); } - if(realActions.size() != 4 && comboxs.size() != 3) + if (realActions.size() != 4 && comboxs.size() != 3) return; pannel1->addLargeAction(realActions.at(0)); pannel1->addLargeAction(realActions.at(1)); @@ -173,10 +158,10 @@ namespace GUI { void SubWindowManager::remove3dRenderPage() { - if(_threeD_render_page == nullptr) + if (_threeD_render_page == nullptr) return; auto pannels = _threeD_render_page->pannelList(); - for(SARibbonPannel* pannel : pannels) { + for (SARibbonPannel* pannel : pannels) { _threeD_render_page->removePannel(pannel); pannel = nullptr; } @@ -196,19 +181,19 @@ namespace GUI { } void SubWindowManager::updatePreMeshActor() { - if(_preWindow.second != nullptr) { + if (_preWindow.second != nullptr) { emit _preWindow.second->updateMeshActorSig(); } } void SubWindowManager::updatePreGeometryActor() { - if(_preWindow.second != nullptr) { + if (_preWindow.second != nullptr) { _preWindow.second->updateGeometryActor(); } } void SubWindowManager::closePreWindow() { - _preWindow.first = nullptr; + _preWindow.first = nullptr; _preWindow.second = nullptr; _mainWindow->getUi()->actionPre_Window->setEnabled(true); @@ -223,20 +208,21 @@ namespace GUI { } void SubWindowManager::openPostWindow(Post::PostWindowBase* pw) { - if(pw == nullptr) { + if (pw == nullptr) { assert(0); return; } - QMdiSubWindow* sw = nullptr; + QMdiSubWindow* sw = nullptr; QList pwl = _postWindow.values(); - if(pwl.contains(pw)) { + if (pwl.contains(pw)) { sw = _postWindow.key(pw); - } else { + } + else { sw = _mdiArea->addSubWindow(pw); _mdiArea->cascadeSubWindows(); _postWindow[sw] = pw; } - if(sw != nullptr) { + if (sw != nullptr) { sw->activateWindow(); sw->showMaximized(); sw->setFocus(); @@ -248,15 +234,16 @@ namespace GUI { void SubWindowManager::openRealTimeWindow(Post::RealTimeWindowBase* pw) { - QMdiSubWindow* sw = nullptr; + QMdiSubWindow* sw = nullptr; QList pwl = _realTimeWindow.values(); - if(pwl.contains(pw)) { + if (pwl.contains(pw)) { sw = _realTimeWindow.key(pw); - } else { - sw = _mdiArea->addSubWindow(pw); + } + else { + sw = _mdiArea->addSubWindow(pw); _realTimeWindow[sw] = pw; } - if(sw != nullptr) { + if (sw != nullptr) { sw->showMaximized(); sw->setFocus(); } @@ -266,17 +253,18 @@ namespace GUI { { QMdiSubWindow* activeWindow = nullptr; - auto subWins = _mdiArea->subWindowList(); - if(subWins.size() == 1) { + auto subWins = _mdiArea->subWindowList(); + if (subWins.size() == 1) { activeWindow = subWins.at(0); - } else { + } + else { activeWindow = _mdiArea->activeSubWindow(); } - if(activeWindow == nullptr) + if (activeWindow == nullptr) return nullptr; - else if(activeWindow == _preWindow.first) + else if (activeWindow == _preWindow.first) return _preWindow.second; - else if(_postWindow.contains(activeWindow)) + else if (_postWindow.contains(activeWindow)) return _postWindow[activeWindow]; else return nullptr; @@ -284,13 +272,13 @@ namespace GUI { Post::PostWindowBase* SubWindowManager::getPostWindowByIDType(int id, int type) { QList pwl = _postWindow.values(); - for(int i = 0; i < pwl.size(); ++i) { + for (int i = 0; i < pwl.size(); ++i) { Post::PostWindowBase* w = pwl.at(i); - if(w == nullptr) + if (w == nullptr) continue; - int wid = w->getID(); + int wid = w->getID(); int wtype = (int)w->getPostWindowType(); - if(wid == id && wtype == type) + if (wid == id && wtype == type) return w; } return nullptr; @@ -298,7 +286,7 @@ namespace GUI { void SubWindowManager::removeToolBars() { const int n = _currentToolBars.size(); - for(int i = 0; i < n; ++i) { + for (int i = 0; i < n; ++i) { QToolBar* t = _currentToolBars.at(i); _mainWindow->removeToolBar(t); } @@ -307,28 +295,29 @@ namespace GUI { void SubWindowManager::showPostWindowInfo(int id, int type) { Post::PostWindowBase* pwb = getPostWindowByIDType(id, type); - if(pwb == nullptr) + if (pwb == nullptr) return; // QWidget* ptree = pwb->getTreeWidget(); // QWidget* pprop = pwb->getPropWidget(); QMdiSubWindow* subWin = _postWindow.key(pwb); - if(subWin != nullptr) { + if (subWin != nullptr) { subWin->showMaximized(); subWin->setFocus(); } //_controlPanel->updatePostWidget(ptree, pprop); - if(type == 2) + if (type == 2) _controlPanel->updatePostWidget(); QList toolBars = pwb->getToolBarList(); - if(_mainWindow->isUseRibbon()) { - if(_threeD_render_page) + if (_mainWindow->isUseRibbon()) { + if (_threeD_render_page) return; add3dRenderPage(toolBars); - } else { + } + else { this->removeToolBars(); _mainWindow->addToolBarBreak(); - for(int i = 0; i < toolBars.size(); ++i) { + for (int i = 0; i < toolBars.size(); ++i) { _mainWindow->addToolBar(toolBars.at(i)); (toolBars.at(i))->show(); _currentToolBars.append(toolBars.at(i)); @@ -338,25 +327,25 @@ namespace GUI { void SubWindowManager::closePostWindow(Post::PostWindowBase* w) { QMdiSubWindow* subw = _postWindow.key(w); - if(subw == nullptr) + if (subw == nullptr) return; Post::PostWindowType type = w->getPostWindowType(); removeToolBars(); - if(type == Post::PostWindowType::D3 - && _mainWindow->isUseRibbon()) // 使用ribbon,并且关闭的是3ç»´çª—å£ + if (type == Post::PostWindowType::D3 + && _mainWindow->isUseRibbon()) // 使用ribbon,并且关闭的是3ç»´çª—å£ remove3dRenderPage(); - if(_controlPanel != nullptr) + if (_controlPanel != nullptr) _controlPanel->updatePostWidget(nullptr, nullptr); emit _mainWindow->updateProperty(nullptr); _postWindow.remove(subw); QList postsubwlist = _postWindow.values(); - if(_preWindow.first != nullptr) + if (_preWindow.first != nullptr) showPreWindow(); - else if(postsubwlist.size() > 0) { - Post::PostWindowBase* w = postsubwlist.at(0); - int id = w->getID(); + else if (postsubwlist.size() > 0) { + Post::PostWindowBase* w = postsubwlist.at(0); + int id = w->getID(); Post::PostWindowType type = w->getPostWindowType(); showPostWindowInfo(id, type); } @@ -365,10 +354,10 @@ namespace GUI { void SubWindowManager::showPreWindow() { removeToolBars(); - if(_controlPanel == nullptr) + if (_controlPanel == nullptr) return; _controlPanel->updatePostWidget(nullptr, nullptr); - if(_preWindow.first != nullptr) { + if (_preWindow.first != nullptr) { _preWindow.first->showMaximized(); _preWindow.first->setFocus(); } @@ -377,22 +366,22 @@ namespace GUI { { removeToolBars(); _controlPanel->updatePostWidget(nullptr, nullptr); - if(_realTimeWindow.contains(w)) { + if (_realTimeWindow.contains(w)) { w->showMaximized(); w->setFocus(); } } void SubWindowManager::subWindowActived(QMdiSubWindow* sw) { - if(sw == nullptr) + if (sw == nullptr) return; - if(sw == _preWindow.first) + if (sw == _preWindow.first) showPreWindow(); - else if(_realTimeWindow.contains(sw)) + else if (_realTimeWindow.contains(sw)) showRealTimeWindow(sw); - else if(_postWindow.contains(sw)) { - Post::PostWindowBase* pwb = _postWindow.value(sw); - int id = pwb->getID(); + else if (_postWindow.contains(sw)) { + Post::PostWindowBase* pwb = _postWindow.value(sw); + int id = pwb->getID(); Post::PostWindowType type = pwb->getPostWindowType(); showPostWindowInfo(id, type); } @@ -401,10 +390,10 @@ namespace GUI { void SubWindowManager::closeRealTimeWindow(Post::RealTimeWindowBase* w) { QMdiSubWindow* subw = _realTimeWindow.key(w); - if(subw == nullptr) + if (subw == nullptr) return; _realTimeWindow.remove(subw); - if(_preWindow.first != nullptr) + if (_preWindow.first != nullptr) showPreWindow(); emit _mainWindow->updateActionStatesSig(); } @@ -415,9 +404,9 @@ namespace GUI { if (gwb == nullptr) return; gwb->setView(view);*/ ModuleBase::GraphWindowBase* gwb = getCurrentWindow(); - if(gwb == nullptr) + if (gwb == nullptr) return; - const int id = gwb->getID(); + const int id = gwb->getID(); QString win = gwb->getStringGraphWindowType(); qDebug() << win; QString pycode = QString("MainWindow.setView(%1,\"%2\",\"%3\")").arg(id).arg(win).arg(view); @@ -432,15 +421,16 @@ namespace GUI { } void SubWindowManager::openReportWindow(XReport::ReportWindow* w) { - QMdiSubWindow* sw = nullptr; + QMdiSubWindow* sw = nullptr; QList rws = _reportWindow.values(); - if(rws.contains(w)) { + if (rws.contains(w)) { sw = _reportWindow.key(w); - } else { - sw = _mdiArea->addSubWindow(w); + } + else { + sw = _mdiArea->addSubWindow(w); _reportWindow[sw] = w; } - if(sw != nullptr) { + if (sw != nullptr) { sw->showMaximized(); sw->setFocus(); } @@ -449,19 +439,19 @@ namespace GUI { void SubWindowManager::closeReportWindow(XReport::ReportWindow* w) { QMdiSubWindow* s = _reportWindow.key(w); - if(s != nullptr) { + if (s != nullptr) { _reportWindow.remove(s); } } bool SubWindowManager::isPreWindowOpened() { - if(_preWindow.first == nullptr || _preWindow.second == nullptr) + if (_preWindow.first == nullptr || _preWindow.second == nullptr) return false; return true; } bool SubWindowManager::isPostWindowOpened() { - if(_postWindow.size() > 0) + if (_postWindow.size() > 0) return true; return false; } @@ -469,24 +459,25 @@ namespace GUI { bool SubWindowManager::isPostWindowOpening() { QMdiSubWindow* activeWindow = _mdiArea->activeSubWindow(); - if(activeWindow == nullptr) + if (activeWindow == nullptr) return false; - else if(_postWindow.contains(activeWindow)) + else if (_postWindow.contains(activeWindow)) return true; else return false; } void SubWindowManager::saveImage(QString fileName, int winType, Post::PostWindowBase* winhandle, - int w, int h) + int w, int h) { - if(winType == 0) { + if (winType == 0) { MainWidget::PreWindow* preW = _preWindow.second; - if(preW == nullptr) + if (preW == nullptr) return; preW->saveImage(fileName, w, h, false); - } else if(winType == 1) { - if(_postWindow.key(winhandle) == nullptr) + } + else if (winType == 1) { + if (_postWindow.key(winhandle) == nullptr) return; winhandle->saveImage(fileName, w, h, false); } @@ -495,18 +486,18 @@ namespace GUI { void SubWindowManager::saveImage(int w, int h, QString f) { ModuleBase::GraphWindowBase* gw = this->getCurrentWindow(); - if(gw == nullptr) { + if (gw == nullptr) { _mainWindow->printMessage(Common::Message::Error, tr("No GraphWindow opened!")); return; } - QString type = gw->getStringGraphWindowType(); - const int id = gw->getID(); + QString type = gw->getStringGraphWindowType(); + const int id = gw->getID(); QString pycode = QString("MainWindow.saveImage(%1,%2,%3,\"%4\",\"%5\")") - .arg(w) - .arg(h) - .arg(id) - .arg(type) - .arg(f); + .arg(w) + .arg(h) + .arg(id) + .arg(type) + .arg(f); qDebug() << pycode; Py::PythonAgent::getInstance()->submit(pycode); } @@ -514,7 +505,7 @@ namespace GUI { void SubWindowManager::saveImage(int w, int h, int id, QString winType, QString file) { ModuleBase::GraphWindowBase* win = this->getWindowByTypeID(winType, id); - if(win == nullptr) + if (win == nullptr) return; win->saveImage(file, w, h, false); Py::PythonAgent::getInstance()->unLock(); @@ -522,16 +513,16 @@ namespace GUI { void SubWindowManager::setView(int id, QString winType, QString view) // liu { ModuleBase::GraphWindowBase* gwb = getWindowByTypeID(winType, id); - if(gwb == nullptr) + if (gwb == nullptr) return; gwb->setView(view); Py::PythonAgent::getInstance()->unLock(); } void SubWindowManager::setViewValue(int id, QString win, int x1, int x2, int x3, int y1, int y2, - int y3, int z1, int z2, int z3) + int y3, int z1, int z2, int z3) { ModuleBase::GraphWindowBase* gwb = getWindowByTypeID(win, id); - if(gwb == nullptr) + if (gwb == nullptr) return; gwb->setViewValue(x1, x2, x3, y1, y2, y3, z1, z2, z3); Py::PythonAgent::getInstance()->unLock(); @@ -546,37 +537,37 @@ namespace GUI { void SubWindowManager::reTranslate() { MainWidget::PreWindow* prew = _preWindow.second; - if(prew != nullptr) + if (prew != nullptr) prew->reTranslate(); - int n = 0; + int n = 0; QList postWinList = _postWindow.values(); - n = postWinList.size(); - for(int i = 0; i < n; ++i) { + n = postWinList.size(); + for (int i = 0; i < n; ++i) { Post::PostWindowBase* pw = postWinList.at(i); - if(pw != nullptr) + if (pw != nullptr) pw->reTranslate(); } QList rwList = _realTimeWindow.values(); - n = rwList.size(); - for(int i = 0; i < n; ++i) { + n = rwList.size(); + for (int i = 0; i < n; ++i) { Post::RealTimeWindowBase* rw = rwList.at(i); - if(rw != nullptr) + if (rw != nullptr) rw->reTranslate(); } QList repWin = _reportWindow.values(); - n = repWin.size(); - for(int i = 0; i < n; ++i) { + n = repWin.size(); + for (int i = 0; i < n; ++i) { XReport::ReportWindow* w = repWin.at(i); w->reTranslate(); } - if(_threeD_render_page != nullptr) + if (_threeD_render_page != nullptr) _threeD_render_page->setWindowTitle(tr("3D Render")); } void SubWindowManager::closeGeometryWindow() { - _geometryWindow.first = nullptr; + _geometryWindow.first = nullptr; _geometryWindow.second = nullptr; _signalHander->clearData(false); @@ -588,7 +579,7 @@ namespace GUI { GenerateGeometry::GenerateGeometryWidget* SubWindowManager::getGeometryWindow() { - if(!_geometryWindow.second) { + if (!_geometryWindow.second) { openGeometryWindow(); } return _geometryWindow.second; @@ -600,7 +591,7 @@ namespace GUI { // _mdiArea->setTabPosition(QTabWidget::North); MainWidget::PreWindow* pre = _preWindow.second; - if(pre != nullptr) { + if (pre != nullptr) { _preWindow.first->close(); _mdiArea->removeSubWindow(pre); pre->close(); @@ -608,7 +599,7 @@ namespace GUI { } QList postlist = _postWindow.values(); - for(int i = 0; i < postlist.size(); ++i) { + for (int i = 0; i < postlist.size(); ++i) { Post::PostWindowBase* p = postlist.at(i); _postWindow.key(p)->close(); _mdiArea->removeSubWindow(p); @@ -617,7 +608,7 @@ namespace GUI { } QList realtimelist = _realTimeWindow.values(); - for(int i = 0; i < realtimelist.size(); ++i) { + for (int i = 0; i < realtimelist.size(); ++i) { Post::RealTimeWindowBase* r = realtimelist.at(i); _realTimeWindow.key(r)->close(); _mdiArea->removeSubWindow(r); @@ -626,7 +617,7 @@ namespace GUI { } QList reportlist = _reportWindow.values(); - for(int i = 0; i < reportlist.size(); ++i) { + for (int i = 0; i < reportlist.size(); ++i) { XReport::ReportWindow* r = reportlist.at(i); _reportWindow.key(r)->close(); _mdiArea->removeSubWindow(r); @@ -638,35 +629,38 @@ namespace GUI { ModuleBase::GraphWindowBase* SubWindowManager::getWindowByTypeID(QString type, int id) { ModuleBase::GraphWindowBase* g = nullptr; - type = type.toLower(); - if(type == "prewindow") { + type = type.toLower(); + if (type == "prewindow") { g = _preWindow.second; - } else if(type == "realtime") { + } + else if (type == "realtime") { QList wlist = _realTimeWindow.values(); - for(int i = 0; i < wlist.size(); ++i) { + for (int i = 0; i < wlist.size(); ++i) { ModuleBase::GraphWindowBase* t = wlist.at(i); const int d = t->getID(); - if(id == d) { + if (id == d) { g = t; break; } } - } else if(type == "post2d") { + } + else if (type == "post2d") { QList wlist = _postWindow.values(); - for(int i = 0; i < wlist.size(); ++i) { + for (int i = 0; i < wlist.size(); ++i) { ModuleBase::GraphWindowBase* t = wlist.at(i); const int d = t->getID(); - if(id == d && t->getGraphWindowType() == ModuleBase::Post2D) { + if (id == d && t->getGraphWindowType() == ModuleBase::Post2D) { g = t; break; } } - } else if(type == "post3d") { + } + else if (type == "post3d") { QList wlist = _postWindow.values(); - for(int i = 0; i < wlist.size(); ++i) { + for (int i = 0; i < wlist.size(); ++i) { ModuleBase::GraphWindowBase* t = wlist.at(i); const int d = t->getID(); - if(id == d && t->getGraphWindowType() == ModuleBase::Post3D) { + if (id == d && t->getGraphWindowType() == ModuleBase::Post3D) { g = t; break; } @@ -677,11 +671,11 @@ namespace GUI { void SubWindowManager::setIcon(QString icon) { - if(_preWindow.first != nullptr) + if (_preWindow.first != nullptr) _preWindow.first->setWindowIcon(QIcon(icon)); QList subw = _postWindow.keys() + _realTimeWindow.keys() + _reportWindow.keys(); - for(auto w : subw) { + for (auto w : subw) { w->setWindowIcon(QIcon(icon)); } } diff --git a/src/PythonModule/PyAgent.cpp b/src/PythonModule/PyAgent.cpp index d90d32a..ad5858d 100644 --- a/src/PythonModule/PyAgent.cpp +++ b/src/PythonModule/PyAgent.cpp @@ -53,7 +53,7 @@ namespace Py { { _mainWindow = m; connectSignals(); - Py_SetProgramName(L"FastCAE_LAMP"); + Py_SetProgramName(L"FastCAE_LAMP"); // 设置程åºåç§° Py_Initialize(); if(!_interpreter->init(this)) emit printInfo(Common::Message::Error, tr("Python Initialize failed!")); diff --git a/src/WBCLFZSystemModule/.command_history.lst b/src/WBCLFZSystemModule/.command_history.lst new file mode 100644 index 0000000..e69de29 diff --git a/src/WBCLFZSystemModule/AllHead.cpp b/src/WBCLFZSystemModule/AllHead.cpp new file mode 100644 index 0000000..f334aae --- /dev/null +++ b/src/WBCLFZSystemModule/AllHead.cpp @@ -0,0 +1,58 @@ +#include "AllHead.h" + +QSettings* getQSetting() +{ + + QString fileName = QCoreApplication::applicationDirPath() + "/Config.ini"; + QSettings* setting = new QSettings(fileName, QSettings::IniFormat); + setting->setIniCodec(QTextCodec::codecForName("UTF-8")); + + if (QFile::exists(fileName)) + { + return setting; + } + else {// Îļþ²»´æÔÚ£¬Ð´ÈëÅäÖÃÏÉú³ÉÅäÖÃÎļþ + setting->setValue("application", u8"΢²¨²âÁ¿·ÂÕæ·Öϵͳ"); + setting->sync(); + } + + return setting; +} + +QString getOpenFilePath(QWidget* parent, const QString& caption, const QString& filter) +{ + QSettings* setting = getQSetting(); + QString curpath = u8"."; + if (setting->contains("FileSelectPath")) { + curpath = setting->value("FileSelectPath").toString(); + } + else { + + } + + QString filepath = QFileDialog::getOpenFileName( parent,caption, curpath, filter); + if (!filepath.isEmpty()&&QFile::exists(filepath)) { + setting->setValue("FileSelectPath", getParantFromPath(filepath)); + setting->sync(); + } + return filepath; +} + +QString getSaveFilePath(QWidget* parent, const QString& caption, const QString& filter) +{ + QSettings* setting = getQSetting(); + QString curpath = u8"."; + if (setting->contains("FileSelectPath")) { + curpath = setting->value("FileSelectPath").toString(); + } + else { + + } + + QString filepath = QFileDialog::getSaveFileName(parent, caption, curpath, filter); + if (!filepath.isEmpty() && isExists(getParantFromPath(filepath))) { + setting->setValue("FileSelectPath", getParantFromPath(filepath)); + setting->sync(); + } + return filepath; +} diff --git a/src/WBCLFZSystemModule/AllHead.h b/src/WBCLFZSystemModule/AllHead.h new file mode 100644 index 0000000..fdd804d --- /dev/null +++ b/src/WBCLFZSystemModule/AllHead.h @@ -0,0 +1,210 @@ +#pragma once +#ifndef ALLHEAD_H +#define ALLHEAD_H + + +//================================== +// ÏßÐÔ¼ÆËã¿âÓÅ»¯ +//=============================== +//#define EIGEN_NO_DEBUG + + +//===================================================== +// ÄÚ²¿¿â LAMPTool +//===================================================== +#include "referenceHeader.h" +// Basetoollib +#include "Basetoollib/BaseConstVariable.h" +#include "Basetoollib/BaseTool.h" +#include "Basetoollib/FileOperator.h" +//#include "Basetoollib/GeoOperator.h" +#include "Basetoollib/ImageOperatorBase.h" +//#include "Basetoollib/interpolation.h" + +// SARBaseToolLib +//#include "SARBaseToolLib/BackScatterModel.h" +//#include "SARBaseToolLib/SARBaseTool.h" +//#include "SARBaseToolLib/SARCalibration.h" +#include "SARBaseToolLib/SARImageBase.h" + +// SARImage +#include "SARImage/FEKOBaseToolClass.h" +#include "SARImage/FEKONearBPBasic.h" +#include "FEKOSimulationSARClass.h" +#include "OCCTBase.h" +#include "FEKOFarFieldFileClass.h" + +//===================================================== +// ÄÚ²¿¿â SharedModuleLib +//===================================================== + + + +//===================================================== +// ÄÚÖà command +//===================================================== + + // ===================================================== +// ÆäËû¹¤³Ì¿â +// +// ====================================================== +#include "qcustomplot.h" + +//======================================================= +// ÒýÓÿâ +//======================================================= +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +class QObject; + + +// ===================================================== +// ³£Óú궨Òå +// +// ====================================================== +#define __SHOWPROCESS + + + +// ===================================================== +//#include +// +// ====================================================== + + + + +//======================================================= +// ³£Óûù´¡±äÁ¿ÀàÐͶ¨Òå +//======================================================= + + +//======================================================= +// ³£Óûù´¡º¯Êý +//======================================================= ] +QSettings* getQSetting(); + +QString getOpenFilePath(QWidget* parent = nullptr, const QString& caption = QString(), const QString& filter = QString()); + +QString getSaveFilePath(QWidget* parent = nullptr, const QString& caption = QString(), const QString& filter = QString()); + + +/* + QString filepath = getOpenFilePath( + nullptr, + QString::fromUtf8(u8"µ¼ÈëÀ×´ïÄ£ÐÍ"), + ".", + QString::fromUtf8(u8"STL Files (*.stl);;STL Files (*.stla);;step Files (*.stp);;step Files (*.step);;IGES Files (*.iges);;IGES Files (*.igs)")); + + +*/ + + + + + +#endif // ! ALLHEAD_H \ No newline at end of file diff --git a/src/WBCLFZSystemModule/CMakeLists.txt b/src/WBCLFZSystemModule/CMakeLists.txt new file mode 100644 index 0000000..5888357 --- /dev/null +++ b/src/WBCLFZSystemModule/CMakeLists.txt @@ -0,0 +1,68 @@ +#----------------------------------------------------------------------------- +# 头文件æœç´¢è·¯å¾„ +#----------------------------------------------------------------------------- +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/..) + +#----------------------------------------------------------------------------- +# 自动添加include目录 +#----------------------------------------------------------------------------- +set(CMAKE_INCLUDE_CURRENT_DIR ON) + +#----------------------------------------------------------------------------- +# æ·»åŠ èµ„æºæ–‡ä»¶ +#----------------------------------------------------------------------------- +set(_qrc "${CMAKE_CURRENT_SOURCE_DIR}/../qrc/WBCLFZSystemModule.qrc") + +qt5_add_resources(_resource ${_qrc} ${_lang}) + +#----------------------------------------------------------------------------- +# æºç æ‰«æ +#----------------------------------------------------------------------------- +file(GLOB _ui "*.ui") +file(GLOB _header "*.h*") +file(GLOB _source "*.cpp") +qt5_wrap_ui(_interface ${_ui}) + +#----------------------------------------------------------------------------- +# 添加动æ€åº“目标 +#----------------------------------------------------------------------------- +add_library(WBCLFZSystemModule + ${_resource} + ${_interface} + ${_header} + ${_source} +) + +#----------------------------------------------------------------------------- +# 添加接å£å£°æ˜Žå® +#----------------------------------------------------------------------------- +target_compile_definitions(WBCLFZSystemModule PRIVATE "WBCLFZSystemModule_API") + + + + +list(APPEND _depend_library qcustomplot LAMPTool qscintilla2 qhexedit) + +list(APPEND _runtimes_libraries + Qt5::Core Qt5::Gui Qt5::Widgets +) + +target_include_directories(WBCLFZSystemModule PRIVATE ${Qwt_INCLUDE_DIRS}) + +#----------------------------------------------------------------------------- +# 链接ä¾èµ–库 +#----------------------------------------------------------------------------- +target_link_libraries(WBCLFZSystemModule PRIVATE + ${_runtimes_libraries} + ${_depend_library} +) + +#----------------------------------------------------------------------------- +# 添加ä¾èµ–关系 +#----------------------------------------------------------------------------- +add_dependencies(WBCLFZSystemModule ${_depend_library}) + +#----------------------------------------------------------------------------- +# 添加è¿è¡Œæ—¶ä¾èµ–关系 +#----------------------------------------------------------------------------- +set(FastCAE_WBCLFZSystemModule_Runtimes_Libraries ${_runtimes_libraries} PARENT_SCOPE) \ No newline at end of file diff --git a/src/WBCLFZSystemModule/DialogBatchExport.ui b/src/WBCLFZSystemModule/DialogBatchExport.ui new file mode 100644 index 0000000..2fb7328 --- /dev/null +++ b/src/WBCLFZSystemModule/DialogBatchExport.ui @@ -0,0 +1,195 @@ + + + DialogBatchExport + + + + 0 + 0 + 739 + 133 + + + + + 16777215 + 250 + + + + 场景文件批é‡å¯¼å‡º + + + + + + + 60 + 30 + + + + + 60 + 30 + + + + 导出路径 + + + + + + + + 60 + 30 + + + + + 60 + 30 + + + + 选择 + + + + + + + + 0 + 30 + + + + + 16777215 + 30 + + + + + + + + + 0 + 30 + + + + + 16777215 + 30 + + + + TextLabel + + + + + + + + 60 + 30 + + + + + 60 + 30 + + + + å¯¼å‡ºæ ¼å¼ + + + + + + + + 0 + 30 + + + + + 16777215 + 30 + + + + + + + + + 60 + 30 + + + + + 60 + 30 + + + + 导出 + + + + + + + + 16777215 + 50 + + + + + + + + + + + 16777215 + 25 + + + + åˆå¹¶ + + + + + + + + 16777215 + 25 + + + + ä¸åˆå¹¶ + + + + + + + + + + + diff --git a/src/WBCLFZSystemModule/EchoShowProcess/CMDExcuteApp.cpp b/src/WBCLFZSystemModule/EchoShowProcess/CMDExcuteApp.cpp new file mode 100644 index 0000000..7882ac8 --- /dev/null +++ b/src/WBCLFZSystemModule/EchoShowProcess/CMDExcuteApp.cpp @@ -0,0 +1,82 @@ +#include "CMDExcuteApp.h" +#include +#include +#include +#include + +CMDExcuteApp::CMDExcuteApp(QWidget* parent) +{ + this->ui.setupUi(this); + this->cmd = new QProcess(); + connect(this->cmd, SIGNAL(readyReadStandardOutput()), this, SLOT(on_readoutput())); + connect(this->cmd, SIGNAL(readyReadStandardError()), this, SLOT(on_readerror())); + +} + +CMDExcuteApp::~CMDExcuteApp() +{ + if (nullptr != this->cmd) { + + delete this->cmd; + this->cmd = nullptr; + + } +} + +int CMDExcuteApp::excuteCmd(QString cmdText) +{ + qDebug() << u8"Ö´ÐÐÃüÁ" << cmdText ; + this->ui.textEdit->append("cmd.exe\n"); + this->cmd->start("cmd.exe"); + this->cmd->waitForStarted(); //µÈ´ý³ÌÐòÆô¶¯ + this->ui.textEdit->append(QString::QString(cmdText)); + this->ui.textEdit->append("\n"); + this->cmd->write(cmdText.toUtf8().constData()); + + this->cmd->close(); + this->waitExcutedFinish(); + return 0; +} + +int CMDExcuteApp::excuteCmd(QString exePath, QString params) +{ + qDebug() << u8"Ö´ÐÐÃüÁ" << exePath<setWindowTitle(exePath); + QString program = QString::QString(exePath); + QStringList prams_txt; + prams_txt.append(QString::QString(params)); + this->cmd->start(program, prams_txt); + //this->cmd->waitForFinished(); + this->show(); + this->waitExcutedFinish(); + return 0; +} + +int CMDExcuteApp::waitExcutedFinish() +{ + while (!this->cmd->waitForFinished()) { + qDebug() << u8"ÔËÐÐ״̬£º" << this->cmd->state(); + QCoreApplication::processEvents(); + } + qDebug() << u8"Í˳öÑ­»·ÔËÐÐ״̬£º" << this->cmd->state(); + qDebug() << u8"Í˳öÑ­»·Â룺" << this->cmd->exitCode(); + this->on_readerror(); + this->on_readoutput(); + emit this->callbackExcuteResult(); + return 0; +} + +int CMDExcuteApp::on_readerror() +{ + QString out = this->cmd->readAllStandardError().data(); + qDebug()<ui.textEdit->append(out); + return 0; +} +int CMDExcuteApp::on_readoutput() +{ + QString out = this->cmd->readAllStandardOutput().data(); + qDebug() << u8"on_readoutput:\t" << out; + this->ui.textEdit->append(out); //½«Êä³öÐÅÏ¢¶ÁÈ¡µ½±à¼­¿ò + return 0; +} \ No newline at end of file diff --git a/src/WBCLFZSystemModule/EchoShowProcess/CMDExcuteApp.h b/src/WBCLFZSystemModule/EchoShowProcess/CMDExcuteApp.h new file mode 100644 index 0000000..ea1abdc --- /dev/null +++ b/src/WBCLFZSystemModule/EchoShowProcess/CMDExcuteApp.h @@ -0,0 +1,34 @@ +#pragma once + +#ifndef CMDEXCUTEAPP_H +#define CMDEXCUTEAPP_H + +#include +#include +#include "ui_CMDExcuteApp.h" + + +class CMDExcuteApp : public QMainWindow +{ + Q_OBJECT + +public: + CMDExcuteApp(QWidget* parent = nullptr); + ~CMDExcuteApp(); + int excuteCmd(QString cmdText); + int excuteCmd(QString exePath,QString params); + int waitExcutedFinish(); +private: + Ui::cmdExcuteWindows ui; + QProcess* cmd; + +signals: + void callbackExcuteResult(); + +private slots: + int on_readoutput(); + int on_readerror(); +}; + + +#endif \ No newline at end of file diff --git a/src/WBCLFZSystemModule/EchoShowProcess/CMDExcuteApp.ui b/src/WBCLFZSystemModule/EchoShowProcess/CMDExcuteApp.ui new file mode 100644 index 0000000..6473855 --- /dev/null +++ b/src/WBCLFZSystemModule/EchoShowProcess/CMDExcuteApp.ui @@ -0,0 +1,26 @@ + + + cmdExcuteWindows + + + + 0 + 0 + 568 + 260 + + + + cmd + + + + + + + + + + + + diff --git a/src/WBCLFZSystemModule/EchoShowProcess/EchoTableEditWindow.cpp b/src/WBCLFZSystemModule/EchoShowProcess/EchoTableEditWindow.cpp new file mode 100644 index 0000000..ecbf897 --- /dev/null +++ b/src/WBCLFZSystemModule/EchoShowProcess/EchoTableEditWindow.cpp @@ -0,0 +1,394 @@ +#include "EchoTableEditWindow.h" +#include "TableProcess/TableMainWindow.h" +#include "TableProcess/TableViewModel.h" +#include "SharedModuleLib/BaseUiTool.h" +#include "LAMPImageCreateClass.h" + +#include +#include +#include +#include +#include +#include +#include + + + +EchoTableEditWindow::EchoTableEditWindow(QWidget* parent) +{ + this->FILEOPENLOCK = false; + this->CheckFieldContextHasEmptyCeilLOCK = false; + this->ui.setupUi(this); + this->setWindowTitle(u8"FEKO»Ø²¨Êý¾Ý½âÎöÓëµ¼³ö½çÃæ"); + this->initTableViewContextMenu(); + this->initTableViewStatusBarControl(); + + // ¶¨±ê³£Êý½çÃæ¹Ø±Õ + this->ui.tab_calibration->setEnabled(false); + this->ui.tabWidget->removeTab(1);// ɾ³ý¶¨±ê³£Êý½çÃæ + + +} + +EchoTableEditWindow::~EchoTableEditWindow() +{ + delete this->statusprogressBar; + delete this->tableViewContextMenu; + delete this->m_undoStack; + + + + +} + +int EchoTableEditWindow::initTableViewContextMenu() +{ + qDebug() << u8"ÕýÔÚ³õʼ»¯contextMenu"; + m_undoStack = new QUndoStack(this); //´æ·ÅÃüÁîµÄÕ» + + this->ui.tableView->setContextMenuPolicy(Qt::CustomContextMenu); + //this->ui.tableView->setFocusPolicy(Qt::NoFocus); // ÔÊÐí¿ì½Ý¼ü + this->tableViewContextMenu = new QMenu(this->ui.tableView); // ±í¸ñ¿Ø¼þµÄÓÒ¼ü²Ëµ¥ + + QAction* m_undoAction = m_undoStack->createUndoAction(this, u8"³·Ïú");//Ìí¼ÓQAction£¬Ctrl-Z×÷Ϊ»Ø³·µÄ¿ì½Ý¼ü + m_undoAction->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Z)); + QObject::connect(m_undoAction, SIGNAL(triggered()), this, SLOT(tableView_UndoAction())); + + QAction* m_redoAction = m_undoStack->createRedoAction(this, u8"ÖØ×ö");//Ìí¼ÓQAction£¬Ctrl-Y×óÓÒǰ½øµÄ¿ì½Ý¼ü + m_redoAction->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Y)); + QObject::connect(m_redoAction, SIGNAL(triggered()), this, SLOT(tableView_RedoAction())); + + this->tableViewContextMenu->addAction(m_undoAction); + this->tableViewContextMenu->addAction(m_redoAction); + + + QAction *copyAction= this->tableViewContextMenu->addAction(u8"¸´ÖÆ"); // ¸´ÖÆ + copyAction->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_C)); + QObject::connect(copyAction, SIGNAL(triggered()), this, SLOT(tableView_CopyAction())); + + QAction* PasteAction = this->tableViewContextMenu->addAction(u8"Õ³Ìù"); // Õ³Ìù + PasteAction->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_V)); + QObject::connect(PasteAction, SIGNAL(triggered()), this, SLOT(tableView_PasteAction())); + + QAction* CheckFieldHasEmptyCeilAction = this->tableViewContextMenu->addAction(u8"¼ì²éµ¥Ôª¸ñΪ¿Õ"); + QObject::connect(CheckFieldHasEmptyCeilAction, SIGNAL(triggered()), this, SLOT(tableView_CheckFieldHasEmptyCeilAction())); + qDebug() << u8"³õʼ»¯contextMenu½áÊø"; + return 0; +} + +void EchoTableEditWindow::ShowTableViewContextMenu(QPoint p) +{ + qDebug() << u8"ÕýÔÚչʾtableview ÓÒ¼ü²Ëµ¥"; + //Q_UNUSED(pos); + this->tableViewContextMenu->exec(QCursor::pos()); +} + +void EchoTableEditWindow::tableView_CopyAction() +{ + qDebug() << u8"ÕýÔÚÆô¶¯tableview ÓÒ¼ü¸´ÖÆ´úÂë"; + QItemSelectionModel* selectionModel = this->ui.tableView->selectionModel(); + QModelIndexList selectedIndexes = selectionModel->selectedIndexes(); + if (selectedIndexes.count() == 0) { + return; + } + + QTableView* tableView = this->ui.tableView; // Your table view object + + /* + * a\tb\tc\n + * d\tf\te\n + **/ + int min_row, max_row, min_col, max_col; + min_row = selectedIndexes.at(0).row(); + max_row = selectedIndexes.at(0).row(); + min_col = selectedIndexes.at(0).column(); + max_col = selectedIndexes.at(0).column(); + for (int i = 0; i < selectedIndexes.count(); i++) { + min_row = min_row > selectedIndexes.at(i).row() ? selectedIndexes.at(i).row() : min_row; + max_row = max_row < selectedIndexes.at(i).row() ? selectedIndexes.at(i).row() : max_row; + min_col = min_col > selectedIndexes.at(i).column() ? selectedIndexes.at(i).column() : min_col; + max_col = max_col < selectedIndexes.at(i).column() ? selectedIndexes.at(i).column() : max_col; + } + std::vector> copylist(max_row-min_row+1); + for (int i = min_row; i <= max_row; i++) { + copylist[i - min_row] = std::vector(max_col - min_col + 1); + } + qDebug() << u8"minRow"<horizontalHeader(); + //for (int i = 0; i < header->count(); i++) { + // QVariant headerData = header->model()->headerData(i, Qt::Horizontal); + // clipboardData.insert(i, headerData.toString()); + //} + qDebug() << u8"============================"; + qDebug() << clipboardText; + qDebug() << u8"============================"; + + QApplication::clipboard()->setText(clipboardText); +} + +int EchoTableEditWindow::setDragDropOverwriteMode(bool flag) { + this->ui.tableView->setDragDropOverwriteMode(flag); + return 0; +} + +int EchoTableEditWindow::setTablCalibrationTab(bool flag) +{ + if (flag) { + this->ui.tab_calibration->setEnabled(true); + this->ui.tabWidget->insertTab(1, this->ui.tab_calibration, u8"¶¨±ê³£Êý"); + } + else { + this->ui.tab_calibration->setEnabled(false); + this->ui.tabWidget->removeTab(1);// ɾ³ý¶¨±ê³£Êý½çÃæ + } + return 0; +} + +void EchoTableEditWindow::tableView_PasteAction() { + qDebug() << u8"ÕýÔÚÆô¶¯tableview ÓÒ¼üÕ³Ìù´úÂë"; + QTableView* tableview = this->ui.tableView; + QClipboard* clipboard = QApplication::clipboard(); + QString clipboardData = QApplication::clipboard()->text(); + QItemSelectionModel* selectionModel = this->ui.tableView->selectionModel(); + QModelIndexList selectedIndexes = selectionModel->selectedIndexes(); + this->m_undoStack->push(new PasteCommand(this->ui.tableView, selectedIndexes, clipboardData)); + tableview->show(); +} + +void EchoTableEditWindow::tableView_UndoAction() +{ + qDebug() << u8"ÕýÔÚ³·ÏúÃüÁî"; + int index = this->m_undoStack->index(); + this->m_undoStack->setIndex(index); +} + +void EchoTableEditWindow::tableView_RedoAction() +{ + qDebug() << u8"ÕýÔÚÖØ×öÃüÁî"; + int index = this->m_undoStack->index(); + this->m_undoStack->setIndex(index ); +} + + +// ¼ì²é´æÔÚ¿Õµ¥Ôª¸ñµÄÁУ¬²¢ÐÞ¸Äչʾ +void EchoTableEditWindow::tableView_CheckFieldHasEmptyCeilAction() +{ + this->ui.statusbar->showMessage(u8"ÕýÔÚ¼ì²é´æÔÚ¿ÕÊý¾ÝµÄµ¥ÔªÁÐ"); + size_t colcount = this->ui.tableView->model()->columnCount(); + size_t rowcount = this->ui.tableView->model()->rowCount(); + this->statusprogressBar->setRange(0, colcount - 1); + this->statusprogressBar->setValue(0); + QList cellIndexes; + for (int j = 0; j < colcount; j++) { + for (int i = 0; i < rowcount; i++) { + if (this->ui.tableView->model()->index(i, j).data().toString().count() < 1) { + cellIndexes.append(this->ui.tableView->model()->index(i, j)); + break; + } + } + this->statusprogressBar->setValue(j); + } + if (cellIndexes.count() == 0) { + return; + } + else {} + this->ui.statusbar->showMessage(u8"ÕýÔÚÑ¡Ôñ¿Õ¸ñ"); + this->statusprogressBar->setRange(0, cellIndexes.count()-1); + this->statusprogressBar->setValue(0); + QItemSelectionModel* selectionModel = this->ui.tableView->selectionModel(); + for (int i = 0; i < cellIndexes.count(); i++) { + selectionModel->select(cellIndexes[i], QItemSelectionModel::Select); + this->statusprogressBar->setValue(i); + } + this->ui.tableView->show(); + this->ui.tableView->scrollTo(cellIndexes[0], QAbstractItemView::EnsureVisible); + + +} + +void EchoTableEditWindow::on_actionOpen_triggered() +{ + this->OpenCSVDialog(); +} + +void EchoTableEditWindow::on_actionSave_triggered() +{ + this->SaveCSVDialog(); +} + +void EchoTableEditWindow::on_actionSaveAs_triggered() +{ + this->SaveAsDialog(); +} + +void EchoTableEditWindow::on_actionEchoSplitExport_triggered() +{ + // ÔÚ´°¿Ú¹Ø±ÕʼþÖÐѯÎÊÓû§ÊÇ·ñ¹Ø±Õ + QMessageBox::StandardButton reply; + qDebug() << u8"¼ì²éÂÒÂëÎļþËùÔÚλÖÃ"; + reply = QMessageBox::question(this, u8"ѯÎÊ", u8"µ¼³ö»Ø²¨Îļþǰ£¬Çë±£´æÎļþ", QMessageBox::Yes | QMessageBox::No); + if (reply == QMessageBox::Yes) { + // Óû§µã»÷ÁË"Yes"°´Å¥£¬¹Ø±Õ´°¿Ú + this->SaveCSVDialog(); + } + else { + // Óû§µã»÷ÁË"No"°´Å¥£¬È¡Ïû¹Ø±Õ²Ù×÷ + return; + } + // ±£´æ²¢µ¼³ö»Ø²¨Îļþ + + this->ui.statusbar->showMessage(u8"ÕýÔÚ·ÖÎö»Ø²¨Îļþ"); + this->statusprogressBar->setRange(0,100); + this->statusprogressBar->setValue(10); + FEKOBase::NearFieldEchoCSVParser nearfilePraseclass; + QString echocsvfilepath = this->model->getCSVPath(); + if (!nearfilePraseclass.parseCSV(echocsvfilepath)) { + QMessageBox::warning(this, u8"¾¯¸æ", u8"»Ø²¨Îļþ½á¹¹½âÎö´íÎó£¬Çë¼ì²éÎļþ"); + return; + } + this->statusprogressBar->setValue(25); + QMessageBox::information(this, u8"ÐÅÏ¢", u8"Çë·Ö±ðΪtheta¼«»¯¡¢phi¼«»¯¡¢R¼«»¯·ÖÁ¿»Ø²¨Ö¸¶¨±£´æÂ·¾¶"); + + QString thetafilepath = getSaveFilePath( + this, + QString::fromUtf8(u8"Áí´æÎª"), + QString::fromUtf8(u8"thetaÎļþ (*.theta)"));//¶à×éÀ©Õ¹ÃûÓÃË«·ÖºÅ";;"¸ô¿ª + + QString phifilepath = getSaveFilePath( + this, + QString::fromUtf8(u8"Áí´æÎª"), + QString::fromUtf8(u8"phiÎļþ (*.phi)"));//¶à×éÀ©Õ¹ÃûÓÃË«·ÖºÅ";;"¸ô¿ª + + QString Rfilepath = getSaveFilePath( + this, + QString::fromUtf8(u8"Áí´æÎª"), + QString::fromUtf8(u8"RÎļþ (*.R)"));//¶à×éÀ©Õ¹ÃûÓÃË«·ÖºÅ";;"¸ô¿ª + + + this->ui.statusbar->showMessage(u8"ÕýÔÚµ¼³ötheta¼«»¯"); + nearfilePraseclass.toThetapolar(thetafilepath); + this->statusprogressBar->setValue(50); + this->ui.statusbar->showMessage(u8"ÕýÔÚµ¼³öphi¼«»¯"); + nearfilePraseclass.toPhiPolar(phifilepath); + this->statusprogressBar->setValue(75); + + this->ui.statusbar->showMessage(u8"ÕýÔÚµ¼³öR¼«»¯"); + nearfilePraseclass.toRPolar(Rfilepath); + this->statusprogressBar->setValue(99); + QMessageBox::information(this, u8"ÐÅÏ¢", u8"¼«»¯»Ø²¨ÒѾ­±£´æÍê±Ï"); + + // ѯÎÊÓû§ÊÇ·ñ¹Ø±Õ´°¿Ú + + reply = QMessageBox::question(this, u8"Ìáʾ", u8"ÊÇ·ñÖ±½Ó½øÐгÉÏñ?",QMessageBox::Yes | QMessageBox::No); + if (reply == QMessageBox::Yes) { + LAMPImageCreateClass* imagewindows = new LAMPImageCreateClass; + imagewindows->show(); + } + else { + return; + } +} + +void EchoTableEditWindow::on_actionCalibrationConst_triggered() +{ + +} + + + + +int EchoTableEditWindow::LockFileOpen(bool flag) +{ + this->FILEOPENLOCK = flag; + return 0; +} + +int EchoTableEditWindow::setCheckFieldContextHasEmptyCeilLOCK(bool flag) +{ + this->CheckFieldContextHasEmptyCeilLOCK = flag; + return 0; +} + +int EchoTableEditWindow::loadTablemode(std::shared_ptr mode) +{ + this->model = mode; + this->ui.tableView->setModel(this->model.get()); + if (this->model->rowCount() > 1e4) { + this->ui.tableView->horizontalHeader()->setSectionResizeMode(QHeaderView::Interactive); + } + return 0; +} + +int EchoTableEditWindow::setTableViewAutoSort(bool flag) +{ + this->ui.tableView->setSortingEnabled(flag); + return flag; +} + +int EchoTableEditWindow::initTableViewStatusBarControl() +{ + this->statusprogressBar = new QProgressBar(); + this->statusprogressBar->setRange(0, 100); // ÉèÖýø¶ÈÌõ·¶Î§ + this->statusprogressBar->setValue(0); // ÉèÖõ±Ç°½ø¶È + this->ui.statusbar->addPermanentWidget(this->statusprogressBar); // ÔÚ״̬À¸ÖÐÌí¼Ó½ø¶ÈÌõ + + return 0; +} + + + +int EchoTableEditWindow::OpenCSVDialog() +{ + if (this->FILEOPENLOCK) { + return 0; + } + else {} + QString tableFilepath = getOpenFilePath( + this, + QString::fromUtf8(u8"´ò¿ª±í¸ñÎļþ"), + QString::fromUtf8(u8"csvÎļþ (*.csv);;xlsÎļþ(*.xls)")); + + + this->ui.statusbar->showMessage(u8"ÕýÔÚ´ò¿ªÎļþ...."); + std::shared_ptr< FEKOResultCsvTableModel> tablemode = std::make_shared< FEKOResultCsvTableModel>(); + tablemode->loadCSVFilePath(tableFilepath); + this->loadTablemode(tablemode); + this->setTableViewAutoSort(true); + this->LockFileOpen(); + this->ui.statusbar->showMessage(u8"Îļþ´ò¿ª½áÊø"); + return -1; +} + + +int EchoTableEditWindow::SaveCSVDialog() +{ + this->model->saveFilePath(); + return 0; +} + +int EchoTableEditWindow::SaveAsDialog() +{ + QString filepath = getSaveFilePath( + this, + QString::fromUtf8(u8"Áí´æÎª"), + QString::fromUtf8(u8"csvÎļþ (*.csv)"));//¶à×éÀ©Õ¹ÃûÓÃË«·ÖºÅ";;"¸ô¿ª + this->model->saveAsFilePath(filepath); + return 0; +} diff --git a/src/WBCLFZSystemModule/EchoShowProcess/EchoTableEditWindow.h b/src/WBCLFZSystemModule/EchoShowProcess/EchoTableEditWindow.h new file mode 100644 index 0000000..75b611a --- /dev/null +++ b/src/WBCLFZSystemModule/EchoShowProcess/EchoTableEditWindow.h @@ -0,0 +1,96 @@ +#pragma once +#ifndef ECHOTABLEEDITWINDOW_H +#define ECHOTABLEEDITWINDOW_H +#include "AllHead.h" +#include +#include "ui_EchoTableEditWindow.h" +#include "TableProcess/TableViewModel.h" +#include +#include +#include +#include + + +/* +* ÃüÁî +***/ + + +/* +* ±í¸ñ±à¼­´°ÌåÇé¿ö·ÖÎö +****/ +class EchoTableEditWindow : public QMainWindow +{ + Q_OBJECT +public: + bool FILEOPENLOCK; + bool CheckFieldContextHasEmptyCeilLOCK; +private: + std::shared_ptr model; + QMenu* tableViewContextMenu; + QUndoStack* m_undoStack; + + /*²Ëµ¥*/ + QProgressBar* statusprogressBar; + + +public: + EchoTableEditWindow(QWidget* parent = nullptr); + ~EchoTableEditWindow(); + + int initTableViewStatusBarControl(); + int initTableViewContextMenu(); // ³õʼ»¯ÉÏÏÂÎIJ˵¥ + int LockFileOpen(bool flag=true); // Ëø¶¨Îļþ£¬²»ÔÊÐí½øÐÐÖØÐ´ò¿ªÎļþ + int setCheckFieldContextHasEmptyCeilLOCK(bool flag=true);// ÔÊÐíÆô¶¯µ±Ç°×Ö¶ÎÖдæÔÚ¿Õ¸ñ¼ì²é£¬-- Ìṩ¸øFEKOResult·ÖÎöʹÓà + int loadTablemode(std::shared_ptr mode); // ¼ÓÔØtableview ʹÓõÄmodel + int setTableViewAutoSort(bool flag); + int setDragDropOverwriteMode(bool flag); // ÊÇ·ñ½ûÓÃÁе÷»» + + int setTablCalibrationTab(bool flag); + +private: + Ui::EchoTableEditWindow ui; + int OpenCSVDialog(); + int SaveCSVDialog(); + int SaveAsDialog(); + + +public slots: + + + // tableview ÓÒ¼ü²Ëµ¥ + void ShowTableViewContextMenu(QPoint p); + void tableView_CopyAction(); + void tableView_PasteAction(); + void tableView_UndoAction(); + void tableView_RedoAction(); + void tableView_CheckFieldHasEmptyCeilAction(); + + void on_actionOpen_triggered(); + void on_actionSave_triggered(); + void on_actionSaveAs_triggered(); + + void on_actionEchoSplitExport_triggered(); // »Ø²¨Êý¾Ýµ¼³ö + void on_actionCalibrationConst_triggered(); // ¼ÆË㶨±ê³£Êý + + + + +protected: // ÖØÐ´º¯Êý + void closeEvent(QCloseEvent* event) override { + // ÔÚ´°¿Ú¹Ø±ÕʼþÖÐѯÎÊÓû§ÊÇ·ñ¹Ø±Õ + QMessageBox::StandardButton reply; + reply = QMessageBox::question(this, u8"Close", u8"Äú»Ø²¨Êý¾Ýµ¼³öÁËÂð£¿", QMessageBox::Yes | QMessageBox::No); + + if (reply == QMessageBox::Yes) { + // Óû§µã»÷ÁË"Yes"°´Å¥£¬¹Ø±Õ´°¿Ú + event->accept(); + } + else { + // Óû§µã»÷ÁË"No"°´Å¥£¬È¡Ïû¹Ø±Õ²Ù×÷ + event->ignore(); + } + }; +}; + +#endif // !ECHOTABLEEDITWINDOW_H \ No newline at end of file diff --git a/src/WBCLFZSystemModule/EchoShowProcess/EchoTableEditWindow.ui b/src/WBCLFZSystemModule/EchoShowProcess/EchoTableEditWindow.ui new file mode 100644 index 0000000..04f9a5a --- /dev/null +++ b/src/WBCLFZSystemModule/EchoShowProcess/EchoTableEditWindow.ui @@ -0,0 +1,285 @@ + + + EchoTableEditWindow + + + + 0 + 0 + 752 + 520 + + + + å›žæ³¢è¡¨æ ¼å¤„ç† + + + + + + + true + + + 0 + + + + 回波文件 + + + + + + + + + + 定标常数 + + + + + + + 0 + 25 + + + + + 16777215 + 25 + + + + 定标çƒå¤§å° + + + + + + + + 0 + 25 + + + + + 16777215 + 25 + + + + 0.001 + + + + + + + + + + + + + + + + toolBar + + + TopToolBarArea + + + false + + + + + + 0 + 0 + 752 + 26 + + + + + 文件 + + + + + + + + 回波工具 + + + + + + + + 定标工具 + + + + + + + + + + + 打开文件 + + + + + ä¿å­˜æ–‡ä»¶ + + + + + å¦å­˜ä¸º + + + + + 展示所有字段 + + + + + 添加字段 + + + + + 移除字段 + + + + + 编辑字段 + + + + + 创建新文件 + + + + + FEKO检查 + + + + + 森林目标属性表检查 + + + + + 农作物目标属性表检查 + + + + + è‰åœ°ç›®æ ‡å±žæ€§è¡¨æ£€æŸ¥ + + + + + 水体目标属性表检查 + + + + + 土壤目标属性表检查 + + + + + åŠ¨æ€æ°´ä½“目标属性表检查 + + + + + é“路目标属性表检查 + + + + + 人工目标属性表检查 + + + + + 几何校正场景属性表检查 + + + + + è¾å°„校正场景属性表检查 + + + + + 陆表场景属性表检查 + + + + + 水体场景属性表检查 + + + + + æ¤è¢«åœºæ™¯å±žæ€§è¡¨æ£€æŸ¥ + + + + + ExportThetaData + + + + + exportData + + + + + 回波切分导出 + + + + + å›žæ³¢å®šä½ + + + + + 计算定标常数 + + + + + 导入定标常数表 + + + + + + + OpenCSVDialog() + SaveCSVDialog() + SaveAsDialog() + ShowTableViewContextMenu(QPoint) + + diff --git a/src/WBCLFZSystemModule/EchoShowProcess/FEKOResultImport.cpp b/src/WBCLFZSystemModule/EchoShowProcess/FEKOResultImport.cpp new file mode 100644 index 0000000..07a2b86 --- /dev/null +++ b/src/WBCLFZSystemModule/EchoShowProcess/FEKOResultImport.cpp @@ -0,0 +1,427 @@ +#include "FEKOResultImport.h" +#include "BaseToolLib/FileOperator.h" +#include "SharedModuleLib/BaseUiTool.h" +#include "TaskXml/TaskTreeClass.h" +#include "EchoTableEditWindow.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "CMDExcuteApp.h" +#include +#include +#include + +FEKOResultImport::FEKOResultImport(QWidget* parent) +{ + //this->setAttribute(Qt::WidgetAttribute::WA_DeleteOnClose); + //this->setWindowModality(Qt::WindowModality::WindowModal); + this->ui.setupUi(this); + this->ListViewmodel = new QStandardItemModel(this); + this->ui.listView->setModel(this->ListViewmodel); + this->selectListViewmodel = new QStandardItemModel(this); + this->selectListViewmodel->clear(); + this->ListViewmodel->clear(); + this->p = nullptr; +} + +FEKOResultImport::~FEKOResultImport() +{ + if (nullptr == this->ListViewmodel || NULL == this->ListViewmodel) {} + else { + this->ListViewmodel->clear(); + delete this->ListViewmodel; + this->ListViewmodel = nullptr; + } + if (nullptr == this->selectListViewmodel || NULL == this->selectListViewmodel) {} + else { + this->selectListViewmodel->clear(); // ÊÍ·ÅËùÓжÔÏóµÄÄÚ´æ + delete this->selectListViewmodel; + this->selectListViewmodel = nullptr; + } + if (nullptr == this->p) {} + else { + this->p->close(); + //delete this->p; + this->p = nullptr; + } +} + +QString FEKOResultImport::getFEKOPreFileName() +{ + return this->FEKOPreFileName; + return QString(); +} + +int FEKOResultImport::setFEKOPreFileName(QString preFileName) +{ + this->FEKOPreFileName = preFileName; + return 0; +} + +int FEKOResultImport::setNearFieldNames(std::vector nearFieldNames) +{ + this->nearFieldNames.clear(); + this->nearFieldNames.shrink_to_fit(); + this->nearFieldNames = nearFieldNames; + return 0; +} + +std::vector FEKOResultImport::getNearFieldNames() +{ + return this->nearFieldNames; +} + +int FEKOResultImport::setFarFieldNames(std::vector farFieldNames) +{ + this->farFieldNames.clear(); + this->farFieldNames.shrink_to_fit(); + this->farFieldNames = farFieldNames; + return 0; +} + +std::vector FEKOResultImport::getFarFieldNames() +{ + return this->farFieldNames; +} + +int FEKOResultImport::setSelectFieldNames(std::vector SelectFieldNames, bool nearOrfar) +{ + if (nearOrfar) { + this->ui.NearradioButton->setChecked(1); + this->ui.FarradioButton->setChecked(0); + } + else { + this->ui.NearradioButton->setChecked(0); + this->ui.FarradioButton->setChecked(1); + } + // ÌÞ³ýÊý¾Ý + this->ListViewmodel->clear(); + this->selectListViewmodel->clear(); + // ÖØÐ·ÖÅäÊý¾Ý + for (int i = 0; i < SelectFieldNames.size(); i++) { + QStandardItem* item = new QStandardItem(QString::QString(SelectFieldNames[i])); + this->selectListViewmodel->appendRow(item); + } + std::unordered_set selectSET; + for (int i = 0; i < SelectFieldNames.size(); i++) { + selectSET.insert(SelectFieldNames[i]);// ²åÈë + } + if (nearOrfar) { + + for (int i = 0; i < this->nearFieldNames.size(); i++) + { + if (selectSET.insert(this->nearFieldNames[i]).second)//ÅжÏÊÇ·ñÄܲåÈë³É¹¦ + { + QStandardItem* item = new QStandardItem(QString::QString(this->nearFieldNames[i])); + this->ListViewmodel->appendRow(item); + } + else { + + } + } + + } + else { + + for (int i = 0; i < this->farFieldNames.size(); i++) + { + if (selectSET.insert(this->farFieldNames[i]).second)//ÅжÏÊÇ·ñÄܲåÈë³É¹¦ + { + QStandardItem* item = new QStandardItem(QString::QString(this->farFieldNames[i])); + this->ListViewmodel->appendRow(item); + } + else { + + } + } + } + this->ui.listView->setModel(this->ListViewmodel); + this->ui.SelectlistView->setModel(this->selectListViewmodel); + return 0; +} + +std::vector FEKOResultImport::getSelectFieldNames() +{ + std::vector result(0); + this->selectListViewmodel = (QStandardItemModel*)(this->ui.SelectlistView->model()); + int selectCount = this->ui.SelectlistView->model()->rowCount(); + for (int i = 0; i < selectCount; i++) { + QStandardItem* listItem = this->selectListViewmodel->item(i); + result.push_back(listItem->text()); + } + return result; +} + +int FEKOResultImport::setFEKOResultCSVPath(QString csvPath) +{ + this->FEKOResultCSVPath = csvPath; + return 0; +} + +QString FEKOResultImport::getFEKOResultCSVPath() +{ + return this->FEKOResultCSVPath; +} + +int FEKOResultImport::setFEKOPreProjectFolderPath(QString FolderPath) +{ + this->FEKOProjectFolderPath = FolderPath; + return 0; +} + +QString FEKOResultImport::getFEKOPreProjectFolderPath() +{ + return this->FEKOProjectFolderPath; +} + +int FEKOResultImport::initView() +{ + this->ui.FolderPathtextEdit->setText(this->FEKOProjectFolderPath); + this->ui.PreFileNametextEdit->setText(this->FEKOPreFileName); + this->ui.csvPathText->setText(this->FEKOResultCSVPath); + this->ui.NearradioButton->setChecked(this->getNearChecked()); + this->ui.FarradioButton->setChecked(this->getFarChecked()); + this->InitListView(); + return 0; +} + +int FEKOResultImport::InitListView() +{ + this->ListViewmodel->clear(); + this->selectListViewmodel->clear(); + if (this->ui.FarradioButton->isChecked()) { + for (int i = 0; i < this->farFieldNames.size(); i++) { + QStandardItem* item = new QStandardItem(QString::QString(this->farFieldNames[i])); + this->ListViewmodel->appendRow(item); + } + } + else { + this->ui.NearradioButton->setChecked(true); + for (int i = 0; i < this->nearFieldNames.size(); i++) { + QStandardItem* item = new QStandardItem(QString::QString(this->nearFieldNames[i])); + this->ListViewmodel->appendRow(item); + } + } + this->ui.listView->setModel(this->ListViewmodel); + this->ui.SelectlistView->setModel(this->selectListViewmodel); + + return 0; +} + +bool FEKOResultImport::getNearChecked() +{ + return this->ui.NearradioButton->isChecked(); + +} + +bool FEKOResultImport::getFarChecked() +{ + return this->ui.FarradioButton->isChecked(); + +} + +bool FEKOResultImport::getSaveSucessfully() +{ + return this->saveSucessfully; +} + +QString FEKOResultImport::getSaveCsvFilePath() +{ + return this->FEKOResultCSVPath; + +} + +// ´ò¿ªÎļþ£¬²¢Ñ°ÕÒpreÎļþ +int FEKOResultImport::OpenPrejectFolderPath() { + //´ò¿ªµ¥¸öÎļþ + QString prefileNamePath = getOpenFilePath( + this, + QString::fromUtf8(u8"Ñ¡Ôñ.pre Îļþ"), + QString::fromUtf8(u8"preÎļþ (*.pre)"));//¶à×éÀ©Õ¹ÃûÓÃË«·ÖºÅ";;"¸ô¿ª + this->FEKOProjectFolderPath = getParantFromPath(prefileNamePath); + this->FEKOPreFileName = getFileNameFromPath(prefileNamePath); + this->farFieldNames = getFilelist(this->FEKOProjectFolderPath, ".ffe"); + this->nearFieldNames = getFilelist(this->FEKOProjectFolderPath, ".efe"); + // ÐÞ¸ÄÏÔʾ + this->ListViewmodel->clear(); + this->ui.FolderPathtextEdit->setText(this->FEKOProjectFolderPath); + this->ui.PreFileNametextEdit->setText(this->FEKOPreFileName); + if (this->ui.FarradioButton->isChecked()) { + for (int i = 0; i < this->farFieldNames.size(); i++) { + QStandardItem* item = new QStandardItem(QString::QString(this->farFieldNames[i])); + this->ListViewmodel->appendRow(item); + } + } + else { + this->ui.NearradioButton->setChecked(true); + for (int i = 0; i < this->nearFieldNames.size(); i++) { + QStandardItem* item = new QStandardItem(QString::QString(this->nearFieldNames[i])); + this->ListViewmodel->appendRow(item); + } + } + + this->ui.listView->setModel(this->ListViewmodel); + qDebug()<<(u8"farField Number:"+QString::number(this->farFieldNames.size()) + "\n" + u8"NearField Number:" + QString::number(this->nearFieldNames.size()) + "\n"); + return -1; +} + + + +void FEKOResultImport::waitCMDExcute() +{ + qDebug() << u8"ת»»³ÌÐòÖ´ÐнáÊø"; + if (isExists(this->FEKOResultCSVPath)) { + messageLog(u8"FEKOResult ±£´æ³É¹¦\n·¾¶£º\t" + this->FEKOResultCSVPath, 1); + this->saveSucessfully = true; + this->p->close(); + delete p; + this->p = nullptr; + } + else { + messageLog(u8"FEKOResult ±£´æÊ§°Ü\n·¾¶£º\t" + this->FEKOResultCSVPath, 1); + this->saveSucessfully = false; + } + + // ´¥·¢½á¹ûʱ¼ä + qDebug() << u8"×¼±¸Ö´ÐÐת»»½á¹û±à¼­¹¦ÄÜ"; + emit this->callbackFekoResultImport(this); + +} + +int FEKOResultImport::closeWindows() +{ + this->close(); + return 0; +} + +int FEKOResultImport::NearRadioButtonSelect(bool selectTrue) +{ + this->ui.NearradioButton->setChecked(selectTrue); + this->ui.FarradioButton->setChecked(!selectTrue); + this->InitListView(); + return 0; +} + +int FEKOResultImport::FarRadioButtonSelect(bool selectsign) +{ + this->ui.NearradioButton->setChecked(!selectsign); + this->ui.FarradioButton->setChecked(selectsign); + this->InitListView(); + return 0; +} + +int FEKOResultImport::FEKOResultImportButtonClick() +{ + if (isExists(this->FEKOResultCSVPath)) { + QFile file(this->FEKOResultCSVPath); + if (!file.open(QIODevice::ReadWrite)) { + QMessageBox::information(nullptr, u8"Îļþ±»Õ¼ÓÃ", this->FEKOResultCSVPath); + return 2; + } + else { + file.close(); + removeFile(this->FEKOResultCSVPath); + } + + } + + QString csvpramarPath = this->FEKOResultCSVPath; + csvpramarPath= csvpramarPath.replace(this->FEKOResultCSVPath.size() - 4, 4, ".params"); + // »ñȡѡÔñÎļþ + std::vector selectfiles = this->getSelectFieldNames(); + QString parmas_text = this->FEKOResultCSVPath +"\n";// Êä³ö·¾¶ + for (int i = 0; i < selectfiles.size(); i++) { + parmas_text = parmas_text + selectfiles[i] + "\n"; + } + if (isExists(csvpramarPath)) { + removeFile(csvpramarPath); + } + + + writeUTF8StringFile(csvpramarPath, (parmas_text)); + // Æ´½ÓÃüÁîÐÐ + QString cmdtext = u8""; + if (this->ui.NearradioButton->isChecked()) { + cmdtext = cmdtext + u8"NearField2csvTool.exe"; + } + else { + cmdtext = cmdtext + u8"FarField2csvTool.exe"; + } + if (nullptr != this->p) { + this->p->close(); + delete this->p; + this->p = nullptr; + } + this->p = new CMDExcuteApp(); + QObject::connect(this->p, SIGNAL(callbackExcuteResult()), this, SLOT(waitCMDExcute())); + this->p->setAttribute(Qt::WA_DeleteOnClose);; + this->p->show(); + this->p->excuteCmd(cmdtext, csvpramarPath); + + return 0; +} + +int FEKOResultImport::AddFekoResultClick() +{ + QModelIndexList sourcelist=this->ui.listView->selectionModel()->selectedIndexes(); + std::vector deleteRowids(0); + for (int i = 0; i < sourcelist.count(); i++) { + deleteRowids.push_back(sourcelist[i].row()); + qDebug() << ("deletaRowids add :"+QString::number(sourcelist[i].row())+"\n"); + } + std::sort(deleteRowids.begin(), deleteRowids.end()); + for (int i = deleteRowids.size() - 1; i >= 0; i--) { + int select_Idx = deleteRowids[i]; + QList listItem = this->ListViewmodel->takeRow(select_Idx); + int nRightCount = this->selectListViewmodel->rowCount(); + this->selectListViewmodel->insertRow(nRightCount, listItem); + qDebug() << ("selectListViewmodel insertRow : "+ QString::number(select_Idx) +"-->" + QString::number(nRightCount) + "\n"); + } + + this->ui.listView->setModel(this->ListViewmodel); + this->ui.SelectlistView->setModel(this->selectListViewmodel); + return 0; +} + +int FEKOResultImport::DeleteFekoResultClick() +{ + + QModelIndexList sourcelist = this->ui.SelectlistView->selectionModel()->selectedIndexes(); + std::vector deleteRowids(0); + for (int i = 0; i < sourcelist.count(); i++) { + deleteRowids.push_back(sourcelist[i].row()); + } + std::sort(deleteRowids.begin(), deleteRowids.end()); + for (int i = deleteRowids.size() - 1; i >= 0; i--) { + int select_Idx = deleteRowids[i]; + QList listItem = this->selectListViewmodel->takeRow(select_Idx); + int nRightCount = this->ListViewmodel->rowCount(); + this->ListViewmodel->insertRow(nRightCount, listItem); + qDebug() << ("ListViewmodel insertRow : " + QString::number(select_Idx) + "-->" + QString::number(nRightCount) + "\n"); + } + this->ui.listView->setModel(this->ListViewmodel); + this->ui.SelectlistView->setModel(this->selectListViewmodel); + + return 0; +} + +int FEKOResultImport::SaveCsvFilePath() +{ + //´ò¿ªµ¥¸öÎļþ + QString csvfileNamePath = getSaveFilePath( + this, + QString::fromUtf8(u8"±£´æFEKO½âÎö½á¹û csv "), + QString::fromUtf8(u8"csvÎļþ (*.csv)"));//¶à×éÀ©Õ¹ÃûÓÃË«·ÖºÅ";;"¸ô¿ª + this->FEKOResultCSVPath = csvfileNamePath; + this->ui.csvPathText->setPlainText(csvfileNamePath); + return 0; +} diff --git a/src/WBCLFZSystemModule/EchoShowProcess/FEKOResultImport.h b/src/WBCLFZSystemModule/EchoShowProcess/FEKOResultImport.h new file mode 100644 index 0000000..3b75686 --- /dev/null +++ b/src/WBCLFZSystemModule/EchoShowProcess/FEKOResultImport.h @@ -0,0 +1,83 @@ +#pragma once + +#ifndef FEKORESULTIMPORT_H +#define FEKORESULTIMPORT_H +#include +#include +#include "ui_FEKOResultImport.h" +#include "TaskXml/TaskTreeClass.h" +#include "CMDExcuteApp.h" +#include +#include +#include +#include +#include +#include + + +class FEKOResultImport : public QMainWindow +{ + Q_OBJECT + + +public: + QString FEKOProjectFolderPath; + QString FEKOPreFileName; + std::vector nearFieldNames; + std::vector farFieldNames; + QString FEKOResultCSVPath; +private : + QStandardItemModel* ListViewmodel; + QStandardItemModel* selectListViewmodel; + bool saveSucessfully; + CMDExcuteApp* p; + +public: + FEKOResultImport(QWidget* parent = nullptr); + ~FEKOResultImport(); + + QString getFEKOPreFileName(); + int setFEKOPreFileName(QString preFileName); + + int setNearFieldNames(std::vector nearFieldNames); + std::vector getNearFieldNames(); + + int setFarFieldNames(std::vector farFieldNames); + std::vector getFarFieldNames(); + + int setSelectFieldNames(std::vector SelectFieldNames,bool nearOrfar); + std::vector getSelectFieldNames(); + + int setFEKOResultCSVPath(QString csvPath); + QString getFEKOResultCSVPath(); + + int setFEKOPreProjectFolderPath(QString FolderPath); + QString getFEKOPreProjectFolderPath(); + + int initView(); + int InitListView(); + bool getNearChecked(); + bool getFarChecked(); + bool getSaveSucessfully(); + QString getSaveCsvFilePath(); + +private: + Ui::FEKOResultImportWindow ui; + +signals: + void callbackFekoResultImport(FEKOResultImport* obj); + +public slots: // Ðźţ¨»òÕßʼþ£© + int OpenPrejectFolderPath(); + int closeWindows(); + int NearRadioButtonSelect(bool); + int FarRadioButtonSelect(bool); + int FEKOResultImportButtonClick(); // Ö´Ðе¼Èë + int AddFekoResultClick(); + int DeleteFekoResultClick(); + int SaveCsvFilePath(); + void waitCMDExcute(); // µ¼ÈëÍê³É +}; + + +#endif diff --git a/src/WBCLFZSystemModule/EchoShowProcess/FEKOResultImport.ui b/src/WBCLFZSystemModule/EchoShowProcess/FEKOResultImport.ui new file mode 100644 index 0000000..7e67281 --- /dev/null +++ b/src/WBCLFZSystemModule/EchoShowProcess/FEKOResultImport.ui @@ -0,0 +1,425 @@ + + + FEKOResultImportWindow + + + + 0 + 0 + 621 + 458 + + + + + 621 + 331 + + + + FEKO近场文件导入 + + + + + + + QLayout::SetDefaultConstraint + + + + + + 16777215 + 30 + + + + pre工程路径: + + + + + + + false + + + + 16777215 + 30 + + + + + + + + + 16777215 + 30 + + + + 打开 + + + + + + + + + + + + 16777215 + 30 + + + + FEKOç»“æžœè¾“å‡ºåœ°å€ + + + + + + + false + + + + 16777215 + 30 + + + + + + + + + 16777215 + 30 + + + + 选择ä¿å­˜æ–‡ä»¶ + + + + + + + + + + + + 16777215 + 30 + + + + .pre文件å + + + + + + + false + + + + 16777215 + 30 + + + + + + + + NearField + + + + + + + FarField + + + + + + + + + + + + 0 + 200 + + + + QAbstractItemView::MultiSelection + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + >> + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + << + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + 0 + 200 + + + + QAbstractItemView::MultiSelection + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + 导入FEKO结果 + + + + + + + + 16777215 + 30 + + + + å–æ¶ˆ + + + + + + + + + + + + OKpushButton + clicked() + FEKOResultImportWindow + OpenPrejectFolderPath() + + + 802 + 52 + + + 519 + 99 + + + + + NearradioButton + clicked(bool) + FEKOResultImportWindow + NearRadioButtonSelect(bool) + + + 728 + 175 + + + 471 + 112 + + + + + FarradioButton + clicked(bool) + FEKOResultImportWindow + FarRadioButtonSelect(bool) + + + 802 + 175 + + + 504 + 86 + + + + + ImportpushButton + clicked() + FEKOResultImportWindow + FEKOResultImportButtonClick() + + + 721 + 435 + + + 514 + 158 + + + + + deletepushButton + clicked() + FEKOResultImportWindow + DeleteFekoResultClick() + + + 443 + 354 + + + 507 + 274 + + + + + AddpushButton + clicked() + FEKOResultImportWindow + AddFekoResultClick() + + + 443 + 277 + + + 542 + 212 + + + + + CancelpushButton + clicked() + FEKOResultImportWindow + closeWindows() + + + 802 + 435 + + + 547 + 48 + + + + + pushButton + clicked() + FEKOResultImportWindow + SaveCsvFilePath() + + + 757 + 106 + + + 767 + 136 + + + + + + OpenPrejectFolderPath() + closeWindows() + NearRadioButtonSelect(bool) + FarRadioButtonSelect(bool) + FEKOResultImportButtonClick() + AddFekoResultClick() + DeleteFekoResultClick() + SaveCsvFilePath() + + diff --git a/src/WBCLFZSystemModule/HeaderSort.h b/src/WBCLFZSystemModule/HeaderSort.h new file mode 100644 index 0000000..7508f7e --- /dev/null +++ b/src/WBCLFZSystemModule/HeaderSort.h @@ -0,0 +1,4 @@ +#pragma once +#include "AllHead.h" +// ÕâÀォϵͳ»·¾³ÖеÄÎļþĬÈÏÏȵ¼Èë +#include \ No newline at end of file diff --git a/src/WBCLFZSystemModule/ImageShowDialogClass.cpp b/src/WBCLFZSystemModule/ImageShowDialogClass.cpp new file mode 100644 index 0000000..6f2f169 --- /dev/null +++ b/src/WBCLFZSystemModule/ImageShowDialogClass.cpp @@ -0,0 +1,367 @@ +#include "ImageShowDialogClass.h" + +ImageShowDialogClass ::ImageShowDialogClass(QWidget *parent) + : QDialog(parent) +{ + ui.setupUi(this); + ui.m_plot->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom); + connect(this->ui.m_plot, SIGNAL(mouseMove(QMouseEvent*)), this, SLOT(updateCursor(QMouseEvent*))); + this->graphclass=LAMPDATASHOWCLASS::NOWINDOWS; + + this->menubar = new QMenuBar(this); + QMenu* windowsMenu = this->menubar->addMenu(u8"Êý¾Ý"); + QAction* action_cursor_enable = windowsMenu->addAction(u8"´ò¿ªÓαê"); + QObject::connect(action_cursor_enable,SIGNAL(triggered()),this,SLOT(on_action_cursor_enable_trigged())); + this->tracer=new QCPItemTracer(this->ui.m_plot); + this->m_plot = ui.m_plot; + + this->desCursor = nullptr; + this->HlineCursor = nullptr; + this->VlineCursor = nullptr; + + this->desCursorflag=false; + this->HlineCursorflag=false; + this->VlineCursorflag = false; + + this->statusbar=new QStatusBar(this); + this->statusbar->setMaximumHeight(20); + this->statusbar->setMinimumHeight(20); + + ui.verticalLayout->setMenuBar(this->menubar); + ui.verticalLayout->addWidget(this->statusbar); + this->setLayout(ui.verticalLayout); +} + + +ImageShowDialogClass::~ImageShowDialogClass() +{} + + +void ImageShowDialogClass::on_action_cursor_enable_trigged() +{ + this->desCursor = new ImageShowCursorDesClass(); + + + QObject::connect(this->desCursor, SIGNAL(windowsClose()), this, SLOT(on_action_descursor_close_trigged())); + + + this->desCursorflag = true; + for (size_t i = 0; i < this->getGraphCount(); i++) { + if (this->getGraphClass(i) == LAMPDATASHOWCLASS::LAMPColorMap) { + this->HlineCursorflag = true; + this->VlineCursorflag = true; + } + } + + //ÏÂÃæµÄ´úÂë¾ÍÊÇÉèÖÃÓαêµÄÍâ¹Û + this->setMouseTracking(true); + tracer->setInterpolating(false);//½ûÓòåÖµ + tracer->setPen(QPen(Qt::DashLine));//ÐéÏßÓαê + tracer->setStyle(QCPItemTracer::tsPlus);//ÓαêÑùʽ£ºÊ®×ÖÐÇ¡¢Ô²È¦¡¢·½¿ò + tracer->setBrush(Qt::red);//ÓαêÑÕÉ« + + if (this->graphclass == LAMPDATASHOWCLASS::LAMPColorMap) { + this->HlineCursor = new ImageShowCursorLineClass(); + this->VlineCursor = new ImageShowCursorLineClass(); + QObject::connect(this->HlineCursor, SIGNAL(windowsClose()), this, SLOT(on_action_Hlinecursor_close_trigged())); + QObject::connect(this->VlineCursor, SIGNAL(windowsClose()), this, SLOT(on_action_VVlinecursor_close_trigged())); + QObject::connect(this->ui.m_plot->xAxis, SIGNAL(rangeChanged(QCPRange)), this->HlineCursor, SLOT(xAxisRangeChanged(QCPRange))); + QObject::connect(this->ui.m_plot->yAxis, SIGNAL(rangeChanged(QCPRange)), this->HlineCursor, SLOT(xAxisRangeChanged(QCPRange))); + this->HlineCursor->show(); + this->VlineCursor->show(); + } + this->desCursor->show(); +} + + + +void ImageShowDialogClass::load_double_MatrixX_data(Eigen::MatrixXd data, QString name) +{ + + int nx = data.rows(); // ÐÐÊý + int ny = data.cols(); // ÁÐÊý + // ´´½¨ Color Map + QCPColorMap* colorMap = new QCPColorMap(ui.m_plot->xAxis, ui.m_plot->yAxis); + colorMap->data()->setSize(nx, ny); // ÉèÖà Color Map µÄ´óС + colorMap->data()->setRange(QCPRange(0, nx), QCPRange(0, ny)); // ÉèÖÃ×ø±êÖáµÄ·¶Î§ + + // Ìî³äÊý¾Ý + for (int xIndex = 0; xIndex < nx; ++xIndex) { + for (int yIndex = 0; yIndex < ny; ++yIndex) { + double magnitude = data(xIndex, yIndex); // »òÕßʹÓà std::arg() »ñÈ¡Ïàλ + colorMap->data()->setCell(xIndex, yIndex, magnitude); + } + } + + colorMap->setGradient(QCPColorGradient::gpJet); + colorMap->rescaleDataRange(true); + ui.m_plot->rescaleAxes(); + ui.m_plot->replot(); + +} + +void ImageShowDialogClass::load_double_MatrixX_data(Eigen::MatrixXd X, Eigen::MatrixXd Y, Eigen::MatrixXd data, QString name) +{ + int nx = data.cols(); // ÐÐÊý + int ny = data.rows(); // ÁÐÊý + // ´´½¨ Color Map + ui.m_plot->xAxis->setRange(X(0, 0), X(0, nx - 1)); + ui.m_plot->yAxis->setRange(Y(0, 0), Y(ny - 1, 0)); + QCPColorMap* colorMap = new QCPColorMap(ui.m_plot->xAxis, ui.m_plot->yAxis); + colorMap->data()->setSize(ny, nx); // ÉèÖà Color Map µÄ´óС + colorMap->data()->setRange(QCPRange(X(0,0), X(0,nx-1)), QCPRange(Y(0,0),Y(ny-1,0))); // ÉèÖÃ×ø±êÖáµÄ·¶Î§ + // Ìî³äÊý¾Ý + for (int xIndex = 0; xIndex < nx; ++xIndex) { + for (int yIndex = 0; yIndex < ny; ++yIndex) { + double magnitude = data(yIndex, xIndex); // »òÕßʹÓà std::arg() »ñÈ¡Ïàλ + colorMap->data()->setCell(yIndex, xIndex, magnitude); + } + } + + colorMap->setGradient(QCPColorGradient::gpJet); + colorMap->rescaleDataRange(true); + ui.m_plot->rescaleAxes(); + ui.m_plot->replot(); +} + +void ImageShowDialogClass::remove_Data(QString name) +{ + for(size_t i=0;im_plot->graphCount();i++){ + if (this->m_plot->graph(i)->name() == name) { + this->m_plot->removeGraph(i); + this->m_plot->replot(); + return; + } + } +} + + + +LAMPDATASHOWCLASS ImageShowDialogClass::getGraphClass(size_t i) +{ + if (this->m_plot->graphCount() == 0 || i > this->m_plot->graphCount()) + { + return LAMPDATASHOWCLASS::NOWINDOWS; + } + QCPAbstractPlottable* plottable = this->ui.m_plot->plottable(i); + if (dynamic_cast(plottable)) { + return LAMPDATASHOWCLASS::LAMPGraph; + } + else if (dynamic_cast(plottable)) { + return LAMPDATASHOWCLASS::LAMPScatterStyle; + } + else if (dynamic_cast(plottable)) { + return LAMPDATASHOWCLASS::LAMPColorMap; + } + else { + return LAMPDATASHOWCLASS::NOWINDOWS; + } +} + +size_t ImageShowDialogClass::getGraphCount() +{ + return this->m_plot->graphCount(); +} + +void ImageShowDialogClass::on_action_descursor_close_trigged() +{ + this->desCursorflag = false; +} + +void ImageShowDialogClass::on_action_Hlinecursor_close_trigged() +{ + this->HlineCursorflag = false; +} + +void ImageShowDialogClass::on_action_VVlinecursor_close_trigged() +{ + this->VlineCursorflag = false; +} + +void ImageShowDialogClass::updateCursor(QMouseEvent *event) +{ + + + if (this->desCursorflag &&this->HlineCursorflag &&this->VlineCursorflag) { + //ÏÂÃæµÄ´úÂë¾ÍÊÇÉèÖÃÓαêµÄÍâ¹Û + this->setMouseTracking(false); + } + else { + // ×¼±¸»ñÈ¡Êý¾Ý + QPoint pos = event->pos(); + double x=this->m_plot->xAxis->pixelToCoord(pos.x()); // ½«Êó±êλÖÃÓ³É䵽ͼ±í×ø±êϵÖÐ + double y = this->m_plot->yAxis->pixelToCoord(pos.y()); + this->statusbar->showMessage(u8"X: "+QString::number(x,'f', 6)+" y: "+QString::number(y, 'f', 6)); + + + + if (this->desCursorflag) { + if (this->graphclass == LAMPDATASHOWCLASS::LAMPColorMap) { + QCPColorMap* colorMap = dynamic_cast(this->ui.m_plot->plottable(0)); + double dataValue = colorMap->data()->data(x, y); + this->desCursor->updateCursorContent(u8"X: " + QString::number(x, 'f', 6) + " y: " + QString::number(y, 'f', 6) +u8"\n" +u8"DataValue: "+QString::number(dataValue)); + } + else if (this->graphclass == LAMPDATASHOWCLASS::LAMPGraph) { + + } + else if (this->graphclass == LAMPDATASHOWCLASS::LAMPScatterStyle) { + + } + else { + this->desCursor->updateCursorContent(u8"ÎÞ·¨Ê¶±ðͼÏñÀàÐÍ"); + } + } + if (this->HlineCursorflag) { + + + } + if (this->VlineCursorflag) { + + } + } +} + + +ImageShowCursorDesClass::ImageShowCursorDesClass(QWidget* parent) +{ + // ´´½¨ QLabel + label = new QLabel(this); + + // ´´½¨²¼¾Ö + QVBoxLayout* layout = new QVBoxLayout(this); + layout->addWidget(label); + + // ÉèÖò¼¾Ö + setLayout(layout); + +} + +ImageShowCursorDesClass::~ImageShowCursorDesClass() +{ +} + +void ImageShowCursorDesClass::closeEvent(QCloseEvent* event) +{ + QDialog::closeEvent(event); +} + + +void ImageShowCursorDesClass::updateCursorContent(QString content) { + + this->label->setText(content); + +} + + +ImageShowCursorLineClass::ImageShowCursorLineClass(QWidget* parent) +{ + this->menubar = new QMenuBar(this); + //QMenu* toolMenu = this->menubar->addMenu(u8"¹¤¾ß"); + //QAction* action_add_compare_line = toolMenu->addAction(u8"Ìí¼Ó¶Ô±ÈÊý¾Ý"); + //QObject::connect(action_add_compare_line, SIGNAL(triggered()), this, SLOT(load_new_compare_line())); + + this->tracerEnable = false; + this->tracer = nullptr; + this->tracerXText = nullptr; + this->tracerYText = nullptr; + // ´´½¨ QLabel + this->customPlot = new QCustomPlot(this); + + // ´´½¨²¼¾Ö + QVBoxLayout* layout = new QVBoxLayout(this); + layout->addWidget(this->customPlot); + + // ÉèÖò¼¾Ö + setLayout(layout); + this->tracer = new QCPItemTracer(this->customPlot); + this->tracerYText = new QCPItemText(this->customPlot); + this->tracerXText = new QCPItemText(this->customPlot); + QObject::connect(this->customPlot, SIGNAL(mouseMove(QMouseEvent*)), this, SLOT(updateCursor(QMouseEvent*))); + this->customPlot->legend->setVisible(true); +} + +ImageShowCursorLineClass::~ImageShowCursorLineClass() +{ +} + +void ImageShowCursorLineClass::loadPlotLine(QVector xs, QVector dataValues,QString Name) +{ + if (dataValues.count() == 0) { return; } + QCPGraph* graph = this->customPlot->addGraph(); + graph->setName(Name); + graph->setData(xs, dataValues); + double min_y = dataValues[0]; + double max_y = dataValues[0]; + for (size_t i = 0; i < dataValues.count(); i++) { + min_y = min_y > dataValues[i] ? dataValues[i] : min_y; + max_y = max_y < dataValues[i] ? dataValues[i] : max_y; + } + customPlot->yAxis->setRange(min_y, max_y); + customPlot->legend->setVisible(true); + customPlot->replot(); + + + //ÏÂÃæµÄ´úÂë¾ÍÊÇÉèÖÃÓαêµÄÍâ¹Û + this->setMouseTracking(true); + tracer->setInterpolating(false);//½ûÓòåÖµ + tracer->setPen(QPen(Qt::DashLine));//ÐéÏßÓαê + tracer->setStyle(QCPItemTracer::tsPlus);//ÓαêÑùʽ£ºÊ®×ÖÐÇ¡¢Ô²È¦¡¢·½¿ò + tracer->setBrush(Qt::red);//ÓαêÑÕÉ« + tracer->setGraph(graph); // È·±£Óαê¸úËæ + this->m_graphMap.insert(Name, graph); + this->TrackName = Name; +} + +void ImageShowCursorLineClass::updateCursor(QMouseEvent* event) +{ + if (tracerEnable)//ÓαêʹÄÜ + { + + double x = this->customPlot->xAxis->pixelToCoord(event->pos().x());//Êó±êµãµÄÏñËØ×ø±êתplot×ø±ê + + tracer->setGraphKey(x);//ÉèÖÃÓαêµÄXÖµ£¨Õâ¾ÍÊÇÓαêËæ¶¯µÄ¹Ø¼ü´úÂ룩 + double traceX = tracer->position->key(); + double traceY = tracer->position->value(); + + tracerXText->setText(QDateTime::fromMSecsSinceEpoch(traceX * 1000.0).toString("hh:mm:ss.zzz"));//ÓαêÎı¾¿ò£¬Ö¸Ê¾ÓαêµÄXÖµ + tracerYText->setText(QString::number(traceY));//ÓαêÎı¾¿ò£¬Ö¸Ê¾ÓαêµÄYÖµ + + ////¼ÆËãÓαêXÖµ¶ÔÓ¦µÄËùÓÐÇúÏßµÄYÖµ + //for (int i = 0; i < this->customPlot->graphCount(); i++) + //{ + // QCPGraph* graph = dynamic_cast(this->customPlot->plottable(i)); + // //ËÑË÷×ó±ßÀëtraceX×î½üµÄkey¶ÔÓ¦µÄµã£¬ÏêÇé²Î¿¼findBeginº¯ÊýµÄ°ïÖú + // QCPDataContainer::const_iterator coorPoint = graph->data().data()->findBegin(traceX, true);//true´ú±íÏò×óËÑË÷ + // qDebug() << QString("graph%1¶ÔÓ¦µÄYÖµÊÇ").arg(i) << coorPoint->value; + //} + } + + +} + +void ImageShowCursorLineClass::closeEvent(QCloseEvent* event) +{ + QDialog::closeEvent(event); +} + +void ImageShowCursorLineClass::xAxisRangeChanged(QCPRange range) { + this->customPlot->xAxis->setRange(range); + customPlot->replot(); +} + +void ImageShowCursorLineClass::yAxisRangeChanged(QCPRange range) { + this->customPlot->yAxis->setRange(range); + customPlot->replot(); +} + +void ImageShowCursorLineClass::on_SwichTracerGraph_Name() +{ +} + +void ImageShowCursorLineClass::load_new_compare_line() +{ + + + +} + diff --git a/src/WBCLFZSystemModule/ImageShowDialogClass.h b/src/WBCLFZSystemModule/ImageShowDialogClass.h new file mode 100644 index 0000000..26059e4 --- /dev/null +++ b/src/WBCLFZSystemModule/ImageShowDialogClass.h @@ -0,0 +1,139 @@ +#pragma once +#ifndef IMAGESHOWDIALOGCLASS_H +#define IMAGESHOWDIALOGCLASS_H +#include "AllHead.h" +#include +#include "TaskXml/TaskTreeClass.h" +#include "ui_ImageShowDialogClass.h" + +//=========================== +// ¶¨ÒåÐèÒª»æÖƵÄͼÏñµÄÀàÐÍ +//=========================== +enum LAMPDATASHOWCLASS { + LAMPGraph, + LAMPColorMap, + LAMPScatterStyle, + NOWINDOWS +}; + + + + + + +//=========================== +// ¹¹½¨ÓαêÀàÐÍ +// 1. µ¥´¿µÄÃèÊöÓα꣬Ö÷ÒªÓÃÀ´Õ¹Ê¾×ø±ê£¬»¹Óе±Ç°Êý¾ÝÐÅÏ¢ +// 2. ÇøÓòÐÔÃèÊöÓα꣬ͨ¹ýÏߣ¬µÈÓÃÀ´Õ¹Ê¾Ä³Ò»¸öÇøÓòµÄÐÅÏ¢ +//=========================== +class ImageShowCursorDesClass : public QDialog +{ + Q_OBJECT +public: + QLabel* label; + + +public: + ImageShowCursorDesClass(QWidget* parent = nullptr); + ~ImageShowCursorDesClass(); +public slots: + void updateCursorContent(QString content); +signals: + bool windowsClose(); +protected: + void closeEvent(QCloseEvent* event) override; + +}; + + +class ImageShowCursorLineClass :public QDialog { + Q_OBJECT +public: + QMenuBar* menubar; + QMenu* DataList; + QMenu* RemoveList; + + QCustomPlot* customPlot; + bool tracerEnable; + + QCPItemTracer* tracer; //Óαê + QCPItemText* tracerYText; //ͼ±ê±êÇ© + QCPItemText* tracerXText; //Óαê±êÇ© + QMap m_graphMap; + QMap data_action_map; + QString TrackName; + +public: + ImageShowCursorLineClass(QWidget* parent = nullptr); + ~ImageShowCursorLineClass(); + +public: + void loadPlotLine(QVector xs, QVector dataValues, QString Name); + void updateCursor(QMouseEvent* event); + + +public slots: + void xAxisRangeChanged(QCPRange); + void yAxisRangeChanged(QCPRange); + void on_SwichTracerGraph_Name(); + void load_new_compare_line(); + +signals: + bool windowsClose(); +protected: + void closeEvent(QCloseEvent* event) override; +}; + + + + +//=========================== +// ¹¹½¨Êý¾Ýչʾ´°¿Ú +// 1. µ¥´¿µÄÃèÊöÓα꣬Ö÷ÒªÓÃÀ´Õ¹Ê¾×ø±ê£¬»¹Óе±Ç°Êý¾ÝÐÅÏ¢ +// 2. ÇøÓòÐÔÃèÊöÓα꣬ͨ¹ýÏߣ¬µÈÓÃÀ´Õ¹Ê¾Ä³Ò»¸öÇøÓòµÄÐÅÏ¢ +//=========================== +class ImageShowDialogClass : public QDialog +{ + Q_OBJECT +private: + LAMPDATASHOWCLASS graphclass; +public: + QMenuBar* menubar; + QStatusBar* statusbar; + ImageShowCursorDesClass* desCursor; // ÃèÊöÓαê + ImageShowCursorLineClass* HlineCursor;// H Óαê + ImageShowCursorLineClass* VlineCursor;// V Óαê + + bool desCursorflag; + bool HlineCursorflag; + bool VlineCursorflag; + + QCustomPlot* m_plot; + QCPItemTracer* tracer; //Óαê + +public: + QMap m_graphMap; +public: + ImageShowDialogClass(QWidget *parent = nullptr); + ~ImageShowDialogClass(); +public: + void load_double_MatrixX_data(Eigen::MatrixXd data, QString name); + void load_double_MatrixX_data(Eigen::MatrixXd X,Eigen::MatrixXd Y,Eigen::MatrixXd data, QString name); + void remove_Data( QString name); + + LAMPDATASHOWCLASS getGraphClass(size_t i = 0); + size_t getGraphCount(); +private: + Ui::ImageShowDialogClass ui; + +public slots: + void updateCursor(QMouseEvent* event); +public slots: // cursor + void on_action_cursor_enable_trigged(); + void on_action_descursor_close_trigged(); + void on_action_Hlinecursor_close_trigged(); + void on_action_VVlinecursor_close_trigged(); +}; + + +#endif \ No newline at end of file diff --git a/src/WBCLFZSystemModule/ImageShowDialogClass.ui b/src/WBCLFZSystemModule/ImageShowDialogClass.ui new file mode 100644 index 0000000..271d5bc --- /dev/null +++ b/src/WBCLFZSystemModule/ImageShowDialogClass.ui @@ -0,0 +1,33 @@ + + + ImageShowDialogClass + + + + 0 + 0 + 600 + 400 + + + + 夿•°å±•示 + + + + + + + + + + + QCustomPlot + QWidget +
qcustomplot.h
+ 1 +
+
+ + +
diff --git a/src/WBCLFZSystemModule/LAMPDataShowClass.cpp b/src/WBCLFZSystemModule/LAMPDataShowClass.cpp new file mode 100644 index 0000000..36d4f22 --- /dev/null +++ b/src/WBCLFZSystemModule/LAMPDataShowClass.cpp @@ -0,0 +1,111 @@ +#include "LAMPDataShowClass.h" + +LAMPDataShowClass::LAMPDataShowClass(QWidget *parent) + : QMainWindow(parent) +{ + ui.setupUi(this); + + // Ìí¼Ó²Ëµ¥Ïî + QMenu* FileOpenMenu = this->ui.menuFile->addMenu(u8"´ò¿ª"); + QAction* action_openfile_tiff = FileOpenMenu->addAction(u8"tiffÎļþ"); // Ìí¼Ó²Ëµ¥Ïî + QObject::connect(action_openfile_tiff, SIGNAL(triggered()), this, SLOT(on_action_openfile_tiff_triggered())); + + QMenu* ComplexFileOpenMenu = this->ui.menuFile->addMenu(u8"´ò¿ª¸´ÊýÊý¾Ý"); + QAction* action_openfile_tiff_complex = ComplexFileOpenMenu->addAction(u8"tiffÎļþ"); // Ìí¼Ó²Ëµ¥Ïî + QObject::connect(action_openfile_tiff_complex, SIGNAL(triggered()), this, SLOT(on_action_openfile_tiff_complex_triggered())); + QAction* action_openfile_envi_complex = ComplexFileOpenMenu->addAction(u8"enviÎļþ"); // Ìí¼Ó²Ëµ¥Ïî + QObject::connect(action_openfile_envi_complex, SIGNAL(triggered()), this, SLOT(on_action_openfile_envi_complex_triggered())); + + this->setContextMenuPolicy(Qt::CustomContextMenu); + + this->ui.listWidgetContent->setContextMenuPolicy(Qt::CustomContextMenu); +} + +LAMPDataShowClass::~LAMPDataShowClass() +{} + + +void LAMPDataShowClass::add_DataTree(TaskNode* node) { + + QListWidgetItem* itemtemp = new QListWidgetItem(this->ui.listWidgetContent); + itemtemp->setSizeHint(node->sizeHint()); + this->ui.listWidgetContent->setItemWidget(itemtemp, node); + this->ui.listWidgetContent->addItem(itemtemp); + +} +void ShowComplexMatrixPlot(QCustomPlot* customPlot, const Eigen::MatrixXcd& complexMatrix) { + int nx = complexMatrix.rows(); // ÐÐÊý + int ny = complexMatrix.cols(); // ÁÐÊý + // ´´½¨ Color Map + QCPColorMap* colorMap = new QCPColorMap(customPlot->xAxis, customPlot->yAxis); + colorMap->data()->setSize(nx, ny); // ÉèÖà Color Map µÄ´óС + colorMap->data()->setRange(QCPRange(0, nx), QCPRange(0, ny)); // ÉèÖÃ×ø±êÖáµÄ·¶Î§ + + // Ìî³äÊý¾Ý + for (int xIndex = 0; xIndex < nx; ++xIndex) { + for (int yIndex = 0; yIndex < ny; ++yIndex) { + double magnitude = std::abs(complexMatrix(xIndex, yIndex)); // »òÕßʹÓà std::arg() »ñÈ¡Ïàλ + colorMap->data()->setCell(xIndex, yIndex, magnitude); + } + } + + colorMap->setGradient(QCPColorGradient::gpJet); + colorMap->rescaleDataRange(true); + customPlot->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom); + customPlot->rescaleAxes(); + customPlot->replot(); +} + +void LAMPDataShowClass::on_action_openfile_tiff_triggered() +{ +} + +void LAMPDataShowClass::on_action_openfile_envi_triggered() { + + +} + +void LAMPDataShowClass::on_action_openfile_tiff_complex_triggered() +{ + ComplexDataShowNode* node = new ComplexDataShowNode(); + node->bangdindWindows(this); + node->TaskXmlPath = getOpenFilePath(nullptr, u8"´ò¿ª¸´ÊýÊý¾Ý", u8" tiffÎļþ(*.tiff ,*.tif)"); + if (!isExists(node->TaskXmlPath)) { + return; + } + else {} + node->OpenData(node->TaskXmlPath); + this->add_DataTree(node); + node->ExcuteTask(); +} + +void LAMPDataShowClass::on_action_openfile_envi_complex_triggered() +{ + ComplexDataShowNode* node = new ComplexDataShowNode(); + node->bangdindWindows(this); + node->TaskXmlPath = getOpenFilePath(nullptr, u8"´ò¿ª¸´ÊýÊý¾Ý", u8"enviÎļþ(*.dat ) "); + if (!isExists(node->TaskXmlPath)) { + return; + } + else {} + node->OpenData(node->TaskXmlPath); + this->add_DataTree(node); + node->ExcuteTask(); +} + +void LAMPDataShowClass::load_complex_data(QString path) +{ + ComplexDataShowNode* node = new ComplexDataShowNode(); + node->bangdindWindows(this); + node->TaskXmlPath = path; + if (!isExists(node->TaskXmlPath)) { + return; + } + else {} + node->OpenData(node->TaskXmlPath); + this->add_DataTree(node); + node->ExcuteTask(); +} + + + diff --git a/src/WBCLFZSystemModule/LAMPDataShowClass.h b/src/WBCLFZSystemModule/LAMPDataShowClass.h new file mode 100644 index 0000000..0f40c0a --- /dev/null +++ b/src/WBCLFZSystemModule/LAMPDataShowClass.h @@ -0,0 +1,50 @@ +#pragma once + +#ifndef LAMPDATASHOWClASS_H +#define LAMPDATASHOWClASS_H + +#include "AllHead.h" +#include +#include "ui_LAMPDataShowClass.h" +#include "TaskXml/TaskTreeClass.h" +#include "TaskNodeList.h" +#include "ImageShowDialogClass.h" + + +class LAMPDataShowClass : public QMainWindow +{ + Q_OBJECT + +public: + LAMPDataShowClass(QWidget *parent = nullptr); + ~LAMPDataShowClass(); + +public: + QList Dialog; + + + +public slots: // ²Ëµ¥action ²Ûº¯Êý + void add_DataTree(TaskNode* node); + void on_action_openfile_tiff_triggered(); + void on_action_openfile_envi_triggered(); + void on_action_openfile_tiff_complex_triggered(); + void on_action_openfile_envi_complex_triggered(); + +public: + void load_complex_data(QString path); +private: + Ui::LAMPDataShowClassClass ui; +}; + + +/////////////////////////////////////////////////////// +// »ù´¡º¯Êý +/////////////////////////////////////////////////////// +void ShowComplexMatrixPlot(QCustomPlot* customPlot, const Eigen::MatrixXcd& complexMatrix); + + + + + +#endif \ No newline at end of file diff --git a/src/WBCLFZSystemModule/LAMPDataShowClass.ui b/src/WBCLFZSystemModule/LAMPDataShowClass.ui new file mode 100644 index 0000000..7c39ae8 --- /dev/null +++ b/src/WBCLFZSystemModule/LAMPDataShowClass.ui @@ -0,0 +1,57 @@ + + + LAMPDataShowClassClass + + + + 0 + 0 + 285 + 426 + + + + æ•°æ®å±•ç¤ºçª—å£ + + + + + + + + + + + + 0 + 0 + 285 + 22 + + + + + 文件 + + + + + + + TopToolBarArea + + + false + + + + + + Open + + + + + + + diff --git a/src/WBCLFZSystemModule/LAMPImageCreateClass.cpp b/src/WBCLFZSystemModule/LAMPImageCreateClass.cpp new file mode 100644 index 0000000..73cbda6 --- /dev/null +++ b/src/WBCLFZSystemModule/LAMPImageCreateClass.cpp @@ -0,0 +1,196 @@ +#include "LAMPImageCreateClass.h" + +LAMPImageCreateClass::LAMPImageCreateClass(QWidget *parent) + : QDialog(parent) +{ + ui.setupUi(this); + this->simulationparams = std::make_shared(); + + this->ui.comboBox_ImageMode->addItem(FEKOBase::FEKOImageModeenumToString(FEKOBase::FEKOImageMode::Strip)); + this->ui.comboBox_ImageMode->addItem(FEKOBase::FEKOImageModeenumToString(FEKOBase::FEKOImageMode::Scane)); + this->ui.comboBox_ImageMode->addItem(FEKOBase::FEKOImageModeenumToString(FEKOBase::FEKOImageMode::ISAR)); + this->ui.comboBox_ImageMode->addItem(FEKOBase::FEKOImageModeenumToString(FEKOBase::FEKOImageMode::CircleSAR)); + + + + // ÏÞÖÆlineeditÊäÈëΪÊýÖµ + QDoubleValidator* doubleValidator = new QDoubleValidator(); + this->ui.lineEdit_minX->setValidator(doubleValidator); + this->ui.lineEdit__maxX->setValidator(doubleValidator); + this->ui.lineEdit__minY->setValidator(doubleValidator); + this->ui.lineEdit__maxY->setValidator(doubleValidator); + this->ui.lineEdit_planeZ->setValidator(doubleValidator); + QIntValidator* intValidator = new QIntValidator(1,100000000000000); + this->ui.lineEdit_height->setValidator(intValidator); + this->ui.lineEdit_width->setValidator(intValidator); + + + this->ui.lineEdit_minX->setText("-1.0"); + this->ui.lineEdit__maxX->setText("1.0"); + this->ui.lineEdit__minY->setText("-1.0"); + this->ui.lineEdit__maxY->setText("1.0"); + this->ui.lineEdit_planeZ->setText("0"); + this->ui.lineEdit_height->setText("101"); + this->ui.lineEdit_width->setText("101"); + this->ui.checkBoxTheta->setChecked(true); + this->ui.checkBox_phi->setChecked(true); +} + +LAMPImageCreateClass::~LAMPImageCreateClass() +{} + +Q_INVOKABLE FEKOBase::FEKOImageSettingParams LAMPImageCreateClass::getFEKOImageSettingParams() +{ + + FEKOBase::FEKOImageSettingParams result; + result.min_x = this->ui.lineEdit_minX->text().toDouble(); + result.max_x = this->ui.lineEdit__maxX->text().toDouble(); + result.min_y = this->ui.lineEdit__minY->text().toDouble(); + result.max_y = this->ui.lineEdit__maxY->text().toDouble(); + result.plane_z = this->ui.lineEdit_planeZ->text().toDouble(); + result.ImageHeight = this->ui.lineEdit_height->text().toDouble(); + result.ImageWidth = this->ui.lineEdit_width->text().toDouble(); + + return Q_INVOKABLE result; +} + +void LAMPImageCreateClass::on_pushButton_theta_clicked() +{ + QString thetaechopath = getOpenFilePath(this, u8"´ò¿ªtheta»Ø²¨Îļþ", u8"theta Files (*.theta)"); + this->ui.lineEdit_thetaechopath->setText(thetaechopath); +} + +void LAMPImageCreateClass::on_pushButton_phi_clicked() +{ + QString phiechopath = getOpenFilePath(this, u8"´ò¿ªphi»Ø²¨Îļþ", u8"theta Files (*.phi)"); + this->ui.lineEdit_phiechopath->setText(phiechopath); +} + +void LAMPImageCreateClass::on_pushButton_thetaimage_clicked() +{ + QString thetaimagePath = getSaveFilePath(this, u8"±£´ætheta¼«»¯»Ø²¨³ÉÏñ½á¹û", u8"ENVI (*.dat)"); + this->ui.lineEdit_thetaimagepath->setText(thetaimagePath); +} + +void LAMPImageCreateClass::on_pushButton_phiImage_clicked() +{ + QString phiimagePath = getSaveFilePath(this, u8"±£´ætheta¼«»¯»Ø²¨³ÉÏñ½á¹û", u8"ENVI (*.dat)"); + this->ui.lineEdit_phiimagepath->setText(phiimagePath); +} + +void LAMPImageCreateClass::on_checkBoxTheta_toggled(bool flag) +{ + this->ui.pushButton_theta->setEnabled(this->ui.checkBoxTheta->isChecked()); + this->ui.pushButton_thetaimage->setEnabled(this->ui.checkBoxTheta->isChecked()); + this->ui.lineEdit_thetaechopath->setEnabled(this->ui.checkBoxTheta->isChecked()); + this->ui.lineEdit_thetaimagepath->setEnabled(this->ui.checkBoxTheta->isChecked()); +} + +void LAMPImageCreateClass::on_checkBox_phi_toggled(bool flag) +{ + this->ui.pushButton_phi->setEnabled(this->ui.checkBox_phi->isChecked()); + this->ui.pushButton_phiImage->setEnabled(this->ui.checkBox_phi->isChecked()); + this->ui.lineEdit_phiechopath->setEnabled(this->ui.checkBox_phi->isChecked()); + this->ui.lineEdit_phiimagepath->setEnabled(this->ui.checkBox_phi->isChecked()); + +} + +void LAMPImageCreateClass::on_pushButton_OK_clicked() +{ + + FEKOBase::FEKOImageSettingParams imageparams = this->getFEKOImageSettingParams(); + // ¼ÆËã»Ø²¨ + if (this->ui.checkBoxTheta->isChecked()) { // theta + + QString thetafileptah= this->ui.lineEdit_thetaechopath->text().trimmed(); + QString theta_tiff_filepath=this->ui.lineEdit_thetaimagepath->text().trimmed(); + + FEKOBase::EchoDataClass data; + data.loadEchoData(thetafileptah); + if (this->simulationparams&&(this->simulationparams->imagemode==FEKOBase::FEKOImageMode::Strip|| this->simulationparams->imagemode == FEKOBase::FEKOImageMode::Scane)) { + FEKOBase::FEKOImageProcess(data, imageparams, theta_tiff_filepath,FEKOBase::FEKOImageAlgorithm::TBP_FREQ,FEKOBase::ImageAlgWindowFun::HANMMING); + } + else { + FEKOBase::FEKOImageProcess(data, imageparams, theta_tiff_filepath); + } + } + else { + + } + + if (this->ui.checkBox_phi->isChecked()) { // phi + + QString phifileptah = this->ui.lineEdit_phiechopath->text().trimmed(); + QString phi_tiff_filepath = this->ui.lineEdit_phiimagepath->text().trimmed(); + + FEKOBase::EchoDataClass data; + data.loadEchoData(phifileptah); + //FEKOBase::FEKOImageProcess(data, imageparams, phi_tiff_filepath); + if (this->simulationparams && (this->simulationparams->imagemode == FEKOBase::FEKOImageMode::Strip || this->simulationparams->imagemode == FEKOBase::FEKOImageMode::Scane)) { + FEKOBase::FEKOImageProcess(data, imageparams, phi_tiff_filepath, FEKOBase::FEKOImageAlgorithm::TBP_FREQ, FEKOBase::ImageAlgWindowFun::HANMMING); + } + else { + FEKOBase::FEKOImageProcess(data, imageparams, phi_tiff_filepath); + } + } + else { + + } + + QMessageBox::StandardButton reply = QMessageBox::question(this, u8"Ìáʾ", u8"ÊÇ·ñ²é¿´Í¼Ïñ", QMessageBox::Yes | QMessageBox::No); + if (reply == QMessageBox::Yes) { + LAMPDataShowClass* datashow=new LAMPDataShowClass(); + datashow->show(); + if (this->ui.checkBoxTheta->isChecked()) { // theta + QString theta_tiff_filepath = this->ui.lineEdit_thetaimagepath->text().trimmed(); + datashow->load_complex_data(theta_tiff_filepath); + + } + if (this->ui.checkBox_phi->isChecked()) { // phi + QString phi_tiff_filepath = this->ui.lineEdit_phiimagepath->text().trimmed(); + datashow->load_complex_data(phi_tiff_filepath); + } + + } + else { + return; + } + + +} + +void LAMPImageCreateClass::on_pushButton_cancel_clicked() +{ + this->close(); +} + +void LAMPImageCreateClass::on_pushButton_loadfekosimulationxml_clicked() +{ + QString xmlpath = getOpenFilePath(this, u8"·ÂÕæÈÎÎñxml", u8"xmlÎļþ (*.xml)"); + if (isExists(xmlpath)) { + this->OpenFEKOSimulationImageSettingXml(xmlpath); + } + else { + + } +} + +void LAMPImageCreateClass::OpenFEKOSimulationImageSettingXml(QString& xmlpath) +{ + this->simulationparams->loadXml(xmlpath); + this->ui.lineEdit_TaskName->setText(this->simulationparams->taskName); + this->ui.comboBox_ImageMode->setCurrentText(FEKOBase::FEKOImageModeenumToString(this->simulationparams->imagemode)); + this->ui.lineEdit_minX->setText(QString::number(this->simulationparams->x_min)); + this->ui.lineEdit__maxX->setText(QString::number(this->simulationparams->x_max)); + this->ui.lineEdit__minY->setText(QString::number(this->simulationparams->y_min)); + this->ui.lineEdit__maxY->setText(QString::number(this->simulationparams->y_max)); + this->ui.lineEdit_planeZ->setText(QString::number(this->simulationparams->z_plane)); + this->ui.lineEdit_height->setText(QString::number(this->simulationparams->imageheight)); + this->ui.lineEdit_width->setText(QString::number(this->simulationparams->imagewidth)); +} + +void LAMPImageCreateClass::bandingsetFEKOSimulationDataparams() +{ +} + + diff --git a/src/WBCLFZSystemModule/LAMPImageCreateClass.h b/src/WBCLFZSystemModule/LAMPImageCreateClass.h new file mode 100644 index 0000000..c2e4559 --- /dev/null +++ b/src/WBCLFZSystemModule/LAMPImageCreateClass.h @@ -0,0 +1,48 @@ +#pragma once +#ifndef LAMPIMAGECREATECLASS_H +#define LAMPIMAGECREATECLASS_H +#include "AllHead.h" +#include +#include "ui_LAMPImageCreateClass.h" +#include "LAMPDataShowClass.h" + +class LAMPImageCreateClass : public QDialog,public FEKOBase::FEKOSimulationDataparamsHandler +{ + Q_OBJECT + +public: + Q_INVOKABLE LAMPImageCreateClass(QWidget *parent = nullptr); + ~LAMPImageCreateClass(); + +private: + Ui::LAMPImageCreateClassClass ui; + +public: + Q_INVOKABLE FEKOBase::FEKOImageSettingParams getFEKOImageSettingParams(); + +public slots: + void on_pushButton_theta_clicked(); + void on_pushButton_phi_clicked(); + void on_pushButton_thetaimage_clicked(); + void on_pushButton_phiImage_clicked(); + + void on_checkBoxTheta_toggled(bool flag); + void on_checkBox_phi_toggled(bool flag); + + void on_pushButton_OK_clicked(); + void on_pushButton_cancel_clicked(); + + void on_pushButton_loadfekosimulationxml_clicked(); + +public: + QString workspace; + QString xmlpath; +public: + void OpenFEKOSimulationImageSettingXml(QString& xmlpath); + void bandingsetFEKOSimulationDataparams() override; + + +}; + + +#endif \ No newline at end of file diff --git a/src/WBCLFZSystemModule/LAMPImageCreateClass.ui b/src/WBCLFZSystemModule/LAMPImageCreateClass.ui new file mode 100644 index 0000000..1c1228d --- /dev/null +++ b/src/WBCLFZSystemModule/LAMPImageCreateClass.ui @@ -0,0 +1,657 @@ + + + LAMPImageCreateClassClass + + + + 0 + 0 + 712 + 615 + + + + LAMPImageCreateClass + + + + + + + + + 100 + 25 + + + + + 100 + 25 + + + + æˆåƒæ¨¡å¼ + + + + + + + + 0 + 30 + + + + + 16777215 + 30 + + + + + + + + + + + + + 100 + 25 + + + + + 100 + 25 + + + + 任务åç§° + + + + + + + + 0 + 30 + + + + + 16777215 + 30 + + + + + + + + + + + 0 + 60 + + + + + 16777215 + 60 + + + + æˆåƒæžåŒ–选择 + + + + + 40 + 30 + 91 + 19 + + + + thetaæžåŒ– + + + + + + 190 + 30 + 91 + 19 + + + + phiæžåŒ– + + + + + + + + + + + 100 + 25 + + + + + 100 + 25 + + + + theta回波文件: + + + + + + + + 0 + 30 + + + + + 16777215 + 30 + + + + + + + + + 16777215 + 30 + + + + 打开 + + + + + + + + + + + + 100 + 25 + + + + + 100 + 25 + + + + phi回波文件: + + + + + + + + 0 + 30 + + + + + 16777215 + 30 + + + + + + + + + 16777215 + 30 + + + + 打开 + + + + + + + + + + + + 100 + 25 + + + + + 100 + 25 + + + + thetaæˆåƒç»“果: + + + + + + + + 0 + 30 + + + + + 16777215 + 30 + + + + + + + + + 16777215 + 30 + + + + 打开 + + + + + + + + + + + + 100 + 25 + + + + + 100 + 25 + + + + phiæˆåƒç»“果: + + + + + + + + 0 + 30 + + + + + 16777215 + 30 + + + + + + + + + 16777215 + 30 + + + + 打开 + + + + + + + + + æˆåƒå‡ ä½•设置 + + + + + + + 0 + 25 + + + + + 16777215 + 25 + + + + X范围 + + + + + + + + 0 + 25 + + + + + 16777215 + 25 + + + + Y范围 + + + + + + + + 0 + 25 + + + + + 16777215 + 25 + + + + æˆåƒå¹³é¢é«˜ç¨‹Z + + + + + + + + 0 + 25 + + + + + 16777215 + 25 + + + + 最å°å€¼ + + + + + + + + 0 + 25 + + + + + 16777215 + 25 + + + + 最大值 + + + + + + + + 0 + 25 + + + + + 16777215 + 25 + + + + + + + + + 0 + 25 + + + + + 16777215 + 25 + + + + + + + + + 0 + 25 + + + + + 16777215 + 25 + + + + + + + + + 0 + 25 + + + + + 16777215 + 25 + + + + + + + + + 0 + 25 + + + + + 16777215 + 25 + + + + + + + + + + + 图åƒè®¾ç½® + + + + + + 图åƒé«˜åƒç´ ï¼ˆY) + + + + + + + + + + 图åƒå®½åƒç´ ï¼ˆX) + + + + + + + + + + + + + + 0 + 40 + + + + + 16777215 + 40 + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 0 + 25 + + + + + 16777215 + 25 + + + + 加载仿真æˆåƒå‚æ•° + + + + + + + + 0 + 25 + + + + + 16777215 + 25 + + + + 确定 + + + + + + + + 0 + 25 + + + + + 16777215 + 25 + + + + å–æ¶ˆ + + + + + + + + + + + + diff --git a/src/WBCLFZSystemModule/LAMP_ScatterSettingClass.cpp b/src/WBCLFZSystemModule/LAMP_ScatterSettingClass.cpp new file mode 100644 index 0000000..41ecf8c --- /dev/null +++ b/src/WBCLFZSystemModule/LAMP_ScatterSettingClass.cpp @@ -0,0 +1,2032 @@ +#include "AllHead.h" +#include "LAMP_ScatterSettingClass.h" + + +LAMP_ScatterSettingClass::LAMP_ScatterSettingClass(QWidget* parent) + : QDialog(parent) +{ + ui.setupUi(this); + this->setWindowTitle(u8"É¢ÉäÒÇÆ÷·ÂÕæÉèÖýçÃæ"); + this->settingobj = new LAMP_ScatterSettingXmlClass; + this->myContext = nullptr; + QDoubleValidator* doubleValidator = new QDoubleValidator; + this->ui.lineEdit_A1_incAngle->setValidator(doubleValidator); + this->ui.lineEdit_A2_incAngle->setValidator(doubleValidator); + this->ui.checkBox_A1->setChecked(true); + this->ui.checkBox_A2->setChecked(true); + + this->ui.radioButton_nearfield->setVisible(false); + this->ui.radioButton_nearfield->setChecked(false); + this->ui.radioButton_nearfield->setEnabled(false); + + this->ui.radioButton_farfield->setCheckable(true); + + this->ui.radioButton_S1 ->setEnabled(this->ui.checkBox_AllScatter->isChecked()); + this->ui.radioButton_S3 ->setEnabled(this->ui.checkBox_AllScatter->isChecked()); + this->ui.radioButton_S5 ->setEnabled(this->ui.checkBox_AllScatter->isChecked()); + this->ui.radioButton_S8 ->setEnabled(this->ui.checkBox_AllScatter->isChecked()); + this->ui.radioButton_S10 ->setEnabled(this->ui.checkBox_AllScatter->isChecked()); + this->ui.radioButton_S12 ->setEnabled(this->ui.checkBox_AllScatter->isChecked()); + this->ui.radioButton_F1 ->setEnabled(this->ui.checkBox_AllScatter->isChecked()); + this->ui.radioButton_F2 ->setEnabled(this->ui.checkBox_AllScatter->isChecked()); + this->ui.radioButton_F3 ->setEnabled(this->ui.checkBox_AllScatter->isChecked()); + this->ui.radioButton_F4 ->setEnabled(this->ui.checkBox_AllScatter->isChecked()); + this->ui.radioButton_F5 ->setEnabled(this->ui.checkBox_AllScatter->isChecked()); + this->ui.radioButton_F6 ->setEnabled(this->ui.checkBox_AllScatter->isChecked()); + this->ui.radioButton_F7 ->setEnabled(this->ui.checkBox_AllScatter->isChecked()); + this->ui.radioButton_F8 ->setEnabled(this->ui.checkBox_AllScatter->isChecked()); + this->ui.radioButton_F9 ->setEnabled(this->ui.checkBox_AllScatter->isChecked()); + this->ui.radioButton_F10 ->setEnabled(this->ui.checkBox_AllScatter->isChecked()); + this->ui.radioButton_F11 ->setEnabled(this->ui.checkBox_AllScatter->isChecked()); + this->ui.radioButton_F12 ->setEnabled(this->ui.checkBox_AllScatter->isChecked()); + +} + +LAMP_ScatterSettingClass::~LAMP_ScatterSettingClass() +{} + +void LAMP_ScatterSettingClass::loadxml(QString xmlpath) +{ + this->ui.lineEdit_xmlpath->setText(xmlpath); + this->xmlpath = xmlpath; + this->workpsace = getParantFromPath(xmlpath); + this->settingobj->loadxml(xmlpath); + this->renderSettingObj(); + +} + +void LAMP_ScatterSettingClass::savexml() +{ + this->sycnSettingObj(); + if (this->xmlpath.isEmpty()) { + QString xmlpath=getSaveFilePath(this, u8"É¢ÉäÈÎÎñÅäÖÃxml", u8"xmlÎļþ (*.xml)"); + if (xmlpath.isEmpty()) { + return; + } + else { + this->xmlpath = xmlpath; + this->workpsace = getParantFromPath(xmlpath); + } + } + this->settingobj->savexml(this->xmlpath); +} + +void LAMP_ScatterSettingClass::renderSettingObj() +{ + + this->ui.checkBox_A1->setChecked(this->settingobj->A1); + this->ui.checkBox_A2->setChecked(this->settingobj->A2); + this->ui.lineEdit_A1_incAngle->setText(QString::number(this->settingobj->incidence_A1)); + this->ui.lineEdit_A2_incAngle->setText(QString::number(this->settingobj->incidence_A2)); + + + this->ui.checkBox_AllScatter->setChecked(this->settingobj->enableScatter); + this->ui.radioButton_S1->setEnabled(this->ui.checkBox_AllScatter->isChecked()); + this->ui.radioButton_S3->setEnabled(this->ui.checkBox_AllScatter->isChecked()); + this->ui.radioButton_S5->setEnabled(this->ui.checkBox_AllScatter->isChecked()); + this->ui.radioButton_S8->setEnabled(this->ui.checkBox_AllScatter->isChecked()); + this->ui.radioButton_S10->setEnabled(this->ui.checkBox_AllScatter->isChecked()); + this->ui.radioButton_S12->setEnabled(this->ui.checkBox_AllScatter->isChecked()); + this->ui.radioButton_F1->setEnabled(this->ui.checkBox_AllScatter->isChecked()); + this->ui.radioButton_F2->setEnabled(this->ui.checkBox_AllScatter->isChecked()); + this->ui.radioButton_F3->setEnabled(this->ui.checkBox_AllScatter->isChecked()); + this->ui.radioButton_F4->setEnabled(this->ui.checkBox_AllScatter->isChecked()); + this->ui.radioButton_F5->setEnabled(this->ui.checkBox_AllScatter->isChecked()); + this->ui.radioButton_F6->setEnabled(this->ui.checkBox_AllScatter->isChecked()); + this->ui.radioButton_F7->setEnabled(this->ui.checkBox_AllScatter->isChecked()); + this->ui.radioButton_F8->setEnabled(this->ui.checkBox_AllScatter->isChecked()); + this->ui.radioButton_F9->setEnabled(this->ui.checkBox_AllScatter->isChecked()); + this->ui.radioButton_F10->setEnabled(this->ui.checkBox_AllScatter->isChecked()); + this->ui.radioButton_F11->setEnabled(this->ui.checkBox_AllScatter->isChecked()); + this->ui.radioButton_F12->setEnabled(this->ui.checkBox_AllScatter->isChecked()); + + + this->ui.radioButton_S1->setChecked(this->settingobj->S1); + this->ui.radioButton_S3->setChecked(this->settingobj->S3); + this->ui.radioButton_S5->setChecked(this->settingobj->S5); + this->ui.radioButton_S8->setChecked(this->settingobj->S8); + this->ui.radioButton_S10->setChecked(this->settingobj->S10); + this->ui.radioButton_S12->setChecked(this->settingobj->S12); + this->ui.radioButton_F1->setChecked(this->settingobj->F1); + this->ui.radioButton_F2->setChecked(this->settingobj->F2); + this->ui.radioButton_F3->setChecked(this->settingobj->F3); + this->ui.radioButton_F4->setChecked(this->settingobj->F4); + this->ui.radioButton_F5->setChecked(this->settingobj->F5); + this->ui.radioButton_F6->setChecked(this->settingobj->F6); + this->ui.radioButton_F7->setChecked(this->settingobj->F7); + this->ui.radioButton_F8->setChecked(this->settingobj->F8); + this->ui.radioButton_F9->setChecked(this->settingobj->F9); + this->ui.radioButton_F10->setChecked(this->settingobj->F10); + this->ui.radioButton_F11->setChecked(this->settingobj->F11); + this->ui.radioButton_F12->setChecked(this->settingobj->F12); + + this->ui.lineEdit_startFreq->setText(QString::number(this->settingobj->startfre)); + this->ui.lineEdit_endfreq->setText(QString::number(this->settingobj->endfre)); + this->ui.lineEdit_freqPoints->setText(QString::number(this->settingobj->freponts)); + this->ui.radioButton_farfield->setChecked(this->settingobj->farfield); + this->ui.radioButton_nearfield->setChecked(this->settingobj->nearfield); + this->ui.lineEdit_TaskName->setText(this->settingobj->taskName); + this->ui.lineEdit_xmlpath->setText(this->xmlpath); + + +} + +void LAMP_ScatterSettingClass::sycnSettingObj() +{ + //renderSettingObj º¯ÊýµÄ¹ØÏµ£¬Ê¹ÓýçÃæ¿Ø¼þÖµ£¬¸üРsettingobj µÄÖµ + this->settingobj->A1 = this->ui.checkBox_A1->isChecked(); + this->settingobj->A2 = this->ui.checkBox_A2->isChecked(); + this->settingobj->incidence_A1 = this->ui.lineEdit_A1_incAngle->text().toDouble(); + this->settingobj->incidence_A2 = this->ui.lineEdit_A2_incAngle->text().toDouble(); + + this->settingobj->enableScatter = this->ui.checkBox_AllScatter->isChecked(); + this->settingobj->S1 = this->ui.radioButton_S1->isChecked(); + this->settingobj->S3 = this->ui.radioButton_S3->isChecked(); + this->settingobj->S5 = this->ui.radioButton_S5->isChecked(); + this->settingobj->S8 = this->ui.radioButton_S8->isChecked(); + this->settingobj->S10 = this->ui.radioButton_S10->isChecked(); + this->settingobj->S12 = this->ui.radioButton_S12->isChecked(); + this->settingobj->F1 = this->ui.radioButton_F1->isChecked(); + this->settingobj->F2 = this->ui.radioButton_F2->isChecked(); + this->settingobj->F3 = this->ui.radioButton_F3->isChecked(); + this->settingobj->F4 = this->ui.radioButton_F4->isChecked(); + this->settingobj->F5 = this->ui.radioButton_F5->isChecked(); + this->settingobj->F6 = this->ui.radioButton_F6->isChecked(); + this->settingobj->F7 = this->ui.radioButton_F7->isChecked(); + this->settingobj->F8 = this->ui.radioButton_F8->isChecked(); + this->settingobj->F9 = this->ui.radioButton_F9->isChecked(); + this->settingobj->F10 = this->ui.radioButton_F10->isChecked(); + this->settingobj->F11 = this->ui.radioButton_F11->isChecked(); + this->settingobj->F12 = this->ui.radioButton_F12->isChecked(); + + this->settingobj->startfre = this->ui.lineEdit_startFreq->text().toDouble(); + this->settingobj->endfre = this->ui.lineEdit_endfreq->text().toDouble(); + this->settingobj->freponts = this->ui.lineEdit_freqPoints->text().toDouble(); + this->settingobj->farfield = this->ui.radioButton_farfield->isChecked(); + this->settingobj->nearfield = this->ui.radioButton_nearfield->isChecked(); + + this->settingobj->taskName = this->ui.lineEdit_TaskName->text(); + + + + +} + +void LAMP_ScatterSettingClass::createAntModel() +{ + // ·Ö¿é¼ÆËã + for (map::iterator iter = AntSettingdict.begin(); iter != AntSettingdict.end(); ++iter) { + std::string k = iter->first; + SphericalCoordinates sp = iter->second; + sp.phi = sp.phi * M_PI / 180; + sp.theta = sp.theta * M_PI / 180; + CartesianCoordinates cp = sphericalToCartesian(sp); + TopoDS_Shape shape_ax = CreateCartesianCoordinatesAxis(0.2, 0.4, 0.8); + TopoDS_Shape shape_ant = Process_RotationThetaPhi_MoveXYZ(shape_ax, M_PI - sp.theta, sp.phi + M_PI, cp.x, cp.y, cp.z); + Handle(AIS_InteractiveObject) shape_ais = new AIS_Shape(shape_ant); + + DataAISMap[k] = shape_ais; + } +} + +void LAMP_ScatterSettingClass::initAntModelSettingParams() +{ + QString fileName = QCoreApplication::applicationDirPath() + "/ScattingAntParams/ScatteringAntSetting.ini"; // É¢ÉäÄ£ÐÍÉèÖà + QSettings* setting = new QSettings(fileName, QSettings::IniFormat); + setting->setIniCodec(QTextCodec::codecForName("UTF-8")); + + if (QFile::exists(fileName)) + { + + } + else { + setting->setValue("CoordinateSystemName", u8"Spheric(R,theta,phi)"); + setting->setValue("description", u8"R£º°ë¾¶£¬theta ÈëÉä½Ç£¬phi ·½Î»½Ç"); + // ÌìÏß×ø±ê + // A1 ,A2 S1 S3 S5 S8 S10 S12 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 + setting->setValue("A1", u8"9.3,90,0"); + setting->setValue("A2", u8"9.3,90,180"); + setting->setValue("S1", u8"9.3,45,14"); + setting->setValue("S3", u8"9.3,45,45"); + setting->setValue("S5", u8"9.3,45,60"); + setting->setValue("S8", u8"9.3,45,120"); + setting->setValue("S10", u8"9.3,45,135"); + setting->setValue("S12", u8"9.3,45,166"); + setting->setValue("F1", u8"9.3,75,15"); + setting->setValue("F2", u8"9.3,75,30"); + setting->setValue("F3", u8"9.3,75,45"); + setting->setValue("F4", u8"9.3,75,60"); + setting->setValue("F5", u8"9.3,75,75"); + setting->setValue("F6", u8"9.3,75,86"); + setting->setValue("F7", u8"9.3,75,94"); + setting->setValue("F8", u8"9.3,75,105"); + setting->setValue("F9", u8"9.3,75,120"); + setting->setValue("F10", u8"9.3,75,135"); + setting->setValue("F11", u8"9.3,75,151"); + setting->setValue("F12", u8"9.3,75,165"); + + // A1,A2, Ϊ S1 S3 S5 S8 S10 S12 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 µÄÀ×´ï·øÉä·½Ïòͼ·ÂտģÐÍ + setting->setValue("ant_A1", u8"A1_ant.ffe"); + setting->setValue("ant_A2", u8"A2_ant.ffe"); + setting->setValue("ant_S1", u8"S1_ant.ffe"); + setting->setValue("ant_S3", u8"S3_ant.ffe"); + setting->setValue("ant_S5", u8"S5_ant.ffe"); + setting->setValue("ant_S8", u8"S8_ant.ffe"); + setting->setValue("ant_S10", u8"S10_ant.ffe"); + setting->setValue("ant_S12", u8"S12_ant.ffe"); + setting->setValue("ant_F1", u8"F1_ant.ffe"); + setting->setValue("ant_F2", u8"F2_ant.ffe"); + setting->setValue("ant_F3", u8"F3_ant.ffe"); + setting->setValue("ant_F4", u8"F4_ant.ffe"); + setting->setValue("ant_F5", u8"F5_ant.ffe"); + setting->setValue("ant_F6", u8"F6_ant.ffe"); + setting->setValue("ant_F7", u8"F7_ant.ffe"); + setting->setValue("ant_F8", u8"F8_ant.ffe"); + setting->setValue("ant_F9", u8"F9_ant.ffe"); + setting->setValue("ant_F10", u8"F10_ant.ffe"); + setting->setValue("ant_F11", u8"F11_ant.ffe"); + setting->setValue("ant_F12", u8"F12_ant.ffe"); + setting->sync(); + } + + // ÖØÐ¼ÓÔØÅäÖÃÏò + AntSettingdict["A1"] = antsettingstring2Spherical(setting->value("A1").toString()); + AntSettingdict["A2"] = antsettingstring2Spherical(setting->value("A2").toString()); + AntSettingdict["S1"] = antsettingstring2Spherical(setting->value("S1").toString()); + AntSettingdict["S3"] = antsettingstring2Spherical(setting->value("S3").toString()); + AntSettingdict["S5"] = antsettingstring2Spherical(setting->value("S5").toString()); + AntSettingdict["S8"] = antsettingstring2Spherical(setting->value("S8").toString()); + AntSettingdict["S10"] = antsettingstring2Spherical(setting->value("S10").toString()); + AntSettingdict["S12"] = antsettingstring2Spherical(setting->value("S12").toString()); + AntSettingdict["F1"] = antsettingstring2Spherical(setting->value("F1").toString()); + AntSettingdict["F2"] = antsettingstring2Spherical(setting->value("F2").toString()); + AntSettingdict["F3"] = antsettingstring2Spherical(setting->value("F3").toString()); + AntSettingdict["F4"] = antsettingstring2Spherical(setting->value("F4").toString()); + AntSettingdict["F5"] = antsettingstring2Spherical(setting->value("F5").toString()); + AntSettingdict["F6"] = antsettingstring2Spherical(setting->value("F6").toString()); + AntSettingdict["F7"] = antsettingstring2Spherical(setting->value("F7").toString()); + AntSettingdict["F8"] = antsettingstring2Spherical(setting->value("F8").toString()); + AntSettingdict["F9"] = antsettingstring2Spherical(setting->value("F9").toString()); + AntSettingdict["F10"] = antsettingstring2Spherical(setting->value("F10").toString()); + AntSettingdict["F11"] = antsettingstring2Spherical(setting->value("F11").toString()); + AntSettingdict["F12"] = antsettingstring2Spherical(setting->value("F12").toString()); + + // »ñÈ¡À×´ïµÄ·øÉä·ÂÕæ·½Ïòͼ£¬²¢¼ÓÔØµ½ AntffePathDict, + AntffePathDict["A1"] = QCoreApplication::applicationDirPath() + "/ScattingAntParams/" + setting->value("ant_A1").toString(); + AntffePathDict["A2"] = QCoreApplication::applicationDirPath() + "/ScattingAntParams/" + setting->value("ant_A2").toString(); + AntffePathDict["S1"] = QCoreApplication::applicationDirPath() + "/ScattingAntParams/" + setting->value("ant_S1").toString(); + AntffePathDict["S3"] = QCoreApplication::applicationDirPath() + "/ScattingAntParams/" + setting->value("ant_S3").toString(); + AntffePathDict["S5"] = QCoreApplication::applicationDirPath() + "/ScattingAntParams/" + setting->value("ant_S5").toString(); + AntffePathDict["S8"] = QCoreApplication::applicationDirPath() + "/ScattingAntParams/" + setting->value("ant_S8").toString(); + AntffePathDict["S10"] = QCoreApplication::applicationDirPath() + "/ScattingAntParams/" + setting->value("ant_S10").toString(); + AntffePathDict["S12"] = QCoreApplication::applicationDirPath() + "/ScattingAntParams/" + setting->value("ant_S12").toString(); + AntffePathDict["F1"] = QCoreApplication::applicationDirPath() + "/ScattingAntParams/" + setting->value("ant_F1").toString(); + AntffePathDict["F2"] = QCoreApplication::applicationDirPath() + "/ScattingAntParams/" + setting->value("ant_F2").toString(); + AntffePathDict["F3"] = QCoreApplication::applicationDirPath() + "/ScattingAntParams/" + setting->value("ant_F3").toString(); + AntffePathDict["F4"] = QCoreApplication::applicationDirPath() + "/ScattingAntParams/" + setting->value("ant_F4").toString(); + AntffePathDict["F5"] = QCoreApplication::applicationDirPath() + "/ScattingAntParams/" + setting->value("ant_F5").toString(); + AntffePathDict["F6"] = QCoreApplication::applicationDirPath() + "/ScattingAntParams/" + setting->value("ant_F6").toString(); + AntffePathDict["F7"] = QCoreApplication::applicationDirPath() + "/ScattingAntParams/" + setting->value("ant_F7").toString(); + AntffePathDict["F8"] = QCoreApplication::applicationDirPath() + "/ScattingAntParams/" + setting->value("ant_F8").toString(); + AntffePathDict["F9"] = QCoreApplication::applicationDirPath() + "/ScattingAntParams/" + setting->value("ant_F9").toString(); + AntffePathDict["F10"] = QCoreApplication::applicationDirPath() + "/ScattingAntParams/" + setting->value("ant_F10").toString(); + AntffePathDict["F11"] = QCoreApplication::applicationDirPath() + "/ScattingAntParams/" + setting->value("ant_F11").toString(); + AntffePathDict["F12"] = QCoreApplication::applicationDirPath() + "/ScattingAntParams/" + setting->value("ant_F12").toString(); +} + +void LAMP_ScatterSettingClass::closeWindows() +{ + + + for (map::iterator iter = DataAISMap.begin(); iter != DataAISMap.end(); ++iter) { + this->myContext->Erase(iter->second, Standard_True); + this->myContext->Remove(iter->second, Standard_True); + } + this->close(); +} + +void LAMP_ScatterSettingClass::setDocument3d(Handle(AIS_InteractiveContext) myContext) +{ + this->myContext = myContext; + this->initAntModelSettingParams(); + this->createAntModel(); + this->myContext->Display(DataAISMap["A1"],Standard_True); + this->myContext->Display(DataAISMap["A2"], Standard_True); + +} + +void LAMP_ScatterSettingClass::createFEKOLua() +{ + // չʾ¼ÆËã + QProgressDialog progressDialog(u8"´´½¨½Å±¾..", u8"ÖÕÖ¹", 0, AntSettingdict.size() * 2); + progressDialog.setWindowTitle(u8"³ÉÏñÖÐ"); + progressDialog.setWindowModality(Qt::WindowModal); + progressDialog.setAutoClose(true); + progressDialog.setValue(0); + progressDialog.setMinimum(0); + progressDialog.show(); + + + this->sycnSettingObj(); + std::map antfarfiledatastr; + if (isExists(this->workpsace)) { + // ¸´ÖÆÌìÏß·½Ïòͼ + for (map::iterator iter = AntffePathDict.begin(); iter != AntffePathDict.end(); ++iter) { + QString sourcepath = iter->second; + QString desPath= this->workpsace + u8"/" + getFileNameFromPath(sourcepath); + copyFile(sourcepath, desPath); + progressDialog.setWindowTitle(u8"½âÎö·ÂÕæÌìÏß·½Ïòͼ....."); + FEKOBase::FEKOFarFieldFileClass temp; + temp.parseFarFieldFile(desPath); + if (temp.dataBlockList.count() == 0) { + QMessageBox::warning(nullptr, u8"¾¯¸æ", u8"ffeÎļþ½âÎöʧ°Ü£¬Çë¼ì²éÎļþ¸ñʽÊÇ·ñÕýÈ·£¡"); + } + size_t thetapoints = temp.dataBlockList[0].thetaSamples; + size_t phipoints = temp.dataBlockList[0].phiSamples; + antfarfiledatastr[QString::fromStdString(iter->first)] = QString(u8"%1_farfieldData = project.FieldDataList:AddFarFieldData(\"%1\",%2,%3)") + .arg(getFileNameFromPath(sourcepath)) + .arg(QString::number(thetapoints)) + .arg(QString::number(phipoints)); + progressDialog.setValue(progressDialog.value() + 1); + } + } + else { + this->savexml(); + if (isExists(this->workpsace)) {} + else { return; } + } + + + + // ´´½¨½Å±¾ + QString luascript = QString(u8"--- create feko task :%1\n--- mode:Scatter\n\n").arg(this->settingobj->taskName); + luascript = luascript + QString(u8"-- create strip pulse \n"); + luascript = luascript + QString(u8"-- LAMP \n\n"); + luascript = luascript + QString(u8"-- warning:the configure's number of a feko project should be less than 600. if greater than 600,the program will very slow\n"); + luascript = luascript + QString(u8"\n"); + luascript = luascript + QString(u8"\n"); + luascript = luascript + QString(u8"app=cf.GetApplication()\n"); + luascript = luascript + QString(u8"project=app.Project --- get current project\n"); + + if (this->settingobj->nearfield) { // ¹¹½¨ÌìÏß·½Ïòͼ + for (map::iterator iter = antfarfiledatastr.begin(); iter != antfarfiledatastr.end(); ++iter) { + luascript = luascript + iter->second; + luascript = luascript + QString(u8"\n"); + } + } + else {} + luascript = luascript + QString(u8"\n"); + luascript = luascript + QString(u8"--const values\n"); + luascript = luascript + QString(u8"local pi=3.141592653589793238462643383279\n"); + luascript = luascript + QString(u8"local r2d=180.0/pi;\n"); + luascript = luascript + QString(u8"local d2r=pi/180.0;\n"); + luascript = luascript + QString(u8"\n"); + luascript = luascript + QString(u8"\n"); + luascript = luascript + QString(u8"\n"); + luascript = luascript + QString(u8"-- varables \n"); + luascript = luascript + QString(u8"\n"); + luascript = luascript + QString(u8"\n"); + // ÉèÖÃÆµÂÊ + luascript = luascript + QString(u8"local f1=%1 -- start freq\n").arg(QString::number(this->settingobj->startfre * 1e9)); + luascript = luascript + QString(u8"local f2=%2 -- end freq\n").arg(QString::number(this->settingobj->endfre * 1e9)); + luascript = luascript + QString(u8"local freq_num=%3 -- freq point \n").arg(QString::number(this->settingobj->freponts)); + luascript = luascript + QString(u8"\n"); + // ´´½¨configuration + luascript = luascript + QString(u8"temp_standardConfiguration = project.SolutionConfigurations:AddStandardConfiguration()\n"); + luascript = luascript + QString(u8"temp_standardConfiguration.Label=\"ScatterFEKOSetting\" -- set standardConfiguration label PRF Count\n"); + luascript = luascript + QString(u8"--- set frequency\n"); // ÉèÖÃÆµÂÊ + luascript = luascript + QString(u8"frequencyRange=temp_standardConfiguration.Frequency\n"); + luascript = luascript + QString(u8"properties = frequencyRange:GetProperties()\n"); + luascript = luascript + QString(u8"properties.RangeType = cf.Enums.FrequencyRangeTypeEnum.LinearSpacedDiscrete\n"); + luascript = luascript + QString(u8"properties.Start = f1 -- start\n"); + luascript = luascript + QString(u8"properties.End=f2 --end \n"); + luascript = luascript + QString(u8"properties.NumberOfDiscreteValues=freq_num -- freq_num\n"); + luascript = luascript + QString(u8"frequencyRange:SetProperties(properties)\n"); + if (this->settingobj->nearfield) { //½ü³¡ + if (this->settingobj->A1) { + SphericalCoordinates p = AntSettingdict["A1"]; + CartesianCoordinates cp = sphericalToCartesian(p); + luascript = luascript + QString(u8"-- set Source\n"); + luascript = luascript + QString(u8"A1_farFieldSource = temp_standardConfiguration.Sources:AddFarFieldSource(A1_farfieldData)\n"); // ÉèÖ÷¢ÉäÔ´ + luascript = luascript + QString(u8"A1_farFieldSource.Label=\"A1\"\n"); + luascript = luascript + QString(u8"A1_farFieldSource.Position.U=%1\n").arg(QString::number(cp.x)); + luascript = luascript + QString(u8"A1_farFieldSource.Position.V=%1\n").arg(QString::number(cp.y)); + luascript = luascript + QString(u8"A1_farFieldSource.Position.N=%1\n").arg(QString::number(cp.z)); + luascript = luascript + QString(u8"A1_farFieldSource.Theta=%1\n").arg(QString::number(180-p.theta)); + luascript = luascript + QString(u8"A1_farFieldSource.Phi=%1\n").arg(QString::number(180+p.phi)); + luascript = luascript + QString(u8"A1_farFieldSource_workplane=A1_farFieldSource.LocalWorkplane\n"); + luascript = luascript + QString(u8"A1_farFieldSource_workplane.Origin.X=0 -- move reference Point\n"); + luascript = luascript + QString(u8"A1_farFieldSource_workplane.Origin.Y=0\n"); + luascript = luascript + QString(u8"A1_farFieldSource_workplane.Origin.Z=0 \n"); + luascript = luascript + QString(u8"\n"); + luascript = luascript + QString(u8"-- set nearfield\n"); + luascript = luascript + QString(u8"A1_nearFieldRequest=temp_standardConfiguration.NearFields:AddSpherical(%1,%2,%3,%4,%5,%6,1,1,1) -- nearfield \n").arg(QString::number(0)) + .arg(QString::number(p.theta)) + .arg(QString::number(p.phi)) + .arg(QString::number(0)) + .arg(QString::number(p.theta)) + .arg(QString::number(p.phi)); // ÉèÖýÓÊÕµã + luascript = luascript + QString(u8"A1_nearFieldRequest.Label=\"A1\"\n"); + luascript = luascript + QString(u8"A1_nearFieldRequest_workplane=A1_nearFieldRequest.LocalWorkplane\n"); + luascript = luascript + QString(u8"A1_nearFieldRequest_workplane.Origin.X=%1\n").arg(QString::number(cp.x)); + luascript = luascript + QString(u8"A1_nearFieldRequest_workplane.Origin.Y=%1\n").arg(QString::number(cp.y)); + luascript = luascript + QString(u8"A1_nearFieldRequest_workplane.Origin.Z=%1\n").arg(QString::number(cp.z)); + luascript = luascript + QString(u8"A1_nearfieldAdvance=A1_nearFieldRequest.Advanced\n"); + luascript = luascript + QString(u8"A1_nearfieldAdvance.CalculationType=cf.Enums.NearFieldCalculationTypeEnum.Fields\n"); + luascript = luascript + QString(u8"A1_nearfieldAdvance.CalculateElectricFields=true\n"); + luascript = luascript + QString(u8"A1_nearfieldAdvance.CalculateMagneticFields=true\n"); + luascript = luascript + QString(u8"A1_nearfieldAdvance.ExportSettings.ASCIIEnabled=true\n"); + luascript = luascript + QString(u8"A1_nearfieldAdvance.ExportSettings.OutFileEnabled=true\n"); + luascript = luascript + QString(u8"A1_nearfieldAdvance.OnlyScatteredPartCalculationEnabled=true \n"); + luascript = luascript + QString(u8"\n"); + + + } + else {} + if (this->settingobj->A2) { + SphericalCoordinates p = AntSettingdict["A2"]; + CartesianCoordinates cp = sphericalToCartesian(p); + luascript = luascript + QString(u8"-- set Source\n"); + luascript = luascript + QString(u8"A2_farFieldSource = temp_standardConfiguration.Sources:AddFarFieldSource(A2_farfieldData)\n"); // ÉèÖ÷¢ÉäÔ´ + luascript = luascript + QString(u8"A2_farFieldSource.Label=\"A2\"\n"); + luascript = luascript + QString(u8"A2_farFieldSource.Position.U=%1\n").arg(QString::number(cp.x)); + luascript = luascript + QString(u8"A2_farFieldSource.Position.V=%1\n").arg(QString::number(cp.y)); + luascript = luascript + QString(u8"A2_farFieldSource.Position.N=%1\n").arg(QString::number(cp.z)); + luascript = luascript + QString(u8"A2_farFieldSource.Theta=%1\n").arg(QString::number(180 - p.theta)); + luascript = luascript + QString(u8"A2_farFieldSource.Phi=%1\n").arg(QString::number(180 + p.phi)); + luascript = luascript + QString(u8"A2_farFieldSource_workplane=A2_farFieldSource.LocalWorkplane\n"); + luascript = luascript + QString(u8"A2_farFieldSource_workplane.Origin.X=0 -- move reference Point\n"); + luascript = luascript + QString(u8"A2_farFieldSource_workplane.Origin.Y=0\n"); + luascript = luascript + QString(u8"A2_farFieldSource_workplane.Origin.Z=0 \n"); + luascript = luascript + QString(u8"\n"); + luascript = luascript + QString(u8"-- set nearfield\n"); + luascript = luascript + QString(u8"A2_nearFieldRequest=temp_standardConfiguration.NearFields:AddSpherical(%1,%2,%3,%4,%5,%6,1,1,1) -- nearfield \n").arg(QString::number(0)) + .arg(QString::number(p.theta)) + .arg(QString::number(p.phi)) + .arg(QString::number(0)) + .arg(QString::number(p.theta)) + .arg(QString::number(p.phi)); // ÉèÖýÓÊÕµã + luascript = luascript + QString(u8"A2_nearFieldRequest.Label=\"A2\"\n"); + luascript = luascript + QString(u8"A2_nearFieldRequest_workplane=A2_nearFieldRequest.LocalWorkplane\n"); + luascript = luascript + QString(u8"A2_nearFieldRequest_workplane.Origin.X=%1\n").arg(QString::number(cp.x)); + luascript = luascript + QString(u8"A2_nearFieldRequest_workplane.Origin.Y=%1\n").arg(QString::number(cp.y)); + luascript = luascript + QString(u8"A2_nearFieldRequest_workplane.Origin.Z=%1\n").arg(QString::number(cp.z)); + luascript = luascript + QString(u8"A2_nearfieldAdvance=A2_nearFieldRequest.Advanced\n"); + luascript = luascript + QString(u8"A2_nearfieldAdvance.CalculationType=cf.Enums.NearFieldCalculationTypeEnum.Fields\n"); + luascript = luascript + QString(u8"A2_nearfieldAdvance.CalculateElectricFields=true\n"); + luascript = luascript + QString(u8"A2_nearfieldAdvance.CalculateMagneticFields=true\n"); + luascript = luascript + QString(u8"A2_nearfieldAdvance.ExportSettings.ASCIIEnabled=true\n"); + luascript = luascript + QString(u8"A2_nearfieldAdvance.ExportSettings.OutFileEnabled=true\n"); + luascript = luascript + QString(u8"A2_nearfieldAdvance.OnlyScatteredPartCalculationEnabled=true \n"); + luascript = luascript + QString(u8"\n"); + + + } + else {} + if (this->settingobj->enableScatter) { + if (this->settingobj->S1) { + SphericalCoordinates p = AntSettingdict["S1"]; + CartesianCoordinates cp = sphericalToCartesian(p); + luascript = luascript + QString(u8"-- set Source\n"); + luascript = luascript + QString(u8"S1_farFieldSource = temp_standardConfiguration.Sources:AddFarFieldSource(S1_farfieldData)\n"); // ÉèÖ÷¢ÉäÔ´ + luascript = luascript + QString(u8"S1_farFieldSource.Label=\"S1\"\n"); + luascript = luascript + QString(u8"S1_farFieldSource.Position.U=%1\n").arg(QString::number(cp.x)); + luascript = luascript + QString(u8"S1_farFieldSource.Position.V=%1\n").arg(QString::number(cp.y)); + luascript = luascript + QString(u8"S1_farFieldSource.Position.N=%1\n").arg(QString::number(cp.z)); + luascript = luascript + QString(u8"S1_farFieldSource.Theta=%1\n").arg(QString::number(180 - p.theta)); + luascript = luascript + QString(u8"S1_farFieldSource.Phi=%1\n").arg(QString::number(180 + p.phi)); + luascript = luascript + QString(u8"S1_farFieldSource_workplane=S1_farFieldSource.LocalWorkplane\n"); + luascript = luascript + QString(u8"S1_farFieldSource_workplane.Origin.X=0 -- move reference Point\n"); + luascript = luascript + QString(u8"S1_farFieldSource_workplane.Origin.Y=0\n"); + luascript = luascript + QString(u8"S1_farFieldSource_workplane.Origin.Z=0 \n"); + luascript = luascript + QString(u8"\n"); + luascript = luascript + QString(u8"-- set nearfield\n"); + luascript = luascript + QString(u8"S1_nearFieldRequest=temp_standardConfiguration.NearFields:AddSpherical(%1,%2,%3,%4,%5,%6,1,1,1) -- nearfield \n").arg(QString::number(0)) + .arg(QString::number(p.theta)) + .arg(QString::number(p.phi)) + .arg(QString::number(0)) + .arg(QString::number(p.theta)) + .arg(QString::number(p.phi)); // ÉèÖýÓÊÕµã + luascript = luascript + QString(u8"S1_nearFieldRequest.Label=\"S1\"\n"); + luascript = luascript + QString(u8"S1_nearFieldRequest_workplane=S1_nearFieldRequest.LocalWorkplane\n"); + luascript = luascript + QString(u8"S1_nearFieldRequest_workplane.Origin.X=%1\n").arg(QString::number(cp.x)); + luascript = luascript + QString(u8"S1_nearFieldRequest_workplane.Origin.Y=%1\n").arg(QString::number(cp.y)); + luascript = luascript + QString(u8"S1_nearFieldRequest_workplane.Origin.Z=%1\n").arg(QString::number(cp.z)); + luascript = luascript + QString(u8"S1_nearfieldAdvance=S1_nearFieldRequest.Advanced\n"); + luascript = luascript + QString(u8"S1_nearfieldAdvance.CalculationType=cf.Enums.NearFieldCalculationTypeEnum.Fields\n"); + luascript = luascript + QString(u8"S1_nearfieldAdvance.CalculateElectricFields=true\n"); + luascript = luascript + QString(u8"S1_nearfieldAdvance.CalculateMagneticFields=true\n"); + luascript = luascript + QString(u8"S1_nearfieldAdvance.ExportSettings.ASCIIEnabled=true\n"); + luascript = luascript + QString(u8"S1_nearfieldAdvance.ExportSettings.OutFileEnabled=true\n"); + luascript = luascript + QString(u8"S1_nearfieldAdvance.OnlyScatteredPartCalculationEnabled=true \n"); + luascript = luascript + QString(u8"\n"); + + } + else {} + if (this->settingobj->S3) { + SphericalCoordinates p = AntSettingdict["S3"]; + CartesianCoordinates cp = sphericalToCartesian(p); + luascript = luascript + QString(u8"-- set Source\n"); + luascript = luascript + QString(u8"S3_farFieldSource = temp_standardConfiguration.Sources:AddFarFieldSource(S3_farfieldData)\n"); // ÉèÖ÷¢ÉäÔ´ + luascript = luascript + QString(u8"S3_farFieldSource.Label=\"S3\"\n"); + luascript = luascript + QString(u8"S3_farFieldSource.Position.U=%1\n").arg(QString::number(cp.x)); + luascript = luascript + QString(u8"S3_farFieldSource.Position.V=%1\n").arg(QString::number(cp.y)); + luascript = luascript + QString(u8"S3_farFieldSource.Position.N=%1\n").arg(QString::number(cp.z)); + luascript = luascript + QString(u8"S3_farFieldSource.Theta=%1\n").arg(QString::number(180 - p.theta)); + luascript = luascript + QString(u8"S3_farFieldSource.Phi=%1\n").arg(QString::number(180 + p.phi)); + luascript = luascript + QString(u8"S3_farFieldSource_workplane=S3_farFieldSource.LocalWorkplane\n"); + luascript = luascript + QString(u8"S3_farFieldSource_workplane.Origin.X=0 -- move reference Point\n"); + luascript = luascript + QString(u8"S3_farFieldSource_workplane.Origin.Y=0\n"); + luascript = luascript + QString(u8"S3_farFieldSource_workplane.Origin.Z=0 \n"); + luascript = luascript + QString(u8"\n"); + luascript = luascript + QString(u8"-- set nearfield\n"); + luascript = luascript + QString(u8"S3_nearFieldRequest=temp_standardConfiguration.NearFields:AddSpherical(%1,%2,%3,%4,%5,%6,1,1,1) -- nearfield \n").arg(QString::number(0)) + .arg(QString::number(p.theta)) + .arg(QString::number(p.phi)) + .arg(QString::number(0)) + .arg(QString::number(p.theta)) + .arg(QString::number(p.phi)); // ÉèÖýÓÊÕµã + luascript = luascript + QString(u8"S3_nearFieldRequest.Label=\"S3\"\n"); + luascript = luascript + QString(u8"S3_nearFieldRequest_workplane=S3_nearFieldRequest.LocalWorkplane\n"); + luascript = luascript + QString(u8"S3_nearFieldRequest_workplane.Origin.X=%1\n").arg(QString::number(cp.x)); + luascript = luascript + QString(u8"S3_nearFieldRequest_workplane.Origin.Y=%1\n").arg(QString::number(cp.y)); + luascript = luascript + QString(u8"S3_nearFieldRequest_workplane.Origin.Z=%1\n").arg(QString::number(cp.z)); + luascript = luascript + QString(u8"S3_nearfieldAdvance=S3_nearFieldRequest.Advanced\n"); + luascript = luascript + QString(u8"S3_nearfieldAdvance.CalculationType=cf.Enums.NearFieldCalculationTypeEnum.Fields\n"); + luascript = luascript + QString(u8"S3_nearfieldAdvance.CalculateElectricFields=true\n"); + luascript = luascript + QString(u8"S3_nearfieldAdvance.CalculateMagneticFields=true\n"); + luascript = luascript + QString(u8"S3_nearfieldAdvance.ExportSettings.ASCIIEnabled=true\n"); + luascript = luascript + QString(u8"S3_nearfieldAdvance.ExportSettings.OutFileEnabled=true\n"); + luascript = luascript + QString(u8"S3_nearfieldAdvance.OnlyScatteredPartCalculationEnabled=true \n"); + luascript = luascript + QString(u8"\n"); + } + else {} + if (this->settingobj->S5) { + SphericalCoordinates p = AntSettingdict["S5"]; + CartesianCoordinates cp = sphericalToCartesian(p); + luascript = luascript + QString(u8"-- set Source\n"); + luascript = luascript + QString(u8"S5_farFieldSource = temp_standardConfiguration.Sources:AddFarFieldSource(S5_farfieldData)\n"); // ÉèÖ÷¢ÉäÔ´ + luascript = luascript + QString(u8"S5_farFieldSource.Label=\"S5\"\n"); + luascript = luascript + QString(u8"S5_farFieldSource.Position.U=%1\n").arg(QString::number(cp.x)); + luascript = luascript + QString(u8"S5_farFieldSource.Position.V=%1\n").arg(QString::number(cp.y)); + luascript = luascript + QString(u8"S5_farFieldSource.Position.N=%1\n").arg(QString::number(cp.z)); + luascript = luascript + QString(u8"S5_farFieldSource.Theta=%1\n").arg(QString::number(180 - p.theta)); + luascript = luascript + QString(u8"S5_farFieldSource.Phi=%1\n").arg(QString::number(180 + p.phi)); + luascript = luascript + QString(u8"S5_farFieldSource_workplane=S5_farFieldSource.LocalWorkplane\n"); + luascript = luascript + QString(u8"S5_farFieldSource_workplane.Origin.X=0 -- move reference Point\n"); + luascript = luascript + QString(u8"S5_farFieldSource_workplane.Origin.Y=0\n"); + luascript = luascript + QString(u8"S5_farFieldSource_workplane.Origin.Z=0 \n"); + luascript = luascript + QString(u8"\n"); + luascript = luascript + QString(u8"-- set nearfield\n"); + luascript = luascript + QString(u8"S5_nearFieldRequest=temp_standardConfiguration.NearFields:AddSpherical(%1,%2,%3,%4,%5,%6,1,1,1) -- nearfield \n").arg(QString::number(0)) + .arg(QString::number(p.theta)) + .arg(QString::number(p.phi)) + .arg(QString::number(0)) + .arg(QString::number(p.theta)) + .arg(QString::number(p.phi)); // ÉèÖýÓÊÕµã + luascript = luascript + QString(u8"S5_nearFieldRequest.Label=\"S5\"\n"); + luascript = luascript + QString(u8"S5_nearFieldRequest_workplane=S5_nearFieldRequest.LocalWorkplane\n"); + luascript = luascript + QString(u8"S5_nearFieldRequest_workplane.Origin.X=%1\n").arg(QString::number(cp.x)); + luascript = luascript + QString(u8"S5_nearFieldRequest_workplane.Origin.Y=%1\n").arg(QString::number(cp.y)); + luascript = luascript + QString(u8"S5_nearFieldRequest_workplane.Origin.Z=%1\n").arg(QString::number(cp.z)); + luascript = luascript + QString(u8"S5_nearfieldAdvance=S5_nearFieldRequest.Advanced\n"); + luascript = luascript + QString(u8"S5_nearfieldAdvance.CalculationType=cf.Enums.NearFieldCalculationTypeEnum.Fields\n"); + luascript = luascript + QString(u8"S5_nearfieldAdvance.CalculateElectricFields=true\n"); + luascript = luascript + QString(u8"S5_nearfieldAdvance.CalculateMagneticFields=true\n"); + luascript = luascript + QString(u8"S5_nearfieldAdvance.ExportSettings.ASCIIEnabled=true\n"); + luascript = luascript + QString(u8"S5_nearfieldAdvance.ExportSettings.OutFileEnabled=true\n"); + luascript = luascript + QString(u8"S5_nearfieldAdvance.OnlyScatteredPartCalculationEnabled=true \n"); + luascript = luascript + QString(u8"\n"); + } + else {} + if (this->settingobj->S8) { + SphericalCoordinates p = AntSettingdict["S8"]; + CartesianCoordinates cp = sphericalToCartesian(p); + luascript = luascript + QString(u8"-- set Source\n"); + luascript = luascript + QString(u8"S8_farFieldSource = temp_standardConfiguration.Sources:AddFarFieldSource(S8_farfieldData)\n"); // ÉèÖ÷¢ÉäÔ´ + luascript = luascript + QString(u8"S8_farFieldSource.Label=\"S8\"\n"); + luascript = luascript + QString(u8"S8_farFieldSource.Position.U=%1\n").arg(QString::number(cp.x)); + luascript = luascript + QString(u8"S8_farFieldSource.Position.V=%1\n").arg(QString::number(cp.y)); + luascript = luascript + QString(u8"S8_farFieldSource.Position.N=%1\n").arg(QString::number(cp.z)); + luascript = luascript + QString(u8"S8_farFieldSource.Theta=%1\n").arg(QString::number(180 - p.theta)); + luascript = luascript + QString(u8"S8_farFieldSource.Phi=%1\n").arg(QString::number(180 + p.phi)); + luascript = luascript + QString(u8"S8_farFieldSource_workplane=S8_farFieldSource.LocalWorkplane\n"); + luascript = luascript + QString(u8"S8_farFieldSource_workplane.Origin.X=0 -- move reference Point\n"); + luascript = luascript + QString(u8"S8_farFieldSource_workplane.Origin.Y=0\n"); + luascript = luascript + QString(u8"S8_farFieldSource_workplane.Origin.Z=0 \n"); + luascript = luascript + QString(u8"\n"); + luascript = luascript + QString(u8"-- set nearfield\n"); + luascript = luascript + QString(u8"S8_nearFieldRequest=temp_standardConfiguration.NearFields:AddSpherical(%1,%2,%3,%4,%5,%6,1,1,1) -- nearfield \n").arg(QString::number(0)) + .arg(QString::number(p.theta)) + .arg(QString::number(p.phi)) + .arg(QString::number(0)) + .arg(QString::number(p.theta)) + .arg(QString::number(p.phi)); // ÉèÖýÓÊÕµã + luascript = luascript + QString(u8"S8_nearFieldRequest.Label=\"S8\"\n"); + luascript = luascript + QString(u8"S8_nearFieldRequest_workplane=S8_nearFieldRequest.LocalWorkplane\n"); + luascript = luascript + QString(u8"S8_nearFieldRequest_workplane.Origin.X=%1\n").arg(QString::number(cp.x)); + luascript = luascript + QString(u8"S8_nearFieldRequest_workplane.Origin.Y=%1\n").arg(QString::number(cp.y)); + luascript = luascript + QString(u8"S8_nearFieldRequest_workplane.Origin.Z=%1\n").arg(QString::number(cp.z)); + luascript = luascript + QString(u8"S8_nearfieldAdvance=S8_nearFieldRequest.Advanced\n"); + luascript = luascript + QString(u8"S8_nearfieldAdvance.CalculationType=cf.Enums.NearFieldCalculationTypeEnum.Fields\n"); + luascript = luascript + QString(u8"S8_nearfieldAdvance.CalculateElectricFields=true\n"); + luascript = luascript + QString(u8"S8_nearfieldAdvance.CalculateMagneticFields=true\n"); + luascript = luascript + QString(u8"S8_nearfieldAdvance.ExportSettings.ASCIIEnabled=true\n"); + luascript = luascript + QString(u8"S8_nearfieldAdvance.ExportSettings.OutFileEnabled=true\n"); + luascript = luascript + QString(u8"S8_nearfieldAdvance.OnlyScatteredPartCalculationEnabled=true \n"); + luascript = luascript + QString(u8"\n"); + } + else {} + if (this->settingobj->S10) { + SphericalCoordinates p = AntSettingdict["S10"]; + CartesianCoordinates cp = sphericalToCartesian(p); + luascript = luascript + QString(u8"-- set Source\n"); + luascript = luascript + QString(u8"S10_farFieldSource = temp_standardConfiguration.Sources:AddFarFieldSource(S10_farfieldData)\n"); // ÉèÖ÷¢ÉäÔ´ + luascript = luascript + QString(u8"S10_farFieldSource.Label=\"S10\"\n"); + luascript = luascript + QString(u8"S10_farFieldSource.Position.U=%1\n").arg(QString::number(cp.x)); + luascript = luascript + QString(u8"S10_farFieldSource.Position.V=%1\n").arg(QString::number(cp.y)); + luascript = luascript + QString(u8"S10_farFieldSource.Position.N=%1\n").arg(QString::number(cp.z)); + luascript = luascript + QString(u8"S10_farFieldSource.Theta=%1\n").arg(QString::number(180 - p.theta)); + luascript = luascript + QString(u8"S10_farFieldSource.Phi=%1\n").arg(QString::number(180 + p.phi)); + luascript = luascript + QString(u8"S10_farFieldSource_workplane=S10_farFieldSource.LocalWorkplane\n"); + luascript = luascript + QString(u8"S10_farFieldSource_workplane.Origin.X=0 -- move reference Point\n"); + luascript = luascript + QString(u8"S10_farFieldSource_workplane.Origin.Y=0\n"); + luascript = luascript + QString(u8"S10_farFieldSource_workplane.Origin.Z=0 \n"); + luascript = luascript + QString(u8"\n"); + luascript = luascript + QString(u8"-- set nearfield\n"); + luascript = luascript + QString(u8"S10_nearFieldRequest=temp_standardConfiguration.NearFields:AddSpherical(%1,%2,%3,%4,%5,%6,1,1,1) -- nearfield \n").arg(QString::number(0)) + .arg(QString::number(p.theta)) + .arg(QString::number(p.phi)) + .arg(QString::number(0)) + .arg(QString::number(p.theta)) + .arg(QString::number(p.phi)); // ÉèÖýÓÊÕµã + luascript = luascript + QString(u8"S10_nearFieldRequest.Label=\"S10\"\n"); + luascript = luascript + QString(u8"S10_nearFieldRequest_workplane=S10_nearFieldRequest.LocalWorkplane\n"); + luascript = luascript + QString(u8"S10_nearFieldRequest_workplane.Origin.X=%1\n").arg(QString::number(cp.x)); + luascript = luascript + QString(u8"S10_nearFieldRequest_workplane.Origin.Y=%1\n").arg(QString::number(cp.y)); + luascript = luascript + QString(u8"S10_nearFieldRequest_workplane.Origin.Z=%1\n").arg(QString::number(cp.z)); + luascript = luascript + QString(u8"S10_nearfieldAdvance=S10_nearFieldRequest.Advanced\n"); + luascript = luascript + QString(u8"S10_nearfieldAdvance.CalculationType=cf.Enums.NearFieldCalculationTypeEnum.Fields\n"); + luascript = luascript + QString(u8"S10_nearfieldAdvance.CalculateElectricFields=true\n"); + luascript = luascript + QString(u8"S10_nearfieldAdvance.CalculateMagneticFields=true\n"); + luascript = luascript + QString(u8"S10_nearfieldAdvance.ExportSettings.ASCIIEnabled=true\n"); + luascript = luascript + QString(u8"S10_nearfieldAdvance.ExportSettings.OutFileEnabled=true\n"); + luascript = luascript + QString(u8"S10_nearfieldAdvance.OnlyScatteredPartCalculationEnabled=true \n"); + luascript = luascript + QString(u8"\n"); + + } + else {} + if (this->settingobj->S12) { + SphericalCoordinates p = AntSettingdict["S12"]; + CartesianCoordinates cp = sphericalToCartesian(p); + luascript = luascript + QString(u8"-- set Source\n"); + luascript = luascript + QString(u8"S12_farFieldSource = temp_standardConfiguration.Sources:AddFarFieldSource(S12_farfieldData)\n"); // ÉèÖ÷¢ÉäÔ´ + luascript = luascript + QString(u8"S12_farFieldSource.Label=\"S12\"\n"); + luascript = luascript + QString(u8"S12_farFieldSource.Position.U=%1\n").arg(QString::number(cp.x)); + luascript = luascript + QString(u8"S12_farFieldSource.Position.V=%1\n").arg(QString::number(cp.y)); + luascript = luascript + QString(u8"S12_farFieldSource.Position.N=%1\n").arg(QString::number(cp.z)); + luascript = luascript + QString(u8"S12_farFieldSource.Theta=%1\n").arg(QString::number(180 - p.theta)); + luascript = luascript + QString(u8"S12_farFieldSource.Phi=%1\n").arg(QString::number(180 + p.phi)); + luascript = luascript + QString(u8"S12_farFieldSource_workplane=S12_farFieldSource.LocalWorkplane\n"); + luascript = luascript + QString(u8"S12_farFieldSource_workplane.Origin.X=0 -- move reference Point\n"); + luascript = luascript + QString(u8"S12_farFieldSource_workplane.Origin.Y=0\n"); + luascript = luascript + QString(u8"S12_farFieldSource_workplane.Origin.Z=0 \n"); + luascript = luascript + QString(u8"\n"); + luascript = luascript + QString(u8"-- set nearfield\n"); + luascript = luascript + QString(u8"S12_nearFieldRequest=temp_standardConfiguration.NearFields:AddSpherical(%1,%2,%3,%4,%5,%6,1,1,1) -- nearfield \n").arg(QString::number(0)) + .arg(QString::number(p.theta)) + .arg(QString::number(p.phi)) + .arg(QString::number(0)) + .arg(QString::number(p.theta)) + .arg(QString::number(p.phi)); // ÉèÖýÓÊÕµã + luascript = luascript + QString(u8"S12_nearFieldRequest.Label=\"S12\"\n"); + luascript = luascript + QString(u8"S12_nearFieldRequest_workplane=S12_nearFieldRequest.LocalWorkplane\n"); + luascript = luascript + QString(u8"S12_nearFieldRequest_workplane.Origin.X=%1\n").arg(QString::number(cp.x)); + luascript = luascript + QString(u8"S12_nearFieldRequest_workplane.Origin.Y=%1\n").arg(QString::number(cp.y)); + luascript = luascript + QString(u8"S12_nearFieldRequest_workplane.Origin.Z=%1\n").arg(QString::number(cp.z)); + luascript = luascript + QString(u8"S12_nearfieldAdvance=S12_nearFieldRequest.Advanced\n"); + luascript = luascript + QString(u8"S12_nearfieldAdvance.CalculationType=cf.Enums.NearFieldCalculationTypeEnum.Fields\n"); + luascript = luascript + QString(u8"S12_nearfieldAdvance.CalculateElectricFields=true\n"); + luascript = luascript + QString(u8"S12_nearfieldAdvance.CalculateMagneticFields=true\n"); + luascript = luascript + QString(u8"S12_nearfieldAdvance.ExportSettings.ASCIIEnabled=true\n"); + luascript = luascript + QString(u8"S12_nearfieldAdvance.ExportSettings.OutFileEnabled=true\n"); + luascript = luascript + QString(u8"S12_nearfieldAdvance.OnlyScatteredPartCalculationEnabled=true \n"); + luascript = luascript + QString(u8"\n"); + } + else {} + if (this->settingobj->F1) { + SphericalCoordinates p = AntSettingdict["F1"]; + CartesianCoordinates cp = sphericalToCartesian(p); + luascript = luascript + QString(u8"-- set Source\n"); + luascript = luascript + QString(u8"F1_farFieldSource = temp_standardConfiguration.Sources:AddFarFieldSource(F1_farfieldData)\n"); // ÉèÖ÷¢ÉäÔ´ + luascript = luascript + QString(u8"F1_farFieldSource.Label=\"F1\"\n"); + luascript = luascript + QString(u8"F1_farFieldSource.Position.U=%1\n").arg(QString::number(cp.x)); + luascript = luascript + QString(u8"F1_farFieldSource.Position.V=%1\n").arg(QString::number(cp.y)); + luascript = luascript + QString(u8"F1_farFieldSource.Position.N=%1\n").arg(QString::number(cp.z)); + luascript = luascript + QString(u8"F1_farFieldSource.Theta=%1\n").arg(QString::number(180 - p.theta)); + luascript = luascript + QString(u8"F1_farFieldSource.Phi=%1\n").arg(QString::number(180 + p.phi)); + luascript = luascript + QString(u8"F1_farFieldSource_workplane=F1_farFieldSource.LocalWorkplane\n"); + luascript = luascript + QString(u8"F1_farFieldSource_workplane.Origin.X=0 -- move reference Point\n"); + luascript = luascript + QString(u8"F1_farFieldSource_workplane.Origin.Y=0\n"); + luascript = luascript + QString(u8"F1_farFieldSource_workplane.Origin.Z=0 \n"); + luascript = luascript + QString(u8"\n"); + luascript = luascript + QString(u8"-- set nearfield\n"); + luascript = luascript + QString(u8"F1_nearFieldRequest=temp_standardConfiguration.NearFields:AddSpherical(%1,%2,%3,%4,%5,%6,1,1,1) -- nearfield \n").arg(QString::number(0)) + .arg(QString::number(p.theta)) + .arg(QString::number(p.phi)) + .arg(QString::number(0)) + .arg(QString::number(p.theta)) + .arg(QString::number(p.phi)); // ÉèÖýÓÊÕµã + luascript = luascript + QString(u8"F1_nearFieldRequest.Label=\"F1\"\n"); + luascript = luascript + QString(u8"F1_nearFieldRequest_workplane=F1_nearFieldRequest.LocalWorkplane\n"); + luascript = luascript + QString(u8"F1_nearFieldRequest_workplane.Origin.X=%1\n").arg(QString::number(cp.x)); + luascript = luascript + QString(u8"F1_nearFieldRequest_workplane.Origin.Y=%1\n").arg(QString::number(cp.y)); + luascript = luascript + QString(u8"F1_nearFieldRequest_workplane.Origin.Z=%1\n").arg(QString::number(cp.z)); + luascript = luascript + QString(u8"F1_nearfieldAdvance=F1_nearFieldRequest.Advanced\n"); + luascript = luascript + QString(u8"F1_nearfieldAdvance.CalculationType=cf.Enums.NearFieldCalculationTypeEnum.Fields\n"); + luascript = luascript + QString(u8"F1_nearfieldAdvance.CalculateElectricFields=true\n"); + luascript = luascript + QString(u8"F1_nearfieldAdvance.CalculateMagneticFields=true\n"); + luascript = luascript + QString(u8"F1_nearfieldAdvance.ExportSettings.ASCIIEnabled=true\n"); + luascript = luascript + QString(u8"F1_nearfieldAdvance.ExportSettings.OutFileEnabled=true\n"); + luascript = luascript + QString(u8"F1_nearfieldAdvance.OnlyScatteredPartCalculationEnabled=true \n"); + luascript = luascript + QString(u8"\n"); + } + else {} + if (this->settingobj->F2) { + SphericalCoordinates p = AntSettingdict["F2"]; + CartesianCoordinates cp = sphericalToCartesian(p); + luascript = luascript + QString(u8"-- set Source\n"); + luascript = luascript + QString(u8"F2_farFieldSource = temp_standardConfiguration.Sources:AddFarFieldSource(F2_farfieldData)\n"); // ÉèÖ÷¢ÉäÔ´ + luascript = luascript + QString(u8"F2_farFieldSource.Label=\"F2\"\n"); + luascript = luascript + QString(u8"F2_farFieldSource.Position.U=%1\n").arg(QString::number(cp.x)); + luascript = luascript + QString(u8"F2_farFieldSource.Position.V=%1\n").arg(QString::number(cp.y)); + luascript = luascript + QString(u8"F2_farFieldSource.Position.N=%1\n").arg(QString::number(cp.z)); + luascript = luascript + QString(u8"F2_farFieldSource.Theta=%1\n").arg(QString::number(180 - p.theta)); + luascript = luascript + QString(u8"F2_farFieldSource.Phi=%1\n").arg(QString::number(180 + p.phi)); + luascript = luascript + QString(u8"F2_farFieldSource_workplane=F2_farFieldSource.LocalWorkplane\n"); + luascript = luascript + QString(u8"F2_farFieldSource_workplane.Origin.X=0 -- move reference Point\n"); + luascript = luascript + QString(u8"F2_farFieldSource_workplane.Origin.Y=0\n"); + luascript = luascript + QString(u8"F2_farFieldSource_workplane.Origin.Z=0 \n"); + luascript = luascript + QString(u8"\n"); + luascript = luascript + QString(u8"-- set nearfield\n"); + luascript = luascript + QString(u8"F2_nearFieldRequest=temp_standardConfiguration.NearFields:AddSpherical(%1,%2,%3,%4,%5,%6,1,1,1) -- nearfield \n").arg(QString::number(0)) + .arg(QString::number(p.theta)) + .arg(QString::number(p.phi)) + .arg(QString::number(0)) + .arg(QString::number(p.theta)) + .arg(QString::number(p.phi)); // ÉèÖýÓÊÕµã + luascript = luascript + QString(u8"F2_nearFieldRequest.Label=\"F2\"\n"); + luascript = luascript + QString(u8"F2_nearFieldRequest_workplane=F2_nearFieldRequest.LocalWorkplane\n"); + luascript = luascript + QString(u8"F2_nearFieldRequest_workplane.Origin.X=%1\n").arg(QString::number(cp.x)); + luascript = luascript + QString(u8"F2_nearFieldRequest_workplane.Origin.Y=%1\n").arg(QString::number(cp.y)); + luascript = luascript + QString(u8"F2_nearFieldRequest_workplane.Origin.Z=%1\n").arg(QString::number(cp.z)); + luascript = luascript + QString(u8"F2_nearfieldAdvance=F2_nearFieldRequest.Advanced\n"); + luascript = luascript + QString(u8"F2_nearfieldAdvance.CalculationType=cf.Enums.NearFieldCalculationTypeEnum.Fields\n"); + luascript = luascript + QString(u8"F2_nearfieldAdvance.CalculateElectricFields=true\n"); + luascript = luascript + QString(u8"F2_nearfieldAdvance.CalculateMagneticFields=true\n"); + luascript = luascript + QString(u8"F2_nearfieldAdvance.ExportSettings.ASCIIEnabled=true\n"); + luascript = luascript + QString(u8"F2_nearfieldAdvance.ExportSettings.OutFileEnabled=true\n"); + luascript = luascript + QString(u8"F2_nearfieldAdvance.OnlyScatteredPartCalculationEnabled=true \n"); + luascript = luascript + QString(u8"\n"); + } + else {} + if (this->settingobj->F3) { + SphericalCoordinates p = AntSettingdict["F3"]; + CartesianCoordinates cp = sphericalToCartesian(p); + luascript = luascript + QString(u8"-- set Source\n"); + luascript = luascript + QString(u8"F3_farFieldSource = temp_standardConfiguration.Sources:AddFarFieldSource(F3_farfieldData)\n"); // ÉèÖ÷¢ÉäÔ´ + luascript = luascript + QString(u8"F3_farFieldSource.Label=\"F3\"\n"); + luascript = luascript + QString(u8"F3_farFieldSource.Position.U=%1\n").arg(QString::number(cp.x)); + luascript = luascript + QString(u8"F3_farFieldSource.Position.V=%1\n").arg(QString::number(cp.y)); + luascript = luascript + QString(u8"F3_farFieldSource.Position.N=%1\n").arg(QString::number(cp.z)); + luascript = luascript + QString(u8"F3_farFieldSource.Theta=%1\n").arg(QString::number(180 - p.theta)); + luascript = luascript + QString(u8"F3_farFieldSource.Phi=%1\n").arg(QString::number(180 + p.phi)); + luascript = luascript + QString(u8"F3_farFieldSource_workplane=F3_farFieldSource.LocalWorkplane\n"); + luascript = luascript + QString(u8"F3_farFieldSource_workplane.Origin.X=0 -- move reference Point\n"); + luascript = luascript + QString(u8"F3_farFieldSource_workplane.Origin.Y=0\n"); + luascript = luascript + QString(u8"F3_farFieldSource_workplane.Origin.Z=0 \n"); + luascript = luascript + QString(u8"\n"); + luascript = luascript + QString(u8"-- set nearfield\n"); + luascript = luascript + QString(u8"F3_nearFieldRequest=temp_standardConfiguration.NearFields:AddSpherical(%1,%2,%3,%4,%5,%6,1,1,1) -- nearfield \n").arg(QString::number(0)) + .arg(QString::number(p.theta)) + .arg(QString::number(p.phi)) + .arg(QString::number(0)) + .arg(QString::number(p.theta)) + .arg(QString::number(p.phi)); // ÉèÖýÓÊÕµã + luascript = luascript + QString(u8"F3_nearFieldRequest.Label=\"F3\"\n"); + luascript = luascript + QString(u8"F3_nearFieldRequest_workplane=F3_nearFieldRequest.LocalWorkplane\n"); + luascript = luascript + QString(u8"F3_nearFieldRequest_workplane.Origin.X=%1\n").arg(QString::number(cp.x)); + luascript = luascript + QString(u8"F3_nearFieldRequest_workplane.Origin.Y=%1\n").arg(QString::number(cp.y)); + luascript = luascript + QString(u8"F3_nearFieldRequest_workplane.Origin.Z=%1\n").arg(QString::number(cp.z)); + luascript = luascript + QString(u8"F3_nearfieldAdvance=F3_nearFieldRequest.Advanced\n"); + luascript = luascript + QString(u8"F3_nearfieldAdvance.CalculationType=cf.Enums.NearFieldCalculationTypeEnum.Fields\n"); + luascript = luascript + QString(u8"F3_nearfieldAdvance.CalculateElectricFields=true\n"); + luascript = luascript + QString(u8"F3_nearfieldAdvance.CalculateMagneticFields=true\n"); + luascript = luascript + QString(u8"F3_nearfieldAdvance.ExportSettings.ASCIIEnabled=true\n"); + luascript = luascript + QString(u8"F3_nearfieldAdvance.ExportSettings.OutFileEnabled=true\n"); + luascript = luascript + QString(u8"F3_nearfieldAdvance.OnlyScatteredPartCalculationEnabled=true \n"); + luascript = luascript + QString(u8"\n"); + } + else {} + if (this->settingobj->F4) { + SphericalCoordinates p = AntSettingdict["F4"]; + CartesianCoordinates cp = sphericalToCartesian(p); + luascript = luascript + QString(u8"-- set Source\n"); + luascript = luascript + QString(u8"F4_farFieldSource = temp_standardConfiguration.Sources:AddFarFieldSource(F4_farfieldData)\n"); // ÉèÖ÷¢ÉäÔ´ + luascript = luascript + QString(u8"F4_farFieldSource.Label=\"F4\"\n"); + luascript = luascript + QString(u8"F4_farFieldSource.Position.U=%1\n").arg(QString::number(cp.x)); + luascript = luascript + QString(u8"F4_farFieldSource.Position.V=%1\n").arg(QString::number(cp.y)); + luascript = luascript + QString(u8"F4_farFieldSource.Position.N=%1\n").arg(QString::number(cp.z)); + luascript = luascript + QString(u8"F4_farFieldSource.Theta=%1\n").arg(QString::number(180 - p.theta)); + luascript = luascript + QString(u8"F4_farFieldSource.Phi=%1\n").arg(QString::number(180 + p.phi)); + luascript = luascript + QString(u8"F4_farFieldSource_workplane=F4_farFieldSource.LocalWorkplane\n"); + luascript = luascript + QString(u8"F4_farFieldSource_workplane.Origin.X=0 -- move reference Point\n"); + luascript = luascript + QString(u8"F4_farFieldSource_workplane.Origin.Y=0\n"); + luascript = luascript + QString(u8"F4_farFieldSource_workplane.Origin.Z=0 \n"); + luascript = luascript + QString(u8"\n"); + luascript = luascript + QString(u8"-- set nearfield\n"); + luascript = luascript + QString(u8"F4_nearFieldRequest=temp_standardConfiguration.NearFields:AddSpherical(%1,%2,%3,%4,%5,%6,1,1,1) -- nearfield \n").arg(QString::number(0)) + .arg(QString::number(p.theta)) + .arg(QString::number(p.phi)) + .arg(QString::number(0)) + .arg(QString::number(p.theta)) + .arg(QString::number(p.phi)); // ÉèÖýÓÊÕµã + luascript = luascript + QString(u8"F4_nearFieldRequest.Label=\"F4\"\n"); + luascript = luascript + QString(u8"F4_nearFieldRequest_workplane=F4_nearFieldRequest.LocalWorkplane\n"); + luascript = luascript + QString(u8"F4_nearFieldRequest_workplane.Origin.X=%1\n").arg(QString::number(cp.x)); + luascript = luascript + QString(u8"F4_nearFieldRequest_workplane.Origin.Y=%1\n").arg(QString::number(cp.y)); + luascript = luascript + QString(u8"F4_nearFieldRequest_workplane.Origin.Z=%1\n").arg(QString::number(cp.z)); + luascript = luascript + QString(u8"F4_nearfieldAdvance=F4_nearFieldRequest.Advanced\n"); + luascript = luascript + QString(u8"F4_nearfieldAdvance.CalculationType=cf.Enums.NearFieldCalculationTypeEnum.Fields\n"); + luascript = luascript + QString(u8"F4_nearfieldAdvance.CalculateElectricFields=true\n"); + luascript = luascript + QString(u8"F4_nearfieldAdvance.CalculateMagneticFields=true\n"); + luascript = luascript + QString(u8"F4_nearfieldAdvance.ExportSettings.ASCIIEnabled=true\n"); + luascript = luascript + QString(u8"F4_nearfieldAdvance.ExportSettings.OutFileEnabled=true\n"); + luascript = luascript + QString(u8"F4_nearfieldAdvance.OnlyScatteredPartCalculationEnabled=true \n"); + luascript = luascript + QString(u8"\n"); + } + else {} + if (this->settingobj->F5) { + SphericalCoordinates p = AntSettingdict["F5"]; + CartesianCoordinates cp = sphericalToCartesian(p); + luascript = luascript + QString(u8"-- set Source\n"); + luascript = luascript + QString(u8"F5_farFieldSource = temp_standardConfiguration.Sources:AddFarFieldSource(F5_farfieldData)\n"); // ÉèÖ÷¢ÉäÔ´ + luascript = luascript + QString(u8"F5_farFieldSource.Label=\"F5\"\n"); + luascript = luascript + QString(u8"F5_farFieldSource.Position.U=%1\n").arg(QString::number(cp.x)); + luascript = luascript + QString(u8"F5_farFieldSource.Position.V=%1\n").arg(QString::number(cp.y)); + luascript = luascript + QString(u8"F5_farFieldSource.Position.N=%1\n").arg(QString::number(cp.z)); + luascript = luascript + QString(u8"F5_farFieldSource.Theta=%1\n").arg(QString::number(180 - p.theta)); + luascript = luascript + QString(u8"F5_farFieldSource.Phi=%1\n").arg(QString::number(180 + p.phi)); + luascript = luascript + QString(u8"F5_farFieldSource_workplane=F5_farFieldSource.LocalWorkplane\n"); + luascript = luascript + QString(u8"F5_farFieldSource_workplane.Origin.X=0 -- move reference Point\n"); + luascript = luascript + QString(u8"F5_farFieldSource_workplane.Origin.Y=0\n"); + luascript = luascript + QString(u8"F5_farFieldSource_workplane.Origin.Z=0 \n"); + luascript = luascript + QString(u8"\n"); + luascript = luascript + QString(u8"-- set nearfield\n"); + luascript = luascript + QString(u8"F5_nearFieldRequest=temp_standardConfiguration.NearFields:AddSpherical(%1,%2,%3,%4,%5,%6,1,1,1) -- nearfield \n").arg(QString::number(0)) + .arg(QString::number(p.theta)) + .arg(QString::number(p.phi)) + .arg(QString::number(0)) + .arg(QString::number(p.theta)) + .arg(QString::number(p.phi)); // ÉèÖýÓÊÕµã + luascript = luascript + QString(u8"F5_nearFieldRequest.Label=\"F5\"\n"); + luascript = luascript + QString(u8"F5_nearFieldRequest_workplane=F5_nearFieldRequest.LocalWorkplane\n"); + luascript = luascript + QString(u8"F5_nearFieldRequest_workplane.Origin.X=%1\n").arg(QString::number(cp.x)); + luascript = luascript + QString(u8"F5_nearFieldRequest_workplane.Origin.Y=%1\n").arg(QString::number(cp.y)); + luascript = luascript + QString(u8"F5_nearFieldRequest_workplane.Origin.Z=%1\n").arg(QString::number(cp.z)); + luascript = luascript + QString(u8"F5_nearfieldAdvance=F5_nearFieldRequest.Advanced\n"); + luascript = luascript + QString(u8"F5_nearfieldAdvance.CalculationType=cf.Enums.NearFieldCalculationTypeEnum.Fields\n"); + luascript = luascript + QString(u8"F5_nearfieldAdvance.CalculateElectricFields=true\n"); + luascript = luascript + QString(u8"F5_nearfieldAdvance.CalculateMagneticFields=true\n"); + luascript = luascript + QString(u8"F5_nearfieldAdvance.ExportSettings.ASCIIEnabled=true\n"); + luascript = luascript + QString(u8"F5_nearfieldAdvance.ExportSettings.OutFileEnabled=true\n"); + luascript = luascript + QString(u8"F5_nearfieldAdvance.OnlyScatteredPartCalculationEnabled=true \n"); + luascript = luascript + QString(u8"\n"); + } + else {} + if (this->settingobj->F6) { + SphericalCoordinates p = AntSettingdict["F6"]; + CartesianCoordinates cp = sphericalToCartesian(p); + luascript = luascript + QString(u8"-- set Source\n"); + luascript = luascript + QString(u8"F6_farFieldSource = temp_standardConfiguration.Sources:AddFarFieldSource(F6_farfieldData)\n"); // ÉèÖ÷¢ÉäÔ´ + luascript = luascript + QString(u8"F6_farFieldSource.Label=\"F6\"\n"); + luascript = luascript + QString(u8"F6_farFieldSource.Position.U=%1\n").arg(QString::number(cp.x)); + luascript = luascript + QString(u8"F6_farFieldSource.Position.V=%1\n").arg(QString::number(cp.y)); + luascript = luascript + QString(u8"F6_farFieldSource.Position.N=%1\n").arg(QString::number(cp.z)); + luascript = luascript + QString(u8"F6_farFieldSource.Theta=%1\n").arg(QString::number(180 - p.theta)); + luascript = luascript + QString(u8"F6_farFieldSource.Phi=%1\n").arg(QString::number(180 + p.phi)); + luascript = luascript + QString(u8"F6_farFieldSource_workplane=F6_farFieldSource.LocalWorkplane\n"); + luascript = luascript + QString(u8"F6_farFieldSource_workplane.Origin.X=0 -- move reference Point\n"); + luascript = luascript + QString(u8"F6_farFieldSource_workplane.Origin.Y=0\n"); + luascript = luascript + QString(u8"F6_farFieldSource_workplane.Origin.Z=0 \n"); + luascript = luascript + QString(u8"\n"); + luascript = luascript + QString(u8"-- set nearfield\n"); + luascript = luascript + QString(u8"F6_nearFieldRequest=temp_standardConfiguration.NearFields:AddSpherical(%1,%2,%3,%4,%5,%6,1,1,1) -- nearfield \n").arg(QString::number(0)) + .arg(QString::number(p.theta)) + .arg(QString::number(p.phi)) + .arg(QString::number(0)) + .arg(QString::number(p.theta)) + .arg(QString::number(p.phi)); // ÉèÖýÓÊÕµã + luascript = luascript + QString(u8"F6_nearFieldRequest.Label=\"F6\"\n"); + luascript = luascript + QString(u8"F6_nearFieldRequest_workplane=F6_nearFieldRequest.LocalWorkplane\n"); + luascript = luascript + QString(u8"F6_nearFieldRequest_workplane.Origin.X=%1\n").arg(QString::number(cp.x)); + luascript = luascript + QString(u8"F6_nearFieldRequest_workplane.Origin.Y=%1\n").arg(QString::number(cp.y)); + luascript = luascript + QString(u8"F6_nearFieldRequest_workplane.Origin.Z=%1\n").arg(QString::number(cp.z)); + luascript = luascript + QString(u8"F6_nearfieldAdvance=F6_nearFieldRequest.Advanced\n"); + luascript = luascript + QString(u8"F6_nearfieldAdvance.CalculationType=cf.Enums.NearFieldCalculationTypeEnum.Fields\n"); + luascript = luascript + QString(u8"F6_nearfieldAdvance.CalculateElectricFields=true\n"); + luascript = luascript + QString(u8"F6_nearfieldAdvance.CalculateMagneticFields=true\n"); + luascript = luascript + QString(u8"F6_nearfieldAdvance.ExportSettings.ASCIIEnabled=true\n"); + luascript = luascript + QString(u8"F6_nearfieldAdvance.ExportSettings.OutFileEnabled=true\n"); + luascript = luascript + QString(u8"F6_nearfieldAdvance.OnlyScatteredPartCalculationEnabled=true \n"); + luascript = luascript + QString(u8"\n"); + } + else {} + if (this->settingobj->F7) { + SphericalCoordinates p = AntSettingdict["F7"]; + CartesianCoordinates cp = sphericalToCartesian(p); + luascript = luascript + QString(u8"-- set Source\n"); + luascript = luascript + QString(u8"F7_farFieldSource = temp_standardConfiguration.Sources:AddFarFieldSource(F7_farfieldData)\n"); // ÉèÖ÷¢ÉäÔ´ + luascript = luascript + QString(u8"F7_farFieldSource.Label=\"F7\"\n"); + luascript = luascript + QString(u8"F7_farFieldSource.Position.U=%1\n").arg(QString::number(cp.x)); + luascript = luascript + QString(u8"F7_farFieldSource.Position.V=%1\n").arg(QString::number(cp.y)); + luascript = luascript + QString(u8"F7_farFieldSource.Position.N=%1\n").arg(QString::number(cp.z)); + luascript = luascript + QString(u8"F7_farFieldSource.Theta=%1\n").arg(QString::number(180 - p.theta)); + luascript = luascript + QString(u8"F7_farFieldSource.Phi=%1\n").arg(QString::number(180 + p.phi)); + luascript = luascript + QString(u8"F7_farFieldSource_workplane=F7_farFieldSource.LocalWorkplane\n"); + luascript = luascript + QString(u8"F7_farFieldSource_workplane.Origin.X=0 -- move reference Point\n"); + luascript = luascript + QString(u8"F7_farFieldSource_workplane.Origin.Y=0\n"); + luascript = luascript + QString(u8"F7_farFieldSource_workplane.Origin.Z=0 \n"); + luascript = luascript + QString(u8"\n"); + luascript = luascript + QString(u8"-- set nearfield\n"); + luascript = luascript + QString(u8"F7_nearFieldRequest=temp_standardConfiguration.NearFields:AddSpherical(%1,%2,%3,%4,%5,%6,1,1,1) -- nearfield \n").arg(QString::number(0)) + .arg(QString::number(p.theta)) + .arg(QString::number(p.phi)) + .arg(QString::number(0)) + .arg(QString::number(p.theta)) + .arg(QString::number(p.phi)); // ÉèÖýÓÊÕµã + luascript = luascript + QString(u8"F7_nearFieldRequest.Label=\"F7\"\n"); + luascript = luascript + QString(u8"F7_nearFieldRequest_workplane=F7_nearFieldRequest.LocalWorkplane\n"); + luascript = luascript + QString(u8"F7_nearFieldRequest_workplane.Origin.X=%1\n").arg(QString::number(cp.x)); + luascript = luascript + QString(u8"F7_nearFieldRequest_workplane.Origin.Y=%1\n").arg(QString::number(cp.y)); + luascript = luascript + QString(u8"F7_nearFieldRequest_workplane.Origin.Z=%1\n").arg(QString::number(cp.z)); + luascript = luascript + QString(u8"F7_nearfieldAdvance=F7_nearFieldRequest.Advanced\n"); + luascript = luascript + QString(u8"F7_nearfieldAdvance.CalculationType=cf.Enums.NearFieldCalculationTypeEnum.Fields\n"); + luascript = luascript + QString(u8"F7_nearfieldAdvance.CalculateElectricFields=true\n"); + luascript = luascript + QString(u8"F7_nearfieldAdvance.CalculateMagneticFields=true\n"); + luascript = luascript + QString(u8"F7_nearfieldAdvance.ExportSettings.ASCIIEnabled=true\n"); + luascript = luascript + QString(u8"F7_nearfieldAdvance.ExportSettings.OutFileEnabled=true\n"); + luascript = luascript + QString(u8"F7_nearfieldAdvance.OnlyScatteredPartCalculationEnabled=true \n"); + luascript = luascript + QString(u8"\n"); + } + else {} + if (this->settingobj->F8) { + SphericalCoordinates p = AntSettingdict["F8"]; + CartesianCoordinates cp = sphericalToCartesian(p); + luascript = luascript + QString(u8"-- set Source\n"); + luascript = luascript + QString(u8"F8_farFieldSource = temp_standardConfiguration.Sources:AddFarFieldSource(F8_farfieldData)\n"); // ÉèÖ÷¢ÉäÔ´ + luascript = luascript + QString(u8"F8_farFieldSource.Label=\"F8\"\n"); + luascript = luascript + QString(u8"F8_farFieldSource.Position.U=%1\n").arg(QString::number(cp.x)); + luascript = luascript + QString(u8"F8_farFieldSource.Position.V=%1\n").arg(QString::number(cp.y)); + luascript = luascript + QString(u8"F8_farFieldSource.Position.N=%1\n").arg(QString::number(cp.z)); + luascript = luascript + QString(u8"F8_farFieldSource.Theta=%1\n").arg(QString::number(180 - p.theta)); + luascript = luascript + QString(u8"F8_farFieldSource.Phi=%1\n").arg(QString::number(180 + p.phi)); + luascript = luascript + QString(u8"F8_farFieldSource_workplane=F8_farFieldSource.LocalWorkplane\n"); + luascript = luascript + QString(u8"F8_farFieldSource_workplane.Origin.X=0 -- move reference Point\n"); + luascript = luascript + QString(u8"F8_farFieldSource_workplane.Origin.Y=0\n"); + luascript = luascript + QString(u8"F8_farFieldSource_workplane.Origin.Z=0 \n"); + luascript = luascript + QString(u8"\n"); + luascript = luascript + QString(u8"-- set nearfield\n"); + luascript = luascript + QString(u8"F8_nearFieldRequest=temp_standardConfiguration.NearFields:AddSpherical(%1,%2,%3,%4,%5,%6,1,1,1) -- nearfield \n").arg(QString::number(0)) + .arg(QString::number(p.theta)) + .arg(QString::number(p.phi)) + .arg(QString::number(0)) + .arg(QString::number(p.theta)) + .arg(QString::number(p.phi)); // ÉèÖýÓÊÕµã + luascript = luascript + QString(u8"F8_nearFieldRequest.Label=\"F8\"\n"); + luascript = luascript + QString(u8"F8_nearFieldRequest_workplane=F8_nearFieldRequest.LocalWorkplane\n"); + luascript = luascript + QString(u8"F8_nearFieldRequest_workplane.Origin.X=%1\n").arg(QString::number(cp.x)); + luascript = luascript + QString(u8"F8_nearFieldRequest_workplane.Origin.Y=%1\n").arg(QString::number(cp.y)); + luascript = luascript + QString(u8"F8_nearFieldRequest_workplane.Origin.Z=%1\n").arg(QString::number(cp.z)); + luascript = luascript + QString(u8"F8_nearfieldAdvance=F8_nearFieldRequest.Advanced\n"); + luascript = luascript + QString(u8"F8_nearfieldAdvance.CalculationType=cf.Enums.NearFieldCalculationTypeEnum.Fields\n"); + luascript = luascript + QString(u8"F8_nearfieldAdvance.CalculateElectricFields=true\n"); + luascript = luascript + QString(u8"F8_nearfieldAdvance.CalculateMagneticFields=true\n"); + luascript = luascript + QString(u8"F8_nearfieldAdvance.ExportSettings.ASCIIEnabled=true\n"); + luascript = luascript + QString(u8"F8_nearfieldAdvance.ExportSettings.OutFileEnabled=true\n"); + luascript = luascript + QString(u8"F8_nearfieldAdvance.OnlyScatteredPartCalculationEnabled=true \n"); + luascript = luascript + QString(u8"\n"); + } + else {} + if (this->settingobj->F9) { + SphericalCoordinates p = AntSettingdict["F9"]; + CartesianCoordinates cp = sphericalToCartesian(p); + luascript = luascript + QString(u8"-- set Source\n"); + luascript = luascript + QString(u8"F9_farFieldSource = temp_standardConfiguration.Sources:AddFarFieldSource(F9_farfieldData)\n"); // ÉèÖ÷¢ÉäÔ´ + luascript = luascript + QString(u8"F9_farFieldSource.Label=\"F9\"\n"); + luascript = luascript + QString(u8"F9_farFieldSource.Position.U=%1\n").arg(QString::number(cp.x)); + luascript = luascript + QString(u8"F9_farFieldSource.Position.V=%1\n").arg(QString::number(cp.y)); + luascript = luascript + QString(u8"F9_farFieldSource.Position.N=%1\n").arg(QString::number(cp.z)); + luascript = luascript + QString(u8"F9_farFieldSource.Theta=%1\n").arg(QString::number(180 - p.theta)); + luascript = luascript + QString(u8"F9_farFieldSource.Phi=%1\n").arg(QString::number(180 + p.phi)); + luascript = luascript + QString(u8"F9_farFieldSource_workplane=F9_farFieldSource.LocalWorkplane\n"); + luascript = luascript + QString(u8"F9_farFieldSource_workplane.Origin.X=0 -- move reference Point\n"); + luascript = luascript + QString(u8"F9_farFieldSource_workplane.Origin.Y=0\n"); + luascript = luascript + QString(u8"F9_farFieldSource_workplane.Origin.Z=0 \n"); + luascript = luascript + QString(u8"\n"); + luascript = luascript + QString(u8"-- set nearfield\n"); + luascript = luascript + QString(u8"F9_nearFieldRequest=temp_standardConfiguration.NearFields:AddSpherical(%1,%2,%3,%4,%5,%6,1,1,1) -- nearfield \n").arg(QString::number(0)) + .arg(QString::number(p.theta)) + .arg(QString::number(p.phi)) + .arg(QString::number(0)) + .arg(QString::number(p.theta)) + .arg(QString::number(p.phi)); // ÉèÖýÓÊÕµã + luascript = luascript + QString(u8"F9_nearFieldRequest.Label=\"F9\"\n"); + luascript = luascript + QString(u8"F9_nearFieldRequest_workplane=F9_nearFieldRequest.LocalWorkplane\n"); + luascript = luascript + QString(u8"F9_nearFieldRequest_workplane.Origin.X=%1\n").arg(QString::number(cp.x)); + luascript = luascript + QString(u8"F9_nearFieldRequest_workplane.Origin.Y=%1\n").arg(QString::number(cp.y)); + luascript = luascript + QString(u8"F9_nearFieldRequest_workplane.Origin.Z=%1\n").arg(QString::number(cp.z)); + luascript = luascript + QString(u8"F9_nearfieldAdvance=F9_nearFieldRequest.Advanced\n"); + luascript = luascript + QString(u8"F9_nearfieldAdvance.CalculationType=cf.Enums.NearFieldCalculationTypeEnum.Fields\n"); + luascript = luascript + QString(u8"F9_nearfieldAdvance.CalculateElectricFields=true\n"); + luascript = luascript + QString(u8"F9_nearfieldAdvance.CalculateMagneticFields=true\n"); + luascript = luascript + QString(u8"F9_nearfieldAdvance.ExportSettings.ASCIIEnabled=true\n"); + luascript = luascript + QString(u8"F9_nearfieldAdvance.ExportSettings.OutFileEnabled=true\n"); + luascript = luascript + QString(u8"F9_nearfieldAdvance.OnlyScatteredPartCalculationEnabled=true \n"); + luascript = luascript + QString(u8"\n"); + } + else {} + if (this->settingobj->F10) { + SphericalCoordinates p = AntSettingdict["F10"]; + CartesianCoordinates cp = sphericalToCartesian(p); + luascript = luascript + QString(u8"-- set Source\n"); + luascript = luascript + QString(u8"F10_farFieldSource = temp_standardConfiguration.Sources:AddFarFieldSource(F10_farfieldData)\n"); // ÉèÖ÷¢ÉäÔ´ + luascript = luascript + QString(u8"F10_farFieldSource.Label=\"F10\"\n"); + luascript = luascript + QString(u8"F10_farFieldSource.Position.U=%1\n").arg(QString::number(cp.x)); + luascript = luascript + QString(u8"F10_farFieldSource.Position.V=%1\n").arg(QString::number(cp.y)); + luascript = luascript + QString(u8"F10_farFieldSource.Position.N=%1\n").arg(QString::number(cp.z)); + luascript = luascript + QString(u8"F10_farFieldSource.Theta=%1\n").arg(QString::number(180 - p.theta)); + luascript = luascript + QString(u8"F10_farFieldSource.Phi=%1\n").arg(QString::number(180 + p.phi)); + luascript = luascript + QString(u8"F10_farFieldSource_workplane=F10_farFieldSource.LocalWorkplane\n"); + luascript = luascript + QString(u8"F10_farFieldSource_workplane.Origin.X=0 -- move reference Point\n"); + luascript = luascript + QString(u8"F10_farFieldSource_workplane.Origin.Y=0\n"); + luascript = luascript + QString(u8"F10_farFieldSource_workplane.Origin.Z=0 \n"); + luascript = luascript + QString(u8"\n"); + luascript = luascript + QString(u8"-- set nearfield\n"); + luascript = luascript + QString(u8"F10_nearFieldRequest=temp_standardConfiguration.NearFields:AddSpherical(%1,%2,%3,%4,%5,%6,1,1,1) -- nearfield \n").arg(QString::number(0)) + .arg(QString::number(p.theta)) + .arg(QString::number(p.phi)) + .arg(QString::number(0)) + .arg(QString::number(p.theta)) + .arg(QString::number(p.phi)); // ÉèÖýÓÊÕµã + luascript = luascript + QString(u8"F10_nearFieldRequest.Label=\"F10\"\n"); + luascript = luascript + QString(u8"F10_nearFieldRequest_workplane=F10_nearFieldRequest.LocalWorkplane\n"); + luascript = luascript + QString(u8"F10_nearFieldRequest_workplane.Origin.X=%1\n").arg(QString::number(cp.x)); + luascript = luascript + QString(u8"F10_nearFieldRequest_workplane.Origin.Y=%1\n").arg(QString::number(cp.y)); + luascript = luascript + QString(u8"F10_nearFieldRequest_workplane.Origin.Z=%1\n").arg(QString::number(cp.z)); + luascript = luascript + QString(u8"F10_nearfieldAdvance=F10_nearFieldRequest.Advanced\n"); + luascript = luascript + QString(u8"F10_nearfieldAdvance.CalculationType=cf.Enums.NearFieldCalculationTypeEnum.Fields\n"); + luascript = luascript + QString(u8"F10_nearfieldAdvance.CalculateElectricFields=true\n"); + luascript = luascript + QString(u8"F10_nearfieldAdvance.CalculateMagneticFields=true\n"); + luascript = luascript + QString(u8"F10_nearfieldAdvance.ExportSettings.ASCIIEnabled=true\n"); + luascript = luascript + QString(u8"F10_nearfieldAdvance.ExportSettings.OutFileEnabled=true\n"); + luascript = luascript + QString(u8"F10_nearfieldAdvance.OnlyScatteredPartCalculationEnabled=true \n"); + luascript = luascript + QString(u8"\n"); + } + else {} + if (this->settingobj->F11) { + SphericalCoordinates p = AntSettingdict["F11"]; + CartesianCoordinates cp = sphericalToCartesian(p); + luascript = luascript + QString(u8"-- set Source\n"); + luascript = luascript + QString(u8"F11_farFieldSource = temp_standardConfiguration.Sources:AddFarFieldSource(F11_farfieldData)\n"); // ÉèÖ÷¢ÉäÔ´ + luascript = luascript + QString(u8"F11_farFieldSource.Label=\"F11\"\n"); + luascript = luascript + QString(u8"F11_farFieldSource.Position.U=%1\n").arg(QString::number(cp.x)); + luascript = luascript + QString(u8"F11_farFieldSource.Position.V=%1\n").arg(QString::number(cp.y)); + luascript = luascript + QString(u8"F11_farFieldSource.Position.N=%1\n").arg(QString::number(cp.z)); + luascript = luascript + QString(u8"F11_farFieldSource.Theta=%1\n").arg(QString::number(180 - p.theta)); + luascript = luascript + QString(u8"F11_farFieldSource.Phi=%1\n").arg(QString::number(180 + p.phi)); + luascript = luascript + QString(u8"F11_farFieldSource_workplane=F11_farFieldSource.LocalWorkplane\n"); + luascript = luascript + QString(u8"F11_farFieldSource_workplane.Origin.X=0 -- move reference Point\n"); + luascript = luascript + QString(u8"F11_farFieldSource_workplane.Origin.Y=0\n"); + luascript = luascript + QString(u8"F11_farFieldSource_workplane.Origin.Z=0 \n"); + luascript = luascript + QString(u8"\n"); + luascript = luascript + QString(u8"-- set nearfield\n"); + luascript = luascript + QString(u8"F11_nearFieldRequest=temp_standardConfiguration.NearFields:AddSpherical(%1,%2,%3,%4,%5,%6,1,1,1) -- nearfield \n").arg(QString::number(0)) + .arg(QString::number(p.theta)) + .arg(QString::number(p.phi)) + .arg(QString::number(0)) + .arg(QString::number(p.theta)) + .arg(QString::number(p.phi)); // ÉèÖýÓÊÕµã + luascript = luascript + QString(u8"F11_nearFieldRequest.Label=\"F11\"\n"); + luascript = luascript + QString(u8"F11_nearFieldRequest_workplane=F11_nearFieldRequest.LocalWorkplane\n"); + luascript = luascript + QString(u8"F11_nearFieldRequest_workplane.Origin.X=%1\n").arg(QString::number(cp.x)); + luascript = luascript + QString(u8"F11_nearFieldRequest_workplane.Origin.Y=%1\n").arg(QString::number(cp.y)); + luascript = luascript + QString(u8"F11_nearFieldRequest_workplane.Origin.Z=%1\n").arg(QString::number(cp.z)); + luascript = luascript + QString(u8"F11_nearfieldAdvance=F11_nearFieldRequest.Advanced\n"); + luascript = luascript + QString(u8"F11_nearfieldAdvance.CalculationType=cf.Enums.NearFieldCalculationTypeEnum.Fields\n"); + luascript = luascript + QString(u8"F11_nearfieldAdvance.CalculateElectricFields=true\n"); + luascript = luascript + QString(u8"F11_nearfieldAdvance.CalculateMagneticFields=true\n"); + luascript = luascript + QString(u8"F11_nearfieldAdvance.ExportSettings.ASCIIEnabled=true\n"); + luascript = luascript + QString(u8"F11_nearfieldAdvance.ExportSettings.OutFileEnabled=true\n"); + luascript = luascript + QString(u8"F11_nearfieldAdvance.OnlyScatteredPartCalculationEnabled=true \n"); + luascript = luascript + QString(u8"\n"); + } + else {} + if (this->settingobj->F12) { + SphericalCoordinates p = AntSettingdict["F12"]; + CartesianCoordinates cp = sphericalToCartesian(p); + luascript = luascript + QString(u8"-- set Source\n"); + luascript = luascript + QString(u8"F12_farFieldSource = temp_standardConfiguration.Sources:AddFarFieldSource(F12_farfieldData)\n"); // ÉèÖ÷¢ÉäÔ´ + luascript = luascript + QString(u8"F12_farFieldSource.Label=\"F12\"\n"); + luascript = luascript + QString(u8"F12_farFieldSource.Position.U=%1\n").arg(QString::number(cp.x)); + luascript = luascript + QString(u8"F12_farFieldSource.Position.V=%1\n").arg(QString::number(cp.y)); + luascript = luascript + QString(u8"F12_farFieldSource.Position.N=%1\n").arg(QString::number(cp.z)); + luascript = luascript + QString(u8"F12_farFieldSource.Theta=%1\n").arg(QString::number(180 - p.theta)); + luascript = luascript + QString(u8"F12_farFieldSource.Phi=%1\n").arg(QString::number(180 + p.phi)); + luascript = luascript + QString(u8"F12_farFieldSource_workplane=F12_farFieldSource.LocalWorkplane\n"); + luascript = luascript + QString(u8"F12_farFieldSource_workplane.Origin.X=0 -- move reference Point\n"); + luascript = luascript + QString(u8"F12_farFieldSource_workplane.Origin.Y=0\n"); + luascript = luascript + QString(u8"F12_farFieldSource_workplane.Origin.Z=0 \n"); + luascript = luascript + QString(u8"\n"); + luascript = luascript + QString(u8"-- set nearfield\n"); + luascript = luascript + QString(u8"F12_nearFieldRequest=temp_standardConfiguration.NearFields:AddSpherical(%1,%2,%3,%4,%5,%6,1,1,1) -- nearfield \n").arg(QString::number(0)) + .arg(QString::number(p.theta)) + .arg(QString::number(p.phi)) + .arg(QString::number(0)) + .arg(QString::number(p.theta)) + .arg(QString::number(p.phi)); // ÉèÖýÓÊÕµã + luascript = luascript + QString(u8"F12_nearFieldRequest.Label=\"F12\"\n"); + luascript = luascript + QString(u8"F12_nearFieldRequest_workplane=F12_nearFieldRequest.LocalWorkplane\n"); + luascript = luascript + QString(u8"F12_nearFieldRequest_workplane.Origin.X=%1\n").arg(QString::number(cp.x)); + luascript = luascript + QString(u8"F12_nearFieldRequest_workplane.Origin.Y=%1\n").arg(QString::number(cp.y)); + luascript = luascript + QString(u8"F12_nearFieldRequest_workplane.Origin.Z=%1\n").arg(QString::number(cp.z)); + luascript = luascript + QString(u8"F12_nearfieldAdvance=F12_nearFieldRequest.Advanced\n"); + luascript = luascript + QString(u8"F12_nearfieldAdvance.CalculationType=cf.Enums.NearFieldCalculationTypeEnum.Fields\n"); + luascript = luascript + QString(u8"F12_nearfieldAdvance.CalculateElectricFields=true\n"); + luascript = luascript + QString(u8"F12_nearfieldAdvance.CalculateMagneticFields=true\n"); + luascript = luascript + QString(u8"F12_nearfieldAdvance.ExportSettings.ASCIIEnabled=true\n"); + luascript = luascript + QString(u8"F12_nearfieldAdvance.ExportSettings.OutFileEnabled=true\n"); + luascript = luascript + QString(u8"F12_nearfieldAdvance.OnlyScatteredPartCalculationEnabled=true \n"); + luascript = luascript + QString(u8"\n"); + } + else {} + } + else {} + + } + else {} + if (this->settingobj->farfield) { // Ô¶³¡ + + if (this->settingobj->A1) { + SphericalCoordinates p = AntSettingdict["A1"]; + luascript = luascript + QString(u8"A1_temp_source = temp_standardConfiguration.Sources:AddPlaneWave(%1, %2)\n").arg(QString::number(p.theta)).arg(QString::number(p.phi)); + luascript = luascript + QString(u8"A1_temp_source.Label = \"%1\"\n").arg("A1"); + luascript = luascript + QString(u8"A1_temp_source.PolarisationAngle = 0\n"); + luascript = luascript + QString(u8"A1_temp_source_workplane = A1_temp_source.LocalWorkplane\n"); + luascript = luascript + QString(u8"A1_temp_source_workplane.Origin.X = 0\n"); + luascript = luascript + QString(u8"A1_temp_source_workplane.Origin.Y = 0\n"); + luascript = luascript + QString(u8"A1_temp_source_workplane.Origin.Z = 0\n"); + luascript = luascript + QString(u8"\n"); + + luascript = luascript + QString(u8"A1_farFieldRequest = temp_standardConfiguration.FarFields:Add(0,0,0,0,1,1)\n"); + luascript = luascript + QString(u8"A1_farFieldRequest.Label =\"%1\"\n").arg("A1"); + luascript = luascript + QString(u8"A1_farFieldRequest.CalculationDirection=cf.Enums.FarFieldCalculationDirectionEnum.FromPlaneWave\n"); + luascript = luascript + QString(u8"\n"); + } + else {} + if (this->settingobj->A2) { + SphericalCoordinates p = AntSettingdict["A2"]; + luascript = luascript + QString(u8"A2_temp_source = temp_standardConfiguration.Sources:AddPlaneWave(%1, %2)\n").arg(QString::number(p.theta)).arg(QString::number(p.phi)); + luascript = luascript + QString(u8"A2_temp_source.Label = \"%1\"\n").arg("A2"); + luascript = luascript + QString(u8"A2_temp_source.PolarisationAngle = 0\n"); + luascript = luascript + QString(u8"A2_temp_source_workplane = A2_temp_source.LocalWorkplane\n"); + luascript = luascript + QString(u8"A2_temp_source_workplane.Origin.X = 0\n"); + luascript = luascript + QString(u8"A2_temp_source_workplane.Origin.Y = 0\n"); + luascript = luascript + QString(u8"A2_temp_source_workplane.Origin.Z = 0\n"); + luascript = luascript + QString(u8"\n"); + + luascript = luascript + QString(u8"A2_farFieldRequest = temp_standardConfiguration.FarFields:Add(0,0,0,0,1,1)\n"); + luascript = luascript + QString(u8"A2_farFieldRequest.Label =\"%1\"\n").arg("A2"); + luascript = luascript + QString(u8"A2_farFieldRequest.CalculationDirection=cf.Enums.FarFieldCalculationDirectionEnum.FromPlaneWave\n"); + luascript = luascript + QString(u8"\n"); + } + else {} + if (this->settingobj->enableScatter) { + if (this->settingobj->S1) { + SphericalCoordinates p = AntSettingdict["S1"]; + luascript = luascript + QString(u8"S1_temp_source = temp_standardConfiguration.Sources:AddPlaneWave(%1, %2)\n").arg(QString::number(p.theta)).arg(QString::number(p.phi)); + luascript = luascript + QString(u8"S1_temp_source.Label = \"%1\"\n").arg("S1"); + luascript = luascript + QString(u8"S1_temp_source.PolarisationAngle = 0\n"); + luascript = luascript + QString(u8"S1_temp_source_workplane = S1_temp_source.LocalWorkplane\n"); + luascript = luascript + QString(u8"S1_temp_source_workplane.Origin.X = 0\n"); + luascript = luascript + QString(u8"S1_temp_source_workplane.Origin.Y = 0\n"); + luascript = luascript + QString(u8"S1_temp_source_workplane.Origin.Z = 0\n"); + luascript = luascript + QString(u8"\n"); + + luascript = luascript + QString(u8"S1_farFieldRequest = temp_standardConfiguration.FarFields:Add(0,0,0,0,1,1)\n"); + luascript = luascript + QString(u8"S1_farFieldRequest.Label =\"%1\"\n").arg("S1"); + luascript = luascript + QString(u8"S1_farFieldRequest.CalculationDirection=cf.Enums.FarFieldCalculationDirectionEnum.FromPlaneWave\n\n"); + luascript = luascript + QString(u8"\n"); + } + else {} + if (this->settingobj->S3) { // ·ÂÕÕS1 ,¹¹½¨ S3 µÄ´´½¨ + SphericalCoordinates p_S3 = AntSettingdict["S3"]; + luascript = luascript + QString(u8"S3_temp_source = temp_standardConfiguration.Sources:AddPlaneWave(%1, %2)\n").arg(QString::number(p_S3.theta)).arg(QString::number(p_S3.phi)); + luascript = luascript + QString(u8"S3_temp_source.Label = \"%1\"\n").arg("S3"); + luascript = luascript + QString(u8"S3_temp_source.PolarisationAngle = 0\n"); + luascript = luascript + QString(u8"S3_temp_source_workplane = S3_temp_source.LocalWorkplane\n"); + luascript = luascript + QString(u8"S3_temp_source_workplane.Origin.X = 0\n"); + luascript = luascript + QString(u8"S3_temp_source_workplane.Origin.Y = 0\n"); + luascript = luascript + QString(u8"S3_temp_source_workplane.Origin.Z = 0\n"); + luascript = luascript + QString(u8"\n"); + luascript = luascript + QString(u8"S3_farFieldRequest = temp_standardConfiguration.FarFields:Add(0,0,0,0,1,1)\n"); + luascript = luascript + QString(u8"S3_farFieldRequest.Label =\"%1\"\n").arg("S3"); + luascript = luascript + QString(u8"S3_farFieldRequest.CalculationDirection=cf.Enums.FarFieldCalculationDirectionEnum.FromPlaneWave\n\n"); + luascript = luascript + QString(u8"\n"); + + } + else {} + if (this->settingobj->S5) { + SphericalCoordinates p_S5 = AntSettingdict["S5"]; + luascript = luascript + QString(u8"S5_temp_source = temp_standardConfiguration.Sources:AddPlaneWave(%1, %2)\n").arg(QString::number(p_S5.theta)).arg(QString::number(p_S5.phi)); + luascript = luascript + QString(u8"S5_temp_source.Label = \"%1\"\n").arg("S5"); + luascript = luascript + QString(u8"S5_temp_source.PolarisationAngle = 0\n"); + luascript = luascript + QString(u8"S5_temp_source_workplane = S5_temp_source.LocalWorkplane\n"); + luascript = luascript + QString(u8"S5_temp_source_workplane.Origin.X = 0\n"); + luascript = luascript + QString(u8"S5_temp_source_workplane.Origin.Y = 0\n"); + luascript = luascript + QString(u8"S5_temp_source_workplane.Origin.Z = 0\n"); + luascript = luascript + QString(u8"\n"); + + luascript = luascript + QString(u8"S5_farFieldRequest = temp_standardConfiguration.FarFields:Add(0,0,0,0,1,1)\n"); + luascript = luascript + QString(u8"S5_farFieldRequest.Label =\"%1\"\n").arg("S5"); + luascript = luascript + QString(u8"S5_farFieldRequest.CalculationDirection=cf.Enums.FarFieldCalculationDirectionEnum.FromPlaneWave\n\n"); + luascript = luascript + QString(u8"\n"); + + } + else {} + if (this->settingobj->S8) { + SphericalCoordinates p_S8 = AntSettingdict["S8"]; + luascript = luascript + QString(u8"S8_temp_source = temp_standardConfiguration.Sources:AddPlaneWave(%1, %2)\n").arg(QString::number(p_S8.theta)).arg(QString::number(p_S8.phi)); + luascript = luascript + QString(u8"S8_temp_source.Label = \"%1\"\n").arg("S8"); + luascript = luascript + QString(u8"S8_temp_source.PolarisationAngle = 0\n"); + luascript = luascript + QString(u8"S8_temp_source_workplane = S8_temp_source.LocalWorkplane\n"); + luascript = luascript + QString(u8"S8_temp_source_workplane.Origin.X = 0\n"); + luascript = luascript + QString(u8"S8_temp_source_workplane.Origin.Y = 0\n"); + luascript = luascript + QString(u8"S8_temp_source_workplane.Origin.Z = 0\n"); + luascript = luascript + QString(u8"\n"); + luascript = luascript + QString(u8"S8_farFieldRequest = temp_standardConfiguration.FarFields:Add(0,0,0,0,1,1)\n"); + luascript = luascript + QString(u8"S8_farFieldRequest.Label =\"%1\"\n").arg("S8"); + luascript = luascript + QString(u8"S8_farFieldRequest.CalculationDirection=cf.Enums.FarFieldCalculationDirectionEnum.FromPlaneWave\n\n"); + luascript = luascript + QString(u8"\n"); + + } + else {} + if (this->settingobj->S10) { + SphericalCoordinates p_S10 = AntSettingdict["S10"]; + luascript = luascript + QString(u8"S10_temp_source = temp_standardConfiguration.Sources:AddPlaneWave(%1, %2)\n").arg(QString::number(p_S10.theta)).arg(QString::number(p_S10.phi)); + luascript = luascript + QString(u8"S10_temp_source.Label = \"%1\"\n").arg("S10"); + luascript = luascript + QString(u8"S10_temp_source.PolarisationAngle = 0\n"); + luascript = luascript + QString(u8"S10_temp_source_workplane = S10_temp_source.LocalWorkplane\n"); + luascript = luascript + QString(u8"S10_temp_source_workplane.Origin.X = 0\n"); + luascript = luascript + QString(u8"S10_temp_source_workplane.Origin.Y = 0\n"); + luascript = luascript + QString(u8"S10_temp_source_workplane.Origin.Z = 0\n"); + luascript = luascript + QString(u8"\n"); + luascript = luascript + QString(u8"S10_farFieldRequest = temp_standardConfiguration.FarFields:Add(0,0,0,0,1,1)\n"); + luascript = luascript + QString(u8"S10_farFieldRequest.Label =\"%1\"\n").arg("S10"); + luascript = luascript + QString(u8"S10_farFieldRequest.CalculationDirection=cf.Enums.FarFieldCalculationDirectionEnum.FromPlaneWave\n\n"); + luascript = luascript + QString(u8"\n"); + + } + else {} + if (this->settingobj->S12) { + SphericalCoordinates p_S12 = AntSettingdict["S12"]; + luascript = luascript + QString(u8"S12_temp_source = temp_standardConfiguration.Sources:AddPlaneWave(%1, %2)\n").arg(QString::number(p_S12.theta)).arg(QString::number(p_S12.phi)); + luascript = luascript + QString(u8"S12_temp_source.Label = \"%1\"\n").arg("S12"); + luascript = luascript + QString(u8"S12_temp_source.PolarisationAngle = 0\n"); + luascript = luascript + QString(u8"S12_temp_source_workplane = S12_temp_source.LocalWorkplane\n"); + luascript = luascript + QString(u8"S12_temp_source_workplane.Origin.X = 0\n"); + luascript = luascript + QString(u8"S12_temp_source_workplane.Origin.Y = 0\n"); + luascript = luascript + QString(u8"S12_temp_source_workplane.Origin.Z = 0\n"); + luascript = luascript + QString(u8"\n"); + luascript = luascript + QString(u8"S12_farFieldRequest = temp_standardConfiguration.FarFields:Add(0,0,0,0,1,1)\n"); + luascript = luascript + QString(u8"S12_farFieldRequest.Label =\"%1\"\n").arg("S12"); + luascript = luascript + QString(u8"S12_farFieldRequest.CalculationDirection=cf.Enums.FarFieldCalculationDirectionEnum.FromPlaneWave\n\n"); + luascript = luascript + QString(u8"\n"); + + } + else {} + if (this->settingobj->F1) { + SphericalCoordinates p_F1 = AntSettingdict["F1"]; + luascript = luascript + QString(u8"F1_temp_source = temp_standardConfiguration.Sources:AddPlaneWave(%1, %2)\n").arg(QString::number(p_F1.theta)).arg(QString::number(p_F1.phi)); + luascript = luascript + QString(u8"F1_temp_source.Label = \"%1\"\n").arg("F1"); + luascript = luascript + QString(u8"F1_temp_source.PolarisationAngle = 0\n"); + luascript = luascript + QString(u8"F1_temp_source_workplane = F1_temp_source.LocalWorkplane\n"); + luascript = luascript + QString(u8"F1_temp_source_workplane.Origin.X = 0\n"); + luascript = luascript + QString(u8"F1_temp_source_workplane.Origin.Y = 0\n"); + luascript = luascript + QString(u8"F1_temp_source_workplane.Origin.Z = 0\n"); + luascript = luascript + QString(u8"\n"); + luascript = luascript + QString(u8"F1_farFieldRequest = temp_standardConfiguration.FarFields:Add(0,0,0,0,1,1)\n"); + luascript = luascript + QString(u8"F1_farFieldRequest.Label =\"%1\"\n").arg("F1"); + luascript = luascript + QString(u8"F1_farFieldRequest.CalculationDirection=cf.Enums.FarFieldCalculationDirectionEnum.FromPlaneWave\n\n"); + luascript = luascript + QString(u8"\n"); + + } + else {} + if (this->settingobj->F2) { + SphericalCoordinates p_F2 = AntSettingdict["F2"]; + luascript = luascript + QString(u8"F2_temp_source = temp_standardConfiguration.Sources:AddPlaneWave(%1, %2)\n").arg(QString::number(p_F2.theta)).arg(QString::number(p_F2.phi)); + luascript = luascript + QString(u8"F2_temp_source.Label = \"%1\"\n").arg("F2"); + luascript = luascript + QString(u8"F2_temp_source.PolarisationAngle = 0\n"); + luascript = luascript + QString(u8"F2_temp_source_workplane = F2_temp_source.LocalWorkplane\n"); + luascript = luascript + QString(u8"F2_temp_source_workplane.Origin.X = 0\n"); + luascript = luascript + QString(u8"F2_temp_source_workplane.Origin.Y = 0\n"); + luascript = luascript + QString(u8"F2_temp_source_workplane.Origin.Z = 0\n"); + luascript = luascript + QString(u8"\n"); + luascript = luascript + QString(u8"F2_farFieldRequest = temp_standardConfiguration.FarFields:Add(0,0,0,0,1,1)\n"); + luascript = luascript + QString(u8"F2_farFieldRequest.Label =\"%1\"\n").arg("F2"); + luascript = luascript + QString(u8"F2_farFieldRequest.CalculationDirection=cf.Enums.FarFieldCalculationDirectionEnum.FromPlaneWave\n\n"); + + + luascript = luascript + QString(u8"\n"); + + } + else {} + if (this->settingobj->F3) { + SphericalCoordinates p_F3 = AntSettingdict["F3"]; + luascript = luascript + QString(u8"F3_temp_source = temp_standardConfiguration.Sources:AddPlaneWave(%1, %2)\n").arg(QString::number(p_F3.theta)).arg(QString::number(p_F3.phi)); + luascript = luascript + QString(u8"F3_temp_source.Label = \"%1\"\n").arg("F3"); + luascript = luascript + QString(u8"F3_temp_source.PolarisationAngle = 0\n"); + luascript = luascript + QString(u8"F3_temp_source_workplane = F3_temp_source.LocalWorkplane\n"); + luascript = luascript + QString(u8"F3_temp_source_workplane.Origin.X = 0\n"); + luascript = luascript + QString(u8"F3_temp_source_workplane.Origin.Y = 0\n"); + luascript = luascript + QString(u8"F3_temp_source_workplane.Origin.Z = 0\n"); + luascript = luascript + QString(u8"\n"); + luascript = luascript + QString(u8"F3_farFieldRequest = temp_standardConfiguration.FarFields:Add(0,0,0,0,1,1)\n"); + luascript = luascript + QString(u8"F3_farFieldRequest.Label =\"%1\"\n").arg("F3"); + luascript = luascript + QString(u8"F3_farFieldRequest.CalculationDirection=cf.Enums.FarFieldCalculationDirectionEnum.FromPlaneWave\n\n"); + + + luascript = luascript + QString(u8"\n"); + + } + else {} + if (this->settingobj->F4) { + SphericalCoordinates p_F4 = AntSettingdict["F4"]; + luascript = luascript + QString(u8"F4_temp_source = temp_standardConfiguration.Sources:AddPlaneWave(%1, %2)\n").arg(QString::number(p_F4.theta)).arg(QString::number(p_F4.phi)); + luascript = luascript + QString(u8"F4_temp_source.Label = \"%1\"\n").arg("F4"); + luascript = luascript + QString(u8"F4_temp_source.PolarisationAngle = 0\n"); + luascript = luascript + QString(u8"F4_temp_source_workplane = F4_temp_source.LocalWorkplane\n"); + luascript = luascript + QString(u8"F4_temp_source_workplane.Origin.X = 0\n"); + luascript = luascript + QString(u8"F4_temp_source_workplane.Origin.Y = 0\n"); + luascript = luascript + QString(u8"F4_temp_source_workplane.Origin.Z = 0\n"); + luascript = luascript + QString(u8"\n"); + luascript = luascript + QString(u8"F4_farFieldRequest = temp_standardConfiguration.FarFields:Add(0,0,0,0,1,1)\n"); + luascript = luascript + QString(u8"F4_farFieldRequest.Label =\"%1\"\n").arg("F4"); + luascript = luascript + QString(u8"F4_farFieldRequest.CalculationDirection=cf.Enums.FarFieldCalculationDirectionEnum.FromPlaneWave\n\n"); + + + + luascript = luascript + QString(u8"\n"); + } + else {} + if (this->settingobj->F5) { + SphericalCoordinates p_F5 = AntSettingdict["F5"]; + luascript = luascript + QString(u8"F5_temp_source = temp_standardConfiguration.Sources:AddPlaneWave(%1, %2)\n").arg(QString::number(p_F5.theta)).arg(QString::number(p_F5.phi)); + luascript = luascript + QString(u8"F5_temp_source.Label = \"%1\"\n").arg("F5"); + luascript = luascript + QString(u8"F5_temp_source.PolarisationAngle = 0\n"); + luascript = luascript + QString(u8"F5_temp_source_workplane = F5_temp_source.LocalWorkplane\n"); + luascript = luascript + QString(u8"F5_temp_source_workplane.Origin.X = 0\n"); + luascript = luascript + QString(u8"F5_temp_source_workplane.Origin.Y = 0\n"); + luascript = luascript + QString(u8"F5_temp_source_workplane.Origin.Z = 0\n"); + luascript = luascript + QString(u8"\n"); + + luascript = luascript + QString(u8"F5_farFieldRequest = temp_standardConfiguration.FarFields:Add(0,0,0,0,1,1)\n"); + luascript = luascript + QString(u8"F5_farFieldRequest.Label =\"%1\"\n").arg("F5"); + luascript = luascript + QString(u8"F5_farFieldRequest.CalculationDirection=cf.Enums.FarFieldCalculationDirectionEnum.FromPlaneWave\n\n"); + + + luascript = luascript + QString(u8"\n"); + + } + else {} + if (this->settingobj->F6) { + SphericalCoordinates p_F6 = AntSettingdict["F6"]; + luascript = luascript + QString(u8"F6_temp_source = temp_standardConfiguration.Sources:AddPlaneWave(%1, %2)\n").arg(QString::number(p_F6.theta)).arg(QString::number(p_F6.phi)); + luascript = luascript + QString(u8"F6_temp_source.Label = \"%1\"\n").arg("F6"); + luascript = luascript + QString(u8"F6_temp_source.PolarisationAngle = 0\n"); + luascript = luascript + QString(u8"F6_temp_source_workplane = F6_temp_source.LocalWorkplane\n"); + luascript = luascript + QString(u8"F6_temp_source_workplane.Origin.X = 0\n"); + luascript = luascript + QString(u8"F6_temp_source_workplane.Origin.Y = 0\n"); + luascript = luascript + QString(u8"F6_temp_source_workplane.Origin.Z = 0\n"); + luascript = luascript + QString(u8"\n"); + + luascript = luascript + QString(u8"F6_farFieldRequest = temp_standardConfiguration.FarFields:Add(0,0,0,0,1,1)\n"); + luascript = luascript + QString(u8"F6_farFieldRequest.Label =\"%1\"\n").arg("F6"); + luascript = luascript + QString(u8"F6_farFieldRequest.CalculationDirection=cf.Enums.FarFieldCalculationDirectionEnum.FromPlaneWave\n\n"); + + + luascript = luascript + QString(u8"\n"); + } + else {} + if (this->settingobj->F7) { + SphericalCoordinates p_F7 = AntSettingdict["F7"]; + luascript = luascript + QString(u8"F7_temp_source = temp_standardConfiguration.Sources:AddPlaneWave(%1, %2)\n").arg(QString::number(p_F7.theta)).arg(QString::number(p_F7.phi)); + luascript = luascript + QString(u8"F7_temp_source.Label = \"%1\"\n").arg("F7"); + luascript = luascript + QString(u8"F7_temp_source.PolarisationAngle = 0\n"); + luascript = luascript + QString(u8"F7_temp_source_workplane = F7_temp_source.LocalWorkplane\n"); + luascript = luascript + QString(u8"F7_temp_source_workplane.Origin.X = 0\n"); + luascript = luascript + QString(u8"F7_temp_source_workplane.Origin.Y = 0\n"); + luascript = luascript + QString(u8"F7_temp_source_workplane.Origin.Z = 0\n"); + luascript = luascript + QString(u8"\n"); + + luascript = luascript + QString(u8"F7_farFieldRequest = temp_standardConfiguration.FarFields:Add(0,0,0,0,1,1)\n"); + luascript = luascript + QString(u8"F7_farFieldRequest.Label =\"%1\"\n").arg("F7"); + luascript = luascript + QString(u8"F7_farFieldRequest.CalculationDirection=cf.Enums.FarFieldCalculationDirectionEnum.FromPlaneWave\n\n"); + + + luascript = luascript + QString(u8"\n"); + } + else {} + if (this->settingobj->F8) { + SphericalCoordinates p_F8 = AntSettingdict["F8"]; + luascript = luascript + QString(u8"F8_temp_source = temp_standardConfiguration.Sources:AddPlaneWave(%1, %2)\n").arg(QString::number(p_F8.theta)).arg(QString::number(p_F8.phi)); + luascript = luascript + QString(u8"F8_temp_source.Label = \"%1\"\n").arg("F8"); + luascript = luascript + QString(u8"F8_temp_source.PolarisationAngle = 0\n"); + luascript = luascript + QString(u8"F8_temp_source_workplane = F8_temp_source.LocalWorkplane\n"); + luascript = luascript + QString(u8"F8_temp_source_workplane.Origin.X = 0\n"); + luascript = luascript + QString(u8"F8_temp_source_workplane.Origin.Y = 0\n"); + luascript = luascript + QString(u8"F8_temp_source_workplane.Origin.Z = 0\n"); + luascript = luascript + QString(u8"\n"); + + luascript = luascript + QString(u8"F8_farFieldRequest = temp_standardConfiguration.FarFields:Add(0,0,0,0,1,1)\n"); + luascript = luascript + QString(u8"F8_farFieldRequest.Label =\"%1\"\n").arg("F8"); + luascript = luascript + QString(u8"F8_farFieldRequest.CalculationDirection=cf.Enums.FarFieldCalculationDirectionEnum.FromPlaneWave\n\n"); + + + luascript = luascript + QString(u8"\n"); + } + else {} + if (this->settingobj->F9) { + SphericalCoordinates p_F9 = AntSettingdict["F9"]; + luascript = luascript + QString(u8"F9_temp_source = temp_standardConfiguration.Sources:AddPlaneWave(%1, %2)\n").arg(QString::number(p_F9.theta)).arg(QString::number(p_F9.phi)); + luascript = luascript + QString(u8"F9_temp_source.Label = \"%1\"\n").arg("F9"); + luascript = luascript + QString(u8"F9_temp_source.PolarisationAngle = 0\n"); + luascript = luascript + QString(u8"F9_temp_source_workplane = F9_temp_source.LocalWorkplane\n"); + luascript = luascript + QString(u8"F9_temp_source_workplane.Origin.X = 0\n"); + luascript = luascript + QString(u8"F9_temp_source_workplane.Origin.Y = 0\n"); + luascript = luascript + QString(u8"F9_temp_source_workplane.Origin.Z = 0\n"); + luascript = luascript + QString(u8"\n"); + + luascript = luascript + QString(u8"F9_farFieldRequest = temp_standardConfiguration.FarFields:Add(0,0,0,0,1,1)\n"); + luascript = luascript + QString(u8"F9_farFieldRequest.Label =\"%1\"\n").arg("F9"); + luascript = luascript + QString(u8"F9_farFieldRequest.CalculationDirection=cf.Enums.FarFieldCalculationDirectionEnum.FromPlaneWave\n\n"); + + + luascript = luascript + QString(u8"\n"); + } + + else {} + if (this->settingobj->F10) { + SphericalCoordinates p_F10 = AntSettingdict["F10"]; + luascript = luascript + QString(u8"F10_temp_source = temp_standardConfiguration.Sources:AddPlaneWave(%1, %2)\n").arg(QString::number(p_F10.theta)).arg(QString::number(p_F10.phi)); + luascript = luascript + QString(u8"F10_temp_source.Label = \"%1\"\n").arg("F10"); + luascript = luascript + QString(u8"F10_temp_source.PolarisationAngle = 0\n"); + luascript = luascript + QString(u8"F10_temp_source_workplane = F10_temp_source.LocalWorkplane\n"); + luascript = luascript + QString(u8"F10_temp_source_workplane.Origin.X = 0\n"); + luascript = luascript + QString(u8"F10_temp_source_workplane.Origin.Y = 0\n"); + luascript = luascript + QString(u8"F10_temp_source_workplane.Origin.Z = 0\n"); + luascript = luascript + QString(u8"\n"); + + luascript = luascript + QString(u8"F10_farFieldRequest = temp_standardConfiguration.FarFields:Add(0,0,0,0,1,1)\n"); + luascript = luascript + QString(u8"F10_farFieldRequest.Label =\"%1\"\n").arg("F10"); + luascript = luascript + QString(u8"F10_farFieldRequest.CalculationDirection=cf.Enums.FarFieldCalculationDirectionEnum.FromPlaneWave\n\n"); + + + luascript = luascript + QString(u8"\n"); + } + else {} + if (this->settingobj->F11) { + SphericalCoordinates p_F11 = AntSettingdict["F11"]; + luascript = luascript + QString(u8"F11_temp_source = temp_standardConfiguration.Sources:AddPlaneWave(%1, %2)\n").arg(QString::number(p_F11.theta)).arg(QString::number(p_F11.phi)); + luascript = luascript + QString(u8"F11_temp_source.Label = \"%1\"\n").arg("F11"); + luascript = luascript + QString(u8"F11_temp_source.PolarisationAngle = 0\n"); + luascript = luascript + QString(u8"F11_temp_source_workplane = F11_temp_source.LocalWorkplane\n"); + luascript = luascript + QString(u8"F11_temp_source_workplane.Origin.X = 0\n"); + luascript = luascript + QString(u8"F11_temp_source_workplane.Origin.Y = 0\n"); + luascript = luascript + QString(u8"F11_temp_source_workplane.Origin.Z = 0\n"); + luascript = luascript + QString(u8"\n"); + luascript = luascript + QString(u8"F11_farFieldRequest = temp_standardConfiguration.FarFields:Add(0,0,0,0,1,1)\n"); + luascript = luascript + QString(u8"F11_farFieldRequest.Label =\"%1\"\n").arg("F11"); + luascript = luascript + QString(u8"F11_farFieldRequest.CalculationDirection=cf.Enums.FarFieldCalculationDirectionEnum.FromPlaneWave\n\n"); + + + + luascript = luascript + QString(u8"\n"); + } + else {} + if (this->settingobj->F12) { + SphericalCoordinates p_F12 = AntSettingdict["F12"]; + luascript = luascript + QString(u8"F12_temp_source = temp_standardConfiguration.Sources:AddPlaneWave(%1, %2)\n").arg(QString::number(p_F12.theta)).arg(QString::number(p_F12.phi)); + luascript = luascript + QString(u8"F12_temp_source.Label = \"%1\"\n").arg("F12"); + luascript = luascript + QString(u8"F12_temp_source.PolarisationAngle = 0\n"); + luascript = luascript + QString(u8"F12_temp_source_workplane = F12_temp_source.LocalWorkplane\n"); + luascript = luascript + QString(u8"F12_temp_source_workplane.Origin.X = 0\n"); + luascript = luascript + QString(u8"F12_temp_source_workplane.Origin.Y = 0\n"); + luascript = luascript + QString(u8"F12_temp_source_workplane.Origin.Z = 0\n"); + luascript = luascript + QString(u8"\n"); + + luascript = luascript + QString(u8"F12_farFieldRequest = temp_standardConfiguration.FarFields:Add(0,0,0,0,1,1)\n"); + luascript = luascript + QString(u8"F12_farFieldRequest.Label =\"%1\"\n").arg("F12"); + luascript = luascript + QString(u8"F12_farFieldRequest.CalculationDirection=cf.Enums.FarFieldCalculationDirectionEnum.FromPlaneWave\n\n"); + + luascript = luascript + QString(u8"\n"); + } + else {} + } + else {} + + } + else {} + + + + + QString filePath = this->workpsace + QDir::separator() + this->settingobj->taskName+ QString(u8"_Scattering.lua"); + QFile file(filePath); // ´´½¨Îļþ¶ÔÏó + if (file.open(QIODevice::WriteOnly | QIODevice::Text)) { + QTextStream stream(&file); // ´´½¨Îı¾Á÷£¬²¢ÉèÖñàÂëΪUTF-8 + stream.setCodec("UTF-8"); + stream << luascript; + file.close(); + QMessageBox::information(nullptr, QString::fromUtf8(u8"Ìáʾ"), QString::fromUtf8(u8"ÎļþдÈë³É¹¦!\n%1").arg(filePath)); // ÌáʾÎļþдÈë³É¹¦ + qDebug() << "File written successfully."; + } + else { + qDebug() << "Could not open file for writing."; + QMessageBox::information(nullptr, QString::fromUtf8(u8"Ìáʾ"), QString::fromUtf8(u8"ÎļþдÈëʧ°Ü")); + } + progressDialog.setValue(progressDialog.maximum()); + progressDialog.close(); + return ; +} + +void LAMP_ScatterSettingClass::setTaskName(QString name) +{ + this->ui.lineEdit_TaskName->setText(name); + this->settingobj->taskName = name; +} + +void LAMP_ScatterSettingClass::setWorkSpacePath(QString path) +{ + this->workpsace = getParantFromPath(path); + this->xmlpath = path; + this->ui.lineEdit_xmlpath->setText(this->xmlpath); +} + +void LAMP_ScatterSettingClass::on_radioButton_S1_toggled(bool flag) +{ + if (this->myContext.IsNull()) {} + else { return; } + + this->switchAntShowAndHide("S1", flag); + +} +void LAMP_ScatterSettingClass::on_radioButton_S3_toggled(bool flag) +{ + if (this->myContext.IsNull()) {} + else { return; } + this->switchAntShowAndHide("S3", flag); + +} +void LAMP_ScatterSettingClass::on_radioButton_S5_toggled(bool flag) +{ + if (this->myContext.IsNull()) {} + else { return; } + this->switchAntShowAndHide("S5", flag); + +} +void LAMP_ScatterSettingClass::on_radioButton_S8_toggled(bool flag) +{ + if (this->myContext.IsNull()) {} + else { return; } + this->switchAntShowAndHide("S8", flag); + +} +void LAMP_ScatterSettingClass::on_radioButton_S10_toggled(bool flag) +{ + if (this->myContext.IsNull()) {} + else { return; } + this->switchAntShowAndHide("S10", flag); + +} +void LAMP_ScatterSettingClass::on_radioButton_S12_toggled(bool flag) +{ + if (this->myContext.IsNull()) {} + else { return; } + this->switchAntShowAndHide("S12", flag); + +} +void LAMP_ScatterSettingClass::on_radioButton_F1_toggled(bool flag) +{ + if (this->myContext.IsNull()) {} + else { return; } + this->switchAntShowAndHide("F1", flag); +} +void LAMP_ScatterSettingClass::on_radioButton_F2_toggled(bool flag) +{ + if (this->myContext.IsNull()) {} + else { return; } + this->switchAntShowAndHide("F2", flag); + +} +void LAMP_ScatterSettingClass::on_radioButton_F3_toggled(bool flag) +{ + if (this->myContext.IsNull()) {} + else { return; } + this->switchAntShowAndHide("F3", flag); this->switchAntShowAndHide("F1", flag); + +} +void LAMP_ScatterSettingClass::on_radioButton_F4_toggled(bool flag) +{ + if (this->myContext.IsNull()) {} + else { return; } + this->switchAntShowAndHide("F4", flag); + +} +void LAMP_ScatterSettingClass::on_radioButton_F5_toggled(bool flag) +{ + if (this->myContext.IsNull()) {} + else { return; } + this->switchAntShowAndHide("F5", flag); + +} +void LAMP_ScatterSettingClass::on_radioButton_F6_toggled(bool flag) +{ + if (this->myContext.IsNull()) {} + else { return; } + this->switchAntShowAndHide("F6", flag); + +} +void LAMP_ScatterSettingClass::on_radioButton_F7_toggled(bool flag) +{ + if (this->myContext.IsNull()) {} + else { return; } + this->switchAntShowAndHide("F7", flag); + +} +void LAMP_ScatterSettingClass::on_radioButton_F8_toggled(bool flag) +{ + if (this->myContext.IsNull()) {} + else { return; } + this->switchAntShowAndHide("F8", flag); + +} +void LAMP_ScatterSettingClass::on_radioButton_F9_toggled(bool flag) +{ + if (this->myContext.IsNull()) {} + else { return; } + this->switchAntShowAndHide("F9", flag); + +} +void LAMP_ScatterSettingClass::on_radioButton_F10_toggled(bool flag) +{ + if (this->myContext.IsNull()) {} + else { return; } + this->switchAntShowAndHide("F10", flag); + +} +void LAMP_ScatterSettingClass::on_radioButton_F11_toggled(bool flag) +{ + if (this->myContext.IsNull()) {} + else { return; } + this->switchAntShowAndHide("F11", flag); + +} +void LAMP_ScatterSettingClass::on_radioButton_F12_toggled(bool flag) +{ + if (this->myContext.IsNull()) {} + else { return; } + this->switchAntShowAndHide("F12", flag); + +} +void LAMP_ScatterSettingClass::on_checkBox_A1_toggled(bool flag) +{ + this->ui.lineEdit_A1_incAngle->setEnabled(this->ui.checkBox_A1->isChecked()); + this->switchAntShowAndHide("A1", this->ui.checkBox_A1->isChecked()); + if (this->myContext.IsNull()) {} + else { return; } + +} +void LAMP_ScatterSettingClass::on_checkBox_A2_toggled(bool flag) +{ + this->ui.lineEdit_A2_incAngle->setEnabled(this->ui.checkBox_A2->isChecked()); + this->switchAntShowAndHide("A2", this->ui.checkBox_A2->isChecked()); + if (this->myContext.IsNull()) {} + else { return; } + +} + +void LAMP_ScatterSettingClass::on_checkBox_AllScatter_toggled(bool flag) +{ + this->ui.radioButton_S1->setEnabled(this->ui.checkBox_AllScatter->isChecked()); + this->ui.radioButton_S3->setEnabled(this->ui.checkBox_AllScatter->isChecked()); + this->ui.radioButton_S5->setEnabled(this->ui.checkBox_AllScatter->isChecked()); + this->ui.radioButton_S8->setEnabled(this->ui.checkBox_AllScatter->isChecked()); + this->ui.radioButton_S10->setEnabled(this->ui.checkBox_AllScatter->isChecked()); + this->ui.radioButton_S12->setEnabled(this->ui.checkBox_AllScatter->isChecked()); + this->ui.radioButton_F1->setEnabled(this->ui.checkBox_AllScatter->isChecked()); + this->ui.radioButton_F2->setEnabled(this->ui.checkBox_AllScatter->isChecked()); + this->ui.radioButton_F3->setEnabled(this->ui.checkBox_AllScatter->isChecked()); + this->ui.radioButton_F4->setEnabled(this->ui.checkBox_AllScatter->isChecked()); + this->ui.radioButton_F5->setEnabled(this->ui.checkBox_AllScatter->isChecked()); + this->ui.radioButton_F6->setEnabled(this->ui.checkBox_AllScatter->isChecked()); + this->ui.radioButton_F7->setEnabled(this->ui.checkBox_AllScatter->isChecked()); + this->ui.radioButton_F8->setEnabled(this->ui.checkBox_AllScatter->isChecked()); + this->ui.radioButton_F9->setEnabled(this->ui.checkBox_AllScatter->isChecked()); + this->ui.radioButton_F10->setEnabled(this->ui.checkBox_AllScatter->isChecked()); + this->ui.radioButton_F11->setEnabled(this->ui.checkBox_AllScatter->isChecked()); + this->ui.radioButton_F12->setEnabled(this->ui.checkBox_AllScatter->isChecked()); +} + +void LAMP_ScatterSettingClass::on_lineEdit_A1_incAngle_editingFinished() +{ + // ¸ù¾Ý×ø±ê¼ÆËã + this->myContext->Erase(DataAISMap["A1"], Standard_True); + AntSettingdict["A1"].theta = this->ui.lineEdit_A1_incAngle->text().toDouble(); + SphericalCoordinates sp = AntSettingdict["A1"]; + sp.phi = sp.phi * M_PI / 180; + sp.theta = sp.theta * M_PI / 180; + CartesianCoordinates cp = sphericalToCartesian(sp); + TopoDS_Shape shape_ax = CreateCartesianCoordinatesAxis(0.2, 0.4, 0.8); + TopoDS_Shape shape_ant = Process_RotationThetaPhi_MoveXYZ(shape_ax, M_PI - sp.theta, sp.phi + M_PI, cp.x, cp.y, cp.z); + Handle(AIS_InteractiveObject) shape_ais = new AIS_Shape(shape_ant); + DataAISMap["A1"] = shape_ais; + this->myContext->Display(DataAISMap["A1"],Standard_True); +} +void LAMP_ScatterSettingClass::on_lineEdit_A2_incAngle_editingFinished() +{ + // ¸ù¾Ý×ø±ê¼ÆËã + this->myContext->Erase(DataAISMap["A2"], Standard_True); + AntSettingdict["A2"].theta = this->ui.lineEdit_A2_incAngle->text().toDouble(); + SphericalCoordinates sp = AntSettingdict["A2"]; + sp.phi = sp.phi * M_PI / 180; + sp.theta = sp.theta * M_PI / 180; + CartesianCoordinates cp = sphericalToCartesian(sp); + TopoDS_Shape shape_ax = CreateCartesianCoordinatesAxis(0.2, 0.4, 0.8); + TopoDS_Shape shape_ant = Process_RotationThetaPhi_MoveXYZ(shape_ax, M_PI - sp.theta, sp.phi + M_PI, cp.x, cp.y, cp.z); + Handle(AIS_InteractiveObject) shape_ais = new AIS_Shape(shape_ant); + DataAISMap["A2"] = shape_ais; + this->myContext->Display(DataAISMap["A2"], Standard_True); +} +void LAMP_ScatterSettingClass::on_pushButton_load_clicked() +{ + QString xmlpath = getOpenFilePath(this, u8"É¢ÉäÈÎÎñÅäÖÃxml", u8"xmlÎļþ (*.xml)"); + if (isExists(xmlpath)) { + this->loadxml(xmlpath); + } + else { + + } + +} +void LAMP_ScatterSettingClass::on_pushButton_apply_clicked() +{ + this->savexml(); + this->createFEKOLua(); +} + +void LAMP_ScatterSettingClass::on_okButton_clicked() +{ + this->savexml(); + this->createFEKOLua(); + + // È·¶¨°´Å¥ÅжÏÊÇ·ñÐèÒª½Ó¿Ú + QMessageBox::StandardButton reply = QMessageBox::question(this, u8"Ìáʾ", u8"ÊÇ·ñ¹Ø±Õ´°¿Ú", QMessageBox::Yes | QMessageBox::No); + if (reply == QMessageBox::Yes) { + this->closeWindows(); + } + else { + return; + } +} +void LAMP_ScatterSettingClass::on_cancelButton_clicked() +{ + this->closeWindows(); +} + +void LAMP_ScatterSettingClass::switchAntShowAndHide(std::string antName, bool flag) { + if (flag) { + this->myContext->Display(DataAISMap[antName], Standard_True); + } + else { + this->myContext->Erase(DataAISMap[antName], Standard_True); + } +} + +SphericalCoordinates LAMP_ScatterSettingClass::antsettingstring2Spherical(QString sphericalStr) +{ + QList ps = sphericalStr.split(","); + SphericalCoordinates p{ + ps[0].toDouble(), + ps[1].toDouble(), + ps[2].toDouble() + }; + return p; +} + +LAMP_ScatterSettingXmlClass::LAMP_ScatterSettingXmlClass() +{ + // ¶Ô³ÉÔ±±äÁ¿½øÐгõʼ»¯ + this->taskName = u8"TESTScatterimage"; + this->A1 = true; + this->A2 = true; + this->incidence_A1 = 90; + this->incidence_A2 = 90; + this->startfre = 0; + this->endfre = 0; + this->freponts = 0; + this->farfield=false; + this->nearfield=true; + this->enableScatter=true; + this->S1=true; + this->S3=false; + this->S5=false; + this->S8=false; + this->S10=false; + this->S12=false; + this->F1=false; + this->F2=false; + this->F3=false; + this->F4=false; + this->F5=false; + this->F6=false; + this->F7=false; + this->F8=false; + this->F9=false; + this->F10=false; + this->F11=false; + this->F12 = false; +} + +LAMP_ScatterSettingXmlClass::~LAMP_ScatterSettingXmlClass() +{ +} + +void LAMP_ScatterSettingXmlClass::loadxml(QString fileName) +{ + QFile file(fileName); + if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { + QMessageBox::warning(nullptr, u8"¾¯¸æ", u8"ÎÞ·¨´ò¿ªÎļþ"); + return; + } + + QXmlStreamReader xmlReader(&file); + + while (!xmlReader.atEnd() && !xmlReader.hasError()) { + QXmlStreamReader::TokenType token = xmlReader.readNext(); + + if (token == QXmlStreamReader::StartElement) { + QString name= xmlReader.name().toString(); + qDebug() << name< +#include "ui_LAMP_ScatterSettingClass.h" + +class LAMP_ScatterSettingXmlClass { +public: + QString taskName; + double startfre; + double endfre; + double freponts; + bool farfield; + bool nearfield; + bool A1; + double incidence_A1; + bool A2; + double incidence_A2; + bool enableScatter; + bool S1; + bool S3; + bool S5; + bool S8; + bool S10; + bool S12; + bool F1; + bool F2; + bool F3; + bool F4; + bool F5; + bool F6; + bool F7; + bool F8; + bool F9; + bool F10; + bool F11; + bool F12; +public: + LAMP_ScatterSettingXmlClass(); + ~LAMP_ScatterSettingXmlClass(); + void loadxml(QString xmlpath); + void savexml(QString xmlpath); + +}; + + +class LAMP_ScatterSettingClass : public QDialog +{ + Q_OBJECT + +public: + LAMP_ScatterSettingClass(QWidget *parent = nullptr); + ~LAMP_ScatterSettingClass(); + +public: + Handle(AIS_InteractiveContext) myContext; // ´°¿Ú½»»¥ // Ä£Ð͹ÜÀí + QString xmlpath; + QString workpsace; + LAMP_ScatterSettingXmlClass* settingobj; + //QMap DataAISMap; + std::map DataAISMap; // ¹¹½¨À×´ïÕÕÉäÄ£ÐÍ + std::map AntSettingdict; // ¹¹½¨À×´ïÕÕÉäÄ£ÐÍ + std::map AntffePathDict; +public: + void loadxml(QString xmlpath); + void savexml(); + void renderSettingObj(); + void sycnSettingObj(); + void createAntModel(); + void initAntModelSettingParams(); // Ä£ÐÍÉèÖòÎÊý + void closeWindows(); + void setDocument3d(Handle(AIS_InteractiveContext) myContext); + void createFEKOLua(); + void setTaskName(QString name); + void setWorkSpacePath(QString path); +public slots: + void on_radioButton_S1_toggled(bool flag); + void on_radioButton_S3_toggled(bool flag); + void on_radioButton_S5_toggled(bool flag); + void on_radioButton_S8_toggled(bool flag); + void on_radioButton_S10_toggled(bool flag); + void on_radioButton_S12_toggled(bool flag); + void on_radioButton_F1_toggled(bool flag); + void on_radioButton_F2_toggled(bool flag); + void on_radioButton_F3_toggled(bool flag); + void on_radioButton_F4_toggled(bool flag); + void on_radioButton_F5_toggled(bool flag); + void on_radioButton_F6_toggled(bool flag); + void on_radioButton_F7_toggled(bool flag); + void on_radioButton_F8_toggled(bool flag); + void on_radioButton_F9_toggled(bool flag); + void on_radioButton_F10_toggled(bool flag); + void on_radioButton_F11_toggled(bool flag); + void on_radioButton_F12_toggled(bool flag); + + void on_checkBox_A1_toggled(bool flag); + void on_checkBox_A2_toggled(bool flag); + void on_checkBox_AllScatter_toggled(bool flag); + + void on_lineEdit_A1_incAngle_editingFinished(); + void on_lineEdit_A2_incAngle_editingFinished(); + + void on_pushButton_load_clicked(); + void on_pushButton_apply_clicked(); + void on_okButton_clicked(); + void on_cancelButton_clicked(); + + void switchAntShowAndHide(std::string antName,bool isShow); + + +private: + SphericalCoordinates antsettingstring2Spherical(QString sphericalStr); + +private: + Ui::LAMP_ScatterSettingClassClass ui; +}; + + + + +#endif diff --git a/src/WBCLFZSystemModule/LAMP_ScatterSettingClass.ui b/src/WBCLFZSystemModule/LAMP_ScatterSettingClass.ui new file mode 100644 index 0000000..01f53ac --- /dev/null +++ b/src/WBCLFZSystemModule/LAMP_ScatterSettingClass.ui @@ -0,0 +1,585 @@ + + + LAMP_ScatterSettingClassClass + + + + 0 + 0 + 692 + 581 + + + + LAMP_ScatterSettingClass + + + + + + + + + 0 + 30 + + + + + 16777215 + 30 + + + + 任务å + + + + + + + + 0 + 30 + + + + + 16777215 + 30 + + + + 任务地å€: + + + + + + + + 0 + 30 + + + + + 16777215 + 30 + + + + + + + + + 0 + 30 + + + + + 16777215 + 30 + + + + true + + + + + + + + + + + + 16777215 + 16777215 + + + + 这里å‡è®¾æ³¢çš„æ–¹ä½å‘垂直90度 + + + 雷达馈æºè®¾ç½® + + + + + + + 0 + 30 + + + + + 16777215 + 30 + + + + 7 + + + + + + + 频率间隔(MHz) + + + + + + + false + + + + 0 + 30 + + + + + 16777215 + 30 + + + + + + + + + 16777215 + 40 + + + + + + + + + + A1 + + + + + + + A2 + + + + + + + + + + A2入射角(度) + + + + + + + A1入射角(度) + + + + + + + å‘射天线 + + + + + + + + 0 + 30 + + + + + + + + + 0 + 120 + + + + + 16777215 + 120 + + + + 全散射装置天线 + + + + + + F7 + + + + + + + F12 + + + + + + + F6 + + + + + + + S1 + + + + + + + å¯åŠ¨æ•£å°„å¤©çº¿ + + + + + + + F11 + + + + + + + S8 + + + + + + + S10 + + + + + + + S5 + + + + + + + F4 + + + + + + + S3 + + + + + + + S12 + + + + + + + F5 + + + + + + + F9 + + + + + + + F3 + + + + + + + F8 + + + + + + + F1 + + + + + + + F2 + + + + + + + F10 + + + + + + + + + + + 0 + 30 + + + + + 16777215 + 30 + + + + 5 + + + + + + + + 0 + 30 + + + + + 16777215 + 30 + + + + + + + + 终止频率(GHZ) + + + + + + + 起始频率(GHZ): + + + + + + + + 0 + 30 + + + + + 16777215 + 30 + + + + 频率点数 + + + + + + + + 0 + 30 + + + + + 16777215 + 30 + + + + + + + + ä»¿çœŸæ–¹å¼ + + + + + + + + + + 0 + 30 + + + + + 16777215 + 30 + + + + 远场 + + + + + + + + 0 + 30 + + + + + 16777215 + 30 + + + + 近场 + + + + + + + + + + + + + + 6 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Qt::Horizontal + + + + 131 + 31 + + + + + + + + Qt::NoFocus + + + 加载 + + + + + + + Qt::NoFocus + + + 应用 + + + + + + + Qt::NoFocus + + + 确定 + + + + + + + Qt::NoFocus + + + 退出 + + + + + + + + + + + diff --git a/src/WBCLFZSystemModule/OCCTBaseOperaorClass.cpp b/src/WBCLFZSystemModule/OCCTBaseOperaorClass.cpp new file mode 100644 index 0000000..a707939 --- /dev/null +++ b/src/WBCLFZSystemModule/OCCTBaseOperaorClass.cpp @@ -0,0 +1,6 @@ +#include "AllHead.h" +#include "OCCTBaseOperaorClass.h" + + + + diff --git a/src/WBCLFZSystemModule/OCCTBaseOperaorClass.h b/src/WBCLFZSystemModule/OCCTBaseOperaorClass.h new file mode 100644 index 0000000..e2f0f3b --- /dev/null +++ b/src/WBCLFZSystemModule/OCCTBaseOperaorClass.h @@ -0,0 +1,19 @@ +#pragma once +#ifndef OCCTBASEOPERAORCLASS_H +#define OCCTBASEOPERAORCLASS_H +#include +#include +#include "OCCViewer/CommonSample.h" +#include "allHead.h" + + + + + + + + + + + +#endif \ No newline at end of file diff --git a/src/WBCLFZSystemModule/OCCTModelOperator.cpp b/src/WBCLFZSystemModule/OCCTModelOperator.cpp new file mode 100644 index 0000000..fa16605 --- /dev/null +++ b/src/WBCLFZSystemModule/OCCTModelOperator.cpp @@ -0,0 +1,465 @@ +#include "OCCTModelOperator.h" +#include +#include +#include + + +OCCTModelOperator::OCCTModelOperator(QString TopoName,QWidget *parent, Handle(AIS_InteractiveContext) myContext) + : QDialog(parent) +{ + ui.setupUi(this); + setWindowFlags(Qt::Window); + setWindowTitle(TopoName); + // ²ÎÊý³õÉè + this->ui.radioButton_NoCopy->setChecked(true); + this->ui.radioButton_Time->setChecked(true); + this->myContext = myContext; + this->ModelName = TopoName; + // ´¦ÀíÆ½ÒÆ + + QDoubleValidator* validator = new QDoubleValidator(); // ÏÞÖÆ²ÎÊý + ui.lineEdit_Move_From_X->setValidator(validator); + ui.lineEdit_Move_From_Z->setValidator(validator); + ui.lineEdit_Move_From_Y->setValidator(validator); + ui.lineEdit_Move_To_X->setValidator(validator); + ui.lineEdit_Move_To_Y->setValidator(validator); + ui.lineEdit_Move_To_Z->setValidator(validator); + ui.lineEdit_Rotation_Center_X->setValidator(validator); + ui.lineEdit_Rotation_Center_Y->setValidator(validator); + ui.lineEdit_Rotation_Center_Z->setValidator(validator); + ui.lineEdit_Rotation_Axis_X->setValidator(validator); + ui.lineEdit_Rotation_Axis_Y->setValidator(validator); + ui.lineEdit_Rotation_Axis_Z->setValidator(validator); + + ui.lineEdit_Scale_refrence_point_X->setValidator(validator); + ui.lineEdit_Scale_refrence_point_Y->setValidator(validator); + ui.lineEdit_Scale_refrence_point_Z->setValidator(validator); + + QDoubleValidator* validatorScale = new QDoubleValidator(); + validatorScale->setBottom(0.0); + ui.lineEdit_ScaleValue->setValidator(validatorScale); + + // ³õʼ»¯ + ui.lineEdit_Move_From_X->setText(u8"0.0"); + ui.lineEdit_Move_From_Z->setText(u8"0.0"); + ui.lineEdit_Move_From_Y->setText(u8"0.0"); + ui.lineEdit_Move_To_X->setText(u8"0.0"); + ui.lineEdit_Move_To_Y->setText(u8"0.0"); + ui.lineEdit_Move_To_Z->setText(u8"0.0"); + ui.lineEdit_Rotation_Center_X->setText(u8"0.0"); + ui.lineEdit_Rotation_Center_Y->setText(u8"0.0"); + ui.lineEdit_Rotation_Center_Z->setText(u8"0.0"); + ui.lineEdit_Rotation_Axis_X->setText(u8"0.0"); + ui.lineEdit_Rotation_Axis_Y->setText(u8"0.0"); + ui.lineEdit_Rotation_Axis_Z->setText(u8"0.0"); + ui.lineEdit_ScaleValue->setText(u8"1.0"); + ui.lineEdit_Scale_refrence_point_X->setText(u8"0.0"); + ui.lineEdit_Scale_refrence_point_Y->setText(u8"0.0"); + ui.lineEdit_Scale_refrence_point_Z->setText(u8"0.0"); + // Ëõ·ÅÖÐÐIJÎÊý»¯ + ui.radioButton_Auto->setChecked(true); + // ²ÎÊý³õʼ»¯ + this->UpdataVariable(); + // ʼþ°ó¶¨ + + if (TopoName.isEmpty()) { + this->ui.radioButton_Copy->setChecked(true); + this->ui.radioButton_NoCopy->setEnabled(false); + } + +} + +OCCTModelOperator::~OCCTModelOperator() +{} + +void OCCTModelOperator::setTopoDs_Shape(TopoDS_Shape ds) +{ + // ´´½¨Ò»¸ö¸´ÖÆÄ£ÐÍ + BRepBuilderAPI_Copy copyBuilder; + copyBuilder.Perform(ds); + this->Datashape = copyBuilder.Shape(); + + // ´´½¨Ò»¸ö¸´ÖÆÄ£ÐÍ + BRepBuilderAPI_Copy copyBuilder2; + copyBuilder2.Perform(ds); + this->DataShapeBAK = copyBuilder2.Shape(); + + this->Data_AIS = new AIS_Shape(this->Datashape); // ¼ÆËã + + this->UpdateScaleRefrencepoint(); + this->UpdataVariable(); + +} + +TopoDS_Shape OCCTModelOperator::getTopoDs_Shape() +{ + return this->Datashape; +} + +TopoDS_Shape OCCTModelOperator::getTopoDs_ShapeBAK() +{ + return this->DataShapeBAK; +} + +void OCCTModelOperator::toString() +{ + qDebug() << u8"move "; + qDebug() < %1").arg(Move_From_X, 0, 'e', 8).arg(Move_To_X, 0, 'e', 8); + qDebug() < %1").arg(Move_From_Y, 0, 'e', 8).arg(Move_To_Y, 0, 'e', 8); + qDebug() < %1").arg(Move_From_Z, 0, 'e', 8).arg(Move_To_Z, 0, 'e', 8); + qDebug() << u8"Rotatino Center Point "; + qDebug() <ScaleRefrencePoint_X); + qDebug() <ScaleRefrencePoint_Y); + qDebug() <ScaleRefrencePoint_Z); +} + +Handle(AIS_InteractiveObject) OCCTModelOperator::getAIS() +{ + return new AIS_Shape(this->Datashape); +} + +Handle(AIS_InteractiveObject) OCCTModelOperator::getAISBAK() +{ + return new AIS_Shape(this->DataShapeBAK); +} + +void OCCTModelOperator::ExcuteOperator() +{ + this->ProcesssModel(); + if (this->ui.radioButton_Copy->isChecked()) { // ¸´ÖÆÄ£ÐÍ + emit this->ResultExportCopyAndCreateNew(this); + } + else { + emit this->ResultExport(this); + } + + +} + +void OCCTModelOperator::UpdataVariable() +{ + this->Move_From_X = this->ui.lineEdit_Move_From_X->text().toDouble(); + this->Move_From_Z = this->ui.lineEdit_Move_From_Z->text().toDouble(); + this->Move_From_Y = this->ui.lineEdit_Move_From_Y->text().toDouble(); + this->Move_To_X = this->ui.lineEdit_Move_To_X->text().toDouble(); + this->Move_To_Y = this->ui.lineEdit_Move_To_Y->text().toDouble(); + this->Move_To_Z = this->ui.lineEdit_Move_To_Z->text().toDouble(); + this->Rotation_Center_X = this->ui.lineEdit_Rotation_Center_X->text().toDouble(); + this->Rotation_Center_Y = this->ui.lineEdit_Rotation_Center_Y->text().toDouble(); + this->Rotation_Center_Z = this->ui.lineEdit_Rotation_Center_Z->text().toDouble(); + this->Rotation_angle_X = this->ui.lineEdit_Rotation_Axis_X->text().toDouble(); + this->Rotation_angle_Y = this->ui.lineEdit_Rotation_Axis_Y->text().toDouble(); + this->ScaleDouble = this->ui.lineEdit_ScaleValue->text().toDouble(); + + this->ScaleRefrencePoint_X=this->ui.lineEdit_Scale_refrence_point_X->text().toDouble(); + this->ScaleRefrencePoint_Y=this->ui.lineEdit_Scale_refrence_point_Y->text().toDouble(); + this->ScaleRefrencePoint_Z=this->ui.lineEdit_Scale_refrence_point_Z->text().toDouble(); +} + +void OCCTModelOperator::UpdateScaleRefrencepoint() +{ + if (this->ui.radioButton_Auto->isChecked()) { + // ¼ÙÉèÄãÓÐÒ»¸ö TopoDS_Shape ¶ÔÏó£¬ÀýÈçÒ»¸öÁ¢·½Ìå + TopoDS_Shape myShape = this->DataShapeBAK; // ÄãÐèÒª½«ÆäÌæ»»ÎªÊµ¼ÊµÄÐÎ×´¶ÔÏó + GProp_GProps volumeProperties; + + // ¼ÆË㼸ºÎÌØÐÔ + BRepGProp::VolumeProperties(myShape, volumeProperties, Standard_False, Standard_False, Standard_False); + + //// »ñÈ¡ÖÊÐÄ + gp_Pnt centerOfMass = volumeProperties.CentreOfMass(); + + this->ui.lineEdit_Scale_refrence_point_X->setText(QString("%1").arg(centerOfMass.X(), 0, 'e', 8)); + this->ui.lineEdit_Scale_refrence_point_Y->setText(QString("%1").arg(centerOfMass.Y(), 0, 'e', 8)); + this->ui.lineEdit_Scale_refrence_point_Z->setText(QString("%1").arg(centerOfMass.Z(), 0, 'e', 8)); + } +} + +void OCCTModelOperator::PreViewOperator() +{ + this->UpdataVariable(); + this->toString(); + + if (this->ui.radioButton_Time->isChecked()) { + this->ProcesssModel(); + } +} + +void OCCTModelOperator::ApplyModel() +{ + + if (this->myContext) { + qDebug() << u8"Ä£ÐÍÒÆ³ý"; + + //this->myContext->Erase(this->Data_AIS, Standard_True); + this->myContext->Remove(this->Data_AIS, Standard_False); + this->myContext->UpdateCurrentViewer(); + this->Datashape.Nullify(); + //this->Data_AIS->Delete(); + //this->myContext->Remove(this->Datashape, Standard_True); + } + + // Æ½ÒÆÄ£ÐÍ + double move_x = this->Move_To_X - this->Move_From_X; + double move_y = this->Move_To_Y - this->Move_From_Y; + double move_z = this->Move_To_Z - this->Move_From_Z; + + // ½øÐÐÆ½ÒÆ + gp_Trsf translation; + translation.SetTranslation(gp_Vec(move_x, move_y, move_z)); + BRepBuilderAPI_Transform translateTransform(this->DataShapeBAK, translation); + + TopoDS_Shape translatedShape = translateTransform.Shape(); + + double Rotation_centor_x = this->Rotation_Center_X; + double Rotation_centor_y = this->Rotation_Center_Y; + double Rotation_centor_z = this->Rotation_Center_Z; + // È·¶¨ÐýתÖÐÐÄ + gp_Pnt rotationCenter(Rotation_centor_x, Rotation_centor_y, Rotation_centor_z); // ÖÐÐĵã×ø±ê + // ¼ÆËãÐýתÖá + gp_Ax1 rotationAxis_X(rotationCenter, gp_Dir(1.0, 0.0, 0.0)); + gp_Ax1 rotationAxis_Y(rotationCenter, gp_Dir(0.0, 1.0, 0.0)); + gp_Ax1 rotationAxis_Z(rotationCenter, gp_Dir(0.0, 0.0, 1.0)); + + double angle_x = this->Rotation_angle_X / 180.0 * M_PI; + double angle_y = this->Rotation_angle_Y / 180.0 * M_PI; + double angle_z = this->Rotation_angle_Z / 180.0 * M_PI; + + // ½øÐÐÐýת + gp_Trsf rotation_X; + rotation_X.SetRotation(rotationAxis_X, angle_x); // X + BRepBuilderAPI_Transform rotateTransform_X(translatedShape, rotation_X); + TopoDS_Shape rotatedShape_X = rotateTransform_X.Shape(); + + // ½øÐÐÐýת + gp_Trsf rotation_Y; + rotation_Y.SetRotation(rotationAxis_Y, angle_y); // Y + BRepBuilderAPI_Transform rotateTransform_Y(rotatedShape_X, rotation_Y); + TopoDS_Shape rotatedShape_Y = rotateTransform_Y.Shape(); + + // ½øÐÐÐýת + gp_Trsf rotation_Z; + rotation_Z.SetRotation(rotationAxis_Z, angle_z); // Z + BRepBuilderAPI_Transform rotateTransform_Z(rotatedShape_Y, rotation_Z); + TopoDS_Shape rotatedShape = rotateTransform_Z.Shape(); + + // ´´½¨Ò»¸ö BRepBuilderAPI_Transform ¶ÔÏóÀ´½øÐÐËõ·Å + gp_Pnt refrenceCenter(ScaleRefrencePoint_X, ScaleRefrencePoint_Y, ScaleRefrencePoint_Z); // ÖÐÐĵã×ø±ê + gp_Trsf scaleTransform; + scaleTransform.SetScale(refrenceCenter, ScaleDouble); + BRepBuilderAPI_Transform scaleTransformBuilder(rotatedShape, scaleTransform); + + // Ó¦Óñ任 + if (scaleTransformBuilder.IsDone()) { + this->Datashape = scaleTransformBuilder.Shape(); + } + else { + + } + // ÄÚ´æÊÍ·Å + translatedShape.Nullify(); + rotatedShape_X.Nullify(); + rotatedShape_Y.Nullify(); + rotatedShape.Nullify(); + + if (this->myContext) { + qDebug() << u8"ͼÏñË¢ÐÂ"; + this->Data_AIS.Nullify(); + + // ´´½¨»ò»ñÈ¡¶ÔÏóµÄ AIS_Shape + Handle(AIS_Shape) aisShape = new AIS_Shape(this->Datashape); + + // ´´½¨Ò»¸öÑÕÉ«¶ÔÏó£¬ÀýÈçºìÉ« + Quantity_Color redColor(1.0, 0.0, 0.0, Quantity_TOC_RGB); // RGBºìÉ« + + ChangeModelColor(aisShape, redColor); + + this->Data_AIS = aisShape; + + this->myContext->Display(this->Data_AIS, Standard_True); // Á¢¿ÌˢР+ this->myContext->AddOrRemoveSelected(this->Data_AIS, Standard_True); + } + // ´¦ÀíÏìÓ¦Âß¼­ + emit this->RefreshResult(this); + +} + +void OCCTModelOperator::ProcesssModel() +{ + this->ApplyModel(); +} + +void OCCTModelOperator::on_lineEdit_Move_From_X_returnPressed() +{ + + this->PreViewOperator(); +} + + + +void OCCTModelOperator::on_lineEdit_Move_From_Z_returnPressed() +{ + this->PreViewOperator(); +} + +void OCCTModelOperator::on_lineEdit_Move_From_Y_returnPressed() +{ + this->PreViewOperator(); +} + +void OCCTModelOperator::on_lineEdit_Move_To_X_returnPressed() +{ + this->PreViewOperator(); +} + +void OCCTModelOperator::on_lineEdit_Move_To_Y_returnPressed() +{ + this->PreViewOperator(); +} + +void OCCTModelOperator::on_lineEdit_Move_To_Z_returnPressed() +{ + this->PreViewOperator(); +} + +void OCCTModelOperator::on_lineEdit_Rotation_Center_X_returnPressed() +{ + this->PreViewOperator(); +} + +void OCCTModelOperator::on_lineEdit_Rotation_Center_Y_returnPressed() +{ + this->PreViewOperator(); +} + +void OCCTModelOperator::on_lineEdit_Rotation_Center_Z_returnPressed() +{ + this->PreViewOperator(); +} + +void OCCTModelOperator::on_lineEdit_Rotation_Axis_X_returnPressed() +{ + this->PreViewOperator(); +} + +void OCCTModelOperator::on_lineEdit_Rotation_Axis_Y_returnPressed() +{ + this->PreViewOperator(); +} + +void OCCTModelOperator::on_lineEdit_Rotation_Axis_Z_returnPressed() +{ + this->PreViewOperator(); +} + +void OCCTModelOperator::on_lineEdit_Scale_returnPressed() +{ + this->PreViewOperator(); +} + +void OCCTModelOperator::on_lineEdit_Scale_refrence_point_X_returnPressed() +{ + this->PreViewOperator(); +} + +void OCCTModelOperator::on_lineEdit_Scale_refrence_point_Y_returnPressed() +{ + this->PreViewOperator(); +} + +void OCCTModelOperator::on_lineEdit_Scale_refrence_point_Z_returnPressed() +{ + this->PreViewOperator(); +} + +void OCCTModelOperator::on_lineEdit_ScaleValue_returnPressed() +{ + this->PreViewOperator(); +} + +void OCCTModelOperator::on_radioButton_Auto_toggled(bool flag) +{ + if (flag) { + this->ui.lineEdit_Scale_refrence_point_X->setEnabled(false); + this->ui.lineEdit_Scale_refrence_point_Y->setEnabled(false); + this->ui.lineEdit_Scale_refrence_point_Z->setEnabled(false); + this->UpdateScaleRefrencepoint(); + } +} + +void OCCTModelOperator::on_radioButton_NoAuto_toggled(bool flag) +{ + if (flag) { + this->ui.lineEdit_Scale_refrence_point_X->setEnabled(true); + this->ui.lineEdit_Scale_refrence_point_Y->setEnabled(true); + this->ui.lineEdit_Scale_refrence_point_Z->setEnabled(true); + this->UpdateScaleRefrencepoint(); + } +} + + +void OCCTModelOperator::on_pushButton_ok_clicked() +{ + this->UpdataVariable(); + + this->ApplyModel(); + + if (this->myContext) { + qDebug() << u8"Ä£ÐÍÒÆ³ý"; + this->myContext->Remove(this->Data_AIS, Standard_False); + this->myContext->UpdateCurrentViewer(); + + } + // ´´½¨Ò»¸ö¸´ÖÆÄ£ÐÍ + BRepBuilderAPI_Copy copyBuilder; + copyBuilder.Perform(this->Datashape); + this->DataShapeBAK = copyBuilder.Shape(); + + if (this->ui.radioButton_Copy->isChecked()) { + emit this->ResultExportCopyAndCreateNew(this); + } + else { + emit this->ResultExport(this); + } + this->close(); +} + +void OCCTModelOperator::on_pushButton_apply_clicked() +{ + this->UpdataVariable(); + + this->ApplyModel(); + + if (this->myContext) { + qDebug() << u8"Ä£ÐÍÒÆ³ý"; + //this->myContext->Erase(this->Data_AIS, Standard_True); + this->myContext->Remove(this->Data_AIS, Standard_False); + this->myContext->UpdateCurrentViewer(); + + } + // ´´½¨Ò»¸ö¸´ÖÆÄ£ÐÍ + BRepBuilderAPI_Copy copyBuilder; + copyBuilder.Perform(this->Datashape); + this->DataShapeBAK = copyBuilder.Shape(); + + if (this->ui.radioButton_Copy->isChecked()) { + emit this->ResultExportCopyAndCreateNew(this); + } + else { + emit this->ResultExport(this); + } +} + +void OCCTModelOperator::on_pushButton_Cancel_clicked() +{ + this->close(); +} diff --git a/src/WBCLFZSystemModule/OCCTModelOperator.h b/src/WBCLFZSystemModule/OCCTModelOperator.h new file mode 100644 index 0000000..4d59ab8 --- /dev/null +++ b/src/WBCLFZSystemModule/OCCTModelOperator.h @@ -0,0 +1,125 @@ +#pragma once +/// +/// ¿ØÖÆÄ£ÐÍÕûÌåÆ½ÒÆ×ª»» +/// 1. Æ½ÒÆ·½·¨ +/// a. ʸÁ¿Æ½ÒÆ·¨ +/// b. ÖØÐÄÉèÖà +/// 2. Ðýת·½·¨ +/// a. ÖØÐÄת»»·½·¨£¬¸ù¾Ý×ø±êϵ +/// b. +/// + +#ifndef OCCT_MODEL_OPERATOR_H +#define OCCT_MODEL_OPERATOR_H +#include "AllHead.h" +#include "ui_OCCTModelOperator.h" +#include "OCCTBaseOperaorClass.h" +class OCCTModelOperator : public QDialog +{ + Q_OBJECT + +public: + OCCTModelOperator(QString TopoName,QWidget *parent = nullptr, Handle(AIS_InteractiveContext) myContext = nullptr); + ~OCCTModelOperator(); + + void setTopoDs_Shape(TopoDS_Shape ds); + + TopoDS_Shape getTopoDs_Shape(); + TopoDS_Shape getTopoDs_ShapeBAK(); + Handle(AIS_InteractiveContext) myContext; + Handle(AIS_InteractiveObject) getAIS(); + Handle(AIS_InteractiveObject) getAISBAK(); + +private: + Ui::OCCTModelOperatorClass ui; + +public: + TopoDS_Shape Datashape; // ´¦Àí¿ØÖÆµÄÄ£ÐÍ + TopoDS_Shape DataShapeBAK; + Handle(AIS_InteractiveObject) Data_AIS; // ´¦ÀíÄ£ÐÍ + QString ModelName; + + + + + double Move_From_X; + double Move_From_Y; + double Move_From_Z; + double Move_To_X; + double Move_To_Y; + double Move_To_Z; + + double Rotation_Center_X; + double Rotation_Center_Y; + double Rotation_Center_Z; + + double Rotation_angle_X; // ÈÆXÖáÐýת½Ç¶È + double Rotation_angle_Y; + double Rotation_angle_Z; + + double ScaleRefrencePoint_X; + double ScaleRefrencePoint_Y; + double ScaleRefrencePoint_Z; + double ScaleDouble; + +signals: // ÐźÅÓò + void ResultExportCopyAndCreateNew( OCCTModelOperator*); // ´´½¨²¢¸´ÖÆÄ£ÐÍ + void ResultExport(OCCTModelOperator*); // ·µ»ØÐ޸ĺóµÄÄ£ÐÍ + void RefreshResult(OCCTModelOperator*); // Ä£ÐÍÖØÐ»æÖÆ + +public slots: + void on_lineEdit_Move_From_X_returnPressed(); + void on_lineEdit_Move_From_Z_returnPressed(); + void on_lineEdit_Move_From_Y_returnPressed(); + void on_lineEdit_Move_To_X_returnPressed(); + void on_lineEdit_Move_To_Y_returnPressed(); + void on_lineEdit_Move_To_Z_returnPressed(); + void on_lineEdit_Rotation_Center_X_returnPressed(); + void on_lineEdit_Rotation_Center_Y_returnPressed(); + void on_lineEdit_Rotation_Center_Z_returnPressed(); + void on_lineEdit_Rotation_Axis_X_returnPressed(); + void on_lineEdit_Rotation_Axis_Y_returnPressed(); + void on_lineEdit_Rotation_Axis_Z_returnPressed(); + void on_lineEdit_Scale_returnPressed(); + + void on_lineEdit_Scale_refrence_point_X_returnPressed(); + void on_lineEdit_Scale_refrence_point_Y_returnPressed(); + void on_lineEdit_Scale_refrence_point_Z_returnPressed(); + void on_lineEdit_ScaleValue_returnPressed(); + + + + void on_radioButton_Auto_toggled(bool flag); + void on_radioButton_NoAuto_toggled(bool flag); + + // °´Å¥ + void on_pushButton_ok_clicked(); + void on_pushButton_apply_clicked(); + void on_pushButton_Cancel_clicked(); + // + void PreViewOperator(); // Ô¤´¦Àí + void ApplyModel(); + void ProcesssModel(); + void ExcuteOperator(); // Ö´ÐÐÌæ»»²Ù×÷ + void UpdataVariable(); + + // ¸üÐÂËõ·Å²ÎÊý + void UpdateScaleRefrencepoint(); + void toString(); + + // +protected: + // ÖØÐ´ closeEvent º¯ÊýÀ´²¶»ñ¹Ø±Õʼþ + void closeEvent(QCloseEvent* event) override { + // ÔڹرÕʼþ·¢ÉúʱִÐÐÄãÏëÒªµÄ²Ù×÷ + qDebug() << u8"Ä£ÐͲÙ×÷Àà is closing!"; + this->myContext->Remove(this->Data_AIS, Standard_False); + this->myContext->UpdateCurrentViewer(); + this->Datashape.Nullify(); + this->Data_AIS.Nullify(); + // µ÷Óø¸ÀàµÄ closeEvent º¯Êý£¬ÒÔÈ·±£ÕýÈ·´¦Àí´°¿ÚµÄ¹Ø±Õ + QDialog::closeEvent(event); + }; +}; + +#endif \ No newline at end of file diff --git a/src/WBCLFZSystemModule/OCCTModelOperator.ui b/src/WBCLFZSystemModule/OCCTModelOperator.ui new file mode 100644 index 0000000..dce86c2 --- /dev/null +++ b/src/WBCLFZSystemModule/OCCTModelOperator.ui @@ -0,0 +1,868 @@ + + + OCCTModelOperatorClass + + + + 0 + 0 + 510 + 741 + + + + + 0 + 660 + + + + + 16777215 + 800 + + + + 模型æ“ä½œæŽ§åˆ¶å° + + + + + + + 16777215 + 100 + + + + + + + + + + + 16777215 + 80 + + + + 模型生æˆç»“æžœ + + + + + + + 0 + 25 + + + + + 100 + 25 + + + + ä¸å¤åˆ¶ + + + + + + + + 0 + 25 + + + + + 100 + 25 + + + + å¤åˆ¶ + + + + + + + + + + + 16777215 + 80 + + + + 处ç†å®žæ—¶æ€§ + + + + + + å®žæ—¶å¤„ç† + + + + + + + éžå®žæ—¶å¤„ç† + + + + + + + + + + + + + + 16777215 + 150 + + + + 模型平移 + + + + + + + 16777215 + 200 + + + + 从 + + + + + + + 0 + 25 + + + + + 20 + 25 + + + + X + + + + + + + + 0 + 25 + + + + + 20 + 25 + + + + Y + + + + + + + + 0 + 25 + + + + + 20 + 25 + + + + Z + + + + + + + + 16777215 + 25 + + + + + + + + + 16777215 + 25 + + + + + + + + + 16777215 + 25 + + + + + + + + + + + + 16777215 + 200 + + + + 至 + + + + + + + 0 + 25 + + + + + 20 + 25 + + + + Z + + + + + + + + 0 + 25 + + + + + 20 + 25 + + + + Y + + + + + + + + 0 + 25 + + + + + 20 + 25 + + + + X + + + + + + + + 16777215 + 25 + + + + + + + + + 16777215 + 25 + + + + + + + + + 16777215 + 25 + + + + + + + + + + + + + + + 16777215 + 150 + + + + 旋转 + + + + + + + 16777215 + 120 + + + + 旋转中心 + + + + + + + 16777215 + 25 + + + + + + + + + 16777215 + 25 + + + + + + + + + 20 + 25 + + + + X + + + + + + + + 16777215 + 25 + + + + + + + + + 20 + 25 + + + + Z + + + + + + + + 20 + 25 + + + + Y + + + + + + + + + + + 16777215 + 120 + + + + 旋转矩阵 + + + + + + + 16777215 + 25 + + + + + + + + + 30 + 25 + + + + + 30 + 25 + + + + 绕Yè½´ + + + + + + + + 16777215 + 25 + + + + + + + + + 16777215 + 25 + + + + + + + + + 30 + 25 + + + + + 30 + 25 + + + + 绕Xè½´ + + + + + + + + 30 + 25 + + + + + 30 + 25 + + + + 绕Zè½´ + + + + + + + + + + + + + + 16777215 + 300 + + + + 模型缩放 + + + + + + + 0 + 25 + + + + + 16777215 + 25 + + + + ç¼©æ”¾å› å­ + + + + + + + + 16777215 + 25 + + + + + + + + + 0 + 180 + + + + + 16777215 + 200 + + + + å‚考中心 + + + + + + + 0 + 25 + + + + + 30 + 25 + + + + Z + + + + + + + + 0 + 25 + + + + + 30 + 25 + + + + X + + + + + + + + 0 + 25 + + + + + 30 + 25 + + + + Y + + + + + + + + 0 + 25 + + + + + 16777215 + 25 + + + + 自动计算(模型é‡å¿ƒï¼‰ + + + + + + + + 0 + 25 + + + + + 16777215 + 25 + + + + 手动 + + + + + + + + 0 + 25 + + + + + 16777215 + 25 + + + + + + + + + 0 + 25 + + + + + 16777215 + 25 + + + + + + + + + 0 + 25 + + + + + 16777215 + 25 + + + + + + + + + + + + + + + 16777215 + 60 + + + + + + + + QLayout::SetDefaultConstraint + + + 0 + + + 0 + + + 0 + + + + + Qt::Horizontal + + + QSizePolicy::Expanding + + + + 308 + 20 + + + + + + + + + 0 + 30 + + + + + 16777215 + 30 + + + + Qt::NoFocus + + + 确定 + + + + + + + + 0 + 30 + + + + + 16777215 + 30 + + + + Qt::NoFocus + + + 预览 + + + + + + + + 0 + 30 + + + + + 16777215 + 30 + + + + Qt::NoFocus + + + å–æ¶ˆ + + + + + + + + + + + + diff --git a/src/WBCLFZSystemModule/OCCTopoShapeTreeViewer.cpp b/src/WBCLFZSystemModule/OCCTopoShapeTreeViewer.cpp new file mode 100644 index 0000000..75a1f31 --- /dev/null +++ b/src/WBCLFZSystemModule/OCCTopoShapeTreeViewer.cpp @@ -0,0 +1,43 @@ + +#include "OCCTopoShapeTreeViewer.h" +#include +#include "SharedModuleLib/BaseUiTool.h" +#include +#include + + +OCCTopoShapeTreeViewer::OCCTopoShapeTreeViewer(QWidget* parent) + : QTreeWidget(parent) +{ + // ¹¹Ô캯Êý +} + +void OCCTopoShapeTreeViewer::setTopoShape(const TopoDS_Shape& shape) +{ + this->displayTopoShape(shape); +} + +void OCCTopoShapeTreeViewer::displayTopoShape(const TopoDS_Shape& shape) +{ + // Çå¿ÕQTreeWidget + clear(); + + // µ÷Óõݹ麯ÊýÀ´Ìí¼ÓTopo_ShapeµÄ²ã´Î½á¹¹ + addTopoShapeToTreeWidget(shape, nullptr); + + // Õ¹¿ªËùÓÐÏîÄ¿ + expandAll(); +} + + +void OCCTopoShapeTreeViewer::addTopoShapeToTreeWidget(const TopoDS_Shape& shape, QTreeWidgetItem* parentItem) +{ + // »ñÈ¡µ±Ç°Topo_ShapeµÄÀàÐÍ + TopAbs_ShapeEnum shapeType = shape.ShapeType(); + + // ´´½¨Ò»¸öеÄQTreeWidgetItemÀ´±íʾµ±Ç°Topo_Shape + QTreeWidgetItem* currentItem = new QTreeWidgetItem(parentItem); + currentItem->setText(0, TopAbs_ShapeEnum2QString(shapeType)); + +} + diff --git a/src/WBCLFZSystemModule/OCCTopoShapeTreeViewer.h b/src/WBCLFZSystemModule/OCCTopoShapeTreeViewer.h new file mode 100644 index 0000000..8be548c --- /dev/null +++ b/src/WBCLFZSystemModule/OCCTopoShapeTreeViewer.h @@ -0,0 +1,25 @@ +#ifndef OCCTOPOSHAPETREEVIEWER_H +#define OCCTOPOSHAPETREEVIEWER_H + + +#include "AllHead.h" +class OCCTopoShapeTreeViewer : public QTreeWidget +{ + Q_OBJECT + +public: + OCCTopoShapeTreeViewer(QWidget* parent = nullptr); + void setTopoShape(const TopoDS_Shape& shape); + // ÏÔʾTopo_ShapeµÄ²ã´Î½á¹¹ + void displayTopoShape(const TopoDS_Shape& shape); + +private: + // µÝ¹éº¯Êý£¬ÓÃÓÚÔÚQTreeWidgetÖÐÌí¼ÓTopo_ShapeµÄ²ã´Î½á¹¹ + void addTopoShapeToTreeWidget(const TopoDS_Shape& shape, QTreeWidgetItem* parentItem); +}; + + + + + +#endif // OCCTOPOSHAPETREEVIEWER_H diff --git a/src/WBCLFZSystemModule/OCCViewer/CommonSample.h b/src/WBCLFZSystemModule/OCCViewer/CommonSample.h new file mode 100644 index 0000000..0bb38ac --- /dev/null +++ b/src/WBCLFZSystemModule/OCCViewer/CommonSample.h @@ -0,0 +1,43 @@ +// Copyright (c) 2020 OPEN CASCADE SAS +// +// This file is part of the examples of the Open CASCADE Technology software library. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE + +#ifndef COMMONSAMPLE_H +#define COMMONSAMPLE_H + +#ifndef NO_COMMONSAMPLE_EXPORTS +#ifdef COMMONSAMPLE_EXPORTS +#ifdef _WIN32 +#define COMMONSAMPLE_EXPORT __declspec( dllexport ) +#else +#define COMMONSAMPLE_EXPORT +#endif +#else +#ifdef _WIN32 +#define COMMONSAMPLE_EXPORT __declspec( dllimport ) +#else +#define COMMONSAMPLE_EXPORT +#endif +#endif +#else +#define COMMONSAMPLE_EXPORT +#endif + +#endif diff --git a/src/WBCLFZSystemModule/OCCViewer/DocumentCommon.cpp b/src/WBCLFZSystemModule/OCCViewer/DocumentCommon.cpp new file mode 100644 index 0000000..24d600d --- /dev/null +++ b/src/WBCLFZSystemModule/OCCViewer/DocumentCommon.cpp @@ -0,0 +1,890 @@ +// Copyright (c) 2020 OPEN CASCADE SAS +// +// This file is part of the examples of the Open CASCADE Technology software library. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE + + + +#include "OCCT_Test/MakeBottle.h" +#include "DocumentCommon.h" +#include "Transparency.h" +#include "AllHead.h" +#include + + + + +// ======================================================================= +// function : Viewer +// purpose : +// ======================================================================= +Handle(V3d_Viewer) DocumentCommon::Viewer(const Standard_ExtString, + const Standard_CString, + const Standard_Real theViewSize, + const V3d_TypeOfOrientation theViewProj, + const Standard_Boolean theComputedMode, + const Standard_Boolean theDefaultComputedMode) +{ + static Handle(OpenGl_GraphicDriver) aGraphicDriver; + if (aGraphicDriver.IsNull()) + { + Handle(Aspect_DisplayConnection) aDisplayConnection; +#if !defined(_WIN32) && !defined(__WIN32__) && (!defined(__APPLE__) || defined(MACOSX_USE_GLX)) + aDisplayConnection = new Aspect_DisplayConnection(OSD_Environment("DISPLAY").Value()); +#endif + aGraphicDriver = new OpenGl_GraphicDriver(aDisplayConnection); +} + + Handle(V3d_Viewer) aViewer = new V3d_Viewer(aGraphicDriver); + aViewer->SetDefaultViewSize(theViewSize); + aViewer->SetDefaultViewProj(theViewProj); + aViewer->SetComputedMode(theComputedMode); + aViewer->SetDefaultComputedMode(theDefaultComputedMode); + return aViewer; +} + +void DocumentCommon::ShowOrHideActivateGridMesh() { + qDebug() << u8"Çл»Æ½ÃæÍø¸ñÏÔʾ \n"; + if (this->isActivateGridMesh) { + myViewer->DeactivateGrid(); + this->isActivateGridMesh = false; + } + else { + // ÉèÖÃXOYÆ½ÃæµÄÍø¸ñ + myViewer->SetGridEcho(Standard_True); + myViewer->ActivateGrid(Aspect_GT_Rectangular, Aspect_GDM_Lines); + this->isActivateGridMesh = true; + } + myViewer->Redraw(); +} + +void DocumentCommon::ShowOrHideActivateAxisGris() +{ + qDebug() << u8"Çл»×ø±êÖáÍø¸ñÏÔʾ \n"; + if (this->isActivateAxisGrid) { + + for (NCollection_List::Iterator anIter(this->myViewer->ActiveViews()); + anIter.More(); anIter.Next()) + { + const Handle(V3d_View)& anObject = anIter.Value(); + anObject->GraduatedTrihedronErase(); + } + this->isActivateAxisGrid = false; + } + else { + + for (NCollection_List::Iterator anIter(this->myViewer->ActiveViews()); + anIter.More(); anIter.Next()) + { + const Handle(V3d_View)& anObject = anIter.Value(); + // ´´½¨Á¢·½ÌåÍø¸ñ¶ÔÏó + Graphic3d_GraduatedTrihedron grid; + anObject->GraduatedTrihedronDisplay(grid); + } + + this->isActivateAxisGrid = true; + } + + myViewer->Redraw(); +} + +bool DocumentCommon::getActivateGridMesh() +{ + return this->isActivateGridMesh; +} + +bool DocumentCommon::getActivateAxisGrid() +{ + return this->isActivateAxisGrid; +} + + +Handle(AIS_InteractiveObject) DocumentCommon::ShowTopoDS_Shape(TopoDS_Shape& shape) +{ + Handle(AIS_InteractiveObject) aShape = new AIS_Shape(shape); + this->myContext->Display(aShape, Standard_True); + return aShape; +} + +bool DocumentCommon::HideTopoDS_Shape(Handle(AIS_InteractiveObject) aShape) +{ + + this->myContext->Erase(aShape, Standard_True); + return true; +} + +bool DocumentCommon::ShowTopoDs_ShapeAIS(Handle(AIS_InteractiveObject) aShape) +{ + this->myContext->Display(aShape, Standard_True); + return true; +} + +bool DocumentCommon::RemoveTopoDS_Shape(Handle(AIS_InteractiveObject) aShape) +{ + this->myContext->Remove(aShape, Standard_True); + return true; +} + +DocumentCommon::DocumentCommon(QWidget* theApp) + :myContextIsEmpty(true), + QTreeWidget(theApp) +{ + this->ShapeInfomationWindows = nullptr; + TCollection_ExtendedString a3DName("Visu3D"); + myViewer = Viewer(a3DName.ToExtString(), "", 1000.0, V3d_XposYnegZpos, Standard_True, Standard_True); + myViewer->SetDefaultLights(); + myViewer->SetLightOn(); + myContext = new AIS_InteractiveContext(myViewer); + this->setColumnCount(1); + this->initTaskTreeRootNode(); + this->initDocumentCommonContextMenu(); // ³õʼ»¯ÓÒ¼ü²Ëµ¥ +} + +void DocumentCommon::SetObjects(const NCollection_Vector& theObjects, + Standard_Boolean theDisplayShaded) +{ + myContext->RemoveAll(Standard_False); // Çå¿Õ¶ÔÏó + myContextIsEmpty = theObjects.IsEmpty(); + + for (NCollection_Vector::Iterator anIter(theObjects); + anIter.More(); anIter.Next()) + { + const Handle(AIS_InteractiveObject)& anObject = anIter.Value(); + if (!theDisplayShaded) + { + myContext->Display(anObject, Standard_False); + } + else + { + myContext->Display(anObject, AIS_Shaded, 0, Standard_False); + } + } + myViewer->Redraw(); +} + +void DocumentCommon::ClearShape() +{ + myContext->RemoveAll(Standard_True); + myContextIsEmpty = true; +} + +void DocumentCommon::AppendCube() +{ + qDebug() << u8"³õʼ»¯×ø±êϵ \n"; + Handle(AIS_ViewCube) aViewCube = new AIS_ViewCube(); + myObject3d.Append(aViewCube); + +} + +void DocumentCommon::InitAixs() +{ + this->AppendCube(); + + myContext->RemoveAll(Standard_False); + myContextIsEmpty = this->myObject3d.IsEmpty(); + + for (NCollection_Vector::Iterator anIter(this->myObject3d); + anIter.More(); anIter.Next()) + { + const Handle(AIS_InteractiveObject)& anObject = anIter.Value(); + myContext->Display(anObject, Standard_False); + } + this->isActivateAxisGrid = false; + this->isActivateGridMesh = false; + //this->ShowOrHideActivateAxisGris(); + this->ShowOrHideActivateGridMesh(); + myViewer->Redraw(); +} + +TaskNode* DocumentCommon::getItemByName(QString name) +{ + if (this->dataMap.contains(name)) { + QTreeWidgetItem* item = this->dataMap.value(name); + TaskNode* obj = item->data(0, Qt::UserRole).value(); + return obj; + } + else { + return nullptr; + } +} + +std::shared_ptr DocumentCommon::getSenceExtend() +{ + + std::shared_ptr theOverallBox_ptr = std::make_shared();; + AIS_ListOfInteractive aListOfObjects; + this->myContext->DisplayedObjects(aListOfObjects); + + AIS_ListIteratorOfListOfInteractive anIter(aListOfObjects); + for (; anIter.More(); anIter.Next()) { + Handle(AIS_InteractiveObject) anIO = anIter.Value(); + Handle_AIS_Shape aShape = Handle_AIS_Shape::DownCast(anIO); + if (!aShape.IsNull()) { + // Get the TopoDS_Shape + TopoDS_Shape aTopoShape = aShape->Shape(); + BRepBndLib::Add(aTopoShape, *theOverallBox_ptr); + + } + } + return theOverallBox_ptr; +} + +std::shared_ptr DocumentCommon::getSenceExtend(QString name) +{ + TaskNode* temp = this->getItemByName(name); + if (temp) { + + OCCTShapeModelNode* node= dynamic_cast(temp); + + + TopoDS_Shape aTopoShape = node->Shape(); + std::shared_ptr aBox_ptr = std::make_shared();; + BRepBndLib::Add(aTopoShape, *aBox_ptr); + + return aBox_ptr; + } + else { + std::shared_ptr aBox_ptr(nullptr); + return aBox_ptr; + } +} + +void DocumentCommon::OpenOCCTShapeFile() +{ + qDebug() << u8"´ò¿ªÎļþ \n"; + QString stlpath = getOpenFilePath( + nullptr, + QString::fromUtf8(u8"µ¼ÈëÄ£ÐÍ"), + + QString::fromUtf8(u8"STL Files (*.stl);;STL Files (*.stla);;step Files (*.stp);;step Files (*.step);;IGES Files (*.iges);;IGES Files (*.igs)")); + this->addShapeDsItem(stlpath); +} + + +// ´ò¿ªÄ£ÐÍ +void DocumentCommon::addShapeDsItem(QString filepath) +{ + OCCTShapeModelNode* checkBox = new OCCTShapeModelNode(this); + checkBox->setContext(this->myContext); + if (checkBox->setDataFile(filepath)) { + this->addOCCTObjectItem(checkBox); + } + else { + qDebug() << u8"ûÓдò¿ªÎļþ£º" << filepath << "\n"; + } +} + +void DocumentCommon::oncheckBoxStateChanged(int state) { + +} + + +void DocumentCommon::initDocumentCommonContextMenu() +{ + qDebug() << u8"³õʼ»¯initDocumentCommonContextMenu£¬Ä£Ðͱ༭ģ¿é"; + this->m_undoStack = new QUndoStack(this); //´æ·ÅÃüÁîµÄÕ» + + this->setContextMenuPolicy(Qt::CustomContextMenu); + this->ContentListContextMenu = new QMenu(this); // ±í¸ñ¿Ø¼þµÄÓÒ¼ü²Ëµ¥ + + //QAction* m_undoAction = m_undoStack->createUndoAction(this, u8"³·Ïú");//Ìí¼ÓQAction£¬Ctrl-Z×÷Ϊ»Ø³·µÄ¿ì½Ý¼ü + //m_undoAction->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Z)); + //QObject::connect(m_undoAction, SIGNAL(triggered()), this, SLOT(tableView_UndoAction())); + + //QAction* m_redoAction = m_undoStack->createRedoAction(this, u8"ÖØ×ö");//Ìí¼ÓQAction£¬Ctrl-Y×óÓÒǰ½øµÄ¿ì½Ý¼ü + //m_redoAction->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Y)); + //QObject::connect(m_redoAction, SIGNAL(triggered()), this, SLOT(tableView_RedoAction())); + + //this->ContentListContextMenu->addAction(m_undoAction); + //this->ContentListContextMenu->addAction(m_redoAction); + + //QAction* TranslationdAction = this->ContentListContextMenu->addAction(u8"Ä£ÐͲÙ×÷"); // + //QObject::connect(TranslationdAction, SIGNAL(triggered()), this, SLOT(TranslationObjectWindShow())); + + + //QAction* BatchExportAction = this->ContentListContextMenu->addAction(u8"Ä£ÐÍÅúÁ¿µ¼³ö"); // + //QObject::connect(BatchExportAction, SIGNAL(triggered()), this, SLOT(ContentListContextMenu_BatchExportAction())); + + QObject::connect(this, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(ShowContentListContextMenu(QPoint))); + qDebug() << u8"³õʼ»¯contextMenu½áÊø"; + +} +void DocumentCommon::initTaskTreeRootNode() +{ + this->clear(); //ɾ³ýËùÓнڵã + this->setHeaderHidden(true); // ÏÔʾ±íÍ· + + // ´´½¨2¸ö¸ù½Úµã Êý¾Ý ÈÎÎñ + dataRoot = new QTreeWidgetItem(this); + dataRoot->setText(0, u8"Êý¾Ý"); + // ´´½¨3¸ö½Úµã Ä£ÐÍ Í¼Ïñ µãÔÆ + modelRoot = new QTreeWidgetItem(dataRoot); + modelRoot->setText(0, u8"Ä£ÐÍ"); + imageRoot = new QTreeWidgetItem(dataRoot); + imageRoot->setText(0, u8"ͼÏñ"); + + pointCloudRoot = new QTreeWidgetItem(dataRoot); + pointCloudRoot->setText(0, u8"ÊôÐÔÊý¾Ý¿â"); + atriTableRoot = new QTreeWidgetItem(dataRoot); + atriTableRoot->setText(0, u8"ÊôÐÔÊý¾Ý¿â"); + + taskRoot = new QTreeWidgetItem(this); + taskRoot->setText(0, u8"ÈÎÎñ"); + + // ´´½¨3¸ö½Úµã ·ÂÕæÍ¼ÏñÈÎÎñ¡¢ºóÏòÉ¢ÉäϵÊýµ¼³öÈÎÎñ¡¢·ÂÕæºóÏòÉ¢ÉäÈÎÎñ + fekoSimulationRoot = new QTreeWidgetItem(taskRoot); + fekoSimulationRoot->setText(0, u8"·ÂÕæÈÎÎñ"); + exportScatteringRoot = new QTreeWidgetItem(taskRoot); + exportScatteringRoot->setText(0, u8"ºóÏòÉ¢ÉäϵÊýµ¼³öÈÎÎñ"); + fekoScatteringRoot = new QTreeWidgetItem(taskRoot); + fekoScatteringRoot->setText(0, u8"·ÂÕæºóÏòÉ¢ÉäÈÎÎñ"); + + + // ½«¸ù½ÚµãÌí¼Óµ½ QTreeWidget ÖÐ + this->addTopLevelItem(dataRoot); + this->addTopLevelItem(taskRoot); + this->show(); +} + +void DocumentCommon::addTaskNode(TaskNode* node) +{ + if (node) { + node->setParent(this); + if (dynamic_cast(node) != nullptr) { // Ä£ÐÍÊý¾Ý½Úµã + this->addOCCTObjectItem(node); + } + else if (dynamic_cast(node) != nullptr) { // ¸¨ÖúͼÏñ½Úµã + this->addImageObjectItem(node); + } + else if (dynamic_cast(node) != nullptr) { // ¸¨ÖúͼÏñ½Úµã + this->addImageObjectItem(node); + } + else if (dynamic_cast(node) != nullptr) { // ºóÏòÉ¢ÉäϵÊýÄ£ÄâÈÎÎñ½Úµã + this->addScatterSettingTaskItem(node); + } + else if (dynamic_cast(node) != nullptr) { // ºóÏòÉ¢Éäµ¼Èë + this->addFEKOResultDataConvertItem(node); + } + else if (dynamic_cast(node) != nullptr) { // ·ÂÕæ³ÉÏñ²ÎÊýÈÎÎñ + this->addFEKOSimulationImageSettingItem(node); + } + else { + QMessageBox::warning(this, u8"¾¯¸æ", u8"δ֪ÈÎÎñ½Úµã"); + delete node; + return; + } + + // Ìí¼ÓÐźÅÁ¬½Ó + QObject::connect(node, SIGNAL(renameNode(QString, QString)), this, SLOT(renameTaskNode(QString, QString))); + QObject::connect(node, SIGNAL(deleteItem(QString)), this, SLOT(removeTaskNode(QString))); + QObject::connect(node, SIGNAL(deleteNode(QString)), this, SLOT(removeTaskNode(QString))); + } + else { + // nullptr + } +} +void DocumentCommon::addOCCTObjectItem(TaskNode* node) +{ + + QTreeWidgetItem* itemtemp = this->newQTaskTreeWidgetItem(node); + if (itemtemp) { + //if (this->addUniqueNode(itemtemp)) { + this->UpdateItemParantNode(itemtemp, modelRoot); + //} + } + else { + + } +} +void DocumentCommon::addImageObjectItem(TaskNode* node) +{ + QTreeWidgetItem* itemtemp = this->newQTaskTreeWidgetItem(node); + if (itemtemp) { + //if (this->addUniqueNode(itemtemp)) { + this->UpdateItemParantNode(itemtemp, imageRoot); + //} + } + else { + + } +} +void DocumentCommon::addPointCloudObjectItem(TaskNode* node) +{ + QTreeWidgetItem* itemtemp = this->newQTaskTreeWidgetItem(node); + if (itemtemp) { + //if (this->addUniqueNode(itemtemp)) { + + this->UpdateItemParantNode(itemtemp, pointCloudRoot); + // } + } + else { + + } +} +void DocumentCommon::addAtriTableObjectItem(TaskNode* node) +{ + QTreeWidgetItem* itemtemp = this->newQTaskTreeWidgetItem(node); + if (itemtemp) { + //if (this->addUniqueNode(itemtemp)) { + + this->UpdateItemParantNode(itemtemp, atriTableRoot); + //} + } + else { + + } +} +void DocumentCommon::addScatterSettingTaskItem(TaskNode* node) +{ + QTreeWidgetItem* itemtemp = this->newQTaskTreeWidgetItem(node); + if (itemtemp) { + //if (this->addUniqueNode(itemtemp)) { + + this->UpdateItemParantNode(itemtemp, fekoScatteringRoot); + // } + } + else { + + } +} +void DocumentCommon::addFEKOResultDataConvertItem(TaskNode* node) +{ + QTreeWidgetItem* itemtemp = this->newQTaskTreeWidgetItem(node); + if (itemtemp) { + //if (this->addUniqueNode(itemtemp)) { + + this->UpdateItemParantNode(itemtemp, exportScatteringRoot); + //} + } + else { + + } +} +void DocumentCommon::addFEKOSimulationImageSettingItem(TaskNode* node) +{ + QTreeWidgetItem* itemtemp = this->newQTaskTreeWidgetItem(node); + if (itemtemp) { + // if (this->addUniqueNode(itemtemp)) { + + this->UpdateItemParantNode(itemtemp, fekoSimulationRoot); + // } + } + else { + } +} + + +void DocumentCommon::removeTaskNode(QTreeWidgetItem* node) +{ + if (node) { + node->parent()->removeChild(node); + this->dataMap.remove(node->text(0)); + } + else { + QMessageBox::warning(this, u8"¾¯¸æ", u8"δ֪½Úµã"); + } +} +void DocumentCommon::removeTaskNode(QString itemName) +{ + if (this->dataMap.contains(itemName)) { + QTreeWidgetItem* item = this->dataMap.value(itemName); + TaskNode* obj = item->data(0, Qt::UserRole).value(); + if (obj->status != TaskStatusEnum::finish) { + obj->FinishTask(); // µ÷ÓÃÖ´ÐнáÊøÁ÷³Ì + } + this->removeTaskNode(item); + } + else { + QMessageBox::warning(this, u8"¾¯¸æ", u8"δÕÒµ½½Úµã£º"+ itemName); + } + +} +bool DocumentCommon::addUniqueNode(QTreeWidgetItem* item) +{ + if (this->dataMap.contains(item->text(0))) { + QMessageBox::warning(this, u8"¾¯¸æ", u8"·¢ÏÖͬÃû½Úµã£º"+ item->text(0)); + return false; + } + else { + this->dataMap.insert(item->text(0), item); + return true; + } +} + +QTreeWidgetItem* DocumentCommon::newQTaskTreeWidgetItem(TaskNode* node) +{ + + QTreeWidgetItem* itemtemp; + + if (node) { + if (dynamic_cast(node) != nullptr) { // Ä£ÐÍÊý¾Ý½Úµã + itemtemp = new QTreeWidgetItem(this->modelRoot); + } + else if (dynamic_cast(node) != nullptr) { // ¸¨ÖúͼÏñ½Úµã + itemtemp = new QTreeWidgetItem(this->imageRoot); + } + else if (dynamic_cast(node) != nullptr) { // ¸¨ÖúͼÏñ½Úµã + itemtemp = new QTreeWidgetItem(this->imageRoot); + } + else if (dynamic_cast(node) != nullptr) { // ºóÏòÉ¢ÉäϵÊýÄ£ÄâÈÎÎñ½Úµã + itemtemp = new QTreeWidgetItem(this->fekoScatteringRoot); + } + else if (dynamic_cast(node) != nullptr) { // ºóÏòÉ¢Éäµ¼Èë + itemtemp = new QTreeWidgetItem(this->exportScatteringRoot); + } + else if (dynamic_cast(node) != nullptr) { // ·ÂÕæ³ÉÏñ²ÎÊýÈÎÎñ + itemtemp = new QTreeWidgetItem(this->fekoSimulationRoot); + } + else { + QMessageBox::warning(this, u8"¾¯¸æ", u8"δ֪ÈÎÎñ½Úµã"); + delete node; + return nullptr; + } + + // Ìí¼ÓÐźÅÁ¬½Ó + QObject::connect(node, SIGNAL(renameNode(QString, QString)), this, SLOT(renameTaskNode(QString, QString))); + QObject::connect(node, SIGNAL(deleteItem(QString)), this, SLOT(removeTaskNode(QString))); + } + else { + QMessageBox::warning(this, u8"¾¯¸æ", u8"δ֪ÈÎÎñ½Úµã"); + delete node; + return nullptr; + } + qDebug() << node->getTaskName(); + itemtemp->setText(0, node->getTaskName()); + itemtemp->setData(0, Qt::UserRole, QVariant::fromValue(node)); + + // ´¦Àíʼþ°ó¶¨ + + if (this->addUniqueNode(itemtemp)) { + return itemtemp; + } + else { + delete itemtemp; + return nullptr; + } +} + +void DocumentCommon::renameTaskNode(QString olditemName, QString newitemName) +{ + qDebug() << u8"ÕýÔÚÖ´ÐÐÖØÃüÃûÃüÁî"; + if (this->dataMap.contains(newitemName)) { + QMessageBox::warning(this, u8"¾¯¸æ", u8"´æÔÚͬÃû½Úµã"); + } + else { + QTreeWidgetItem* item = this->dataMap.value(olditemName); + item->setText(0, newitemName); + this->dataMap.remove(olditemName); + this->dataMap.insert(newitemName, item); + TaskNode* obj = item->data(0, Qt::UserRole).value(); + obj->setName(newitemName); + } +} + +void DocumentCommon::copyNewNode(TaskNode* newNode) +{ + if (newNode) { + QString newName = QInputDialog::getText(this, u8"ÖØÃüÃû", u8"ÇëÊäÈëеÄÃû³Æ", QLineEdit::Normal, newNode->getName() + u8"_1"); + if (newName.isEmpty()) { + QMessageBox::warning(this, u8"¾¯¸æ", u8"ÎÞЧÃû³Æ"); + delete newNode;// ÎÞЧ¶ÔÏó£¬Ö±½Óɾ³ý + } + else { + newNode->setName(newName); + this->addTaskNode(newNode); + } + + } + else { + // nullptr + } + +} + +void DocumentCommon::UpdateItemParantNode(QTreeWidgetItem* n, QTreeWidgetItem* p) +{ + if (n) { + QTreeWidgetItem * parentOfn =n->parent();//»ñÈ¡½Úµã n µÄ¸¸½Úµã + if (parentOfn) { + parentOfn->removeChild(n); + if (p) { + p->addChild(n); + } + else { + this->addTopLevelItem(n); + } + } + else { + if (p) { + int index=this->indexOfTopLevelItem(n); + this->takeTopLevelItem(index); + p->addChild(n); + } + else { // ±¾Éí¾ÍÊǽڵã¾ÍÊǸù½Úµã£¬ÎÞÐëÔÙÌáÉý + return; + } + + } + } + else { + // ²»ÊǸù½Úµã£¬Ö±½Ó·µ»Ø + } +} + + + + +void DocumentCommon::addOCCTObjItem(TopoDS_Shape shape, QString name, bool ishow) +{ + OCCTShapeModelNode* checkBox = new OCCTShapeModelNode(this); + checkBox->setContext(this->myContext); + checkBox->setShape(shape); + checkBox->setText(name); + //QObject::connect(checkBox, SIGNAL(copyNew()), this, SLOT(copyOCCTObjectCheckBoxItem())); + //QObject::connect(checkBox, SIGNAL(ShowFullExtend(const TopoDS_Shape&)), this, SLOT(SelectItemFullShow(const TopoDS_Shape&))); + //QObject::connect(checkBox, SIGNAL(ModelModify(OCCTShapeModelNode*)), this, SLOT(ShapeModifyShape(OCCTShapeModelNode*))); + this->addTaskNode(checkBox); + if (ishow) { + checkBox->ShowShape(); // չʾģÐÍ + } + else { + checkBox->HideShape(); // Òþ²ØÄ£ÐÍ + } +} + + +TopoDS_Shape DocumentCommon::MergeCOntextAllModels() { + TopoDS_Compound compound; + BRep_Builder builder; + builder.MakeCompound(compound); + + this->myContext->InitSelected(); // ³õʼ»¯Ä£ÐÍ + for (; myContext->MoreSelected(); myContext->NextSelected()) { + Handle(AIS_InteractiveObject) selectedObject = myContext->SelectedInteractive(); + + if (!selectedObject.IsNull()) { + TopoDS_Shape shape = this->getTopoDSShape(selectedObject); + // ½«Ã¿¸öÐÎ×´Ìí¼Óµ½ Compound + builder.Add(compound, shape); + } + } + return compound; +} + +// ±£´æÄ£ÐÍ +void DocumentCommon::SaveModelFile() { + + // Ñ¡Ôñ±£´æÎļþ + qDebug() << u8"´ò¿ªÎļþ \n"; + QString filepath = getSaveFilePath( + nullptr, + QString::fromUtf8(u8"±£´æFEKO½á¹ûµ¼È볡¾°Ä£ÐÍ"), + QString::fromUtf8(u8"STL Files (*.stl);;STL Files (*.stla);;step Files (*.stp);;step Files (*.step);;IGES Files (*.iges);;IGES Files (*.igs)")); + QFileInfo fileinfo(filepath); + QString filename = fileinfo.fileName(); + QString fileSuffix = fileinfo.suffix(); + TopoDS_Shape shape_TopoDs = this->MergeCOntextAllModels(); // ºÏ²¢ËùÓÐÄ£ÐÍ + // ±£´æÄ£ÐÍ + if (fileSuffix.compare(u8"stl") == 0 || fileSuffix.compare(u8"stla") == 0) { + SaveTopoDs_Stl(filepath, shape_TopoDs); + } + else if (fileSuffix.compare(u8"step") == 0 || fileSuffix.compare(u8"stp") == 0) { + SaveTopoDs_Step(filepath, shape_TopoDs); + } + else if (fileSuffix.compare(u8"iges") == 0 || fileSuffix.compare(u8"igs") == 0) { + SaveTopoDs_IGES(filepath, shape_TopoDs); + } + else { + + } + +} + + +void DocumentCommon::ShowContentListContextMenu(QPoint p) { + qDebug() << u8"ÕýÔÚչʾShowContentListContextMenu ÓÒ¼ü²Ëµ¥"; + + + QList < QTreeWidgetItem* > selectitems =this->selectedItems(); + if (selectitems.count() == 0) { + // ³õʼ»¯ÓÒ¼ü²Ëµ¥ + return; + } + else if (selectitems.count() == 1) { + TaskNode* obj=this->getItemByName(selectitems[0]->text(0)); + if (obj) { + obj->ShowContentListContextMenu(p); + } + else {} + return; + }else if(selectitems.count()>1){ + for (size_t i = 0; i < selectitems.count(); i++) { + TaskNode* obj = this->getItemByName(selectitems[i]->text(0)); + obj->ContentListContextMenu->setTitle(obj->getTaskName()); + this->ContentListContextMenu->addMenu(obj->ContentListContextMenu); + } + this->ContentListContextMenu->exec(QCursor::pos()); + } + else { + return; + } +} + + +void DocumentCommon::ContentListContextMenu_UndoAction() +{ + qDebug() << u8"ÕýÔÚ³·ÏúÃüÁî"; + int index = this->m_undoStack->index(); + this->m_undoStack->setIndex(index); +} + +void DocumentCommon::ContentListContextMenu_RedoAction() +{ + qDebug() << u8"ÕýÔÚÖØ×öÃüÁî"; + int index = this->m_undoStack->index(); + this->m_undoStack->setIndex(index); +} + +void DocumentCommon::ContentListContextMenu_BatchExportAction() +{ + qDebug() << u8"ÅúÁ¿µ¼³öÄ£ÐÍ"; + DialogBatchExport* exportWindows = new DialogBatchExport(); + for (int i = 0; i < this->modelRoot->childCount(); ++i) { + QTreeWidgetItem* item = this->modelRoot->child(i); + TaskNode* obj = item->data(0, Qt::UserRole).value(); + if (obj) { + OCCTShapeModelNode* checkBox = dynamic_cast(obj); + exportWindows->addDataShape(checkBox->text(), checkBox->Shape()); + } + else { + QMessageBox::warning(this, u8"´íÎó", u8"·¢ÏÖ´íÎó£º" + item->text(0)); + continue; + } + } + exportWindows->show(); +} + + +/////////////////////////// +// ´°¿ÚÓÒ¼ü²Ëµ¥ +////////////////////////// + + +void DocumentCommon::VerticesSelect3dSample() +{ + qDebug() << u8"Çл»Ñ¡ÔñģʽΪ£ºTopAbs_VERTEX"; + myContext->Deactivate(); + myContext->Activate(AIS_Shape::SelectionMode(TopAbs_VERTEX)); +} + +void DocumentCommon::EdgesSelect3dSample() +{ + qDebug() << u8"Çл»Ñ¡ÔñģʽΪ£ºTopAbs_EDGE"; + myContext->Deactivate(); + myContext->Activate(AIS_Shape::SelectionMode(TopAbs_EDGE)); +} + +void DocumentCommon::FacesSelect3dSample() +{ + qDebug() << u8"Çл»Ñ¡ÔñģʽΪ£ºTopAbs_FACE"; + myContext->Deactivate(); + myContext->Activate(AIS_Shape::SelectionMode(TopAbs_FACE)); +} + +void DocumentCommon::NeutralPointSelect3dSample() +{ + qDebug() << u8"Çл»Ñ¡ÔñģʽΪ£ºTopAbs_COMPOUND"; + myContext->Deactivate(); + myContext->Activate(TopAbs_COMPOUND); +} + +//void DocumentCommon::ShapeModifyShape(OCCTShapeModelNode* dataItem) +//{ +// qDebug() << u8"Ä£ÐͲÙ×÷"; +// OCCTModelOperator* operatorWindows = new OCCTModelOperator(dataItem->text(), nullptr, this->myContext); +// operatorWindows->setModal(false); +// //operatorWindows->setTopoDs_Shape(dataItem->DataShape); +// // °ó¶¨Ä£ÐÍ +// QObject::connect(operatorWindows, SIGNAL(ResultExportCopyAndCreateNew(OCCTModelOperator*)), this, SLOT(TranslationExportCopy(OCCTModelOperator*))); +// QObject::connect(operatorWindows, SIGNAL(ResultExport(OCCTModelOperator*)), this, SLOT(TranslationExport(OCCTModelOperator*))); +// QObject::connect(operatorWindows, SIGNAL(RefreshResult(OCCTModelOperator*)), this, SLOT(RefreshResult(OCCTModelOperator*))); +// operatorWindows->show(); +//} + +//////////////////////////////////////////////////////////// +// Ä£ÐͽçÃæµÄÑ¡Ôñʼþ +//////////////////////////////////////////////////////////// +void DocumentCommon::ViewerMousePressEvent(QMouseEvent* theEvent) { + qDebug() << u8"view ´°Ìå°´¼ü°´Ïµã»÷ʼþ±»¼¤»î \n"; +} + +void DocumentCommon::ViewerMouseReleaseEvent(QMouseEvent* theEvent) +{ + qDebug() << u8"view ´°Ìå°´¼üÊÍ·Åʼþ±»¼¤»î \n"; + for (this->myContext->InitSelected(); this->myContext->MoreSelected(); this->myContext->NextSelected()) { + Handle(AIS_InteractiveObject) selectedObject = this->myContext->SelectedInteractive(); + qDebug() << u8"view ·¢ÏÖÑ¡ÖжÔÏó \n"; + TopoDS_Shape selectShape = this->getTopoDSShape(selectedObject); + emit this->SelectObjectList(selectShape); + this->showSelectShape(selectShape); + } + +} + +void DocumentCommon::SelectItemFullShow(const TopoDS_Shape& shape) +{ + emit this->ShowSelectItemFullExtend(shape); +} + + + +void DocumentCommon::setShapeInfomationWindows(OCCTopoShapeTreeViewer* ShapeInfomationWindows) +{ + this->ShapeInfomationWindows = ShapeInfomationWindows; +} + +// Function to get TopoDS_Shape from AIS_InteractiveObject +TopoDS_Shape DocumentCommon::getTopoDSShape(const Handle(AIS_InteractiveObject)& aisObject) +{ + if (aisObject.IsNull() || !aisObject->HasInteractiveContext()) + return TopoDS_Shape(); // Return an empty shape if AIS_InteractiveObject is null or not associated with an interactive context + + Handle(AIS_Shape) aisShape = Handle(AIS_Shape)::DownCast(aisObject); + if (aisShape.IsNull()) + return TopoDS_Shape(); // Return an empty shape if AIS_InteractiveObject is not a shape + + // Get the shape from AIS_Shape + TopoDS_Shape topoShape = aisShape->Shape(); + + return topoShape; +} + +void DocumentCommon::showSelectShape(const TopoDS_Shape& selectShape) +{ + qDebug() << u8"ÏÔʾѡÖеĶÔÏó \n"; + if (this->ShapeInfomationWindows) { + this->ShapeInfomationWindows->setTopoShape(selectShape); + } + else {} +} + + + + + \ No newline at end of file diff --git a/src/WBCLFZSystemModule/OCCViewer/DocumentCommon.h b/src/WBCLFZSystemModule/OCCViewer/DocumentCommon.h new file mode 100644 index 0000000..a0b462c --- /dev/null +++ b/src/WBCLFZSystemModule/OCCViewer/DocumentCommon.h @@ -0,0 +1,209 @@ +// Copyright (c) 2020 OPEN CASCADE SAS +// +// This file is part of the examples of the Open CASCADE Technology software library. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE + +#ifndef DOCUMENT_COMMON_OVERVIEW_H +#define DOCUMENT_COMMON_OVERVIEW_H + + +#include "AllHead.h" +#include + +#include "TaskXml/TaskTreeClass.h" +#include "TaskNodeList.h" + + + + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// ÎļþÄ£ÐÍ¿ØÖÆ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +//! Implements visualization of samples content +class DocumentCommon : public QTreeWidget +{ + Q_OBJECT +public: + + Q_INVOKABLE DocumentCommon(QWidget*); + ~DocumentCommon() { } + +//========================================= +// ÈÎÎñ½Úµã¹ÜÀí +//========================================= + +public: // Êý¾Ý¹ÜÀí²ã´Î + QTreeWidgetItem* dataRoot; // ¸ù½Úµã + QTreeWidgetItem* taskRoot; + + QTreeWidgetItem* modelRoot; // Êý¾ÝÀàÐÍ + QTreeWidgetItem* imageRoot; + QTreeWidgetItem* pointCloudRoot; + QTreeWidgetItem* atriTableRoot; + + QTreeWidgetItem* fekoSimulationRoot; // ÈÎÎñÀàÐÍ + QTreeWidgetItem* exportScatteringRoot; + QTreeWidgetItem* fekoScatteringRoot; + + QMap dataMap; // Êý¾ÝÃû-½ÚµãÏî°ó¶¨ + +public slots: + + void initTaskTreeRootNode(); //³õʼ»¯ÈÎÎñÊ÷ + + TaskNode* getItemByName(QString name);// ³¡¾°½Úµã + void addTaskNode(TaskNode*); // Ìí¼Ó½Úµã + void removeTaskNode(QString itemName); // ÒÆ³ý½Úµã + bool addUniqueNode(QTreeWidgetItem* item); // Ìí¼ÓΨһÐÔ½Úµã + QTreeWidgetItem* newQTaskTreeWidgetItem(TaskNode* node); // ´´½¨ÈÎÎñ½Úµã + void renameTaskNode(QString olditemName,QString newitemName); // ÖØÃüÃû½Úµã + void copyNewNode(TaskNode* newNode); + void UpdateItemParantNode(QTreeWidgetItem* n, QTreeWidgetItem* p = nullptr);// ¸ü±ä¸¸½Úµã£¬Èç¹ûÊÇ¿ÕÖ¸Õ룬±êʶÌáÉýΪ¸ù½Úµã + + + + +public slots: // Ìí¼Ó Îļþ½Úµã·Ö²¼ + void addOCCTObjectItem(TaskNode*); // ¼ÓÔØÊý¾Ý + void addImageObjectItem(TaskNode*); + void addPointCloudObjectItem(TaskNode*); // ¹¦ÄÜ´ýʵÏÖ + void addAtriTableObjectItem(TaskNode*); // ¹¦ÄÜ´ýʵÏÖ + + void addScatterSettingTaskItem(TaskNode*); // ¼ÓÔØÈÎÎñ + void addFEKOResultDataConvertItem(TaskNode*); + void addFEKOSimulationImageSettingItem(TaskNode*); + + void addOCCTObjItem(TopoDS_Shape shape, QString name, bool ishow = true);// Ìí¼ÓÄ£ÐÍ + void addShapeDsItem(QString filepath); // ¼ÓÔØÄ£ÐÍ + + +public slots: // ÒÆ³ý½Úµã + void removeTaskNode(QTreeWidgetItem*); + +public slots: // ÈÎÎñ½Úµã£¬¹²ÓÐÄÚÈÝ + + void ContentListContextMenu_UndoAction(); // ³·Ïú + void ContentListContextMenu_RedoAction(); // ÖØ×ö + void ContentListContextMenu_BatchExportAction(); + + + +public slots: + void initDocumentCommonContextMenu(); // ³õʼ»¯ÓÒ¼ü²Ëµ¥ + void ShowContentListContextMenu(QPoint p); + + +//========================================= +// Ä£ÐͲÙ×÷ +//========================================= + +private:// ˽ÓбäÁ¿ + bool isActivateGridMesh ; + bool isActivateAxisGrid; + Graphic3d_GraduatedTrihedron aTrihedron_aixs; +public:// ¹«¿ª±äÁ¿ + Handle(V3d_Viewer) myViewer; + Handle(AIS_InteractiveContext) myContext; + bool myContextIsEmpty; + NCollection_Vector myObject3d; // ¿ØÖÆÆ÷Áбí + QUndoStack* m_undoStack; + QSet ItemSets; + QMenu* ContentListContextMenu; + OCCTopoShapeTreeViewer* ShapeInfomationWindows; //չʾ±»Ñ¡ÔñµÄÄ£ÐÍ + +public: + Handle(AIS_InteractiveObject) ShowTopoDS_Shape(TopoDS_Shape& shape); // ÏÔʾģÐÍ + bool HideTopoDS_Shape(Handle(AIS_InteractiveObject) aShape); // Òþ²ØÄ£ÐÍ + bool ShowTopoDs_ShapeAIS(Handle(AIS_InteractiveObject) aShape); // ÏÔʾģÐÍ + bool RemoveTopoDS_Shape(Handle(AIS_InteractiveObject) aShape); // ÒÆ³ýÄ£ÐÍ + + const Handle(AIS_InteractiveContext)& getContext() { return myContext; } + const Handle(V3d_Viewer)& getViewer() { return myViewer; } + void setViewer(const Handle(V3d_Viewer)& theViewer) { myViewer = theViewer; } + void SetObjects(const NCollection_Vector& theObjects, Standard_Boolean theDisplayShaded = Standard_False); + void ClearShape(); // Çå³ýÄ£ÐÍ + bool IsEmpty() const { return myContextIsEmpty; } + void AppendCube(); // Ôö¼ÓÊÓ¾õÁ¢·½Ìå + void InitAixs(); // Ôö¼ÓÈýÎ¬×ø±êÖá + + std::shared_ptr getSenceExtend(); // ³¡¾°Êý¾Ý»ñÈ¡ + std::shared_ptr getSenceExtend(QString name); + + +signals: + void selectionChanged(); + void sendCloseDocument(DocumentCommon*); + +private: + Handle(V3d_Viewer) Viewer(const Standard_ExtString theName, + const Standard_CString theDomain, + const Standard_Real theViewSize, + const V3d_TypeOfOrientation theViewProj, + const Standard_Boolean theComputedMode, + const Standard_Boolean theDefaultComputedMode); + + + +public slots: + + void ShowOrHideActivateGridMesh(); + void ShowOrHideActivateAxisGris(); + bool getActivateGridMesh(); + bool getActivateAxisGrid(); + + + void VerticesSelect3dSample(); + void EdgesSelect3dSample(); + void FacesSelect3dSample(); + void NeutralPointSelect3dSample(); + //void ShapeModifyShape(OCCTShapeModelNode* dataItem); // Ä£ÐÍÐÞ¸Ä + + + +public: + void OpenOCCTShapeFile(); + void SaveModelFile(); + void oncheckBoxStateChanged(int state); + + TopoDS_Shape MergeCOntextAllModels(); + + +public slots: // Ä£ÐÍ´°¿ÚÓÒ¼ü²Ëµ¥ + + + /////////////////////////////////////////////////// + // »ñÈ¡view´°ÌåÖÐµÄ Ñ¡ÔñÄ£ÐÍ + /////////////////////////////////////////////////// +signals: + void SelectObjectList(const TopoDS_Shape& selectShape); + void ShowSelectItemFullExtend(const TopoDS_Shape& shape); + +public slots: + void ViewerMousePressEvent(QMouseEvent* theEvent); + void ViewerMouseReleaseEvent(QMouseEvent* theEvent); + void SelectItemFullShow(const TopoDS_Shape& shape); + void setShapeInfomationWindows(OCCTopoShapeTreeViewer* ShapeInfomationWindows); +public: + TopoDS_Shape getTopoDSShape(const Handle(AIS_InteractiveObject)& aisObject); + void showSelectShape(const TopoDS_Shape& selectShape); + +}; +#endif diff --git a/src/WBCLFZSystemModule/OCCViewer/GeomWidget.cpp b/src/WBCLFZSystemModule/OCCViewer/GeomWidget.cpp new file mode 100644 index 0000000..18f94f3 --- /dev/null +++ b/src/WBCLFZSystemModule/OCCViewer/GeomWidget.cpp @@ -0,0 +1,98 @@ +// Copyright (c) 2020 OPEN CASCADE SAS +// +// This file is part of the examples of the Open CASCADE Technology software library. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE + +#include "GeomWidget.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +GeomWidget::GeomWidget (DocumentCommon* theDocument3d, QWidget* theParent) +: QWidget(theParent), + myDocument3d(theDocument3d) +{ + QVBoxLayout* aMainLayout = new QVBoxLayout(this); + aMainLayout->setContentsMargins(0, 0, 0, 0); + + + this->my3dVidget = new QWidget;// 3DÄ£ÐÍ ÏÔʾ + + QVBoxLayout* a3dLayout = new QVBoxLayout(my3dVidget); + a3dLayout->setContentsMargins(0, 0, 0, 0); + a3dLayout->setSpacing(0); + myView3d = new View(myDocument3d->getContext(), true, my3dVidget); // ´´½¨Ò»¸ö 3D Ä£ÐÍ View + + QToolBar* aToolBar3d = new QToolBar; + aToolBar3d->addActions(myView3d->getViewActions()); + aToolBar3d->addSeparator(); + aToolBar3d->addActions(myView3d->getRaytraceActions()); + a3dLayout->addWidget(aToolBar3d); + a3dLayout->addWidget(myView3d); + myStackWidget = new QStackedWidget(this); + aMainLayout->addWidget(myStackWidget); + myStackWidget->addWidget(my3dVidget); + this->initEvents(); + FitAll(); +} + +void GeomWidget::FitAll() +{ + Show3d(); +} + +void GeomWidget::Show3d() +{ + myView3d->axo(); + myView3d->fitAll(); + QAction* aShadingAction = myView3d->getViewAction(ViewAction_Shading); + aShadingAction->trigger(); + aShadingAction->setChecked(true); + QAction* aHlrOffAction = myView3d->getViewAction(ViewAction_HlrOff); + aHlrOffAction->trigger(); + aHlrOffAction->setChecked(true); + myStackWidget->setCurrentWidget(my3dVidget); + setStatusTip("Mouse buttons: Right-Zoom, Middle-Pan, Left-Rotate"); +} + +void GeomWidget::initEvents() +{ + QObject::connect(this->myView3d, SIGNAL(ViewMousePressEvent(QMouseEvent *)), this->myDocument3d, SLOT(ViewerMousePressEvent(QMouseEvent *))); + QObject::connect(this->myView3d, SIGNAL(ViewMouseReleaseEvent(QMouseEvent*)), this->myDocument3d, SLOT(ViewerMouseReleaseEvent(QMouseEvent*))); + QObject::connect(this->myDocument3d, SIGNAL(ShowSelectItemFullExtend(const TopoDS_Shape&)), this, SLOT(ShowExtend(const TopoDS_Shape&))); + +} + + +void GeomWidget::ShowExtend(const TopoDS_Shape& Data_Shape) { + // Ëõ·Åµ½Ñ¡¶¨µÄÄ£ÐÍ + qDebug() << "Ëõ·Åµ½Ñ¡¶¨µÄÄ£ÐÍ"; + this->myDocument3d->myContext->FitSelected(this->Get3dView()); // Ëõ·Åµ½Ñ¡Ôñͼ²ã + this->myDocument3d->myContext->ClearSelected(Standard_True); + +} \ No newline at end of file diff --git a/src/WBCLFZSystemModule/OCCViewer/GeomWidget.h b/src/WBCLFZSystemModule/OCCViewer/GeomWidget.h new file mode 100644 index 0000000..330a51d --- /dev/null +++ b/src/WBCLFZSystemModule/OCCViewer/GeomWidget.h @@ -0,0 +1,68 @@ +// Copyright (c) 2020 OPEN CASCADE SAS +// +// This file is part of the examples of the Open CASCADE Technology software library. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE + +#ifndef GEOMWIDGET_H +#define GEOMWIDGET_H + +#include "OCCViewer\View.h" +#include "OCCViewer\DocumentCommon.h" + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +//! Qt widget for organize 3D & 2D documents +class GeomWidget : public QWidget +{ + Q_OBJECT +public: + GeomWidget(DocumentCommon* theDocument3d, + QWidget* theParent = nullptr); + void FitAll(); + Handle(V3d_View) Get3dView() { return myView3d->getView(); } + void Show3d(); + void initEvents(); + + + +public: + View* myView3d; + QWidget* my3dVidget; + QStackedWidget* myStackWidget; + DocumentCommon* myDocument3d; + + +public slots: + void ShowExtend(const TopoDS_Shape& Data_Shape); +}; + +#endif //GEOMWIDGET_H diff --git a/src/WBCLFZSystemModule/OCCViewer/OCCT_Test/BaseSample.cpp b/src/WBCLFZSystemModule/OCCViewer/OCCT_Test/BaseSample.cpp new file mode 100644 index 0000000..2024101 --- /dev/null +++ b/src/WBCLFZSystemModule/OCCViewer/OCCT_Test/BaseSample.cpp @@ -0,0 +1,185 @@ +// Copyright (c) 2020 OPEN CASCADE SAS +// +// This file is part of the examples of the Open CASCADE Technology software library. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE + +#include "BaseSample.h" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +const TCollection_AsciiString BaseSample::FILE_EXTENSION = "cxx"; + +void BaseSample::Clear() +{ + myObject3d.Clear(); + myObject2d.Clear(); + myCode.Clear(); + myResult.str(""); +} + +TCollection_AsciiString BaseSample::GetResult() +{ + TCollection_AsciiString aResult(myResult.str().c_str()); + myResult.str(""); + return aResult; +} + +void BaseSample::AppendCube() +{ + Handle(AIS_ViewCube) aViewCube = new AIS_ViewCube(); + myObject3d.Append(aViewCube); +} + +void BaseSample::Process (const TCollection_AsciiString& theSampleName) +{ + myObject3d.Clear(); + myObject2d.Clear(); + myCode.Clear(); + myIsProcessed = Standard_False; + try + { + ExecuteSample(theSampleName); + if (!myObject3d.IsEmpty()) + { + Handle(AIS_ViewCube) aViewCube = new AIS_ViewCube(); + myObject3d.Append(aViewCube); + } + } + catch (...) + { + TraceError(TCollection_AsciiString("Error in sample: ") + theSampleName); + } +} + +void BaseSample::TraceError (const TCollection_AsciiString& theErrorMessage) +{ + Message::SendFail() << "\nERROR: " << theErrorMessage.ToCString() << "\n"; + myResult << "\nERROR: " << theErrorMessage << "\n"; +} + +void BaseSample::FindSourceCode (const TCollection_AsciiString& theSampleName) +{ + TCollection_AsciiString aClassName = DynamicType()->Name(); + char aSeparator = QDir::separator().toLatin1(); + TCollection_AsciiString aCxxFilePach = myCodePath + aSeparator + aClassName + '.' + FILE_EXTENSION; + OSD_File aCxxFile(aCxxFilePach); + try + { + const Standard_Integer aFileBufferSize = 100 * 1024; + TCollection_AsciiString aReadedText(aFileBufferSize); + aCxxFile.Open(OSD_ReadOnly, OSD_Protection()); + aCxxFile.Read(aReadedText, aFileBufferSize); + TCollection_AsciiString aRegexpTemplate = aClassName + "::" + theSampleName + "[\\n\\s]*\\([\\n\\s]*\\)[\\n\\s]*\\{"; + Standard_Integer aOpeningBracketPosition = findEndOfPhrase (aReadedText, aRegexpTemplate); + Standard_Integer aClosingBracketPosition = findClosingBracket (aReadedText, aOpeningBracketPosition, '}'); + myCode = aReadedText.SubString(aOpeningBracketPosition + 1, aClosingBracketPosition - 1); + } + catch (...) + { + TraceError(TCollection_AsciiString("Cannot open file: ") + aCxxFilePach); + } +} + +Standard_Integer BaseSample::findEndOfPhrase (const TCollection_AsciiString& theText, + const TCollection_AsciiString& theRegexpTemplate) +{ + Standard_Integer aIndexOfLastFoundSymbol = -1; + std::string aStdText = theText.ToCString(); + std::string aRegexpTemplate = theRegexpTemplate.ToCString(); + + try + { + std::regex aRegex(theRegexpTemplate.ToCString()); + + std::sregex_iterator aDetectIterator = std::sregex_iterator(aStdText.begin(), aStdText.end(), aRegex); + if (aDetectIterator != std::sregex_iterator()) + { + std::smatch aMatch = *aDetectIterator; + std::string aFoundString = aMatch.str(); + aIndexOfLastFoundSymbol = static_cast(aStdText.find(aFoundString) + aFoundString.length()); + } + else + { + TraceError(TCollection_AsciiString("No code found for template: ") + theRegexpTemplate); + } + } + catch (const std::regex_error& aRegError) + { + TraceError(TCollection_AsciiString("regex_error: ") + aRegError.what()); + } + catch (const std::exception& aEx) + { + TraceError(TCollection_AsciiString("common error: ") + aEx.what()); + } + catch (...) + { + TraceError("unknown error!"); + } + return aIndexOfLastFoundSymbol; +} + +Standard_Integer BaseSample::findClosingBracket (const TCollection_AsciiString& theText, + const Standard_Integer theOpeningBracketIndex, + Standard_Character theClosingBracketSymbol) +{ + // TODO this function not implemented at least 2 cases: + // - brackets in strings & chars + // - brackets in comments + Standard_Integer aClosingBracketIndex = -1; + Standard_Character anOpeningBracketSymbol = theText.Value(theOpeningBracketIndex); + TCollection_AsciiString aBracketsSet(theClosingBracketSymbol); + aBracketsSet += anOpeningBracketSymbol; + Standard_Integer aBracketDepth = 1; + Standard_Integer aStartFindIndex = theOpeningBracketIndex + 1; + //Standard_Character aStartFindChar = theText.Value(aStartFindIndex-1); + while (aBracketDepth) + { + aStartFindIndex = theText.FirstLocationInSet(aBracketsSet, aStartFindIndex, theText.Length()); + if (!aStartFindIndex) + { + TraceError("No closing bracket found!"); + break; + } + TCollection_AsciiString aRSubstr = theText.SubString(aStartFindIndex, theText.Length()); + if (theText.Value(aStartFindIndex) == anOpeningBracketSymbol) + aBracketDepth++; + else if (theText.Value(aStartFindIndex) == theClosingBracketSymbol) + aBracketDepth--; + if (!aBracketDepth) + { + aClosingBracketIndex = aStartFindIndex; + break; + } + aStartFindIndex++; + } + return aClosingBracketIndex; +} diff --git a/src/WBCLFZSystemModule/OCCViewer/OCCT_Test/BaseSample.h b/src/WBCLFZSystemModule/OCCViewer/OCCT_Test/BaseSample.h new file mode 100644 index 0000000..20c2470 --- /dev/null +++ b/src/WBCLFZSystemModule/OCCViewer/OCCT_Test/BaseSample.h @@ -0,0 +1,87 @@ +// Copyright (c) 2020 OPEN CASCADE SAS +// +// This file is part of the examples of the Open CASCADE Technology software library. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE + +#ifndef BASESAMPLE_H +#define BASESAMPLE_H + +#include + +#include +#include +#include + +//! Base class for specified category classes +class BaseSample: public Standard_Transient +{ + DEFINE_STANDARD_RTTI_INLINE(BaseSample, Standard_Transient) +public: + BaseSample (const TCollection_AsciiString& theSampleSourcePath, + const Handle(AIS_InteractiveContext)& theContext) + : myCodePath (theSampleSourcePath), + myContext (theContext) + { + // + } + + void Clear(); + void AppendCube(); + + Standard_Boolean IsProcessed() const { return myIsProcessed; } + + const NCollection_Vector& Get2dObjects() const { return myObject2d; } + + const NCollection_Vector& Get3dObjects() const { return myObject3d; } + + TCollection_AsciiString GetResult(); + + TCollection_AsciiString GetCode() const { return myCode; } + + virtual void Process (const TCollection_AsciiString& theSampleName); + +protected: + virtual void ExecuteSample (const TCollection_AsciiString& theSampleName) = 0; + + void FindSourceCode (const TCollection_AsciiString& theSampleName); + void TraceError (const TCollection_AsciiString& theErrorMessage); + +protected: + + Standard_Boolean myIsProcessed; + NCollection_Vector myObject2d; + NCollection_Vector myObject3d; + + std::ostringstream myResult; + TCollection_AsciiString myCode; + TCollection_AsciiString myCodePath; + Handle(AIS_InteractiveContext) myContext; + +protected: + static const TCollection_AsciiString FILE_EXTENSION; + +private: + Standard_Integer findEndOfPhrase (const TCollection_AsciiString& theText, + const TCollection_AsciiString& theRegexpTemplate); + Standard_Integer findClosingBracket (const TCollection_AsciiString& theText, + Standard_Integer theOpeningBracketIndex, + Standard_Character theClosingBracketSymbol); +}; + +#endif //BASESAMPLE_H diff --git a/src/WBCLFZSystemModule/OCCViewer/OCCT_Test/MakeBottle.cpp b/src/WBCLFZSystemModule/OCCViewer/OCCT_Test/MakeBottle.cpp new file mode 100644 index 0000000..44307e0 --- /dev/null +++ b/src/WBCLFZSystemModule/OCCViewer/OCCT_Test/MakeBottle.cpp @@ -0,0 +1,218 @@ +// Copyright (c) 2020 OPEN CASCADE SAS +// +// This file is part of the examples of the Open CASCADE Technology software library. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE + +#include "MakeBottle.h" + +#include + +#include + +#include +#include +#include +#include + +#include + +#include + +#include +#include + +#include +#include + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +#include + +TopoDS_Shape MakeBottle (const Standard_Real theWidth, + const Standard_Real theHeight, + const Standard_Real theThickness) +{ + // Profile : Define Support Points + gp_Pnt aPnt1(-theWidth / 2., 0, 0); + gp_Pnt aPnt2(-theWidth / 2., -theThickness / 4., 0); + gp_Pnt aPnt3(0, -theThickness / 2., 0); + gp_Pnt aPnt4(theWidth / 2., -theThickness / 4., 0); + gp_Pnt aPnt5(theWidth / 2., 0, 0); + + // Profile : Define the Geometry + Handle(Geom_TrimmedCurve) anArcOfCircle = GC_MakeArcOfCircle(aPnt2, aPnt3, aPnt4); + Handle(Geom_TrimmedCurve) aSegment1 = GC_MakeSegment(aPnt1, aPnt2); + Handle(Geom_TrimmedCurve) aSegment2 = GC_MakeSegment(aPnt4, aPnt5); + + // Profile : Define the Topology + TopoDS_Edge anEdge1 = BRepBuilderAPI_MakeEdge(aSegment1); + TopoDS_Edge anEdge2 = BRepBuilderAPI_MakeEdge(anArcOfCircle); + TopoDS_Edge anEdge3 = BRepBuilderAPI_MakeEdge(aSegment2); + TopoDS_Wire aWire = BRepBuilderAPI_MakeWire(anEdge1, anEdge2, anEdge3); + + // Complete Profile + gp_Ax1 xAxis = gp::OX(); + gp_Trsf aTrsf; + + aTrsf.SetMirror(xAxis); + BRepBuilderAPI_Transform aBRepTrsf(aWire, aTrsf); + TopoDS_Shape aMirroredShape = aBRepTrsf.Shape(); + TopoDS_Wire aMirroredWire = TopoDS::Wire(aMirroredShape); + + BRepBuilderAPI_MakeWire mkWire; + mkWire.Add(aWire); + mkWire.Add(aMirroredWire); + TopoDS_Wire myWireProfile = mkWire.Wire(); + + // Body : Prism the Profile + TopoDS_Face myFaceProfile = BRepBuilderAPI_MakeFace(myWireProfile); + gp_Vec aPrismVec(0, 0, theHeight); + TopoDS_Shape myBody = BRepPrimAPI_MakePrism(myFaceProfile, aPrismVec); + + // Body : Apply Fillets + BRepFilletAPI_MakeFillet mkFillet(myBody); + TopExp_Explorer anEdgeExplorer(myBody, TopAbs_EDGE); + while (anEdgeExplorer.More()) + { + TopoDS_Edge anEdge = TopoDS::Edge(anEdgeExplorer.Current()); + //Add edge to fillet algorithm + mkFillet.Add(theThickness / 12., anEdge); + anEdgeExplorer.Next(); + } + + myBody = mkFillet.Shape(); + + // Body : Add the Neck + gp_Pnt neckLocation(0, 0, theHeight); + gp_Dir neckAxis = gp::DZ(); + gp_Ax2 neckAx2(neckLocation, neckAxis); + + Standard_Real myNeckRadius = theThickness / 4.; + Standard_Real myNeckHeight = theHeight / 10.; + + BRepPrimAPI_MakeCylinder MKCylinder(neckAx2, myNeckRadius, myNeckHeight); + TopoDS_Shape myNeck = MKCylinder.Shape(); + + myBody = BRepAlgoAPI_Fuse(myBody, myNeck); + + // Body : Create a Hollowed Solid + TopoDS_Face faceToRemove; + Standard_Real zMax = -1; + + for (TopExp_Explorer aFaceExplorer(myBody, TopAbs_FACE); aFaceExplorer.More(); aFaceExplorer.Next()) + { + TopoDS_Face aFace = TopoDS::Face(aFaceExplorer.Current()); + // Check if is the top face of the bottle’s neck + Handle(Geom_Surface) aSurface = BRep_Tool::Surface(aFace); + if (aSurface->DynamicType() == STANDARD_TYPE(Geom_Plane)) + { + Handle(Geom_Plane) aPlane = Handle(Geom_Plane)::DownCast(aSurface); + gp_Pnt aPnt = aPlane->Location(); + Standard_Real aZ = aPnt.Z(); + if (aZ > zMax) + { + zMax = aZ; + faceToRemove = aFace; + } + } + } + + TopTools_ListOfShape facesToRemove; + facesToRemove.Append(faceToRemove); + BRepOffsetAPI_MakeThickSolid aSolidMaker; + aSolidMaker.MakeThickSolidByJoin(myBody, facesToRemove, -theThickness / 50, 1.e-3); + myBody = aSolidMaker.Shape(); + // Threading : Create Surfaces + Handle(Geom_CylindricalSurface) aCyl1 = new Geom_CylindricalSurface(neckAx2, myNeckRadius * 0.99); + Handle(Geom_CylindricalSurface) aCyl2 = new Geom_CylindricalSurface(neckAx2, myNeckRadius * 1.05); + + // Threading : Define 2D Curves + gp_Pnt2d aPnt(2. * M_PI, myNeckHeight / 2.); + gp_Dir2d aDir(2. * M_PI, myNeckHeight / 4.); + gp_Ax2d anAx2d(aPnt, aDir); + + Standard_Real aMajor = 2. * M_PI; + Standard_Real aMinor = myNeckHeight / 10; + + Handle(Geom2d_Ellipse) anEllipse1 = new Geom2d_Ellipse(anAx2d, aMajor, aMinor); + Handle(Geom2d_Ellipse) anEllipse2 = new Geom2d_Ellipse(anAx2d, aMajor, aMinor / 4); + Handle(Geom2d_TrimmedCurve) anArc1 = new Geom2d_TrimmedCurve(anEllipse1, 0, M_PI); + Handle(Geom2d_TrimmedCurve) anArc2 = new Geom2d_TrimmedCurve(anEllipse2, 0, M_PI); + gp_Pnt2d anEllipsePnt1 = anEllipse1->Value(0); + gp_Pnt2d anEllipsePnt2 = anEllipse1->Value(M_PI); + + Handle(Geom2d_TrimmedCurve) aSegment = GCE2d_MakeSegment(anEllipsePnt1, anEllipsePnt2); + // Threading : Build Edges and Wires + TopoDS_Edge anEdge1OnSurf1 = BRepBuilderAPI_MakeEdge(anArc1, aCyl1); + TopoDS_Edge anEdge2OnSurf1 = BRepBuilderAPI_MakeEdge(aSegment, aCyl1); + TopoDS_Edge anEdge1OnSurf2 = BRepBuilderAPI_MakeEdge(anArc2, aCyl2); + TopoDS_Edge anEdge2OnSurf2 = BRepBuilderAPI_MakeEdge(aSegment, aCyl2); + TopoDS_Wire threadingWire1 = BRepBuilderAPI_MakeWire(anEdge1OnSurf1, anEdge2OnSurf1); + TopoDS_Wire threadingWire2 = BRepBuilderAPI_MakeWire(anEdge1OnSurf2, anEdge2OnSurf2); + BRepLib::BuildCurves3d(threadingWire1); + BRepLib::BuildCurves3d(threadingWire2); + + // Create Threading + BRepOffsetAPI_ThruSections aTool(Standard_True); + aTool.AddWire(threadingWire1); + aTool.AddWire(threadingWire2); + aTool.CheckCompatibility(Standard_False); + + TopoDS_Shape myThreading = aTool.Shape(); + + // Building the Resulting Compound + TopoDS_Compound aRes; + BRep_Builder aBuilder; + aBuilder.MakeCompound(aRes); + aBuilder.Add(aRes, myBody); + aBuilder.Add(aRes, myThreading); + + return aRes; +} diff --git a/src/WBCLFZSystemModule/OCCViewer/OCCT_Test/MakeBottle.h b/src/WBCLFZSystemModule/OCCViewer/OCCT_Test/MakeBottle.h new file mode 100644 index 0000000..ad1e783 --- /dev/null +++ b/src/WBCLFZSystemModule/OCCViewer/OCCT_Test/MakeBottle.h @@ -0,0 +1,33 @@ +// Copyright (c) 2020 OPEN CASCADE SAS +// +// This file is part of the examples of the Open CASCADE Technology software library. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE + +#ifndef MAKEBOTTLE_H +#define MAKEBOTTLE_H + +#include +#include + +//! Returns sample bottle TopoDS_Shape +TopoDS_Shape MakeBottle(const Standard_Real theWidth, + const Standard_Real theyHeight, + const Standard_Real theThickness); + +#endif // MAKEBOTTLE_H diff --git a/src/WBCLFZSystemModule/OCCViewer/OCCT_Test/Viewer3d.xml b/src/WBCLFZSystemModule/OCCViewer/OCCT_Test/Viewer3d.xml new file mode 100644 index 0000000..2c504e5 --- /dev/null +++ b/src/WBCLFZSystemModule/OCCViewer/OCCT_Test/Viewer3d.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/WBCLFZSystemModule/OCCViewer/OCCT_Test/Viewer3dSamples.cpp b/src/WBCLFZSystemModule/OCCViewer/OCCT_Test/Viewer3dSamples.cpp new file mode 100644 index 0000000..356a88f --- /dev/null +++ b/src/WBCLFZSystemModule/OCCViewer/OCCT_Test/Viewer3dSamples.cpp @@ -0,0 +1,346 @@ +// Copyright (c) 2020 OPEN CASCADE SAS +// +// This file is part of the examples of the Open CASCADE Technology software library. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE +#include +#include "Viewer3dSamples.h" + +#include "MakeBottle.h" + +#include +#include +#include +#include +#include +#include +#include + +void Viewer3dSamples::ExecuteSample(const TCollection_AsciiString& theSampleName) +{ + Standard_Boolean anIsSamplePresent = Standard_True; + FindSourceCode(theSampleName); + if (theSampleName == "SpotLight3dSample") + SpotLight3dSample(); + else if (theSampleName == "PositionalLight3dSample") + PositionalLight3dSample(); + else if (theSampleName == "DirectionalLight3dSample") + DirectionalLight3dSample(); + else if (theSampleName == "AmbientLight3dSample") + AmbientLight3dSample(); + else if (theSampleName == "ClearLight3dSample") + ClearLight3dSample(); + else if (theSampleName == "VerticesSelect3dSample") + VerticesSelect3dSample(); + else if (theSampleName == "EdgesSelect3dSample") + EdgesSelect3dSample(); + else if (theSampleName == "FacesSelect3dSample") + FacesSelect3dSample(); + else if (theSampleName == "NeutralPointSelect3dSample") + NeutralPointSelect3dSample(); + else if (theSampleName == "WireFramePresentation3dSample") + WireFramePresentation3dSample(); + else if (theSampleName == "ShadingPresentation3dSample") + ShadingPresentation3dSample(); + else if (theSampleName == "RedColorPresentation3dSample") + RedColorPresentation3dSample(); + else if (theSampleName == "GrayColorPresentation3dSample") + GrayColorPresentation3dSample(); + else if (theSampleName == "PlasticPresentation3dSample") + PlasticPresentation3dSample(); + else if (theSampleName == "BronzePresentation3dSample") + BronzePresentation3dSample(); + else if (theSampleName == "OpaquePresentation3dSample") + OpaquePresentation3dSample(); + else if (theSampleName == "HalfTransparencyPresentation3dSample") + HalfTransparencyPresentation3dSample(); + else if (theSampleName == "VboOn3dSample") + VboOn3dSample(); + else if (theSampleName == "VboOff3dSample") + VboOff3dSample(); + else + { + myResult << "No function found: " << theSampleName; + myCode += TCollection_AsciiString("No function found: ") + theSampleName; + anIsSamplePresent = Standard_False; + } + myIsProcessed = anIsSamplePresent; +} + +void Viewer3dSamples::AppendBottle() +{ + TopoDS_Shape aBottle = MakeBottle(50, 70, 30); + Handle(AIS_InteractiveObject) aShape = new AIS_Shape(aBottle); + myObject3d.Append(aShape); + Handle(AIS_ViewCube) aViewCube = new AIS_ViewCube(); + myObject3d.Append(aViewCube); + myResult << "A bottle shape was created." << "\n"; +} + +void Viewer3dSamples::ClearExtra() +{ + NeutralPointSelect3dSample(); + VboOff3dSample(); + ClearLight3dSample(); + // Delete Lights + V3d_ListOfLight aLights; + for (V3d_ListOfLightIterator anIter = myView->Viewer()->DefinedLightIterator(); + anIter.More(); anIter.Next()) + { + aLights.Append(anIter.Value()); + } + + for (V3d_ListOfLightIterator aLightIter(aLights); + aLightIter.More(); aLightIter.Next()) + { + myView->Viewer()->DelLight(aLightIter.Value()); + } + myView->Viewer()->SetDefaultLights(); // Setting the default lights on + myView->Update(); + + myContext->RemoveAll(Standard_True); +} + +void Viewer3dSamples::SpotLight3dSample() +{ + // Spot light source creation + Handle(V3d_SpotLight) aSpotLight = + new V3d_SpotLight(gp_Pnt(100.0, 0.0, 0.0), gp_Dir(-1.0, 0.0, 0.0), Quantity_NOC_RED); + aSpotLight->SetIntensity(5000); + myView->SetLightOn(aSpotLight); +} + +void Viewer3dSamples::PositionalLight3dSample() +{ + Handle(V3d_PositionalLight) aPositionalLight = + new V3d_PositionalLight(gp_Pnt(0.0, -100.0, 5.0), Quantity_NOC_GREEN); + aPositionalLight->SetAttenuation(1, 0); + myView->SetLightOn(aPositionalLight); +} + +void Viewer3dSamples::DirectionalLight3dSample() +{ + Handle(V3d_DirectionalLight) aDirectionalLight = + new V3d_DirectionalLight(gp_Dir(-1.0, 0.0, -1.0), Quantity_NOC_BLUE1); + myView->SetLightOn(aDirectionalLight); +} + +void Viewer3dSamples::AmbientLight3dSample() +{ + Handle(V3d_AmbientLight) aAmbientLight = + new V3d_AmbientLight(Quantity_NOC_MAGENTA1); + myView->SetLightOn(aAmbientLight); +} + +void Viewer3dSamples::ClearLight3dSample() +{ + // Setting Off all viewer active lights + V3d_ListOfLight aLights; + for (V3d_ListOfLightIterator anIter = myView->Viewer()->ActiveLightIterator(); + anIter.More(); anIter.Next()) + { + aLights.Append(anIter.Value()); + } + + for (V3d_ListOfLightIterator aLightIter(aLights); + aLightIter.More(); aLightIter.Next()) + { + myView->Viewer()->SetLightOff(aLightIter.Value()); + } + // Setting Off all view active lights + aLights.Clear(); + for (V3d_ListOfLightIterator anIter = myView->ActiveLightIterator(); + anIter.More(); anIter.Next()) + { + aLights.Append(anIter.Value()); + } + + for (V3d_ListOfLightIterator aLightIter(aLights); + aLightIter.More(); aLightIter.Next()) + { + myView->SetLightOff(aLightIter.Value()); + } + myView->Viewer()->SetDefaultLights(); // Setting the default lights on + myView->Update(); +} + +void Viewer3dSamples::VerticesSelect3dSample() +{ + qDebug() << u8"Çл»Ñ¡ÔñģʽΪ£ºTopAbs_VERTEX"; + myContext->Deactivate(); + myContext->Activate(AIS_Shape::SelectionMode(TopAbs_VERTEX)); +} + +void Viewer3dSamples::EdgesSelect3dSample() +{ + qDebug() << u8"Çл»Ñ¡ÔñģʽΪ£ºTopAbs_EDGE"; + myContext->Deactivate(); + myContext->Activate(AIS_Shape::SelectionMode(TopAbs_EDGE)); +} + +void Viewer3dSamples::FacesSelect3dSample() +{ + qDebug() << u8"Çл»Ñ¡ÔñģʽΪ£ºTopAbs_FACE"; + myContext->Deactivate(); + myContext->Activate(AIS_Shape::SelectionMode(TopAbs_FACE)); +} + +void Viewer3dSamples::NeutralPointSelect3dSample() +{ + qDebug() << u8"Çл»Ñ¡ÔñģʽΪ£ºTopAbs_COMPOUND"; + myContext->Deactivate(); + myContext->Activate(TopAbs_COMPOUND); +} + +void Viewer3dSamples::WireFramePresentation3dSample() +{ + AIS_ListOfInteractive anAisObjectsList; + myContext->DisplayedObjects(anAisObjectsList); + for (AIS_ListOfInteractive::Iterator anIter(anAisObjectsList); + anIter.More(); anIter.Next()) + { + const Handle(AIS_InteractiveObject)& anAisObject = anIter.Value(); + myContext->SetDisplayMode(anAisObject, 0, false); // set wireframe + } + myContext->UpdateCurrentViewer(); +} + +void Viewer3dSamples::ShadingPresentation3dSample() +{ + AIS_ListOfInteractive anAisObjectsList; + myContext->DisplayedObjects(anAisObjectsList); + for (AIS_ListOfInteractive::Iterator anIter(anAisObjectsList); + anIter.More(); anIter.Next()) + { + const Handle(AIS_InteractiveObject)& anAisObject = anIter.Value(); + myContext->SetDisplayMode(anAisObject, 1, false); // set shading + } + myContext->UpdateCurrentViewer(); +} + +void Viewer3dSamples::RedColorPresentation3dSample() +{ + AIS_ListOfInteractive anAisObjectsList; + myContext->DisplayedObjects(anAisObjectsList); + for (AIS_ListOfInteractive::Iterator anIter(anAisObjectsList); + anIter.More(); anIter.Next()) + { + const Handle(AIS_InteractiveObject)& anAisObject = anIter.Value(); + Quantity_Color aShapeColor; + myContext->Color(anAisObject, aShapeColor); + myResult << "A Current shape color: Red = " << aShapeColor.Red() + << " Green = " << aShapeColor.Green() << " Blue = " << aShapeColor.Blue() << "\n"; + aShapeColor.SetValues(0.8, 0.1, 0.1, Quantity_TOC_RGB); + myContext->SetColor(anAisObject, aShapeColor, Standard_False); + myResult << "A New shape color: Red = " << aShapeColor.Red() + << " Green = " << aShapeColor.Green() << " Blue = " << aShapeColor.Blue() << "\n"; + } +} + +void Viewer3dSamples::GrayColorPresentation3dSample() +{ + AIS_ListOfInteractive anAisObjectsList; + myContext->DisplayedObjects(anAisObjectsList); + for (AIS_ListOfInteractive::Iterator anIter(anAisObjectsList); + anIter.More(); anIter.Next()) + { + const Handle(AIS_InteractiveObject)& anAisObject = anIter.Value(); + Quantity_Color aShapeColor; + myContext->Color(anAisObject, aShapeColor); + myResult << "A Current shape color: Hue = " << aShapeColor.Hue() + << " Light = " << aShapeColor.Light() + << " Saturation = " << aShapeColor.Saturation() << "\n"; + aShapeColor.SetValues(0.0, 0.3, 0.1, Quantity_TOC_HLS); + myContext->SetColor(anAisObject, aShapeColor, Standard_False); + myResult << "A New shape color: Hue = " << aShapeColor.Hue() + << " Light = " << aShapeColor.Light() + << " Saturation = " << aShapeColor.Saturation() << "\n"; + } +} + +void Viewer3dSamples::PlasticPresentation3dSample() +{ + AIS_ListOfInteractive anAisObjectsList; + myContext->DisplayedObjects(anAisObjectsList); + Graphic3d_NameOfMaterial aMaterial = Graphic3d_NOM_PLASTIC; + for (AIS_ListOfInteractive::Iterator anIter(anAisObjectsList); + anIter.More(); anIter.Next()) + { + const Handle(AIS_InteractiveObject)& anAisObject = anIter.Value(); + myContext->SetMaterial(anAisObject, aMaterial, Standard_False); + } + myContext->UpdateCurrentViewer(); +} + +void Viewer3dSamples::BronzePresentation3dSample() +{ + AIS_ListOfInteractive anAisObjectsList; + myContext->DisplayedObjects(anAisObjectsList); + Graphic3d_NameOfMaterial aMaterial = Graphic3d_NOM_BRONZE; + for (AIS_ListOfInteractive::Iterator anIter(anAisObjectsList); + anIter.More(); anIter.Next()) + { + const Handle(AIS_InteractiveObject)& anAisObject = anIter.Value(); + myContext->SetMaterial(anAisObject, aMaterial, Standard_False); + } + myContext->UpdateCurrentViewer(); +} + +void Viewer3dSamples::OpaquePresentation3dSample() +{ + AIS_ListOfInteractive anAisObjectsList; + myContext->DisplayedObjects(anAisObjectsList); + for (AIS_ListOfInteractive::Iterator anIter(anAisObjectsList); + anIter.More(); anIter.Next()) + { + const Handle(AIS_InteractiveObject)& anAisObject = anIter.Value(); + myContext->SetTransparency(anAisObject, 0.0, Standard_False); + } + myContext->UpdateCurrentViewer(); +} + +void Viewer3dSamples::HalfTransparencyPresentation3dSample() +{ + AIS_ListOfInteractive anAisObjectsList; + myContext->DisplayedObjects(anAisObjectsList); + for (AIS_ListOfInteractive::Iterator anIter(anAisObjectsList); + anIter.More(); anIter.Next()) + { + const Handle(AIS_InteractiveObject)& anAisObject = anIter.Value(); + myContext->SetTransparency(anAisObject, 0.5, Standard_False); + } + myContext->UpdateCurrentViewer(); +} + +void Viewer3dSamples::VboOn3dSample() +{ + if (Handle(OpenGl_GraphicDriver) aDriver = + Handle(OpenGl_GraphicDriver)::DownCast(myContext->CurrentViewer()->Driver())) + { + aDriver->ChangeOptions().vboDisable = Standard_False; + } +} + +void Viewer3dSamples::VboOff3dSample() +{ + if (Handle(OpenGl_GraphicDriver) aDriver = + Handle(OpenGl_GraphicDriver)::DownCast(myContext->CurrentViewer()->Driver())) + { + aDriver->ChangeOptions().vboDisable = Standard_True; + } +} diff --git a/src/WBCLFZSystemModule/OCCViewer/OCCT_Test/Viewer3dSamples.h b/src/WBCLFZSystemModule/OCCViewer/OCCT_Test/Viewer3dSamples.h new file mode 100644 index 0000000..1691736 --- /dev/null +++ b/src/WBCLFZSystemModule/OCCViewer/OCCT_Test/Viewer3dSamples.h @@ -0,0 +1,78 @@ +// Copyright (c) 2020 OPEN CASCADE SAS +// +// This file is part of the examples of the Open CASCADE Technology software library. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE + +#ifndef VIEWER3DSAMPLES_H +#define VIEWER3DSAMPLES_H + +#include "BaseSample.h" + +#include +#include + +//! Implements viewer 3D samples. +class Viewer3dSamples : public BaseSample +{ + DEFINE_STANDARD_RTTI_INLINE(Viewer3dSamples, BaseSample) +public: + + Viewer3dSamples (const TCollection_AsciiString& theSampleSourcePath, + const Handle(V3d_View)& theView, + const Handle(AIS_InteractiveContext)& theContext) + : BaseSample (theSampleSourcePath, theContext), + myView (theView) + {} + + void AppendBottle(); + void ClearExtra(); + +protected: + virtual void ExecuteSample (const TCollection_AsciiString& theSampleName) Standard_OVERRIDE; + +private: + + // One function for every sample + void SpotLight3dSample(); + void PositionalLight3dSample(); + void DirectionalLight3dSample(); + void AmbientLight3dSample(); + void ClearLight3dSample(); + void VerticesSelect3dSample(); + void EdgesSelect3dSample(); + void FacesSelect3dSample(); + void NeutralPointSelect3dSample(); + void WireFramePresentation3dSample(); + void ShadingPresentation3dSample(); + void RedColorPresentation3dSample(); + void GrayColorPresentation3dSample(); + void PlasticPresentation3dSample(); + void BronzePresentation3dSample(); + void OpaquePresentation3dSample(); + void HalfTransparencyPresentation3dSample(); + void VboOn3dSample(); + void VboOff3dSample(); + +private: + + Handle(V3d_View) myView; + +}; + +#endif //VIEWER3DSAMPLES_H diff --git a/src/WBCLFZSystemModule/OCCViewer/OcctHighlighter.cpp b/src/WBCLFZSystemModule/OCCViewer/OcctHighlighter.cpp new file mode 100644 index 0000000..5dcc887 --- /dev/null +++ b/src/WBCLFZSystemModule/OCCViewer/OcctHighlighter.cpp @@ -0,0 +1,222 @@ +// Copyright (c) 2020 OPEN CASCADE SAS +// +// This file is part of the examples of the Open CASCADE Technology software library. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE + +#include "OcctHighlighter.h" + +#include +#include +#include +#include + + + + + +OcctHighlighter::OcctHighlighter(QTextDocument* theParent) +: QSyntaxHighlighter (theParent) +{ + QStringList aKeywordPatterns; + aKeywordPatterns + << "\\balignas\\b" << "\\balignof\\b" << "\\band\\b" << "\\band_eq\\b" << "\\basm\\b" + << "\\bauto\\b" << "\\bbitand\\b" << "\\bbitor\\b" << "\\bbool\\b" << "\\bbreak\\b" + << "\\bcase\\b" << "\\bcatch\\b" << "\\bchar\\b" << "\\bchar16_t\\b" << "\\bchar32_t\\b" + << "\\bclass\\b" << "\\bcompl\\b" << "\\bconst\\b" << "\\bconstexpr\\b" << "\\bconst_cast\\b" + << "\\bcontinue\\b" << "\\bdecltype\\b" << "\\bdefault\\b" << "\\bdelete\\b" << "\\bdo\\b" + << "\\bdouble\\b" << "\\bdynamic_cast\\b" << "\\belse\\b" << "\\benum\\b" << "\\bexplicit\\b" + << "\\bexport\\b" << "\\bextern\\b" << "\\bfalse\\b" << "\\bfloat\\b" << "\\bfor\\b" + << "\\bfriend\\b" << "\\bgoto\\b" << "\\bif\\b" << "\\binline\\b" << "\\bint\\b" << "\\blong\\b" + << "\\bmutable\\b" << "\\bnamespace\\b" << "\\bnew\\b" << "\\bnoexcept\\b" << "\\bnot\\b" + << "\\bnot_eq\\b" << "\\bnullptr\\b" << "\\boperator\\b" << "\\bor\\b" << "\\bor_eq\\b" + << "\\bprivate\\b" << "\\bprotected\\b" << "\\bpublic\\b" << "\\bregister\\b" + << "\\breinterpret_cast\\b" << "\\breturn\\b" << "\\bshort\\b" << "\\bsigned\\b" << "\\bsizeof\\b" + << "\\bstatic\\b" << "\\bstatic_assert\\b" << "\\bstatic_cast\\b" << "\\bstruct\\b" + << "\\bswitch\\b" << "\\btemplate\\b" << "\\bthis\\b" << "\\bthread_local\\b" << "\\bthrow\\b" + << "\\btrue\\b" << "\\btry\\b" << "\\btypedef\\b" << "\\btypeid\\b" << "\\btypename\\b" + << "\\bunion\\b" << "\\bunsigned\\b" << "\\busing\\b" << "\\bvirtual\\b" << "\\bvoid\\b" + << "\\bvolatile\\b" << "\\bwchar_t\\b" << "\\bwhile\\b" << "\\bxor\\b" << "\\bxor_eq\\b" + << "\\boverride\\b" << "\\bfinal\\b"; + + QStringList anOcctPatterns; + anOcctPatterns + << "gp_Pnt" << "gp_XYZ" << "gp_Vec" << "gp_Dir" << "gp_Ax1" << "gp_Ax2" << "gp_Ax3" << "gp_Lin" + << "gp_Circ" << "gp_Elips" << "gp_Parab" << "gp_Hypr" << "gp_Cylinder" << "gp_Cone" << "gp_Sphere" + << "gp_Torus" << "gp_Pnt2d" << "gp_XY" << "gp_Ax2d" << "gp_Ax22d" << "gp_Lin2d" << "gp_Circ2d" + << "gp_Elips2d" << "gp_Parab2d" << "gp_Hypr2d" << "Geom2d_BSplineCurve" << "Geom2d_BezierCurve" + << "Geom2d_OffsetCurve" << "ProjLib" << "ElSLib" << "IntAna_IntConicQuad" << "GccAna_Lin2d2Tan" + << "GccEnt_QualifiedCirc" << "Geom2dAPI_ProjectPointOnCurve" << "Geom2dAPI_ExtremaCurveCurve" + << "Geom2dAPI_InterCurveCurve" << "Geom2dAPI_PointsToBSpline" << "Geom_CartesianPoint" + << "Geom_VectorWithMagnitude" << "Geom_Axis1Placement" << "Geom_Axis2Placement" << "Geom_Line" + << "Geom_Circle" << "Geom_Ellipse" << "Geom_Parabola" << "Geom_Hyperbola" << "Geom_BSplineCurve" + << "Geom_BezierCurve" << "Geom_TrimmedCurve" << "Geom_OffsetCurve" << "Geom_BSplineSurface" + << "Geom_BezierSurface" << "Geom_Plane" << "Geom_CylindricalSurface" << "Geom_ConicalSurface" + << "Geom_SphericalSurface" << "Geom_ToroidalSurface" << "Geom_RectangularTrimmedSurface" + << "Geom_OffsetSurface" << "Geom_SurfaceOfLinearExtrusion" << "Geom_SurfaceOfRevolution" + << "BndLib_Add3dCurve" << "BndLib_AddSurface" << "GeomAdaptor_Curve" << "GeomAdaptor_Surface" + << "GeomAPI_PointsToBSpline" << "GeomAPI_PointsToBSplineSurface" << "GeomConvert" + << "Geom2d_CartesianPoint" << "Geom2d_VectorWithMagnitude" << "Geom2d_Line" << "Geom2d_Circle" + << "Geom2d_Ellipse" << "Geom2d_Parabola" << "Geom2d_Hyperbola" << "Geom2d_TrimmedCurve" + << "Geom2dAdaptor_Curve" << "Bnd_Box2d" << "BndLib_Add2dCurve" << "Adaptor2d_Curve2d" + << "BRepBuilderAPI_MakeEdge" << "BRepBuilderAPI_MakeFace" << "BRepPrimAPI_MakeBox" << "AIS_Point" + << "AIS_TextLabel" << "AIS_Axis" << "AIS_Circle" << "AIS_Plane" << "AIS_Shape" + << "AIS_ColoredShape" << "GProp_PEquation" << "Extrema_ExtCS" << "GCPnts_QuasiUniformDeflection" + << "GProp_GProps" << "GProp_PrincipalProps" << "TopoDS" << "TopoDS_Iterator" << "TopoDS_Compound" + << "TopoDS_Edge" << "TopoDS_Face" << "TopoDS_Shell" << "TopoDS_Solid" << "TopoDS_Vertex" + << "TopoDS_Wire" << "TopExp" << "TopExp_Explorer" << "TColgp_Array2OfPnt" << "BRep_Builder" + << "BRepGProp" << "BRep_Tool" << "BRepTools" << "BRepTools_ReShape" << "BRepAdaptor_Curve" + << "BRepAdaptor_CompCurve" << "BRepAdaptor_Surface" << "BRepAlgoAPI_Common" << "BRepAlgoAPI_Cut" + << "BRepAlgoAPI_Fuse" << "BRepAlgoAPI_Section" << "BRepAlgoAPI_Splitter" << "BRepAlgoAPI_Defeaturing" + << "BRepBuilderAPI_Copy" << "BRepBuilderAPI_MakeVertex" << "BRepBuilderAPI_MakeEdge" + << "BRepBuilderAPI_MakeFace" << "BRepBuilderAPI_MakePolygon" << "BRepBuilderAPI_MakeShell" + << "BRepBuilderAPI_MakeSolid" << "BRepBuilderAPI_MakeWire" << "BRepBuilderAPI_NurbsConvert" + << "BRepBuilderAPI_Sewing" << "BRepBuilderAPI_Transform" << "BRepCheck_Analyzer" + << "BRepPrimAPI_MakeBox" << "BRepPrimAPI_MakeCylinder" << "BRepPrimAPI_MakeRevol" + << "BRepFilletAPI_MakeChamfer" << "BRepFilletAPI_MakeFillet" << "BRepOffsetAPI_MakeOffset" + << "BRepOffsetAPI_MakeEvolved.hxx" << "Standard_Integer" << "Standard_Real" << "Standard_Boolean" + << "Standard_ShortReal" << "Standard_Character" << "Standard_Byte" << "Standard_Address" + << "Standard_Size" << "Standard_Time" << "Standard_Utf8Char" << "Standard_Utf8UChar" + << "Standard_ExtCharacter" << "Standard_Utf16Char" << "Standard_Utf32Char" << "Standard_WideChar" + << "Standard_CString" << "Standard_ExtString" << "NCollection_Vector" << "TCollection_AsciiString" + << "TCollection_ExtendedString" << "TCollection_HAsciiString" << "TCollection_HExtendedString" + << "Standard_False" << "Standard_True" + << "TCollection" << "NCollection" << "gp_Trsf" << "Handle" << "Aspect_TOL_DASH" + << "Aspect_TOM_O_STAR" << "Aspect_TOL_SOLID" << "Aspect_TOM_O_STAR" << "AIS_InteractiveObject" + << "AIS_ListOfInteractive" << "Aspect_GDM_Lines" << "Aspect_GDM_Points" << "Aspect_TOM_POINT" + << "Aspect_TOM_RING1" << "Aspect_TOM_O" << "BinDrivers" << "DefineFormat" << "Font_FA_Bold" + << "Font_FA_BoldItalic" << "Font_FA_Italic" << "Font_FA_Regular" << "DownCast" << "gp_Pln" + << "Graphic3d_AspectMarker3d" << "Graphic3d_HTA_LEFT" << "Graphic3d_NameOfMaterial" + << "Graphic3d_NOM_BRONZE" << "Graphic3d_NOM_PLASTIC" << "Graphic3d_VTA_BOTTOM" + << "OpenGl_GraphicDriver" << "PCDM_RS_OK" << "PCDM_SS_OK" << "PCDM_ReaderStatus" + << "PCDM_StoreStatus" << "Prs3d_Drawer" << "TPrsStd_AISPresentation" << "Quantity_Color" + << "Quantity_NameOfColor" << "Quantity_NOC_BLUE1" << "Quantity_NOC_CADETBLUE" + << "Quantity_NOC_GREEN" << "Quantity_NOC_MAGENTA1" << "Quantity_NOC_RED" << "Quantity_NOC_YELLOW" + << "Quantity_NOC_WHITE" << "Quantity_NOC_MATRABLUE" << "Quantity_TOC_RGB" << "Quantity_TOC_HLS" + << "Standard_GUID" << "TColStd_ListIteratorOfListOfTransient" << "TColStd_ListOfTransient" + << "TDataStd_Integer" << "TDataStd_Name" << "TDataStd_Real" << "TFunction_Driver" + << "TFunction_DriverTable" << "TFunction_Function" << "TFunction_Logbook" << "TDF_Label" + << "TDF_TagSource" << "TNaming_NamedShape" << "TopAbs_EDGE" << "TopAbs_FACE" << "TopAbs_VERTEX" + << "TPrsStd_AISPresentation" << "TPrsStd_AISViewer" << "V3d_AmbientLight" + << "V3d_DirectionalLight" << "V3d_PositionalLight" << "V3d_SpotLight" << "XmlDrivers"; + + QStringList aHelperPatterns; + aHelperPatterns + << "AdaptorCurve_AIS" << "AdaptorVec_AIS" << "AdaptorCurve2d_AIS" << "AdaptorPnt2d_AIS" + << "Sample2D_Image" << "Sample2D_Markers" << "Sample2D_Face" << "TOcafFunction_BoxDriver" + << "TOcafFunction_CylDriver" << "DisplayPresentation"; + + HighlightingRule aRule; + + myOcctFormat.setForeground(Qt::darkCyan); + + foreach (const QString& aPattern, anOcctPatterns) + { + aRule.myPattern = QRegExp(aPattern); + aRule.myFormat = myOcctFormat; + myHighlightingRules.append(aRule); + } + + myHelperFormat.setForeground(Qt::red); + foreach (const QString& aPattern, aHelperPatterns) + { + aRule.myPattern = QRegExp(aPattern); + aRule.myFormat = myHelperFormat; + myHighlightingRules.append(aRule); + } + + + myKeywordFormat.setForeground(Qt::darkBlue); + myKeywordFormat.setFontWeight(QFont::Bold); + foreach (const QString& aPattern, aKeywordPatterns) + { + aRule.myPattern = QRegExp(aPattern); + aRule.myFormat = myKeywordFormat; + myHighlightingRules.append(aRule); + } + + myMemberFormat.setFontWeight(QFont::Bold); + aRule.myPattern = QRegExp(QLatin1String("\\bmy[0-9A-Za-z]+\\b")); + aRule.myFormat = myMemberFormat; + myHighlightingRules.append(aRule); + + myLocalFormat.setForeground(Qt::darkMagenta); + aRule.myPattern = QRegExp(QLatin1String("\\ba[0-9A-Za-z]+\\b")); + aRule.myFormat = myLocalFormat; + myHighlightingRules.append(aRule); + + myQuotationFormat.setForeground(Qt::darkRed); + aRule.myPattern = QRegExp(QLatin1String("\".*\"")); + aRule.myFormat = myQuotationFormat; + myHighlightingRules.append(aRule); + + myFunctionFormat.setFontItalic(true); + myFunctionFormat.setForeground(Qt::blue); + aRule.myPattern = QRegExp(QLatin1String("\\b[A-Za-z0-9_]+(?=\\()")); + aRule.myFormat = myFunctionFormat; + myHighlightingRules.append(aRule); + + mySingleLineCommentFormat.setForeground(Qt::darkGreen); + aRule.myPattern = QRegExp(QLatin1String("//[^\n]*")); + aRule.myFormat = mySingleLineCommentFormat; + myHighlightingRules.append(aRule); + + myMultiLineCommentFormat.setForeground(Qt::darkGreen); + + myCommentStartExpression = QRegExp(QLatin1String("/\\*")); + myCommentEndExpression = QRegExp(QLatin1String("\\*/")); +} + +void OcctHighlighter::highlightBlock (const QString& theText) +{ + foreach (const HighlightingRule &rule, myHighlightingRules) + { + QRegExp expression(rule.myPattern); + int index = expression.indexIn(theText); + while (index >= 0) + { + int length = expression.matchedLength(); + setFormat(index, length, rule.myFormat); + index = expression.indexIn(theText, index + length); + } + } + + setCurrentBlockState(0); + + int startIndex = 0; + if (previousBlockState() != 1) + startIndex = theText.indexOf(myCommentStartExpression); + + while (startIndex >= 0) + { + int endIndex = myCommentEndExpression.indexIn(theText, startIndex); + int commentLength; + if (endIndex == -1) + { + setCurrentBlockState(1); + commentLength = theText.length() - startIndex; + } + else + { + commentLength = endIndex - startIndex + + myCommentEndExpression.matchedLength(); + } + setFormat(startIndex, commentLength, myMultiLineCommentFormat); + startIndex = myCommentEndExpression.indexIn(theText, startIndex + commentLength); + } +} diff --git a/src/WBCLFZSystemModule/OCCViewer/OcctHighlighter.h b/src/WBCLFZSystemModule/OCCViewer/OcctHighlighter.h new file mode 100644 index 0000000..967fa49 --- /dev/null +++ b/src/WBCLFZSystemModule/OCCViewer/OcctHighlighter.h @@ -0,0 +1,77 @@ +// Copyright (c) 2020 OPEN CASCADE SAS +// +// This file is part of the examples of the Open CASCADE Technology software library. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE + +#ifndef OCCTHIGHLIGHTER_H +#define OCCTHIGHLIGHTER_H + +#include + +#include +#include +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE +class QTextDocument; +QT_END_NAMESPACE + +//! Implements C++ and OCCT objects syntax +//! highlighting for sample code window +class OcctHighlighter: public QSyntaxHighlighter +{ + Q_OBJECT +public: + + OcctHighlighter(QTextDocument* theParent = 0); + +protected: + void highlightBlock(const QString& theText) Standard_OVERRIDE; + +private: + struct HighlightingRule + { + QRegExp myPattern; + QTextCharFormat myFormat; + }; + +private: + QVector myHighlightingRules; + // QRegExp (Qt4+) introduced by the patch as alternative to QRegularExpression + // (Qt5+) for compatibility reasons. QRegExp will be moved in future Qt6 to + // a qt5compat module: QRegExp -> Qt5::QRegExp + QRegExp myCommentStartExpression; + QRegExp myCommentEndExpression; + + QTextCharFormat myKeywordFormat; + QTextCharFormat mySingleLineCommentFormat; + QTextCharFormat myMultiLineCommentFormat; + QTextCharFormat myQuotationFormat; + QTextCharFormat myFunctionFormat; + QTextCharFormat myOcctFormat; + QTextCharFormat myMemberFormat; + QTextCharFormat myLocalFormat; + QTextCharFormat myHelperFormat; +}; + +#endif diff --git a/src/WBCLFZSystemModule/OCCViewer/TranslateDialog.cpp b/src/WBCLFZSystemModule/OCCViewer/TranslateDialog.cpp new file mode 100644 index 0000000..fdf0eef --- /dev/null +++ b/src/WBCLFZSystemModule/OCCViewer/TranslateDialog.cpp @@ -0,0 +1,113 @@ +// Copyright (c) 2020 OPEN CASCADE SAS +// +// This file is part of the examples of the Open CASCADE Technology software library. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE + +#include "TranslateDialog.h" + +#include +#include +#include + +TranslateDialog::TranslateDialog(QWidget* parent, Qt::WindowFlags flags, bool modal) +: QFileDialog(parent, flags) +{ + setOption(QFileDialog::DontUseNativeDialog); + setModal(modal); + + QGridLayout* grid = ::qobject_cast(layout()); + + if (grid) + { + QVBoxLayout *vbox = new QVBoxLayout; + + QWidget* paramGroup = new QWidget(this); + paramGroup->setLayout(vbox); + + myBox = new QComboBox(paramGroup); + vbox->addWidget(myBox); + + int row = grid->rowCount(); + grid->addWidget(paramGroup, row, 1, 1, 3); // make combobox occupy 1 row and 3 columns starting from 1 + } +} + +TranslateDialog::~TranslateDialog() +{ +} + +int TranslateDialog::getMode() const +{ + if (myBox->currentIndex() < 0 || myBox->currentIndex() > (int)myList.count() - 1) + { + return -1; + } + else + { + return myList.at(myBox->currentIndex()); + } +} + +void TranslateDialog::setMode(const int mode) +{ + int idx = myList.indexOf(mode); + if (idx >= 0) + { + myBox->setCurrentIndex(idx); + } +} + +void TranslateDialog::addMode(const int mode, const QString& name) +{ + myBox->show(); + myBox->addItem(name); + myList.append(mode); + myBox->updateGeometry(); + updateGeometry(); +} + +void TranslateDialog::clear() +{ + myList.clear(); + myBox->clear(); + myBox->hide(); + myBox->updateGeometry(); + updateGeometry(); +} + +QListView* TranslateDialog::findListView(const QObjectList & childList) +{ + QListView* listView = 0; + for (int i = 0, n = childList.count(); i < n && !listView; i++) + { + listView = qobject_cast(childList.at(i)); + if (!listView && childList.at(i)) + { + listView = findListView(childList.at(i)->children()); + } + } + return listView; +} + +void TranslateDialog::showEvent(QShowEvent* event) +{ + QFileDialog::showEvent(event); + QListView* aListView = findListView(children()); + aListView->setViewMode(QListView::ListMode); +} diff --git a/src/WBCLFZSystemModule/OCCViewer/TranslateDialog.h b/src/WBCLFZSystemModule/OCCViewer/TranslateDialog.h new file mode 100644 index 0000000..df28094 --- /dev/null +++ b/src/WBCLFZSystemModule/OCCViewer/TranslateDialog.h @@ -0,0 +1,56 @@ +// Copyright (c) 2020 OPEN CASCADE SAS +// +// This file is part of the examples of the Open CASCADE Technology software library. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE + +#ifndef TRANSLATEDIALOG_H +#define TRANSLATEDIALOG_H + +#include +#include +#include +#include +#include +#include +#include +#include + +//! Qt file dialog for save and restore sample files +class TranslateDialog : public QFileDialog +{ +public: + TranslateDialog(QWidget* = 0, Qt::WindowFlags flags = 0, bool = true); + ~TranslateDialog(); + int getMode() const; + void setMode(const int); + void addMode(const int, const QString&); + void clear(); + +protected: + void showEvent(QShowEvent* event); + +private: + QListView* findListView(const QObjectList&); + +private: + QComboBox* myBox; + QList myList; +}; + +#endif // TRANSLATEDIALOG_H diff --git a/src/WBCLFZSystemModule/OCCViewer/Transparency.cpp b/src/WBCLFZSystemModule/OCCViewer/Transparency.cpp new file mode 100644 index 0000000..33fd02f --- /dev/null +++ b/src/WBCLFZSystemModule/OCCViewer/Transparency.cpp @@ -0,0 +1,46 @@ +// Copyright (c) 2020 OPEN CASCADE SAS +// +// This file is part of the examples of the Open CASCADE Technology software library. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE + +#include "Transparency.h" + +#include +#include +#include +#include + +DialogTransparency::DialogTransparency(QWidget* parent) +: QDialog(parent, Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint | Qt::WindowCloseButtonHint) +{ + setWindowTitle(tr("Transparency")); + QHBoxLayout* base = new QHBoxLayout(this); + + base->addWidget(new QLabel("0", this)); + + mySlider = new QSlider(Qt::Horizontal, this); + mySlider->setRange(0, 10); + mySlider->setTickPosition(QSlider::TicksBelow); + mySlider->setTickInterval(1); + mySlider->setPageStep(2); + base->addWidget(mySlider); + connect(mySlider, SIGNAL(valueChanged(int)), this, SIGNAL(sendTransparencyChanged(int))); + + base->addWidget(new QLabel("10", this)); +} diff --git a/src/WBCLFZSystemModule/OCCViewer/Transparency.h b/src/WBCLFZSystemModule/OCCViewer/Transparency.h new file mode 100644 index 0000000..fc21bfb --- /dev/null +++ b/src/WBCLFZSystemModule/OCCViewer/Transparency.h @@ -0,0 +1,60 @@ +// Copyright (c) 2020 OPEN CASCADE SAS +// +// This file is part of the examples of the Open CASCADE Technology software library. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE + +#ifndef TRANSPARENCY_H +#define TRANSPARENCY_H + + +#include +#include +#include +#include +#include + +#include + +class QSlider; + +//! Qt dialog with slider for change shapes transparency +class DialogTransparency : public QDialog +{ + Q_OBJECT +public: + DialogTransparency ( QWidget * parent=0 ); + ~DialogTransparency() { } + + int value() const + { + return mySlider->value(); + } + + void setValue(int theVal) const + { + mySlider->setValue(theVal); + } + +signals: + void sendTransparencyChanged(int value); + +private: + QSlider* mySlider; +}; +#endif \ No newline at end of file diff --git a/src/WBCLFZSystemModule/OCCViewer/View.cpp b/src/WBCLFZSystemModule/OCCViewer/View.cpp new file mode 100644 index 0000000..f587251 --- /dev/null +++ b/src/WBCLFZSystemModule/OCCViewer/View.cpp @@ -0,0 +1,720 @@ +// Copyright (c) 2020 OPEN CASCADE SAS +// +// This file is part of the examples of the Open CASCADE Technology software library. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE + +#if !defined _WIN32 +#define QT_CLEAN_NAMESPACE /* avoid definition of INT32 and INT8 */ +#endif +#include +#include "OCCViewer\View.h" +#include +#include "Transparency.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if !defined(_WIN32) && (!defined(__APPLE__) || defined(MACOSX_USE_GLX)) && QT_VERSION < 0x050000 +#include +#endif + +#include +#include +#include + + +namespace +{ + //! Map Qt buttons bitmask to virtual keys. + static Aspect_VKeyMouse qtMouseButtons2VKeys(Qt::MouseButtons theButtons) + { + Aspect_VKeyMouse aButtons = Aspect_VKeyMouse_NONE; + if ((theButtons & Qt::LeftButton) != 0) + { + aButtons |= Aspect_VKeyMouse_LeftButton; + } + if ((theButtons & Qt::MiddleButton) != 0) + { + aButtons |= Aspect_VKeyMouse_MiddleButton; + } + if ((theButtons & Qt::RightButton) != 0) + { + aButtons |= Aspect_VKeyMouse_RightButton; + } + return aButtons; + } + + //! Map Qt mouse modifiers bitmask to virtual keys. + static Aspect_VKeyFlags qtMouseModifiers2VKeys(Qt::KeyboardModifiers theModifiers) + { + Aspect_VKeyFlags aFlags = Aspect_VKeyFlags_NONE; + if ((theModifiers & Qt::ShiftModifier) != 0) + { + aFlags |= Aspect_VKeyFlags_SHIFT; + } + if ((theModifiers & Qt::ControlModifier) != 0) + { + aFlags |= Aspect_VKeyFlags_CTRL; + } + if ((theModifiers & Qt::AltModifier) != 0) + { + aFlags |= Aspect_VKeyFlags_ALT; + } + return aFlags; + } + + static QCursor* defCursor = NULL; + static QCursor* handCursor = NULL; + static QCursor* panCursor = NULL; + static QCursor* globPanCursor = NULL; + static QCursor* zoomCursor = NULL; + static QCursor* rotCursor = NULL; + +} + +View::View(const Handle(AIS_InteractiveContext)& theContext, bool theIs3dView, QWidget* theParent) + : QWidget(theParent), + myIsRaytracing(false), + myIsShadowsEnabled(true), + myIsReflectionsEnabled(false), + myIsAntialiasingEnabled(false), + myIs3dView(theIs3dView), + myBackMenu(NULL) +{ +#if !defined(_WIN32) && (!defined(__APPLE__) || defined(MACOSX_USE_GLX)) && QT_VERSION < 0x050000 + XSynchronize(x11Info().display(), true); +#endif + + + myContext = theContext; + myCurZoom = 0; + + setAttribute(Qt::WA_PaintOnScreen); + setAttribute(Qt::WA_NoSystemBackground); + + myDefaultGestures = myMouseGestureMap; + myCurrentMode = CurrentAction3d_Nothing; + setMouseTracking(true); + + initViewActions(); + initCursors(); + + setBackgroundRole(QPalette::NoRole);//NoBackground ); + // set focus policy to threat QContextMenuEvent from keyboard + setFocusPolicy(Qt::StrongFocus); + setAttribute(Qt::WA_PaintOnScreen); + setAttribute(Qt::WA_NoSystemBackground); + init(); +} + +void View::init() +{ + initializeGL(); +} + +void View::paintEvent(QPaintEvent*) +{ + myV3dView->InvalidateImmediate(); + FlushViewEvents(myContext, myV3dView, true); +} + +void View::resizeEvent(QResizeEvent*) +{ + if (!myV3dView.IsNull()) + { + myV3dView->MustBeResized(); + } +} + +void View::OnSelectionChanged(const Handle(AIS_InteractiveContext)& theCtx, + const Handle(V3d_View)& theView) +{ + Q_UNUSED(theCtx) + Q_UNUSED(theView) +} + +void View::fitAll() +{ + myV3dView->FitAll(); + myV3dView->ZFitAll(); + myV3dView->Redraw(); +} + +void View::axo() +{ + if (myIs3dView) + { + myV3dView->SetProj(V3d_XposYnegZpos); + } +} + +void View::hlrOff() +{ + QApplication::setOverrideCursor(Qt::WaitCursor); + myV3dView->SetComputedMode(Standard_False); + myV3dView->Redraw(); + QAction* aShadingAction = getViewAction(ViewAction_Shading); + aShadingAction->setEnabled(true); + QAction* aWireframeAction = getViewAction(ViewAction_Wireframe); + aWireframeAction->setEnabled(true); + QApplication::restoreOverrideCursor(); +} + +void View::hlrOn() +{ + QApplication::setOverrideCursor(Qt::WaitCursor); + myV3dView->SetComputedMode(Standard_True); + myV3dView->Redraw(); + QAction* aShadingAction = getViewAction(ViewAction_Shading); + aShadingAction->setEnabled(false); + QAction* aWireframeAction = getViewAction(ViewAction_Wireframe); + aWireframeAction->setEnabled(false); + QApplication::restoreOverrideCursor(); +} + +void View::shading() +{ + myContext->SetDisplayMode(1, Standard_True); +} + +void View::wireframe() +{ + myContext->SetDisplayMode(0, Standard_True); +} + +void View::SetRaytracedShadows(bool theState) +{ + myV3dView->ChangeRenderingParams().IsShadowEnabled = theState; + myIsShadowsEnabled = theState; + myContext->UpdateCurrentViewer(); +} + +void View::SetRaytracedReflections(bool theState) +{ + myV3dView->ChangeRenderingParams().IsReflectionEnabled = theState; + myIsReflectionsEnabled = theState; + myContext->UpdateCurrentViewer(); +} + +void View::onRaytraceAction() +{ + QAction* aSentBy = (QAction*)sender(); + + if (aSentBy == myRaytraceActions.value(RaytraceAction_Raytracing)) + { + bool aState = myRaytraceActions.value(RaytraceAction_Raytracing)->isChecked(); + + QApplication::setOverrideCursor(Qt::WaitCursor); + if (aState) + EnableRaytracing(); + else + DisableRaytracing(); + QApplication::restoreOverrideCursor(); + } + + if (aSentBy == myRaytraceActions.value(RaytraceAction_Shadows)) + { + bool aState = myRaytraceActions.value(RaytraceAction_Shadows)->isChecked(); + SetRaytracedShadows(aState); + } + + if (aSentBy == myRaytraceActions.value(RaytraceAction_Reflections)) + { + bool aState = myRaytraceActions.value(RaytraceAction_Reflections)->isChecked(); + SetRaytracedReflections(aState); + } + + if (aSentBy == myRaytraceActions.value(RaytraceAction_Antialiasing)) + { + bool aState = myRaytraceActions.value(RaytraceAction_Antialiasing)->isChecked(); + SetRaytracedAntialiasing(aState); + } +} + +void View::initializeGL() +{ + if (myV3dView.IsNull()) + { + myV3dView = myContext->CurrentViewer()->CreateView(); + } + // Get window handle. This returns something suitable for all platforms. + WId window_handle = (WId)winId(); + + // Create appropriate window for platform + Handle(WNT_Window) wind = new WNT_Window((Aspect_Handle)window_handle); + + myV3dView->SetWindow(wind); + if (!wind->IsMapped()) + { + wind->Map(); + } + + if (myIs3dView) + { + SetAllowRotation(Standard_True); + myV3dView->SetBackgroundColor(Quantity_Color(0.0, 0.0, 0.3, Quantity_TOC_RGB)); + } + else + { + SetAllowRotation(Standard_False); + myV3dView->SetBackgroundColor(Quantity_Color(0.0, 0.2, 0.0, Quantity_TOC_RGB)); + myV3dView->SetProj(V3d_Zpos); + } + + myV3dView->MustBeResized(); + + if (myIsRaytracing) + { + myV3dView->ChangeRenderingParams().Method = Graphic3d_RM_RAYTRACING; + } + + // ×ø±êÖá + //myV3dView->ZBufferTriedronSetup(); + + qDebug() << u8"³õʼ»¯Èýά´°¿Ú\n"; +} + +void View::resizeGL(int w, int h) +{ + if (!myV3dView.IsNull()) + { + myV3dView->MustBeResized(); + } +} + +void View::paintGL() +{ + if (!myV3dView.IsNull()) { + myV3dView->Redraw(); + } +} + +void View::SetRaytracedAntialiasing(bool theState) +{ + myV3dView->ChangeRenderingParams().IsAntialiasingEnabled = theState; + myIsAntialiasingEnabled = theState; + myContext->UpdateCurrentViewer(); +} + +void View::EnableRaytracing() +{ + if (!myIsRaytracing) + { + myV3dView->ChangeRenderingParams().Method = Graphic3d_RM_RAYTRACING; + } + myIsRaytracing = true; + myContext->UpdateCurrentViewer(); +} + +void View::DisableRaytracing() +{ + if (myIsRaytracing) + { + myV3dView->ChangeRenderingParams().Method = Graphic3d_RM_RASTERIZATION; + } + myIsRaytracing = false; + myContext->UpdateCurrentViewer(); +} + +void View::updateToggled(bool isOn) +{ + QAction* sentBy = (QAction*)sender(); + if (!isOn) + { + return; + } + + foreach(QAction * anAction, myViewActions) + { + if (anAction && (anAction != sentBy)) + { + anAction->setCheckable(true); + anAction->setChecked(false); + } + else + { + if (sentBy == myViewActions.value(ViewAction_FitArea)) + setCursor(*handCursor); + else if (sentBy == myViewActions.value(ViewAction_Zoom)) + setCursor(*zoomCursor); + else if (sentBy == myViewActions.value(ViewAction_Pan)) + setCursor(*panCursor); + else if (sentBy == myViewActions.value(ViewAction_GlobalPan)) + setCursor(*globPanCursor); + else if (sentBy == myViewActions.value(ViewAction_Rotation)) + setCursor(*rotCursor); + else + setCursor(*defCursor); + + sentBy->setCheckable(false); + } + } +} + +void View::initCursors() +{ + if (!defCursor) + defCursor = new QCursor(Qt::ArrowCursor); + if (!handCursor) + handCursor = new QCursor(Qt::PointingHandCursor); + if (!panCursor) + panCursor = new QCursor(Qt::SizeAllCursor); + if (!globPanCursor) + globPanCursor = new QCursor(Qt::CrossCursor); + if (!zoomCursor) + zoomCursor = new QCursor(QPixmap(":/icons/cursor_zoom.png")); + if (!rotCursor) + rotCursor = new QCursor(QPixmap(":/icons/cursor_rotate.png")); +} + +QList View::getViewActions() +{ + initViewActions(); + return myViewActions.values(); +} + +QList View::getRaytraceActions() +{ + initRaytraceActions(); + return myRaytraceActions.values(); +} + +QAction* View::getViewAction(ViewAction theAction) +{ + return myViewActions.value(theAction); +} + +QAction* View::getRaytraceAction(RaytraceAction theAction) +{ + return myRaytraceActions.value(theAction); +} + +/*! + Get paint engine for the OpenGL viewer. [ virtual public ] +*/ +QPaintEngine* View::paintEngine() const +{ + return 0; +} + +QAction* View::RegisterAction(QString theIconPath, QString thePromt) +{ + QAction* anAction = new QAction(QPixmap(theIconPath), thePromt, this); + anAction->setToolTip(thePromt); + anAction->setStatusTip(thePromt); + return anAction; +} + +void View::initViewActions() +{ + if (!myViewActions.empty()) + return; + myViewActions[ViewAction_FitAll] = RegisterAction(":/icons/view_fitall.png", tr(u8"Ëõ·Åȫͼ")); + connect(myViewActions[ViewAction_FitAll], SIGNAL(triggered()), this, SLOT(fitAll())); + if (myIs3dView) + { + myViewActions[ViewAction_Axo] = RegisterAction(":/icons/view_axo.png", tr(u8"ÊӽǸ´Î»")); + connect(myViewActions[ViewAction_Axo], SIGNAL(triggered()), this, SLOT(axo())); + + QActionGroup* aShadingActionGroup = new QActionGroup(this); + QAction* aShadingAction = RegisterAction(":/icons/tool_shading.png", tr(u8"Ôö¼ÓÒõÓ°")); + connect(aShadingAction, SIGNAL(triggered()), this, SLOT(shading())); + aShadingAction->setCheckable(true); + aShadingActionGroup->addAction(aShadingAction); + myViewActions[ViewAction_Shading] = aShadingAction; + + QAction* aWireframeAction = RegisterAction(":/icons/tool_wireframe.png", tr(u8"Ïß¿òģʽ")); + connect(aWireframeAction, SIGNAL(triggered()), this, SLOT(wireframe())); + aWireframeAction->setCheckable(true); + aShadingActionGroup->addAction(aWireframeAction); + myViewActions[ViewAction_Wireframe] = aWireframeAction; + + QActionGroup* aHlrActionGroup = new QActionGroup(this); + QAction* aHlrOffAction = RegisterAction(":/icons/view_comp_off.png", tr(u8"Òþ²ØÏß¿ò")); + connect(aHlrOffAction, SIGNAL(triggered()), this, SLOT(hlrOff())); + aHlrOffAction->setCheckable(true); + aHlrActionGroup->addAction(aHlrOffAction); + myViewActions[ViewAction_HlrOff] = aHlrOffAction; + + QAction* aHlrOnAction = RegisterAction(":/icons/view_comp_on.png", tr(u8"ÏÔʾÏß¿ò")); + connect(aHlrOnAction, SIGNAL(triggered()), this, SLOT(hlrOn())); + aHlrOnAction->setCheckable(true); + aHlrActionGroup->addAction(aHlrOnAction); + myViewActions[ViewAction_HlrOn] = aHlrOnAction; + + QAction* aTransparencyAction = RegisterAction(":/icons/tool_transparency.png", tr(u8"͸Ã÷¶È")); + connect(aTransparencyAction, SIGNAL(triggered()), this, SLOT(onTransparency())); + myViewActions[ViewAction_Transparency] = aTransparencyAction; + } +} + +void View::initRaytraceActions() +{ + if (!myRaytraceActions.empty()) + { + return; + } + + QAction* aRayTraceAction = RegisterAction(":/icons/raytracing.png", tr(u8"¹âÏß×·×ÙäÖȾ")); + connect(aRayTraceAction, SIGNAL(triggered()), this, SLOT(onRaytraceAction())); + myRaytraceActions[RaytraceAction_Raytracing] = aRayTraceAction; + aRayTraceAction->setCheckable(true); + aRayTraceAction->setChecked(false); + + QAction* aShadowAction = RegisterAction(":/icons/shadows.png", tr(u8"ÒõÓ°äÖȾ")); + connect(aShadowAction, SIGNAL(triggered()), this, SLOT(onRaytraceAction())); + myRaytraceActions[RaytraceAction_Shadows] = aShadowAction; + aShadowAction->setCheckable(true); + aShadowAction->setChecked(true); + + QAction* aReflectAction = RegisterAction(":/icons/reflections.png", tr(u8"·¢Éä")); + connect(aReflectAction, SIGNAL(triggered()), this, SLOT(onRaytraceAction())); + myRaytraceActions[RaytraceAction_Reflections] = aReflectAction; + aReflectAction->setCheckable(true); + aReflectAction->setChecked(false); + + QAction* anAntiAliasingAction = RegisterAction(":/icons/antialiasing.png", tr(u8"¿¹¾â³Ý")); + connect(anAntiAliasingAction, SIGNAL(triggered()), this, SLOT(onRaytraceAction())); + myRaytraceActions[RaytraceAction_Antialiasing] = anAntiAliasingAction; + anAntiAliasingAction->setCheckable(true); + anAntiAliasingAction->setChecked(false); +} + +void View::activateCursor(const CurrentAction3d theMode) +{ + QCursor* aCursor = defCursor; + switch (theMode) + { + case CurrentAction3d_DynamicPanning: aCursor = panCursor; break; + case CurrentAction3d_DynamicZooming: aCursor = zoomCursor; break; + case CurrentAction3d_DynamicRotation: aCursor = rotCursor; break; + case CurrentAction3d_GlobalPanning: aCursor = globPanCursor; break; + case CurrentAction3d_WindowZooming: aCursor = handCursor; break; + case CurrentAction3d_Nothing: aCursor = defCursor; break; + default: + break; + } + setCursor(*aCursor); +} + +void View::mousePressEvent(QMouseEvent* theEvent) +{ + qDebug() << u8"View mousePressEvent \n"; + Qt::MouseButtons aMouseButtons = theEvent->buttons(); + const Graphic3d_Vec2i aPnt(theEvent->pos().x(), theEvent->pos().y()); + const Aspect_VKeyFlags aFlags = qtMouseModifiers2VKeys(theEvent->modifiers()); + if (!myV3dView.IsNull() + && UpdateMouseButtons(aPnt, qtMouseButtons2VKeys(aMouseButtons), aFlags, false)) + { + updateView(); + } + myClickPos = aPnt; + + emit this->ViewMousePressEvent(theEvent); + +} + +void View::mouseReleaseEvent(QMouseEvent* theEvent) +{ + qDebug() << u8"View mouseReleaseEvent \n"; + Qt::MouseButtons aMouseButtons = theEvent->buttons(); + const Graphic3d_Vec2i aPnt(theEvent->pos().x(), theEvent->pos().y()); + const Aspect_VKeyFlags aFlags = qtMouseModifiers2VKeys(theEvent->modifiers()); + if (!myV3dView.IsNull() + && UpdateMouseButtons(aPnt, qtMouseButtons2VKeys(aMouseButtons), aFlags, false)) + { + updateView(); + } + + if (myCurrentMode == CurrentAction3d_GlobalPanning) + { + myV3dView->Place(aPnt.x(), aPnt.y(), myCurZoom); + } + if (myCurrentMode != CurrentAction3d_Nothing) + { + setCurrentAction(CurrentAction3d_Nothing); + } + + + emit this->ViewMouseReleaseEvent(theEvent); + +} + +void View::mouseMoveEvent(QMouseEvent* theEvent) +{ + Qt::MouseButtons aMouseButtons = theEvent->buttons(); + const Graphic3d_Vec2i aNewPos(theEvent->pos().x(), theEvent->pos().y()); + if (!myV3dView.IsNull() + && UpdateMousePosition(aNewPos, qtMouseButtons2VKeys(aMouseButtons), qtMouseModifiers2VKeys(theEvent->modifiers()), false)) + { + updateView(); + } +} + +//============================================================================== +//function : wheelEvent +//purpose : +//============================================================================== +void View::wheelEvent(QWheelEvent* theEvent) +{ + const Graphic3d_Vec2i aPos(theEvent->pos().x(), theEvent->pos().y()); + if (!myV3dView.IsNull() + && UpdateZoom(Aspect_ScrollDelta(aPos, theEvent->delta() / 8))) + { + updateView(); + } +} + +// ======================================================================= +// function : updateView +// purpose : +// ======================================================================= +void View::updateView() +{ + update(); +} + +void View::defineMouseGestures() +{ + myMouseGestureMap.Clear(); + AIS_MouseGesture aRot = AIS_MouseGesture_RotateOrbit; + activateCursor(myCurrentMode); + switch (myCurrentMode) + { + case CurrentAction3d_Nothing: + { + myMouseGestureMap = myDefaultGestures; + break; + } + case CurrentAction3d_DynamicZooming: + { + myMouseGestureMap.Bind(Aspect_VKeyMouse_LeftButton, AIS_MouseGesture_Zoom); + break; + } + case CurrentAction3d_GlobalPanning: + { + break; + } + case CurrentAction3d_WindowZooming: + { + myMouseGestureMap.Bind(Aspect_VKeyMouse_LeftButton, AIS_MouseGesture_ZoomWindow); + break; + } + case CurrentAction3d_DynamicPanning: + { + myMouseGestureMap.Bind(Aspect_VKeyMouse_LeftButton, AIS_MouseGesture_Pan); + break; + } + case CurrentAction3d_DynamicRotation: + { + myMouseGestureMap.Bind(Aspect_VKeyMouse_LeftButton, aRot); + break; + } + default: + { + break; + } + } +} + + +void View::addItemInPopup(QMenu* theMenu) +{ + Q_UNUSED(theMenu) +} + +void View::onBackground() +{ + QColor aColor; + Standard_Real R1; + Standard_Real G1; + Standard_Real B1; + myV3dView->BackgroundColor(Quantity_TOC_RGB, R1, G1, B1); + aColor.setRgb((Standard_Integer)(R1 * 255), (Standard_Integer)(G1 * 255), (Standard_Integer)(B1 * 255)); + + QColor aRetColor = QColorDialog::getColor(aColor); + if (aRetColor.isValid()) + { + R1 = aRetColor.red() / 255.; + G1 = aRetColor.green() / 255.; + B1 = aRetColor.blue() / 255.; + myV3dView->SetBackgroundColor(Quantity_TOC_RGB, R1, G1, B1); + } + myV3dView->Redraw(); +} + +void View::onEnvironmentMap() +{ + if (myBackMenu->actions().at(1)->isChecked()) + { + QString fileName = getOpenFilePath(this, tr("Open File"), + tr("All Image Files (*.bmp *.gif *.jpg *.jpeg *.png *.tga)")); + + const TCollection_AsciiString anUtf8Path(fileName.toUtf8().data()); + Handle(Graphic3d_TextureEnv) aTexture = new Graphic3d_TextureEnv(anUtf8Path); + myV3dView->SetTextureEnv(aTexture); + } + else + { + myV3dView->SetTextureEnv(Handle(Graphic3d_TextureEnv)()); + } + + myV3dView->Redraw(); +} + +void View::onTransparency() +{ + AIS_ListOfInteractive anAisObjectsList; + myContext->DisplayedObjects(anAisObjectsList); + if (anAisObjectsList.Extent() == 0) + { + return; + } + + double aTranspValue = anAisObjectsList.First()->Transparency(); + DialogTransparency aDlg(this); + aDlg.setValue(int(aTranspValue * 10)); + connect(&aDlg, SIGNAL(sendTransparencyChanged(int)), SLOT(onTransparencyChanged(int))); + aDlg.exec(); +} + +void View::onTransparencyChanged(int theVal) +{ + AIS_ListOfInteractive anAisObjectsList; + myContext->DisplayedObjects(anAisObjectsList); + double aTranspValue = theVal / 10.; + for (AIS_ListOfInteractive::Iterator anIter(anAisObjectsList); + anIter.More(); anIter.Next()) + { + const Handle(AIS_InteractiveObject)& anAisObject = anIter.Value(); + myContext->SetTransparency(anAisObject, aTranspValue, Standard_False); + } + myContext->UpdateCurrentViewer(); +} diff --git a/src/WBCLFZSystemModule/OCCViewer/View.h b/src/WBCLFZSystemModule/OCCViewer/View.h new file mode 100644 index 0000000..5bbb247 --- /dev/null +++ b/src/WBCLFZSystemModule/OCCViewer/View.h @@ -0,0 +1,227 @@ + + +// Copyright (c) 2020 OPEN CASCADE SAS +// +// This file is part of the examples of the Open CASCADE Technology software library. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE + +#ifndef VIEW_H +#define VIEW_H +#include "AllHead.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + + +class TopoDS_Shape; + +enum CurrentAction3d +{ + CurrentAction3d_Nothing, + CurrentAction3d_DynamicZooming, + CurrentAction3d_WindowZooming, + CurrentAction3d_DynamicPanning, + CurrentAction3d_GlobalPanning, + CurrentAction3d_DynamicRotation, + CurrentAction3d_ObjectDececting +}; +enum ViewAction +{ + ViewAction_FitAll, + ViewAction_FitArea, + ViewAction_Zoom, + ViewAction_Pan, + ViewAction_GlobalPan, + ViewAction_Front, + ViewAction_Back, + ViewAction_Top, + ViewAction_Bottom, + ViewAction_Left, + ViewAction_Right, + ViewAction_Axo, + ViewAction_Rotation, + ViewAction_Reset, + ViewAction_HlrOff, + ViewAction_HlrOn, + ViewAction_Shading, + ViewAction_Wireframe, + ViewAction_Transparency +}; +enum RaytraceAction +{ + RaytraceAction_Raytracing, + RaytraceAction_Shadows, + RaytraceAction_Reflections, + RaytraceAction_Antialiasing +}; + +//! Qt widget containing V3d_View and toolbar with view manipulation buttons. +//! Also use AIS_ViewController for redirecting user input (mouse, keyboard) +//! into 3D viewer events (rotation, panning, zooming) +class View: public QWidget, protected AIS_ViewController +{ + Q_OBJECT +public: + View (const Handle(AIS_InteractiveContext)& theContext, bool theIs3dView, QWidget* theParent); + + ~View() + { + delete myBackMenu; + } + + virtual void init(); + QList getViewActions(); + QAction* getViewAction(ViewAction theAction); + QList getRaytraceActions(); + QAction* getRaytraceAction(RaytraceAction theAction); + + void EnableRaytracing(); + void DisableRaytracing(); + + void SetRaytracedShadows (bool theState); + void SetRaytracedReflections (bool theState); + void SetRaytracedAntialiasing (bool theState); + + bool IsRaytracingMode() const { return myIsRaytracing; } + bool IsShadowsEnabled() const { return myIsShadowsEnabled; } + bool IsReflectionsEnabled() const { return myIsReflectionsEnabled; } + bool IsAntialiasingEnabled() const { return myIsAntialiasingEnabled; } + + static QString GetMessages(int type,TopAbs_ShapeEnum aSubShapeType, TopAbs_ShapeEnum aShapeType); + static QString GetShapeType(TopAbs_ShapeEnum aShapeType); + + Standard_EXPORT static void OnButtonuseraction(int ExerciceSTEP, Handle(AIS_InteractiveContext)& ); + Standard_EXPORT static void DoSelection(int Id, Handle(AIS_InteractiveContext)& ); + Standard_EXPORT static void OnSetSelectionMode(Handle(AIS_InteractiveContext)&, + Standard_Integer&, + TopAbs_ShapeEnum& SelectionMode, + Standard_Boolean& ); + virtual QPaintEngine* paintEngine() const; + const Handle(V3d_View)& getView() const { return myV3dView; } + +signals: + void selectionChanged(); + void ViewMousePressEvent(QMouseEvent* theEvent); + void ViewMouseReleaseEvent(QMouseEvent* theEvent); + +public slots: + void fitAll(); + void axo(); + void hlrOn(); + void hlrOff(); + void shading(); + void wireframe(); + void onTransparency(); + + void updateToggled( bool ); + void onBackground(); + void onEnvironmentMap(); + void onRaytraceAction(); + +private slots: +void onTransparencyChanged(int theVal); + + +//protected: +// void initializeGL() Standard_OVERRIDE; +// void resizeGL(int w, int h) Standard_OVERRIDE; +// void paintGL() Standard_OVERRIDE; + +protected: + void initializeGL() ; + void resizeGL(int w, int h) ; + void paintGL() ; + + +protected: + virtual void paintEvent( QPaintEvent* ) Standard_OVERRIDE; + virtual void resizeEvent( QResizeEvent* ) Standard_OVERRIDE; + virtual void mousePressEvent( QMouseEvent* ) Standard_OVERRIDE; + virtual void mouseReleaseEvent(QMouseEvent* ) Standard_OVERRIDE; + virtual void mouseMoveEvent( QMouseEvent* ) Standard_OVERRIDE; + virtual void wheelEvent(QWheelEvent*) Standard_OVERRIDE; + + virtual void addItemInPopup( QMenu* ); + + Handle(AIS_InteractiveContext)& getContext() { return myContext; } + + void activateCursor( const CurrentAction3d ); + + CurrentAction3d getCurrentMode() const { return myCurrentMode; } + +private: + void initCursors(); + void initViewActions(); + void initRaytraceActions(); + + QAction* RegisterAction(QString theIconPath, QString thePromt); + +private: + bool myIsRaytracing; + bool myIsShadowsEnabled; + bool myIsReflectionsEnabled; + bool myIsAntialiasingEnabled; + + bool myIs3dView; + Handle(Graphic3d_GraphicDriver) m_graphic_driver; + Handle(V3d_View) myV3dView; + Handle(AIS_InteractiveContext) myContext; + AIS_MouseGestureMap myDefaultGestures; + Graphic3d_Vec2i myClickPos; + + void updateView(); + + //! Setup mouse gestures. + void defineMouseGestures(); + + //! Set current action. + void setCurrentAction (CurrentAction3d theAction) + { + myCurrentMode = theAction; + defineMouseGestures(); + } + + //! Handle selection changed event. + void OnSelectionChanged(const Handle(AIS_InteractiveContext)& theCtx, + const Handle(V3d_View)& theView) Standard_OVERRIDE; + CurrentAction3d myCurrentMode; + Standard_Real myCurZoom; + QMap myViewActions; + QMap myRaytraceActions; + QMenu* myBackMenu; + QToolBar* myViewBar; + + + +}; + +#endif diff --git a/src/WBCLFZSystemModule/OCCViewer/res/antialiasing.png b/src/WBCLFZSystemModule/OCCViewer/res/antialiasing.png new file mode 100644 index 0000000000000000000000000000000000000000..da8e5047a4ff2c2738718a56cfd47c1d19d24d1e GIT binary patch literal 230 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Ea{HEjtmSN`?>!lvI6;>1s;*b z3=DjSK$uZf!>a)(C{^MbQ4*Y=R#Ki=l*$m0n3-3i=jR%tP-d)Ws%L2E{@KYKs4B_R z#WBRfKl#W1|MtwP5^E$m99X#OzQ2<_94$HZzXDHEaxn8XZexZe9J0#N4SMWG6BaPu z;A!pTHDdl?DLP-qhNpm4Oy@}sOGTn}2R UAKHp91KP&m>FVdQ&MBb@07Pj*oB#j- literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/OCCViewer/res/cursor_rotate.png b/src/WBCLFZSystemModule/OCCViewer/res/cursor_rotate.png new file mode 100644 index 0000000000000000000000000000000000000000..a3cb0c1ecc31ed66595b4387c55dd2731809a5e1 GIT binary patch literal 291 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnH%)r1{DZJ<-ki!|^6XJT{zyToh|NsBJ3q{m` zEXI-`zhDN3XE)M7oFs2|7lsa2Sq~sbti&~FS$q5M)5)u*~FeEXuNpvI#I2A}-X}F}rqr=I=%gfWlk;uj_@bD7j z6|DtF4jh=G!12UL&ENr>PlD1KMh`VE4Ti0yjJ+8Jj78ER4MKcUJUm)LTnfPsZpKOG zEV4cgmtt0nIY{(yPjhvQn8U-#ZQ{ry%Esx*uHnq2v$d(wm(@i-H9286!$zGf)iWM5 e)|F^Z8<^g0e zmIV0)GdMiEkp|?5mAFQf1m~xflqVLYGNfmw85QKED;Vh+=o#9^?aKhFU`h9MOJ`zW zkPLd4!Up7Lc)B=-RLn_EP!KOz+h7#dX4;UsjI)PRK$4w})1Y}W<0Lc-a$k!M*zN28VxpF`U#yCAY@F9!>Q{yu)SmYHks0PSS(boFyt=akR{08E}qwEzGB literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/OCCViewer/res/help.png b/src/WBCLFZSystemModule/OCCViewer/res/help.png new file mode 100644 index 0000000000000000000000000000000000000000..e57336285ea67f393322fd6f19a64d9d1de42e53 GIT binary patch literal 214 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!9%)r1XI!iqT$l(m|32{Ae;K2X?Kn}y={c$Bg zim@cfFPOpM*^M+1C&}C0g(;1@2Bci9#5JNMI6tkVJh3R1Aw4tAs30$0!AQ?Q&(Jn* zUj|TxkEe@cNX4AwgoJ(PcjV()C>w#3=B*S3``o9LZ`&mG989ZJ6T-G@yGywpz CnKtYI literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/OCCViewer/res/lamp.png b/src/WBCLFZSystemModule/OCCViewer/res/lamp.png new file mode 100644 index 0000000000000000000000000000000000000000..a5a6775c33f5655a31ef8152b0fa94fcaa73abf3 GIT binary patch literal 1355 zcmd^7i%XMH6hGglY)YE@mdni4rBLY*sVE7}O{Z?9Q&P-u!OCnICac6xjOt62ED8#G zTV`Zg2|ehcV$dp*UZzAy#gd9_84Ol4A0@4Gt{Oq~7j)pL)q+D}fNWcF8TBSX#DVWbcMABR%wvq6 zOe?HhV$RPqnX_{B%gwoKHrYyx&0C7MLMe)I8OC&Yiaz8gt9A+#DIszqR^lKJXN!gf zdPCEk%tJX`YNz1#Qvgeh$Seqj{!0-t;V7pgQ$0lrr$BvDEr;CzDwvB_oFRhL;;~vQ zt8s%S7-X=Q178M%`5VuK#w;tlE3po7iW0tj7{MBq5RF#SiErxA;I9Q{KpK;zi04j$tPAP#rd;Vs?mU!8tK9N|$Dx_y|RY@hW(Jp^Ii z6AG6Q8^jqTsEgQBIj02eoM4Q`!Ar!~Eo%{MXrn#@3!TC^Ha@dRj6a>d1gJy&`dl~b zS&qLNf*9=-G0l~7pa^mrHc|!NIp{+)xtkBW#&@&7E|vM{H*U949px)bxwNyi_5Uk* zYOD`&RNswyU0&r$*P*-oy?D9)Xj$!`cV|IlR`YAU>+XzG1L0Nii3M_n$M{YX_x6dn z);3?F4bQbNmF=sw=%BYr?Y+5Y8dtt3p~3IQG3mMHn%K1A*+2KE?CWj&tlqJ?WdCr? zeAliAZyNLakKB>uuh#Ww1}>L8c^vGoRk|%xyOoAbRmtrax_VPpZcWPZ1JCalT&r4M z-EtwdpbW2l$bb}#O0PmqO1O?{N1)#yf4VfS~p9CTG=r+0j)KWl~4LFX61<28v_ zxCS4M(6Oyowk1n_>S6`g(mm(apj6wQ)aq#MpLI2<;A`iqkJiGSgWUp`9O&TGNzus~ RS6?!1j4{omzno&J{srsJK~Vqz literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/OCCViewer/res/raytracing.png b/src/WBCLFZSystemModule/OCCViewer/res/raytracing.png new file mode 100644 index 0000000000000000000000000000000000000000..211e697237314addce4eeaf9399e49c448101e9d GIT binary patch literal 223 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|SkfJR9T^xl z_H+M9WCij$3p^r=85sBugD~Uq{1qucL8%hgh?3y^w370~qEv=}#LT=BJwMkFg)(D3 zQ$0gN_s>q|KvjO8E{-7<{%3m}xfm394*&VTe7T%iyUT`G2b~vqpYEC&+Ze>Sl*y}A zFzU>X!lvI6;>1s;*b z3=DjSL74G){)!Z!pj3%#L`iUdT1k0gQ7S_~VrE{6o}X)oLYc9ish**s`)4O}psG+$ z7sn6_|KuP4|JyUGO01jN*!a+1QzA{Xi}C$B(?9BL%{o%+*aAd4p17%6h`oCK`v2r+ z$0|)P7Y()vub6sD7>pkLoy_Z!IN_FK7K7%)hKH<0ml+wBY8~9U`j0vf&;kZeS3j3^ HP6!lvI6;>1s;*b z3=DjSL74G){)!Z!pj3%#L`iUdT1k0gQ7S_~VrE{6o}X)oLYc9ish**s`)4O}psE&6 z7sn6_|F@Gbavo3+aL)g7?je`o10`AKi}|X#e1A4{guY6*mus4%IAcx+M;fDo|GVu> z^>XVA-feF9E~j#=W6tJXkwpn>SqsmtJh7?4kgY|j+))78&qol`;+0OTi5IRF3v literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/OCCViewer/res/tool_delete.png b/src/WBCLFZSystemModule/OCCViewer/res/tool_delete.png new file mode 100644 index 0000000000000000000000000000000000000000..3886af51d843d2599fdb390ba81a5da47333e5c4 GIT binary patch literal 203 zcmeAS@N?(olHy`uVBq!ia0vp^0zk~q!VDzkV}oRXltF+`h%1n80OJNQ)d1u*G#of^ zprN7RKT!NX!+$UZq=76T@E2C|1d4}wx;TbZ%uzkHQSg8P2eU)e`iE^ww=W);D_x$^ zV&FZkyC?Lo=OnEK5}GdF4{nRAN?QMQW`1X>V#~o(d3T;Duj$c7-=yoA6^dG+Uk^QN hEjX;OV#k6GdE?J!s@uX>g#vA0@O1TaS?83{1ONg@Ml}Ec literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/OCCViewer/res/tool_material.png b/src/WBCLFZSystemModule/OCCViewer/res/tool_material.png new file mode 100644 index 0000000000000000000000000000000000000000..f846a56371c43ec6a49f0414e444a52372e66929 GIT binary patch literal 293 zcmeAS@N?(olHy`uVBq!ia0vp^0zk~q!3HGX7W?Z1DVB6cUq=RpjeRx011AId3dtTp zz6=aistgPb%?u1b{{!h43=E|P3=FRl7#OUkGcbtfPhUCn3Q+9^PZ!6KiaAMt{{OdU zR%K9Vi1^@b{K(+1y>bt$fI|fjL#CU?5mj~p2cIR`Z95qrSv4>mN@O@AaA+Mfhk}p3 z0h8+g!#M{MIXtvO*c2Kzv@_liSmDG3GUq_o$D2+E1c2&=*^V$aFeEkp5WktWqPyb@ zlLJE{KXZh_qb_!pW=1BC%MJfKERM|-`=@+}SE1oU3u7TCr$R%4M8g}d9EOP#7??Qx i;|`>A94cjCWMk;*Fw)(Yz}5+LJA7wL~P(RGc!vv-MVkzJi%BVg$4-+J%?kwyu2@*3V0?ui?VPiEHZs;#G=qJ!(i_H zhRgeJJYitsQ095{TDm~0$(K)|VFR0zhvG({Q3iV)v=}%Px_EIBlZ_l043kdxE=f^q cU|?oAQNC34y-L7&ptBe}UHx3vIVCg!0Cd_&#sB~S literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/OCCViewer/res/tool_transparency.png b/src/WBCLFZSystemModule/OCCViewer/res/tool_transparency.png new file mode 100644 index 0000000000000000000000000000000000000000..786803a5cf0deba83f1107153186a098c9eab7cc GIT binary patch literal 318 zcmeAS@N?(olHy`uVBq!ia0vp^0zk~q!3HGX7W?Z1DVB6cUq=RpjeRx011AId3dtTp zz6=aistgPb%?u1b{{!h43=E|P3=FRl7#OUkGcbtfPhUCn3Q+AyPZ!6KiaAMt{{OdU zR%K9Vh}ghsW@eUTx^>^ad4jP#3JnqtdJe~Ud3giWIvkcN7Oi;2$kdT>)*$so8v~1g z@UqX+4JyhPxc^ID%7wL~P(Teq`{~UU?UX14E)A!xG70MLo*~h9spp<1?%))-iJ^sQI|=n8UxF!Ied! zVM7JuWw8*;5Mc%;4tIq|pV_n+I23f^6nGg}1dg)72~JLhh7+D18cGa|El0UogoV0* trW+;(I%p^^oWUUA@I*yLgh3#Iq3NTFdbspE4WP>yJYD@<);T3K0RX6BL^A*Y literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/OCCViewer/res/view_axo.png b/src/WBCLFZSystemModule/OCCViewer/res/view_axo.png new file mode 100644 index 0000000000000000000000000000000000000000..4801ab45921b9e94e59e7d21f649cd9fddce3187 GIT binary patch literal 392 zcmeAS@N?(olHy`uVBq!ia0vp^A|TAc1|)ksWqE-VOS+@4BLl<6zM9{GlYxANWRD>fq_xj)5S5QVouVZ|Nrfo zO&J{+3yVfB}5L~FmRsu zG=V{(p+Kr5Pr~RxI#4F@tI@`Xt-K5@0_O}^Zg%OPDfkIg@S#m{*L8^nnPTw;K$%I6 z3cfc)6{TBp1kD%(9DFzqPso&*Ex6?K|9Xw~#*P?P0fzwQM6*S=cuX1@a|F&T3@}r6 zQ4G7x$iz{;$$k6pkaB59_eSi+7sPC=(S1m`g@wmft4IC7wgD_-S6S7rl4 zl8f%X4NEOOs#+v{G?p(-?sK#ov=Pl)S*0|);9XJ`O&|Nn1j z0MS=oah(NHj3q&S!3+-1Zlr-YN#5=*tUvN!9tU#7N?apKg7ec#$`gxH8PYS;j0*D7 z6^!%@^bBp|_GJK7gn7C+hE&W6?YYR?;K1RmeVws@Ic1XZ&cErC7-<7ih3=n&$O8-AbydZPvd1h4VK1=GLcmtkzf;be3Jl Wo1>Y@*B}>Y1B0ilpUXO@geCy{=uV9Q literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/OCCViewer/res/view_bottom.png b/src/WBCLFZSystemModule/OCCViewer/res/view_bottom.png new file mode 100644 index 0000000000000000000000000000000000000000..c7cfdc208aa04cd5f0109df2d262083e1b71de62 GIT binary patch literal 233 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!7%)r1n>(-?sK#ov=Pl)S*0|);9XJ`O&|Nn1j z0MS=oah(NHj3q&S!3+-1Zlr-YN#5=*tUvN!9tU#7N?apKg7ec#$`gxH8PYS;j0*D7 z6^!%@^bBp|_GJK7gn7C+hE&Xn?QP_22;gv;|CC|t!Q-4Vj)(rHd+Bmmx%k`qi+IeD z-PX$H6H&Nc^d3{mM+M_uz3yL^dS~TaGn&aPA8*1PC>Le_LomDNXXT9>-6wu$yyBJO WlFzshE?T;J_^FaAHf7qhq6^A*XP{?j8@De5 zs6yA%#WAE}PI7_+Gj~Hk-$7Om#{+!_dmA}TmWih@O1TaS?83{1OT?)Gj{+0 literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/OCCViewer/res/view_fitall.png b/src/WBCLFZSystemModule/OCCViewer/res/view_fitall.png new file mode 100644 index 0000000000000000000000000000000000000000..21d2f423ef4acbf4380ff497084e7fb206037100 GIT binary patch literal 231 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!7%)r1n>(-?sKn{O^Pl)S*0|y!!82HV0oYtJyeg`d=T#E!A>Kj7jX5<^IG- zWuF9VJ&8BQ4WU+a-=k0smdMUac*xWgB?+c&Q#}%=uzu8aq Wv#}d9=CuH=VDNPHb6Mw<&;$Ud^G!kk literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/OCCViewer/res/view_front.png b/src/WBCLFZSystemModule/OCCViewer/res/view_front.png new file mode 100644 index 0000000000000000000000000000000000000000..a9e99c59b697ddef7e013bb5c5957b9a6c45be01 GIT binary patch literal 238 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!7%)r1n>(-?sK#ov=Pl)S*0|);9XJ`O&|Nn1j z0MS=oah(NHj3q&S!3+-1Zlr-YN#5=*tUvN!9tU#7N?apKg7ec#$`gxH8PYS;j0*D7 z6^!%@^bBp|_GJK7M0>h8hE&Y)?Y+p`V8G#W{uX0^xI;;UT4_UF$^V%)8`Sn5cq+Jq zp@l1~sw^j`_to4Oq35mB&KQVrKY8Z9pY!dPr+HnTJ1Z0(rJdsMJpbXK8uODC*PR9K c-3$J~n&8hKB9R!|3bcm7)78&qol`;+0Em)S00000 literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/OCCViewer/res/view_left.png b/src/WBCLFZSystemModule/OCCViewer/res/view_left.png new file mode 100644 index 0000000000000000000000000000000000000000..7d25b6ab2f8b8f778ac779da4db96d5a8d9f5756 GIT binary patch literal 231 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!7%)r1n>(-?sK#ov=Pl)S*0|);9XJ`O&|Nn1j z0MS=oah(NHj3q&S!3+-1Zlr-YN#5=*tUvN!9tU#7N?apKg7ec#$`gxH8PYS;j0*D7 z6^!%@^bBp|_GJK7gm}6*hE&W6?P=s}FyLW1e}U1fkipS>1+&PRf5tyE1->er|LiHZ z;y{;Yx0;W4{yUvx9tUeDi0HN)&s`XLvSi!D`1rIJ6XmlyZmoKff1`T;x$oZ|vZ?K7 V-?`&Y+ialu44$rjF6*2UngIO(RG`Pkan1T+sEd~k@tDPaMF snn^>8P{+}&O^zxI9?hI#>?@QQ)XuT#9Aufl8)zDXr>mdKI;Vst02TW;XaE2J literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/OCCViewer/res/view_right.png b/src/WBCLFZSystemModule/OCCViewer/res/view_right.png new file mode 100644 index 0000000000000000000000000000000000000000..5540220cfa7e1f7a8b5258efe3bef0d1a70b2263 GIT binary patch literal 230 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!7%)r1n>(-?sK#ov=Pl)S*0|);9XJ`O&|Nn1j z0MS=oah(NHj3q&S!3+-1Zlr-YN#5=*tUvN!9tU#7N?apKg7ec#$`gxH8PYS;j0*D7 z6^!%@^bBp|_GJK71bezThE&Y)^>yTGFyP^y&A-8Z#Xbj#d#<1Vo3GuNEOkrZQVY`# z29aKu1Fr5mFF&zOeB9T{BDbmdKI;Vst0DV4DIRF3v literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/OCCViewer/res/view_top.png b/src/WBCLFZSystemModule/OCCViewer/res/view_top.png new file mode 100644 index 0000000000000000000000000000000000000000..b788de36fb11bef11761670ac5ceda6892d5e7d0 GIT binary patch literal 235 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!7%)r1n>(-?sK#ov=Pl)S*0|);9XJ`O&|Nn1j z0MS=oah(NHj3q&S!3+-1Zlr-YN#5=*tUvN!9tU#7N?apKg7ec#$`gxH8PYS;j0*D7 z6^!%@^bBp|_GJK7M0mP5hE&YS^*tzfz<}e>3kF}c6PAweHZ}CWvk$(wZ2u<#Kaqw* zO=d5SIXXNJJ!_lGEFv=@=395$hf}p|ocC{7PrbT)j?VkVM$aAz>n2M+iq9xBK9$$> ahr!_{$FWT{v)h1nFnGH9xvX +#include + + +OcctExportClass::OcctExportClass(QWidget *parent) + : QDialog(parent) +{ + ui.setupUi(this); + QObject::connect(this->ui.pushButton_saveFile, SIGNAL(pressed()), this, SLOT(SaveButonClick())); + QObject::connect(this->ui.pushButton_export, SIGNAL(pressed()), this, SLOT(ExportButonClick())); + + + ui.comboBox->clear(); + ui.comboBox->addItems(getOCCTShapeTypeEmnu()); + ui.comboBox->setCurrentIndex(0); + + + ui.label_text->setText(u8""); +} + +OcctExportClass::~OcctExportClass() +{} + +void OcctExportClass::setDataShape(const TopoDS_Shape & data) +{ + this->Datashape = data; +} + + +void OcctExportClass::ExportButonClick() { + + this->Filepath = this->ui.lineEdit->text(); + // ¿ªÊ¼±£´æÄ£ÐͶÔÏó + QString comboxStr = ui.comboBox->itemText(ui.comboBox->currentIndex()); + OCCTShapeType type = str2OCCTShapeType(comboxStr); + ui.label_text->setText(u8"Êý¾ÝÕýÔÚµ¼³öÖÐ........"); + SaveTopoDs(this->Filepath, this->Datashape, type); + QMessageBox::information(this, "info", u8"Êý¾Ýµ¼³ö³É¹¦£¡£¡£¡"); + this->close(); +} + +void OcctExportClass::SaveButonClick() { + qDebug() << u8"Ñ¡Ôñµ¼³ö·¾¶"; + QString filterStr; + QString comboxStr = ui.comboBox->itemText(ui.comboBox->currentIndex()); + OCCTShapeType type = str2OCCTShapeType(comboxStr); + filterStr = getOCCTShapeTypeFilterString(type); + QString savePath = getSaveFilePath( + nullptr,QString::fromUtf8(u8"µ¼³ö·¾¶") ,filterStr); + this->Filepath = savePath; + this->ui.lineEdit->setText(this->Filepath); +} + +DialogBatchExport::DialogBatchExport(QWidget* parent) +{ + ui.setupUi(this); + QObject::connect(this->ui.pushButton_saveFile, SIGNAL(pressed()), this, SLOT(SaveButonClick())); + QObject::connect(this->ui.pushButton_export, SIGNAL(pressed()), this, SLOT(ExportButonClick())); + + ui.radioButton_Merged->setChecked(false); + ui.comboBox->clear(); + ui.comboBox->addItems(getOCCTShapeTypeEmnu()); + ui.comboBox->setCurrentIndex(0); + + ui.label_text->setText(u8""); + this->Datashapelist= QMap(); + this->Datashapelist.clear(); + +} + +DialogBatchExport::~DialogBatchExport() +{ +} + +void DialogBatchExport::addDataShape(QString name, const TopoDS_Shape& data) +{ + this->Datashapelist.insert(name, data); +} + +TopoDS_Shape DialogBatchExport::getMerged() +{ + std::vector< TopoDS_Shape> dsList; + + // ʹÓõü´úÆ÷±éÀú QMap ÖеÄÔªËØ + QMap::const_iterator it; + for (it = this->Datashapelist.constBegin(); it != this->Datashapelist.constEnd(); ++it) { + QString key = it.key(); + TopoDS_Shape value = it.value(); + dsList.push_back(value); + } + return MergedTopoShape(dsList); +} + +void DialogBatchExport::ExportButonClick() { + // ·ÖÅú + QString comboxStr = ui.comboBox->itemText(ui.comboBox->currentIndex()); + OCCTShapeType type = str2OCCTShapeType(comboxStr); + ui.label_text->setText(u8"Êý¾ÝÕýÔÚµ¼³öÖÐ........"); + + this->Filepath = this->ui.lineEdit->text(); + if (this->Filepath.isEmpty()) { + QMessageBox::warning(this, "warning", u8"ûÓÐÑ¡ÖÐÎļþ¼Ð"); + return; + } + else { + if (this->ui.radioButton_Split->isChecked()) { // ·ÖÅúµ¼³öÎļþ + // ʹÓõü´úÆ÷±éÀú QMap ÖеÄÔªËØ + QMap::const_iterator it; + for (it = this->Datashapelist.constBegin(); it != this->Datashapelist.constEnd(); ++it) { + QString key = it.key(); + TopoDS_Shape value = it.value(); + QMessageBox::information(this, "info", u8"Êý¾Ýµ¼³ö³É¹¦£¡£¡£¡"); + QString saveResultPath= QDir::cleanPath(this->Filepath +"\\" + key); + SaveTopoDs(saveResultPath, value, type); + } + } + else { + TopoDS_Shape Ds = this->getMerged(); + SaveTopoDs(this->Filepath, Ds, type); + } + } +} + +void DialogBatchExport::SaveButonClick() +{ + + qDebug() << u8"Ñ¡Ôñµ¼³ö·¾¶"; + if (this->ui.radioButton_Split->isChecked()) { // ·ÖÅúµ¼³öÎļþ + // µ¯³öÑ¡ÔñÎļþ¼ÐµÄ¶Ô»°¿ò + QString selectedDirectory = QFileDialog::getExistingDirectory(nullptr, + "Ñ¡ÔñÎļþ¼Ð", + ".", + QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks); + + // Óû§µã»÷ÁËÑ¡ÔñÎļþ¼Ð°´Å¥ + if (!selectedDirectory.isEmpty()) { + qDebug() << "Îļþ¼Ð·¾¶ÊÇ£º" << selectedDirectory; + + this->Filepath = selectedDirectory; + } + else { + QMessageBox::warning(this, "warning", u8"ûÓÐÑ¡ÖÐÎļþ¼Ð"); + qDebug() << "È¡ÏûÎļþ¼Ð²Ù×÷¡£"; + this->Filepath.clear(); + return; + } + + } + else { // Ñ¡ÔñºÏ²¢Îļþ + QString filterStr; + QString comboxStr = ui.comboBox->itemText(ui.comboBox->currentIndex()); + OCCTShapeType type = str2OCCTShapeType(comboxStr); + filterStr = getOCCTShapeTypeFilterString(type); + QString savePath = getSaveFilePath( + nullptr, QString::fromUtf8(u8"ºÏ²¢Ä£Ð͵¼³ö·¾¶"), filterStr); + + // Óû§µã»÷ÁËÑ¡ÔñÎļþ¼Ð°´Å¥ + if (!savePath.isEmpty()) { + qDebug() << "Îļþ¼Ð·¾¶ÊÇ£º" << savePath; + this->Filepath = savePath; + } + else { + QMessageBox::warning(this, "warning", u8"ûÓÐÑ¡ÖÐÎļþ¼Ð"); + qDebug() << "È¡ÏûÎļþ¼Ð²Ù×÷¡£"; + this->Filepath.clear(); + return; + } + + this->Filepath = savePath; + this->ui.lineEdit->setText(this->Filepath); + + } + +} diff --git a/src/WBCLFZSystemModule/OcctExportClass.h b/src/WBCLFZSystemModule/OcctExportClass.h new file mode 100644 index 0000000..eb30e8f --- /dev/null +++ b/src/WBCLFZSystemModule/OcctExportClass.h @@ -0,0 +1,55 @@ +#pragma once +#ifndef OCCT_EXPORTCLASS_H +#define OCCT_EXPORTCLASS_H +#include "AllHead.h" +#include +#include "ui_DialogBatchExport.h" +#include "ui_OcctExportClass.h" +#include "OCCTBaseOperaorClass.h" +#include + + + +class OcctExportClass : public QDialog +{ + Q_OBJECT + +public: + OcctExportClass(QWidget *parent = nullptr); + ~OcctExportClass(); + void setDataShape(const TopoDS_Shape& data); +private: + TopoDS_Shape Datashape; + QString Filepath; +private: + Ui::OcctExportClassClass ui; + +public slots: + void ExportButonClick(); + void SaveButonClick(); +}; + + + + +class DialogBatchExport : public QDialog +{ + Q_OBJECT + +public: + DialogBatchExport(QWidget* parent = nullptr); + ~DialogBatchExport(); + void addDataShape(QString name,const TopoDS_Shape& data); + TopoDS_Shape getMerged(); +private: + QMap Datashapelist; + QString Filepath; +private: + Ui::DialogBatchExport ui; + +public slots: + void ExportButonClick(); + void SaveButonClick(); +}; + +#endif \ No newline at end of file diff --git a/src/WBCLFZSystemModule/OcctExportClass.ui b/src/WBCLFZSystemModule/OcctExportClass.ui new file mode 100644 index 0000000..1a4183e --- /dev/null +++ b/src/WBCLFZSystemModule/OcctExportClass.ui @@ -0,0 +1,161 @@ + + + OcctExportClassClass + + + + 0 + 0 + 532 + 120 + + + + + 0 + 120 + + + + + 16777215 + 120 + + + + 导出 + + + + + + + 60 + 30 + + + + + 60 + 30 + + + + 导出路径 + + + + + + + + 0 + 30 + + + + + 16777215 + 30 + + + + + + + + + 60 + 30 + + + + + 60 + 30 + + + + å¯¼å‡ºæ ¼å¼ + + + + + + + + 60 + 30 + + + + + 60 + 30 + + + + 导出 + + + + + + + + 0 + 30 + + + + + 16777215 + 30 + + + + + + + + + 60 + 30 + + + + + 60 + 30 + + + + 选择文件 + + + + + + + + 0 + 30 + + + + + 16777215 + 30 + + + + TextLabel + + + + + + + + + diff --git a/src/WBCLFZSystemModule/PointCloudProcess/BasePCL.cpp b/src/WBCLFZSystemModule/PointCloudProcess/BasePCL.cpp new file mode 100644 index 0000000..53fcfa9 --- /dev/null +++ b/src/WBCLFZSystemModule/PointCloudProcess/BasePCL.cpp @@ -0,0 +1,120 @@ +#include "BasePCL.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include // TicToc +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include //Ëæ»úÊý +#include +#include +#include // TicToc +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include // 4PCSËã·¨ +#include //K4PCSË㷨ͷÎļþ +#include +#include +#include +#include +#include //̰À·Í¶Ó°Èý½Ç»¯Ëã·¨ÀඨÒåµÄÍ·Îļþ +#include //ÒÆ¶¯Á¢·½Ìå +#include +#include //MLS +#include //²´ËÉÖØ½¨ +#include +#include +#include +#include +#include + +#include // TicToc +#include // ÌåËØÂ˲¨ +#include // ÌåËØÂ˲¨ +#include + +#include +#include +#include +#include +#include +#include //Ëæ»ú²ÎÊý¹À¼Æ·½·¨ +#include //Ä£ÐͶ¨Òå +#include //RANSAC·Ö¸î +#include +#include +#include //rand()Í·Îļþ +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +//¿ÉÊÓ»¯Ïà¹ØÍ·Îļþ +#include +#include +#include +#include +#include +#include +#include +#include +// Boost +#include + +// Visualization Toolkit (VTK) +#include +#include +#include +#include +#include + + diff --git a/src/WBCLFZSystemModule/PointCloudProcess/BasePCL.h b/src/WBCLFZSystemModule/PointCloudProcess/BasePCL.h new file mode 100644 index 0000000..06493cc --- /dev/null +++ b/src/WBCLFZSystemModule/PointCloudProcess/BasePCL.h @@ -0,0 +1,127 @@ +#pragma once + +// PCL »ù´¡²Ù×÷ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +//#include +#include +#include +#include +#include // TicToc +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include //Ëæ»úÊý +#include +#include +#include // TicToc +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include // 4PCSËã·¨ +#include //K4PCSË㷨ͷÎļþ +#include +#include +#include +#include +#include //̰À·Í¶Ó°Èý½Ç»¯Ëã·¨ÀඨÒåµÄÍ·Îļþ +#include //ÒÆ¶¯Á¢·½Ìå +#include +#include //MLS +#include //²´ËÉÖØ½¨ +#include +#include +#include +#include +#include + +#include // TicToc +#include // ÌåËØÂ˲¨ +#include // ÌåËØÂ˲¨ +#include + +#include +#include +#include +#include +#include +#include //Ëæ»ú²ÎÊý¹À¼Æ·½·¨ +#include //Ä£ÐͶ¨Òå +#include //RANSAC·Ö¸î +#include +#include +#include //rand()Í·Îļþ +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +//¿ÉÊÓ»¯Ïà¹ØÍ·Îļþ +#include +#include +#include +#include +#include +#include +#include +#include +// Boost +#include + +// Visualization Toolkit (VTK) +#include +//ʹÓõĵãÔÆ¸ñʽ + + + + + + + + diff --git a/src/WBCLFZSystemModule/PointCloudProcess/BilateralFilterWindows.ui b/src/WBCLFZSystemModule/PointCloudProcess/BilateralFilterWindows.ui new file mode 100644 index 0000000..3eeb717 --- /dev/null +++ b/src/WBCLFZSystemModule/PointCloudProcess/BilateralFilterWindows.ui @@ -0,0 +1,243 @@ + + + BilateralFilterWindowsDialog + + + + 0 + 0 + 546 + 177 + + + + Dialog + + + + + + + + + 0 + 25 + + + + + 16777215 + 25 + + + + + + + + Qt::RightToLeft + + + 标准差: + + + + + + + + 0 + 25 + + + + + 16777215 + 25 + + + + 2.5 + + + + + + + + 0 + 25 + + + + + 16777215 + 25 + + + + + + + + + 0 + 25 + + + + + 16777215 + 25 + + + + 5 + + + + + + + + 16777215 + 30 + + + + Qt::RightToLeft + + + 滤波窗å£çš„åŠå°ºå¯¸: + + + + + + + Qt::RightToLeft + + + ä¿å­˜è·¯å¾„: + + + + + + + 点云: + + + + + + + 选择路径 + + + + + + + + + 6 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Qt::Horizontal + + + + 131 + 31 + + + + + + + + OK + + + + + + + Cancel + + + + + + + + + + + okButton + clicked() + BilateralFilterWindowsDialog + accept() + + + 454 + 162 + + + 96 + 254 + + + + + cancelButton + clicked() + BilateralFilterWindowsDialog + reject() + + + 535 + 162 + + + 179 + 282 + + + + + FileOpenpushButton + clicked() + BilateralFilterWindowsDialog + pushFileButton() + + + 498 + 53 + + + 272 + 88 + + + + + + pushFileButton() + + diff --git a/src/WBCLFZSystemModule/PointCloudProcess/DialogTriangulationSurfaceMesh.ui b/src/WBCLFZSystemModule/PointCloudProcess/DialogTriangulationSurfaceMesh.ui new file mode 100644 index 0000000..5d9473e --- /dev/null +++ b/src/WBCLFZSystemModule/PointCloudProcess/DialogTriangulationSurfaceMesh.ui @@ -0,0 +1,386 @@ + + + DialogTriangulationSurfaceMeshDialog + + + + 0 + 0 + 546 + 300 + + + + + 500 + 300 + + + + 贪婪投影三角化算法 + + + + + + + + + 0 + 25 + + + + + 16777215 + 25 + + + + 120 + + + + + + + 点云: + + + + + + + + 0 + 25 + + + + + 16777215 + 25 + + + + 2.5 + + + + + + + Qt::RightToLeft + + + 三角形内角的最大角度: + + + + + + + + 0 + 25 + + + + + 16777215 + 25 + + + + 1 + + + + + + + + 0 + 25 + + + + + 16777215 + 25 + + + + + + + + + 16777215 + 30 + + + + Qt::RightToLeft + + + 坿œç´¢çš„邻域个数: + + + + + + + Qt::RightToLeft + + + ä¿å­˜è·¯å¾„: + + + + + + + Qt::RightToLeft + + + 三角形的最大边长: + + + + + + + + 0 + 25 + + + + + 16777215 + 25 + + + + 10 + + + + + + + + 0 + 25 + + + + + 16777215 + 25 + + + + 100 + + + + + + + + 0 + 25 + + + + + 16777215 + 25 + + + + + + + + Qt::RightToLeft + + + 临近点的最远è·ç¦»: + + + + + + + + 0 + 25 + + + + + 16777214 + 25 + + + + 选择路径 + + + + + + + Qt::RightToLeft + + + 三角形内角的最å°è§’度: + + + + + + + è¡¨é¢æ³•å¼ä¸Žç‚¹æ³•矢夹角最大: + + + + + + + + 0 + 25 + + + + + 16777215 + 25 + + + + 3600 + + + + + + + + + 6 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Qt::Horizontal + + + + 131 + 23 + + + + + + + + + 16777215 + 23 + + + + OK + + + + + + + + 16777215 + 23 + + + + Cancel + + + + + + + + + + + okButton + clicked() + DialogTriangulationSurfaceMeshDialog + accept() + + + 278 + 253 + + + 96 + 254 + + + + + cancelButton + clicked() + DialogTriangulationSurfaceMeshDialog + reject() + + + 369 + 253 + + + 179 + 282 + + + + + FileOpenpushButton + clicked() + DialogTriangulationSurfaceMeshDialog + pushFileButton() + + + 498 + 53 + + + 272 + 88 + + + + + + pushFileButton() + + diff --git a/src/WBCLFZSystemModule/PointCloudProcess/MedianFilterWindows.ui b/src/WBCLFZSystemModule/PointCloudProcess/MedianFilterWindows.ui new file mode 100644 index 0000000..bf280f9 --- /dev/null +++ b/src/WBCLFZSystemModule/PointCloudProcess/MedianFilterWindows.ui @@ -0,0 +1,217 @@ + + + MedianFilterWindowsDialog + + + + 0 + 0 + 565 + 146 + + + + Dialog + + + + + + + + + 0 + 25 + + + + + 16777215 + 25 + + + + + + + + + 16777215 + 30 + + + + Qt::RightToLeft + + + æœç´¢çª—å£å¤§å°: + + + Qt::PlainText + + + + + + + 选择路径 + + + + + + + + 0 + 25 + + + + + 16777215 + 25 + + + + 5 + + + + + + + + 0 + 25 + + + + + 16777215 + 25 + + + + + + + + 点云: + + + + + + + Qt::RightToLeft + + + ä¿å­˜è·¯å¾„: + + + + + + + + + 6 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Qt::Horizontal + + + + 131 + 31 + + + + + + + + OK + + + + + + + Cancel + + + + + + + + + + + okButton + clicked() + MedianFilterWindowsDialog + accept() + + + 278 + 253 + + + 96 + 254 + + + + + cancelButton + clicked() + MedianFilterWindowsDialog + reject() + + + 369 + 253 + + + 179 + 282 + + + + + FileOpenpushButton + clicked() + MedianFilterWindowsDialog + pushFileButton() + + + 498 + 53 + + + 272 + 88 + + + + + + pushFileButton() + + diff --git a/src/WBCLFZSystemModule/PointCloudProcess/PointCloudAlg.cpp b/src/WBCLFZSystemModule/PointCloudProcess/PointCloudAlg.cpp new file mode 100644 index 0000000..45209cc --- /dev/null +++ b/src/WBCLFZSystemModule/PointCloudProcess/PointCloudAlg.cpp @@ -0,0 +1,486 @@ +#include "PointCloudAlg.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include //Ìí¼ÓQDateTimeÍ·Îļþ +#include +#include +#include +#include + +// Point Cloud Library +#include +#include +#include +#include // TicToc +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include //Ëæ»úÊý +#include +#include +#include // TicToc +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include // 4PCSËã·¨ +#include //K4PCSË㷨ͷÎļþ +#include +#include +#include +#include +#include //̰À·Í¶Ó°Èý½Ç»¯Ëã·¨ÀඨÒåµÄÍ·Îļþ +#include //ÒÆ¶¯Á¢·½Ìå +#include +#include //MLS +#include //²´ËÉÖØ½¨ +#include +#include +#include +#include +#include + +#include // TicToc +#include // ÌåËØÂ˲¨ +#include // ÌåËØÂ˲¨ +#include + +#include +#include +#include +#include +#include +#include //Ëæ»ú²ÎÊý¹À¼Æ·½·¨ +#include //Ä£ÐͶ¨Òå +#include //RANSAC·Ö¸î +#include +#include +#include //rand()Í·Îļþ +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +//¿ÉÊÓ»¯Ïà¹ØÍ·Îļþ +#include +#include +#include +#include +#include +#include +#include +#include +// Boost +#include + +// Visualization Toolkit (VTK) +#include +#include "BasePCL.h" +// +// +//// ¹¹½¨ +void NormalEstimation(pcl::PointCloud::Ptr cloud, pcl::PointCloud::Ptr cloud_with_normals) +{ + //----------------·¨Ïß¹À¼Æ------------------------- + pcl::PointCloud::Ptr cloud_in(new pcl::PointCloud); + + pcl::copyPointCloud(*cloud, *cloud_in); + + pcl::NormalEstimation n; + pcl::PointCloud::Ptr normals(new pcl::PointCloud); + pcl::search::KdTree::Ptr tree(new pcl::search::KdTree); + tree->setInputCloud(cloud_in); + n.setInputCloud(cloud_in); + n.setSearchMethod(tree); + n.setKSearch(10); + n.compute(*normals); + pcl::concatenateFields(*cloud_in, *normals, *cloud_with_normals); +} +// +///* +// ϲÉÑù +//*/ +void downSampling(pcl::PointCloud::Ptr cloud, + pcl::PointCloud::Ptr cloud_filtered, + double leafSize ) +{ + pcl::VoxelGrid vg; + vg.setInputCloud(cloud); + vg.setLeafSize(leafSize, leafSize, leafSize); + vg.filter(*cloud_filtered); + int downsampled_points_total_size = cloud_filtered->points.size(); + // show_point_cloud(cloud_filtered, "down sampled point cloud"); + qDebug() << "PointCloud after filtering has: " + << downsampled_points_total_size << " data points." << "\n"; +}; + +/* + Ìí¼Ó¸ß˹ÔëÉù +*/ +void GenerateGaussNoise(pcl::PointCloud::Ptr& cloud, + pcl::PointCloud::Ptr& noise_cloud, + double miu , + double sigma ) +{ + noise_cloud->points.resize( + cloud->points.size()); //½«µãÔÆcloudµÄsize¸³Öµ¸øÔëÉù + noise_cloud->header = cloud->header; + noise_cloud->width = cloud->width; + noise_cloud->height = cloud->height; + boost::mt19937 my_seed; // Ëæ»úÊýÉú³É + my_seed.seed(static_cast(time(0))); + boost::normal_distribution<> nd( + miu, sigma); // ´´½¨Ò»¸öÓÐÌØ¶¨ÆÚÍûÖµºÍ±ê×¼²îµÄÕý̬·Ö²¼£º + boost::variate_generator> ok( + my_seed, nd); + for (size_t i = 0; i < cloud->size(); ++i) { + noise_cloud->points[i].x = cloud->points[i].x + static_cast(ok()); + noise_cloud->points[i].y = cloud->points[i].y + static_cast(ok()); + noise_cloud->points[i].z = cloud->points[i].z + static_cast(ok()); + } +}; + +/* + ¸ß˹Â˲¨ +*/ + +void gaussian_filter(pcl::PointCloud::Ptr cloud, + pcl::PointCloud::Ptr cloud_filtered, + double radius) +{ + /*double radius = 0.02;*/ + // Set up the Gaussian Kernel + pcl::filters::GaussianKernel::Ptr kernel( + new pcl::filters::GaussianKernel); + (*kernel).setSigma(4); + (*kernel).setThresholdRelativeToSigma(4); + qDebug() << "Kernel made" << "\n"; + + // Set up the KDTree + pcl::search::KdTree::Ptr kdtree( + new pcl::search::KdTree); + (*kdtree).setInputCloud(cloud); + qDebug() << "KdTree made" << "\n"; + + // Set up the Convolution Filter + pcl::filters::Convolution3D< + pcl::PointXYZRGBA, + pcl::PointXYZRGBA, + pcl::filters::GaussianKernel> + convolution; + convolution.setKernel(*kernel); + convolution.setInputCloud(cloud); + convolution.setSearchMethod(kdtree); + convolution.setRadiusSearch(radius); + convolution.setNumberOfThreads( + 10); // important! Set Thread number for openMP + qDebug() << "Convolution Start" << "\n"; + convolution.convolve(*cloud_filtered); + qDebug() << "Convoluted" << "\n"; +}; + +void bilateralFilter(pcl::PointCloud::Ptr input, + pcl::PointCloud::Ptr output, + float sigma_s, + float sigma_r) +{ + + pcl::KdTreeFLANN::Ptr tree( + new pcl::KdTreeFLANN); + + // Apply the filter + pcl::FastBilateralFilter fbf; + fbf.setInputCloud(input); + fbf.setSigmaS(sigma_s); + fbf.setSigmaR(sigma_r); + fbf.filter(*output); +}; +/* + °ë¾¶Â˲¨Æ÷: + »ùÓÚÃܶȵÄÔÓÉ¢µãÒÆ³ý +*/ +void radius_filter(pcl::PointCloud::Ptr cloud, + pcl::PointCloud::Ptr cloud_filtered, + pcl::PointCloud::Ptr cloud_filtered_out, + double RadiusSearch , + int minNearSearch ) +{ + pcl::RadiusOutlierRemoval sor; + sor.setInputCloud(cloud); + sor.setRadiusSearch(RadiusSearch); //ÉèÖð뾶Ϊ0.04mµÄ·¶Î§ÄÚÕÒÁÙ½üµã + sor.setMinNeighborsInRadius(minNearSearch); //ÉèÖòéѯµãµÄÁÚÓòµã¼¯ÊýСÓÚ2µÄɾ³ý + sor.filter(*cloud_filtered); // + sor.setNegative(true); //ÒÔ»ñÈ¡ÀëȺµãÊý¾Ý(Ò²¾ÍÊÇÔ­±¾Â˳ýµôµÄµã) + + sor.filter(*cloud_filtered_out); +}; +/* + ͳ¼ÆÂ˲¨Æ÷: + »ùÓÚͳ¼ÆµÄÔÓÉ¢µãÒÆ³ý +*/ +void statistical_filter( + pcl::PointCloud::Ptr cloud, + pcl::PointCloud::Ptr cloud_filtered, + pcl::PointCloud::Ptr cloud_filtered_out, + int meanK , + double StddevThresh) +{ + // ´´½¨Â˲¨Æ÷¶ÔÏó + pcl::StatisticalOutlierRemoval sor; + sor.setInputCloud(cloud); //ÉèÖôýÂ˲¨µÄµãÔÆ + sor.setMeanK(meanK); //ÉèÖÃÔÚ½øÐÐͳ¼ÆÊ±¿¼ÂDzéѯµãÁÚ¾ÓµãÊý£¬K¸ö×î½üÁÚµã + sor.setStddevMulThresh(StddevThresh); //ÉèÖÃÅжÏÊÇ·ñΪÀëȺµãµÄãÐÖµ + sor.filter(*cloud_filtered); //½«Â˲¨½á¹û±£´æÔÚcloud_filteredÖÐ + sor.setNegative(true); //ÒÔ»ñÈ¡ÀëȺµãÊý¾Ý(Ò²¾ÍÊÇÔ­±¾Â˳ýµôµÄµã) + sor.filter(*cloud_filtered_out); + // writer.write("table_scene_lms400_outliers.pcd", + // *cloud_filtered, false); +}; + + +// +///************************************************************************/ +///* ±íÃæÖØ½¨ */ +///************************************************************************/ +// +//void MLS(pcl::PointCloud::Ptr cloud_in, +// pcl::PointCloud::Ptr cloud_with_normals) +//{ +// qDebug() << "MLS alg module:" << cloud_in->points.size(); +// +// pcl::search::KdTree::Ptr tree(new pcl::search::KdTree); // ´´½¨Ò»¸öKDÊ÷ +// // Êä³öÎļþÖÐÓÐPointNormalÀàÐÍ£¬ÓÃÀ´´æ´¢Òƶ¯×îС¶þ³Ë·¨Ëã³öµÄ·¨Ïß +// // pcl::PointCloud mls_points; +// // ¶¨Òå¶ÔÏó (µÚ¶þÖÖ¶¨ÒåÀàÐÍÊÇΪÁË´æ´¢·¨Ïß, ¼´Ê¹Óò»µ½Ò²ÐèÒª¶¨Òå³öÀ´) +// pcl::MovingLeastSquares mls; +// mls.setComputeNormals(true); +// //ÉèÖòÎÊý +// mls.setInputCloud(cloud_in); +// mls.setPolynomialOrder(5); // ÔÚδÉèÖÃÄâºÏ½×Êýʱ£¬Ä¬ÈϽ×ÊýÊÇ2 +// mls.setSearchMethod(tree); +// mls.setSearchRadius(0.005); +// // ÇúÃæÖØ½¨ +// mls.process(*cloud_with_normals); +// qDebug() << "MLS alg module over:" << cloud_with_normals->points.size(); +//}; +//void Pos(pcl::PointCloud::Ptr cloud_with_normals, +// pcl::PolygonMesh& mesh, +// int Degree, +// int Depth, +// int IsoDivide , +// float SamplesPerNode, +// int SolverDivide) +//{ +// //------------²´ËÉÖØ½¨----------------------------- +// pcl::search::KdTree::Ptr tree2( new pcl::search::KdTree); +// tree2->setInputCloud(cloud_with_normals); +// pcl::Poisson pn; +// pn.setConfidence(false); //ÊÇ·ñʹÓ÷¨ÏòÁ¿µÄ´óС×÷ΪÖÃÐÅÐÅÏ¢¡£Èç¹ûfalse£¬ËùÓз¨ÏòÁ¿¾ù¹éÒ»»¯¡£ +// pn.setDegree(Degree); //ÉèÖòÎÊýdegree[1,5],ÖµÔ½´óÔ½¾«Ï¸£¬ºÄʱԽ¾Ã¡£ +// pn.setDepth(Depth); //Ê÷µÄ×î´óÉî¶È£¬Çó½â2^d x 2^d x 2^dÁ¢·½ÌåÔª¡£ +// // ÓÉÓڰ˲æÊ÷×ÔÊÊÓ¦²ÉÑùÃܶȣ¬Ö¸¶¨Öµ½öΪ×î´óÉî¶È¡£ +// +// pn.setIsoDivide(IsoDivide); //ÓÃÓÚÌáÈ¡ISOµÈÖµÃæµÄËã·¨µÄÉî¶È +// pn.setManifold(false); //ÊÇ·ñÌí¼Ó¶à±ßÐεÄÖØÐÄ£¬µ±¶à±ßÐÎÈý½Ç»¯Ê±¡£ +// // ÉèÖÃÁ÷ÐбêÖ¾£¬Èç¹ûÉèÖÃΪtrue£¬Ôò¶Ô¶à±ßÐνøÐÐϸ·ÖÈý½Ç»°Ê±Ìí¼ÓÖØÐÄ£¬ÉèÖÃfalseÔò²»Ìí¼Ó +// pn.setOutputPolygons(false); //ÊÇ·ñÊä³ö¶à±ßÐÎÍø¸ñ£¨¶ø²»ÊÇÈý½Ç»¯Òƶ¯Á¢·½ÌåµÄ½á¹û£© +// pn.setSamplesPerNode(SamplesPerNode); //ÉèÖÃÂäÈëÒ»¸ö°Ë²æÊ÷½áµãÖеÄÑù±¾µãµÄ×îСÊýÁ¿¡£ÎÞÔëÉù£¬[1.0-5.0],ÓÐÔëÉù[15.-20.]ƽ»¬ +// pn.setScale(1); //ÉèÖÃÓÃÓÚÖØ¹¹µÄÁ¢·½ÌåÖ±¾¶ºÍÑù±¾±ß½çÁ¢·½ÌåÖ±¾¶µÄ±ÈÂÊ¡£ +// pn.setSolverDivide(SolverDivide); //ÉèÖÃÇó½âÏßÐÔ·½³Ì×éµÄGauss-Seidelµü´ú·½·¨µÄÉî¶È +// // pn.setIndices(); +// +// //ÉèÖÃËÑË÷·½·¨ºÍÊäÈëµãÔÆ +// pn.setSearchMethod(tree2); +// pn.setInputCloud(cloud_with_normals); +// pn.performReconstruction(mesh); +//}; +//// ̰À·Èý½ÇÍø +void GP(pcl::PointCloud::Ptr cloud_with_normals, + pcl::PolygonMesh& mesh, + double SearchRadius , + double Mu, + int MaximumNearestNeighbors, + double MaximumSurfaceAngle, + double MinimumAngle, + double MaximumAngle) +{ + qDebug() << "[GP ]The number of points :" << cloud_with_normals->points.size(); + //------------------¶¨ÒåËÑË÷Ê÷¶ÔÏó------------------------ + pcl::search::KdTree::Ptr tree2( + new pcl::search::KdTree); + tree2->setInputCloud(cloud_with_normals); + //------------------̰À·Í¶Ó°Èý½Ç»¯------------------ + pcl::GreedyProjectionTriangulation gp3; //¶¨ÒåÈý½Ç»¯¶ÔÏó + + gp3.setSearchRadius(SearchRadius); //ÉèÖÃÁ¬½ÓµãÖ®¼äµÄ×î´ó¾àÀ루¼´Èý½ÇÐεÄ×î´ó±ß³¤£© + gp3.setMu(Mu); //ÉèÖñ»Ñù±¾µãËÑË÷ÆäÁÙ½üµãµÄ×îÔ¶¾àÀ룬ΪÁËÊÊÓ¦µãÔÆÃܶȵı仯 + gp3.setMaximumNearestNeighbors(MaximumNearestNeighbors); //ÉèÖÃÑù±¾µã¿ÉËÑË÷µÄÁÚÓò¸öÊý + gp3.setMaximumSurfaceAngle(MaximumSurfaceAngle); // ÉèÖÃijµã·¨Ïß·½ÏòÆ«ÀëÑù±¾µã·¨Ïß·½ÏòµÄ×î´ó½Ç¶È + gp3.setMinimumAngle(MinimumAngle); // ÉèÖÃÈý½Ç»¯ºóµÃµ½Èý½ÇÐÎÄڽǵÄ×îС½Ç¶È + gp3.setMaximumAngle(MaximumAngle); // ÉèÖÃÈý½Ç»¯ºóµÃµ½Èý½ÇÐÎÄڽǵÄ×î´ó½Ç¶È + gp3.setNormalConsistency(false); //ÉèÖøòÎÊý±£Ö¤·¨Ïß³¯ÏòÒ»Ö + //qDebug() << "[GP] start reconstruct :" << cloud_in->points.size(); + // Get result + gp3.setInputCloud(cloud_with_normals); //ÉèÖÃÊäÈëµãÔÆÎªÓÐÏòµãÔÆ + gp3.setSearchMethod(tree2); //ÉèÖÃËÑË÷·½Ê½ + gp3.reconstruct(mesh); //ÖØ½¨ÌáÈ¡Èý½Ç»¯ + // cout << triangles; + // qDebug() << "[GP ] reconstruct process over :" << cloud_in->points.size(); +}; +// +////ÒÆ¶¯Á¢·½Ìå +//void MC(pcl::PointCloud::Ptr cloud, pcl::PolygonMesh& mesh) +//{ +// ////-------------------·¨Ïß¹À¼Æ---------------------- +// pcl::NormalEstimation n; +// pcl::PointCloud::Ptr normals(new pcl::PointCloud); +// pcl::search::KdTree::Ptr tree( +// new pcl::search::KdTree); +// tree->setInputCloud(cloud); +// n.setInputCloud(cloud); +// n.setSearchMethod(tree); +// n.setKSearch(5); +// n.compute(*normals); +// //----------½«µãÔÆºÍ·¨Ï߷ŵ½Ò»Æð------------------ +// pcl::PointCloud::Ptr cloud_with_normals( +// new pcl::PointCloud); +// pcl::concatenateFields(*cloud, *normals, *cloud_with_normals); +// //---------³õʼ»¯MarchingCubes¶ÔÏ󣬲¢ÉèÖòÎÊý------- +// pcl::MarchingCubes* mc; +// mc = new pcl::MarchingCubesHoppe(); +// // mc = new pcl::MarchingCubesRBF(); +// //´´½¨ËÑË÷Ê÷ +// pcl::search::KdTree::Ptr tree2( +// new pcl::search::KdTree); +// tree2->setInputCloud(cloud_with_normals); +// mc->setInputCloud(cloud_with_normals); +// //ÉèÖÃMarchingCubes¶ÔÏóµÄ²ÎÊý +// mc->setIsoLevel(0.0f); //¸Ã·½·¨ÉèÖÃÒªÌáÈ¡±íÃæµÄiso¼¶±ð +// int resolution = 50; +// mc->setGridResolution( +// resolution, resolution, resolution); //ÓÃÓÚÉèÖÃÐнøÁ¢·½ÌåÍø¸ñ·Ö±æÂÊ +// mc->setPercentageExtendGrid( 0.02); //¸Ã²ÎÊý¶¨ÒåÔÚµãÔÆµÄ±ß¿òºÍÍø¸ñÏÞÖÆÖ®¼äµÄÍø¸ñÄÚÓ¦¸Ã±£Áô¶àÉÙ×ÔÓɿռä +// +// mc->reconstruct(mesh); //Ö´ÐÐÖØ¹¹£¬½á¹û±£´æÔÚmeshÖÐ +//}; +// +///************************************************************************/ +///* µãÔÆÅä×¼Ëã·¨ */ +///************************************************************************/ +// +////// ½ÓÏÂÀ´Ê¹ÓõĵãÔÆÖ¸Õë +////PointCloudT::Ptr cloud_in; // Original point cloud +////PointCloudT::Ptr cloud_tr; // Transformed point cloud +////PointCloudT::Ptr cloud_RE; // ICP output point cloud +//// +//////ʹÓÃÅä×¼»ùÀàRegistrationÀ´ÊµÏÖ¶à̬ +////pcl::Registration::Ptr ALIGN; +////pcl::IterativeClosestPoint::Ptr icp; +//// +//////µü´ú´ÎÊý +////int iterations = 1; // Default number of ICP iterations +////// bool next_iteration = false; +// +///* +// ´òÓ¡4*4µÄ¾ØÕó +//*/ +void print4x4Matrix(const Eigen::Matrix4d& matrix) +{ + printf("\nRotate Matrix :\n"); + printf( + " | %6.3f %6.3f %6.3f | \n", matrix(0, 0), matrix(0, 1), matrix(0, 2)); + printf( + "R = | %6.3f %6.3f %6.3f | \n", matrix(1, 0), matrix(1, 1), matrix(1, 2)); + printf( + " | %6.3f %6.3f %6.3f | \n", matrix(2, 0), matrix(2, 1), matrix(2, 2)); + printf("\nVector :\n"); + printf("t = < %6.3f, %6.3f, %6.3f >\n\n", + matrix(0, 3), + matrix(1, 3), + matrix(2, 3)); +}; +// +//// TODO +///* +// 4*4µÄ¾ØÕó +//*/ +QString get4x4MatrixStr(const Eigen::Matrix4d& matrix) +{ + QString res = QString::number(matrix(0, 0), 'g', 4) + "\t" + + QString::number(matrix(0, 1), 'g', 4) + "\t" + + QString::number(matrix(0, 2), 'g', 4) + "\t" + + QString::number(matrix(0, 3), 'g', 4) + "\n"; + res += QString::number(matrix(1, 0), 'g', 4) + "\t" + + QString::number(matrix(1, 1), 'g', 4) + "\t" + + QString::number(matrix(1, 2), 'g', 4) + "\t" + + QString::number(matrix(1, 3), 'g', 4) + "\n"; + res += QString::number(matrix(2, 0), 'g', 4) + "\t" + + QString::number(matrix(2, 1), 'g', 4) + "\t" + + QString::number(matrix(2, 2), 'g', 4) + "\t" + + QString::number(matrix(2, 3), 'g', 4) + "\n"; + res += QString::number(0, 'g', 4) + "\t" + QString::number(0, 'g', 4) + + "\t" + QString::number(0, 'g', 4) + "\t" + + QString::number(1, 'g', 4) + "\n"; + return res; +}; diff --git a/src/WBCLFZSystemModule/PointCloudProcess/PointCloudAlg.h b/src/WBCLFZSystemModule/PointCloudProcess/PointCloudAlg.h new file mode 100644 index 0000000..b6950ae --- /dev/null +++ b/src/WBCLFZSystemModule/PointCloudProcess/PointCloudAlg.h @@ -0,0 +1,268 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include //Ìí¼ÓQDateTimeÍ·Îļþ +#include +#include +#include +#include + +// Point Cloud Library +#include +#include +#include +#include // TicToc +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include //Ëæ»úÊý +#include +#include +#include // TicToc +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include // 4PCSËã·¨ +#include //K4PCSË㷨ͷÎļþ +#include +#include +#include +#include +#include //̰À·Í¶Ó°Èý½Ç»¯Ëã·¨ÀඨÒåµÄÍ·Îļþ +#include //ÒÆ¶¯Á¢·½Ìå +#include +#include //MLS +#include //²´ËÉÖØ½¨ +#include +#include +#include +#include +#include + +#include // TicToc +#include // ÌåËØÂ˲¨ +#include // ÌåËØÂ˲¨ +#include + +#include +#include +#include +#include +#include +#include //Ëæ»ú²ÎÊý¹À¼Æ·½·¨ +#include //Ä£ÐͶ¨Òå +#include //RANSAC·Ö¸î +#include +#include +#include //rand()Í·Îļþ +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +//¿ÉÊÓ»¯Ïà¹ØÍ·Îļþ +#include +#include +#include +#include +#include +#include +#include +#include +// Boost +#include + +// Visualization Toolkit (VTK) +#include + +#include "BasePCL.h" + + +/////////////////////////////////////////////////////////// +//// ¹¹½¨ µã·¨ÏòÁ¿ +////////////////////////////////////////////////////////// + +// ¹¹½¨µãÔÆ·¨ÏòÁ¿ +void NormalEstimation(pcl::PointCloud::Ptr cloud, pcl::PointCloud::Ptr cloud_with_normals); + +//////////////////////////////////////////////////////////////////// +// ÀëȺµã + Â˲¨ +////////////////////////////////////////////////////////////////// +/* + ϲÉÑù +*/ +void downSampling(pcl::PointCloud::Ptr cloud, + pcl::PointCloud::Ptr cloud_filtered, + double leafSize = 0.01f); + + +/* + ¸ß˹Â˲¨ +*/ +void gaussian_filter(pcl::PointCloud::Ptr cloud, + pcl::PointCloud::Ptr cloud_filtered, + double radius); + +/* + Ë«±ßÂ˲¨1 +*/ +void bilateralFilter(pcl::PointCloud::Ptr input, + pcl::PointCloud::Ptr output, + float sigma_s, + float sigma_r); + +/* + °ë¾¶Â˲¨Æ÷: + »ùÓÚÃܶȵÄÔÓÉ¢µãÒÆ³ý +*/ +void radius_filter(pcl::PointCloud::Ptr cloud, + pcl::PointCloud::Ptr cloud_filtered, + pcl::PointCloud::Ptr cloud_filtered_out, + double RadiusSearch=0.015, + int minNearSearch=35); +/* + ͳ¼ÆÂ˲¨Æ÷: + »ùÓÚͳ¼ÆµÄÔÓÉ¢µãÒÆ³ý +*/ +void statistical_filter( + pcl::PointCloud::Ptr cloud, + pcl::PointCloud::Ptr cloud_filtered, + pcl::PointCloud::Ptr cloud_filtered_out, + int meanK= 50, + double StddevThresh=1.0); + + + + +/************************************************************************/ +/* ±íÃæÖØ½¨ */ +/************************************************************************/ + +/* + ϲÉÑùµãÔÆ¾«¼ò + +*/ + + +void MLS(pcl::PointCloud::Ptr cloud_in, + pcl::PointCloud::Ptr cloud_with_normals); + +void Pos(pcl::PointCloud::Ptr cloud_with_normals, + pcl::PolygonMesh& mesh, + int Degree = 2, + int Depth = 8, + int IsoDivide = 8, + float SamplesPerNode=3.0, + int SolverDivide=8 + ); + +// ̰À·Èý½ÇÍø +void GP(pcl::PointCloud::Ptr cloud_with_normals, + pcl::PolygonMesh& mesh, + double SearchRadius=1, + double Mu=2.5, + int MaximumNearestNeighbors=100, + double MaximumSurfaceAngle=M_PI/4.0, + double MinimumAngle=M_PI/18, + double MaximumAngle=M_PI/3 + ); + +//ÒÆ¶¯Á¢·½Ìå +void MC(pcl::PointCloud::Ptr cloud, pcl::PolygonMesh& mesh); + + + + + +/************************************************************************/ +/* µãÔÆÅä×¼Ëã·¨ */ +/************************************************************************/ + +//// ½ÓÏÂÀ´Ê¹ÓõĵãÔÆÖ¸Õë +//PointCloudT::Ptr cloud_in; // Original point cloud +//PointCloudT::Ptr cloud_tr; // Transformed point cloud +//PointCloudT::Ptr cloud_RE; // ICP output point cloud +// +////ʹÓÃÅä×¼»ùÀàRegistrationÀ´ÊµÏÖ¶à̬ +//pcl::Registration::Ptr ALIGN; +//pcl::IterativeClosestPoint::Ptr icp; +// +////µü´ú´ÎÊý +//int iterations = 1; // Default number of ICP iterations +//// bool next_iteration = false; + +/* + ´òÓ¡4*4µÄ¾ØÕó +*/ +void print4x4Matrix(const Eigen::Matrix4d& matrix); + +// TODO +/* + 4*4µÄ¾ØÕó +*/ +QString get4x4MatrixStr(const Eigen::Matrix4d& matrix); + + \ No newline at end of file diff --git a/src/WBCLFZSystemModule/PointCloudProcess/PointManagerClass.cpp b/src/WBCLFZSystemModule/PointCloudProcess/PointManagerClass.cpp new file mode 100644 index 0000000..730058f --- /dev/null +++ b/src/WBCLFZSystemModule/PointCloudProcess/PointManagerClass.cpp @@ -0,0 +1,281 @@ +#include "PointManagerClass.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include //Ìí¼ÓQDateTimeÍ·Îļþ +#include +#include +#include +#include + +// Point Cloud Library +#include +#include +#include +#include // TicToc +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include //Ëæ»úÊý +#include +#include +#include // TicToc +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include // 4PCSËã·¨ +#include //K4PCSË㷨ͷÎļþ +#include +#include +#include +#include +#include //̰À·Í¶Ó°Èý½Ç»¯Ëã·¨ÀඨÒåµÄÍ·Îļþ +#include //ÒÆ¶¯Á¢·½Ìå +#include +#include //MLS +#include //²´ËÉÖØ½¨ +#include +#include +#include +#include +#include + +#include // TicToc +#include // ÌåËØÂ˲¨ +#include // ÌåËØÂ˲¨ +#include + +#include +#include +#include +#include +#include +#include //Ëæ»ú²ÎÊý¹À¼Æ·½·¨ +#include //Ä£ÐͶ¨Òå +#include //RANSAC·Ö¸î +#include +#include +#include //rand()Í·Îļþ +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//¿ÉÊÓ»¯Ïà¹ØÍ·Îļþ +#include +#include +#include +#include +#include +#include +#include +#include +// Boost +#include + +// Visualization Toolkit (VTK) +#include +#include "inputdialog.h" +#include "BasePCL.h" +#include "ToolDialog.h" + + + + +int CloudPointManagerClass::addMeshSTL(QString filepath) +{ + + + // Éú³ÉµãÔÆ¶ÔÏó + std::shared_ptr meshItem(new MeshItemClass); + QFileInfo fileinfo(filepath); + meshItem->name = fileinfo.fileName();// ÎļþÃû + meshItem->filepath = filepath; + meshItem->mesh_ptr.reset(new pcl::PolygonMesh); + + // ¼ÓÔØSTLÎļþ + pcl::PolygonMesh mesh; + pcl::io::loadPolygonFileSTL(filepath.toUtf8().constData(), *(meshItem->mesh_ptr)); // ¼ÓÔØmesh + + + // °ó¶¨item + this->DataList.insert(meshItem->name, meshItem); + // Ìí¼Óµ½ filelist + QListWidgetItem* item = new QListWidgetItem; + + item->setBackground(QBrush(QColor(220, 230, 250))); + item->setData(Qt::DisplayRole, meshItem->name); + item->setData(Qt::CheckStateRole, Qt::Checked); + this->filelist->addItem(item); + // Ìí¼Óµ½äÖȾ + meshItem->ViewerShow(this->viewerPtr); + meshItem->ZoomOnExtend(this->viewerPtr); + return 0; +} + +int CloudPointManagerClass::RemovePointCloud(QString name) +{ + return 0; +} + +int CloudPointManagerClass::ZoomOn(QString cloudname) +{ + std::shared_ptr < FileListManagerAbstractItem> fileItem = this->DataList.value(cloudname); + fileItem->ZoomOnExtend(this->viewerPtr); + return 0; +} + +QStringList CloudPointManagerClass::getItemNames() +{ + return this->DataList.keys(); +} + +std::shared_ptr CloudPointManagerClass::getItemFromName(QString Name) +{ + if (!this->DataList.contains(Name)) { + return nullptr; + } + else { + return this->DataList.value(Name); + } +} + +std::shared_ptr CloudPointManagerClass::getCloudPointItemFromName(QString Name) +{ + if (!this->DataList.contains(Name)) { + return nullptr; + } + else { + return std::dynamic_pointer_cast(this->DataList.value(Name)); + } +} + + +void MeshItemClass::ViewerShow(pcl::visualization::PCLVisualizer::Ptr viewer) +{ + viewer->addPolygonMesh(*(this->mesh_ptr), this->name.toUtf8().constData()); + viewer->getRenderWindow()->Render(); +} + +void MeshItemClass::ZoomOnExtend(pcl::visualization::PCLVisualizer::Ptr viewer) +{ + pcl::PointXYZ minPt, maxPt; + + // »ñÈ¡°üΧºÐ + pcl::PointCloud::Ptr cloud(new pcl::PointCloud); + pcl::fromPCLPointCloud2(this->mesh_ptr->cloud, *cloud); + + pcl::getMinMax3D(*cloud, minPt, maxPt); + // ¼ÆËãµãÔÆÖÐÐÄλÖúͶԽÇÏß³¤¶È + Eigen::Vector3f center((maxPt.x + minPt.x) / 2, (maxPt.y + minPt.y) / 2, (maxPt.z + minPt.z) / 2); + Eigen::Vector3f diff = maxPt.getVector3fMap() - minPt.getVector3fMap(); + float distance = diff.norm(); + + // ÉèÖÃÏà»úλÖúÍÊÓ½Ç + // (³¡¾°ÖÐÐĵãµÄ×ø±ê, ÉãÏñ»úµ½³¡¾°ÖÐÐĵãµÄ¾àÀë, ÉãÏñ»úµÄ·½ÏòÏòÁ¿) + viewer->setCameraPosition(center(0), center(1), center(2) + distance, center(0), center(1), center(2), -0.7, -0.9, 0.2); + viewer->spin(); + return; + +} + +void CloudPointItemClass::ViewerShow(pcl::visualization::PCLVisualizer::Ptr viewer) +{ + pcl::visualization::PointCloudColorHandlerRandom RandomColor(this->pointCloud); // Ëæ»ú¸øµãÔÆÉú³ÉÑÕÉ« + viewer->addPointCloud(this->pointCloud, RandomColor, this->name.toUtf8().constData()); // Ìí¼ÓµãÔÆ + viewer->getRenderWindow()->Render(); +} + +void CloudPointItemClass::ZoomOnExtend(pcl::visualization::PCLVisualizer::Ptr viewer) +{ + pcl::PointXYZRGBA minPt, maxPt; + pcl::getMinMax3D(*(this->pointCloud), minPt, maxPt); + // ¼ÆËãµãÔÆÖÐÐÄλÖúͶԽÇÏß³¤¶È + Eigen::Vector3f center((maxPt.x + minPt.x) / 2, (maxPt.y + minPt.y) / 2, (maxPt.z + minPt.z) / 2); + Eigen::Vector3f diff = maxPt.getVector3fMap() - minPt.getVector3fMap(); + float distance = diff.norm(); + + // ÉèÖÃÏà»úλÖúÍÊÓ½Ç + // (³¡¾°ÖÐÐĵãµÄ×ø±ê, ÉãÏñ»úµ½³¡¾°ÖÐÐĵãµÄ¾àÀë, ÉãÏñ»úµÄ·½ÏòÏòÁ¿) + viewer->setCameraPosition(center(0), center(1), center(2) + distance, center(0), center(1), center(2), -0.7, -0.9, 0.2); + viewer->spin(); + return; +} + + +void FileListManagerAbstractItem::ViewerShow(pcl::visualization::PCLVisualizer::Ptr viewer) +{ +} + +void FileListManagerAbstractItem::ZoomOnExtend(pcl::visualization::PCLVisualizer::Ptr viewer) +{ +} + +FileListManagerAbstractItemType FileListManagerAbstractItem::getType() +{ + return this->itemtype; +} diff --git a/src/WBCLFZSystemModule/PointCloudProcess/PointManagerClass.h b/src/WBCLFZSystemModule/PointCloudProcess/PointManagerClass.h new file mode 100644 index 0000000..547f76d --- /dev/null +++ b/src/WBCLFZSystemModule/PointCloudProcess/PointManagerClass.h @@ -0,0 +1,197 @@ +#pragma once +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include //Ìí¼ÓQDateTimeÍ·Îļþ +#include +#include +#include +#include + +// Point Cloud Library +#include +#include +#include +#include // TicToc +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include //Ëæ»úÊý +#include +#include +#include // TicToc +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include // 4PCSËã·¨ +#include //K4PCSË㷨ͷÎļþ +#include +#include +#include +#include +#include //̰À·Í¶Ó°Èý½Ç»¯Ëã·¨ÀඨÒåµÄÍ·Îļþ +#include //ÒÆ¶¯Á¢·½Ìå +#include +#include //MLS +#include //²´ËÉÖØ½¨ +#include +#include +#include +#include +#include + +#include // TicToc +#include // ÌåËØÂ˲¨ +#include // ÌåËØÂ˲¨ +#include + +#include +#include +#include +#include +#include +#include //Ëæ»ú²ÎÊý¹À¼Æ·½·¨ +#include //Ä£ÐͶ¨Òå +#include //RANSAC·Ö¸î +#include +#include +#include //rand()Í·Îļþ +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +//¿ÉÊÓ»¯Ïà¹ØÍ·Îļþ +#include +#include +#include +#include +#include +#include +#include +#include +// Boost +#include + +// Visualization Toolkit (VTK) +#include +#include "inputdialog.h" +#include "BasePCL.h" +#include "ToolDialog.h" + + +enum FileListManagerAbstractItemType { + PointCloudType, + PolygonMeshType +}; + +class FileListManagerAbstractItem { +public: + QString name; + QString filepath; + FileListManagerAbstractItemType itemtype; +public: + virtual void ViewerShow(pcl::visualization::PCLVisualizer::Ptr viewer); // ÐéÄ⺯Êý + virtual void ZoomOnExtend(pcl::visualization::PCLVisualizer::Ptr viewer); + virtual FileListManagerAbstractItemType getType(); +}; + +class CloudPointItemClass :public FileListManagerAbstractItem { // µãÔÆ¶ÔÏó +public: + pcl::PointCloud< pcl::PointXYZRGBA>::Ptr pointCloud; // µãÔÆ¶ÔÏó +public: + FileListManagerAbstractItemType itemtype = FileListManagerAbstractItemType::PointCloudType; + void ViewerShow(pcl::visualization::PCLVisualizer::Ptr viewer) override; + void ZoomOnExtend(pcl::visualization::PCLVisualizer::Ptr viewer) override; +}; + +class MeshItemClass :public FileListManagerAbstractItem { // Íø¸ñ¶ÔÏó +public: + pcl::PolygonMesh::Ptr mesh_ptr; +public: + FileListManagerAbstractItemType itemtype = FileListManagerAbstractItemType::PolygonMeshType; + void ViewerShow(pcl::visualization::PCLVisualizer::Ptr viewer) override; + void ZoomOnExtend(pcl::visualization::PCLVisualizer::Ptr viewer) override; +}; + +// µãÔÆ×´Ì¬¹ÜÀíÀà +class CloudPointManagerClass : public QObject { + Q_OBJECT + QMap> DataList; // µãÔÆ¹ÜÀí¶ÔÏó + pcl::visualization::PCLVisualizer::Ptr viewerPtr;// Ö¸Õë + QListWidget* filelist;// ÎļþÁбí +public: + CloudPointManagerClass(QWidget* parent = nullptr); + ~CloudPointManagerClass(); + int bandingViewer(pcl::visualization::PCLVisualizer::Ptr viewerPtr, QListWidget* filelist); // °ó¶¨Ö¸Õë + int addPointCloud(QString filePathWithName, QString formatstr); // µãÔÆÊý¾Ý´¦Àí + int addMeshSTL(QString filepath); + int RemovePointCloud(QString name); // µãÔÆÊý¾ÝÒÆ³ý + int ZoomOn(QString cloudname); // Ëõ·Åµ½Ö¸¶¨µãÔÆ + QStringList getItemNames(); + std::shared_ptr getItemFromName(QString Name); + std::shared_ptr getCloudPointItemFromName(QString Name); + std::shared_ptr getMeshItemClassFromName(QString Name); +}; diff --git a/src/WBCLFZSystemModule/PointCloudProcess/PoissonReSurfaceWindows.ui b/src/WBCLFZSystemModule/PointCloudProcess/PoissonReSurfaceWindows.ui new file mode 100644 index 0000000..f60b420 --- /dev/null +++ b/src/WBCLFZSystemModule/PointCloudProcess/PoissonReSurfaceWindows.ui @@ -0,0 +1,333 @@ + + + PoissonReSurfaceWindowsDialog + + + + 0 + 0 + 583 + 294 + + + + Dialog + + + + + + + + + 0 + 25 + + + + + 16777215 + 25 + + + + 120 + + + + + + + Qt::RightToLeft + + + ISO 等值é¢çš„分割数: + + + + + + + + 0 + 25 + + + + + 16777215 + 25 + + + + + + + + + 16777215 + 30 + + + + Qt::RightToLeft + + + 精细度级别: + + + + + + + + 0 + 25 + + + + + 16777215 + 25 + + + + 2.5 + + + + + + + 选择路径 + + + + + + + + 0 + 25 + + + + + 16777215 + 25 + + + + + + + + Qt::RightToLeft + + + ä¿å­˜è·¯å¾„: + + + + + + + Qt::RightToLeft + + + 求解器中的分割数: + + + + + + + 树节点样本数 + + + + + + + + 0 + 25 + + + + + 16777215 + 25 + + + + 10 + + + + + + + + 0 + 25 + + + + + 16777215 + 25 + + + + + + + + + + 2 + + + + + + + 点云: + + + + + + + Qt::RightToLeft + + + æ ‘æ·±: + + + + + + + + 0 + 25 + + + + + 16777215 + 25 + + + + 3.0 + + + + + + + + + 6 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Qt::Horizontal + + + + 131 + 31 + + + + + + + + OK + + + + + + + Cancel + + + + + + + + + + + okButton + clicked() + PoissonReSurfaceWindowsDialog + accept() + + + 278 + 253 + + + 96 + 254 + + + + + cancelButton + clicked() + PoissonReSurfaceWindowsDialog + reject() + + + 369 + 253 + + + 179 + 282 + + + + + FileOpenpushButton + clicked() + PoissonReSurfaceWindowsDialog + pushFileButton() + + + 498 + 53 + + + 272 + 88 + + + + + + pushFileButton() + + diff --git a/src/WBCLFZSystemModule/PointCloudProcess/RadiusOutlierRemovalWindows.ui b/src/WBCLFZSystemModule/PointCloudProcess/RadiusOutlierRemovalWindows.ui new file mode 100644 index 0000000..e1597e6 --- /dev/null +++ b/src/WBCLFZSystemModule/PointCloudProcess/RadiusOutlierRemovalWindows.ui @@ -0,0 +1,269 @@ + + + RadiusOutlierRemovalWindowsDialog + + + + 0 + 0 + 507 + 177 + + + + Dialog + + + + + + + + Qt::RightToLeft + + + ä¿å­˜è·¯å¾„: + + + + + + + + 0 + 25 + + + + + 16777215 + 25 + + + + 2.5 + + + + + + + + + + + + + + + + Qt::RightToLeft + + + åŠå¾„内最å°ç‚¹æ•°: + + + + + + + 点云: + + + + + + + 选择路径 + + + + + + + + 0 + 25 + + + + + 16777215 + 25 + + + + 100 + + + + + + + + 0 + 25 + + + + + 16777215 + 25 + + + + + + + + + 0 + 25 + + + + + 16777215 + 25 + + + + + + + + + 16777215 + 30 + + + + Qt::RightToLeft + + + 邻近点查找范围: + + + + + + + + + 6 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Qt::Horizontal + + + + 131 + 31 + + + + + + + + + 16777215 + 31 + + + + OK + + + + + + + + 16777215 + 31 + + + + Cancel + + + + + + + + + + + okButton + clicked() + RadiusOutlierRemovalWindowsDialog + accept() + + + 278 + 253 + + + 96 + 254 + + + + + cancelButton + clicked() + RadiusOutlierRemovalWindowsDialog + reject() + + + 369 + 253 + + + 179 + 282 + + + + + + FileOpenpushButton + clicked() + RadiusOutlierRemovalWindowsDialog + pushFileButton() + + + 498 + 53 + + + 272 + 88 + + + + + + + + + + pushFileButton() + + diff --git a/src/WBCLFZSystemModule/PointCloudProcess/Scance_FEKOSourceSettingPlaneWaveWIndows.ui b/src/WBCLFZSystemModule/PointCloudProcess/Scance_FEKOSourceSettingPlaneWaveWIndows.ui new file mode 100644 index 0000000..e688f2c --- /dev/null +++ b/src/WBCLFZSystemModule/PointCloudProcess/Scance_FEKOSourceSettingPlaneWaveWIndows.ui @@ -0,0 +1,60 @@ + + + MainWindow + + + + 0 + 0 + 685 + 464 + + + + MainWindow + + + + + + + + 1 + + + + + + + + 0 + + + + Tab 1 + + + + + Tab 2 + + + + + + + + + + 0 + 0 + 685 + 22 + + + + + + + + diff --git a/src/WBCLFZSystemModule/PointCloudProcess/Scene_StripQtWidgetsClass.cpp b/src/WBCLFZSystemModule/PointCloudProcess/Scene_StripQtWidgetsClass.cpp new file mode 100644 index 0000000..482ccca --- /dev/null +++ b/src/WBCLFZSystemModule/PointCloudProcess/Scene_StripQtWidgetsClass.cpp @@ -0,0 +1,10 @@ +#include "Scene_StripQtWidgetsClass.h" + +Scene_StripQtWidgetsClass::Scene_StripQtWidgetsClass(QWidget *parent) + : QWidget(parent) +{ + ui.setupUi(this); +} + +Scene_StripQtWidgetsClass::~Scene_StripQtWidgetsClass() +{} diff --git a/src/WBCLFZSystemModule/PointCloudProcess/Scene_StripQtWidgetsClass.h b/src/WBCLFZSystemModule/PointCloudProcess/Scene_StripQtWidgetsClass.h new file mode 100644 index 0000000..11f9448 --- /dev/null +++ b/src/WBCLFZSystemModule/PointCloudProcess/Scene_StripQtWidgetsClass.h @@ -0,0 +1,16 @@ +#pragma once + +#include +#include "ui_Scene_StripQtWidgetsClass.h" + +class Scene_StripQtWidgetsClass : public QWidget +{ + Q_OBJECT + +public: + Scene_StripQtWidgetsClass(QWidget *parent = nullptr); + ~Scene_StripQtWidgetsClass(); + +private: + Ui::Scene_StripQtWidgetsClassClass ui; +}; diff --git a/src/WBCLFZSystemModule/PointCloudProcess/Scene_StripQtWidgetsClass.ui b/src/WBCLFZSystemModule/PointCloudProcess/Scene_StripQtWidgetsClass.ui new file mode 100644 index 0000000..a1e0562 --- /dev/null +++ b/src/WBCLFZSystemModule/PointCloudProcess/Scene_StripQtWidgetsClass.ui @@ -0,0 +1,238 @@ + + + Scene_StripQtWidgetsClassClass + + + + 0 + 0 + 554 + 520 + + + + Scene_StripQtWidgetsClass + + + + + + 雷达馈æºè®¾ç½® + + + + + + + 0 + 25 + + + + + 16777215 + 25 + + + + + + + + 等效PRF(Hz): + + + + + + + æ–¹ä½è§’(度): + + + + + + + 入射角(度): + + + + + + + 中心频率: + + + + + + + + 0 + 25 + + + + + 16777215 + 25 + + + + + + + + + 0 + 25 + + + + + 16777215 + 25 + + + + + + + + 等效地速(m/s): + + + + + + + æˆåƒå¼€å§‹æ—¶é—´(s): + + + + + + + è·ç¦»å‘分辨率: + + + + + + + æ–¹ä½å‘分辨率: + + + + + + + æˆåƒç»“æŸæ—¶é—´(s): + + + + + + + + 0 + 25 + + + + + 16777215 + 25 + + + + + + + + + 0 + 25 + + + + + 16777215 + 25 + + + + + + + + + 0 + 25 + + + + + 16777215 + 25 + + + + + + + + + 0 + 25 + + + + + 16777215 + 25 + + + + + + + + + 0 + 25 + + + + + 16777215 + 25 + + + + + + + + + 0 + 25 + + + + + 16777215 + 25 + + + + + + + + + + + + + diff --git a/src/WBCLFZSystemModule/PointCloudProcess/StatisticalOutlierRemovalWindows.ui b/src/WBCLFZSystemModule/PointCloudProcess/StatisticalOutlierRemovalWindows.ui new file mode 100644 index 0000000..a8b248e --- /dev/null +++ b/src/WBCLFZSystemModule/PointCloudProcess/StatisticalOutlierRemovalWindows.ui @@ -0,0 +1,246 @@ + + + StatisticalOutlierRemovalWindowsDialog + + + + 0 + 0 + 540 + 177 + + + + Dialog + + + + + + + + Qt::RightToLeft + + + ä¿å­˜è·¯å¾„: + + + + + + + + 0 + 25 + + + + + 16777215 + 25 + + + + 2.5 + + + + + + + Qt::RightToLeft + + + 标准差阈值: + + + + + + + 点云: + + + + + + + 选择路径 + + + + + + + + 0 + 25 + + + + + 16777215 + 25 + + + + 100 + + + + + + + + 0 + 25 + + + + + 16777215 + 25 + + + + + + + + + 0 + 25 + + + + + 16777215 + 25 + + + + + + + + + 16777215 + 30 + + + + Qt::RightToLeft + + + 邻近点数: + + + + + + + + + 6 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Qt::Horizontal + + + + 131 + 31 + + + + + + + + OK + + + + + + + Cancel + + + + + + + + + + + okButton + clicked() + StatisticalOutlierRemovalWindowsDialog + accept() + + + 278 + 253 + + + 96 + 254 + + + + + cancelButton + clicked() + StatisticalOutlierRemovalWindowsDialog + reject() + + + 369 + 253 + + + 179 + 282 + + + + + + + + FileOpenpushButton + clicked() + StatisticalOutlierRemovalWindowsDialog + pushFileButton() + + + 498 + 53 + + + 272 + 88 + + + + + + pushFileButton() + + diff --git a/src/WBCLFZSystemModule/PointCloudProcess/Strips_FEKOSourceSettingPlaneWaveWIndows.ui b/src/WBCLFZSystemModule/PointCloudProcess/Strips_FEKOSourceSettingPlaneWaveWIndows.ui new file mode 100644 index 0000000..fbb0a65 --- /dev/null +++ b/src/WBCLFZSystemModule/PointCloudProcess/Strips_FEKOSourceSettingPlaneWaveWIndows.ui @@ -0,0 +1,381 @@ + + + Dialog_Strip + + + + 0 + 0 + 600 + 635 + + + + + 600 + 0 + + + + æ¡å¸¦æ¨¡å¼FEKOå‘å°„æºå‚æ•°è®¾ç½®ç•Œé¢ + + + + + + + + + + 16777215 + 16777215 + + + + 这里å‡è®¾æ³¢çš„æ–¹ä½å‘垂直90度 + + + 雷达馈æºè®¾ç½® + + + + + + + 0 + 30 + + + + + 16777215 + 30 + + + + 5 + + + + + + + æ–¹å‘角(度): + + + + + + + 中心频率(GHZ): + + + + + + + 入射角(度): + + + + + + + + 0 + 30 + + + + + 16777215 + 30 + + + + 30 + + + + + + + + 0 + 30 + + + + + 16777215 + 30 + + + + 0 + + + + + + + + + + æˆåƒå›¾åƒè®¾ç½® + + + + + + è·ç¦»å‘分辨率(m): + + + + + + + + 0 + 30 + + + + + 16777215 + 30 + + + + 0 + + + + + + + æˆåƒä¸­å¿ƒåæ ‡(x,y,z,å•ä½m): + + + + + + + + 0 + 30 + + + + + 16777215 + 30 + + + + 2 + + + + + + + + 0 + 30 + + + + + 16777215 + 30 + + + + + + + + 幅宽(m): + + + + + + + è·ç¦»å‘åƒç´ æ•°ï¼š + + + + + + + å‚考斜è·(m): + + + + + + + + 0 + 30 + + + + + 16777215 + 30 + + + + 10 + + + + + + + æ–¹ä½å‘分辨率(m): + + + + + + + å‚考平é¢(Z,å•ä½m): + + + + + + + + 0 + 30 + + + + + 16777215 + 30 + + + + (0,0,0) + + + + + + + + 0 + 30 + + + + + 16777215 + 30 + + + + 0 + + + + + + + æ–¹ä½å‘åƒç´ æ•°ï¼š + + + + + + + + 0 + 30 + + + + + 16777215 + 30 + + + + + + + + + 0 + 30 + + + + + 16777215 + 30 + + + + + + + + + + + + + + + Qt::Horizontal + + + + 40 + 25 + + + + + + + + + 0 + 25 + + + + + 16777215 + 25 + + + + OK + + + + + + + Cancal + + + + + + + + + + + + diff --git a/src/WBCLFZSystemModule/PointCloudProcess/ToolDialog.cpp b/src/WBCLFZSystemModule/PointCloudProcess/ToolDialog.cpp new file mode 100644 index 0000000..a9e7aea --- /dev/null +++ b/src/WBCLFZSystemModule/PointCloudProcess/ToolDialog.cpp @@ -0,0 +1,242 @@ +#include "ToolDialog.h" +#include + +BilateralFilterWindows::BilateralFilterWindows(QWidget* parent):ToolBaseFunClass(parent) +{ + this->ui.setupUi(this); + this->setComboBox(this->ui.comboBox_clouldName); + this->setLineEdit(this->ui.lineEdit_savePath); + this->setPushButton(this->ui.FileOpenpushButton); + QObject::connect(this->ui.FileOpenpushButton, SIGNAL(clicked()), this, SLOT(SaveFileButton())); + QObject::connect(this->ui.okButton, SIGNAL(clicked()), this, SLOT(OKpushButton())); + QObject::connect(this->ui.cancelButton, SIGNAL(clicked()), this, SLOT(CannelpushButton())); + + +} + +BilateralFilterWindows::~BilateralFilterWindows() +{ + +} + +// +// ·µ»Ø¼ÆËã½á¹û ply +// +QString BilateralFilterWindows::ExcuteCmd(pcl::PointCloud::Ptr pointcloudPtr) +{ + // ¼ÆËãµãÔÆÂ˲¨½á¹û + pcl::PointCloud::Ptr output(new pcl::PointCloud); // Êä³ö½á¹û + + float sigma_s = this->ui.lineEdit_NearSearchNumber->text().toFloat(); // ´°¿Ú + float sigma_r = this->ui.lineEdit_NearSearchDistance->text().toFloat(); // ±ê×¼²î + + //bilateralFilter(pointcloudPtr, output, sigma_s, sigma_r); // Ö´ÐÐÂ˲¨ + // ±£´æÂ˲¨½á¹û + QString save_path = this->ui.lineEdit_savePath->text(); + save_path = save_path.trimmed(); + int flag=pcl::io::savePLYFileBinary(save_path.toUtf8().constData(), *output); + QString logstr = "[" + QString::number(flag) + "]"; + QString logStrQString(logstr.toUtf8().constData()); + qDebug() << logStrQString << ":" << save_path; + return save_path; +} + + + +MedianFilterWindows::MedianFilterWindows(QWidget* parent) :ToolBaseFunClass(parent) +{ + this->ui.setupUi(this); + this->setComboBox(this->ui.comboBox_clouldName); + this->setLineEdit(this->ui.lineEdit_savePath); + this->setPushButton(this->ui.FileOpenpushButton); + QObject::connect(this->ui.FileOpenpushButton, SIGNAL(clicked()), this, SLOT(SaveFileButton())); + QObject::connect(this->ui.okButton, SIGNAL(clicked()), this, SLOT(OKpushButton())); + QObject::connect(this->ui.cancelButton, SIGNAL(clicked()), this, SLOT(CannelpushButton())); +} + +MedianFilterWindows::~MedianFilterWindows() +{ + +} + + +PoissonReSurfaceWindows::PoissonReSurfaceWindows(QWidget* parent) :ToolBaseFunClass(parent) +{ + this->ui.setupUi(this); + this->setComboBox(this->ui.comboBox_clouldName); + this->setLineEdit(this->ui.lineEdit_savePath); + this->setPushButton(this->ui.FileOpenpushButton); + QObject::connect(this->ui.FileOpenpushButton, SIGNAL(clicked()), this, SLOT(SaveFileButton())); + QObject::connect(this->ui.okButton, SIGNAL(clicked()), this, SLOT(OKpushButton())); + QObject::connect(this->ui.cancelButton, SIGNAL(clicked()), this, SLOT(CannelpushButton())); +} + +PoissonReSurfaceWindows::~PoissonReSurfaceWindows() +{ + +} + + + +RadiusOutlierRemovalWindows::RadiusOutlierRemovalWindows(QWidget* parent) :ToolBaseFunClass(parent) +{ + this->ui.setupUi(this); + this->setComboBox(this->ui.comboBox_clouldName); + this->setLineEdit(this->ui.lineEdit_savePath); + this->setPushButton(this->ui.FileOpenpushButton); + QObject::connect(this->ui.FileOpenpushButton, SIGNAL(clicked()), this, SLOT(SaveFileButton())); + QObject::connect(this->ui.okButton, SIGNAL(clicked()), this, SLOT(OKpushButton())); + QObject::connect(this->ui.cancelButton, SIGNAL(clicked()), this, SLOT(CannelpushButton())); +} + +RadiusOutlierRemovalWindows::~RadiusOutlierRemovalWindows() +{ + +} + + + +StatisticalOutlierRemovalWindows::StatisticalOutlierRemovalWindows(QWidget* parent) :ToolBaseFunClass(parent) +{ + this->ui.setupUi(this); + this->setComboBox(this->ui.comboBox_clouldName); + this->setLineEdit(this->ui.lineEdit_savePath); + this->setPushButton(this->ui.FileOpenpushButton); + QObject::connect(this->ui.FileOpenpushButton, SIGNAL(clicked()), this, SLOT(SaveFileButton())); + QObject::connect(this->ui.okButton, SIGNAL(clicked()), this, SLOT(OKpushButton())); + QObject::connect(this->ui.cancelButton, SIGNAL(clicked()), this, SLOT(CannelpushButton())); +} + +StatisticalOutlierRemovalWindows::~StatisticalOutlierRemovalWindows() +{ + +} + + +DialogTriangulationSurfaceMesh::DialogTriangulationSurfaceMesh(QWidget* parent) :ToolBaseFunClass(parent) +{ + this->ui.setupUi(this); + this->setComboBox(this->ui.comboBox_clouldName); + this->setLineEdit(this->ui.lineEdit_savePath); + this->setPushButton(this->ui.FileOpenpushButton); + QObject::connect(this->ui.FileOpenpushButton, SIGNAL(clicked()), this, SLOT(SaveFileSTLButton())); + QObject::connect(this->ui.okButton, SIGNAL(clicked()), this, SLOT(OKpushButton())); + QObject::connect(this->ui.cancelButton, SIGNAL(clicked()), this, SLOT(CannelpushButton())); +} + +DialogTriangulationSurfaceMesh::~DialogTriangulationSurfaceMesh() +{ + +} + +QString DialogTriangulationSurfaceMesh::ExcuteCmd(pcl::PointCloud::Ptr pointcloudPtr) +{ + + // ¼ÆËãµãÔÆÂ˲¨½á¹û + pcl::PointCloud::Ptr output(new pcl::PointCloud); // Êä³ö½á¹û + pcl::PointCloud::Ptr cloud_with_normals(new pcl::PointCloud); + + NormalEstimation(pointcloudPtr, cloud_with_normals); + pcl::PolygonMesh mesh; + double SearchRadius = this->ui.lineEdit_maxTrangleEdge->text().toDouble(); + double Mu = this->ui.lineEdit_NearSearchDistance->text().toDouble(); + int MaximumNearestNeighbors = this->ui.lineEdit_NearSearchNumber->text().toInt(); + double MaximumSurfaceAngle = this->ui.lineEdit_SurfaceAngle->text().toDouble() / 180.0 * M_PI; + double MinimumAngle = this->ui.lineEdit_minTrangleAngle->text().toDouble() / 180.0 * M_PI; + double MaximumAngle = this->ui.lineEdit_MaxTrangleAngle->text().toDouble() / 180.0 * M_PI; + + GP(cloud_with_normals, + mesh, + SearchRadius, + Mu, + MaximumNearestNeighbors, + MaximumSurfaceAngle, + MinimumAngle, + MaximumAngle + ); + // ±£´æÂ˲¨½á¹û + QString save_path = this->ui.lineEdit_savePath->text(); + save_path = save_path.trimmed(); + int flag = pcl::io::savePolygonFileSTL(save_path.toUtf8().constData(), mesh); + + QString logstr = "[" + QString::number(flag) + "]"; + QString logStrQString(logstr.toUtf8().constData()); + qDebug() << logStrQString << ":" << save_path; + return save_path; +} + +void DialogTriangulationSurfaceMesh::SaveFileSTLButton() { + + QString filepath = QFileDialog::getSaveFileName( + this->FileOpenpushButton->parentWidget(), + QString::fromUtf8(u8"Áí´æÎª"), + QString::fromUtf8(u8"stlÎļþ (*.stl)"));//¶à×éÀ©Õ¹ÃûÓÃË«·ÖºÅ";;"¸ô¿ª + this->lineEdit_savePath->setText(filepath); + this->saveOk = true; +} + + +ToolBaseFunClass::ToolBaseFunClass(QWidget* parent) :QDialog(parent) +{ +} + +ToolBaseFunClass::~ToolBaseFunClass() +{ +} + +int ToolBaseFunClass::setComboBox(QComboBox* comboBox_clouldName) +{ + this->comboBox_clouldName = comboBox_clouldName; + return 0; +} + +int ToolBaseFunClass::setLineEdit(QLineEdit* lineEdit_savePath) +{ + this->lineEdit_savePath = lineEdit_savePath; + return 0; +} + +int ToolBaseFunClass::setPushButton(QPushButton* FileOpenpushButton) +{ + this->FileOpenpushButton = FileOpenpushButton; + return 0; +} + +int ToolBaseFunClass::bandingComboxAndPoint(QStringList itemvalues) +{ + this->comboBox_clouldName->addItems(itemvalues); + return 0; +} + +QString ToolBaseFunClass::getComboxSelect() +{ + return this->comboBox_clouldName->currentText(); +} + + + +void ToolBaseFunClass::SaveFileButton() { + QString filepath = QFileDialog::getSaveFileName( + this->FileOpenpushButton->parentWidget(), + QString::fromUtf8(u8"Áí´æÎª"), + + QString::fromUtf8(u8"plyÎļþ (*.ply)"));//¶à×éÀ©Õ¹ÃûÓÃË«·ÖºÅ";;"¸ô¿ª + this->lineEdit_savePath->setText(filepath); + this->saveOk = true; +} +bool ToolBaseFunClass::isOK() +{ + return this->isok&&this->saveOk; +} +void ToolBaseFunClass::OKpushButton() +{ + this->isok = true; + this->close(); +} + +void ToolBaseFunClass::CannelpushButton() +{ + this->isok = false; + this->close(); +} + \ No newline at end of file diff --git a/src/WBCLFZSystemModule/PointCloudProcess/ToolDialog.h b/src/WBCLFZSystemModule/PointCloudProcess/ToolDialog.h new file mode 100644 index 0000000..091d447 --- /dev/null +++ b/src/WBCLFZSystemModule/PointCloudProcess/ToolDialog.h @@ -0,0 +1,297 @@ +#pragma once +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include //Ìí¼ÓQDateTimeÍ·Îļþ +#include +#include +#include +#include +#include + +// Point Cloud Library +#include +#include +#include +#include // TicToc +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include //Ëæ»úÊý +#include +#include +#include // TicToc +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include // 4PCSËã·¨ +#include //K4PCSË㷨ͷÎļþ +#include +#include +#include +#include +#include //̰À·Í¶Ó°Èý½Ç»¯Ëã·¨ÀඨÒåµÄÍ·Îļþ +#include //ÒÆ¶¯Á¢·½Ìå +#include +#include //MLS +#include //²´ËÉÖØ½¨ +#include +#include +#include +#include +#include + +#include // TicToc +#include // ÌåËØÂ˲¨ +#include // ÌåËØÂ˲¨ +#include + +#include +#include +#include +#include +#include +#include //Ëæ»ú²ÎÊý¹À¼Æ·½·¨ +#include //Ä£ÐͶ¨Òå +#include //RANSAC·Ö¸î +#include +#include +#include //rand()Í·Îļþ +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +//¿ÉÊÓ»¯Ïà¹ØÍ·Îļþ +#include +#include +#include +#include +#include +#include +#include +#include +// Boost +#include + +// Visualization Toolkit (VTK) +#include +#include "BasePCL.h" +#include "PointCloudAlg.h" + +// ¹¤¾ß´°¿Ú +#include "ui_BilateralFilterWindows.h" +#include "ui_MedianFilterWindows.h" + +#include "ui_RadiusOutlierRemovalWindows.h" +#include "ui_StatisticalOutlierRemovalWindows.h" + +#include "ui_DialogTriangulationSurfaceMesh.h" +#include "ui_PoissonReSurfaceWindows.h" + + +///////////////////////////////////////////////////////////////////////////////////// +// ¹«Ó÷½·¨ +/////////////////////////////////////////////////////////////////////////////////// +class ToolBaseFunClass:public QDialog +{ + Q_OBJECT // ÿ¸ö×ÓÀà±ØÐëʹÓÃÕâ¸öºê +public: + QLineEdit* lineEdit_savePath; + QComboBox* comboBox_clouldName; + QPushButton* FileOpenpushButton; + bool isok=false; // ÊÇ·ñÖ´ÐÐ + bool saveOk = false; +public: + ToolBaseFunClass(QWidget* parent = nullptr); + ~ToolBaseFunClass(); + int setComboBox(QComboBox* comboBox_clouldName); + int setLineEdit(QLineEdit* lineEdit_savePath); + int setPushButton(QPushButton* FileOpenpushButton); + int bandingComboxAndPoint(QStringList itemvalues); + QString getComboxSelect(); + bool isOK(); +public slots: + virtual void SaveFileButton(); + virtual void OKpushButton(); + virtual void CannelpushButton(); +}; + + +////////////////////////////////////////////////////////////////////////////////////////// +// ²ÎÊý´°¿Ú +///////////////////////////////////////////////////////////////////////////////////////// + +class BilateralFilterWindows : public ToolBaseFunClass +{ + Q_OBJECT // ÿ¸ö×ÓÀà±ØÐëʹÓÃÕâ¸öºê +public: + QString TaskXmlPath; + +public: + QString name; +public: + BilateralFilterWindows(QWidget* parent = nullptr); + ~BilateralFilterWindows(); + + // Ö´ÐвÙ×÷ + QString ExcuteCmd(pcl::PointCloud::Ptr pointcloudPtr); + +private: + Ui::BilateralFilterWindowsDialog ui; +}; + + + + +class MedianFilterWindows : public ToolBaseFunClass +{ + Q_OBJECT // ÿ¸ö×ÓÀà±ØÐëʹÓÃÕâ¸öºê +public: + QString TaskXmlPath; + +public: + QString name; +public: + MedianFilterWindows(QWidget* parent = nullptr); + ~MedianFilterWindows(); + +private: + Ui::MedianFilterWindowsDialog ui; +}; + + + +class RadiusOutlierRemovalWindows : public ToolBaseFunClass +{ + Q_OBJECT // ÿ¸ö×ÓÀà±ØÐëʹÓÃÕâ¸öºê +public: + QString TaskXmlPath; + +public: + QString name; +public: + RadiusOutlierRemovalWindows(QWidget* parent = nullptr); + ~RadiusOutlierRemovalWindows(); + +private: + Ui::RadiusOutlierRemovalWindowsDialog ui; +}; + + +class StatisticalOutlierRemovalWindows : public ToolBaseFunClass +{ + Q_OBJECT // ÿ¸ö×ÓÀà±ØÐëʹÓÃÕâ¸öºê +public: + QString TaskXmlPath; + +public: + QString name; +public: + StatisticalOutlierRemovalWindows(QWidget* parent = nullptr); + ~StatisticalOutlierRemovalWindows(); + +private: + Ui::StatisticalOutlierRemovalWindowsDialog ui; +}; + + + +class DialogTriangulationSurfaceMesh : public ToolBaseFunClass +{ + Q_OBJECT // ÿ¸ö×ÓÀà±ØÐëʹÓÃÕâ¸öºê +public: + QString TaskXmlPath; + +public: + QString name; +public: + DialogTriangulationSurfaceMesh(QWidget* parent = nullptr); + ~DialogTriangulationSurfaceMesh(); + // Ö´ÐвÙ×÷ + QString ExcuteCmd(pcl::PointCloud::Ptr pointcloudPtr); +private: + Ui::DialogTriangulationSurfaceMeshDialog ui; +public slots: + void SaveFileSTLButton(); +}; + + + +class PoissonReSurfaceWindows : public ToolBaseFunClass +{ + Q_OBJECT // ÿ¸ö×ÓÀà±ØÐëʹÓÃÕâ¸öºê +public: + QString TaskXmlPath; + +public: + QString name; +public: + PoissonReSurfaceWindows(QWidget* parent = nullptr); + ~PoissonReSurfaceWindows(); + +private: + Ui::PoissonReSurfaceWindowsDialog ui; +}; + diff --git a/src/WBCLFZSystemModule/PointCloudProcess/images/1.gif b/src/WBCLFZSystemModule/PointCloudProcess/images/1.gif new file mode 100644 index 0000000000000000000000000000000000000000..0004449612d8dda88a908c171efb7530b6dd7588 GIT binary patch literal 276082 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 literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/PointCloudProcess/images/RGB.png b/src/WBCLFZSystemModule/PointCloudProcess/images/RGB.png new file mode 100644 index 0000000000000000000000000000000000000000..24668432ac16e5ae37da336725b5e4ce267a7968 GIT binary patch literal 3331 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 N002ovPDHLkV1kKZI4l4F literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/PointCloudProcess/images/algorithm/DASHBOARD.png b/src/WBCLFZSystemModule/PointCloudProcess/images/algorithm/DASHBOARD.png new file mode 100644 index 0000000000000000000000000000000000000000..c84211a6080261b819eef1b36df3170886dd2395 GIT binary patch literal 2785 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 literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/PointCloudProcess/images/algorithm/DBSCAN.png b/src/WBCLFZSystemModule/PointCloudProcess/images/algorithm/DBSCAN.png new file mode 100644 index 0000000000000000000000000000000000000000..17a7f0ab23df0fe99b3ffbb9d969395bbd994c23 GIT binary patch literal 2041 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 RAL#%9002ovPDHLkV1l=e$^!rZ literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/PointCloudProcess/images/algorithm/binary.png b/src/WBCLFZSystemModule/PointCloudProcess/images/algorithm/binary.png new file mode 100644 index 0000000000000000000000000000000000000000..fc5726a55034b0f4e08be7d2f5ec818d00c78678 GIT binary patch literal 1544 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 literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/PointCloudProcess/images/algorithm/extract.png b/src/WBCLFZSystemModule/PointCloudProcess/images/algorithm/extract.png new file mode 100644 index 0000000000000000000000000000000000000000..6fca78d0d52778b42ecf7d5b751b15b9f19f7c98 GIT binary patch literal 2922 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 literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/PointCloudProcess/images/algorithm/more.png b/src/WBCLFZSystemModule/PointCloudProcess/images/algorithm/more.png new file mode 100644 index 0000000000000000000000000000000000000000..85f9e610c0edbcbece340dec43c5029c7674347d GIT binary patch literal 2259 zcmV;^2rT!BP)g>@AhtCYef#{QTFtP`bUOmv{;l6F-a=i`#5G&V&lh%WIx)1|R}c5L6- zKBN1??_asRzvp?M_jk{|U(fTJkX5|F&W%L$H2^CCtjMk}`k636jAKkVF*A*QlP9HN zD>@p3J6aOLOpusbtl$e_m~fUg3}D*z--%PZr;5=>NwD{`-}eYLwfh*nz8D2XV&7*C zTgL~b1Nr2Zg~ZRffNlU^FH*NPI73zkqz-FfV3r_%%l%7dgxa%Kh04V-gxklJU;iar zk1r%X1YlRW`mM?HN>%AOZibyD$QKk}1>r_Bu&wnPU8fFq|2wI(p>_Mc%)H;$HVP{n zR~5-;)*dyi=v>Ddy^sl{Hh~gvkM{35W~RWb-n(L(5A3>)7+nB9lg86ORi*n&`m?u1 zTtxy71GqXvALBs~QY4zSm9L(O>!HzYMEG7NhJU3hJr5MpOTM7^00_S@fPSYc(#BGa z$tULviC+O`Nl2E9sv=#bKQx5IO$_|TD61+`YJ9ZI7H_KOnxkFQ!UR zm7vVgrTU4P%q~@essxp{0I7OV)q|=Yq%-i5ujZ>O>FP?_+NW0?q^pCpHBZThs(Mh> zgFb2x3W^aB!s%wIO;x%xjz7yYDJ|^_iKF@nYw9#_1_3=z=5xTQX8viuwR0<&_9g)Y zyf~&v>+B*WsmB}YT1(JgOg=MkZd{R;>d)Ed;siQ0rgU$x+lI#0AFR<>c+;RabuONl zpvF+=EgI-=833lo1tD?3uBZlSuFdn~UHrVN^n6oqH+N(OyHrK`sa+(^1r7ALo8fpl z9a+gs(Ciz`a&fzi%BzPkQTzS}Eki@{dr6EhB>oA&H?m~(FtJj$J%oBNg4ueQar5|q z^!GygQ=t`KNaV5&v8X^GY98(H9?FLMLgKsgVq+F{77Zi(Qtg)>G?UASJ$Xahw-9)r znNZ2~j3YJtzYW8KPfq63;R}g-0BkF{4GV$7yn0!}c|YtZmVb)fsNX82^i?a@oC z4O_*{4X#$6w&N10a&?6J zd>@~>P;-v}x)Z=Hrky2BFyndBw1b{4Bd?p{3jiFIK$XkRsYqZa5%g@6PnXnD!Xb_6 znfemFDt`hMVFHX(B^hND%CksARsvP7c4EDOJ}_)a2_(W!cYE|_#r7v>0u=$9#}vu7 zY%gzX=Xzr5%QUX=GCw8CIU>6w zX=q&be~Uo}jfOL{JL|$D`bM_oG8GB@hX|iHD0s;ej^1iTp<@V|h%8@Ji-oUcc7zUi z!bA63=|~~Wg~&C{2}12w|TmlwCGakEZX zsgLyrc7X9%3d68+aL)H^6g+ zHhaQD1!rqV5ER?r*n%0?K+64rQ+45}A*b3Z1%+{O*}sKBspA|Xyx?w+W*^dJC~*cs z^FObHp78K@?4c#CaMMEExBsbX=mq2XKyKp@LhL%^!Jq^$bXtZ%_-eAiJ)iG=wQCK9N|H6IdGT_ z(FQHSH`U)aT#;n9O0R=1JlWWksBxW1eaeg{+#S)ajweVrFedxo1ZYhqSJJcX z7!KjAOa_kdpv#6=b}wf1lJoogv+;Q=Go@n)dhcnUdsuJ$ z97B+9^t*Ckn+E8i=X5FIn6wxI%&_FN>yX(CIlTh}e$*Wv{;^qSDp60_7i#q&-?$=O zYj={wQ^$HlXX?mp;5`-JvZD)>_BAZ@r%>C66+TK^;-|a}Y`Hrec zpR!`KP7+VoJVL|;54G~?`WS1=ujm*l>nArd6R29n>j`)mjDpK=E1k=O=}{F)ELJ|= z8@Q1f_W;my8W&rVw`umvd79>wpQgzsLf>o>@wx;WgJ$~x#{~s?BQj9UgQ4RnA002ovPDHLkV1ky%MtT4M literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/PointCloudProcess/images/algorithm/nihe.png b/src/WBCLFZSystemModule/PointCloudProcess/images/algorithm/nihe.png new file mode 100644 index 0000000000000000000000000000000000000000..c94631ae4c25d857846b85e13780eec321cad9de GIT binary patch literal 2180 zcmV-~2z&R5P)nA31st>`;r0@w7+am87Hf3|O`vpY#{`*bDFdPm{^+Qk5^i@dzwY*N_L2*myG__j zF3II!|GRtNeV^z1d7t;!^Df~Mf9Mj|kIMiqN5CacV9JI-FxY$x5jHU6dVqI!cR#!> zA6ZWsfbw8V2f(+dM4N2Z9zEL7HdPR`-O}wOppJl3UV&aLsnt%nu{DJNnt8MX)Y;X& z<_?Cql1JJ_Kg96b50G2c3BoVC>mFR1Bp|P;^RVLc$+{3(CRP-k=*85g@UJe06 zl`XMfObH{?JvGhX8_Dc(-iA4CmR{tkd|IrluR^oOGD*@~ZW0I}VH zB`olpHpkD1incIaNGu|6Wya%<0vRjBI_>3&h@Wu)PRp1ecoy1+Lo6cwkeMEJ66k?& zcY@4f0BgVqGO$xpwC`mDW5!njLzV42#x_yWYEuG?u)GU|dM81GfLndF+UtfYkD4$6 zx;K5v91qBh1F)Ra)j*YC;|%BjpG{y?#ZXC8AaE5W$RG$q26u&H800Ek5npaD!jsIjL&Q0BE9Ri2fHg?&U zGX^wC(E>gD=FBVVGcEBW+h3dW|MR2dDpKCp+z86H&a?tJ@@QjyJdU>rn41hg;s<>R z?lc6Uoq&v70TG||oz<_R&4_0!%x(Q?1z;sa&b7{+TWThj4+!)|@xVa8=`FH){^oRt z88|5^+O_}v@fDK4w6}#o9f>&h2kN!=-HLNlZ`uK*oaze)KA9l4wy)(G;u&vCb=nQq z|MqAU%Cm9?VRN9$x$SM&@MLXB>C{ z{6!5#ZA0B>}U@I>m@~NvjBWy;a|{n*FF?^1~YXqJulWpA4wJH zs@zDx_eUxccZ(rCV~NZ)kVy}LltWe|cnLo*89u3fQr{R!$lgex+GO7A)U*kFS5~xdJC#`z zs$il*@OXcne(IZmo338TIs){tw2z3ADQW<3ii&oV-IAfo3V^Vqb>dCL_%MSiiExsc zJKbJjxKcBLN?8FgRM|SJ{?cy8GIpu))N4s^wJ9wq9rthq-2G$XHyOU=-USEOzf4-&j(Avk^)9>;; z0$np!W+-PW$7v`l09HHp*_sIEYAY+lr>{1BuB1oKOTLqaY$b!;B3X#tG+; zpz7OpZGClgSpfmiBhn6H`g(?V#(M&Bl~2(-oKAyN^@+^1Mt~6xJO|>2bfX0P4M4SD z(UNz41qnb8%PJ9)hZp<9!0}?itSYX(a3N7}0AgWzFB7UW$2@l@h^o`i@C5}RrUqVQ zaHYdodt+e0Q$4St=S=!X4g~`s7M3cQ=%tLXXZjsDQAGkhOrS;vWB_em;;q(+uwVdK zxjsRljx+$j>W_P?KU9D2yrIh0jqc|!ln;HORWJaC*ZdAMT$m+_eXw zujIr?-ZwIIHW>jB3^p$(VE@$nZJEqWluo_fObZNDjsRG^xaBrB`J$hf&xE5>W|Pbd z5s;j?%9}TXVco+O{zGW#>Z-5L$On{_?Y_=~#Fe=sz~JN+IFs-Wk!j?r-O02QkCz@h zcC0p;iJEXiWHJuq)4P`e);Ou9er`a|dqicqA~xShS*4x`Wl(E?A32%(UI z^3L783ll-17fmD!?t(t&ch9rk=NGdt=kDF^&d%QM?7DaJ-|X}9 z`+h(3JimEn_8GzqKPc_LWqEHGfL0LQRo6_IN9W9Ic>Cl@&t=1B0zk|1UOx!#x;CC| zZj^!6;bCty3Bc9MGst|>Dx)Vj;@z1S00S2YbfG@LunT~i?S+Pd!(Ht;0Z2?wpBm}< zsy@sEE?4gYVswGfbHh_U0I8u-FXq!eR<8WO8IR5T1AvnJEgt|9?ZII8P`v?2=DNN? zfZJvP)Zz%x_bP2H=&aML|68fiSCb{nj{u$_SUDdT;zrh6*^q2>S>S6z~5aI#qj zIuuPGC^v+f0}u@;yP4_LDMpD7$?nkF82~^XWJW40XWXF)Lk_pzUiSdiPOV!SLjD8eOReGZ2%F!vIC%u^>jKs_khJ=*%KYLA}Hcl zGoM0_$(sIzmG)NamH~kJIe=&K1}6T71P(Vjn+9m@KjF#s#(l~IaS3hA^bir6GZP?# z)+<_Qzg1IK>Q5g)K=}|%FPjA=a8v+?frfrXyL#NHKNe6P6HNO6+?lI=snf_zOJ@1B z0p!ctg+=g10RG%lC!;0tu=?OkpV)N34it##Y6n z@3PXS*t)g@FoaFI)tPD~!j~*Ca4D)EyZ050n>Mgep;`d`25`Ftoyn?1r-{XoAU>+N zBi~wXpQAyw0Qi7JPAL5#It|7VNl<@N=hffBKIaCKxQ&3tEa)dDK2^-)b9DeDlVWjs zfN&0srG-clVJO!VB!B@~(>n^atqOod9tb!Of_aVE5NIS`I?o+GukTg5C5g5JSZLNJ zvz&nU9Gd=mzBW|@U=D#V3W1GkXE^I^w6W%hF>SFjg*YyjDP57%xgb;*fKUAughhrh z2F^;rA`s3q^HIzdee#CrpM|b=#IG88#Kkw9xLF0&vaeyeCflONOX7WKDm^ z%uHr^WS?UJt~XpVZNqq0_UK>K6o80N-3x*zElLv7Vk4WInweA~5>SF*GXCewc`$JK zKdGVlwvH=TY72m0HLlzOLzI!lOMTy$|9wQ#E`#?gT6ld;B|+V%tdociOo$?M%5L3s zF6T25^*awRc-_=;J}ya(-lmQ#dH>O_N)n9v)O}2txGIi04uv-U6|p+}v+_Y=Z9z{G z@%;dwfxroeCw$1PPg?CE_5 z838vRfEm9{4#3RbD480wGi?kUp zB)+q2$GWW}AORrjqlG*;Y}~Rx3!tbWS*A*}BVcw4+{8Jc=nQT)U5ZJ9EcHMVS^0^X zQ|D6pX(e%#E2t>gjHHg^e-Z>kLQ5p?O1JQD&1cAbJ?`HN42ob^$qq%DQ z6;zBO_U76>T0kv70|iphNJ~^I?E6mZ4~#~XDnCMjKzqA;Ep%@lGuQ6U?B4Cp%x>2l znVbK1_j#Z9c|Py+ywCH_%o1XLQOy0vJb?KKh&h4z6bKsty1xFbu(FNh%4O`?y?c01 zGd*W6S%1=@E_|rnxuhK45k^N~1n9li2ng%KC<`OQpiN2{1GC8rF?uI~E)Jt7giOKV zM6YcRKHE$-7=W-i#AJ~~y2{SUJO4ENqJPkIgt4|glA<7C#x`l2E9M*kkhWaPp_&lw z2msIysf^|A0XUoj7XUat2zc1v9o9Z$+e43cGy(_@0nW`qdqH3dgmtQ!oGz>>09r+c z9R6&6SN69-0HiWIZePbIaGlhJRR)l#I!t`Fl-b|J3BX$bx+)Gc@HwT-U&jf+n*fff zrU3Ifc{}@PoB$jEu)s?JS|O#eEk*!FCjsjArNFsLnUBN>fK>#LtT?POo%ghDJRBzg z69Ce_6!?Oa#?}}C7~K!hLSGsDqLkSOV+3IA4SNINqPwe61^P-) zX5yBp5F!I8Y)GA@X;gb|Cstabe17+32md>p0e!;S%fP$66rc<9wox_S{eHINaHGRe zz4H~l$xI=#KamHxlTGH*_cGA$cb0%B9nI-a4U}H4hoB3~{q8-!6u3xAV@oR$(8zgW z+|)BzxW3~N;7(A?C6^F1cN2Sm9fa-O3$%W^c>fzU&I#)!04I6?v@c0H^sA@<8aWT5 zdy;D>R!4Q-m2W8m+=0`nkf6K3UT7aN;L)D0o>jDFZ>eHXpRitF;H1iDhn-7od-xYo z0Cd9nh5(9V$)!wGt=o;rCNwN!&>aA(ef|;Itv%(!Dl&0sI=_YWJb;tEJ%BIG+u1wA z0%+#EGv)j|%*v;SinHD&o)H0)((av3bXSr?YOuPpYZ zfRVS24N(BNvZY*l48TymgT$>vXbHe%F4fPVU;1x!P8-#rA<@O?-vRn?)o_L>ZPRro za1*R|wzM&I3y7{bS`b?M+m9PA+i?P1}d|Kr*gNK#M)|}oVodt5~A2M)F z?fk5gYm0i6@Sk3@r~{6KqFa}}O){Vr6~cOkfRA_p@MWdU^{qreWlU*f`nw?9=xqjg zCb_oo(Ww5k1Ypv?0wMZvU08ns;2FobLfYo7?EpBu5UCLYu47OSFtf=C1EVDXu41=C zo5G=kvz`9xC)S1aX8>pTR_jVB&7ZXkz#Y$bqnlR4eeTfG)iQu6vk77CCSZv#1+G%c z{OQpE5XFw!WdAP!bYblRu(VLe zWp9oTfL`lq5c<3nz_od0{wO{Gg!M-N%e)l8b<#F}5FY@#^&}W)`pV$-Qkpl#2SBg& z2M|8tD}y&GWqv?aNzAmNtowp4DA*^M@_)z5zoMJy(ng8yS3%y*IM#hL;T!ukLKO-y&-V6LxFr|p}MfKC&h>-zr(-moujon&;e00000NkvXXu0mjf5gl+V literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/PointCloudProcess/images/algorithm/transform.png b/src/WBCLFZSystemModule/PointCloudProcess/images/algorithm/transform.png new file mode 100644 index 0000000000000000000000000000000000000000..cdebf0c6dfca0f8060d900b1372d6f0ea2eff1d6 GIT binary patch literal 2478 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 aPsvQH#I3=6+Qc}Z1_n=8KbLh*2~7aB2&RPq literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/PointCloudProcess/images/camera.png b/src/WBCLFZSystemModule/PointCloudProcess/images/camera.png new file mode 100644 index 0000000000000000000000000000000000000000..e85444adac33a0c544e87b97d148f300cda0a65b GIT binary patch literal 4517 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 DV@!4j literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/PointCloudProcess/images/color.png b/src/WBCLFZSystemModule/PointCloudProcess/images/color.png new file mode 100644 index 0000000000000000000000000000000000000000..54b7ebcdee015a8e44ec3a12d7f030b0bf222fe1 GIT binary patch literal 117 zcmeAS@N?(olHy`uVBq!ia0vp^Vj#@K3?z5nYFPoKcmjMvT!Hle|NH;%-@pI-e}NBQ zrvdpYo-U3d9MQ=M4Gb3p6bcmDnwZvxI$UtzVP*aHzwrTsp$H2DgN&H<(XFc<*#Olu Nc)I$ztaD0e0sw4SBhUZ< literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/PointCloudProcess/images/coodinate.png b/src/WBCLFZSystemModule/PointCloudProcess/images/coodinate.png new file mode 100644 index 0000000000000000000000000000000000000000..a876d149e1d675442bb4bb25b46c331bb50f17b2 GIT binary patch literal 982 zcmV;{11bE8P)Nkl$v z4_3Of#a??Uc&LJ{C&hz;_&CJu$mZ3ilhkY;v(0Aa7-sjI-*4ud%p)N*c%cU8hkOC; zQz1-uB)5uqxdI~Q6o3$RP$y=z--3kjL>Ry^5OHv_U~3Dt79~$W8ooUP^a=^56AQ8L z0$`hY1`h27(?)9z@4jD-fPDBYmkpjg3%mbI4)l0@4;&tYrC*T&FGoOO_zWK{f)b}; z4SY&{5RQ+mfjjfC4ZGGNYC8h*fOrcC-6`ZL`UB8GFvC5U%qzh^4`_`?!TAby@3IRW#|K|P>a1~M9JVpom`7p}^Bv&C zz+&@_Cm>?Fdyg=fUUZ}fI|b4=O{=htwG-%ungrcrd0V@=*_mdrM}V6Gob1gc1YdwV z2XMMkOhRJ_NNvFjOYlcPRW2IJcu4^Xas;%Q`{2+N!1tHY>?%G&OF*&%EVi6|Y3&7U zgm-&ERw3?Q#^7SUYP(f=f}bH3%=2m5x9H-BK#vTeV~js`1(kB0>qr30MlZ=l9U^)5op`Db8S`bW{OBn*P%P(4nJr3!Gl9S}~!(q{w-k@y<`JHfOg_0;>tQy_h*SiG$NFHhJU1>q=w z6*M`+n2UX^Ckdr5gzAaPLtB*q53&MTRgHi^cB==de+MwlP^*-e_5c6?07*qoM6N<$ Ef_o#dcK`qY literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/PointCloudProcess/images/files/CSV.png b/src/WBCLFZSystemModule/PointCloudProcess/images/files/CSV.png new file mode 100644 index 0000000000000000000000000000000000000000..bd647f6fcb307945c990bc468a15dbf7dea70a8d GIT binary patch literal 1452 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 literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/PointCloudProcess/images/files/cloud.png b/src/WBCLFZSystemModule/PointCloudProcess/images/files/cloud.png new file mode 100644 index 0000000000000000000000000000000000000000..c03b518f45e2dc9b75a704922157677a473cb36f GIT binary patch literal 2357 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 uPzhba0+7&-42tUkU=Y~9k9+oNvTDGjUJ`E4N( zfZh?y)xBU;dzVMf=gVjj0G(akEsKVSo2rWdU<6Q`z?z=@z1^TUtp*my+buc}%!K*Z}Re`WdkXHs702DGOx&SCUw(sUH z0uYxDFg^uP2cQn%BY;8(g^&S4$aoS&Arx{?5S1WjN2o2NFpmeWjt?PBGo-5zV0L)h z-m&!p#*-idfKnKxFc$&r1w!-!QMSZXKCC3R3WU`Gs$Z56fVj5ARLh_j0c1fWhA0rX zEmJ_`xUTWUrhqO7MRpJXRSpm#EE-p3aglw|xMTzrRsdjDWIW7xDgj`Q<*dn506GxH z$)NwF769fHD^)T8c;(GIZJufXWSsY+=jXUR0+7Z-QnGLUYaT`brT}ul_njj~f~qN{ zIzRG3N!10@cIis{#mTf?yVDK;i=gayevVKWRgETH^C^LY%5G`d&t5D5=z8$~u!8{n d2g*ra;~n_v{BAwtgj@gs002ovPDHLkV1nY%D$W1^ literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/PointCloudProcess/images/files/cut.png b/src/WBCLFZSystemModule/PointCloudProcess/images/files/cut.png new file mode 100644 index 0000000000000000000000000000000000000000..aa825e6b38bf2b598af5e3ac1f143efc7519cb83 GIT binary patch literal 2305 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 literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/PointCloudProcess/images/files/new1.png b/src/WBCLFZSystemModule/PointCloudProcess/images/files/new1.png new file mode 100644 index 0000000000000000000000000000000000000000..65248923310c713b598f862078885bb7d23df17b GIT binary patch literal 1438 zcmV;P1!4M$P)DhISCk2g*e}_o)BvBN-`GZmMqDV9dyDl?RHRG@@QC#vqR61SHuy{N^9E-)~iD*o}|3@#2g;s%R2>>bOqX6&{09?t66Vb;+G-p}XPi_oJ zCX?4A;yfZgsN4Sr0MkmTcir^&(k4&PQadRKA;u7q6Rc~Ta@z)gqdrGshw$S(6H2LL ztpp*Z+^Mt5+iW>bUD^hK1&xi3T@Z`KUPiAFnVEib#;=JYX$^E9vB#S#d(MVfVXS4+LUEk zzuRMX6o9QnJRaX}7zU@n57>c{*Qrv9>pT}Jj*Bv$twJf0my!natKorSiIcOGHGc z_|T)2`kgR@Mfl;zg&t_p%~mDVXNZ)tAe2@eP=a@Pah_W;~_-}-jG&jMaEt{`X4ud(&|bsd1=@nh=`TfXc)y|B}jZLS(Q zHSoLE+ING0G zxbJH(Nx;_ePj9z(hn52%qNDnQC!g7Um3lda?b_W8!1-Z>4S&ZljM;oX&tGsom5l(L zZ=j9`K~`*Zbo7$J!9l(jPdgNSV|aLYGMCF$+*0US0JedtRO(tH;tP&l4x{-(gRj9F zmYxS-TgZ2L(P)(a?65CE{{(=UMmIZ~27nDhN_oG&^14CS@gE_RN~uqRIt+D13~1!r zLWmJWc>VW%SH)K#}7k|j9+Kq9(^r7q(OX0L=#G>GyLpl3AmNt zvOK`80?u|qi2cqFsfc)}SS(KT4FHD0KT1}s)q_NosRuELD>grq@Q7JM@5{NcQSDp$GKp%mtNklXT_mlTH>+>J)^ZpqKzy$O;16Tp`0F;Um zp1XN*icBln1tCkTt()WaeBLuO=(=EnjsH%>x!CmuvI$jrwbQF7K1aG&2Y_<+|Bry-Bqr9!|RFO2aD1#qV^ z-mq@aum%Kdt1v>H;+A&a8`cdyg8(zN_jybJRzTXqbzvfC07MYC0Ios9e-d1SCI;XG zV1(cV;RL(Tz)6DyCkQ79Cn(1W-c&}V?WK%F{(%Ql8fh93dyJC`+7*=YBuS+}fGiQj z1YiZA0VL6}D+nTpTL9M}Y1`lf?DhdW!_^N&tp5_vv!ugaD}q#D&AOx-E@~aySAYr( z1Tz>%07*qoM6N<$f(KIk zaP8B(70eDhj-LAcam$h8$ON3gGV}95BM|D%T+A=ka^H|^2tpgP{Hk~G$^>d4#39lw zflGKD?!fUqQl`;eq&svG-ayF`N{n$|qjQ4ui8sB3KePSh6(93=8N~oaGfTX7wSY86(ogt)^GKe1|-v zJ`I_|xMo48%}9upbqSCVn^b|ae7w&w5LkN$vxIhAn`Deq>qOi^trox>OHd~%!yOcW zWlkPiQjY2qGzf>;Q_#Weu)8@r#JPXTAaK!@$|de#AmBVBs&DqJLbA`1x`T9ux$+!K zz)GEemS;BN6P?s~PSAM2ha};+BCh6awdW6a(s)s*Vqs?M7?v3t1`hrOTTo{I1Xs X7n6r>&e5?000000NkvXXu0mjfie^%Y literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/PointCloudProcess/images/files/pointCloud.png b/src/WBCLFZSystemModule/PointCloudProcess/images/files/pointCloud.png new file mode 100644 index 0000000000000000000000000000000000000000..33364dd1167baaed5e2f0308be4de711486f5ac4 GIT binary patch literal 2681 zcmV-<3WoKGP)GRkQ5lEC&!9l5;TH>Vu58iqE!TfNJy5Q?S4P2H_0-6%ue@Q8|I&_ z+WwuN_xc^b_nOe)U)$|G)>7>RF-;(%6PR%Vz~cbtFLnX+CJ}Zq^DYoSXIuO8n-(0o zr;%Y&Bb;ezJ_}N|fjAD(MbUlIQ_Q@DgxF+u(T?c)(KPA`r!k=F0@Q2Sm>>^9CaO1yW+pAo^}DL+>Usd^CWg*&a9s5T`Svl|Zck z#tvtb7&qp!%Fk;Bre;tQY5P`YEGr!tJzital2QZ2rF}4%J;(B@#$BpSZbzWP;cH4lPa|vRWGjFza-!qe_|q@ zGiYN}dyag?Jtdx&PZ0CPZm0CZ5e2$veHC3dY7#9OKBCFuJcBPR)@7n6^IhT_QSDU> zC6VGQ`M?6r^<&6H-iVo%1X7JoTp!Q~BIoNZEUwCB=~q#0SJYE9-P#I}cl3Y2G?W{n z22d+`O}CxJ+x4Di+HM+Z;4C$q-^ftnI-f$2o+*#sX3zzBgI=vwl2Pp(h>M>E*tPmq zRB`%-4E;Tdy~t2Bov#DrO3!<9znN8Tj^el;vYKvp1Mto|KQ;|zn3c9ak_w>6#{i!0 z8q}DR`Ksbq;?@ z#N>Nk8PiZAHGU-FwhW(OTk=g;FKO_)q#VGwF1HZ4rC3f;#kdU_+Eq^X(DO)8CZ`9^ zmn{C^es!=ipRIiL7&g$ba`BYCg2=tf79=M=)fL+s)|%~wmXQi&@<*;7Nrms35urMKLT)fu|o--vC&X_>YZ#@`>nc_6ri;p`A9QRR46|I zka3SGJS}gi>%#_JZ@I)gzL=$a!s91n8p<7EeV2uj=;Y&B$Zs=fs&@bzbV9h<>{9Lz z>#*K(TAHr~OJBi@2|rU6u{_K|t|XL$FlK>h7MMRfOfm~hL+Pw{vSIDVQ+6j2N|z;x z@?iN$K~>iEX6T(DyMa*JGW90+ zO_=So^Vv~nw;jdCClgB9Rl}|ma_i>!WqR63aS`e zY6)CRPekhuNi^R&Byz^bZRtDf?9rP9BPv@m~juvwc3sGp2mH5i8h{hH`L)>$;=M zz&n&k*{hgvwYz2I*G(g~IZSI;BQw%av`(uHf`04Hfme{GTh{^PI`Jdmww$3XttR0x zx+4xnx7z`@itYr_Mw93Ac&W;l0E{V05UYW zc*?q*i2S>MA*Psj(uOegln&ES7MDw~lIJ4|rG%kGa>Hjjho zCCU7}WM%v2Ed9HZ9&$*ho=_5<`;M2Q=}ZEh$>0eDN|uOquW2Yp7C-Y<^UH%NjUnj9 z^P)%hO%aNi$xPFU&}%bw&Pg`C>{tl{WnoYMX$tXtX0#CTB8O&S>7B=o)CUB!=w8LaD_w+e89yPB%Gp^~F(fnZX|06(o3ydXZR#{T2!ONZ{4}IO`1V=?J z9$?W6W$~l?&xN4CgEaug% zy6xPED0)l99?5t`+Ia1~@z}ZJ`tYCAM1m4!d>NWydiI|WU_C%JC|t3#qo3NI93A>r zQYA6h9m?P=vv&U_Agcai4|B48#^}1=!fXf>2h5^J_uWWBRD6$xrM#)*(lN^`Y5Ax+ z4TCZWrl;=?0_H^xl7TxrlFhC$BdU!k@(qPD2xe{H0~FyqWoC4D%xL!9xsQ@!blHYO zInZPFuOraZa^W&~eMfTiv~qH_em){l4!%m;2{@-zLJU0Dk!&t8mDd`B+un#lIWQ~r zy$-_Xd?_;CXrIx1VtrFDZGA+c41($D>jyBZD8xd0vbp%syWwm`9Ey|ilAaG&Gk7L| nty1|QF=yJ?ioX=C1;PIV2tGRV&n`O-00000NkvXXu0mjfrK}Ik literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/PointCloudProcess/images/files/search.png b/src/WBCLFZSystemModule/PointCloudProcess/images/files/search.png new file mode 100644 index 0000000000000000000000000000000000000000..b24cd070ad0d825c576526f908cfc74bad6e5e6c GIT binary patch literal 2148 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 QEdT%j07*qoM6N<$g1#|Z;s5{u literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/PointCloudProcess/images/files/txt.png b/src/WBCLFZSystemModule/PointCloudProcess/images/files/txt.png new file mode 100644 index 0000000000000000000000000000000000000000..e89f1bfd3e2a2191b6dfe37e577b58f31e457660 GIT binary patch literal 1359 zcmV-V1+e;wP)yHxoHT|TKmn9=r)ZothhtqC4f(=)i~FA`(F^; zAn+1^@znP?b-p7a5O@oqs=NrFes_{H1YQFmV}L6J-UHwYAua%Lfe<$U!i5l50K$O~ zcK||#5SIW#fe^O<*h1hf0JhtRU>PGX0k9SCqn;go`ef#HUIF;wmka3bXYK~sqo8+@ zeR>bgyaK>pu6Iq5`b*bE0e}zz!Vuu?B)B1SK-1Z#V$t8CvrgbGE)Jt%o12@9T|3|R z>6-N|qJ9c1tdIrNI!+veuZFh8b(sc^*3$SHNZcu--vrl0jGJDj^ z$<9Gdb#>$bNTpKL*X<438Fz)&wpRT0{5chdBpgY(b-NdnlapR;Xw(`g^YW>_#<`?K&)0Pu3WoHbtdoiJiMpTP@mV<)^MY< z1M~CqbVuc{$?>69OMPEiSwWZ42o3p2!+ zp=+^PV7J@pdYbKOD3wa;``p|du6Nv^fBWL|2Kw`@-d;@Je-R;xiHRNn{P~-GI_m`~ z;t}BMZ(w#_f7;;ppGrtbK>gl&ypoK;PXv)KW#3EK)|t#?Wu-5BP7h^+y_s zDFCEH3b`EGDp#nJ@<-22daYhuTtw^THaHxP_ys_ey<1j>qBo1YM7CdV$Dhxh1s&_W zjsUm1y4qUEGGw$^^Ux3m&4WS3lL~PG;ElpURFqfHg4?cK#=^qF<^YhEmWG4-4|s?r z;t2#ch4&G_T-R+&Hb`EUP`U@rX0J?+%c>KTt3cV?@1VH2n9}v|(IX5G--B+Cj@C(X z1Ck>ID!h$=?5u3;uBoB5o&N0%wd55R6kuD$HtISV3M6|Bv=s6dz@D1j$jZv1gmxLb zF!SUI4MU?=Lz(Bw5=TZyVHz;`4FX;QC{>k0RZ>EU8XF(O-G0w(FDWUBijE9v236-~ zPY)hUJ@5&EcL10hD6$bccm8*u!kB3*$qLC(VD2T{MllD#J*$(=2y-*!?l2QT^Tie{ zEiL&CZ;~OBOp(k5Bu(~}8`SA)A(P2qv)Ryc>0-bMb3^t5uV!XKE>~cDVjQcht3EqK zZiuX}uTxv$V1?W}2-a4|&oGSKm&-$(~v21K?OixZu_IVQgSL3}SGgjNtqx(LN=gdI{Y!r(BmezJ+sQY`6?zK#qG8~eHcB(ehe3dtTp zz6=aiY77hwEes65fI|ZCY4JL~(AhgSA6$NXg4h|FZo{pRW3! z>0Nq%{=dh|{-wE>-kSFJ#-zUqF4?B0rk5^VGS#;D|Ns9BuMIgsTNsnP-Cbl~GZ#(- za@b2eeO=j~a*Ob>$RFe}*$fn#=jq}YqH+H2q(HuA1s(_2U6F!q8eO;d{I_hM*vq8% zJ91OX`UB?|FUefFs=o26%!93d&wb2$l9#Z0n2LMsc`&0YW8#l>hp$`@(ku;R)chms zxA&cyFfD&%+0 z*Vy;3`c~a#ew8ir{jK({*}vvw+y1Omr}q7PUw4}MX1g$7aDeU!pi5OtTq8$X`y O4Gf;HelF{r5}E)}8N}cK literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/PointCloudProcess/images/grey.png b/src/WBCLFZSystemModule/PointCloudProcess/images/grey.png new file mode 100644 index 0000000000000000000000000000000000000000..bda44ca1fe85a2633393f228a60cfc2f4f3f0675 GIT binary patch literal 2024 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 YU!qCEQ#X~~=Kufz07*qoM6N<$g4ynldH?_b literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/PointCloudProcess/images/ic-undo.png b/src/WBCLFZSystemModule/PointCloudProcess/images/ic-undo.png new file mode 100644 index 0000000000000000000000000000000000000000..2754aa951f46dfe16e32a4363e7e8254a44399e4 GIT binary patch literal 1355 zcmV-R1+@B!P)AKMOksw~x%l z%BN9o3KH}`^f?LA&Y4@&V+yxw2buv+OR zk}b~;55jz6XQyJ3M)mfvHnY5LHG7wN#UV2CO_$?s1J;xe8d3{oJE_EKqrUu=Uncu1 zs;^bm)LQI5;R;}ORXR#K%iSd7yUK$o3>EJogpaEbQJeFK&%VBt375ALvu*>{12$APQ@Z?4rJ7`x^pOUKdbhq8Dh^(!k^7?|<1L9)#{s4Ha zgpkn!@eMF10EnL2f+&0|?u#IA4-zvvATr)jlo1F!^#Nh3vk%XOn0ZBG?ndel!s(g@){g;t11O#K17Q>$_~B~KpEpVLY~7z1 zR=23yR$mbRCeiHsB;)G>eOrE-&4= z*O8prG4?>%?h-_XT)@<((Lc%lnJIY270u-HeU3j$d| zGQK0)Ae1en5(B2(2=)lENyhIOoHnBcLODSyF}2hT6d@4$JIR)b!%f4{03m!y+sHq+ zi~xv%*Z)!M5x*hQPFwtSKdaIP?Ge&JY+O4_r<*ehU!{RSNDrdBQQAvA7Ar?1>>!RK zWKhizYtFEA`ss2F4p)w_ti?kFYyJW%-G#rVTsKY4-7K78ezH)L@(;p@qiJaa9~l4u N002ovPDHLkV1nt!eNX@Z literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/PointCloudProcess/images/keda.ico b/src/WBCLFZSystemModule/PointCloudProcess/images/keda.ico new file mode 100644 index 0000000000000000000000000000000000000000..8c55425db265ba9390ba5a95bbfb010250af3a32 GIT binary patch literal 67646 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 QR6*jnZ|3n;Yi(}+A7eL?t^fc4 literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/PointCloudProcess/images/left.png b/src/WBCLFZSystemModule/PointCloudProcess/images/left.png new file mode 100644 index 0000000000000000000000000000000000000000..20f105b9ef6c3bc53ba0fb83391dee17a17c366f GIT binary patch literal 521 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 Q25MmNboFyt=akR{0HS5dN&o-= literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/PointCloudProcess/images/rotate0.png b/src/WBCLFZSystemModule/PointCloudProcess/images/rotate0.png new file mode 100644 index 0000000000000000000000000000000000000000..73343545480004d5afdc5bf731017a983719ffe8 GIT binary patch literal 2865 zcmV-13(oY3P)?u7ryocyKvZ*^Nm3L+! ztVH-NS^Ko6Aw(NYzI|u5Zk~wdCW5h);2G010n#z}0AkMB2sZ<}1_LXpbg^dM<{`0wm}4W{2#m}te+N2pA>Q;ii97CK1JD{uz67!s zq>HV?x_I=we^%6sJKqNG1D4_1?R71tyh5yF7&3Yl$Qk)p@1uG#UMf?pI%EJ;&qk~^ z(8*Qy_}##2RM&vtiP!#W)5?}Nh&!i%t^oO5{?%%7xdn8!Zz`!egaG1rDUZ|dY2od6 zP6aU_+JMkEl$Jk(tVaDcU>yhk`k-y2CGHsKI;+RS>!o-pbH=DFLk^%^gjVNhd_60$ z4%LII3TZraBM>H~$I~MB0{iFtc@oLZC)@sbO?KNHKvc40m+j6l>l}o0fC-gC%i}1I zRE3dnE=9Sb*hcgQvZ)1ijb^(7P`Qpn4-M}EyO+KGN8mStM=t_7DtvD~Z*qRa=ZTL6 z0J8)vc@6caB22Au$T8aAg6=REZ~8}dXTDJ3V*?<1AWEc9!6}8h&M(E!(vP)KlgY4_W=81S?AC>`(@%z zcp7ZhODCLLQO>Ox+-ey^=d8B|4L}qsJdA7S;|HaZR0j|h+OodZX80 znWsSy1AQFzPrz&cPs0FW=|d4&gye1`+x|#Hk{c_*KM;|#O6nJuTJYXnmE?Xy=bRU6 z_E{6a(gTndv&s5mwV-S%fOuv$Xc%Qt>twvy4;2TjX92P0$0NEth#4vm;@RJ72!N>+ zwFKcdlr6Y+vIKl+$1eiEL)FEzA1>*?x1C_ZS%6|LZa`!f+2qPX+cE&oAAzH)Do_A` z6~mpqzGUz)Om3FVun=Bzk=b6q0x@SXA}P?Ft6E6mkG%mnxMKvP#~9rvpsd5QO%NyK zQS3Apn93`m0-S|s|FVp5J|&{lsd7e zLFVEnpJ+=U)n9t()4ZvvSIti`pb zR47pmzzHiq%a*MU=-(JI{K}d)L-mOCXCoATwTz?OukP}TXYL0zzUkh=S0)0$xf?h$ z2u8T}%$fj#poZ>;ub1Pc%)NjAOJ4xQmVX2B&2^iJB^1g%SX@r0{g)Ayv~qDkhykntsnIPCk2}f_z=zQkJoOpJW5Lt5ThhH^bb&a(&Q; za4lK;l0tvgPJ?U1n_u0E($=RCbv0?*mh4UUaI;iek-&fK+pAKdE7@ZYn|sg5^;3Bh ze^>`H4CD=ROrb0Jr`iBoSB%BanWOAz;0d-2Z{x8UAM{IzYK>zn4}k90z&Z>R*dt%< z8I&ZRZ7iXG<(OM`VMMq2GMPjwGyPL>lg7~(OO1$7dKxN)O+|6r*gt9Nw2nLDPBa*qG$LD2u8_`8%Q!DDp)EI!!p^VFCe48zEp_mQIDj0bu z-t_vv0Es(hBQqM;u9i(@1?JjsrmpDOO%OP#8jr9v#R_Dq@d`5Z@MnKW2EA(AdvXw!x0 zoxE?YVq*hG;n$E6n|!A3;%>0QzygR4YGUzwjTwtrV<9Y)v1{k1 zH8!YJGt~wUKrJbXS8r@am`v90YDVCJt~;~<%zb^~r*xvz$(F7Ef!3~p{)P^K@#a3} zZqGQsYpUKBHz4ppR~b40;g6q80CRPpQsxI*^L&3p2VjsC=x?{5dI0|e93^gy+j9Xg P00000NkvXXu0mjfI*(52 literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/PointCloudProcess/images/rotate180.png b/src/WBCLFZSystemModule/PointCloudProcess/images/rotate180.png new file mode 100644 index 0000000000000000000000000000000000000000..453cdbe501f4dc0b769ed1e754e2f98d01e39130 GIT binary patch literal 2373 zcmV-L3A*-)P)!oBRazc9$9yyQF|#vs-xt`xmuzLk~nQvjT@fMbDx(LWxMn?WuB#-d~_sIl(f-q;7S4^jKP zztsRrJ%&ARcc;bcoC_FzlR@=BViw5w<`hx8!Fe2H3wH0;=6F<})m{L49y%YVs~6O* zz~yZgcn`>rNDTI|id+3H%Y1CX># zS8>IAYX~z4Yynk-K=o#yyUX;P-o8efR<~bdC6w%%txA8r#S!&OZ(xt@Pf)y+)np5BTUUXMowE> z91t&Hn+@+jjRRm<5-F%+5qa~0no6{TAZ2|S;p>sCY%{1+DtjA}Sc=Fl3Z{0cz-SDB zRBk6C9|$e1)B^J9I^lq68Z1m3r=chxa{u8*cc^5FOg}}FiOyz#;%(t46vEy@$?B_v!v+6o^?*Z<` zrh7*)wpY8b)9>%NBCRZ7(zAiL5BLp;4rYzm710XtA^V~eSuW@YqzZ!FH> zmw*dEJ%gPN-w9IIB!qAtv8D@zAkzZbQbLi%fES|hgrb`H0MrVZG>Pn*5_S09F=-PIHyU zQ`qLTNaeLKhmKs2Qu-SF?hpXiJY!raUQQYL4v$UY5fLRsO`)iTNiT))>NF}eIy{Qv}9BQb-* zyq_^KcOl*KOV?sVmQu)kp$I_HT;#$+{ zB@q4!nVOl`s(V1$3=bmgL2-3axi=7IQ80hbl-#)tN-=jR*I{R#_5t9TvEmW(<{j?; z>)8Y~U6TO34xCjMKrxfNxgp8`%KxhdK%^i;HnyI=D{&IP^-NujrjXuW;axW4_`N7j zxZ@5$Pyb~&j*iPcS5fK@i0IAo4DU1Z$(t((062Iyh0pxgX92~aOs&IC-(2-U4E-{6 zFHrx$P6tkfa3Iu97f9vqMq~x>8-%+kn9nlx!MAewoO{cA#%bN>bLhyGm1DH~QVMr! zH}po*@-}6WhbUzH(P@2H__IYy=8(_)&_6K(fCe_fvXC)xfMKlzW}#S4-ds>#c;dsO z=|21~@3Z!O8dGCl-3nK%bdSK8e)`+)k48$D8d0_xbh*ua# zAA|mdQRrP?m3gx7 z9_TtZ@-md{{}{+L_c8?9)c@`VHBm!np%YvS?1!!mFwZrTD$6Jy)rj$@<5l-xTRl)pvjR!O$j zaGm-rpbSD>d)#qom@smmaC?Wt;{d4X*lAtbuQ?h6z};zM+T=J!jT6b-D3qf^^-QF8 zb@;u1UgH4h*>UZ1bhuG6nY$5WNo-$ogUV}FnghVIgy^<87v3Tei6iUUQc*UnIl%22 z`sk<5CK#ArwS3p|CK$yau6?dT`x=T(2pf=rA2%eRk-Zjlv$Wh$_1%NGx?oN3_XwJ| z0Dqj&O1r!;h{zaJVl*P-P+S4%I$yA;8CK{ya2B@uCQ0i6Xu*!{3lnd;RiYz@zryzU zUahf((H;Ow0+e5wVNS5Ws09ftQwI?B2=FL{bhs(9$tBtgfL{o&&uBX6?61Gssv${r z@pCguZRYUcW`5DDU%+VV=o|okF?H98!;F~M=JcyEI(T^nD-9PaZ^dJFhJRK=feVINcf00000NkvXXu0mjf>+^_D literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/PointCloudProcess/images/rotate270.png b/src/WBCLFZSystemModule/PointCloudProcess/images/rotate270.png new file mode 100644 index 0000000000000000000000000000000000000000..5f84dd559d20cfae987c29609a8e619ca8a7bbec GIT binary patch literal 2537 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 literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/PointCloudProcess/images/seting.png b/src/WBCLFZSystemModule/PointCloudProcess/images/seting.png new file mode 100644 index 0000000000000000000000000000000000000000..8f8558fc3d41be6c7360d374b32989c7d100e089 GIT binary patch literal 3092 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 iEW7U)r(4cmTT92|^Lz?sYqTq5BZo& zv*t3FSO7iw9GJ#E*Y`vMF!FZ+y5<;z zlkYE8&eR4lI;vr2w@CS+5CaItG_z4Jgk%5^7&Ua^ZT5pI(Pl4!ig@`aG&-UR!5e@W zB92XP{X@qb?93sRERX{rEXHLS^o))&urmcuu_Xa{074?#2%u9YC;%nc+1mFL6-N945QZ9cA!3a02eeO;07Mx`ZI1i{C_`w_m6&eb0`aI6 z1fq+W&OGvx4F*6NLIW;Ed#v+dp7aW8@prxlJ9phnHaGywBZYY_u0QMmEqwM0YU%eE zu(NA#sH>EN2T;z2kRC>kS$nX7zr`Pb@Gy+0F}-jWW%mb5eJg;WR-xFXg0q%>!_05@2yQkoyQG zrn5O2;dlTL>AmV}+qU@5=yrnW9DvO-!K}zI55dVjlhKI>0K*iuT?IkL{q$oa28CjL3rc$IXs?CuzD*T+rP-D z%xaU!#-j;F2&)AkLin*5x|IR3n1%?QXk|cz@MAG_D+6LN4G}u=54VU_P$}V@j{pDw M07*qoM6N<$f^4O|Pyhe` literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/PointCloudProcess/images/up.png b/src/WBCLFZSystemModule/PointCloudProcess/images/up.png new file mode 100644 index 0000000000000000000000000000000000000000..e1cf7bc3b47238c81af48604320e6561a3809526 GIT binary patch literal 487 zcmeAS@N?(olHy`uVBq!ia0vp^@<1%d!3-oH>zJ+sQY`6?zK#qG8~eHcB(ehe3dtTp zz6=aiY77hwEes65fIFHg+e!a4?^2m`Rfq{W@=FIv3|Np9rWoT`MaC`{m<`W zNnOSruBJA}iL#;eC`KVGHbs*chCHvuk3=_Et*Tc zqc*T8c%QG>n~*5Cui}{4=PSm~e;#@HYJDp|qf-6luLf+tUSwWeaoh0CvC!sBjZ^F2 zMGDC8|5N_|Dd+$5!qQhoYXg8zQY~?fC`m~yNwrEYN(E93Mg~TPx`u|jMg}2#4` literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/PointCloudProcess/images/zoomin.png b/src/WBCLFZSystemModule/PointCloudProcess/images/zoomin.png new file mode 100644 index 0000000000000000000000000000000000000000..83eb56471bcd96a04095c25f9f46ad13194fb960 GIT binary patch literal 2339 zcmV+;3EcLHP)~p-#za^x@X?J zH}|gnUu*r}+WV}%);>aijSIXJIhm0M3Bwd!XlU_Cf9EAGP1YK9uJfH26Ut zo&C4|GOHd}GF3Eb`B~(0lM%TLxT*#00Q4bp+DT{I&K7VIr)EPyu{;fA7Ru#`8k-l` z3bF>@UfKNATHmUT6L@W`PmZDJONgD z1xTrR!!w_;8sC}IDr$2CSnkh&sZA*TE6@q@G{PRbbPtl>O)z&4#qtPX1l8Q|+V7l> zLYWMVZ36#sPCK>0hUr~R%;_bXo`8b86XC-t6#Wv^N2NmGY)c{ETcogjB)ObLl_Db7 zq?o@C)$s(S7gETEMA8vpxi14JH&medTO`+xZ?Er*A(3;6?j))#M3|O{sWOqkemqgG zP9T{8%iY_Z#Kew0sI)Wel=fCav7zAw_iBWNK;unU^_*rSp)moL_Xy~eSmRWF0r>?4 zbN)HTo0JnVD4+Yp=a}C$z+(RMmzyUw;koi1}IDModv11WGPheZbx)c1ISGb ze)Teb_2qx3Q5#J_q5LgGz8Viu9f#j$5|d*yCcC4l@=SbW>PCXnXVVxLCZLw&=&AwhBPfR(L0kt+UU?UAKzJ#gc~NnDsPF+@KmoODBYI?I$+;hE2cuukH$dvPPE-UL`>leI-1Z1$i!vDrsV zS|3`Lv%H^xUJ-%w0!Q9)A)9Bt6sP0A1ehbO%8w%jRc<^2y)|;HtbJH?Z$SBeguo;C&Zqm!=FD;9k|g17Do$ix)4c~2yoV9} zOxPg34Zjq#!)9)N>wtxopG2yUhJZw#qhgPaj({m0Cvo`TftU@XPbaL_J!t{K^7era z3nS#l;?E0Zk3!MC7A5KkyBFU%vjtO*&D5g15#`E|a@CmxrFHe63k7#E!p#xkzaGCd ziUhx@kl_?eI8|0o#DIjo%cl% zuq(0|Av&H)={HIKAEyyu>VYTLErG~v&@6$+pw^M;JyfO<*bgQWP+JDx?WyEi5o&Ox z?FBnw#VHKV?T=6uc`7snm@M$x2m-Dru$Q-D^D&uQD33+NM0NcL@Et3>1meoy!uO~+ zrWx`7H45I9h;9t;X|jZh9m;r31hfHB|LNc1J861>#}`4Cy9}5gHcBGv8p5Ym59i3? z=-pnsMiI;(n66J&G+OR+z`5Zi-Sts|`A>(JfceC7qn?`}I*&>zzDJOi(OKb4UU44P z+>QviS9wK-vfVx$LqPc^kne<9)B6cZ;SDk?gR{mdxHlrShhgbkSNc;-O( z1Qlmf*0yGjS6Ds-$(yrF_=1J7fQqv;o`CLU@DwmU90hD7a8mWzGIy#Oz}N_`!jkbvHaBLJnOkFK|uTmlw+?fb#W2FB`UWz(|IAS4bj++FK8LR6tyQbcnZ{i zWx1Py3Gt>>FUN2D`GAvPl`jQ}zYeGD0+~)=|2~av@nx^89?0|0{pJcvxLVYMEPS1c zb5|NgnaEgWb1{2$0@efg&edu4HLm*=%4Z|;=f+_25INfEwEM3z-2I$4NApx+4YD5J zPSw;&E_@ce35c5IkTAqUX-^w^Nock2O?sQlFGOq3M!f5XDbiKYG;5!B*cBCV~OuwXjIwy$f6irI! zmAr)L6QB=6Zaaqu?~c5yV`_MVWCS7~1TiXPbWD1Cvy#*oA@|MDt20))10aFM-0X@-h_+5qsvooKa zm3s|v4x)6BuP&yuE&4u_<*otZ?=nUddizd5kENy?n?Kx!sCi>-T=qoN{^K2Jz9ZGG z^g?+RBJr=%h%TX0I$9lWoq+%K*z(3BYF?qc0@V+-K*j;korv5|^|iHe#f(_|f?Gy# z8f^VXFHL1jKrb>@jzPQ5hula+O`p!}?4uAFf~sj<9YEy3(Z7wuoc01^v;9G9dB&{43EX~J*a#shSCjheFADExZg(k zN*xIs@SW*z4+3f=cz2=twKqwqIdA@c`w-Ag!Xi{h_c(7p`Va1k={@$(dBy+$002ov JPDHLkV1n?4dQJcU literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/PointCloudProcess/images/zoomout.png b/src/WBCLFZSystemModule/PointCloudProcess/images/zoomout.png new file mode 100644 index 0000000000000000000000000000000000000000..3a254c14c312728d6ad17b2fd5359a74a5153f57 GIT binary patch literal 2399 zcmV-l3840gP)6@b4p(@KO!giKh z?a#bvX(e0RAWbZyq6j5|b zoO{l>-<*5jx#!*|3|2d>ayUmagPNX>$Y@|R)ZPbuf3q9v|NdG3U)YWEEW?K1&HZ!# zK3Hxw>Xo({n!5Z1a=B@UoCjRgg6?|HV44*e*w&B!sy?CZji?jcG9Cek^BzA`8z3=#{grf<&LlapVM(D z(}0Oh=zoY~jxMlaR!QymS8oy%+jgST$*7|`TM5NP#|!?&2#bK^MOXEtW+NdPfK#~-bb73FD!+pKRfO~Y z*ev-0$vb`pSdh^7RbJN^;v-Wx5|%!f#knYedXl575|lSR z&$2kuw9J&saSYR>P18aGZ$+BkC;+FtB{suTy_~RgN1Dex#Hnx1ur+dEH5)Z5u{p(R~ih*z)fx9G0aen|#*<@|D zjm=I}r!@PB>1Q}@@lsh#=-xQ6(I4pLRDK3}fknr2yz#En**xckIQ{KeY;~ zTubQQ){>Kh31C{qp{CUs-xC4934s4|>wey3c%w$1*>aLIm;lVkor(|YS|DsA@IILw z0aI6)hYCQ^ z--vQy#1Ylmgr#+jp9=+l3Bt9O@Lx|*y6mk7pgbRyXazYY-w>Qi7w8u(E9aL8-0#2j z08~DKs%@jTj=-B8jexj4zsM}A?uJYN3gtq&T<%=!HrD(y)E-RjAC|&Y86z-d%_xTL zv(*E(5_pkogeB$`F=O&0QpjwJQBgppK_eu=~fN3jEp_Y5X;?^s?EF*c$-5&#> zd=1F=qSW+G!cugBY-ZqnvO@u&;9rf<8Ffz|At;?~bGtX&izf%dxm3MP0~vF_K7$RQ zuzUoPH+z@p1q34dGxhY39m7C9HI}0 zgP%B+1)%2m*%CoqLg@XZr6?Fo08{;Oy&9K8OxWxEW^8{2I;Miyn@DJ1{ra*Ei&NHoO05*I1g?Q>Yw+XzYnEXqlj7TN4tV z0*zle{$}8uc;{;86LkEtY3Ez*;FQk>iN6k~JP9(3(EUReQ}Jc5i|)$vuNTb~lxVf6 zPqXk1s@~0647EkZDVvMgt5bB{Mc`eW)n0PluTVY_k-sD>lY7X~Nw+(AmEqp!yxE#( z3Tu${1a787o%F(Ip>htQW;&!asi1Ub4ZSpN_3ur3o69dk>w~u>IZ0Y{EkWsvX?D^9 z)E%iuf_YZIJ0%)kszX2?CR|`jZ3Alse-ffo>Mvn5cX_(e-j4`8qa(Iu17NzJRX&!( z#GDjO%{D4|0nvv+?}glB>>s|vdRNEP@P^44L_Q2+ZlX^G9h=PtW}!2$)Xa*NSG}FE zG(Yb9>;R00=}V4a--xw{q+edPTYMcbhb=o0#-Nxh^Zl#08AlFu(IdCA$$b*1vJUj~ z@eqj32%7`YXQ5t3lMc`c+5K&oq&^S1Z%1C8amrmFmP6hHc14y^b+2snVqgIJqGA7g z3pV+S9CFt3U(nY?ugzgUeeJ00W1H|8Dv=n*=4xrCda~hl9-+`!kV{B6ULDYZo zE;Qej=~jB7yb6){S7}6Vqgpyx9c~@Kn@8+aCL?NIp}PRpkF)?|59oG8?xgnW+PGpy ztp0*uMu_e_`#QYo(o}l^^nsetupUi(this); +} + +inputDialog::~inputDialog() +{ + delete ui; +} diff --git a/src/WBCLFZSystemModule/PointCloudProcess/inputdialog.h b/src/WBCLFZSystemModule/PointCloudProcess/inputdialog.h new file mode 100644 index 0000000..6a8a175 --- /dev/null +++ b/src/WBCLFZSystemModule/PointCloudProcess/inputdialog.h @@ -0,0 +1,23 @@ +#pragma once +#ifndef INPUTDIALOG_H +#define INPUTDIALOG_H + +#include + +namespace Ui { +class inputDialog; +} + +class inputDialog : public QDialog +{ + Q_OBJECT + +public: + explicit inputDialog(QWidget *parent = nullptr); + ~inputDialog(); + +private: + Ui::inputDialog *ui; +}; + +#endif // INPUTDIALOG_H diff --git a/src/WBCLFZSystemModule/PointCloudProcess/inputdialog.ui b/src/WBCLFZSystemModule/PointCloudProcess/inputdialog.ui new file mode 100644 index 0000000..d5ba1cd --- /dev/null +++ b/src/WBCLFZSystemModule/PointCloudProcess/inputdialog.ui @@ -0,0 +1,330 @@ + + + inputDialog + + + + 0 + 0 + 250 + 466 + + + + 颜色属性控制 + + + + :/images/color.png:/images/color.png + + + + + + + + + 0 + 0 + + + + + 180 + 60 + + + + + 16 + 75 + true + + + + è½´å‘颜色å˜åŒ– + + + + + + + 16 + 50 + false + + + + X + + + false + + + + + + + + 16 + 50 + false + + + + Y + + + true + + + + + + + + 16 + 50 + false + + + + Z + + + false + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + 0 + 0 + + + + + 230 + 180 + + + + + 16 + 75 + true + + + + Color mode + + + + + + + 16 + 50 + false + + + + è“色->红色 + + + + + + + + 16 + 50 + false + + + + 绿色->å“红 + + + + + + + + 16 + 50 + false + + + + 白->红 + + + + + + + + 16 + 50 + false + + + + ç°/红 + + + + + + + + 16 + 50 + false + + + + 彩虹 + + + true + + + + + + + 自定义 + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + + + 0 + 0 + + + + + 50 + 40 + + + + + 24 + 75 + true + + + + - + + + + + + + + 0 + 0 + + + + + 16 + + + + Qt::LeftToRight + + + QFrame::NoFrame + + + 1 + + + 1 + + + Qt::AlignCenter + + + + + + + + 0 + 0 + + + + + 50 + 40 + + + + + 24 + 75 + true + + + + + + + + + + + + + + + + + + + diff --git a/src/WBCLFZSystemModule/PointCloudProcess/pclvisualizer.cpp b/src/WBCLFZSystemModule/PointCloudProcess/pclvisualizer.cpp new file mode 100644 index 0000000..87cdefa --- /dev/null +++ b/src/WBCLFZSystemModule/PointCloudProcess/pclvisualizer.cpp @@ -0,0 +1,1263 @@ +#pragma execution_character_set("utf-8") + +#include "pclvisualizer.h" +#include "ui_pclvisualizer.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "BasePCL.h" +#include "PointCloudAlg.h" +#include "ToolDialog.h" + +PCLVisualizer::PCLVisualizer(QWidget* parent) + : QMainWindow(parent) + , point_size(5) // 设置åˆå§‹èƒŒæ™¯é¢œè‰² + , ui(new Ui::PCLVisualizer) //是å¦é»˜è®¤å¼€å¯RGBA显示点云 + , isRBGA(true) // æ˜¯å¦æ˜¾ç¤ºç¬¬äºŒä¸ªç‚¹äº‘ + , bgColor(0, 0, 50) // åˆå§‹åŒ–顺åºè¦å’Œå£°æ˜Žçš„顺åºä¸€è‡´ +{ + ui->setupUi(this); + // cout << "INIT" << endl; + initPCV(); + + // //创建动作,工具æ ä»¥åŠèœå•æ  + createActions(); + // createMenus(); + // åˆ›å»ºå·¥å…·æ  + createToolBars(); + + //åˆå§‹åŒ–ç‚¹äº‘æ•°æ® + initPointCloud(); + + // ç»™QVTKé…ç½®PCLViewer显示 + viewer_.reset(new pcl::visualization::PCLVisualizer("viewer", false)); + //设置背景颜色 + viewer_->setBackgroundColor(double(bgColor.red()) / 255, + double(bgColor.green()) / 255, + double(bgColor.blue()) / 255); + + + // 原始代ç å› ä¸º pcl 1.13.1 涉åŠçš„ vtk 版本废弃,å‚考:https://blog.csdn.net/dyk4ever/article/details/126715543 + vtkSmartPointer renderer2 = vtkSmartPointer::New(); + vtkSmartPointer renderWindow2 = vtkSmartPointer::New(); + renderWindow2->AddRenderer(renderer2); + + viewer_.reset(new pcl::visualization::PCLVisualizer(renderer2, renderWindow2, "viewer", false)); + ui->qvtkWidget->setRenderWindow(viewer_->getRenderWindow()); + viewer_->setupInteractor(ui->qvtkWidget->interactor(), ui->qvtkWidget->renderWindow()); + viewer_->setBackgroundColor(0, 0, 0); + ui->qvtkWidget->update(); + connectSS(); + + + viewer_->setPointCloudRenderingProperties( + pcl::visualization::PCL_VISUALIZER_POINT_SIZE, point_size); + // viewer_->addCoordinateSystem(1); + viewer_->resetCamera(); + // æž„å»ºç‚¹äº‘ç®¡ç†æ¨¡å—,并进行绑定 + this->cloudmanager=new CloudPointManagerClass(this); // åˆå§‹åŒ–点云管ç†å™¨ + this->cloudmanager->bandingViewer(viewer_, this->ui->filesList); // 绑定点云显示窗å£ï¼Œç‚¹äº‘æ–‡ä»¶åˆ—è¡¨ç®¡ç†æ¨¡å— + // åˆå§‹åŒ–çŠ¶æ€æ  + this->statusbarprogressBar = new QProgressBar(); + this->ui->statusbar->addPermanentWidget(this->statusbarprogressBar); + qDebug() << "ç‚¹äº‘å¤„ç† ç³»ç»Ÿ,系统åˆå§‹åŒ–完æˆã€‚"; +} + +PCLVisualizer::~PCLVisualizer() +{ + delete ui; + delete cloudmanager; +} + +void PCLVisualizer::initPCV() +{ + //设置窗å£åç§° + QString str = "PointCloudViewer"; + this->setWindowTitle(str); + + showLogItem("PCV 系统", "系统正在åˆå§‹åŒ–..."); + + logStr = "主窗å£ä½ç½®å·²è¿˜åŽŸ: " + QString("X-Y-Width-Height(%1,%2,%3,%4)") + .arg(this->x()) + .arg(this->y()) + .arg(this->width()) + .arg(this->height()); + showLogItem("PCV 窗å£", logStr); + + //写ini文件,记录当å‰çª—å£ä½ç½®å’Œå¤§å°ï¼š + QString wstrFilePath = + qApp->applicationDirPath() + "/setting.ini"; // .iniæ”¾åœ¨å·¥ç¨‹æºæ–‡ä»¶ç›®å½•下 + settings = new QSettings( + wstrFilePath, QSettings::IniFormat); //用QSetting获å–iniæ–‡ä»¶ä¸­çš„æ•°æ® + // settings->clear(); //清空当å‰é…置文件中的内容 +} + +void +PCLVisualizer::showLogItem(QString item, QString info) +{ + //--------------------LOG-------------------------- + logStr = "[" + QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss") + + "] " + " [ " + item + " ] " + info; + logList.push_back(logStr); + ui->logList->addItem(logStr); + //--------------------LOG-------------------------- +} + +void +PCLVisualizer::saveSetting(QString key, QString value) +{ + //写ini文件,记录当å‰çª—å£ä½ç½®å’Œå¤§å°ï¼š + QString wstrFilePath = + qApp->applicationDirPath() + "/setting.ini"; // .iniæ”¾åœ¨å·¥ç¨‹æºæ–‡ä»¶ç›®å½•下 + QSettings* settings = new QSettings( + wstrFilePath, QSettings::IniFormat); //用QSetting获å–iniæ–‡ä»¶ä¸­çš„æ•°æ® + // settings->clear(); //清空当å‰é…置文件中的内容 + settings->setValue(key, value); + settings->sync(); +} + +QVariant +PCLVisualizer::getSetting(QString name) +{ + return settings->value(name); +} + +void +PCLVisualizer::createActions() +{ + //添加点云 + // addCloudAction = + // new QAction(QIcon(":/images/files/cloud.png"), "添加点云", this); + // addCloudAction->setShortcut(tr("Ctrl+O")); //(b) + // addCloudAction->setStatusTip(tr("添加点云")); //(c) + + //æ–°å»ºå·¥ä½œå° + newWorkStationAction = + new QAction(QIcon(":/images/files/add.png"), tr("new"), this); + newWorkStationAction->setShortcut(tr("Ctrl+N")); + newWorkStationAction->setStatusTip(tr("new")); + + //打开点云文件 + newCloudAction = + new QAction(QIcon(":/images/files/new2.png"), tr("打开点云文件"), this); + // exitAction->setShortcut(tr("Ctrl+Q")); + newCloudAction->setStatusTip(tr("打开点云文件")); + + //å¤åˆ¶ç‚¹äº‘ + copyCloudAction = + new QAction(QIcon(":/images/files/copy.png"), tr("å¤åˆ¶ç‚¹äº‘"), this); + copyCloudAction->setShortcut(tr("Ctrl+C")); + copyCloudAction->setStatusTip(tr("å¤åˆ¶ç‚¹äº‘")); + + //剪切点云 + cutCloudAction = + new QAction(QIcon(":/images/files/cut.png"), tr("剪切点云"), this); + cutCloudAction->setShortcut(tr("Ctrl+X")); + cutCloudAction->setStatusTip(tr("剪切点云")); + + //粘贴点云 + pasteCloudAction = + new QAction(QIcon(":/images/files/paste.png"), tr("粘贴点云"), this); + pasteCloudAction->setShortcut(tr("Ctrl+V")); + pasteCloudAction->setStatusTip(tr("粘贴点云")); + + //查找点云文件 + searchCloudAction = + new QAction(QIcon(":/images/files/search.png"), tr("查找点云文件"), this); + searchCloudAction->setShortcut(tr("Ctrl+F")); + searchCloudAction->setStatusTip(tr("查找点云文件")); + + //导出点云至PCD文件 + exportCloud2PCDAction = new QAction( + QIcon(":/images/files/pointCloud.png"), tr("导出点云至PCD文件"), this); + exportCloud2PCDAction->setStatusTip(tr("导出点云至PCD文件")); + + //导出点云至PLY文件 + exportCloud2PLYAction = new QAction( + QIcon(":/images/files/cloud2.png"), tr("导出点云至PLY文件"), this); + exportCloud2PLYAction->setStatusTip(tr("导出点云至PLY文件")); + + //导出点云至CSV文件 + export2CSVAction = + new QAction(QIcon(":/images/files/CSV.png"), tr("导出点云至CSV文件"), this); + export2CSVAction->setStatusTip(tr("导出点云至CSV文件")); + + //导出点云至TXT文件 + export2TXTAction = + new QAction(QIcon(":/images/files/txt.png"), tr("导出点云至TXT文件"), this); + export2TXTAction->setStatusTip(tr("导出点云至TXT文件")); + + //æ”¶è—点云文件 + starCloudAction = + new QAction(QIcon(":/images/files/star.png"), tr("æ”¶è—点云文件"), this); + starCloudAction->setStatusTip(tr("æ”¶è—点云文件")); + + //导出å±å¹•截图 + snapShotAction = + new QAction(QIcon(":/images/files/snapshot.png"), tr("导出å±å¹•截图"), this); + snapShotAction->setStatusTip(tr("导出å±å¹•截图")); + + //离群点移除 + outliersRemoveAction = new QAction( + QIcon(":/images/algorithm/KMeans.png"), tr("outliersRemove"), this); + outliersRemoveAction->setStatusTip(tr("outliersRemove")); + + //滤波平滑 + filterAction = + new QAction(QIcon(":/images/algorithm/filter.png"), tr("滤波平滑"), this); + filterAction->setStatusTip(tr("滤波平滑")); + + //点云下采样 + downSampleAction = + new QAction(QIcon(":/images/algorithm/density.png"), "downSampling", this); + downSampleAction->setStatusTip(tr("downSampling")); + + //点云拼接 + cloudSpliceAction = + new QAction(QIcon(":/images/algorithm/pingjie.png"), "点云拼接", this); + cloudSpliceAction->setStatusTip(tr("点云拼接")); + + //点云直方图 + HistogramAction = + new QAction(QIcon(":/images/algorithm/Histogram.png"), "Histogram", this); + HistogramAction->setStatusTip(tr("Histogram")); + + //表é¢é‡å»º + surfaceAction = + new QAction(QIcon(":/images/algorithm/matrix.png"), "surface", this); + surfaceAction->setStatusTip(tr("surface")); + + //点云é…准 + alignAction = + new QAction(QIcon(":/images/algorithm/DBSCAN.png"), "点云é…准", this); + alignAction->setStatusTip(tr("点云é…准")); + // MLS细化 + MLSAction = + new QAction(QIcon(":/images/algorithm/nihe.png"), "MLS细化", this); + MLSAction->setStatusTip(tr("MLS细化")); +} + +void PCLVisualizer::createMenus() +{} + +void PCLVisualizer::createToolBars() +{ + //ç‚¹äº‘æ–‡ä»¶å·¥å…·æ  + fileTool = addToolBar("cloudFile"); + + fileTool->addAction(newWorkStationAction); + // fileTool->addAction(addCloudAction); + fileTool->addAction(ui->actionload_point_cloud); + fileTool->addAction(newCloudAction); + fileTool->addAction(copyCloudAction); + fileTool->addAction(cutCloudAction); + fileTool->addAction(pasteCloudAction); + + fileTool->addSeparator(); + + fileTool->addAction(exportCloud2PCDAction); + fileTool->addAction(exportCloud2PLYAction); + fileTool->addAction(export2CSVAction); + fileTool->addAction(export2TXTAction); + fileTool->addAction(ui->actionExportLog); + fileTool->addAction(snapShotAction); + + fileTool->addSeparator(); + + fileTool->addAction(starCloudAction); + fileTool->addAction(searchCloudAction); + fileTool->addAction(ui->actionBGColor); + + //ç®—æ³•å·¥å…·æ  + algorithmTool = addToolBar("algorithm"); + algorithmTool->addAction(ui->actionbestRemoval); + algorithmTool->addAction(ui->actionbestFiltering); + algorithmTool->addAction(ui->actionbestKeypoint); + algorithmTool->addAction(ui->actionbestRegistration); + algorithmTool->addAction(ui->actionbestSurface); + algorithmTool->addAction(MLSAction); + algorithmTool->addAction(HistogramAction); +} + +void PCLVisualizer::test() +{ + qDebug() << "Hello World!"; +} + +void PCLVisualizer::initPointCloud() +{ + //// Setup the cloud pointer + //cloud_.reset(new PointCloudT); + //cloud.reset(new PointCloudT); + //cloud_noise.reset(new PointCloudT); + //cloud_filtered.reset(new PointCloudT); + //cloud_filtered_guass.reset(new PointCloudT); + //cloud_filtered_guass_down.reset(new PointCloudT); + //cloud_filtered_out.reset(new PointCloudT); + + //cloud_in.reset(new PointCloudT); + //cloud_tr.reset(new PointCloudT); + //cloud_RE.reset(new PointCloudT); + + //cloudRGBA_.reset(new PointCloudTRGBA); + + //// The number of points in the cloud + //cloud_->resize(1000); + //cloudRGBA_->resize(1000); + //// Fill the cloud with random points + //for (size_t i = 0; i < cloud_->points.size(); ++i) { + // cloud_->points[i].x = 1024 * rand() / (RAND_MAX + 1.0f); + // cloud_->points[i].y = 1024 * rand() / (RAND_MAX + 1.0f); + // cloud_->points[i].z = 1024 * rand() / (RAND_MAX + 1.0f); + //} + + //// 获å–点云内的最大点和最å°ç‚¹ + //pcl::getMinMax3D(*cloud_, p_min, p_max); + //maxLen = getMaxValue(p_max, p_min); + + ////æ‹·è´ä¸€ä»½ç»™RGBA点云 + //pcl::copyPointCloud(*cloud_, *cloudRGBA_); + + //showLogItem("PCV 主窗å£", "点云åˆå§‹åŒ–完æˆ"); +} + +//è¿žæŽ¥ä¿¡å·æ§½ +void PCLVisualizer::connectSS() +{ + + connect(ui->actionload_point_cloud, + &QAction::triggered, + this, + &PCLVisualizer::loadPCDFile); + connect(ui->actionsave_point_cloud, + &QAction::triggered, + this, + &PCLVisualizer::savePCDFile); + connect(ui->actionCoordinateSystem, + &QAction::triggered, + this, + &PCLVisualizer::AddCoordinateSystem); + // Connect "Load" and "Save" buttons and their functions + + //增加新工作å°åŠŸèƒ½ + connect(newWorkStationAction, + &QAction::triggered, + this, + &PCLVisualizer::newWorkStation); +} + +void PCLVisualizer::savePCDFile() +{ + //QString filename = + // getSaveFilePath(this, + // tr("Open point cloud"), + // "/home/", + // tr("Point cloud data(*.pcd *.ply)")); + //PCL_INFO("File chosen: %s\n", filename.toUtf8().constData()); + + //if (filename.isEmpty()) + // return; + //int return_status; + //if (filename.endsWith(".pcd", Qt::CaseInsensitive)) + // return_status = pcl::io::savePCDFileBinary(filename, *cloud_); + //else if (filename.endsWith(".ply", Qt::CaseInsensitive)) + // return_status = pcl::io::savePLYFileBinary(filename, *cloud_); + //else { + // filename.append(".ply"); + // return_status = pcl::io::savePLYFileBinary(filename, *cloud_); + //} + //if (return_status != 0) { + // PCL_ERROR("Error writing point cloud %s\n", filename.toUtf8().constData()); + // return; + //} +} + +void PCLVisualizer::loadPCDFile() +{ + QString fileFormat, fileName, fileBaseName, pointCount, filePath, fileSuffix, + lastPath; + //è¯»å–æ–‡ä»¶å + //è®°ä½ä¸Šä¸€æ¬¡åŠ è½½çš„è·¯å¾„ + + lastPath = getSetting("FilePath/lastPath").toString(); + + QString filePathWithName = + QFileDialog::getOpenFileName(this, tr("Open point cloud or Soil SCane File xyz"), + lastPath, + tr("Point cloud data (*.pcd *.ply *.xyz)")); + QFileInfo fileInfo; + fileInfo = QFileInfo(filePathWithName); + //文件å + fileName = fileInfo.fileName(); + //文件åŽç¼€ + fileSuffix = fileInfo.suffix(); + //ç»å¯¹è·¯å¾„ + filePath = fileInfo.absolutePath(); + fileBaseName = fileInfo.baseName(); + //qDebug() << fileName << endl + // << fileSuffix << endl + // << filePath << endl + // << fileInfo.baseName() << endl + // << fileInfo.completeBaseName(); + + showLogItem("点云文件选择", filePath); + // PCL_INFO("File chosen: %s\n", filePathWithName.toUtf8().constData()); + + pcl::PointCloud::Ptr cloud_tmp(new pcl::PointCloud); + + if (filePathWithName.isEmpty()) { + showLogItem("文件加载失败", filePathWithName); + return; + } + + showLogItem("文件加载æˆåŠŸ", filePathWithName); + // 将当剿–‡ä»¶è·¯å¾„ä¿å­˜ï¼Œä¸‹æ¬¡ä½¿ç”¨ + saveSetting("FilePath/lastPath", filePathWithName); + + //判断文件类型然åŽåŠ è½½ç‚¹äº‘ + int return_status; + showLogItem("点云加载中", "文件格å¼ä¸ºï¼š" + fileFormat); + + return_status = cloudmanager->addPointCloud(filePathWithName, fileSuffix); + + //判断是å¦åŠ è½½æˆåŠŸ + if (return_status != 0) { + PCL_ERROR("Error reading point cloud %s\n", + filePathWithName.toUtf8().constData()); + + showLogItem("点云加载中", fileName + " 文件读å–失败。"); + return; + } + PCL_INFO("file has loaded\n"); + + showLogItem("点云加载完æˆ", fileFormat); + +} + +void PCLVisualizer::loadPLYFile() +{ + QString fileFormat, fileName, fileBaseName, pointCount, filePath, fileSuffix; + //è¯»å–æ–‡ä»¶å + QString lastPath = getSetting("FilePath/lastPath").toString(); + filePathWithName = + QFileDialog::getOpenFileName(this, + tr("Open point cloud"), + lastPath, + tr("Point cloud data (*.pcd *.ply)")); + QFileInfo fileInfo; + fileInfo = QFileInfo(filePathWithName); + //文件å + fileName = fileInfo.fileName(); + //文件åŽç¼€ + fileSuffix = fileInfo.suffix(); + //ç»å¯¹è·¯å¾„ + filePath = fileInfo.absolutePath(); + fileBaseName = fileInfo.baseName(); + + QString cloudFile = fileName + " [" + filePath + "]"; + QListWidgetItem* item = new QListWidgetItem; + // item->setBackgroundColor(QColor(220, 230, 250)); + item->setBackground(QBrush(QColor(220, 230, 250))); + item->setData(Qt::DisplayRole, cloudFile); + item->setData(Qt::CheckStateRole, Qt::Checked); + ui->filesList->addItem(item); +} + +void PCLVisualizer::chooseAxis() +{ + +} + +void PCLVisualizer::chooseColorMode() +{ + + +} + +void PCLVisualizer::IncPointSize() +{ + // setValue函数会自动调用 SpinBox的触å‘动作 + ui->pointSizeEdt->setValue(++point_size); +} + +void PCLVisualizer::DecPointSize() +{ + if (point_size == 1) + return; + ui->pointSizeEdt->setValue(--point_size); +} + +void PCLVisualizer::AddCoordinateSystem() +{ + QString str = ui->actionCoordinateSystem->text(); + if (str.compare("CoordinateSystem [OFF]") == 0) { + qDebug() << str; + ui->actionCoordinateSystem->setText("CoordinateSystem [ON]"); + viewer_->addCoordinateSystem(); + } else { + ui->actionCoordinateSystem->setText("CoordinateSystem [OFF]"); + viewer_->removeCoordinateSystem(); + } + ui->qvtkWidget->update(); +} + + +//软件关闭时动作 +void +PCLVisualizer::closeEvent(QCloseEvent* event) +{ + //写ini文件,记录当å‰çª—å£ä½ç½®å’Œå¤§å°ï¼š + QString wstrFilePath = + qApp->applicationDirPath() + "/setting.ini"; // .iniæ”¾åœ¨å·¥ç¨‹æºæ–‡ä»¶ç›®å½•下 + QSettings* settings = new QSettings( + wstrFilePath, QSettings::IniFormat); //用QSetting获å–iniæ–‡ä»¶ä¸­çš„æ•°æ® + // settings->clear(); //清空当å‰é…置文件中的内容 + settings->setValue("WindowGeometry/x", this->x()); + settings->setValue("WindowGeometry/y", this->y()); + settings->setValue("WindowGeometry/width", this->width()); + settings->setValue("WindowGeometry/height", this->height()); + qDebug() << "Position is right:" << this->x() << " " << this->y() << " " + << this->width() << " " << this->height(); +} + +void +PCLVisualizer::on_actionUp_triggered() +{ + //if (!cloud_->empty()) { + // viewer_->setCameraPosition(0.5 * (p_min.x + p_max.x), + // 0.5 * (p_min.y + p_max.y), + // p_max.z + 2 * maxLen, + // 0.5 * (p_min.x + p_max.x), + // 0.5 * (p_min.y + p_max.y), + // p_max.z, + // 0, + // 1, + // 0); + // ui->qvtkWidget->update(); + //} +} + +void +PCLVisualizer::on_actionBottom_triggered() +{ + //if (!cloud_->empty()) { + // viewer_->setCameraPosition(0.5 * (p_min.x + p_max.x), + // 0.5 * (p_min.y + p_max.y), + // p_min.z - 2 * maxLen, + // 0.5 * (p_min.x + p_max.x), + // 0.5 * (p_min.y + p_max.y), + // p_min.z, + // 0, + // 1, + // 0); + // ui->qvtkWidget->update(); + //} +} + +void +PCLVisualizer::on_actionFront_triggered() +{ + //if (!cloud_->empty()) { + // viewer_->setCameraPosition(0.5 * (p_min.x + p_max.x), + // p_min.y - 2 * maxLen, + // 0.5 * (p_min.z + p_max.z), + // 0.5 * (p_min.x + p_max.x), + // p_min.y, + // 0.5 * (p_min.z + p_max.z), + // 0, + // 0, + // 1); + // ui->qvtkWidget->update(); + //} +} + +void +PCLVisualizer::on_actionBack_triggered() +{ + //if (!cloud_->empty()) { + // viewer_->setCameraPosition(0.5 * (p_min.x + p_max.x), + // p_max.y + 2 * maxLen, + // 0.5 * (p_min.z + p_max.z), + // 0.5 * (p_min.x + p_max.x), + // p_min.y, + // 0.5 * (p_min.z + p_max.z), + // 0, + // 0, + // 1); + // ui->qvtkWidget->update(); + //} +} + +void +PCLVisualizer::on_actionLeft_triggered() +{ + +} + +void +PCLVisualizer::on_actionRight_triggered() +{ + +} + +double +PCLVisualizer::getMinValue(pcl::PointXYZRGBA p1, pcl::PointXYZRGBA p2) +{ + double min = 0; + + if (p1.x - p2.x > p1.y - p2.y) { + min = p1.y - p2.y; + } else { + min = p1.x - p2.x; + } + + if (min > p1.z - p2.z) { + min = p1.z - p2.z; + } + return min; +} + +double +PCLVisualizer::getMaxValue(pcl::PointXYZRGBA p1, pcl::PointXYZRGBA p2) +{ + double max = 0; + + if (p1.x - p2.x > p1.y - p2.y) { + max = p1.x - p2.x; + + } else { + max = p1.y - p2.y; + } + + if (max < p1.z - p2.z) { + max = p1.z - p2.z; + } + + return max; +} + +void +PCLVisualizer::openProgressDlg(int num = 500) +{ + //åˆ›å»ºä¸€ä¸ªè¿›åº¦å¯¹è¯æ¡† + QProgressDialog* progressDialog = new QProgressDialog(this); + QFont font("ZYSong18030", 12); + progressDialog->setFont(font); + progressDialog->setWindowModality(Qt::WindowModal); //(d) + progressDialog->setMinimumDuration(5); //(e) + progressDialog->setWindowTitle(tr("Please Wait")); //(f) + progressDialog->setLabelText(tr("Processing...")); //(g) + progressDialog->setCancelButtonText(tr("Cancel")); //(h) + progressDialog->setRange(0, num); //è®¾ç½®è¿›åº¦å¯¹è¯æ¡†çš„æ­¥è¿›èŒƒå›´ + for (int i = 1; i < num + 1; i++) { + Sleep(10); + progressDialog->setValue(i); //(i) + if (progressDialog->wasCanceled()) //(j) + return; + } +} + +void PCLVisualizer::showStatusBarTip(QString text, size_t value) +{ + this->ui->statusbar->showMessage(text); + if (this->statusbarprogressBar->maximum() > value) { + this->statusbarprogressBar->setValue(value); + } + else { + this->statusbarprogressBar->setValue(this->statusbarprogressBar->maximum()); + } + return; +} + +void +PCLVisualizer::updateCloudInfo() +{ + // TODO æš‚æ—¶åªæ›´æ–°ç‚¹äº‘æ•°é‡ + //ui->pointCountEdt->setText(QString::number(cloud_->points.size())); +} + +void +PCLVisualizer::best_filter() +{ + +} + +void +PCLVisualizer::cloudTransform(pcl::PointCloud< pcl::PointXYZRGBA>::Ptr cloud_in, + pcl::PointCloud< pcl::PointXYZRGBA>::Ptr cloud_tr, + double theta, + double z) +{ + //设置旋转矩阵和平移å‘é‡ + Eigen::Matrix4d transformation_matrix = Eigen::Matrix4d::Identity(); + + //旋转角度 + // double theta = M_PI / 4; // The angle of rotation in radians + transformation_matrix(0, 0) = cos(theta); + transformation_matrix(0, 1) = -sin(theta); + transformation_matrix(1, 0) = sin(theta); + transformation_matrix(1, 1) = cos(theta); + + double x = ui->lineEdit_X->text().toDouble(); + double y = ui->lineEdit_Y->text().toDouble(); + double zz = ui->lineEdit_Z->text().toDouble(); + qDebug() << "x:" << x << " y:" << y << " z:" << zz << endl; + transformation_matrix(0, 3) = x; // 0.1m + transformation_matrix(1, 3) = y; // 0.1m + transformation_matrix(2, 3) = zz; // 0.1m + // transformation_matrix(2, 3) = z; // 0.1m + // Zè½´æ–¹å‘上的平移 + // A translation on Z axis (0.4 meters) + // transformation_matrix(2, 3) = z; // 0.1m + + // Display in terminal the transformation matrix + // qDebug() << "对æºç‚¹äº‘进行旋转平移:" << "\n"; + print4x4Matrix(transformation_matrix); + + //将原始点云先旋转平移 + // Executing the transformation + pcl::transformPointCloud(*cloud_in, *cloud_tr, transformation_matrix); +} + +void +PCLVisualizer::ICP_aligin(pcl::IterativeClosestPoint::Ptr icp, + pcl::PointCloud< pcl::PointXYZRGBA>::Ptr cloud_in, + pcl::PointCloud< pcl::PointXYZRGBA>::Ptr cloud_RE) +{ + icp->setMaximumIterations(1); + icp->setInputSource(cloud_RE); + icp->setInputTarget(cloud_in); + icp->align(*cloud_RE); + icp->setMaximumIterations(1); // We set this variable to 1 for the next time + // we will call .align () function + //qDebug() << "Applied " << iterations << " iteration(s)" << "\n"; + if (icp->hasConverged()) { + qDebug() << "\nHasConverged: " << icp->hasConverged() + << ", getFitnessScore: " << icp->getFitnessScore() << "\n"; + cout << "Transformation: \n" << icp->getFinalTransformation() << endl; + print4x4Matrix(icp->getFinalTransformation().cast()); + qDebug() << get4x4MatrixStr(icp->getFinalTransformation().cast()) + << endl; + ////ui->matEdit.setText(get4x4MatrixStr(icp->getFinalTransformation().cast())); + ui->matEdit->setPlainText( + get4x4MatrixStr(icp->getFinalTransformation().cast())); + } else { + PCL_ERROR("\nICP has not converged.\n"); + // return (-1); + } +} + +void +PCLVisualizer::best_aligin() +{ + +} + +void +PCLVisualizer::best_surface() +{ + +} + +void +PCLVisualizer::newWorkStation() +{ + PCLVisualizer* newPCV = new PCLVisualizer; + //新建的工作窗å£ä½äºŽä¹‹å‰çª—å£çš„å³ä¸‹æ–¹ + newPCV->setGeometry( + this->x() + 20, this->y() + 50, this->width(), this->height()); + newPCV->show(); +} + +void +PCLVisualizer::on_actionBGColor_triggered() +{ + QColor color = QColorDialog::getColor( + bgColor, this); //打开颜色选择窗å£ï¼Œå¹¶ç”¨å½“å‰é¢œè‰²åˆå§‹åŒ– + if (color.isValid()) { + bgColor = color; + qDebug() << "color: " << bgColor.red() << " " << bgColor.green() << " " + << bgColor.blue(); + viewer_->setBackgroundColor(double(bgColor.red()) / 255, + double(bgColor.green()) / 255, + double(bgColor.blue()) / 255); + ui->qvtkWidget->update(); + } +} + +void +PCLVisualizer::on_actionabout_triggered() +{} + +void +PCLVisualizer::on_comboBox_Color_currentIndexChanged(const QString& arg1) +{ + + +} + +void +PCLVisualizer::on_actionCoordinateSystem_triggered() +{} + +void +PCLVisualizer::on_actionCameraview_triggered() +{} + +void +PCLVisualizer::on_pointSizeEdt_valueChanged(int arg1) +{ + +} + +void +PCLVisualizer::on_actionbestSurface_triggered() +{ + +} + +void +PCLVisualizer::on_actionbestRemoval_triggered() +{ + + +} + +void +PCLVisualizer::on_actionbestFiltering_triggered() +{ + +} + +void +PCLVisualizer::on_actionbestRegistration_triggered() +{ + +} + +void +PCLVisualizer::on_actionbestKeypoint_triggered() +{ + +} + +void +PCLVisualizer::on_actionTXT_triggered() +{} + +void +PCLVisualizer::on_actionExportLog_triggered() +{ + + QString filename = QFileDialog::getSaveFileName( + this, tr("Save Log"), tr("Log(*.txt)")); + PCL_INFO("File chosen: %s\n", filename.toUtf8().constData()); + + QFile file; + file.setFileName(filename); + QByteArray data; + + QString log; + for (auto it = logList.begin(); it != logList.end(); ++it) { + log.append(*it + "\n"); + } + if (file.open(QIODevice::WriteOnly)) { + QByteArray res2 = log.toUtf8(); // toLatin1()转为QByteArray + file.write(res2); + file.close(); + } +} + +void +PCLVisualizer::on_actionRedo_triggered() +{ + +} + +void +PCLVisualizer::on_actionquit_triggered() +{} + +double +obb(pcl::PointCloud::Ptr cloud) //点云OBB有å‘包围盒 +{ + pcl::MomentOfInertiaEstimation feature_extractor; + feature_extractor.setInputCloud(cloud); + feature_extractor.compute(); + + std::vector moment_of_inertia; + std::vector eccentricity; + pcl::PointXYZRGBA min_point_OBB; + pcl::PointXYZRGBA max_point_OBB; + pcl::PointXYZRGBA position_OBB; + Eigen::Matrix3f rotational_matrix_OBB; + float major_value, middle_value, minor_value; + Eigen::Vector3f major_vector, middle_vector, minor_vector; + Eigen::Vector3f mass_center; + + feature_extractor.getMomentOfInertia(moment_of_inertia); + feature_extractor.getEccentricity(eccentricity); + feature_extractor.getOBB( + min_point_OBB, max_point_OBB, position_OBB, rotational_matrix_OBB); + feature_extractor.getEigenValues(major_value, middle_value, minor_value); + feature_extractor.getEigenVectors(major_vector, middle_vector, minor_vector); + feature_extractor.getMassCenter(mass_center); + + return (max_point_OBB.x - min_point_OBB.x) * + (max_point_OBB.y - min_point_OBB.y) * + (max_point_OBB.z - min_point_OBB.z); + +} + +double +aabb(pcl::PointCloud::Ptr cloud) //点云AABB包围盒 +{ + pcl::MomentOfInertiaEstimation feature_extractor; + feature_extractor.setInputCloud(cloud); + feature_extractor.compute(); + + std::vector moment_of_inertia; + std::vector eccentricity; + + pcl::PointXYZRGBA min_point_AABB; // AABB包围盒 + pcl::PointXYZRGBA max_point_AABB; + + Eigen::Vector3f major_vector, middle_vector, minor_vector; + Eigen::Vector3f mass_center; + + feature_extractor.getMomentOfInertia(moment_of_inertia); + feature_extractor.getEccentricity(eccentricity); + feature_extractor.getAABB(min_point_AABB, max_point_AABB); + feature_extractor.getEigenVectors(major_vector, middle_vector, minor_vector); + feature_extractor.getMassCenter(mass_center); + + return (max_point_AABB.x - min_point_AABB.x) * + (max_point_AABB.y - min_point_AABB.y) * + (max_point_AABB.z - min_point_AABB.z); +} + +void +PCLVisualizer::on_actiongetAllGeo_triggered() +{ + vtkSmartPointer reader = vtkSmartPointer::New(); + reader->SetFileName(filePathWithName.toUtf8()); + reader->Update(); + vtkSmartPointer tri = + vtkSmartPointer::New(); + tri->SetInputData(reader->GetOutput()); + tri->Update(); + vtkSmartPointer poly = + vtkSmartPointer::New(); + poly->SetInputData(tri->GetOutput()); + poly->Update(); + + double pV = poly->GetVolumeProjected(); + double pX = poly->GetVolumeX(); + double pY = poly->GetVolumeY(); + double pZ = poly->GetVolumeZ(); + double vol = poly->GetVolume(); //体积 + double area = poly->GetSurfaceArea(); //表é¢ç§¯ + double maxArea = poly->GetMaxCellArea(); //最大å•å…ƒé¢ç§¯ + double minArea = poly->GetMinCellArea(); //最å°å•å…ƒé¢ç§¯ + + pcl::PLYReader PLY_reader; + pcl::PointCloud::Ptr cloud(new pcl::PointCloud); + PLY_reader.read(filePathWithName.toUtf8().constData(), *cloud); + + double vol_aabb = aabb(cloud); + double vol_obb = obb(cloud); + + ui->lineEdit_AABB->setText(QString::number(vol_aabb)); + ui->lineEdit_OBB->setText(QString::number(vol_obb)); + ui->lineEdit_area->setText(QString::number(area)); + ui->lineEdit_maxUnitAera->setText(QString::number(maxArea)); + ui->lineEdit_minUnitAera->setText(QString::number(minArea)); + ui->lineEdit_vol->setText(QString::number(vol)); + + // QMessageBox::information( + // this, "几何属性æå–æˆåŠŸ", "表é¢ç§¯ã€ä½“积等计算完æˆ", "确定"); + + cout << "vol: " << vol << endl; + cout << "area: " << area << endl; + cout << "maxArea: " << maxArea << endl; + cout << "minArea: " << minArea << endl; + cout << "pV: " << pV << endl; + cout << "pX: " << pX << endl; + cout << "pY: " << pY << endl; + cout << "pZ: " << pZ << endl; +} + +void +PCLVisualizer::on_actionplaneSeg_triggered() +{ + +} + +//显示PLY文件 +void +PCLVisualizer::on_actionarea_triggered() +{ + loadPLYFile(); + // pcl::PolygonMesh mesh; + // pcl::io::loadPLYFile(filePathWithName, mesh); + // viewer_->removePointCloud("cloud"); + // viewer_->addPolygonMesh(mesh, "my"); + // viewer_->resetCamera(); + // ui->qvtkWidget->update(); +} + +void +PCLVisualizer::on_actionvol_triggered() +{ + QMessageBox::information( + this, "几何属性æå–æˆåŠŸ", "表é¢ç§¯ã€ä½“积等计算完æˆ", "确定"); +} + +//////////////////////////////////////////////////// +// ç¦»ç¾¤ç‚¹ã€æ»¤æ³¢ã€é‡å»ºè¡¨é¢ +//////////////////////////////////////////////////// + +/// +/// 统计离群点去除 +/// +void PCLVisualizer::on_actionStatisticalRemove_triggered() +{ + StatisticalOutlierRemovalWindows tool(this); + tool.bandingComboxAndPoint(this->cloudmanager->getItemNames()); + tool.exec(); + + QString in_cloud_name = tool.getComboxSelect(); + // -- LOG --- + logStr = "[" + QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss") +"] " + "[统计离群点去除] " + "Point Cloud Plane Segmentation Done."; + logList.push_back(in_cloud_name); + ui->logList->addItem(logStr); + // --- end LOG ---- + std::shared_ptr item_ptr= this->cloudmanager->getItemFromName(in_cloud_name); + + +} + +/// +/// 密度离群点去除 +/// +void PCLVisualizer::on_actionDB_triggered() +{ + RadiusOutlierRemovalWindows tool(this); + tool.bandingComboxAndPoint(this->cloudmanager->getItemNames()); + tool.exec(); + + +} + + +void PCLVisualizer::on_actionBilateral_triggered() +{ + BilateralFilterWindows tool(this); + tool.bandingComboxAndPoint(this->cloudmanager->getItemNames()); + tool.exec(); + + +} + +void PCLVisualizer::on_actionMedian2_triggered() +{ + MedianFilterWindows tool(this); + tool.bandingComboxAndPoint(this->cloudmanager->getItemNames()); + tool.exec(); +} + +void PCLVisualizer::on_actionGP_triggered() +{ + DialogTriangulationSurfaceMesh tool(this); + tool.bandingComboxAndPoint(this->cloudmanager->getItemNames()); + tool.exec(); + QString in_cloud_name = tool.getComboxSelect(); + // -- LOG --- + logStr = "[" + QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss") + "] " + "[贪婪三角网构建å¯åЍ] " + "Point Cloud Plane Segmentation Done."; + logList.push_back(in_cloud_name); + ui->logList->addItem(logStr); + // --- end LOG ---- + std::shared_ptr item_ptr = this->cloudmanager->getCloudPointItemFromName(in_cloud_name); + + QString meshpath=tool.ExcuteCmd(item_ptr->pointCloud); + this->cloudmanager->addMeshSTL(meshpath); + // -- LOG --- + logStr = "[" + QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss") + "] " + "[贪婪三角网构建结æŸ] " + "FILE has Save:"+ meshpath; + logList.push_back(in_cloud_name); + ui->logList->addItem(logStr); + // --- end LOG ---- +} + +void PCLVisualizer::on_actionPoisson_triggered() +{ + PoissonReSurfaceWindows tool(this); + tool.bandingComboxAndPoint(this->cloudmanager->getItemNames()); + tool.exec(); +} + +int ShowPclvisualizer(QWidget* parent) +{ + vtkOutputWindow::SetGlobalWarningDisplay(0); //ä¸å¼¹å‡ºvtkOutputWindowçª—å£ + + QPixmap pixmap("logo1.png"); // 读å–图片 + QSplashScreen splash(pixmap); // + + //读å–ini文件中上一次关闭软件时候的窗å£ä½ç½®å’Œå¤§å°ï¼š + qDebug() << qApp->applicationDirPath() << endl; + QString wstrFilePath = qApp->applicationDirPath() + "/setting.ini"; + QSettings* settings = new QSettings( + wstrFilePath, QSettings::IniFormat); //用QSetting获å–iniæ–‡ä»¶ä¸­çš„æ•°æ® + int x = settings->value("WindowGeometry/x").toInt(); + int y = settings->value("WindowGeometry/y").toInt(); + int width = settings->value("WindowGeometry/width").toInt(); + int height = settings->value("WindowGeometry/height").toInt(); + qDebug() << "Position is right:" << x << " " << y << " " << width << " " + << height; + QDesktopWidget* desktopWidget = QApplication::desktop(); + QRect clientRect = desktopWidget->availableGeometry(); + QRect targRect0 = QRect(clientRect.width() / 4, + clientRect.height() / 4, + clientRect.width() / 2, + clientRect.height() / 2); + QRect targRect = QRect(x, y, width, height); + if ( + width == 0 || height == 0 || x < 0 || x > clientRect.width() || y < 0 || + y > clientRect.height()) //如果上一次关闭软件的时候,窗å£ä½ç½®ä¸æ­£å¸¸ï¼Œåˆ™æœ¬æ¬¡æ˜¾ç¤ºåœ¨æ˜¾ç¤ºå™¨çš„æ­£ä¸­å¤® + { + targRect = targRect0; + qDebug() << "Position is not right:" << x << " " << y << " " << width << " " << height; + } + + PCLVisualizer* w=new PCLVisualizer(parent); + w->setAttribute(Qt::WA_DeleteOnClose);// 关闭时自动释放 + w->setGeometry(targRect); //设置主窗å£çš„å¤§å° + w->show(); + + //splash.finish(w); //在主体对象åˆå§‹åŒ–完æˆåŽç»“æŸå¯åŠ¨åŠ¨ç”» + + return 0; +} + + + +////////////////// 测试点云构网 //////////////////////////////////////////////////// +void PCLVisualizer::Test_BestSurface() { + // 加载点云 + best_surface(); +} + +CloudPointManagerClass::CloudPointManagerClass(QWidget* parent) +{ + + +} + + +CloudPointManagerClass::~CloudPointManagerClass() +{ +} + +int CloudPointManagerClass::bandingViewer(pcl::visualization::PCLVisualizer::Ptr viewerPtr, QListWidget* filelist) +{ + this->viewerPtr = viewerPtr; + this->filelist = filelist; + return 0; +} + +int CloudPointManagerClass::addPointCloud(QString filePathWithName, QString fileFormat) +{ + int return_status; + pcl::PointCloud< pcl::PointXYZRGBA>::Ptr cloud_tmp(new pcl::PointCloud< pcl::PointXYZRGBA>); + if (filePathWithName.endsWith(".pcd", Qt::CaseInsensitive)) { + return_status = + pcl::io::loadPCDFile(filePathWithName.toUtf8().constData(), *cloud_tmp); + fileFormat = "PCD"; + + } + else if (filePathWithName.endsWith(".xyz", Qt::CaseInsensitive)) { + + // 1. 打开文件 + QString filePathWithName = "your_file_path.txt"; + QFile file(filePathWithName); + if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { + qDebug() << "Failed to open the file."; + return -1; + } + + // 2. è¯»å–æ–‡ä»¶å†…容 + QTextStream in(&file); + int pointcount = 0; + QStringList templist; + + // 3. å¤„ç†æ¯ä¸€è¡Œæ•°æ® + while (!in.atEnd()) { + QString line = in.readLine(); + templist = line.split(' '); + + // 4. 处ç†åˆ†å‰²å¾—åˆ°çš„æ•°æ® + if (templist.size() >= 3) { + // 开始相关的点云存储设置 + double x = templist[0].toDouble() / 100.0; + double y = templist[1].toDouble() / 100.0; + double z = templist[2].toDouble() / 100.0; + + pcl::PointXYZRGBA p; + p.x = templist[0].toDouble() / 100.0; + p.y = templist[1].toDouble() / 100.0; + p.z = templist[2].toDouble() / 100.0;//åæ ‡ + cloud_tmp->points.push_back(p); + + } + } + + // 5. 关闭文件 + file.close(); + cloud_tmp->is_dense = false; + return_status = 0; + } + else { + return_status = pcl::io::loadPLYFile(filePathWithName.toUtf8().constData(), *cloud_tmp); + fileFormat = "PLY"; + } + + + // 生æˆç‚¹äº‘对象 + std::shared_ptr cloudItem(new CloudPointItemClass); + QFileInfo fileinfo(filePathWithName); + cloudItem->name = fileinfo.fileName();// 文件å + cloudItem->filepath = filePathWithName; + cloudItem->pointCloud.reset(new pcl::PointCloud< pcl::PointXYZRGBA>); + pcl::copyPointCloud(*cloud_tmp, *(cloudItem->pointCloud)); // 这样写å¯èƒ½å­˜åœ¨é—®é¢˜ + + // 绑定item + this->DataList.insert(cloudItem->name, cloudItem); + // 添加到 filelist + QListWidgetItem* item = new QListWidgetItem; + + item->setBackground(QBrush(QColor(220, 230, 250))); + item->setData(Qt::DisplayRole, cloudItem->name); + item->setData(Qt::CheckStateRole, Qt::Checked); + this->filelist->addItem(item); + // 添加到渲染 + cloudItem->ViewerShow(this->viewerPtr); + cloudItem->ZoomOnExtend(this->viewerPtr); + qDebug() << "The number of points :" << cloudItem->pointCloud->points.size(); + return 0; +} + diff --git a/src/WBCLFZSystemModule/PointCloudProcess/pclvisualizer.h b/src/WBCLFZSystemModule/PointCloudProcess/pclvisualizer.h new file mode 100644 index 0000000..6192d5e --- /dev/null +++ b/src/WBCLFZSystemModule/PointCloudProcess/pclvisualizer.h @@ -0,0 +1,398 @@ +#pragma once +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include //添加QDateTime头文件 +#include +#include +#include +#include + +// Point Cloud Library +#include +#include +#include +#include // TicToc +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include //éšæœºæ•° +#include +#include +#include // TicToc +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include // 4PCS算法 +#include //K4PCS算法头文件 +#include +#include +#include +#include +#include //贪婪投影三角化算法类定义的头文件 +#include //移动立方体 +#include +#include //MLS +#include //泊æ¾é‡å»º +#include +#include +#include +#include +#include + +#include // TicToc +#include // 体素滤波 +#include // 体素滤波 +#include + +#include +#include +#include +#include +#include +#include //éšæœºå‚数估计方法 +#include //模型定义 +#include //RANSAC分割 +#include +#include +#include //rand()头文件 +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +//å¯è§†åŒ–相关头文件 +#include +#include +#include +#include +#include +#include +#include +#include +// Boost +#include + +// Visualization Toolkit (VTK) +#include +#include "ui_pclvisualizer.h" +#include "inputdialog.h" +#include "BasePCL.h" +#include "ToolDialog.h" +#include "PointManagerClass.h" + + +QT_BEGIN_NAMESPACE +namespace Ui { + class PCLVisualizer; +}; +QT_END_NAMESPACE + + + +class PCLVisualizer : public QMainWindow +{ + Q_OBJECT + +public: + CloudPointManagerClass *cloudmanager; // 点云管ç†å™¨ + QProgressBar* statusbarprogressBar; // çŠ¶æ€æ  +public: + PCLVisualizer(QWidget* parent = nullptr); + ~PCLVisualizer(); + + void initPCV(); + void showLogItem(QString item, QString info); //显示logä¿¡æ¯ + void saveSetting(QString name, QString item); // ä¿å­˜è®¾ç½® + QVariant getSetting(QString name); + void createActions(); //创建动作 + void createMenus(); //创建èœå• + void createToolBars(); //åˆ›å»ºå·¥å…·æ  + + //ç‚¹äº‘åæ ‡æžå€¼ + pcl::PointXYZRGBA p_min, p_max; + + double maxLen; + + double getMinValue(pcl::PointXYZRGBA p1, pcl::PointXYZRGBA p2); + double getMaxValue(pcl::PointXYZRGBA p1, pcl::PointXYZRGBA p2); + + QString filePathWithName; + + // æ‰“å¼€è¿›åº¦çª—å£ + void openProgressDlg(int num); + void showStatusBarTip(QString text, size_t value); + // æ›´æ–°ç‚¹äº‘ä¿¡æ¯ + void updateCloudInfo(); + + /************************************************************************/ + /* 点云预处ç†ç®—法 */ + /************************************************************************/ + //全局å˜é‡ PCD文件IO + pcl::PCDWriter writer; + pcl::PCDReader reader; + + //键盘事件 + int nextShow = 0; + bool next_iteration = false; + void keyboardEventOccurred(const pcl::visualization::KeyboardEvent& event, + void* nothing) + { + if (event.getKeySym() == "space" && event.keyDown()) { + ++nextShow; + next_iteration = true; + } + } + + void best_filter(); + /* + 将点云旋转平移 + */ + void cloudTransform(pcl::PointCloud< pcl::PointXYZRGBA>::Ptr cloud_in, + pcl::PointCloud< pcl::PointXYZRGBA>::Ptr cloud_tr, + double theta = M_PI / 4, + double z = 0.1); + + /* + 迭代最近点算法 + é…ç½®ICPçš„å‚æ•°,并设置åªè¿›è¡Œä¸€æ¬¡è¿­ä»£ï¼Œç„¶åŽè®¡ç®—一次 +*/ + void ICP_aligin(pcl::IterativeClosestPoint::Ptr icp, + pcl::PointCloud< pcl::PointXYZRGBA>::Ptr cloud_in, + pcl::PointCloud< pcl::PointXYZRGBA>::Ptr cloud_RE); + + void best_aligin(); + + void best_surface(); + +public slots: + + //æ–°å»ºå·¥ä½œå° + void newWorkStation(); + + void test(); + //åˆå§‹åŒ–æ•°æ® + void initPointCloud(); + //è¿žæŽ¥ä¿¡å·æ§½ + void connectSS(); + //ä¿å­˜æ–‡ä»¶ + void savePCDFile(); + void loadPCDFile(); + void loadPLYFile(); + + //é€‰æ‹©éœ€è¦æŽ§åˆ¶çš„åæ ‡è½´ + void chooseAxis(); + //é€‰æ‹©é¢œè‰²æ¨¡å¼ + void chooseColorMode(); + //增大 Point Size + void IncPointSize(); + //å‡å° Point Size + void DecPointSize(); + //添加/å–æ¶ˆå标轴 + void AddCoordinateSystem(); + +protected: + virtual void closeEvent(QCloseEvent* event); + + int point_size; + QColor point_color; + //创建一个共享的PCLVisualizer 对象用于显示 + pcl::visualization::PCLVisualizer::Ptr viewer_; + //创建一个共享指针用于ä¿å­˜ç‚¹äº‘ + ////原始点云 + //PointCloudT::Ptr cloud_; + ////彩色点云 + //PointCloudTRGBA::Ptr cloudRGBA_; + + /** @brief åæ ‡è½´ï¼š0 = x | 1 = y | 2 = z */ + int filtering_axis_; + + /** @brief 颜色模å¼ï¼šHolds the color mode for @ref colorCloudDistances */ + int color_mode_; + +private slots: + + // 测试模型 + void Test_BestSurface(); + + + //工具æ ä¸­çš„视图选择工作 6个 + void on_actionUp_triggered(); + + void on_actionBottom_triggered(); + + void on_actionFront_triggered(); + + void on_actionBack_triggered(); + + void on_actionLeft_triggered(); + + void on_actionRight_triggered(); + + void on_actionBGColor_triggered(); + + void on_actionabout_triggered(); + + void on_comboBox_Color_currentIndexChanged(const QString& arg1); + + void on_actionCoordinateSystem_triggered(); + + void on_actionCameraview_triggered(); + + void on_pointSizeEdt_valueChanged(int arg1); + + void on_actionbestSurface_triggered(); + + void on_actionbestRemoval_triggered(); + + void on_actionbestFiltering_triggered(); + + void on_actionbestRegistration_triggered(); + + void on_actionbestKeypoint_triggered(); + + void on_actionTXT_triggered(); + + void on_actionExportLog_triggered(); + + void on_actionRedo_triggered(); + + void on_actionquit_triggered(); + + void on_actiongetAllGeo_triggered(); + + void on_actionplaneSeg_triggered(); + + void on_actionarea_triggered(); + + void on_actionvol_triggered(); + + // 新增工具项 + void on_actionStatisticalRemove_triggered(); // 统计离群点 + + void on_actionDB_triggered(); // 密度离群点 + + void on_actionBilateral_triggered(); // åŒè¾¹æ»¤æ³¢ + + void on_actionMedian2_triggered(); // 中值 + + void on_actionGP_triggered(); // 贪婪三角网 + + void on_actionPoisson_triggered(); // æ³Šæ¾ + + + +private: + Ui::PCLVisualizer* ui; + inputDialog* inputDlg; + + //软件设置 + QSettings* settings; + QString logStr; + QStringList logList; + + QTime q_time; + + bool isRBGA; + + QColor bgColor; + + QMenu* fileMenu; //å„项èœå•æ  + QMenu* zoomMenu; + QMenu* rotateMenu; + QMenu* mirrorMenu; + + QString fileName; + + //点云文件处ç†åŠ¨ä½œ + QAction* addCloudAction; + QAction* newWorkStationAction; + QAction* exportCloud2PCDAction; + QAction* exportCloud2PLYAction; + QAction* newCloudAction; + QAction* copyCloudAction; + QAction* cutCloudAction; + QAction* pasteCloudAction; + QAction* searchCloudAction; + QAction* export2CSVAction; + QAction* export2TXTAction; + QAction* starCloudAction; + QAction* snapShotAction; + + QAction* outliersRemoveAction; //镜åƒèœå•项 + QAction* filterAction; + QAction* alignAction; + QAction* MLSAction; + QAction* downSampleAction; + QAction* cloudSpliceAction; + QAction* HistogramAction; + QAction* surfaceAction; + + QToolBar* fileTool; //å·¥å…·æ  + QToolBar* algorithmTool; +}; + + +int ShowPclvisualizer(QWidget* parent); diff --git a/src/WBCLFZSystemModule/PointCloudProcess/pclvisualizer.ui b/src/WBCLFZSystemModule/PointCloudProcess/pclvisualizer.ui new file mode 100644 index 0000000..ee6438a --- /dev/null +++ b/src/WBCLFZSystemModule/PointCloudProcess/pclvisualizer.ui @@ -0,0 +1,1963 @@ + + + PCLVisualizer + + + + 0 + 0 + 1059 + 787 + + + + PCLVisualizer + + + + + + + + 50 + 0 + + + + + 640 + 480 + + + + + + + + + 255 + 255 + 255 + + + + + + + 255 + 255 + 255 + + + + + + + + + 255 + 255 + 255 + + + + + + + 255 + 255 + 255 + + + + + + + + + 255 + 255 + 255 + + + + + + + 255 + 255 + 255 + + + + + + + + Qt::PreventContextMenu + + + + + + + + + 0 + 0 + 1059 + 22 + + + + + 文件 + + + + 导出为 + + + + + + + + + + + + + + + + + + + + å¿«æ·é”® + + + + + + + + + + + + + + + + 工具 + + + + + + + + + + + + + + + + + 离群点移除 + + + + + + + + + + + + 连接 + + + + + + + + + 滤波 + + + + + + + + + + + + + + + é…准 + + + + + + + + + + + + + + + 表é¢é‡å»º + + + + + + + + + + + + + + + çª—å£ + + + + + + + + + + 关键点 + + + + + + + + + + + + + + 几何属性 + + + + + + + + + + + + + + + 点云分割 + + + + + + + + + + + + + + + 文件导出 + + + + + + + + + + + + + + + + + + + + toolBar + + + LeftToolBarArea + + + false + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 点云处ç†è¾“出 + + + 8 + + + + + + + QAbstractItemView::AllEditTriggers + + + QAbstractItemView::SingleSelection + + + + + + + + + 点云属性 + + + 1 + + + + + + + QAbstractItemView::AllEditTriggers + + + QAbstractItemView::SingleSelection + + + + + + + + 0 + 0 + + + + 0 + + + + 点云属性 + + + + + + QFrame::NoFrame + + + QFrame::Raised + + + ç‚¹äº‘æ•°é‡ + + + Qt::AlignCenter + + + + + + + 56932 + + + Qt::AlignCenter + + + false + + + + + + + QFrame::NoFrame + + + QFrame::Raised + + + 颜色 + + + Qt::AlignCenter + + + + + + + QFrame::NoFrame + + + QFrame::Raised + + + ç‚¹å¤§å° + + + Qt::AlignCenter + + + + + + + Qt::AlignCenter + + + 1 + + + + + + + bunny + + + Qt::AlignCenter + + + false + + + + + + + binary + + + Qt::AlignCenter + + + false + + + + + + + å¦ + + + Qt::AlignCenter + + + true + + + + + + + Qt::PreventContextMenu + + + Qt::LeftToRight + + + false + + + QComboBox::AdjustToContents + + + + RGB + + + + :/images/RGB.png:/images/RGB.png + + + + + NONE + + + + :/images/grey.png:/images/grey.png + + + + + + + + X-Y-Z + + + Qt::AlignCenter + + + false + + + + + + + QFrame::NoFrame + + + QFrame::Raised + + + 有åºç‚¹äº‘ + + + Qt::AlignCenter + + + + + + + QFrame::NoFrame + + + QFrame::Raised + + + æ ¼å¼ + + + Qt::AlignCenter + + + + + + + QFrame::NoFrame + + + QFrame::Raised + + + 字段 + + + Qt::AlignCenter + + + + + + + QFrame::NoFrame + + + QFrame::Raised + + + 文件åç§° + + + Qt::AlignCenter + + + + + + + QFrame::NoFrame + + + QFrame::Raised + + + æ•°æ®æ ¼å¼ + + + Qt::AlignCenter + + + + + + + PCD + + + Qt::AlignCenter + + + false + + + + + + + 1 + + + + 转æ¢çŸ©é˜µ + + + + + + QFrame::Box + + + 1.00 0.00 0.00 0.00 +0.00 1.00 0.00 0.00 +0.00 0.00 1.00 0.00 +0.00 0.00 0.00 1.00 + + + + + + + + + 旋转角度 + + + + + 10 + 10 + 113 + 20 + + + + 0 + + + + + + 10 + 40 + 113 + 20 + + + + 1 + + + + + + 10 + 70 + 113 + 20 + + + + 0 + + + + + + + + + + 几何属性 + + + + + + QFrame::NoFrame + + + QFrame::Raised + + + 表é¢ç§¯ï¼š + + + Qt::AlignCenter + + + + + + + QFrame::NoFrame + + + QFrame::Raised + + + 最大å•å…ƒé¢ç§¯ï¼š + + + Qt::AlignCenter + + + + + + + QFrame::NoFrame + + + QFrame::Raised + + + 立方米 + + + Qt::AlignCenter + + + + + + + QFrame::NoFrame + + + QFrame::Raised + + + 平方米 + + + Qt::AlignCenter + + + + + + + 24.6096 + + + Qt::AlignCenter + + + false + + + + + + + QFrame::NoFrame + + + QFrame::Raised + + + OBB包围盒体积 + + + Qt::AlignCenter + + + + + + + QFrame::NoFrame + + + QFrame::Raised + + + 体积: + + + Qt::AlignCenter + + + + + + + QFrame::NoFrame + + + QFrame::Raised + + + AABB包围盒体积 + + + Qt::AlignCenter + + + + + + + 318.685 + + + Qt::AlignCenter + + + false + + + + + + + QFrame::NoFrame + + + QFrame::Raised + + + 平方米 + + + Qt::AlignCenter + + + + + + + QFrame::NoFrame + + + QFrame::Raised + + + 立方米 + + + Qt::AlignCenter + + + + + + + 0.00520274 + + + Qt::AlignCenter + + + false + + + + + + + QFrame::NoFrame + + + QFrame::Raised + + + 立方米 + + + Qt::AlignCenter + + + + + + + 0.00520274 + + + Qt::AlignCenter + + + false + + + + + + + 0.00520274 + + + Qt::AlignCenter + + + false + + + + + + + QFrame::NoFrame + + + QFrame::Raised + + + 最å°å•å…ƒé¢ç§¯ï¼š + + + Qt::AlignCenter + + + + + + + 983.484 + + + Qt::AlignCenter + + + false + + + + + + + QFrame::NoFrame + + + QFrame::Raised + + + 平方米 + + + Qt::AlignCenter + + + + + + + + + + + + + + :/images/camera.png:/images/camera.png + + + 打开 + + + 相机视角 + + + + + + :/images/up.png:/images/up.png + + + Up + + + + + + :/images/bottom.png:/images/bottom.png + + + Bottom + + + + + + :/images/front.png:/images/front.png + + + Front + + + + + + :/images/back.png:/images/back.png + + + Back + + + + + + :/images/left.png:/images/left.png + + + Left + + + + + + :/images/right.png:/images/right.png + + + Right + + + + + + :/images/files/cloud.png:/images/files/cloud.png + + + 加载点云 + + + Ctrl+O + + + + + ä¿å­˜ç‚¹äº‘ + + + + + Point-Based [P] + + + + + WireFrame-Based [W] + + + + + Snapshot [J] + + + + + Camera Param [C] + + + + + Point Size [+/-] + + + + + Zoom [ALT + (+/-)] + + + + + Scale Grid [G] + + + + + LUT [U] + + + + + Perspectice [O] + + + + + Reset Camera [R] + + + + + Stereo Mode [ALT + S] + + + + + æ·»åŠ åæ ‡è½´ + + + + + + :/images/files/bgColor.png:/images/files/bgColor.png + + + 背景颜色 + + + + + Velodyne Lidar + + + + + LeiShen Lidar + + + + + PCD + + + + + PLY + + + + + + :/images/files/txt.png:/images/files/txt.png + + + TXT + + + + + OBJ + + + + + STL + + + + + PCAP + + + + + + :/images/rotate0.png:/images/rotate0.png + + + Rotate0 + + + 旋转 + + + + + + :/images/rotate90.png:/images/rotate90.png + + + Rotate90 + + + 旋转90度 + + + + + + :/images/rotate180.png:/images/rotate180.png + + + Rotate180 + + + 旋转180度 + + + + + + :/images/rotate270.png:/images/rotate270.png + + + Rotate270 + + + 旋转270度 + + + + + + :/images/zoomout.png:/images/zoomout.png + + + zoomIn + + + ç¼©å° + + + + + + :/images/zoomin.png:/images/zoomin.png + + + zoomOut + + + 放大 + + + + + + :/images/redo.png:/images/redo.png + + + Redo + + + é‡åš + + + + + + :/images/undo.png:/images/undo.png + + + Undo + + + 撤销 + + + + + + :/images/reset.png:/images/reset.png + + + ResetPos + + + é‡ç½®ä½ç½® + + + + + + :/images/seting.png:/images/seting.png + + + settin + + + 系统设置 + + + + + ä¸»çª—å£ + + + + + 控制å°çª—å£ + + + + + 点云信æ¯çª—å£ + + + + + 文件信æ¯çª—å£ + + + + + 最近使用文件 + + + + + 关闭所有 + + + + + é€€å‡ºç¨‹åº + + + + + + :/images/coodinate.png:/images/coodinate.png + + + addCoordinate + + + <!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:'SimSun'; font-size:9pt; 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;">æ·»åŠ åæ ‡è½´</p></body></html> + + + + + å±žæ€§æŽ§åˆ¶çª—å£ + + + + + 关于软件 + + + + + è”系作者 + + + + + RPLIDAR + + + + + RS-LIDAR + + + + + 基于统计 + + + + + 基于密度 + + + + + DBSCAN + + + + + DBSCAN-KD + + + + + KANN-DBSCAN + + + + + KANN-DBSCAN-KD + + + + + 高斯滤波 + + + + + 拉普拉斯滤波 + + + + + Desbrun滤波 + + + + + 直通滤波 + + + + + RANSAC滤波 + + + + + 平凿»¤æ³¢ + + + + + Median + + + + + åŒè¾¹æ»¤æ³¢ + + + + + Voxel Grid + + + + + Uniform + + + + + ICP + + + + + NDT + + + + + Super 4PCS + + + + + ISS-Super 4PCS + + + + + MLS + + + + + MLS-GreedyProjection + + + + + 泊æ¾ç®—法 + + + + + NURBS + + + + + RBF + + + + + blobby + + + + + AgastKeypoint2D + + + + + BriskKeypoint2D + + + + + HarrisKeypoint2D + + + + + HarrisKeypoint3D + + + + + ISSKeypoint3D + + + + + NarfKeypoint + + + + + SIFTKeypoint + + + + + SUSANKeypoint + + + + + æ¡ä»¶æ»¤æ³¢ + + + + + KD-tree + + + + + OC-tree + + + + + FPFH + + + + + NICP + + + + + GICP + + + + + MBICP + + + + + SAC-IA + + + + + plane Seg + + + + + å¹³é¢æå– + + + + + 圆柱体æå– + + + + + 法线估计 + + + + + 中值滤波 + + + + + + :/images/algorithm/KMeans.png:/images/algorithm/KMeans.png + + + 一键移除 + + + + + + :/images/algorithm/filter.png:/images/algorithm/filter.png + + + 一键滤波 + + + + + + :/images/algorithm/pingjie.png:/images/algorithm/pingjie.png + + + 一键é…准 + + + + + + :/images/algorithm/binary.png:/images/algorithm/binary.png + + + 一键æå– + + + + + + :/images/algorithm/matrix.png:/images/algorithm/matrix.png + + + 一键é‡å»º + + + + + + :/images/files/log.png:/images/files/log.png + + + å¤„ç†æ—¥å¿—导出 + + + + + 表é¢ç§¯ + + + + + 体积 + + + + + 一键æå– + + + + + å¹³é¢åˆ†å‰² + + + + + 圆柱体分割 + + + + + 欧å¼èšç±»åˆ†å‰² + + + + + 基于颜色的分割 + + + + + 区域生长分割 + + + + + 超体素分割 + + + + + 地é¢åˆ†å‰² + + + + + 点云质心 + + + + + 外接圆 + + + + + 点云密度 + + + + + VoxelGrid + + + + + Uniform + + + + + 体素下采样 + + + + + å‡åŒ€é‡‡æ · + + + + + 增采样 + + + + + 边界æå– + + + + + 贪婪投影三角化算法 + + + + + 移动立方体算法 + + + + + α-shape算法 + + + + + éšæœºé‡‡æ · + + + + + 法线空间采样 + + + + + 法线微分分割 + + + + + 最å°å›¾åˆ†å‰² + + + + + åæ–¹å·®çŸ©é˜µ + + + + + StripImage + + + false + + + + + ScaneImage + + + false + + + + + ISARImage + + + false + + + + + CySARImage + + + false + + + + + ExportStl + + + + + + QVTKOpenGLNativeWidget + QWidget +
QVTKOpenGLNativeWidget.h
+ + test_bestSurface() + +
+
+ + + + + + actionbestSurface + triggered() + PCLVisualizer + Test_BestSurface() + + + -1 + -1 + + + 527 + 351 + + + + + actionCySARImage + triggered() + PCLVisualizer + TestCySARImage() + + + -1 + -1 + + + 527 + 351 + + + + + actionISARImage + triggered() + PCLVisualizer + TestISARImage() + + + -1 + -1 + + + 527 + 351 + + + + + actionScaneImage + triggered() + PCLVisualizer + TestScaneImage() + + + -1 + -1 + + + 527 + 351 + + + + + actionStripImage + triggered() + PCLVisualizer + TestStripImage() + + + -1 + -1 + + + 527 + 351 + + + + + + Test_BestSurface() + TestStripImage() + TestScaneImage() + TestISARImage() + TestCySARImage() + +
diff --git a/src/WBCLFZSystemModule/ProgramParamLoadingClass.cpp b/src/WBCLFZSystemModule/ProgramParamLoadingClass.cpp new file mode 100644 index 0000000..e828ba6 --- /dev/null +++ b/src/WBCLFZSystemModule/ProgramParamLoadingClass.cpp @@ -0,0 +1 @@ +#include "ProgramParamLoadingClass.h" diff --git a/src/WBCLFZSystemModule/ProgramParamLoadingClass.h b/src/WBCLFZSystemModule/ProgramParamLoadingClass.h new file mode 100644 index 0000000..0a84e65 --- /dev/null +++ b/src/WBCLFZSystemModule/ProgramParamLoadingClass.h @@ -0,0 +1,18 @@ +#pragma once +/////////////////////////// +// ϵͳ»·¾³±äÁ¿Àà +////////////////////////// + +#ifndef PROGRAMPARAMLOADINGCLASS_H +#define PROGRAMPARAMLOADINGCLASS_H +#include "AllHead.h" + +class ProgramParamLoadingClass +{ +public: + QString programName ; // ³ÌÐòÃû³Æ + QString lastFilePath ; // Éϴδò¿ªµÄÎļþ·¾¶ + +}; + +#endif \ No newline at end of file diff --git a/src/WBCLFZSystemModule/QConsoleCommandAction.cpp b/src/WBCLFZSystemModule/QConsoleCommandAction.cpp new file mode 100644 index 0000000..088f4cd --- /dev/null +++ b/src/WBCLFZSystemModule/QConsoleCommandAction.cpp @@ -0,0 +1,74 @@ +#include "QConsoleCommandAction.h" + + + + +void BandingModelPrcessAndQConsoleWidget(ModelProcess* w) +{ + + +} + +void OpenQConsoleWidgetFromModelProcess(ModelProcess* w) +{ + // ³õʼ»¯ÃüÁîÐпØÖÆÌ¨ + QConsoleWidget* console = new QConsoleWidget(); + console->setModelProcess(w); +} + +BandingModelPrcessAndQConsoleWidgetClass::BandingModelPrcessAndQConsoleWidgetClass(QObject* parent) +{ +} + +BandingModelPrcessAndQConsoleWidgetClass::~BandingModelPrcessAndQConsoleWidgetClass() +{ +} + +void BandingModelPrcessAndQConsoleWidgetClass::setModelProcess(ModelProcess* modelprocess) +{ + this->modelprocess = modelprocess; +} + +void BandingModelPrcessAndQConsoleWidgetClass::setQConsoleWidget(QConsoleWidget* console) +{ + this->console = console; +} + +ModelProcess* BandingModelPrcessAndQConsoleWidgetClass::getModelProcess() +{ + return this->modelprocess; +} + +QConsoleWidget* BandingModelPrcessAndQConsoleWidgetClass::getQConsoleWidget() +{ + return this->console; +} + +ModelProcess* BandingModelPrcessAndQConsoleWidgetClass::createModelProcess() +{ + this->modelprocess=new ModelProcess(); + return this->modelprocess; +} + +QConsoleWidget* BandingModelPrcessAndQConsoleWidgetClass::createQConsoleWidget() +{ + this->console = new QConsoleWidget(); + return this->console; +} + +void BandingModelPrcessAndQConsoleWidgetClass::bandingModelProcessAndQConsoleWidget() +{ + if (this->console&&this->modelprocess) { + this->console->setModelProcess(this->modelprocess); + QObject::connect(this->modelprocess, SIGNAL(OpenCommandWidget(ModelProcess*)), this, SLOT(OpenQConsoleWidgetFromModelProcess(ModelProcess*))); + } +} + +void BandingModelPrcessAndQConsoleWidgetClass::OpenQConsoleWidgetFromModelProcess(ModelProcess* w) +{ + if (this->console && this->modelprocess) { + this->console->setModelProcess(this->modelprocess); + //QObject::connect(this->modelprocess, SIGNAL(OpenCommandWidget(ModelProcess*)), this, SLOT(OpenQConsoleWidgetFromModelProcess(ModelProcess*))); + } + +} diff --git a/src/WBCLFZSystemModule/QConsoleCommandAction.h b/src/WBCLFZSystemModule/QConsoleCommandAction.h new file mode 100644 index 0000000..0d87109 --- /dev/null +++ b/src/WBCLFZSystemModule/QConsoleCommandAction.h @@ -0,0 +1,77 @@ +#pragma once +#ifndef QCONSOLECOMMANDACTION_H +#define QCONSOLECOMMANDACTION_H +#include "AllHead.h" +#include "OCCTBase.h" +#include "QConsoleWidget.h" +#include "modelProcess/ModelProcess.h" +#include "OCCViewer\DocumentCommon.h" +#include "OCCViewer\GeomWidget.h" + + + +class BandingModelPrcessAndQConsoleWidgetClass:public QObject +{ + Q_OBJECT +public: + BandingModelPrcessAndQConsoleWidgetClass(QObject* parent = nullptr); + ~BandingModelPrcessAndQConsoleWidgetClass(); + +public: + ModelProcess* modelprocess; + QConsoleWidget* console; + +public: + void setModelProcess(ModelProcess* modelprocess); + void setQConsoleWidget(QConsoleWidget* console); + ModelProcess* getModelProcess(); + QConsoleWidget* getQConsoleWidget(); + ModelProcess* createModelProcess(); + QConsoleWidget* createQConsoleWidget(); + + + void bandingModelProcessAndQConsoleWidget(); + void OpenQConsoleWidgetFromModelProcess(ModelProcess* w); +}; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#endif // !QCONSOLECOMMANDACTION_H + + diff --git a/src/WBCLFZSystemModule/QConsoleIODevice.cpp b/src/WBCLFZSystemModule/QConsoleIODevice.cpp new file mode 100644 index 0000000..48d7757 --- /dev/null +++ b/src/WBCLFZSystemModule/QConsoleIODevice.cpp @@ -0,0 +1,95 @@ +#include "QConsoleIODevice.h" +#include "QConsoleWidget.h" + +#include +#include +#include +#include + +QConsoleIODevice::QConsoleIODevice(QConsoleWidget *w, QObject *parent) + : QIODevice(parent), widget_(w), + readpos_(0), writtenSinceLastEmit_(0), readSinceLastEmit_(0) +{ + setCurrentWriteChannel(QConsoleWidget::StandardOutput); + + open(QIODevice::ReadWrite | QIODevice::Unbuffered); +} + +QConsoleIODevice::~QConsoleIODevice() +{ +} + +qint64 QConsoleIODevice::bytesAvailable() const +{ + return (qint64)(readbuff_.size() - readpos_); +} + +bool QConsoleIODevice::waitForReadyRead(int msecs) +{ + if (!widget_->device()->isOpen() || widget_->mode()!=QConsoleWidget::Input) + return false; + + if (bytesAvailable()) return true; + + + QEventLoop loop; + + connect(this,SIGNAL(readyRead()),&loop,SLOT(quit())); + connect(this,SIGNAL(aboutToClose()),&loop,SLOT(quit())); + if (msecs>0) + QTimer::singleShot(msecs,&loop,SLOT(quit())); + + readyReadEmmited_ = false; + loop.exec(); + return readyReadEmmited_; + +} + +qint64 QConsoleIODevice::readData(char *data, qint64 len) +{ + int b = bytesAvailable(); + if (b) { + b = qMin((int)len, b); + memcpy(data, readbuff_.constData() + readpos_, b); + readpos_ += b; + } + return (qint64)b; +} + +qint64 QConsoleIODevice::writeData(const char *data, qint64 len) +{ + QByteArray ba(data,(int)len); + int ch = currentWriteChannel(); + if (ch==QConsoleWidget::StandardError) + widget_->writeStdErr(ba); + else + widget_->writeStdOut(ba); + + writtenSinceLastEmit_ += len; + if (!signalsBlocked()) { + emit bytesWritten(writtenSinceLastEmit_); + writtenSinceLastEmit_ = 0; + } + return len; +} + +void QConsoleIODevice::consoleWidgetInput(const QString &in) +{ + QByteArray ba = in.toLatin1(); + int sz = ba.size(); + if (bytesAvailable()) { + if (readpos_) readbuff_ = readbuff_.mid(readpos_); + readbuff_.append(ba); + } else { + readbuff_ = ba; + } + readpos_ = 0; + + readSinceLastEmit_ += sz; + if (!signalsBlocked()) { + emit readyRead(); + readyReadEmmited_ = true; + readSinceLastEmit_ = 0; + } +} + diff --git a/src/WBCLFZSystemModule/QConsoleIODevice.h b/src/WBCLFZSystemModule/QConsoleIODevice.h new file mode 100644 index 0000000..3fbbeab --- /dev/null +++ b/src/WBCLFZSystemModule/QConsoleIODevice.h @@ -0,0 +1,40 @@ +#ifndef QCONSOLEIODEVICE_H +#define QCONSOLEIODEVICE_H + +#include +#include + +class QConsoleWidget; + + +class QConsoleIODevice : public QIODevice +{ + + Q_OBJECT + +public: + + explicit QConsoleIODevice(QConsoleWidget* w, QObject *parent = nullptr); + ~QConsoleIODevice(); + qint64 bytesAvailable() const override; + bool waitForReadyRead(int msecs) override; + QConsoleWidget* widget() const { return widget_; } + +protected: + + qint64 readData(char *data, qint64 maxlen) override; + qint64 writeData(const char *data, qint64 len) override; + +private: + + friend class QConsoleWidget; + QConsoleWidget* widget_; + QByteArray readbuff_; + int readpos_; + qint64 writtenSinceLastEmit_, readSinceLastEmit_; + bool readyReadEmmited_; + void consoleWidgetInput(const QString& in); +}; + +#endif + diff --git a/src/WBCLFZSystemModule/QConsoleWidget.cpp b/src/WBCLFZSystemModule/QConsoleWidget.cpp new file mode 100644 index 0000000..18a5fb2 --- /dev/null +++ b/src/WBCLFZSystemModule/QConsoleWidget.cpp @@ -0,0 +1,628 @@ +#include "QConsoleWidget.h" +#include "QConsoleIODevice.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + + +void QConsoleWidget::setModelProcess(ModelProcess* app) +{ + this->application = app; + // ´´½¨dockerWidget + qDebug() << u8"initCommandDocker,µÈ´ý³õʼ»¯ÃüÁîÐд°¿Ú"; + QDockWidget* dockWidget_command = this->application->getdockWidget_command(u8"ÃüÁîÐд°¿Ú"); + dockWidget_command->setHidden(false); + dockWidget_command->setWidget(this); + this->qs = new ScriptSession(this); // ´´½¨½Å±¾ + QTimer::singleShot(200,qs, SLOT(REPL())); + + // °ó¶¨application + //this->qs->settingApplication() + this->qs->settingApplication(this->application); + qDebug() << u8"initCommandDocker,½áÊø³õʼ»¯ÃüÁîÐд°¿Ú"; +} + +QConsoleWidget::QConsoleWidget(QWidget* parent) + : QPlainTextEdit(parent), mode_(Output), completer_(0) +{ + iodevice_ = new QConsoleIODevice(this,this); + + QTextCharFormat fmt = currentCharFormat(); + for(int i=0; itextCursor(); + textCursor.movePosition(QTextCursor::End); + textCursor.setPosition(inpos_,QTextCursor::KeepAnchor); + QString code = textCursor.selectedText(); + code.replace(QChar::ParagraphSeparator,QChar::LineFeed); + return code; +} + +void QConsoleWidget::handleReturnKey() +{ + QString code = getCommandLine(); + + // start new block + appendPlainText(QString()); + setMode(Output); + + QTextCursor textCursor = this->textCursor(); + textCursor.movePosition(QTextCursor::End); + setTextCursor(textCursor); + + // Update the history + if (!code.isEmpty()) history_.add(code); + + // append the newline char and + // send signal / update iodevice + code += "\n"; + if (iodevice_->isOpen()) + iodevice_->consoleWidgetInput(code); + else { + emit consoleCommand(code); + } +} + +void QConsoleWidget::handleTabKey() +{ + QTextCursor tc = this->textCursor(); + int anchor = tc.anchor(); + int position = tc.position(); + tc.setPosition(inpos_); + tc.setPosition(position, QTextCursor::KeepAnchor); + QString text = tc.selectedText().trimmed(); + tc.setPosition(anchor, QTextCursor::MoveAnchor); + tc.setPosition(position, QTextCursor::KeepAnchor); + if (text.isEmpty()) + { + tc.insertText(" "); + } + else + { + updateCompleter(); + if (completer_ && completer_->completionCount() == 1) + { + insertCompletion(completer_->currentCompletion()); + completer_->popup()->hide(); + } + } +} + +void QConsoleWidget::updateCompleter() +{ + if (!completer_) return; + + // if the completer is first shown, mark + // the text position + QTextCursor textCursor = this->textCursor(); + if (!completer_->popup()->isVisible()) { + completion_pos_ = textCursor.position(); + // qDebug() << "show completer, pos " << completion_pos_; + } + + // Get the text between the current cursor position + // and the start of the input + textCursor.setPosition(inpos_, QTextCursor::KeepAnchor); + QString commandText = textCursor.selectedText(); + // qDebug() << "code to complete: " << commandText; + + // Call the completer to update the completion model + // Place and show the completer if there are available completions + int count; + if ((count = completer_->updateCompletionModel(commandText))) + { + // qDebug() << "found " << count << " completions"; + + // Get a QRect for the cursor at the start of the + // current word and then translate it down 8 pixels. + textCursor = this->textCursor(); + textCursor.movePosition(QTextCursor::StartOfWord); + QRect cr = this->cursorRect(textCursor); + cr.translate(0, 8); + cr.setWidth(completer_->popup()->sizeHintForColumn(0) + + completer_->popup()->verticalScrollBar()->sizeHint().width()); + completer_->complete(cr); + } + else + { + // qDebug() << "no completions - hiding"; + completer_->popup()->hide(); + } +} + +void QConsoleWidget::checkCompletionTriggers(const QString &txt) +{ + if (!completer_ || completion_triggers_.isEmpty() || txt.isEmpty()) return; + + foreach(const QString& tr, completion_triggers_) + { + if (tr.endsWith(txt)) + { + QTextCursor tc = this->textCursor(); + tc.movePosition(QTextCursor::Left,QTextCursor::KeepAnchor,tr.length()); + if (tc.selectedText()==tr) { + updateCompleter(); + return; + } + } + } +} + +void QConsoleWidget::insertCompletion(const QString& completion) +{ + QTextCursor tc = textCursor(); + tc.movePosition(QTextCursor::Left, QTextCursor::KeepAnchor, + tc.position() - inpos_ - completer_->insertPos()); + tc.insertText(completion,chanFormat_[StandardInput]); + setTextCursor(tc); +} + +void QConsoleWidget::setCompleter(QConsoleWidgetCompleter *c) +{ + if (completer_) + { + completer_->setWidget(0); + QObject::disconnect(completer_, SIGNAL(activated(const QString&)), this, + SLOT(insertCompletion(const QString&))); + } + completer_ = c; + if (completer_) + { + completer_->setWidget(this); + QObject::connect(completer_, SIGNAL(activated(const QString&)), this, + SLOT(insertCompletion(const QString&))); + } +} + +void QConsoleWidget::keyPressEvent(QKeyEvent* e) +{ + if (completer_ && completer_->popup()->isVisible()) + { + // The following keys are forwarded by the completer to the widget + switch (e->key()) + { + case Qt::Key_Tab: + case Qt::Key_Enter: + case Qt::Key_Return: + case Qt::Key_Escape: + case Qt::Key_Backtab: + e->ignore(); + return; // let the completer do default behavior + default: + break; + } + } + + QTextCursor textCursor = this->textCursor(); + bool selectionInEditZone = isSelectionInEditZone(); + + // check for user abort request + if (e->modifiers() & Qt::ControlModifier) + { + if (e->key()==Qt::Key_Q) // Ctrl-Q aborts + { + emit abortEvaluation(); + e->accept(); + return; + } + } + + // Allow copying anywhere in the console ... + if (e->key() == Qt::Key_C && e->modifiers() == Qt::ControlModifier) + { + if (textCursor.hasSelection()) copy(); + e->accept(); + return; + } + + // the rest of key events are ignored during output mode + if (mode()!=Input) { + e->ignore(); + return; + } + + // Allow cut only if the selection is limited to the interactive area ... + if (e->key() == Qt::Key_X && e->modifiers() == Qt::ControlModifier) + { + if (selectionInEditZone) cut(); + e->accept(); + return; + } + + // Allow paste only if the selection is in the interactive area ... + if (e->key() == Qt::Key_V && e->modifiers() == Qt::ControlModifier) + { + if (selectionInEditZone || isCursorInEditZone()) + { + const QMimeData* const clipboard = QApplication::clipboard()->mimeData(); + const QString text = clipboard->text(); + if (!text.isNull()) + { + textCursor.insertText(text,channelCharFormat(StandardInput)); + } + } + + e->accept(); + return; + } + + + int key = e->key(); + int shiftMod = e->modifiers() == Qt::ShiftModifier; + + if (history_.isActive() && key!=Qt::Key_Up && key!=Qt::Key_Down) + history_.deactivate(); + + // Force the cursor back to the interactive area + // for all keys except modifiers + if (!isCursorInEditZone() && + key != Qt::Key_Control && + key != Qt::Key_Shift && + key != Qt::Key_Alt) + { + textCursor.movePosition(QTextCursor::End); + setTextCursor(textCursor); + } + + switch (key) + { + case Qt::Key_Up: + // Activate the history and move to the 1st matching history item + if (!history_.isActive()) history_.activate(getCommandLine()); + if (history_.move(true)) + replaceCommandLine(history_.currentValue()); + else QApplication::beep(); + e->accept(); + break; + + case Qt::Key_Down: + if (history_.move(false)) + replaceCommandLine(history_.currentValue()); + else QApplication::beep(); + e->accept(); + + case Qt::Key_Left: + if (textCursor.position() > inpos_) + QPlainTextEdit::keyPressEvent(e); + else + { + QApplication::beep(); + e->accept(); + } + break; + + case Qt::Key_Delete: + e->accept(); + if (selectionInEditZone) cut(); + else + { + // cursor must be in edit zone + if (textCursor.position() < inpos_) QApplication::beep(); + else QPlainTextEdit::keyPressEvent(e); + } + break; + + case Qt::Key_Backspace: + e->accept(); + if (selectionInEditZone) cut(); + else + { + // cursor must be in edit zone + if (textCursor.position() <= inpos_) QApplication::beep(); + else QPlainTextEdit::keyPressEvent(e); + } + break; + + case Qt::Key_Tab: + e->accept(); + handleTabKey(); + return; + + case Qt::Key_Home: + e->accept(); + textCursor.setPosition(inpos_, + shiftMod ? QTextCursor::KeepAnchor : QTextCursor::MoveAnchor); + setTextCursor(textCursor); + break; + + case Qt::Key_Enter: + case Qt::Key_Return: + e->accept(); + handleReturnKey(); + break; + + + case Qt::Key_Escape: + e->accept(); + replaceCommandLine(QString()); + break; + + + default: + e->accept(); + setCurrentCharFormat(chanFormat_[StandardInput]); + QPlainTextEdit::keyPressEvent(e); + // check if the last key triggers a completion + checkCompletionTriggers(e->text()); + break; + } + + if (completer_ && completer_->popup()->isVisible()) + { + // if the completer is visible check if it should be updated + if (this->textCursor().position()popup()->hide(); + else + updateCompleter(); + } +} + +void QConsoleWidget::contextMenuEvent(QContextMenuEvent *event) +{ + QMenu *menu = createStandardContextMenu(); + + QAction* a; + if ((a = menu->findChild("edit-cut"))) + a->setEnabled(canCut()); + if ((a = menu->findChild("edit-delete"))) + a->setEnabled(canCut()); + if ((a = menu->findChild("edit-paste"))) + a->setEnabled(canPaste()); + + menu->exec(event->globalPos()); + delete menu; +} + +bool QConsoleWidget::isSelectionInEditZone() const +{ + QTextCursor textCursor = this->textCursor(); + if (!textCursor.hasSelection()) return false; + + int selectionStart = textCursor.selectionStart(); + int selectionEnd = textCursor.selectionEnd(); + + return selectionStart >= inpos_ && selectionEnd >= inpos_; +} + +bool QConsoleWidget::isCursorInEditZone() const +{ + return textCursor().position()>=inpos_; +} + +bool QConsoleWidget::canPaste() const +{ + QTextCursor textCursor = this->textCursor(); + if (textCursor.position()textCursor(); + textCursor.movePosition(QTextCursor::End); + textCursor.setPosition(inpos_, QTextCursor::KeepAnchor); + + // ... and replace it with new string. + textCursor.insertText(str,chanFormat_[StandardInput]); + + // move to the end of the document + textCursor.movePosition(QTextCursor::End); + setTextCursor(textCursor); +} + +void QConsoleWidget::write(const QString & message, const QTextCharFormat& fmt) +{ + QTextCharFormat currfmt = currentCharFormat(); + QTextCursor tc = textCursor(); + + if (mode()==Input) + { + // in Input mode output messages are inserted + // before the edit block + + // get offset of current pos from the end + int editpos = tc.position(); + tc.movePosition(QTextCursor::End); + editpos = tc.position() - editpos; + + // convert the input pos as relative from the end + inpos_ = tc.position() - inpos_; + + // insert block + tc.movePosition(QTextCursor::StartOfBlock); + tc.insertBlock(); + tc.movePosition(QTextCursor::PreviousBlock); + + tc.insertText(message,fmt); + tc.movePosition(QTextCursor::End); + // restore input pos + inpos_ = tc.position() - inpos_; + // restore the edit pos + tc.movePosition(QTextCursor::Left,QTextCursor::MoveAnchor,editpos); + setTextCursor(tc); + setCurrentCharFormat(currfmt); + } + else + { + // in output mode messages are appended + QTextCursor tc1 = tc; + tc1.movePosition(QTextCursor::End); + + // check is cursor was not at the end + // (e.g. had been moved per mouse action) + bool needsRestore = tc1.position()!=tc.position(); + + // insert text + setTextCursor(tc1); + textCursor().insertText(message,fmt); + ensureCursorVisible(); + + // restore cursor if needed + if (needsRestore) setTextCursor(tc); + } + + +} + +void QConsoleWidget::writeStdOut(const QString& s) +{ + write(s,chanFormat_[StandardOutput]); +} + +void QConsoleWidget::writeStdErr(const QString& s) +{ + write(s,chanFormat_[StandardError]); +} + +/////////////////// QConsoleWidget::History ///////////////////// + +#define HISTORY_FILE ".command_history.lst" + +QConsoleWidget::History QConsoleWidget::history_; + +QConsoleWidget::History::History(void) : pos_(0), active_(false), maxsize_(10000) +{ + QFile f(HISTORY_FILE); + if (f.open(QFile::ReadOnly)) { + QTextStream is(&f); + while(!is.atEnd()) add(is.readLine()); + } +} +QConsoleWidget::History::~History(void) +{ + QFile f(HISTORY_FILE); + if (f.open(QFile::WriteOnly | QFile::Truncate)) { + QTextStream os(&f); + int n = strings_.size(); + while(n>0) os << strings_.at(--n) << endl; + } +} + +void QConsoleWidget::History::add(const QString& str) +{ + active_ = false; + //if (strings_.contains(str)) return; + if (strings_.size() == maxsize_) strings_.pop_back(); + strings_.push_front(str); +} + +void QConsoleWidget::History::activate(const QString& tk) +{ + active_ = true; + token_ = tk; + pos_ = -1; +} + +bool QConsoleWidget::History::move(bool dir) +{ + if (active_) + { + int next = indexOf ( dir, pos_ ); + if (pos_!=next) + { + pos_=next; + return true; + } + else return false; + } + else return false; +} + +int QConsoleWidget::History::indexOf(bool dir, int from) const +{ + int i = from, to = from; + if (dir) + { + while(i < strings_.size()-1) + { + const QString& si = strings_.at(++i); + if (si.startsWith(token_)) { return i; } + } + } + else + { + while(i > 0) + { + const QString& si = strings_.at(--i); + if (si.startsWith(token_)) { return i; } + } + return -1; + } + return to; +} + +/////////////////// Stream manipulators ///////////////////// + +QTextStream &waitForInput(QTextStream &s) +{ + QConsoleIODevice* d = qobject_cast(s.device()); + if (d) d->waitForReadyRead(-1); + return s; +} + +QTextStream &inputMode(QTextStream &s) +{ + QConsoleIODevice* d = qobject_cast(s.device()); + if (d && d->widget()) d->widget()->setMode(QConsoleWidget::Input); + return s; +} +QTextStream &outChannel(QTextStream &s) +{ + QConsoleIODevice* d = qobject_cast(s.device()); + if (d) d->setCurrentWriteChannel(QConsoleWidget::StandardOutput); + return s; +} +QTextStream &errChannel(QTextStream &s) +{ + QConsoleIODevice* d = qobject_cast(s.device()); + if (d) d->setCurrentWriteChannel(QConsoleWidget::StandardError); + return s; +} + diff --git a/src/WBCLFZSystemModule/QConsoleWidget.h b/src/WBCLFZSystemModule/QConsoleWidget.h new file mode 100644 index 0000000..71200a8 --- /dev/null +++ b/src/WBCLFZSystemModule/QConsoleWidget.h @@ -0,0 +1,159 @@ +#ifndef _QCONSOLEWIDGET_H_ +#define _QCONSOLEWIDGET_H_ +#include "AllHead.h" +#include +#include +#include +#include "modelProcess/ModelProcess.h" +#include "scriptsession.h" + +class QConsoleIODevice; +class QConsoleWidgetCompleter; + +class QConsoleWidget : public QPlainTextEdit +{ + Q_OBJECT + +public: + ModelProcess* application; + ScriptSession* qs; + + void setModelProcess(ModelProcess* app); + + + +public: + enum ConsoleMode { + Input, + Output + }; + Q_ENUM(ConsoleMode) + + enum ConsoleChannel { + StandardInput, + StandardOutput, + StandardError, + nConsoleChannels + }; + Q_ENUM(ConsoleChannel) + + QConsoleWidget(QWidget* parent = 0); + ~QConsoleWidget(); + + ConsoleMode mode() const { return mode_; } + void setMode(ConsoleMode m); + QIODevice* device() const { return (QIODevice*)iodevice_; } + QTextCharFormat channelCharFormat(ConsoleChannel ch) const + { return chanFormat_[ch]; } + void setChannelCharFormat(ConsoleChannel ch, const QTextCharFormat& fmt) + { chanFormat_[ch] = fmt; } + const QStringList& completionTriggers() const + { return completion_triggers_; } + void setCompletionTriggers(const QStringList& l) + { completion_triggers_ = l; } + virtual QSize sizeHint() const + { return QSize(600,400); } + // write a formatted message to the console + void write(const QString & message, const QTextCharFormat& fmt); + static const QStringList& history() + { return history_.strings_; } + void setCompleter(QConsoleWidgetCompleter* c); + // get the current command line + QString getCommandLine(); + +public slots: + + // write to StandardOutput + void writeStdOut(const QString& s); + // write to StandardError + void writeStdErr(const QString& s); + +signals: + + // fired when user hits the return key + void consoleCommand(const QString& code); + // fired when user enters a Ctrl-Q + void abortEvaluation(); + +protected: + + bool canPaste() const; + bool canCut() const + { return isSelectionInEditZone(); } + void handleReturnKey(); + void handleTabKey(); + void updateCompleter(); + void checkCompletionTriggers(const QString& txt); + // reimp QPlainTextEdit functions + void keyPressEvent (QKeyEvent * e) override; + void contextMenuEvent(QContextMenuEvent *event) override; + // Returns true if there is a selection in edit zone + bool isSelectionInEditZone() const; + // Returns true if cursor is in edit zone + bool isCursorInEditZone() const; + // replace the command line + void replaceCommandLine(const QString& str); + +protected slots: + + // insert the completion from completer + void insertCompletion(const QString& completion); + +private: + + struct History + { + QStringList strings_; + int pos_; + QString token_; + bool active_; + int maxsize_; + History(void); + ~History(void); + void add(const QString& str); + const QString& currentValue() const + { return pos_ == -1 ? token_ : strings_.at(pos_); } + void activate(const QString& tk = QString()); + void deactivate() { active_ = false; } + bool isActive() const { return active_; } + bool move(bool dir); + int indexOf(bool dir, int from) const; + }; + + static History history_; + ConsoleMode mode_; + int inpos_, completion_pos_; + QStringList completion_triggers_; + QString currentMultiLineCode_; + QConsoleIODevice* iodevice_; + QTextCharFormat chanFormat_[nConsoleChannels]; + QConsoleWidgetCompleter* completer_; +}; + +QTextStream &waitForInput(QTextStream &s); +QTextStream &inputMode(QTextStream &s); +QTextStream &outChannel(QTextStream &s); +QTextStream &errChannel(QTextStream &s); + +class QConsoleWidgetCompleter : public QCompleter +{ +public: + /* + * Update the completion model given a string. The given string + * is the current console text between the cursor and the start of + * the line. + * + * Return the completion count + */ + virtual int updateCompletionModel(const QString& str) = 0; + + /* + * Return the position in the command line where the completion + * should be inserted + */ + virtual int insertPos() = 0; +}; + + + +#endif diff --git a/src/WBCLFZSystemModule/QtEchoExportWindows.ui b/src/WBCLFZSystemModule/QtEchoExportWindows.ui new file mode 100644 index 0000000..2a46db4 --- /dev/null +++ b/src/WBCLFZSystemModule/QtEchoExportWindows.ui @@ -0,0 +1,141 @@ + + + Form + + + + 0 + 0 + 656 + 403 + + + + 回波定标导出 + + + + + + 打开定标文件 + + + + + + + 傿•°é¡¹ + + + + + + 定标çƒåŠå¾„ + + + + + + + + + + + + + + 0 + 25 + + + + + 16777215 + 25 + + + + å®šæ ‡çƒæµ‹é‡æ•°æ® + + + + + + + + 0 + 25 + + + + + 16777215 + 25 + + + + + + + + + 0 + 25 + + + + + 16777215 + 25 + + + + + + + + 打开 + + + + + + + + 0 + 25 + + + + + 16777215 + 25 + + + + 目标回波文件 + + + + + + + 1 + + + + 目标回波 + + + + + 定标çƒå›žæ³¢ + + + + + + + + + diff --git a/src/WBCLFZSystemModule/QtFreqParamsSetting.cpp b/src/WBCLFZSystemModule/QtFreqParamsSetting.cpp new file mode 100644 index 0000000..3964d85 --- /dev/null +++ b/src/WBCLFZSystemModule/QtFreqParamsSetting.cpp @@ -0,0 +1,177 @@ +#include "QtFreqParamsSetting.h" + + +QtFreqParamsSetting::QtFreqParamsSetting(QWidget* parent) + : QWidget(parent) +{ + ui.setupUi(this); + QDoubleValidator* validator = new QDoubleValidator(); // ÏÞÖÆ²ÎÊý + this->ui.lineEdit_centerfreq->setValidator(validator); + this->ui.lineEdit_bandwidth->setValidator(validator); + this->ui.lineEdit_Resolution->setValidator(validator); + this->ui.lineEdit_SenceRange->setValidator(validator); + + // ³õʼ»¯ + ui.lineEdit_centerfreq->setText(u8"9.6"); + ui.lineEdit_bandwidth->setText(u8"0.8"); + ui.lineEdit_Resolution->setText(u8"1.0"); + ui.lineEdit_SenceRange->setText(u8"10.0"); + +} + +QtFreqParamsSetting::~QtFreqParamsSetting() +{} + +void QtFreqParamsSetting::CalcFreqParams() +{ + bool resolutionRadio = this->ui.radioButton_Resolution->isChecked(); + bool bandwidthRadio = this->ui.radioButton_bandwidth->isChecked(); + QString centerfreq_str = this->ui.lineEdit_centerfreq->text(); + QString resolution_str = this->ui.lineEdit_Resolution->text(); + QString bandwidth_str = this->ui.lineEdit_bandwidth->text(); + QString senceRange_str = this->ui.lineEdit_SenceRange->text(); + double centerfreq = 0; + double resolution = 1; + double bandwidth = 1; + double senceRange = 1; + + + { // ¼ì²é²ÎÊý + if (centerfreq_str.isEmpty()) { + QMessageBox::warning(this, u8"¾¯¸æ", u8"ÖÐÐÄÆµÂʲ»ÄÜΪ¿Õ"); + return; + } + else { + centerfreq = centerfreq_str.toDouble(); + } + + if (senceRange_str.isEmpty()) { + QMessageBox::warning(this, u8"¾¯¸æ", u8"¾àÀ볡¾°×îСֵ²»ÄÜΪ¿Õ"); + return; + } + else { + senceRange = senceRange_str.toDouble(); + } + + if (resolution_str.isEmpty() && resolutionRadio) { + QMessageBox::warning(this, u8"¾¯¸æ", u8"·Ö±æÂʲ»ÄÜΪ¿Õ"); + return; + } + else { + resolution = resolution_str.toDouble(); + } + + if (bandwidth_str.isEmpty() && bandwidthRadio) { + QMessageBox::warning(this, u8"¾¯¸æ", u8"´ø¿í²»ÄÜΪ¿Õ"); + return; + } + else { + bandwidth = bandwidth_str.toDouble(); + } + + if (senceRange < 0) { + QMessageBox::warning(this, u8"¾¯¸æ", u8"¾àÀ볡¾°×îСֵ²»ÄÜСÓÚ0"); + return; + } + else {} + } + + { // ºÏ·¨ÐÔ¼ì²é + if (resolutionRadio && resolution <= 0) { + QMessageBox::warning(this, u8"¾¯¸æ", u8"·Ö±æÂʲ»ÄÜСÓÚ0"); + return; + } + if (bandwidthRadio && bandwidth <= 0) { + QMessageBox::warning(this, u8"¾¯¸æ", u8"´ø¿í²»ÄÜСÓÚ0"); + return; + } + if(centerfreq<=0){ + QMessageBox::warning(this, u8"¾¯¸æ", u8"ÖÐÐÄÆµÂʲ»ÄÜСÓÚ0"); + return; + } + if (senceRange <= 0) { + QMessageBox::warning(this, u8"¾¯¸æ", u8"³¡¾°·¶Î§²»ÄÜСÓÚ0"); + return; + } + } + + // ¼ÆËã + this->freqParams=FEKOBase::getFreqSetting(centerfreq, resolution, bandwidth, senceRange, resolutionRadio); + + // ÏÔʾ + this->ui.lineEdit_Startfreq->setText(QString::number(freqParams.startfreqs)); + this->ui.lineEdit_endFreq->setText(QString::number(freqParams.endfreqs)); + this->ui.lineEdit_PointNum->setText(QString::number(freqParams.freqpoint)); + + if (resolutionRadio) { + this->ui.lineEdit_bandwidth->setText(QString::number(this->freqParams.endfreqs - this->freqParams.startfreqs)); + } + else { + + //this->ui.lineEdit_Resolution->setText(QString::number(0.299792458 / bandwidthcal)); + } + double bandwidthcal = this->freqParams.endfreqs - this->freqParams.startfreqs; + resolution = 0.299792458 / bandwidth / 2; + // ¸üÐÂÆµÂʲÎÊý + this->simulationparams->setStartfreq(freqParams.startfreqs); + this->simulationparams->setEndfreq(freqParams.endfreqs); + this->simulationparams->setFreqpoints(freqParams.freqpoint); + this->simulationparams->setCenterFreq(centerfreq); + this->simulationparams->setRangeResolution(resolution); + this->simulationparams->setBandwidth(bandwidthcal); + this->ui.lineEdit_freqdelta->setText(QString::number(bandwidthcal / (freqParams.freqpoint - 1) * 1e3));// GHz --> MHz +} + + +FEKOBase::freqParams QtFreqParamsSetting::getParams() +{ + return this->freqParams; +} + +void QtFreqParamsSetting::on_lineEdit_centerfreq_returnPressed() +{ + this->CalcFreqParams(); +} + +void QtFreqParamsSetting::on_lineEdit_bandwidth_returnPressed() +{ + this->CalcFreqParams(); +} + +void QtFreqParamsSetting::on_lineEdit_Resolution_returnPressed() +{ + this->CalcFreqParams(); +} + +void QtFreqParamsSetting::on_lineEdit_SenceRange_returnPressed() +{ + this->CalcFreqParams(); +} + +void QtFreqParamsSetting::FEKOSimulationDataparamsChanged_slots() +{ + this->ui.lineEdit_centerfreq->setText(QString::number(this->simulationparams->getCenterFreq())); + this->ui.lineEdit_bandwidth->setText(QString::number(this->simulationparams->getBandwidth())); + this->ui.lineEdit_Resolution->setText(QString::number(this->simulationparams->getRangeResolution())); + this->ui.lineEdit_SenceRange->setText(QString::number((this->simulationparams->freqpoints-1)*this->simulationparams->rangeResolution)); + this->ui.lineEdit_Startfreq->setText(QString::number(this->simulationparams->getStartfreq())); + this->ui.lineEdit_endFreq->setText(QString::number(this->simulationparams->getEndfreq())); + this->ui.lineEdit_PointNum->setText(QString::number(this->simulationparams->getFreqpoints())); + double bandwidthcal=this->simulationparams->getEndfreq() - this->simulationparams->getStartfreq(); + size_t freqpoints = this->simulationparams->getFreqpoints(); + this->ui.lineEdit_freqdelta->setText(QString::number(bandwidthcal / (freqpoints - 1) * 1e3)); // GHz --> MHz +} + +void QtFreqParamsSetting::bandingsetFEKOSimulationDataparams() +{ + QObject::connect(this->simulationparams.get(), SIGNAL(FEKOSimulationDataparamsChanged()), this, SLOT(FEKOSimulationDataparamsChanged_slots())); + +} + + + +void QtFreqParamsSetting::on_pushButton_OK_clicked() +{ + this->CalcFreqParams(); + emit OKClick( ); +} \ No newline at end of file diff --git a/src/WBCLFZSystemModule/QtFreqParamsSetting.h b/src/WBCLFZSystemModule/QtFreqParamsSetting.h new file mode 100644 index 0000000..b196f7d --- /dev/null +++ b/src/WBCLFZSystemModule/QtFreqParamsSetting.h @@ -0,0 +1,49 @@ +#pragma once + +#include "AllHead.h" +#include +#include "ui_QtFreqParamsSetting.h" + +class QtFreqParamsSetting : public QWidget, public FEKOBase::FEKOSimulationDataparamsHandler +{ + Q_OBJECT + +public: + FEKOBase::freqParams freqParams; // ÎÀÐDzÎÊý + +public: + QtFreqParamsSetting(QWidget*parent = nullptr); + ~QtFreqParamsSetting(); + + void CalcFreqParams(); + FEKOBase::freqParams getParams(); +signals: + void OKClick( ); + void refRangleChanged(double refRangle); + +public slots: + void on_pushButton_OK_clicked(); + +public slots: + void on_lineEdit_centerfreq_returnPressed(); + void on_lineEdit_bandwidth_returnPressed(); + void on_lineEdit_Resolution_returnPressed(); + void on_lineEdit_SenceRange_returnPressed(); + +public slots: + void FEKOSimulationDataparamsChanged_slots(); +public: + void bandingsetFEKOSimulationDataparams() override; + +private: + Ui::QtFreqParamsSettingClass ui; +}; + + + + + + + + + diff --git a/src/WBCLFZSystemModule/QtFreqParamsSetting.ui b/src/WBCLFZSystemModule/QtFreqParamsSetting.ui new file mode 100644 index 0000000..28d29a3 --- /dev/null +++ b/src/WBCLFZSystemModule/QtFreqParamsSetting.ui @@ -0,0 +1,404 @@ + + + QtFreqParamsSettingClass + + + + 0 + 0 + 375 + 413 + + + + å¤©çº¿å‚æ•°è®¾ç½® + + + + + + + 0 + 40 + + + + + 16777215 + 40 + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 0 + 25 + + + + + 16777215 + 25 + + + + 确定 + + + + + + + + + + + + + + 0 + 25 + + + + + 16777215 + 25 + + + + + + + + + 0 + 25 + + + + + 16777215 + 25 + + + + + + + + + 0 + 25 + + + + + 16777215 + 25 + + + + 频率点数 + + + + + + + GHz + + + + + + + + 0 + 25 + + + + + 16777215 + 25 + + + + + + + + + 0 + 25 + + + + + 16777215 + 25 + + + + + + + + GHz + + + + + + + + 0 + 25 + + + + + 16777215 + 25 + + + + + + + + GHz + + + + + + + GHz + + + + + + + + 0 + 25 + + + + + 16777215 + 25 + + + + 终止频率 + + + + + + + + 0 + 25 + + + + + 16777215 + 25 + + + + 场景范围 + + + + + + + + 0 + 25 + + + + + 16777215 + 25 + + + + 中心频率 + + + + + + + + 0 + 25 + + + + + 16777215 + 25 + + + + 起始频率 + + + + + + + m + + + + + + + m + + + + + + + + 0 + 25 + + + + + 16777215 + 25 + + + + + + + + + 0 + 25 + + + + + 16777215 + 25 + + + + 分辨率 + + + + + + + + 0 + 25 + + + + + 16777215 + 25 + + + + + + + + + 0 + 25 + + + + + 16777215 + 25 + + + + 带宽 + + + true + + + + + + + 频率间隔 + + + + + + + false + + + + 0 + 25 + + + + + 16777215 + 25 + + + + + + + + MHz + + + + + + + + + + + + diff --git a/src/WBCLFZSystemModule/QtSARAntModelSetting.cpp b/src/WBCLFZSystemModule/QtSARAntModelSetting.cpp new file mode 100644 index 0000000..47abe52 --- /dev/null +++ b/src/WBCLFZSystemModule/QtSARAntModelSetting.cpp @@ -0,0 +1,543 @@ +#include "QtSARAntModelSetting.h" +#include "AllHead.h" +#include +#include +#include +#include +#include "OCCTBase.h" + +antModelClass::antModelClass(QString filpath) +{ + QMessageBox::information(nullptr, QString::fromUtf8(u8"Ä£ÐÍ×ø±êϵÌáʾ"), QString::fromUtf8(u8"Ä£Ð͵ÄYÖáΪ·ÉÐз½Ïò£¬ZÖáΪÀ×´ïÖ¸Ïò")); + if (QFile::exists(filpath)) { + ReadTopoDs_Shape(filpath, this->antModel); + } + else { + this->createDefaultAntModel(); + } +} + +antModelClass::antModelClass() +{ + QMessageBox::information(nullptr, QString::fromUtf8(u8"Ä£ÐÍ×ø±êϵÌáʾ"), QString::fromUtf8(u8"Ä£Ð͵ÄYÖáΪ·ÉÐз½Ïò£¬ZÖáΪÀ×´ïÖ¸Ïò")); + this->createDefaultAntModel(); +} + +antModelClass::~antModelClass() +{ + this->antModelShow.Nullify(); + this->antModel.Nullify(); +} + +void antModelClass::initAxis() +{ + gp_Pnt rotationCenter(0, 0, 0); + gp_Ax1 rotationAxis_X(rotationCenter, gp_Dir(1.0, 0.0, 0.0)); + gp_Ax1 rotationAxis_Y(rotationCenter, gp_Dir(0.0, 1.0, 0.0)); + gp_Ax1 rotationAxis_Z(rotationCenter, gp_Dir(0.0, 0.0, 1.0)); +} + +// +// ¸ù¾Ý²àÊӽǰڶ¯Ê±£¬Ó¦¸ÃÊÇÔÚÎÀÐÇ·ÉÐÐÓëÀ×´ïÕÕÉäµÄÆ½ÃæÉϽøÐаڶ¯ +// +void antModelClass::applyAntModel( + double Sx, double Sy, double Sz, + double Vx , double Vy , double Vz , + double incidenceAngle, double AzAngle, bool isRIGHT) { + + FEKOBase::SatelliteState satepos{ + FEKOBase::SatellitePosition{Sx,Sy,Sz}, + FEKOBase::SatelliteVelocity{Vx,Vy,Vz}, + }; + + FEKOBase::FEKOantPitionDirect antposition_Direct; + TopoDS_Shape inDs = this->antModel; + TopoDS_Shape outDs = FEKOBase::SatellitePos2FEKOAntPos(satepos, incidenceAngle, AzAngle, isRIGHT, &antposition_Direct, inDs); + Handle(AIS_Shape) aisShape = new AIS_Shape(outDs); + this->antModelShow = aisShape; + this->antposition_Direct = antposition_Direct; + + return; +} + +void antModelClass::createDefaultAntModel() +{ + + // ´´½¨Èý¸ö·½ÏòµÄ¼ýÍ· + //TopoDS_Shape arrow1 = CreateArrow(gp_Dir(1, 0, 0), 0.3, 0.1); // X·½Ïò + TopoDS_Shape arrow2 = CreateArrow(gp_Dir(0, 1, 0), 1, 0.1); // Y·½Ïò + TopoDS_Shape arrow3 = CreateArrow(gp_Dir(0, 0, 1), 1.5, 0.1); // Z·½Ïò + + // ´´½¨À×´ïÄ£ÐÍ + + gp_Ax2 modelCoor = gp_Ax2(gp_Pnt(0, 0, 0), gp_Dir(0, 0, 1), gp_Dir(1, 0, 0)); + + //TopoDS_Shape ant_pyramid = BRepPrimAPI_MakeWedge(modelCoor, 0.1, 0.1, 1.0,-1.0,-1.0,1.0,1.0).Shape(); + + + // ´´½¨Ò»¸ö°üº¬ËùÓмýÍ·µÄ¸´ºÏÌå + TopoDS_Compound compound; + BRep_Builder builder; + + + builder.MakeCompound(compound); + //builder.Add(compound, arrow1); + builder.Add(compound, arrow2); + builder.Add(compound, arrow3); + //builder.Add(compound, ant_pyramid); + this->antModel = compound; // À×´ïÈýάģÐÍ + +} + +FEKOBase::FEKOantPitionDirect antModelClass::get_antposition_Direct() +{ + return this->antposition_Direct; +} + +Handle(AIS_InteractiveObject) antModelClass::get_antModelShow() +{ + return this->antModelShow; +} + +antModelClass antModelClassFactory() +{ + QString filepath = getOpenFilePath( + nullptr, + QString::fromUtf8(u8"µ¼ÈëÀ×´ïÄ£ÐÍ"), + QString::fromUtf8(u8"STL Files (*.stl);;STL Files (*.stla);;step Files (*.stp);;step Files (*.step);;IGES Files (*.iges);;IGES Files (*.igs)")); + antModelClass result(filepath); + return result; +} + + +QtSARAntModelSettingClass::QtSARAntModelSettingClass(QWidget* parent) +{ + ui.setupUi(this); + this->simulationparams = std::make_shared(); // ²ÎÊý³õʼ»¯ + this->ui.lineEdit_TaskName->setText(this->simulationparams->taskName); + this->ui.lineEdit_farsourcePath->setText(this->simulationparams->AntennaRadiationFileName); + + this->Widgetfreqsetting=new QtFreqParamsSetting(this); + this->WidgetImageSetting = new QtWidgetsClass_ImageSetting(this); + // Ìí¼Ó³ÉÏñģʽ + this->WidgetISARMode = new QtWidgetsClass_ISAR(); + this->WidgetCirCleSARMode = new QtWidgetsClass_CircleSAR(); + this->WidgetScanMode = new QtWidgetsClass_Scan(); + this->WidgetstriMode = new QtWidgetsClass_Strip(); + + + + QObject::connect(this->WidgetISARMode, SIGNAL(OKClick()), this, SLOT(OKClickISAR( ))); + QObject::connect(this->WidgetstriMode,SIGNAL(OKClick()),this,SLOT(OKClickStrip( ))); + QObject::connect(this->WidgetCirCleSARMode, SIGNAL(OKClick()), this, SLOT(OKClickCircleSAR( ))); + QObject::connect(this->WidgetScanMode, SIGNAL(OKClick()), this, SLOT(OKClickScane( ))); + QObject::connect(this->Widgetfreqsetting, SIGNAL(OKClick()), this, SLOT(OKClickFreqSetting( ))); + QObject::connect(this->WidgetImageSetting, SIGNAL(OKClick()), this, SLOT(OKClickImageSetting( ))); + // Ìí¼ÓƵÂÊ + //this->Widgetfreqsetting->freqParams = this->freqSetting; + this->ui.tabWidget->removeTab(0); + this->ui.tabWidget->insertTab(0, this->Widgetfreqsetting, u8"ƵÂÊÉèÖÃ"); + this->ui.tabWidget->removeTab(2); + this->ui.tabWidget->insertTab(2, this->WidgetImageSetting, u8"³ÉÏñÉèÖÃ"); + + this->ui.comboBox_ImageMode->addItem(FEKOBase::FEKOImageModeenumToString(FEKOBase::FEKOImageMode::Strip)); + this->ui.comboBox_ImageMode->addItem(FEKOBase::FEKOImageModeenumToString(FEKOBase::FEKOImageMode::Scane)); + this->ui.comboBox_ImageMode->addItem(FEKOBase::FEKOImageModeenumToString(FEKOBase::FEKOImageMode::ISAR)); + this->ui.comboBox_ImageMode->addItem(FEKOBase::FEKOImageModeenumToString(FEKOBase::FEKOImageMode::CircleSAR)); + + this->ui.comboBox_LookSide->addItem(u8"×óÊÓ"); + this->ui.comboBox_LookSide->addItem(u8"ÓÒÊÓ"); + + + // »æÖÆÄ£ÐÍ + this->antModel = nullptr; + this->myContext = nullptr; + this->ui.tabantModeMove->setEnabled(false); + +} + +QtSARAntModelSettingClass::~QtSARAntModelSettingClass() +{ + +} + +void QtSARAntModelSettingClass::removeModeSettingWidget() +{ + this->ui.tabWidget->removeTab(1); + this->FEKOAntPoselist.clear(); +} + +void QtSARAntModelSettingClass::switchStripImageParamsWeight() +{ + this->removeModeSettingWidget(); + this->ui.tabWidget->insertTab(1, this->WidgetstriMode, u8"Ìõ´ø³ÉÏñÉèÖÃ"); + this->ui.comboBox_LookSide->setEnabled(true); +} + +void QtSARAntModelSettingClass::switchScanImageParamsWeight() +{ + this->removeModeSettingWidget(); + this->ui.tabWidget->insertTab(1, this->WidgetScanMode, u8"ɨÃè³ÉÏñÉèÖÃ"); + this->ui.comboBox_LookSide->setEnabled(true); + +} + +void QtSARAntModelSettingClass::switchISARImageParamsWeight() +{ + this->removeModeSettingWidget(); + this->ui.tabWidget->insertTab(1, this->WidgetISARMode, u8"ISAR³ÉÏñÉèÖÃ"); + this->ui.comboBox_LookSide->setEnabled(false); +} + +void QtSARAntModelSettingClass::switchCircleSARImageParamsWeight() +{ + this->removeModeSettingWidget(); + this->ui.tabWidget->insertTab(1, this->WidgetCirCleSARMode, u8"Ô²¼£SAR³ÉÏñÉèÖÃ"); + this->ui.comboBox_LookSide->setEnabled(false); +} + +void QtSARAntModelSettingClass::ReferenceWindows() +{ + this->ui.lineEdit_TaskName->setText(this->simulationparams->getTaskName()); + //this->ui.comboBox_ImageMode->setCurrentText(FEKOBase::FEKOImageModeenumToString(this->simulationparams->imagemode)); + + switch (this->simulationparams->imagemode) { + case FEKOBase::FEKOImageMode::Strip: + this->ui.comboBox_ImageMode->setCurrentIndex(0); + break; + case FEKOBase::FEKOImageMode::Scane: + this->ui.comboBox_ImageMode->setCurrentIndex(1); + break; + case FEKOBase::FEKOImageMode::ISAR: + this->ui.comboBox_ImageMode->setCurrentIndex(2); + break; + case FEKOBase::FEKOImageMode::CircleSAR: + this->ui.comboBox_ImageMode->setCurrentIndex(3); + break; + } + + if (this->simulationparams->isRight) { + this->ui.comboBox_LookSide->setCurrentIndex(1); + } + else { + this->ui.comboBox_LookSide->setCurrentIndex(0); + } + + this->ui.lineEdit_refRange->setText(QString::number(this->simulationparams->refRange)); + this->ui.lineEdit_incangle->setText(QString::number(this->simulationparams->incangle)); + + emit this->simulationparams->FEKOSimulationDataparamsChanged(); // ½«²ÎÊýÐ޸ķ¢Ë͵½²»Í¬½çÃæÖÐ + + this->generator_FEKOSatelliteParams(); + +} + +void QtSARAntModelSettingClass::refreshFEKOSimulationParams() +{ + this->simulationparams->taskName = this->ui.lineEdit_TaskName->text(); + this->simulationparams->AntennaRadiationFileName = this->ui.lineEdit_farsourcePath->text(); + this->simulationparams->isRight = this->ui.comboBox_LookSide->currentIndex() == 1; + this->simulationparams->imagemode=FEKOBase::FEKOImageModeString2Enum(this->ui.comboBox_ImageMode->currentText().trimmed()); + this->simulationparams->refRange = this->ui.lineEdit_refRange->text().toDouble(); + this->simulationparams->incangle = this->ui.lineEdit_incangle->text().toDouble(); +} + +void QtSARAntModelSettingClass::setOCCTDocument(Handle(AIS_InteractiveContext) myContext) +{ + this->myContext = myContext; + + QString antFilePath=getOpenFilePath( + nullptr, + QString::fromUtf8(u8"µ¼ÈëÀ×´ïÄ£ÐÍ"), + QString::fromUtf8(u8"STL Files (*.stl);;STL Files (*.stla);;step Files (*.stp);;step Files (*.step);;IGES Files (*.iges);;IGES Files (*.igs)")); + + if (isExists(antFilePath)) { + this->antModel = new antModelClass(antFilePath); + } + else { + this->antModel = new antModelClass(); + } + this->ui.tabantModeMove->setEnabled(true); +} + + +void QtSARAntModelSettingClass::OKClickISAR( ) +{ + + this->refreshFEKOSimulationParams(); + this->generator_FEKOSatelliteParams(); + // »æÖÆÕ¹Ê¾Ä£ÐÍ + if (this->myContext.IsNull()) { + this->ui.horizontalSlider_PRF->setValue(0); + //this->on_horizontalSlider_PRF_valueChanged(0); + } + emit this->simulationparams->FEKOSimulationDataparamsChanged(); +} +void QtSARAntModelSettingClass::OKClickStrip( ) +{ + qDebug() << u8"¼ÆËã Strip..."; + this->refreshFEKOSimulationParams(); + this->generator_FEKOSatelliteParams(); + if (this->myContext.IsNull()) { + this->ui.horizontalSlider_PRF->setValue(0); + } + emit this->simulationparams->FEKOSimulationDataparamsChanged(); +} +void QtSARAntModelSettingClass::OKClickCircleSAR( ) +{ + this->refreshFEKOSimulationParams(); + this->generator_FEKOSatelliteParams(); + // »æÖÆÕ¹Ê¾Ä£ÐÍ + if (this->myContext.IsNull()) { + this->ui.horizontalSlider_PRF->setValue(0); + //this->on_horizontalSlider_PRF_valueChanged(0); + } + emit this->simulationparams->FEKOSimulationDataparamsChanged(); + +} +void QtSARAntModelSettingClass::OKClickScane( ) +{ + this->refreshFEKOSimulationParams(); + this->generator_FEKOSatelliteParams(); + if (this->myContext.IsNull()) { + this->ui.horizontalSlider_PRF->setValue(0); + } + emit this->simulationparams->FEKOSimulationDataparamsChanged(); +} + +void QtSARAntModelSettingClass::OKClickFreqSetting( ) +{ + this->refreshFEKOSimulationParams(); + emit this->simulationparams->FEKOSimulationDataparamsChanged(); +} + +void QtSARAntModelSettingClass::OKClickImageSetting( ) +{ + this->refreshFEKOSimulationParams(); + emit this->simulationparams->FEKOSimulationDataparamsChanged(); +} + +void QtSARAntModelSettingClass::on_comboBox_ImageMode_currentIndexChanged(int index) +{ + QString text = this->ui.comboBox_ImageMode->currentText(); + this->simulationparams->imagemode = FEKOBase::FEKOImageModeString2Enum(text.trimmed()); + if (this->simulationparams->imagemode == FEKOBase::FEKOImageMode::UNKNOW) { + QMessageBox::information(nullptr, QString::fromUtf8(u8"´íÎó"), QString::fromUtf8(u8"δ֪µÄ³ÉÏñģʽ")); + return; + } + else if (this->simulationparams->imagemode == FEKOBase::FEKOImageMode::Strip) { + this->switchStripImageParamsWeight(); + } + else if (this->simulationparams->imagemode == FEKOBase::FEKOImageMode::Scane) { + this->switchScanImageParamsWeight(); + } + else if (this->simulationparams->imagemode == FEKOBase::FEKOImageMode::ISAR) { + this->switchISARImageParamsWeight(); + } + else if (this->simulationparams->imagemode == FEKOBase::FEKOImageMode::CircleSAR) { + this->switchCircleSARImageParamsWeight(); + } + else { + QMessageBox::information(nullptr, QString::fromUtf8(u8"´íÎó"), QString::fromUtf8(u8"δ֪µÄ³ÉÏñģʽ")); + } +} + +void QtSARAntModelSettingClass::on_pushButton_ffe_clicked() +{ + QtWidgetsClass_FarSourceSetting* ffeselectwindows = new QtWidgetsClass_FarSourceSetting(this); + QObject::connect(ffeselectwindows, SIGNAL(setResultSelected(size_t, size_t, QString)), this, SLOT(SelectFFESourcePath(size_t, size_t, QString))); + ffeselectwindows->show(); +} + +void QtSARAntModelSettingClass::on_comboBox_LookSide_currentIndexChanged(int index) +{ + QString lookside = this->ui.comboBox_LookSide->currentText(); + if (lookside == u8"×óÊÓ") { + this->simulationparams->isRight = false; + } + else { + this->simulationparams->isRight = true; + } +} + +void QtSARAntModelSettingClass::on_horizontalSlider_PRF_valueChanged(int value) +{ + if (this->FEKOAntPoselist.size() == 0) { + return; + } + + this->ui.horizontalSlider_PRF->setMinimum(0); + this->ui.horizontalSlider_PRF->setMaximum(this->FEKOAntPoselist.size()-1); + + + // ÒÆ³ý¾É + Handle(AIS_InteractiveObject) moveShapeold = this->antModel->get_antModelShow(); + this->myContext->Remove(moveShapeold,Standard_False); + + // Ôö¼ÓР+ FEKOBase::FEKOSatelliteParams temp = this->FEKOAntPoselist[value]; + this->antModel->applyAntModel(temp.pose.pos.Px, temp.pose.pos.Py, temp.pose.pos.Pz, temp.pose.vel.Vx, temp.pose.vel.Vy, temp.pose.vel.Vz, temp.incidenceAngle, temp.AzAngle, this->simulationparams->isRight); + Handle(AIS_InteractiveObject) moveShape = this->antModel->get_antModelShow(); + this->myContext->Display(moveShape, Standard_True); + + + if (this->simulationparams->imagemode == FEKOBase::FEKOImageMode::ISAR || this->simulationparams->imagemode == FEKOBase::FEKOImageMode::CircleSAR) { + this->ui.label_AZ_Angle->setText(u8"·½Î»½Ç£º"); + } + else { + this->ui.label_AZ_Angle->setText(u8"²à°Ú½Ç£º"); + } + this->ui.lineEdit_PRF_Show->setText(QString::number(temp.PRFidx)); + this->ui.lineEdit_X_Show->setText(QString::number(temp.pose.pos.Px)); + this->ui.lineEdit_Y_Show->setText(QString::number(temp.pose.pos.Py)); + this->ui.lineEdit_Z_Show->setText(QString::number(temp.pose.pos.Pz)); + this->ui.lineEdit_Az_Show->setText(QString::number(temp.AzAngle)); + this->ui.lineEdit_incangle_Show->setText(QString::number(temp.incidenceAngle)); + + this->ui.lineEdit_X_Show->setReadOnly(true); + this->ui.lineEdit_Y_Show->setReadOnly(true); + this->ui.lineEdit_Z_Show->setReadOnly(true); + this->ui.lineEdit_Az_Show->setReadOnly(true); + this->ui.lineEdit_incangle_Show->setReadOnly(true); + + +} + +void QtSARAntModelSettingClass::on_pushButton_OK_clicked() +{ + this->refreshFEKOSimulationParams(); // ×îºó¸üÐÂϲÎÊý + this->saveFEKOImageSettingXML(); + + QString luatext = this->createLuaSciptString(0, this->FEKOAntPoselist.size()); + + // дÈëÎļþ + QString filePath = this->workSpace + QDir::separator() + this->simulationparams->taskName + QString(u8"_%1.lua").arg(FEKOBase::FEKOImageModeenumToString(this->simulationparams->imagemode)); + // ´´½¨Îļþ¶ÔÏó + QFile file(filePath); + + // ´ò¿ªÎļþÒÔ¹©Ð´È룬Èç¹ûÎļþ²»´æÔÚ½«´´½¨ÐÂÎļþ + if (file.open(QIODevice::WriteOnly | QIODevice::Text)) { + // ´´½¨Îı¾Á÷£¬²¢ÉèÖñàÂëΪUTF-8 + QTextStream stream(&file); + stream.setCodec("UTF-8"); + stream << luatext; + // ¹Ø±ÕÎļþ + file.close(); + // ÌáʾÎļþдÈë³É¹¦ + QMessageBox::information(nullptr, QString::fromUtf8(u8"Ìáʾ"), QString::fromUtf8(u8"ÎļþдÈë³É¹¦!\n%1").arg(filePath)); + qDebug() << "File written successfully."; + } + else { + qDebug() << "Could not open file for writing."; + QMessageBox::information(nullptr, QString::fromUtf8(u8"Ìáʾ"), QString::fromUtf8(u8"ÎļþдÈëʧ°Ü")); + } + // ѯÎÊÓû§ÊÇ·ñ¹Ø±Õ´°¿Ú + QMessageBox::StandardButton reply; + reply = QMessageBox::question(this, QString::fromUtf8(u8"Ìáʾ"), QString::fromUtf8(u8"ÊÇ·ñ¹Ø±Õ´°¿Ú?"), + QMessageBox::Yes | QMessageBox::No); + if (reply == QMessageBox::Yes) { + this->close(); + } + else { + return; + } +} + +void QtSARAntModelSettingClass::on_pushButton_Cancel_clicked() +{ + // ѯÎÊÓû§ÊÇ·ñ¹Ø±Õ´°¿Ú + QMessageBox::StandardButton reply; + reply = QMessageBox::question(this, QString::fromUtf8(u8"Ìáʾ"), QString::fromUtf8(u8"ÊÇ·ñ¹Ø±Õ´°¿Ú?"), + QMessageBox::Yes | QMessageBox::No); + if (reply == QMessageBox::Yes) { + this->close(); + } + else { + return; + } +} + +void QtSARAntModelSettingClass::on_lineEdit_Range_editingFinished() +{ + // ´«²¥¼ÆËã + this->simulationparams->setRefRange(this->ui.lineEdit_refRange->text().toDouble()); + QMessageBox::StandardButton reply = QMessageBox::question(this, u8"Ìáʾ", u8"ÊÇ·ñÖØÐ¼ÆËã×Ë̬", QMessageBox::Yes | QMessageBox::No); + if (reply == QMessageBox::Yes) { + this->generator_FEKOSatelliteParams(); + } + else { + return; + } +} + +void QtSARAntModelSettingClass::SelectFFESourcePath(size_t thetaPoints, size_t phiPoints, QString ffePath) +{ + if (!isExists(ffePath)) { + // ¾¯¸æÎļþ²»´æÔÚ + QMessageBox::information(nullptr, QString::fromUtf8(u8"´íÎó"), QString::fromUtf8(u8"Îļþ²»´æÔÚ")); + return; + } + QString filename = getFileNameFromPath(ffePath); + { + QFile sourceFile(ffePath); + + QString fullpath = QDir::cleanPath(this->workSpace + QDir::separator() + filename); + QFile destinationFile(fullpath); + + // ´ò¿ªÔ´ÎļþÒÔ¹©¶ÁÈ¡ + if (sourceFile.open(QIODevice::ReadOnly)) { + // ´ò¿ªÄ¿±êÎļþÒÔ¹©Ð´Èë + if (destinationFile.open(QIODevice::WriteOnly)) { + // ½«Ô´ÎļþÄÚÈݸ´ÖƵ½Ä¿±êÎļþ + QByteArray data = sourceFile.readAll(); + destinationFile.write(data); + // ¹Ø±ÕÎļþ + destinationFile.close(); + } + else { + qDebug() << "Could not open destination file for writing."; + } + + // ¹Ø±ÕÔ´Îļþ + sourceFile.close(); + } + else { + qDebug() << "Could not open source file for reading."; + } + + } + + + this->ui.lineEdit_farsourcePath->setText(filename); + this->simulationparams->setAntennaRadiationFileName(filename); + this->simulationparams->setFarsourceThetaPoints(thetaPoints); + this->simulationparams->setFarsourcePhiPoints(phiPoints); + + +} + +void QtSARAntModelSettingClass::FEKOSimulationDataparamsChanged_slots() +{ + qDebug() << u8"QtSARAntModelSettingClass::bandingsetFEKOSimulationDataparams()"; + + + + +} + +void QtSARAntModelSettingClass::bandingsetFEKOSimulationDataparams() +{ + QObject::connect(this->simulationparams.get(), SIGNAL(FEKOSimulationDataparamsChanged()), this, SLOT(FEKOSimulationDataparamsChanged_slots())); + + this->Widgetfreqsetting->setFEKOSimulationDataparams(this->simulationparams); + this->WidgetImageSetting->setFEKOSimulationDataparams(this->simulationparams); + // Ìí¼Ó³ÉÏñģʽ + this->WidgetISARMode->setFEKOSimulationDataparams(this->simulationparams); + this->WidgetCirCleSARMode->setFEKOSimulationDataparams(this->simulationparams); + this->WidgetScanMode->setFEKOSimulationDataparams(this->simulationparams); + this->WidgetstriMode->setFEKOSimulationDataparams(this->simulationparams); + emit this->simulationparams->FEKOSimulationDataparamsChanged(); + +} + + diff --git a/src/WBCLFZSystemModule/QtSARAntModelSetting.h b/src/WBCLFZSystemModule/QtSARAntModelSetting.h new file mode 100644 index 0000000..299a75c --- /dev/null +++ b/src/WBCLFZSystemModule/QtSARAntModelSetting.h @@ -0,0 +1,121 @@ +#pragma once +#include "AllHead.h" +#include "OCCTBaseOperaorClass.h" +#include +#include "ui_QtSARAntModelSetting.h" +#include +#include "QtWidgetsClass_Strip.h" +#include "QtWidgetsClass_Scan.h" +#include "QtWidgetsClass_ISAR.h" +#include "QtWidgetsClass_CircleSAR.h" +#include "QtWidgetsClass_FarSourceSetting.h" +#include "QtWidgetsClass_ImageSetting.h" + + +/////////////////////////////////////////////////// +// ÎÀÐÇÀ×´ïÄ£ÐÍ +// ĬÈÏÀ×´ïÖÐÐÄ +// XÖáΪ·ÉÐз½Ïò +// ZÖáΪÕÕÉä·½Ïò ĬÈÏ×óÈëÉäΪ - £¬ÓÒÈëÉäΪ + +// X +// ^ +// L | R +// Y<--Z +// | +// TopoSAR : http://radarst.cnjournals.com/html/2022/2/202202004.html +// 1. ´´½¨Ä£ÐÍ +// 2. ×¢ÈëλÖá¢ËÙ¶È·½Ïò¡¢ÈëÉä½Ç¡¢·½Î»½Ç +// 3. »ñÈ¡À×´ïÌìÏß¼ÆËã½á¹û +// 4. äÖȾģÐÍ +////////////////////////////////////////////////// +class antModelClass { // Ä£ÐͲÎÊý +public: + antModelClass(QString filpath); // 1. ´´½¨Ä£ÐÍ + antModelClass(); + ~antModelClass(); + void initAxis(); +public: + void applyAntModel( // 2. ×¢ÈëλÖá¢ËÙ¶È·½Ïò¡¢ÈëÉä½Ç¡¢·½Î»½Ç + double Sx, double Sy, double Sz, // ÎÀÐÇ×ø±ê + double Vx,double Vy,double Vz, // ÎÀÐÇËÙ¶È + double incidenceAngle, double AzAngle ,bool isRIGHT=false); // ÈëÉä½Ç¡¢·½Î»½Ç ¡¢ ×óÓÒÊÓ + + void createDefaultAntModel(); // ´´½¨Ä¬ÈÏÄ£ÐÍ + + FEKOBase::FEKOantPitionDirect get_antposition_Direct(); // 3. »ñÈ¡À×´ïÌìÏß¼ÆËã½á¹û + Handle(AIS_InteractiveObject) get_antModelShow(); // 4. äÖȾģÐÍ + +private: + Handle(AIS_InteractiveObject) antModelShow; // ÓÃÓÚչʾµÄÀ×´ïÄ£ÐÍ£¬ + TopoDS_Shape antModel; // ԭʼÀ×´ïÄ£ÐÍ + FEKOBase::FEKOantPitionDirect antposition_Direct; // À×´ïÌìÏßµÄ×ø±êÓëÖ¸Ïò + +}; + + + + +/////////////////////////////////////////////////// +// À×´ïÖ¸ÏòÄ£ÐÍÉèÖÃÀà +////////////////////////////////////////////////// +class QtSARAntModelSettingClass : public QDialog, public FEKOBase::FEKOSimulationSARClass +{ + Q_OBJECT +public: + QtSARAntModelSettingClass(QWidget *parent = nullptr); + ~QtSARAntModelSettingClass(); + +private: + Ui::QtSARAntModelSettingClass ui; + QtFreqParamsSetting* Widgetfreqsetting; // ƵÂÊÉèÖô°¿Ú + + QtWidgetsClass_Strip* WidgetstriMode;// ³ÉÏñ²ÎÊýÉèÖà + QtWidgetsClass_Scan* WidgetScanMode; + QtWidgetsClass_ISAR* WidgetISARMode; + QtWidgetsClass_CircleSAR* WidgetCirCleSARMode; + + QtWidgetsClass_ImageSetting* WidgetImageSetting; + antModelClass* antModel; // Ä£ÐÍ + //DocumentCommon* occtdocument; // Îĵµ + Handle(AIS_InteractiveContext) myContext; // ´°¿Ú½»»¥ +public: + + void removeModeSettingWidget(); // ÒÆ³ýģʽÉèÖô°¿Ú + void setOCCTDocument(Handle(AIS_InteractiveContext) myContext); + // Çл» Ìõ´øÍ¼Ïñ¡¢É¨ÃèͼÏñ¡¢ISAR¡¢Ô²¼£SAR + void switchStripImageParamsWeight(); // Çл»Ìõ´øÍ¼Ïñ²ÎÊýÈ¨ÖØ + void switchScanImageParamsWeight(); // Çл»É¨ÃèͼÏñ²ÎÊýÈ¨ÖØ + void switchISARImageParamsWeight(); // Çл»ISARͼÏñ²ÎÊýÈ¨ÖØ + void switchCircleSARImageParamsWeight(); // Çл»Ô²¼£SARͼÏñ²ÎÊýÈ¨ÖØ + void ReferenceWindows(); // äÖȾ´°Ìå + + void refreshFEKOSimulationParams(); + +signals: + + + +public slots: + void OKClickISAR( ); + void OKClickStrip( ); + void OKClickCircleSAR( ); + void OKClickScane( ); + void OKClickFreqSetting( ); + void OKClickImageSetting( ); + + void on_comboBox_ImageMode_currentIndexChanged(int index); + void on_pushButton_ffe_clicked(); + void on_comboBox_LookSide_currentIndexChanged(int index); + void on_horizontalSlider_PRF_valueChanged(int value); + void on_pushButton_OK_clicked(); + void on_pushButton_Cancel_clicked(); + void on_lineEdit_Range_editingFinished(); + + void SelectFFESourcePath(size_t thetaPoints, size_t phiPoints, QString ffePath); +public slots: + void FEKOSimulationDataparamsChanged_slots() ; +public: + void bandingsetFEKOSimulationDataparams() override; +}; + +antModelClass antModelClassFactory(); \ No newline at end of file diff --git a/src/WBCLFZSystemModule/QtSARAntModelSetting.ui b/src/WBCLFZSystemModule/QtSARAntModelSetting.ui new file mode 100644 index 0000000..619ce8a --- /dev/null +++ b/src/WBCLFZSystemModule/QtSARAntModelSetting.ui @@ -0,0 +1,575 @@ + + + QtSARAntModelSettingClass + + + + 0 + 0 + 759 + 737 + + + + å¤©çº¿å‚æ•°è®¾ç½® + + + + + + + 0 + 25 + + + + + 120 + 25 + + + + æˆåƒæ¨¡å¼ + + + + + + + 3 + + + + 频率设置 + + + + + + 模å¼å‚数设置 + + + + + + æˆåƒå‚数设置 + + + + + + é›·è¾¾å§¿æ€æŸ¥çœ‹æŽ§åˆ¶é¡µé¢ + + + + + + Qt::Horizontal + + + + + + + ä¿¡æ¯ + + + + + + + 0 + 25 + + + + + 16777215 + 25 + + + + Z: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + 0 + 25 + + + + + 16777215 + 25 + + + + + + + + + 0 + 25 + + + + + 16777215 + 25 + + + + + + + + + 0 + 25 + + + + + 16777215 + 25 + + + + 入射角: + + + + + + + + 0 + 25 + + + + + 16777215 + 25 + + + + X: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + 0 + 25 + + + + + 16777215 + 25 + + + + + + + + + 0 + 25 + + + + + 16777215 + 25 + + + + PRF: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + 0 + 25 + + + + + 16777215 + 25 + + + + Y: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + 0 + 25 + + + + + 16777215 + 25 + + + + + + + + + 0 + 25 + + + + + 16777215 + 25 + + + + + + + + + 0 + 25 + + + + + 16777215 + 25 + + + + + + + + + 0 + 25 + + + + + 16777215 + 25 + + + + 侧摆角: + + + + + + + + + + + + + + + 0 + 30 + + + + + 16777215 + 30 + + + + + + + + + 0 + 25 + + + + + 16777215 + 25 + + + + è¾å°„æ–¹å‘图文件 + + + + + + + + 0 + 30 + + + + + 16777215 + 30 + + + + + + + + + 0 + 30 + + + + + 16777215 + 30 + + + + + + + + + 0 + 30 + + + + + 16777215 + 30 + + + + 入射角 + + + + + + + + 16777215 + 30 + + + + 打开 + + + + + + + + 0 + 30 + + + + + 16777215 + 30 + + + + + + + + + 0 + 30 + + + + + 16777215 + 30 + + + + + + + + + 0 + 40 + + + + + 16777215 + 40 + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 0 + 25 + + + + + 16777215 + 25 + + + + 确定 + + + + + + + + 0 + 25 + + + + + 16777215 + 25 + + + + å–æ¶ˆ + + + + + + + + + + å·¦å³è§† + + + + + + + + 0 + 25 + + + + + 16777215 + 25 + + + + å‚考斜è·ï¼ˆm): + + + + + + + + 0 + 25 + + + + + 16777215 + 25 + + + + 任务åç§° + + + + + + + + 0 + 30 + + + + + 16777215 + 30 + + + + + + + + + + diff --git a/src/WBCLFZSystemModule/QtStripImageSettingClass.cpp b/src/WBCLFZSystemModule/QtStripImageSettingClass.cpp new file mode 100644 index 0000000..8e7d8d9 --- /dev/null +++ b/src/WBCLFZSystemModule/QtStripImageSettingClass.cpp @@ -0,0 +1,10 @@ +#include "QtStripImageSettingClass.h" + +QtStripImageSettingClass::QtStripImageSettingClass(QWidget *parent) + : QWidget(parent) +{ + ui.setupUi(this); +} + +QtStripImageSettingClass::~QtStripImageSettingClass() +{} diff --git a/src/WBCLFZSystemModule/QtStripImageSettingClass.h b/src/WBCLFZSystemModule/QtStripImageSettingClass.h new file mode 100644 index 0000000..6c8c5e9 --- /dev/null +++ b/src/WBCLFZSystemModule/QtStripImageSettingClass.h @@ -0,0 +1,19 @@ +#pragma once + + + +#include "AllHead.h" +#include +#include "ui_QtStripImageSettingClass.h" + +class QtStripImageSettingClass : public QWidget +{ + Q_OBJECT + +public: + QtStripImageSettingClass(QWidget *parent = nullptr); + ~QtStripImageSettingClass(); + +private: + Ui::QtStripImageSettingClassClass ui; +}; diff --git a/src/WBCLFZSystemModule/QtStripImageSettingClass.ui b/src/WBCLFZSystemModule/QtStripImageSettingClass.ui new file mode 100644 index 0000000..1fe2f02 --- /dev/null +++ b/src/WBCLFZSystemModule/QtStripImageSettingClass.ui @@ -0,0 +1,20 @@ + + + QtStripImageSettingClassClass + + + + 0 + 0 + 600 + 400 + + + + æ¡å¸¦æ¨¡å¼å¤©çº¿å§¿æ€è®¾ç½® + + + + + + diff --git a/src/WBCLFZSystemModule/QtWidgetsClass_CircleSAR.cpp b/src/WBCLFZSystemModule/QtWidgetsClass_CircleSAR.cpp new file mode 100644 index 0000000..7214d5d --- /dev/null +++ b/src/WBCLFZSystemModule/QtWidgetsClass_CircleSAR.cpp @@ -0,0 +1,41 @@ +#include "QtWidgetsClass_CircleSAR.h" + + + +QtWidgetsClass_CircleSAR::QtWidgetsClass_CircleSAR(QWidget *parent) + : QWidget(parent) +{ + ui.setupUi(this); +} + +QtWidgetsClass_CircleSAR::~QtWidgetsClass_CircleSAR() +{} + +void QtWidgetsClass_CircleSAR::FEKOSimulationDataparamsChanged_slots() +{ + if (this->simulationparams->imagemode == FEKOBase::FEKOImageMode::CircleSAR) { + this->ui.lineEdit_deltaAzAngle->setText(QString::number(this->simulationparams->delta_angle)); + } + else if (this->simulationparams->imagemode == FEKOBase::FEKOImageMode::ISAR) { + this->ui.lineEdit_deltaAzAngle->setText(QString::number(this->simulationparams->delta_angle)); + } + else { + return; + } +} + +void QtWidgetsClass_CircleSAR::bandingsetFEKOSimulationDataparams() +{ + QObject::connect(this->simulationparams.get(), SIGNAL(FEKOSimulationDataparamsChanged()), this, SLOT(FEKOSimulationDataparamsChanged_slots())); + +} + + + +void QtWidgetsClass_CircleSAR::on_pushButton_OK_clicked() { + + this->simulationparams->setDelta_angle(ui.lineEdit_deltaAzAngle->text().toDouble()); + this->simulationparams->setImagemode(FEKOBase::FEKOImageMode::CircleSAR); + emit this->OKClick(); + +} \ No newline at end of file diff --git a/src/WBCLFZSystemModule/QtWidgetsClass_CircleSAR.h b/src/WBCLFZSystemModule/QtWidgetsClass_CircleSAR.h new file mode 100644 index 0000000..cfdbf70 --- /dev/null +++ b/src/WBCLFZSystemModule/QtWidgetsClass_CircleSAR.h @@ -0,0 +1,30 @@ +#pragma once +#ifndef QTWIDGETSCLASS_CIRCLESAR_H +#define QTWIDGETSCLASS_CIRCLESAR_H +#include "AllHead.h" +#include +#include "ui_QtWidgetsClass_CircleSAR.h" + +class QtWidgetsClass_CircleSAR : public QWidget, public FEKOBase::FEKOSimulationDataparamsHandler +{ + Q_OBJECT + +public: + QtWidgetsClass_CircleSAR(QWidget *parent = nullptr); + ~QtWidgetsClass_CircleSAR(); + +public slots: + void FEKOSimulationDataparamsChanged_slots(); +public: + void bandingsetFEKOSimulationDataparams() override; + +signals: + void OKClick(); +public slots: + void on_pushButton_OK_clicked(); +private: + Ui::QtWidgetsClass_CircleSARClass ui; +}; + + +#endif \ No newline at end of file diff --git a/src/WBCLFZSystemModule/QtWidgetsClass_CircleSAR.ui b/src/WBCLFZSystemModule/QtWidgetsClass_CircleSAR.ui new file mode 100644 index 0000000..8c94724 --- /dev/null +++ b/src/WBCLFZSystemModule/QtWidgetsClass_CircleSAR.ui @@ -0,0 +1,77 @@ + + + QtWidgetsClass_CircleSARClass + + + + 0 + 0 + 600 + 280 + + + + QtWidgetsClass_CircleSAR + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + 0 + 25 + + + + + 16777215 + 25 + + + + æ–¹ä½è§’度间隔 + + + + + + + + 0 + 25 + + + + + 16777215 + 25 + + + + + + + + 计算 + + + + + + + + + diff --git a/src/WBCLFZSystemModule/QtWidgetsClass_FarSourceSetting.cpp b/src/WBCLFZSystemModule/QtWidgetsClass_FarSourceSetting.cpp new file mode 100644 index 0000000..9fa722d --- /dev/null +++ b/src/WBCLFZSystemModule/QtWidgetsClass_FarSourceSetting.cpp @@ -0,0 +1,49 @@ +#include "QtWidgetsClass_FarSourceSetting.h" + +QtWidgetsClass_FarSourceSetting::QtWidgetsClass_FarSourceSetting(QWidget *parent) + : QDialog(parent) +{ + ui.setupUi(this); +} + +QtWidgetsClass_FarSourceSetting::~QtWidgetsClass_FarSourceSetting() +{} + +size_t QtWidgetsClass_FarSourceSetting::getThetaPoints() +{ + return this->ui.lineEdit_thetaPoints->text().toInt(); +} + +size_t QtWidgetsClass_FarSourceSetting::getPhiPoints() +{ + return this->ui.lineEdit_phiPoints->text().toInt(); +} + +QString QtWidgetsClass_FarSourceSetting::getFFEPath() +{ + return this->ui.lineEdit_filepath->text().trimmed(); +} + +void QtWidgetsClass_FarSourceSetting::on_pushButton_Cancel_clicked() +{ + this->close(); +} +void QtWidgetsClass_FarSourceSetting::on_pushButton_select_clicked() +{ + QString fileName = getOpenFilePath(this, u8"Open File", u8"FFE Files (*.ffe)"); + if (!fileName.isEmpty()) { + this->ui.lineEdit_filepath->setText(fileName); + // ´ò¿ªÎļþ + FEKOBase::FEKOFarFieldFileClass* farfieldfile = new FEKOBase::FEKOFarFieldFileClass(); + farfieldfile->parseFarFieldFile(fileName); + if (farfieldfile->dataBlockList.count() == 0) { + QMessageBox::warning(nullptr, u8"¾¯¸æ", u8"ffeÎļþ½âÎöʧ°Ü£¬Çë¼ì²éÎļþ¸ñʽÊÇ·ñÕýÈ·£¡"); + } + this->ui.lineEdit_thetaPoints->setText(QString::number( farfieldfile->dataBlockList[0].thetaSamples)); + this->ui.lineEdit_phiPoints->setText(QString::number(farfieldfile->dataBlockList[0].phiSamples)); + } +} +void QtWidgetsClass_FarSourceSetting::on_pushButton_OK_clicked() { + emit this->setResultSelected(this->getThetaPoints(), this->getPhiPoints(), this->getFFEPath()); + this->close(); +} \ No newline at end of file diff --git a/src/WBCLFZSystemModule/QtWidgetsClass_FarSourceSetting.h b/src/WBCLFZSystemModule/QtWidgetsClass_FarSourceSetting.h new file mode 100644 index 0000000..3fb562a --- /dev/null +++ b/src/WBCLFZSystemModule/QtWidgetsClass_FarSourceSetting.h @@ -0,0 +1,38 @@ +#pragma once +#ifndef QTWIDGETSCLASS_FARSOURCESETTING_H +#define QTWIDGETSCLASS_FARSOURCESETTING_H + +#include "AllHead.h" +#include +#include "ui_QtWidgetsClass_FarSourceSetting.h" + +class QtWidgetsClass_FarSourceSetting : public QDialog +{ + Q_OBJECT +public: + QtWidgetsClass_FarSourceSetting(QWidget *parent = nullptr); + ~QtWidgetsClass_FarSourceSetting(); + + size_t getThetaPoints(); + size_t getPhiPoints(); + QString getFFEPath(); + + +public slots: + void on_pushButton_OK_clicked(); + void on_pushButton_Cancel_clicked(); + void on_pushButton_select_clicked(); + +signals: + void setResultSelected(size_t thetaPoints, size_t phiPoints, QString ffePath); + +private: + Ui::QtWidgetsClass_FarSourceSettingClass ui; +}; + + + + + + +#endif diff --git a/src/WBCLFZSystemModule/QtWidgetsClass_FarSourceSetting.ui b/src/WBCLFZSystemModule/QtWidgetsClass_FarSourceSetting.ui new file mode 100644 index 0000000..96dd5e4 --- /dev/null +++ b/src/WBCLFZSystemModule/QtWidgetsClass_FarSourceSetting.ui @@ -0,0 +1,214 @@ + + + QtWidgetsClass_FarSourceSettingClass + + + + 0 + 0 + 600 + 400 + + + + 远场天线方å‘图文件 + + + + + + + 0 + 25 + + + + + 16777215 + 25 + + + + + + + + + 0 + 25 + + + + + 16777215 + 25 + + + + 天线文件 + + + + + + + + 0 + 25 + + + + + 16777215 + 25 + + + + phi点数 + + + + + + + + 0 + 25 + + + + + 16777215 + 25 + + + + 选择 + + + + + + + + 0 + 25 + + + + + 16777215 + 25 + + + + + + + + + 0 + 25 + + + + + 16777215 + 25 + + + + + + + + + 0 + 25 + + + + + 16777215 + 25 + + + + theta点数 + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 0 + 25 + + + + + 16777215 + 25 + + + + 确定 + + + + + + + + 0 + 25 + + + + + 16777215 + 25 + + + + 退出 + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + diff --git a/src/WBCLFZSystemModule/QtWidgetsClass_ISAR.cpp b/src/WBCLFZSystemModule/QtWidgetsClass_ISAR.cpp new file mode 100644 index 0000000..4084e4d --- /dev/null +++ b/src/WBCLFZSystemModule/QtWidgetsClass_ISAR.cpp @@ -0,0 +1,50 @@ +#include "QtWidgetsClass_ISAR.h" + + + +void QtWidgetsClass_ISAR::FEKOSimulationDataparamsChanged_slots() +{ + if (this->simulationparams->imagemode == FEKOBase::FEKOImageMode::ISAR) { + this->ui.lineEdit_deltaAngle->setText(QString::number(this->simulationparams->delta_angle)); + this->ui.lineEdit_startAzAngle->setText(QString::number(this->simulationparams->start_circle_angle)); + this->ui.lineEdit_EndAzAngle->setText(QString::number(this->simulationparams->end_circle_angle)); + } + else if (this->simulationparams->imagemode == FEKOBase::FEKOImageMode::CircleSAR) { + this->ui.lineEdit_deltaAngle->setText(QString::number(this->simulationparams->delta_angle)); + } + else { + return; + } + +} + +void QtWidgetsClass_ISAR::bandingsetFEKOSimulationDataparams() +{ + QObject::connect(this->simulationparams.get(), SIGNAL(FEKOSimulationDataparamsChanged()), this, SLOT(FEKOSimulationDataparamsChanged_slots())); + +} + +QtWidgetsClass_ISAR::QtWidgetsClass_ISAR(QWidget* parent) + : QWidget(parent) +{ + ui.setupUi(this); +} + +QtWidgetsClass_ISAR::~QtWidgetsClass_ISAR() +{} + + +void QtWidgetsClass_ISAR::on_pushButton_OK_clicked() { + + //¸ù¾ÝOKClick²ÎÊý,½áºÏ¿Ø¼þ£¬»ñÈ¡²ÎÊý + + double startAngle = this->ui.lineEdit_startAzAngle->text().toDouble(); + double endAngle = this->ui.lineEdit_EndAzAngle->text().toDouble(); + double deltaAngle = this->ui.lineEdit_deltaAngle->text().toDouble(); + this->simulationparams->setStart_circle_angle(startAngle); + this->simulationparams->setEnd_circle_angle(endAngle); + this->simulationparams->setDelta_angle(deltaAngle); + this->simulationparams->setImagemode(FEKOBase::FEKOImageMode::ISAR); + emit this->OKClick(); + +} \ No newline at end of file diff --git a/src/WBCLFZSystemModule/QtWidgetsClass_ISAR.h b/src/WBCLFZSystemModule/QtWidgetsClass_ISAR.h new file mode 100644 index 0000000..e0272c7 --- /dev/null +++ b/src/WBCLFZSystemModule/QtWidgetsClass_ISAR.h @@ -0,0 +1,32 @@ +#pragma once +#ifndef QTWIDGETSCLASS_ISAR_H +#define QTWIDGETSCLASS_ISAR_H + +#include "AllHead.h" +#include +#include "ui_QtWidgetsClass_ISAR.h" + +class QtWidgetsClass_ISAR : public QWidget, public FEKOBase::FEKOSimulationDataparamsHandler +{ + Q_OBJECT + + +public slots: + void FEKOSimulationDataparamsChanged_slots(); +public: + void bandingsetFEKOSimulationDataparams() override; + +public: + QtWidgetsClass_ISAR(QWidget *parent = nullptr); + ~QtWidgetsClass_ISAR(); +signals: + void OKClick(); +public slots: + void on_pushButton_OK_clicked(); +private: + Ui::QtWidgetsClass_ISARClass ui; +}; + + + +#endif \ No newline at end of file diff --git a/src/WBCLFZSystemModule/QtWidgetsClass_ISAR.ui b/src/WBCLFZSystemModule/QtWidgetsClass_ISAR.ui new file mode 100644 index 0000000..7369b9f --- /dev/null +++ b/src/WBCLFZSystemModule/QtWidgetsClass_ISAR.ui @@ -0,0 +1,147 @@ + + + QtWidgetsClass_ISARClass + + + + 0 + 0 + 545 + 212 + + + + QtWidgetsClass_ISAR + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + 0 + 25 + + + + + 16777215 + 25 + + + + 终止方ä½è§’ + + + + + + + + 0 + 25 + + + + + 16777215 + 25 + + + + æ–¹ä½è§’é—´éš” + + + + + + + + 0 + 25 + + + + + 16777215 + 25 + + + + + + + + + 0 + 25 + + + + + 16777215 + 25 + + + + + + + + 计算 + + + + + + + + 0 + 25 + + + + + 16777215 + 25 + + + + + + + + + 0 + 25 + + + + + 16777215 + 25 + + + + èµ·å§‹æ–¹ä½è§’ + + + + + + + + + diff --git a/src/WBCLFZSystemModule/QtWidgetsClass_ImageSetting.cpp b/src/WBCLFZSystemModule/QtWidgetsClass_ImageSetting.cpp new file mode 100644 index 0000000..19c0db0 --- /dev/null +++ b/src/WBCLFZSystemModule/QtWidgetsClass_ImageSetting.cpp @@ -0,0 +1,45 @@ +#include "QtWidgetsClass_ImageSetting.h" + + + +void QtWidgetsClass_ImageSetting::FEKOSimulationDataparamsChanged_slots() +{ + this->ui.lineEdit_minX->setText(QString::number(this->simulationparams->getX_min())); + this->ui.lineEdit__maxX->setText(QString::number(this->simulationparams->getX_max())); + this->ui.lineEdit__minY->setText(QString::number(this->simulationparams->getY_min())); + this->ui.lineEdit__maxY->setText(QString::number(this->simulationparams->getY_max())); + this->ui.lineEdit_planeZ->setText(QString::number(this->simulationparams->getZ_plane())); + this->ui.lineEdit_height->setText(QString::number(this->simulationparams->getImageheight())); + this->ui.lineEdit_width->setText(QString::number(this->simulationparams->getImagewidth())); +} + +void QtWidgetsClass_ImageSetting::bandingsetFEKOSimulationDataparams() +{ + QObject::connect(this->simulationparams.get(), SIGNAL(FEKOSimulationDataparamsChanged()), this, SLOT(FEKOSimulationDataparamsChanged_slots())); + +} + +QtWidgetsClass_ImageSetting::QtWidgetsClass_ImageSetting(QWidget *parent) + : QWidget(parent) +{ + ui.setupUi(this); +} + +QtWidgetsClass_ImageSetting::~QtWidgetsClass_ImageSetting() +{} + + + +void QtWidgetsClass_ImageSetting::on_pushButton_OK_clicked() { + + this->simulationparams->setX_min(this->ui.lineEdit_minX->text().toDouble()); + this->simulationparams->setX_max(this->ui.lineEdit__maxX->text().toDouble()); + this->simulationparams->setY_min(this->ui.lineEdit__minY->text().toDouble()); + this->simulationparams->setY_max(this->ui.lineEdit__maxY->text().toDouble()); + this->simulationparams->setZ_plane(this->ui.lineEdit_planeZ->text().toDouble()); + this->simulationparams->setImageheight(this->ui.lineEdit_height->text().toInt()); + this->simulationparams->setImagewidth(this->ui.lineEdit_width->text().toInt()); + + + emit this->OKClick(); +} \ No newline at end of file diff --git a/src/WBCLFZSystemModule/QtWidgetsClass_ImageSetting.h b/src/WBCLFZSystemModule/QtWidgetsClass_ImageSetting.h new file mode 100644 index 0000000..ae94a2e --- /dev/null +++ b/src/WBCLFZSystemModule/QtWidgetsClass_ImageSetting.h @@ -0,0 +1,36 @@ +#pragma once + +#ifndef QTWIDGETSCLASS_IMAGESETTING_H +#define QTWIDGETSCLASS_IMAGESETTING_H + +#include "AllHead.h" +#include +#include "ui_QtWidgetsClass_ImageSetting.h" + +class QtWidgetsClass_ImageSetting : public QWidget, public FEKOBase::FEKOSimulationDataparamsHandler +{ + Q_OBJECT + +public slots: + void FEKOSimulationDataparamsChanged_slots(); +public: + void bandingsetFEKOSimulationDataparams() override; + +public: + QtWidgetsClass_ImageSetting(QWidget *parent = nullptr); + ~QtWidgetsClass_ImageSetting(); + +signals: + + void OKClick( ); + +public slots: + void on_pushButton_OK_clicked(); + +private: + Ui::QtWidgetsClass_ImageSettingClass ui; +}; + + + +#endif \ No newline at end of file diff --git a/src/WBCLFZSystemModule/QtWidgetsClass_ImageSetting.ui b/src/WBCLFZSystemModule/QtWidgetsClass_ImageSetting.ui new file mode 100644 index 0000000..6550869 --- /dev/null +++ b/src/WBCLFZSystemModule/QtWidgetsClass_ImageSetting.ui @@ -0,0 +1,266 @@ + + + QtWidgetsClass_ImageSettingClass + + + + 0 + 0 + 600 + 400 + + + + QtWidgetsClass_ImageSetting + + + + + + æˆåƒå‡ ä½•设置 + + + + + + + 0 + 25 + + + + + 16777215 + 25 + + + + X范围 + + + + + + + + 0 + 25 + + + + + 16777215 + 25 + + + + Y范围 + + + + + + + + 0 + 25 + + + + + 16777215 + 25 + + + + æˆåƒå¹³é¢é«˜ç¨‹Z + + + + + + + + 0 + 25 + + + + + 16777215 + 25 + + + + 最å°å€¼ + + + + + + + + 0 + 25 + + + + + 16777215 + 25 + + + + 最大值 + + + + + + + + 0 + 25 + + + + + 16777215 + 25 + + + + + + + + + 0 + 25 + + + + + 16777215 + 25 + + + + + + + + + 0 + 25 + + + + + 16777215 + 25 + + + + + + + + + 0 + 25 + + + + + 16777215 + 25 + + + + + + + + + 0 + 25 + + + + + 16777215 + 25 + + + + + + + + + + + 图åƒè®¾ç½® + + + + + + 图åƒé«˜åƒç´ ï¼ˆY) + + + + + + + + + + 图åƒå®½åƒç´ ï¼ˆX) + + + + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + ä¿å­˜ + + + + + + + + + + + + + + + + + + diff --git a/src/WBCLFZSystemModule/QtWidgetsClass_Scan.cpp b/src/WBCLFZSystemModule/QtWidgetsClass_Scan.cpp new file mode 100644 index 0000000..3bc08f2 --- /dev/null +++ b/src/WBCLFZSystemModule/QtWidgetsClass_Scan.cpp @@ -0,0 +1,74 @@ +#include "QtWidgetsClass_Scan.h" + + +void QtWidgetsClass_Scan::FEKOSimulationDataparamsChanged_slots() +{ + if (this->simulationparams->imagemode == FEKOBase::FEKOImageMode::Scane) { + this->ui.lineEdit_PRF->setText(QString::number(this->simulationparams->getPRFCount())); + this->ui.lineEdit_Start_x->setText(QString::number(this->simulationparams->start_x)); + this->ui.lineEdit_start_y->setText(QString::number(this->simulationparams->start_y)); + this->ui.lineEdit_start_z->setText(QString::number(this->simulationparams->start_z)); + this->ui.lineEdit_end_x->setText(QString::number(this->simulationparams->end_x)); + this->ui.lineEdit_end_y->setText(QString::number(this->simulationparams->end_y)); + this->ui.lineEdit_end_z->setText(QString::number(this->simulationparams->end_z)); + this->ui.lineEdit_startAzAngle->setText(QString::number(this->simulationparams->start_az_angle)); + this->ui.lineEdit_EndAzAngle->setText(QString::number(this->simulationparams->end_az_angle)); + } + else if (this->simulationparams->imagemode == FEKOBase::FEKOImageMode::Strip) { + this->ui.lineEdit_PRF->setText(QString::number(this->simulationparams->getPRFCount())); + this->ui.lineEdit_Start_x->setText(QString::number(this->simulationparams->start_x)); + this->ui.lineEdit_start_y->setText(QString::number(this->simulationparams->start_y)); + this->ui.lineEdit_start_z->setText(QString::number(this->simulationparams->start_z)); + this->ui.lineEdit_end_x->setText(QString::number(this->simulationparams->end_x)); + this->ui.lineEdit_end_y->setText(QString::number(this->simulationparams->end_y)); + this->ui.lineEdit_end_z->setText(QString::number(this->simulationparams->end_z)); + } + + else { + return; + } +} + +void QtWidgetsClass_Scan::bandingsetFEKOSimulationDataparams() +{ + QObject::connect(this->simulationparams.get(), SIGNAL(FEKOSimulationDataparamsChanged()), this, SLOT(FEKOSimulationDataparamsChanged_slots())); + +} + +QtWidgetsClass_Scan::QtWidgetsClass_Scan(QWidget *parent) + : QWidget(parent) +{ + ui.setupUi(this); + + + +} + +QtWidgetsClass_Scan::~QtWidgetsClass_Scan() +{ + + +} + + +void QtWidgetsClass_Scan::on_pushButton_OK_clicked() { + //²Î¿¼void QtWidgetsClass_ISAR::on_pushButton_OK_clicked() Âß¼­Éú³É´úÂë + + //void OKClick(double incAngle, double refRange, double startAzAngle, double endAzAngle, double start_x, double start_y, double start_z, double end_x, double end_y, double end_z, size_t prfcount); + + this->simulationparams->setStart_az_angle(ui.lineEdit_startAzAngle->text().toDouble()); + this->simulationparams->setEnd_az_angle(ui.lineEdit_EndAzAngle->text().toDouble()); + this->simulationparams->setPRFCount(this->ui.lineEdit_PRF->text().toInt()); + this->simulationparams->setStart_x(this->ui.lineEdit_Start_x->text().toDouble()); + this->simulationparams->setStart_y(this->ui.lineEdit_start_y->text().toDouble()); + this->simulationparams->setStart_z(this->ui.lineEdit_start_z->text().toDouble()); + this->simulationparams->setEnd_x(this->ui.lineEdit_end_x->text().toDouble()); + this->simulationparams->setEnd_y(this->ui.lineEdit_end_y->text().toDouble()); + this->simulationparams->setEnd_z(this->ui.lineEdit_end_z->text().toDouble()); + this->simulationparams->setImagemode(FEKOBase::FEKOImageMode::Scane); + + + + emit this->OKClick(); + +} \ No newline at end of file diff --git a/src/WBCLFZSystemModule/QtWidgetsClass_Scan.h b/src/WBCLFZSystemModule/QtWidgetsClass_Scan.h new file mode 100644 index 0000000..e93bd43 --- /dev/null +++ b/src/WBCLFZSystemModule/QtWidgetsClass_Scan.h @@ -0,0 +1,32 @@ +#pragma once +#ifndef QTWIDGETSCLASS_SCAN_H +#define QTWIDGETSCLASS_SCAN_H + +#include "AllHead.h" +#include +#include "ui_QtWidgetsClass_Scan.h" + +class QtWidgetsClass_Scan : public QWidget, public FEKOBase::FEKOSimulationDataparamsHandler +{ + Q_OBJECT + +public slots: + void FEKOSimulationDataparamsChanged_slots(); +public: + void bandingsetFEKOSimulationDataparams() override; + +public: + QtWidgetsClass_Scan(QWidget *parent = nullptr); + ~QtWidgetsClass_Scan(); +signals: + void OKClick( ); +public slots: + void on_pushButton_OK_clicked(); +private: + Ui::QtWidgetsClass_ScanClass ui; +}; + + + + +#endif \ No newline at end of file diff --git a/src/WBCLFZSystemModule/QtWidgetsClass_Scan.ui b/src/WBCLFZSystemModule/QtWidgetsClass_Scan.ui new file mode 100644 index 0000000..7b47198 --- /dev/null +++ b/src/WBCLFZSystemModule/QtWidgetsClass_Scan.ui @@ -0,0 +1,337 @@ + + + QtWidgetsClass_ScanClass + + + + 0 + 0 + 600 + 400 + + + + QtWidgetsClass_Scan + + + + + + + + + 0 + 30 + + + + + 16777215 + 30 + + + + + + + + + 60 + 0 + + + + + 60 + 16777215 + + + + --Z--> + + + + + + + + 0 + 30 + + + + + 16777215 + 30 + + + + + + + + + 0 + 25 + + + + + 16777215 + 25 + + + + ç»ˆæ­¢åæ ‡ + + + + + + + + 60 + 0 + + + + + 60 + 16777215 + + + + --Y--> + + + + + + + + 60 + 0 + + + + + 60 + 16777215 + + + + --X--> + + + + + + + + 0 + 30 + + + + + 16777215 + 30 + + + + + + + + + 0 + 30 + + + + + 16777215 + 30 + + + + + + + + + 0 + 30 + + + + + 16777215 + 30 + + + + + + + + + 0 + 30 + + + + + 16777215 + 30 + + + + + + + + + 0 + 25 + + + + + 16777215 + 25 + + + + èµ·å§‹åæ ‡ + + + + + + + ----> + + + + + + + + + + 0 + 25 + + + + + 16777215 + 25 + + + + 起始侧摆角 + + + + + + + + 0 + 25 + + + + + 16777215 + 25 + + + + + + + + + 0 + 25 + + + + + 16777215 + 25 + + + + + + + + 计算 + + + + + + + Qt::Vertical + + + + 20 + 35 + + + + + + + + PRF脉冲数 + + + + + + + + 0 + 25 + + + + + 16777215 + 25 + + + + 终止侧摆角 + + + + + + + + 0 + 25 + + + + + 16777215 + 25 + + + + + + + + + + diff --git a/src/WBCLFZSystemModule/QtWidgetsClass_Strip.cpp b/src/WBCLFZSystemModule/QtWidgetsClass_Strip.cpp new file mode 100644 index 0000000..1891524 --- /dev/null +++ b/src/WBCLFZSystemModule/QtWidgetsClass_Strip.cpp @@ -0,0 +1,60 @@ +#include "QtWidgetsClass_Strip.h" + + + +void QtWidgetsClass_Strip::FEKOSimulationDataparamsChanged_slots() +{ + if (this->simulationparams->imagemode == FEKOBase::FEKOImageMode::Strip) { + this->ui.lineEdit_PRF->setText(QString::number(this->simulationparams->getPRFCount())); + this->ui.lineEdit_Start_x->setText(QString::number(this->simulationparams->start_x)); + this->ui.lineEdit_start_y->setText(QString::number(this->simulationparams->start_y)); + this->ui.lineEdit_start_z->setText(QString::number(this->simulationparams->start_z)); + this->ui.lineEdit_end_x->setText(QString::number(this->simulationparams->end_x)); + this->ui.lineEdit_end_y->setText(QString::number(this->simulationparams->end_y)); + this->ui.lineEdit_end_z->setText(QString::number(this->simulationparams->end_z)); + } + else if (this->simulationparams->imagemode == FEKOBase::FEKOImageMode::Scane) { + this->ui.lineEdit_PRF->setText(QString::number(this->simulationparams->getPRFCount())); + this->ui.lineEdit_Start_x->setText(QString::number(this->simulationparams->start_x)); + this->ui.lineEdit_start_y->setText(QString::number(this->simulationparams->start_y)); + this->ui.lineEdit_start_z->setText(QString::number(this->simulationparams->start_z)); + this->ui.lineEdit_end_x->setText(QString::number(this->simulationparams->end_x)); + this->ui.lineEdit_end_y->setText(QString::number(this->simulationparams->end_y)); + this->ui.lineEdit_end_z->setText(QString::number(this->simulationparams->end_z)); + } + else { + return; + } + +} + +void QtWidgetsClass_Strip::bandingsetFEKOSimulationDataparams() +{ + QObject::connect(this->simulationparams.get(), SIGNAL(FEKOSimulationDataparamsChanged()), this, SLOT(FEKOSimulationDataparamsChanged_slots())); +} + +QtWidgetsClass_Strip::QtWidgetsClass_Strip(QWidget *parent) + : QWidget(parent) +{ + ui.setupUi(this); +} + +QtWidgetsClass_Strip::~QtWidgetsClass_Strip() +{} + + +void QtWidgetsClass_Strip::on_pushButton_OK_clicked() { + + + //void OKClick(double incAngle, double refRange, double start_x, double start_y, double start_z, double end_x, double end_y, double end_z, size_t prfcount); + this->simulationparams->setPRFCount(this->ui.lineEdit_PRF->text().toInt()); + this->simulationparams->setStart_x(this->ui.lineEdit_Start_x->text().toDouble()); + this->simulationparams->setStart_y(this->ui.lineEdit_start_y->text().toDouble()); + this->simulationparams->setStart_z(this->ui.lineEdit_start_z->text().toDouble()); + this->simulationparams->setEnd_x(this->ui.lineEdit_end_x->text().toDouble()); + this->simulationparams->setEnd_y(this->ui.lineEdit_end_y->text().toDouble()); + this->simulationparams->setEnd_z(this->ui.lineEdit_end_z->text().toDouble()); + this->simulationparams->setImagemode(FEKOBase::FEKOImageMode::Strip); + emit this->OKClick(); + +} \ No newline at end of file diff --git a/src/WBCLFZSystemModule/QtWidgetsClass_Strip.h b/src/WBCLFZSystemModule/QtWidgetsClass_Strip.h new file mode 100644 index 0000000..5a91dd2 --- /dev/null +++ b/src/WBCLFZSystemModule/QtWidgetsClass_Strip.h @@ -0,0 +1,34 @@ +#pragma once + +#ifndef QTWIDGETSCLASS_STRIP_H +#define QTWIDGETSCLASS_STRIP_H + +#include "AllHead.h" +#include +#include "ui_QtWidgetsClass_Strip.h" + +class QtWidgetsClass_Strip : public QWidget, public FEKOBase::FEKOSimulationDataparamsHandler +{ + Q_OBJECT + +public slots: + void FEKOSimulationDataparamsChanged_slots(); +public: + void bandingsetFEKOSimulationDataparams() override; + +public: + QtWidgetsClass_Strip(QWidget *parent = nullptr); + ~QtWidgetsClass_Strip(); +signals: + void OKClick(); + +public slots: + void on_pushButton_OK_clicked(); + +private: + Ui::QtWidgetsClass_StripClass ui; +}; + + + +#endif \ No newline at end of file diff --git a/src/WBCLFZSystemModule/QtWidgetsClass_Strip.ui b/src/WBCLFZSystemModule/QtWidgetsClass_Strip.ui new file mode 100644 index 0000000..b019d69 --- /dev/null +++ b/src/WBCLFZSystemModule/QtWidgetsClass_Strip.ui @@ -0,0 +1,288 @@ + + + QtWidgetsClass_StripClass + + + + 0 + 0 + 600 + 400 + + + + QtWidgetsClass_Strip + + + + + + 计算 + + + + + + + + 0 + 25 + + + + + 16777215 + 25 + + + + 101 + + + + + + + + + + 60 + 0 + + + + + 60 + 16777215 + + + + --Y--> + + + + + + + + 0 + 30 + + + + + 16777215 + 30 + + + + 10 + + + + + + + + 0 + 30 + + + + + 16777215 + 30 + + + + 10 + + + + + + + + 60 + 0 + + + + + 60 + 16777215 + + + + --Z--> + + + + + + + + 0 + 30 + + + + + 16777215 + 30 + + + + 10 + + + + + + + + 60 + 0 + + + + + 60 + 16777215 + + + + --X--> + + + + + + + + 0 + 25 + + + + + 16777215 + 25 + + + + ç»ˆæ­¢åæ ‡ + + + + + + + + 0 + 25 + + + + + 16777215 + 25 + + + + èµ·å§‹åæ ‡ + + + + + + + + 0 + 30 + + + + + 16777215 + 30 + + + + 10 + + + + + + + + 0 + 30 + + + + + 16777215 + 30 + + + + 10 + + + + + + + + 0 + 30 + + + + + 16777215 + 30 + + + + -10 + + + + + + + ----> + + + + + + + + + PRF脉冲数 + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + diff --git a/src/WBCLFZSystemModule/SharedModuleLib/BaseUiTool.cpp b/src/WBCLFZSystemModule/SharedModuleLib/BaseUiTool.cpp new file mode 100644 index 0000000..1306b2e --- /dev/null +++ b/src/WBCLFZSystemModule/SharedModuleLib/BaseUiTool.cpp @@ -0,0 +1,182 @@ +#include "BaseUiTool.h" +#include +#include +#include +#include +#include +#include +#include +#include + + +QString TopAbs_ShapeEnum2QString(TopAbs_ShapeEnum v) + +{ + switch (v) + { + case TopAbs_COMPOUND: + return QString("TopAbs_COMPOUND"); + break; + case TopAbs_COMPSOLID: + return QString("TopAbs_COMPSOLID"); + break; + case TopAbs_SOLID: + return QString("TopAbs_SOLID"); + break; + case TopAbs_SHELL: + return QString("TopAbs_SHELL"); + break; + case TopAbs_FACE: + return QString("TopAbs_FACE"); + break; + case TopAbs_WIRE: + return QString("TopAbs_WIRE"); + break; + case TopAbs_EDGE: + return QString("TopAbs_EDGE"); + break; + case TopAbs_VERTEX: + return QString("TopAbs_VERTEX"); + break; + case TopAbs_SHAPE: + return QString("TopAbs_SHAPE"); + break; + default: + return QString(""); + break; + } +} + +int findStdVectordouble(const std::vector& sortedVector, double target, double precision) +{ + int low = 0; + int high = sortedVector.size() - 1; + + while (low <= high) { + int mid = low + (high - low) / 2; + double midValue = sortedVector[mid]; + + // Check if the difference between target and midValue is smaller than precision + if (std::abs(target - midValue) <= precision) { + return mid; // Found a match + } + + // Decide whether to search in the left half or right half of the vector + if (target < midValue) { + high = mid - 1; // Target is in the left half + } + else { + low = mid + 1; // Target is in the right half + } + } + + return -1; // Target not found +} + + + + + +int messageLog(QString logtext, int value) +{ + QMessageBox msgBox; + QString messagestr = logtext; + msgBox.setText(messagestr); + msgBox.exec(); + return -1; +} + + +QString writeUTF8StringFile(QString path,QString unicodeString) { + QFile fileOut(path); + if (!fileOut.open(QIODevice::WriteOnly | QIODevice::Text)) + { + return ""; + } + + QTextStream streamFileOut(&fileOut); + streamFileOut.setCodec("UTF-8"); + streamFileOut << unicodeString; + streamFileOut.flush(); + fileOut.close(); + return path; +} + +bool isNumeric(const QString& str) +{ + bool isNumber = false; + str.toDouble(&isNumber); + return isNumber; +} + +std::complex QVariant2Complex(const QVariant& variant) +{ + QVariantList list = variant.toList(); + if (list.size() >= 2) { + double real = list[0].toDouble(); + double imag = list[1].toDouble(); + return std::complex(real, imag); + } + else { + // ĬÈÏ·µ»ØÖµ»ò´íÎó´¦Àí + return std::complex(); + } +} + +QVariant Complex2QVariant(const std::complex& value) +{ + QVariantList list; + list << value.real() << value.imag(); + return QVariant::fromValue(list); +} + +QMap QStringVector2QMapIndex(std::vector& vlist) +{ + QMap result; + for (size_t i = 0; i < vlist.size(); i++) { + result.insert(vlist[i], i); + } + + return result; +} + +int QAbstracmodel2CsvFile(QString filepath, const QAbstractItemModel* model) +{ + qDebug() << u8"ÕýÔÚ±£´æÎª csvÎļþÖÐ"; + QFile file(filepath); + if (file.open(QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Text)) + { + QTextStream stream(&file); + size_t columnCount = model->columnCount(); + size_t rowCount = model->rowCount(); + // »ñÈ¡ÎļþÍ· + for (size_t column = 0; column < columnCount; ++column) { + QString title = model->headerData(column, Qt::Horizontal, Qt::DisplayRole).toString(); + stream << title; + if (column < columnCount - 1) { + stream << ","; + } + else {} + } + stream << "\n"; + + + // + for (size_t i = 0; i < rowCount; ++i) { + for (size_t j = 0; j < columnCount; j++) { + QString title = model->index(i, j).data().toString(); + stream << title; + if (j < columnCount - 1) { + stream << ","; + } + else {} + } + stream << "\n"; + } + file.close(); + } + qDebug() << filepath; + return 0; +} + + diff --git a/src/WBCLFZSystemModule/SharedModuleLib/BaseUiTool.h b/src/WBCLFZSystemModule/SharedModuleLib/BaseUiTool.h new file mode 100644 index 0000000..f3da06d --- /dev/null +++ b/src/WBCLFZSystemModule/SharedModuleLib/BaseUiTool.h @@ -0,0 +1,60 @@ +#pragma once +#ifndef BASEUITOOL_H +#define BASEUITOOL_H + + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +//-------------------- FEKO »ù±¾²ÎÊý ------------------------- +enum FEKOCoordinateSystem { + None, + Cartesian, + Spherical +}; + + +QString TopAbs_ShapeEnum2QString(TopAbs_ShapeEnum v); + + +// ------------------- UI Öг£Óú¯Êý--------------------------------------- + +int findStdVectordouble(const std::vector& sortedVector, double target, double precision=1e-5); + +int messageLog(QString logtext, int value) ; + +QString writeUTF8StringFile(QString path, QString context); + +bool isNumeric(const QString& str); + +std::complex QVariant2Complex(const QVariant& variant); + +QVariant Complex2QVariant(const std::complex& value); + +QMap QStringVector2QMapIndex(std::vector& vlist); + +int QAbstracmodel2CsvFile(QString filepath, const QAbstractItemModel* model); + + +// ----------------------------------------------------------------------------- + + + + +#endif \ No newline at end of file diff --git a/src/WBCLFZSystemModule/SharedModuleLib/CMDExcuteApp.cpp b/src/WBCLFZSystemModule/SharedModuleLib/CMDExcuteApp.cpp new file mode 100644 index 0000000..79a554e --- /dev/null +++ b/src/WBCLFZSystemModule/SharedModuleLib/CMDExcuteApp.cpp @@ -0,0 +1,82 @@ +#include "CMDExcuteApp.h" +#include +#include +#include +#include + +CMDExcuteApp::CMDExcuteApp(QWidget* parent) +{ + this->ui.setupUi(this); + this->cmd = new QProcess(); + connect(this->cmd, SIGNAL(readyReadStandardOutput()), this, SLOT(on_readoutput())); + connect(this->cmd, SIGNAL(readyReadStandardError()), this, SLOT(on_readerror())); + +} + +CMDExcuteApp::~CMDExcuteApp() +{ + if (nullptr != this->cmd) { + + delete this->cmd; + this->cmd = nullptr; + + } +} + +int CMDExcuteApp::excuteCmd(std::string cmdText) +{ + qDebug() << u8"Ö´ÐÐÃüÁ" << cmdText.c_str() ; + this->ui.textEdit->append("cmd.exe\n"); + this->cmd->start("cmd.exe"); + this->cmd->waitForStarted(); //µÈ´ý³ÌÐòÆô¶¯ + this->ui.textEdit->append(QString::QString(cmdText.c_str())); + this->ui.textEdit->append("\n"); + this->cmd->write(cmdText.c_str()); + + this->cmd->close(); + this->waitExcutedFinish(); + return 0; +} + +int CMDExcuteApp::excuteCmd(std::string exePath, std::string params) +{ + qDebug() << u8"Ö´ÐÐÃüÁ" << exePath.c_str()<setWindowTitle(exePath.c_str()); + QString program = QString::QString(exePath.c_str()); + QStringList prams_txt; + prams_txt.append(QString::QString(params.c_str())); + this->cmd->start(program, prams_txt); + //this->cmd->waitForFinished(); + this->show(); + this->waitExcutedFinish(); + return 0; +} + +int CMDExcuteApp::waitExcutedFinish() +{ + while (!this->cmd->waitForFinished()) { + qDebug() << u8"ÔËÐÐ״̬£º" << this->cmd->state(); + QCoreApplication::processEvents(); + } + qDebug() << u8"Í˳öÑ­»·ÔËÐÐ״̬£º" << this->cmd->state(); + qDebug() << u8"Í˳öÑ­»·Â룺" << this->cmd->exitCode(); + this->on_readerror(); + this->on_readoutput(); + emit this->callbackExcuteResult(); + return 0; +} + +int CMDExcuteApp::on_readerror() +{ + QString out = this->cmd->readAllStandardError().data(); + qDebug()<ui.textEdit->append(out); + return 0; +} +int CMDExcuteApp::on_readoutput() +{ + QString out = this->cmd->readAllStandardOutput().data(); + qDebug() << u8"on_readoutput:\t" << out; + this->ui.textEdit->append(out); //½«Êä³öÐÅÏ¢¶ÁÈ¡µ½±à¼­¿ò + return 0; +} \ No newline at end of file diff --git a/src/WBCLFZSystemModule/SharedModuleLib/CMDExcuteApp.h b/src/WBCLFZSystemModule/SharedModuleLib/CMDExcuteApp.h new file mode 100644 index 0000000..18f8774 --- /dev/null +++ b/src/WBCLFZSystemModule/SharedModuleLib/CMDExcuteApp.h @@ -0,0 +1,27 @@ +#pragma once +#include +#include +#include "ui_CMDExcuteApp.h" + + +class CMDExcuteApp : public QMainWindow +{ + Q_OBJECT + +public: + CMDExcuteApp(QWidget* parent = nullptr); + ~CMDExcuteApp(); + int excuteCmd(std::string cmdText); + int excuteCmd(std::string exePath,std::string params); + int waitExcutedFinish(); +private: + Ui::cmdExcuteWindows ui; + QProcess* cmd; + +signals: + void callbackExcuteResult(); + +private slots: + int on_readoutput(); + int on_readerror(); +}; diff --git a/src/WBCLFZSystemModule/SharedModuleLib/CMDExcuteApp.ui b/src/WBCLFZSystemModule/SharedModuleLib/CMDExcuteApp.ui new file mode 100644 index 0000000..6473855 --- /dev/null +++ b/src/WBCLFZSystemModule/SharedModuleLib/CMDExcuteApp.ui @@ -0,0 +1,26 @@ + + + cmdExcuteWindows + + + + 0 + 0 + 568 + 260 + + + + cmd + + + + + + + + + + + + diff --git a/src/WBCLFZSystemModule/SharedModuleLib/ProcessOn.cpp b/src/WBCLFZSystemModule/SharedModuleLib/ProcessOn.cpp new file mode 100644 index 0000000..735b846 --- /dev/null +++ b/src/WBCLFZSystemModule/SharedModuleLib/ProcessOn.cpp @@ -0,0 +1,30 @@ +#include "ProcessOn.h" +#include +#include +#include +#include +#include +#include +#include + +ProcessOn::ProcessOn(QWidget* parent) +{ + this->setAttribute(Qt::WA_DeleteOnClose); + this->ui.setupUi(this); +} + +ProcessOn::~ProcessOn() +{ +} + +void ProcessOn::setRange(size_t start, size_t end) +{ + this->ui.progressBar->setRange(start, end); +} + +void ProcessOn::setValue(size_t v) +{ + this->ui.progressBar->setValue(v); + QCoreApplication::processEvents(QEventLoop::AllEvents); + this->show(); +} diff --git a/src/WBCLFZSystemModule/SharedModuleLib/ProcessOn.h b/src/WBCLFZSystemModule/SharedModuleLib/ProcessOn.h new file mode 100644 index 0000000..dcd3dbd --- /dev/null +++ b/src/WBCLFZSystemModule/SharedModuleLib/ProcessOn.h @@ -0,0 +1,27 @@ +#pragma once +#ifndef PROCESSON_H +#define PROCESSON_H +#include +#include +#include +#include +#include +#include +#include "ui_ProcessOn.h" + +class ProcessOn : public QMainWindow +{ + Q_OBJECT +private: + Ui::ProcessOnMainWindow ui; + +public: + ProcessOn(QWidget* parent = nullptr); + ~ProcessOn(); + void setRange(size_t start, size_t end); + void setValue(size_t v); + +}; + +#endif + diff --git a/src/WBCLFZSystemModule/SharedModuleLib/ProcessOn.ui b/src/WBCLFZSystemModule/SharedModuleLib/ProcessOn.ui new file mode 100644 index 0000000..8c40592 --- /dev/null +++ b/src/WBCLFZSystemModule/SharedModuleLib/ProcessOn.ui @@ -0,0 +1,42 @@ + + + ProcessOnMainWindow + + + + 0 + 0 + 600 + 40 + + + + + 600 + 40 + + + + + 600 + 40 + + + + MainWindow + + + + + + + 24 + + + + + + + + + diff --git a/src/WBCLFZSystemModule/SharedModuleLib/TaskTreeClass.cpp b/src/WBCLFZSystemModule/SharedModuleLib/TaskTreeClass.cpp new file mode 100644 index 0000000..2539ec5 --- /dev/null +++ b/src/WBCLFZSystemModule/SharedModuleLib/TaskTreeClass.cpp @@ -0,0 +1,154 @@ +#include "TaskTreeClass.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +std::string TaskNode::getName() +{ + return this->name; +} + +int TaskNode::setName(std::string anme) +{ + this->name = anme; + return 0; +} + +int TaskNode::loadXmlDocument(std::string xmlFilePath, QDomDocument& doc) +{ + QFile file(xmlFilePath.c_str()); //Ïà¶Ô·¾¶¡¢¾ø¶Ô·¾¶¡¢×ÊԴ·¾¶¶¼¿ÉÒÔ + if (!file.open(QFile::ReadOnly)) //¿ÉÒÔÓÃQIODevice£¬Truncate±íʾÇå¿ÕÔ­À´µÄÄÚÈÝ + { + std::string tiptext = "File isn't opened in readonly mode ,file path "+ xmlFilePath; + qDebug() << tiptext.c_str(); + return 2; + } + + QTextStream stream(&file); + QTextCodec* codec = QTextCodec::codecForName("UTF-8"); + stream.setCodec(codec); + QString content = stream.readAll(); + file.close(); + if (!doc.setContent(content)) // ¹ØÁªÎļþÁ÷ + { + std::string tiptext = "File isn't readed in xml format ,file path " + xmlFilePath; + qDebug() << tiptext.c_str(); + file.close(); + return 3; + } + file.close(); // Îļþ¶ÁÈ¡½áÊø + return -1; +} + +int TaskNode::writeXmlDocument(QDomDocument& doc) +{ + + QFile wfile(this->TaskXmlPath.c_str()); // ±£´æ XML Îļþ + if (wfile.open(QFile::ReadWrite | QFile::Text)) + { + QTextStream out(&wfile); + doc.save(out, QDomNode::EncodingFromDocument); + wfile.close(); + } + return -1; +} + +int TaskNode::loadXmlFile(std::string xmlFilePath) +{ + return 0; +} + +int TaskNode::saveXmlFile() +{ + return 0; +} + + +int TaskNode::addNode(std::shared_ptr n) +{ + this->Nodelist.push_back(n); + return 0; +} + +std::shared_ptr TaskNode::getNode(int nid) +{ + if (nid < this->Nodelist.size()) { + return this->Nodelist[nid]; + } + return std::shared_ptr(nullptr); +} + +std::shared_ptr TaskNode::getNode(std::string nodename) +{ + for (int i = 0; i < this->Nodelist.size(); i++) { + if (strcmp(nodename.c_str(), this->Nodelist[i]->name.c_str()) == 0) { + return this->Nodelist[i]; + } + } + return std::shared_ptr(nullptr); +} + +std::shared_ptr TaskNode::removeAt(int nid) +{ + if (nid < this->Nodelist.size()) { + std::shared_ptr result = this->Nodelist[nid]; + this->Nodelist.erase(this->Nodelist.begin()+nid); // ɾ³ý nid + return result; + } + return std::shared_ptr(nullptr); +} + +std::shared_ptr TaskNode::removeByName(std::string nodename) +{ + for (int i = 0; i < this->Nodelist.size(); i++) { + if (strcmp(nodename.c_str(), this->Nodelist[i]->name.c_str()) == 0) { + std::shared_ptr result = this->Nodelist[i]; + this->Nodelist.erase(this->Nodelist.begin() + i); // ɾ³ý nid + return result; + } + } + return std::shared_ptr(nullptr); +} + +TaskStatusEnum TaskNode::getStatus() +{ + return this->status; + // return TaskStatusEnum(); +} + +int TaskNode::setStatus(TaskStatusEnum taskstatus) +{ + this->status = taskstatus; + return 0; +} + +int TaskNode::ExcuteTask() +{ + return 0; +} + +int TaskNode::preView() +{ + return 0; +} + + +int TaskTreeClass::loadXmlFile(std::string xmlFilePath) +{ + return 0; +} + +int TaskTreeClass::saveXmlFile() +{ + return 0; +} diff --git a/src/WBCLFZSystemModule/SharedModuleLib/TaskTreeClass.h b/src/WBCLFZSystemModule/SharedModuleLib/TaskTreeClass.h new file mode 100644 index 0000000..785a192 --- /dev/null +++ b/src/WBCLFZSystemModule/SharedModuleLib/TaskTreeClass.h @@ -0,0 +1,88 @@ +#pragma once +/* +* ËùÓеŦÄÜÖ¸Õë´«µÝ ¶¼ÊÇʹÓà ¹²ÏíÖ¸Õ룬²»ÊÖ¶¯ÊÍ·Å +* ¶¨Òå¸÷ÖÖÈÎÎñ¹ÜÀíÀà +* ÈÎÎñ¹ÜÀíÀàÒÔÊ÷×´½Úµã½øÐб£´æ£¬ +* Ê÷×´½Úµã¶¼ÊÇÒ»¸öÊ÷£¬¾ßÓÐÍêÕûµÄÈÎÎñ¹ÜÀíÄÜÁ¦ +* ÈÎÎñ°´ÕÕ ÖÆ±¸ÈÎÎñ¡¢²âÁ¿ÈÎÎñ¡¢·ÂÕæÈÎÎñ +* ÈÎÎñ»ùÀࣺ +* 1.ÈÎÎñÃû +* 2. ÈÎÎñÃèÊö +* 3. ×ÓÈÎÎñÏî +* 4. ½ÚµãÀàÐÍ -- Îļþ½Úµã¡¢ÈÎÎñ½Úµã¡¢ +* 5. µ±Ç°½Úµã²Ù×÷´°¿Ú +* ·ÂÕæÈÎÎñ£º +* +* +* +* +***/ +#include +#include +#include +#include +#include +#include +#include +#include //rapidxml::file +#include //rapidxml::print +#include // QObject ½èÖú QOject ÖеÄÐźŲۻúÖÆ£¬Íê³ÉÈÎÎñµÄ»Øµ÷£¬Ï൱ÓÚ Ê¼þµÄÁÓ»¯°æ +#include + +enum TaskStatusEnum { + wait, + success, + fail +}; + + +// ÈÎÎñÁбí +class TaskNode :public QObject +{ + Q_OBJECT // ÿ¸ö×ÓÀà±ØÐëʹÓÃÕâ¸öºê +public: + std::string TaskXmlPath; +public: + std::string name; + std::string description; // ÃèÊö + TaskStatusEnum status; + std::vector> Nodelist; +public: + std::string getName(); + int setName(std::string anme); + + // ÎļþÏà¹Ø²Ù×÷ + + int loadXmlDocument(std::string xmlfilepath, QDomDocument& doc); + int writeXmlDocument(QDomDocument& doc); + + + virtual int loadXmlFile(std::string xmlFilePath); // ¼ÓÔØÈÎÎñÎļþ,±ØÐëÖØÐ´ + virtual int saveXmlFile(); // ±£´æÈÎÎñÎļþ£¬±ØÐëÖØÐ´ + // ½Úµã²Ù×÷ + virtual int addNode(std::shared_ptr n); + virtual std::shared_ptr getNode(int nid); + virtual std::shared_ptr getNode(std::string nodename); + virtual std::shared_ptr removeAt(int nid); + virtual std::shared_ptr removeByName(std::string nodename); + virtual TaskStatusEnum getStatus(); + virtual int setStatus(TaskStatusEnum taskstatus); + + virtual int ExcuteTask(); // ÈÎÎñÖ´ÐвÙ×÷ + virtual int preView(); // Ô¤ÀÀÐÅÏ¢ +}; + + +/// +/// ÈÎÎñ¹ÜÀíµØÖ· +/// +class TaskTreeClass +{ +public: + std::string TaskName; + std::vector tasknodes; +public: + virtual int loadXmlFile(std::string xmlFilePath); // ¼ÓÔØÈÎÎñÎļþ,±ØÐëÖØÐ´ + virtual int saveXmlFile(); // ±£´æÈÎÎñÎļþ£¬±ØÐëÖØÐ´ + +}; diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/images/logo.png b/src/WBCLFZSystemModule/SqliteDBProcess/images/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..7897a11e5a55c58d79e6bd147590886011712e24 GIT binary patch literal 15047 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 literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/images/logo.svg b/src/WBCLFZSystemModule/SqliteDBProcess/images/logo.svg new file mode 100644 index 0000000..7817ec7 --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/images/logo.svg @@ -0,0 +1,391 @@ + + + logo + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + logo + + + + + + https://sqlitebrowser.org + + + + + DB Browser for SQLite Logo + 2020Jun05 + + + GPL3+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/images/sqlitebrowser.png b/src/WBCLFZSystemModule/SqliteDBProcess/images/sqlitebrowser.png new file mode 100644 index 0000000000000000000000000000000000000000..5c1e48d179c7c08376c561a505982ff8e194dfe6 GIT binary patch literal 96368 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
A0$};$EbqAuezb`2!5+{ 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 literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/AboutDialog.cpp b/src/WBCLFZSystemModule/SqliteDBProcess/src/AboutDialog.cpp new file mode 100644 index 0000000..0525f59 --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/AboutDialog.cpp @@ -0,0 +1,18 @@ +#include "AboutDialog.h" +#include "ui_AboutDialog.h" +#include "Application.h" + +AboutDialog::AboutDialog(QWidget *parent) : + QDialog(parent), + ui(new Ui::AboutDialog) +{ + ui->setupUi(this); + this->setFixedSize(this->width(), this->height()); + this->setWindowFlags(this->windowFlags() & ~Qt::WindowContextHelpButtonHint); + ui->label_version->setText(Application::versionInformation()); +} + +AboutDialog::~AboutDialog() +{ + delete ui; +} diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/AboutDialog.h b/src/WBCLFZSystemModule/SqliteDBProcess/src/AboutDialog.h new file mode 100644 index 0000000..3eb5aee --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/AboutDialog.h @@ -0,0 +1,22 @@ +#ifndef ABOUTDIALOG_H +#define ABOUTDIALOG_H + +#include + +namespace Ui { +class AboutDialog; +} + +class AboutDialog : public QDialog +{ + Q_OBJECT + +public: + explicit AboutDialog(QWidget *parent = nullptr); + ~AboutDialog(); + +private: + Ui::AboutDialog *ui; +}; + +#endif diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/AboutDialog.ui b/src/WBCLFZSystemModule/SqliteDBProcess/src/AboutDialog.ui new file mode 100644 index 0000000..e284480 --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/AboutDialog.ui @@ -0,0 +1,164 @@ + + + AboutDialog + + + + 0 + 0 + 653 + 502 + + + + About DB Browser for SQLite + + + + :/icons/appicon:/icons/appicon + + + false + + + + + + 0 + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + Version + + + 5 + + + Qt::TextSelectableByMouse + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + 0 + 0 + + + + + 128 + 128 + + + + + + + :/icons/appicon + + + true + + + + + + + + + <html><head/><body><p>DB Browser for SQLite is an open source, freeware visual tool used to create, design and edit SQLite database files.</p><p>It is bi-licensed under the Mozilla Public License Version 2, as well as the GNU General Public License Version 3 or later. You can modify or redistribute it under the conditions of these licenses.</p><p>See <a href="http://www.gnu.org/licenses/gpl.html">http://www.gnu.org/licenses/gpl.html</a> and <a href="https://www.mozilla.org/MPL/2.0/index.txt">https://www.mozilla.org/MPL/2.0/index.txt</a> for details.</p><p>For more information on this program please visit our website at: <a href="http://sqlitebrowser.org">http://sqlitebrowser.org</a></p><p><span style=" font-size:small;">This software uses the GPL/LGPL Qt Toolkit from </span><a href="http://qt-project.org/"><span style=" font-size:small;">http://qt-project.org/</span></a><span style=" font-size:small;"><br/>See </span><a href="http://qt-project.org/doc/qt-5/licensing.html"><span style=" font-size:small;">http://qt-project.org/doc/qt-5/licensing.html</span></a><span style=" font-size:small;"> for licensing terms and information.</span></p><p><span style=" font-size:small;">It also uses the Silk icon set by Mark James licensed under a Creative Commons Attribution 2.5 and 3.0 license.<br/>See </span><a href="http://www.famfamfam.com/lab/icons/silk/"><span style=" font-size:small;">http://www.famfamfam.com/lab/icons/silk/</span></a><span style=" font-size:small;"> for details.</span></p></body></html> + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + true + + + true + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Close + + + + + + + + + + + buttonBox + accepted() + AboutDialog + accept() + + + 248 + 340 + + + 157 + 274 + + + + + buttonBox + rejected() + AboutDialog + reject() + + + 316 + 340 + + + 286 + 274 + + + + + diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/AddRecordDialog.cpp b/src/WBCLFZSystemModule/SqliteDBProcess/src/AddRecordDialog.cpp new file mode 100644 index 0000000..1f86b6c --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/AddRecordDialog.cpp @@ -0,0 +1,367 @@ +#include "AddRecordDialog.h" +#include "ui_AddRecordDialog.h" +#include "sqlitedb.h" +#include "Settings.h" + +#include +#include +#include +#include +#include +#include +#include + +class NullLineEdit: public QLineEdit { + Q_OBJECT +private: + bool m_isNull; + +public: + explicit NullLineEdit(QWidget* parent=nullptr): QLineEdit(parent), m_isNull (true) {} + + bool isNull() {return m_isNull;} + void setNull(bool value) { + if (value) { + clear(); + setStyleSheet("QLineEdit{ font-style: italic; }"); + setPlaceholderText(Settings::getValue("databrowser", "null_text").toString()); + setModified(false); + } else { + setStyleSheet(""); + setPlaceholderText(""); + } + m_isNull = value; + } +protected: + void contextMenuEvent(QContextMenuEvent *event) + { + QMenu* editContextMenu = createStandardContextMenu(); + + QAction* nullAction = new QAction(QIcon(":/icons/set_to_null"), tr("Set to NULL"), editContextMenu); + connect(nullAction, &QAction::triggered, [&]() { + setNull(true); + }); + nullAction->setShortcut(QKeySequence(tr("Alt+Del"))); + editContextMenu->addSeparator(); + editContextMenu->addAction(nullAction); + + editContextMenu->exec(event->globalPos()); + delete editContextMenu; + } + + void keyPressEvent(QKeyEvent *evt) { + // Alt+Del sets field to NULL + if((evt->modifiers() & Qt::AltModifier) && (evt->key() == Qt::Key_Delete)) + setNull(true); + else { + // Remove any possible NULL mark when user starts typing + setStyleSheet(""); + setPlaceholderText(""); + QLineEdit::keyPressEvent(evt); + } + } +}; + +// Styled Item Delegate for non-editable columns (all except Value) +class NoEditDelegate: public QStyledItemDelegate { +public: + explicit NoEditDelegate(QObject* parent=nullptr): QStyledItemDelegate(parent) {} + QWidget* createEditor(QWidget* /* parent */, const QStyleOptionViewItem& /* option */, const QModelIndex& /* index */) const override { + return nullptr; + } +}; + +// Styled Item Delegate for editable columns (Value) +class EditDelegate: public QStyledItemDelegate { + +public: + explicit EditDelegate(QObject* parent=nullptr): QStyledItemDelegate(parent) {} + QWidget* createEditor(QWidget *parent, const QStyleOptionViewItem& /* option */, const QModelIndex& /* index */) const override { + return new NullLineEdit(parent); + } + + void setEditorData(QWidget *editor, const QModelIndex &index) const override { + + NullLineEdit* lineEditor = static_cast(editor); + // Set the editor in the null state (unless the user has actually written NULL) + if (index.model()->data(index, Qt::UserRole).isNull() && + index.model()->data(index, Qt::DisplayRole) == Settings::getValue("databrowser", "null_text")) + lineEditor->setNull(true); + else { + QStyledItemDelegate::setEditorData(editor, index); + lineEditor->setNull(false); + } + } + void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const override { + + NullLineEdit* lineEditor = static_cast(editor); + // Restore NULL text (unless the user has already modified the value) + if (lineEditor->isNull() && !lineEditor->isModified()) { + model->setData(index, Settings::getValue("databrowser", "null_text"), Qt::DisplayRole); + model->setData(index, QVariant(), Qt::UserRole); + } else { + // Get isModified flag before calling setModelData + bool modified = lineEditor->isModified(); + QStyledItemDelegate::setModelData(editor, model, index); + // Copy the just edited data to the user role, so it can be later used in the SQL insert statement. + if (modified) { + lineEditor->setNull(false); + model->setData(index, model->data(index, Qt::EditRole), Qt::UserRole); + } + } + } +}; + +AddRecordDialog::AddRecordDialog(DBBrowserDB& db, const sqlb::ObjectIdentifier& tableName, QWidget* parent, const std::vector& _pseudo_pk) + : QDialog(parent), + ui(new Ui::AddRecordDialog), + pdb(db), + curTable(tableName), + pseudo_pk(_pseudo_pk) +{ + // Create UI + ui->setupUi(this); + connect(ui->treeWidget, &QTreeWidget::itemChanged, this, &AddRecordDialog::itemChanged); + + populateFields(); + + ui->sqlTextEdit->setReadOnly(true); + + // Update UI + ui->treeWidget->resizeColumnToContents(kName); + ui->treeWidget->resizeColumnToContents(kType); + ui->treeWidget->setFrameShape(QFrame::Box); +} + +AddRecordDialog::~AddRecordDialog() +{ + delete ui; +} + +void AddRecordDialog::keyPressEvent(QKeyEvent *evt) +{ + if((evt->modifiers() & Qt::ControlModifier) + && (evt->key() == Qt::Key_Enter || evt->key() == Qt::Key_Return)) + { + accept(); + return; + } + if(evt->key() == Qt::Key_Enter || evt->key() == Qt::Key_Return) + return; + QDialog::keyPressEvent(evt); +} + +void AddRecordDialog::setDefaultsStyle(QTreeWidgetItem* item) +{ + // Default values are displayed with the style configured for NULL values in the Data Browser. + QFont font; + font.setItalic(true); + item->setData(kValue, Qt::FontRole, font); + item->setData(kValue, Qt::BackgroundRole, QColor(Settings::getValue("databrowser", "null_bg_colour").toString())); + item->setData(kValue, Qt::ForegroundRole, QColor(Settings::getValue("databrowser", "null_fg_colour").toString())); +} + +void AddRecordDialog::populateFields() +{ + // Block the itemChanged signal or the SQL text will be updated while filling the treewidget. + ui->treeWidget->blockSignals(true); + + ui->treeWidget->clear(); + + // Allow all Edit Triggers, but they will only apply to the columns with + // editors (Value) + ui->treeWidget->setEditTriggers(QAbstractItemView::AllEditTriggers); + + // Disallow edition of columns except Value + ui->treeWidget->setItemDelegateForColumn(kName, new NoEditDelegate(this)); + ui->treeWidget->setItemDelegateForColumn(kType, new NoEditDelegate(this)); + ui->treeWidget->setItemDelegateForColumn(kValue, new EditDelegate(this)); + + sqlb::FieldVector fields; + std::vector fks; + sqlb::StringVector pk; + bool auto_increment = false; + + // Initialize fields, fks and pk differently depending on whether it's a table or a view. + const sqlb::ObjectPtr obj = pdb.getObjectByName(curTable); + if (obj->type() == sqlb::Object::Table) + { + sqlb::TablePtr m_table = pdb.getObjectByName(curTable); + fields = m_table->fields; + for(const sqlb::Field& f : fields) + fks.push_back(m_table->constraint({f.name()}, sqlb::Constraint::ForeignKeyConstraintType)); + + const auto pk_constraint = m_table->primaryKey(); + if(pk_constraint) + { + pk = pk_constraint->columnList(); + auto_increment = pk_constraint->autoIncrement(); + } + } else { + sqlb::ViewPtr m_view = pdb.getObjectByName(curTable); + fields = m_view->fields; + fks.resize(fields.size(), sqlb::ConstraintPtr(nullptr)); + pk = pseudo_pk; + } + + for(uint i = 0; i < fields.size(); i++) + { + const sqlb::Field& f = fields[i]; + QTreeWidgetItem *tbitem = new QTreeWidgetItem(ui->treeWidget); + + tbitem->setFlags(Qt::ItemIsEnabled | Qt::ItemIsEditable); + + tbitem->setText(kName, QString::fromStdString(f.name())); + tbitem->setText(kType, QString::fromStdString(f.type())); + tbitem->setData(kType, Qt::UserRole, f.affinity()); + + // NOT NULL fields are indicated in bold. + if (f.notnull()) { + QFont font; + font.setBold(true); + tbitem->setData(kName, Qt::FontRole, font); + } + if (contains(pk, f.name())) + tbitem->setIcon(kName, QIcon(":/icons/field_key")); + else if (fks[i]) + tbitem->setIcon(kName, QIcon(":/icons/field_fk")); + else + tbitem->setIcon(kName, QIcon(":/icons/field")); + + QString toolTip; + + if (auto_increment && contains(pk, f.name())) + toolTip.append(tr("Auto-increment\n")); + + if (f.unique()) + toolTip.append(tr("Unique constraint\n")); + + if (!f.check().empty()) + toolTip.append(tr("Check constraint:\t %1\n").arg(QString::fromStdString(f.check()))); + + auto fk = std::dynamic_pointer_cast(fks[i]); + if(fk) + toolTip.append(tr("Foreign key:\t %1\n").arg(QString::fromStdString(fk->toString()))); + + setDefaultsStyle(tbitem); + + // Display Role is used for displaying the default values. + // Only when they are changed, the User Role is updated and then used in the INSERT query. + if (!f.defaultValue().empty()) { + QString defaultValue = QString::fromStdString(f.defaultValue()); + tbitem->setData(kValue, Qt::DisplayRole, defaultValue); + toolTip.append(tr("Default value:\t %1\n").arg(defaultValue)); + } else + tbitem->setData(kValue, Qt::DisplayRole, Settings::getValue("databrowser", "null_text")); + + + if (!toolTip.isEmpty()) { + // Chop last end-of-line + toolTip.chop(1); + tbitem->setToolTip(kValue, toolTip); + tbitem->setToolTip(kType, toolTip); + } + } + + updateSqlText(); + + // Enable signals from tree widget + ui->treeWidget->blockSignals(false); +} + +void AddRecordDialog::accept() +{ + if(!pdb.executeSQL(ui->sqlTextEdit->text().toStdString())) + { + QMessageBox::warning( + this, + QApplication::applicationName(), + tr("Error adding record. Message from database engine:\n\n%1").arg(pdb.lastError())); + return; + } + + QDialog::accept(); +} + +void AddRecordDialog::updateSqlText() +{ + QString stmt = QString("INSERT INTO %1").arg(QString::fromStdString(curTable.toString())); + + QStringList vals; + QStringList fields; + + // If the User Role of the Value column is not null, the entered value is used + // in the INSERT statement. Otherwise, SQLite just uses the default value for the field. + for(int i = 0; i < ui->treeWidget->topLevelItemCount(); ++i) + { + QTreeWidgetItem *item = ui->treeWidget->topLevelItem(i); + // User role contains now values entered by the user, that we actually need to insert. + QVariant value = item->data(kValue, Qt::UserRole); + + if (!value.isNull()) { + bool isNumeric; + fields << sqlb::escapeIdentifier(item->text(kName)); + value.toDouble(&isNumeric); + // If it has a numeric format and has no text affinity, do not quote it. + if (isNumeric && item->data(kType, Qt::UserRole).toInt() != sqlb::Field::TextAffinity) + vals << value.toString(); + else + vals << sqlb::escapeString(value.toString()); + } + } + + if(fields.empty()) + { + stmt.append(" DEFAULT VALUES;"); + } else { + stmt.append("\n("); + stmt.append(fields.join(", ")); + stmt.append(")\nVALUES ("); + stmt.append(vals.join(", ")); + stmt.append(");"); + } + + ui->sqlTextEdit->setText(stmt); +} + +void AddRecordDialog::itemChanged(QTreeWidgetItem *item, int column) +{ + if (item->data(column, Qt::UserRole).isNull()) + setDefaultsStyle(item); + else { + // Restore default fore/background for the value column, + // since the value has changed away from the default. + QFont font; + font.setItalic(false); + item->setData(column, Qt::FontRole, font); + item->setData(column, Qt::BackgroundRole, item->data(kName, Qt::BackgroundRole)); + item->setData(column, Qt::ForegroundRole, item->data(kName, Qt::ForegroundRole)); + } + + updateSqlText(); +} + +void AddRecordDialog::help() +{ + QWhatsThis::enterWhatsThisMode(); +} + +void AddRecordDialog::on_buttonBox_clicked(QAbstractButton* button) +{ + if (button == ui->buttonBox->button(QDialogButtonBox::Cancel)) + reject(); + else if (button == ui->buttonBox->button(QDialogButtonBox::Save)) + accept(); + else if (button == ui->buttonBox->button(QDialogButtonBox::Help)) + help(); + else if (button == ui->buttonBox->button(QDialogButtonBox::RestoreDefaults)) { + if (QMessageBox::warning(this, + QApplication::applicationName(), + tr("Are you sure you want to restore all the entered values to their defaults?"), + QMessageBox::RestoreDefaults | QMessageBox::Cancel, + QMessageBox::Cancel) == QMessageBox::RestoreDefaults) + populateFields(); + } +} + +#include "AddRecordDialog.moc" diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/AddRecordDialog.h b/src/WBCLFZSystemModule/SqliteDBProcess/src/AddRecordDialog.h new file mode 100644 index 0000000..cc9767b --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/AddRecordDialog.h @@ -0,0 +1,52 @@ +#ifndef ADDRECORDDIALOG_H +#define ADDRECORDDIALOG_H + +#include "sql/ObjectIdentifier.h" + +#include + +class DBBrowserDB; +class QTreeWidgetItem; + +namespace Ui { +class AddRecordDialog; +} +class QAbstractButton; + + +class AddRecordDialog : public QDialog +{ + Q_OBJECT + +public: + explicit AddRecordDialog(DBBrowserDB& pdb, const sqlb::ObjectIdentifier& tableName, QWidget* parent = nullptr, const std::vector& pseudo_pk = {}); + ~AddRecordDialog() override; + +protected: + void keyPressEvent(QKeyEvent *evt) override; + +private: + enum Columns { + kName = 0, + kType = 1, + kValue = 2, + }; + + void updateSqlText(); + void populateFields(); + void setDefaultsStyle(QTreeWidgetItem* item); + +private slots: + void accept() override; + void itemChanged(QTreeWidgetItem* item, int column); + void help(); + void on_buttonBox_clicked(QAbstractButton* button); + +private: + Ui::AddRecordDialog* ui; + DBBrowserDB& pdb; + sqlb::ObjectIdentifier curTable; + std::vector pseudo_pk; +}; + +#endif diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/AddRecordDialog.ui b/src/WBCLFZSystemModule/SqliteDBProcess/src/AddRecordDialog.ui new file mode 100644 index 0000000..74d1fe9 --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/AddRecordDialog.ui @@ -0,0 +1,158 @@ + + + AddRecordDialog + + + + 0 + 0 + 650 + 500 + + + + Add New Record + + + + :/icons/table:/icons/table + + + true + + + + + + Enter values for the new record considering constraints. Fields in bold are mandatory. + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Qt::Vertical + + + + + 0 + 0 + + + + + 0 + 140 + + + + In the Value column you can specify the value for the field identified in the Name column. The Type column indicates the type of the field. Default values are displayed in the same style as NULL values. + + + false + + + + Name + + + + + Type + + + + + Value + + + Values to insert. Pre-filled default values are inserted automatically unless they are changed. + + + + + + When you edit the values in the upper frame, the SQL query for inserting this new record is shown here. You can edit manually the query before saving. + + + true + + + + + + + + + + + + + + <html><head/><body><p><span style=" font-weight:600;">Save</span> will submit the shown SQL statement to the database for inserting the new record.</p><p><span style=" font-weight:600;">Restore Defaults</span> will restore the initial values in the <span style=" font-weight:600;">Value</span> column.</p><p><span style=" font-weight:600;">Cancel</span> will close this dialog without executing the query.</p></body></html> + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Help|QDialogButtonBox::RestoreDefaults|QDialogButtonBox::Save + + + + + + + + SqlTextEdit + QWidget +
sqltextedit.h
+ 1 +
+
+ + treeWidget + sqlTextEdit + + + + + + + buttonBox + clicked(QAbstractButton*) + AddRecordDialog + on_buttonBox_clicked(QAbstractButton*) + + + 324 + 477 + + + 324 + 249 + + + + + + itemChanged() + +
diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/Application.cpp b/src/WBCLFZSystemModule/SqliteDBProcess/src/Application.cpp new file mode 100644 index 0000000..d4d07d4 --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/Application.cpp @@ -0,0 +1,280 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "Application.h" +#include "SqliteDBMainWindow.h" +//#include "RemoteNetwork.h" +#include "Settings.h" +#include "version.h" +#include "sqlitedb.h" + +Application::Application(int& argc, char** argv) : + QApplication(argc, argv) +{ + // Set organisation and application names + setOrganizationName(u8"lamp"); + setApplicationName(u8"ÊôÐÔ±í¹ÜÀíÓë±à¼­"); + + // Set character encoding to UTF8 + QTextCodec::setCodecForLocale(QTextCodec::codecForName("UTF-8")); + + // Load translations + bool ok; + QString name = Settings::getValue("General", "language").toString(); + + // First of all try to load the application translation file. + m_translatorApp = new QTranslator(this); + ok = m_translatorApp->load("sqlb_" + name, + QCoreApplication::applicationDirPath() + "/translations"); + // If failed then try to load .qm file from resources + if (ok == false) { + ok = m_translatorApp->load("sqlb_" + name, ":/translations"); + } + + if (ok == true) { + Settings::setValue("General", "language", name); + installTranslator(m_translatorApp); + + // The application translation file has been found and loaded. + // And now try to load a Qt translation file. + // Search path: + // 1) standard Qt translations directory; + // 2) the application translations directory. + m_translatorQt = new QTranslator(this); + + ok = m_translatorQt->load("qt_" + name, + QLibraryInfo::location(QLibraryInfo::TranslationsPath)); + if (ok == false) + ok = m_translatorQt->load("qt_" + name, "translations"); + if (ok == true) + installTranslator(m_translatorQt); + } else { + // Set the correct locale so that the program won't erroneously detect + // a language change when the user toggles settings for the first time. + // (it also prevents the program from always looking for a translation on launch) + Settings::setValue("General", "language", "en_US"); + + // Don't install a translator for Qt texts if no translator for DB4S texts could be loaded + m_translatorQt = nullptr; + } + + // On Windows, add the plugins subdirectory to the list of library directories. We need this + // for Qt to search for more image format plugins. +#ifdef Q_WS_WIN + QApplication::addLibraryPath(QApplication::applicationDirPath() + "/plugins"); +#endif + + // Work around a bug in QNetworkAccessManager which sporadically causes high pings for Wifi connections + // See https://bugreports.qt.io/browse/QTBUG-40332 + qputenv("QT_BEARER_POLL_TIMEOUT", QByteArray::number(INT_MAX)); + + // Remember default font size + Settings::rememberDefaultFontSize(font().pointSize()); + + // Parse command line + QString fileToOpen; + QString tableToBrowse; + QStringList sqlToExecute; + bool readOnly = false; + m_dontShowMainWindow = false; + for(int i=1;i|]\n"). + arg(QFileInfo(argv[0]).fileName())); + qWarning() << qPrintable(tr("Possible command line arguments:")); + qWarning() << qPrintable(tr(" -h, --help Show command line options")); + qWarning() << qPrintable(tr(" -q, --quit Exit application after running scripts")); + qWarning() << qPrintable(tr(" -s, --sql Execute this SQL file after opening the DB")); + qWarning() << qPrintable(tr(" -t, --table Browse this table after opening the DB")); + qWarning() << qPrintable(tr(" -R, --read-only Open database in read-only mode")); + qWarning() << qPrintable(tr(" -o, --option /=")); + qWarning() << qPrintable(tr(" Run application with this setting temporarily set to value")); + qWarning() << qPrintable(tr(" -O, --save-option /=")); + qWarning() << qPrintable(tr(" Run application saving this value for this setting")); + qWarning() << qPrintable(tr(" -v, --version Display the current version")); + qWarning() << qPrintable(tr(" Open this SQLite database")); + qWarning() << qPrintable(tr(" Open this project file (*.sqbpro)")); + m_dontShowMainWindow = true; + } else if(arguments().at(i) == "-v" || arguments().at(i) == "--version") { + qWarning() << qPrintable(versionInformation()); + m_dontShowMainWindow = true; + } else if(arguments().at(i) == "-s" || arguments().at(i) == "--sql") { + // Run SQL file: If file exists add it to list of scripts to execute + if(++i >= arguments().size()) + qWarning() << qPrintable(tr("The -s/--sql option requires an argument")); + else if(!QFile::exists(arguments().at(i))) + qWarning() << qPrintable(tr("The file %1 does not exist").arg(arguments().at(i))); + else + sqlToExecute.append(arguments().at(i)); + } else if(arguments().at(i) == "-t" || arguments().at(i) == "--table") { + if(++i >= arguments().size()) + qWarning() << qPrintable(tr("The -t/--table option requires an argument")); + else + tableToBrowse = arguments().at(i); + } else if(arguments().at(i) == "-q" || arguments().at(i) == "--quit") { + m_dontShowMainWindow = true; + } else if(arguments().at(i) == "-R" || arguments().at(i) == "--read-only") { + readOnly = true; + } else if(arguments().at(i) == "-o" || arguments().at(i) == "--option" || + arguments().at(i) == "-O" || arguments().at(i) == "--save-option") { + const QString optionWarning = tr("The -o/--option and -O/--save-option options require an argument in the form group/setting=value"); + bool saveToDisk = arguments().at(i) == "-O" || arguments().at(i) == "--save-option"; + if(++i >= arguments().size()) + qWarning() << qPrintable(optionWarning); + else { + QStringList option = arguments().at(i).split("="); + if (option.size() != 2) + qWarning() << qPrintable(optionWarning); + else { + QStringList setting = option.at(0).split("/"); + if (setting.size() != 2) + qWarning() << qPrintable(optionWarning); + else { + QVariant value; + // Split string lists. This assumes they are always named "*list" + if (setting.at(1).endsWith("list", Qt::CaseInsensitive)) + value = option.at(1).split(","); + else + value = option.at(1); + Settings::setValue(setting.at(0).toStdString(), setting.at(1).toStdString(), value, !saveToDisk); + } + } + } + } else { + // Other: Check if it's a valid file name + if(QFile::exists(arguments().at(i))) + fileToOpen = arguments().at(i); + else + qWarning() << qPrintable(tr("Invalid option/non-existant file: %1").arg(arguments().at(i))); + } + } + + if(m_dontShowMainWindow) { + m_mainWindow = nullptr; + return; + } + + // Show main window + m_mainWindow = new SqliteDBMainWindow(); + m_mainWindow->show(); + connect(this, &Application::lastWindowClosed, this, &Application::quit); + + // Open database if one was specified + if(fileToOpen.size()) + { + if(m_mainWindow->fileOpen(fileToOpen, false, readOnly)) + { + // If database could be opened run the SQL scripts + for(const QString& f : sqlToExecute) + { + QFile file(f); + if(file.open(QIODevice::ReadOnly)) + { + m_mainWindow->getDb().executeMultiSQL(file.readAll(), false, true); + file.close(); + } + } + if(!sqlToExecute.isEmpty()) + m_mainWindow->refresh(); + + // Jump to table if the -t/--table parameter was set + if(!tableToBrowse.isEmpty()) { + m_mainWindow->switchToBrowseDataTab(sqlb::ObjectIdentifier("main", tableToBrowse.toStdString())); + m_mainWindow->refresh(); + } + } + } +} + +Application::~Application() +{ + if(m_mainWindow) + delete m_mainWindow; +} + +bool Application::event(QEvent* event) +{ + switch(event->type()) + { + case QEvent::FileOpen: + m_mainWindow->fileOpen(static_cast(event)->file()); + return true; + default: + return QApplication::event(event); + } +} + +QString Application::versionString() +{ + // Nightly builds use a patch number of 99, and for these we include the build date in the version string. For + // our release versions (which use any other patch number) we don't include the build date. This should avoid + // confusion about what is more important, version number or build date, and about different build dates for + // the same version. This also should help making release builds reproducible out of the box. +#if PATCH_VERSION == 99 + return QString("%1 (%2)").arg(APP_VERSION, __DATE__); +#else + return QString("%1").arg(APP_VERSION); +#endif +} + +QString Application::versionInformation() +{ + QString sqlite_version, sqlcipher_version; + DBBrowserDB::getSqliteVersion(sqlite_version, sqlcipher_version); + if(sqlcipher_version.isNull()) + sqlite_version = tr("SQLite Version ") + sqlite_version; + else + sqlite_version = tr("SQLCipher Version %1 (based on SQLite %2)").arg(sqlcipher_version, sqlite_version); + + return + tr("DB Browser for SQLite Version %1.").arg(versionString() + "\n\n" + + tr("Built for %1, running on %2").arg(QSysInfo::buildAbi(), QSysInfo::currentCpuArchitecture()) + "\n" + + tr("Qt Version %1").arg(QT_VERSION_STR) + "\n" + + sqlite_version + ); +} + +void Application::reloadSettings() +{ + // Network settings + //RemoteNetwork::get().reloadSettings(); + + // Font settings + QFont f = font(); + f.setPointSize(Settings::getValue("General", "fontsize").toInt()); + setFont(f); +} + +// Functions for documenting the shortcuts in the user interface using native names +static QString shortcutsTip(const QList& keys) +{ + QString tip; + + if (!keys.isEmpty()) { + tip = " ["; + + for (const auto& shortcut : keys) + tip.append(shortcut.toString(QKeySequence::NativeText) + ", "); + tip.chop(2); + + tip.append("]"); + } + return tip; +} + +void addShortcutsTooltip(QAction* action, const QList& extraKeys) +{ + if (!action->shortcuts().isEmpty() || !extraKeys.isEmpty()) + action->setToolTip(action->toolTip() + shortcutsTip(action->shortcuts() + extraKeys)); +} diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/Application.h b/src/WBCLFZSystemModule/SqliteDBProcess/src/Application.h new file mode 100644 index 0000000..7c40b26 --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/Application.h @@ -0,0 +1,43 @@ +#ifndef APPLICATION_H +#define APPLICATION_H + +#include +#include + +class QAction; +class QTranslator; + +class SqliteDBMainWindow; + +class Application : public QApplication +{ + Q_OBJECT + +public: + explicit Application(int& argc, char** argv); + ~Application() override; + + bool dontShowMainWindow() const { return m_dontShowMainWindow; } + + SqliteDBMainWindow* mainWindow() { return m_mainWindow; } + + // DB4S version number as string + static QString versionString(); + // Version of DB4S and dependencies as string + static QString versionInformation(); + + static void reloadSettings(); + +protected: + bool event(QEvent* event) override; + +private: + bool m_dontShowMainWindow; + SqliteDBMainWindow* m_mainWindow; + QTranslator* m_translatorQt; + QTranslator* m_translatorApp; +}; + +void addShortcutsTooltip(QAction* action, const QList& extraKeys = QList()); + +#endif diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/CipherDialog.cpp b/src/WBCLFZSystemModule/SqliteDBProcess/src/CipherDialog.cpp new file mode 100644 index 0000000..6b00961 --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/CipherDialog.cpp @@ -0,0 +1,146 @@ +#include "CipherDialog.h" +#include "ui_CipherDialog.h" +#include "sqlitedb.h" + +#include +#include + +#include + +CipherDialog::CipherDialog(QWidget* parent, bool encrypt) : + QDialog(parent), + ui(new Ui::CipherDialog), + encryptMode(encrypt), + rawKeyValidator(new QRegularExpressionValidator(QRegularExpression("\\A(0x[a-fA-F0-9]+)\\Z"))) +{ + ui->setupUi(this); + + int minimumPageSizeExponent = 9; + int maximumPageSizeExponent = 16; + int defaultPageSizeExponent = 10; + + for(int exponent = minimumPageSizeExponent; exponent <= maximumPageSizeExponent; exponent++) + { + int pageSize = static_cast(qPow(2, exponent)); + ui->comboPageSize->addItem(QLocale().toString(pageSize), pageSize); + + if (exponent == defaultPageSizeExponent) + ui->comboPageSize->setCurrentIndex(exponent - minimumPageSizeExponent); + } + + ui->comboPageSize->setMinimumWidth(ui->editPassword->width()); + + if(encrypt) + { + ui->labelDialogDescription->setText(tr("Please set a key to encrypt the database.\nNote that if you change any of the other, optional, settings you'll need " + "to re-enter them as well every time you open the database file.\nLeave the password fields empty to disable the " + "encryption.\nThe encryption process might take some time and you should have a backup copy of your database! Unsaved " + "changes are applied before modifying the encryption.")); + } else { + ui->labelDialogDescription->setText(tr("Please enter the key used to encrypt the database.\nIf any of the other settings were altered for this database file " + "you need to provide this information as well.")); + ui->editPassword2->setVisible(false); + ui->labelPassword2->setVisible(false); + } + + // Set the default encryption settings depending on the SQLCipher version we use + QString sqlite_version, sqlcipher_version; + DBBrowserDB::getSqliteVersion(sqlite_version, sqlcipher_version); + if(sqlcipher_version.startsWith('4')) + ui->radioEncryptionSqlCipher4->setChecked(true); + else + ui->radioEncryptionSqlCipher3->setChecked(true); +} + +CipherDialog::~CipherDialog() +{ + delete rawKeyValidator; + delete ui; +} + +CipherSettings CipherDialog::getCipherSettings() const +{ + CipherSettings::KeyFormats keyFormat = CipherSettings::getKeyFormat(ui->comboKeyFormat->currentIndex()); + std::string password = ui->editPassword->text().toStdString(); + int pageSize = ui->comboPageSize->itemData(ui->comboPageSize->currentIndex()).toInt(); + + CipherSettings cipherSettings; + + cipherSettings.setKeyFormat(keyFormat); + cipherSettings.setPassword(password); + cipherSettings.setPageSize(pageSize); + cipherSettings.setKdfIterations(ui->spinKdfIterations->value()); + cipherSettings.setHmacAlgorithm("HMAC_" + ui->comboHmacAlgorithm->currentText().toStdString()); + cipherSettings.setKdfAlgorithm("PBKDF2_HMAC_" + ui->comboKdfAlgorithm->currentText().toStdString()); + cipherSettings.setPlaintextHeaderSize(ui->plaintextHeaderSize->value()); + + return cipherSettings; +} + +void CipherDialog::checkInputFields() +{ + if(sender() == ui->comboKeyFormat) + { + CipherSettings::KeyFormats keyFormat = CipherSettings::getKeyFormat(ui->comboKeyFormat->currentIndex()); + + if(keyFormat == CipherSettings::KeyFormats::Passphrase) + { + ui->editPassword->setValidator(nullptr); + ui->editPassword2->setValidator(nullptr); + ui->editPassword->setPlaceholderText(""); + } else if(keyFormat == CipherSettings::KeyFormats::RawKey) { + ui->editPassword->setValidator(rawKeyValidator); + ui->editPassword2->setValidator(rawKeyValidator); + ui->editPassword->setPlaceholderText("0x..."); + } + + ui->editPassword->setText(""); + ui->editPassword2->setText(""); + } + + bool valid = true; + if(encryptMode) + valid = ui->editPassword->text() == ui->editPassword2->text(); + + ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(valid); +} + +void CipherDialog::toggleEncryptionSettings() +{ + if(ui->radioEncryptionSqlCipher3->isChecked()) + { + // SQLCipher3 + ui->comboPageSize->setCurrentText(QLocale().toString(1024)); + ui->spinKdfIterations->setValue(64000); + ui->comboHmacAlgorithm->setCurrentText("SHA1"); + ui->comboKdfAlgorithm->setCurrentText("SHA1"); + ui->plaintextHeaderSize->setValue(0); + + ui->comboPageSize->setEnabled(false); + ui->spinKdfIterations->setEnabled(false); + ui->comboHmacAlgorithm->setEnabled(false); + ui->comboKdfAlgorithm->setEnabled(false); + ui->plaintextHeaderSize->setEnabled(false); + } else if(ui->radioEncryptionSqlCipher4->isChecked()) { + // SQLCipher4 + ui->comboPageSize->setCurrentText(QLocale().toString(4096)); + ui->spinKdfIterations->setValue(256000); + ui->comboHmacAlgorithm->setCurrentText("SHA512"); + ui->comboKdfAlgorithm->setCurrentText("SHA512"); + ui->plaintextHeaderSize->setValue(0); + + ui->comboPageSize->setEnabled(false); + ui->spinKdfIterations->setEnabled(false); + ui->comboHmacAlgorithm->setEnabled(false); + ui->comboKdfAlgorithm->setEnabled(false); + ui->plaintextHeaderSize->setEnabled(false); + } else if(ui->radioEncryptionCustom->isChecked()) { + // Custom + + ui->comboPageSize->setEnabled(true); + ui->spinKdfIterations->setEnabled(true); + ui->comboHmacAlgorithm->setEnabled(true); + ui->comboKdfAlgorithm->setEnabled(true); + ui->plaintextHeaderSize->setEnabled(true); + } +} diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/CipherDialog.h b/src/WBCLFZSystemModule/SqliteDBProcess/src/CipherDialog.h new file mode 100644 index 0000000..ac7adc9 --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/CipherDialog.h @@ -0,0 +1,36 @@ +#ifndef CIPHERDIALOG_H +#define CIPHERDIALOG_H + +#include + +#include "CipherSettings.h" + +class QRegularExpressionValidator; + +namespace Ui { +class CipherDialog; +} + +class CipherDialog : public QDialog +{ + Q_OBJECT + +public: + // Set the encrypt parameter to true when the dialog is used to encrypt a database; + // set it to false if the dialog is used to ask the user for the key to decrypt a file. + explicit CipherDialog(QWidget* parent, bool encrypt); + ~CipherDialog() override; + + CipherSettings getCipherSettings() const; + +private: + Ui::CipherDialog* ui; + bool encryptMode; + QRegularExpressionValidator* rawKeyValidator; + +private slots: + void checkInputFields(); + void toggleEncryptionSettings(); +}; + +#endif diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/CipherDialog.ui b/src/WBCLFZSystemModule/SqliteDBProcess/src/CipherDialog.ui new file mode 100644 index 0000000..00c1d28 --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/CipherDialog.ui @@ -0,0 +1,403 @@ + + + CipherDialog + + + + 0 + 0 + 712 + 299 + + + + SQLCipher encryption + + + + + + + + + + + + + &Password + + + editPassword + + + + + + + QLineEdit::Password + + + + + + + &Reenter password + + + editPassword2 + + + + + + + QLineEdit::Password + + + + + + + + + + + + Passphrase + + + + + Raw key + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + + + Encr&yption settings + + + radioEncryptionSqlCipher3 + + + + + + + + + SQLCipher &3 defaults + + + + + + + SQLCipher &4 defaults + + + + + + + Custo&m + + + + + + + + + Page si&ze + + + comboPageSize + + + + + + + + + + &KDF iterations + + + spinKdfIterations + + + + + + + 1 + + + 1000000 + + + + + + + HMAC algorithm + + + comboHmacAlgorithm + + + + + + + + SHA512 + + + + + SHA256 + + + + + SHA1 + + + + + + + + KDF algorithm + + + comboKdfAlgorithm + + + + + + + + SHA512 + + + + + SHA256 + + + + + SHA1 + + + + + + + + Plaintext Header Size + + + plaintextHeaderSize + + + + + + + 0 + + + 1000000 + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + editPassword + editPassword2 + comboKeyFormat + radioEncryptionSqlCipher3 + radioEncryptionSqlCipher4 + radioEncryptionCustom + comboPageSize + spinKdfIterations + comboHmacAlgorithm + comboKdfAlgorithm + plaintextHeaderSize + + + + + buttonBox + accepted() + CipherDialog + accept() + + + 175 + 265 + + + 157 + 126 + + + + + buttonBox + rejected() + CipherDialog + reject() + + + 175 + 265 + + + 286 + 126 + + + + + editPassword + textChanged(QString) + CipherDialog + checkInputFields() + + + 150 + 38 + + + 155 + 26 + + + + + editPassword2 + textChanged(QString) + CipherDialog + checkInputFields() + + + 446 + 79 + + + 206 + 46 + + + + + comboKeyFormat + currentIndexChanged(int) + CipherDialog + checkInputFields() + + + 670 + 38 + + + 665 + 0 + + + + + radioEncryptionSqlCipher3 + toggled(bool) + CipherDialog + toggleEncryptionSettings() + + + 217 + 114 + + + 231 + 94 + + + + + radioEncryptionSqlCipher4 + toggled(bool) + CipherDialog + toggleEncryptionSettings() + + + 353 + 117 + + + 407 + 97 + + + + + radioEncryptionCustom + toggled(bool) + CipherDialog + toggleEncryptionSettings() + + + 552 + 120 + + + 590 + 99 + + + + + + checkInputFields() + toggleEncryptionSettings() + + diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/CipherSettings.cpp b/src/WBCLFZSystemModule/SqliteDBProcess/src/CipherSettings.cpp new file mode 100644 index 0000000..f7e3215 --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/CipherSettings.cpp @@ -0,0 +1,26 @@ +#include "CipherSettings.h" +#include "sqlitedb.h" + +CipherSettings::CipherSettings() + : keyFormat(Passphrase), + pageSize(0), + kdfIterations(0), + plaintextHeaderSize(0) +{ +} + +std::string CipherSettings::getPassword() const +{ + if(keyFormat == Passphrase) + { + return sqlb::escapeString(password); + } else { + // Remove the '0x' part at the beginning + return "\"x'" + password.substr(2) + "'\""; + } +} + +CipherSettings::KeyFormats CipherSettings::getKeyFormat(int rawKeyFormat) +{ + return static_cast(rawKeyFormat); +} diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/CipherSettings.h b/src/WBCLFZSystemModule/SqliteDBProcess/src/CipherSettings.h new file mode 100644 index 0000000..54b8ecd --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/CipherSettings.h @@ -0,0 +1,50 @@ +#ifndef CIPHERSETTINGS_H +#define CIPHERSETTINGS_H + +#include + +class CipherSettings +{ +public: + CipherSettings(); + + enum KeyFormats + { + Passphrase, + RawKey + }; + + KeyFormats getKeyFormat() const { return keyFormat; } + void setKeyFormat(const KeyFormats &value) { keyFormat = value; } + + std::string getPassword() const; + void setPassword(const std::string& value) { password = value; } + + int getPageSize() const { return pageSize; } + void setPageSize(int value) { pageSize = value; } + + int getKdfIterations() const { return kdfIterations; } + void setKdfIterations(int value) { kdfIterations = value; } + + int getPlaintextHeaderSize() const { return plaintextHeaderSize; } + void setPlaintextHeaderSize(int value) { plaintextHeaderSize = value; } + + std::string getHmacAlgorithm() const { return hmacAlgorithm; } + void setHmacAlgorithm(const std::string& value) { hmacAlgorithm = value; } + + std::string getKdfAlgorithm() const { return kdfAlgorithm; } + void setKdfAlgorithm(const std::string& value) { kdfAlgorithm = value; } + + static KeyFormats getKeyFormat(int rawKeyFormat); + +private: + KeyFormats keyFormat; + std::string password; + int pageSize; + int kdfIterations; + int plaintextHeaderSize; + std::string hmacAlgorithm; + std::string kdfAlgorithm; +}; + +#endif // CIPHERSETTINGS_H diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/ColumnDisplayFormatDialog.cpp b/src/WBCLFZSystemModule/SqliteDBProcess/src/ColumnDisplayFormatDialog.cpp new file mode 100644 index 0000000..001ae6d --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/ColumnDisplayFormatDialog.cpp @@ -0,0 +1,139 @@ +#include + +#include "ColumnDisplayFormatDialog.h" +#include "ui_ColumnDisplayFormatDialog.h" +#include "sql/sqlitetypes.h" +#include "sqlitedb.h" + +ColumnDisplayFormatDialog::ColumnDisplayFormatDialog(DBBrowserDB& db, const sqlb::ObjectIdentifier& tableName, const QString& colname, const QString& current_format, QWidget* parent) + : QDialog(parent), + ui(new Ui::ColumnDisplayFormatDialog), + column_name(colname), + pdb(db), + curTable(tableName) +{ + // Create UI + ui->setupUi(this); + ui->comboDisplayFormat->addItem(tr("Default"), "default"); + ui->comboDisplayFormat->insertSeparator(ui->comboDisplayFormat->count()); + ui->comboDisplayFormat->addItem(tr("Decimal number"), "decimal"); + ui->comboDisplayFormat->addItem(tr("Exponent notation"), "exponent"); + ui->comboDisplayFormat->addItem(tr("Hex blob"), "hexblob"); + ui->comboDisplayFormat->addItem(tr("Hex number"), "hex"); + ui->comboDisplayFormat->addItem(tr("Octal number"), "octal"); + ui->comboDisplayFormat->addItem(tr("Round number"), "round"); + ui->comboDisplayFormat->insertSeparator(ui->comboDisplayFormat->count()); + ui->comboDisplayFormat->addItem(tr("Apple NSDate to date"), "appleDate"); + ui->comboDisplayFormat->addItem(tr("Java epoch (milliseconds) to date"), "javaEpoch"); + ui->comboDisplayFormat->addItem(tr(".NET DateTime.Ticks to date"), "dotNetTicks"); + ui->comboDisplayFormat->addItem(tr("Julian day to date"), "julian"); + ui->comboDisplayFormat->addItem(tr("Unix epoch to date"), "epoch"); + ui->comboDisplayFormat->addItem(tr("Unix epoch to local time"), "epochLocalTime"); + ui->comboDisplayFormat->addItem(tr("Windows DATE to date"), "winDate"); + ui->comboDisplayFormat->addItem(tr("Date as dd/mm/yyyy"), "ddmmyyyyDate"); + ui->comboDisplayFormat->insertSeparator(ui->comboDisplayFormat->count()); + ui->comboDisplayFormat->addItem(tr("Lower case"), "lower"); + ui->comboDisplayFormat->addItem(tr("Upper case"), "upper"); + ui->comboDisplayFormat->insertSeparator(ui->comboDisplayFormat->count()); + ui->comboDisplayFormat->addItem(tr("Custom"), "custom"); + + ui->labelDisplayFormat->setText(ui->labelDisplayFormat->text().arg(column_name)); + + formatFunctions["decimal"] = "printf('%d', " + sqlb::escapeIdentifier(column_name) + ")"; + formatFunctions["exponent"] = "printf('%e', " + sqlb::escapeIdentifier(column_name) + ")"; + formatFunctions["hexblob"] = "hex(" + sqlb::escapeIdentifier(column_name) + ")"; + formatFunctions["hex"] = "printf('0x%x', " + sqlb::escapeIdentifier(column_name) + ")"; + formatFunctions["octal"] = "printf('%o', " + sqlb::escapeIdentifier(column_name) + ")"; + formatFunctions["round"] = "round(" + sqlb::escapeIdentifier(column_name) + ")"; + formatFunctions["appleDate"] = "datetime('2001-01-01', " + sqlb::escapeIdentifier(column_name) + " || ' seconds')"; + formatFunctions["javaEpoch"] = "strftime('%Y-%m-%d %H:%M:%S.', " + sqlb::escapeIdentifier(column_name) + + "/1000, 'unixepoch') || (" + sqlb::escapeIdentifier(column_name) + "%1000)"; + formatFunctions["dotNetTicks"] = "datetime(" + sqlb::escapeIdentifier(column_name) + " / 10000000 - 62135596800, 'unixepoch')"; + formatFunctions["julian"] = "datetime(" + sqlb::escapeIdentifier(column_name) + ")"; + formatFunctions["epoch"] = "datetime(" + sqlb::escapeIdentifier(column_name) + ", 'unixepoch')"; + formatFunctions["epochLocalTime"] = "datetime(" + sqlb::escapeIdentifier(column_name) + ", 'unixepoch', 'localtime')"; + formatFunctions["winDate"] = "datetime('1899-12-30', " + sqlb::escapeIdentifier(column_name) + " || ' days')"; + formatFunctions["ddmmyyyyDate"] = "strftime('%d/%m/%Y', " + sqlb::escapeIdentifier(column_name) + ")"; + formatFunctions["lower"] = "lower(" + sqlb::escapeIdentifier(column_name) + ")"; + formatFunctions["upper"] = "upper(" + sqlb::escapeIdentifier(column_name) + ")"; + + // Set the current format, if it's empty set the default format + if(current_format.isEmpty()) + { + ui->comboDisplayFormat->setCurrentIndex(0); + updateSqlCode(); + } else { + // When it doesn't match any predefined format, it is considered custom + QString formatName = "custom"; + auto it = std::find_if(formatFunctions.begin(), formatFunctions.end(), [current_format](const std::pair& s) { + return s.second == current_format; + }); + if(it != formatFunctions.end()) + formatName = QString::fromStdString(it->first); + ui->comboDisplayFormat->setCurrentIndex(ui->comboDisplayFormat->findData(formatName)); + ui->editDisplayFormat->setText(current_format); + } +} + +ColumnDisplayFormatDialog::~ColumnDisplayFormatDialog() +{ + delete ui; +} + +QString ColumnDisplayFormatDialog::selectedDisplayFormat() const +{ + if(ui->comboDisplayFormat->currentData().toString() == "default") + return QString(); + else + return ui->editDisplayFormat->text(); +} + +void ColumnDisplayFormatDialog::updateSqlCode() +{ + std::string format = ui->comboDisplayFormat->currentData().toString().toStdString(); + + if(format == "default") + ui->editDisplayFormat->setText(sqlb::escapeIdentifier(column_name)); + else if(format != "custom") + ui->editDisplayFormat->setText(formatFunctions.at(format)); +} + +void ColumnDisplayFormatDialog::accept() +{ + QString errorMessage; + + // Accept the SQL code if it's the column name (default), it contains a function invocation applied to the column name and it can be + // executed without errors returning only one column. + // Users could still devise a way to break this, but this is considered good enough for letting them know about simple incorrect + // cases. + if(!(ui->editDisplayFormat->text() == sqlb::escapeIdentifier(column_name) || + ui->editDisplayFormat->text().contains(QRegularExpression("[a-z]+[a-z_0-9]* *\\(.*" + QRegularExpression::escape(sqlb::escapeIdentifier(column_name)) + ".*\\)", QRegularExpression::CaseInsensitiveOption)))) + errorMessage = tr("Custom display format must contain a function call applied to %1").arg(sqlb::escapeIdentifier(column_name)); + else { + // Execute a query using the display format and check that it only returns one column. + int customNumberColumns = 0; + + DBBrowserDB::execCallback callback = [&customNumberColumns](int numberColumns, std::vector, std::vector) -> bool { + customNumberColumns = numberColumns; + // Return false so the query is not aborted and no error is reported. + return false; + }; + if(!pdb.executeSQL("SELECT " + ui->editDisplayFormat->text().toStdString() + " FROM " + curTable.toString() + " LIMIT 1", + false, true, callback)) + errorMessage = tr("Error in custom display format. Message from database engine:\n\n%1").arg(pdb.lastError()); + else if(customNumberColumns != 1) + errorMessage = tr("Custom display format must return only one column but it returned %1.").arg(customNumberColumns); + + } + if(!errorMessage.isEmpty()) + QMessageBox::warning(this, QApplication::applicationName(), errorMessage); + else + QDialog::accept(); +} + +void ColumnDisplayFormatDialog::setCustom(bool modified) +{ + // If the SQL code is modified by user, select the custom value in the combo-box + if(modified && ui->editDisplayFormat->hasFocus()) + ui->comboDisplayFormat->setCurrentIndex(ui->comboDisplayFormat->findData("custom")); +} diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/ColumnDisplayFormatDialog.h b/src/WBCLFZSystemModule/SqliteDBProcess/src/ColumnDisplayFormatDialog.h new file mode 100644 index 0000000..1360612 --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/ColumnDisplayFormatDialog.h @@ -0,0 +1,41 @@ +#ifndef COLUMNDISPLAYFORMATDIALOG_H +#define COLUMNDISPLAYFORMATDIALOG_H + +#include + +#include + +#include "sql/ObjectIdentifier.h" + +class QString; + +class DBBrowserDB; + +namespace Ui { +class ColumnDisplayFormatDialog; +} + +class ColumnDisplayFormatDialog : public QDialog +{ + Q_OBJECT + +public: + explicit ColumnDisplayFormatDialog(DBBrowserDB& db, const sqlb::ObjectIdentifier& tableName, const QString& colname, const QString& current_format, QWidget* parent = nullptr); + ~ColumnDisplayFormatDialog() override; + + QString selectedDisplayFormat() const; + +private slots: + void updateSqlCode(); + void accept() override; + void setCustom(bool modified); + +private: + Ui::ColumnDisplayFormatDialog* ui; + QString column_name; + std::unordered_map formatFunctions; + DBBrowserDB& pdb; + sqlb::ObjectIdentifier curTable; +}; + +#endif diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/ColumnDisplayFormatDialog.ui b/src/WBCLFZSystemModule/SqliteDBProcess/src/ColumnDisplayFormatDialog.ui new file mode 100644 index 0000000..5816b8b --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/ColumnDisplayFormatDialog.ui @@ -0,0 +1,134 @@ + + + ColumnDisplayFormatDialog + + + + 0 + 0 + 624 + 205 + + + + Choose display format + + + + + + Display format + + + + + + Choose a display format for the column '%1' which is applied to each value prior to showing it. + + + + + + + + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + SqlTextEdit + QTextEdit +
sqltextedit.h
+ 1 +
+
+ + comboDisplayFormat + editDisplayFormat + + + + + buttonBox + accepted() + ColumnDisplayFormatDialog + accept() + + + 227 + 188 + + + 157 + 204 + + + + + buttonBox + rejected() + ColumnDisplayFormatDialog + reject() + + + 295 + 194 + + + 286 + 204 + + + + + comboDisplayFormat + currentIndexChanged(int) + ColumnDisplayFormatDialog + updateSqlCode() + + + 125 + 69 + + + 244 + 4 + + + + + editDisplayFormat + modificationChanged(bool) + ColumnDisplayFormatDialog + setCustom(bool) + + + 125 + 69 + + + 244 + 4 + + + + + + updateSqlCode() + setCustom() + +
diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/CondFormat.cpp b/src/WBCLFZSystemModule/SqliteDBProcess/src/CondFormat.cpp new file mode 100644 index 0000000..0597026 --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/CondFormat.cpp @@ -0,0 +1,176 @@ +#include "CondFormat.h" +#include "Settings.h" +#include "Data.h" +#include "sqlitedb.h" + +#include + +CondFormat::Alignment CondFormat::fromCombinedAlignment(Qt::Alignment align) +{ + if (align.testFlag(Qt::AlignLeft)) + return AlignLeft; + if (align.testFlag(Qt::AlignRight)) + return AlignRight; + if (align.testFlag(Qt::AlignCenter)) + return AlignCenter; + if (align.testFlag(Qt::AlignJustify)) + return AlignJustify; + + return AlignLeft; +} + +CondFormat::CondFormat(const QString& filter, + const QColor& foreground, + const QColor& background, + const QFont& font, + const Alignment alignment, + const QString& encoding) + : m_filter(filter), + m_bgColor(background), + m_fgColor(foreground), + m_font(font), + m_align(alignment) +{ + if (!filter.isEmpty()) + m_sqlCondition = filterToSqlCondition(filter, encoding); +} + +CondFormat::CondFormat(const QString& filter, + const QAbstractTableModel* model, + const QModelIndex index, + const QString& encoding) + : m_filter(filter) +{ + + if (!filter.isEmpty()) + m_sqlCondition = filterToSqlCondition(filter, encoding); + + m_bgColor = QColor(model->data(index, Qt::BackgroundRole).toString()); + m_fgColor = QColor(model->data(index, Qt::ForegroundRole).toString()); + m_align = fromCombinedAlignment(Qt::Alignment(model->data(index, Qt::TextAlignmentRole).toInt())); + m_font.fromString(model->data(index, Qt::FontRole).toString()); +} + +std::string CondFormat::filterToSqlCondition(const QString& value, const QString& encoding) +{ + if(value.isEmpty()) + return {}; + + // Check for any special comparison operators at the beginning of the value string. If there are none default to LIKE. + QString op = "LIKE"; + QString val, val2; + QString escape; + bool numeric = false, ok = false; + + // range/BETWEEN operator + if (value.contains("~")) { + int sepIdx = value.indexOf('~'); + val = value.mid(0, sepIdx); + val2 = value.mid(sepIdx+1); + float valf = val.toFloat(&ok); + if (ok) { + float val2f = val2.toFloat(&ok); + ok = ok && (valf < val2f); + } + } + if (ok) { + op = "BETWEEN"; + numeric = true; + } else { + val.clear(); + val2.clear(); + if(value.left(2) == ">=" || value.left(2) == "<=" || value.left(2) == "<>") + { + // Check if we're filtering for '<> NULL'. In this case we need a special comparison operator. + if(value.left(2) == "<>" && value.mid(2) == "NULL") + { + // We are filtering for '<>NULL'. Override the comparison operator to search for NULL values in this column. Also treat search value (NULL) as number, + // in order to avoid putting quotes around it. + op = "IS NOT"; + numeric = true; + val = "NULL"; + } else if(value.left(2) == "<>" && value.mid(2) == "''") { + // We are filtering for "<>''", i.e. for everything which is not an empty string + op = "<>"; + numeric = true; + val = "''"; + } else { + value.midRef(2).toFloat(&numeric); + op = value.left(2); + val = value.mid(2); + } + } else if(value.left(1) == ">" || value.left(1) == "<") { + value.midRef(1).toFloat(&numeric); + op = value.at(0); + val = value.mid(1); + } else if(value.left(1) == "=") { + val = value.mid(1); + + // Check if value to compare with is 'NULL' + if(val != "NULL") + { + // It's not, so just compare normally to the value, whatever it is. + op = "="; + } else { + // It is NULL. Override the comparison operator to search for NULL values in this column. Also treat search value (NULL) as number, + // in order to avoid putting quotes around it. + op = "IS"; + numeric = true; + } + } else if(value.left(1) == "/" && value.right(1) == "/" && value.size() > 2) { + val = value.mid(1, value.length() - 2); + op = "REGEXP"; + numeric = false; + } else { + // Keep the default LIKE operator + + // Set the escape character if one has been specified in the settings dialog + QString escape_character = Settings::getValue("databrowser", "filter_escape").toString(); + if(escape_character == "'") escape_character = "''"; + if(escape_character.length()) + escape = QString("ESCAPE '%1'").arg(escape_character); + + // Add % wildcards at the start and at the beginning of the filter query, but only if there weren't set any + // wildcards manually. The idea is to assume that a user who's just typing characters expects the wildcards to + // be added but a user who adds them herself knows what she's doing and doesn't want us to mess up her query. + if(!value.contains("%")) + { + val = value; + val.prepend('%'); + val.append('%'); + } + } + } + if(val.isEmpty()) + val = value; + + if(val.isEmpty() || val == "%" || val == "%%") + return {}; + else { + // Quote and escape value, but only if it's not numeric and not the empty string sequence + if(!numeric && val != "''") + val = sqlb::escapeString(val); + + QString whereClause(op + " " + QString(encodeString(val.toUtf8(), encoding))); + if (!val2.isEmpty()) + whereClause += " AND " + QString(encodeString(val2.toUtf8(), encoding)); + whereClause += " " + escape; + return whereClause.toStdString(); + } +} + +Qt::AlignmentFlag CondFormat::alignmentFlag() const +{ + switch (m_align) { + case AlignLeft: + return Qt::AlignLeft; + case AlignCenter: + return Qt::AlignCenter; + case AlignRight: + return Qt::AlignRight; + case AlignJustify: + return Qt::AlignJustify; + } + + return Qt::AlignLeft; +} diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/CondFormat.h b/src/WBCLFZSystemModule/SqliteDBProcess/src/CondFormat.h new file mode 100644 index 0000000..3541fd8 --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/CondFormat.h @@ -0,0 +1,81 @@ +#ifndef CONDFORMAT_H +#define CONDFORMAT_H + +#include +#include +#include +#include + +class QAbstractTableModel; + +// Conditional formatting for given format to table cells based on a specified condition. +class CondFormat +{ +public: + + enum Alignment { + AlignLeft = 0, + AlignRight, + AlignCenter, + AlignJustify + }; + + // List of alignment texts. Order must be as Alignment definition above. + static QStringList alignmentTexts() { + return {QObject::tr("Left"), QObject::tr("Right"), QObject::tr("Center"), QObject::tr("Justify")}; + } + + // Get alignment from combined Qt alignment (note that this will lose any combination of our Alignment enum + // with other values present in the flag (e.g. vertical alignment). + static Alignment fromCombinedAlignment(Qt::Alignment align); + + CondFormat() {} + CondFormat(const QString& filter, + const QColor& foreground, + const QColor& background, + const QFont& font, + const Alignment alignment = AlignLeft, + const QString& encoding = QString()); + + // Create a new CondFormat from values obtained from the model + CondFormat(const QString& filter, + const QAbstractTableModel* model, + const QModelIndex index, + const QString& encoding = QString()); + + static std::string filterToSqlCondition(const QString& value, const QString& encoding = QString()); + +private: + std::string m_sqlCondition; + QString m_filter; + QColor m_bgColor; + QColor m_fgColor; + QFont m_font; + Alignment m_align; + +public: + std::string sqlCondition() const { return m_sqlCondition; } + QString filter() const { return m_filter; } + + QColor backgroundColor() const { return m_bgColor; } + QColor foregroundColor() const { return m_fgColor; } + void setBackgroundColor(QColor color) { m_bgColor = color; } + void setForegroundColor(QColor color) { m_fgColor = color; } + + bool isBold() const { return m_font.bold(); } + bool isItalic() const { return m_font.italic(); } + bool isUnderline() const { return m_font.underline(); } + void setBold(bool value) { m_font.setBold(value); } + void setItalic(bool value) { m_font.setItalic(value); } + void setUnderline(bool value) { m_font.setUnderline(value); } + + QFont font() const { return m_font; } + void setFontFamily(const QString &family) { m_font.setFamily(family); } + void setFontPointSize(int pointSize) { m_font.setPointSize(pointSize); } + + Alignment alignment() const { return m_align; } + void setAlignment(Alignment value) { m_align = value; } + Qt::AlignmentFlag alignmentFlag() const; +}; + +#endif // CONDFORMAT_H diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/CondFormatManager.cpp b/src/WBCLFZSystemModule/SqliteDBProcess/src/CondFormatManager.cpp new file mode 100644 index 0000000..93367c7 --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/CondFormatManager.cpp @@ -0,0 +1,252 @@ +#include "CondFormatManager.h" +#include "ui_CondFormatManager.h" +#include "CondFormat.h" +#include "Settings.h" +#include "FilterLineEdit.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// Styled Item Delegate for non-editable columns (all except Condition) +class DefaultDelegate: public QStyledItemDelegate { +public: + explicit DefaultDelegate(QObject* parent=nullptr): QStyledItemDelegate(parent) {} + QWidget* createEditor(QWidget* /* parent */, const QStyleOptionViewItem& /* option */, const QModelIndex& /* index */) const override { + return nullptr; + } +}; + +// Styled Item Delegate for the Condition column as a filter line editor. +class FilterEditDelegate: public QStyledItemDelegate { + +public: + explicit FilterEditDelegate(QObject* parent=nullptr): QStyledItemDelegate(parent) {} + QWidget* createEditor(QWidget *parent, const QStyleOptionViewItem& /* option */, const QModelIndex& /* index */) const override { + FilterLineEdit* filterEditor = new FilterLineEdit(parent); + filterEditor->setConditionFormatContextMenuEnabled(false); + return filterEditor; + } +}; + +CondFormatManager::CondFormatManager(const std::vector& condFormats, const QString& encoding, QWidget *parent) : + QDialog(parent), + ui(new Ui::CondFormatManager), + m_condFormats(condFormats), + m_encoding(encoding) +{ + ui->setupUi(this); + + for(const CondFormat& aCondFormat : condFormats) + addItem(aCondFormat); + + // Make condition editable as a filter line editor. + ui->tableCondFormats->setEditTriggers(QAbstractItemView::AllEditTriggers); + ui->tableCondFormats->setItemDelegateForColumn(ColumnFilter, new FilterEditDelegate(this)); + + // Make columns not text-editable, except for the condition. + for(int col = ColumnForeground; col < ColumnFilter; ++col) { + ui->tableCondFormats->setItemDelegateForColumn(col, new DefaultDelegate(this)); + ui->tableCondFormats->resizeColumnToContents(col); + } + + connect(ui->buttonAdd, &QToolButton::clicked, this, &CondFormatManager::addNewItem); + connect(ui->buttonRemove, &QToolButton::clicked, this, &CondFormatManager::removeItem); + + connect(ui->buttonDown, &QToolButton::clicked, this, &CondFormatManager::downItem); + connect(ui->buttonUp, &QToolButton::clicked, this, &CondFormatManager::upItem); + + connect(ui->tableCondFormats, &QTreeWidget::itemClicked, this, &CondFormatManager::itemClicked); +} + +CondFormatManager::~CondFormatManager() +{ + delete ui; +} + +void CondFormatManager::addNewItem() +{ + // Clear focus from the current widget, so if there is some input, it is saved now. + QWidget* currentWidget = ui->tableCondFormats->itemWidget(ui->tableCondFormats->currentItem(), ColumnFilter); + if (currentWidget != nullptr) + currentWidget->clearFocus(); + + QFont font = QFont(Settings::getValue("databrowser", "font").toString()); + font.setPointSize(Settings::getValue("databrowser", "fontsize").toInt()); + + CondFormat newCondFormat("", QColor(Settings::getValue("databrowser", "reg_fg_colour").toString()), + m_condFormatPalette.nextSerialColor(Palette::appHasDarkTheme()), + font, + CondFormat::AlignLeft, + m_encoding); + addItem(newCondFormat); +} + +void CondFormatManager::addItem(const CondFormat& aCondFormat) +{ + int i = ui->tableCondFormats->topLevelItemCount(); + QTreeWidgetItem *newItem = new QTreeWidgetItem(ui->tableCondFormats); + newItem->setFlags(Qt::ItemIsEnabled | Qt::ItemIsEditable); + + newItem->setForeground(ColumnForeground, aCondFormat.foregroundColor()); + newItem->setBackground(ColumnForeground, aCondFormat.foregroundColor()); + newItem->setForeground(ColumnBackground, aCondFormat.backgroundColor()); + newItem->setBackground(ColumnBackground, aCondFormat.backgroundColor()); + newItem->setToolTip(ColumnBackground, tr("Click to select color")); + newItem->setToolTip(ColumnForeground, tr("Click to select color")); + + QFontComboBox* fontCombo = new QFontComboBox(ui->tableCondFormats); + fontCombo->setCurrentFont(aCondFormat.font()); + // Avoid that the font combo box gets too wide and work around a possible Qt bug where the box overlaps the next column. + fontCombo->setMaximumWidth(150); + ui->tableCondFormats->setItemWidget(newItem, ColumnFont, fontCombo); + + QSpinBox* sizeBox = new QSpinBox(ui->tableCondFormats); + sizeBox->setMinimum(1); + sizeBox->setValue(aCondFormat.font().pointSize()); + ui->tableCondFormats->setItemWidget(newItem, ColumnSize, sizeBox); + + newItem->setCheckState(ColumnBold, aCondFormat.isBold() ? Qt::Checked : Qt::Unchecked); + newItem->setCheckState(ColumnItalic, aCondFormat.isItalic() ? Qt::Checked : Qt::Unchecked); + newItem->setCheckState(ColumnUnderline, aCondFormat.isUnderline() ? Qt::Checked : Qt::Unchecked); + + QComboBox* alignCombo = new QComboBox(ui->tableCondFormats); + alignCombo->addItems(CondFormat::alignmentTexts()); + alignCombo->setCurrentIndex(aCondFormat.alignment()); + ui->tableCondFormats->setItemWidget(newItem, ColumnAlignment, alignCombo); + + newItem->setText(ColumnFilter, aCondFormat.filter()); + ui->tableCondFormats->insertTopLevelItem(i, newItem); +} + +void CondFormatManager::removeItem() +{ + QTreeWidgetItem* item = ui->tableCondFormats->takeTopLevelItem(ui->tableCondFormats->currentIndex().row()); + delete item; +} + +void CondFormatManager::moveItem(int offset) +{ + if (!ui->tableCondFormats->currentIndex().isValid()) + return; + + int selectedRow = ui->tableCondFormats->currentIndex().row(); + int newRow = selectedRow + offset; + if(newRow < 0 || newRow >= ui->tableCondFormats->topLevelItemCount()) + return; + + QTreeWidgetItem* item = ui->tableCondFormats->topLevelItem(selectedRow); + + // Rescue widgets, since they will be deleted, and add them later. + QFontComboBox* fontCombo = qobject_cast(ui->tableCondFormats->itemWidget(item, ColumnFont)); + QFontComboBox* fontCombo2 = new QFontComboBox(ui->tableCondFormats); + fontCombo2->setCurrentFont(fontCombo->currentFont()); + + QSpinBox* sizeBox = qobject_cast(ui->tableCondFormats->itemWidget(item, ColumnSize)); + QSpinBox* sizeBox2 = new QSpinBox(ui->tableCondFormats); + sizeBox2->setValue(sizeBox->value()); + sizeBox2->setMinimum(sizeBox->minimum()); + + QComboBox* alignCombo = qobject_cast(ui->tableCondFormats->itemWidget(item, ColumnAlignment)); + QComboBox* alignCombo2 = new QComboBox(ui->tableCondFormats); + alignCombo2->addItems(CondFormat::alignmentTexts()); + alignCombo2->setCurrentIndex(alignCombo->currentIndex()); + + item = ui->tableCondFormats->takeTopLevelItem(selectedRow); + ui->tableCondFormats->insertTopLevelItem(newRow, item); + + // Restore widgets and state + ui->tableCondFormats->setItemWidget(item, ColumnFont, fontCombo2); + ui->tableCondFormats->setItemWidget(item, ColumnSize, sizeBox2); + ui->tableCondFormats->setItemWidget(item, ColumnAlignment, alignCombo2); + ui->tableCondFormats->setCurrentIndex(ui->tableCondFormats->currentIndex().sibling(newRow, + ui->tableCondFormats->currentIndex().column())); + // This is added so the widgets are readjusted. Otherwise they can be misplaced when moving an item to the top. + ui->tableCondFormats->adjustSize(); +} + +void CondFormatManager::upItem() +{ + moveItem(-1); +} + +void CondFormatManager::downItem() +{ + moveItem(+1); +} + +std::vector CondFormatManager::getCondFormats() const +{ + std::vector result; + + for (int i = 0; i < ui->tableCondFormats->topLevelItemCount(); ++i) + { + QTreeWidgetItem* item = ui->tableCondFormats->topLevelItem(i); + + QFontComboBox* fontCombo = qobject_cast(ui->tableCondFormats->itemWidget(item, ColumnFont)); + QSpinBox* sizeBox = qobject_cast(ui->tableCondFormats->itemWidget(item, ColumnSize)); + QFont font = fontCombo->currentFont(); + font.setPointSize(sizeBox->value()); + font.setBold(item->checkState(ColumnBold) == Qt::Checked); + font.setItalic(item->checkState(ColumnItalic) == Qt::Checked); + font.setUnderline(item->checkState(ColumnUnderline) == Qt::Checked); + QComboBox* alignCombo = qobject_cast(ui->tableCondFormats->itemWidget(item, ColumnAlignment)); + + result.emplace_back(item->text(ColumnFilter), + item->background(ColumnForeground).color(), + item->background(ColumnBackground).color(), + font, + static_cast(alignCombo->currentIndex()), + m_encoding); + } + return result; +} + + +void CondFormatManager::itemClicked(QTreeWidgetItem* item, int column) +{ + switch (column) { + case ColumnForeground: + case ColumnBackground: { + QColor color = QColorDialog::getColor(item->background(column).color(), this); + if(color.isValid()) { + item->setTextColor(column, color); + item->setBackgroundColor(column, color); + } + break; + } + case ColumnBold: + case ColumnItalic: + case ColumnUnderline: + item->setCheckState(column, item->checkState(column) != Qt::Checked ? Qt::Checked : Qt::Unchecked); + break; + default: + // Nothing to do + break; + } +} + +void CondFormatManager::on_buttonBox_clicked(QAbstractButton* button) +{ + if (button == ui->buttonBox->button(QDialogButtonBox::Cancel)) + reject(); + else if (button == ui->buttonBox->button(QDialogButtonBox::Ok)) + accept(); + else if (button == ui->buttonBox->button(QDialogButtonBox::Help)) + QDesktopServices::openUrl(QUrl("https://github.com/sqlitebrowser/sqlitebrowser/wiki/Conditional-Formats")); + else if (button == ui->buttonBox->button(QDialogButtonBox::Reset)) { + if (QMessageBox::warning(this, + QApplication::applicationName(), + tr("Are you sure you want to clear all the conditional formats of this field?"), + QMessageBox::Reset | QMessageBox::Cancel, + QMessageBox::Cancel) == QMessageBox::Reset) + if(ui->tableCondFormats->model()->hasChildren()) + ui->tableCondFormats->model()->removeRows(0, ui->tableCondFormats->model()->rowCount()); + } +} diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/CondFormatManager.h b/src/WBCLFZSystemModule/SqliteDBProcess/src/CondFormatManager.h new file mode 100644 index 0000000..bf0e284 --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/CondFormatManager.h @@ -0,0 +1,56 @@ +#ifndef CONDFORMATMANAGER_H +#define CONDFORMATMANAGER_H + +#include +#include + +#include "Palette.h" + +namespace Ui { + class CondFormatManager; +} + +class CondFormat; +class QTreeWidgetItem; +class QAbstractButton; + +class CondFormatManager : public QDialog +{ + Q_OBJECT + +public: + explicit CondFormatManager(const std::vector& condFormats, const QString& encoding, QWidget *parent = nullptr); + ~CondFormatManager() override; + + std::vector getCondFormats() const; +private: + enum Columns { + ColumnForeground = 0, + ColumnBackground, + ColumnFont, + ColumnSize, + ColumnBold, + ColumnItalic, + ColumnUnderline, + ColumnAlignment, + ColumnFilter + }; + Ui::CondFormatManager *ui; + std::vector m_condFormats; + Palette m_condFormatPalette; + QString m_encoding; + +private slots: + void addNewItem(); + void addItem(const CondFormat& aCondFormat); + void removeItem(); + void moveItem(int offset); + void upItem(); + void downItem(); + void on_buttonBox_clicked(QAbstractButton* button); + +public slots: + void itemClicked(QTreeWidgetItem* item, int column); +}; + +#endif // CONDFORMATMANAGER_H diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/CondFormatManager.ui b/src/WBCLFZSystemModule/SqliteDBProcess/src/CondFormatManager.ui new file mode 100644 index 0000000..41ead4d --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/CondFormatManager.ui @@ -0,0 +1,279 @@ + + + CondFormatManager + + + + 0 + 0 + 750 + 400 + + + + Conditional Format Manager + + + + + + This dialog allows creating and editing conditional formats. Each cell style will be selected by the first accomplished condition for that cell data. Conditional formats can be moved up and down, where those at higher rows take precedence over those at lower. Syntax for conditions is the same as for filters and an empty condition applies to all values. + + + true + + + + + + + + + Add new conditional format + + + &Add + + + + :/icons/field_add:/icons/field_add + + + Qt::ToolButtonTextBesideIcon + + + true + + + + + + + Remove selected conditional format + + + &Remove + + + + :/icons/field_delete:/icons/field_delete + + + Qt::ToolButtonTextBesideIcon + + + true + + + + + + + Move selected conditional format up + + + Move &up + + + + :/icons/up:/icons/up + + + Qt::ToolButtonTextBesideIcon + + + true + + + + + + + Move selected conditional format down + + + Move &down + + + + :/icons/down:/icons/down + + + Qt::ToolButtonTextBesideIcon + + + true + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + QAbstractScrollArea::AdjustToContents + + + QAbstractItemView::AllEditTriggers + + + true + + + QAbstractItemView::SelectItems + + + 0 + + + false + + + true + + + false + + + false + + + 25 + + + + Foreground + + + Text color + + + + + Background + + + Background color + + + + + Font + + + + + Size + + + + + + + + Bold + + + + :/icons/text_bold.png:/icons/text_bold.png + + + + + + + + Italic + + + + :/icons/text_italic.png:/icons/text_italic.png + + + + + + + + Underline + + + + :/icons/text_underline.png:/icons/text_underline.png + + + + + Alignment + + + + + Condition + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Help|QDialogButtonBox::Ok|QDialogButtonBox::Reset + + + + + + + + + + + buttonBox + accepted() + CondFormatManager + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + CondFormatManager + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/DBsqliconwin.ico b/src/WBCLFZSystemModule/SqliteDBProcess/src/DBsqliconwin.ico new file mode 100644 index 0000000000000000000000000000000000000000..12063c9755382d2282b976e388cfd4d8513181cd GIT binary patch literal 21662 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 OKY!1_dj|gh82E3Umc;@9 literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/DBsqliconwin.jpg b/src/WBCLFZSystemModule/SqliteDBProcess/src/DBsqliconwin.jpg new file mode 100644 index 0000000000000000000000000000000000000000..751c65f69495fac250549cdcecc456ecad70215d GIT binary patch literal 1662 zcmbu+dpOg390%~Pi~8l@r)3OAwp&@5e=cot>%&*o92?sArjgt znoBsXLKhAWW0*KDX(?rfnT_pmI#1_$&R^#_eZJ54kI(b{eBaOW`hJC@!YM$~-WF*K zfIuK1c54B`ap2^3_g%Fe@?8Pjmxa#&DKS6|Py>VZ10qr&uoOtx38(@9Nc3wq@OObk zz!1?LP_doj5?cd}l7I*Z3>JZaMMWWyt?9(Aa{wYGDy@FZa)*qwA9R1@9=+t;axo37 z`scDP1FQr3{!uAA#pUGpDk#D=4<6F`(ZJBi_^0D0C#`L4PuU^uUC+3=pY=HBc_AP$ z=wdJ?wlunSD3+p7~+^;}Uy$WtFqWUFU7PKmhpLlYNE#%O$nt5`jR# z5a_lGB!b)8U@3^G`mr6-md;SWNSXb5$zpq~a?9(V@6^zDVafVO4T#GfFqnofZPWge z{Wn<3|B`)!{o`T)yTG8W&jU*V2taV-i@+ekW3z&SH;bs_c664?vz+ir14gM+s^aJ) zC3W-1(7l*_3<0Hy5JKpWrw_ihQ7OdTvk8mP#vaJmBeC0Yr@3%e5-$!uB2dA!4tEd& zTSgj{u^y#XUfK)1>*S~?q}dhb2aD`Ye1hc^oV$Bk0Df}Zo>;PcBhY;u`2`ECL@n9*Hi^+f<9i@Vix5g zUIo6CpPFzy(4yv-SXkGZkul4rf&r`%gX7=IxyM(vbKC`i{lr>}dQMl`3F5eE9C^Ke z*4vj;Le=x+T8XV(R+CWXG+zys#YL?DW)z_gBvek9y$3`i3eNWMsL!2lHK4IR#@zm; z%=gQd0~@9@rgaa0n5X&LR84%L1*IsR3v6k%YcjPf|2gMb|D^zrS%RToX`EZNf~{U2 zF$#H=T;ns|vasrog15zM#M0WDjrE+v`|O>p+mMy3eE#D#KIexe-}F$##YORX6>3u4v04+xOg!n-Ky7A_P+}fmJfUx-3x-wn1b%#^w+#%h>-#MJ zDw=U#+qtPQI=4Jvm%v>ouRXj<@gTcH)*o`X<1AeWh$k51_y$}ZSUOd@9X{iA3l@u6 zRA&i+PAY8P<&(ue>OkNV5_?b?>sU`>b}G8p1#)V%p<|RDvW^4RF1(1%K+ZM$W*{)C zc!6}=((XASko?p%;RtK9xV|&1D)zDa^+~~?$1Hmy&18kMY!#GyjsX(C{klg5nA|gG zh*M%5{`@MYyZDTkV{b^Sm+fl3M}cz8sdn5P{!D%* zlR&fCtZs+LD0h68D}$|+Akag7?AcHkOshpDKWB-66dyH%tn>azp|TwMGpPy*IC=a= zpl+8p&aQj2y918I_hdQEcRkc>l!7tp4vQs{}=E!Kv;S@=?t0bTWK32CP6*FH} z9p~GJ%M`l|*U;|KkeWlDF3u6&XyS+ig*bU9lbJUmTS?yQTBhIH;M;!F_#J~8`Jovh G9QzZY*WWJy literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/Data.cpp b/src/WBCLFZSystemModule/SqliteDBProcess/src/Data.cpp new file mode 100644 index 0000000..3429bd8 --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/Data.cpp @@ -0,0 +1,157 @@ +#include "Data.h" + +#include +#include +#include +#include +#include + +#include + +// Note that these aren't all possible BOMs. But they are probably the most common ones. +// The size is needed at least for the ones with character zero in them. +static const QByteArray bom3("\xEF\xBB\xBF", 3); +static const QByteArray bom2a("\xFE\xFF", 2); +static const QByteArray bom2b("\xFF\xFE", 2); +static const QByteArray bom4a("\x00\x00\xFE\xFF", 4); +static const QByteArray bom4b("\xFF\xFE\x00\x00", 4); + +bool isTextOnly(QByteArray data, const QString& encoding, bool quickTest) +{ + // If the data starts with a Unicode BOM, we can use detection provided by QTextCodec. + if(startsWithBom(data)) { + QTextCodec *codec = encoding.isEmpty()? QTextCodec::codecForName("UTF-8") : QTextCodec::codecForName(encoding.toUtf8()); + QTextCodec *detectedCodec = QTextCodec::codecForUtfText(data, nullptr); + return detectedCodec == codec; + } + + // Truncate to the first few bytes for quick testing + int testSize = quickTest? std::min(512, data.size()) : data.size(); + + // If the quick test has been requested and we have to truncate the string, we have to use + // an approach where truncated multibyte characters are not interpreted as invalid characters. + if(quickTest && data.size() > testSize) { + + // We can assume that the default encoding (UTF-8) and all the ISO-8859 + // cannot contain character zero. + // This has to be checked explicitly because toUnicode() is using zero as + // a terminator for these encodings. + if((encoding.isEmpty() || encoding.startsWith("ISO-8859")) && data.contains('\0')) + return false; + + QTextCodec::ConverterState state; + QTextCodec *codec = encoding.isEmpty()? QTextCodec::codecForName("UTF-8") : QTextCodec::codecForName(encoding.toUtf8()); + codec->toUnicode(data.constData(), testSize, &state); + return state.invalidChars == 0; + } else { + // Convert to Unicode if necessary + data = decodeString(data, encoding); + // Perform check + return QString(data).toUtf8() == data; + } +} + +bool containsRightToLeft(const QString& text) { + + for(QChar ch : text) { + switch(ch.direction()) { + case QChar::DirR: + case QChar::DirAL: + case QChar::DirRLE: + case QChar::DirRLO: + case QChar::DirRLI: + return true; + default: + break; + } + } + return false; +} + +bool startsWithBom(const QByteArray& data) +{ + if(data.startsWith(bom3) || + data.startsWith(bom2a) || data.startsWith(bom2b) || + data.startsWith(bom4a) || data.startsWith(bom4b)) + return true; + else + return false; +} + +QByteArray removeBom(QByteArray& data) +{ + if(data.startsWith(bom3)) + { + QByteArray bom = data.left(3); + data.remove(0, 3); + return bom; + } else if(data.startsWith(bom2a) || data.startsWith(bom2b)) { + QByteArray bom = data.left(2); + data.remove(0, 2); + return bom; + } else if(data.startsWith(bom4a) || data.startsWith(bom4b)) { + QByteArray bom = data.left(4); + data.remove(0, 4); + return bom; + } else { + return QByteArray(); + } +} + +QString isImageData(const QByteArray& data) +{ + // Check if it's an image. First do a quick test by calling canRead() which only checks the first couple of bytes or so. Only if + // that returned true, do a more sophisticated test of the data. This way we get both, good performance and proper data checking. + QBuffer imageBuffer(const_cast(&data)); + QImageReader readerBuffer(&imageBuffer); + QString imageFormat = readerBuffer.format(); + if(readerBuffer.canRead() && !readerBuffer.read().isNull()) + return imageFormat; + else + return QString(); +} + +QStringList toStringList(const QList& list) { + QStringList strings; + for (const QByteArray &item : list) { + strings.append(QString::fromUtf8(item)); + } + return strings; +} + +QByteArray encodeString(const QByteArray& str, const QString& encoding) +{ + if(encoding.isEmpty()) + return str; + else + return QTextCodec::codecForName(encoding.toUtf8())->fromUnicode(str); +} + +QByteArray decodeString(const QByteArray& str, const QString& encoding) +{ + if(encoding.isEmpty()) + return str; + else + return QTextCodec::codecForName(encoding.toUtf8())->toUnicode(str).toUtf8(); +} + +QString humanReadableSize(unsigned long byteCount) +{ + static const std::vector units = {"B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB"}; + + double size = static_cast(byteCount); + for(const QString& unit : units) + { + if(size < 1024.0) + return QString::number(size, 'f', 2) + " " + unit; + + size /= 1024.0; + } + + return QString::number(size, 'f', 2) + " YiB"; +} + +QString isoDateTimeStringToLocalDateTimeString(const QString& date_string) +{ + return QLocale::system().toString(QDateTime::fromString(date_string, Qt::ISODate).toLocalTime(), QLocale::ShortFormat); +} diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/Data.h b/src/WBCLFZSystemModule/SqliteDBProcess/src/Data.h new file mode 100644 index 0000000..8284588 --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/Data.h @@ -0,0 +1,37 @@ +#ifndef DATA_H +#define DATA_H + +#include +#include + +// This returns false if the data in the data parameter contains binary data. If it is text only, the function returns +// true. If the second parameter is specified, it will be used to convert the data from the given encoding to Unicode +// before doing the check. The third parameter can be used to only check the first couple of bytes which speeds up the +// text but makes it less reliable +bool isTextOnly(QByteArray data, const QString& encoding = QString(), bool quickTest = false); + +// This returns true if text contains some character whose direction is right-to-left. +bool containsRightToLeft(const QString& text); + +// This function returns true if the data in the data parameter starts with a Unicode BOM. Otherwise it returns false. +bool startsWithBom(const QByteArray& data); + +// This function checks if the data in the data parameter starts with a Unicode BOM. If so, the BOM is removed from the +// byte array and passed back to the caller separately as the return value of the function. If the data does not start +// with a BOM an empty byte array is returned and the original data is not modified. +QByteArray removeBom(QByteArray& data); + +// Check if a byte array contains an image. Returns the name of the image format for images or a null string for non-image data. +QString isImageData(const QByteArray& data); + +QStringList toStringList(const QList& list); + +QByteArray encodeString(const QByteArray& str, const QString& encoding); + +QByteArray decodeString(const QByteArray& str, const QString& encoding); + +QString humanReadableSize(unsigned long byteCount); + +QString isoDateTimeStringToLocalDateTimeString(const QString& date_string); + +#endif diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/DbStructureModel.cpp b/src/WBCLFZSystemModule/SqliteDBProcess/src/DbStructureModel.cpp new file mode 100644 index 0000000..22c2157 --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/DbStructureModel.cpp @@ -0,0 +1,429 @@ +#include "DbStructureModel.h" +#include "IconCache.h" +#include "sqlitedb.h" +#include "sqlitetablemodel.h" +#include "Settings.h" + +#include +#include +#include +#include +#include +#include + +DbStructureModel::DbStructureModel(DBBrowserDB& db, QObject* parent) + : QAbstractItemModel(parent), + m_db(db), + browsablesRootItem(nullptr), + m_dropQualifiedNames(false), + m_dropEnquotedNames(false) +{ + // Create root item and use its columns to store the header strings + QStringList header; + header << tr("Name") << tr("Object") << tr("Type") << tr("Schema") << tr("Database"); + rootItem = new QTreeWidgetItem(header); +} + +DbStructureModel::~DbStructureModel() +{ + delete rootItem; +} + +int DbStructureModel::columnCount(const QModelIndex&) const +{ + return rootItem->columnCount(); +} + +QVariant DbStructureModel::data(const QModelIndex& index, int role) const +{ + if(!index.isValid()) + return QVariant(); + + // Get the item the index points at + QTreeWidgetItem* item = static_cast(index.internalPointer()); + + // Depending on the role either return the text or the icon + switch(role) + { + case Qt::DisplayRole: + // For the display role and the browsable branch of the tree we want to show the column name including the schema name if necessary (i.e. + // for schemata != "main"). For the normal structure branch of the tree we don't want to add the schema name because it's already obvious from + // the position of the item in the tree. + if(index.column() == ColumnName && item->parent() == browsablesRootItem) + return QString::fromStdString(sqlb::ObjectIdentifier(item->text(ColumnSchema).toStdString(), item->text(ColumnName).toStdString()).toDisplayString()); + else + return Settings::getValue("db", "hideschemalinebreaks").toBool() ? item->text(index.column()).simplified() : item->text(index.column()); + case Qt::EditRole: + return item->text(index.column()); + case Qt::ToolTipRole: { + // Show the original text but limited, when it's supposed to be shown in a tooltip + QString text = item->text(index.column()); + if (text.length() > 512) { + text.truncate(509); + text.append("..."); + } + return text; + } + case Qt::DecorationRole: + return item->icon(index.column()); + default: + return QVariant(); + } +} + +Qt::ItemFlags DbStructureModel::flags(const QModelIndex &index) const +{ + if(!index.isValid()) + return Qt::ItemIsDropEnabled; + + // All items are enabled and selectable + Qt::ItemFlags flags = Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDropEnabled; + + // Only enable dragging for SQLite objects and for fields (composition in SQL text editor). + // Grouping nodes have no type. + QString type = data(index.sibling(index.row(), ColumnObjectType), Qt::DisplayRole).toString(); + if(!type.isEmpty()) + flags |= Qt::ItemIsDragEnabled; + + return flags; +} + +QVariant DbStructureModel::headerData(int section, Qt::Orientation orientation, int role) const +{ + // Get the header string from the root item + if(orientation == Qt::Horizontal && role == Qt::DisplayRole) + return rootItem->data(section, role); + + return QVariant(); +} + +QModelIndex DbStructureModel::index(int row, int column, const QModelIndex& parent) const +{ + if(!hasIndex(row, column, parent)) + return QModelIndex(); + + QTreeWidgetItem *parentItem; + if(!parent.isValid()) + parentItem = rootItem; + else + parentItem = static_cast(parent.internalPointer()); + + QTreeWidgetItem* childItem = parentItem->child(row); + if(childItem) + return createIndex(row, column, childItem); + else + return QModelIndex(); +} + +QModelIndex DbStructureModel::parent(const QModelIndex& index) const +{ + if(!index.isValid()) + return QModelIndex(); + + QTreeWidgetItem* childItem = static_cast(index.internalPointer()); + QTreeWidgetItem* parentItem = childItem->parent(); + + if(parentItem == rootItem) + return QModelIndex(); + else + return createIndex(0, 0, parentItem); +} + +int DbStructureModel::rowCount(const QModelIndex& parent) const +{ + if(parent.column() > 0) + return 0; + + if(!parent.isValid()) + return rootItem->childCount(); + else + return static_cast(parent.internalPointer())->childCount(); +} + +void DbStructureModel::reloadData() +{ + beginResetModel(); + + // Remove all data except for the root item + while(rootItem->childCount()) + delete rootItem->child(0); + + // Return here if no DB is opened + if(!m_db.isOpen()) + { + endResetModel(); + emit structureUpdated(); + return; + } + + // Create the nodes for browsables and for tables, indices, views and triggers. The idea here is to basically have two trees in one model: + // In the root node there are two nodes: 'browsables' and 'all'. The first node contains a list of all browsable objects, i.e. views and tables. + // The second node contains four sub-nodes (tables, indices, views and triggers), each containing a list of objects of that type. + // This way we only have to have and only have to update one model and can use it in all sorts of places, just by setting a different root node. + browsablesRootItem = new QTreeWidgetItem(rootItem); + browsablesRootItem->setIcon(ColumnName, IconCache::get("view")); + browsablesRootItem->setText(ColumnName, tr("Browsables")); + + // Make sure to always load the main schema first + QTreeWidgetItem* itemAll = new QTreeWidgetItem(rootItem); + itemAll->setIcon(ColumnName, IconCache::get("database")); + itemAll->setText(ColumnName, tr("All")); + itemAll->setText(ColumnObjectType, "database"); + buildTree(itemAll, "main"); + + // Add the temporary database as a node if it isn't empty. Make sure it's always second if it exists. + if(!m_db.schemata["temp"].empty()) + { + QTreeWidgetItem* itemTemp = new QTreeWidgetItem(itemAll); + itemTemp->setIcon(ColumnName, IconCache::get("database")); + itemTemp->setText(ColumnName, tr("Temporary")); + itemTemp->setText(ColumnObjectType, "database"); + buildTree(itemTemp, "temp"); + } + + // Now load all the other schemata last + for(const auto& it : m_db.schemata) + { + // Don't load the main and temp schema again + if(it.first != "main" && it.first != "temp") + { + QTreeWidgetItem* itemSchema = new QTreeWidgetItem(itemAll); + itemSchema->setIcon(ColumnName, IconCache::get("database")); + itemSchema->setText(ColumnName, QString::fromStdString(it.first)); + itemSchema->setText(ColumnObjectType, "database"); + buildTree(itemSchema, it.first); + } + } + + // Refresh the view + endResetModel(); + emit structureUpdated(); +} + +QStringList DbStructureModel::mimeTypes() const +{ + QStringList types; + types << "text/plain"; + return types; +} + +QMimeData* DbStructureModel::mimeData(const QModelIndexList& indices) const +{ + // We store the SQL data and the names data separately + QByteArray sqlData, namesData; + + // Loop through selected indices + for(const QModelIndex& index : indices) + { + // Get the item the index points at + QTreeWidgetItem* item = static_cast(index.internalPointer()); + + // Only export data for valid indices and only once per row (SQL column or Name column). + if(index.isValid()) { + QString objectType = data(index.sibling(index.row(), ColumnObjectType), Qt::DisplayRole).toString(); + + // For names, export a (qualified) (escaped) identifier of the item for statement composition in SQL editor. + if(objectType == "field") + namesData.append(getNameForDropping(item->text(ColumnSchema), item->parent()->text(ColumnName), item->text(ColumnName))); + else if(objectType == "database") + namesData.append(getNameForDropping(item->text(ColumnName), "", "")); + else if(!objectType.isEmpty()) + namesData.append(getNameForDropping(item->text(ColumnSchema), item->text(ColumnName), "")); + + if(objectType != "field" && index.column() == ColumnSQL) + { + // Add the SQL code used to create the object + sqlData.append(data(index, Qt::DisplayRole).toString() + ";\n"); + + // If it is a table also add the content + if(objectType == "table") + { + SqliteTableModel tableModel(m_db); + sqlb::ObjectIdentifier objid(data(index.sibling(index.row(), ColumnSchema), Qt::DisplayRole).toString().toStdString(), + data(index.sibling(index.row(), ColumnName), Qt::DisplayRole).toString().toStdString()); + tableModel.setQuery(sqlb::Query(objid)); + if(tableModel.completeCache()) + { + // Only continue if all data was fetched + + for(int i=0; i < tableModel.rowCount(); ++i) + { + QString insertStatement = "INSERT INTO " + QString::fromStdString(objid.toString()) + " VALUES("; + for(int j=1; j < tableModel.columnCount(); ++j) + insertStatement += QString("'%1',").arg(tableModel.data(tableModel.index(i, j), Qt::EditRole).toString()); + insertStatement.chop(1); + insertStatement += ");\n"; + sqlData.append(insertStatement); + } + } + } + } + } + } + + // Create the MIME data object + QMimeData* mime = new QMimeData(); + mime->setProperty("db_file", m_db.currentFile()); // Also save the file name to avoid dropping an object on the same database as it comes from + // When we have both SQL and Names data (probable row selection mode) we give precedence to the SQL data + if (sqlData.length() == 0 && namesData.length() > 0) { + // Remove last ", " or "." + if (namesData.endsWith(", ")) + namesData.chop(2); + else if (namesData.endsWith(".")) + namesData.chop(1); + + mime->setData("text/plain", namesData); + } else + mime->setData("text/plain", sqlData); + return mime; +} + +bool DbStructureModel::dropMimeData(const QMimeData* data, Qt::DropAction action, int, int, const QModelIndex&) +{ + if(action == Qt::IgnoreAction) + return true; + + if(!data->hasFormat("text/plain")) + return false; + + if(data->property("db_file") == m_db.currentFile()) + return false; + + // Get data + QByteArray d = data->data("text/plain"); + + // Try to execute the SQL statement + if(m_db.executeMultiSQL(d, true, true)) + { + m_db.updateSchema(); + return true; + } else { + QMessageBox::warning(nullptr, QApplication::applicationName(), m_db.lastError()); + return false; + } +} + +static long calc_number_of_objects_by_type(const objectMap& objmap, const std::string& type) +{ + auto objects = objmap.equal_range(type); + if(objects.first == objmap.end()) + return 0; + else + return std::distance(objects.first, objects.second); +} + +void DbStructureModel::buildTree(QTreeWidgetItem* parent, const std::string& schema) +{ + // Build a map from object type to tree node to simplify finding the correct tree node later + std::unordered_map typeToParentItem; + + // Get object map for the given schema + objectMap objmap = m_db.schemata[schema]; + + // Prepare tree + QTreeWidgetItem* itemTables = new QTreeWidgetItem(parent); + itemTables->setIcon(ColumnName, IconCache::get("table")); + itemTables->setText(ColumnName, tr("Tables (%1)").arg(calc_number_of_objects_by_type(objmap, "table"))); + typeToParentItem.insert({"table", itemTables}); + + QTreeWidgetItem* itemIndices = new QTreeWidgetItem(parent); + itemIndices->setIcon(ColumnName, IconCache::get("index")); + itemIndices->setText(ColumnName, tr("Indices (%1)").arg(calc_number_of_objects_by_type(objmap, "index"))); + typeToParentItem.insert({"index", itemIndices}); + + QTreeWidgetItem* itemViews = new QTreeWidgetItem(parent); + itemViews->setIcon(ColumnName, IconCache::get("view")); + itemViews->setText(ColumnName, tr("Views (%1)").arg(calc_number_of_objects_by_type(objmap, "view"))); + typeToParentItem.insert({"view", itemViews}); + + QTreeWidgetItem* itemTriggers = new QTreeWidgetItem(parent); + itemTriggers->setIcon(ColumnName, IconCache::get("trigger")); + itemTriggers->setText(ColumnName, tr("Triggers (%1)").arg(calc_number_of_objects_by_type(objmap, "trigger"))); + typeToParentItem.insert({"trigger", itemTriggers}); + + // Get all database objects and sort them by their name. + // This needs to be a multimap because SQLite allows views and triggers with the same name which means that names can appear twice. + std::multimap dbobjs; + for(const auto& it : objmap) + dbobjs.insert({it.second->name(), it.second}); + + // Add the database objects to the tree nodes + for(const auto& obj : dbobjs) + { + sqlb::ObjectPtr it = obj.second; + + // Object node + QTreeWidgetItem* item = addNode(typeToParentItem.at(sqlb::Object::typeToString(it->type())), it, schema); + + // If it is a table or view add the field nodes, add an extra node for the browsable section + if(it->type() == sqlb::Object::Types::Table || it->type() == sqlb::Object::Types::View) + addNode(browsablesRootItem, it, schema); + + // Add field nodes if there are any + sqlb::FieldInfoList fieldList = it->fieldInformation(); + if(!fieldList.empty()) + { + sqlb::StringVector pk_columns; + if(it->type() == sqlb::Object::Types::Table) + { + const auto pk = std::dynamic_pointer_cast(it)->primaryKey(); + if(pk) + pk_columns = pk->columnList(); + } + + for(const sqlb::FieldInfo& field : fieldList) + { + QTreeWidgetItem *fldItem = new QTreeWidgetItem(item); + bool isFK = false; + if(it->type() == sqlb::Object::Types::Table) + isFK = std::dynamic_pointer_cast(it)->constraint({field.name}, sqlb::Constraint::ForeignKeyConstraintType) != nullptr; + + fldItem->setText(ColumnName, QString::fromStdString(field.name)); + fldItem->setText(ColumnObjectType, "field"); + fldItem->setText(ColumnDataType, QString::fromStdString(field.type)); + fldItem->setText(ColumnSQL, QString::fromStdString(field.sql)); + fldItem->setText(ColumnSchema, QString::fromStdString(schema)); + if(contains(pk_columns, field.name)) + fldItem->setIcon(ColumnName, IconCache::get("field_key")); + else if(isFK) + fldItem->setIcon(ColumnName, IconCache::get("field_fk")); + else + fldItem->setIcon(ColumnName, IconCache::get("field")); + } + } + } +} + +QTreeWidgetItem* DbStructureModel::addNode(QTreeWidgetItem* parent, const sqlb::ObjectPtr& object, const std::string& schema) +{ + std::string type = sqlb::Object::typeToString(object->type()); + + QTreeWidgetItem *item = new QTreeWidgetItem(parent); + item->setIcon(ColumnName, IconCache::get(type)); + item->setText(ColumnName, QString::fromStdString(object->name())); + item->setText(ColumnObjectType, QString::fromStdString(type)); + item->setText(ColumnSQL, QString::fromStdString(object->originalSql())); + item->setText(ColumnSchema, QString::fromStdString(schema)); + + return item; +} + +QString DbStructureModel::getNameForDropping(const QString& domain, const QString& object, const QString& field) const +{ + // Take into account the drag&drop options for composing a name. Commas are included for composing a + // list of fields. A dot is added after other items, in order to allow composing a fully qualified name + // by selecting together and dropping a parent item and a child (e.g. select with control an attached + // database and a table, and drag and drop them to get "schema1"."table1".) Note that this only makes + // sense when the "Drop Qualified Names" option is not set. + QString name; + if ((domain != "main" && m_dropQualifiedNames) || object.isEmpty()) + name = m_dropEnquotedNames ? sqlb::escapeIdentifier(domain) + "." : domain + "."; + + if (!object.isEmpty() && (m_dropQualifiedNames || field.isEmpty())) + name += m_dropEnquotedNames ? sqlb::escapeIdentifier(object) + "." : object + "."; + + if (!field.isEmpty()) + name += m_dropEnquotedNames ? sqlb::escapeIdentifier(field) + ", " : field + ", "; + + return name; +} diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/DbStructureModel.h b/src/WBCLFZSystemModule/SqliteDBProcess/src/DbStructureModel.h new file mode 100644 index 0000000..73e1a93 --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/DbStructureModel.h @@ -0,0 +1,60 @@ +#ifndef DBSTRUCTUREMODEL_H +#define DBSTRUCTUREMODEL_H + +#include +#include + +class DBBrowserDB; +class QTreeWidgetItem; +namespace sqlb { class Object; using ObjectPtr = std::shared_ptr; } + +class DbStructureModel : public QAbstractItemModel +{ + Q_OBJECT + +public: + explicit DbStructureModel(DBBrowserDB& db, QObject* parent = nullptr); + ~DbStructureModel() override; + + QVariant data(const QModelIndex& index, int role) const override; + Qt::ItemFlags flags(const QModelIndex& index) const override; + QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override; + QModelIndex index(int row, int column, const QModelIndex& parent = QModelIndex()) const override; + QModelIndex parent(const QModelIndex& index) const override; + int rowCount(const QModelIndex& parent = QModelIndex()) const override; + int columnCount(const QModelIndex& = QModelIndex()) const override; + + QStringList mimeTypes() const override; + QMimeData* mimeData(const QModelIndexList& indices) const override; + bool dropMimeData(const QMimeData* data, Qt::DropAction action, int row, int column, const QModelIndex& parent) override; + + enum Columns + { + ColumnName, + ColumnObjectType, + ColumnDataType, + ColumnSQL, + ColumnSchema, + }; + +public slots: + void reloadData(); + void setDropQualifiedNames(bool value) { m_dropQualifiedNames = value; } + void setDropEnquotedNames(bool value) { m_dropEnquotedNames = value; } + +signals: + void structureUpdated(); + +private: + DBBrowserDB& m_db; + QTreeWidgetItem* rootItem; + QTreeWidgetItem* browsablesRootItem; + bool m_dropQualifiedNames; + bool m_dropEnquotedNames; + + void buildTree(QTreeWidgetItem* parent, const std::string& schema); + QTreeWidgetItem* addNode(QTreeWidgetItem* parent, const sqlb::ObjectPtr& object, const std::string& schema); + QString getNameForDropping(const QString& domain, const QString& object, const QString& field) const; +}; + +#endif diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/DotenvFormat.cpp b/src/WBCLFZSystemModule/SqliteDBProcess/src/DotenvFormat.cpp new file mode 100644 index 0000000..8e4361e --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/DotenvFormat.cpp @@ -0,0 +1,28 @@ +#include "DotenvFormat.h" + +#include +#include + +bool DotenvFormat::readEnvFile(QIODevice &device, QSettings::SettingsMap &map) +{ + QTextStream in(&device); + + QString line; + + QRegularExpression keyValueRegex("^\\s*([\\w\\.\\-]+)\\s*=\\s*(.*)\\s*$"); + + while (in.readLineInto(&line)) { + QRegularExpressionMatch match = keyValueRegex.match(line); + + if (match.capturedLength() < 3) { + continue; + } + + QString key = match.captured(1); + QString value = match.captured(2); + + map.insert(key, value); + } + + return true; +} diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/DotenvFormat.h b/src/WBCLFZSystemModule/SqliteDBProcess/src/DotenvFormat.h new file mode 100644 index 0000000..8835754 --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/DotenvFormat.h @@ -0,0 +1,14 @@ +#ifndef DOTENVFORMAT_H +#define DOTENVFORMAT_H + +#include + +class QIODevice; + +class DotenvFormat +{ +public: + static bool readEnvFile(QIODevice &device, QSettings::SettingsMap &map); +}; + +#endif // DOTENVFORMAT_H diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/EditDialog.cpp b/src/WBCLFZSystemModule/SqliteDBProcess/src/EditDialog.cpp new file mode 100644 index 0000000..08fe58f --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/EditDialog.cpp @@ -0,0 +1,1258 @@ +#include "EditDialog.h" +#include "ui_EditDialog.h" +#include "sqlitedb.h" +#include "Settings.h" +#include "qhexedit.h" +#include "docktextedit.h" +#include "FileDialog.h" +#include "Data.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +using json = nlohmann::json; + +EditDialog::EditDialog(QWidget* parent) + : QDialog(parent), + ui(new Ui::EditDialog), + m_currentIndex(QModelIndex()), + dataSource(SciBuffer), + dataType(Null), + isReadOnly(true) +{ + ui->setupUi(this); + + // Add Ctrl-Enter (Cmd-Enter on OSX) as a shortcut for the Apply button + ui->buttonApply->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Return)); + ui->buttonApply->setToolTip(ui->buttonApply->toolTip() + " [" + ui->buttonApply->shortcut().toString(QKeySequence::NativeText) + "]"); + + QHBoxLayout* hexLayout = new QHBoxLayout(ui->editorBinary); + hexEdit = new QHexEdit(this); + hexLayout->addWidget(hexEdit); + hexEdit->setOverwriteMode(false); + + QHBoxLayout* sciLayout = new QHBoxLayout(ui->editorSci); + sciEdit = new DockTextEdit(this); + sciLayout->addWidget(sciEdit); + + QShortcut* ins = new QShortcut(QKeySequence(Qt::Key_Insert), this); + connect(ins, &QShortcut::activated, this, &EditDialog::toggleOverwriteMode); + + connect(sciEdit, &DockTextEdit::textChanged, this, &EditDialog::updateApplyButton); + connect(sciEdit, &DockTextEdit::textChanged, this, &EditDialog::editTextChanged); + connect(ui->qtEdit, &QTextEdit::textChanged, this, &EditDialog::updateApplyButton); + connect(hexEdit, &QHexEdit::dataChanged, this, &EditDialog::updateApplyButton); + + // Create shortcuts for the widgets that doesn't have its own print action or printing mechanism. + QShortcut* shortcutPrint = new QShortcut(QKeySequence::Print, this, nullptr, nullptr, Qt::WidgetShortcut); + connect(shortcutPrint, &QShortcut::activated, this, &EditDialog::openPrintDialog); + + // Add actions to editors that have a context menu based on actions. This also activates the shortcuts. + ui->editorImage->addAction(ui->actionPrintImage); + ui->editorBinary->addAction(ui->actionPrint); + ui->editorBinary->addAction(ui->actionCopyHexAscii); + + // Set up popup menus + QMenu* popupImportFileMenu = new QMenu(this); + popupImportFileMenu->addAction(ui->actionImportInMenu); + popupImportFileMenu->addAction(ui->actionImportAsLink); + ui->actionImport->setMenu(popupImportFileMenu); + + connect(ui->actionImportAsLink, &QAction::triggered, this, [&]() { + importData(/* asLink */ true); + }); + + connect(ui->actionOpenInApp, &QAction::triggered, this, [&]() { + switch (dataSource) { + case SciBuffer: + emit requestUrlOrFileOpen(sciEdit->text()); + break; + case QtBuffer: + emit requestUrlOrFileOpen(ui->qtEdit->toPlainText()); + break; + default: + return; + } + }); + connect(ui->actionOpenInExternal, &QAction::triggered, this, &EditDialog::openDataWithExternal); + + mustIndentAndCompact = Settings::getValue("databrowser", "indent_compact").toBool(); + ui->actionIndent->setChecked(mustIndentAndCompact); + + ui->buttonAutoSwitchMode->setChecked(Settings::getValue("databrowser", "auto_switch_mode").toBool()); + ui->actionWordWrap->setChecked(Settings::getValue("databrowser", "editor_word_wrap").toBool()); + setWordWrapping(ui->actionWordWrap->isChecked()); + + reloadSettings(); +} + +EditDialog::~EditDialog() +{ + Settings::setValue("databrowser", "indent_compact", mustIndentAndCompact); + Settings::setValue("databrowser", "auto_switch_mode", ui->buttonAutoSwitchMode->isChecked()); + Settings::setValue("databrowser", "editor_word_wrap", ui->actionWordWrap->isChecked()); + delete ui; +} + +void EditDialog::setCurrentIndex(const QModelIndex& idx) +{ + m_currentIndex = QPersistentModelIndex(idx); + + QByteArray bArrData = idx.data(Qt::EditRole).toByteArray(); + loadData(bArrData); + updateCellInfoAndMode(bArrData); + + ui->buttonApply->setDisabled(true); +} + +void EditDialog::showEvent(QShowEvent*) +{ + // Whenever the dialog is shown, position it at the center of the parent dialog + QMainWindow* parentDialog = qobject_cast(parent()); + if(parentDialog) + { + move(parentDialog->x() + parentDialog->width() / 2 - width() / 2, + parentDialog->y() + parentDialog->height() / 2 - height() / 2); + } +} + +void EditDialog::reject() +{ + // We override this, to ensure the Escape key doesn't make the Edit Cell + // dock go away + return; +} + +// Loads data from a cell into the Edit Cell window +void EditDialog::loadData(const QByteArray& bArrdata) +{ + QImage img; + + // Clear previously removed BOM + removedBom.clear(); + + // Determine the data type, saving that info in the class variable + dataType = checkDataType(bArrdata); + + // Get the current editor mode (eg text, hex, image, json or xml mode) + int editMode = ui->comboMode->currentIndex(); + + // Data type specific handling + switch (dataType) { + case Null: + // Set enabled the text widget + sciEdit->setEnabled(true); + switch (editMode) { + case TextEditor: + case JsonEditor: + case XmlEditor: + + // The JSON widget buffer is now the main data source + dataSource = SciBuffer; + + // Empty the text editor contents, then enable text editing + sciEdit->clear(); + + break; + + case RtlTextEditor: + // The text widget buffer is now the main data source + dataSource = QtBuffer; + + // Empty the Qt text editor contents, then enable text editing + ui->qtEdit->clear(); + + break; + + case HexEditor: + // The hex widget buffer is now the main data source + dataSource = HexBuffer; + + // Load the Null into the hex editor + hexEdit->setData(bArrdata); + + break; + + case ImageViewer: + // The hex widget buffer is now the main data source + dataSource = HexBuffer; + + // Clear any image from the image viewing widget + ui->editorImage->setPixmap(QPixmap(0,0)); + + // Load the Null into the hex editor + hexEdit->setData(bArrdata); + + break; + } + break; + + case Text: + case RtlText: + case JSON: + case XML: + // Can be stored in any widget, except the ImageViewer + + sciEdit->clearTextInMargin(); + + switch (editMode) { + case TextEditor: + case JsonEditor: + case XmlEditor: + setDataInBuffer(bArrdata, SciBuffer); + break; + case RtlTextEditor: + setDataInBuffer(bArrdata, QtBuffer); + break; + case HexEditor: + setDataInBuffer(bArrdata, HexBuffer); + break; + case ImageViewer: + // The image viewer cannot hold data nor display text. + + // Clear any image from the image viewing widget + ui->editorImage->setPixmap(QPixmap(0,0)); + + // Load the text into the text editor + setDataInBuffer(bArrdata, SciBuffer); + + break; + } + break; + + case Image: + // Image data is kept in the hex widget, mainly for safety. If we + // stored it in the editorImage widget instead, it would be a pixmap + // and there's no good way to restore that back to the original + // (pristine) image data. eg image metadata would be lost + setDataInBuffer(bArrdata, HexBuffer); + + // Update the display if in text edit or image viewer mode + switch (editMode) { + case TextEditor: + case XmlEditor: + case JsonEditor: + // Disable text editing, and use a warning message as the contents + sciEdit->setText(tr("Image data can't be viewed in this mode.") % '\n' % + tr("Try switching to Image or Binary mode.")); + sciEdit->setTextInMargin(tr("Image")); + sciEdit->setEnabled(false); + break; + + case RtlTextEditor: + // Disable text editing, and use a warning message as the contents + ui->qtEdit->setText(QString("" % + tr("Image data can't be viewed in this mode.") % "
" % + tr("Try switching to Image or Binary mode.") % + "
")); + ui->qtEdit->setEnabled(false); + break; + + case ImageViewer: + // Load the image into the image viewing widget + if (img.loadFromData(bArrdata)) { + ui->editorImage->setPixmap(QPixmap::fromImage(img)); + } + break; + } + break; + case SVG: + // Set the XML data in any buffer or update image in image viewer mode + switch (editMode) { + case TextEditor: + case JsonEditor: + case XmlEditor: + + setDataInBuffer(bArrdata, SciBuffer); + break; + + case HexEditor: + + setDataInBuffer(bArrdata, HexBuffer); + break; + + case ImageViewer: + // Set data in the XML (Sci) Buffer and load the SVG Image + setDataInBuffer(bArrdata, SciBuffer); + sciEdit->setLanguage(DockTextEdit::XML); + + // Load the image into the image viewing widget + if (img.loadFromData(bArrdata)) { + ui->editorImage->setPixmap(QPixmap::fromImage(img)); + } + break; + case RtlTextEditor: + setDataInBuffer(bArrdata, QtBuffer); + break; + } + break; + + default: + + // The data seems to be general binary data, which is always loaded + // into the hex widget (the only safe place for it) + + // Load the data into the hex buffer + setDataInBuffer(bArrdata, HexBuffer); + + switch (editMode) { + case TextEditor: + case JsonEditor: + case XmlEditor: + // Disable text editing, and use a warning message as the contents + sciEdit->setText(QString(tr("Binary data can't be viewed in this mode.") % '\n' % + tr("Try switching to Binary mode."))); + sciEdit->setTextInMargin(Settings::getValue("databrowser", "blob_text").toString()); + sciEdit->setEnabled(false); + break; + + case RtlTextEditor: + // Disable text editing, and use a warning message as the contents + ui->qtEdit->setText(QString("" % + tr("Binary data can't be viewed in this mode.") % "
" % + tr("Try switching to Binary mode.") % + "
")); + ui->qtEdit->setEnabled(false); + break; + + case ImageViewer: + // Clear any image from the image viewing widget + ui->editorImage->setPixmap(QPixmap(0,0)); + break; + } + } +} + +void EditDialog::importData(bool asLink) +{ + // Get list of supported image file formats to include them in the file dialog filter + QString image_formats; + QList image_formats_list = QImageReader::supportedImageFormats(); + for(int i=0;icomboMode->currentIndex(); + + // Set as selected filter the appropriate for the current mode. + switch (mode) { + case TextEditor: + case RtlTextEditor: + selectedFilter = FILE_FILTER_TXT; + break; + case HexEditor: + selectedFilter = FILE_FILTER_BIN; + break; + case ImageViewer: + selectedFilter = tr("Image files (%1)").arg(image_formats); + break; + case JsonEditor: + selectedFilter = FILE_FILTER_JSON; + break; + case XmlEditor: + selectedFilter = FILE_FILTER_XML; + break; + } + QString fileName = FileDialog::getOpenFileName( + OpenDataFile, + this, + tr("Choose a file to import") +#ifndef Q_OS_MAC // Filters on OS X are buggy + , filters.join(";;") + , &selectedFilter +#endif + ); + if(QFile::exists(fileName)) + { + if(asLink) { + QByteArray fileNameBa = fileName.toUtf8(); + loadData(fileNameBa); + updateCellInfoAndMode(fileNameBa); + } else { + QFile file(fileName); + if(file.open(QIODevice::ReadOnly)) + { + QByteArray d = file.readAll(); + loadData(d); + file.close(); + + // Update the cell data info in the bottom left of the Edit Cell + // and update mode (if required) to the just imported data type. + updateCellInfoAndMode(d); + } + } + } +} + +void EditDialog::exportData() +{ + QStringList filters; + switch (dataType) { + case Image: { + // Images get special treatment. + // Determine the likely filename extension. + QByteArray cellData = hexEdit->data(); + QBuffer imageBuffer(&cellData); + QImageReader imageReader(&imageBuffer); + QString imageFormat = imageReader.format(); + filters << tr("%1 Image").arg(imageFormat.toUpper()) % " (*." % imageFormat.toLower() % ")"; + break; + } + case Binary: + filters << tr("Binary files (*.bin)"); + break; + case RtlText: + case Text: + // Include the XML case on the text data type, since XML detection is not very sofisticated. + if (ui->comboMode->currentIndex() == XmlEditor) + filters << FILE_FILTER_XML + << FILE_FILTER_TXT; + else + filters << FILE_FILTER_TXT + << FILE_FILTER_XML; + break; + case JSON: + filters << FILE_FILTER_JSON; + break; + case SVG: + filters << FILE_FILTER_SVG; + break; + case XML: + filters << FILE_FILTER_XML; + break; + case Null: + return; + } + + if (dataSource == HexBuffer) + filters << FILE_FILTER_HEX; + + filters << FILE_FILTER_ALL; + + QString selectedFilter = filters.first(); + QString fileName = FileDialog::getSaveFileName( + CreateDataFile, + this, + tr("Choose a filename to export data"), + filters.join(";;"), + /* defaultFileName */ QString(), + &selectedFilter); + if(fileName.size() > 0) + { + QFile file(fileName); + if(file.open(QIODevice::WriteOnly)) + { + switch (dataSource) { + case HexBuffer: + // Data source is the hex buffer + // If text option has been selected, the readable representation of the content is saved to file. + if (selectedFilter == FILE_FILTER_HEX) + file.write(hexEdit->toReadableString().toUtf8()); + else + file.write(hexEdit->data()); + break; + case SciBuffer: + // Data source is the Scintilla buffer + file.write(sciEdit->text().toUtf8()); + break; + case QtBuffer: + // Data source is the text buffer + file.write(ui->qtEdit->toPlainText().toUtf8()); + break; + } + file.close(); + } + } +} + +void EditDialog::setNull() +{ + ui->qtEdit->clear(); + ui->editorImage->clear(); + hexEdit->setData(QByteArray()); + sciEdit->clear(); + dataType = Null; + removedBom.clear(); + + // The text editors don't know the difference between an empty string + // and a NULL, so we need to record NULL outside of that + dataType = Null; + + // Ensure the text (Scintilla) editor is enabled + sciEdit->setEnabled(true); + + // Update the cell data info in the bottom left of the Edit Cell + // The mode is also (if required) updated to text since it gives + // the better visual clue of containing a NULL value (placeholder). + updateCellInfoAndMode(hexEdit->data()); + + sciEdit->setFocus(); +} + +void EditDialog::updateApplyButton() +{ + if (!isReadOnly) + ui->buttonApply->setEnabled(true); +} + +bool EditDialog::promptInvalidData(const QString& data_type, const QString& errorString) +{ + QMessageBox::StandardButton reply = QMessageBox::question( + this, + tr("Invalid data for this mode"), + tr("The cell contains invalid %1 data. Reason: %2. Do you really want to apply it to the cell?").arg(data_type, errorString), + QMessageBox::Apply | QMessageBox::Cancel); + return (reply == QMessageBox::Apply); +} + +void EditDialog::accept() +{ + if(!m_currentIndex.isValid()) + return; + + if (dataType == Null) { + emit recordTextUpdated(m_currentIndex, hexEdit->data(), true); + return; + } + + // New data for the plain text cases. This is processed after the case. + QString newTextData; + + switch (dataSource) { + case QtBuffer: + newTextData = removedBom + ui->qtEdit->toPlainText(); + break; + case SciBuffer: + switch (sciEdit->language()) { + case DockTextEdit::PlainText: + newTextData = removedBom + sciEdit->text(); + break; + case DockTextEdit::JSON: + { + sciEdit->clearErrorIndicators(); + + QString oldData = m_currentIndex.data(Qt::EditRole).toString(); + + QString newData; + bool proceed = true; + json jsonDoc; + + try { + jsonDoc = json::parse(sciEdit->text().toStdString()); + } catch(json::parse_error& parseError) { + sciEdit->setErrorIndicator(static_cast(parseError.byte - 1)); + + proceed = promptInvalidData("JSON", parseError.what()); + } + + if (!jsonDoc.is_null()) { + if (mustIndentAndCompact) + // Compact the JSON data before storing + newData = QString::fromStdString(jsonDoc.dump()); + else + newData = sciEdit->text(); + } else { + newData = sciEdit->text(); + } + proceed = proceed && (oldData != newData); + + if (proceed) + // The data is different, so commit it back to the database + emit recordTextUpdated(m_currentIndex, newData.toUtf8(), false); + } + break; + case DockTextEdit::XML: + { + QString oldData = m_currentIndex.data(Qt::EditRole).toString(); + + QString newData; + QDomDocument xmlDoc; + QString errorMsg; + int errorLine, errorColumn; + + bool isValid = xmlDoc.setContent(sciEdit->text().toUtf8(), true, &errorMsg, &errorLine, &errorColumn); + bool proceed; + + sciEdit->clearErrorIndicators(); + if (!isValid) { + sciEdit->setErrorIndicator(errorLine-1, errorColumn-1, errorLine, 0); + newData = sciEdit->text(); + proceed = (oldData != newData && promptInvalidData("XML", errorMsg)); + } else { + if (mustIndentAndCompact) + // Compact the XML data before storing. If indent is -1, no whitespace at all is added. + newData = xmlDoc.toString(-1); + else + newData = sciEdit->text(); + proceed = (oldData != newData); + } + if (proceed) + // The data is different, so commit it back to the database + emit recordTextUpdated(m_currentIndex, newData.toUtf8(), false); + } + break; + } + break; + case HexBuffer: + // The data source is the hex widget buffer, thus binary data + QByteArray oldData = m_currentIndex.data(Qt::EditRole).toByteArray(); + QByteArray newData = hexEdit->data(); + if (newData != oldData) + emit recordTextUpdated(m_currentIndex, newData, true); + break; + } + + if (!newTextData.isEmpty()) { + + QString oldData = m_currentIndex.data(Qt::EditRole).toString(); + // Check first for null case, otherwise empty strings cannot overwrite NULL values + if ((m_currentIndex.data(Qt::EditRole).isNull() && dataType != Null) || oldData != newTextData) + // The data is different, so commit it back to the database + emit recordTextUpdated(m_currentIndex, removedBom + newTextData.toUtf8(), false); + } +} + +void EditDialog::setDataInBuffer(const QByteArray& bArrdata, DataSources source) +{ + dataSource = source; + QString textData; + + // 1) Perform validation and text formatting (if applicable). + // 2) Set the text in the corresponding editor widget (the text widget for the Image case). + // 3) Enable the widget. + switch (dataSource) { + case QtBuffer: + { + // Load the text into the text editor, remove BOM first if there is one + QByteArray dataWithoutBom = bArrdata; + removedBom = removeBom(dataWithoutBom); + + textData = QString::fromUtf8(dataWithoutBom.constData(), dataWithoutBom.size()); + ui->qtEdit->setPlainText(textData); + + // Select all of the text by default (this is useful for simple text data that we usually edit as a whole). + // We don't want this when the QtBuffer has been automatically switched due to the insertion of RTL text, + // (detected through the state of the apply button) otherwise that would break the typing flow of the user. + if (!isReadOnly) + { + if (!ui->buttonApply->isEnabled()) + ui->qtEdit->selectAll(); + else + ui->qtEdit->moveCursor(QTextCursor::End); + } + ui->qtEdit->setEnabled(true); + break; + } + case SciBuffer: + switch (sciEdit->language()) { + case DockTextEdit::PlainText: + { + // Load the text into the text editor, remove BOM first if there is one + QByteArray dataWithoutBom = bArrdata; + removedBom = removeBom(dataWithoutBom); + + textData = QString::fromUtf8(dataWithoutBom.constData(), dataWithoutBom.size()); + sciEdit->setText(textData); + + // Select all of the text by default (this is useful for simple text data that we usually edit as a whole) + if (!isReadOnly) + sciEdit->selectAll(); + sciEdit->setEnabled(true); + break; + } + case DockTextEdit::JSON: + { + sciEdit->clearErrorIndicators(); + + json jsonDoc; + + try { + jsonDoc = json::parse(std::string(bArrdata.constData(), static_cast(bArrdata.size()))); + } catch(json::parse_error& parseError) { + sciEdit->setErrorIndicator(static_cast(parseError.byte - 1)); + } + + if (mustIndentAndCompact && !jsonDoc.is_null() && !jsonDoc.is_discarded()) { + // Load indented JSON into the JSON editor + textData = QString::fromStdString(jsonDoc.dump(4)); + } else { + // Fallback case. The data is not yet valid JSON or no auto-formatting applied. + textData = QString::fromUtf8(bArrdata.constData(), bArrdata.size()); + } + + sciEdit->setText(textData); + sciEdit->setEnabled(true); + } + + break; + + case DockTextEdit::XML: + { + QString errorMsg; + int errorLine, errorColumn; + QDomDocument xmlDoc; + bool isValid = xmlDoc.setContent(bArrdata, true, &errorMsg, &errorLine, &errorColumn); + + if (mustIndentAndCompact && isValid) { + // Load indented XML into the XML editor + textData = xmlDoc.toString(Settings::getValue("editor", "tabsize").toInt()); + } else { + // Fallback case. The data is not yet valid JSON or no auto-formatting applied. + textData = QString::fromUtf8(bArrdata.constData(), bArrdata.size()); + } + sciEdit->setText(textData); + + sciEdit->clearErrorIndicators(); + if (!isValid) + // Adjust line and column by one (Scintilla starts at 1 and QDomDocument at 0) + sciEdit->setErrorIndicator(errorLine-1, errorColumn-1, errorLine, 0); + sciEdit->setEnabled(true); + + } + break; + } + break; + case HexBuffer: + hexEdit->setData(bArrdata); + hexEdit->setEnabled(true); + + break; + } + +} + +// Called when the user manually changes the "Mode" drop down combobox +void EditDialog::editModeChanged(int newMode) +{ + ui->actionIndent->setEnabled(newMode == JsonEditor || newMode == XmlEditor); + setStackCurrentIndex(newMode); + + // * If the dataSource is the text buffer, the data is always text * + switch (dataSource) { + case QtBuffer: + switch (newMode) { + case RtlTextEditor: // Switching to the RTL text editor + // Nothing to do, as the text is already in the Qt buffer + break; + + case TextEditor: // Switching to one of the Scintilla editor modes + case JsonEditor: + case XmlEditor: + + setDataInBuffer(ui->qtEdit->toPlainText().toUtf8(), SciBuffer); + break; + + case HexEditor: // Switching to the hex editor + // Convert the text widget buffer for the hex widget + // The hex widget buffer is now the main data source + setDataInBuffer(removedBom + ui->qtEdit->toPlainText().toUtf8(), HexBuffer); + break; + + case ImageViewer: + // Clear any image from the image viewing widget + ui->editorImage->setPixmap(QPixmap(0,0)); + break; + } + break; + case HexBuffer: + + // * If the dataSource is the hex buffer, the contents could be anything + // so we just pass it to our loadData() function to handle * + // Note that we have already set the editor, as loadData() relies on it + // being current + + // Load the data into the appropriate widget, as done by loadData() + loadData(hexEdit->data()); + break; + case SciBuffer: + switch (newMode) { + case RtlTextEditor: // Switching to the RTL text editor + // Convert the Scintilla widget buffer for the Qt widget + setDataInBuffer(sciEdit->text().toUtf8(), QtBuffer); + break; + case HexEditor: // Switching to the hex editor + // Convert the text widget buffer for the hex widget + setDataInBuffer(sciEdit->text().toUtf8(), HexBuffer); + break; + case ImageViewer: + { + // When SVG format, load the image, else clear it. + QByteArray bArrdata = sciEdit->text().toUtf8(); + dataType = checkDataType(bArrdata); + if (dataType == SVG) { + QImage img; + + if (img.loadFromData(bArrdata)) + ui->editorImage->setPixmap(QPixmap::fromImage(img)); + else + // Clear any image from the image viewing widget + ui->editorImage->setPixmap(QPixmap(0,0)); + } + } + break; + + case TextEditor: // Switching to the text editor + case JsonEditor: // Switching to the JSON editor + case XmlEditor: // Switching to the XML editor + // The text is already in the Sci buffer but we need to perform the necessary formatting. + setDataInBuffer(sciEdit->text().toUtf8(), SciBuffer); + + break; + } + } +} + +// Called for every keystroke in the text editor (only) +void EditDialog::editTextChanged() +{ + if (dataSource == SciBuffer || dataSource == QtBuffer) { + + // Update the cell info in the bottom left manually. This is because + // updateCellInfoAndMode() only works with QByteArray's (for now) + int dataLength; + bool isModified; + + if(dataSource == QtBuffer) { + // QtBuffer + dataLength = ui->qtEdit->toPlainText().length(); + isModified = ui->qtEdit->document()->isModified(); + } else { + // SciBuffer + dataLength = sciEdit->text().length(); + isModified = sciEdit->isModified(); + + // Switch to the Qt Editor if we detect right-to-left text, + // since the QScintilla editor does not support it. + if (containsRightToLeft(sciEdit->text())) + ui->comboMode->setCurrentIndex(RtlTextEditor); + } + + // If data has been entered in the text editor, it can't be a NULL + // any more. It hasn't been validated yet, so it cannot be JSON nor XML. + if (dataType == Null && isModified && dataLength != 0) + dataType = Text; + + if (dataType != Null) + ui->labelType->setText(tr("Type of data currently in cell: Text / Numeric")); + ui->labelSize->setText(tr("%n character(s)", "", dataLength)); + } +} + +void EditDialog::setMustIndentAndCompact(bool enable) +{ + mustIndentAndCompact = enable; + + // Indent or compact if necessary. If data has changed (button Apply indicates so), reload from the widget, else from the table. + if (ui->buttonApply->isEnabled()) { + setDataInBuffer(sciEdit->text().toUtf8(), SciBuffer); + } else + setCurrentIndex(m_currentIndex); +} + +// Determine the type of data in the cell +int EditDialog::checkDataType(const QByteArray& bArrdata) const +{ + QByteArray cellData = bArrdata; + + // Check for NULL data type + if (cellData.isNull()) { + return Null; + } + + // Check if it's an image + QString imageFormat = isImageData(cellData); + if(!imageFormat.isNull()) + return imageFormat == "svg" ? SVG : Image; + + // Check if it's text only + if(isTextOnly(cellData)) + { + if (cellData.startsWith("setOverwriteMode(currentMode); + ui->qtEdit->setOverwriteMode(currentMode); + sciEdit->setOverwriteMode(currentMode); +} + +void EditDialog::setFocus() +{ + QDialog::setFocus(); + + // Set the focus to the editor widget. The idea here is that setting focus + // to the dock itself doesn't make much sense as it's just a frame; you'd + // have to tab to the editor which is what you most likely want to use. So + // in order to save the user from doing this we explicitly set the focus + // to the current editor. + int editMode = ui->editorStack->currentIndex(); + + switch (editMode) { + case TextEditor: + sciEdit->setFocus(); + if (sciEdit->language() == DockTextEdit::PlainText && !isReadOnly) + sciEdit->selectAll(); + break; + case RtlTextEditor: + ui->qtEdit->setFocus(); + ui->qtEdit->selectAll(); + break; + case HexEditor: + hexEdit->setFocus(); + break; + case ImageViewer: + // Nothing to do + break; + } + +} + +// Enables or disables the Apply, Null, & Import buttons in the Edit Cell dock. +// Sets or unsets read-only properties for the editors. +void EditDialog::setReadOnly(bool ro) +{ + isReadOnly = ro; + + ui->buttonApply->setEnabled(!ro); + ui->actionNull->setEnabled(!ro); + ui->actionImport->setEnabled(!ro); + + ui->qtEdit->setReadOnly(ro); + sciEdit->setReadOnly(ro); + hexEdit->setReadOnly(ro); + + // This makes the caret being visible for selection, although the editor is read-only. The read-only state is hinted by the + // caret not blinking. The same is done in ExtendedScintilla. + Qt::TextInteractionFlags textFlags = ro? Qt::TextSelectableByMouse | Qt::TextSelectableByKeyboard : Qt::TextEditorInteraction; + ui->qtEdit->setTextInteractionFlags(textFlags); +} + +void EditDialog::switchEditorMode(bool autoSwitchForType) +{ + if (autoSwitchForType) { + // Switch automatically the editing mode according to the detected data. + switch (dataType) { + case Image: + ui->comboMode->setCurrentIndex(ImageViewer); + break; + case Binary: + ui->comboMode->setCurrentIndex(HexEditor); + break; + case Null: + case Text: + ui->comboMode->setCurrentIndex(TextEditor); + break; + case RtlText: + ui->comboMode->setCurrentIndex(RtlTextEditor); + break; + case JSON: + ui->comboMode->setCurrentIndex(JsonEditor); + break; + case SVG: + case XML: + ui->comboMode->setCurrentIndex(XmlEditor); + break; + } + } +} + +// Update the information labels in the bottom left corner of the dialog +// and switches the editor mode, if required, according to the detected data type. +void EditDialog::updateCellInfoAndMode(const QByteArray& bArrdata) +{ + QByteArray cellData = bArrdata; + + switchEditorMode(ui->buttonAutoSwitchMode->isChecked()); + + // Image data needs special treatment + if (dataType == Image || dataType == SVG) { + QBuffer imageBuffer(&cellData); + QImageReader imageReader(&imageBuffer); + + // Display the image format + QString imageFormat = imageReader.format(); + + ui->labelType->setText(tr("Type of data currently in cell: %1 Image").arg(imageFormat.toUpper())); + + // Display the image dimensions and size + QSize imageDimensions = imageReader.size(); + unsigned int imageSize = static_cast(cellData.size()); + + QString labelSizeText = tr("%1x%2 pixel(s)").arg(imageDimensions.width()).arg(imageDimensions.height()) + ", " + humanReadableSize(imageSize); + + ui->labelSize->setText(labelSizeText); + + return; + } + + // Use a switch statement for the other data types to keep things neat :) + switch (dataType) { + case Null: { + // NULL data type + ui->labelType->setText(tr("Type of data currently in cell: NULL")); + ui->labelSize->setText(tr("%n byte(s)", "", 0)); + + // Use margin to set the NULL text. + sciEdit->setTextInMargin(Settings::getValue("databrowser", "null_text").toString()); + break; + } + case XML: + case Text: + case RtlText: { + // Text only + // Determine the length of the cell text in characters (possibly different to number of bytes). + int textLength = QString(cellData).length(); + ui->labelType->setText(tr("Type of data currently in cell: Text / Numeric")); + ui->labelSize->setText(tr("%n character(s)", "", textLength)); + break; + } + case JSON: { + // Valid JSON + // Determine the length of the cell text in characters (possibly different to number of bytes). + int jsonLength = QString(cellData).length(); + ui->labelType->setText(tr("Type of data currently in cell: Valid JSON")); + ui->labelSize->setText(tr("%n character(s)", "", jsonLength)); + break; + } + default: + + // Determine the length of the cell data + int dataLength = cellData.length(); + // If none of the above data types, consider it general binary data + ui->labelType->setText(tr("Type of data currently in cell: Binary")); + ui->labelSize->setText(tr("%n byte(s)", "", dataLength)); + break; + } +} + +void EditDialog::reloadSettings() +{ + // Set the (SQL) editor font for hex editor, since it needs a + // Monospace font and the databrowser font would be usually of + // variable width. + QFont hexFont(Settings::getValue("editor", "font").toString()); + hexFont.setPointSize(Settings::getValue("databrowser", "fontsize").toInt()); + hexEdit->setFont(hexFont); + + ui->editCellToolbar->setToolButtonStyle(static_cast + (Settings::getValue("General", "toolbarStyleEditCell").toInt())); + + sciEdit->reloadSettings(); +} + +void EditDialog::setStackCurrentIndex(int editMode) +{ + switch (editMode) { + case TextEditor: + // Scintilla case: switch to the single Scintilla editor and set language + ui->editorStack->setCurrentIndex(TextEditor); + sciEdit->setLanguage(DockTextEdit::PlainText); + break; + case HexEditor: + case ImageViewer: + case RtlTextEditor: + // General case: switch to the selected editor + ui->editorStack->setCurrentIndex(editMode); + break; + case JsonEditor: + // Scintilla case: switch to the single Scintilla editor and set language + ui->editorStack->setCurrentIndex(TextEditor); + sciEdit->setLanguage(DockTextEdit::JSON); + break; + case XmlEditor: + // Scintilla case: switch to the single Scintilla editor and set language + ui->editorStack->setCurrentIndex(TextEditor); + sciEdit->setLanguage(DockTextEdit::XML); + break; + } +} + +void EditDialog::openPrintDialog() +{ + int editMode = ui->editorStack->currentIndex(); + if (editMode == ImageViewer) { + openPrintImageDialog(); + return; + } + + QPrinter printer; + QPrintPreviewDialog *dialog = new QPrintPreviewDialog(&printer); + + connect(dialog, &QPrintPreviewDialog::paintRequested, [this](QPrinter *previewPrinter) { + QTextDocument document; + switch (dataSource) { + case SciBuffer: + // This case isn't really expected because the Scintilla widget has it's own printing slot + document.setPlainText(sciEdit->text()); + break; + case HexBuffer: + document.setPlainText(hexEdit->toReadableString()); + document.setDefaultFont(hexEdit->font()); + break; + case QtBuffer: + document.setPlainText(ui->qtEdit->toPlainText()); + break; + } + + document.print(previewPrinter); + }); + + dialog->exec(); + delete dialog; + +} + +void EditDialog::openPrintImageDialog() +{ + QPrinter printer; + QPrintPreviewDialog *dialog = new QPrintPreviewDialog(&printer); + + connect(dialog, &QPrintPreviewDialog::paintRequested, [&](QPrinter *previewPrinter) { + QPainter painter(previewPrinter); + QRect rect = painter.viewport(); + QSize size = ui->editorImage->pixmap()->size(); + size.scale(rect.size(), Qt::KeepAspectRatio); + painter.setViewport(rect.x(), rect.y(), size.width(), size.height()); + painter.setWindow(ui->editorImage->pixmap()->rect()); + painter.drawPixmap(0, 0, *ui->editorImage->pixmap()); + }); + + dialog->exec(); + + delete dialog; +} + +void EditDialog::copyHexAscii() +{ + QApplication::clipboard()->setText(hexEdit->selectionToReadableString()); +} + +void EditDialog::setWordWrapping(bool value) +{ + // Set wrap lines + sciEdit->setWrapMode(value ? QsciScintilla::WrapWord : QsciScintilla::WrapNone); + ui->qtEdit->setWordWrapMode(value ? QTextOption::WrapAtWordBoundaryOrAnywhere : QTextOption::NoWrap); +} + +void EditDialog::openDataWithExternal() +{ + QString extension; + switch (dataType) { + case Image: { + // Images get special treatment. + // Determine the likely filename extension. + QByteArray cellData = hexEdit->data(); + QBuffer imageBuffer(&cellData); + QImageReader imageReader(&imageBuffer); + extension = imageReader.format().toLower().prepend("."); + break; + } + case Binary: + extension = FILE_EXT_BIN_DEFAULT; + break; + case RtlText: + case Text: + if (ui->comboMode->currentIndex() == XmlEditor) + extension = FILE_EXT_XML_DEFAULT; + else + extension = FILE_EXT_TXT_DEFAULT; + break; + case JSON: + extension = FILE_EXT_JSON_DEFAULT; + break; + case SVG: + extension = FILE_EXT_SVG_DEFAULT; + break; + case XML: + extension = FILE_EXT_XML_DEFAULT; + break; + case Null: + return; + } + QTemporaryFile* file = new QTemporaryFile (QDir::tempPath() + QString("/DB4S-XXXXXX") + extension); + + if(!file->open()) { + QMessageBox::warning(this, qApp->applicationName(), + tr("Couldn't save file: %1.").arg(file->fileName())); + delete file; + } else { + switch (dataSource) { + case HexBuffer: + file->write(hexEdit->data()); + break; + case SciBuffer: + file->write(sciEdit->text().toUtf8()); + break; + case QtBuffer: + file->write(ui->qtEdit->toPlainText().toUtf8()); + break; + } + // We don't want the file to be automatically removed by Qt when destroyed. + file->setAutoRemove(false); + // But we don't want Qt to keep the file open (and locked in Windows), + // and the only way is to destroy the object. + QString fileName = file->fileName(); + delete file; + emit requestUrlOrFileOpen(fileName); + + QMessageBox::StandardButton reply = QMessageBox::information + (nullptr, + QApplication::applicationName(), + tr("The data has been saved to a temporary file and has been opened with the default application. " + "You can now edit the file and, when you are ready, apply the saved new data to the cell editor or cancel any changes."), + QMessageBox::Apply | QMessageBox::Cancel); + + QFile readFile(fileName); + if(reply == QMessageBox::Apply && readFile.open(QIODevice::ReadOnly)){ + QByteArray d = readFile.readAll(); + loadData(d); + readFile.close(); + } + readFile.remove(); + } +} diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/EditDialog.h b/src/WBCLFZSystemModule/SqliteDBProcess/src/EditDialog.h new file mode 100644 index 0000000..7144a6f --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/EditDialog.h @@ -0,0 +1,106 @@ +#ifndef EDITDIALOG_H +#define EDITDIALOG_H + +#include +#include + +class QHexEdit; +class DockTextEdit; + +namespace Ui { +class EditDialog; +} + +class EditDialog : public QDialog +{ + Q_OBJECT + +public: + explicit EditDialog(QWidget* parent = nullptr); + ~EditDialog() override; + + void setCurrentIndex(const QModelIndex& idx); + QPersistentModelIndex currentIndex() { return m_currentIndex; }; + +public slots: + void setFocus(); + void reject() override; + void setReadOnly(bool ro); + void reloadSettings(); + +protected: + void showEvent(QShowEvent* ev) override; + +private slots: + void importData(bool asLink = false); + void exportData(); + void setNull(); + void updateApplyButton(); + void accept() override; + void loadData(const QByteArray& bArrdata); + void toggleOverwriteMode(); + void editModeChanged(int newMode); + void editTextChanged(); + void switchEditorMode(bool autoSwitchForType); + void updateCellInfoAndMode(const QByteArray& bArrdata); + void setMustIndentAndCompact(bool enable); + void openPrintDialog(); + void openPrintImageDialog(); + void copyHexAscii(); + void setWordWrapping(bool value); + +signals: + void recordTextUpdated(const QPersistentModelIndex& idx, const QByteArray& bArrdata, bool isBlob); + void requestUrlOrFileOpen(const QString& urlString); + +private: + Ui::EditDialog* ui; + QHexEdit* hexEdit; + DockTextEdit* sciEdit; + QPersistentModelIndex m_currentIndex; + int dataSource; + int dataType; + bool isReadOnly; + bool mustIndentAndCompact; + QByteArray removedBom; + + enum DataSources { + QtBuffer, + HexBuffer, + SciBuffer + }; + + // SVG is both an Image and an XML document so it is treated separately + enum DataTypes { + Binary, + Image, + Null, + Text, + JSON, + SVG, + XML, + RtlText + }; + + // Edit modes and editor stack (this must be aligned with the UI). + // Note that text modes (plain, JSON and XML) share the Scintilla widget, + // Consequently the editor stack range is TextEditor..ImageViewer. + enum EditModes { + // Modes with their own widget in the stack: + TextEditor = 0, + RtlTextEditor = 1, + HexEditor = 2, + ImageViewer = 3, + // Modes in the Scintilla editor: + JsonEditor = 4, + XmlEditor = 5 + }; + + int checkDataType(const QByteArray& bArrdata) const; + bool promptInvalidData(const QString& data_type, const QString& errorString); + void setDataInBuffer(const QByteArray& bArrdata, DataSources source); + void setStackCurrentIndex(int editMode); + void openDataWithExternal(); +}; + +#endif diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/EditDialog.ui b/src/WBCLFZSystemModule/SqliteDBProcess/src/EditDialog.ui new file mode 100644 index 0000000..a1aab0f --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/EditDialog.ui @@ -0,0 +1,690 @@ + + + EditDialog + + + + 0 + 0 + 618 + 382 + + + + Edit database cell + + + This area displays information about the data present in this database cell + + + + + + + + + 0 + 0 + + + + Mode: + + + comboMode + + + + + + + + 0 + 0 + + + + This is the list of supported modes for the cell editor. Choose a mode for viewing or editing the data of the current cell. + + + + Text + + + + + RTL Text + + + + + Binary + + + + + Image + + + + + JSON + + + + + XML + + + + + + + + Automatically adjust the editor mode to the loaded data type + + + Automatically adjust the editor mode to the loaded data type + + + This checkable button enables or disables the automatic switching of the editor mode. When a new cell is selected or new data is imported and the automatic switching is enabled, the mode adjusts to the detected data type. You can then change the editor mode manually. If you want to keep this manually switched mode while moving through the cells, switch the button off. + + + Auto-switch + + + + :/icons/keyword + :/icons/cog_go.png:/icons/keyword + + + true + + + true + + + + + + + Qt::Horizontal + + + + 0 + 0 + + + + + + + + + + + + + + + + + + + + + + 0 + + + + The text editor modes let you edit plain text, as well as JSON or XML data with syntax highlighting, automatic formatting and validation before saving. + +Errors are indicated with a red squiggle underline. + + + + + + + + + Monospace + + + + This Qt editor is used for right-to-left scripts, which are not supported by the default Text editor. The presence of right-to-left characters is detected and this editor mode is automatically selected. + + + false + + + + + + + + Qt::ActionsContextMenu + + + + + true + + + + + 0 + 0 + 84 + 35 + + + + + + + Qt::ActionsContextMenu + + + + + + + + + + + + + + + + + + + + 0 + 0 + + + + + 100 + 0 + + + + Type of data currently in cell + + + true + + + + + + + + 0 + 0 + + + + + 100 + 0 + + + + Size of data currently in table + + + Qt::PlainText + + + true + + + + + + + + + + 0 + 0 + + + + Apply data to cell + + + This button saves the changes performed in the cell editor to the database cell. + + + Apply + + + true + + + + + + + + + + :/icons/print:/icons/print + + + Print... + + + Open preview dialog for printing displayed image + + + Ctrl+P + + + + + + :/icons/print:/icons/print + + + Print... + + + Open preview dialog for printing displayed text + + + Open preview dialog for printing the data currently stored in the cell + + + Ctrl+P + + + Qt::WidgetShortcut + + + + + + :/icons/special_copy:/icons/special_copy + + + Copy Hex and ASCII + + + Copy selected hexadecimal and ASCII columns to the clipboard + + + Ctrl+Shift+C + + + + + true + + + + :/icons/text_indent:/icons/text_indent + + + Autoformat + + + Auto-format: pretty print on loading, compact on saving. + + + When enabled, the auto-format feature formats the data on loading, breaking the text in lines and indenting it for maximum readability. On data saving, the auto-format feature compacts the data removing end of lines, and unnecessary whitespace. + + + + + + :/icons/save_sql:/icons/save_sql + + + &Export... + + + Export to file + + + Opens a file dialog used to export the contents of this database cell to a file. + + + + + + :/icons/document_open:/icons/document_open + + + &Import... + + + Import from file + + + Opens a file dialog used to import any kind of data to this database cell. + + + + + + :/icons/set_to_null:/icons/set_to_null + + + Set as &NULL + + + Erases the contents of the cell + + + + + true + + + true + + + + :/icons/word_wrap:/icons/word_wrap + + + Word Wrap + + + Wrap lines on word boundaries + + + + + + :/icons/open_in_app:/icons/open_in_app + + + Open in default application or browser + + + Open in application + + + Open in default application or browser + + + The value is interpreted as a file or URL and opened in the default application or web browser. + + + + + + :/icons/document_link:/icons/document_link + + + Save file reference... + + + Save reference to file + + + + + + :/icons/document_open:/icons/document_open + + + &Import... + + + Import from file + + + Opens a file dialog used to import any kind of data to this database cell. + + + + + + :/icons/open_data_in_app:/icons/open_data_in_app + + + Open in external application + + + Open in external application + + + + + comboMode + buttonAutoSwitchMode + buttonApply + + + + + + + buttonApply + clicked() + EditDialog + accept() + + + 605 + 358 + + + 241 + 406 + + + + + comboMode + currentIndexChanged(int) + EditDialog + editModeChanged(int) + + + 71 + 27 + + + 201 + 431 + + + + + qtEdit + textChanged() + EditDialog + editTextChanged() + + + 279 + 191 + + + 339 + 335 + + + + + actionIndent + toggled(bool) + EditDialog + setMustIndentAndCompact(bool) + + + -1 + -1 + + + 308 + 190 + + + + + buttonAutoSwitchMode + toggled(bool) + EditDialog + switchEditorMode(bool) + + + 162 + 33 + + + 308 + 190 + + + + + actionPrintImage + triggered() + EditDialog + openPrintImageDialog() + + + -1 + -1 + + + 308 + 190 + + + + + actionPrint + triggered() + EditDialog + openPrintDialog() + + + -1 + -1 + + + 308 + 190 + + + + + actionCopyHexAscii + triggered() + EditDialog + copyHexAscii() + + + -1 + -1 + + + 308 + 190 + + + + + actionNull + triggered() + EditDialog + setNull() + + + -1 + -1 + + + 308 + 190 + + + + + actionImport + triggered() + EditDialog + importData() + + + -1 + -1 + + + 308 + 190 + + + + + actionExport + triggered() + EditDialog + exportData() + + + -1 + -1 + + + 308 + 190 + + + + + actionWordWrap + toggled(bool) + EditDialog + setWordWrapping(bool) + + + -1 + -1 + + + 308 + 190 + + + + + actionImportInMenu + triggered() + EditDialog + importData() + + + -1 + -1 + + + 308 + 190 + + + + + + importData() + exportData() + editTextChanged() + editModeChanged(int) + setNull() + + diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/EditIndexDialog.cpp b/src/WBCLFZSystemModule/SqliteDBProcess/src/EditIndexDialog.cpp new file mode 100644 index 0000000..d8449b7 --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/EditIndexDialog.cpp @@ -0,0 +1,351 @@ +#include "EditIndexDialog.h" +#include "ui_EditIndexDialog.h" +#include "sqlitedb.h" +#include "IconCache.h" + +#include +#include + +EditIndexDialog::EditIndexDialog(DBBrowserDB& db, const sqlb::ObjectIdentifier& indexName, bool createIndex, QWidget* parent) + : QDialog(parent), + pdb(db), + curIndex(indexName), + index(indexName.name()), + newIndex(createIndex), + ui(new Ui::EditIndexDialog), + m_sRestorePointName(pdb.generateSavepointName("editindex")) +{ + // Create UI + ui->setupUi(this); + ui->sqlTextEdit->setReadOnly(true); + + // Get list of tables, sort it alphabetically and fill the combobox + std::map dbobjs; // Map from display name to full object identifier + if(newIndex) // If this is a new index, offer all tables of all database schemata + { + for(const auto& it : pdb.schemata) + { + auto tables = it.second.equal_range("table"); + for(auto jt=tables.first;jt!=tables.second;++jt) + { + // Only show the schema name for non-main schemata + sqlb::ObjectIdentifier obj(it.first, jt->second->name()); + dbobjs.insert({obj.toDisplayString(), obj}); + } + } + } else { // If this is an existing index, only offer tables of the current database schema + auto tables = pdb.schemata[curIndex.schema()].equal_range("table"); + for(auto it=tables.first;it!=tables.second;++it) + { + // Only show the schema name for non-main schemata + sqlb::ObjectIdentifier obj(curIndex.schema(), it->second->name()); + dbobjs.insert({obj.toDisplayString(), obj}); + } + } + ui->comboTableName->blockSignals(true); + for(auto it=dbobjs.cbegin();it!=dbobjs.cend();++it) + ui->comboTableName->addItem(IconCache::get("table"), QString::fromStdString(it->first), QString::fromStdString(it->second.toSerialised())); + ui->comboTableName->blockSignals(false); + + QHeaderView *tableHeaderView = ui->tableIndexColumns->horizontalHeader(); + tableHeaderView->setSectionResizeMode(0, QHeaderView::Stretch); + + // Editing an existing index? + if(!newIndex) + { + // Load the current layout and fill in the dialog fields + index = *(pdb.getObjectByName(curIndex)); + + ui->editIndexName->blockSignals(true); + ui->editIndexName->setText(QString::fromStdString(index.name())); + ui->editIndexName->blockSignals(false); + ui->checkIndexUnique->blockSignals(true); + ui->checkIndexUnique->setChecked(index.unique()); + ui->checkIndexUnique->blockSignals(false); + ui->comboTableName->blockSignals(true); + ui->comboTableName->setCurrentText(QString::fromStdString(index.table())); + ui->comboTableName->blockSignals(false); + ui->editPartialClause->blockSignals(true); + ui->editPartialClause->setText(QString::fromStdString(index.whereExpr())); + ui->editPartialClause->blockSignals(false); + + tableChanged(QString::fromStdString(index.table()), true); + } else { + tableChanged(ui->comboTableName->currentText(), false); + } + + // Add event handler for index column name changes. These are only allowed for expression columns, though. + connect(ui->tableIndexColumns, &QTableWidget::itemChanged, + [=](QTableWidgetItem* item) + { + index.fields[static_cast(item->row())].setName(item->text().toStdString()); + updateSqlText(); + }); + + // Create a savepoint to revert back to + pdb.setSavepoint(m_sRestorePointName); +} + +EditIndexDialog::~EditIndexDialog() +{ + delete ui; +} + +void EditIndexDialog::tableChanged(const QString& new_table, bool initialLoad) +{ + // Set the table name and clear all index columns + if(!initialLoad) + { + index.setTable(sqlb::ObjectIdentifier(ui->comboTableName->currentData().toString().toStdString()).name()); + index.fields.clear(); + } + + // Stop here if table name is empty + if(new_table.isEmpty()) + { + // Call checkInput() before to make sure the OK button is disabled + checkInput(); + return; + } + + updateColumnLists(); +} + +void EditIndexDialog::updateColumnLists() +{ + // Fill the table column list + sqlb::TablePtr table = pdb.getObjectByName(sqlb::ObjectIdentifier(ui->comboTableName->currentData().toString().toStdString())); + if(!table) + return; + sqlb::FieldInfoList tableFields = table->fieldInformation(); + ui->tableTableColumns->setRowCount(static_cast(tableFields.size())); + int tableRows = 0; + for(size_t i=0;isetFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); + ui->tableTableColumns->setItem(tableRows, 0, name); + + // Put the data type in the second column + QTableWidgetItem* type = new QTableWidgetItem(QString::fromStdString(tableFields.at(i).type)); + type->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); + ui->tableTableColumns->setItem(tableRows, 1, type); + + tableRows++; + } + } + + // Set row count to actual count. This is needed for the intial loading, when some rows might have been omitted because they were used in the index + ui->tableTableColumns->setRowCount(tableRows); + + // Fill the index column list. This is done separately from the table column to include expression columns (these are not found in the original + // table) and to preserve the order of the index columns + auto indexFields = index.fields; + ui->tableIndexColumns->blockSignals(true); + ui->tableIndexColumns->setRowCount(static_cast(indexFields.size())); + for(size_t i=0;isetFlags(flags); + ui->tableIndexColumns->setItem(static_cast(i), 0, name); + + // And put a combobox to select the order in which to index the field in the last column + QComboBox* order = new QComboBox(this); + order->addItem(""); + order->addItem("ASC"); + order->addItem("DESC"); + order->setCurrentText(QString::fromStdString(indexFields.at(i).order()).toUpper()); + ui->tableIndexColumns->setCellWidget(static_cast(i), 1, order); + connect(order, &QComboBox::currentTextChanged, + [=](QString new_order) + { + auto colnum = sqlb::findField(index, indexFields.at(i).name()); + if(colnum != index.fields.end()) + { + colnum->setOrder(new_order.toStdString()); + updateSqlText(); + } + }); + } + ui->tableIndexColumns->blockSignals(false); + + checkInput(); +} + +void EditIndexDialog::addToIndex(const QModelIndex& idx) +{ + // Get current row number + int row; + if(idx.isValid()) + row = idx.row(); + else + row = ui->tableTableColumns->currentRow(); + + // No row selected? Abort. + if(row == -1) + return; + + // Add field to index + index.fields.emplace_back( + ui->tableTableColumns->item(row, 0)->text().toStdString(), // Column name + false, // Is expression + ""); // Order + + // Update UI + updateColumnLists(); +} + +void EditIndexDialog::removeFromIndex(const QModelIndex& idx) +{ + // Get current row number + int row; + if(idx.isValid()) + row = idx.row(); + else + row = ui->tableIndexColumns->currentRow(); + + // No row selected? Abort. + if(row == -1) + return; + + // If this is an expression column and the action was triggered by a double click event instead of a button click, + // we won't remove the expression column because it's too likely that this was only done by accident by the user. + // Instead just open the expression column for editing. + if(index.fields[static_cast(row)].expression() && sender() != ui->buttonFromIndex) + { + ui->tableIndexColumns->editItem(ui->tableIndexColumns->item(row, 0)); + return; + } + + // Remove column from index + sqlb::removeField(index, ui->tableIndexColumns->item(row, 0)->text().toStdString()); + + // Update UI + updateColumnLists(); +} + +void EditIndexDialog::checkInput() +{ + // Check if index name is set + bool valid = true; + if(ui->editIndexName->text().isEmpty()) + valid = false; + + // Check if a table is selected (this is especially important in the case where there are no tables in the database yet). + if(ui->comboTableName->currentText().isNull()) + valid = false; + + // Check if index has any columns + if(index.fields.size() == 0) + valid = false; + + // Only activate OK button if index data is valid + ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(valid); + + // Set the index name and the unique flag + index.setName(ui->editIndexName->text().toStdString()); + index.setUnique(ui->checkIndexUnique->isChecked()); + index.setWhereExpr(ui->editPartialClause->text().toStdString()); + updateSqlText(); +} + +void EditIndexDialog::accept() +{ + // When editing an index, delete the old one first + if(!newIndex) + { + if(!pdb.executeSQL("DROP INDEX IF EXISTS " + curIndex.toString())) + { + QMessageBox::warning(this, qApp->applicationName(), tr("Deleting the old index failed:\n%1").arg(pdb.lastError())); + return; + } + } + + // Create the new index in the schema of the selected table + if(pdb.executeSQL(index.sql(sqlb::ObjectIdentifier(ui->comboTableName->currentData().toString().toStdString()).schema()))) + QDialog::accept(); + else + QMessageBox::warning(this, QApplication::applicationName(), tr("Creating the index failed:\n%1").arg(pdb.lastError())); +} + +void EditIndexDialog::reject() +{ + // Rollback to our savepoint + pdb.revertToSavepoint(m_sRestorePointName); + + QDialog::reject(); +} + +void EditIndexDialog::updateSqlText() +{ + ui->sqlTextEdit->setText(QString::fromStdString(index.sql(sqlb::ObjectIdentifier(ui->comboTableName->currentData().toString().toStdString()).schema()))); +} + +void EditIndexDialog::moveColumnUp() +{ + moveCurrentColumn(false); +} + +void EditIndexDialog::moveColumnDown() +{ + moveCurrentColumn(true); +} + +void EditIndexDialog::moveCurrentColumn(bool down) +{ + // Get current row number and calculate row number after the movement. Check the values + int currentRow = ui->tableIndexColumns->currentRow(); + if(currentRow == -1) + return; + int newRow = currentRow + (down ? 1 : -1); + if(newRow < 0) + return; + if(newRow >= ui->tableIndexColumns->rowCount()) + return; + + // Swap the columns + std::swap(index.fields[static_cast(currentRow)], index.fields[static_cast(newRow)]); + + // Update UI + updateColumnLists(); + + // Select old row at new position + ui->tableIndexColumns->selectRow(newRow); +} + +void EditIndexDialog::addExpressionColumn() +{ + // Check if there already is an empty expression column + auto field_it = sqlb::findField(index, ""); + int row = static_cast(std::distance(index.fields.begin(), field_it)); + if(field_it == index.fields.end()) + { + // There is no empty expression column yet, so add one. + + // Add new expression column to the index + index.fields.emplace_back( + "", // Column name + true, // Is expression + ""); // Order + + // Update UI + updateColumnLists(); + + // Get row number of new column + row = ui->tableIndexColumns->rowCount() - 1; + } + + // Now we should have the row number of the empty expression column, no matter if it was newly added or it already existed. + // Select the row for editing + ui->tableIndexColumns->editItem(ui->tableIndexColumns->item(row, 0)); +} diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/EditIndexDialog.h b/src/WBCLFZSystemModule/SqliteDBProcess/src/EditIndexDialog.h new file mode 100644 index 0000000..79fa2ae --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/EditIndexDialog.h @@ -0,0 +1,49 @@ +#ifndef EDITINDEXDIALOG_H +#define EDITINDEXDIALOG_H + +#include "sql/ObjectIdentifier.h" +#include "sql/sqlitetypes.h" + +#include +#include + +class DBBrowserDB; + +namespace Ui { +class EditIndexDialog; +} + +class EditIndexDialog : public QDialog +{ + Q_OBJECT + +public: + explicit EditIndexDialog(DBBrowserDB& db, const sqlb::ObjectIdentifier& indexName, bool createIndex, QWidget* parent = nullptr); + ~EditIndexDialog() override; + +private slots: + void accept() override; + void reject() override; + + void tableChanged(const QString& new_table, bool initialLoad = false); + void checkInput(); + void addToIndex(const QModelIndex& idx = QModelIndex()); + void removeFromIndex(const QModelIndex& idx = QModelIndex()); + void moveColumnUp(); + void moveColumnDown(); + void addExpressionColumn(); + +private: + DBBrowserDB& pdb; + sqlb::ObjectIdentifier curIndex; + sqlb::Index index; + bool newIndex; + Ui::EditIndexDialog* ui; + std::string m_sRestorePointName; + + void updateColumnLists(); + void updateSqlText(); + void moveCurrentColumn(bool down); +}; + +#endif diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/EditIndexDialog.ui b/src/WBCLFZSystemModule/SqliteDBProcess/src/EditIndexDialog.ui new file mode 100644 index 0000000..4477fbc --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/EditIndexDialog.ui @@ -0,0 +1,573 @@ + + + EditIndexDialog + + + + 0 + 0 + 703 + 543 + + + + Edit Index Schema + + + + :/icons/index_create:/icons/index_create + + + + + + + + &Name + + + editIndexName + + + + + + + + + + &Table + + + comboTableName + + + + + + + + + + &Unique + + + checkIndexUnique + + + + + + + + + + + + + + For restricting the index to only a part of the table you can specify a WHERE clause here that selects the part of the table that should be indexed + + + Partial inde&x clause + + + editPartialClause + + + + + + + + + + Colu&mns + + + tableIndexColumns + + + + + + + + 0 + 0 + + + + Qt::Vertical + + + + + + + QAbstractItemView::NoEditTriggers + + + false + + + true + + + QAbstractItemView::SingleSelection + + + QAbstractItemView::SelectRows + + + true + + + false + + + + Table column + + + + + Type + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + Qt::RightArrow + + + + + + + Qt::LeftArrow + + + + + + + Add a new expression column to the index. Expression columns contain SQL expression rather than column names. + + + + :/icons/cog_go.png:/icons/cog_go.png + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + 0 + 1 + + + + + 0 + 250 + + + + QAbstractItemView::AnyKeyPressed|QAbstractItemView::EditKeyPressed|QAbstractItemView::SelectedClicked + + + false + + + true + + + QAbstractItemView::SingleSelection + + + QAbstractItemView::SelectRows + + + true + + + false + + + + Index column + + + + + Order + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + Qt::UpArrow + + + + + + + Qt::DownArrow + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + 0 + 100 + + + + true + + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + SqlTextEdit + QWidget +
sqltextedit.h
+ 1 +
+
+ + editIndexName + comboTableName + checkIndexUnique + editPartialClause + tableTableColumns + tableIndexColumns + buttonToIndex + buttonFromIndex + + + + + + + buttonBox + accepted() + EditIndexDialog + accept() + + + 264 + 536 + + + 157 + 274 + + + + + buttonBox + rejected() + EditIndexDialog + reject() + + + 332 + 536 + + + 286 + 274 + + + + + comboTableName + currentIndexChanged(QString) + EditIndexDialog + tableChanged(QString) + + + 145 + 74 + + + 236 + 31 + + + + + editIndexName + textChanged(QString) + EditIndexDialog + checkInput() + + + 429 + 14 + + + 443 + 39 + + + + + tableIndexColumns + cellChanged(int,int) + EditIndexDialog + checkInput() + + + 443 + 170 + + + 566 + 40 + + + + + checkIndexUnique + toggled(bool) + EditIndexDialog + checkInput() + + + 153 + 100 + + + 304 + 251 + + + + + buttonToIndex + clicked() + EditIndexDialog + addToIndex() + + + 406 + 247 + + + 385 + 103 + + + + + buttonFromIndex + clicked() + EditIndexDialog + removeFromIndex() + + + 406 + 285 + + + 350 + 95 + + + + + tableIndexColumns + doubleClicked(QModelIndex) + EditIndexDialog + removeFromIndex(QModelIndex) + + + 520 + 236 + + + 684 + 175 + + + + + tableTableColumns + doubleClicked(QModelIndex) + EditIndexDialog + addToIndex(QModelIndex) + + + 231 + 357 + + + 19 + 205 + + + + + editPartialClause + textChanged(QString) + EditIndexDialog + checkInput() + + + 242 + 129 + + + 47 + 103 + + + + + buttonMoveColumnUp + clicked() + EditIndexDialog + moveColumnUp() + + + 676 + 241 + + + 700 + 212 + + + + + buttonMoveColumnDown + clicked() + EditIndexDialog + moveColumnDown() + + + 686 + 299 + + + 699 + 307 + + + + + buttonAddExpressionColumn + clicked() + EditIndexDialog + addExpressionColumn() + + + 398 + 311 + + + 379 + 500 + + + + + + tableChanged(QString) + checkInput() + addToIndex() + addToIndex(QModelIndex) + removeFromIndex() + removeFromIndex(QModelIndex) + moveColumnUp() + moveColumnDown() + addExpressionColumn() + +
diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/EditTableDialog.cpp b/src/WBCLFZSystemModule/SqliteDBProcess/src/EditTableDialog.cpp new file mode 100644 index 0000000..02a2303 --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/EditTableDialog.cpp @@ -0,0 +1,1008 @@ +#include "EditTableDialog.h" +#include "Settings.h" +#include "ForeignKeyEditorDelegate.h" +#include "ui_EditTableDialog.h" +#include "sqlitetablemodel.h" +#include "sqlitedb.h" +#include "SelectItemsPopup.h" + +#include +#include +#include +#include +#include +#include + +#include + +Q_DECLARE_METATYPE(sqlb::ConstraintPtr) + +EditTableDialog::EditTableDialog(DBBrowserDB& db, const sqlb::ObjectIdentifier& tableName, bool createTable, QWidget* parent) + : QDialog(parent), + ui(new Ui::EditTableDialog), + pdb(db), + curTable(tableName), + m_table(tableName.name()), + m_bNewTable(createTable), + m_sRestorePointName(pdb.generateSavepointName("edittable")) +{ + // Create UI + ui->setupUi(this); + ui->widgetExtension->setVisible(false); + connect(ui->treeWidget, &QTreeWidget::itemChanged, this, &EditTableDialog::fieldItemChanged); + connect(ui->tableConstraints, &QTableWidget::itemChanged, this, &EditTableDialog::constraintItemChanged); + + // Set item delegate for foreign key column + m_fkEditorDelegate = new ForeignKeyEditorDelegate(db, m_table, this); + ui->treeWidget->setItemDelegateForColumn(kForeignKey, m_fkEditorDelegate); + + // Set up popup menu for adding constraints + QMenu* constraint_menu = new QMenu(this); + constraint_menu->addAction(ui->actionAddPrimaryKey); + constraint_menu->addAction(ui->actionAddForeignKey); + constraint_menu->addAction(ui->actionAddUniqueConstraint); + constraint_menu->addAction(ui->actionAddCheckConstraint); + connect(ui->actionAddPrimaryKey, &QAction::triggered, [this]() { addConstraint(sqlb::Constraint::PrimaryKeyConstraintType); }); + connect(ui->actionAddForeignKey, &QAction::triggered, [this]() { addConstraint(sqlb::Constraint::ForeignKeyConstraintType); }); + connect(ui->actionAddUniqueConstraint, &QAction::triggered, [this]() { addConstraint(sqlb::Constraint::UniqueConstraintType); }); + connect(ui->actionAddCheckConstraint, &QAction::triggered, [this]() { addConstraint(sqlb::Constraint::CheckConstraintType); }); + ui->buttonAddConstraint->setMenu(constraint_menu); + + // Get list of all collations + db.executeSQL("PRAGMA collation_list;", false, true, [this](int column_count, std::vector columns, std::vector) -> bool { + if(column_count >= 2) + m_collationList.push_back(columns.at(1)); + return false; + }); + if(!m_collationList.contains("")) + m_collationList.push_back(""); + m_collationList.sort(); + + // Editing an existing table? + if(m_bNewTable == false) + { + // Existing table, so load and set the current layout + m_table = *(pdb.getObjectByName(curTable)); + ui->labelEditWarning->setVisible(!m_table.fullyParsed()); + + // Initialise the list of tracked columns for table layout changes + for(const auto& field : m_table.fields) + trackColumns[QString::fromStdString(field.name())] = QString::fromStdString(field.name()); + + // Set without rowid checkbox and schema dropdown. No need to trigger any events here as we're only loading a table exactly as it is stored by SQLite, so no need + // for error checking etc. + ui->checkWithoutRowid->blockSignals(true); + ui->checkWithoutRowid->setChecked(m_table.withoutRowidTable()); + ui->checkWithoutRowid->blockSignals(false); + ui->comboSchema->blockSignals(true); + for(const auto& n : pdb.schemata) // Load list of database schemata + ui->comboSchema->addItem(QString::fromStdString(n.first)); + ui->comboSchema->setCurrentText(QString::fromStdString(curTable.schema())); + ui->comboSchema->blockSignals(false); + + populateFields(); + populateConstraints(); + } else { + for(const auto& n : pdb.schemata) // Load list of database schemata + ui->comboSchema->addItem(QString::fromStdString(n.first)); + ui->comboSchema->setCurrentText("main"); // Always create tables in the main schema by default + ui->labelEditWarning->setVisible(false); + } + + // Enable/disable remove constraint button depending on whether a constraint is selected + connect(ui->tableConstraints, &QTableWidget::itemSelectionChanged, [this]() { + bool hasSelection = ui->tableConstraints->selectionModel()->hasSelection(); + ui->buttonRemoveConstraint->setEnabled(hasSelection); + }); + + // And create a savepoint + pdb.setSavepoint(m_sRestorePointName); + + // Update UI + ui->editTableName->setText(QString::fromStdString(curTable.name())); + updateColumnWidth(); + + // Allow editing of constraint columns by double clicking the columns column of the constraints table + connect(ui->tableConstraints, &QTableWidget::itemDoubleClicked, [this](QTableWidgetItem* item) { + // Check whether the double clicked item is in the columns column + if(item->column() == kConstraintColumns) + { + sqlb::ConstraintPtr constraint = ui->tableConstraints->item(item->row(), kConstraintColumns)->data(Qt::UserRole).value(); + + // Do not allow editing the columns list of a CHECK constraint because CHECK constraints are independent of column lists + if(constraint->type() == sqlb::Constraint::CheckConstraintType) + return; + + // Show the select items popup dialog + SelectItemsPopup* dialog = new SelectItemsPopup(m_table.fieldNames(), item->data(Qt::UserRole).value()->columnList(), this); + QRect item_rect = ui->tableConstraints->visualItemRect(item); + dialog->move(ui->tableConstraints->mapToGlobal(QPoint(ui->tableConstraints->x() + item_rect.x(), + ui->tableConstraints->y() + item_rect.y() + item_rect.height() / 2))); + dialog->show(); + + // When clicking the Apply button in the popup dialog, save the new columns list + connect(dialog, &SelectItemsPopup::accepted, [this, dialog, constraint]() { + // Check if column selection changed at all + sqlb::StringVector new_columns = dialog->selectedItems(); + if(constraint->columnList() != new_columns) + { + // Remove the constraint with the old columns and add a new one with the new columns + m_table.removeConstraint(constraint); + constraint->setColumnList(new_columns); + m_table.addConstraint(constraint); + + // Update the UI + populateFields(); + populateConstraints(); + updateSqlText(); + } + }); + } + }); + + // (De-)activate fields + checkInput(); + + ui->sqlTextEdit->setReadOnly(true); +} + +EditTableDialog::~EditTableDialog() +{ + delete ui; +} + +void EditTableDialog::keyPressEvent(QKeyEvent *evt) +{ + if((evt->modifiers() & Qt::ControlModifier) + && (evt->key() == Qt::Key_Enter || evt->key() == Qt::Key_Return)) + { + accept(); + return; + } + if(evt->key() == Qt::Key_Enter || evt->key() == Qt::Key_Return) + return; + QDialog::keyPressEvent(evt); +} + +void EditTableDialog::updateColumnWidth() +{ + ui->treeWidget->setColumnWidth(kName, 190); + ui->treeWidget->setColumnWidth(kType, 100); + ui->treeWidget->setColumnWidth(kNotNull, 30); + ui->treeWidget->setColumnWidth(kPrimaryKey, 30); + ui->treeWidget->setColumnWidth(kAutoIncrement, 30); + ui->treeWidget->setColumnWidth(kUnique, 30); + ui->treeWidget->setColumnWidth(kForeignKey, 500); + + ui->tableConstraints->setColumnWidth(kConstraintColumns, 180); + ui->tableConstraints->setColumnWidth(kConstraintType, 130); + ui->tableConstraints->setColumnWidth(kConstraintName, 130); + ui->tableConstraints->setColumnWidth(kConstraintSql, 300); +} + +void EditTableDialog::populateFields() +{ + // Disable the itemChanged signal or the table item will be updated while filling the treewidget + ui->treeWidget->blockSignals(true); + + ui->treeWidget->clear(); + const auto& fields = m_table.fields; + const auto pk = m_table.primaryKey(); + for(const sqlb::Field& f : fields) + { + QTreeWidgetItem *tbitem = new QTreeWidgetItem(ui->treeWidget); + tbitem->setFlags(tbitem->flags() | Qt::ItemIsEditable); + tbitem->setText(kName, QString::fromStdString(f.name())); + QComboBox* typeBox = new QComboBox(ui->treeWidget); + typeBox->setProperty("column", QString::fromStdString(f.name())); + typeBox->setEditable(true); + typeBox->addItems(DBBrowserDB::Datatypes); + int index = typeBox->findText(QString::fromStdString(f.type()), Qt::MatchExactly); + if(index == -1) + { + // non standard named type + typeBox->addItem(QString::fromStdString(f.type())); + index = typeBox->count() - 1; + } + typeBox->setCurrentIndex(index); + typeBox->installEventFilter(this); + connect(typeBox, SIGNAL(currentIndexChanged(int)), this, SLOT(updateTypeAndCollation())); + ui->treeWidget->setItemWidget(tbitem, kType, typeBox); + + tbitem->setCheckState(kNotNull, f.notnull() ? Qt::Checked : Qt::Unchecked); + tbitem->setCheckState(kPrimaryKey, pk && contains(pk->columnList(), f.name()) ? Qt::Checked : Qt::Unchecked); + tbitem->setCheckState(kAutoIncrement, pk && pk->autoIncrement() && contains(pk->columnList(), f.name()) ? Qt::Checked : Qt::Unchecked); + tbitem->setCheckState(kUnique, f.unique() ? Qt::Checked : Qt::Unchecked); + + // For the default value check if it is surrounded by parentheses and if that's the case + // add a '=' character before the entire string to match the input format we're expecting + // from the user when using functions in the default value field. + if(f.defaultValue().front() == '(' && f.defaultValue().back() == ')') + tbitem->setText(kDefault, "=" + QString::fromStdString(f.defaultValue())); + else + tbitem->setText(kDefault, QString::fromStdString(f.defaultValue())); + + tbitem->setText(kCheck, QString::fromStdString(f.check())); + + QComboBox* collationBox = new QComboBox(ui->treeWidget); + collationBox->setProperty("column", QString::fromStdString(f.name())); + collationBox->addItems(m_collationList); + index = collationBox->findText(QString::fromStdString(f.collation()), Qt::MatchCaseSensitive); + if(index == -1) + { + // some non-existing collation + collationBox->addItem(QString::fromStdString(f.collation())); + index = collationBox->count() - 1; + } + collationBox->setCurrentIndex(index); + collationBox->installEventFilter(this); + connect(collationBox, SIGNAL(currentIndexChanged(int)), this, SLOT(updateTypeAndCollation())); + ui->treeWidget->setItemWidget(tbitem, kCollation, collationBox); + + auto fk = std::dynamic_pointer_cast(m_table.constraint({f.name()}, sqlb::Constraint::ForeignKeyConstraintType)); + if(fk) + tbitem->setText(kForeignKey, QString::fromStdString(fk->toString())); + ui->treeWidget->addTopLevelItem(tbitem); + } + + // and reconnect + ui->treeWidget->blockSignals(false); +} + +void EditTableDialog::populateConstraints() +{ + // Disable the itemChanged signal or the table item will be updated while filling the treewidget + ui->tableConstraints->blockSignals(true); + + const auto& constraints = m_table.allConstraints(); + + ui->tableConstraints->setRowCount(static_cast(constraints.size())); + int row = 0; + for(const auto& constraint : constraints) + { + const auto columns = constraint->columnList(); + + // Columns + QTableWidgetItem* column = new QTableWidgetItem(QString::fromStdString(sqlb::joinStringVector(columns, ","))); + column->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); + column->setData(Qt::UserRole, QVariant::fromValue(constraint)); // Remember address of constraint object. This is used for modifying it later + ui->tableConstraints->setItem(row, kConstraintColumns, column); + + // Type + QComboBox* type = new QComboBox(this); + type->addItem(tr("Primary Key")); // NOTE: The order of the items here have to match the order in the sqlb::Constraint::ConstraintTypes enum! + type->addItem(tr("Unique")); + type->addItem(tr("Foreign Key")); + type->addItem(tr("Check")); + type->setCurrentIndex(constraint->type()); + connect(type, static_cast(&QComboBox::currentIndexChanged), [this, type, constraint](int index) { + // Handle change of constraint type. Effectively this means removing the old constraint and replacing it by an entirely new one. + // Only the column list and the name can be migrated to the new constraint. + + // Make sure there is only one primary key at a time + if(index == 0 && m_table.primaryKey()) + { + QMessageBox::warning(this, qApp->applicationName(), tr("There can only be one primary key for each table. Please modify the existing primary " + "key instead.")); + + // Set combo box back to original constraint type + type->blockSignals(true); + type->setCurrentIndex(constraint->type()); + type->blockSignals(false); + return; + } + + // Create new constraint depending on selected type + sqlb::ConstraintPtr new_constraint = sqlb::Constraint::makeConstraint(static_cast(index)); + new_constraint->setName(constraint->name()); + new_constraint->setColumnList(constraint->columnList()); + + // Replace old by new constraint + m_table.replaceConstraint(constraint, new_constraint); + + // Update SQL and view + populateFields(); + populateConstraints(); + updateSqlText(); + }); + ui->tableConstraints->setCellWidget(row, kConstraintType, type); + + // Name + QTableWidgetItem* name = new QTableWidgetItem(QString::fromStdString(constraint->name())); + name->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsEditable); + ui->tableConstraints->setItem(row, kConstraintName, name); + + // SQL + QTableWidgetItem* sql = new QTableWidgetItem(QString::fromStdString(constraint->toSql())); + sql->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); + ui->tableConstraints->setItem(row, kConstraintSql, sql); + + row++; + } + + ui->tableConstraints->blockSignals(false); +} + +void EditTableDialog::accept() +{ + // Are we editing an already existing table or designing a new one? In the first case there is a table name set, + // in the latter the current table name is empty + if(m_bNewTable) + { + // Creation of new table + if(!pdb.executeSQL(m_table.sql(ui->comboSchema->currentText().toStdString()))) + { + QMessageBox::warning( + this, + QApplication::applicationName(), + tr("Error creating table. Message from database engine:\n%1").arg(pdb.lastError())); + return; + } + } else { + // Editing of old table + + // Apply all changes to the actual table in the database + if(!pdb.alterTable(curTable, m_table, trackColumns, ui->comboSchema->currentText().toStdString())) + { + QMessageBox::warning(this, QApplication::applicationName(), pdb.lastError()); + return; + } + } + + QDialog::accept(); +} + +void EditTableDialog::reject() +{ + // Then rollback to our savepoint + pdb.revertToSavepoint(m_sRestorePointName); + + QDialog::reject(); +} + +void EditTableDialog::updateSqlText() +{ + ui->sqlTextEdit->setText(QString::fromStdString(m_table.sql(ui->comboSchema->currentText().toStdString()))); +} + +void EditTableDialog::checkInput() +{ + std::string normTableName = ui->editTableName->text().toStdString(); + bool valid = true; + if(normTableName.empty()) + valid = false; + if(ui->treeWidget->topLevelItemCount() == 0) + valid = false; + if (normTableName != m_table.name()) { + const std::string oldTableName = m_table.name(); + m_table.setName(normTableName); + + // update fk's that refer to table itself recursively + const auto& fields = m_table.fields; + for(const sqlb::Field& f : fields) { + auto fk = std::dynamic_pointer_cast(m_table.constraint({f.name()}, sqlb::Constraint::ForeignKeyConstraintType)); + if(fk && oldTableName == fk->table()) + fk->setTable(normTableName); + } + + populateFields(); + } + + updateSqlText(); + ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(valid); +} + +void EditTableDialog::updateTypeAndCollation(QObject* object) +{ + // Get sender combo box and retrieve field name from it + QComboBox* combo = qobject_cast(object); + if(!combo) + return; + QString column = combo->property("column").toString(); + + // Get type *and* collation combo box for this field + auto item = ui->treeWidget->findItems(column, Qt::MatchExactly, kName); + if(item.size() != 1) + return; + QComboBox* typeBox = qobject_cast(ui->treeWidget->itemWidget(item.front(), kType)); + QComboBox* collationBox = qobject_cast(ui->treeWidget->itemWidget(item.front(), kCollation)); + + // Update table + if(typeBox && collationBox) + { + QString type = typeBox->currentText(); + QString collation = collationBox->currentText(); + + for(size_t index=0; index < m_table.fields.size(); ++index) + { + if(m_table.fields.at(index).name() == column.toStdString()) + { + m_table.fields.at(index).setType(type.toStdString()); + m_table.fields.at(index).setCollation(collation.toStdString()); + break; + } + } + + checkInput(); + } +} + +void EditTableDialog::updateTypeAndCollation() +{ + updateTypeAndCollation(sender()); +} + +bool EditTableDialog::eventFilter(QObject *object, QEvent *event) +{ + if(event->type() == QEvent::FocusOut) + { + updateTypeAndCollation(object); + } + return false; +} + +void EditTableDialog::fieldItemChanged(QTreeWidgetItem *item, int column) +{ + size_t index = static_cast(ui->treeWidget->indexOfTopLevelItem(item)); + if(index < m_table.fields.size()) + { + sqlb::Field& field = m_table.fields.at(index); + QString oldFieldName = QString::fromStdString(field.name()); + + switch(column) + { + case kName: + { + // When a field of that name already exists, show a warning to the user and don't apply the new name. This is done by searching for an + // existing field with the new name. There is one exception, however, to this rule: if the field that we have found is the same field + // as the one we are currently trying to rename, this means the user is trying to rename the field to essentially the same name but + // with different case. Example: if I rename column 'COLUMN' to 'column', findField() is going to return the current field number + // because it's doing a case-independent search and it can't return another field number because SQLite prohibits duplicate field + // names (no matter the case). So when this happens we just allow the renaming because there's no harm to be expected from it. + auto foundField = sqlb::findField(m_table, item->text(column).toStdString()); + if(foundField != m_table.fields.end() && foundField-m_table.fields.begin() != static_cast(index)) + { + QMessageBox::warning(this, qApp->applicationName(), tr("There already is a field with that name. Please rename it first or choose a different " + "name for this field.")); + // Reset the name to the old value but avoid calling this method again for that automatic change + ui->treeWidget->blockSignals(true); + item->setText(column, oldFieldName); + ui->treeWidget->blockSignals(false); + return; + } + + // When editing an exiting table, check if any foreign keys would cause trouble in case this name is edited + if(!m_bNewTable) + { + const auto pk = m_table.primaryKey(); + const auto tables = pdb.schemata[curTable.schema()].equal_range("table"); + for(auto it=tables.first;it!=tables.second;++it) + { + const sqlb::ObjectPtr& fkobj = it->second; + + + auto fks = std::dynamic_pointer_cast(fkobj)->constraints({}, sqlb::Constraint::ForeignKeyConstraintType); + for(const sqlb::ConstraintPtr& fkptr : fks) + { + auto fk = std::dynamic_pointer_cast(fkptr); + if(fk->table() == m_table.name()) + { + if(contains(fk->columns(), field.name()) || (pk && contains(pk->columnList(), field.name()))) + { + QMessageBox::warning(this, qApp->applicationName(), tr("This column is referenced in a foreign key in table %1 and thus " + "its name cannot be changed.") + .arg(QString::fromStdString(fkobj->name()))); + // Reset the name to the old value but avoid calling this method again for that automatic change + ui->treeWidget->blockSignals(true); + item->setText(column, oldFieldName); + ui->treeWidget->blockSignals(false); + return; + } + } + } + } + } + + field.setName(item->text(column).toStdString()); + m_table.renameKeyInAllConstraints(oldFieldName.toStdString(), item->text(column).toStdString()); + qobject_cast(ui->treeWidget->itemWidget(item, kType))->setProperty("column", item->text(column)); + qobject_cast(ui->treeWidget->itemWidget(item, kCollation))->setProperty("column", item->text(column)); + + // Update the field name in the map of old column names to new column names + if(!m_bNewTable) + { + for(const auto& it : trackColumns) + { + if(trackColumns[it.first] == oldFieldName) + trackColumns[it.first] = QString::fromStdString(field.name()); + } + } + + // Update the constraints view + populateConstraints(); + } break; + case kType: + case kCollation: + // see updateTypeAndCollation() SLOT + break; + case kPrimaryKey: + { + // Check if there already is a primary key + auto pk = m_table.primaryKey(); + if(pk) + { + // There already is a primary key for this table. So edit that one as there always can only be one primary key anyway. + if(item->checkState(column) == Qt::Checked) + { + pk->addToColumnList(field.name()); + } else { + pk->removeFromColumnList(field.name()); + + // If this is now a primary key constraint without any columns, remove it entirely + if(pk->columnList().empty()) + m_table.removeConstraints({}, sqlb::Constraint::PrimaryKeyConstraintType); + } + } else if(item->checkState(column) == Qt::Checked) { + // There is no primary key in the table yet. This means we need to add a default one. + m_table.addConstraint(sqlb::ConstraintPtr(new sqlb::PrimaryKeyConstraint({field.name()}))); + } + + if(item->checkState(column) == Qt::Checked) + { + // this will unset any other autoincrement + for(int i = 0; i < ui->treeWidget->topLevelItemCount(); ++i) + { + QTreeWidgetItem* tbitem = ui->treeWidget->topLevelItem(i); + if(tbitem != item) + tbitem->setCheckState(kAutoIncrement, Qt::Unchecked); + } + } else { + item->setCheckState(kAutoIncrement, Qt::Unchecked); + } + + // Update the constraints view + populateConstraints(); + } + break; + case kNotNull: + { + // When editing an existing table and trying to set a column to Not Null an extra check is needed + if(!m_bNewTable && item->checkState(column) == Qt::Checked) + { + // Because our renameColumn() function fails when setting a column to Not Null when it already contains some NULL values + // we need to check for this case and cancel here. Maybe we can think of some way to modify the INSERT INTO ... SELECT statement + // to at least replace all troublesome NULL values by the default value + SqliteTableModel m(pdb, this); + m.setQuery(QString("SELECT COUNT(%1) FROM %2 WHERE coalesce(NULL,%3) IS NULL;").arg( + QString::fromStdString(sqlb::joinStringVector(sqlb::escapeIdentifier(pdb.getObjectByName(curTable)->rowidColumns()), ",")), + QString::fromStdString(curTable.toString()), + QString::fromStdString(sqlb::escapeIdentifier(field.name())))); + if(!m.completeCache()) + { + // If we couldn't load all data because the cancel button was clicked, just unset the checkbox again and stop. + item->setCheckState(column, Qt::Unchecked); + return; + } + if(m.data(m.index(0, 0)).toInt() > 0) + { + // There is a NULL value, so print an error message, uncheck the combobox, and return here + QMessageBox::information(this, qApp->applicationName(), tr("There is at least one row with this field set to NULL. " + "This makes it impossible to set this flag. Please change the table data first.")); + item->setCheckState(column, Qt::Unchecked); + return; + } + } + field.setNotNull(item->checkState(column) == Qt::Checked); + } + break; + case kAutoIncrement: + { + bool ischecked = item->checkState(column) == Qt::Checked; + if(ischecked) + { + // First check if the contents of this column are all integers. If not this field cannot be set to AI + if(!m_bNewTable) + { + SqliteTableModel m(pdb, this); + m.setQuery(QString("SELECT COUNT(*) FROM %1 WHERE %2 <> CAST(%3 AS INTEGER);").arg( + QString::fromStdString(curTable.toString()), + QString::fromStdString(sqlb::escapeIdentifier(field.name())), + QString::fromStdString(sqlb::escapeIdentifier(field.name())))); + if(!m.completeCache()) + { + // If we couldn't load all data because the cancel button was clicked, just unset the checkbox again and stop. + item->setCheckState(column, Qt::Unchecked); + return; + } + if(m.data(m.index(0, 0)).toInt() > 0) + { + // There is a non-integer value, so print an error message, uncheck the combobox, and return here + QMessageBox::information(this, qApp->applicationName(), tr("There is at least one row with a non-integer value in this field. " + "This makes it impossible to set the AI flag. Please change the table data first.")); + item->setCheckState(column, Qt::Unchecked); + return; + } + } + + // Make sure the data type is set to integer + QComboBox* comboType = qobject_cast(ui->treeWidget->itemWidget(item, kType)); + comboType->setCurrentIndex(comboType->findText("INTEGER")); + item->setCheckState(kPrimaryKey, Qt::Checked); + + // this will unset all other primary keys + // there can't be more than one autoincrement pk + for(int i = 0; i < ui->treeWidget->topLevelItemCount(); ++i) + { + QTreeWidgetItem* tbitem = ui->treeWidget->topLevelItem(i); + if(tbitem != item) + { + tbitem->setCheckState(kAutoIncrement, Qt::Unchecked); + tbitem->setCheckState(kPrimaryKey, Qt::Unchecked); + } + } + } + if(m_table.primaryKey()) + m_table.primaryKey()->setAutoIncrement(ischecked); + } + break; + case kUnique: + { + // When editing an existing table and trying to set a column to unique an extra check is needed + if(!m_bNewTable && item->checkState(column) == Qt::Checked) + { + // Because our renameColumn() function fails when setting a column to unique when it already contains the same values + SqliteTableModel m(pdb, this); + m.setQuery(QString("SELECT COUNT(%2) FROM %1;").arg( + QString::fromStdString(curTable.toString()), + QString::fromStdString(sqlb::escapeIdentifier(field.name())))); + if(!m.completeCache()) + { + // If we couldn't load all data because the cancel button was clicked, just unset the checkbox again and stop. + item->setCheckState(column, Qt::Unchecked); + return; + } + int rowcount = m.data(m.index(0, 0)).toInt(); + m.setQuery(QString("SELECT COUNT(DISTINCT %2) FROM %1;").arg( + QString::fromStdString(curTable.toString()), + QString::fromStdString(sqlb::escapeIdentifier(field.name())))); + if(!m.completeCache()) + { + // If we couldn't load all data because the cancel button was clicked, just unset the checkbox again and stop. + item->setCheckState(column, Qt::Unchecked); + return; + } + int uniquecount = m.data(m.index(0, 0)).toInt(); + if(rowcount != uniquecount) + { + // There is a NULL value, so print an error message, uncheck the combobox, and return here + QMessageBox::information(this, qApp->applicationName(), tr("Column '%1' has duplicate data.\n").arg(QString::fromStdString(field.name())) + + tr("This makes it impossible to enable the 'Unique' flag. Please remove the duplicate data, which will allow the 'Unique' flag to then be enabled.")); + item->setCheckState(column, Qt::Unchecked); + return; + } + } + field.setUnique(item->checkState(column) == Qt::Checked); + } + break; + case kDefault: + { + QString new_value = item->text(column); + // If the default value isn't a SQL keyword perform an extra check: If it isn't numeric but doesn't start and end with quotes, + // add the quotes + if(new_value.size() && new_value.compare("null", Qt::CaseInsensitive) && + new_value.compare("current_time", Qt::CaseInsensitive) && + new_value.compare("current_date", Qt::CaseInsensitive) && + new_value.compare("current_timestamp", Qt::CaseInsensitive)) + { + QChar first_char = new_value.trimmed().at(0); + if(!((first_char == '\'' || first_char == '"') && new_value.trimmed().endsWith(first_char))) + { + bool is_numeric; + new_value.toDouble(&is_numeric); + if(!is_numeric) + { + if(new_value.trimmed().startsWith("=(") && new_value.trimmed().endsWith(')')) + { + new_value = new_value.trimmed().mid(1); // Leave the brackets as they are needed for a valid SQL expression + } else { + new_value = sqlb::escapeString(new_value); + item->setText(column, new_value); + } + } + } + } + field.setDefaultValue(new_value.toStdString()); + } + break; + case kCheck: + field.setCheck(item->text(column).toStdString()); + break; + case kForeignKey: + // handled in delegate + break; + } + } + + checkInput(); +} + +void EditTableDialog::constraintItemChanged(QTableWidgetItem* item) +{ + // Find modified constraint + sqlb::ConstraintPtr constraint = ui->tableConstraints->item(item->row(), kConstraintColumns)->data(Qt::UserRole).value(); + + // Which column has been modified? + switch(item->column()) + { + case kConstraintName: + constraint->setName(item->text().toStdString()); + break; + } + + // Update SQL + ui->tableConstraints->item(item->row(), kConstraintSql)->setText(QString::fromStdString(constraint->toSql())); + checkInput(); +} + +void EditTableDialog::addField() +{ + QTreeWidgetItem *tbitem = new QTreeWidgetItem(ui->treeWidget); + tbitem->setFlags(tbitem->flags() | Qt::ItemIsEditable); + + // Find an unused name for the field by starting with 'Fieldx' where x is the number of fields + 1. + // If this name happens to exist already, increase x by one until we find an unused name. + { + int field_number = ui->treeWidget->topLevelItemCount(); + std::string field_name; + do + { + field_name = "Field" + std::to_string(field_number); + field_number++; + } while(sqlb::findField(m_table, field_name) != m_table.fields.end()); + tbitem->setText(kName, QString::fromStdString(field_name)); + } + + QComboBox* typeBox = new QComboBox(ui->treeWidget); + typeBox->setProperty("column", tbitem->text(kName)); + typeBox->setEditable(true); + typeBox->addItems(DBBrowserDB::Datatypes); + + int defaultFieldTypeIndex = Settings::getValue("db", "defaultfieldtype").toInt(); + + if (defaultFieldTypeIndex < DBBrowserDB::Datatypes.count()) + { + typeBox->setCurrentIndex(defaultFieldTypeIndex); + } + + ui->treeWidget->setItemWidget(tbitem, kType, typeBox); + typeBox->installEventFilter(this); + connect(typeBox, SIGNAL(currentIndexChanged(int)), this, SLOT(updateTypeAndCollation())); + + QComboBox* collationBox = new QComboBox(ui->treeWidget); + collationBox->setProperty("column", tbitem->text(kName)); + collationBox->addItems(m_collationList); + collationBox->setCurrentIndex(collationBox->findText("")); + ui->treeWidget->setItemWidget(tbitem, kCollation, collationBox); + collationBox->installEventFilter(this); + connect(collationBox, SIGNAL(currentIndexChanged(int)), this, SLOT(updateTypeAndCollation())); + + tbitem->setCheckState(kNotNull, Qt::Unchecked); + tbitem->setCheckState(kPrimaryKey, Qt::Unchecked); + tbitem->setCheckState(kAutoIncrement, Qt::Unchecked); + tbitem->setCheckState(kUnique, Qt::Unchecked); + + ui->treeWidget->addTopLevelItem(tbitem); + ui->treeWidget->scrollToBottom(); + ui->treeWidget->editItem(tbitem, 0); + + // add field to table object + m_table.fields.emplace_back(tbitem->text(kName).toStdString(), typeBox->currentText().toStdString()); + + // Add the new column to the list of tracked columns to indicate it has been added + if(!m_bNewTable) + trackColumns.insert({QString(), tbitem->text(kName)}); + + checkInput(); +} + +void EditTableDialog::removeField() +{ + // Is there any item selected to delete? + if(!ui->treeWidget->currentItem()) + return; + + // If we are editing an existing table, ask the user for confirmation + if(!m_bNewTable) + { + QString msg = tr("Are you sure you want to delete the field '%1'?\nAll data currently stored in this field will be lost.").arg(ui->treeWidget->currentItem()->text(0)); + if(QMessageBox::warning(this, QApplication::applicationName(), msg, QMessageBox::Yes | QMessageBox::No, QMessageBox::No) == QMessageBox::No) + return; + + // Update the map of tracked columns to indicate the column is deleted + QString name = ui->treeWidget->currentItem()->text(0); + for(const auto& it : trackColumns) + { + if(trackColumns[it.first] == name) + trackColumns[it.first] = QString(); + } + } + + // Just delete that item. At this point there is no DB table to edit or data to be lost anyway + m_table.fields.erase(m_table.fields.begin() + ui->treeWidget->indexOfTopLevelItem(ui->treeWidget->currentItem())); + m_table.removeKeyFromAllConstraints(ui->treeWidget->currentItem()->text(kName).toStdString()); + delete ui->treeWidget->currentItem(); + + // Update the constraints view + populateConstraints(); + + checkInput(); +} + +void EditTableDialog::fieldSelectionChanged() +{ + bool hasSelection = ui->treeWidget->selectionModel()->hasSelection(); + + // Enable the remove and the move up/down buttons if a field is selected, disable it otherwise + ui->removeFieldButton->setEnabled(hasSelection); + ui->buttonMoveUp->setEnabled(hasSelection); + ui->buttonMoveDown->setEnabled(hasSelection); + + // If the selected line is the first one disable the move up button, it it's the last one disable the move down button + if(hasSelection) + { + ui->buttonMoveUp->setEnabled(ui->treeWidget->selectionModel()->currentIndex().row() != 0); + ui->buttonMoveTop->setEnabled(ui->buttonMoveUp->isEnabled()); + ui->buttonMoveDown->setEnabled(ui->treeWidget->selectionModel()->currentIndex().row() != ui->treeWidget->topLevelItemCount() - 1); + ui->buttonMoveBottom->setEnabled(ui->buttonMoveDown->isEnabled()); + } +} + +void EditTableDialog::moveUp() +{ + moveCurrentField(MoveUp); +} + +void EditTableDialog::moveDown() +{ + moveCurrentField(MoveDown); +} + +void EditTableDialog::moveTop() +{ + moveCurrentField(MoveTop); +} + +void EditTableDialog::moveBottom() +{ + moveCurrentField(MoveBottom); +} + +void EditTableDialog::moveCurrentField(MoveFieldDirection dir) +{ + int currentRow = ui->treeWidget->currentIndex().row(); + int newRow; + if(dir == MoveUp) + newRow = currentRow - 1; + else if(dir == MoveDown) + newRow = currentRow + 1; + else if(dir == MoveTop) + newRow = 0; + else if(dir == MoveBottom) + newRow = ui->treeWidget->topLevelItemCount() - 1; + else + return; + + // Save the comboboxes first by making copies + QComboBox* newCombo[2]; + for(int c=0;c<2;c++) + { + int column = (c == 0 ? kType : kCollation); + + QComboBox* oldCombo = qobject_cast(ui->treeWidget->itemWidget(ui->treeWidget->topLevelItem(currentRow), column)); + newCombo[c] = new QComboBox(ui->treeWidget); + newCombo[c]->setProperty("column", oldCombo->property("column")); + newCombo[c]->installEventFilter(this); + connect(newCombo[c], SIGNAL(currentIndexChanged(int)), this, SLOT(updateTypeAndCollation())); + newCombo[c]->setEditable(oldCombo->isEditable()); + for(int i=0; i < oldCombo->count(); ++i) + newCombo[c]->addItem(oldCombo->itemText(i)); + newCombo[c]->setCurrentIndex(oldCombo->currentIndex()); + } + + // Now, just remove the item and insert it at it's new position, then restore the combobox + QTreeWidgetItem* item = ui->treeWidget->takeTopLevelItem(currentRow); + ui->treeWidget->insertTopLevelItem(newRow, item); + ui->treeWidget->setItemWidget(item, kType, newCombo[0]); + ui->treeWidget->setItemWidget(item, kCollation, newCombo[1]); + + // Select the old item at its new position + ui->treeWidget->setCurrentIndex(ui->treeWidget->currentIndex().sibling(newRow, 0)); + + // Finally update the table SQL + sqlb::Field temp = m_table.fields[static_cast(currentRow)]; + m_table.fields.erase(m_table.fields.begin() + currentRow); + m_table.fields.insert(m_table.fields.begin() + newRow, temp); + + // Update the SQL preview + updateSqlText(); +} + +void EditTableDialog::setWithoutRowid(bool without_rowid) +{ + if(without_rowid) + { + // Before setting the without rowid flag, first perform a check to see if the table meets all the required criteria for without rowid tables + const auto pk = m_table.primaryKey(); + if(!pk || pk->autoIncrement()) + { + QMessageBox::information(this, QApplication::applicationName(), + tr("Please add a field which meets the following criteria before setting the without rowid flag:\n" + " - Primary key flag set\n" + " - Auto increment disabled")); + + // Reset checkbox state to unchecked. Block any signals while doing this in order to avoid an extra call to + // this function being triggered. + ui->checkWithoutRowid->blockSignals(true); + ui->checkWithoutRowid->setChecked(false); + ui->checkWithoutRowid->blockSignals(false); + return; + } + + // If it does, set the without rowid flag of the table + m_table.setWithoutRowidTable(true); + } else { + // If the without rowid flag is unset no further checks are required. Just unset the without rowid flag + m_table.setWithoutRowidTable(false); + } + + // Update the SQL preview + updateSqlText(); +} + +void EditTableDialog::changeSchema(const QString& /*schema*/) +{ + // Update the SQL preview + updateSqlText(); +} + +void EditTableDialog::removeConstraint() +{ + // Is there any item selected to delete? + if(!ui->tableConstraints->currentItem()) + return; + + // Find constraint to delete + int row = ui->tableConstraints->currentRow(); + sqlb::ConstraintPtr constraint = ui->tableConstraints->item(row, kConstraintColumns)->data(Qt::UserRole).value(); + + // Remove the constraint. If there is more than one constraint with this combination of columns and constraint type, only delete the first one. + m_table.removeConstraint(constraint); + ui->tableConstraints->removeRow(ui->tableConstraints->currentRow()); + + // Update SQL and view + updateSqlText(); + populateFields(); +} + +void EditTableDialog::addConstraint(sqlb::Constraint::ConstraintTypes type) +{ + // There can only be one primary key + if(type == sqlb::Constraint::PrimaryKeyConstraintType) + { + if(m_table.primaryKey()) + { + QMessageBox::information(this, qApp->applicationName(), tr("There can only be one primary key for each table. Please modify the existing primary " + "key instead.")); + return; + } + } + + // Create new constraint + sqlb::ConstraintPtr constraint = sqlb::Constraint::makeConstraint(type); + m_table.addConstraint(constraint); + + // Update SQL and view + populateFields(); + populateConstraints(); + updateSqlText(); +} diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/EditTableDialog.h b/src/WBCLFZSystemModule/SqliteDBProcess/src/EditTableDialog.h new file mode 100644 index 0000000..7c7191a --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/EditTableDialog.h @@ -0,0 +1,101 @@ +#ifndef EDITTABLEDIALOG_H +#define EDITTABLEDIALOG_H + +#include "sql/ObjectIdentifier.h" +#include "sql/sqlitetypes.h" + +#include + +#include + +class DBBrowserDB; +class ForeignKeyEditorDelegate; + +class QTableWidgetItem; +class QTreeWidgetItem; + +namespace Ui { +class EditTableDialog; +} + +class EditTableDialog : public QDialog +{ + Q_OBJECT + +public: + explicit EditTableDialog(DBBrowserDB& pdb, const sqlb::ObjectIdentifier& tableName, bool createTable, QWidget* parent = nullptr); + ~EditTableDialog() override; + +protected: + void keyPressEvent(QKeyEvent *evt) override; + +private: + enum Columns { + kName = 0, + kType = 1, + kNotNull = 2, + kPrimaryKey = 3, + kAutoIncrement = 4, + kUnique = 5, + kDefault = 6, + kCheck = 7, + kCollation = 8, + kForeignKey = 9 + }; + + enum ConstraintColumns { + kConstraintColumns = 0, + kConstraintType = 1, + kConstraintName = 2, + kConstraintSql = 3 + }; + + enum MoveFieldDirection + { + MoveUp, + MoveDown, + MoveTop, + MoveBottom + }; + + void updateColumnWidth(); + void updateSqlText(); + + void moveCurrentField(MoveFieldDirection dir); + +private slots: + void populateFields(); + void populateConstraints(); + void addField(); + void removeField(); + void fieldSelectionChanged(); + void accept() override; + void reject() override; + void checkInput(); + void fieldItemChanged(QTreeWidgetItem* item, int column); + void constraintItemChanged(QTableWidgetItem* item); + void updateTypeAndCollation(QObject *object); + bool eventFilter(QObject *object, QEvent *event) override; + void updateTypeAndCollation(); + void moveUp(); + void moveDown(); + void moveTop(); + void moveBottom(); + void setWithoutRowid(bool without_rowid); + void changeSchema(const QString& schema); + void removeConstraint(); + void addConstraint(sqlb::Constraint::ConstraintTypes type); + +private: + Ui::EditTableDialog* ui; + DBBrowserDB& pdb; + ForeignKeyEditorDelegate* m_fkEditorDelegate; + sqlb::ObjectIdentifier curTable; + std::map trackColumns; + sqlb::Table m_table; + bool m_bNewTable; + std::string m_sRestorePointName; + QStringList m_collationList; +}; + +#endif diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/EditTableDialog.ui b/src/WBCLFZSystemModule/SqliteDBProcess/src/EditTableDialog.ui new file mode 100644 index 0000000..a4cf505 --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/EditTableDialog.ui @@ -0,0 +1,782 @@ + + + EditTableDialog + + + + 0 + 0 + 652 + 600 + + + + Edit table definition + + + + :/icons/table:/icons/table + + + true + + + + + + Table + + + + + + + 75 + true + + + + + + + + Advanced + + + true + + + Qt::ToolButtonTextBesideIcon + + + Qt::DownArrow + + + + + + + + + + Database sche&ma + + + comboSchema + + + + + + + + + + Without Rowid + + + checkWithoutRowid + + + + + + + Make this a 'WITHOUT rowid' table. Setting this flag requires a field of type INTEGER with the primary key flag set and the auto increment flag unset. + + + + + + + + + + + + + Qt::Vertical + + + + 0 + + + + Fields + + + + + + + + Add + + + + :/icons/field_add:/icons/field_add + + + Qt::ToolButtonTextBesideIcon + + + true + + + + + + + false + + + Remove + + + + :/icons/field_delete:/icons/field_delete + + + Qt::ToolButtonTextBesideIcon + + + true + + + + + + + false + + + Move to top + + + + :/icons/arrow_top:/icons/arrow_top + + + Qt::ToolButtonTextBesideIcon + + + true + + + Qt::NoArrow + + + + + + + false + + + Move up + + + + :/icons/up:/icons/up + + + Qt::ToolButtonTextBesideIcon + + + true + + + + + + + false + + + Move down + + + + :/icons/down:/icons/down + + + Qt::ToolButtonTextBesideIcon + + + true + + + + + + + false + + + Move to bottom + + + + :/icons/arrow_bottom:/icons/arrow_bottom + + + Qt::ToolButtonTextBesideIcon + + + true + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + 0 + 0 + + + + + 0 + 140 + + + + false + + + + Name + + + + + Type + + + + + NN + + + Not null + + + + + PK + + + Primary key + + + + + AI + + + Autoincrement + + + + + U + + + Unique + + + + + Default + + + Default value + + + + + Check + + + Check constraint + + + + + Collation + + + + + Foreign Key + + + + + + + + + Constraints + + + + + + + + Add constraint + + + + :/icons/field_add:/icons/field_add + + + QToolButton::InstantPopup + + + Qt::ToolButtonTextBesideIcon + + + true + + + + + + + false + + + Remove constraint + + + + :/icons/field_delete:/icons/field_delete + + + Qt::ToolButtonTextBesideIcon + + + true + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + QAbstractItemView::ScrollPerPixel + + + + Columns + + + + + Type + + + + + Name + + + + + SQL + + + + + + + + + + true + + + + + + + + <html><head/><body><p><span style=" font-weight:600; color:#ff0000;">Warning: </span>There is something with this table definition that our parser doesn't fully understand. Modifying and saving this table might result in problems.</p></body></html> + + + true + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + :/icons/field_key:/icons/field_key + + + Primary Key + + + Add a primary key constraint + + + + + + :/icons/field_fk:/icons/field_fk + + + Foreign Key + + + Add a foreign key constraint + + + + + Unique + + + Add a unique constraint + + + + + Check + + + Add a check constraint + + + + + + SqlTextEdit + QWidget +
sqltextedit.h
+ 1 +
+
+ + editTableName + buttonMore + comboSchema + checkWithoutRowid + groupDefinition + addFieldButton + removeFieldButton + buttonMoveTop + buttonMoveUp + buttonMoveDown + buttonMoveBottom + treeWidget + sqlTextEdit + buttonAddConstraint + buttonRemoveConstraint + tableConstraints + + + + + + + buttonBox + accepted() + EditTableDialog + accept() + + + 261 + 590 + + + 157 + 274 + + + + + buttonBox + rejected() + EditTableDialog + reject() + + + 329 + 590 + + + 286 + 274 + + + + + treeWidget + itemSelectionChanged() + EditTableDialog + fieldSelectionChanged() + + + 137 + 367 + + + 411 + 181 + + + + + addFieldButton + clicked() + EditTableDialog + addField() + + + 78 + 255 + + + 79 + 65 + + + + + removeFieldButton + clicked() + EditTableDialog + removeField() + + + 167 + 255 + + + 249 + 63 + + + + + editTableName + textChanged(QString) + EditTableDialog + checkInput() + + + 62 + 48 + + + 115 + 3 + + + + + buttonMoveUp + clicked() + EditTableDialog + moveUp() + + + 343 + 253 + + + 308 + 235 + + + + + buttonMoveDown + clicked() + EditTableDialog + moveDown() + + + 481 + 253 + + + 308 + 235 + + + + + buttonMore + toggled(bool) + widgetExtension + setVisible(bool) + + + 97 + 78 + + + 138 + 172 + + + + + checkWithoutRowid + toggled(bool) + EditTableDialog + setWithoutRowid(bool) + + + 485 + 160 + + + 324 + 299 + + + + + treeWidget + currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*) + EditTableDialog + fieldSelectionChanged() + + + 324 + 294 + + + 324 + 299 + + + + + comboSchema + currentIndexChanged(QString) + EditTableDialog + changeSchema(QString) + + + 327 + 139 + + + 647 + 157 + + + + + buttonRemoveConstraint + clicked() + EditTableDialog + removeConstraint() + + + 295 + 255 + + + 647 + 157 + + + + + buttonMoveTop + clicked() + EditTableDialog + moveTop() + + + 207 + 240 + + + 202 + 190 + + + + + buttonMoveBottom + clicked() + EditTableDialog + moveBottom() + + + 530 + 246 + + + 400 + 186 + + + + + + fieldSelectionChanged() + addField() + editField() + removeField() + checkInput() + itemChanged() + moveUp() + moveDown() + setWithoutRowid(bool) + changeSchema(QString) + removeConstraint() + moveTop() + moveBottom() + +
diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/ExportDataDialog.cpp b/src/WBCLFZSystemModule/SqliteDBProcess/src/ExportDataDialog.cpp new file mode 100644 index 0000000..6d2e382 --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/ExportDataDialog.cpp @@ -0,0 +1,585 @@ +#include "ExportDataDialog.h" +#include "ui_ExportDataDialog.h" +#include "sqlitedb.h" +#include "Settings.h" +#include "sqlite.h" +#include "FileDialog.h" +#include "IconCache.h" + +#include +#include +#include +#include +#include + +using json = nlohmann::json; + +ExportDataDialog::ExportDataDialog(DBBrowserDB& db, ExportFormats format, QWidget* parent, const std::string& query, const sqlb::ObjectIdentifier& selection) + : QDialog(parent), + ui(new Ui::ExportDataDialog), + pdb(db), + m_format(format), + m_sQuery(query) +{ + // Create UI + ui->setupUi(this); + + // Show different option widgets depending on the export format + ui->stackFormat->setCurrentIndex(format); + if(format == ExportFormatJson) { + setWindowTitle(tr("Export data as JSON")); + } + + // Retrieve the saved dialog preferences + ui->checkHeader->setChecked(Settings::getValue("exportcsv", "firstrowheader").toBool()); + setSeparatorChar(Settings::getValue("exportcsv", "separator").toInt()); + setQuoteChar(Settings::getValue("exportcsv", "quotecharacter").toInt()); + setNewLineString(Settings::getValue("exportcsv", "newlinecharacters").toString()); + ui->checkPrettyPrint->setChecked(Settings::getValue("exportjson", "prettyprint").toBool()); + + // Update the visible/hidden status of the "Other" line edit fields + showCustomCharEdits(); + + // If a SQL query was specified hide the table combo box. If not fill it with tables to export + if(query.empty()) + { + // Get list of tables to export + for(const auto& it : pdb.schemata) + { + const auto tables = it.second.equal_range("table"); + const auto views = it.second.equal_range("view"); + std::map objects; + for(auto jt=tables.first;jt!=tables.second;++jt) + objects.insert({jt->second->name(), jt->second}); + for(auto jt=views.first;jt!=views.second;++jt) + objects.insert({jt->second->name(), jt->second}); + + for(const auto& jt : objects) + { + sqlb::ObjectIdentifier obj(it.first, jt.second->name()); + QListWidgetItem* item = new QListWidgetItem(IconCache::get(sqlb::Object::typeToString(jt.second->type())), QString::fromStdString(obj.toDisplayString())); + item->setData(Qt::UserRole, QString::fromStdString(obj.toSerialised())); + ui->listTables->addItem(item); + } + } + + // Sort list of tables and select the table specified in the selection parameter or alternatively the first one + ui->listTables->model()->sort(0); + if(selection.isEmpty()) + { + ui->listTables->setCurrentItem(ui->listTables->item(0)); + } else { + for(int i=0;ilistTables->count();i++) + { + if(sqlb::ObjectIdentifier(ui->listTables->item(i)->data(Qt::UserRole).toString().toStdString()) == selection) + { + ui->listTables->setCurrentRow(i); + break; + } + } + } + } else { + // Hide table combo box + ui->labelTable->setVisible(false); + ui->listTables->setVisible(false); + resize(minimumSize()); + } +} + +ExportDataDialog::~ExportDataDialog() +{ + delete ui; +} + +bool ExportDataDialog::exportQuery(const std::string& sQuery, const QString& sFilename) +{ + switch(m_format) + { + case ExportFormatCsv: + return exportQueryCsv(sQuery, sFilename); + case ExportFormatJson: + return exportQueryJson(sQuery, sFilename); + } + + return false; +} + +bool ExportDataDialog::exportQueryCsv(const std::string& sQuery, const QString& sFilename) +{ + // Prepare the quote and separating characters + QChar quoteChar = currentQuoteChar(); + QString quotequoteChar = QString(quoteChar) + quoteChar; + QChar sepChar = currentSeparatorChar(); + QString newlineStr = currentNewLineString(); + + // Chars that require escaping + std::string special_chars = newlineStr.toStdString() + sepChar.toLatin1() + quoteChar.toLatin1(); + + // Open file + QFile file(sFilename); + if(file.open(QIODevice::WriteOnly)) + { + // Open text stream to the file + QTextStream stream(&file); + + auto pDb = pdb.get(tr("exporting CSV")); + + sqlite3_stmt* stmt; + int status = sqlite3_prepare_v2(pDb.get(), sQuery.c_str(), static_cast(sQuery.size()), &stmt, nullptr); + if(SQLITE_OK == status) + { + if(ui->checkHeader->isChecked()) + { + int columns = sqlite3_column_count(stmt); + for (int i = 0; i < columns; ++i) + { + QString content = QString::fromUtf8(sqlite3_column_name(stmt, i)); + if(content.toStdString().find_first_of(special_chars) != std::string::npos) + stream << quoteChar << content.replace(quoteChar, quotequoteChar) << quoteChar; + else + stream << content; + if(i != columns - 1) + // Only output the separator value if sepChar isn't 0, + // as that's used to indicate no separator character + // should be used + if(!sepChar.isNull()) + stream << sepChar; + } + stream << newlineStr; + } + + QApplication::setOverrideCursor(Qt::WaitCursor); + int columns = sqlite3_column_count(stmt); + size_t counter = 0; + while(sqlite3_step(stmt) == SQLITE_ROW) + { + for (int i = 0; i < columns; ++i) + { + QString content = QString::fromUtf8( + reinterpret_cast(sqlite3_column_blob(stmt, i)), + sqlite3_column_bytes(stmt, i)); + + // If no quote char is set but the content contains a line break, we enforce some quote characters. This probably isn't entirely correct + // but still better than having the line breaks unquoted and effectively outputting a garbage file. + if(quoteChar.isNull() && content.contains(newlineStr)) + stream << '"' << content.replace('"', "\"\"") << '"'; + // If the content needs to be quoted, quote it. But only if a quote char has been specified + else if(!quoteChar.isNull() && content.toStdString().find_first_of(special_chars) != std::string::npos) + stream << quoteChar << content.replace(quoteChar, quotequoteChar) << quoteChar; + // If it doesn't need to be quoted, don't quote it + else + stream << content; + + if(i != columns - 1) + // Only output the separator value if sepChar isn't 0, + // as that's used to indicate no separator character + // should be used + if(!sepChar.isNull()) + stream << sepChar; + } + stream << newlineStr; + if(counter % 1000 == 0) + qApp->processEvents(); + counter++; + } + } + sqlite3_finalize(stmt); + + QApplication::restoreOverrideCursor(); + qApp->processEvents(); + + // Done writing the file + file.close(); + } else { + QMessageBox::warning(this, QApplication::applicationName(), + tr("Could not open output file: %1").arg(sFilename)); + return false; + } + + return true; +} + +bool ExportDataDialog::exportQueryJson(const std::string& sQuery, const QString& sFilename) +{ + // Open file + QFile file(sFilename); + if(file.open(QIODevice::WriteOnly)) + { + auto pDb = pdb.get(tr("exporting JSON")); + + sqlite3_stmt* stmt; + int status = sqlite3_prepare_v2(pDb.get(), sQuery.c_str(), static_cast(sQuery.size()), &stmt, nullptr); + + json json_table; + + if(SQLITE_OK == status) + { + QApplication::setOverrideCursor(Qt::WaitCursor); + int columns = sqlite3_column_count(stmt); + size_t counter = 0; + std::vector column_names; + while(sqlite3_step(stmt) == SQLITE_ROW) + { + // Get column names if we didn't do so before + if(!column_names.size()) + { + for(int i=0;i(i)]; + + switch (type) { + case SQLITE_INTEGER: { + qint64 content = sqlite3_column_int64(stmt, i); + json_row[column_name] = content; + break; + } + case SQLITE_FLOAT: { + double content = sqlite3_column_double(stmt, i); + json_row[column_name] = content; + break; + } + case SQLITE_NULL: { + json_row[column_name] = nullptr; + break; + } + case SQLITE_TEXT: { + QString content = QString::fromUtf8( + reinterpret_cast(sqlite3_column_text(stmt, i)), + sqlite3_column_bytes(stmt, i)); + json_row[column_name] = content.toStdString(); + break; + } + case SQLITE_BLOB: { + QByteArray content(reinterpret_cast(sqlite3_column_blob(stmt, i)), + sqlite3_column_bytes(stmt, i)); + QTextCodec *codec = QTextCodec::codecForName("UTF-8"); + QString string = codec->toUnicode(content.toBase64(QByteArray::Base64Encoding)); + json_row[column_name] = string.toStdString(); + break; + } + } + } + + json_table.push_back(json_row); + + if(counter % 1000 == 0) + qApp->processEvents(); + counter++; + } + } + + sqlite3_finalize(stmt); + + // Create JSON document + file.write(json_table.dump(ui->checkPrettyPrint->isChecked() ? 4 : -1).c_str()); + + QApplication::restoreOverrideCursor(); + qApp->processEvents(); + + // Done writing the file + file.close(); + } else { + QMessageBox::warning(this, QApplication::applicationName(), + tr("Could not open output file: %1").arg(sFilename)); + return false; + } + + return true; +} + +void ExportDataDialog::accept() +{ + QStringList file_dialog_filter; + QString default_file_extension; + switch(m_format) + { + case ExportFormatCsv: + file_dialog_filter << FILE_FILTER_CSV + << FILE_FILTER_TSV + << FILE_FILTER_DSV + << FILE_FILTER_TXT + << FILE_FILTER_ALL; + default_file_extension = FILE_EXT_CSV_DEFAULT; + break; + case ExportFormatJson: + file_dialog_filter << FILE_FILTER_JSON + << FILE_FILTER_TXT + << FILE_FILTER_ALL; + default_file_extension = FILE_EXT_JSON_DEFAULT; + break; + } + + if(!m_sQuery.empty()) + { + // called from sqlexecute query tab + QString sFilename = FileDialog::getSaveFileName( + CreateDataFile, + this, + tr("Choose a filename to export data"), + file_dialog_filter.join(";;")); + if(sFilename.isEmpty()) + { + close(); + return; + } + + exportQuery(m_sQuery, sFilename); + } else { + // called from the File export menu + QList selectedItems = ui->listTables->selectedItems(); + + if(selectedItems.isEmpty()) + { + QMessageBox::warning(this, QApplication::applicationName(), + tr("Please select at least 1 table.")); + return; + } + + // Get filename + QStringList filenames; + if(selectedItems.size() == 1) + { + QString fileName = FileDialog::getSaveFileName( + CreateDataFile, + this, + tr("Choose a filename to export data"), + file_dialog_filter.join(";;"), + selectedItems.at(0)->text() + default_file_extension); + if(fileName.isEmpty()) + { + close(); + return; + } + + filenames << fileName; + } else { + // ask for folder + QString exportfolder = FileDialog::getExistingDirectory( + CreateDataFile, + this, + tr("Choose a directory"), + QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks); + + if(exportfolder.isEmpty()) + { + close(); + return; + } + + for(const QListWidgetItem* item : selectedItems) + filenames << QDir(exportfolder).filePath(item->text() + default_file_extension); + } + + // Only if the user hasn't clicked the cancel button + for(int i = 0; i < selectedItems.size(); ++i) + { + // if we are called from execute sql tab, query is already set + // and we only export 1 select + std::string sQuery = "SELECT * FROM " + sqlb::ObjectIdentifier(selectedItems.at(i)->data(Qt::UserRole).toString().toStdString()).toString() + ";"; + exportQuery(sQuery, filenames.at(i)); + } + } + + // Save the dialog preferences for future use + Settings::setValue("exportcsv", "firstrowheader", ui->checkHeader->isChecked()); + Settings::setValue("exportjson", "prettyprint", ui->checkPrettyPrint->isChecked()); + Settings::setValue("exportcsv", "separator", currentSeparatorChar()); + Settings::setValue("exportcsv", "quotecharacter", currentQuoteChar()); + Settings::setValue("exportcsv", "newlinecharacters", currentNewLineString()); + + // Notify the user the export has completed + QMessageBox::information(this, QApplication::applicationName(), tr("Export completed.")); + QDialog::accept(); +} + +void ExportDataDialog::showCustomCharEdits() +{ + // Retrieve selection info for the quote, separator, and newline widgets + int quoteIndex = ui->comboQuoteCharacter->currentIndex(); + int quoteCount = ui->comboQuoteCharacter->count(); + int sepIndex = ui->comboFieldSeparator->currentIndex(); + int sepCount = ui->comboFieldSeparator->count(); + int newLineIndex = ui->comboNewLineString->currentIndex(); + int newLineCount = ui->comboNewLineString->count(); + + // Determine which will have their 'Other' line edit widget visible + bool quoteVisible = quoteIndex == (quoteCount - 1); + bool sepVisible = sepIndex == (sepCount - 1); + bool newLineVisible = newLineIndex == (newLineCount - 1); + + // Update the visibility of the 'Other' line edit widgets + ui->editCustomQuote->setVisible(quoteVisible); + ui->editCustomSeparator->setVisible(sepVisible); + ui->editCustomNewLine->setVisible(newLineVisible); +} + +void ExportDataDialog::setQuoteChar(const QChar& c) +{ + QComboBox* combo = ui->comboQuoteCharacter; + + // Set the combo and/or Other box to the correct selection + switch (c.toLatin1()) { + case '"': + combo->setCurrentIndex(0); // First option is a quote character + break; + + case '\'': + combo->setCurrentIndex(1); // Second option is a single quote character + break; + + case 0: + combo->setCurrentIndex(2); // Third option is blank (no character) + break; + + default: + // For everything else, set the combo box to option 3 ('Other') and + // place the desired string into the matching edit line box + combo->setCurrentIndex(3); + if(!c.isNull()) + { + // Don't set it if/when it's the 0 flag value + ui->editCustomQuote->setText(c); + } + break; + } +} + +char ExportDataDialog::currentQuoteChar() const +{ + QComboBox* combo = ui->comboQuoteCharacter; + + switch (combo->currentIndex()) { + case 0: + return '"'; // First option is a quote character + + case 1: + return '\''; // Second option is a single quote character + + case 2: + return 0; // Third option is a blank (no character) + + default: + // The 'Other' option was selected, so check if the matching edit + // line widget contains something + int customQuoteLength = ui->editCustomQuote->text().length(); + if (customQuoteLength > 0) { + // Yes it does. Return its first character + char customQuoteChar = ui->editCustomQuote->text().at(0).toLatin1(); + return customQuoteChar; + } else { + // No it doesn't, so return 0 to indicate it was empty + return 0; + } + } +} + +void ExportDataDialog::setSeparatorChar(const QChar& c) +{ + QComboBox* combo = ui->comboFieldSeparator; + + // Set the combo and/or Other box to the correct selection + switch (c.toLatin1()) { + case ',': + combo->setCurrentIndex(0); // First option is a comma character + break; + + case ';': + combo->setCurrentIndex(1); // Second option is a semi-colon character + break; + + case '\t': + combo->setCurrentIndex(2); // Third option is a tab character + break; + + case '|': + combo->setCurrentIndex(3); // Fourth option is a pipe symbol + break; + + default: + // For everything else, set the combo box to option 3 ('Other') and + // place the desired string into the matching edit line box + combo->setCurrentIndex(4); + + // Only put the separator character in the matching line edit box if + // it's not the flag value of 0, which is for indicating its empty + if(!c.isNull()) + ui->editCustomSeparator->setText(c); + break; + } +} + +char ExportDataDialog::currentSeparatorChar() const +{ + QComboBox* combo = ui->comboFieldSeparator; + + switch (combo->currentIndex()) { + case 0: + return ','; // First option is a comma character + + case 1: + return ';'; // Second option is a semi-colon character + + case 2: + return '\t'; // Third option is a tab character + + case 3: + return '|'; // Fourth option is a pipe character + + default: + // The 'Other' option was selected, so check if the matching edit + // line widget contains something + int customSeparatorLength = ui->editCustomSeparator->text().length(); + if (customSeparatorLength > 0) { + // Yes it does. Return its first character + char customSeparatorChar = ui->editCustomSeparator->text().at(0).toLatin1(); + return customSeparatorChar; + } else { + // No it doesn't, so return 0 to indicate it was empty + return 0; + } + } +} + +void ExportDataDialog::setNewLineString(const QString& s) +{ + QComboBox* combo = ui->comboNewLineString; + + // Set the combo and/or Other box to the correct selection + if (s == "\r\n") { + // For Windows style newlines, set the combo box to option 0 + combo->setCurrentIndex(0); + } else if (s == "\n") { + // For Unix style newlines, set the combo box to option 1 + combo->setCurrentIndex(1); + } else { + // For everything else, set the combo box to option 2 ('Other') and + // place the desired string into the matching edit line box + combo->setCurrentIndex(2); + ui->editCustomNewLine->setText(s); + } +} + +QString ExportDataDialog::currentNewLineString() const +{ + QComboBox* combo = ui->comboNewLineString; + + switch (combo->currentIndex()) { + case 0: + // Windows style newlines + return QString("\r\n"); + + case 1: + // Unix style newlines + return QString("\n"); + + default: + // Return the text from the 'Other' box + return QString(ui->editCustomNewLine->text().toLatin1()); + } +} diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/ExportDataDialog.h b/src/WBCLFZSystemModule/SqliteDBProcess/src/ExportDataDialog.h new file mode 100644 index 0000000..3b697a7 --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/ExportDataDialog.h @@ -0,0 +1,56 @@ +#ifndef ExportDataDialog_H +#define ExportDataDialog_H + +#include + +#include "sql/ObjectIdentifier.h" + +class DBBrowserDB; + +namespace Ui { +class ExportDataDialog; +} + +class ExportDataDialog : public QDialog +{ + Q_OBJECT + +public: + enum ExportFormats + { + ExportFormatCsv, + ExportFormatJson, + }; + + explicit ExportDataDialog(DBBrowserDB& db, ExportFormats format, QWidget* parent = nullptr, + const std::string& query = {}, const sqlb::ObjectIdentifier& selection = sqlb::ObjectIdentifier()); + ~ExportDataDialog() override; + +private slots: + void accept() override; + void showCustomCharEdits(); + +private: + void setQuoteChar(const QChar& c); + char currentQuoteChar() const; + + void setSeparatorChar(const QChar& c); + char currentSeparatorChar() const; + + void setNewLineString(const QString& s); + QString currentNewLineString() const; + + bool exportQuery(const std::string& sQuery, const QString& sFilename); + bool exportQueryCsv(const std::string& sQuery, const QString& sFilename); + bool exportQueryJson(const std::string& sQuery, const QString& sFilename); + +private: + Ui::ExportDataDialog* ui; + DBBrowserDB& pdb; + + ExportFormats m_format; + + std::string m_sQuery; +}; + +#endif diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/ExportDataDialog.ui b/src/WBCLFZSystemModule/SqliteDBProcess/src/ExportDataDialog.ui new file mode 100644 index 0000000..262e8e1 --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/ExportDataDialog.ui @@ -0,0 +1,408 @@ + + + ExportDataDialog + + + + 0 + 0 + 527 + 381 + + + + Export data as CSV + + + + + + + + Tab&le(s) + + + listTables + + + + + + + + 360 + 0 + + + + QAbstractItemView::MultiSelection + + + false + + + + + + + + + 0 + + + + + + + Colu&mn names in first line + + + checkHeader + + + + + + + + + + true + + + + + + + Fie&ld separator + + + comboFieldSeparator + + + + + + + + + + 180 + 0 + + + + + 180 + 16777215 + + + + + , + + + + + ; + + + + + Tab + + + + + | + + + + + Other + + + + + + + + 1 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + &Quote character + + + comboQuoteCharacter + + + + + + + + + + 180 + 0 + + + + + 180 + 16777215 + + + + + " + + + + + ' + + + + + + + + + + Other + + + + + + + + 1 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + New line characters + + + + + + + + + + 180 + 0 + + + + + 180 + 16777215 + + + + + Windows: CR+LF (\r\n) + + + + + Unix: LF (\n) + + + + + Other + + + + + + + + 5 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + + Pretty print + + + checkPrettyPrint + + + + + + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Save + + + + + + + listTables + checkHeader + comboFieldSeparator + editCustomSeparator + comboQuoteCharacter + editCustomQuote + + + + + buttonBox + accepted() + ExportDataDialog + accept() + + + 263 + 612 + + + 157 + 140 + + + + + buttonBox + rejected() + ExportDataDialog + reject() + + + 263 + 612 + + + 286 + 140 + + + + + comboFieldSeparator + currentIndexChanged(int) + ExportDataDialog + showCustomCharEdits() + + + 390 + 293 + + + 264 + 45 + + + + + comboQuoteCharacter + currentIndexChanged(int) + ExportDataDialog + showCustomCharEdits() + + + 390 + 332 + + + 270 + 85 + + + + + comboNewLineString + currentIndexChanged(int) + ExportDataDialog + showCustomCharEdits() + + + 390 + 371 + + + 296 + 248 + + + + + + showCustomCharEdits() + + diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/ExportSqlDialog.cpp b/src/WBCLFZSystemModule/SqliteDBProcess/src/ExportSqlDialog.cpp new file mode 100644 index 0000000..6e9b510 --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/ExportSqlDialog.cpp @@ -0,0 +1,133 @@ +#include "ExportSqlDialog.h" +#include "ui_ExportSqlDialog.h" +#include "sqlitedb.h" +#include "FileDialog.h" +#include "Settings.h" +#include "IconCache.h" + +#include +#include + +enum WhatComboEntries +{ + ExportEverything, + ExportSchemaOnly, + ExportDataOnly, +}; + +ExportSqlDialog::ExportSqlDialog(DBBrowserDB* db, QWidget* parent, const QString& selection) + : QDialog(parent), + ui(new Ui::ExportSqlDialog), + pdb(db) +{ + // Create UI + ui->setupUi(this); + + // Load settings + ui->checkColNames->setChecked(Settings::getValue("exportsql", "insertcolnames").toBool()); + ui->checkMultiple->setChecked(Settings::getValue("exportsql", "insertmultiple").toBool()); + ui->comboOldSchema->setCurrentIndex(Settings::getValue("exportsql", "oldschema").toInt()); + + // Get list of tables to export + const auto objects = pdb->schemata["main"].equal_range("table"); + for(auto it=objects.first;it!=objects.second;++it) + ui->listTables->addItem(new QListWidgetItem(IconCache::get(sqlb::Object::typeToString(it->second->type())), QString::fromStdString(it->second->name()))); + + // Sort list of tables and select the table specified in the + // selection parameter or all tables if table not specified + ui->listTables->model()->sort(0); + if(selection.isEmpty()) + { + for (int i = 0; i < ui->listTables->count(); ++i) + ui->listTables->item(i)->setSelected(true); + } + else + { + QList items = ui->listTables->findItems(selection, Qt::MatchExactly); + ui->listTables->setCurrentItem(items.at(0)); + } + ui->listTables->setFocus(); +} + +ExportSqlDialog::~ExportSqlDialog() +{ + delete ui; +} + +void ExportSqlDialog::doSelectAll() +{ + for (int i = 0; i < ui->listTables->count(); ++i) + ui->listTables->item(i)->setSelected(true); +} + +void ExportSqlDialog::doDeselectAll() +{ + for (int i = 0; i < ui->listTables->count(); ++i) + ui->listTables->item(i)->setSelected(false); +} + +void ExportSqlDialog::accept() +{ + QList selectedItems = ui->listTables->selectedItems(); + if(selectedItems.isEmpty()) + { + QMessageBox::warning(this, QApplication::applicationName(), + tr("Please select at least one table.")); + return; + } + + // Try to find a default file name + QString defaultFileName; + if(selectedItems.count() == 1) // One table -> Suggest table name + defaultFileName = selectedItems.at(0)->text() + FILE_EXT_SQL_DEFAULT; + else if(selectedItems.count() == ui->listTables->count()) // All tables -> Suggest database name + defaultFileName = pdb->currentFile() + FILE_EXT_SQL_DEFAULT; + + QString fileName = FileDialog::getSaveFileName( + CreateSQLFile, + this, + tr("Choose a filename to export"), + FILE_FILTER_SQL, + defaultFileName); + if(fileName.isEmpty()) + return; + + // Save settings + Settings::setValue("exportsql", "insertcolnames", ui->checkColNames->isChecked()); + Settings::setValue("exportsql", "insertmultiple", ui->checkMultiple->isChecked()); + Settings::setValue("exportsql", "oldschema", ui->comboOldSchema->currentIndex()); + + std::vector tables; + for(const QListWidgetItem* item : ui->listTables->selectedItems()) + tables.push_back(item->text().toStdString()); + + // Check what to export. The indices here depend on the order of the items in the combobox in the ui file + bool exportSchema = ui->comboWhat->currentIndex() == ExportEverything || ui->comboWhat->currentIndex() == ExportSchemaOnly; + bool exportData = ui->comboWhat->currentIndex() == ExportEverything || ui->comboWhat->currentIndex() == ExportDataOnly; + bool keepSchema = ui->comboOldSchema->currentIndex() == 0; + + // Perform actual export + bool dumpOk = pdb->dump(fileName, + tables, + ui->checkColNames->isChecked(), + ui->checkMultiple->isChecked(), + exportSchema, + exportData, + keepSchema); + if (dumpOk) + QMessageBox::information(this, QApplication::applicationName(), tr("Export completed.")); + else + QMessageBox::warning(this, QApplication::applicationName(), tr("Export cancelled or failed.")); + + QDialog::accept(); +} + +void ExportSqlDialog::whatChanged(int index) +{ + // Only show the combobox for deciding what to do with the old schema when importing into an existing database when we're + // actually exporting the schema here + if(index != ExportDataOnly) + ui->comboOldSchema->setVisible(true); + else + ui->comboOldSchema->setVisible(false); +} diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/ExportSqlDialog.h b/src/WBCLFZSystemModule/SqliteDBProcess/src/ExportSqlDialog.h new file mode 100644 index 0000000..1e585b2 --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/ExportSqlDialog.h @@ -0,0 +1,31 @@ +#ifndef ExportSqlDialog_H +#define ExportSqlDialog_H + +#include + +class DBBrowserDB; + +namespace Ui { +class ExportSqlDialog; +} + +class ExportSqlDialog : public QDialog +{ + Q_OBJECT + +public: + explicit ExportSqlDialog(DBBrowserDB* db, QWidget* parent = nullptr, const QString& selection = QString()); + ~ExportSqlDialog() override; + +private slots: + void accept() override; + void doSelectAll(); + void doDeselectAll(); + void whatChanged(int index); + +private: + Ui::ExportSqlDialog* ui; + DBBrowserDB* pdb; +}; + +#endif diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/ExportSqlDialog.ui b/src/WBCLFZSystemModule/SqliteDBProcess/src/ExportSqlDialog.ui new file mode 100644 index 0000000..b65fcca --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/ExportSqlDialog.ui @@ -0,0 +1,242 @@ + + + ExportSqlDialog + + + + 0 + 0 + 497 + 352 + + + + Export SQL... + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Save + + + + + + + QFormLayout::AllNonFixedFieldsGrow + + + + + Tab&le(s) + + + listTables + + + + + + + QAbstractItemView::MultiSelection + + + false + + + + + + + QLayout::SetFixedSize + + + 10 + + + + + Select All + + + + + + + Deselect All + + + + + + + + + &Options + + + + + + Keep column names in INSERT INTO + + + true + + + + + + + Multiple rows (VALUES) per INSERT statement + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + Export everything + + + + + Export schema only + + + + + Export data only + + + + + + + + + Keep old schema (CREATE TABLE IF NOT EXISTS) + + + + + Overwrite old schema (DROP TABLE, then CREATE TABLE) + + + + + + + + + + + + + listTables + + + + + buttonBox + accepted() + ExportSqlDialog + accept() + + + 258 + 331 + + + 157 + 140 + + + + + buttonDeselectAll + clicked() + ExportSqlDialog + doDeselectAll() + + + 488 + 129 + + + 20 + 20 + + + + + buttonSelectAll + clicked() + ExportSqlDialog + doSelectAll() + + + 140 + 129 + + + 20 + 20 + + + + + buttonBox + rejected() + ExportSqlDialog + reject() + + + 248 + 317 + + + 248 + 168 + + + + + comboWhat + currentIndexChanged(int) + ExportSqlDialog + whatChanged(int) + + + 320 + 234 + + + 492 + 226 + + + + + + showCustomCharEdits() + whatChanged(int) + + diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/ExtendedScintilla.cpp b/src/WBCLFZSystemModule/SqliteDBProcess/src/ExtendedScintilla.cpp new file mode 100644 index 0000000..1b332d5 --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/ExtendedScintilla.cpp @@ -0,0 +1,325 @@ +#include "ExtendedScintilla.h" +#include "FindReplaceDialog.h" +#include "Settings.h" + +#include "Qsci/qscilexer.h" +#include "Qsci/qsciprinter.h" +#ifdef Q_OS_MACX +#include +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +ExtendedScintilla::ExtendedScintilla(QWidget* parent) : + QsciScintilla(parent), + showErrorIndicators(true), + findReplaceDialog(new FindReplaceDialog(this)) +{ + // This class does not set any lexer, that must be done in the child classes. + + // Enable UTF8 + setUtf8(true); + + // Enable brace matching + setBraceMatching(QsciScintilla::SloppyBraceMatch); + + // Enable auto indentation + setAutoIndent(true); + + // Enable folding + setFolding(QsciScintilla::BoxedTreeFoldStyle); + + // Create error indicator + errorIndicatorNumber = indicatorDefine(QsciScintilla::SquiggleIndicator); + setIndicatorForegroundColor(Qt::red, errorIndicatorNumber); + + // Set a sensible scroll width, so the scroll bar is avoided in + // most cases. + setScrollWidth(80); + + // Scroll width is adjusted to ensure that all of the lines + // currently displayed can be completely scrolled. This mode never + // adjusts the scroll width to be narrower. + setScrollWidthTracking(true); + + // Visual flags for when wrap lines is enabled + setWrapVisualFlags(QsciScintilla::WrapFlagByBorder); + + // Connect signals + connect(this, &ExtendedScintilla::linesChanged, this, &ExtendedScintilla::updateLineNumberAreaWidth); + + // The shortcuts are constrained to the Widget context so they do not conflict with other SqlTextEdit widgets in the Main Window. + QShortcut* shortcutFindReplace = new QShortcut(QKeySequence(tr("Ctrl+H")), this, nullptr, nullptr, Qt::WidgetShortcut); + connect(shortcutFindReplace, &QShortcut::activated, this, &ExtendedScintilla::openFindReplaceDialog); + shortcutFind = new QShortcut(QKeySequence(tr("Ctrl+F")), this, nullptr, nullptr, Qt::WidgetShortcut); + connect(shortcutFind, &QShortcut::activated, this, &ExtendedScintilla::openFindDialog); + +#ifdef Q_OS_MACX + // Alt+Backspace on Mac is expected to delete one word to the left, + // instead of undoing (default Scintilla binding). + QsciCommand * command = standardCommands()->find(QsciCommand::DeleteWordLeft); + command->setKey(Qt::AltModifier+Qt::Key_Backspace); + // And Cmd+Backspace should delete from cursor to the beginning of line + command = standardCommands()->find(QsciCommand::DeleteLineLeft); + command->setKey(Qt::ControlModifier+Qt::Key_Backspace); +#endif + + QShortcut* shortcutPrint = new QShortcut(QKeySequence(tr("Ctrl+P")), this, nullptr, nullptr, Qt::WidgetShortcut); + connect(shortcutPrint, &QShortcut::activated, this, &ExtendedScintilla::openPrintDialog); + + // Prepare for adding the find/replace option to the QScintilla context menu + setContextMenuPolicy(Qt::CustomContextMenu); + connect(this, &ExtendedScintilla::customContextMenuRequested, this, &ExtendedScintilla::showContextMenu); +} + +void ExtendedScintilla::updateLineNumberAreaWidth() +{ + // Calculate number of digits of the current number of lines + int digits = static_cast(std::log10(lines())) + 1; + + // Calculate the width of this number if it was all zeros (this is because a 1 might require less space than a 0 and this could + // cause some flickering depending on the font) and set the new margin width. + setMarginWidth(0, QFontMetrics(font()).width(QString("0").repeated(digits)) + 5); +} + +void ExtendedScintilla::dropEvent(QDropEvent* e) +{ + QList urls = e->mimeData()->urls(); + if(urls.isEmpty()) + return QsciScintilla::dropEvent(e); + + QString file = urls.first().toLocalFile(); + if(!QFile::exists(file)) + return; + + QFile f(file); + f.open(QIODevice::ReadOnly); + setText(f.readAll()); + f.close(); +} + +void ExtendedScintilla::setupSyntaxHighlightingFormat(QsciLexer* lexer, const std::string& settings_name, int style) +{ + lexer->setColor(QColor(Settings::getValue("syntaxhighlighter", settings_name + "_colour").toString()), style); + + QFont font(Settings::getValue("editor", "font").toString()); + font.setPointSize(Settings::getValue("editor", "fontsize").toInt()); + font.setBold(Settings::getValue("syntaxhighlighter", settings_name + "_bold").toBool()); + font.setItalic(Settings::getValue("syntaxhighlighter", settings_name + "_italic").toBool()); + font.setUnderline(Settings::getValue("syntaxhighlighter", settings_name + "_underline").toBool()); + lexer->setFont(font, style); +} + +void ExtendedScintilla::setLexer(QsciLexer *lexer) +{ + QsciScintilla::setLexer(lexer); + reloadCommonSettings(); +} + +void ExtendedScintilla::reloadCommonSettings() +{ + // Set margins and default text colours according to settings. setLexer seems to reset these colours. + + // Use desktop default colors for margins when following desktop + // style, or the colors matching the dark style-sheet, otherwise. + switch (Settings::getValue("General", "appStyle").toInt()) { + case Settings::FollowDesktopStyle : + setMarginsBackgroundColor(QPalette().color(QPalette::Active, QPalette::Window)); + setMarginsForegroundColor(QPalette().color(QPalette::Active, QPalette::WindowText)); + break; + case Settings::DarkStyle : + setMarginsBackgroundColor(QColor("#32414B")); + setMarginsForegroundColor(QColor("#EFF0F1")); + break; + } + setPaper(Settings::getValue("syntaxhighlighter", "background_colour").toString()); + setColor(Settings::getValue("syntaxhighlighter", "foreground_colour").toString()); +} + +void ExtendedScintilla::reloadKeywords() +{ + // Set lexer again to reload the updated keywords list + setLexer(lexer()); +} + +void ExtendedScintilla::reloadSettings() +{ + reloadLexerSettings(lexer()); + reloadKeywords(); +} +void ExtendedScintilla::reloadLexerSettings(QsciLexer *lexer) +{ + QColor foreground (Settings::getValue("syntaxhighlighter", "foreground_colour").toString()); + QColor background (Settings::getValue("syntaxhighlighter", "background_colour").toString()); + + QFont defaultfont(Settings::getValue("editor", "font").toString()); + defaultfont.setStyleHint(QFont::TypeWriter); + defaultfont.setPointSize(Settings::getValue("editor", "fontsize").toInt()); + + // Set syntax highlighting settings + if(lexer) + { + lexer->setFont(defaultfont); + + lexer->setDefaultPaper(background); + lexer->setDefaultColor(foreground); + + // This sets the base colors for all the styles + lexer->setPaper(background); + lexer->setColor(foreground); + } + + // Set font + setFont(defaultfont); + + // Show line numbers + setMarginsFont(defaultfont); + setMarginLineNumbers(0, true); + updateLineNumberAreaWidth(); + + // Highlight current line + setCaretLineVisible(true); + setCaretLineBackgroundColor(QColor(Settings::getValue("syntaxhighlighter", "currentline_colour").toString())); + setCaretForegroundColor(foreground); + + // Set tab width + setTabWidth(Settings::getValue("editor", "tabsize").toInt()); + if(lexer) + lexer->refreshProperties(); + + // Check if error indicators are enabled and clear them if they just got disabled + showErrorIndicators = Settings::getValue("editor", "error_indicators").toBool(); + if(!showErrorIndicators) + clearErrorIndicators(); + +} + +void ExtendedScintilla::clearErrorIndicators() +{ + // Clear any error indicators from position (0,0) to the last column of the last line + clearIndicatorRange(0, 0, lines(), lineLength(lines()), errorIndicatorNumber); +} + +void ExtendedScintilla::setErrorIndicator(int fromRow, int fromIndex, int toRow, int toIndex) +{ + // Set error indicator for the specified range but only if they're enabled + if(showErrorIndicators) + fillIndicatorRange(fromRow, fromIndex, toRow, toIndex, errorIndicatorNumber); +} + +void ExtendedScintilla::setErrorIndicator(int position) +{ + // Set error indicator for the position until end of line, but only if they're enabled + if(showErrorIndicators) { + + int column = static_cast(SendScintilla(QsciScintillaBase::SCI_GETCOLUMN, position)); + int line = static_cast(SendScintilla(QsciScintillaBase::SCI_LINEFROMPOSITION, position)); + + fillIndicatorRange(line, column, line+1, 0, errorIndicatorNumber); + } +} + +bool ExtendedScintilla::findText(QString text, bool regexp, bool caseSensitive, bool words, bool wrap, bool forward) { + + // For finding the previous occurrence, we need to skip the current + // selection, otherwise we'd always found the same occurrence. + if (!forward && hasSelectedText()) { + int lineFrom, indexFrom; + int lineTo, indexTo; + getSelection(&lineFrom, &indexFrom, &lineTo, &indexTo); + setCursorPosition(lineFrom, indexFrom); + } + + return findFirst(text, regexp, caseSensitive, words, wrap, forward, + /* line */ -1, /* index */ -1, + /* show */ true, /* posix */ true, /* cxx11 */ true); +} + +void ExtendedScintilla::setEnabledFindDialog(bool value) +{ + shortcutFind->setEnabled(value); +} + +void ExtendedScintilla::clearSelection() +{ + setSelection(-1,-1,-1,-1); +} + +void ExtendedScintilla::openFindReplaceDialog() +{ + findReplaceDialog->setExtendedScintilla(this); + findReplaceDialog->showFindReplaceDialog(true); +} + +void ExtendedScintilla::openFindDialog() +{ + findReplaceDialog->setExtendedScintilla(this); + findReplaceDialog->showFindReplaceDialog(false); +} + +void ExtendedScintilla::showContextMenu(const QPoint &pos) +{ + + // This has to be created here, otherwise the set of enabled options would not update accordingly. + QMenu* editContextMenu = createStandardContextMenu(); + editContextMenu->addSeparator(); + if (shortcutFind->isEnabled()) { + QAction* findAction = new QAction(QIcon(":/icons/find"), tr("Find..."), this); + findAction->setShortcut(shortcutFind->key()); + connect(findAction, &QAction::triggered, this, &ExtendedScintilla::openFindDialog); + editContextMenu->addAction(findAction); + } + QAction* findReplaceAction = new QAction(QIcon(":/icons/text_replace"), tr("Find and Replace..."), this); + findReplaceAction->setShortcut(QKeySequence(tr("Ctrl+H"))); + connect(findReplaceAction, &QAction::triggered, this, &ExtendedScintilla::openFindReplaceDialog); + + QAction* printAction = new QAction(QIcon(":/icons/print"), tr("Print..."), this); + printAction->setShortcut(QKeySequence(tr("Ctrl+P"))); + connect(printAction, &QAction::triggered, this, &ExtendedScintilla::openPrintDialog); + + editContextMenu->addAction(findReplaceAction); + editContextMenu->addSeparator(); + editContextMenu->addAction(printAction); + + editContextMenu->exec(mapToGlobal(pos)); +} + +void ExtendedScintilla::openPrintDialog() +{ + QsciPrinter printer; + QPrintPreviewDialog *dialog = new QPrintPreviewDialog(&printer); + + connect(dialog, &QPrintPreviewDialog::paintRequested, [&](QPrinter *previewPrinter) { + QsciPrinter* sciPrinter = static_cast(previewPrinter); + sciPrinter->printRange(this); + }); + + dialog->exec(); + + delete dialog; +} + +void ExtendedScintilla::setReadOnly(bool ro) +{ + QsciScintilla::setReadOnly(ro); + // Disable or enable caret blinking so it is obvious whether the text can be modified or not. Otherwise there isn't any other hint. + SendScintilla(QsciScintillaBase::SCI_SETCARETPERIOD, ro ? 0 : 500); +} + +void ExtendedScintilla::setText(const QString& text) +{ + // Reset scroll width, so the scroll bar is readjusted to the new text. + // Otherwise, it grows always bigger. + setScrollWidth(80); + QsciScintilla::setText(text); +} diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/ExtendedScintilla.h b/src/WBCLFZSystemModule/SqliteDBProcess/src/ExtendedScintilla.h new file mode 100644 index 0000000..6eca7de --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/ExtendedScintilla.h @@ -0,0 +1,58 @@ +#ifndef EXTENDEDSCINTILLA_H +#define EXTENDEDSCINTILLA_H + +#include "Qsci/qsciscintilla.h" + +class FindReplaceDialog; +class QShortcut; + +/** + * @brief The ExtendedScintilla class + * This class extends the QScintilla widget for the application + */ +class ExtendedScintilla : public QsciScintilla +{ + Q_OBJECT + +public: + explicit ExtendedScintilla(QWidget *parent = nullptr); + + bool findText(QString text, bool regexp, bool caseSensitive, bool words, bool wrap, bool forward); + void setEnabledFindDialog(bool value); + void clearSelection(); + // Override parent setLexer + void setLexer(QsciLexer *lexer) override; + // Override parent setReadOnly + void setReadOnly(bool ro) override; + // Override parent setText + void setText(const QString& text) override; + +public slots: + void reloadKeywords(); + void reloadSettings(); + void clearErrorIndicators(); + void setErrorIndicator(int fromRow, int fromIndex, int toRow, int toIndex); + // Set error indicator from position to end of line + void setErrorIndicator(int position); + void openFindReplaceDialog(); + void openFindDialog(); + void openPrintDialog(); + +protected: + void dropEvent(QDropEvent* e) override; + + void setupSyntaxHighlightingFormat(QsciLexer* lexer, const std::string& settings_name, int style); + void reloadLexerSettings(QsciLexer *lexer); + void reloadCommonSettings(); + + int errorIndicatorNumber; + bool showErrorIndicators; + FindReplaceDialog* findReplaceDialog; + QShortcut* shortcutFind; + +private slots: + void updateLineNumberAreaWidth(); + void showContextMenu(const QPoint &pos); +}; + +#endif diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/ExtendedTableWidget.cpp b/src/WBCLFZSystemModule/SqliteDBProcess/src/ExtendedTableWidget.cpp new file mode 100644 index 0000000..fb58963 --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/ExtendedTableWidget.cpp @@ -0,0 +1,1081 @@ +#include "ExtendedTableWidget.h" +#include "sqlitetablemodel.h" +#include "FilterTableHeader.h" +#include "sql/sqlitetypes.h" +#include "Settings.h" +#include "sqlitedb.h" +#include "CondFormat.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +using BufferRow = std::vector; +std::vector ExtendedTableWidget::m_buffer; +QString ExtendedTableWidget::m_generatorStamp; + +namespace +{ + +std::vector parseClipboard(QString clipboard) +{ + // Remove trailing line break from the clipboard text. This is necessary because some applications append an extra + // line break to the clipboard contents which we would then interpret as regular data, setting the first field of the + // first row after the paste area to NULL. One problem here is that this breaks for those cases where an empty line at + // the end of the selection is explicitly copied and the originating application doesn't add an extra line break. However, + // there are two reasons for favoring this way: 1) Spreadsheet applications seem to add an extra line break and they are + // probably the main source for pasted data, 2) Having to manually delete on extra field seems to be less problematic than + // having one extra field deleted without any warning. + if(clipboard.endsWith("\n")) + clipboard.chop(1); + if(clipboard.endsWith("\r")) + clipboard.chop(1); + + // Make sure there is some data in the clipboard + std::vector result; + if(clipboard.isEmpty()) + return result; + + result.push_back(BufferRow()); + + QRegExp re("(\"(?:[^\t\"]+|\"\"[^\"]*\"\")*)\"|(\t|\r?\n)"); + int offset = 0; + int whitespace_offset = 0; + + while (offset >= 0) { + QString text; + int pos = re.indexIn(clipboard, offset); + if (pos < 0) { + // insert everything that left + text = clipboard.mid(whitespace_offset); + if(QRegExp("\".*\"").exactMatch(text)) + text = text.mid(1, text.length() - 2); + text.replace("\"\"", "\""); + result.back().push_back(text.toUtf8()); + break; + } + + if (re.pos(2) < 0) { + offset = pos + re.cap(1).length() + 1; + continue; + } + + QString ws = re.cap(2); + // if two whitespaces in row - that's an empty cell + if (!(pos - whitespace_offset)) { + result.back().push_back(QByteArray()); + } else { + text = clipboard.mid(whitespace_offset, pos - whitespace_offset); + if(QRegExp("\".*\"").exactMatch(text)) + text = text.mid(1, text.length() - 2); + text.replace("\"\"", "\""); + result.back().push_back(text.toUtf8()); + } + + if (ws.endsWith("\n")) + // create new row + result.push_back(BufferRow()); + + whitespace_offset = offset = pos + ws.length(); + } + + return result; +} + +} + +UniqueFilterModel::UniqueFilterModel(QObject* parent) + : QSortFilterProxyModel(parent) +{ +} + +bool UniqueFilterModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const +{ + QModelIndex index = sourceModel()->index(sourceRow, filterKeyColumn(), sourceParent); + const std::string value = index.data(Qt::EditRole).toString().toStdString(); + + if (!value.empty() && m_uniqueValues.find(value) == m_uniqueValues.end()) { + const_cast(this)->m_uniqueValues.insert(value); + return true; + } + else + return false; + +} + +ExtendedTableWidgetEditorDelegate::ExtendedTableWidgetEditorDelegate(QObject* parent) + : QStyledItemDelegate(parent) +{ +} + +QWidget* ExtendedTableWidgetEditorDelegate::createEditor(QWidget* parent, const QStyleOptionViewItem& /*option*/, const QModelIndex& index) const +{ + + SqliteTableModel* m = qobject_cast(const_cast(index.model())); + sqlb::ForeignKeyClause fk = m->getForeignKeyClause(static_cast(index.column()-1)); + + if(fk.isSet()) { + + sqlb::ObjectIdentifier foreignTable = sqlb::ObjectIdentifier(m->currentTableName().schema(), fk.table()); + + std::string column; + // If no column name is set, assume the primary key is meant + if(fk.columns().empty()) { + sqlb::TablePtr obj = m->db().getObjectByName(foreignTable); + column = obj->primaryKey()->columnList().front(); + } else + column = fk.columns().at(0); + + sqlb::TablePtr currentTable = m->db().getObjectByName(m->currentTableName()); + QString query = QString("SELECT %1 FROM %2").arg(QString::fromStdString(sqlb::escapeIdentifier(column)), QString::fromStdString(foreignTable.toString())); + + // if the current column of the current table does NOT have not-null constraint, + // the NULL is united to the query to get the possible values in the combo-box. + if (!currentTable->fields.at(static_cast(index.column())-1).notnull()) + query.append (" UNION SELECT NULL"); + + SqliteTableModel* fkModel = new SqliteTableModel(m->db(), parent, m->encoding()); + fkModel->setQuery(query); + + QComboBox* combo = new QComboBox(parent); + + // Complete cache so it is ready when setEditorData is invoked. + fkModel->completeCache(); + combo->setModel(fkModel); + + return combo; + } else { + + QLineEdit* editor = new QLineEdit(parent); + // If the row count is not greater than the complete threshold setting, set a completer of values based on current values in the column. + if (index.model()->rowCount() <= Settings::getValue("databrowser", "complete_threshold").toInt()) { + QCompleter* completer = new QCompleter(editor); + UniqueFilterModel* completerFilter = new UniqueFilterModel(completer); + // Provide a filter for the source model, so only unique and non-empty values are accepted. + completerFilter->setSourceModel(const_cast(index.model())); + completerFilter->setFilterKeyColumn(index.column()); + completer->setModel(completerFilter); + // Complete on this column, using a popup and case-insensitively. + completer->setCompletionColumn(index.column()); + completer->setCompletionMode(QCompleter::PopupCompletion); + completer->setCaseSensitivity(Qt::CaseInsensitive); + editor->setCompleter(completer); + } + // Set the maximum length to the highest possible value instead of the default 32768. + editor->setMaxLength(std::numeric_limits::max()); + return editor; + } +} + +void ExtendedTableWidgetEditorDelegate::setEditorData(QWidget* editor, const QModelIndex& index) const +{ + QLineEdit* lineedit = dynamic_cast(editor); + // Set the data for the editor + QString data = index.data(Qt::EditRole).toString(); + + if(!lineedit) { + QComboBox* combo = static_cast(editor); + int comboIndex = combo->findText(data); + if (comboIndex >= 0) + // if it is valid, adjust the combobox + combo->setCurrentIndex(comboIndex); + } else { + lineedit->setText(data); + + // Put the editor in read only mode if the actual data is larger than the maximum length to avoid accidental truncation of the data + lineedit->setReadOnly(data.size() > lineedit->maxLength()); + } +} + +void ExtendedTableWidgetEditorDelegate::setModelData(QWidget* editor, QAbstractItemModel* model, const QModelIndex& index) const +{ + // Only apply the data back to the model if the editor is not in read only mode to avoid accidental truncation of the data + QLineEdit* lineedit = dynamic_cast(editor); + if(!lineedit) { + QComboBox* combo = static_cast(editor); + model->setData(index, combo->currentData(Qt::EditRole), Qt::EditRole); + } else + if(!lineedit->isReadOnly()) + model->setData(index, lineedit->text()); +} + +void ExtendedTableWidgetEditorDelegate::updateEditorGeometry(QWidget* editor, const QStyleOptionViewItem& option, const QModelIndex& /*index*/) const +{ + editor->setGeometry(option.rect); +} + + +ExtendedTableWidget::ExtendedTableWidget(QWidget* parent) : + QTableView(parent) +{ + setHorizontalScrollMode(ExtendedTableWidget::ScrollPerPixel); + // Force ScrollPerItem, so scrolling shows all table rows + setVerticalScrollMode(ExtendedTableWidget::ScrollPerItem); + + connect(verticalScrollBar(), &QScrollBar::valueChanged, this, &ExtendedTableWidget::vscrollbarChanged); + connect(this, &ExtendedTableWidget::clicked, this, &ExtendedTableWidget::cellClicked); + + // Set up filter row + m_tableHeader = new FilterTableHeader(this); + setHorizontalHeader(m_tableHeader); + + // Disconnect clicking in header to select column, since we will use it for sorting. + // Note that, in order to work, this cannot be converted to the standard C++11 format. + disconnect(m_tableHeader, SIGNAL(sectionPressed(int)),this, SLOT(selectColumn(int))); + + // Set up vertical header context menu + verticalHeader()->setContextMenuPolicy(Qt::CustomContextMenu); + + // Set up table view context menu + m_contextMenu = new QMenu(this); + + QAction* filterAction = new QAction(QIcon(":/icons/filter"), tr("Use as Exact Filter"), m_contextMenu); + QAction* containingAction = new QAction(tr("Containing"), m_contextMenu); + QAction* notContainingAction = new QAction(tr("Not containing"), m_contextMenu); + QAction* notEqualToAction = new QAction(tr("Not equal to"), m_contextMenu); + QAction* greaterThanAction = new QAction(tr("Greater than"), m_contextMenu); + QAction* lessThanAction = new QAction(tr("Less than"), m_contextMenu); + QAction* greaterEqualAction = new QAction(tr("Greater or equal"), m_contextMenu); + QAction* lessEqualAction = new QAction(tr("Less or equal"), m_contextMenu); + QAction* inRangeAction = new QAction(tr("Between this and..."), m_contextMenu); + QAction* regexpAction = new QAction(tr("Regular expression"), m_contextMenu); + QAction* condFormatAction = new QAction(QIcon(":/icons/edit_cond_formats"), tr("Edit Conditional Formats..."), m_contextMenu); + + QAction* nullAction = new QAction(QIcon(":/icons/set_to_null"), tr("Set to NULL"), m_contextMenu); + QAction* copyAction = new QAction(QIcon(":/icons/copy"), tr("Copy"), m_contextMenu); + QAction* copyWithHeadersAction = new QAction(QIcon(":/icons/special_copy"), tr("Copy with Headers"), m_contextMenu); + QAction* copyAsSQLAction = new QAction(QIcon(":/icons/sql_copy"), tr("Copy as SQL"), m_contextMenu); + QAction* pasteAction = new QAction(QIcon(":/icons/paste"), tr("Paste"), m_contextMenu); + QAction* printAction = new QAction(QIcon(":/icons/print"), tr("Print..."), m_contextMenu); + + m_contextMenu->addAction(filterAction); + QMenu* filterMenu = m_contextMenu->addMenu(tr("Use in Filter Expression")); + filterMenu->addAction(containingAction); + filterMenu->addAction(notContainingAction); + filterMenu->addAction(notEqualToAction); + filterMenu->addAction(greaterThanAction); + filterMenu->addAction(lessThanAction); + filterMenu->addAction(greaterEqualAction); + filterMenu->addAction(lessEqualAction); + filterMenu->addAction(inRangeAction); + filterMenu->addAction(regexpAction); + m_contextMenu->addAction(condFormatAction); + + m_contextMenu->addSeparator(); + m_contextMenu->addAction(nullAction); + m_contextMenu->addSeparator(); + m_contextMenu->addAction(copyAction); + m_contextMenu->addAction(copyWithHeadersAction); + m_contextMenu->addAction(copyAsSQLAction); + m_contextMenu->addAction(pasteAction); + m_contextMenu->addSeparator(); + m_contextMenu->addAction(printAction); + setContextMenuPolicy(Qt::CustomContextMenu); + + // Create and set up delegate + m_editorDelegate = new ExtendedTableWidgetEditorDelegate(this); + setItemDelegate(m_editorDelegate); + + // This is only for displaying the shortcut in the context menu. + // An entry in keyPressEvent is still needed. + nullAction->setShortcut(QKeySequence(tr("Alt+Del"))); + copyAction->setShortcut(QKeySequence::Copy); + copyWithHeadersAction->setShortcut(QKeySequence(tr("Ctrl+Shift+C"))); + copyAsSQLAction->setShortcut(QKeySequence(tr("Ctrl+Alt+C"))); + pasteAction->setShortcut(QKeySequence::Paste); + printAction->setShortcut(QKeySequence::Print); + + // Set up context menu actions + connect(this, &QTableView::customContextMenuRequested, + [=](const QPoint& pos) + { + // Deactivate context menu options if there is no model set + bool enabled = model(); + filterAction->setEnabled(enabled); + filterMenu->setEnabled(enabled); + copyAction->setEnabled(enabled); + copyWithHeadersAction->setEnabled(enabled); + copyAsSQLAction->setEnabled(enabled); + printAction->setEnabled(enabled); + condFormatAction->setEnabled(enabled); + + // Hide filter actions when there isn't any filters + bool hasFilters = m_tableHeader->hasFilters(); + filterAction->setVisible(hasFilters); + filterMenu->menuAction()->setVisible(hasFilters); + condFormatAction->setVisible(hasFilters); + + // Try to find out whether the current view is editable and (de)activate menu options according to that + bool editable = editTriggers() != QAbstractItemView::NoEditTriggers; + nullAction->setEnabled(enabled && editable); + pasteAction->setEnabled(enabled && editable); + + // Show menu + m_contextMenu->popup(viewport()->mapToGlobal(pos)); + }); + connect(filterAction, &QAction::triggered, [&]() { + useAsFilter(QString ("=")); + }); + connect(containingAction, &QAction::triggered, [&]() { + useAsFilter(QString ("")); + }); + // Use a regular expression for the not containing filter. Simplify this if we ever support the NOT LIKE filter. + connect(notContainingAction, &QAction::triggered, [&]() { + useAsFilter(QString ("/^((?!"), /* binary */ false, QString (").)*$/")); + }); + connect(notEqualToAction, &QAction::triggered, [&]() { + useAsFilter(QString ("<>")); + }); + connect(greaterThanAction, &QAction::triggered, [&]() { + useAsFilter(QString (">")); + }); + connect(lessThanAction, &QAction::triggered, [&]() { + useAsFilter(QString ("<")); + }); + connect(greaterEqualAction, &QAction::triggered, [&]() { + useAsFilter(QString (">=")); + }); + connect(lessEqualAction, &QAction::triggered, [&]() { + useAsFilter(QString ("<=")); + }); + connect(inRangeAction, &QAction::triggered, [&]() { + useAsFilter(QString ("~"), /* binary */ true); + }); + connect(regexpAction, &QAction::triggered, [&]() { + useAsFilter(QString ("/"), /* binary */ false, QString ("/")); + }); + connect(condFormatAction, &QAction::triggered, [&]() { + emit editCondFormats(currentIndex().column()); + }); + + connect(nullAction, &QAction::triggered, [&]() { + setToNull(selectedIndexes()); + }); + connect(copyAction, &QAction::triggered, [&]() { + copy(false, false); + }); + connect(copyWithHeadersAction, &QAction::triggered, [&]() { + copy(true, false); + }); + connect(copyAsSQLAction, &QAction::triggered, [&]() { + copy(false, true); + }); + connect(pasteAction, &QAction::triggered, [&]() { + paste(); + }); + connect(printAction, &QAction::triggered, [&]() { + openPrintDialog(); + }); + + // Add spreadsheet shortcuts for selecting entire columns or entire rows. + QShortcut* selectColumnShortcut = new QShortcut(QKeySequence("Ctrl+Space"), this); + connect(selectColumnShortcut, &QShortcut::activated, [this]() { + if(!hasFocus() || selectionModel()->selectedIndexes().isEmpty()) + return; + selectionModel()->select(QItemSelection(selectionModel()->selectedIndexes().first(), selectionModel()->selectedIndexes().last()), QItemSelectionModel::Select | QItemSelectionModel::Columns); + }); + QShortcut* selectRowShortcut = new QShortcut(QKeySequence("Shift+Space"), this); + connect(selectRowShortcut, &QShortcut::activated, [this]() { + if(!hasFocus() || selectionModel()->selectedIndexes().isEmpty()) + return; + selectionModel()->select(QItemSelection(selectionModel()->selectedIndexes().first(), selectionModel()->selectedIndexes().last()), QItemSelectionModel::Select | QItemSelectionModel::Rows); + }); + +#if QT_VERSION >= QT_VERSION_CHECK(5, 12, 0) && QT_VERSION < QT_VERSION_CHECK(5, 12, 3) + // This work arounds QTBUG-73721 and it is applied only for the affected version range. + setWordWrap(false); +#endif +} + +void ExtendedTableWidget::reloadSettings() +{ + // Set the new font and font size + QFont dataBrowserFont(Settings::getValue("databrowser", "font").toString()); + dataBrowserFont.setPointSize(Settings::getValue("databrowser", "fontsize").toInt()); + setFont(dataBrowserFont); + + // Set new default row height depending on the font size + verticalHeader()->setDefaultSectionSize(verticalHeader()->fontMetrics().height()+10); +} + +void ExtendedTableWidget::copyMimeData(const QModelIndexList& fromIndices, QMimeData* mimeData, const bool withHeaders, const bool inSQL) +{ + QModelIndexList indices = fromIndices; + + // Remove all indices from hidden columns, because if we don't we might copy data from hidden columns as well which is very + // unintuitive; especially copying the rowid column when selecting all columns of a table is a problem because pasting the data + // won't work as expected. + QMutableListIterator it(indices); + while (it.hasNext()) { + if (isColumnHidden(it.next().column())) + it.remove(); + } + + // Abort if there's nothing to copy + if (indices.isEmpty()) + return; + + SqliteTableModel* m = qobject_cast(model()); + + // Clear internal copy-paste buffer + m_buffer.clear(); + + // If a single cell is selected which contains an image, copy it to the clipboard + if (!inSQL && !withHeaders && indices.size() == 1) { + QImage img; + QVariant varData = m->data(indices.first(), Qt::EditRole); + + if (img.loadFromData(varData.toByteArray())) + { + // If it's an image, copy the image data to the clipboard + mimeData->setImageData(img); + return; + } + } + + // If we got here, a non-image cell was or multiple cells were selected, or copy with headers was requested. + // In this case, we copy selected data into internal copy-paste buffer and then + // we write a table both in HTML and text formats to the system clipboard. + + // Copy selected data into internal copy-paste buffer + int last_row = indices.first().row(); + BufferRow lst; + for(int i=0;i"; + htmlResult.append(""); + htmlResult.append(""); + + // The generator-stamp is later used to know whether the data in the system clipboard is still ours. + // In that case we will give precedence to our internal copy buffer. + QString now = QDateTime::currentDateTime().toString("YYYY-MM-DDTHH:mm:ss.zzz"); + m_generatorStamp = QString("").arg(QApplication::applicationName().toHtmlEscaped(), now); + htmlResult.append(m_generatorStamp); + // TODO: is this really needed by Excel, since we use
 for multi-line cells?
+    htmlResult.append(""
+                      "
"); + + int currentRow = indices.first().row(); + + const QString fieldSepText = "\t"; +#ifdef Q_OS_WIN + const QString rowSepText = "\r\n"; +#else + const QString rowSepText = "\n"; +#endif + + QString sqlInsertStatement = QString("INSERT INTO %1 (").arg(QString::fromStdString(m->currentTableName().toString())); + // Table headers + if (withHeaders || inSQL) { + htmlResult.append(""); + sqlInsertStatement.append(") VALUES ("); + } + + // Table data rows + for(const QModelIndex& index : indices) { + QFont font; + font.fromString(index.data(Qt::FontRole).toString()); + const QString fontStyle(font.italic() ? "italic" : "normal"); + const QString fontWeigth(font.bold() ? "bold" : "normal"); + const QString fontDecoration(font.underline() ? " text-decoration: underline;" : ""); + const QColor bgColor(index.data(Qt::BackgroundRole).toString()); + const QColor fgColor(index.data(Qt::ForegroundRole).toString()); + const Qt::Alignment align(index.data(Qt::TextAlignmentRole).toInt()); + const QString textAlign(CondFormat::alignmentTexts().at(CondFormat::fromCombinedAlignment(align)).toLower()); + const QString style = QString("font-family: '%1'; font-size: %2pt; font-style: %3; font-weight: %4;%5 " + "background-color: %6; color: %7; text-align: %8").arg( + font.family().toHtmlEscaped(), + QString::number(font.pointSize()), + fontStyle, + fontWeigth, + fontDecoration, + bgColor.name(), + fgColor.name(), + textAlign); + + // Separators. For first cell, only opening table row tags must be added for the HTML and nothing for the text version. + if (indices.first() == index) { + htmlResult.append(QString("
"); + int firstColumn = indices.front().column(); + for(int i = firstColumn; i <= indices.back().column(); i++) { + QByteArray headerText = model()->headerData(i, Qt::Horizontal, Qt::EditRole).toByteArray(); + if (i != firstColumn) { + result.append(fieldSepText); + htmlResult.append(""); + sqlInsertStatement.append(", "); + } + + result.append(headerText); + htmlResult.append(headerText); + sqlInsertStatement.append(sqlb::escapeIdentifier(headerText)); + } + result.append(rowSepText); + htmlResult.append("
").arg(style)); + sqlResult.append(sqlInsertStatement); + } else if (index.row() != currentRow) { + result.append(rowSepText); + htmlResult.append(QString("
").arg(style)); + sqlResult.append(");" + rowSepText + sqlInsertStatement); + } else { + result.append(fieldSepText); + htmlResult.append(QString("").arg(style)); + sqlResult.append(", "); + } + currentRow = index.row(); + + QImage img; + QVariant bArrdata = index.data(Qt::EditRole); + + // Table cell data: image? Store it as an embedded image in HTML + if (!inSQL && img.loadFromData(bArrdata.toByteArray())) + { + QByteArray ba; + QBuffer buffer(&ba); + buffer.open(QIODevice::WriteOnly); + img.save(&buffer, "PNG"); + buffer.close(); + + QString imageBase64 = ba.toBase64(); + htmlResult.append("\"Image\""); + } else { + QByteArray text; + if (!m->isBinary(index)) { + text = bArrdata.toByteArray(); + + // Table cell data: text + if (text.contains('\n') || text.contains('\t')) + htmlResult.append("
" + QString(text).toHtmlEscaped() + "
"); + else + htmlResult.append(QString(text).toHtmlEscaped()); + + result.append(text); + sqlResult.append(sqlb::escapeString(text)); + } else + // Table cell data: binary. Save as BLOB literal in SQL + sqlResult.append( "X'" + bArrdata.toByteArray().toHex() + "'" ); + + } + } + sqlResult.append(");"); + + if ( inSQL ) + { + mimeData->setText(sqlResult); + } else { + mimeData->setHtml(htmlResult + "
"); + mimeData->setText(result); + } +} + +void ExtendedTableWidget::copy(const bool withHeaders, const bool inSQL ) +{ + QMimeData *mimeData = new QMimeData; + copyMimeData(selectionModel()->selectedIndexes(), mimeData, withHeaders, inSQL); + qApp->clipboard()->setMimeData(mimeData); +} + +void ExtendedTableWidget::paste() +{ + // Get list of selected items + QItemSelectionModel* selection = selectionModel(); + QModelIndexList indices = selection->selectedIndexes(); + + // Abort if there's nowhere to paste + if(indices.isEmpty()) + return; + + SqliteTableModel* m = qobject_cast(model()); + + // We're also checking for system clipboard data first. Only if the data in the system clipboard is not ours, we use the system + // clipboard, otherwise we prefer the internal buffer. That's because the data in the internal buffer is easier to parse and more + // accurate, too. However, if we always preferred the internal copy-paste buffer there would be no way to copy data from other + // applications in here once the internal buffer has been filled. + + // If clipboard contains an image and no text, just insert the image + const QMimeData* mimeClipboard = qApp->clipboard()->mimeData(); + if (mimeClipboard->hasImage() && !mimeClipboard->hasText()) { + QImage img = qApp->clipboard()->image(); + QByteArray ba; + QBuffer buffer(&ba); + buffer.open(QIODevice::WriteOnly); + img.save(&buffer, "PNG"); // We're always converting the image format to PNG here. TODO: Is that correct? + buffer.close(); + + m->setData(indices.first(), ba); + return; + } + + // Get the clipboard text + QString clipboard = qApp->clipboard()->text(); + + + // If data in system clipboard is ours and the internal copy-paste buffer is filled, use the internal buffer; otherwise parse the + // system clipboard contents (case for data copied by other application). + + std::vector clipboardTable; + std::vector* source; + + if(mimeClipboard->hasHtml() && mimeClipboard->html().contains(m_generatorStamp) && !m_buffer.empty()) + { + source = &m_buffer; + } else { + clipboardTable = parseClipboard(clipboard); + source = &clipboardTable; + } + + // Stop here if there's nothing to paste + if(!source->size()) + return; + + // Starting from assumption that selection is rectangular, and then first index is upper-left corner and last is lower-right. + int rows = static_cast(source->size()); + int columns = static_cast(source->front().size()); + + int firstRow = indices.front().row(); + int firstColumn = indices.front().column(); + int selectedRows = indices.back().row() - firstRow + 1; + int selectedColumns = indices.back().column() - firstColumn + 1; + + // If last row and column are after table size, clamp it + int lastRow = qMin(firstRow + rows - 1, m->rowCount() - 1); + int lastColumn = qMin(firstColumn + columns - 1, m->columnCount() - 1); + + // Special case: if there is only one cell of data to be pasted, paste it into all selected fields + if(rows == 1 && columns == 1) + { + QByteArray bArrdata = source->front().front(); + for(int row=firstRow;rowsetData(m->index(row, column), bArrdata); + } + return; + } + + // If more than one cell was selected, check if the selection matches the cliboard dimensions + if(selectedRows != rows || selectedColumns != columns) + { + // Ask user if they are sure about this + if(QMessageBox::question(this, QApplication::applicationName(), + tr("The content of the clipboard is bigger than the range selected.\nDo you want to insert it anyway?"), + QMessageBox::Yes | QMessageBox::No) != QMessageBox::Yes) + { + // If the user doesn't want to paste the clipboard data anymore, stop now + return; + } + } + + // If we get here, we can definitely start pasting: either the ranges match in their size or the user agreed to paste anyway + + // Copy the data cell by cell and as-is from the source buffer to the table + int row = firstRow; + for(const auto& source_row : *source) + { + int column = firstColumn; + for(const QByteArray& source_cell : source_row) + { + m->setData(m->index(row, column), source_cell); + + column++; + if (column > lastColumn) + break; + } + + row++; + if (row > lastRow) + break; + } +} + +void ExtendedTableWidget::useAsFilter(const QString& filterOperator, bool binary, const QString& operatorSuffix) +{ + QModelIndex index = selectionModel()->currentIndex(); + SqliteTableModel* m = qobject_cast(model()); + + // Abort if there's nothing to filter + if (!index.isValid() || !selectionModel()->hasSelection() || m->isBinary(index)) + return; + + QVariant bArrdata = model()->data(index, Qt::EditRole); + QString value; + if (bArrdata.isNull()) + value = "NULL"; + else if (bArrdata.toString().isEmpty()) + value = "''"; + else + value = bArrdata.toString(); + + // When Containing filter is requested (empty operator) and the value starts with + // an operator character, the character is escaped. + if (filterOperator.isEmpty()) + value.replace(QRegExp("^(<|>|=|/)"), Settings::getValue("databrowser", "filter_escape").toString() + QString("\\1")); + + // If binary operator, the cell data is used as first value and + // the second value must be added by the user. + size_t column = static_cast(index.column()); + if (binary) + m_tableHeader->setFilter(column, value + filterOperator); + else + m_tableHeader->setFilter(column, filterOperator + value + operatorSuffix); +} + +void ExtendedTableWidget::duplicateUpperCell() +{ + const QModelIndex& currentIndex = selectionModel()->currentIndex(); + QModelIndex upperIndex = currentIndex.sibling(currentIndex.row() - 1, currentIndex.column()); + if (upperIndex.isValid()) { + SqliteTableModel* m = qobject_cast(model()); + // When the data is binary, just copy it, since it cannot be edited inline. + if (m->isBinary(upperIndex)) + m->setData(currentIndex, m->data(upperIndex, Qt::EditRole), Qt::EditRole); + else { + // Open the inline editor and set the value (this mimics the behaviour of LibreOffice Calc) + edit(currentIndex); + QLineEdit* editor = qobject_cast(indexWidget(currentIndex)); + editor->setText(upperIndex.data().toString()); + } + } +} + +void ExtendedTableWidget::keyPressEvent(QKeyEvent* event) +{ + // Call a custom copy method when Ctrl-C is pressed + if(event->matches(QKeySequence::Copy)) + { + copy(false, false); + return; + } else if(event->matches(QKeySequence::Paste)) { + // Call a custom paste method when Ctrl-V is pressed + paste(); + } else if(event->matches(QKeySequence::Print)) { + openPrintDialog(); + } else if(event->modifiers().testFlag(Qt::ControlModifier) && event->modifiers().testFlag(Qt::ShiftModifier) && (event->key() == Qt::Key_C)) { + // Call copy with headers when Ctrl-Shift-C is pressed + copy(true, false); + } else if(event->modifiers().testFlag(Qt::ControlModifier) && event->modifiers().testFlag(Qt::AltModifier) && (event->key() == Qt::Key_C)) { + // Call copy in SQL format when Ctrl-Alt-C is pressed + copy(false, true); + } else if(event->modifiers().testFlag(Qt::ControlModifier) && (event->key() == Qt::Key_Apostrophe)) { + // Call duplicateUpperCell when Ctrl-' is pressed (this is used by spreadsheets for "Copy Formula from Cell Above") + duplicateUpperCell(); + } else if(event->key() == Qt::Key_Tab && hasFocus() && + selectedIndexes().count() == 1 && + selectedIndexes().at(0).row() == model()->rowCount()-1 && selectedIndexes().at(0).column() == model()->columnCount()-1) { + // If the Tab key was pressed while the focus was on the last cell of the last row insert a new row automatically + model()->insertRow(model()->rowCount()); + } else if ((event->key() == Qt::Key_Delete) || (event->key() == Qt::Key_Backspace)) { + // Check if entire rows are selected. We call the selectedRows() method here not only for simplicity reasons but also because it distinguishes between + // "an entire row is selected" and "all cells of a row are selected", the former is e.g. the case when the row number is clicked, the latter when all cells + // are selected manually. This is an important distinction (especially when a table has only one column!) to match the users' expectations. Also never + // delete records when the backspace key was pressed. + if(event->key() == Qt::Key_Delete && selectionModel()->selectedRows().size()) + { + // At least on entire row is selected. Because we don't allow completely arbitrary selections (at least at the moment) but only block selections, + // this means that only entire entire rows are selected. If an entire row is (or multiple entire rows are) selected, we delete that record instead + // of deleting only the cell contents. + + emit selectedRowsToBeDeleted(); + } else { + // No entire row is selected. So just set the selected cells to null or empty string depending on the modifier keys + + if(event->modifiers().testFlag(Qt::AltModifier)) + { + // When pressing Alt+Delete set the value to NULL + setToNull(selectedIndexes()); + } else { + // When pressing Delete only set the value to empty string + for(const QModelIndex& index : selectedIndexes()) + model()->setData(index, ""); + } + } + } else if(event->modifiers().testFlag(Qt::ControlModifier) && (event->key() == Qt::Key_PageUp || event->key() == Qt::Key_PageDown)) { + // When pressing Ctrl + Page up/down send a signal indicating the user wants to change the current table + emit switchTable(event->key() == Qt::Key_PageDown); + return; + } + + // This prevents the current selection from being changed when pressing tab to move to the next filter. Note that this is in an 'if' condition, + // not in an 'else if' because this way, when the tab key was pressed and the focus was on the last cell, a new row is inserted and then the tab + // key press is processed a second time to move the cursor as well + if((event->key() != Qt::Key_Tab && event->key() != Qt::Key_Backtab) || hasFocus()) + QTableView::keyPressEvent(event); +} + +void ExtendedTableWidget::updateGeometries() +{ + // Call the parent implementation first - it does most of the actual logic + QTableView::updateGeometries(); + + // Check if a model has already been set yet + if(model()) + { + // If so and if it is a SqliteTableModel and if the parent implementation of this method decided that a scrollbar is needed, update its maximum value + SqliteTableModel* m = qobject_cast(model()); + if(m && verticalScrollBar()->maximum()) + verticalScrollBar()->setMaximum(m->rowCount() - numVisibleRows() + 1); + } +} + +void ExtendedTableWidget::vscrollbarChanged(int value) +{ + // Cancel if there is no model set yet - this shouldn't happen (because without a model there should be no scrollbar) but just to be sure... + if(!model()) + return; + + // Fetch more data from the DB if necessary + const auto nrows = model()->rowCount(); + if(nrows == 0) + return; + + if(auto * m = dynamic_cast(model())) + { + int row_begin = std::min(value, nrows - 1); + int row_end = std::min(value + numVisibleRows(), nrows); + m->triggerCacheLoad(row_begin, row_end); + } +} + +int ExtendedTableWidget::numVisibleRows() const +{ + if(!isVisible() || !model() || !verticalHeader()) + return 0; + + // Get the row numbers of the rows currently visible at the top and the bottom of the widget + int row_top = rowAt(0) == -1 ? 0 : rowAt(0); + int row_bottom = verticalHeader()->visualIndexAt(height()) == -1 ? model()->rowCount() : (verticalHeader()->visualIndexAt(height()) - 1); + if(horizontalScrollBar()->isVisible()) // Assume the scrollbar covers about one row + row_bottom--; + + // Calculate the number of visible rows + return row_bottom - row_top; +} + +std::unordered_set ExtendedTableWidget::selectedCols() const +{ + std::unordered_set selectedCols; + for(const auto& idx : selectionModel()->selectedColumns()) + selectedCols.insert(static_cast(idx.column())); + return selectedCols; +} + +std::unordered_set ExtendedTableWidget::colsInSelection() const +{ + std::unordered_set colsInSelection; + for(const QModelIndex & idx : selectedIndexes()) + colsInSelection.insert(static_cast(idx.column())); + return colsInSelection; +} + +void ExtendedTableWidget::cellClicked(const QModelIndex& index) +{ + // If Ctrl-Shift is pressed try to jump to the row referenced by the foreign key of the clicked cell + if(qApp->keyboardModifiers().testFlag(Qt::ControlModifier) && qApp->keyboardModifiers().testFlag(Qt::ShiftModifier) && model()) + { + SqliteTableModel* m = qobject_cast(model()); + sqlb::ForeignKeyClause fk = m->getForeignKeyClause(static_cast(index.column()-1)); + + if(fk.isSet()) + emit foreignKeyClicked(sqlb::ObjectIdentifier(m->currentTableName().schema(), fk.table()), + fk.columns().size() ? fk.columns().at(0) : "", + m->data(index, Qt::EditRole).toByteArray()); + else { + // If this column does not have a foreign-key, try to interpret it as a filename/URL and open it in external application. + + // TODO: Qt is doing a contiguous selection when Control+Click is pressed. It should be disabled, but at least moving the + // current index gives better result. + setCurrentIndex(index); + emit requestUrlOrFileOpen(model()->data(index, Qt::EditRole).toString()); + } + } +} + +void ExtendedTableWidget::dragEnterEvent(QDragEnterEvent* event) +{ + event->accept(); +} + +void ExtendedTableWidget::dragMoveEvent(QDragMoveEvent* event) +{ + event->accept(); +} + +void ExtendedTableWidget::dropEvent(QDropEvent* event) +{ + QModelIndex index = indexAt(event->pos()); + + if (!index.isValid()) + { + if (event->mimeData()->hasUrls() && event->mimeData()->urls().first().isLocalFile()) + emit openFileFromDropEvent(event->mimeData()->urls().first().toLocalFile()); + return; + } + + model()->dropMimeData(event->mimeData(), Qt::CopyAction, index.row(), index.column(), QModelIndex()); + event->acceptProposedAction(); +} + +void ExtendedTableWidget::selectTableLine(int lineToSelect) +{ + SqliteTableModel* m = qobject_cast(model()); + + // Are there even that many lines? + if(lineToSelect >= m->rowCount()) + return; + + QApplication::setOverrideCursor( Qt::WaitCursor ); + m->triggerCacheLoad(lineToSelect); + + // Select it + clearSelection(); + selectRow(lineToSelect); + scrollTo(currentIndex(), QAbstractItemView::PositionAtTop); + QApplication::restoreOverrideCursor(); +} + +void ExtendedTableWidget::selectTableLines(int firstLine, int count) +{ + SqliteTableModel* m = qobject_cast(model()); + + int lastLine = firstLine+count-1; + // Are there even that many lines? + if(lastLine >= m->rowCount()) + return; + + selectTableLine(firstLine); + + QModelIndex topLeft = m->index(firstLine, 0); + QModelIndex bottomRight = m->index(lastLine, m->columnCount()-1); + + selectionModel()->select(QItemSelection(topLeft, bottomRight), QItemSelectionModel::Select | QItemSelectionModel::Rows); +} + +void ExtendedTableWidget::selectAll() +{ + SqliteTableModel* m = qobject_cast(model()); + + // Fetch all the data if needed and user accepts, then call parent's selectAll() + + QMessageBox::StandardButton answer = QMessageBox::Yes; + + // If we can fetch more data, ask user if they are sure about it. + if (!m->isCacheComplete()) { + + answer = QMessageBox::question(this, QApplication::applicationName(), + tr("

Not all data has been loaded. Do you want to load all data before selecting all the rows?

" + "

Answering No means that no more data will be loaded and the selection will not be performed.
" + "Answering Yes might take some time while the data is loaded but the selection will be complete.

" + "Warning: Loading all the data might require a great amount of memory for big tables."), + QMessageBox::Yes | QMessageBox::No); + + if (answer == QMessageBox::Yes) + m->completeCache(); + } + if (answer == QMessageBox::Yes) + QTableView::selectAll(); +} + +void ExtendedTableWidget::openPrintDialog() +{ + QMimeData *mimeData = new QMimeData; + QModelIndexList indices; + + // Print the selection, if active, or the entire table otherwise. + // Given that simply clicking over a cell, selects it, one-cell selections are ignored. + if (selectionModel()->hasSelection() && selectionModel()->selectedIndexes().count() > 1) + indices = selectionModel()->selectedIndexes(); + else + for (int row=0; row < model()->rowCount(); row++) + for (int column=0; column < model()->columnCount(); column++) + indices << model()->index(row, column); + + // Copy the specified indices content to mimeData for getting the HTML representation of + // the table with headers. We can then print it using an HTML text document. + copyMimeData(indices, mimeData, true, false); + + QPrinter printer; + QPrintPreviewDialog *dialog = new QPrintPreviewDialog(&printer); + + connect(dialog, &QPrintPreviewDialog::paintRequested, [mimeData](QPrinter *previewPrinter) { + QTextDocument document; + document.setHtml(mimeData->html()); + document.print(previewPrinter); + }); + + dialog->exec(); + + delete dialog; + delete mimeData; +} + +void ExtendedTableWidget::sortByColumns(const std::vector& columns) +{ + // Are there even any columns to sort by? + if(columns.size() == 0) + return; + + // Are we using a SqliteTableModel as a model? These support multiple sort columns. Other models might not; for those we just use the first sort column + SqliteTableModel* sqlite_model = dynamic_cast(model()); + if(sqlite_model == nullptr) + model()->sort(static_cast(columns.front().column), columns.front().direction == sqlb::Ascending ? Qt::AscendingOrder : Qt::DescendingOrder); + else + sqlite_model->sort(columns); +} + +void ExtendedTableWidget::currentChanged(const QModelIndex ¤t, const QModelIndex &previous) +{ + QTableView::currentChanged(current, previous); + emit currentIndexChanged(current, previous); +} + +void ExtendedTableWidget::setToNull(const QModelIndexList& indices) +{ + SqliteTableModel* m = qobject_cast(const_cast(model())); + sqlb::TablePtr currentTable = m->db().getObjectByName(m->currentTableName()); + + // Check if some column in the selection has a NOT NULL constraint, before trying to update the cells. + if(currentTable) + for(const QModelIndex& index : indices) { + const sqlb::Field& field = currentTable->fields.at(static_cast(index.column())-1); + if(field.notnull()) { + QMessageBox::warning(nullptr, qApp->applicationName(), + tr("Cannot set selection to NULL. Column %1 has a NOT NULL constraint."). + arg(QString::fromStdString(field.name()))); + return; + } + } + + for(const QModelIndex& index : indices) + model()->setData(index, QVariant()); +} diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/ExtendedTableWidget.h b/src/WBCLFZSystemModule/SqliteDBProcess/src/ExtendedTableWidget.h new file mode 100644 index 0000000..f97bc78 --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/ExtendedTableWidget.h @@ -0,0 +1,110 @@ +#ifndef EXTENDEDTABLEWIDGET_H +#define EXTENDEDTABLEWIDGET_H + +#include +#include +#include +#include + +#include "sql/Query.h" + +class QMenu; +class QMimeData; +class QDropEvent; +class QDragMoveEvent; + +class FilterTableHeader; +namespace sqlb { class ObjectIdentifier; } + +// Filter proxy model that only accepts distinct non-empty values. +class UniqueFilterModel : public QSortFilterProxyModel +{ + Q_OBJECT + +public: + explicit UniqueFilterModel(QObject* parent = nullptr); + bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override; + private: + std::unordered_set m_uniqueValues; +}; + +// We use this class to provide editor widgets for the ExtendedTableWidget. It's used for every cell in the table view. +class ExtendedTableWidgetEditorDelegate : public QStyledItemDelegate +{ + Q_OBJECT + +public: + explicit ExtendedTableWidgetEditorDelegate(QObject* parent = nullptr); + + QWidget* createEditor(QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index) const override; + void setEditorData(QWidget* editor, const QModelIndex& index) const override; + void setModelData(QWidget* editor, QAbstractItemModel* model, const QModelIndex& index) const override; + void updateEditorGeometry(QWidget* editor, const QStyleOptionViewItem& option, const QModelIndex& index) const override; +}; + +class ExtendedTableWidget : public QTableView +{ + Q_OBJECT + +public: + explicit ExtendedTableWidget(QWidget* parent = nullptr); + + FilterTableHeader* filterHeader() { return m_tableHeader; } + +public: + // Get set of selected columns (all cells in column has to be selected) + std::unordered_set selectedCols() const; + // Get set of columns traversed by selection (only some cells in column has to be selected) + std::unordered_set colsInSelection() const; + + int numVisibleRows() const; + + void sortByColumns(const std::vector& columns); + +public slots: + void reloadSettings(); + void selectTableLine(int lineToSelect); + void selectTableLines(int firstLine, int count); + void selectAll() override; + void openPrintDialog(); + +signals: + void foreignKeyClicked(const sqlb::ObjectIdentifier& table, const std::string& column, const QByteArray& value); + void switchTable(bool next); // 'next' parameter is set to true if next table should be selected and to false if previous table should be selected + void openFileFromDropEvent(QString); + void selectedRowsToBeDeleted(); + void editCondFormats(int column); + void currentIndexChanged(const QModelIndex ¤t, const QModelIndex &previous); + void requestUrlOrFileOpen(const QString& urlString); + +private: + void copyMimeData(const QModelIndexList& fromIndices, QMimeData* mimeData, const bool withHeaders, const bool inSQL); + void copy(const bool withHeaders, const bool inSQL); + void paste(); + + void useAsFilter(const QString& filterOperator, bool binary = false, const QString& operatorSuffix = QString()); + void duplicateUpperCell(); + + void setToNull(const QModelIndexList& indices); + + static std::vector> m_buffer; + static QString m_generatorStamp; + +private slots: + void vscrollbarChanged(int value); + void cellClicked(const QModelIndex& index); + +protected: + void keyPressEvent(QKeyEvent* event) override; + void updateGeometries() override; + void dragEnterEvent(QDragEnterEvent* event) override; + void dragMoveEvent(QDragMoveEvent* event) override; + void dropEvent(QDropEvent* event) override; + void currentChanged(const QModelIndex ¤t, const QModelIndex &previous) override; + + FilterTableHeader* m_tableHeader; + QMenu* m_contextMenu; + ExtendedTableWidgetEditorDelegate* m_editorDelegate; +}; + +#endif diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/FileDialog.cpp b/src/WBCLFZSystemModule/SqliteDBProcess/src/FileDialog.cpp new file mode 100644 index 0000000..6f96293 --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/FileDialog.cpp @@ -0,0 +1,83 @@ +#include "FileDialog.h" +#include "Settings.h" + +QString FileDialog::getOpenFileName(const FileDialogTypes dialogType, QWidget* parent, const QString& caption, const QString &filter, QString *selectedFilter, Options options) +{ + QString result = QFileDialog::getOpenFileName(parent, caption, getFileDialogPath(dialogType), filter, selectedFilter, options); + if(!result.isEmpty()) + setFileDialogPath(dialogType, result); + return result; +} + +QStringList FileDialog::getOpenFileNames(const FileDialogTypes dialogType, QWidget *parent, const QString &caption, const QString &filter, QString *selectedFilter, QFileDialog::Options options) +{ + QStringList result = QFileDialog::getOpenFileNames(parent, caption, getFileDialogPath(dialogType), filter, selectedFilter, options); + if(!result.isEmpty()) + { + QFileInfo path = QFileInfo(result.first()); + setFileDialogPath(dialogType, path.absolutePath()); + } + return result; +} + +QString FileDialog::getSaveFileName(const FileDialogTypes dialogType, QWidget* parent, const QString& caption, const QString& filter, const QString& defaultFileName, QString* selectedFilter, Options options) +{ + QString dir = getFileDialogPath(dialogType); + if(!defaultFileName.isEmpty()) + dir += "/" + defaultFileName; + + QString result = QFileDialog::getSaveFileName(parent, caption, dir, filter, selectedFilter, options); + if(!result.isEmpty()) + setFileDialogPath(dialogType, result); + return result; +} + +QString FileDialog::getExistingDirectory(const FileDialogTypes dialogType, QWidget* parent, const QString& caption, Options options) +{ + QString result = QFileDialog::getExistingDirectory(parent, caption, getFileDialogPath(dialogType), options); + if(!result.isEmpty()) + setFileDialogPath(dialogType, result); + return result; +} + +QString FileDialog::getFileDialogPath(const FileDialogTypes dialogType) +{ + switch(Settings::getValue("db", "savedefaultlocation").toInt()) + { + case 0: // Remember last location + case 2: { // Remember last location for current session only + QHash lastLocations = Settings::getValue("db", "lastlocations").toHash(); + + return lastLocations[QString(dialogType)].toString(); + } + case 1: // Always use this locations + return Settings::getValue("db", "defaultlocation").toString(); + default: + return QString(); + } +} + +void FileDialog::setFileDialogPath(const FileDialogTypes dialogType, const QString& new_path) +{ + QString dir = QFileInfo(new_path).absolutePath(); + QHash lastLocations = Settings::getValue("db", "lastlocations").toHash(); + + lastLocations[QString(dialogType)] = dir; + + switch(Settings::getValue("db", "savedefaultlocation").toInt()) + { + case 0: // Remember last location + Settings::setValue("db", "lastlocations", lastLocations); + break; + case 2: // Remember last location for current session only + Settings::setValue("db", "lastlocations", lastLocations, true); + break; + case 1: // Always use this locations + break; // Do nothing + } +} + +QString FileDialog::getSqlDatabaseFileFilter() +{ + return Settings::getValue("General", "DBFileExtensions").toString() + ";;" + QObject::tr("All files (*)"); //Always add "All files (*)" to the available filters +} diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/FileDialog.h b/src/WBCLFZSystemModule/SqliteDBProcess/src/FileDialog.h new file mode 100644 index 0000000..6b4999f --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/FileDialog.h @@ -0,0 +1,104 @@ +#ifndef FILEDIALOG_H +#define FILEDIALOG_H + +#include + +// +// File Extensions Filters +// - space separated list of file extensions in QString +// - used during import/export +// - passed to QFileDialog to filter files shown based on extension +// +// SQLite DB File Extensions +static const QString FILE_FILTER_SQLDB(QObject::tr("SQLite Database Files (*.db *.sqlite *.sqlite3 *.db3)")); + +// SQLite DB Project File Extensions +static const QString FILE_FILTER_SQLPRJ(QObject::tr("DB Browser for SQLite Project Files (*.sqbpro)")); +static const QString FILE_EXT_SQLPRJ_DEFAULT(".sqbpro"); + +// SQL File Extensions Filter +static const QString FILE_FILTER_SQL(QObject::tr("SQL Files (*.sql)")); +static const QString FILE_EXT_SQL_DEFAULT(".sql"); + +// All Files Extensions Filter +static const QString FILE_FILTER_ALL(QObject::tr("All Files (*)")); + +// Text Files Extensions Filter +static const QString FILE_FILTER_TXT(QObject::tr("Text Files (*.txt)")); +static const QString FILE_EXT_TXT_DEFAULT(".txt"); + +// Comma,Tab,or Delimiter-Separated Values File Extensions Filter +static const QString FILE_FILTER_CSV(QObject::tr("Comma-Separated Values Files (*.csv)")); +static const QString FILE_EXT_CSV_DEFAULT(".csv"); +static const QString FILE_FILTER_TSV(QObject::tr("Tab-Separated Values Files (*.tsv)")); +static const QString FILE_FILTER_DSV(QObject::tr("Delimiter-Separated Values Files (*.dsv)")); +static const QString FILE_FILTER_DAT(QObject::tr("Concordance DAT files (*.dat)")); + +// JSON File Extensions Filter +static const QString FILE_FILTER_JSON(QObject::tr("JSON Files (*.json *.js)")); +static const QString FILE_EXT_JSON_DEFAULT(".json"); + +// XML File Extensions Filter +static const QString FILE_FILTER_XML(QObject::tr("XML Files (*.xml)")); +static const QString FILE_EXT_XML_DEFAULT(".xml"); + +// Binary File Extensions Filter +static const QString FILE_FILTER_BIN(QObject::tr("Binary Files (*.bin *.dat)")); +static const QString FILE_EXT_BIN_DEFAULT(".bin"); + +// Scalar Vector Graphics File Extensions Filter +static const QString FILE_FILTER_SVG(QObject::tr("SVG Files (*.svg)")); +static const QString FILE_EXT_SVG_DEFAULT(".svg"); + +// Hex-Dump File Extension Filter +static const QString FILE_FILTER_HEX(QObject::tr("Hex Dump Files (*.dat *.bin)")); + +// Dynamic/Shared Objects File Extension Filter +static const QString FILE_FILTER_DYN(QObject::tr("Extensions (*.so *.dylib *.dll)")); + +enum FileDialogTypes { + NoSpecificType, + + CreateProjectFile, + OpenProjectFile, + + CreateDatabaseFile, + OpenDatabaseFile, + + CreateSQLFile, + OpenSQLFile, + + OpenCSVFile, + + CreateDataFile, + OpenDataFile, + + OpenExtensionFile, + OpenCertificateFile +}; + +class FileDialog : public QFileDialog +{ + Q_OBJECT + +public: + static QString getOpenFileName(const FileDialogTypes dialogType, QWidget* parent = nullptr, const QString& caption = QString(), + const QString& filter = QString(), QString* selectedFilter = nullptr, + Options options = Options()); + static QStringList getOpenFileNames(const FileDialogTypes dialogType, QWidget* parent = nullptr, const QString& caption = QString(), + const QString& filter = QString(), QString* selectedFilter = nullptr, + Options options = Options()); + static QString getSaveFileName(const FileDialogTypes dialogType, QWidget* parent = nullptr, const QString& caption = QString(), + const QString& filter = QString(), const QString& defaultFileName = QString(), QString* selectedFilter = nullptr, + Options options = Options()); + static QString getExistingDirectory(const FileDialogTypes dialogType, QWidget* parent = nullptr, const QString& caption = QString(), + Options options = Options()); + + static QString getSqlDatabaseFileFilter(); + +private: + static QString getFileDialogPath(const FileDialogTypes dialogType); + static void setFileDialogPath(const FileDialogTypes dialogType, const QString& new_path); +}; + +#endif diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/FileExtensionManager.cpp b/src/WBCLFZSystemModule/SqliteDBProcess/src/FileExtensionManager.cpp new file mode 100644 index 0000000..71ce8eb --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/FileExtensionManager.cpp @@ -0,0 +1,104 @@ +#include "FileExtensionManager.h" +#include "ui_FileExtensionManager.h" + +#include + +FileExtensionManager::FileExtensionManager(QStringList init, QWidget *parent) : + QDialog(parent), + ui(new Ui::FileExtensionManager) +{ + ui->setupUi(this); + + int i = 0; + for(const QString& itemString : init) + { + QString description = itemString.left(itemString.indexOf('(')).trimmed(); + QString extension = itemString; + extension = extension.remove (0, itemString.indexOf('(')+1).remove(')').simplified().trimmed(); + + QTableWidgetItem *newItemDescription = new QTableWidgetItem(description); + QTableWidgetItem *newItemExtension = new QTableWidgetItem(extension); + ui->tableExtensions->insertRow(i); + ui->tableExtensions->setItem(i, 0, newItemDescription); + ui->tableExtensions->setItem(i, 1, newItemExtension); + i++; + } + + connect(ui->buttonAdd, SIGNAL(clicked(bool)), this, SLOT(addItem())); + connect(ui->buttonRemove, SIGNAL(clicked(bool)), this, SLOT(removeItem())); + + connect(ui->buttonDown, SIGNAL(clicked(bool)), this, SLOT(downItem())); + connect(ui->buttonUp, SIGNAL(clicked(bool)), this, SLOT(upItem())); +} + +FileExtensionManager::~FileExtensionManager() +{ + delete ui; +} + +void FileExtensionManager::addItem() +{ + int i = ui->tableExtensions->rowCount(); + ui->tableExtensions->insertRow(i); + QTableWidgetItem *newItemDescription = new QTableWidgetItem(tr("Description")); + QTableWidgetItem *newItemExtension = new QTableWidgetItem(tr("*.extension")); + ui->tableExtensions->setItem(i, 0, newItemDescription); + ui->tableExtensions->setItem(i, 1, newItemExtension); +} + +void FileExtensionManager::removeItem() +{ + std::set selectedRows; + for (const QTableWidgetItem* item : ui->tableExtensions->selectedItems()) + selectedRows.insert(item->row()); + + for(int row : selectedRows) + ui->tableExtensions->removeRow(row); +} + +void FileExtensionManager::upItem() +{ + if (ui->tableExtensions->selectedItems().isEmpty()) return; + + int selectedRow = ui->tableExtensions->selectedItems().first()->row(); + if(selectedRow == 0) + return; + + QTableWidgetItem *t1, *t2; + t1 = ui->tableExtensions->takeItem(selectedRow, 0); + t2 = ui->tableExtensions->takeItem(selectedRow, 1); + ui->tableExtensions->removeRow(selectedRow); + ui->tableExtensions->insertRow(selectedRow-1); + ui->tableExtensions->setItem(selectedRow-1, 0, t1); + ui->tableExtensions->setItem(selectedRow-1, 1, t2); + ui->tableExtensions->selectRow(selectedRow-1); +} + +void FileExtensionManager::downItem() +{ + if (ui->tableExtensions->selectedItems().isEmpty()) return; + + int selectedRow = ui->tableExtensions->selectedItems().first()->row(); + if(selectedRow == ui->tableExtensions->rowCount() - 1) + return; + + QTableWidgetItem *t1, *t2; + t1 = ui->tableExtensions->takeItem(selectedRow, 0); + t2 = ui->tableExtensions->takeItem(selectedRow, 1); + ui->tableExtensions->removeRow(selectedRow); + ui->tableExtensions->insertRow(selectedRow+1); + ui->tableExtensions->setItem(selectedRow+1, 0, t1); + ui->tableExtensions->setItem(selectedRow+1, 1, t2); + ui->tableExtensions->selectRow(selectedRow+1); +} + +QStringList FileExtensionManager::getDBFileExtensions() const +{ + QStringList result; + for (int i = 0; i < ui->tableExtensions->rowCount(); ++i) + { + result.append(QString("%1 (%2)").arg(ui->tableExtensions->item(i, 0)->text(), ui->tableExtensions->item(i, 1)->text())); + } + return result; +} + diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/FileExtensionManager.h b/src/WBCLFZSystemModule/SqliteDBProcess/src/FileExtensionManager.h new file mode 100644 index 0000000..7e0156e --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/FileExtensionManager.h @@ -0,0 +1,30 @@ +#ifndef FILEEXTENSIONMANAGER_H +#define FILEEXTENSIONMANAGER_H + +#include + +namespace Ui { +class FileExtensionManager; +} + +class FileExtensionManager : public QDialog +{ + Q_OBJECT + +public: + explicit FileExtensionManager(QStringList init, QWidget *parent = nullptr); + ~FileExtensionManager() override; + + QStringList getDBFileExtensions() const; + +private: + Ui::FileExtensionManager *ui; + +public slots: + void addItem(); + void removeItem(); + void upItem(); + void downItem(); +}; + +#endif // FILEEXTENSIONMANAGER_H diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/FileExtensionManager.ui b/src/WBCLFZSystemModule/SqliteDBProcess/src/FileExtensionManager.ui new file mode 100644 index 0000000..691d5b5 --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/FileExtensionManager.ui @@ -0,0 +1,153 @@ + + + FileExtensionManager + + + + 0 + 0 + 578 + 463 + + + + File Extension Manager + + + + + + + + &Up + + + + :/icons/up:/icons/up + + + + + + + &Down + + + + :/icons/down:/icons/down + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + &Add + + + + :/icons/field_add:/icons/field_add + + + + + + + &Remove + + + + :/icons/field_delete:/icons/field_delete + + + + + + + + + QAbstractScrollArea::AdjustToContents + + + true + + + 100 + + + 100 + + + + Description + + + + + Extensions + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + + + buttonBox + accepted() + FileExtensionManager + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + FileExtensionManager + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/FilterLineEdit.cpp b/src/WBCLFZSystemModule/SqliteDBProcess/src/FilterLineEdit.cpp new file mode 100644 index 0000000..73e8e74 --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/FilterLineEdit.cpp @@ -0,0 +1,224 @@ +#include "FilterLineEdit.h" +#include "Settings.h" + +#include +#include +#include +#include + +FilterLineEdit::FilterLineEdit(QWidget* parent, std::vector* filters, size_t columnnum) : + QLineEdit(parent), + filterList(filters), + columnNumber(columnnum), + conditional_format(true) +{ + setPlaceholderText(tr("Filter")); + setClearButtonEnabled(true); + setProperty("column", static_cast(columnnum)); // Store the column number for later use + + // Introduce a timer for delaying the signal triggered whenever the user changes the filter value. + // The idea here is that the textChanged() event isn't connected to the update filter slot directly anymore + // but instead there this timer mechanism in between: whenever the user changes the filter the delay timer + // is (re)started. As soon as the user stops typing the timer has a chance to trigger and call the + // delayedSignalTimerTriggered() method which then stops the timer and emits the delayed signal. + delaySignalTimer = new QTimer(this); + delaySignalTimer->setInterval(Settings::getValue("databrowser", "filter_delay").toInt()); // This is the milliseconds of not-typing we want to wait before triggering + connect(this, &FilterLineEdit::textChanged, delaySignalTimer, static_cast(&QTimer::start)); + connect(delaySignalTimer, &QTimer::timeout, this, &FilterLineEdit::delayedSignalTimerTriggered); + + setWhatsThis(tr("These input fields allow you to perform quick filters in the currently selected table.\n" + "By default, the rows containing the input text are filtered out.\n" + "The following operators are also supported:\n" + "%\tWildcard\n" + ">\tGreater than\n" + "<\tLess than\n" + ">=\tEqual to or greater\n" + "<=\tEqual to or less\n" + "=\tEqual to: exact match\n" + "<>\tUnequal: exact inverse match\n" + "x~y\tRange: values between x and y\n" + "/regexp/\tValues matching the regular expression")); + + // Immediately emit the delayed filter value changed signal if the user presses the enter or the return key or + // the line edit widget loses focus + connect(this, &FilterLineEdit::editingFinished, this, &FilterLineEdit::delayedSignalTimerTriggered); + + // Prepare for adding the What's This information and filter helper actions to the context menu + setContextMenuPolicy(Qt::CustomContextMenu); + connect(this, &FilterLineEdit::customContextMenuRequested, this, &FilterLineEdit::showContextMenu); +} + +void FilterLineEdit::delayedSignalTimerTriggered() +{ + // Stop the timer first to avoid triggering in intervals + delaySignalTimer->stop(); + + // Only emit text changed signal if the text has actually changed in comparison to the last emitted signal. This is necessary + // because this method is also called whenever the line edit loses focus and not only when its text has definitely been changed. + if(text() != lastValue) + { + // Emit the delayed signal using the current value + emit delayedTextChanged(text()); + + // Remember this value for the next time + lastValue = text(); + } +} + +void FilterLineEdit::keyReleaseEvent(QKeyEvent* event) +{ + if(event->key() == Qt::Key_Tab) + { + if(filterList && columnNumber < filterList->size() - 1) + { + filterList->at(columnNumber + 1)->setFocus(); + event->accept(); + } + } else if(event->key() == Qt::Key_Backtab) { + if(filterList && columnNumber > 0) + { + filterList->at(columnNumber - 1)->setFocus(); + event->accept(); + } + } +} + +void FilterLineEdit::clear() +{ + // When programatically clearing the line edit's value make sure the effects are applied immediately, i.e. + // bypass the delayed signal timer + QLineEdit::clear(); + delayedSignalTimerTriggered(); +} + +void FilterLineEdit::setText(const QString& text) +{ + // When programatically setting the line edit's value make sure the effects are applied immediately, i.e. + // bypass the delayed signal timer + QLineEdit::setText(text); + delayedSignalTimerTriggered(); +} + +void FilterLineEdit::setFilterHelper(const QString& filterOperator, const QString& operatorSuffix) +{ + setText(filterOperator + "?" + operatorSuffix); + // Select the value for easy editing of the expression + setSelection(filterOperator.length(), 1); +} + +void FilterLineEdit::showContextMenu(const QPoint &pos) +{ + + // This has to be created here, otherwise the set of enabled options would not update accordingly. + QMenu* editContextMenu = createStandardContextMenu(); + editContextMenu->addSeparator(); + + QMenu* filterMenu = editContextMenu->addMenu(tr("Set Filter Expression")); + + QAction* whatsThisAction = new QAction(QIcon(":/icons/whatis"), tr("What's This?"), editContextMenu); + connect(whatsThisAction, &QAction::triggered, [&]() { + QWhatsThis::showText(pos, whatsThis(), this); + }); + + QAction* isNullAction = new QAction(tr("Is NULL"), editContextMenu); + connect(isNullAction, &QAction::triggered, [&]() { + setText("=NULL"); + }); + + QAction* isNotNullAction = new QAction(tr("Is not NULL"), editContextMenu); + connect(isNotNullAction, &QAction::triggered, [&]() { + setText("<>NULL"); + }); + + QAction* isEmptyAction = new QAction(tr("Is empty"), editContextMenu); + connect(isEmptyAction, &QAction::triggered, [&]() { + setText("=''"); + }); + + QAction* isNotEmptyAction = new QAction(tr("Is not empty"), editContextMenu); + connect(isNotEmptyAction, &QAction::triggered, [&]() { + setText("<>''"); + }); + // Simplify this if we ever support a NOT LIKE filter + QAction* notContainingAction = new QAction(tr("Not containing..."), editContextMenu); + connect(notContainingAction, &QAction::triggered, [&]() { + setFilterHelper(QString ("/^((?!"), QString(").)*$/")); + }); + QAction* equalToAction = new QAction(tr("Equal to..."), editContextMenu); + connect(equalToAction, &QAction::triggered, [&]() { + setFilterHelper(QString ("=")); + }); + QAction* notEqualToAction = new QAction(tr("Not equal to..."), editContextMenu); + connect(notEqualToAction, &QAction::triggered, [&]() { + setFilterHelper(QString ("<>")); + }); + QAction* greaterThanAction = new QAction(tr("Greater than..."), editContextMenu); + connect(greaterThanAction, &QAction::triggered, [&]() { + setFilterHelper(QString (">")); + }); + QAction* lessThanAction = new QAction(tr("Less than..."), editContextMenu); + connect(lessThanAction, &QAction::triggered, [&]() { + setFilterHelper(QString ("<")); + }); + QAction* greaterEqualAction = new QAction(tr("Greater or equal..."), editContextMenu); + connect(greaterEqualAction, &QAction::triggered, [&]() { + setFilterHelper(QString (">=")); + }); + QAction* lessEqualAction = new QAction(tr("Less or equal..."), editContextMenu); + connect(lessEqualAction, &QAction::triggered, [&]() { + setFilterHelper(QString ("<=")); + }); + QAction* inRangeAction = new QAction(tr("In range..."), editContextMenu); + connect(inRangeAction, &QAction::triggered, [&]() { + setFilterHelper(QString ("?~")); + }); + + QAction* regexpAction = new QAction(tr("Regular expression..."), editContextMenu); + connect(regexpAction, &QAction::triggered, [&]() { + setFilterHelper(QString ("/"), QString ("/")); + }); + + + if(conditional_format) + { + QAction* conditionalFormatAction; + if (text().isEmpty()) { + conditionalFormatAction = new QAction(QIcon(":/icons/clear_cond_formats"), tr("Clear All Conditional Formats"), editContextMenu); + connect(conditionalFormatAction, &QAction::triggered, [&]() { + emit clearAllCondFormats(); + }); + } else { + conditionalFormatAction = new QAction(QIcon(":/icons/add_cond_format"), tr("Use for Conditional Format"), editContextMenu); + connect(conditionalFormatAction, &QAction::triggered, [&]() { + emit addFilterAsCondFormat(text()); + }); + } + QAction* editCondFormatsAction = new QAction(QIcon(":/icons/edit_cond_formats"), tr("Edit Conditional Formats..."), editContextMenu); + connect(editCondFormatsAction, &QAction::triggered, [&]() { + emit editCondFormats(); + }); + editContextMenu->addSeparator(); + + editContextMenu->addAction(conditionalFormatAction); + editContextMenu->addAction(editCondFormatsAction); + } + + + filterMenu->addAction(whatsThisAction); + filterMenu->addSeparator(); + filterMenu->addAction(isNullAction); + filterMenu->addAction(isNotNullAction); + filterMenu->addAction(isEmptyAction); + filterMenu->addAction(isNotEmptyAction); + filterMenu->addSeparator(); + filterMenu->addAction(notContainingAction); + filterMenu->addAction(equalToAction); + filterMenu->addAction(notEqualToAction); + filterMenu->addAction(greaterThanAction); + filterMenu->addAction(lessThanAction); + filterMenu->addAction(greaterEqualAction); + filterMenu->addAction(lessEqualAction); + filterMenu->addAction(inRangeAction); + filterMenu->addAction(regexpAction); + editContextMenu->exec(mapToGlobal(pos)); +} diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/FilterLineEdit.h b/src/WBCLFZSystemModule/SqliteDBProcess/src/FilterLineEdit.h new file mode 100644 index 0000000..5a7c16d --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/FilterLineEdit.h @@ -0,0 +1,47 @@ +#ifndef FILTERLINEEDIT_H +#define FILTERLINEEDIT_H + +#include +#include + +class QTimer; +class QKeyEvent; + +class FilterLineEdit : public QLineEdit +{ + Q_OBJECT + +public: + explicit FilterLineEdit(QWidget* parent, std::vector* filters = nullptr, size_t columnnum = 0); + + // Override methods for programatically changing the value of the line edit + void clear(); + void setText(const QString& text); + + void setConditionFormatContextMenuEnabled(bool enable) { conditional_format = enable; } + +private slots: + void delayedSignalTimerTriggered(); + +signals: + void delayedTextChanged(QString text); + void addFilterAsCondFormat(QString text); + void clearAllCondFormats(); + void editCondFormats(); + +protected: + void keyReleaseEvent(QKeyEvent* event) override; + void setFilterHelper(const QString& filterOperator, const QString& operatorSuffix = QString()); + +private: + std::vector* filterList; + size_t columnNumber; + QTimer* delaySignalTimer; + QString lastValue; + bool conditional_format; + +private slots: + void showContextMenu(const QPoint &pos); +}; + +#endif diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/FilterTableHeader.cpp b/src/WBCLFZSystemModule/SqliteDBProcess/src/FilterTableHeader.cpp new file mode 100644 index 0000000..0149e39 --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/FilterTableHeader.cpp @@ -0,0 +1,130 @@ +#include "FilterTableHeader.h" +#include "FilterLineEdit.h" + +#include +#include +#include + +FilterTableHeader::FilterTableHeader(QTableView* parent) : + QHeaderView(Qt::Horizontal, parent) +{ + // Activate the click signals to allow sorting + setSectionsClickable(true); + + // But use our own indicators allowing multi-column sorting + setSortIndicatorShown(false); + + // Make sure to not automatically resize the columns according to the contents + setSectionResizeMode(QHeaderView::Interactive); + + // Highlight column headers of selected cells to emulate spreadsheet behaviour + setHighlightSections(true); + + // Do some connects: Basically just resize and reposition the input widgets whenever anything changes + connect(this, &FilterTableHeader::sectionResized, this, &FilterTableHeader::adjustPositions); + connect(parent->horizontalScrollBar(), &QScrollBar::valueChanged, this, &FilterTableHeader::adjustPositions); + connect(parent->verticalScrollBar(), &QScrollBar::valueChanged, this, &FilterTableHeader::adjustPositions); + + // Set custom context menu handling + setContextMenuPolicy(Qt::CustomContextMenu); +} + +void FilterTableHeader::generateFilters(size_t number, bool showFirst) +{ + // Delete all the current filter widgets + qDeleteAll(filterWidgets); + filterWidgets.clear(); + + // And generate a bunch of new ones + for(size_t i=0;i < number; ++i) + { + FilterLineEdit* l = new FilterLineEdit(this, &filterWidgets, i); + if(!showFirst && i == 0) // This hides the first input widget which belongs to the hidden rowid column + l->setVisible(false); + else + l->setVisible(true); + connect(l, &FilterLineEdit::delayedTextChanged, this, &FilterTableHeader::inputChanged); + connect(l, &FilterLineEdit::addFilterAsCondFormat, this, &FilterTableHeader::addFilterAsCondFormat); + connect(l, &FilterLineEdit::clearAllCondFormats, this, &FilterTableHeader::clearAllCondFormats); + connect(l, &FilterLineEdit::editCondFormats, this, &FilterTableHeader::editCondFormats); + filterWidgets.push_back(l); + } + + // Position them correctly + adjustPositions(); +} + +QSize FilterTableHeader::sizeHint() const +{ + // For the size hint just take the value of the standard implementation and add the height of a input widget to it if necessary + QSize s = QHeaderView::sizeHint(); + if(filterWidgets.size()) + s.setHeight(s.height() + filterWidgets.at(0)->sizeHint().height() + 4); // The 4 adds just adds some extra space + return s; +} + +void FilterTableHeader::updateGeometries() +{ + // If there are any input widgets add a viewport margin to the header to generate some empty space for them which is not affected by scrolling + if(filterWidgets.size()) + setViewportMargins(0, 0, 0, filterWidgets.at(0)->sizeHint().height()); + else + setViewportMargins(0, 0, 0, 0); + + // Now just call the parent implementation and reposition the input widgets + QHeaderView::updateGeometries(); + adjustPositions(); +} + +void FilterTableHeader::adjustPositions() +{ + // Loop through all widgets + for(int i=0;i < static_cast(filterWidgets.size()); ++i) + { + // Get the current widget, move it and resize it + QWidget* w = filterWidgets.at(static_cast(i)); + // The two adds some extra space between the header label and the input widget + int y = QHeaderView::sizeHint().height() + 2; + if (QApplication::layoutDirection() == Qt::RightToLeft) + w->move(width() - (sectionPosition(i) + sectionSize(i) - offset()), y); + else + w->move(sectionPosition(i) - offset(), y); + w->resize(sectionSize(i), w->sizeHint().height()); + } +} + +void FilterTableHeader::inputChanged(const QString& new_value) +{ + // Just get the column number and the new value and send them to anybody interested in filter changes + emit filterChanged(sender()->property("column").toUInt(), new_value); +} + +void FilterTableHeader::addFilterAsCondFormat(const QString& filter) +{ + // Just get the column number and the new value and send them to anybody interested in new conditional formatting + emit addCondFormat(sender()->property("column").toUInt(), filter); +} + +void FilterTableHeader::clearAllCondFormats() +{ + // Just get the column number and send it to anybody responsible or interested in clearing conditional formatting + emit allCondFormatsCleared(sender()->property("column").toUInt()); +} + +void FilterTableHeader::editCondFormats() +{ + // Just get the column number and the new value and send them to anybody interested in editting conditional formatting + emit condFormatsEdited(sender()->property("column").toUInt()); +} + +void FilterTableHeader::clearFilters() +{ + for(FilterLineEdit* filterLineEdit : filterWidgets) + filterLineEdit->clear(); +} + +void FilterTableHeader::setFilter(size_t column, const QString& value) +{ + if(column < filterWidgets.size()) + filterWidgets.at(column)->setText(value); +} diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/FilterTableHeader.h b/src/WBCLFZSystemModule/SqliteDBProcess/src/FilterTableHeader.h new file mode 100644 index 0000000..ef64eaf --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/FilterTableHeader.h @@ -0,0 +1,44 @@ +#ifndef FILTERTABLEHEADER_H +#define FILTERTABLEHEADER_H + +#include +#include + +class QTableView; +class FilterLineEdit; + +class FilterTableHeader : public QHeaderView +{ + Q_OBJECT + +public: + explicit FilterTableHeader(QTableView* parent = nullptr); + QSize sizeHint() const override; + bool hasFilters() const {return (filterWidgets.size() > 0);} + +public slots: + void generateFilters(size_t number, bool showFirst = false); + void adjustPositions(); + void clearFilters(); + void setFilter(size_t column, const QString& value); + +signals: + void filterChanged(size_t column, QString value); + void addCondFormat(size_t column, QString filter); + void allCondFormatsCleared(size_t column); + void condFormatsEdited(size_t column); + +protected: + void updateGeometries() override; + +private slots: + void inputChanged(const QString& new_value); + void addFilterAsCondFormat(const QString& filter); + void clearAllCondFormats(); + void editCondFormats(); + +private: + std::vector filterWidgets; +}; + +#endif diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/FindReplaceDialog.cpp b/src/WBCLFZSystemModule/SqliteDBProcess/src/FindReplaceDialog.cpp new file mode 100644 index 0000000..4279b3f --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/FindReplaceDialog.cpp @@ -0,0 +1,227 @@ +#include "FindReplaceDialog.h" +#include "ui_FindReplaceDialog.h" +#include "ExtendedScintilla.h" + +#include + +FindReplaceDialog::FindReplaceDialog(QWidget* parent) + : QDialog(parent), + ui(new Ui::FindReplaceDialog), + m_scintilla(nullptr), + foundIndicatorNumber(0), + findInProgress(false) +{ + // Create UI + ui->setupUi(this); +} + +FindReplaceDialog::~FindReplaceDialog() +{ + delete ui; +} + +void FindReplaceDialog::setExtendedScintilla(ExtendedScintilla* scintilla) +{ + m_scintilla = scintilla; + + // Create indicator for find-all and replace-all occurrences + foundIndicatorNumber = m_scintilla->indicatorDefine(QsciScintilla::StraightBoxIndicator); + m_scintilla->setIndicatorForegroundColor(Qt::magenta, foundIndicatorNumber); + m_scintilla->setIndicatorDrawUnder(true, foundIndicatorNumber); + + bool isWriteable = ! m_scintilla->isReadOnly(); + ui->replaceWithText->setEnabled(isWriteable); + ui->replaceButton->setEnabled(isWriteable); + ui->replaceAllButton->setEnabled(isWriteable); + + connect(m_scintilla, &ExtendedScintilla::destroyed, this, &FindReplaceDialog::hide); + connect(ui->findText, &QLineEdit::editingFinished, this, &FindReplaceDialog::cancelFind); + connect(ui->regexpCheckBox, &QCheckBox::toggled, this, &FindReplaceDialog::cancelFind); + connect(ui->caseCheckBox, &QCheckBox::toggled, this, &FindReplaceDialog::cancelFind); + connect(ui->wholeWordsCheckBox, &QCheckBox::toggled, this, &FindReplaceDialog::cancelFind); + connect(ui->wrapCheckBox, &QCheckBox::toggled, this, &FindReplaceDialog::cancelFind); + connect(ui->backwardsCheckBox, &QCheckBox::toggled, this, &FindReplaceDialog::cancelFind); + connect(ui->selectionCheckBox, &QCheckBox::toggled, this, &FindReplaceDialog::cancelFind); + connect(ui->selectionCheckBox, &QCheckBox::toggled, ui->wrapCheckBox, &QCheckBox::setDisabled); +} + +bool FindReplaceDialog::findFirst(bool wrap, bool forward) +{ + if (ui->selectionCheckBox->isChecked()) + return m_scintilla->findFirstInSelection + (ui->findText->text(), + ui->regexpCheckBox->isChecked(), + ui->caseCheckBox->isChecked(), + ui->wholeWordsCheckBox->isChecked(), + forward, + /* show */ true, + /* posix */ true, + /* cxx11 */ true); + else + return m_scintilla->findFirst + (ui->findText->text(), + ui->regexpCheckBox->isChecked(), + ui->caseCheckBox->isChecked(), + ui->wholeWordsCheckBox->isChecked(), + wrap, + forward, + /* line */ -1, + /* index */ -1, + /* show */ true, + /* posix */ true, + /* cxx11 */ true); +} + +bool FindReplaceDialog::findNext() +{ + clearIndicators(); + + if (findInProgress) + findInProgress = m_scintilla->findNext(); + else + findInProgress = findFirst(ui->wrapCheckBox->isChecked(), + !ui->backwardsCheckBox->isChecked()); + + if (!findInProgress) + ui->messageLabel->setText(tr("The searched text was not found")); + + return findInProgress; + +} + +void FindReplaceDialog::showFindReplaceDialog(bool hasReplace) +{ + ui->replaceWithText->setVisible(hasReplace); + ui->replaceButton->setVisible(hasReplace); + ui->replaceWithLabel->setVisible(hasReplace); + ui->replaceAllButton->setVisible(hasReplace); + show(); +} + +void FindReplaceDialog::show() +{ + ui->findText->setFocus(); + + // If there is multi-line selected text set automatically the selection + // check box. If it's only part of a line, use it as text to find. + if (m_scintilla->hasSelectedText()) + if (m_scintilla->selectedText().contains("\n")) + ui->selectionCheckBox->setChecked(true); + else { + ui->findText->setText(m_scintilla->selectedText()); + ui->selectionCheckBox->setChecked(false); + } + else + ui->selectionCheckBox->setChecked(false); + + ui->findText->selectAll(); + QDialog::show(); +} + +void FindReplaceDialog::replace() +{ + if (m_scintilla->hasSelectedText()) + m_scintilla->replace(ui->replaceWithText->text()); + findNext(); +} + +void FindReplaceDialog::indicateSelection() +{ + int fromRow, fromIndex, toRow, toIndex; + m_scintilla->getSelection(&fromRow, &fromIndex, &toRow, &toIndex); + m_scintilla->fillIndicatorRange(fromRow, fromIndex, toRow, toIndex, foundIndicatorNumber); +} + +void FindReplaceDialog::searchAll(bool replace) +{ + clearIndicators(); + if (!ui->selectionCheckBox->isChecked()) + m_scintilla->setCursorPosition(0, 0); + + bool found = findFirst(/* wrap */ false, /* fordward */ true); + + int occurrences = 0; + while (found) { + if (replace) + m_scintilla->replace(ui->replaceWithText->text()); + indicateSelection(); + ++occurrences; + found = m_scintilla->findNext(); + } + + if (!ui->selectionCheckBox->isChecked()) + m_scintilla->clearSelection(); + + QString message; + switch (occurrences) { + case 0: + message = tr("The searched text was not found."); + break; + case 1: + if (replace) + message = tr("The searched text was replaced one time."); + else + message = tr("The searched text was found one time."); + break; + default: + if (replace) + message = tr("The searched text was replaced %1 times.").arg(occurrences); + else + message = tr("The searched text was found %1 times.").arg(occurrences); + + break; + } + + ui->messageLabel->setText(message); +} + +void FindReplaceDialog::findAll() +{ + searchAll(/* replace */ false); +} + +void FindReplaceDialog::replaceAll() +{ + searchAll(/* replace */ true); +} + +void FindReplaceDialog::cancelFind() +{ + m_scintilla->findFirst(QString(), false, false, false, false); + clearIndicators(); + findInProgress = false; + ui->messageLabel->setText(""); +} +void FindReplaceDialog::help() +{ + QWhatsThis::enterWhatsThisMode(); +} + +void FindReplaceDialog::clearIndicators() +{ + m_scintilla->clearIndicatorRange(0, 0, m_scintilla->lines(), m_scintilla->lineLength(m_scintilla->lines()), foundIndicatorNumber); + ui->messageLabel->setText(""); +} + +void FindReplaceDialog::close() +{ + m_scintilla->clearSelection(); + // Reset any previous find so it does not interfere with the next time + // the dialog is open. + cancelFind(); + QDialog::close(); +} + +void FindReplaceDialog::buttonBox_clicked(QAbstractButton* button) +{ + if (button == ui->buttonBox->button(QDialogButtonBox::Help)) + help(); + else if (button == ui->buttonBox->button(QDialogButtonBox::Close)) + close(); + +} +void FindReplaceDialog::reject() +{ + close(); + QDialog::reject(); +} diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/FindReplaceDialog.h b/src/WBCLFZSystemModule/SqliteDBProcess/src/FindReplaceDialog.h new file mode 100644 index 0000000..b4865d6 --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/FindReplaceDialog.h @@ -0,0 +1,48 @@ +#ifndef FindReplaceDialog_H +#define FindReplaceDialog_H + +#include + +class QAbstractButton; + +class ExtendedScintilla; + +namespace Ui { +class FindReplaceDialog; +} + +class FindReplaceDialog : public QDialog +{ + Q_OBJECT + +public: + + explicit FindReplaceDialog(QWidget* parent = nullptr); + ~FindReplaceDialog() override; + void setExtendedScintilla(ExtendedScintilla* scintilla); + void show(); + void showFindReplaceDialog(bool hasReplace); + +private slots: + bool findNext(); + void replace(); + void findAll(); + void replaceAll(); + void cancelFind(); + void help(); + void close(); + void reject() override; + void buttonBox_clicked(QAbstractButton* button); + +private: + bool findFirst(bool wrap, bool forward); + void searchAll(bool replace); + void indicateSelection(); + void clearIndicators(); + Ui::FindReplaceDialog* ui; + ExtendedScintilla* m_scintilla; + int foundIndicatorNumber; + bool findInProgress; +}; + +#endif diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/FindReplaceDialog.ui b/src/WBCLFZSystemModule/SqliteDBProcess/src/FindReplaceDialog.ui new file mode 100644 index 0000000..25a0a51 --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/FindReplaceDialog.ui @@ -0,0 +1,322 @@ + + + FindReplaceDialog + + + + 0 + 0 + 451 + 288 + + + + Find and Replace + + + + + + true + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + QFormLayout::ExpandingFieldsGrow + + + + + Fi&nd text: + + + findText + + + + + + + + + + Re&place with: + + + replaceWithText + + + + + + + + + + Match &exact case + + + false + + + + + + + Match &only whole words + + + + + + + When enabled, the search continues from the other end when it reaches one end of the page + + + &Wrap around + + + + + + + When set, the search goes backwards from cursor position, otherwise it goes forward + + + Search &backwards + + + + + + + <html><head/><body><p>When checked, the pattern to find is searched only in the current selection.</p></body></html> + + + &Selection only + + + + + + + <html><head/><body><p>When checked, the pattern to find is interpreted as a UNIX regular expression. See <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>.</p></body></html> + + + Use regular e&xpressions + + + + + + + + + 7 + + + QLayout::SetDefaultConstraint + + + 0 + + + + + Find the next occurrence from the cursor position and in the direction set by "Search backwards" + + + &Find Next + + + F3 + + + + + + + &Replace + + + + + + + Highlight all the occurrences of the text in the page + + + F&ind All + + + + + + + Replace all the occurrences of the text in the page + + + Replace &All + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + + + 75 + true + + + + + + + Qt::AlignCenter + + + + + + + QDialogButtonBox::Close|QDialogButtonBox::Help + + + + + + + findText + replaceWithText + caseCheckBox + wholeWordsCheckBox + wrapCheckBox + backwardsCheckBox + selectionCheckBox + regexpCheckBox + findNextButton + replaceButton + findAllButton + replaceAllButton + + + + + findNextButton + clicked() + FindReplaceDialog + findNext() + + + 225 + 242 + + + 225 + 132 + + + + + replaceButton + clicked() + FindReplaceDialog + replace() + + + 225 + 242 + + + 225 + 132 + + + + + findAllButton + clicked() + FindReplaceDialog + findAll() + + + 225 + 242 + + + 225 + 132 + + + + + replaceAllButton + clicked() + FindReplaceDialog + replaceAll() + + + 225 + 242 + + + 225 + 132 + + + + + buttonBox + clicked(QAbstractButton*) + FindReplaceDialog + buttonBox_clicked(QAbstractButton*) + + + 225 + 265 + + + 225 + 143 + + + + + + updatePreview() + checkInput() + updateSelection(bool) + matchSimilar() + + diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/ForeignKeyEditorDelegate.cpp b/src/WBCLFZSystemModule/SqliteDBProcess/src/ForeignKeyEditorDelegate.cpp new file mode 100644 index 0000000..dd8bfc4 --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/ForeignKeyEditorDelegate.cpp @@ -0,0 +1,190 @@ +#include "sqlitedb.h" +#include "ForeignKeyEditorDelegate.h" + +#include +#include +#include +#include + +class ForeignKeyEditor : public QWidget +{ + Q_OBJECT + +public: + explicit ForeignKeyEditor(QWidget* parent = nullptr) + : QWidget(parent) + , tablesComboBox(new QComboBox(this)) + , idsComboBox(new QComboBox(this)) + , clauseEdit(new QLineEdit(this)) + , m_btnReset(new QPushButton(tr("&Reset"), this)) + { + idsComboBox->setSizeAdjustPolicy(QComboBox::AdjustToContents); + clauseEdit->setPlaceholderText(tr("Foreign key clauses (ON UPDATE, ON DELETE etc.)")); + + QHBoxLayout* layout = new QHBoxLayout(this); + layout->addWidget(tablesComboBox); + layout->addWidget(idsComboBox); + layout->addWidget(clauseEdit); + layout->addWidget(m_btnReset); + layout->setSpacing(0); + layout->setMargin(0); + setLayout(layout); + + connect(m_btnReset, &QPushButton::clicked, [&] + { + tablesComboBox->setCurrentIndex(-1); + idsComboBox->setCurrentIndex(-1); + clauseEdit->clear(); + }); + + connect(tablesComboBox, static_cast(&QComboBox::currentIndexChanged), + [=](int index) + { + // reset ids combo box + idsComboBox->setCurrentIndex(-1); + + // disable clauses editor if none of tables is selected + bool enableClausesEditor = (index!= -1); + clauseEdit->setEnabled(enableClausesEditor); + }); + } + + QString getSql() const + { + if (tablesComboBox->currentText().isEmpty()) + return QString(); + + const QString table = sqlb::escapeIdentifier(tablesComboBox->currentText()); + const QString clauses = clauseEdit->text(); + + QString id = idsComboBox->currentText(); + if (!id.isEmpty()) + id = QString("(%1)").arg(sqlb::escapeIdentifier(id)); + + return QString("%1%2 %3").arg( + table, + id, + clauses) + .trimmed(); + } + + QComboBox* tablesComboBox; + QComboBox* idsComboBox; + QLineEdit* clauseEdit; // for ON CASCADE and such + +private: + QPushButton* m_btnReset; +}; + +ForeignKeyEditorDelegate::ForeignKeyEditorDelegate(const DBBrowserDB& db, sqlb::Table& table, QObject* parent) + : QStyledItemDelegate(parent) + , m_db(db) + , m_table(table) +{ + for(const auto& it : m_db.schemata) + { + for(const auto& jt : it.second) + { + // Don't insert the current table into the list. The name and fields of the current table are always taken from the m_table reference + if(jt.second->type() == sqlb::Object::Types::Table && jt.second->name() != m_table.name()) + m_tablesIds.insert({jt.second->name(), std::dynamic_pointer_cast(jt.second)->fieldNames()}); + } + } +} + +QWidget* ForeignKeyEditorDelegate::createEditor(QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index) const +{ + Q_UNUSED(option) + Q_UNUSED(index) + + ForeignKeyEditor* editor = new ForeignKeyEditor(parent); + editor->setAutoFillBackground(true); + + connect(editor->tablesComboBox, static_cast(&QComboBox::currentIndexChanged), + [=](const QString& tableName) + { + QComboBox* box = editor->idsComboBox; + box->clear(); + box->addItem(QString()); // for those heroes who don't like to specify key explicitly + + // For recursive foreign keys get the field list from the m_table reference. For other foreign keys from the prepared field lists. + if(tableName.toStdString() == m_table.name()) + { + for(const auto& n : m_table.fieldNames()) + box->addItem(QString::fromStdString(n)); + } else { + for(const auto& n : m_tablesIds[tableName.toStdString()]) + box->addItem(QString::fromStdString(n)); + } + + + box->setCurrentIndex(0); + }); + + editor->tablesComboBox->clear(); + for(const auto& i : m_tablesIds) + editor->tablesComboBox->addItem(QString::fromStdString(i.first)); + editor->tablesComboBox->addItem(QString::fromStdString(m_table.name())); // For recursive foreign keys + + return editor; +} + +void ForeignKeyEditorDelegate::setEditorData(QWidget* editor, const QModelIndex& index) const +{ + ForeignKeyEditor* fkEditor = static_cast(editor); + + size_t column = static_cast(index.row()); // weird? I know right + const sqlb::Field& field = m_table.fields.at(column); + auto fk = std::dynamic_pointer_cast(m_table.constraint({field.name()}, sqlb::Constraint::ForeignKeyConstraintType)); + if (fk) { + fkEditor->tablesComboBox->setCurrentText(QString::fromStdString(fk->table())); + fkEditor->clauseEdit->setText(QString::fromStdString(fk->constraint())); + if (!fk->columns().empty()) + fkEditor->idsComboBox->setCurrentText(QString::fromStdString(fk->columns().front())); + } else { + fkEditor->tablesComboBox->setCurrentIndex(-1); + } +} + +void ForeignKeyEditorDelegate::setModelData(QWidget* editor, QAbstractItemModel* model, const QModelIndex& index) const +{ + ForeignKeyEditor* fkEditor = static_cast(editor); + QString sql = fkEditor->getSql(); + + size_t column = static_cast(index.row()); + const sqlb::Field& field = m_table.fields.at(column); + if (sql.isEmpty()) { + // Remove the foreign key + m_table.removeConstraints({field.name()}, sqlb::Constraint::ConstraintTypes::ForeignKeyConstraintType); + } else { + // Set the foreign key + sqlb::ForeignKeyClause* fk = new sqlb::ForeignKeyClause; + + const QString table = fkEditor->tablesComboBox->currentText(); + const std::string id = fkEditor->idsComboBox->currentText().toStdString(); + const QString clause = fkEditor->clauseEdit->text(); + + fk->setTable(table.toStdString()); + fk->setColumnList({ field.name() }); + + if (!id.empty()) + fk->setColumns({id}); + + if (!clause.trimmed().isEmpty()) { + fk->setConstraint(clause.toStdString()); + } + + m_table.setConstraint(sqlb::ConstraintPtr(fk)); + } + + model->setData(index, sql); +} + +void ForeignKeyEditorDelegate::updateEditorGeometry(QWidget* editor, const QStyleOptionViewItem& option, const QModelIndex& index) const +{ + Q_UNUSED(index) + + editor->setGeometry(option.rect); +} + +#include "ForeignKeyEditorDelegate.moc" diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/ForeignKeyEditorDelegate.h b/src/WBCLFZSystemModule/SqliteDBProcess/src/ForeignKeyEditorDelegate.h new file mode 100644 index 0000000..076706a --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/ForeignKeyEditorDelegate.h @@ -0,0 +1,34 @@ +#ifndef FOREIGNKEYDELEGATE_H +#define FOREIGNKEYDELEGATE_H + +#include +#include +#include +#include + +class DBBrowserDB; + +namespace sqlb +{ +class Table; +} + +class ForeignKeyEditorDelegate : public QStyledItemDelegate +{ + Q_OBJECT + +public: + explicit ForeignKeyEditorDelegate(const DBBrowserDB& db, sqlb::Table& table, QObject* parent = nullptr); + + QWidget* createEditor(QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index) const override; + void setEditorData(QWidget* editor, const QModelIndex& index) const override; + void setModelData(QWidget* editor, QAbstractItemModel* model, const QModelIndex& index) const override; + void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const override; + +private: + const DBBrowserDB& m_db; + sqlb::Table& m_table; + mutable std::unordered_map> m_tablesIds; +}; + +#endif // FOREIGNKEYDELEGATE_H diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/IconCache.cpp b/src/WBCLFZSystemModule/SqliteDBProcess/src/IconCache.cpp new file mode 100644 index 0000000..fcc219f --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/IconCache.cpp @@ -0,0 +1,22 @@ +#include "IconCache.h" + +QIcon IconCache::null_icon; +std::unordered_map IconCache::icons; + +const QIcon& IconCache::get(const std::string& name) +{ + // Check if we already have an icon object with that name in the cache. If so, just return that + auto it = icons.find(name); + if(it != icons.end()) + return it->second; + + // If now, try to load an icon with that name and insert it into the cache + QIcon icon(":/icons/" + QString::fromStdString(name)); + auto ins = icons.insert({name, icon}); + + // If the insertion was successful, return the inserted icon object. If it was not, return a null icon. + if(ins.second) + return ins.first->second; + else + return null_icon; +} diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/IconCache.h b/src/WBCLFZSystemModule/SqliteDBProcess/src/IconCache.h new file mode 100644 index 0000000..73200f5 --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/IconCache.h @@ -0,0 +1,21 @@ +#ifndef ICONCACHE_H +#define ICONCACHE_H + +#include + +#include +#include + +class IconCache +{ +public: + IconCache() = delete; + + static const QIcon& get(const std::string& name); + +private: + static QIcon null_icon; + static std::unordered_map icons; +}; + +#endif diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/ImportCsvDialog.cpp b/src/WBCLFZSystemModule/SqliteDBProcess/src/ImportCsvDialog.cpp new file mode 100644 index 0000000..eb50838 --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/ImportCsvDialog.cpp @@ -0,0 +1,843 @@ +#include "ImportCsvDialog.h" +#include "ui_ImportCsvDialog.h" +#include "sqlitedb.h" +#include "csvparser.h" +#include "sqlite.h" +#include "Settings.h" +#include "Data.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// Enable this line to show basic performance stats after each imported CSV file. Please keep in mind that while these +// numbers might help to estimate the performance of the algorithm, this is not a proper benchmark. +//#define CSV_BENCHMARK + +#ifdef CSV_BENCHMARK +#include +#endif + +ImportCsvDialog::ImportCsvDialog(const std::vector& filenames, DBBrowserDB* db, QWidget* parent) + : QDialog(parent), + ui(new Ui::ImportCsvDialog), + csvFilenames(filenames), + pdb(db) +{ + ui->setupUi(this); + + // Hide "Advanced" section of the settings + toggleAdvancedSection(false); + + // Get the actual file name out of the provided path and use it as the default table name for import + // For importing several files at once, the fields have to be the same so we can safely use the first + QFileInfo file(filenames.front()); + ui->editName->setText(file.baseName()); + + // Create a list of all available encodings and create an auto completion list from them + encodingCompleter = new QCompleter(toStringList(QTextCodec::availableCodecs()), this); + encodingCompleter->setCaseSensitivity(Qt::CaseInsensitive); + ui->editCustomEncoding->setCompleter(encodingCompleter); + + // Load last used settings and apply them + ui->checkboxHeader->blockSignals(true); + ui->checkBoxTrimFields->blockSignals(true); + ui->checkBoxSeparateTables->blockSignals(true); + ui->comboSeparator->blockSignals(true); + ui->comboQuote->blockSignals(true); + ui->comboEncoding->blockSignals(true); + + ui->checkboxHeader->setChecked(Settings::getValue("importcsv", "firstrowheader").toBool()); + ui->checkBoxTrimFields->setChecked(Settings::getValue("importcsv", "trimfields").toBool()); + ui->checkBoxSeparateTables->setChecked(Settings::getValue("importcsv", "separatetables").toBool()); + setSeparatorChar(Settings::getValue("importcsv", "separator").toChar()); + setQuoteChar(Settings::getValue("importcsv", "quotecharacter").toChar()); + setEncoding(Settings::getValue("importcsv", "encoding").toString()); + + ui->checkboxHeader->blockSignals(false); + ui->checkBoxTrimFields->blockSignals(false); + ui->checkBoxSeparateTables->blockSignals(false); + ui->comboSeparator->blockSignals(false); + ui->comboQuote->blockSignals(false); + ui->comboEncoding->blockSignals(false); + + // Prepare and show interface depending on how many files are selected + if (csvFilenames.size() > 1) + { + ui->separateTables->setVisible(true); + ui->checkBoxSeparateTables->setVisible(true); + ui->filePickerBlock->setVisible(true); + selectFiles(); + } + else if (csvFilenames.size() == 1) + { + ui->separateTables->setVisible(false); + ui->checkBoxSeparateTables->setVisible(false); + ui->filePickerBlock->setVisible(false); + } + + selectedFile = csvFilenames.front(); + updatePreview(); + checkInput(); +} + +ImportCsvDialog::~ImportCsvDialog() +{ + delete ui; +} + +namespace { +void rollback( + ImportCsvDialog* dialog, + DBBrowserDB* pdb, + DBBrowserDB::db_pointer_type* db_ptr, + const std::string& savepointName, + size_t nRecord, + const QString& message) +{ + // Release DB handle. This needs to be done before calling revertToSavepoint as that function needs to be able to acquire its own handle. + if(db_ptr) + *db_ptr = nullptr; + + QApplication::restoreOverrideCursor(); // restore original cursor + if(!message.isEmpty()) + { + QString sCSVInfo = QObject::tr("Error importing data"); + if(nRecord) + sCSVInfo += QObject::tr(" from record number %1").arg(nRecord); + QString error = sCSVInfo + QObject::tr(".\n%1").arg(message); + QMessageBox::warning(dialog, QApplication::applicationName(), error); + } + pdb->revertToSavepoint(savepointName); +} +} + +class CSVImportProgress : public CSVProgress +{ +public: + explicit CSVImportProgress(int64_t filesize) + : m_pProgressDlg(new QProgressDialog( + QObject::tr("Importing CSV file..."), + QObject::tr("Cancel"), + 0, + 10000)), + totalFileSize(filesize) + { + m_pProgressDlg->setWindowModality(Qt::ApplicationModal); + } + + CSVImportProgress(const CSVImportProgress&) = delete; + bool operator=(const CSVImportProgress&) = delete; + + void start() override + { + m_pProgressDlg->show(); + } + + bool update(int64_t pos) override + { + m_pProgressDlg->setValue(static_cast((static_cast(pos) / static_cast(totalFileSize)) * 10000.0f)); + qApp->processEvents(); + + return !m_pProgressDlg->wasCanceled(); + } + + void end() override + { + m_pProgressDlg->hide(); + } + +private: + std::unique_ptr m_pProgressDlg; + + int64_t totalFileSize; +}; + +void ImportCsvDialog::accept() +{ + // Save settings + Settings::setValue("importcsv", "firstrowheader", ui->checkboxHeader->isChecked()); + Settings::setValue("importcsv", "separator", currentSeparatorChar()); + Settings::setValue("importcsv", "quotecharacter", currentQuoteChar()); + Settings::setValue("importcsv", "trimfields", ui->checkBoxTrimFields->isChecked()); + Settings::setValue("importcsv", "separatetables", ui->checkBoxSeparateTables->isChecked()); + Settings::setValue("importcsv", "encoding", currentEncoding()); + + // Get all the selected files and start the import + if (ui->filePickerBlock->isVisible()) + { + bool filesLeft = false; + + // Loop through all the rows in the file picker list + for (int i = 0; i < ui->filePicker->count(); i++) { + auto item = ui->filePicker->item(i); + int row = ui->filePicker->row(item); + + // Check for files that aren't hidden (=imported) yet but that are checked and thus marked for import + if (item->checkState() == Qt::Checked && !ui->filePicker->isRowHidden(row)) { + if(!importCsv(item->data(Qt::DisplayRole).toString(), item->data(Qt::UserRole).toString())) + { + // If we're supposed to cancel the import process, we always have at least one file left (the cancelled one). Also + // we stop looping through the rest of the CSV files. + filesLeft = true; + break; + } + + // Hide each row after it's done + ui->filePicker->setRowHidden(row, true); + } else if(!ui->filePicker->isRowHidden(row)) { + // Check for files that aren't hidden yet but that aren't checked either. These are files that are still left + // to be imported + filesLeft = true; + } + } + + // Don't close the window if there are still files left to be imported + if(filesLeft) + { + QApplication::restoreOverrideCursor(); // restore original cursor + return; + } + } else { + importCsv(csvFilenames.front()); + } + + QApplication::restoreOverrideCursor(); // restore original cursor + QDialog::accept(); +} + +void ImportCsvDialog::updatePreview() +{ + // Show/hide custom quote/separator input fields + ui->editCustomQuote->setVisible(ui->comboQuote->currentIndex() == ui->comboQuote->count() - OtherPrintable); + ui->editCustomSeparator->setVisible(ui->comboSeparator->currentIndex() == ui->comboSeparator->count() - OtherPrintable); + ui->spinBoxQuote->setVisible(ui->comboQuote->currentIndex() == ui->comboQuote->count() - OtherCode); + ui->spinBoxSeparator->setVisible(ui->comboSeparator->currentIndex() == ui->comboSeparator->count() - OtherCode); + + ui->editCustomEncoding->setVisible(ui->comboEncoding->currentIndex() == ui->comboEncoding->count()-1); + + // Reset preview widget + ui->tablePreview->clear(); + ui->tablePreview->setColumnCount(0); + ui->tablePreview->setRowCount(0); + + // Analyse CSV file + sqlb::FieldVector fieldList = generateFieldList(selectedFile); + + // Reset preview widget + ui->tablePreview->clear(); + ui->tablePreview->setColumnCount(static_cast(fieldList.size())); + + // Exit if there are no lines to preview at all + if(fieldList.size() == 0) + return; + + // Set horizontal header data + QStringList horizontalHeader; + for(const sqlb::Field& field : fieldList) + horizontalHeader.push_back(QString::fromStdString(field.name())); + ui->tablePreview->setHorizontalHeaderLabels(horizontalHeader); + + // Parse file + parseCSV(selectedFile, [this](size_t rowNum, const CSVRow& rowData) -> bool { + // Skip first row if it is to be used as header + if(rowNum == 0 && ui->checkboxHeader->isChecked()) + return true; + + // Decrease the row number by one if the header checkbox is checked to take into account that the first row was used for the table header labels + // and therefore all data rows move one row up. + if(ui->checkboxHeader->isChecked()) + rowNum--; + + // Fill data section + ui->tablePreview->setRowCount(ui->tablePreview->rowCount() + 1); + for(size_t i=0;itablePreview->setVerticalHeaderItem(static_cast(rowNum), new QTableWidgetItem(QString::number(rowNum + 1))); + + // Add table item. Limit data length to a maximum character count to avoid a sluggish UI. And it's very unlikely that this + // many characters are going to be needed anyway for a preview. + uint64_t data_length = rowData.fields[i].data_length; + if(data_length > 1024) + data_length = 1024; + ui->tablePreview->setItem( + static_cast(rowNum), + static_cast(i), + new QTableWidgetItem(QString::fromUtf8(rowData.fields[i].data, static_cast(data_length)))); + } + + return true; + }, 20); +} + +void ImportCsvDialog::checkInput() +{ + bool allowImporting = false; + if (ui->filePickerBlock->isVisible()) { + bool checkedItem = false; + for (int i = 0; i < ui->filePicker->count(); i++) { + if (ui->filePicker->item(i)->checkState() == Qt::Checked) checkedItem = true; + } + allowImporting = !ui->editName->text().isEmpty() && checkedItem; + } else { + allowImporting = !ui->editName->text().isEmpty(); + } + + if (ui->filePicker->currentItem() && ui->checkBoxSeparateTables->isChecked()) { + ui->filePicker->currentItem()->setData(Qt::UserRole, ui->editName->text()); + } + + ui->matchSimilar->setEnabled(ui->filePicker->currentItem() != nullptr); + ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(allowImporting); +} + +void ImportCsvDialog::selectFiles() +{ + for (const auto& fileName : csvFilenames) { + auto fInfo = QFileInfo(fileName); + auto item = new QListWidgetItem(); + item->setText(fileName); + item->setData(Qt::UserRole, fInfo.baseName()); + item->setCheckState(Qt::Checked); + ui->filePicker->addItem(item); + } + + connect(ui->filePicker, &QListWidget::itemSelectionChanged, this, &ImportCsvDialog::updateSelectedFilePreview); +} + +void ImportCsvDialog::updateSelectedFilePreview() +{ + auto selection = ui->filePicker->selectedItems(); + if(!selection.isEmpty()) + { + auto item = selection.first(); + selectedFile = item->data(Qt::DisplayRole).toString(); + ui->editName->setText(item->data(Qt::UserRole).toString()); + updatePreview(); + checkInput(); + } +} + +void ImportCsvDialog::updateSelection(bool selected) +{ + for (int i = 0; i < ui->filePicker->count(); i++) + ui->filePicker->item(i)->setCheckState(selected ? Qt::Checked : Qt::Unchecked); + ui->toggleSelected->setText(selected ? tr("Deselect All") : tr("Select All")); + checkInput(); +} + +void ImportCsvDialog::matchSimilar() +{ + auto selectedHeader = generateFieldList(ui->filePicker->currentItem()->data(Qt::DisplayRole).toString()); + + for (int i = 0; i < ui->filePicker->count(); i++) + { + auto item = ui->filePicker->item(i); + auto header = generateFieldList(item->data(Qt::DisplayRole).toString()); + + if (selectedHeader.size() == header.size()) + { + bool matchingHeader = std::equal(selectedHeader.begin(), selectedHeader.end(), header.begin(), + [](const sqlb::Field& item1, const sqlb::Field& item2) -> bool { + return (item1.name() == item2.name()); + }); + if (matchingHeader) { + item->setCheckState(Qt::Checked); + item->setBackgroundColor(Qt::green); + } + } + else + { + item->setCheckState(Qt::Unchecked); + item->setBackground(Qt::white); + } + } + + checkInput(); +} + +CSVParser::ParserResult ImportCsvDialog::parseCSV(const QString &fileName, std::function rowFunction, size_t count) const +{ + // Parse all csv data + QFile file(fileName); + file.open(QIODevice::ReadOnly); + + CSVParser csv(ui->checkBoxTrimFields->isChecked(), toUtf8(currentSeparatorChar()), toUtf8(currentQuoteChar())); + + // Only show progress dialog if we parse all rows. The assumption here is that if a row count limit has been set, it won't be a very high one. + if(count == 0) + csv.setCSVProgress(new CSVImportProgress(file.size())); + + QTextStream tstream(&file); + tstream.setCodec(currentEncoding().toUtf8()); + + return csv.parse(rowFunction, tstream, count); +} + +sqlb::FieldVector ImportCsvDialog::generateFieldList(const QString& filename) const +{ + sqlb::FieldVector fieldList; // List of fields in the file + + // Parse the first couple of records of the CSV file and only analyse them + parseCSV(filename, [this, &fieldList](size_t rowNum, const CSVRow& rowData) -> bool { + // Has this row more columns than the previous one? Then add more fields to the field list as necessary. + for(size_t i=fieldList.size();icheckboxHeader->isChecked()) + { + // Take field name from CSV and remove invalid characters + fieldname = std::string(rowData.fields[i].data, rowData.fields[i].data_length); + fieldname.erase(std::remove(fieldname.begin(), fieldname.end(), '`'), fieldname.end()); + fieldname.erase(std::remove(fieldname.begin(), fieldname.end(), ' '), fieldname.end()); + fieldname.erase(std::remove(fieldname.begin(), fieldname.end(), '"'), fieldname.end()); + fieldname.erase(std::remove(fieldname.begin(), fieldname.end(), '\''), fieldname.end()); + fieldname.erase(std::remove(fieldname.begin(), fieldname.end(), ','), fieldname.end()); + fieldname.erase(std::remove(fieldname.begin(), fieldname.end(), ';'), fieldname.end()); + } + + // If we don't have a field name by now, generate one + if(fieldname.empty()) + fieldname = "field" + std::to_string(i + 1); + + // Add field to the column list. For now we set the data type to nothing but this might be overwritten later in the automatic + // type detection code. + fieldList.emplace_back(fieldname, ""); + } + + // Try to find out a data type for each column. Skip the header row if there is one. + if(!ui->checkNoTypeDetection->isChecked() && !(rowNum == 0 && ui->checkboxHeader->isChecked())) + { + for(size_t i=0;i(rowData.fields[i].data_length)); + + // Check if the content can be converted to an integer or to float + bool convert_to_int, convert_to_float; + content.toInt(&convert_to_int); + content.toFloat(&convert_to_float); + + // Set new data type. If we don't find any better data type, we fall back to the TEXT data type + std::string new_type = "TEXT"; + if(old_type == "INTEGER" && !convert_to_int && convert_to_float) // So far it's integer, but now it's only convertible to float + new_type = "REAL"; + else if(old_type.empty() && convert_to_int) // No type yet, but this bit is convertible to integer + new_type = "INTEGER"; + else if(old_type.empty() && convert_to_float) // No type yet and only convertible to float (less 'difficult' than integer) + new_type = "REAL"; + else if(old_type == "REAL" && convert_to_float) // It was float so far and still is + new_type = "INTEGER"; + else if(old_type == "INTEGER" && convert_to_int) // It was integer so far and still is + new_type = "INTEGER"; + + fieldList.at(i).setType(new_type); + } + } + } + + // All good + return true; + }, 20); + + return fieldList; +} + +bool ImportCsvDialog::importCsv(const QString& fileName, const QString& name) +{ + // This function returns a boolean to indicate whether to continue or abort the import process. It's worth keeping in mind that + // this doesn't correlate 100% to this import being a success or not. The general rule is that if there was some internal error + // when writing to the database, we stop the entire import process. Also, if the user has clicked Cancel during the import of one + // file, we stop the entire import process, i.e. also the import of the remaining files. Furthermore, if the user clicks the Cancel + // button in a message box we (obviously) cancel the import process, too. In all other cases we return true to indicate that the import + // should continue. + +#ifdef CSV_BENCHMARK + // If benchmark mode is enabled start measuring the performance now + qint64 timesRowFunction = 0; + QElapsedTimer timer; + timer.start(); +#endif + + QString tableName; + + if (csvFilenames.size() > 1 && ui->checkBoxSeparateTables->isChecked()) { + if (name.isEmpty()) { + QFileInfo fileInfo(fileName); + tableName = fileInfo.baseName(); + } else { + tableName = name; + } + } else { + tableName = ui->editName->text(); + } + + // Analyse CSV file + sqlb::FieldVector fieldList = generateFieldList(fileName); + if(fieldList.size() == 0) + return true; + + // Are we importing into an existing table? + bool importToExistingTable = false; + const sqlb::ObjectPtr obj = pdb->getObjectByName(sqlb::ObjectIdentifier("main", tableName.toStdString())); + if(obj && obj->type() == sqlb::Object::Types::Table) + { + if(std::dynamic_pointer_cast(obj)->fields.size() != fieldList.size()) + { + QMessageBox::warning(this, QApplication::applicationName(), + tr("There is already a table named '%1' and an import into an existing table is only possible if the number of columns match.").arg(tableName)); + return true; + } else { + // Only ask whether to import into the existing table if the 'Yes all' button has not been clicked (yet) + if(!dontAskForExistingTableAgain.contains(tableName)) + { + int answer = QMessageBox::question(this, QApplication::applicationName(), + tr("There is already a table named '%1'. Do you want to import the data into it?").arg(tableName), + QMessageBox::Yes | QMessageBox::No | QMessageBox::YesAll | QMessageBox::Cancel, QMessageBox::No); + + // Stop now if the No button has been clicked + if(answer == QMessageBox::No) + return true; + + // Stop now if the Cancel button has been clicked. But also indicate, that the entire import process should be stopped. + if(answer == QMessageBox::Cancel) + return false; + + // If the 'Yes all' button has been clicked, save that for later + if(answer == QMessageBox::YesAll) + dontAskForExistingTableAgain.append(tableName); + } + + // If we reached this point, this means that either the 'Yes' or the 'Yes all' button has been clicked or that no message box was shown at all + // because the 'Yes all' button has been clicked for a previous file + importToExistingTable = true; + } + } + + // Create a savepoint, so we can rollback in case of any errors during importing + // db needs to be saved or an error will occur + std::string restorepointName = pdb->generateSavepointName("csvimport"); + if(!pdb->setSavepoint(restorepointName)) + { + rollback(this, pdb, nullptr, restorepointName, 0, tr("Creating restore point failed: %1").arg(pdb->lastError())); + return false; + } + + // Create table + std::vector nullValues; + std::vector failOnMissingFieldList; + bool ignoreDefaults = ui->checkIgnoreDefaults->isChecked(); + bool failOnMissing = ui->checkFailOnMissing->isChecked(); + if(!importToExistingTable) + { + if(!pdb->createTable(sqlb::ObjectIdentifier("main", tableName.toStdString()), fieldList)) + { + rollback(this, pdb, nullptr, restorepointName, 0, tr("Creating the table failed: %1").arg(pdb->lastError())); + return false; + } + + // If we're creating the table in this import session, don't ask the user if it's okay to import more data into it. It seems + // safe to just assume that's what they want. + dontAskForExistingTableAgain.append(tableName); + } else { + // Importing into an existing table. So find out something about it's structure. + + // Prepare the values for each table column that are to be inserted if the field in the CSV file is empty. Depending on the data type + // and the constraints of a field, we need to handle this case differently. + sqlb::TablePtr tbl = pdb->getObjectByName(sqlb::ObjectIdentifier("main", tableName.toStdString())); + if(tbl) + { + for(const sqlb::Field& f : tbl->fields) + { + // For determining the value for empty fields we follow a set of rules + + // Normally we don't have to fail the import when importing an empty field. This last value of the vector + // is changed to true later if we actually do want to fail the import for this field. + failOnMissingFieldList.push_back(false); + + // If a field has a default value, that gets priority over everything else. + // Exception: if the user wants to ignore default values we never use them. + if(!ignoreDefaults && !f.defaultValue().empty()) + { + nullValues.push_back(f.defaultValue().c_str()); + } else { + // If it has no default value, check if the field is NOT NULL + if(f.notnull()) + { + // The field is NOT NULL + + // If this is an integer column insert 0. Otherwise insert an empty string. + if(f.isInteger()) + nullValues.push_back("0"); + else + nullValues.push_back(""); + + // If the user wants to fail the import, remember this field + if(failOnMissing) + failOnMissingFieldList.back() = true; + } else { + // The field is not NOT NULL (stupid double negation here! NULL values are allowed in this case) + + // Just insert a NULL value + nullValues.push_back(QByteArray()); + } + } + } + } + } + + // Prepare the INSERT statement. The prepared statement can then be reused for each row to insert + std::string sQuery = "INSERT " + currentOnConflictStrategy() + " INTO " + sqlb::escapeIdentifier(tableName.toStdString()) + " VALUES("; + for(size_t i=1;i<=fieldList.size();i++) + sQuery += "?" + std::to_string(i) + ","; + sQuery.pop_back(); // Remove last comma + sQuery.append(")"); + sqlite3_stmt* stmt; + auto pDb = pdb->get(tr("importing CSV")); + sqlite3_prepare_v2(pDb.get(), sQuery.c_str(), static_cast(sQuery.size()), &stmt, nullptr); + + // Parse entire file + size_t lastRowNum = 0; + CSVParser::ParserResult result = parseCSV(fileName, [&](size_t rowNum, const CSVRow& rowData) -> bool { + // Process the parser results row by row + +#ifdef CSV_BENCHMARK + qint64 timeAtStartOfRowFunction = timer.elapsed(); +#endif + + // Save row num for later use. This is used in the case of an error to tell the user in which row the error ocurred + lastRowNum = rowNum; + + // If this is the first row and we want to use the first row as table header, skip it now because this is the data import, not the header parsing + if(rowNum == 0 && ui->checkboxHeader->isChecked()) + return true; + + // Bind all values + for(size_t i=0;i i) + { + // Do we want to fail when trying to import an empty value into this field? Then exit with an error. + if(failOnMissingFieldList.at(i)) + return false; + + // This is an empty value. We'll need to look up how to handle it depending on the field to be inserted into. + const QByteArray& val = nullValues.at(i); + if(!val.isNull()) // No need to bind NULL values here as that is the default bound value in SQLite + sqlite3_bind_text(stmt, static_cast(i)+1, val, val.size(), SQLITE_STATIC); + // When importing into a new table, use the missing values setting directly + } else if(!importToExistingTable && rowData.fields[i].data_length == 0) { + // No need to bind NULL values here as that is the default bound value in SQLite + } else { + // This is a non-empty value, or we want to insert the empty string. Just add it to the statement + sqlite3_bind_text(stmt, static_cast(i)+1, rowData.fields[i].data, static_cast(rowData.fields[i].data_length), SQLITE_STATIC); + } + } + + // Insert row + if(sqlite3_step(stmt) != SQLITE_DONE) + return false; + + // Reset statement for next use. Also reset all bindings to NULL. This is important, so we don't need to bind missing columns or empty values in NULL + // columns manually. + sqlite3_reset(stmt); + sqlite3_clear_bindings(stmt); + +#ifdef CSV_BENCHMARK + timesRowFunction += timer.elapsed() - timeAtStartOfRowFunction; +#endif + + return true; + }); + + // Success? + if(result != CSVParser::ParserResult::ParserResultSuccess) + { + // Some error occurred or the user cancelled the action + + // Rollback the entire import. If the action was cancelled, don't show an error message. If it errored, show an error message. + if(result == CSVParser::ParserResult::ParserResultCancelled) + { + sqlite3_finalize(stmt); + rollback(this, pdb, &pDb, restorepointName, 0, QString()); + return false; + } else { + QString error(sqlite3_errmsg(pDb.get())); + sqlite3_finalize(stmt); + rollback(this, pdb, &pDb, restorepointName, lastRowNum, tr("Inserting row failed: %1").arg(error)); + return false; + } + } + + // Clean up prepared statement + sqlite3_finalize(stmt); + +#ifdef CSV_BENCHMARK + QMessageBox::information(this, qApp->applicationName(), + tr("Importing the file '%1' took %2ms. Of this %3ms were spent in the row function.") + .arg(fileName) + .arg(timer.elapsed()) + .arg(timesRowFunction)); +#endif + + return true; +} + +void ImportCsvDialog::setQuoteChar(QChar c) +{ + QComboBox* combo = ui->comboQuote; + int index = combo->findText(QString(c)); + ui->spinBoxQuote->setValue(c.unicode()); + if(index == -1) + { + if(c.isPrint()) + { + combo->setCurrentIndex(combo->count() - OtherPrintable); + ui->editCustomQuote->setText(QString(c)); + } + else + { + combo->setCurrentIndex(combo->count() - OtherCode); + } + } + else + { + combo->setCurrentIndex(index); + } +} + +QChar ImportCsvDialog::currentQuoteChar() const +{ + QString value; + + // The last item in the combobox is the 'Other' item; if it is selected return the text of the line edit field instead + if(ui->comboQuote->currentIndex() == ui->comboQuote->count() - OtherPrintable) + value = ui->editCustomQuote->text().length() ? ui->editCustomQuote->text() : ""; + else if(ui->comboQuote->currentIndex() == ui->comboQuote->count() - OtherCode) + value = QString(QChar(ui->spinBoxQuote->value())); + else if(ui->comboQuote->currentText().length()) + value = ui->comboQuote->currentText(); + + return value.size() ? value.at(0) : QChar(); +} + +void ImportCsvDialog::setSeparatorChar(QChar c) +{ + QComboBox* combo = ui->comboSeparator; + QString sText = c == '\t' ? QString("Tab") : QString(c); + int index = combo->findText(sText); + ui->spinBoxSeparator->setValue(c.unicode()); + if(index == -1) + { + if(c.isPrint()) + { + combo->setCurrentIndex(combo->count() - OtherPrintable); + ui->editCustomSeparator->setText(QString(c)); + } + else + { + combo->setCurrentIndex(combo->count() - OtherCode); + } + } + else + { + combo->setCurrentIndex(index); + } +} + +QChar ImportCsvDialog::currentSeparatorChar() const +{ + QString value; + + // The last options in the combobox are the 'Other (*)' items; + // if one of them is selected return the text or code of the corresponding field instead + if(ui->comboSeparator->currentIndex() == ui->comboSeparator->count() - OtherPrintable) + value = ui->editCustomSeparator->text().length() ? ui->editCustomSeparator->text() : ""; + else if(ui->comboSeparator->currentIndex() == ui->comboSeparator->count() - OtherCode) + value = QString(QChar(ui->spinBoxSeparator->value())); + else + value = ui->comboSeparator->currentText() == tr("Tab") ? "\t" : ui->comboSeparator->currentText(); + + return value.size() ? value.at(0) : QChar(); +} + +void ImportCsvDialog::setEncoding(const QString& sEnc) +{ + QComboBox* combo = ui->comboEncoding; + int index = combo->findText(sEnc); + if(index == -1) + { + combo->setCurrentIndex(combo->count() - 1); + ui->editCustomEncoding->setText(sEnc); + } + else + { + combo->setCurrentIndex(index); + } +} + +QString ImportCsvDialog::currentEncoding() const +{ + // The last item in the combobox is the 'Other' item; if it is selected return the text of the line edit field instead + if(ui->comboEncoding->currentIndex() == ui->comboEncoding->count()-1) + return ui->editCustomEncoding->text().length() ? ui->editCustomEncoding->text() : "UTF-8"; + else + return ui->comboEncoding->currentText(); +} + +std::string ImportCsvDialog::currentOnConflictStrategy() const +{ + switch(ui->comboOnConflictStrategy->currentIndex()) + { + case 1: + return "OR IGNORE"; + case 2: + return "OR REPLACE"; + default: + return {}; + } +} + +void ImportCsvDialog::toggleAdvancedSection(bool show) +{ + ui->labelNoTypeDetection->setVisible(show); + ui->checkNoTypeDetection->setVisible(show); + ui->labelFailOnMissing->setVisible(show); + ui->checkFailOnMissing->setVisible(show); + ui->labelIgnoreDefaults->setVisible(show); + ui->checkIgnoreDefaults->setVisible(show); + ui->labelOnConflictStrategy->setVisible(show); + ui->comboOnConflictStrategy->setVisible(show); +} + +char32_t ImportCsvDialog::toUtf8(const QString& s) const +{ + if(s.isEmpty()) + return 0; + + QByteArray ba = s.toUtf8(); + + char32_t result = 0; + for(int i=std::min(ba.size()-1,3);i>=0;i--) + result = (result << 8) + static_cast(ba.at(i)); + + return result; +} diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/ImportCsvDialog.h b/src/WBCLFZSystemModule/SqliteDBProcess/src/ImportCsvDialog.h new file mode 100644 index 0000000..6e7f92e --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/ImportCsvDialog.h @@ -0,0 +1,67 @@ +#ifndef IMPORTCSVDIALOG_H +#define IMPORTCSVDIALOG_H + +#include "csvparser.h" +#include "sql/sqlitetypes.h" + +#include +#include + +class DBBrowserDB; +class QCompleter; + +namespace Ui { +class ImportCsvDialog; +} + +class ImportCsvDialog : public QDialog +{ + Q_OBJECT + +public: + explicit ImportCsvDialog(const std::vector& filenames, DBBrowserDB* db, QWidget* parent = nullptr); + ~ImportCsvDialog() override; + +private slots: + void accept() override; + void updatePreview(); + void checkInput(); + void selectFiles(); + void updateSelectedFilePreview(); + void updateSelection(bool); + void matchSimilar(); + void toggleAdvancedSection(bool show); + +private: + + // Positions for combos starting at the bottom + enum {OtherCode = 1, + OtherPrintable = 2}; + + Ui::ImportCsvDialog* ui; + std::vector csvFilenames; + QString selectedFile; + DBBrowserDB* pdb; + QCompleter* encodingCompleter; + QStringList dontAskForExistingTableAgain; + + CSVParser::ParserResult parseCSV(const QString& fileName, std::function rowFunction, size_t count = 0) const; + sqlb::FieldVector generateFieldList(const QString& filename) const; + + bool importCsv(const QString& f, const QString& n = QString()); + + void setQuoteChar(QChar c); + QChar currentQuoteChar() const; + + void setSeparatorChar(QChar c); + QChar currentSeparatorChar() const; + + void setEncoding(const QString& sEnc); + QString currentEncoding() const; + + std::string currentOnConflictStrategy() const; + + char32_t toUtf8(const QString& s) const; +}; + +#endif diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/ImportCsvDialog.ui b/src/WBCLFZSystemModule/SqliteDBProcess/src/ImportCsvDialog.ui new file mode 100644 index 0000000..c470c8d --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/ImportCsvDialog.ui @@ -0,0 +1,786 @@ + + + ImportCsvDialog + + + + 0 + 0 + 788 + 717 + + + + Import CSV file + + + + + + QFormLayout::ExpandingFieldsGrow + + + + + Table na&me + + + editName + + + + + + + + + + &Column names in first line + + + checkboxHeader + + + + + + + + + + + + + + Field &separator + + + comboSeparator + + + + + + + + + + , + + + + + ; + + + + + Tab + + + + + | + + + + + Other (printable) + + + + + Other (code) + + + + + + + + 1 + + + + + + + 1114112 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + &Quote character + + + comboQuote + + + + + + + + + + " + + + + + ' + + + + + + + + + + Other (printable) + + + + + Other (code) + + + + + + + + 1 + + + + + + + 1114112 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + &Encoding + + + comboEncoding + + + + + + + + + + UTF-8 + + + + + UTF-16 + + + + + ISO-8859-1 + + + + + Other + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + Trim fields? + + + checkBoxTrimFields + + + + + + + + + + true + + + + + + + Separate tables + + + checkBoxSeparateTables + + + + + + + + + + + + + + Advanced + + + + :/icons/down:/icons/down + + + true + + + + + + + When importing an empty value from the CSV file into an existing table with a default value for this column, that default value is inserted. Activate this option to insert an empty value instead. + + + + + + + Ignore default &values + + + checkIgnoreDefaults + + + + + + + Activate this option to stop the import when trying to import an empty value into a NOT NULL column without a default value. + + + + + + + Fail on missing values + + + checkFailOnMissing + + + + + + + Disable data type detection + + + checkNoTypeDetection + + + + + + + Disable the automatic data type detection when creating a new table. + + + + + + + When importing into an existing table with a primary key, unique constraints or a unique index there is a chance for a conflict. This option allows you to select a strategy for that case: By default the import is aborted and rolled back but you can also choose to ignore and not import conflicting rows or to replace the existing row in the table. + + + + Abort import + + + + + Ignore row + + + + + Replace existing row + + + + + + + + Conflict strategy + + + comboOnConflictStrategy + + + + + + + + + Qt::Vertical + + + false + + + + true + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + + 7 + + + QLayout::SetDefaultConstraint + + + 0 + + + + + Deselect All + + + true + + + true + + + + + + + false + + + Match Similar + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + editName + checkboxHeader + comboSeparator + editCustomSeparator + comboQuote + editCustomQuote + comboEncoding + editCustomEncoding + checkBoxTrimFields + checkBoxSeparateTables + buttonAdvanced + checkIgnoreDefaults + checkNoTypeDetection + checkFailOnMissing + comboOnConflictStrategy + filePicker + toggleSelected + matchSimilar + tablePreview + + + + + + + comboSeparator + currentIndexChanged(int) + ImportCsvDialog + updatePreview() + + + 245 + 92 + + + 445 + 64 + + + + + editName + textChanged(QString) + ImportCsvDialog + checkInput() + + + 609 + 13 + + + 631 + 45 + + + + + editCustomSeparator + textChanged(QString) + ImportCsvDialog + updatePreview() + + + 511 + 92 + + + 577 + 76 + + + + + editCustomQuote + textChanged(QString) + ImportCsvDialog + updatePreview() + + + 511 + 126 + + + 530 + 90 + + + + + editCustomEncoding + textChanged(QString) + ImportCsvDialog + updatePreview() + + + 524 + 160 + + + 540 + 133 + + + + + checkBoxTrimFields + toggled(bool) + ImportCsvDialog + updatePreview() + + + 192 + 182 + + + 368 + 244 + + + + + comboEncoding + currentIndexChanged(int) + ImportCsvDialog + updatePreview() + + + 271 + 160 + + + 572 + 121 + + + + + checkboxHeader + toggled(bool) + ImportCsvDialog + updatePreview() + + + 192 + 56 + + + 354 + 45 + + + + + toggleSelected + toggled(bool) + ImportCsvDialog + updateSelection(bool) + + + 777 + 385 + + + 368 + 244 + + + + + comboQuote + currentIndexChanged(int) + ImportCsvDialog + updatePreview() + + + 245 + 126 + + + 350 + 88 + + + + + buttonBox + accepted() + ImportCsvDialog + accept() + + + 281 + 707 + + + 157 + 274 + + + + + buttonBox + rejected() + ImportCsvDialog + reject() + + + 349 + 707 + + + 286 + 274 + + + + + checkBoxSeparateTables + toggled(bool) + ImportCsvDialog + checkInput() + + + 192 + 206 + + + 368 + 244 + + + + + matchSimilar + pressed() + ImportCsvDialog + matchSimilar() + + + 777 + 418 + + + 368 + 244 + + + + + buttonAdvanced + toggled(bool) + ImportCsvDialog + toggleAdvancedSection(bool) + + + 265 + 241 + + + 393 + 358 + + + + + spinBoxQuote + valueChanged(int) + ImportCsvDialog + updatePreview() + + + 529 + 111 + + + 393 + 358 + + + + + spinBoxSeparator + valueChanged(int) + ImportCsvDialog + updatePreview() + + + 529 + 77 + + + 393 + 358 + + + + + + updatePreview() + checkInput() + updateSelection(bool) + matchSimilar() + toggleAdvancedSection(bool) + + diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/MainWindow.cpp b/src/WBCLFZSystemModule/SqliteDBProcess/src/MainWindow.cpp new file mode 100644 index 0000000..8f99604 --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/MainWindow.cpp @@ -0,0 +1,3473 @@ +#include "MainWindow.h" +#include "ui_MainWindow.h" + +#include "Application.h" +#include "EditIndexDialog.h" +#include "AboutDialog.h" +#include "EditTableDialog.h" +#include "ImportCsvDialog.h" +#include "ExportDataDialog.h" +#include "Settings.h" +#include "PreferencesDialog.h" +#include "EditDialog.h" +#include "sqlitetablemodel.h" +#include "SqlExecutionArea.h" +#include "VacuumDialog.h" +#include "DbStructureModel.h" +#include "version.h" +#include "sqlite.h" +#include "CipherDialog.h" +#include "ExportSqlDialog.h" +#include "SqlUiLexer.h" +#include "FileDialog.h" +#include "FilterTableHeader.h" +//#include "remoteDock.h" +#include "FindReplaceDialog.h" +#include "RunSql.h" +#include "ExtendedTableWidget.h" +#include "Data.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include // This include seems to only be necessary for the Windows build +#include +#include +#include + +#ifdef Q_OS_MACX //Needed only on macOS + #include +#endif + +#include + +const int MainWindow::MaxRecentFiles; + +// These are needed for reading and writing object files +QDataStream& operator>>(QDataStream& ds, sqlb::ObjectIdentifier& objid) +{ + // Read in the item + QVariant v; + ds >> v; + + // If it is a string list, we can treat it as an object identifier. If it isn't, we assume it's just a + // single string and use interpret it as the table name in the main schema. This is done for backwards + // compatability with old project file formats. + QStringList str = v.toStringList(); + if(str.isEmpty()) + { + objid = sqlb::ObjectIdentifier("main", v.toString().toStdString()); + } else { + objid.setSchema(str.first().toStdString()); + if(str.size() >= 2) + objid.setName(str.last().toStdString()); + } + return ds; +} + +// This is a temporary helper function. Delete it once we clean up the project file loading. +static std::vector toSortOrderVector(int index, Qt::SortOrder mode) +{ + std::vector vector; + vector.emplace_back(index, mode == Qt::AscendingOrder ? sqlb::Ascending : sqlb::Descending); + return vector; +} + +MainWindow::MainWindow(QWidget* parent) + : QMainWindow(parent), + ui(new Ui::MainWindow), + db(), + editDock(new EditDialog(this)), + plotDock(new PlotDock(this)), + ////remoteDock(new remoteDock(this)), // ²Ã¼ô³öµÄ¹¦ÄÜÖ»ÊÊÓñ¾µØ£¬²»¿¼ÂÇÔ¶³ÌÊý¾Ý¿âÁ¬½Ó¹¦ÄÜ + findReplaceDialog(new FindReplaceDialog(this)), + execute_sql_worker(nullptr), + isProjectModified(false) +{ + ui->setupUi(this); + init(); + + activateFields(false); + updateRecentFileActions(); +} + +MainWindow::~MainWindow() +{ + delete ui; +} + +void MainWindow::init() +{ + // Load window settings + tabifyDockWidget(ui->dockLog, ui->dockPlot); + tabifyDockWidget(ui->dockLog, ui->dockSchema); + tabifyDockWidget(ui->dockLog, ui->dockRemote); + +#ifdef Q_OS_MACX + // Add OpenGL Context for macOS + QOpenGLWidget *ogl = new QOpenGLWidget(this); + ui->verticalLayout->addWidget(ogl); + ogl->setHidden(true); +#endif + + // Automatic update check +#ifdef CHECKNEWVERSION + connect(&RemoteNetwork::get(), &RemoteNetwork::networkReady, [this]() { + // Check for a new version if automatic update check aren't disabled in the settings dialog + if(Settings::getValue("checkversion", "enabled").toBool()) + { + RemoteNetwork::get().fetch(QUrl("https://download.sqlitebrowser.org/currentrelease"), RemoteNetwork::RequestTypeCustom, + QString(), [this](const QByteArray& reply) { + QList info = reply.split('\n'); + if(info.size() >= 2) + { + QString version = info.at(0).trimmed(); + QString url = info.at(1).trimmed(); + checkNewVersion(version, url); + } + }); + } + }); +#endif + + // Connect SQL logging and database state setting to main window + connect(&db, &DBBrowserDB::dbChanged, this, &MainWindow::dbState, Qt::QueuedConnection); + connect(&db, &DBBrowserDB::sqlExecuted, this, &MainWindow::logSql, Qt::QueuedConnection); + connect(&db, &DBBrowserDB::requestCollation, this, &MainWindow::requestCollation); + + // Initialise table browser first + ui->tableBrowser->init(&db); + + // Set project modified flag when the settings in the table browser were changed + connect(ui->tableBrowser, &TableBrowser::projectModified, this, [this]() { + isProjectModified = true; + }); + + connect(ui->tableBrowser->model(), &SqliteTableModel::dataChanged, this, &MainWindow::dataTableSelectionChanged); + connect(ui->tableBrowser, &TableBrowser::selectionChanged, this, &MainWindow::dataTableSelectionChanged); + connect(ui->tableBrowser, &TableBrowser::selectionChangedByDoubleClick, this, &MainWindow::doubleClickTable); + connect(ui->tableBrowser, &TableBrowser::updatePlot, this, &MainWindow::attachPlot); + connect(ui->tableBrowser, &TableBrowser::createView, this, &MainWindow::saveAsView); + connect(ui->tableBrowser, &TableBrowser::requestFileOpen, this, [this](const QString& file) { + fileOpen(file); + }); + connect(ui->tableBrowser, &TableBrowser::statusMessageRequested, ui->statusbar, [this](const QString& message) { + ui->statusbar->showMessage(message); + }); + + m_currentTabTableModel = ui->tableBrowser->model(); + + // Set up DB structure tab + dbStructureModel = new DbStructureModel(db, this); + connect(&db, &DBBrowserDB::structureUpdated, this, [this]() { + sqlb::ObjectIdentifier old_table = ui->tableBrowser->currentlyBrowsedTableName(); + dbStructureModel->reloadData(); + populateStructure(old_table); + }); + ui->dbTreeWidget->setModel(dbStructureModel); + ui->dbTreeWidget->setColumnWidth(DbStructureModel::ColumnName, 300); + ui->dbTreeWidget->setColumnHidden(DbStructureModel::ColumnObjectType, true); + ui->dbTreeWidget->setColumnHidden(DbStructureModel::ColumnSchema, true); + + // Set up DB schema dock + ui->treeSchemaDock->setModel(dbStructureModel); + ui->treeSchemaDock->setColumnHidden(DbStructureModel::ColumnObjectType, true); + ui->treeSchemaDock->setColumnHidden(DbStructureModel::ColumnSchema, true); + + // Set up the table combo box in the Browse Data tab + ui->tableBrowser->setStructure(dbStructureModel); + + // Create docks + ui->dockEdit->setWidget(editDock); + ui->dockPlot->setWidget(plotDock); + //ui->dockRemote->setWidget(//remoteDock); + + // Set up edit dock + editDock->setReadOnly(true); + + // Restore window geometry + restoreGeometry(Settings::getValue("MainWindow", "geometry").toByteArray()); + + // Save default and restore window state + defaultWindowState = saveState(); + restoreState(Settings::getValue("MainWindow", "windowState").toByteArray()); + + // Save default and restore open tab order if the openTabs setting is saved. + defaultOpenTabs = saveOpenTabs(); + restoreOpenTabs(Settings::getValue("MainWindow", "openTabs").toString()); + + // Restore dock state settings + ui->comboLogSubmittedBy->setCurrentIndex(ui->comboLogSubmittedBy->findText(Settings::getValue("SQLLogDock", "Log").toString())); + + // Add keyboard shortcuts + QShortcut* shortcutBrowseRefreshF5 = new QShortcut(QKeySequence("F5"), this); + connect(shortcutBrowseRefreshF5, &QShortcut::activated, this, &MainWindow::refresh); + QShortcut* shortcutBrowseRefreshCtrlR = new QShortcut(QKeySequence("Ctrl+R"), this); + connect(shortcutBrowseRefreshCtrlR, &QShortcut::activated, this, &MainWindow::refresh); + + // Add print shortcut for the DB Structure tab (dbTreeWidget) with context to the widget, so other print shortcuts aren't eclipsed. + QShortcut* shortcutPrint = new QShortcut(QKeySequence(QKeySequence::Print), ui->dbTreeWidget, nullptr, nullptr, Qt::WidgetShortcut); + connect(shortcutPrint, &QShortcut::activated, this, &MainWindow::printDbStructure); + + QShortcut* closeTabShortcut = new QShortcut(tr("Ctrl+W"), ui->tabSqlAreas, nullptr, nullptr, Qt::WidgetWithChildrenShortcut); + connect(closeTabShortcut, &QShortcut::activated, this, [this]() { + if(ui->tabSqlAreas->currentIndex() >= 0) + closeSqlTab(ui->tabSqlAreas->currentIndex()); + }); + + // Create the actions for the recently opened dbs list + for(int i = 0; i < MaxRecentFiles; ++i) { + recentFileActs[i] = new QAction(this); + recentFileActs[i]->setVisible(false); + connect(recentFileActs[i], &QAction::triggered, this, &MainWindow::openRecentFile); + } + for(int i = 0; i < MaxRecentFiles; ++i) + ui->fileMenu->insertAction(ui->fileExitAction, recentFileActs[i]); + recentSeparatorAct = ui->fileMenu->insertSeparator(ui->fileExitAction); + + // Create popup menus + popupTableMenu = new QMenu(this); + popupTableMenu->addAction(ui->actionEditBrowseTable); + popupTableMenu->addAction(ui->editModifyObjectAction); + popupTableMenu->addAction(ui->editDeleteObjectAction); + popupTableMenu->addSeparator(); + popupTableMenu->addAction(ui->actionEditCopyCreateStatement); + popupTableMenu->addAction(ui->actionExportCsvPopup); + + popupSchemaDockMenu = new QMenu(this); + popupSchemaDockMenu->addAction(ui->actionPopupSchemaDockBrowseTable); + popupSchemaDockMenu->addSeparator(); + popupSchemaDockMenu->addAction(ui->actionDropQualifiedCheck); + popupSchemaDockMenu->addAction(ui->actionEnquoteNamesCheck); + + popupOpenDbMenu = new QMenu(this); + popupOpenDbMenu->addAction(ui->fileOpenAction); + popupOpenDbMenu->addAction(ui->fileOpenReadOnlyAction); + ui->fileOpenActionPopup->setMenu(popupOpenDbMenu); + + popupSaveSqlFileMenu = new QMenu(this); + popupSaveSqlFileMenu->addAction(ui->actionSqlSaveFile); + popupSaveSqlFileMenu->addAction(ui->actionSqlSaveFileAs); + ui->actionSqlSaveFilePopup->setMenu(popupSaveSqlFileMenu); + + popupSaveSqlResultsMenu = new QMenu(this); + popupSaveSqlResultsMenu->addAction(ui->actionSqlResultsExportCsv); + popupSaveSqlResultsMenu->addAction(ui->actionSqlResultsSaveAsView); + ui->actionSqlResultsSave->setMenu(popupSaveSqlResultsMenu); + qobject_cast(ui->toolbarSql->widgetForAction(ui->actionSqlResultsSave))->setPopupMode(QToolButton::InstantPopup); + + // Add menu item for log dock + ui->viewMenu->insertAction(ui->viewDBToolbarAction, ui->dockLog->toggleViewAction()); + ui->viewMenu->actions().at(0)->setShortcut(QKeySequence(tr("Ctrl+L"))); + ui->viewMenu->actions().at(0)->setIcon(QIcon(":/icons/log_dock")); + + // Add menu item for plot dock + ui->viewMenu->insertAction(ui->viewDBToolbarAction, ui->dockPlot->toggleViewAction()); + ui->viewMenu->actions().at(1)->setShortcut(QKeySequence(tr("Ctrl+D"))); + ui->viewMenu->actions().at(1)->setIcon(QIcon(":/icons/log_dock")); + + // Add menu item for schema dock + ui->viewMenu->insertAction(ui->viewDBToolbarAction, ui->dockSchema->toggleViewAction()); + ui->viewMenu->actions().at(2)->setShortcut(QKeySequence(tr("Ctrl+I"))); + ui->viewMenu->actions().at(2)->setIcon(QIcon(":/icons/log_dock")); + + // Add menu item for edit dock + ui->viewMenu->insertAction(ui->viewDBToolbarAction, ui->dockEdit->toggleViewAction()); + ui->viewMenu->actions().at(3)->setShortcut(QKeySequence(tr("Ctrl+E"))); + ui->viewMenu->actions().at(3)->setIcon(QIcon(":/icons/log_dock")); + + // Add menu item for plot dock + ui->viewMenu->insertAction(ui->viewDBToolbarAction, ui->dockRemote->toggleViewAction()); + ui->viewMenu->actions().at(4)->setIcon(QIcon(":/icons/log_dock")); + + // Set checked state if toolbar is visible + ui->viewDBToolbarAction->setChecked(!ui->toolbarDB->isHidden()); + ui->viewExtraDBToolbarAction->setChecked(!ui->toolbarExtraDB->isHidden()); + ui->viewProjectToolbarAction->setChecked(!ui->toolbarProject->isHidden()); + + // Add separator between docks and toolbars + ui->viewMenu->insertSeparator(ui->viewDBToolbarAction); + + // Connect the tabCloseRequested to the actual closeTab function. + // This must be done before the connections for checking the actions in the View menu so + // they are updated accordingly. + connect(ui->mainTab, &QTabWidget::tabCloseRequested, this, &MainWindow::closeTab); + + // Add entries for toggling the visibility of main tabs + for (QWidget* widget : {ui->structure, ui->browser, ui->pragmas, ui->query}) { + QAction* action = ui->viewMenu->addAction(QIcon(":/icons/open_sql"), widget->accessibleName()); + action->setObjectName(widget->accessibleName()); + action->setCheckable(true); + action->setChecked(ui->mainTab->indexOf(widget) != -1); + connect(action, &QAction::toggled, [=](bool show) { toggleTabVisible(widget, show); }); + // Connect tabCloseRequested for setting checked the appropiate menu entry. + // Note these are called after the actual tab is closed only because they are connected + // after connecting closeTab. + connect(ui->mainTab, &QTabWidget::tabCloseRequested, [=](int /*index*/) { + action->setChecked(ui->mainTab->indexOf(widget) != -1); + }); + } + + ui->viewMenu->addSeparator(); + + QMenu* layoutMenu = new QMenu(tr("Window Layout"), this); + ui->viewMenu->addMenu(layoutMenu); + + QAction* resetLayoutAction = layoutMenu->addAction(tr("Reset Window Layout")); + resetLayoutAction->setShortcut(QKeySequence(tr("Alt+0"))); + connect(resetLayoutAction, &QAction::triggered, [=]() { + restoreState(defaultWindowState); + restoreOpenTabs(defaultOpenTabs); + ui->viewDBToolbarAction->setChecked(!ui->toolbarDB->isHidden()); + ui->viewExtraDBToolbarAction->setChecked(!ui->toolbarExtraDB->isHidden()); + ui->viewProjectToolbarAction->setChecked(!ui->toolbarProject->isHidden()); + }); + QAction* simplifyLayoutAction = layoutMenu->addAction(tr("Simplify Window Layout")); + simplifyLayoutAction->setShortcut(QKeySequence(tr("Shift+Alt+0"))); + connect(simplifyLayoutAction, &QAction::triggered, [=]() { + ui->viewMenu->findChild(ui->pragmas->accessibleName())->activate(QAction::Trigger); + ui->dockLog->hide(); + ui->dockPlot->hide(); + ui->dockSchema->hide(); + ui->dockEdit->hide(); + ui->dockRemote->hide(); + }); + QAction* atBottomLayoutAction = layoutMenu->addAction(tr("Dock Windows at Bottom")); + connect(atBottomLayoutAction, &QAction::triggered, [=]() { + moveDocksTo(Qt::BottomDockWidgetArea); + }); + QAction* atLeftLayoutAction = layoutMenu->addAction(tr("Dock Windows at Left Side")); + connect(atLeftLayoutAction, &QAction::triggered, [=]() { + moveDocksTo(Qt::LeftDockWidgetArea); + }); + QAction* atTopLayoutAction = layoutMenu->addAction(tr("Dock Windows at Top")); + connect(atTopLayoutAction, &QAction::triggered, [=]() { + moveDocksTo(Qt::TopDockWidgetArea); + }); + + // Set Alt+[1-4] shortcuts for opening the corresponding tab in that position. + // Note that it is safe to call setCurrentIndex with a tab that is currently closed, + // since setCurrentIndex does nothing in that case. + QShortcut* setTab1Shortcut = new QShortcut(QKeySequence("Alt+1"), this); + connect(setTab1Shortcut, &QShortcut::activated, [this]() { ui->mainTab->setCurrentIndex(0); }); + QShortcut* setTab2Shortcut = new QShortcut(QKeySequence("Alt+2"), this); + connect(setTab2Shortcut, &QShortcut::activated, [this]() { ui->mainTab->setCurrentIndex(1); }); + QShortcut* setTab3Shortcut = new QShortcut(QKeySequence("Alt+3"), this); + connect(setTab3Shortcut, &QShortcut::activated, [this]() { ui->mainTab->setCurrentIndex(2); }); + QShortcut* setTab4Shortcut = new QShortcut(QKeySequence("Alt+4"), this); + connect(setTab4Shortcut, &QShortcut::activated, [this]() { ui->mainTab->setCurrentIndex(3); }); + + // If we're not compiling in SQLCipher, hide its FAQ link in the help menu +#ifndef ENABLE_SQLCIPHER + ui->actionSqlCipherFaq->setVisible(false); +#endif + + // Set statusbar fields + statusBusyLabel = new QLabel(ui->statusbar); + statusBusyLabel->setEnabled(false); + statusBusyLabel->setVisible(false); + statusBusyLabel->setToolTip(tr("The database is currenctly busy.")); + ui->statusbar->addPermanentWidget(statusBusyLabel); + + statusStopButton = new QToolButton(ui->statusbar); + statusStopButton->setVisible(false); + statusStopButton->setIcon(QIcon(":icons/cancel")); + statusStopButton->setToolTip(tr("Click here to interrupt the currently running query.")); + statusStopButton->setMaximumSize(ui->statusbar->geometry().height() - 6, ui->statusbar->geometry().height() - 6); + statusStopButton->setAutoRaise(true); + ui->statusbar->addPermanentWidget(statusStopButton); + + statusEncryptionLabel = new QLabel(ui->statusbar); + statusEncryptionLabel->setEnabled(false); + statusEncryptionLabel->setVisible(false); + statusEncryptionLabel->setText(tr("Encrypted")); + statusEncryptionLabel->setToolTip(tr("Database is encrypted using SQLCipher")); + ui->statusbar->addPermanentWidget(statusEncryptionLabel); + + statusReadOnlyLabel = new QLabel(ui->statusbar); + statusReadOnlyLabel->setEnabled(false); + statusReadOnlyLabel->setVisible(false); + statusReadOnlyLabel->setText(tr("Read only")); + statusReadOnlyLabel->setToolTip(tr("Database file is read only. Editing the database is disabled.")); + ui->statusbar->addPermanentWidget(statusReadOnlyLabel); + + statusEncodingLabel = new QLabel(ui->statusbar); + statusEncodingLabel->setEnabled(false); + statusEncodingLabel->setText("UTF-8"); + statusEncodingLabel->setToolTip(tr("Database encoding")); + ui->statusbar->addPermanentWidget(statusEncodingLabel); + + // When changing the text of the toolbar actions, also automatically change their icon text and their tooltip text + connect(ui->editModifyObjectAction, &QAction::changed, [=]() { + ui->editModifyObjectAction->setIconText(ui->editModifyObjectAction->text()); + ui->editModifyObjectAction->setToolTip(ui->editModifyObjectAction->text()); + }); + connect(ui->editDeleteObjectAction, &QAction::changed, [=]() { + ui->editDeleteObjectAction->setIconText(ui->editDeleteObjectAction->text()); + ui->editDeleteObjectAction->setToolTip(ui->editDeleteObjectAction->text()); + }); + + // When clicking the interrupt query button in the status bar, ask SQLite to interrupt the current query + connect(statusStopButton, &QToolButton::clicked, [this]() { + db.interruptQuery(); + }); + + // Connect some more signals and slots + connect(editDock, &EditDialog::recordTextUpdated, this, &MainWindow::updateRecordText); + connect(editDock, &EditDialog::requestUrlOrFileOpen, this, &MainWindow::openUrlOrFile); + connect(ui->dbTreeWidget->selectionModel(), &QItemSelectionModel::currentChanged, this, &MainWindow::changeTreeSelection); + connect(ui->dockEdit, &QDockWidget::visibilityChanged, this, &MainWindow::toggleEditDock); + //connect(//remoteDock, SIGNAL(openFile(QString)), this, SLOT(fileOpen(QString))); + connect(ui->actionDropQualifiedCheck, &QAction::toggled, dbStructureModel, &DbStructureModel::setDropQualifiedNames); + connect(ui->actionEnquoteNamesCheck, &QAction::toggled, dbStructureModel, &DbStructureModel::setDropEnquotedNames); + connect(&db, &DBBrowserDB::databaseInUseChanged, this, &MainWindow::updateDatabaseBusyStatus); + + ui->actionDropQualifiedCheck->setChecked(Settings::getValue("SchemaDock", "dropQualifiedNames").toBool()); + ui->actionEnquoteNamesCheck->setChecked(Settings::getValue("SchemaDock", "dropEnquotedNames").toBool()); + + connect(ui->tableBrowser->model(), &SqliteTableModel::finishedFetch, [this](){ + auto& settings = ui->tableBrowser->settings(ui->tableBrowser->currentlyBrowsedTableName()); + plotDock->updatePlot(ui->tableBrowser->model(), &settings, true, false); + }); + + connect(ui->actionSqlStop, &QAction::triggered, [this]() { + if(execute_sql_worker && execute_sql_worker->isRunning()) + execute_sql_worker->stop(); + }); + + // Connect tool pragmas + connect(ui->actionIntegrityCheck, &QAction::triggered, [this]() { + runSqlNewTab("PRAGMA integrity_check;", ui->actionIntegrityCheck->text(), "https://www.sqlite.org/pragma.html#pragma_integrity_check"); + }); + connect(ui->actionQuickCheck, &QAction::triggered, [this]() { + runSqlNewTab("PRAGMA quick_check;", ui->actionQuickCheck->text(), "https://www.sqlite.org/pragma.html#pragma_quick_check"); + }); + connect(ui->actionForeignKeyCheck, &QAction::triggered, [this]() { + runSqlNewTab("PRAGMA foreign_key_check;", ui->actionForeignKeyCheck->text(), "https://www.sqlite.org/pragma.html#pragma_foreign_key_check"); + }); + connect(ui->actionOptimize, &QAction::triggered, [this]() { + runSqlNewTab("PRAGMA optimize;", ui->actionOptimize->text(), "https://www.sqlite.org/pragma.html#pragma_optimize"); + }); + + // Action for switching the table via the Database Structure tab + connect(ui->actionPopupSchemaDockBrowseTable, &QAction::triggered, [this]() { + sqlb::ObjectIdentifier obj(ui->treeSchemaDock->model()->data(ui->treeSchemaDock->currentIndex().sibling(ui->treeSchemaDock->currentIndex().row(), DbStructureModel::ColumnSchema), Qt::EditRole).toString().toStdString(), + ui->treeSchemaDock->model()->data(ui->treeSchemaDock->currentIndex().sibling(ui->treeSchemaDock->currentIndex().row(), DbStructureModel::ColumnName), Qt::EditRole).toString().toStdString()); + switchToBrowseDataTab(obj); + refresh(); // Required in case the Browse Data tab already was the active main tab + }); + + // Set other window settings + setAcceptDrops(true); + setWindowTitle(QApplication::applicationName()); + + // Add the documentation of shortcuts, which aren't otherwise visible in the user interface, to some buttons. + addShortcutsTooltip(ui->actionDbPrint); + addShortcutsTooltip(ui->actionSqlOpenTab); + addShortcutsTooltip(ui->actionSqlPrint); + addShortcutsTooltip(ui->actionExecuteSql, {shortcutBrowseRefreshF5->key(), shortcutBrowseRefreshCtrlR->key()}); + addShortcutsTooltip(ui->actionSqlExecuteLine); + addShortcutsTooltip(ui->actionSqlFind); + addShortcutsTooltip(ui->actionSqlFindReplace); + addShortcutsTooltip(ui->actionSqlToggleComment); + + // Load all settings + reloadSettings(); + +#ifndef ENABLE_SQLCIPHER + // Only show encryption menu action when SQLCipher support is enabled + ui->actionEncryption->setVisible(false); +#endif + + /* Remove all the '&' signs from the dock titles. On at least Windows and + * OSX, Qt doesn't seem to support them properly, so they end up being + * visible instead of creating a keyboard shortcut + */ + ui->dockEdit->setWindowTitle(ui->dockEdit->windowTitle().remove('&')); + ui->dockLog->setWindowTitle(ui->dockLog->windowTitle().remove('&')); + ui->dockPlot->setWindowTitle(ui->dockPlot->windowTitle().remove('&')); + ui->dockSchema->setWindowTitle(ui->dockSchema->windowTitle().remove('&')); + ui->dockRemote->setWindowTitle(ui->dockRemote->windowTitle().remove('&')); +} + +bool MainWindow::fileOpen(const QString& fileName, bool openFromProject, bool readOnly) +{ + bool retval = false; + + QString wFile = fileName; + // QFile::exist will produce error message if passed empty string. + // Test string length before usage w/ QFile to silence warning + if (wFile.isEmpty() || !QFile::exists(wFile)) + { + wFile = FileDialog::getOpenFileName( + OpenDatabaseFile, + this, + tr("Choose a database file") +#ifndef Q_OS_MAC // Filters on OS X are buggy + , FileDialog::getSqlDatabaseFileFilter() +#endif + ); + } + // catch situation where user has canceled file selection from dialog + if(!wFile.isEmpty() && QFile::exists(wFile) ) + { + // Close the database. If the user didn't want to close it, though, stop here + if (db.isOpen()) + if(!fileClose()) + return false; + + // Try opening it as a project file first + if(loadProject(wFile, readOnly)) + { + retval = true; + } else { + // No project file; so it should be a database file + if(db.open(wFile, readOnly)) + { + // Close all open but empty SQL tabs + for(int i=ui->tabSqlAreas->count()-1;i>=0;i--) + { + if(qobject_cast(ui->tabSqlAreas->widget(i))->getSql().trimmed().isEmpty()) + closeSqlTab(i, true); + } + + statusEncodingLabel->setText(db.getPragma("encoding")); + statusEncryptionLabel->setVisible(db.encrypted()); + statusReadOnlyLabel->setVisible(db.readOnly()); + setCurrentFile(wFile); + if(!openFromProject) { + addToRecentFilesMenu(wFile, readOnly); + // When a new DB file has been open while a project is open, set the project modified. + if(!currentProjectFilename.isEmpty()) + isProjectModified = true; + } + if(ui->tabSqlAreas->count() == 0) + openSqlTab(true); + if(ui->mainTab->currentWidget() == ui->browser) + populateTable(); + else if(ui->mainTab->currentWidget() == ui->pragmas) + loadPragmas(); + + // Update remote dock + //remoteDock->fileOpened(wFile); + + retval = true; + } else { + QMessageBox::warning(this, qApp->applicationName(), tr("Could not open database file.\nReason: %1").arg(db.lastError())); + return false; + } + } + } + + return retval; +} + +void MainWindow::fileNew() +{ + QString fileName = FileDialog::getSaveFileName( + CreateDatabaseFile, + this, + tr("Choose a filename to save under"), + FileDialog::getSqlDatabaseFileFilter()); + if(!fileName.isEmpty()) + { + if(QFile::exists(fileName)) + QFile::remove(fileName); + db.create(fileName); + setCurrentFile(fileName); + addToRecentFilesMenu(fileName); + statusEncodingLabel->setText(db.getPragma("encoding")); + statusEncryptionLabel->setVisible(false); + statusReadOnlyLabel->setVisible(false); + populateTable(); + if(ui->tabSqlAreas->count() == 0) + openSqlTab(true); + createTable(); + } +} + +void MainWindow::fileNewInMemoryDatabase() +{ + db.create(":memory:"); + setCurrentFile(tr("In-Memory database")); + statusEncodingLabel->setText(db.getPragma("encoding")); + statusEncryptionLabel->setVisible(false); + statusReadOnlyLabel->setVisible(false); + ////remoteDock->fileOpened(":memory:"); + populateTable(); + if(ui->tabSqlAreas->count() == 0) + openSqlTab(true); + createTable(); +} + +void MainWindow::populateStructure(const sqlb::ObjectIdentifier& old_table) +{ + // Refresh the structure tab + ui->dbTreeWidget->setRootIndex(dbStructureModel->index(1, 0)); // Show the 'All' part of the db structure + ui->dbTreeWidget->expandToDepth(0); + ui->treeSchemaDock->setRootIndex(dbStructureModel->index(1, 0)); // Show the 'All' part of the db structure + ui->treeSchemaDock->expandToDepth(0); + + // Refresh the browse data tab + ui->tableBrowser->setStructure(dbStructureModel, old_table); + + // Cancel here if no database is opened + if(!db.isOpen()) + return; + + // Update table and column names for syntax highlighting + SqlUiLexer::QualifiedTablesMap qualifiedTablesMap; + for(const auto& it : db.schemata) + { + SqlUiLexer::TablesAndColumnsMap tablesToColumnsMap; + + for(const auto& jt : it.second) + { + if(jt.second->type() == sqlb::Object::Types::Table || jt.second->type() == sqlb::Object::Types::View) + { + QString objectname = QString::fromStdString(jt.second->name()); + + sqlb::FieldInfoList fi = jt.second->fieldInformation(); + for(const sqlb::FieldInfo& f : fi) + tablesToColumnsMap[objectname].push_back(QString::fromStdString(f.name)); + } + } + + qualifiedTablesMap[QString::fromStdString(it.first)] = tablesToColumnsMap; + } + SqlTextEdit::sqlLexer->setTableNames(qualifiedTablesMap); + ui->editLogApplication->reloadKeywords(); + ui->editLogUser->reloadKeywords(); + for(int i=0;itabSqlAreas->count();i++) + qobject_cast(ui->tabSqlAreas->widget(i))->getEditor()->reloadKeywords(); + + // Resize SQL column to fit contents + ui->dbTreeWidget->resizeColumnToContents(DbStructureModel::ColumnSQL); + ui->treeSchemaDock->resizeColumnToContents(DbStructureModel::ColumnSQL); + // Resize also the Name column in the Dock since it has usually + // short content and there is little space there. + ui->treeSchemaDock->resizeColumnToContents(DbStructureModel::ColumnName); + + +} + +void MainWindow::populateTable() +{ + // Early exit if the Browse Data tab isn't visible as there is no need to update it in this case + if(ui->mainTab->currentWidget() != ui->browser) + return; + + QApplication::setOverrideCursor(Qt::WaitCursor); + ui->tableBrowser->updateTable(); + QApplication::restoreOverrideCursor(); +} + +bool MainWindow::fileClose() +{ + // Stop any running SQL statements before closing the database + if(execute_sql_worker && execute_sql_worker->isRunning()) + { + if(QMessageBox::warning(this, qApp->applicationName(), + tr("You are still executing SQL statements. Closing the database now will stop their execution, possibly " + "leaving the database in an inconsistent state. Are you sure you want to close the database?"), + QMessageBox::Yes, QMessageBox::Cancel | QMessageBox::Default | QMessageBox::Escape) == QMessageBox::Cancel) + return false; + + execute_sql_worker->stop(); + execute_sql_worker->wait(); + } + + // Close the database but stop the closing process here if the user pressed the cancel button in there + if(!db.close()) + return false; + + setCurrentFile(QString()); + loadPragmas(); + statusEncryptionLabel->setVisible(false); + statusReadOnlyLabel->setVisible(false); + + // Reset the table browser of the Browse Data tab + ui->tableBrowser->reset(); + + // Clear edit dock + editDock->setCurrentIndex(QModelIndex()); + + // Clear the SQL Log + ui->editLogApplication->clear(); + ui->editLogUser->clear(); + ui->editLogErrorLog->clear(); + + // Remove completion and highlighting for identifiers + SqlTextEdit::sqlLexer->setTableNames(SqlUiLexer::QualifiedTablesMap()); + for(int i=0; i < ui->tabSqlAreas->count(); i++) + qobject_cast(ui->tabSqlAreas->widget(i))->getEditor()->reloadKeywords(); + + // Clear remote dock + //remoteDock->fileOpened(QString()); + + return true; +} + +void MainWindow::closeEvent( QCloseEvent* event ) +{ + if(closeFiles()) + { + Settings::setValue("MainWindow", "geometry", saveGeometry()); + Settings::setValue("MainWindow", "windowState", saveState()); + Settings::setValue("MainWindow", "openTabs", saveOpenTabs()); + + Settings::setValue("SQLLogDock", "Log", ui->comboLogSubmittedBy->currentText()); + Settings::setValue("SchemaDock", "dropQualifiedNames", ui->actionDropQualifiedCheck->isChecked()); + Settings::setValue("SchemaDock", "dropEnquotedNames", ui->actionEnquoteNamesCheck->isChecked()); + + SqlExecutionArea::saveState(); + + QMainWindow::closeEvent(event); + } else { + event->ignore(); + } +} + +bool MainWindow::closeFiles() +{ + bool ignoreUnattachedBuffers = false; + // Ask for saving all modified open SQL files in their files and all the unattached tabs in a project file. + for(int i=0; itabSqlAreas->count(); i++) + // Ask for saving and comply with cancel answer. + if(!askSaveSqlTab(i, ignoreUnattachedBuffers)) + return false; + return closeProject(); +} + +bool MainWindow::closeProject() +{ + if(!currentProjectFilename.isEmpty() && isProjectModified) { + QMessageBox::StandardButton reply = QMessageBox::question + (nullptr, + QApplication::applicationName(), + tr("Do you want to save the changes made to the project file '%1'?"). + arg(QFileInfo(currentProjectFilename).fileName()), + QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel); + switch(reply) { + case QMessageBox::Save: + saveProject(); + break; + case QMessageBox::Cancel: + return false; + default: + break; + } + } + currentProjectFilename.clear(); + return db.close(); +} + +void MainWindow::attachPlot(ExtendedTableWidget* tableWidget, SqliteTableModel* model, BrowseDataTableSettings* settings, bool keepOrResetSelection) +{ + plotDock->updatePlot(model, settings, true, keepOrResetSelection); + // Disconnect previous connection + disconnect(plotDock, SIGNAL(pointsSelected(int,int)), nullptr, nullptr); + if(tableWidget) { + // Connect plot selection to the current table results widget. + connect(plotDock, SIGNAL(pointsSelected(int,int)), tableWidget, SLOT(selectTableLines(int, int))); + connect(tableWidget, &ExtendedTableWidget::destroyed, plotDock, &PlotDock::resetPlot); + // Disconnect requestUrlOrFileOpen in order to make sure that there is only one connection. Otherwise we can open it several times. + disconnect(tableWidget, &ExtendedTableWidget::requestUrlOrFileOpen, this, &MainWindow::openUrlOrFile); + connect(tableWidget, &ExtendedTableWidget::requestUrlOrFileOpen, this, &MainWindow::openUrlOrFile); + } +} + +void MainWindow::refresh() +{ + // What the Refresh function does depends on the currently active tab. This way the keyboard shortcuts (F5 and Ctrl+R) + // always perform some meaningful task; they just happen to be context dependent in the function they trigger. + QWidget* currentTab = ui->mainTab->currentWidget(); + if (currentTab == ui->structure) { + // Refresh the schema + db.updateSchema(); + } else if (currentTab == ui->browser) { + // Refresh the schema and reload the current table + populateTable(); + } else if (currentTab == ui->pragmas) { + // Reload pragma values + loadPragmas(); + } else if (currentTab == ui->query) { + // (Re-)Run the current SQL query + executeQuery(); + } +} + +void MainWindow::createTable() +{ + EditTableDialog dialog(db, sqlb::ObjectIdentifier(), true, this); + if(dialog.exec()) + { + populateTable(); + } +} + +void MainWindow::createIndex() +{ + EditIndexDialog dialog(db, sqlb::ObjectIdentifier(), true, this); + if(dialog.exec()) + populateTable(); +} + +void MainWindow::compact() +{ + VacuumDialog dialog(&db, this); + dialog.exec(); +} + +void MainWindow::deleteObject() +{ + // Get name and type of object to delete + sqlb::ObjectIdentifier name(ui->dbTreeWidget->model()->data(ui->dbTreeWidget->currentIndex().sibling(ui->dbTreeWidget->currentIndex().row(), DbStructureModel::ColumnSchema), Qt::EditRole).toString().toStdString(), + ui->dbTreeWidget->model()->data(ui->dbTreeWidget->currentIndex().sibling(ui->dbTreeWidget->currentIndex().row(), DbStructureModel::ColumnName), Qt::EditRole).toString().toStdString()); + QString type = ui->dbTreeWidget->model()->data(ui->dbTreeWidget->currentIndex().sibling(ui->dbTreeWidget->currentIndex().row(), DbStructureModel::ColumnObjectType), Qt::EditRole).toString(); + + // Due to different grammar in languages (e.g. gender or declension), each message must be given separately to translation. + QString message; + if (type == "table") + message = tr("Are you sure you want to delete the table '%1'?\nAll data associated with the table will be lost."); + else if (type == "view") + message = tr("Are you sure you want to delete the view '%1'?"); + else if (type == "trigger") + message = tr("Are you sure you want to delete the trigger '%1'?"); + else if (type == "index") + message = tr("Are you sure you want to delete the index '%1'?"); + + // Ask user if he really wants to delete that table + if(QMessageBox::warning(this, QApplication::applicationName(), message.arg(QString::fromStdString(name.name())), + QMessageBox::Yes | QMessageBox::No, QMessageBox::No) == QMessageBox::Yes) + { + // Delete the table + QString statement = QString("DROP %1 %2;").arg(type.toUpper(), QString::fromStdString(name.toString())); + if(!db.executeSQL(statement.toStdString())) + { + if (type == "table") + message = tr("Error: could not delete the table."); + else if (type == "view") + message = tr("Error: could not delete the view."); + else if (type == "trigger") + message = tr("Error: could not delete the trigger."); + else if (type == "index") + message = tr("Error: could not delete the index."); + + QString error = tr("Message from database engine:\n%1").arg(db.lastError()); + QMessageBox::warning(this, QApplication::applicationName(), message + " " + error); + } else { + populateTable(); + changeTreeSelection(); + } + } +} + +void MainWindow::editObject() +{ + if(!ui->dbTreeWidget->selectionModel()->hasSelection()) + return; + + // Get name and type of the object to edit + sqlb::ObjectIdentifier name(ui->dbTreeWidget->model()->data(ui->dbTreeWidget->currentIndex().sibling(ui->dbTreeWidget->currentIndex().row(), DbStructureModel::ColumnSchema), Qt::EditRole).toString().toStdString(), + ui->dbTreeWidget->model()->data(ui->dbTreeWidget->currentIndex().sibling(ui->dbTreeWidget->currentIndex().row(), DbStructureModel::ColumnName), Qt::EditRole).toString().toStdString()); + QString type = ui->dbTreeWidget->model()->data(ui->dbTreeWidget->currentIndex().sibling(ui->dbTreeWidget->currentIndex().row(), DbStructureModel::ColumnObjectType), Qt::EditRole).toString(); + + if(type == "table") + { + // For a safe and possibly complex table modification we must follow the steps documented in + // https://www.sqlite.org/lang_altertable.html + // Paragraph (first procedure): Making Other Kinds Of Table Schema Changes + + QString foreign_keys = db.getPragma("foreign_keys"); + if (foreign_keys == "1") { + if(db.getDirty() && QMessageBox::question(this, + QApplication::applicationName(), + tr("Editing the table requires to save all pending changes now.\nAre you sure you want to save the database?"), + QMessageBox::Save | QMessageBox::Default, + QMessageBox::Cancel | QMessageBox::Escape) != QMessageBox::Save) + return; + // Commit all changes so the foreign_keys can be effective. + fileSave(); + db.setPragma("foreign_keys", "0"); + } + + EditTableDialog dialog(db, name, false, this); + bool ok = dialog.exec(); + + // If foreign_keys were enabled, we must commit or rollback the transaction so the foreign_keys pragma can be restored. + if (foreign_keys == "1") { + if (!db.querySingleValueFromDb("PRAGMA " + sqlb::escapeIdentifier(name.schema()) + ".foreign_key_check").isNull()) { + // Raise warning for accepted modification. When rejected, warn user also since we know now that the table has problems, + // but it wasn't our fault. + if (ok) + QMessageBox::warning(this, QApplication::applicationName(), + tr("Error checking foreign keys after table modification. The changes will be reverted.")); + else + QMessageBox::warning(this, QApplication::applicationName(), + tr("This table did not pass a foreign-key check.
" + "You should run 'Tools | Foreign-Key Check' and fix the reported issues.")); + db.revertAll(); + } else { + // Commit all changes so the foreign_keys can be effective. + fileSave(); + } + db.setPragma("foreign_keys", foreign_keys); + } + if(ok) { + ui->tableBrowser->clearFilters(); + populateTable(); + } + } else if(type == "index") { + EditIndexDialog dialog(db, name, false, this); + if(dialog.exec()) + populateTable(); + } else if(type == "view") { + sqlb::ViewPtr view = db.getObjectByName(name); + runSqlNewTab(QString("DROP VIEW %1;\n%2").arg(QString::fromStdString(name.toString())).arg(QString::fromStdString(view->sql())), + tr("Edit View %1").arg(QString::fromStdString(name.toDisplayString())), + "https://www.sqlite.org/lang_createview.html", + /* autoRun */ false); + } else if(type == "trigger") { + sqlb::TriggerPtr trigger = db.getObjectByName(name); + runSqlNewTab(QString("DROP TRIGGER %1;\n%2").arg(QString::fromStdString(name.toString())).arg(QString::fromStdString(trigger->sql())), + tr("Edit Trigger %1").arg(QString::fromStdString(name.toDisplayString())), + "https://www.sqlite.org/lang_createtrigger.html", + /* autoRun */ false); + } +} + +void MainWindow::helpWhatsThis() +{ + QWhatsThis::enterWhatsThisMode (); +} + +void MainWindow::helpAbout() +{ + AboutDialog dialog(this); + dialog.exec(); +} + +void MainWindow::updateRecordText(const QPersistentModelIndex& idx, const QByteArray& text, bool isBlob) +{ + m_currentTabTableModel->setTypedData(idx, isBlob, text); +} + +void MainWindow::toggleEditDock(bool visible) +{ + if (!visible) { + // Update main window + ui->tableBrowser->setFocus(); + } else { + // fill edit dock with actual data, when the current index has changed while the dock was invisible. + // (note that this signal is also emitted when the widget is docked or undocked, so we have to avoid + // reloading data when the user is editing and (un)docks the editor). + if (editDock->currentIndex() != ui->tableBrowser->currentIndex()) + editDock->setCurrentIndex(ui->tableBrowser->currentIndex()); + } +} + +void MainWindow::doubleClickTable(const QModelIndex& index) +{ + // Cancel on invalid index + if (!index.isValid()) { + return; + } + + // * Don't allow editing of other objects than tables and editable views + bool isEditingAllowed = !db.readOnly() && m_currentTabTableModel == ui->tableBrowser->model() && + ui->tableBrowser->model()->isEditable(index); + + // Enable or disable the Apply, Null, & Import buttons in the Edit Cell + // dock depending on the value of the "isEditingAllowed" bool above + editDock->setReadOnly(!isEditingAllowed); + + editDock->setCurrentIndex(index); + + // Show the edit dock + ui->dockEdit->setVisible(true); + + // Set focus on the edit dock + editDock->setFocus(); +} + +void MainWindow::dataTableSelectionChanged(const QModelIndex& index) +{ + // Cancel on invalid index + if(!index.isValid()) { + editDock->setCurrentIndex(QModelIndex()); + return; + } + + bool editingAllowed = !db.readOnly() && (m_currentTabTableModel == ui->tableBrowser->model()) && + ui->tableBrowser->model()->isEditable(index); + + // Don't allow editing of other objects than tables and editable views + editDock->setReadOnly(!editingAllowed); + + // If the Edit Cell dock is visible, load the new value into it + if (editDock->isVisible()) { + editDock->setCurrentIndex(index); + } +} + +/* + * I'm still not happy how the results are represented to the user + * right now you only see the result of the last executed statement. + * A better experience would be tabs on the bottom with query results + * for all the executed statements. + */ +void MainWindow::executeQuery() +{ + // Make sure a database is opened. This is necessary because we allow opened SQL editor tabs even if no database is loaded. Hitting F5 or similar + // then might call this function. + if(!db.isOpen()) + return; + + // Check if other task is still running and stop it if necessary + if(execute_sql_worker && execute_sql_worker->isRunning()) + { + // Ask the user and do nothing if he/she doesn't want to interrupt the running query + if(QMessageBox::warning(this, qApp->applicationName(), + tr("You are already executing SQL statements. Do you want to stop them in order to execute the current " + "statements instead? Note that this might leave the database in an inconsistent state."), + QMessageBox::Yes, QMessageBox::Cancel | QMessageBox::Default | QMessageBox::Escape) == QMessageBox::Cancel) + return; + + // Stop the running query + execute_sql_worker->stop(); + execute_sql_worker->wait(); + } + + // Get current SQL tab and editor + SqlExecutionArea* sqlWidget = qobject_cast(ui->tabSqlAreas->currentWidget()); + SqlTextEdit* editor = sqlWidget->getEditor(); + auto* current_tab = ui->tabSqlAreas->currentWidget(); + const QString tabName = ui->tabSqlAreas->tabText(ui->tabSqlAreas->currentIndex()).remove('&'); + + // Remove any error indicators + editor->clearErrorIndicators(); + + // Determine execution mode: execute all, execute selection or execute current line + enum executionMode + { + All, + Selection, + Line + } mode; + if(sender() && sender()->objectName() == "actionSqlExecuteLine") + mode = Line; + else if(!sqlWidget->getSelectedSql().isEmpty()) + mode = Selection; + else + mode = All; + + // Get SQL code to execute. This depends on the execution mode. + int execute_from_position = 0; // Where we want to start the execution in the query string + int execute_to_position = 0; // Where we roughly want to end the execution in the query string + + switch(mode) + { + case Selection: + { + // Start and end positions are start and end positions from the selection + int execute_from_line, execute_from_index, execute_to_line, execute_to_index; + editor->getSelection(&execute_from_line, &execute_from_index, &execute_to_line, &execute_to_index); + execute_from_position = editor->positionFromLineIndex(execute_from_line, execute_from_index); + execute_to_position = editor->positionFromLineIndex(execute_to_line, execute_to_index); + + db.logSQL(tr("-- EXECUTING SELECTION IN '%1'\n--").arg(tabName), kLogMsg_User); + } break; + case Line: + { + // Start position is the first character of the current line, except for those cases where we're in the middle of a + // statement which started on one the previous line. In that case the start position is actually a bit earlier. For + // the end position we set the last character of the current line. If the statement(s) continue(s) into the next line, + // SQLite will execute it/them anyway and we'll stop afterwards. + int execute_from_line, dummy; + editor->getCursorPosition(&execute_from_line, &dummy); + execute_from_position = editor->positionFromLineIndex(execute_from_line, 0); + + // Need to set the end position here before adjusting the start line + int execute_to_line = execute_from_line; + int execute_to_index = editor->text(execute_to_line).remove('\n').remove('\r').length(); // This chops the line break at the end of the line + execute_to_position = editor->positionFromLineIndex(execute_to_line, execute_to_index); + + QByteArray firstPartEntireSQL = sqlWidget->getSql().toUtf8().left(execute_from_position); + if(firstPartEntireSQL.lastIndexOf(';') != -1) + execute_from_position -= firstPartEntireSQL.length() - firstPartEntireSQL.lastIndexOf(';') - 1; + + db.logSQL(tr("-- EXECUTING LINE IN '%1'\n--").arg(tabName), kLogMsg_User); + } break; + case All: + { + // Start position is the first byte, end position the last. + // Note that we use byte positions that might differ from character positions. + execute_to_position = editor->length(); + + db.logSQL(tr("-- EXECUTING ALL IN '%1'\n--").arg(tabName), kLogMsg_User); + } break; + } + + // Prepare a lambda function for logging the results of a query + auto query_logger = [this, sqlWidget, editor](bool ok, const QString& status_message, int from_position, int to_position) { + int execute_from_line, execute_from_index; + editor->lineIndexFromPosition(from_position, &execute_from_line, &execute_from_index); + + // Special case: if the start position is at the end of a line, then move to the beginning of next line. + // Otherwise for the typical case, the line reference is one less than expected. + // Note that execute_from_index uses character positions and not byte positions, so at() can be used. + QChar char_at_index = editor->text(execute_from_line).at(execute_from_index); + if (char_at_index == '\r' || char_at_index == '\n') { + execute_from_line++; + // The next lines could be empty, so skip all of them too. + while(editor->text(execute_from_line).trimmed().isEmpty()) + execute_from_line++; + execute_from_index = 0; + } + + // If there was an error highlight the erroneous SQL statement + if(!ok) + { + int end_of_current_statement_line, end_of_current_statement_index; + editor->lineIndexFromPosition(to_position, &end_of_current_statement_line, &end_of_current_statement_index); + editor->setErrorIndicator(execute_from_line, execute_from_index, end_of_current_statement_line, end_of_current_statement_index); + + editor->setCursorPosition(execute_from_line, execute_from_index); + } + + // Log the query and the result message. + // The query takes the last placeholder as it may itself contain the sequence '%' + number. + QString query = editor->text(from_position, to_position); + QString log_message = "-- " + tr("At line %1:").arg(execute_from_line+1) + "\n" + query.trimmed() + "\n-- " + tr("Result: %1").arg(status_message); + db.logSQL(log_message, kLogMsg_User); + + log_message = tr("Result: %2").arg(status_message) + "\n" + tr("At line %1:").arg(execute_from_line+1) + "\n" + query.trimmed(); + // Update the execution area + sqlWidget->finishExecution(log_message, ok); + }; + + // Get the statement(s) to execute. When in selection mode crop the query string at exactly the end of the selection to make sure SQLite has + // no chance to execute any further. + QString sql = sqlWidget->getSql(); + if(mode == Selection) + sql = sql.toUtf8().left(execute_to_position); // We have to convert to a QByteArray here because QScintilla gives us the position in bytes, not in characters. + + // Prepare the SQL worker to run the query. We set the context of each signal-slot connection to the current SQL execution area. + // This means that if the tab is closed all these signals are automatically disconnected so the lambdas won't be called for a not + // existing execution area. + execute_sql_worker.reset(new RunSql(db, sql, execute_from_position, execute_to_position, true)); + + connect(execute_sql_worker.get(), &RunSql::structureUpdated, sqlWidget, [this]() { + db.updateSchema(); + }, Qt::QueuedConnection); + connect(execute_sql_worker.get(), &RunSql::statementErrored, sqlWidget, [query_logger, this, sqlWidget](const QString& status_message, int from_position, int to_position) { + sqlWidget->getModel()->reset(); + ui->actionSqlResultsSave->setEnabled(false); + ui->actionSqlResultsSaveAsView->setEnabled(false); + attachPlot(sqlWidget->getTableResult(), sqlWidget->getModel()); + + query_logger(false, status_message, from_position, to_position); + }, Qt::QueuedConnection); + connect(execute_sql_worker.get(), &RunSql::statementExecuted, sqlWidget, [query_logger, this, sqlWidget](const QString& status_message, int from_position, int to_position) { + sqlWidget->getModel()->reset(); + ui->actionSqlResultsSave->setEnabled(false); + ui->actionSqlResultsSaveAsView->setEnabled(false); + attachPlot(sqlWidget->getTableResult(), sqlWidget->getModel()); + + query_logger(true, status_message, from_position, to_position); + execute_sql_worker->startNextStatement(); + }, Qt::QueuedConnection); + connect(execute_sql_worker.get(), &RunSql::statementReturnsRows, sqlWidget, [query_logger, this, sqlWidget](const QString& query, int from_position, int to_position, qint64 time_in_ms_so_far) { + auto time_start = std::chrono::high_resolution_clock::now(); + + ui->actionSqlResultsSave->setEnabled(true); + ui->actionSqlResultsSaveAsView->setEnabled(!db.readOnly()); + + auto * model = sqlWidget->getModel(); + model->setQuery(query); + + // Wait until the initial loading of data (= first chunk and row count) has been performed + auto conn = std::make_shared(); + *conn = connect(model, &SqliteTableModel::finishedFetch, [=](int fetched_row_begin, int fetched_row_end) { + // Avoid attaching the plot when the signal is notifying the row count, since the + // data wouldn't be available yet. + if(fetched_row_begin != fetched_row_end && fetched_row_begin != model->rowCount()) { + // Disconnect this connection right now. This avoids calling this slot multiple times + disconnect(*conn); + + attachPlot(sqlWidget->getTableResult(), sqlWidget->getModel()); + } else { + connect(sqlWidget->getTableResult()->selectionModel(), &QItemSelectionModel::currentChanged, this, &MainWindow::dataTableSelectionChanged); + connect(sqlWidget->getTableResult(), &QTableView::doubleClicked, this, &MainWindow::doubleClickTable); + + auto time_end = std::chrono::high_resolution_clock::now(); + auto time_in_ms = std::chrono::duration_cast(time_end-time_start); + query_logger(true, tr("%1 rows returned in %2ms").arg(model->rowCount()).arg(time_in_ms.count()+time_in_ms_so_far), from_position, to_position); + execute_sql_worker->startNextStatement(); + } + }); + }, Qt::QueuedConnection); + connect(execute_sql_worker.get(), &RunSql::confirmSaveBeforePragmaOrVacuum, sqlWidget, [this]() { + if(QMessageBox::question(nullptr, QApplication::applicationName(), + tr("Setting PRAGMA values or vacuuming will commit your current transaction.\nAre you sure?"), + QMessageBox::Yes | QMessageBox::Default, + QMessageBox::No | QMessageBox::Escape) == QMessageBox::No) + execute_sql_worker->stop(); + + }, Qt::BlockingQueuedConnection); + connect(execute_sql_worker.get(), &RunSql::finished, sqlWidget, [this, current_tab, sqlWidget]() { + // We work with a pointer to the current tab here instead of its index because the user might reorder the tabs in the meantime. + // We set different icons for general tabs, which are either new or loaded from the project file, and for tabs loaded from a file. + if(sqlWidget->fileName().isEmpty()) + ui->tabSqlAreas->setTabIcon(ui->tabSqlAreas->indexOf(current_tab), QIcon(":/icons/open_sql")); + else + ui->tabSqlAreas->setTabIcon(ui->tabSqlAreas->indexOf(current_tab), QIcon(":/icons/document_open")); + + // Set no-running-query state + ui->tabSqlAreas->tabBar()->setTabData(ui->tabSqlAreas->indexOf(current_tab), QVariant(false)); + + // We don't need to check for the current SQL tab here because two concurrently running queries are not allowed + ui->actionSqlExecuteLine->setEnabled(true); + ui->actionExecuteSql->setEnabled(true); + ui->actionSqlStop->setEnabled(false); + sqlWidget->getEditor()->setReadOnly(false); + + // Show Done message + if(sqlWidget->inErrorState()) + sqlWidget->getStatusEdit()->setPlainText(tr("Execution finished with errors.") + "\n" + sqlWidget->getStatusEdit()->toPlainText()); + else + sqlWidget->getStatusEdit()->setPlainText(tr("Execution finished without errors.") + "\n" + sqlWidget->getStatusEdit()->toPlainText()); + }); + + // Add an hourglass icon to the current tab to indicate that there's a running execution in there. + ui->tabSqlAreas->setTabIcon(ui->tabSqlAreas->currentIndex(), QIcon(":icons/hourglass")); + // We use the tab data to check whether a specific SQL tab is currently running a query or not. + ui->tabSqlAreas->tabBar()->setTabData(ui->tabSqlAreas->currentIndex(), QVariant(true)); + + // Deactivate the buttons to start a query and activate the button to stop the query + ui->actionSqlExecuteLine->setEnabled(false); + ui->actionExecuteSql->setEnabled(false); + ui->actionSqlStop->setEnabled(true); + + // Make the SQL editor widget read-only. We do this because the error indicators would be misplaced if the user changed the SQL text during execution + sqlWidget->getEditor()->setReadOnly(true); + + // Start the execution + execute_sql_worker->start(); +} + +void MainWindow::mainTabSelected(int /*tabindex*/) +{ + editDock->setReadOnly(true); + + if(ui->mainTab->currentWidget() == ui->browser) + { + m_currentTabTableModel = ui->tableBrowser->model(); + populateTable(); + } else if(ui->mainTab->currentWidget() == ui->pragmas) { + loadPragmas(); + } else if(ui->mainTab->currentWidget() == ui->query) { + SqlExecutionArea* sqlWidget = qobject_cast(ui->tabSqlAreas->currentWidget()); + + if (sqlWidget) { + m_currentTabTableModel = sqlWidget->getModel(); + + dataTableSelectionChanged(sqlWidget->getTableResult()->currentIndex()); + } + } +} + +void MainWindow::importTableFromCSV() +{ + QStringList file_filter; + file_filter << FILE_FILTER_CSV + << FILE_FILTER_TSV + << FILE_FILTER_DSV + << FILE_FILTER_TXT + << FILE_FILTER_DAT + << FILE_FILTER_ALL; + + QStringList wFiles = FileDialog::getOpenFileNames( + OpenCSVFile, + this, + tr("Choose text files"), + file_filter.join(";;")); + + std::vector validFiles; + for(const auto& file : wFiles) { + if (QFile::exists(file)) + validFiles.push_back(file); + } + + if (!validFiles.empty()) + { + ImportCsvDialog dialog(validFiles, &db, this); + if (dialog.exec()) + populateTable(); + } +} + +void MainWindow::exportTableToCSV() +{ + // Get the current table name if we are in the Browse Data tab + sqlb::ObjectIdentifier current_table; + if(ui->mainTab->currentWidget() == ui->structure) + { + QString type = ui->dbTreeWidget->model()->data(ui->dbTreeWidget->currentIndex().sibling(ui->dbTreeWidget->currentIndex().row(), DbStructureModel::ColumnObjectType)).toString(); + if(type == "table" || type == "view") + { + QString schema = ui->dbTreeWidget->model()->data(ui->dbTreeWidget->currentIndex().sibling(ui->dbTreeWidget->currentIndex().row(), DbStructureModel::ColumnSchema)).toString(); + QString name = ui->dbTreeWidget->model()->data(ui->dbTreeWidget->currentIndex().sibling(ui->dbTreeWidget->currentIndex().row(), DbStructureModel::ColumnName)).toString(); + current_table = sqlb::ObjectIdentifier(schema.toStdString(), name.toStdString()); + } + } else if(ui->mainTab->currentWidget() == ui->browser) { + current_table = ui->tableBrowser->currentlyBrowsedTableName(); + } + + // Open dialog + ExportDataDialog dialog(db, ExportDataDialog::ExportFormatCsv, this, "", current_table); + dialog.exec(); +} + +void MainWindow::exportTableToJson() +{ + // Get the current table name if we are in the Browse Data tab + sqlb::ObjectIdentifier current_table; + if(ui->mainTab->currentWidget() == ui->structure) + { + QString type = ui->dbTreeWidget->model()->data(ui->dbTreeWidget->currentIndex().sibling(ui->dbTreeWidget->currentIndex().row(), DbStructureModel::ColumnObjectType)).toString(); + if(type == "table" || type == "view") + { + QString schema = ui->dbTreeWidget->model()->data(ui->dbTreeWidget->currentIndex().sibling(ui->dbTreeWidget->currentIndex().row(), DbStructureModel::ColumnSchema)).toString(); + QString name = ui->dbTreeWidget->model()->data(ui->dbTreeWidget->currentIndex().sibling(ui->dbTreeWidget->currentIndex().row(), DbStructureModel::ColumnName)).toString(); + current_table = sqlb::ObjectIdentifier(schema.toStdString(), name.toStdString()); + } + } else if(ui->mainTab->currentWidget() == ui->browser) { + current_table = ui->tableBrowser->currentlyBrowsedTableName(); + } + + // Open dialog + ExportDataDialog dialog(db, ExportDataDialog::ExportFormatJson, this, "", current_table); + dialog.exec(); +} + +void MainWindow::dbState(bool dirty) +{ + ui->fileSaveAction->setEnabled(dirty); + ui->fileRevertAction->setEnabled(dirty); + ui->fileAttachAction->setEnabled(db.isOpen() && !dirty); +} + +void MainWindow::fileSave() +{ + if(db.isOpen()) + { + if(!db.releaseAllSavepoints()) + { + QMessageBox::warning(this, QApplication::applicationName(), tr("Error while saving the database file. This means that not all changes to the database were " + "saved. You need to resolve the following error first.\n\n%1").arg(db.lastError())); + } + } +} + +void MainWindow::fileRevert() +{ + if (db.isOpen()){ + QString msg = tr("Are you sure you want to undo all changes made to the database file '%1' since the last save?").arg(db.currentFile()); + if(QMessageBox::question(this, QApplication::applicationName(), msg, QMessageBox::Yes | QMessageBox::Default, QMessageBox::No | QMessageBox::Escape) == QMessageBox::Yes) + { + db.revertAll(); + populateTable(); + } + } +} + +void MainWindow::exportDatabaseToSQL() +{ + QString current_table; + if(ui->mainTab->currentWidget() == ui->browser) + current_table = QString::fromStdString(ui->tableBrowser->currentlyBrowsedTableName().name()); + + ExportSqlDialog dialog(&db, this, current_table); + dialog.exec(); +} + +void MainWindow::importDatabaseFromSQL() +{ + QStringList file_filter; + file_filter << FILE_FILTER_SQL + << FILE_FILTER_TXT + << FILE_FILTER_ALL; + + // Get file name to import + QString fileName = FileDialog::getOpenFileName( + OpenSQLFile, + this, + tr("Choose a file to import"), + file_filter.join(";;")); + + // Cancel when file doesn't exist + if(!QFile::exists(fileName)) + return; + + // If there is already a database file opened ask the user whether to import into + // this one or a new one. If no DB is opened just ask for a DB name directly + QString newDbFile; + if((db.isOpen() && QMessageBox::question(this, + QApplication::applicationName(), + tr("Do you want to create a new database file to hold the imported data?\n" + "If you answer no we will attempt to import the data in the SQL file to the current database."), + QMessageBox::Yes, QMessageBox::No) == QMessageBox::Yes) || !db.isOpen()) + { + newDbFile = FileDialog::getSaveFileName( + CreateDatabaseFile, + this, + tr("Choose a filename to save under"), + FileDialog::getSqlDatabaseFileFilter()); + if(QFile::exists(newDbFile)) + { + QMessageBox::information(this, QApplication::applicationName(), tr("File %1 already exists. Please choose a different name.").arg(newDbFile)); + return; + } else if(newDbFile.size() == 0) { + return; + } + + // Create the new file and open it in the browser + db.create(newDbFile); + db.close(); + fileOpen(newDbFile); + } + + // Defer foreign keys. Just deferring them instead of disabling them should work fine because in the import we only expect CREATE and INSERT + // statements which unlike in the Edit Table dialog shouldn't trigger any problems. + QString foreignKeysOldSettings = db.getPragma("defer_foreign_keys"); + db.setPragma("defer_foreign_keys", "1"); + + // Open, read, execute and close file + QApplication::setOverrideCursor(Qt::WaitCursor); + QFile f(fileName); + f.open(QIODevice::ReadOnly); + QByteArray data = f.readAll(); + removeBom(data); + bool ok = db.executeMultiSQL(data, newDbFile.size() == 0); + // Restore cursor before asking the user to accept the message + QApplication::restoreOverrideCursor(); + if(!ok) + QMessageBox::warning(this, QApplication::applicationName(), tr("Error importing data: %1").arg(db.lastError())); + else if(db.getPragma("foreign_keys") == "1" && !db.querySingleValueFromDb("PRAGMA foreign_key_check").isNull()) + QMessageBox::warning(this, QApplication::applicationName(), tr("Import completed. Some foreign key constraints are violated. Please fix them before saving.")); + else + QMessageBox::information(this, QApplication::applicationName(), tr("Import completed.")); + f.close(); + + // Restore the former foreign key settings + db.setPragma("defer_foreign_keys", foreignKeysOldSettings); + + // Refresh views + db.updateSchema(); + populateTable(); +} + +void MainWindow::openPreferences() +{ + PreferencesDialog dialog(this); + if(dialog.exec()) + reloadSettings(); +} + +//** Db Tree Context Menu +void MainWindow::createTreeContextMenu(const QPoint &qPoint) +{ + if(!ui->dbTreeWidget->selectionModel()->hasSelection()) + return; + + QString type = ui->dbTreeWidget->model()->data(ui->dbTreeWidget->currentIndex().sibling(ui->dbTreeWidget->currentIndex().row(), 1)).toString(); + + if(type == "table" || type == "view" || type == "trigger" || type == "index") + popupTableMenu->exec(ui->dbTreeWidget->mapToGlobal(qPoint)); +} + +//** DB Schema Dock Context Menu +void MainWindow::createSchemaDockContextMenu(const QPoint &qPoint) +{ + bool enable_browse_table = false; + if(ui->treeSchemaDock->selectionModel()->hasSelection()) + { + QString type = ui->treeSchemaDock->model()->data(ui->treeSchemaDock->currentIndex().sibling(ui->treeSchemaDock->currentIndex().row(), DbStructureModel::ColumnObjectType), Qt::EditRole).toString(); + if(type == "table" || type == "view") + enable_browse_table = true; + } + ui->actionPopupSchemaDockBrowseTable->setEnabled(enable_browse_table); + + popupSchemaDockMenu->exec(ui->treeSchemaDock->mapToGlobal(qPoint)); +} + +void MainWindow::changeTreeSelection() +{ + // Just assume first that something's selected that can not be edited at all + ui->editDeleteObjectAction->setEnabled(false); + ui->editModifyObjectAction->setEnabled(false); + ui->actionEditBrowseTable->setEnabled(false); + + if(!ui->dbTreeWidget->currentIndex().isValid()) + return; + + // Change the text and tooltips of the actions + QString type = ui->dbTreeWidget->model()->data(ui->dbTreeWidget->currentIndex().sibling(ui->dbTreeWidget->currentIndex().row(), 1)).toString(); + + if (type.isEmpty()) + { + ui->editDeleteObjectAction->setIcon(QIcon(":icons/table_delete")); + ui->editModifyObjectAction->setIcon(QIcon(":icons/table_modify")); + } else { + ui->editDeleteObjectAction->setIcon(QIcon(QString(":icons/%1_delete").arg(type))); + ui->editModifyObjectAction->setIcon(QIcon(QString(":icons/%1_modify").arg(type))); + } + + if (type == "view") { + ui->editDeleteObjectAction->setText(tr("Delete View")); + ui->editModifyObjectAction->setText(tr("Modify View")); + } else if(type == "trigger") { + ui->editDeleteObjectAction->setText(tr("Delete Trigger")); + ui->editModifyObjectAction->setText(tr("Modify Trigger")); + } else if(type == "index") { + ui->editDeleteObjectAction->setText(tr("Delete Index")); + ui->editModifyObjectAction->setText(tr("Modify Index")); + } else if(type == "table") { + ui->editDeleteObjectAction->setText(tr("Delete Table")); + ui->editModifyObjectAction->setText(tr("Modify Table")); + } else { + // Nothing to do for other types. Set the buttons not visible and return. + ui->editDeleteObjectAction->setVisible(false); + ui->editModifyObjectAction->setVisible(false); + return; + } + + ui->editDeleteObjectAction->setVisible(true); + ui->editModifyObjectAction->setVisible(true); + + // Activate actions + ui->editDeleteObjectAction->setEnabled(!db.readOnly()); + ui->editModifyObjectAction->setEnabled(!db.readOnly()); + + if(type == "table" || type == "view") + { + ui->actionEditBrowseTable->setEnabled(true); + ui->actionExportCsvPopup->setEnabled(true); + } +} + +void MainWindow::openRecentFile() +{ + QAction *action = qobject_cast(sender()); + if (action) + { + QString file = action->data().toString(); + bool read_only = false; + if(file.startsWith("[ro]")) // Check if file is in read-only + { + file = file.mid(4); + read_only = true; + } + + if(fileOpen(file, false, read_only)) + if(read_only) + ui->statusbar->showMessage(tr("Opened '%1' in read-only mode from recent file list").arg(file)); + else + ui->statusbar->showMessage(tr("Opened '%1' from recent file list").arg(file)); + } +} + +void MainWindow::updateRecentFileActions() +{ + // Get recent files list from settings + QStringList files = Settings::getValue("General", "recentFileList").toStringList(); + + // Check if files still exist and remove any non-existent file + for(int i=0;isetText(text); + recentFileActs[i]->setData(files[i]); + recentFileActs[i]->setVisible(true); + + // Add shortcut for opening the file using the keyboard. However, if the application is configured to store + // more than nine recently opened files don't set shortcuts for the later ones which wouldn't be single digit anymore. + if(i < 9) + recentFileActs[i]->setShortcut(QKeySequence(static_cast(Qt::CTRL + (Qt::Key_1+static_cast(i))))); + } + for (int j = numRecentFiles; j < MaxRecentFiles; ++j) + recentFileActs[j]->setVisible(false); + + recentSeparatorAct->setVisible(numRecentFiles > 0); +} + +void MainWindow::setCurrentFile(const QString &fileName) +{ + setWindowFilePath(fileName); + if(currentProjectFilename.isEmpty() && fileName.isEmpty()) + setWindowTitle(QApplication::applicationName()); + else if(currentProjectFilename.isEmpty()) + setWindowTitle(QApplication::applicationName() + " - " + QDir::toNativeSeparators(fileName)); + else { + QFileInfo projectFileInfo(currentProjectFilename); + QFileInfo dbFileInfo(fileName); + QString dbFileName; + if(dbFileInfo.path() == projectFileInfo.path()) + dbFileName = dbFileInfo.fileName(); + else + dbFileName = QDir::toNativeSeparators(fileName); + setWindowTitle(QApplication::applicationName() + " - " + QDir::toNativeSeparators(currentProjectFilename) + " [" + dbFileName + "]"); + } + activateFields(!fileName.isEmpty()); + if(!fileName.isEmpty()) + dbState(db.getDirty()); +} + +void MainWindow::addToRecentFilesMenu(const QString& filename, bool read_only) +{ + QFileInfo info(filename); + QString path = info.absoluteFilePath(); + if(read_only) + path = "[ro]" + path; + + QStringList files = Settings::getValue("General", "recentFileList").toStringList(); + + files.removeAll(path); + files.prepend(path); + while (files.size() > MaxRecentFiles) + files.removeLast(); + + Settings::setValue("General", "recentFileList", files); + + for(QWidget* widget : QApplication::topLevelWidgets()) { + MainWindow *mainWin = qobject_cast(widget); + if (mainWin) + mainWin->updateRecentFileActions(); + } +} + +void MainWindow::dragEnterEvent(QDragEnterEvent *event) +{ + if( event->mimeData()->hasFormat("text/uri-list") ) + event->acceptProposedAction(); +} + +void MainWindow::dropEvent(QDropEvent *event) +{ + QList urls = event->mimeData()->urls(); + + if( urls.isEmpty() ) + return; + + QString fileName = urls.first().toLocalFile(); + + if(!fileName.isEmpty()) { + + // If there is no open database, the only possible option is to open the file. + if (!db.isOpen()) { + fileOpen(fileName); + return; + } + bool ok; + const QString open = tr("Open Database or Project"); + const QString attach = tr("Attach Database..."); + const QString import = tr("Import CSV file(s)..."); + QString action = QInputDialog::getItem(this, + qApp->applicationName(), + tr("Select the action to apply to the dropped file(s).
" + "Note: only 'Import' will process more than one file.", "", urls.count()), + {open, attach, import}, + 0, + false, + &ok); + if(ok) { + if (action == open) { + fileOpen(fileName); + } else if (action == attach) { + fileAttach(fileName); + } else if (action == import) { + + std::vector validFiles; + for(const auto& url : urls) { + if (QFile::exists(url.toLocalFile())) + validFiles.push_back(url.toLocalFile()); + } + ImportCsvDialog dialog(validFiles, &db, this); + if (dialog.exec()) + populateTable(); + } + } + } +} + +void MainWindow::activateFields(bool enable) +{ + bool write = !db.readOnly(); + bool tempDb = db.currentFile() == ":memory:"; + + ui->tableBrowser->setEnabled(enable); + ui->fileCloseAction->setEnabled(enable); + ui->fileAttachAction->setEnabled(enable); + ui->fileCompactAction->setEnabled(enable && write); + ui->fileExportJsonAction->setEnabled(enable); + ui->fileExportCSVAction->setEnabled(enable); + ui->fileExportSQLAction->setEnabled(enable); + ui->fileImportCSVAction->setEnabled(enable && write); + ui->editCreateTableAction->setEnabled(enable && write); + ui->editCreateIndexAction->setEnabled(enable && write); + ui->actionDbPrint->setEnabled(enable); + ui->scrollAreaWidgetContents->setEnabled(enable); + ui->buttonBoxPragmas->setEnabled(enable && write); + ui->actionExecuteSql->setEnabled(enable); + ui->actionLoadExtension->setEnabled(enable); + ui->actionSqlExecuteLine->setEnabled(enable); + ui->actionSaveProject->setEnabled(enable && !tempDb); + ui->actionSaveProjectAs->setEnabled(enable && !tempDb); + ui->actionSaveAll->setEnabled(enable && !tempDb); + ui->actionEncryption->setEnabled(enable && write && !tempDb); + ui->actionIntegrityCheck->setEnabled(enable); + ui->actionQuickCheck->setEnabled(enable); + ui->actionForeignKeyCheck->setEnabled(enable); + ui->actionOptimize->setEnabled(enable); + ui->dockEdit->setEnabled(enable); + ui->dockPlot->setEnabled(enable); + + if(!enable) + ui->actionSqlResultsSave->setEnabled(false); + + //remoteDock->enableButtons(); +} + +void MainWindow::resizeEvent(QResizeEvent*) +{ + ui->tableBrowser->updateRecordsetLabel(); +} + +void MainWindow::loadPragmas() +{ + pragmaValues.autovacuum = db.getPragma("auto_vacuum").toInt(); + pragmaValues.automatic_index = db.getPragma("automatic_index").toInt(); + pragmaValues.checkpoint_fullsync = db.getPragma("checkpoint_fullfsync").toInt(); + pragmaValues.foreign_keys = db.getPragma("foreign_keys").toInt(); + pragmaValues.fullfsync = db.getPragma("fullfsync").toInt(); + pragmaValues.ignore_check_constraints = db.getPragma("ignore_check_constraints").toInt(); + pragmaValues.journal_mode = db.getPragma("journal_mode").toUpper(); + pragmaValues.journal_size_limit = db.getPragma("journal_size_limit").toInt(); + pragmaValues.locking_mode = db.getPragma("locking_mode").toUpper(); + pragmaValues.max_page_count = db.getPragma("max_page_count").toInt(); + pragmaValues.page_size = db.getPragma("page_size").toInt(); + pragmaValues.recursive_triggers = db.getPragma("recursive_triggers").toInt(); + pragmaValues.secure_delete = db.getPragma("secure_delete").toInt(); + pragmaValues.synchronous = db.getPragma("synchronous").toInt(); + pragmaValues.temp_store = db.getPragma("temp_store").toInt(); + pragmaValues.user_version = db.getPragma("user_version").toInt(); + pragmaValues.wal_autocheckpoint = db.getPragma("wal_autocheckpoint").toInt(); + pragmaValues.case_sensitive_like = db.getPragma("case_sensitive_like").toInt(); + + updatePragmaUi(); +} + +void MainWindow::updatePragmaUi() +{ + ui->comboboxPragmaAutoVacuum->setCurrentIndex(pragmaValues.autovacuum); + ui->checkboxPragmaAutomaticIndex->setChecked(pragmaValues.automatic_index); + ui->checkboxPragmaCheckpointFullFsync->setChecked(pragmaValues.checkpoint_fullsync); + ui->checkboxPragmaForeignKeys->setChecked(pragmaValues.foreign_keys); + ui->checkboxPragmaFullFsync->setChecked(pragmaValues.fullfsync); + ui->checkboxPragmaIgnoreCheckConstraints->setChecked(pragmaValues.ignore_check_constraints); + ui->comboboxPragmaJournalMode->setCurrentIndex(ui->comboboxPragmaJournalMode->findText(pragmaValues.journal_mode, Qt::MatchFixedString)); + ui->spinPragmaJournalSizeLimit->setValue(pragmaValues.journal_size_limit); + ui->comboboxPragmaLockingMode->setCurrentIndex(ui->comboboxPragmaLockingMode->findText(pragmaValues.locking_mode, Qt::MatchFixedString)); + ui->spinPragmaMaxPageCount->setValue(pragmaValues.max_page_count); + ui->comboPragmaPageSize->setCurrentIndex(ui->comboPragmaPageSize->findText(QString::number(pragmaValues.page_size), Qt::MatchFixedString)); + ui->checkboxPragmaRecursiveTriggers->setChecked(pragmaValues.recursive_triggers); + ui->checkboxPragmaSecureDelete->setChecked(pragmaValues.secure_delete); + ui->comboboxPragmaSynchronous->setCurrentIndex(pragmaValues.synchronous); + ui->comboboxPragmaTempStore->setCurrentIndex(pragmaValues.temp_store); + ui->spinPragmaUserVersion->setValue(pragmaValues.user_version); + ui->spinPragmaWalAutoCheckpoint->setValue(pragmaValues.wal_autocheckpoint); + ui->checkboxPragmaCaseSensitiveLike->setChecked(pragmaValues.case_sensitive_like); +} + +void MainWindow::savePragmas() +{ + if( db.getDirty() ) + { + QString msg = tr("Setting PRAGMA values will commit your current transaction.\nAre you sure?"); + if(QMessageBox::question(this, QApplication::applicationName(), msg, QMessageBox::Yes | QMessageBox::Default, QMessageBox::No | QMessageBox::Escape) == QMessageBox::No) + { + return; // abort + } + } + db.setPragma("auto_vacuum", ui->comboboxPragmaAutoVacuum->currentIndex(), pragmaValues.autovacuum); + db.setPragma("automatic_index", ui->checkboxPragmaAutomaticIndex->isChecked(), pragmaValues.automatic_index); + db.setPragma("checkpoint_fullfsync", ui->checkboxPragmaCheckpointFullFsync->isChecked(), pragmaValues.checkpoint_fullsync); + db.setPragma("foreign_keys", ui->checkboxPragmaForeignKeys->isChecked(), pragmaValues.foreign_keys); + db.setPragma("fullfsync", ui->checkboxPragmaFullFsync->isChecked(), pragmaValues.fullfsync); + db.setPragma("ignore_check_constraints", ui->checkboxPragmaIgnoreCheckConstraints->isChecked(), pragmaValues.ignore_check_constraints); + db.setPragma("journal_mode", ui->comboboxPragmaJournalMode->currentText().toUpper(), pragmaValues.journal_mode); + db.setPragma("journal_size_limit", ui->spinPragmaJournalSizeLimit->value(), pragmaValues.journal_size_limit); + db.setPragma("locking_mode", ui->comboboxPragmaLockingMode->currentText().toUpper(), pragmaValues.locking_mode); + db.setPragma("max_page_count", ui->spinPragmaMaxPageCount->value(), pragmaValues.max_page_count); + db.setPragma("page_size", ui->comboPragmaPageSize->currentText().toInt(), pragmaValues.page_size); + db.setPragma("recursive_triggers", ui->checkboxPragmaRecursiveTriggers->isChecked(), pragmaValues.recursive_triggers); + db.setPragma("secure_delete", ui->checkboxPragmaSecureDelete->isChecked(), pragmaValues.secure_delete); + db.setPragma("synchronous", ui->comboboxPragmaSynchronous->currentIndex(), pragmaValues.synchronous); + db.setPragma("temp_store", ui->comboboxPragmaTempStore->currentIndex(), pragmaValues.temp_store); + db.setPragma("user_version", ui->spinPragmaUserVersion->value(), pragmaValues.user_version); + db.setPragma("wal_autocheckpoint", ui->spinPragmaWalAutoCheckpoint->value(), pragmaValues.wal_autocheckpoint); + db.setPragma("case_sensitive_like", ui->checkboxPragmaCaseSensitiveLike->isChecked(), pragmaValues.case_sensitive_like); + isProjectModified = true; + + updatePragmaUi(); +} + +void MainWindow::logSql(const QString& sql, int msgtype) +{ + if(msgtype == kLogMsg_User) + { + ui->editLogUser->append(sql + "\n"); + ui->editLogUser->verticalScrollBar()->setValue(ui->editLogUser->verticalScrollBar()->maximum()); + } else if(msgtype == kLogMsg_App) { + ui->editLogApplication->append(sql + "\n"); + ui->editLogApplication->verticalScrollBar()->setValue(ui->editLogApplication->verticalScrollBar()->maximum()); + } else if(msgtype == kLogMsg_ErrorLog) { + ui->editLogErrorLog->append(sql + "\n"); + ui->editLogErrorLog->verticalScrollBar()->setValue(ui->editLogErrorLog->verticalScrollBar()->maximum()); + } +} + +// Ask user to save the buffer in the specified tab index. +// ignoreUnattachedBuffers is used to store answer about buffers not linked to files, so user is only asked once about them. +// Return true unless user wants to cancel the invoking action. +bool MainWindow::askSaveSqlTab(int index, bool& ignoreUnattachedBuffers) +{ + SqlExecutionArea* sqlExecArea = qobject_cast(ui->tabSqlAreas->widget(index)); + + if(sqlExecArea->getEditor()->isModified()) { + if(sqlExecArea->fileName().isEmpty() && !ignoreUnattachedBuffers) { + // Once the project is saved, remaining SQL tabs will not be modified, so this is only expected to be asked once. + QString message = currentProjectFilename.isEmpty() ? + tr("Do you want to save the changes made to SQL tabs in a new project file?") : + tr("Do you want to save the changes made to SQL tabs in the project file '%1'?"). + arg(QFileInfo(currentProjectFilename).fileName()); + QMessageBox::StandardButton reply = QMessageBox::question(nullptr, + QApplication::applicationName(), + message, + QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel); + switch(reply) { + case QMessageBox::Save: + saveProject(); + break; + case QMessageBox::Cancel: + return false; + default: + ignoreUnattachedBuffers = true; + break; + } + } else if(!sqlExecArea->fileName().isEmpty()) { + QMessageBox::StandardButton reply = + QMessageBox::question(nullptr, + QApplication::applicationName(), + tr("Do you want to save the changes made to the SQL file %1?"). + arg(QFileInfo(sqlExecArea->fileName()).fileName()), + QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel); + switch(reply) { + case QMessageBox::Save: + saveSqlFile(index); + break; + case QMessageBox::Cancel: + return false; + default: + break; + } + } + } + return true; +} + +void MainWindow::closeSqlTab(int index, bool force) +{ + // Check if we're still executing statements from this tab and stop them before proceeding + if(ui->tabSqlAreas->tabBar()->tabData(index).toBool()) + { + if(QMessageBox::warning(this, qApp->applicationName(), tr("The statements in this tab are still executing. Closing the tab will stop the " + "execution. This might leave the database in an inconsistent state. Are you sure " + "you want to close the tab?"), + QMessageBox::Yes, + QMessageBox::Cancel | QMessageBox::Default | QMessageBox::Escape) == QMessageBox::Cancel) + return; + + execute_sql_worker->stop(); + execute_sql_worker->wait(); + } + // Ask for saving and comply with cancel answer. + bool ignoreUnattachedBuffers = false; + if (!askSaveSqlTab(index, ignoreUnattachedBuffers)) + return; + // Remove the tab and delete the widget + QWidget* w = ui->tabSqlAreas->widget(index); + ui->tabSqlAreas->removeTab(index); + delete w; + + // Don't let an empty tab widget + if(ui->tabSqlAreas->count() == 0 && !force) + openSqlTab(true); + + // Set focus to the currently selected editor tab. + SqlExecutionArea* sqlarea = qobject_cast(ui->tabSqlAreas->currentWidget()); + if(sqlarea) + sqlarea->getEditor()->setFocus(); +} + +int MainWindow::openSqlTab(bool resetCounter) +{ + static int tabNumber = 0; + + if(resetCounter) + tabNumber = 0; + + // Create new tab, add it to the tab widget and select it + SqlExecutionArea* w = new SqlExecutionArea(db, this); + int index = ui->tabSqlAreas->addTab(w, QString("SQL %1").arg(++tabNumber)); + ui->tabSqlAreas->setCurrentIndex(index); + w->setFindFrameVisibility(ui->actionSqlFind->isChecked()); + // Disable the find dialog in the SQL tabs, since the shortcut + // would interfere with the search bar and it'd be anyway redundant. + w->getEditor()->setEnabledFindDialog(false); + w->getEditor()->setFocus(); + connect(w, &SqlExecutionArea::findFrameVisibilityChanged, ui->actionSqlFind, &QAction::setChecked); + + // Connect now the find shortcut to the editor with widget context, so it isn't ambiguous with other Scintilla Widgets. + QShortcut* shortcutFind = new QShortcut(ui->actionSqlFind->shortcut(), w->getEditor(), nullptr, nullptr, Qt::WidgetShortcut); + connect(shortcutFind, &QShortcut::activated, ui->actionSqlFind, &QAction::toggle); + ui->tabSqlAreas->setTabIcon(index, QIcon(":icons/open_sql")); + // The new tab is not currently running a query + ui->tabSqlAreas->tabBar()->setTabData(index, false); + + return index; +} + +void MainWindow::changeSqlTab(int index) +{ + // Instead of figuring out if there are some execution results in the new tab and which statement was used to generate them, + // we just disable the export buttons in the toolbar. + ui->actionSqlResultsSave->setEnabled(false); + + // Check if the new tab is currently running a query or not + if(!ui->tabSqlAreas->tabBar()->tabData(index).toBool()) + { + // Not running a query + + ui->actionSqlExecuteLine->setEnabled(db.isOpen()); + ui->actionExecuteSql->setEnabled(db.isOpen()); + ui->actionSqlStop->setEnabled(false); + } else { + // Running a query + + ui->actionSqlExecuteLine->setEnabled(false); + ui->actionExecuteSql->setEnabled(false); + ui->actionSqlStop->setEnabled(true); + } +} + +void MainWindow::openSqlFile() +{ + QStringList wfiles = FileDialog::getOpenFileNames( + OpenSQLFile, + this, + tr("Select SQL file to open"), + tr("Text files(*.sql *.txt);;All files(*)")); + + for(QString file: wfiles) + { + if(QFile::exists(file)) + { + // Decide whether to open a new tab or take the current one + int index; + SqlExecutionArea* current_tab = qobject_cast(ui->tabSqlAreas->currentWidget()); + if(current_tab && current_tab->getSql().isEmpty() && current_tab->getModel()->rowCount() == 0) + index = ui->tabSqlAreas->currentIndex(); + else + index = openSqlTab(); + + SqlExecutionArea* sqlarea = qobject_cast(ui->tabSqlAreas->widget(index)); + sqlarea->openFile(file); + + QFileInfo fileinfo(file); + ui->tabSqlAreas->setTabText(index, fileinfo.fileName()); + ui->tabSqlAreas->setTabIcon(index, QIcon(":/icons/document_open")); + } + } +} + +void MainWindow::saveSqlFile(int tabIndex) +{ + SqlExecutionArea* sqlarea = qobject_cast(ui->tabSqlAreas->widget(tabIndex)); + if(!sqlarea) + return; + + // If this SQL file hasn't been saved before open the Save As dialog. Otherwise just use the old file name for saving + if(sqlarea->fileName().isEmpty()) + { + saveSqlFileAs(); + } else { + sqlarea->saveFile(sqlarea->fileName()); + } +} + +void MainWindow::saveSqlFile() +{ + saveSqlFile(ui->tabSqlAreas->currentIndex()); +} + +void MainWindow::saveSqlFileAs() +{ + SqlExecutionArea* sqlarea = qobject_cast(ui->tabSqlAreas->currentWidget()); + if(!sqlarea) + return; + + QStringList file_filter; + file_filter << FILE_FILTER_SQL + << FILE_FILTER_TXT + << FILE_FILTER_ALL; + QString file = FileDialog::getSaveFileName( + CreateSQLFile, + this, + tr("Select file name"), + file_filter.join(";;")); + + if(!file.isEmpty()) + { + sqlarea->saveFile(file); + + QFileInfo fileinfo(file); + ui->tabSqlAreas->setTabText(ui->tabSqlAreas->currentIndex(), fileinfo.fileName()); + ui->tabSqlAreas->setTabIcon(ui->tabSqlAreas->currentIndex(), QIcon(":/icons/document_open")); + } +} + +void MainWindow::saveSqlResultsAsCsv() +{ + qobject_cast(ui->tabSqlAreas->currentWidget())->saveAsCsv(); +} + +void MainWindow::saveSqlResultsAsView() +{ + saveAsView(qobject_cast(ui->tabSqlAreas->currentWidget())->getModel()->query()); +} + +void MainWindow::loadExtension() +{ + QStringList file_filter; + file_filter << FILE_FILTER_DYN + << FILE_FILTER_ALL; + + QString file = FileDialog::getOpenFileName( + OpenExtensionFile, + this, + tr("Select extension file"), + file_filter.join(";;")); + + if(file.isEmpty()) + return; + + if(db.loadExtension(file)) + QMessageBox::information(this, QApplication::applicationName(), tr("Extension successfully loaded.")); + else + QMessageBox::warning(this, QApplication::applicationName(), tr("Error loading extension: %1").arg(db.lastError())); +} + +void MainWindow::reloadSettings() +{ + // Set default application font size + qobject_cast(qApp)->reloadSettings(); + + // Set data browser font + ui->tableBrowser->reloadSettings(); + + switch (static_cast(Settings::getValue("General", "appStyle").toInt())) { + case Settings::FollowDesktopStyle : + qApp->setStyleSheet(""); + + break; + case Settings::DarkStyle : + QFile f(":qdarkstyle/style.qss"); + if (!f.exists()) { + QMessageBox::warning(this, qApp->applicationName(), + tr("Could not find resource file: %1").arg(f.fileName())); + } else { + f.open(QFile::ReadOnly | QFile::Text); + QTextStream ts(&f); + qApp->setStyleSheet(ts.readAll()); + } + break; + } + + setToolButtonStyle(static_cast(Settings::getValue("General", "toolbarStyle").toInt())); + ui->dbToolbar->setToolButtonStyle(static_cast(Settings::getValue("General", "toolbarStyleStructure").toInt())); + ui->toolbarSql->setToolButtonStyle(static_cast(Settings::getValue("General", "toolbarStyleSql").toInt())); + + // Set prefetch sizes for lazy population of table models + for(int i=0;itabSqlAreas->count();++i) + qobject_cast(ui->tabSqlAreas->widget(i))->reloadSettings(); + + // Prepare log font + QFont logfont("Monospace"); + logfont.setStyleHint(QFont::TypeWriter); + logfont.setPointSize(Settings::getValue("log", "fontsize").toInt()); + + // Set font for SQL logs and edit dialog + ui->editLogApplication->reloadSettings(); + ui->editLogUser->reloadSettings(); + ui->editLogErrorLog->reloadSettings(); + ui->editLogApplication->setFont(logfont); + ui->editLogUser->setFont(logfont); + ui->editLogErrorLog->setFont(logfont); + editDock->reloadSettings(); + + // Set font for database structure views + QFont structure_font = ui->dbTreeWidget->font(); + structure_font.setPointSize(Settings::getValue("db", "fontsize").toInt()); + ui->dbTreeWidget->setFont(structure_font); + ui->treeSchemaDock->setFont(structure_font); + + // Load extensions + db.loadExtensionsFromSettings(); + + // Refresh view + dbStructureModel->reloadData(); + populateStructure(); + populateTable(); + + // Hide or show the remote dock as needed + bool showRemoteActions = Settings::getValue("remote", "active").toBool(); + ui->viewMenu->actions().at(4)->setVisible(showRemoteActions); + if(!showRemoteActions) + ui->dockRemote->setHidden(true); + + // Reload remote dock settings + //remoteDock->reloadSettings(); + + sqlb::setIdentifierQuoting(static_cast(Settings::getValue("editor", "identifier_quotes").toInt())); + + ui->tabSqlAreas->setTabsClosable(Settings::getValue("editor", "close_button_on_tabs").toBool()); +} + +void MainWindow::checkNewVersion(const QString& versionstring, const QString& url) +{ + // versionstring contains a major.minor.patch version string + QStringList versiontokens = versionstring.split("."); + if(versiontokens.size() < 3) + return; + + int major = versiontokens[0].toInt(); + int minor = versiontokens[1].toInt(); + int patch = versiontokens[2].toInt(); + + bool newversion = false; + if(major > MAJOR_VERSION) + newversion = true; + else if(major == MAJOR_VERSION) + { + if(minor > MINOR_VERSION) + newversion = true; + else if(minor == MINOR_VERSION) + { + if(patch > PATCH_VERSION) + newversion = true; + } + } + + if(newversion) + { + int ignmajor = Settings::getValue("checkversion", "ignmajor").toInt(); + int ignminor = Settings::getValue("checkversion", "ignminor").toInt(); + int ignpatch = Settings::getValue("checkversion", "ignpatch").toInt(); + + // check if the user doesn't care about the current update + if(!(ignmajor == major && ignminor == minor && ignpatch == patch)) + { + QMessageBox msgBox; + QPushButton *idontcarebutton = msgBox.addButton(tr("Don't show again"), QMessageBox::ActionRole); + msgBox.addButton(QMessageBox::Ok); + msgBox.setTextFormat(Qt::RichText); + msgBox.setWindowTitle(tr("New version available.")); + msgBox.setText(tr("A new DB Browser for SQLite version is available (%1.%2.%3).

" + "Please download at %4.").arg(major).arg(minor).arg(patch). + arg(url)); + msgBox.exec(); + + if(msgBox.clickedButton() == idontcarebutton) + { + // save that the user don't want to get bothered about this update + Settings::setValue("checkversion", "ignmajor", major); + Settings::setValue("checkversion", "ignminor", minor); + Settings::setValue("checkversion", "ignpatch", patch); + } + } + } +} + +void MainWindow::on_actionWiki_triggered() const +{ + QDesktopServices::openUrl(QUrl("https://github.com/sqlitebrowser/sqlitebrowser/wiki")); +} + +// 'Help | Bug Report...' link will set an appropiate body, add the system information and set the label 'bug' automatically to the issue +void MainWindow::on_actionBug_report_triggered() const +{ + const QString version = Application::versionString(); + const QString os = QSysInfo::prettyProductName(); + const QString kernelType = QSysInfo::kernelType(); + const QString kernelVersion = QSysInfo::kernelVersion(); + const QString arch = QSysInfo::currentCpuArchitecture(); + const QString built_for = QSysInfo::buildAbi(); + + QString sqlite_version, sqlcipher_version; + DBBrowserDB::getSqliteVersion(sqlite_version, sqlcipher_version); + if(sqlcipher_version.isNull()) + sqlite_version = QString("SQLite Version ") + sqlite_version; + else + sqlite_version = QString("SQLCipher Version ") + sqlcipher_version + QString(" (based on SQLite %1)").arg(sqlite_version); + + const QString body = + QString("Details for the issue\n" + "--------------------\n\n" + "#### What did you do?\n\n\n" + "#### What did you expect to see?\n\n\n" + "#### What did you see instead?\n\n\n" + "Useful extra information\n" + "-------------------------\n" + "> DB4S v%1 [built for %2] on %3 (%4/%5) [%6]\n" + "> using %7\n" + "> and Qt %8") + .arg(version, built_for, os, kernelType, kernelVersion, arch, sqlite_version, QT_VERSION_STR); + + QUrlQuery query; + query.addQueryItem("labels", "bug"); + query.addQueryItem("body", body); + + QUrl url("https://github.com/sqlitebrowser/sqlitebrowser/issues/new"); + url.setQuery(query); + QDesktopServices::openUrl(url); +} + +// 'Help | Feature Request...' link will set an appropiate body and add the label 'enhancement' automatically to the issue +void MainWindow::on_actionFeature_Request_triggered() const +{ + QUrlQuery query; + + // Add the label enhancement and use the Feature request template that + // we have in GitHub. + query.addQueryItem("labels", "enhancement"); + query.addQueryItem("template", "Feature_request.md"); + + QUrl url("https://github.com/sqlitebrowser/sqlitebrowser/issues/new"); + url.setQuery(query); + QDesktopServices::openUrl(url); +} + +void MainWindow::on_actionSqlCipherFaq_triggered() const +{ + QDesktopServices::openUrl(QUrl("https://discuss.zetetic.net/c/sqlcipher/sqlcipher-faq")); +} + +void MainWindow::on_actionWebsite_triggered() const +{ + QDesktopServices::openUrl(QUrl("https://sqlitebrowser.org")); +} + +void MainWindow::on_actionDonatePatreon_triggered() const +{ + QDesktopServices::openUrl(QUrl("https://www.patreon.com/bePatron?u=11578749")); +} + +static void loadCondFormatMap(BrowseDataTableSettings::CondFormatMap& condFormats, QXmlStreamReader& xml, const QString& encoding) +{ + const QStringRef name = xml.name(); + + while(xml.readNext() != QXmlStreamReader::EndElement && xml.name() != name) { + if (xml.name() == "column") { + size_t index = xml.attributes().value("index").toUInt(); + while(xml.readNext() != QXmlStreamReader::EndElement && xml.name() != "column") { + if(xml.name() == "format") { + QFont font; + if (xml.attributes().hasAttribute("font")) + font.fromString(xml.attributes().value("font").toString()); + else + Settings::getValue("databrowser", "font").toString(); + + CondFormat::Alignment align; + if (xml.attributes().hasAttribute("align")) + align = static_cast(xml.attributes().value("align").toInt()); + else + align = CondFormat::AlignLeft; + + condFormats[index].emplace_back(xml.attributes().value("condition").toString(), + QColor(xml.attributes().value("foreground").toString()), + QColor(xml.attributes().value("background").toString()), + font, align, encoding); + xml.skipCurrentElement(); + } + } + } + } +} + +static void loadBrowseDataTableSettings(BrowseDataTableSettings& settings, QXmlStreamReader& xml) +{ + // TODO Remove this in the near future. This file format was only created temporarily by the nightlies from the late 3.11 development period. + if(xml.attributes().hasAttribute("sort_order_index")) + { + int sortOrderIndex = xml.attributes().value("sort_order_index").toInt(); + Qt::SortOrder sortOrderMode = static_cast(xml.attributes().value("sort_order_mode").toInt()); + settings.query.setOrderBy(toSortOrderVector(sortOrderIndex, sortOrderMode)); + } + + settings.showRowid = xml.attributes().value("show_row_id").toInt(); + settings.encoding = xml.attributes().value("encoding").toString(); + settings.plotXAxis = xml.attributes().value("plot_x_axis").toString(); + settings.unlockViewPk = xml.attributes().value("unlock_view_pk").toString(); + + while(xml.readNext() != QXmlStreamReader::EndElement && xml.name() != "table") { + if(xml.name() == "sort") + { + while(xml.readNext() != QXmlStreamReader::EndElement && xml.name() != "sort") + { + if(xml.name() == "column") + { + int index = xml.attributes().value("index").toInt(); + int mode = xml.attributes().value("mode").toInt(); + settings.query.orderBy().emplace_back(index, mode == Qt::AscendingOrder ? sqlb::Ascending : sqlb::Descending); + xml.skipCurrentElement(); + } + } + } else if(xml.name() == "column_widths") { + while(xml.readNext() != QXmlStreamReader::EndElement && xml.name() != "column_widths") { + if (xml.name() == "column") { + int index = xml.attributes().value("index").toInt(); + settings.columnWidths[index] = xml.attributes().value("value").toInt(); + xml.skipCurrentElement(); + } + } + } else if(xml.name() == "filter_values") { + while(xml.readNext() != QXmlStreamReader::EndElement && xml.name() != "filter_values") { + if (xml.name() == "column") { + int index = xml.attributes().value("index").toInt(); + QString value = xml.attributes().value("value").toString(); + if(!value.isEmpty()) + settings.filterValues[index] = value; + + xml.skipCurrentElement(); + } + } + } else if(xml.name() == "conditional_formats") { + loadCondFormatMap(settings.condFormats, xml, settings.encoding); + } else if(xml.name() == "row_id_formats") { + loadCondFormatMap(settings.rowIdFormats, xml, settings.encoding); + } else if(xml.name() == "display_formats") { + while(xml.readNext() != QXmlStreamReader::EndElement && xml.name() != "display_formats") { + if (xml.name() == "column") { + int index = xml.attributes().value("index").toInt(); + settings.displayFormats[index] = xml.attributes().value("value").toString(); + xml.skipCurrentElement(); + } + } + } else if(xml.name() == "hidden_columns") { + while(xml.readNext() != QXmlStreamReader::EndElement && xml.name() != "hidden_columns") { + if (xml.name() == "column") { + int index = xml.attributes().value("index").toInt(); + settings.hiddenColumns[index] = xml.attributes().value("value").toInt(); + xml.skipCurrentElement(); + } + } + } else if(xml.name() == "plot_y_axes") { + while(xml.readNext() != QXmlStreamReader::EndElement && xml.name() != "plot_y_axes") { + QString y1AxisName; + QString y2AxisName; + PlotDock::PlotSettings y1AxisSettings; + PlotDock::PlotSettings y2AxisSettings; + if (xml.name() == "y_axis") { + y1AxisName = xml.attributes().value("name").toString(); + y1AxisSettings.lineStyle = xml.attributes().value("line_style").toInt(); + y1AxisSettings.pointShape = xml.attributes().value("point_shape").toInt(); + y1AxisSettings.colour = QColor (xml.attributes().value("colour").toString()); + y1AxisSettings.active = xml.attributes().value("active").toInt(); + xml.skipCurrentElement(); + } + settings.plotYAxes[0][y1AxisName] = y1AxisSettings; + if (xml.name() == "y2_axis") { + y2AxisName = xml.attributes().value("name").toString(); + y2AxisSettings.lineStyle = xml.attributes().value("line_style").toInt(); + y2AxisSettings.pointShape = xml.attributes().value("point_shape").toInt(); + y2AxisSettings.colour = QColor (xml.attributes().value("colour").toString()); + y2AxisSettings.active = xml.attributes().value("active").toInt(); + xml.skipCurrentElement(); + } + settings.plotYAxes[1][y2AxisName] = y2AxisSettings; + } + } else if(xml.name() == "global_filter") { + while(xml.readNext() != QXmlStreamReader::EndElement && xml.name() != "global_filter") + { + if(xml.name() == "filter") + { + QString value = xml.attributes().value("value").toString(); + settings.globalFilters.push_back(value); + xml.skipCurrentElement(); + } + } + } + } +} +bool MainWindow::loadProject(QString filename, bool readOnly) +{ + // Show the open file dialog when no filename was passed as parameter + if(filename.isEmpty()) + { + filename = FileDialog::getOpenFileName( + OpenProjectFile, + this, + tr("Choose a project file to open"), + tr("DB Browser for SQLite project file (*.sqbpro)")); + } + + if(!filename.isEmpty()) + { + QFile file(filename); + file.open(QFile::ReadOnly | QFile::Text); + + QXmlStreamReader xml(&file); + xml.readNext(); // token == QXmlStreamReader::StartDocument + xml.readNext(); // name == sqlb_project + if(xml.name() != "sqlb_project") + return false; + + // We are going to open a new project, so close the possible current one before opening another. + // Stop the opening process here if the user pressed the cancel button in there. + if(!closeProject()) + return false; + + addToRecentFilesMenu(filename, readOnly); + currentProjectFilename = filename; + + QString currentTable; + while(!xml.atEnd() && !xml.hasError()) + { + // Read next token + QXmlStreamReader::TokenType token = xml.readNext(); + + // Handle element start + if(token == QXmlStreamReader::StartElement) + { + if(xml.name() == "db") + { + // Read only? + if(xml.attributes().hasAttribute("readonly") && xml.attributes().value("readonly").toInt()) + readOnly = true; + + // DB file + QString dbfilename = xml.attributes().value("path").toString(); + if(!QFile::exists(dbfilename)) { + dbfilename = QFileInfo(filename).absolutePath() + QDir::separator() + dbfilename; + // New DB filename is pending to be saved + isProjectModified = true; + } + fileOpen(dbfilename, true, readOnly); + ui->dbTreeWidget->collapseAll(); + + // PRAGMAs + if(xml.attributes().hasAttribute("foreign_keys")) + db.setPragma("foreign_keys", xml.attributes().value("foreign_keys").toString()); + if(xml.attributes().hasAttribute("case_sensitive_like")) + db.setPragma("case_sensitive_like", xml.attributes().value("case_sensitive_like").toString()); + if(xml.attributes().hasAttribute("temp_store")) + db.setPragma("temp_store", xml.attributes().value("temp_store").toString()); + if(xml.attributes().hasAttribute("wal_autocheckpoint")) + db.setPragma("wal_autocheckpoint", xml.attributes().value("wal_autocheckpoint").toString()); + if(xml.attributes().hasAttribute("synchronous")) + db.setPragma("synchronous", xml.attributes().value("synchronous").toString()); + loadPragmas(); + } else if(xml.name() == "attached") { + while(xml.readNext() != QXmlStreamReader::EndElement && xml.name() != "attached") + { + if(xml.name() == "db") + { + db.attach(xml.attributes().value("path").toString(), xml.attributes().value("schema").toString()); + xml.skipCurrentElement(); + } + } + } else if(xml.name() == "window") { + // Window settings + while(xml.readNext() != QXmlStreamReader::EndElement && xml.name() != "window") + { + if(xml.name() == "main_tabs") { + // Currently open tabs + restoreOpenTabs(xml.attributes().value("open").toString()); + // Currently selected open tab + ui->mainTab->setCurrentIndex(xml.attributes().value("current").toString().toInt()); + xml.skipCurrentElement(); + } else if(xml.name() == "current_tab") { + // Currently selected tab (3.11 or older format, first restore default open tabs) + restoreOpenTabs(defaultOpenTabs); + ui->mainTab->setCurrentIndex(xml.attributes().value("id").toString().toInt()); + xml.skipCurrentElement(); + } + } + } else if(xml.name() == "tab_structure") { + // Database Structure tab settings + while(xml.readNext() != QXmlStreamReader::EndElement && xml.name() != "tab_structure") + { + if(xml.name() == "column_width") + { + // Tree view column widths + ui->dbTreeWidget->setColumnWidth(xml.attributes().value("id").toString().toInt(), + xml.attributes().value("width").toString().toInt()); + xml.skipCurrentElement(); + } else if(xml.name() == "expanded_item") { + // Tree view expanded items + int parent = xml.attributes().value("parent").toString().toInt(); + QModelIndex idx; + if(parent == -1) + idx = ui->dbTreeWidget->model()->index(xml.attributes().value("id").toString().toInt(), 0); + else + idx = ui->dbTreeWidget->model()->index(xml.attributes().value("id").toString().toInt(), 0, ui->dbTreeWidget->model()->index(parent, 0)); + ui->dbTreeWidget->expand(idx); + xml.skipCurrentElement(); + } + } + } else if(xml.name() == "tab_browse") { + // Browse Data tab settings + while(xml.readNext() != QXmlStreamReader::EndElement && xml.name() != "tab_browse") + { + if(xml.name() == "current_table") + { + // Currently selected table + currentTable = xml.attributes().value("name").toString(); + xml.skipCurrentElement(); + } else if(xml.name() == "default_encoding") { + // Default text encoding + ui->tableBrowser->setDefaultEncoding(xml.attributes().value("codec").toString()); + xml.skipCurrentElement(); + } else if(xml.name() == "browsetable_info") { + // This tag is only found in old project files. In newer versions (>= 3.11) it is replaced by a new implementation. + // We still support loading it though we might decide to drop that support later. But for now we show a warning to the + // user when loading an old file. + if(!Settings::getValue("idontcare", "projectBrowseTable").toBool()) + { + QMessageBox msgBox; + QPushButton* idontcarebutton = msgBox.addButton(tr("Don't show again"), QMessageBox::ActionRole); + msgBox.addButton(QMessageBox::Ok); + msgBox.setTextFormat(Qt::RichText); + msgBox.setWindowTitle(qApp->applicationName()); + msgBox.setText(tr("This project file is using an old file format because it was created using DB Browser for SQLite " + "version 3.10 or lower. Loading this file format is still fully supported but we advice you to convert " + "all your project files to the new file format because support for older formats might be dropped " + "at some point in the future. You can convert your files by simply opening and re-saving them.")); + msgBox.exec(); + if(msgBox.clickedButton() == idontcarebutton) + Settings::setValue("idontcare", "projectBrowseTable", true); + } + + QString attrData = xml.attributes().value("data").toString(); + QByteArray temp = QByteArray::fromBase64(attrData.toUtf8()); + QDataStream stream(temp); + QMap settings; + stream >> settings; + for(auto it=settings.begin();it!=settings.end();++it) + ui->tableBrowser->setSettings(it.key(), it.value()); + + xml.skipCurrentElement(); + } else if(xml.name() == "browse_table_settings") { + + while(xml.readNext() != QXmlStreamReader::EndElement && xml.name() != "browse_table_settings") { + if (xml.name() == "table") { + + sqlb::ObjectIdentifier tableIdentifier = + sqlb::ObjectIdentifier (xml.attributes().value("schema").toString().toStdString(), + xml.attributes().value("name").toString().toStdString()); + BrowseDataTableSettings settings; + loadBrowseDataTableSettings(settings, xml); + ui->tableBrowser->setSettings(tableIdentifier, settings); + } + } + } + + } + } else if(xml.name() == "tab_sql") { + // Close all open tabs first + for(int i=ui->tabSqlAreas->count()-1;i>=0;i--) + closeSqlTab(i, true); + + // Execute SQL tab data + while(xml.readNext() != QXmlStreamReader::EndElement && xml.name() != "tab_sql") + { + if(xml.name() == "sql") + { + // SQL editor tab + int index = openSqlTab(); + ui->tabSqlAreas->setTabText(index, xml.attributes().value("name").toString()); + SqlTextEdit* sqlEditor = qobject_cast(ui->tabSqlAreas->widget(index))->getEditor(); + sqlEditor->setText(xml.readElementText()); + sqlEditor->setModified(false); + } else if(xml.name() == "current_tab") { + // Currently selected tab + ui->tabSqlAreas->setCurrentIndex(xml.attributes().value("id").toString().toInt()); + xml.skipCurrentElement(); + } + } + } + } + } + + file.close(); + + if(ui->mainTab->currentWidget() == ui->browser) { + if (!currentTable.isEmpty()) + { + sqlb::ObjectIdentifier obj; + if(!obj.fromSerialised(currentTable.toStdString())) + { + // This is an old project file format which doesn't yet contain serialised table identifiers. This means + // we have to try our best to unserialise this one manually. The only problem is when the name of an + // attached database or of a table contains a dot character. In that case the name becomes ambigious and + // we just try to split it at the first dot. I don't think it affects many (if any) project files. But if + // it turn out to be wrong, we can always add a loop here which checks for any possible combination of schema + // and table name whether an object with that combination exists. + // TODO: Delete this code in the future when we don't expect there to be any project files in the old format anymore. + if(currentTable.contains('.')) + { + obj.setSchema(currentTable.left(currentTable.indexOf('.')).toStdString()); + obj.setName(currentTable.mid(currentTable.indexOf('.')+1).toStdString()); + } else { + obj.setName(currentTable.toStdString()); + } + } + switchToBrowseDataTab(obj); + } + populateTable(); // Refresh view + } + + isProjectModified = false; + + return !xml.hasError(); + } else { + // No project was opened + return false; + } +} + +static void saveDbTreeState(const QTreeView* tree, QXmlStreamWriter& xml, QModelIndex index = QModelIndex(), int parent_row = -1) +{ + for(int i=0;imodel()->rowCount(index);i++) + { + if(tree->isExpanded(tree->model()->index(i, 0, index))) + { + xml.writeStartElement("expanded_item"); + xml.writeAttribute("id", QString::number(i)); + xml.writeAttribute("parent", QString::number(parent_row)); + xml.writeEndElement(); + } + + saveDbTreeState(tree, xml, tree->model()->index(i, 0, index), i); + } +} + +static void saveCondFormatMap(const QString& elementName, const BrowseDataTableSettings::CondFormatMap& condFormats, QXmlStreamWriter& xml) +{ + xml.writeStartElement(elementName); + for(auto iter=condFormats.constBegin(); iter!=condFormats.constEnd(); ++iter) { + xml.writeStartElement("column"); + xml.writeAttribute("index", QString::number(iter.key())); + for(auto format : iter.value()) { + xml.writeStartElement("format"); + xml.writeAttribute("condition", format.filter()); + xml.writeAttribute("background", format.backgroundColor().name()); + xml.writeAttribute("foreground", format.foregroundColor().name()); + xml.writeAttribute("font", format.font().toString()); + xml.writeAttribute("align", QString().setNum(format.alignment())); + xml.writeEndElement(); + } + xml.writeEndElement(); + } + xml.writeEndElement(); +} + +static void saveBrowseDataTableSettings(const BrowseDataTableSettings& object, QXmlStreamWriter& xml) +{ + xml.writeAttribute("show_row_id", QString::number(object.showRowid)); + xml.writeAttribute("encoding", object.encoding); + xml.writeAttribute("plot_x_axis", object.plotXAxis); + xml.writeAttribute("unlock_view_pk", object.unlockViewPk); + + xml.writeStartElement("sort"); + for(const auto& column : object.query.orderBy()) + { + xml.writeStartElement("column"); + xml.writeAttribute("index", QString::number(column.column)); + xml.writeAttribute("mode", QString::number(column.direction)); + xml.writeEndElement(); + } + xml.writeEndElement(); + + xml.writeStartElement("column_widths"); + for(auto iter=object.columnWidths.constBegin(); iter!=object.columnWidths.constEnd(); ++iter) { + xml.writeStartElement("column"); + xml.writeAttribute("index", QString::number(iter.key())); + xml.writeAttribute("value", QString::number(iter.value())); + xml.writeEndElement(); + } + xml.writeEndElement(); + xml.writeStartElement("filter_values"); + for(auto iter=object.filterValues.constBegin(); iter!=object.filterValues.constEnd(); ++iter) { + xml.writeStartElement("column"); + xml.writeAttribute("index", QString::number(iter.key())); + xml.writeAttribute("value", iter.value()); + xml.writeEndElement(); + } + xml.writeEndElement(); + saveCondFormatMap("conditional_formats", object.condFormats, xml); + saveCondFormatMap("row_id_formats", object.rowIdFormats, xml); + xml.writeStartElement("display_formats"); + for(auto iter=object.displayFormats.constBegin(); iter!=object.displayFormats.constEnd(); ++iter) { + xml.writeStartElement("column"); + xml.writeAttribute("index", QString::number(iter.key())); + xml.writeAttribute("value", iter.value()); + xml.writeEndElement(); + } + xml.writeEndElement(); + xml.writeStartElement("hidden_columns"); + for(auto iter=object.hiddenColumns.constBegin(); iter!=object.hiddenColumns.constEnd(); ++iter) { + xml.writeStartElement("column"); + xml.writeAttribute("index", QString::number(iter.key())); + xml.writeAttribute("value", QString::number(iter.value())); + xml.writeEndElement(); + } + xml.writeEndElement(); + xml.writeStartElement("plot_y_axes"); + for(auto iter=object.plotYAxes[0].constBegin(); iter!=object.plotYAxes[0].constEnd(); ++iter) { + PlotDock::PlotSettings plotSettings = iter.value(); + xml.writeStartElement("y_axis"); + xml.writeAttribute("name", iter.key()); + xml.writeAttribute("line_style", QString::number(plotSettings.lineStyle)); + xml.writeAttribute("point_shape", QString::number(plotSettings.pointShape)); + xml.writeAttribute("colour", plotSettings.colour.name()); + xml.writeAttribute("active", QString::number(plotSettings.active)); + xml.writeEndElement(); + } + for(auto iter=object.plotYAxes[1].constBegin(); iter!=object.plotYAxes[1].constEnd(); ++iter) { + PlotDock::PlotSettings plotSettings = iter.value(); + xml.writeStartElement("y2_axis"); + xml.writeAttribute("name", iter.key()); + xml.writeAttribute("line_style", QString::number(plotSettings.lineStyle)); + xml.writeAttribute("point_shape", QString::number(plotSettings.pointShape)); + xml.writeAttribute("colour", plotSettings.colour.name()); + xml.writeAttribute("active", QString::number(plotSettings.active)); + xml.writeEndElement(); + } + xml.writeEndElement(); + xml.writeStartElement("global_filter"); + for(const auto& v : object.globalFilters) + { + xml.writeStartElement("filter"); + xml.writeAttribute("value", v); + xml.writeEndElement(); + } + xml.writeEndElement(); +} + +void MainWindow::saveProject(const QString& currentFilename) +{ + QString filename; + if(currentFilename.isEmpty()) { + QString basePathName = db.currentFile(); + // Remove database suffix + basePathName.chop(QFileInfo(basePathName).suffix().size()+1); + filename = FileDialog::getSaveFileName( + CreateProjectFile, + this, + tr("Choose a filename to save under"), + FILE_FILTER_SQLPRJ, + basePathName); + } else + filename = currentFilename; + + if(!filename.isEmpty()) + { + // Make sure the file has got a .sqbpro ending + if(!filename.endsWith(FILE_EXT_SQLPRJ_DEFAULT, Qt::CaseInsensitive)) + filename.append(FILE_EXT_SQLPRJ_DEFAULT); + + QFile file(filename); + bool opened = file.open(QFile::WriteOnly | QFile::Text); + if(!opened) { + QMessageBox::warning(this, qApp->applicationName(), + tr("Could not open project file for writing.\nReason: %1").arg(file.errorString())); + currentProjectFilename.clear(); + return; + } + currentProjectFilename = filename; + QApplication::setOverrideCursor(Qt::WaitCursor); + + QXmlStreamWriter xml(&file); + xml.writeStartDocument(); + xml.writeStartElement("sqlb_project"); + + // Database file name + xml.writeStartElement("db"); + xml.writeAttribute("path", db.currentFile()); + xml.writeAttribute("readonly", QString::number(db.readOnly())); + xml.writeAttribute("foreign_keys", db.getPragma("foreign_keys")); + xml.writeAttribute("case_sensitive_like", db.getPragma("case_sensitive_like")); + xml.writeAttribute("temp_store", db.getPragma("temp_store")); + xml.writeAttribute("wal_autocheckpoint", db.getPragma("wal_autocheckpoint")); + xml.writeAttribute("synchronous", db.getPragma("synchronous")); + xml.writeEndElement(); + + // Attached databases + xml.writeStartElement("attached"); + db.executeSQL("PRAGMA database_list;", false, true, [&xml](int, std::vector values, std::vector) -> bool { + auto schema = values.at(1); + if(schema != "main" && schema != "temp") + { + auto path = values.at(2); + xml.writeStartElement("db"); + xml.writeAttribute("schema", schema); + xml.writeAttribute("path", path); + xml.writeEndElement(); + } + return false; + }); + xml.writeEndElement(); + + // Window settings + xml.writeStartElement("window"); + xml.writeStartElement("main_tabs"); // Currently open tabs + xml.writeAttribute("open", saveOpenTabs()); + xml.writeAttribute("current", QString::number(ui->mainTab->currentIndex())); + xml.writeEndElement(); + xml.writeEndElement(); + + // Database Structure tab settings + xml.writeStartElement("tab_structure"); + for(int i=0;idbTreeWidget->model()->columnCount();i++) // Widths of tree view columns + { + xml.writeStartElement("column_width"); + xml.writeAttribute("id", QString::number(i)); + xml.writeAttribute("width", QString::number(ui->dbTreeWidget->columnWidth(i))); + xml.writeEndElement(); + } + saveDbTreeState(ui->dbTreeWidget, xml); // Expanded tree items + xml.writeEndElement(); + + // Browse Data tab settings + xml.writeStartElement("tab_browse"); + xml.writeStartElement("current_table"); // Currently selected table + xml.writeAttribute("name", QString::fromStdString(ui->tableBrowser->currentlyBrowsedTableName().toSerialised())); + xml.writeEndElement(); + xml.writeStartElement("default_encoding"); // Default encoding for text stored in tables + xml.writeAttribute("codec", ui->tableBrowser->defaultEncoding()); + xml.writeEndElement(); + + xml.writeStartElement("browse_table_settings"); + const auto settings = ui->tableBrowser->allSettings(); + for(auto tableIt=settings.constBegin(); tableIt!=settings.constEnd(); ++tableIt) { + + xml.writeStartElement("table"); + xml.writeAttribute("schema", QString::fromStdString(tableIt.key().schema())); + xml.writeAttribute("name", QString::fromStdString(tableIt.key().name())); + saveBrowseDataTableSettings(tableIt.value(), xml); + xml.writeEndElement(); + } + // + xml.writeEndElement(); + // + xml.writeEndElement(); + + // Execute SQL tab data + xml.writeStartElement("tab_sql"); + for(int i=0;itabSqlAreas->count();i++) // All SQL tabs content + { + SqlExecutionArea* sqlArea = qobject_cast(ui->tabSqlAreas->widget(i)); + xml.writeStartElement("sql"); + xml.writeAttribute("name", ui->tabSqlAreas->tabText(i)); + xml.writeCharacters(sqlArea->getSql()); + sqlArea->getEditor()->setModified(false); + xml.writeEndElement(); + } + xml.writeStartElement("current_tab"); // Currently selected tab + xml.writeAttribute("id", QString::number(ui->tabSqlAreas->currentIndex())); + xml.writeEndElement(); + xml.writeEndElement(); + + xml.writeEndElement(); + xml.writeEndDocument(); + file.close(); + + addToRecentFilesMenu(filename); + setCurrentFile(db.currentFile()); + isProjectModified = false; + showStatusMessage5s(tr("Project saved to file '%1'").arg(currentProjectFilename)); + QApplication::restoreOverrideCursor(); + } +} + +void MainWindow::saveProject() +{ + saveProject(currentProjectFilename); +} + +void MainWindow::saveProjectAs() +{ + saveProject(QString()); +} + +void MainWindow::fileAttach(const QString& fileName) +{ + QString file; + if (fileName.isEmpty()) { + + // Get file name of database to attach + file = FileDialog::getOpenFileName( + OpenDatabaseFile, + this, + tr("Choose a database file"), + FileDialog::getSqlDatabaseFileFilter()); + } else + file = fileName; + + if(!QFile::exists(file)) + return; + + // Attach it + db.attach(file); + isProjectModified = true; +} + +void MainWindow::editEncryption() +{ +#ifdef ENABLE_SQLCIPHER + CipherDialog cipherDialog(this, true); + if(cipherDialog.exec()) + { + // Show progress dialog even though we can't provide any detailed progress information but this + // process might take some time. + QProgressDialog progress(this); + progress.setCancelButton(nullptr); + progress.setWindowModality(Qt::ApplicationModal); + progress.show(); + qApp->processEvents(); + + // Apply all unsaved changes + bool ok = db.releaseAllSavepoints(); + qApp->processEvents(); + + // Create the new file first or it won't work + if(ok) + { + QFile file(db.currentFile() + ".enctemp"); + file.open(QFile::WriteOnly); + file.close(); + } + + CipherSettings cipherSettings = cipherDialog.getCipherSettings(); + + // Attach a new database using the new settings + qApp->processEvents(); + if(ok) + ok = db.executeSQL("ATTACH DATABASE '" + db.currentFile().toStdString() + ".enctemp' AS sqlitebrowser_edit_encryption KEY " + cipherSettings.getPassword() + ";", + false, false); + qApp->processEvents(); + if(ok) + ok = db.executeSQL("PRAGMA sqlitebrowser_edit_encryption.cipher_page_size = " + std::to_string(cipherSettings.getPageSize()), false, false); + if(ok) + ok = db.executeSQL("PRAGMA sqlitebrowser_edit_encryption.cipher_hmac_algorithm = " + cipherSettings.getHmacAlgorithm(), false, false); + if(ok) + ok = db.executeSQL("PRAGMA sqlitebrowser_edit_encryption.cipher_kdf_algorithm = " + cipherSettings.getKdfAlgorithm(), false, false); + if(ok) + ok = db.executeSQL("PRAGMA sqlitebrowser_edit_encryption.kdf_iter = " + std::to_string(cipherSettings.getKdfIterations()), false, false); + if (ok) + ok = db.executeSQL("PRAGMA sqlitebrowser_edit_encryption.cipher_plaintext_header_size = " + std::to_string(cipherSettings.getPlaintextHeaderSize()), false, false); + + // Export the current database to the new one + qApp->processEvents(); + if(ok) + ok = db.executeSQL("SELECT sqlcipher_export('sqlitebrowser_edit_encryption');", false, false); + + // Set user version of the new database + qApp->processEvents(); + if (ok) + ok = db.executeSQL("PRAGMA sqlitebrowser_edit_encryption.user_version = " + std::to_string(db.getPragma("user_version").toInt()) + ";", false, false); + + // We need to detach the database before proceeding + qApp->processEvents(); + if (ok) + ok = db.executeSQL("DETACH sqlitebrowser_edit_encryption;", false, false); + + // Check for errors + qApp->processEvents(); + if(ok) + { + // No errors: Then close the current database, switch names, open the new one and if that succeeded delete the old one + + fileClose(); + QFile::rename(db.currentFile(), db.currentFile() + ".enctempold"); + QFile::rename(db.currentFile() + ".enctemp", db.currentFile()); + if(fileOpen(db.currentFile())) + QFile::remove(db.currentFile() + ".enctempold"); + } else { + QMessageBox::warning(this, qApp->applicationName(), db.lastError()); + } + } +#endif +} + +void MainWindow::switchToBrowseDataTab(sqlb::ObjectIdentifier tableToBrowse) +{ + // If no table name was provided get the currently selected table fromt he structure tab + if(tableToBrowse.isEmpty()) + { + // Cancel here if there is no selection + if(!ui->dbTreeWidget->selectionModel()->hasSelection()) + return; + + tableToBrowse.setSchema(ui->dbTreeWidget->model()->data(ui->dbTreeWidget->currentIndex().sibling(ui->dbTreeWidget->currentIndex().row(), DbStructureModel::ColumnSchema), Qt::EditRole).toString().toStdString()); + tableToBrowse.setName(ui->dbTreeWidget->model()->data(ui->dbTreeWidget->currentIndex().sibling(ui->dbTreeWidget->currentIndex().row(), DbStructureModel::ColumnName), Qt::EditRole).toString().toStdString()); + } + + ui->tableBrowser->setCurrentTable(tableToBrowse); + if (ui->mainTab->indexOf(ui->browser) == -1) + ui->mainTab->addTab(ui->browser, ui->browser->accessibleName()); + ui->mainTab->setCurrentWidget(ui->browser); +} + +void MainWindow::copyCurrentCreateStatement() +{ + // Cancel if no field is currently selected + if(!ui->dbTreeWidget->selectionModel()->hasSelection()) + return; + + // Get the CREATE statement from the Schema column + QString stmt = ui->dbTreeWidget->model()->data(ui->dbTreeWidget->currentIndex().sibling(ui->dbTreeWidget->currentIndex().row(), 3), Qt::EditRole).toString(); + + // Copy the statement to the global application clipboard + QApplication::clipboard()->setText(stmt); +} + +void MainWindow::fileOpenReadOnly() +{ + // Redirect to 'standard' fileOpen(), with the read only flag set + fileOpen(QString(), false, true); +} + +void MainWindow::requestCollation(const QString& name, int eTextRep) +{ + QMessageBox::StandardButton reply = QMessageBox::question( + this, + tr("Collation needed! Proceed?"), + tr("A table in this database requires a special collation function '%1' " + "that this application can't provide without further knowledge.\n" + "If you choose to proceed, be aware bad things can happen to your database.\n" + "Create a backup!").arg(name), QMessageBox::Yes | QMessageBox::No); + if(reply == QMessageBox::Yes) { + auto pDb = db.get(tr("creating collation")); + sqlite3_create_collation(pDb.get(), name.toUtf8(), eTextRep, nullptr, collCompare); + } +} + +void MainWindow::renameSqlTab(int index) +{ + QString new_name = QInputDialog::getText(this, + qApp->applicationName(), + tr("Set a new name for the SQL tab. Use the '&&' character to allow using the following character as a keyboard shortcut."), + QLineEdit::EchoMode::Normal, + ui->tabSqlAreas->tabText(index)); + + if(!new_name.isNull()) // Don't do anything if the Cancel button was clicked + ui->tabSqlAreas->setTabText(index, new_name); +} + +void MainWindow::setFindFrameVisibility(bool show) +{ + // Set the find frame visibility for all tabs, but leave the + // current as the last, to retain there the focus. + for(int i=0;itabSqlAreas->count();i++) + if (i != ui->tabSqlAreas->currentIndex()) + qobject_cast(ui->tabSqlAreas->widget(i))->setFindFrameVisibility(show); + if (ui->tabSqlAreas->count()>0) + qobject_cast(ui->tabSqlAreas->currentWidget())->setFindFrameVisibility(show); +} + +void MainWindow::openFindReplaceDialog() +{ + // The slot for the shortcut must discover which sqltexedit widget has the focus and then open its dialog. + SqlExecutionArea* sqlWidget = qobject_cast(ui->tabSqlAreas->currentWidget()); + + if (sqlWidget) + sqlWidget->getEditor()->openFindReplaceDialog(); +} + +void MainWindow::toggleSqlBlockComment() +{ + // The slot for the shortcut must discover which sqltexedit widget has the focus + SqlExecutionArea* sqlWidget = qobject_cast(ui->tabSqlAreas->currentWidget()); + + if (sqlWidget) + sqlWidget->getEditor()->toggleBlockComment(); +} + +void MainWindow::openSqlPrintDialog() +{ + // The slot for the shortcut must discover which sqltexedit widget has the focus and then open its dialog. + SqlExecutionArea* sqlWidget = qobject_cast(ui->tabSqlAreas->currentWidget()); + + if (sqlWidget) + sqlWidget->getEditor()->openPrintDialog(); +} + +void MainWindow::saveAsView(const std::string& query) +{ + // Let the user select a name for the new view and make sure it doesn't already exist + QString name; + while(true) + { + name = QInputDialog::getText(this, qApp->applicationName(), tr("Please specify the view name")).trimmed(); + if(name.isNull()) + return; + if(db.getObjectByName(sqlb::ObjectIdentifier("main", name.toStdString())) != nullptr) + QMessageBox::warning(this, qApp->applicationName(), tr("There is already an object with that name. Please choose a different name.")); + else + break; + } + + // Create the view + if(db.executeSQL("CREATE VIEW " + sqlb::escapeIdentifier(name.toStdString()) + " AS " + query + ";")) + QMessageBox::information(this, qApp->applicationName(), tr("View successfully created.")); + else + QMessageBox::warning(this, qApp->applicationName(), tr("Error creating view: %1").arg(db.lastError())); +} + +void MainWindow::runSqlNewTab(const QString& query, const QString& title, const QString& helpUrl, const bool autoRun) +{ + QString message; + + if(autoRun) + message = tr("This action will open a new SQL tab for running:"); + else + message = tr("This action will open a new SQL tab with the following statements for you to edit and run:"); + + message += QString("
%1
").arg(query) + + tr("Press Help for opening the corresponding SQLite reference page."); + + QString windowTitle = title; + windowTitle.remove('&'); + + switch (QMessageBox::information(this, windowTitle, message, QMessageBox::Ok | QMessageBox::Default, QMessageBox::Cancel | QMessageBox::Escape, QMessageBox::Help)) + { + case QMessageBox::Ok: { + if (ui->mainTab->indexOf(ui->query) == -1) + ui->mainTab->addTab(ui->query, ui->query->accessibleName()); + ui->mainTab->setCurrentWidget(ui->query); + int index = openSqlTab(); + ui->tabSqlAreas->setTabText(index, title); + qobject_cast(ui->tabSqlAreas->widget(index))->getEditor()->setText(query); + if(autoRun) + executeQuery(); + break; + } + case QMessageBox::Help: { + QDesktopServices::openUrl(QUrl(helpUrl)); + break; + } + default: + return; + } +} + +void MainWindow::printDbStructure () +{ + const QTreeView* treeView = ui->dbTreeWidget; + const QAbstractItemModel* model = treeView->model(); + + const int rowCount = model->rowCount(treeView->rootIndex()); + const int columnCount = model->columnCount(treeView->rootIndex()); + + QString strStream; + QTextStream out(&strStream); + + out << "" + << QString("%1").arg(treeView->windowTitle()) + << ""; + + for (int row = 0; row < rowCount; row++) { + + QModelIndex headerIndex = model->index(row, 0, treeView->rootIndex()); + QString strData = model->data(headerIndex).toString().toHtmlEscaped(); + out << QString("

%1

").arg(strData); + + // Open a new table for each group of objects + out << ""; + + for (int column = 0; column < columnCount; column++) { + // Headers + if (!treeView->isColumnHidden(column)) + out << QString("").arg(model->headerData(column, Qt::Horizontal).toString().toHtmlEscaped()); + } + out << ""; + + for (int column = 0; column < columnCount; column++) { + QModelIndex groupIndex = model->index(row, column, treeView->rootIndex()); + + // A row for the object name + for (int rowChild = 0; rowChild < model->rowCount(groupIndex); rowChild++) { + QModelIndex objectIndex = model->index(rowChild, column, groupIndex); + out << ""; + for (int column2 = 0; column2 < columnCount; column2++) { + if (!treeView->isColumnHidden(column2)) { + QModelIndex cellIndex = model->index(rowChild, column2, groupIndex); + QString header_data = model->data(cellIndex).toString().toHtmlEscaped(); + if (column2 != DbStructureModel::ColumnSQL) + out << QString("").arg((!header_data.isEmpty()) ? header_data : QString(" ")); + else + out << QString("").arg((!header_data.isEmpty()) ? header_data : QString(" ")); + } + } + out << ""; + + // One row for each object's fields + for (int rowChild2 = 0; rowChild2 < model->rowCount(objectIndex); rowChild2++) { + out << ""; + for (int column2 = 0; column2 < columnCount; column2++) { + if (!treeView->isColumnHidden(column2)) { + QModelIndex fieldIndex = model->index(rowChild2, column2, objectIndex); + QString field_data = model->data(fieldIndex).toString().toHtmlEscaped(); + out << QString("").arg((!field_data.isEmpty()) ? field_data : QString(" ")); + } + } + out << ""; + } + } + } + out << "
%1

%1

%1
%1
"; + } + out << ""; + + QPrinter printer; + printer.setDocName(treeView->windowTitle()); + + QPrintPreviewDialog *dialog = new QPrintPreviewDialog(&printer); + connect(dialog, &QPrintPreviewDialog::paintRequested, [strStream](QPrinter *previewPrinter) { + QTextDocument document; + document.setHtml(strStream); + document.print(previewPrinter); + }); + + dialog->exec(); + delete dialog; + +} + +void MainWindow::updateDatabaseBusyStatus(bool busy, const QString& user) +{ + statusBusyLabel->setText(tr("Busy (%1)").arg(user)); + statusBusyLabel->setVisible(busy); + statusStopButton->setVisible(busy); +} + + +void MainWindow::closeTab(int index) +{ + ui->mainTab->removeTab(index); +} + +void MainWindow::toggleTabVisible(QWidget* tabWidget, bool show) +{ + if (show) + ui->mainTab->addTab(tabWidget, tabWidget->accessibleName()); + else + ui->mainTab->removeTab(ui->mainTab->indexOf(tabWidget)); +} + +void MainWindow::restoreOpenTabs(QString tabs) +{ + // Split the tab list, skiping the empty parts so the empty string turns to an empty list + // and not a list of one empty string. + QStringList tabList = tabs.split(' ', QString::SkipEmptyParts); + + // Clear the tabs and then add them in the order specified by the setting. + // Use the accessibleName attribute for restoring the tab label. + if (!tabList.isEmpty()) { + // Avoid flickering while clearing and adding tabs. + ui->mainTab->setUpdatesEnabled(false); + ui->mainTab->clear(); + for (const auto& objectName : tabList) { + for (QWidget* widget : {ui->structure, ui->browser, ui->pragmas, ui->query}) + if (widget->objectName() == objectName) { + ui->mainTab->addTab(widget, widget->accessibleName()); + break; + } + } + ui->mainTab->setUpdatesEnabled(true); + // Force the update of the View menu toggable entries + // (it doesn't seem to be a better way) + emit ui->mainTab->tabCloseRequested(-1); + } +} + +QString MainWindow::saveOpenTabs() +{ + QString openTabs; + for (int i=0; i < ui->mainTab->count(); i++) + openTabs.append(ui->mainTab->widget(i)->objectName() + ' '); + openTabs.chop(1); + return openTabs; +} + +void MainWindow::showStatusMessage5s(QString message) +{ + ui->statusbar->showMessage(message, 5000); +} + +void MainWindow::saveAll() +{ + for(int i=0; itabSqlAreas->count(); i++) { + SqlExecutionArea* sqlExecArea = qobject_cast(ui->tabSqlAreas->widget(i)); + if(sqlExecArea->getEditor()->isModified() && !sqlExecArea->fileName().isEmpty()) + saveSqlFile(i); + } + if(!currentProjectFilename.isEmpty()) + saveProject(); + fileSave(); + +} + +void MainWindow::showContextMenuSqlTabBar(const QPoint& pos) +{ + // Don't show context menu if the mouse click was outside of all the tabs + int tab = ui->tabSqlAreas->tabBar()->tabAt(pos); + if(tab == -1) + return; + + // Prepare all menu actions + QAction* actionRename = new QAction(this); + actionRename->setText(tr("Rename Tab")); + connect(actionRename, &QAction::triggered, [this, tab]() { + renameSqlTab(tab); + }); + + QAction* actionDuplicate = new QAction(this); + actionDuplicate->setText(tr("Duplicate Tab")); + connect(actionDuplicate, &QAction::triggered, [this, tab]() { + QString tab_name = ui->tabSqlAreas->tabText(tab).remove("&").remove(QRegExp(" \\(\\d+\\)$")); + QString new_tab_name; + for(int i=1;;i++) + { + new_tab_name = tab_name + QString(" (%1)").arg(i); + bool name_already_exists = false; + for(int j=0;jtabSqlAreas->count();j++) + { + if(ui->tabSqlAreas->tabText(j).remove("&") == new_tab_name) + { + name_already_exists = true; + break; + } + } + + if(!name_already_exists) + break; + } + + int new_tab = openSqlTab(); + ui->tabSqlAreas->setTabText(new_tab, new_tab_name); + + SqlExecutionArea* old_area = qobject_cast(ui->tabSqlAreas->widget(tab)); + SqlExecutionArea* new_area = qobject_cast(ui->tabSqlAreas->widget(new_tab)); + new_area->setSql(old_area->getSql()); + }); + + QAction* actionClose = new QAction(this); + actionClose->setText(tr("Close Tab")); + actionClose->setShortcut(tr("Ctrl+W")); + connect(actionClose, &QAction::triggered, [this, tab]() { + closeSqlTab(tab); + }); + + // Show menu + QMenu* menuTabs = new QMenu(this); + menuTabs->addAction(actionRename); + menuTabs->addAction(actionDuplicate); + menuTabs->addAction(actionClose); + menuTabs->exec(ui->tabSqlAreas->mapToGlobal(pos)); +} + +void MainWindow::openUrlOrFile(const QString& urlString) +{ + QUrl url = QUrl::fromUserInput(urlString, QFileInfo(db.currentFile()).path(), QUrl::AssumeLocalFile); + if(url.isValid()) { + if(QDesktopServices::openUrl(url)) + showStatusMessage5s(tr("Opening '%1'...").arg(url.toDisplayString())); + else + showStatusMessage5s(tr("There was an error opening '%1'...").arg(url.toDisplayString())); + + } else + showStatusMessage5s(tr("Value is not a valid URL or filename: %1").arg(url.errorString())); +} + +void MainWindow::focusSqlEditor() +{ + SqlExecutionArea* sqlArea = qobject_cast(ui->tabSqlAreas->currentWidget()); + if(sqlArea) + sqlArea->getEditor()->setFocus(); +} + +void MainWindow::moveDocksTo(Qt::DockWidgetArea area) +{ + addDockWidget(area, ui->dockEdit); + addDockWidget(area, ui->dockLog); + tabifyDockWidget(ui->dockLog, ui->dockPlot); + tabifyDockWidget(ui->dockLog, ui->dockSchema); + tabifyDockWidget(ui->dockLog, ui->dockRemote); +} diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/MainWindow.h b/src/WBCLFZSystemModule/SqliteDBProcess/src/MainWindow.h new file mode 100644 index 0000000..2573dff --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/MainWindow.h @@ -0,0 +1,208 @@ +#ifndef MAINWINDOW_H +#define MAINWINDOW_H + +#include "sqlitedb.h" + +#include +#include + +struct BrowseDataTableSettings; +class DbStructureModel; +class EditDialog; +class ExtendedTableWidget; +class FindReplaceDialog; +class PlotDock; +class RemoteDock; +class RunSql; +class SqliteTableModel; + +class QDragEnterEvent; +class QModelIndex; +class QLabel; +class QPersistentModelIndex; +class QToolButton; + +namespace Ui { +class MainWindow; +} + +class MainWindow : public QMainWindow +{ + Q_OBJECT + +public: + explicit MainWindow(QWidget* parent = nullptr); + ~MainWindow() override; + + DBBrowserDB& getDb() { return db; } + +private: + struct PragmaValues + { + int autovacuum; + int automatic_index; + int checkpoint_fullsync; + int foreign_keys; + int fullfsync; + int ignore_check_constraints; + QString journal_mode; + int journal_size_limit; + QString locking_mode; + int max_page_count; + int page_size; + int recursive_triggers; + int secure_delete; + int synchronous; + int temp_store; + int user_version; + int wal_autocheckpoint; + int case_sensitive_like; + } pragmaValues; + + Ui::MainWindow* ui; + + DBBrowserDB db; + + SqliteTableModel* m_currentTabTableModel; + + QMenu* popupTableMenu; + QMenu* popupSchemaDockMenu; + QMenu* recentFilesMenu; + QMenu* popupOpenDbMenu; + QMenu* popupSaveSqlFileMenu; + QMenu* popupSaveSqlResultsMenu; + + QLabel* statusEncodingLabel; + QLabel* statusEncryptionLabel; + QLabel* statusReadOnlyLabel; + QToolButton* statusStopButton; + QLabel* statusBusyLabel; + + DbStructureModel* dbStructureModel; + + static const int MaxRecentFiles = 5; + QAction *recentFileActs[MaxRecentFiles]; + QAction *recentSeparatorAct; + + EditDialog* editDock; + PlotDock* plotDock; + //RemoteDock* remoteDock; + FindReplaceDialog* findReplaceDialog; + + std::unique_ptr execute_sql_worker; + + QString defaultOpenTabs; + QByteArray defaultWindowState; + + QString currentProjectFilename; + bool isProjectModified; + + void init(); + void clearCompleterModelsFields(); + + void updateRecentFileActions(); + void setCurrentFile(const QString& fileName); + void addToRecentFilesMenu(const QString& filename, bool read_only = false); + void activateFields(bool enable = true); + void saveAsView(const std::string& query); + void attachPlot(ExtendedTableWidget* tableWidget, SqliteTableModel* model, BrowseDataTableSettings* settings = nullptr, bool keepOrResetSelection = true); + + void toggleTabVisible(QWidget* tabWidget, bool show); + void restoreOpenTabs(QString tabs); + QString saveOpenTabs(); + void saveProject(const QString& currentFilename); + bool closeFiles(); + bool closeProject(); + bool askSaveSqlTab(int index, bool& ignoreUnattachedBuffers); + void focusSqlEditor(); + void moveDocksTo(Qt::DockWidgetArea area); + +protected: + void closeEvent(QCloseEvent *) override; + void dragEnterEvent(QDragEnterEvent *event) override; + void dropEvent(QDropEvent *event) override; + void resizeEvent(QResizeEvent *event) override; + +public slots: + bool fileOpen(const QString& fileName = QString(), bool openFromProject = false, bool readOnly = false); + void logSql(const QString &sql, int msgtype); + void dbState(bool dirty); + void refresh(); + void switchToBrowseDataTab(sqlb::ObjectIdentifier tableToBrowse = sqlb::ObjectIdentifier()); + void populateStructure(const sqlb::ObjectIdentifier& old_table = sqlb::ObjectIdentifier{}); + void reloadSettings(); + +private slots: + void createTreeContextMenu(const QPoint & qPoint); + void createSchemaDockContextMenu(const QPoint & qPoint); + void changeTreeSelection(); + void fileNew(); + void fileNewInMemoryDatabase(); + void populateTable(); + bool fileClose(); + void createTable(); + void createIndex(); + void compact(); + void deleteObject(); + void editObject(); + void helpWhatsThis(); + void helpAbout(); + void updateRecordText(const QPersistentModelIndex& idx, const QByteArray& text, bool isBlob); + void toggleEditDock(bool visible); + void dataTableSelectionChanged(const QModelIndex& index); + void doubleClickTable(const QModelIndex& index); + void executeQuery(); + void importTableFromCSV(); + void exportTableToCSV(); + void exportTableToJson(); + void fileSave(); + void fileRevert(); + void exportDatabaseToSQL(); + void importDatabaseFromSQL(); + void openRecentFile(); + void loadPragmas(); + void updatePragmaUi(); + void savePragmas(); + void mainTabSelected( int tabindex ); + int openSqlTab(bool resetCounter = false); + void closeSqlTab(int index, bool force = false); + void changeSqlTab(int index); + void openSqlFile(); + void saveSqlFile(); + void saveSqlFileAs(); + void saveSqlResultsAsCsv(); + void saveSqlResultsAsView(); + void loadExtension(); + void checkNewVersion(const QString& versionstring, const QString& url); + void on_actionWiki_triggered() const; + void on_actionBug_report_triggered() const; + void on_actionFeature_Request_triggered() const; + void on_actionSqlCipherFaq_triggered() const; + void on_actionWebsite_triggered() const; + void on_actionDonatePatreon_triggered() const; + bool loadProject(QString filename = QString(), bool readOnly = false); + void saveProject(); + void saveProjectAs(); + void fileAttach(const QString& fileName = QString()); + void editEncryption(); + void copyCurrentCreateStatement(); + void fileOpenReadOnly(); + void requestCollation(const QString& name, int eTextRep); + void renameSqlTab(int index); + void setFindFrameVisibility(bool show); + void openFindReplaceDialog(); + void toggleSqlBlockComment(); + void openSqlPrintDialog(); + void runSqlNewTab(const QString& query, const QString& title, const QString& helpUrl, const bool autoRun = true); + void printDbStructure(); + void updateDatabaseBusyStatus(bool busy, const QString& user); + void openPreferences(); + void closeTab(int index); + void showStatusMessage5s(QString message); + void saveSqlFile(int tabIndex); + void saveAll(); + void showContextMenuSqlTabBar(const QPoint& pos); + void openUrlOrFile(const QString& urlString); +}; + +#endif diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/Palette.cpp b/src/WBCLFZSystemModule/SqliteDBProcess/src/Palette.cpp new file mode 100644 index 0000000..61e8389 --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/Palette.cpp @@ -0,0 +1,94 @@ +#include "Palette.h" + +#include + +Palette::Palette() + : m_lastColourIndex(0) +{ +} + +QColor Palette::nextSerialColor(bool dark) +{ + if (dark) { + switch(m_lastColourIndex++) + { + case 0: + return QColor(0, 69, 134); + case 1: + return QColor(255, 66, 14); + case 2: + return QColor(255, 211, 32); + case 3: + return QColor(87, 157, 28); + case 4: + return QColor(126, 0, 33); + case 5: + return QColor(131, 202, 255); + case 6: + return QColor(49, 64, 4); + case 7: + return QColor(174, 207, 0); + case 8: + return QColor(75, 31, 111); + case 9: + return QColor(255, 149, 14); + case 10: + return QColor(197, 00, 11); + case 11: + + // Since this is the last colour in our table, reset the counter back + // to the first colour + m_lastColourIndex = 0; + + return QColor(0, 132, 209); + default: + // NOTE: This shouldn't happen! + m_lastColourIndex = 0; + return QColor(0, 0, 0); + } + } else { + // TODO: review the bright colours + switch(m_lastColourIndex++) + { + case 0: + return QColor(Qt::yellow); + case 1: + return QColor(Qt::cyan); + case 2: + return QColor(Qt::green); + case 3: + return QColor(Qt::magenta); + case 4: + return QColor(Qt::lightGray); + case 5: + return QColor("beige"); + case 6: + return QColor("lightblue"); + case 7: + return QColor("turquoise"); + case 8: + return QColor("mediumspringgreen"); + case 9: + return QColor("lightskyblue"); + case 10: + return QColor("moccasin"); + case 11: + + // Since this is the last colour in our table, reset the counter back + // to the first colour + m_lastColourIndex = 0; + + return QColor("pink"); + default: + // NOTE: This shouldn't happen! + return QColor(0, 0, 0); + } + } +} + +bool Palette::appHasDarkTheme() +{ + QColor backgroundColour = QPalette().color(QPalette::Active, QPalette::Base); + QColor foregroundColour = QPalette().color(QPalette::Active, QPalette::Text); + return backgroundColour.value() < foregroundColour.value(); +} diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/Palette.h b/src/WBCLFZSystemModule/SqliteDBProcess/src/Palette.h new file mode 100644 index 0000000..1106b30 --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/Palette.h @@ -0,0 +1,21 @@ +#ifndef PALETTE_H +#define PALETTE_H + +#include + +// Class providing series of colours in a given dark or light side of +// the spectrum. +class Palette +{ +public: + Palette(); + + QColor nextSerialColor(bool dark = true); + + static bool appHasDarkTheme(); + +private: + int m_lastColourIndex; +}; + +#endif diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/PlotDock.cpp b/src/WBCLFZSystemModule/SqliteDBProcess/src/PlotDock.cpp new file mode 100644 index 0000000..d0e9afa --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/PlotDock.cpp @@ -0,0 +1,1003 @@ +#include "PlotDock.h" +#include "ui_PlotDock.h" +#include "Settings.h" +#include "sqlitetablemodel.h" +#include "FileDialog.h" +#include "TableBrowser.h" // Just for BrowseDataTableSettings, not for the actual table browser class + +#include +#include +#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0) +#include +#endif + +// Enable this line to show the most basic performance stats after pressing the fetch-all-data button. Please keep in mind that while these +// numbers might help to estimate the performance of the data loading procedure, this is not a proper benchmark. +//#define LOAD_DATA_BENCHMARK + +#ifdef LOAD_DATA_BENCHMARK +#include +#endif + +static int random_number(int from, int to) +{ +#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0) + return QRandomGenerator::global()->bounded(from, to); +#else + return qrand() % to + from; +#endif +} + +PlotDock::PlotDock(QWidget* parent) + : QDialog(parent), + ui(new Ui::PlotDock), + m_currentPlotModel(nullptr), + m_currentTableSettings(nullptr), + m_showLegend(false), + m_stackedBars(false) +{ + ui->setupUi(this); + + // Init widgets + ui->treePlotColumns->setSelectionMode(QAbstractItemView::NoSelection); + + // Restore state + ui->splitterForPlot->restoreState(Settings::getValue("PlotDock", "splitterSize").toByteArray()); + ui->comboLineType->setCurrentIndex(Settings::getValue("PlotDock", "lineType").toInt()); + ui->comboPointShape->setCurrentIndex(Settings::getValue("PlotDock", "pointShape").toInt()); + + // Connect signals + connect(ui->treePlotColumns, &QTreeWidget::itemChanged, this, &PlotDock::on_treePlotColumns_itemChanged); + connect(ui->plotWidget, &QCustomPlot::selectionChangedByUser, this, &PlotDock::selectionChanged); + + // connect slots that takes care that when an axis is selected, only that direction can be dragged and zoomed: + connect(ui->plotWidget, &QCustomPlot::mousePress, this, &PlotDock::mousePress); + connect(ui->plotWidget, &QCustomPlot::mouseWheel, this, &PlotDock::mouseWheel); + + // Enable: click on items to select them, Ctrl+Click for multi-selection, mouse-wheel for zooming and mouse drag for + // changing the visible range. + // Select one axis for zoom and drag applying only to that orientation. + ui->plotWidget->setInteractions(QCP::iSelectPlottables | QCP::iMultiSelect | QCP::iRangeZoom | QCP::iRangeDrag | QCP::iSelectAxes); + ui->plotWidget->setSelectionRectMode(QCP::srmNone); + + QShortcut* shortcutCopy = new QShortcut(QKeySequence::Copy, ui->plotWidget, nullptr, nullptr, Qt::WidgetShortcut); + connect(shortcutCopy, &QShortcut::activated, this, &PlotDock::copy); + + QShortcut* shortcutPrint = new QShortcut(QKeySequence::Print, ui->plotWidget, nullptr, nullptr, Qt::WidgetShortcut); + connect(shortcutPrint, &QShortcut::activated, this, &PlotDock::openPrintDialog); + + ui->plotWidget->setContextMenuPolicy(Qt::CustomContextMenu); + + // Set up context menu + m_contextMenu = new QMenu(this); + + QAction* copyAction = new QAction(QIcon(":/icons/copy"), tr("Copy"), m_contextMenu); + copyAction->setShortcut(shortcutCopy->key()); + m_contextMenu->addAction(copyAction); + connect(copyAction, &QAction::triggered, [&]() { + copy(); + }); + + QAction* printAction = new QAction(QIcon(":/icons/print"), tr("Print..."), m_contextMenu); + printAction->setShortcut(shortcutPrint->key()); + m_contextMenu->addAction(printAction); + connect(printAction, &QAction::triggered, [&]() { + openPrintDialog(); + }); + + QAction* showLegendAction = new QAction(tr("Show legend"), m_contextMenu); + showLegendAction->setCheckable(true); + m_contextMenu->addAction(showLegendAction); + + connect(showLegendAction, &QAction::toggled, this, &PlotDock::toggleLegendVisible); + + QAction* stackedBarsAction = new QAction(tr("Stacked bars"), m_contextMenu); + stackedBarsAction->setCheckable(true); + m_contextMenu->addAction(stackedBarsAction); + + connect(stackedBarsAction, &QAction::toggled, this, &PlotDock::toggleStackedBars); + + connect(ui->plotWidget, &QTableView::customContextMenuRequested, + [=](const QPoint& pos) { + // Show menu + m_contextMenu->popup(ui->plotWidget->mapToGlobal(pos)); + }); + + // Initialise the y axes and plotcolumn indices for y axes + yAxes = {ui->plotWidget->yAxis, ui->plotWidget->yAxis2}; + PlotColumnY = {PlotColumnY1, PlotColumnY2}; +} + +PlotDock::~PlotDock() +{ + // Save state + Settings::setValue("PlotDock", "splitterSize", ui->splitterForPlot->saveState()); + Settings::setValue("PlotDock", "lineType", ui->comboLineType->currentIndex()); + Settings::setValue("PlotDock", "pointShape", ui->comboPointShape->currentIndex()); + + // Finally, delete all widgets + delete ui; +} + +void PlotDock::updatePlot(SqliteTableModel* model, BrowseDataTableSettings* settings, bool update, bool keepOrResetSelection) +{ + // Each column has an id that we use internally, starting from 0. However, at the beginning of the columns list we want to add + // the virtual 'Row #' column which needs a separate unique id for internal use. This id is defined here as -1. + const int RowNumId = -1; + + // add columns to x/y selection tree widget + if(update) + { + // Store pointer to the current browse table settings in the main window + m_currentTableSettings = settings; + + // disable tree plot columns item changed updates + ui->treePlotColumns->blockSignals(true); + + m_currentPlotModel = model; + + // save current selected columns, so we can restore them after the update + QString sItemX; // selected X column + QList> mapItemsY = {QMap(), QMap()}; + + if(keepOrResetSelection) + { + // Store the currently selected plot columns to restore them later + for(int i = 0; i < ui->treePlotColumns->topLevelItemCount(); ++i) + { + QTreeWidgetItem* item = ui->treePlotColumns->topLevelItem(i); + if(item->checkState(PlotColumnX) == Qt::Checked) + sItemX = item->text(PlotColumnField); + + for(int y_ind = 0; y_ind < 2; y_ind++) + if(item->checkState(PlotColumnY[y_ind]) == Qt::Checked) + mapItemsY[y_ind][item->text(PlotColumnField)] = PlotSettings(0, 0, item->backgroundColor(PlotColumnY[y_ind]), item->checkState(PlotColumnY[y_ind]) == Qt::Checked); + + } + } else { + // Get the plot columns to select from the stored browse table information + sItemX = m_currentTableSettings->plotXAxis; + mapItemsY[0] = m_currentTableSettings->plotYAxes[0]; + mapItemsY[1] = m_currentTableSettings->plotYAxes[1]; + } + + ui->treePlotColumns->clear(); + + if(model) + { + // Add each column with a supported data type to the column selection view + for(int i=0;icolumnCount();++i) + { + QVariant::Type columntype = guessDataType(model, i); + if(columntype != QVariant::Invalid) + { + QTreeWidgetItem* columnitem = new QTreeWidgetItem(ui->treePlotColumns); + + switch (columntype) { + case QVariant::DateTime: + columnitem->setText(PlotColumnType, tr("Date/Time")); + break; + case QVariant::Date: + columnitem->setText(PlotColumnType, tr("Date")); + break; + case QVariant::Time: + columnitem->setText(PlotColumnType, tr("Time")); + break; + case QVariant::Double: + columnitem->setText(PlotColumnType, tr("Numeric")); + break; + case QVariant::String: + columnitem->setText(PlotColumnType, tr("Label")); + break; + default: + // This is not actually expected + columnitem->setText(PlotColumnType, tr("Invalid")); + } + + // Store the model column index in the PlotColumnField and the type + // in the PlotColumnType, both using the User Role. + columnitem->setData(PlotColumnField, Qt::UserRole, i); + columnitem->setData(PlotColumnType, Qt::UserRole, static_cast(columntype)); + columnitem->setText(PlotColumnField, model->headerData(i, Qt::Horizontal, Qt::EditRole).toString()); + + // restore previous check state + for(int y_ind = 0; y_ind < 2; y_ind++) + { + if(mapItemsY[y_ind].contains(columnitem->text(PlotColumnField))) + { + columnitem->setCheckState(PlotColumnY[y_ind], mapItemsY[y_ind][columnitem->text(PlotColumnField)].active ? Qt::Checked : Qt::Unchecked); + columnitem->setBackgroundColor(PlotColumnY[y_ind], mapItemsY[y_ind][columnitem->text(PlotColumnField)].colour); + } else { + if (columntype == QVariant::Double) + columnitem->setCheckState(PlotColumnY[y_ind], Qt::Unchecked); + } + } + + if(sItemX == columnitem->text(PlotColumnField)) + columnitem->setCheckState(PlotColumnX, Qt::Checked); + else + columnitem->setCheckState(PlotColumnX, Qt::Unchecked); + } + } + + ui->treePlotColumns->resizeColumnToContents(PlotColumnField); + + // Add a row number column at the beginning of the column list, but only when there were (other) columns added + if(ui->treePlotColumns->topLevelItemCount()) + { + QTreeWidgetItem* columnitem = new QTreeWidgetItem(ui->treePlotColumns); + + // Just set RowNumId in the user role information field here to somehow indicate what column this is + columnitem->setData(PlotColumnField, Qt::UserRole, RowNumId); + columnitem->setText(PlotColumnField, tr("Row #")); + columnitem->setData(PlotColumnType, Qt::UserRole, static_cast(QVariant::Double)); + columnitem->setText(PlotColumnType, tr("Numeric")); + + // restore previous check state + for(int y_ind = 0; y_ind < 2; y_ind++) + { + if(mapItemsY[y_ind].contains(columnitem->text(PlotColumnField))) + { + columnitem->setCheckState(PlotColumnY[y_ind], mapItemsY[y_ind][columnitem->text(PlotColumnField)].active ? Qt::Checked : Qt::Unchecked); + columnitem->setBackgroundColor(PlotColumnY[y_ind], mapItemsY[y_ind][columnitem->text(PlotColumnField)].colour); + } else { + columnitem->setCheckState(PlotColumnY[y_ind], Qt::Unchecked); + } + } + + if(sItemX == columnitem->text(PlotColumnField)) + columnitem->setCheckState(PlotColumnX, Qt::Checked); + else + columnitem->setCheckState(PlotColumnX, Qt::Unchecked); + + ui->treePlotColumns->takeTopLevelItem(ui->treePlotColumns->indexOfTopLevelItem(columnitem)); + ui->treePlotColumns->insertTopLevelItem(0, columnitem); + } + } + + yAxes[0]->setLabel("Y1"); + yAxes[1]->setLabel("Y2"); + ui->plotWidget->xAxis->setLabel("X"); + ui->treePlotColumns->blockSignals(false); + } + + // search for the x axis select + QTreeWidgetItem* xitem = nullptr; + for(int i = 0; i < ui->treePlotColumns->topLevelItemCount(); ++i) + { + xitem = ui->treePlotColumns->topLevelItem(i); + if(xitem->checkState(PlotColumnX) == Qt::Checked) + break; + + xitem = nullptr; + } + + QList yAxisLabels = {QStringList(), QStringList()}; + + // Clear graphs and axis labels + ui->plotWidget->clearPlottables(); + ui->plotWidget->xAxis->setLabel(QString()); + yAxes[0]->setLabel(QString()); + yAxes[1]->setLabel(QString()); + + if(xitem) + { + // regain the model column index and the datatype + // right now datatype is only important for X axis (Y is always numeric) + int x = xitem->data(PlotColumnField, Qt::UserRole).toInt(); + int xtype = xitem->data(PlotColumnType, Qt::UserRole).toInt(); + + ui->plotWidget->xAxis->setTickLabelRotation(0); + + // check if we have a x axis with datetime data + switch (xtype) { + case QVariant::Date: { + QSharedPointer ticker(new QCPAxisTickerDateTime); + ticker->setDateTimeFormat("yyyy-MM-dd"); + ui->plotWidget->xAxis->setTicker(ticker); + break; + } + case QVariant::DateTime: { + QSharedPointer ticker(new QCPAxisTickerDateTime); + ticker->setDateTimeFormat("yyyy-MM-dd\nhh:mm:ss"); + ui->plotWidget->xAxis->setTicker(ticker); + break; + } + case QVariant::Time: { + QSharedPointer ticker(new QCPAxisTickerDateTime); + ticker->setDateTimeFormat("hh:mm:ss"); + ticker->setDateTimeSpec(Qt::UTC); + ui->plotWidget->xAxis->setTicker(ticker); + break; + } + case QVariant::String: { + // Ticker is set when we have got the labels + ui->plotWidget->xAxis->setTickLabelRotation(60); + break; + } + default: { + QSharedPointer ticker(new QCPAxisTickerFixed); + ticker->setTickStepStrategy(QCPAxisTicker::tssReadability); + ticker->setScaleStrategy(QCPAxisTickerFixed::ssMultiples); + ui->plotWidget->xAxis->setTicker(ticker); + } + } + + // Boolean to decide whether secondary y axis should be displayed + bool displayY2Axis = false; + + // add graph for each selected y axis + for(int i = 0; i < ui->treePlotColumns->topLevelItemCount(); ++i) + { + QTreeWidgetItem* item = ui->treePlotColumns->topLevelItem(i); + QList yItemBool = {false, false}; + + if(item->checkState((PlotColumnY[0])) == Qt::Checked || item->checkState((PlotColumnY[1])) == Qt::Checked) + { + for(int y_ind = 0; y_ind < 2; y_ind++) + if(item->checkState((PlotColumnY[y_ind])) == Qt::Checked) + yItemBool[y_ind] = true; + + if(yItemBool[1]) + displayY2Axis = true; + // regain the model column index + int column = item->data(PlotColumnField, Qt::UserRole).toInt(); + + bool isSorted = true; + + // prepare the data vectors for qcustomplot + // possible improvement might be a QVector subclass that directly + // access the model data, to save memory, we are copying here + + auto nrows = model->rowCount(); + + QList> ydata; + ydata = {QVector(nrows), QVector(nrows)}; + + QVector xdata(nrows), tdata(nrows); + QVector labels; + + for(int j = 0; j < nrows; ++j) + { + tdata[j] = j; + + // NULL values produce gaps in the graph. We use NaN values in + // that case as required by QCustomPlot. + if(x != RowNumId && model->data(model->index(j, x), Qt::EditRole).isNull()) + xdata[j] = qQNaN(); + else { + + // convert x type axis if it's datetime + switch (xtype) { + case QVariant::DateTime: + case QVariant::Date: { + QString s = model->data(model->index(j, x)).toString(); + QDateTime d = QDateTime::fromString(s, Qt::ISODate); + xdata[j] = static_cast(d.toMSecsSinceEpoch()) / 1000.0; + break; + } + case QVariant::Time: { + QString s = model->data(model->index(j, x)).toString(); + QTime t = QTime::fromString(s); + xdata[j] = t.msecsSinceStartOfDay() / 1000.0; + break; + } + case QVariant::String: { + xdata[j] = j+1; + labels << model->data(model->index(j, x)).toString(); + break; + } + default: { + // Get the x value for this point. If the selected column is -1, i.e. the row number, just use the current row number from the loop + // instead of retrieving some value from the model. + if(x == RowNumId) + xdata[j] = j+1; + else + xdata[j] = model->data(model->index(j, x)).toDouble(); + } + } + } + if (j != 0) + isSorted &= (xdata[j-1] <= xdata[j]); + + // Get the y value for this point. If the selected column is -1, i.e. the row number, just use the current row number from the loop + // instead of retrieving some value from the model. + QVariant pointdata; + if(column == RowNumId) + pointdata = j+1; + else + pointdata = model->data(model->index(j, column), Qt::EditRole); + + for(int y_ind = 0; y_ind < 2; y_ind++) + { + if(pointdata.isNull()){ + if(yItemBool[y_ind]) + ydata[y_ind][j] = qQNaN(); + } + else{ + if(yItemBool[y_ind]) + ydata[y_ind][j] = pointdata.toDouble(); + } + } + } + + // Line type and point shape are not supported by the String X type (Bars) + ui->comboLineType->setEnabled(xtype != QVariant::String); + ui->comboPointShape->setEnabled(xtype != QVariant::String); + + // WARN: ssDot is removed + int shapeIdx = ui->comboPointShape->currentIndex(); + if (shapeIdx > 0) shapeIdx += 1; + QCPScatterStyle scatterStyle = QCPScatterStyle(static_cast(shapeIdx), 5); + + QCPAbstractPlottable* plottable; + // When the X type is String, we draw a bar chart. + // When it is already sorted by x, we draw a graph. + // When it is not sorted by x, we draw a curve, so the order selected by the user in the table or in the query is + // respected. In this case the line will have loops and only None and Line is supported as line style. + // TODO: how to make the user aware of this without disturbing. + if (xtype == QVariant::String) { + + for(int y_ind = 0; y_ind < 2; y_ind++) + { + if(yItemBool[y_ind]) + { + QCPBars* bars = new QCPBars(ui->plotWidget->xAxis, yAxes[y_ind]); + plottable = bars; + bars->setData(xdata, ydata[y_ind]); + // Set ticker once + if (ui->plotWidget->plottableCount() == 1) { + QSharedPointer ticker(new QCPAxisTickerText); + ticker->addTicks(xdata, labels); + ui->plotWidget->xAxis->setTicker(ticker); + } + QColor color = item->backgroundColor(PlotColumnY[y_ind]); + bars->setBrush(color); + plottable->setPen(QPen(color.darker(150))); + } + } + } else { + if (isSorted) { + for(int y_ind = 0; y_ind < 2; y_ind++) + { + if(yItemBool[y_ind]) + { + QCPGraph* graph = ui->plotWidget->addGraph(ui->plotWidget->xAxis, yAxes[y_ind]); + plottable = graph; + graph->setData(xdata, ydata[y_ind], /*alreadySorted*/ true); + // set some graph styles not supported by the abstract plottable + graph->setLineStyle(static_cast(ui->comboLineType->currentIndex())); + graph->setScatterStyle(scatterStyle); + plottable->setPen(QPen(item->backgroundColor(PlotColumnY[y_ind]))); + } + } + } else { + for(int y_ind = 0; y_ind < 2; y_ind++) + { + if(yItemBool[y_ind]) + { + QCPCurve* curve = new QCPCurve(ui->plotWidget->xAxis, yAxes[y_ind]); + plottable = curve; + curve->setData(tdata, xdata, ydata[y_ind], /*alreadySorted*/ true); + // set some curve styles not supported by the abstract plottable + if (ui->comboLineType->currentIndex() == QCPCurve::lsNone) + curve->setLineStyle(QCPCurve::lsNone); + else + curve->setLineStyle(QCPCurve::lsLine); + curve->setScatterStyle(scatterStyle); + plottable->setPen(QPen(item->backgroundColor(PlotColumnY[y_ind]))); + } + } + } + } + + plottable->setSelectable(QCP::stDataRange); + plottable->setName(item->text(PlotColumnField)); + + for(int y_ind = 0; y_ind < 2; y_ind++) + { + if(yItemBool[y_ind]) + { + // gather Y label column names + if(column == RowNumId) + yAxisLabels[y_ind] << tr("Row #"); + else + yAxisLabels[y_ind] << model->headerData(column, Qt::Horizontal, Qt::EditRole).toString(); + } + } + } + } + + ui->plotWidget->rescaleAxes(true); + ui->plotWidget->legend->setVisible(m_showLegend); + // Legend with slightly transparent background brush: + ui->plotWidget->legend->setBrush(QColor(255, 255, 255, 150)); + + // set axis labels + if(x == RowNumId) + ui->plotWidget->xAxis->setLabel(tr("Row #")); + else + ui->plotWidget->xAxis->setLabel(model->headerData(x, Qt::Horizontal, Qt::EditRole).toString()); + for(int y_ind = 0; y_ind < 2; y_ind++) + yAxes[y_ind]->setLabel(yAxisLabels[y_ind].join("|")); + + if(displayY2Axis){ + yAxes[1]->setVisible(true); + yAxes[1]->setTickLabels(true); + }else{ + yAxes[1]->setVisible(false); + yAxes[1]->setTickLabels(false); + } + } + + adjustBars(); + ui->plotWidget->replot(); + + // Warn user if not all data has been fetched and hint about the button for loading all the data + if (model && (model->rowCountAvailable() != SqliteTableModel::RowCount::Complete || !model->isCacheComplete())) { + ui->buttonLoadAllData->setEnabled(true); + ui->buttonLoadAllData->setStyleSheet("QToolButton {color: white; background-color: rgb(255, 102, 102)}"); + ui->buttonLoadAllData->setToolTip(tr("Load all data and redraw plot.\n" + "Warning: not all data has been fetched from the table yet due to the partial fetch mechanism.")); + } else { + ui->buttonLoadAllData->setEnabled(false); + ui->buttonLoadAllData->setStyleSheet(""); + ui->buttonLoadAllData->setToolTip(tr("Load all data and redraw plot")); + } +} + +void PlotDock::resetPlot() +{ + updatePlot(nullptr); +} + +void PlotDock::on_treePlotColumns_itemChanged(QTreeWidgetItem* changeitem, int column) +{ + // disable change updates, or we get unwanted redrawing and weird behavior + ui->treePlotColumns->blockSignals(true); + + // make sure only 1 X axis is selected + if(column == PlotColumnX) + { + for(int i = 0; i < ui->treePlotColumns->topLevelItemCount(); ++i) + { + QTreeWidgetItem* item = ui->treePlotColumns->topLevelItem(i); + if(item->checkState(column) == Qt::Checked && item != changeitem) + { + item->setCheckState(column, Qt::Unchecked); + } + } + + // Save settings for this table + if(m_currentTableSettings) + { + if(changeitem->checkState(column) == Qt::Checked) + m_currentTableSettings->plotXAxis = changeitem->text(PlotColumnField); + else + m_currentTableSettings->plotXAxis = QString(); + } + } else if(column == PlotColumnY[0] || column == PlotColumnY[1]) { + // Save check state of this column + for(int y_ind = 0; y_ind < 2; y_ind++) + { + if(column == PlotColumnY[y_ind]) + { + if(m_currentTableSettings) + { + PlotSettings& plot_settings = m_currentTableSettings->plotYAxes[y_ind][changeitem->text(PlotColumnField)]; + plot_settings.active = (changeitem->checkState(column) == Qt::Checked); + } + + if(changeitem->checkState(column) == Qt::Checked) + { + // Generate a default colour if none isn't set yet + QColor colour = changeitem->backgroundColor(column); + if(!colour.isValid()) + colour = m_graphPalette.nextSerialColor(true); + + // Set colour + changeitem->setBackgroundColor(column, colour); + + // Save settings for this table + if(m_currentTableSettings) + { + PlotSettings& plot_settings = m_currentTableSettings->plotYAxes[y_ind][changeitem->text(PlotColumnField)]; + plot_settings.colour = colour; + plot_settings.lineStyle = ui->comboLineType->currentIndex(); + plot_settings.pointShape = (ui->comboPointShape->currentIndex() > 0 ? (ui->comboPointShape->currentIndex()+1) : ui->comboPointShape->currentIndex()); + } + } + } + } + + } + + ui->treePlotColumns->blockSignals(false); + + updatePlot(m_currentPlotModel, m_currentTableSettings, false); +} + +void PlotDock::on_treePlotColumns_itemDoubleClicked(QTreeWidgetItem* item, int column) +{ + // disable change updates, or we get unwanted redrawing and weird behavior + ui->treePlotColumns->blockSignals(true); + + int type = item->data(PlotColumnType, Qt::UserRole).toInt(); + + for(int y_ind = 0; y_ind < 2; y_ind++) + { + if(column == PlotColumnY[y_ind] && type == QVariant::Double) + { + // On double click open the colordialog + QColorDialog colordialog(this); + QColor curbkcolor = item->backgroundColor(column); + QColor precolor = !curbkcolor.isValid() ? static_cast(random_number(5, 13)) : curbkcolor; + QColor color = colordialog.getColor(precolor, this, tr("Choose an axis color")); + if(color.isValid()) + { + item->setCheckState(column, Qt::Checked); + item->setBackgroundColor(column, color); + + // Save settings for this table + if(m_currentTableSettings) + { + PlotSettings& plot_settings = m_currentTableSettings->plotYAxes[y_ind][item->text(PlotColumnField)]; + plot_settings.active = (item->checkState(column) == Qt::Checked); + plot_settings.colour = color; + plot_settings.lineStyle = ui->comboLineType->currentIndex(); + plot_settings.pointShape = (ui->comboPointShape->currentIndex() > 0 ? (ui->comboPointShape->currentIndex()+1) : ui->comboPointShape->currentIndex()); + } + } else { + item->setCheckState(column, Qt::Unchecked); + + // Save settings for this table + if(m_currentTableSettings) + m_currentTableSettings->plotYAxes[y_ind].remove(item->text(PlotColumnField)); + } + } + } + + ui->treePlotColumns->blockSignals(false); + + updatePlot(m_currentPlotModel, m_currentTableSettings, false); +} + +void PlotDock::on_butSavePlot_clicked() +{ + QString fileName = FileDialog::getSaveFileName( + CreateDataFile, + this, + tr("Choose a filename to save under"), + tr("PNG(*.png);;JPG(*.jpg);;PDF(*.pdf);;BMP(*.bmp);;All Files(*)")); + if(!fileName.isEmpty()) + { + if(fileName.endsWith(".png", Qt::CaseInsensitive)) + { + ui->plotWidget->savePng(fileName); + } + else if(fileName.endsWith(".jpg", Qt::CaseInsensitive)) + { + ui->plotWidget->saveJpg(fileName); + } + else if(fileName.endsWith(".pdf", Qt::CaseInsensitive)) + { + ui->plotWidget->savePdf(fileName); + } + else if(fileName.endsWith(".bmp", Qt::CaseInsensitive)) + { + ui->plotWidget->saveBmp(fileName); + } + else + { + fileName += ".png"; + ui->plotWidget->savePng(fileName); + } + } +} + +void PlotDock::on_comboLineType_currentIndexChanged(int index) +{ + Q_ASSERT(index >= QCPGraph::lsNone && + index <= QCPGraph::lsImpulse); + + bool hasCurves = (ui->plotWidget->plottableCount() > ui->plotWidget->graphCount()); + QCPGraph::LineStyle lineStyle = static_cast(index); + if (lineStyle > QCPGraph::lsLine && hasCurves) { + QMessageBox::warning(this, qApp->applicationName(), + tr("There are curves in this plot and the selected line style can only be applied to graphs sorted by X. " + "Either sort the table or query by X to remove curves or select one of the styles supported by curves: " + "None or Line.")); + return; + } + for (int i = 0, ie = ui->plotWidget->graphCount(); i < ie; ++i) + { + QCPGraph * graph = ui->plotWidget->graph(i); + if (graph) + graph->setLineStyle(lineStyle); + } + // We have changed the style only for graphs, but not for curves. + // If there are any in the plot, we have to update it completely in order to apply the new style + if (hasCurves) + updatePlot(m_currentPlotModel, m_currentTableSettings, false); + else + ui->plotWidget->replot(); + + // Save settings for this table + if(m_currentTableSettings) + { + for(int y_ind = 0; y_ind < 2; y_ind++) + { + QMap& graphs = m_currentTableSettings->plotYAxes[y_ind]; + auto it = graphs.begin(); + while(it != graphs.end()) + { + it.value().lineStyle = lineStyle; + ++it; + } + } + } +} + +void PlotDock::on_comboPointShape_currentIndexChanged(int index) +{ + // WARN: because ssDot point shape is removed + if (index > 0) index += 1; + Q_ASSERT(index >= QCPScatterStyle::ssNone && + index < QCPScatterStyle::ssPixmap); + + bool hasCurves = (ui->plotWidget->plottableCount() > ui->plotWidget->graphCount()); + QCPScatterStyle::ScatterShape shape = static_cast(index); + for (int i = 0, ie = ui->plotWidget->graphCount(); i < ie; ++i) + { + QCPGraph * graph = ui->plotWidget->graph(i); + if (graph) + graph->setScatterStyle(QCPScatterStyle(shape, 5)); + } + // We have changed the style only for graphs, but not for curves. + // If there are any in the plot, we have to update it completely in order to apply the new style + if (hasCurves) + updatePlot(m_currentPlotModel, m_currentTableSettings, false); + else + ui->plotWidget->replot(); + + // Save settings for this table + if(m_currentTableSettings) + { + for(int y_ind = 0; y_ind < 2; y_ind++) + { + QMap& graphs = m_currentTableSettings->plotYAxes[y_ind]; + auto it = graphs.begin(); + while(it != graphs.end()) + { + it.value().pointShape = shape; + ++it; + } + } + } +} + +QVariant::Type PlotDock::guessDataType(SqliteTableModel* model, int column) const +{ + QVariant::Type type = QVariant::Invalid; + for(int i = 0; i < std::min(10, model->rowCount()) && type != QVariant::String; ++i) + { + QVariant varData = model->data(model->index(i, column), Qt::EditRole); + if(varData.isNull() || varData.convert(QVariant::Double)) + { + type = QVariant::Double; + } else { + QString s = model->data(model->index(i, column)).toString(); + QDateTime dt = QDateTime::fromString(s, Qt::ISODate); + QTime t = QTime::fromString(s); + if (dt.isValid()) + // Since the way to discriminate dates with times and pure dates is that the time part is 0, we must take into account + // that some DateTimes could have "00:00:00" as time part and still the entire column has time information, so a single + // final Date should not set the type to Date if it has already been guessed as DateTime. + if (type != QVariant::DateTime && dt.time().msecsSinceStartOfDay() == 0) + type = QVariant::Date; + else + type = QVariant::DateTime; + else if (t.isValid()) + type = QVariant::Time; + else + type = QVariant::String; + } + } + + return type; +} + +void PlotDock::fetchAllData() +{ + if(m_currentPlotModel) + { +#ifdef LOAD_DATA_BENCHMARK + // If benchmark mode is enabled start measuring the performance now + QElapsedTimer timer; + timer.start(); +#endif + + // Make sure all data is loaded + m_currentPlotModel->completeCache(); + +#ifdef LOAD_DATA_BENCHMARK + QMessageBox::information(this, qApp->applicationName(), + tr("Loading all remaining data for this table took %1ms.") + .arg(timer.elapsed())); +#endif + + // Update plot + updatePlot(m_currentPlotModel, m_currentTableSettings); + } +} + +void PlotDock::selectionChanged() +{ + + for (const QCPAbstractPlottable* plottable : ui->plotWidget->selectedPlottables()) { + + for (const QCPDataRange& dataRange : plottable->selection().dataRanges()) { + + int index = dataRange.begin(); + if (dataRange.length() != 0) { + emit pointsSelected(index, dataRange.length()); + break; + } + + } + } + +} +void PlotDock::mousePress() +{ + // Allow user to reset the plot + ui->buttonLoadAllData->setEnabled(true); + + // if an axis (or axis labels) is selected, only allow the direction of that axis to be dragged + // if no axis (or axis labels) is selected, all three axes may be dragged + if (ui->plotWidget->xAxis->selectedParts().testFlag(QCPAxis::spAxis) || + ui->plotWidget->xAxis->selectedParts().testFlag(QCPAxis::spTickLabels) || + ui->plotWidget->xAxis->selectedParts().testFlag(QCPAxis::spAxisLabel)) + { + QList< QCPAxis *> axList = {ui->plotWidget->xAxis}; + ui->plotWidget->axisRect()->setRangeDragAxes(axList); + } + else if (yAxes[0]->selectedParts().testFlag(QCPAxis::spAxis) || + yAxes[0]->selectedParts().testFlag(QCPAxis::spTickLabels) || + yAxes[0]->selectedParts().testFlag(QCPAxis::spAxisLabel)) + { + QList< QCPAxis *> axList = {yAxes[0]}; + ui->plotWidget->axisRect()->setRangeDragAxes(axList); + } + else if (yAxes[1]->selectedParts().testFlag(QCPAxis::spAxis) || + yAxes[1]->selectedParts().testFlag(QCPAxis::spTickLabels) || + yAxes[1]->selectedParts().testFlag(QCPAxis::spAxisLabel)) + { + QList< QCPAxis *> axList = {yAxes[1]}; + ui->plotWidget->axisRect()->setRangeDragAxes(axList); + } + else{ + QList< QCPAxis *> axList = {ui->plotWidget->xAxis,yAxes[0], yAxes[1]}; + ui->plotWidget->axisRect()->setRangeDragAxes(axList); + } +} + +void PlotDock::mouseWheel() +{ + // Allow user to reset the plot + ui->buttonLoadAllData->setEnabled(true); + + // if an axis (or axis labels) is selected, only allow the direction of that axis to be zoomed + // if no axis (or axis labels) is selected, all three axes may be zoomed + if (ui->plotWidget->xAxis->selectedParts().testFlag(QCPAxis::spAxis) || + ui->plotWidget->xAxis->selectedParts().testFlag(QCPAxis::spTickLabels) || + ui->plotWidget->xAxis->selectedParts().testFlag(QCPAxis::spAxisLabel)) + { + QList< QCPAxis *> axList = {ui->plotWidget->xAxis}; + ui->plotWidget->axisRect()->setRangeZoomAxes(axList); + } + else if (yAxes[0]->selectedParts().testFlag(QCPAxis::spAxis) || + yAxes[0]->selectedParts().testFlag(QCPAxis::spTickLabels) || + yAxes[0]->selectedParts().testFlag(QCPAxis::spAxisLabel)) + { + QList< QCPAxis *> axList = {yAxes[0]}; + ui->plotWidget->axisRect()->setRangeZoomAxes(axList); + } + else if (yAxes[1]->selectedParts().testFlag(QCPAxis::spAxis) || + yAxes[1]->selectedParts().testFlag(QCPAxis::spTickLabels) || + yAxes[1]->selectedParts().testFlag(QCPAxis::spAxisLabel)) + { + QList< QCPAxis *> axList = {yAxes[1]}; + ui->plotWidget->axisRect()->setRangeZoomAxes(axList); + } + + else{ + QList< QCPAxis *> axList = {ui->plotWidget->xAxis,yAxes[0], yAxes[1]}; + ui->plotWidget->axisRect()->setRangeZoomAxes(axList); + } +} + +void PlotDock::copy() +{ + QApplication::clipboard()->setPixmap(ui->plotWidget->toPixmap()); +} + +void PlotDock::toggleLegendVisible(bool visible) +{ + m_showLegend = visible; + ui->plotWidget->legend->setVisible(m_showLegend); + ui->plotWidget->replot(); +} + +// Stack or group bars and set the appropiate bar width (since it is not automatically done by QCustomPlot). +void PlotDock::adjustBars() +{ + const double padding = 0.15; + int plottableCount = ui->plotWidget->plottableCount(); + + if (plottableCount == 0) + return; + + const double groupedWidth = 1.0 / plottableCount; + QCPBars* previousBar = nullptr; + QCPBarsGroup* barsGroup = m_stackedBars ? nullptr : new QCPBarsGroup(ui->plotWidget); + for (int i = 0, ie = plottableCount; i < ie; ++i) + { + QCPBars* bar = qobject_cast(ui->plotWidget->plottable(i)); + if (bar) { + if (m_stackedBars) { + // Ungroup if grouped + bar->setBarsGroup(nullptr); + if (previousBar) + bar->moveAbove(previousBar); + // Set width to ocuppy the full coordinate space, less padding + bar->setWidth(1.0 - padding); + } else { + // Unstack if stacked + bar->moveAbove(nullptr); + bar->setBarsGroup(barsGroup); + // Set width to a plot coordinate width, less padding + bar->setWidth(groupedWidth - padding); + } + previousBar = bar; + } + } +} + +void PlotDock::toggleStackedBars(bool stacked) +{ + m_stackedBars = stacked; + adjustBars(); + ui->plotWidget->replot(); +} + +void PlotDock::reject() +{ + // We override this, to ensure the Escape key doesn't make this dialog + // dock go away + return; +} + +void PlotDock::openPrintDialog() +{ + QPrinter printer; + QPrintPreviewDialog previewDialog(&printer, this); + connect(&previewDialog, &QPrintPreviewDialog::paintRequested, this, &PlotDock::renderPlot); + previewDialog.exec(); +} + +void PlotDock::renderPlot(QPrinter* printer) +{ + QCPPainter painter(printer); + QRectF pageRect = printer->pageRect(QPrinter::DevicePixel); + + int plotWidth = ui->plotWidget->viewport().width(); + int plotHeight = ui->plotWidget->viewport().height(); + double scale = pageRect.width()/static_cast(plotWidth); + + painter.setMode(QCPPainter::pmVectorized); + painter.setMode(QCPPainter::pmNoCaching); + + painter.scale(scale, scale); + ui->plotWidget->toPainter(&painter, plotWidth, plotHeight); +} diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/PlotDock.h b/src/WBCLFZSystemModule/SqliteDBProcess/src/PlotDock.h new file mode 100644 index 0000000..3ea88f6 --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/PlotDock.h @@ -0,0 +1,126 @@ +#ifndef PLOTDOCK_H +#define PLOTDOCK_H + +#include "Palette.h" + +#include +#include + +class QMenu; +class QPrinter; +class QTreeWidgetItem; +class QCPAxis; + +class SqliteTableModel; +struct BrowseDataTableSettings; + +namespace Ui { +class PlotDock; +} + +class PlotDock : public QDialog +{ + Q_OBJECT + +public: + explicit PlotDock(QWidget* parent = nullptr); + ~PlotDock() override; + + struct PlotSettings + { + int lineStyle; + int pointShape; + QColor colour; + bool active; + + PlotSettings() : + lineStyle(0), + pointShape(0), + active(false) + {} + + PlotSettings(int _lineStyle, int _pointShape, QColor _colour, bool _active) : + lineStyle(_lineStyle), + pointShape(_pointShape), + colour(_colour), + active(_active) + {} + + friend QDataStream& operator<<(QDataStream& stream, const PlotDock::PlotSettings& object) + { + stream << object.lineStyle; + stream << object.pointShape; + stream << object.colour; + stream << object.active; + + return stream; + } + friend QDataStream& operator>>(QDataStream& stream, PlotDock::PlotSettings& object) + { + stream >> object.lineStyle; + stream >> object.pointShape; + stream >> object.colour; + + if(!stream.atEnd()) + stream >> object.active; + + return stream; + } + }; + +public slots: + void updatePlot(SqliteTableModel* model, BrowseDataTableSettings* settings = nullptr, bool update = true, bool keepOrResetSelection = true); + void fetchAllData(); + void resetPlot(); + void reject() override; + +signals: + void pointsSelected(int firstIndex, int count); + +private: + enum PlotColumns + { + PlotColumnField = 0, + PlotColumnX = 1, + PlotColumnY1 = 2, + PlotColumnY2 = 3, + PlotColumnType = 4, + }; + + Ui::PlotDock* ui; + + SqliteTableModel* m_currentPlotModel; + BrowseDataTableSettings* m_currentTableSettings; + QMenu* m_contextMenu; + bool m_showLegend; + bool m_stackedBars; + Palette m_graphPalette; + QList yAxes; + QList PlotColumnY; + + /*! + * \brief guessdatatype try to parse the first 10 rows and decide the datatype + * \param model model to check the data + * \param column index of the column to check + * \return the guessed datatype + */ + QVariant::Type guessDataType(SqliteTableModel* model, int column) const; + void adjustBars(); + +private slots: + void on_treePlotColumns_itemChanged(QTreeWidgetItem* item, int column); + void on_treePlotColumns_itemDoubleClicked(QTreeWidgetItem* item, int column); + void on_butSavePlot_clicked(); + void on_comboLineType_currentIndexChanged(int index); + void on_comboPointShape_currentIndexChanged(int index); + void selectionChanged(); + void mousePress(); + void mouseWheel(); + void copy(); + void toggleLegendVisible(bool visible); + void toggleStackedBars(bool stacked); + void openPrintDialog(); + void renderPlot(QPrinter* printer); +}; + +#endif diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/PlotDock.ui b/src/WBCLFZSystemModule/SqliteDBProcess/src/PlotDock.ui new file mode 100644 index 0000000..9a391bf --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/PlotDock.ui @@ -0,0 +1,361 @@ + + + PlotDock + + + + 0 + 0 + 515 + 553 + + + + Plot + + + + + + Qt::Vertical + + + + + 0 + 2 + + + + <html><head/><body><p>This pane shows the list of columns of the currently browsed table or the just executed query. You can select the columns that you want to be used as X or Y axis for the plot pane below. The table shows detected axis type that will affect the resulting plot. For the Y axis you can only select numeric columns, but for the X axis you will be able to select:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Date/Time</span>: strings with format &quot;yyyy-MM-dd hh:mm:ss&quot; or &quot;yyyy-MM-ddThh:mm:ss&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Date</span>: strings with format &quot;yyyy-MM-dd&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Time</span>: strings with format &quot;hh:mm:ss&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Label</span>: other string formats. Selecting this column as X axis will produce a Bars plot with the column values as labels for the bars</li><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Numeric</span>: integer or real values</li></ul><p>Double-clicking the Y cells you can change the used color for that graph.</p></body></html> + + + true + + + 5 + + + 100 + + + false + + + + Columns + + + + + X + + + + + Y1 + + + + + Y2 + + + + + Axis Type + + + + + + + 0 + 8 + + + + Here is a plot drawn when you select the x and y values above. + +Click on points to select them in the plot and in the table. Ctrl+Click for selecting a range of points. + +Use mouse-wheel for zooming and mouse drag for changing the axis range. + +Select the axes or axes labels to drag and zoom only in that orientation. + + + + + + + + + + Line type: + + + comboLineType + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 0 + + + + + 50 + 0 + + + + 1 + + + + None + + + + + Line + + + + + StepLeft + + + + + StepRight + + + + + StepCenter + + + + + Impulse + + + + + + + + Point shape: + + + comboPointShape + + + + + + + + 0 + 0 + + + + + 50 + 0 + + + + 0 + + + + None + + + + + Cross + + + + + Plus + + + + + Circle + + + + + Disc + + + + + Square + + + + + Diamond + + + + + Star + + + + + Triangle + + + + + TriangleInverted + + + + + CrossSquare + + + + + PlusSquare + + + + + CrossCircle + + + + + PlusCircle + + + + + Peace + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + <html><head/><body><p>Save current plot...</p><p>File format chosen by extension (png, jpg, pdf, bmp)</p></body></html> + + + Save current plot... + + + + + + + :/icons/image_save:/icons/image_save + + + false + + + false + + + false + + + false + + + + + + + Load all data and redraw plot + + + + :/icons/refresh:/icons/refresh + + + + + + + + + + + + + QCustomPlot + QWidget +
qcustomplot.h
+ 1 +
+
+ + + + + + buttonLoadAllData + clicked() + PlotDock + fetchAllData() + + + 463 + 526 + + + 477 + 495 + + + + + + fetchAllData() + +
diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/PreferencesDialog.cpp b/src/WBCLFZSystemModule/SqliteDBProcess/src/PreferencesDialog.cpp new file mode 100644 index 0000000..b4fc4f4 --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/PreferencesDialog.cpp @@ -0,0 +1,686 @@ +#include "PreferencesDialog.h" +#include "ui_PreferencesDialog.h" +#include "FileDialog.h" +#include "Settings.h" +#include "Application.h" +#include "SqliteDBMainWindow.h" +#include "RemoteNetwork.h" +#include "FileExtensionManager.h" +#include "ProxyDialog.h" + +#include +#include +#include +#include +#include +#include + +PreferencesDialog::PreferencesDialog(QWidget* parent, Tabs tab) + : QDialog(parent), + ui(new Ui::PreferencesDialog), + m_proxyDialog(new ProxyDialog(this)), + m_dbFileExtensions(Settings::getValue("General", "DBFileExtensions").toString().split(";;")) +{ + ui->setupUi(this); + ui->treeSyntaxHighlighting->setColumnHidden(0, true); + ui->tableClientCerts->setColumnHidden(0, true); + + ui->fr_bin_bg->installEventFilter(this); + ui->fr_bin_fg->installEventFilter(this); + ui->fr_reg_bg->installEventFilter(this); + ui->fr_reg_fg->installEventFilter(this); + ui->fr_null_bg->installEventFilter(this); + ui->fr_null_fg->installEventFilter(this); + + connect(ui->comboDataBrowserFont, static_cast(&QFontComboBox::currentIndexChanged), this, &PreferencesDialog::updatePreviewFont); + connect(ui->spinDataBrowserFontSize, static_cast(&QSpinBox::valueChanged), this, &PreferencesDialog::updatePreviewFont); + +#ifndef CHECKNEWVERSION + ui->labelUpdates->setVisible(false); + ui->checkUpdates->setVisible(false); +#endif + + loadSettings(); + + connect(ui->appStyleCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(adjustColorsToStyle(int))); + + // Avoid different heights due to having check boxes or not + ui->treeSyntaxHighlighting->setUniformRowHeights(true); + + // Set current tab + ui->tabWidget->setCurrentIndex(tab); +} + +/* + * Destroys the object and frees any allocated resources + */ +PreferencesDialog::~PreferencesDialog() +{ + delete ui; +} + +void PreferencesDialog::chooseLocation() +{ + QString s = FileDialog::getExistingDirectory( + NoSpecificType, + this, + tr("Choose a directory"), + QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks); + + if(!s.isEmpty()) + ui->locationEdit->setText(s); +} + +void PreferencesDialog::loadSettings() +{ + ui->encodingComboBox->setCurrentIndex(ui->encodingComboBox->findText(Settings::getValue("db", "defaultencoding").toString(), Qt::MatchFixedString)); + ui->comboDefaultLocation->setCurrentIndex(Settings::getValue("db", "savedefaultlocation").toInt()); + ui->locationEdit->setText(QDir::toNativeSeparators(Settings::getValue("db", "defaultlocation").toString())); + ui->checkUpdates->setChecked(Settings::getValue("checkversion", "enabled").toBool()); + + ui->checkHideSchemaLinebreaks->setChecked(Settings::getValue("db", "hideschemalinebreaks").toBool()); + ui->foreignKeysCheckBox->setChecked(Settings::getValue("db", "foreignkeys").toBool()); + ui->spinPrefetchSize->setValue(Settings::getValue("db", "prefetchsize").toInt()); + ui->editDatabaseDefaultSqlText->setText(Settings::getValue("db", "defaultsqltext").toString()); + + ui->defaultFieldTypeComboBox->addItems(DBBrowserDB::Datatypes); + + int defaultFieldTypeIndex = Settings::getValue("db", "defaultfieldtype").toInt(); + if (defaultFieldTypeIndex < DBBrowserDB::Datatypes.count()) + { + ui->defaultFieldTypeComboBox->setCurrentIndex(defaultFieldTypeIndex); + } + + ui->spinStructureFontSize->setValue(Settings::getValue("db", "fontsize").toInt()); + + // Gracefully handle the preferred Data Browser font not being available + int matchingFont = ui->comboDataBrowserFont->findText(Settings::getValue("databrowser", "font").toString(), Qt::MatchExactly); + if (matchingFont == -1) + matchingFont = ui->comboDataBrowserFont->findText(Settings::getDefaultValue("databrowser", "font").toString()); + ui->comboDataBrowserFont->setCurrentIndex(matchingFont); + + ui->spinDataBrowserFontSize->setValue(Settings::getValue("databrowser", "fontsize").toInt()); + loadColorSetting(ui->fr_null_fg, "null_fg"); + loadColorSetting(ui->fr_null_bg, "null_bg"); + loadColorSetting(ui->fr_bin_fg, "bin_fg"); + loadColorSetting(ui->fr_bin_bg, "bin_bg"); + loadColorSetting(ui->fr_reg_fg, "reg_fg"); + loadColorSetting(ui->fr_reg_bg, "reg_bg"); + + ui->spinSymbolLimit->setValue(Settings::getValue("databrowser", "symbol_limit").toInt()); + ui->spinCompleteThreshold->setValue(Settings::getValue("databrowser", "complete_threshold").toInt()); + ui->checkShowImagesInline->setChecked(Settings::getValue("databrowser", "image_preview").toBool()); + ui->txtNull->setText(Settings::getValue("databrowser", "null_text").toString()); + ui->txtBlob->setText(Settings::getValue("databrowser", "blob_text").toString()); + ui->editFilterEscape->setText(Settings::getValue("databrowser", "filter_escape").toString()); + ui->spinFilterDelay->setValue(Settings::getValue("databrowser", "filter_delay").toInt()); + + for(int i=0; i < ui->treeSyntaxHighlighting->topLevelItemCount(); ++i) + { + std::string name = ui->treeSyntaxHighlighting->topLevelItem(i)->text(0).toStdString(); + QString colorname = Settings::getValue("syntaxhighlighter", name + "_colour").toString(); + QColor color = QColor(colorname); + ui->treeSyntaxHighlighting->topLevelItem(i)->setTextColor(2, color); + ui->treeSyntaxHighlighting->topLevelItem(i)->setBackgroundColor(2, color); + ui->treeSyntaxHighlighting->topLevelItem(i)->setText(2, colorname); + if (name != "null" && name != "currentline" && name != "background" && name != "foreground") { + ui->treeSyntaxHighlighting->topLevelItem(i)->setCheckState(3, Settings::getValue("syntaxhighlighter", name + "_bold").toBool() ? Qt::Checked : Qt::Unchecked); + ui->treeSyntaxHighlighting->topLevelItem(i)->setCheckState(4, Settings::getValue("syntaxhighlighter", name + "_italic").toBool() ? Qt::Checked : Qt::Unchecked); + ui->treeSyntaxHighlighting->topLevelItem(i)->setCheckState(5, Settings::getValue("syntaxhighlighter", name + "_underline").toBool() ? Qt::Checked : Qt::Unchecked); + } + } + + // Remote settings + ui->checkUseRemotes->setChecked(Settings::getValue("remote", "active").toBool()); + { + auto ca_certs = RemoteNetwork::get().caCertificates(); + ui->tableCaCerts->setRowCount(ca_certs.size()); + for(int i=0;isetFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); + ui->tableCaCerts->setItem(i, 0, cert_cn); + + QTableWidgetItem* cert_o = new QTableWidgetItem(cert.subjectInfo(QSslCertificate::Organization).at(0)); + cert_o->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); + ui->tableCaCerts->setItem(i, 1, cert_o); + + QTableWidgetItem* cert_from = new QTableWidgetItem(cert.effectiveDate().toString()); + cert_from->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); + ui->tableCaCerts->setItem(i, 2, cert_from); + + QTableWidgetItem* cert_to = new QTableWidgetItem(cert.expiryDate().toString()); + cert_to->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); + ui->tableCaCerts->setItem(i, 3, cert_to); + + QTableWidgetItem* cert_serialno = new QTableWidgetItem(QString(cert.serialNumber())); + cert_serialno->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); + ui->tableCaCerts->setItem(i, 4, cert_serialno); + } + } + { + QStringList client_certs = Settings::getValue("remote", "client_certificates").toStringList(); + for(const QString& file : client_certs) + { + auto certs = QSslCertificate::fromPath(file); + for(const QSslCertificate& cert : certs) + addClientCertToTable(file, cert); + } + } + ui->editRemoteCloneDirectory->setText(QDir::toNativeSeparators(Settings::getValue("remote", "clonedirectory").toString())); + + // Gracefully handle the preferred Editor font not being available + matchingFont = ui->comboEditorFont->findText(Settings::getValue("editor", "font").toString(), Qt::MatchExactly); + if (matchingFont == -1) + matchingFont = ui->comboDataBrowserFont->findText(Settings::getDefaultValue("editor", "font").toString()); + ui->comboEditorFont->setCurrentIndex(matchingFont); + + ui->spinEditorFontSize->setValue(Settings::getValue("editor", "fontsize").toInt()); + ui->spinTabSize->setValue(Settings::getValue("editor", "tabsize").toInt()); + ui->spinLogFontSize->setValue(Settings::getValue("log", "fontsize").toInt()); + ui->wrapComboBox->setCurrentIndex(Settings::getValue("editor", "wrap_lines").toInt()); + ui->quoteComboBox->setCurrentIndex(Settings::getValue("editor", "identifier_quotes").toInt()); + ui->checkAutoCompletion->setChecked(Settings::getValue("editor", "auto_completion").toBool()); + ui->checkCompleteUpper->setEnabled(Settings::getValue("editor", "auto_completion").toBool()); + ui->checkCompleteUpper->setChecked(Settings::getValue("editor", "upper_keywords").toBool()); + ui->checkErrorIndicators->setChecked(Settings::getValue("editor", "error_indicators").toBool()); + ui->checkHorizontalTiling->setChecked(Settings::getValue("editor", "horizontal_tiling").toBool()); + ui->checkCloseButtonOnTabs->setChecked(Settings::getValue("editor", "close_button_on_tabs").toBool()); + + ui->listExtensions->addItems(Settings::getValue("extensions", "list").toStringList()); + ui->checkRegexDisabled->setChecked(Settings::getValue("extensions", "disableregex").toBool()); + ui->checkAllowLoadExtension->setChecked(Settings::getValue("extensions", "enable_load_extension").toBool()); + fillLanguageBox(); + ui->appStyleCombo->setCurrentIndex(Settings::getValue("General", "appStyle").toInt()); + ui->toolbarStyleComboMain->setCurrentIndex(Settings::getValue("General", "toolbarStyle").toInt()); + ui->toolbarStyleComboStructure->setCurrentIndex(Settings::getValue("General", "toolbarStyleStructure").toInt()); + ui->toolbarStyleComboBrowse->setCurrentIndex(Settings::getValue("General", "toolbarStyleBrowse").toInt()); + ui->toolbarStyleComboSql->setCurrentIndex(Settings::getValue("General", "toolbarStyleSql").toInt()); + ui->toolbarStyleComboEditCell->setCurrentIndex(Settings::getValue("General", "toolbarStyleEditCell").toInt()); + ui->spinGeneralFontSize->setValue(Settings::getValue("General", "fontsize").toInt()); +} + +void PreferencesDialog::saveSettings() +{ + QApplication::setOverrideCursor(Qt::WaitCursor); + + Settings::setValue("db", "defaultencoding", ui->encodingComboBox->currentText()); + Settings::setValue("db", "defaultlocation", ui->locationEdit->text()); + Settings::setValue("db", "savedefaultlocation", ui->comboDefaultLocation->currentIndex()); + Settings::setValue("db", "hideschemalinebreaks", ui->checkHideSchemaLinebreaks->isChecked()); + Settings::setValue("db", "foreignkeys", ui->foreignKeysCheckBox->isChecked()); + Settings::setValue("db", "prefetchsize", ui->spinPrefetchSize->value()); + Settings::setValue("db", "defaultsqltext", ui->editDatabaseDefaultSqlText->text()); + Settings::setValue("db", "defaultfieldtype", ui->defaultFieldTypeComboBox->currentIndex()); + Settings::setValue("db", "fontsize", ui->spinStructureFontSize->value()); + + Settings::setValue("checkversion", "enabled", ui->checkUpdates->isChecked()); + + Settings::setValue("databrowser", "font", ui->comboDataBrowserFont->currentText()); + Settings::setValue("databrowser", "fontsize", ui->spinDataBrowserFontSize->value()); + Settings::setValue("databrowser", "image_preview", ui->checkShowImagesInline->isChecked()); + saveColorSetting(ui->fr_null_fg, "null_fg"); + saveColorSetting(ui->fr_null_bg, "null_bg"); + saveColorSetting(ui->fr_reg_fg, "reg_fg"); + saveColorSetting(ui->fr_reg_bg, "reg_bg"); + saveColorSetting(ui->fr_bin_fg, "bin_fg"); + saveColorSetting(ui->fr_bin_bg, "bin_bg"); + Settings::setValue("databrowser", "symbol_limit", ui->spinSymbolLimit->value()); + Settings::setValue("databrowser", "complete_threshold", ui->spinCompleteThreshold->value()); + Settings::setValue("databrowser", "null_text", ui->txtNull->text()); + Settings::setValue("databrowser", "blob_text", ui->txtBlob->text()); + Settings::setValue("databrowser", "filter_escape", ui->editFilterEscape->text()); + Settings::setValue("databrowser", "filter_delay", ui->spinFilterDelay->value()); + + for(int i=0; i < ui->treeSyntaxHighlighting->topLevelItemCount(); ++i) + { + std::string name = ui->treeSyntaxHighlighting->topLevelItem(i)->text(0).toStdString(); + Settings::setValue("syntaxhighlighter", name + "_colour", ui->treeSyntaxHighlighting->topLevelItem(i)->text(2)); + Settings::setValue("syntaxhighlighter", name + "_bold", ui->treeSyntaxHighlighting->topLevelItem(i)->checkState(3) == Qt::Checked); + Settings::setValue("syntaxhighlighter", name + "_italic", ui->treeSyntaxHighlighting->topLevelItem(i)->checkState(4) == Qt::Checked); + Settings::setValue("syntaxhighlighter", name + "_underline", ui->treeSyntaxHighlighting->topLevelItem(i)->checkState(5) == Qt::Checked); + } + Settings::setValue("editor", "font", ui->comboEditorFont->currentText()); + Settings::setValue("editor", "fontsize", ui->spinEditorFontSize->value()); + Settings::setValue("editor", "tabsize", ui->spinTabSize->value()); + Settings::setValue("log", "fontsize", ui->spinLogFontSize->value()); + Settings::setValue("editor", "wrap_lines", ui->wrapComboBox->currentIndex()); + Settings::setValue("editor", "identifier_quotes", ui->quoteComboBox->currentIndex()); + Settings::setValue("editor", "auto_completion", ui->checkAutoCompletion->isChecked()); + Settings::setValue("editor", "upper_keywords", ui->checkCompleteUpper->isChecked()); + Settings::setValue("editor", "error_indicators", ui->checkErrorIndicators->isChecked()); + Settings::setValue("editor", "horizontal_tiling", ui->checkHorizontalTiling->isChecked()); + Settings::setValue("editor", "close_button_on_tabs", ui->checkCloseButtonOnTabs->isChecked()); + + QStringList extList; + for(int i=0;ilistExtensions->count();++i) + extList.append(ui->listExtensions->item(i)->text()); + Settings::setValue("extensions", "list", extList); + Settings::setValue("extensions", "disableregex", ui->checkRegexDisabled->isChecked()); + Settings::setValue("extensions", "enable_load_extension", ui->checkAllowLoadExtension->isChecked()); + + // Save remote settings + Settings::setValue("remote", "active", ui->checkUseRemotes->isChecked()); + QStringList old_client_certs = Settings::getValue("remote", "client_certificates").toStringList(); + QStringList new_client_certs; + for(int i=0;itableClientCerts->rowCount();i++) + { + // Loop through the new list of client certs + + // If this certificate was already imported, remove it from the list of old certificates. All remaining certificates on this + // list will be deleted later on. + QString path = ui->tableClientCerts->item(i, 0)->text(); + if(old_client_certs.contains(path)) + { + // This is a cert that is already imported + old_client_certs.removeAll(path); + new_client_certs.push_back(path); + } else { + // This is a new certificate. Copy file to a safe place. + + // Generate unique destination file name + QString copy_to = QStandardPaths::writableLocation( +#if QT_VERSION >= QT_VERSION_CHECK(5, 4, 0) + QStandardPaths::AppDataLocation +#else + QStandardPaths::GenericDataLocation +#endif + ).append("/").append(QFileInfo(path).fileName()); + int suffix = 0; + do + { + suffix++; + } while(QFile::exists(copy_to + QString::number(suffix))); + + // Copy file + copy_to.append(QString::number(suffix)); + QDir().mkpath(QStandardPaths::writableLocation( +#if QT_VERSION >= QT_VERSION_CHECK(5, 4, 0) + QStandardPaths::AppDataLocation +#else + QStandardPaths::GenericDataLocation +#endif + )); + QFile::copy(path, copy_to); + + new_client_certs.push_back(copy_to); + } + } + for(const QString& file : old_client_certs) + { + // Now only the deleted client certs are still in the old list. Delete the cert files associated with them. + QFile::remove(file); + } + Settings::setValue("remote", "client_certificates", new_client_certs); + Settings::setValue("remote", "clonedirectory", ui->editRemoteCloneDirectory->text()); + + // Warn about restarting to change language + QVariant newLanguage = ui->languageComboBox->itemData(ui->languageComboBox->currentIndex()); + if (newLanguage != Settings::getValue("General", "language")) + QMessageBox::information(this, QApplication::applicationName(), + tr("The language will change after you restart the application.")); + + Settings::setValue("General", "language", newLanguage); + Settings::setValue("General", "appStyle", ui->appStyleCombo->currentIndex()); + Settings::setValue("General", "toolbarStyle", ui->toolbarStyleComboMain->currentIndex()); + Settings::setValue("General", "toolbarStyleStructure", ui->toolbarStyleComboStructure->currentIndex()); + Settings::setValue("General", "toolbarStyleBrowse", ui->toolbarStyleComboBrowse->currentIndex()); + Settings::setValue("General", "toolbarStyleSql", ui->toolbarStyleComboSql->currentIndex()); + Settings::setValue("General", "toolbarStyleEditCell", ui->toolbarStyleComboEditCell->currentIndex()); + Settings::setValue("General", "DBFileExtensions", m_dbFileExtensions.join(";;") ); + Settings::setValue("General", "fontsize", ui->spinGeneralFontSize->value()); + + m_proxyDialog->saveSettings(); + + accept(); + + QApplication::restoreOverrideCursor(); +} + +void PreferencesDialog::showColourDialog(QTreeWidgetItem* item, int column) +{ + if(item->text(column).left(1) != "#") + return; + + QColor colour = QColorDialog::getColor(QColor(item->text(column)), this); + if(colour.isValid()) + { + item->setTextColor(column, colour); + item->setBackgroundColor(column, colour); + item->setText(column, colour.name()); + } +} + +bool PreferencesDialog::eventFilter(QObject *obj, QEvent *event) +{ + // Use mouse click and enter press on the frames to pop up a colour dialog + if (obj == ui->fr_bin_bg || obj == ui->fr_bin_fg || + obj == ui->fr_reg_bg || obj == ui->fr_reg_fg || + obj == ui->fr_null_bg || obj == ui->fr_null_fg) + { + if (event->type() == QEvent::KeyPress) + { + QKeyEvent *key = static_cast(event); + // Not interesting, so send to the parent (might be shortcuts) + if((key->key() != Qt::Key_Enter) && (key->key() != Qt::Key_Return)) + { + return QDialog::eventFilter(obj, event); + } + } + else if (event->type() != QEvent::MouseButtonPress) + { + // Not a key event neither a mouse event, send to the parent + return QDialog::eventFilter(obj, event); + } + + QFrame *frame = qobject_cast(obj); + QColor oldColour = frame->palette().color(frame->backgroundRole()); + QColor colour = QColorDialog::getColor(oldColour, frame); + + if (colour.isValid()) + { + setColorSetting(frame, colour); + } + // Consume + return true; + } + + // Send any other events to the parent + return QDialog::eventFilter(obj, event); +} + +void PreferencesDialog::addExtension() +{ + QString file = FileDialog::getOpenFileName( + OpenExtensionFile, + this, + tr("Select extension file"), + tr("Extensions(*.so *.dylib *.dll);;All files(*)")); + + if(QFile::exists(file)) + ui->listExtensions->addItem(file); +} + +void PreferencesDialog::removeExtension() +{ + if(ui->listExtensions->currentIndex().isValid()) + ui->listExtensions->takeItem(ui->listExtensions->currentIndex().row()); +} + +void PreferencesDialog::fillLanguageBox() +{ + QDir translationsDir(QCoreApplication::applicationDirPath() + "/translations", + "sqlb_*.qm"); + + QLocale systemLocale = QLocale::system(); + + // Add default language + if (systemLocale.name() == "en_US") + { + ui->languageComboBox->addItem(QIcon(":/flags/en_US"), + "English (United States) [System Language]", + "en_US"); + } + else + { + ui->languageComboBox->addItem(QIcon(":/flags/en_US"), + "English (United States) [Default Language]", + "en_US"); + } + + // Get available *.qm files from translation dir near executable as well as from resources + QFileInfoList file_infos = translationsDir.entryInfoList(); + file_infos += QDir(":/translations").entryInfoList(); + for(const QFileInfo& file : file_infos) + { + QLocale locale(file.baseName().remove("sqlb_")); + + // Skip invalid locales + if(locale.name() == "C") + continue; + + // Skip translations that were already loaded + if (ui->languageComboBox->findData(locale.name(), Qt::UserRole, Qt::MatchExactly) != -1) + continue; + + QString language = QLocale::languageToString(locale.language()) + " (" + + QLocale::countryToString(locale.country()) + ")"; + + if (locale == systemLocale) + language += " [System language]"; + + ui->languageComboBox->addItem(QIcon(":/flags/" + locale.name()), language, locale.name()); + } + + ui->languageComboBox->model()->sort(0); + + // Try to select the language for the stored locale + int index = ui->languageComboBox->findData(Settings::getValue("General", "language"), + Qt::UserRole, Qt::MatchExactly); + + // If there's no translation for the current locale, default to English + if(index < 0) + index = ui->languageComboBox->findData("en_US", Qt::UserRole, Qt::MatchExactly); + + QString chosenLanguage = ui->languageComboBox->itemText(index); + QVariant chosenLocale = ui->languageComboBox->itemData(index); + QIcon chosenIcon = ui->languageComboBox->itemIcon(index); + + // There's no "move" method, so we remove and add the chosen language again at the top + ui->languageComboBox->removeItem(index); + ui->languageComboBox->insertItem(0, chosenIcon, chosenLanguage, chosenLocale); + ui->languageComboBox->setCurrentIndex(0); + + // This is a workaround needed for QDarkStyleSheet. + // See https://github.com/ColinDuquesnoy/QDarkStyleSheet/issues/169 + QStyledItemDelegate* styledItemDelegate = new QStyledItemDelegate(ui->languageComboBox); + ui->languageComboBox->setItemDelegate(styledItemDelegate); + +} + +void PreferencesDialog::loadColorSetting(QFrame *frame, const std::string& settingName) +{ + QColor color = QColor(Settings::getValue("databrowser", settingName + "_colour").toString()); + setColorSetting(frame, color); +} + +void PreferencesDialog::setColorSetting(QFrame *frame, const QColor &color) +{ + QPalette::ColorRole role; + QLineEdit *line; + + if (frame == ui->fr_bin_bg) { + line = ui->txtBlob; + role = line->backgroundRole(); + } else if (frame == ui->fr_bin_fg) { + line = ui->txtBlob; + role = line->foregroundRole(); + } else if (frame == ui->fr_reg_bg) { + line = ui->txtRegular; + role = line->backgroundRole(); + } else if (frame == ui->fr_reg_fg) { + line = ui->txtRegular; + role = line->foregroundRole(); + } else if (frame == ui->fr_null_bg) { + line = ui->txtNull; + role = line->backgroundRole(); + } else if (frame == ui->fr_null_fg) { + line = ui->txtNull; + role = line->foregroundRole(); + } else + return; + + QPalette palette = frame->palette(); + palette.setColor(frame->backgroundRole(), color); + frame->setPalette(palette); + + frame->setStyleSheet(QString(".QFrame {background-color: %2}").arg(color.name())); + + palette = line->palette(); + palette.setColor(role, color); + line->setPalette(palette); + + line->setStyleSheet(QString(".QLineEdit {color: %1; background-color: %2}").arg(palette.color(line->foregroundRole()).name(), + palette.color(line->backgroundRole()).name())); +} + +void PreferencesDialog::saveColorSetting(QFrame* frame, const std::string& settingName) +{ + Settings::setValue("databrowser", settingName + "_colour", + frame->palette().color(frame->backgroundRole())); +} + +void PreferencesDialog::adjustColorsToStyle(int style) +{ + Settings::AppStyle appStyle = static_cast(style); + setColorSetting(ui->fr_null_fg, Settings::getDefaultColorValue("databrowser", "null_fg_colour", appStyle)); + setColorSetting(ui->fr_null_bg, Settings::getDefaultColorValue("databrowser", "null_bg_colour", appStyle)); + setColorSetting(ui->fr_bin_fg, Settings::getDefaultColorValue("databrowser", "bin_fg_colour", appStyle)); + setColorSetting(ui->fr_bin_bg, Settings::getDefaultColorValue("databrowser", "bin_bg_colour", appStyle)); + setColorSetting(ui->fr_reg_fg, Settings::getDefaultColorValue("databrowser", "reg_fg_colour", appStyle)); + setColorSetting(ui->fr_reg_bg, Settings::getDefaultColorValue("databrowser", "reg_bg_colour", appStyle)); + + for(int i=0; i < ui->treeSyntaxHighlighting->topLevelItemCount(); ++i) + { + std::string name = ui->treeSyntaxHighlighting->topLevelItem(i)->text(0).toStdString(); + QColor color = Settings::getDefaultColorValue("syntaxhighlighter", name + "_colour", appStyle); + ui->treeSyntaxHighlighting->topLevelItem(i)->setTextColor(2, color); + ui->treeSyntaxHighlighting->topLevelItem(i)->setBackgroundColor(2, color); + ui->treeSyntaxHighlighting->topLevelItem(i)->setText(2, color.name()); + } +} + +void PreferencesDialog::activateRemoteTab(bool active) +{ + ui->tabWidget->setTabEnabled(ui->tabWidget->indexOf(ui->tabRemote), active); +} + +void PreferencesDialog::addClientCertificate() +{ + // Get certificate file to import and abort here if no file gets selected + // NOTE: We assume here that this file contains both, certificate and private key! + QString path = FileDialog::getOpenFileName(OpenCertificateFile, this, tr("Import certificate file"), "*.pem"); + if(path.isEmpty()) + return; + + // Open file and check if any certificates were imported + auto certs = QSslCertificate::fromPath(path); + if(certs.size() == 0) + { + QMessageBox::warning(this, qApp->applicationName(), tr("No certificates found in this file.")); + return; + } + + // Add certificates to list + for(int i=0;itableClientCerts->currentRow(); + if(row == -1) + return; + + // Double check + if(QMessageBox::question(this, qApp->applicationName(), tr("Are you sure you want do remove this certificate? All certificate " + "data will be deleted from the application settings!"), + QMessageBox::Yes | QMessageBox::No, QMessageBox::No) == QMessageBox::Yes) + { + ui->tableClientCerts->removeRow(row); + } +} + +void PreferencesDialog::addClientCertToTable(const QString& path, const QSslCertificate& cert) +{ + // Do nothing if the file doesn't even exist + if(!QFile::exists(path)) + return; + + // Add new row + int row = ui->tableClientCerts->rowCount(); + ui->tableClientCerts->setRowCount(row + 1); + + // Fill row with data + QTableWidgetItem* cert_file = new QTableWidgetItem(path); + cert_file->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); + ui->tableClientCerts->setItem(row, 0, cert_file); + + QTableWidgetItem* cert_subject_cn = new QTableWidgetItem(cert.subjectInfo(QSslCertificate::CommonName).at(0)); + cert_subject_cn->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); + ui->tableClientCerts->setItem(row, 1, cert_subject_cn); + + QTableWidgetItem* cert_issuer_cn = new QTableWidgetItem(cert.issuerInfo(QSslCertificate::CommonName).at(0)); + cert_issuer_cn->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); + ui->tableClientCerts->setItem(row, 2, cert_issuer_cn); + + QTableWidgetItem* cert_from = new QTableWidgetItem(cert.effectiveDate().toString()); + cert_from->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); + ui->tableClientCerts->setItem(row, 3, cert_from); + + QTableWidgetItem* cert_to = new QTableWidgetItem(cert.expiryDate().toString()); + cert_to->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); + ui->tableClientCerts->setItem(row, 4, cert_to); + + QTableWidgetItem* cert_serialno = new QTableWidgetItem(QString(cert.serialNumber())); + cert_serialno->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); + ui->tableClientCerts->setItem(row, 5, cert_serialno); +} + +void PreferencesDialog::chooseRemoteCloneDirectory() +{ + QString s = FileDialog::getExistingDirectory( + NoSpecificType, + this, + tr("Choose a directory"), + QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks); + + if(!s.isEmpty() && QDir().mkpath(s)) + ui->editRemoteCloneDirectory->setText(s); +} + +void PreferencesDialog::updatePreviewFont() +{ + if (ui->spinDataBrowserFontSize->value() != 0) { + QFont textFont(ui->comboDataBrowserFont->currentText()); + textFont.setPointSize(ui->spinDataBrowserFontSize->value()); + ui->txtRegular->setFont(textFont); + textFont.setItalic(true); + ui->txtNull->setFont(textFont); + ui->txtBlob->setFont(textFont); + } +} + +void PreferencesDialog::on_buttonManageFileExtension_clicked() +{ + FileExtensionManager *manager = new FileExtensionManager(m_dbFileExtensions, this); + + if(manager->exec() == QDialog::Accepted) + { + m_dbFileExtensions = manager->getDBFileExtensions(); + } +} + +void PreferencesDialog::on_buttonBox_clicked(QAbstractButton* button) +{ + if (button == ui->buttonBox->button(QDialogButtonBox::Cancel)) + reject(); + else if (button == ui->buttonBox->button(QDialogButtonBox::Save)) + saveSettings(); + else if (button == ui->buttonBox->button(QDialogButtonBox::RestoreDefaults)) { + if (QMessageBox::warning(this, QApplication::applicationName(), tr("Are you sure you want to clear all the saved settings?\nAll your preferences will be lost and default values will be used."), + QMessageBox::RestoreDefaults | QMessageBox::Cancel, QMessageBox::Cancel) == QMessageBox::RestoreDefaults) + { + Settings::restoreDefaults(); + accept(); + } + } +} + +void PreferencesDialog::configureProxy() +{ + m_proxyDialog->show(); +} diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/PreferencesDialog.h b/src/WBCLFZSystemModule/SqliteDBProcess/src/PreferencesDialog.h new file mode 100644 index 0000000..cb6defd --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/PreferencesDialog.h @@ -0,0 +1,71 @@ +#ifndef PREFERENCESDIALOG_H +#define PREFERENCESDIALOG_H + +#include + +class QTreeWidgetItem; +class QFrame; +class QSslCertificate; +class QAbstractButton; + +class ProxyDialog; + +namespace Ui { +class PreferencesDialog; +} + +class PreferencesDialog : public QDialog +{ + Q_OBJECT + +public: + enum Tabs + { + TabGeneral, + TabDatabase, + TabDataBrowser, + TabSql, + TabExtensions, + TabRemote + }; + + explicit PreferencesDialog(QWidget* parent = nullptr, Tabs tab = TabGeneral); + ~PreferencesDialog() override; + +private slots: + void loadSettings(); + void saveSettings(); + + void chooseLocation(); + void showColourDialog(QTreeWidgetItem* item, int column); + void addExtension(); + void removeExtension(); + void activateRemoteTab(bool active); + void addClientCertificate(); + void removeClientCertificate(); + void chooseRemoteCloneDirectory(); + void updatePreviewFont(); + void adjustColorsToStyle(int style); + void configureProxy(); + + void on_buttonManageFileExtension_clicked(); + void on_buttonBox_clicked(QAbstractButton* button); + +private: + Ui::PreferencesDialog* ui; + + ProxyDialog* m_proxyDialog; + + QStringList m_dbFileExtensions; + + void fillLanguageBox(); + void loadColorSetting(QFrame *frame, const std::string& name); + void setColorSetting(QFrame* frame, const QColor &color); + void saveColorSetting(QFrame* frame, const std::string& name); + void addClientCertToTable(const QString& path, const QSslCertificate& cert); + +protected: + bool eventFilter(QObject *obj, QEvent *event) override; +}; + +#endif diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/PreferencesDialog.ui b/src/WBCLFZSystemModule/SqliteDBProcess/src/PreferencesDialog.ui new file mode 100644 index 0000000..7c8b405 --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/PreferencesDialog.ui @@ -0,0 +1,2172 @@ + + + PreferencesDialog + + + + 0 + 0 + 755 + 618 + + + + Preferences + + + true + + + + + + 0 + + + + &General + + + + + + Default &location + + + locationEdit + + + + + + + + + + Remember last location + + + + + Always use this location + + + + + Remember last location for session only + + + + + + + + + + false + + + + 0 + 0 + + + + + 316 + 0 + + + + + + + + ... + + + + + + + + + + + Lan&guage + + + languageComboBox + + + + + + + + 0 + 0 + + + + QComboBox::AdjustToContents + + + 35 + + + + 20 + 15 + + + + + + + + Toolbar style + + + toolbarStyleComboMain + + + + + + + + 0 + 0 + + + + 2 + + + QComboBox::AdjustToContents + + + 35 + + + + 20 + 15 + + + + + Only display the icon + + + + + Only display the text + + + + + The text appears beside the icon + + + + + The text appears under the icon + + + + + Follow the style + + + + + + + + + 0 + 0 + + + + 2 + + + QComboBox::AdjustToContents + + + 35 + + + + 20 + 15 + + + + + Only display the icon + + + + + Only display the text + + + + + The text appears beside the icon + + + + + The text appears under the icon + + + + + Follow the style + + + + + + + + + 0 + 0 + + + + 0 + + + QComboBox::AdjustToContents + + + 35 + + + + 20 + 15 + + + + + Only display the icon + + + + + Only display the text + + + + + The text appears beside the icon + + + + + The text appears under the icon + + + + + Follow the style + + + + + + + + + 0 + 0 + + + + 0 + + + QComboBox::AdjustToContents + + + 35 + + + + 20 + 15 + + + + + Only display the icon + + + + + Only display the text + + + + + The text appears beside the icon + + + + + The text appears under the icon + + + + + Follow the style + + + + + + + + Show remote options + + + checkUseRemotes + + + + + + + enabled + + + true + + + + + + + Automatic &updates + + + checkUpdates + + + + + + + enabled + + + + + + + DB file extensions + + + buttonManageFileExtension + + + + + + + Manage + + + + + + + Main Window + + + 20 + + + toolbarStyleComboMain + + + + + + + Database Structure + + + 20 + + + toolbarStyleComboStructure + + + + + + + Browse Data + + + 20 + + + toolbarStyleComboBrowse + + + + + + + Execute SQL + + + 20 + + + toolbarStyleComboSql + + + + + + + + 0 + 0 + + + + 0 + + + QComboBox::AdjustToContents + + + 35 + + + + 20 + 15 + + + + + Only display the icon + + + + + Only display the text + + + + + The text appears beside the icon + + + + + The text appears under the icon + + + + + Follow the style + + + + + + + + Edit Database Cell + + + 20 + + + toolbarStyleComboEditCell + + + + + + + + 0 + 0 + + + + When this value is changed, all the other color preferences are also set to matching colors. + + + 0 + + + QComboBox::AdjustToContents + + + 35 + + + + 20 + 15 + + + + + Follow the desktop style + + + + + Dark style + + + + + + + + Application style + + + toolbarStyleComboStructure + + + + + + + This sets the font size for all UI elements which do not have their own font size option. + + + Font size + + + spinGeneralFontSize + + + + + + + + + + + &Database + + + + + + QFormLayout::FieldsStayAtSizeHint + + + + + Database &encoding + + + encodingComboBox + + + + + + + Open databases with foreign keys enabled. + + + &Foreign keys + + + foreignKeysCheckBox + + + + + + + Remove line breaks in schema &view + + + checkHideSchemaLinebreaks + + + + + + + Prefetch block si&ze + + + spinPrefetchSize + + + + + + + Default field type + + + defaultFieldTypeComboBox + + + + + + + + + + 255 + + + 1000000 + + + + + + + When enabled, the line breaks in the Schema column of the DB Structure tab, dock and printed output are removed. + + + enabled + + + + + + + enabled + + + + + + + + UTF-8 + + + + + UTF-16 + + + + + + + + Database structure font size + + + spinStructureFontSize + + + + + + + + + + + + + + SQ&L to execute after opening database + + + editDatabaseDefaultSqlText + + + + + + + + 20 + 0 + + + + + 16777215 + 16777215 + + + + + + + + + + + Data &Browser + + + + + + + + Font + + + + + + &Font + + + comboDataBrowserFont + + + + + + + + + + Font si&ze + + + spinDataBrowserFontSize + + + + + + + + + + + + + Content + + + + + + Symbol limit in cell + + + spinSymbolLimit + + + + + + + + 0 + 0 + + + + 1 + + + 20000 + + + + + + + + 0 + 0 + + + + This is the maximum number of items allowed for some computationally expensive functionalities to be enabled: +Maximum number of rows in a table for enabling the value completion based on current values in the column. +Maximum number of indexes in a selection for calculating sum and average. +Can be set to 0 for disabling the functionalities. + + + This is the maximum number of rows in a table for enabling the value completion based on current values in the column. +Can be set to 0 for disabling completion. + + + 0 + + + 100000000 + + + + + + + Threshold for completion and calculation on selection + + + spinCompleteThreshold + + + + + + + Show images in cell + + + checkShowImagesInline + + + + + + + Enable this option to show a preview of BLOBs containing image data in the cells. This can affect the performance of the data browser, however. + + + + + + + + + + Field display + + + + + + Displayed &text + + + Qt::AlignCenter + + + txtNull + + + + + + + Binary + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + + + + + NULL + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + + + + + Regular + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + + + + + Qt::StrongFocus + + + Click to set this color + + + true + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + + + Text color + + + Qt::AlignCenter + + + + + + + Qt::StrongFocus + + + Click to set this color + + + true + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + + + Background color + + + Qt::AlignCenter + + + + + + + Qt::StrongFocus + + + Click to set this color + + + true + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + + + Qt::StrongFocus + + + Click to set this color + + + true + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + + + Qt::StrongFocus + + + Click to set this color + + + true + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + + + Qt::StrongFocus + + + Click to set this color + + + true + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + + + + 0 + 0 + + + + + true + + + + NULL + + + + + + + + 0 + 0 + + + + + false + + + + Preview only (N/A) + + + true + + + + + + + + 0 + 0 + + + + + true + + + + BLOB + + + false + + + + + + + + + + Filters + + + + + + 1 + + + + + + + Escape character + + + editFilterEscape + + + + + + + Delay time (&ms) + + + spinFilterDelay + + + + + + + Set the waiting time before a new filter value is applied. Can be set to 0 for disabling waiting. + + + 5000 + + + + + + + + + + + + + &SQL + + + + + + false + + + false + + + + Settings name + + + + + Context + + + + + Colour + + + + + Bold + + + + + Italic + + + + + Underline + + + + + keyword + + + Keyword + + + + + + + + + + + + + + + + + function + + + Function + + + + + table + + + Table + + + + + + + + + + + + + + + + + comment + + + Comment + + + + + + + + + + + + + + + + + identifier + + + Identifier + + + + + + + + + + + + + + + + + string + + + String + + + + + + + + + + + + + + + + + currentline + + + Current line + + + + + background + + + Background + + + + + foreground + + + Foreground + + + + + + + + + + SQL editor &font + + + comboEditorFont + + + + + + + + + + + + SQL &editor font size + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + spinEditorFontSize + + + + + + + 1 + + + + + + + + + SQL &results font size + + + spinLogFontSize + + + + + + + 1 + + + + + + + Tab size + + + spinTabSize + + + + + + + 1 + + + 16 + + + 4 + + + + + + + &Wrap lines + + + wrapComboBox + + + + + + + + Never + + + + + At word boundaries + + + + + At character boundaries + + + + + At whitespace boundaries + + + + + + + + &Quotes for identifiers + + + quoteComboBox + + + + + + + Choose the quoting mechanism used by the application for identifiers in SQL code. + + + + + + + "Double quotes" - Standard SQL (recommended) + + + + + `Grave accents` - Traditional MySQL quotes + + + + + [Square brackets] - Traditional MS SQL Server quotes + + + + + + + + Code co&mpletion + + + checkAutoCompletion + + + + + + + enabled + + + + + + + Keywords in &UPPER CASE + + + checkCompleteUpper + + + + + + + When set, the SQL keywords are completed in UPPER CASE letters. + + + enabled + + + + + + + Error indicators + + + checkErrorIndicators + + + + + + + When set, the SQL code lines that caused errors during the last execution are highlighted and the results frame indicates the error in the background + + + enabled + + + + + + + Hori&zontal tiling + + + checkHorizontalTiling + + + + + + + If enabled the SQL code editor and the result table view are shown side by side instead of one over the other. + + + enabled + + + + + + + Close button on tabs + + + checkCloseButtonOnTabs + + + + + + + If enabled, SQL editor tabs will have a close button. In any case, you can use the contextual menu or the keyboard shortcut to close them. + + + enabled + + + + + + + + + + &Extensions + + + + + + Select extensions to load for every database: + + + + + + + + + QAbstractItemView::NoEditTriggers + + + false + + + + + + + + + Add extension + + + + :/icons/load_extension:/icons/load_extension + + + + + + + Remove extension + + + + :/icons/remove_extension:/icons/remove_extension + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + <html><head/><body><p>While supporting the REGEXP operator SQLite doesn't implement any regular expression<br/>algorithm but calls back the running application. DB Browser for SQLite implements this<br/>algorithm for you to let you use REGEXP out of the box. However, as there are multiple possible<br/>implementations of this and you might want to use another one, you're free to disable the<br/>application's implementation and load your own by using an extension. Requires restart of the application.</p></body></html> + + + Disable Regular Expression extension + + + + + + + <html><head/><body><p>SQLite provides an SQL function for loading extensions from a shared library file. Activate this if you want to use the <span style=" font-style:italic;">load_extension()</span> function from SQL code.</p><p>For security reasons, extension loading is turned off by default and must be enabled through this setting. You can always load extensions through the GUI, even though this option is disabled.</p></body></html> + + + Allow loading extensions from SQL code + + + + + + + + Remote + + + + + + 0 + + + + Your certificates + + + + + + + 550 + 0 + + + + QAbstractItemView::ExtendedSelection + + + QAbstractItemView::SelectRows + + + QAbstractItemView::ScrollPerPixel + + + false + + + + File + + + + + Subject CN + + + Subject Common Name + + + + + Issuer CN + + + Issuer Common Name + + + + + Valid from + + + + + Valid to + + + + + Serial number + + + + + + + + + + + :/icons/trigger_create:/icons/trigger_create + + + + + + + ... + + + + :/icons/trigger_delete:/icons/trigger_delete + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + CA certificates + + + + + + + 550 + 0 + + + + QAbstractItemView::SingleSelection + + + QAbstractItemView::SelectRows + + + QAbstractItemView::ScrollPerPixel + + + false + + + + Subject CN + + + Common Name + + + + + Subject O + + + Organization + + + + + Valid from + + + + + Valid to + + + + + Serial number + + + + + + + + + + + + + + Clone databases into + + + + + + + + + false + + + + 0 + 0 + + + + + 316 + 0 + + + + + + + + ... + + + + + + + + + Proxy + + + + + + + Configure + + + + + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::RestoreDefaults|QDialogButtonBox::Save + + + + + + + + SqlTextEdit + QTextEdit +
sqltextedit.h
+ 1 +
+
+ + tabWidget + comboDefaultLocation + locationEdit + setLocationButton + languageComboBox + appStyleCombo + spinGeneralFontSize + toolbarStyleComboMain + toolbarStyleComboStructure + toolbarStyleComboBrowse + toolbarStyleComboSql + toolbarStyleComboEditCell + checkUseRemotes + checkUpdates + buttonManageFileExtension + encodingComboBox + foreignKeysCheckBox + checkHideSchemaLinebreaks + spinPrefetchSize + defaultFieldTypeComboBox + spinStructureFontSize + comboDataBrowserFont + spinDataBrowserFontSize + spinSymbolLimit + spinCompleteThreshold + checkShowImagesInline + fr_null_fg + fr_null_bg + txtNull + fr_bin_fg + fr_bin_bg + txtBlob + fr_reg_fg + fr_reg_bg + txtRegular + spinFilterDelay + editFilterEscape + treeSyntaxHighlighting + comboEditorFont + spinEditorFontSize + spinLogFontSize + spinTabSize + wrapComboBox + quoteComboBox + checkAutoCompletion + checkCompleteUpper + checkErrorIndicators + checkHorizontalTiling + checkCloseButtonOnTabs + listExtensions + buttonAddExtension + buttonRemoveExtension + checkRegexDisabled + checkAllowLoadExtension + tabCertificates + tableClientCerts + buttonClientCertAdd + buttonClientCertRemove + buttonProxy + editRemoteCloneDirectory + buttonRemoteBrowseCloneDirectory + tableCaCerts + + + + + + + buttonAddExtension + clicked() + PreferencesDialog + addExtension() + + + 732 + 96 + + + 245 + 137 + + + + + buttonRemoveExtension + clicked() + PreferencesDialog + removeExtension() + + + 732 + 125 + + + 245 + 137 + + + + + treeSyntaxHighlighting + itemDoubleClicked(QTreeWidgetItem*,int) + PreferencesDialog + showColourDialog(QTreeWidgetItem*,int) + + + 103 + 48 + + + 395 + 0 + + + + + setLocationButton + clicked() + PreferencesDialog + chooseLocation() + + + 732 + 106 + + + 294 + 202 + + + + + checkUseRemotes + toggled(bool) + PreferencesDialog + activateRemoteTab(bool) + + + 301 + 503 + + + 382 + 572 + + + + + buttonClientCertAdd + clicked() + PreferencesDialog + addClientCertificate() + + + 722 + 110 + + + 596 + 243 + + + + + buttonClientCertRemove + clicked() + PreferencesDialog + removeClientCertificate() + + + 722 + 139 + + + 597 + 295 + + + + + buttonRemoteBrowseCloneDirectory + clicked() + PreferencesDialog + chooseRemoteCloneDirectory() + + + 732 + 538 + + + 595 + 41 + + + + + checkAutoCompletion + toggled(bool) + checkCompleteUpper + setEnabled(bool) + + + 733 + 444 + + + 733 + 474 + + + + + buttonBox + clicked(QAbstractButton*) + PreferencesDialog + on_buttonBox_clicked(QAbstractButton*) + + + 394 + 584 + + + 385 + 306 + + + + + buttonProxy + clicked() + PreferencesDialog + configureProxy() + + + 225 + 506 + + + 385 + 306 + + + + + + saveSettings() + chooseLocation() + showColourDialog(QTreeWidgetItem*,int) + addExtension() + removeExtension() + activateRemoteTab(bool) + addClientCertificate() + removeClientCertificate() + chooseRemoteCloneDirectory() + configureProxy() + +
diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/ProxyDialog.cpp b/src/WBCLFZSystemModule/SqliteDBProcess/src/ProxyDialog.cpp new file mode 100644 index 0000000..c9e8b63 --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/ProxyDialog.cpp @@ -0,0 +1,57 @@ +#include "ProxyDialog.h" +#include "ui_ProxyDialog.h" +#include "Settings.h" + +ProxyDialog::ProxyDialog(QWidget *parent) : + QDialog(parent), + ui(new Ui::ProxyDialog) +{ + ui->setupUi(this); + + // Add different proxy types. We use user data strings for addressing them later + ui->comboType->addItem(tr("None"), "none"); + ui->comboType->addItem(tr("System settings"), "system"); + ui->comboType->addItem(tr("HTTP"), "http"); + ui->comboType->addItem(tr("Socks v5"), "socks5"); + + // Load current settings + ui->comboType->setCurrentIndex(ui->comboType->findData(Settings::getValue("proxy", "type").toString())); + ui->editHost->setText(Settings::getValue("proxy", "host").toString()); + ui->spinPort->setValue(Settings::getValue("proxy", "port").toInt()); + ui->checkAuthentication->setChecked(Settings::getValue("proxy", "authentication").toBool()); + ui->editUser->setText(Settings::getValue("proxy", "user").toString()); + ui->editPassword->setText(Settings::getValue("proxy", "password").toString()); +} + +ProxyDialog::~ProxyDialog() +{ + delete ui; +} + +void ProxyDialog::proxyTypeChanged(int /*new_index*/) +{ + // When selecting the "None" or "System settings" proxy types, disable all the other input fields + bool proxy_configuration = (ui->comboType->currentData() != "none" && ui->comboType->currentData() != "system"); + + ui->editHost->setEnabled(proxy_configuration); + ui->spinPort->setEnabled(proxy_configuration); + ui->checkAuthentication->setEnabled(proxy_configuration); + ui->editUser->setEnabled(ui->checkAuthentication->isChecked() && proxy_configuration); // Enable user name and password only if the... + ui->editPassword->setEnabled(ui->checkAuthentication->isChecked() && proxy_configuration); // ... Authentication Required checkbox is checked +} + +void ProxyDialog::authenticationRequiredChanged(bool required) +{ + ui->editUser->setEnabled(required); + ui->editPassword->setEnabled(required); +} + +void ProxyDialog::saveSettings() const +{ + Settings::setValue("proxy", "type", ui->comboType->currentData()); + Settings::setValue("proxy", "host", ui->editHost->text()); + Settings::setValue("proxy", "port", ui->spinPort->value()); + Settings::setValue("proxy", "authentication", ui->checkAuthentication->isChecked()); + Settings::setValue("proxy", "user", ui->editUser->text()); + Settings::setValue("proxy", "password", ui->editPassword->text()); +} diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/ProxyDialog.h b/src/WBCLFZSystemModule/SqliteDBProcess/src/ProxyDialog.h new file mode 100644 index 0000000..bdc5c03 --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/ProxyDialog.h @@ -0,0 +1,28 @@ +#ifndef PROXYDIALOG_H +#define PROXYDIALOG_H + +#include + +namespace Ui { +class ProxyDialog; +} + +class ProxyDialog : public QDialog +{ + Q_OBJECT + +public: + explicit ProxyDialog(QWidget* parent = nullptr); + ~ProxyDialog(); + + void saveSettings() const; + +private slots: + void proxyTypeChanged(int new_index); + void authenticationRequiredChanged(bool required); + +private: + Ui::ProxyDialog* ui; +}; + +#endif diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/ProxyDialog.ui b/src/WBCLFZSystemModule/SqliteDBProcess/src/ProxyDialog.ui new file mode 100644 index 0000000..2437e60 --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/ProxyDialog.ui @@ -0,0 +1,201 @@ + + + ProxyDialog + + + + 0 + 0 + 535 + 231 + + + + Proxy Configuration + + + + + + + + Pro&xy Type + + + comboType + + + + + + + + + + Host Na&me + + + editHost + + + + + + + + + + Port + + + spinPort + + + + + + + 1 + + + 65536 + + + + + + + Authentication Re&quired + + + checkAuthentication + + + + + + + + + + &User Name + + + editUser + + + + + + + + + + Password + + + editPassword + + + + + + + QLineEdit::Password + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + comboType + editHost + spinPort + checkAuthentication + editUser + editPassword + + + + + buttonBox + accepted() + ProxyDialog + accept() + + + 227 + 210 + + + 157 + 230 + + + + + buttonBox + rejected() + ProxyDialog + reject() + + + 295 + 216 + + + 286 + 230 + + + + + comboType + currentIndexChanged(int) + ProxyDialog + proxyTypeChanged(int) + + + 343 + 22 + + + 267 + 115 + + + + + checkAuthentication + toggled(bool) + ProxyDialog + authenticationRequiredChanged(bool) + + + 343 + 114 + + + 267 + 115 + + + + + + proxyTypeChanged(int) + authenticationRequiredChanged(bool) + + diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/RemoteCommitsModel.cpp b/src/WBCLFZSystemModule/SqliteDBProcess/src/RemoteCommitsModel.cpp new file mode 100644 index 0000000..578daa6 --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/RemoteCommitsModel.cpp @@ -0,0 +1,171 @@ +#include + +#include "Data.h" +#include "RemoteCommitsModel.h" +#include "Settings.h" + +using json = nlohmann::json; + +RemoteCommitsModel::RemoteCommitsModel(QObject* parent) : + QAbstractItemModel(parent) +{ + QStringList header; + header << tr("Commit ID") << tr("Message") << tr("Date") << tr("Author") << tr("Size"); + rootItem = new QTreeWidgetItem(header); +} + +RemoteCommitsModel::~RemoteCommitsModel() +{ + delete rootItem; +} + +void RemoteCommitsModel::clear() +{ + beginResetModel(); + + // Remove all data except for the root item + while(rootItem->childCount()) + delete rootItem->child(0); + + endResetModel(); +} + +void RemoteCommitsModel::refresh(const std::string& json_data, const std::string& last_commit_id, const std::string& current_commit_id) +{ + // Clear previous items + clear(); + beginResetModel(); + + // Read in all commits + json j = json::parse(json_data, nullptr, false); + std::unordered_map commit_to_iterator; + for(auto it=j.begin();it!=j.end();++it) + commit_to_iterator.insert({it.value()["id"], it}); + + // Starting from the last commit add follow the chain up to the first commit + std::string parent_id = last_commit_id; + while(true) + { + if(commit_to_iterator.find(parent_id) == commit_to_iterator.end()) + break; + + json commit = commit_to_iterator[parent_id].value(); + + QTreeWidgetItem* item = new QTreeWidgetItem(rootItem); + item->setText(ColumnCommitId, QString::fromStdString(commit["id"])); + item->setText(ColumnMessage, QString::fromStdString(commit["message"])); + item->setToolTip(ColumnMessage, QString::fromStdString(commit["message"])); + + item->setText(ColumnDate, isoDateTimeStringToLocalDateTimeString(QString::fromStdString(commit["timestamp"]))); + + QString authored_by = QString::fromStdString(commit["author_name"]) + " <" + QString::fromStdString(commit["author_email"]) + ">"; + QString committed_by = QString::fromStdString(commit["committer_name"]) + " <" + QString::fromStdString(commit["committer_email"]) + ">"; + item->setText(ColumnAuthor, authored_by); + if(committed_by == " <>" || authored_by == committed_by) // The first check effectively checks for no committer details + item->setToolTip(ColumnAuthor, tr("Authored and committed by %1").arg(authored_by)); + else + item->setToolTip(ColumnAuthor, tr("Authored by %1, committed by %2").arg(authored_by, committed_by)); + + for(const auto& e : commit["tree"]["entries"]) + { + if(e["entry_type"] == "db") + { + item->setText(ColumnSize, humanReadableSize(e["size"])); + break; + } + } + + // Make the currently checked out commit id bold + if(current_commit_id == commit["id"]) + { + QFont bold_font = item->font(ColumnCommitId); + bold_font.setBold(true); + item->setFont(0, bold_font); + } + + parent_id = QString::fromStdString(commit["parent"]).toStdString(); + } + + // Refresh the view + endResetModel(); +} + +QModelIndex RemoteCommitsModel::index(int row, int column, const QModelIndex& parent) const +{ + if(!hasIndex(row, column, parent)) + return QModelIndex(); + + QTreeWidgetItem *parentItem; + if(!parent.isValid()) + parentItem = rootItem; + else + parentItem = static_cast(parent.internalPointer()); + + QTreeWidgetItem* childItem = parentItem->child(row); + if(childItem) + return createIndex(row, column, childItem); + else + return QModelIndex(); +} + +QModelIndex RemoteCommitsModel::parent(const QModelIndex& index) const +{ + if(!index.isValid()) + return QModelIndex(); + + QTreeWidgetItem* childItem = static_cast(index.internalPointer()); + QTreeWidgetItem* parentItem = childItem->parent(); + + if(parentItem == rootItem) + return QModelIndex(); + else + return createIndex(0, 0, parentItem); +} + +QVariant RemoteCommitsModel::data(const QModelIndex& index, int role) const +{ + if(!index.isValid()) + return QVariant(); + + // Get the item the index points at + QTreeWidgetItem* item = static_cast(index.internalPointer()); + + // Return data depending on the role + switch(role) + { + case Qt::DisplayRole: + case Qt::EditRole: + return item->text(index.column()); + case Qt::ToolTipRole: + return item->toolTip(index.column()); + case Qt::FontRole: + return item->font(0); // Choose font for the entire row depending on the first column + default: + return QVariant(); + } +} + +QVariant RemoteCommitsModel::headerData(int section, Qt::Orientation orientation, int role) const +{ + // Get the header string from the root item + if(orientation == Qt::Horizontal && role == Qt::DisplayRole) + return rootItem->data(section, role); + + return QVariant(); +} + +int RemoteCommitsModel::rowCount(const QModelIndex& parent) const +{ + if(parent.column() > 0) + return 0; + + if(!parent.isValid()) + return rootItem->childCount(); + else + return static_cast(parent.internalPointer())->childCount(); +} + +int RemoteCommitsModel::columnCount(const QModelIndex& /*parent*/) const +{ + return rootItem->columnCount(); +} diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/RemoteCommitsModel.h b/src/WBCLFZSystemModule/SqliteDBProcess/src/RemoteCommitsModel.h new file mode 100644 index 0000000..d2b540c --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/RemoteCommitsModel.h @@ -0,0 +1,44 @@ +#ifndef REMOTECOMMITSMODEL_H +#define REMOTECOMMITSMODEL_H + +#include + +#include + +class QTreeWidgetItem; + +class RemoteCommitsModel : public QAbstractItemModel +{ + Q_OBJECT + +public: + explicit RemoteCommitsModel(QObject* parent); + ~RemoteCommitsModel() override; + + void clear(); + void refresh(const std::string& json_data, const std::string& last_commit_id, const std::string& current_commit_id); + + QModelIndex index(int row, int column,const QModelIndex& parent = QModelIndex()) const override; + QModelIndex parent(const QModelIndex& index) const override; + + QVariant data(const QModelIndex& index, int role) const override; + QVariant headerData(int section, Qt::Orientation orientation, int role) const override; + + int rowCount(const QModelIndex& parent = QModelIndex()) const override; + int columnCount(const QModelIndex& parent = QModelIndex()) const override; + + enum Columns + { + ColumnCommitId, + ColumnMessage, + ColumnDate, + ColumnAuthor, + ColumnSize, + }; + +private: + // Pointer to the root item. This contains all the actual item data. + QTreeWidgetItem* rootItem; +}; + +#endif diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/RemoteDatabase.cpp b/src/WBCLFZSystemModule/SqliteDBProcess/src/RemoteDatabase.cpp new file mode 100644 index 0000000..06d5647 --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/RemoteDatabase.cpp @@ -0,0 +1,432 @@ +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "FileDialog.h" +#include "RemoteDatabase.h" +#include "Settings.h" +#include "sqlite.h" +#include "version.h" + +RemoteDatabase::RemoteDatabase() : + m_dbLocal(nullptr) +{ +} + +RemoteDatabase::~RemoteDatabase() +{ + // Close local storage db - but only if it was created/opened in the meantime + if(m_dbLocal) + sqlite3_close(m_dbLocal); +} + +void RemoteDatabase::localAssureOpened() +{ + // This function should be called first in each RemoteDatabase::local* function. It assures the database for storing + // the local database information is opened and ready. If the database file doesn't exist yet it is created by this + // function. If the database file is already created and opened this function does nothing. The reason to open the + // database on first use instead of doing that in the constructor of this class is that this way no database file is + // going to be created and no database handle is held when it's not actually needed. For people not interested in + // the dbhub.io functionality this means no unnecessary files being created. + + // Check if database is already opened and return if it is + if(m_dbLocal) + return; + + // Make sure the directory exists + QString database_directory = QStandardPaths::writableLocation( +#if QT_VERSION >= QT_VERSION_CHECK(5, 4, 0) + QStandardPaths::AppDataLocation +#else + QStandardPaths::GenericDataLocation +#endif + ); + QDir().mkpath(database_directory); + + // Open file + QString database_file = database_directory + "/remotedbs.db"; + if(sqlite3_open_v2(database_file.toUtf8(), &m_dbLocal, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, nullptr) != SQLITE_OK) + { + QMessageBox::warning(nullptr, qApp->applicationName(), tr("Error opening local databases list.\n%1").arg(QString::fromUtf8(sqlite3_errmsg(m_dbLocal)))); + return; + } + + // Create local local table if it doesn't exists yet + char* errmsg; + QString statement = QString("CREATE TABLE IF NOT EXISTS \"local\"(" + "\"id\" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT," + "\"identity\" TEXT NOT NULL," + "\"name\" TEXT NOT NULL," + "\"url\" TEXT NOT NULL," + "\"commit_id\" TEXT NOT NULL," + "\"file\" TEXT NOT NULL UNIQUE," + "\"modified\" INTEGER DEFAULT 0," + "\"branch\" TEXT NOT NULL DEFAULT \"master\"" + ")"); + if(sqlite3_exec(m_dbLocal, statement.toUtf8(), nullptr, nullptr, &errmsg) != SQLITE_OK) + { + QMessageBox::warning(nullptr, qApp->applicationName(), tr("Error creating local databases list.\n%1").arg(QString::fromUtf8(errmsg))); + sqlite3_free(errmsg); + sqlite3_close(m_dbLocal); + m_dbLocal = nullptr; + return; + } +} + +QString RemoteDatabase::localAdd(QString filename, QString identity, const QUrl& url, const std::string& new_commit_id, const std::string& branch) +{ + localAssureOpened(); + + // Remove the path + QFileInfo f(identity); + identity = f.fileName(); + + // Check if this file has already been checked in + std::string last_commit_id = localLastCommitId(identity, url.toString(), branch); + if(last_commit_id.empty()) + { + // The file hasn't been checked in yet. So add a new record for it. + + // Generate a new file name to save the file under + filename = QString("%2_%1.remotedb").arg(QDateTime::currentMSecsSinceEpoch()).arg(filename); + + // Insert database into local database list + QString sql = QString("INSERT INTO local(identity, name, url, commit_id, file, branch) VALUES(?, ?, ?, ?, ?, ?)"); + sqlite3_stmt* stmt; + if(sqlite3_prepare_v2(m_dbLocal, sql.toUtf8(), -1, &stmt, nullptr) != SQLITE_OK) + return QString(); + + if(sqlite3_bind_text(stmt, 1, identity.toUtf8(), identity.toUtf8().length(), SQLITE_TRANSIENT)) + { + sqlite3_finalize(stmt); + return QString(); + } + + if(sqlite3_bind_text(stmt, 2, url.fileName().toUtf8(), url.fileName().toUtf8().length(), SQLITE_TRANSIENT)) + { + sqlite3_finalize(stmt); + return QString(); + } + + if(sqlite3_bind_text(stmt, 3, url.toString(QUrl::PrettyDecoded | QUrl::RemoveQuery).toUtf8(), + url.toString(QUrl::PrettyDecoded | QUrl::RemoveQuery).toUtf8().length(), SQLITE_TRANSIENT)) + { + sqlite3_finalize(stmt); + return QString(); + } + + if(sqlite3_bind_text(stmt, 4, new_commit_id.c_str(), static_cast(new_commit_id.size()), SQLITE_TRANSIENT)) + { + sqlite3_finalize(stmt); + return QString(); + } + + if(sqlite3_bind_text(stmt, 5, filename.toUtf8(), filename.size(), SQLITE_TRANSIENT)) + { + sqlite3_finalize(stmt); + return QString(); + } + + if(sqlite3_bind_text(stmt, 6, branch.c_str(), static_cast(branch.size()), SQLITE_TRANSIENT)) + { + sqlite3_finalize(stmt); + return QString(); + } + + if(sqlite3_step(stmt) != SQLITE_DONE) + { + sqlite3_finalize(stmt); + return QString(); + } + + sqlite3_finalize(stmt); + + // Return full path to the new file + return Settings::getValue("remote", "clonedirectory").toString() + "/" + filename; + } + + // If we get here, the file has been checked in before. Check next if it has been updated in the meantime. + if(last_commit_id != new_commit_id) + { + // The file has already been checked in and the commit ids are different. If they weren't we wouldn't need to update anything + + QString sql = QString("UPDATE local SET commit_id=? WHERE identity=? AND url=? AND branch=?"); + sqlite3_stmt* stmt; + if(sqlite3_prepare_v2(m_dbLocal, sql.toUtf8(), -1, &stmt, nullptr) != SQLITE_OK) + return QString(); + + if(sqlite3_bind_text(stmt, 1, new_commit_id.c_str(), static_cast(new_commit_id.size()), SQLITE_TRANSIENT)) + { + sqlite3_finalize(stmt); + return QString(); + } + + if(sqlite3_bind_text(stmt, 2, identity.toUtf8(), identity.toUtf8().length(), SQLITE_TRANSIENT)) + { + sqlite3_finalize(stmt); + return QString(); + } + + if(sqlite3_bind_text(stmt, 3, url.toString(QUrl::PrettyDecoded | QUrl::RemoveQuery).toUtf8(), + url.toString(QUrl::PrettyDecoded | QUrl::RemoveQuery).toUtf8().length(), SQLITE_TRANSIENT)) + { + sqlite3_finalize(stmt); + return QString(); + } + + if(sqlite3_bind_text(stmt, 4, branch.c_str(), static_cast(branch.size()), SQLITE_TRANSIENT)) + { + sqlite3_finalize(stmt); + return QString(); + } + + if(sqlite3_step(stmt) != SQLITE_DONE) + { + sqlite3_finalize(stmt); + return QString(); + } + + sqlite3_finalize(stmt); + } + + // If we got here, the file was already checked in (and was either updated or not (obviously)). This mean we can just return the file name as + // we know it. + return localExists(url, identity, branch); +} + +QString RemoteDatabase::localExists(const QUrl& url, QString identity, const std::string& branch) +{ + localAssureOpened(); + + // Extract commit id from url and remove query part afterwards + QString url_commit_id = QUrlQuery(url).queryItemValue("commit"); + + // Query commit id and filename for the given combination of url and identity + QString sql = QString("SELECT id, commit_id, file FROM local WHERE url=? AND identity=? AND branch=?"); + sqlite3_stmt* stmt; + if(sqlite3_prepare_v2(m_dbLocal, sql.toUtf8(), -1, &stmt, nullptr) != SQLITE_OK) + return QString(); + + if(sqlite3_bind_text(stmt, 1, url.toString(QUrl::PrettyDecoded | QUrl::RemoveQuery).toUtf8(), url.toString(QUrl::PrettyDecoded | QUrl::RemoveQuery).toUtf8().length(), SQLITE_TRANSIENT)) + { + sqlite3_finalize(stmt); + return QString(); + } + + QFileInfo f(identity); // Remove the path + identity = f.fileName(); + if(sqlite3_bind_text(stmt, 2, identity.toUtf8(), identity.toUtf8().length(), SQLITE_TRANSIENT)) + { + sqlite3_finalize(stmt); + return QString(); + } + + if(sqlite3_bind_text(stmt, 3, branch.c_str(), static_cast(branch.size()), SQLITE_TRANSIENT)) + { + sqlite3_finalize(stmt); + return QString(); + } + + if(sqlite3_step(stmt) != SQLITE_ROW) + { + // If there was either an error or no record was found for this combination of url and + // identity, stop here. + sqlite3_finalize(stmt); + return QString(); + } + + // Having come here we can assume that at least some local clone for the given combination of + // url, identity and branch exists. So extract all the information we have on it. + QString local_commit_id = QString::fromUtf8(reinterpret_cast(sqlite3_column_text(stmt, 1))); + QString local_file = QString::fromUtf8(reinterpret_cast(sqlite3_column_text(stmt, 2))); + sqlite3_finalize(stmt); + + // There are three possibilities now: either we didn't get any commit id in the URL in which case we just return the file we got, no matter what. + // Or the requested commit id is the same as the local commit id in which case we return the file we got as well. + // Or the requested commit id differ in which case we return no match. + if(url_commit_id.isNull() || local_commit_id == url_commit_id) + { + // Both commit ids are the same. That's the perfect match, so we can open the local file if it still exists + return localCheckFile(local_file); + } else { + // The commit ids differ. This means we have no match + return QString(); + } +} + +QString RemoteDatabase::localCheckFile(const QString& local_file) +{ + // This function takes the file name of a locally cloned database and checks if this file still exists. If it has been deleted in the meantime it returns + // an empty string and deletes the file from the clone database. If the file still exists, it returns the full path to the file. + + localAssureOpened(); + + // Build the full path to where the file should be + QString full_path = Settings::getValue("remote", "clonedirectory").toString() + "/" + local_file; + + // Check if the database still exists. If so return its path, if not return an empty string to redownload it + if(QFile::exists(full_path)) + { + return full_path; + } else { + // Remove the apparently invalid entry from the local clones database to avoid future lookups and confusions. The file column should + // be unique for the entire table because the files are all in the same directory and their names need to be unique because of this. + localDeleteFile(local_file); + + // Return empty string to indicate a redownload request + return QString(); + } +} + +std::string RemoteDatabase::localLastCommitId(QString identity, const QUrl& url, const std::string& branch) +{ + localAssureOpened(); + + // Query commit id for that file name + QString sql = QString("SELECT commit_id FROM local WHERE identity=? AND url=? AND branch=?"); + sqlite3_stmt* stmt; + if(sqlite3_prepare_v2(m_dbLocal, sql.toUtf8(), -1, &stmt, nullptr) != SQLITE_OK) + return std::string(); + + QFileInfo f(identity); // Remove the path + identity = f.fileName(); + if(sqlite3_bind_text(stmt, 1, identity.toUtf8(), identity.toUtf8().length(), SQLITE_TRANSIENT)) + { + sqlite3_finalize(stmt); + return std::string(); + } + + if(sqlite3_bind_text(stmt, 2, url.toString(QUrl::PrettyDecoded | QUrl::RemoveQuery).toUtf8(), + url.toString(QUrl::PrettyDecoded | QUrl::RemoveQuery).toUtf8().size(), SQLITE_TRANSIENT)) + { + sqlite3_finalize(stmt); + return std::string(); + } + + if(sqlite3_bind_text(stmt, 3, branch.c_str(), static_cast(branch.size()), SQLITE_TRANSIENT)) + { + sqlite3_finalize(stmt); + return std::string(); + } + + if(sqlite3_step(stmt) != SQLITE_ROW) + { + // If there was either an error or no record was found for this file name, stop here. + sqlite3_finalize(stmt); + return std::string(); + } + + // Having come here we can assume that at least some local clone with the given file name + std::string local_commit_id = reinterpret_cast(sqlite3_column_text(stmt, 0)); + sqlite3_finalize(stmt); + + return local_commit_id; +} + +std::vector RemoteDatabase::localGetLocalFiles(QString identity) +{ + localAssureOpened(); + + // Get all rows for this identity + QString sql = QString("SELECT name, url, commit_id, file, branch FROM local WHERE identity=? ORDER BY url"); + sqlite3_stmt* stmt; + if(sqlite3_prepare_v2(m_dbLocal, sql.toUtf8(), -1, &stmt, nullptr) != SQLITE_OK) + return {}; + + QFileInfo f(identity); + identity = f.fileName(); + if(sqlite3_bind_text(stmt, 1, identity.toUtf8(), identity.toUtf8().length(), SQLITE_TRANSIENT)) + { + sqlite3_finalize(stmt); + return {}; + } + + std::vector result; + while(sqlite3_step(stmt) == SQLITE_ROW) + { + result.emplace_back(reinterpret_cast(sqlite3_column_text(stmt, 0)), + reinterpret_cast(sqlite3_column_text(stmt, 1)), + reinterpret_cast(sqlite3_column_text(stmt, 2)), + reinterpret_cast(sqlite3_column_text(stmt, 3)), + reinterpret_cast(sqlite3_column_text(stmt, 4)), + identity.toStdString()); + } + + sqlite3_finalize(stmt); + return result; +} + +RemoteDatabase::LocalFileInfo RemoteDatabase::localGetLocalFileInfo(QString filename) +{ + localAssureOpened(); + + // Find this file in our database + QString sql = QString("SELECT name, url, commit_id, branch, identity FROM local WHERE file=?"); + sqlite3_stmt* stmt; + if(sqlite3_prepare_v2(m_dbLocal, sql.toUtf8(), -1, &stmt, nullptr) != SQLITE_OK) + return {}; + + // Remove the path for querying the file name + filename = QFileInfo(filename).fileName(); + if(sqlite3_bind_text(stmt, 1, filename.toUtf8(), filename.toUtf8().length(), SQLITE_TRANSIENT)) + { + sqlite3_finalize(stmt); + return {}; + } + + if(sqlite3_step(stmt) != SQLITE_ROW) + { + // If there was either an error or no record was found for this file name, stop here. + sqlite3_finalize(stmt); + return {}; + } + + // Retrieve and return all the information we have + RemoteDatabase::LocalFileInfo result(reinterpret_cast(sqlite3_column_text(stmt, 0)), + reinterpret_cast(sqlite3_column_text(stmt, 1)), + reinterpret_cast(sqlite3_column_text(stmt, 2)), + filename.toStdString(), + reinterpret_cast(sqlite3_column_text(stmt, 3)), + reinterpret_cast(sqlite3_column_text(stmt, 4))); + sqlite3_finalize(stmt); + return result; +} + +void RemoteDatabase::localDeleteFile(QString filename) +{ + localAssureOpened(); + + // Remove the file's entry in our database + QString sql = QString("DELETE FROM local WHERE file=?"); + sqlite3_stmt* stmt; + if(sqlite3_prepare_v2(m_dbLocal, sql.toUtf8(), -1, &stmt, nullptr) != SQLITE_OK) + return; + if(sqlite3_bind_text(stmt, 1, filename.toUtf8(), filename.toUtf8().length(), SQLITE_TRANSIENT)) + { + sqlite3_finalize(stmt); + return; + } + sqlite3_step(stmt); + sqlite3_finalize(stmt); + + // Delete the actual file on disk + QFile::remove(Settings::getValue("remote", "clonedirectory").toString() + "/" + filename); +} + +QString RemoteDatabase::LocalFileInfo::user_name() const +{ + // Figure out the user name from the URL + + QString path = QUrl(QString::fromStdString(url)).path(); + + if(path.count('/') < 2 || !path.startsWith('/')) + return QString(); + else + return path.mid(1, path.indexOf('/', 1) - 1); +} diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/RemoteDatabase.h b/src/WBCLFZSystemModule/SqliteDBProcess/src/RemoteDatabase.h new file mode 100644 index 0000000..c60f454 --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/RemoteDatabase.h @@ -0,0 +1,86 @@ +#ifndef REMOTEDATABASE_H +#define REMOTEDATABASE_H + +#include +#include + +#include + +struct sqlite3; + +class RemoteDatabase : public QObject +{ + Q_OBJECT + +public: + RemoteDatabase(); + ~RemoteDatabase() override; + + // This class compiles all the information on a lcao database file + class LocalFileInfo + { + public: + LocalFileInfo() + {} + + LocalFileInfo(const std::string& _name, + const std::string& _url, + const std::string& _commit_id, + const std::string& _file, + const std::string& _branch, + const std::string& _identity) : + name(_name), + url(_url), + commit_id(_commit_id), + file(_file), + branch(_branch), + identity(_identity) + {} + + void clear() { name = url = commit_id = file = branch = identity = {}; } + QString user_name() const; + + std::string name; // Database name + std::string url; // URL for cloning + std::string commit_id; // Commit ID at the time of the cloning + std::string file; // Name of the local file on disk + std::string branch; // Cloned branch + std::string identity; // Identity used for cloning + }; + + // Return a list of all checked out databases for a given identity + std::vector localGetLocalFiles(QString identity); + + // Return information on a single file + LocalFileInfo localGetLocalFileInfo(QString filename); + + // Delete a local database clone + void localDeleteFile(QString filename); + + // This function checks if there already is a clone for the given combination of url and identity. It returns the filename + // of this clone if there is or a null string if there isn't a clone yet. The identity needs to be part of this check because + // with the url alone there could be corner cases where different versions or whatever may not be accessible for all users. + // If the URL contains a commit id (optional), this commit id is part of the check. + QString localExists(const QUrl& url, QString identity, const std::string& branch); + + // This function takes a file name and checks with which commit id we had checked out this file or last pushed it. + std::string localLastCommitId(QString clientCert, const QUrl& url, const std::string& branch); + + // This function adds a new local database clone to our internal list. It does so by adding a single + // new record to the remote dbs database. All the fields are extracted from the filename, the identity + // and (most importantly) the url parameters. Note that for the commit id field to be correctly filled we + // require the commit id to be part of the url parameter. Also note that this function doesn't care if the + // database has already been added to the list or not. If you need this information you need to check it before + // calling this function, ideally even before sending out a request to the network. The function returns the full + // path of the newly created/updated file. + QString localAdd(QString filename, QString identity, const QUrl& url, const std::string& new_commit_id, const std::string& branch); + +private: + // Helper functions for managing the list of locally available databases + void localAssureOpened(); + QString localCheckFile(const QString& local_file); + + sqlite3* m_dbLocal; +}; + +#endif diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/RemoteDock.cpp b/src/WBCLFZSystemModule/SqliteDBProcess/src/RemoteDock.cpp new file mode 100644 index 0000000..288073c --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/RemoteDock.cpp @@ -0,0 +1,675 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "RemoteDock.h" +#include "ui_RemoteDock.h" +#include "Settings.h" +#include "RemoteCommitsModel.h" +#include "RemoteDatabase.h" +#include "RemoteLocalFilesModel.h" +#include "RemoteModel.h" +#include "SqliteDBMainWindow.h" +#include "RemotePushDialog.h" +#include "PreferencesDialog.h" + +using json = nlohmann::json; + +RemoteDock::RemoteDock(SqliteDBMainWindow* parent) + : QDialog(parent), + ui(new Ui::RemoteDock), + mainWindow(parent), + remoteModel(new RemoteModel(this)), + remoteLocalFilesModel(new RemoteLocalFilesModel(this, remoteDatabase)), + remoteCommitsModel(new RemoteCommitsModel(this)) +{ + ui->setupUi(this); + + // Set models + ui->treeRemote->setModel(remoteModel); + ui->treeLocal->setModel(remoteLocalFilesModel); + ui->treeDatabaseCommits->setModel(remoteCommitsModel); + + // Set initial column widths for tree views + ui->treeRemote->setColumnWidth(0, 300); // Make name column wider + ui->treeRemote->setColumnWidth(2, 80); // Make size column narrower + ui->treeLocal->setColumnWidth(RemoteLocalFilesModel::ColumnName, 300); // Make name column wider + ui->treeLocal->setColumnWidth(RemoteLocalFilesModel::ColumnSize, 80); // Make size column narrower + ui->treeLocal->setColumnHidden(RemoteLocalFilesModel::ColumnFile, true); // Hide local file name + + // Handle finished uploads and downloads of databases + connect(&RemoteNetwork::get(), &RemoteNetwork::fetchFinished, this, &RemoteDock::fetchFinished); + connect(&RemoteNetwork::get(), &RemoteNetwork::pushFinished, this, &RemoteDock::pushFinished); + + // Whenever a new directory listing has been parsed, check if it was a new root dir and, if so, open the user's directory + connect(remoteModel, &RemoteModel::directoryListingParsed, this, &RemoteDock::newDirectoryNode); + + // When the Preferences link is clicked in the no-certificates-label, open the preferences dialog. For other links than the ones we know, + // just open them in a web browser // Õⲿ·Ö´úÂëÓÃÓÚÔ¶³ÌÁ¬½Ó£¬ÔÝʱ²»ÐèÒª + connect(ui->labelNoCert, &QLabel::linkActivated, [this](const QString& link) { + if (link == "#preferences") + { + PreferencesDialog dialog(mainWindow, PreferencesDialog::TabRemote); + if (dialog.exec()) + mainWindow->reloadSettings(); + } + else { + QDesktopServices::openUrl(QUrl(link)); + } + }); + + // When changing the current branch in the branches combo box, update the tree view accordingly + connect(ui->comboDatabaseBranch, static_cast(&QComboBox::currentIndexChanged), [this](int /*index*/) { + remoteCommitsModel->refresh(current_commit_json, ui->comboDatabaseBranch->currentData().toString().toStdString(), currently_opened_file_info.commit_id); + ui->treeDatabaseCommits->expandAll(); + }); + + // Fetch latest commit action + connect(ui->actionFetchLatestCommit, &QAction::triggered, [this]() { + // Fetch last commit of current branch + // The URL and the branch name is that of the currently opened database file. + // The latest commit id is stored in the data bits of the branch combo box. + QUrl url(QString::fromStdString(currently_opened_file_info.url)); + QUrlQuery query; + query.addQueryItem("branch", QString::fromStdString(currently_opened_file_info.branch)); + query.addQueryItem("commit", ui->comboDatabaseBranch->itemData( + ui->comboDatabaseBranch->findText(QString::fromStdString(currently_opened_file_info.branch))).toString()); + url.setQuery(query); + fetchDatabase(url.toString()); + }); + + // Prepare context menu for list of remote databases + connect(ui->treeRemote->selectionModel(), &QItemSelectionModel::currentChanged, [this](const QModelIndex& index, const QModelIndex&) { + // Only enable database actions when a database was selected + bool enable = index.isValid() && + remoteModel->modelIndexToItem(index)->value(RemoteModelColumnType).toString() == "database"; + ui->actionCloneDatabaseDoubleClick->setEnabled(enable); + }); + ui->treeRemote->selectionModel()->currentChanged(QModelIndex(), QModelIndex()); // Enable/disable all action initially + connect(ui->actionCloneDatabaseDoubleClick, &QAction::triggered, [this]() { + fetchDatabase(ui->treeRemote->currentIndex()); + }); + ui->treeRemote->addAction(ui->actionCloneDatabaseDoubleClick); + + // Prepare context menu for list of local clones + connect(ui->treeLocal->selectionModel(), &QItemSelectionModel::currentChanged, [this](const QModelIndex& index, const QModelIndex&) { + // Only enable database actions when a database was selected + bool enable = index.isValid() && + !index.sibling(index.row(), RemoteLocalFilesModel::ColumnFile).data().isNull(); + ui->actionOpenLocalDatabase->setEnabled(enable); + ui->actionPushLocalDatabase->setEnabled(enable); + ui->actionDeleteDatabase->setEnabled(enable); + }); + ui->treeLocal->selectionModel()->currentChanged(QModelIndex(), QModelIndex()); // Enable/disable all action initially + connect(ui->actionOpenLocalDatabase, &QAction::triggered, [this]() { + openLocalFile(ui->treeLocal->currentIndex()); + }); + connect(ui->actionDeleteDatabase, &QAction::triggered, [this]() { + deleteLocalDatabase(ui->treeLocal->currentIndex()); + }); + ui->treeLocal->addAction(ui->actionOpenLocalDatabase); + ui->treeLocal->addAction(ui->actionPushLocalDatabase); + ui->treeLocal->addAction(ui->actionDeleteDatabase); + + // Prepare context menu for list of commits + connect(ui->treeDatabaseCommits->selectionModel(), &QItemSelectionModel::currentChanged, [this](const QModelIndex& index, const QModelIndex&) { + // Only enable database actions when a commit was selected + bool enable = index.isValid(); + ui->actionFetchCommit->setEnabled(enable); + ui->actionDownloadCommit->setEnabled(enable); + }); + ui->treeDatabaseCommits->selectionModel()->currentChanged(QModelIndex(), QModelIndex()); // Enable/disable all action initially + connect(ui->actionFetchCommit, &QAction::triggered, [this]() { + fetchCommit(ui->treeDatabaseCommits->currentIndex()); + }); + connect(ui->actionDownloadCommit, &QAction::triggered, [this]() { + fetchCommit(ui->treeDatabaseCommits->currentIndex(), RemoteNetwork::RequestTypeDownload); + }); + ui->treeDatabaseCommits->addAction(ui->actionFetchCommit); + ui->treeDatabaseCommits->addAction(ui->actionDownloadCommit); + + // Initial setup + reloadSettings(); +} + +RemoteDock::~RemoteDock() +{ + delete ui; +} + +void RemoteDock::reloadSettings() +{ + // Clear list of client certificates and add a dummy entry which does nothing except serve as + // an explanation to the user. + ui->comboUser->clear(); + ui->comboUser->addItem(tr("Select an identity to connect"), "dummy"); + + // Load list of client certs + QStringList client_certs = Settings::getValue("remote", "client_certificates").toStringList(); + for (const QString& file : client_certs) + { + auto certs = QSslCertificate::fromPath(file); + for (const QSslCertificate& cert : certs) + ui->comboUser->addItem(cert.subjectInfo(QSslCertificate::CommonName).at(0), file); + } + + // Add public certificate for anonymous read-only access to dbhub.io + ui->comboUser->addItem(tr("Public"), ":/user_certs/public.cert.pem"); +} + +void RemoteDock::setNewIdentity(const QString& identity) +{ + // Do nothing if the dummy entry was selected + if (ui->comboUser->currentData() == "dummy") + return; + + // Check if the dummy item is still there and remove it if it is + if (ui->comboUser->itemData(0) == "dummy") + { + ui->comboUser->blockSignals(true); + ui->comboUser->removeItem(0); + ui->comboUser->blockSignals(false); + } + + // Get certificate file name + QString cert = ui->comboUser->itemData(ui->comboUser->findText(identity), Qt::UserRole).toString(); + if (cert.isEmpty()) + return; + + // Open root directory. Get host name from client cert + remoteModel->setNewRootDir(RemoteNetwork::get().getInfoFromClientCert(cert, RemoteNetwork::CertInfoServer), cert); + + // Reset list of local checkouts + remoteLocalFilesModel->setIdentity(cert); + refreshLocalFileList(); + + // Enable buttons if necessary + enableButtons(); +} + +void RemoteDock::fetchDatabase(const QModelIndex& idx) +{ + if (!idx.isValid()) + return; + + // Get item + const RemoteModelItem* item = remoteModel->modelIndexToItem(idx); + + // Only open database file + if (item->value(RemoteModelColumnType).toString() == "database") + fetchDatabase(item->value(RemoteModelColumnUrl).toString()); +} + +void RemoteDock::fetchDatabase(QString url_string, RemoteNetwork::RequestType request_type) +{ + // If no URL was provided ask the user. Default to the current clipboard contents + if (url_string.isEmpty()) + { + url_string = QInputDialog::getText(this, + qApp->applicationName(), + tr("This downloads a database from a remote server for local editing.\n" + "Please enter the URL to clone from. You can generate this URL by\n" + "clicking the 'Clone Database in DB4S' button on the web page\n" + "of the database."), + QLineEdit::Normal, + QApplication::clipboard()->text()); + } + + if (url_string.isEmpty()) + return; + + // Check the URL + QUrl url(url_string); + if (url.authority() != QUrl(RemoteNetwork::get().getInfoFromClientCert(remoteModel->currentClientCertificate(), RemoteNetwork::CertInfoServer)).authority()) + { + QMessageBox::warning(this, qApp->applicationName(), tr("Invalid URL: The host name does not match the host name of the current identity.")); + return; + } + if (!QUrlQuery(url).hasQueryItem("branch")) + { + QMessageBox::warning(this, qApp->applicationName(), tr("Invalid URL: No branch name specified.")); + return; + } + if (!QUrlQuery(url).hasQueryItem("commit")) + { + QMessageBox::warning(this, qApp->applicationName(), tr("Invalid URL: No commit ID specified.")); + return; + } + + // For the user name, take the path, remove the database name and the initial slash + QString username = url.path().remove("/" + url.fileName()).mid(1); + + // There is a chance that we've already cloned that database. So check for that first + QString exists = remoteDatabase.localExists(url, remoteModel->currentClientCertificate(), QUrlQuery(url).queryItemValue("branch").toStdString()); + if (!exists.isEmpty() && request_type == RemoteNetwork::RequestTypeDatabase) + { + // Check for modifications + bool modified = isLocalDatabaseModified(exists, username, url.fileName(), remoteModel->currentClientCertificate(), + QUrlQuery(url).queryItemValue("commit").toStdString()); + + // Database has already been cloned! So open the local file instead of fetching the one from the + // server again. If the local file has been modified don't open it but try to download the last known + // commit again. + if (!modified) + { + emit openFile(exists); + return; + } + } + + // Check if we already have a clone of this database branch and, if so, figure out its local file name. + // For this we do not care about the currently checked out commit id because we only have one file per + // database and branch on the disk. + QUrl url_without_commit_id(url); + QUrlQuery url_without_commit_id_query(url_without_commit_id); + url_without_commit_id_query.removeQueryItem("commit"); + url_without_commit_id.setQuery(url_without_commit_id_query); + QString local_file = remoteDatabase.localExists(url_without_commit_id, remoteModel->currentClientCertificate(), QUrlQuery(url).queryItemValue("branch").toStdString()); + if (request_type == RemoteNetwork::RequestTypeDatabase && !local_file.isEmpty()) + { + // If there is a local clone of this dtabase and branch, figure out if the local file has been modified + + // Get the last local commit id + std::string last_commit_id = remoteDatabase.localLastCommitId(remoteModel->currentClientCertificate(), url, QUrlQuery(url).queryItemValue("branch").toStdString()); + + // Check for modifications + bool modified = isLocalDatabaseModified(local_file, username, url.fileName(), remoteModel->currentClientCertificate(), last_commit_id); + + // Only if the local file has been modified show a warning that checking out this commit overrides local changes + if (modified) + { + if (QMessageBox::warning(nullptr, + QApplication::applicationName(), + tr("You have modified the local clone of the database. Fetching this commit overrides these local changes.\n" + "Are you sure you want to proceed?"), + QMessageBox::Yes | QMessageBox::Cancel, + QMessageBox::Cancel) == QMessageBox::Cancel) + { + return; + } + } + } + + // Clone the database + RemoteNetwork::get().fetch(url.toString(), request_type, remoteModel->currentClientCertificate()); +} + +void RemoteDock::fetchCommit(const QModelIndex& idx, RemoteNetwork::RequestType request_type) +{ + // Fetch selected commit + QUrl url(QString::fromStdString(currently_opened_file_info.url)); + QUrlQuery query; + query.addQueryItem("branch", ui->comboDatabaseBranch->currentText()); + query.addQueryItem("commit", idx.sibling(idx.row(), RemoteCommitsModel::ColumnCommitId).data().toString()); + url.setQuery(query); + fetchDatabase(url.toString(), request_type); +} + +void RemoteDock::enableButtons() +{ + bool db_opened = mainWindow->getDb().isOpen() && mainWindow->getDb().currentFile() != ":memory:"; + bool logged_in = !remoteModel->currentClientCertificate().isEmpty(); + + ui->buttonPushDatabase->setEnabled(db_opened && logged_in); + ui->actionRefresh->setEnabled(logged_in); + ui->actionCloneDatabaseLink->setEnabled(logged_in); + ui->actionDatabaseOpenBrowser->setEnabled(db_opened && logged_in); + ui->actionFetchLatestCommit->setEnabled(db_opened && logged_in); +} + +void RemoteDock::pushCurrentlyOpenedDatabase() +{ + // Show a warning when trying to push a database with unsaved changes + if (mainWindow->getDb().getDirty()) + { + if (QMessageBox::warning(this, + QApplication::applicationName(), + tr("The database has unsaved changes. Are you sure you want to push it before saving?"), + QMessageBox::Yes | QMessageBox::Cancel, + QMessageBox::Cancel) == QMessageBox::Cancel) + return; + } + + // Push currently opened file + pushDatabase(mainWindow->getDb().currentFile(), QString::fromStdString(currently_opened_file_info.branch)); +} + +void RemoteDock::pushSelectedLocalDatabase() +{ + // Return if no file is selected + if (!ui->treeLocal->currentIndex().isValid()) + return; + + const int row = ui->treeLocal->currentIndex().row(); + const QString filename = ui->treeLocal->currentIndex().sibling(row, RemoteLocalFilesModel::ColumnFile).data().toString(); + if (filename.isEmpty()) + return; + + // Push selected file + const QString branch = ui->treeLocal->currentIndex().sibling(row, RemoteLocalFilesModel::ColumnBranch).data().toString(); + pushDatabase(Settings::getValue("remote", "clonedirectory").toString() + "/" + filename, branch); +} + +void RemoteDock::pushDatabase(const QString& path, const QString& branch) +{ + // If the currently active identity is the read-only public access to dbhub.io, don't show the Push Database dialog because it won't work anyway. + // Instead switch to an explanation offering some advice to create and import a proper certificate. + if (remoteModel->currentClientCertificate() == ":/user_certs/public.cert.pem") + { + ui->stack->setCurrentIndex(1); + return; + } + + // The default suggestion for a database name is the local file name. If it is a remote file (like when it initially was fetched using DB4S), + // the extra bit of information at the end of the name gets removed first. + QString name = QFileInfo(path).fileName(); + name = name.remove(QRegExp("_[0-9]+.remotedb$")); + + // Show the user a dialog for setting all the commit details + QString host = RemoteNetwork::get().getInfoFromClientCert(remoteModel->currentClientCertificate(), RemoteNetwork::CertInfoServer); + RemotePushDialog pushDialog(this, host, remoteModel->currentClientCertificate(), name, branch); + if (pushDialog.exec() != QDialog::Accepted) + return; + + // Build push URL + QString url = host; + url.append(pushDialog.user()); + url.append("/"); + url.append(pushDialog.name()); + + // Check if we are pushing a cloned database. Only in this case we provide the last known commit id. + // For this check we use the branch name which was used for cloning this database rather than the + // branch name which was selected in the push dialog. This is because we want to figure out the + // current commit id of we are currently looking at rather than some other commit id or none at all + // when creating a new branch. + QString commit_id; + if (path.startsWith(Settings::getValue("remote", "clonedirectory").toString())) + commit_id = QString::fromStdString(remoteDatabase.localLastCommitId(remoteModel->currentClientCertificate(), url, branch.toStdString())); + + // Push database + RemoteNetwork::get().push(path, url, remoteModel->currentClientCertificate(), pushDialog.name(), + pushDialog.commitMessage(), pushDialog.licence(), pushDialog.isPublic(), pushDialog.branch(), + pushDialog.forcePush(), commit_id); +} + +void RemoteDock::newDirectoryNode(const QModelIndex& parent) +{ + // Was this a new root dir? + if (!parent.isValid()) + { + // Then check if there is a directory with the current user name + + // Get current user name + QString user = RemoteNetwork::get().getInfoFromClientCert(remoteModel->currentClientCertificate(), RemoteNetwork::CertInfoUser); + + for (int i = 0; i < remoteModel->rowCount(); i++) + { + QModelIndex child = remoteModel->index(i, RemoteModelColumnName); + if (child.data().toString() == user) + { + ui->treeRemote->expand(child); + break; + } + } + } +} + +void RemoteDock::reject() +{ + // We override this, to ensure the Escape key doesn't make this dialog + // dock go away + return; +} + +void RemoteDock::switchToMainView() +{ + ui->stack->setCurrentIndex(0); +} + +void RemoteDock::refreshLocalFileList() +{ + remoteLocalFilesModel->refresh(); + + // Expand node for current user + QString user = RemoteNetwork::get().getInfoFromClientCert(remoteModel->currentClientCertificate(), RemoteNetwork::CertInfoUser); + for (int i = 0; i < remoteLocalFilesModel->rowCount(); i++) + { + QModelIndex child = remoteLocalFilesModel->index(i, RemoteLocalFilesModel::ColumnName); + if (child.data().toString() == user) + { + ui->treeLocal->expand(child); + break; + } + } +} + +void RemoteDock::openLocalFile(const QModelIndex& idx) +{ + if (!idx.isValid()) + return; + + QString file = idx.sibling(idx.row(), RemoteLocalFilesModel::ColumnFile).data().toString(); + if (!file.isEmpty()) + emit openFile(Settings::getValue("remote", "clonedirectory").toString() + "/" + file); +} + +void RemoteDock::fileOpened(const QString& filename) +{ + // Clear data first + currently_opened_file_info.clear(); + remoteCommitsModel->clear(); + ui->comboDatabaseBranch->clear(); + ui->editDatabaseUser->clear(); + ui->editDatabaseFile->clear(); + ui->editDatabaseBranch->clear(); + + // Do nothing if the file name is empty (indicating a closed database) or this is an in-memory database + if (filename.isEmpty() || filename == ":memory:") + return; + + // Check if it is a tracked remote database file and retrieve the information we have on it + if (filename.startsWith(Settings::getValue("remote", "clonedirectory").toString())) + currently_opened_file_info = remoteDatabase.localGetLocalFileInfo(filename); + + // Is this actually a clone of a remote database? + if (!currently_opened_file_info.file.empty()) + { + // Copy information to view + ui->editDatabaseUser->setText(currently_opened_file_info.user_name()); + ui->editDatabaseFile->setText(QString::fromStdString(currently_opened_file_info.name)); + ui->editDatabaseBranch->setText(QString::fromStdString(currently_opened_file_info.branch)); + + // Make sure the current identity matches the identity used to clone this file in the first place. + // A mismatch is possible when the local database file has been opened using a recent files menu item or some similar technique. + if (QString::fromStdString(currently_opened_file_info.identity) != QFileInfo(remoteModel->currentClientCertificate()).fileName()) + ui->comboUser->setCurrentIndex(ui->comboUser->findData("/" + QString::fromStdString(currently_opened_file_info.identity), Qt::UserRole, Qt::MatchEndsWith)); + + // Query more information on database from server + refreshMetadata(currently_opened_file_info.user_name(), QString::fromStdString(currently_opened_file_info.name)); + + // Switch to "Current Database" tab + ui->tabs->setCurrentIndex(2); + } +} + +void RemoteDock::refreshMetadata(const QString& username, const QString& dbname) +{ + // Make request for meta data + QUrl url(RemoteNetwork::get().getInfoFromClientCert(remoteModel->currentClientCertificate(), RemoteNetwork::CertInfoServer) + "/metadata/get"); + QUrlQuery query; + query.addQueryItem("username", username); + query.addQueryItem("folder", "/"); + query.addQueryItem("dbname", dbname); + url.setQuery(query); + RemoteNetwork::get().fetch(url.toString(), RemoteNetwork::RequestTypeCustom, remoteModel->currentClientCertificate(), [this](const QByteArray& reply) { + // Read and check results + json obj = json::parse(reply, nullptr, false); + if (obj.is_discarded() || !obj.is_object()) + return; + + // Store all the commit information as-is + json obj_commits = obj["commits"]; + current_commit_json = obj_commits.dump(); + + // Store the link to the web page in the action for opening that link in a browser + ui->actionDatabaseOpenBrowser->setData(QString::fromStdString(obj["web_page"])); + + // Fill branches combo box + json obj_branches = obj["branches"]; + ui->comboDatabaseBranch->clear(); + for (auto it = obj_branches.cbegin(); it != obj_branches.cend(); ++it) + ui->comboDatabaseBranch->addItem(QString::fromStdString(it.key()), QString::fromStdString(it.value()["commit"])); + ui->comboDatabaseBranch->setCurrentIndex(ui->comboDatabaseBranch->findText(ui->editDatabaseBranch->text())); + }); +} + +void RemoteDock::deleteLocalDatabase(const QModelIndex& index) +{ + if (!index.isValid()) + return; + + QString filename = index.sibling(index.row(), RemoteLocalFilesModel::ColumnFile).data().toString(); + QString path = Settings::getValue("remote", "clonedirectory").toString() + "/" + filename; + + // Warn when trying to delete a currently opened database file + if (mainWindow->getDb().currentFile() == path) + { + QMessageBox::warning(this, QApplication::applicationName(), tr("The database you are trying to delete is currently opened. " + "Please close it before deleting.")); + return; + } + + // Let user confirm deleting the database + if (QMessageBox::warning(this, QApplication::applicationName(), tr("This deletes the local version of this database with all the " + "changes you have not committed yet. Are you sure you want to " + "delete this database?"), + QMessageBox::Yes | QMessageBox::Cancel, QMessageBox::Cancel) == QMessageBox::Cancel) + { + return; + } + + // Delete the file + remoteLocalFilesModel->removeRow(index.row(), index.parent()); +} + +void RemoteDock::openCurrentDatabaseInBrowser() const +{ + QDesktopServices::openUrl(ui->actionDatabaseOpenBrowser->data().toUrl()); +} + +void RemoteDock::refresh() +{ + // Refresh Remote tab + remoteModel->refresh(); + + // Refresh Local tab + refreshLocalFileList(); + + // Refresh Current Database tab + if (!currently_opened_file_info.file.empty()) + refreshMetadata(currently_opened_file_info.user_name(), QString::fromStdString(currently_opened_file_info.name)); +} + +void RemoteDock::pushFinished(const QString& filename, const QString& identity, const QUrl& url, const std::string& new_commit_id, + const std::string& branch, const QString& source_file) +{ + // Create or update the record in our local checkout database + QString saveFileAs = remoteDatabase.localAdd(filename, identity, url, new_commit_id, branch); + + // If the name of the source file and the name we're saving as differ, we're doing an initial push. In this case, copy the source file to + // the destination path to avoid redownloading it when it's first used. + if (saveFileAs != source_file) + QFile::copy(source_file, saveFileAs); + + // Update info on currently opened file + if (currently_opened_file_info.file == QFileInfo(saveFileAs).fileName().toStdString()) + currently_opened_file_info = remoteDatabase.localGetLocalFileInfo(saveFileAs); + + // Refresh view + refresh(); +} + +void RemoteDock::fetchFinished(const QString& filename, const QString& identity, const QUrl& url, const std::string& new_commit_id, + const std::string& branch, const QDateTime& last_modified, QIODevice* device) +{ + // Add cloned database to list of local databases + QString saveFileAs = remoteDatabase.localAdd(filename, identity, url, new_commit_id, branch); + + // Save the downloaded data under the generated file name + QFile file(saveFileAs); + file.open(QIODevice::WriteOnly); + file.write(device->readAll()); + + // Set last modified data of the new file to the one provided by the server + // Before version 5.10, Qt didn't offer any option to set this attribute, so we're not setting it at the moment +#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0) + file.setFileTime(last_modified, QFileDevice::FileModificationTime); +#endif + + // Close file + file.close(); + + // Update info on currently opened file + currently_opened_file_info = remoteDatabase.localGetLocalFileInfo(saveFileAs); + + // Refresh data + refreshLocalFileList(); + + // Tell the application to open this file + emit openFile(saveFileAs); +} + +bool RemoteDock::isLocalDatabaseModified(const QString& local_file, const QString& username, const QString& dbname, const QString& identity, const std::string& commit_id) +{ + // Fetch metadata on database + QUrl url(RemoteNetwork::get().getInfoFromClientCert(identity, RemoteNetwork::CertInfoServer) + "/metadata/get"); + QUrlQuery query; + query.addQueryItem("username", username); + query.addQueryItem("folder", "/"); + query.addQueryItem("dbname", dbname); + url.setQuery(query); + + bool modified = true; // By default we assume the database has been modified + RemoteNetwork::get().fetch(url, RemoteNetwork::RequestTypeCustom, identity, [commit_id, dbname, local_file, &modified](const QByteArray& reply) { + // Read and check results + json obj = json::parse(reply, nullptr, false); + if (obj.is_discarded() || !obj.is_object()) + return; + + // Search tree entry for currently checked out commit + json tree = obj["commits"][commit_id]["tree"]["entries"]; + for (const auto& it : tree) + { + if (it["entry_type"] == "db" && it["name"] == dbname.toStdString()) + { + // When we have found it, check if the current file matches the remote file by first checking if the + // file size is equal and then comparing their SHA256 hashes + if (QFileInfo(local_file).size() == it["size"]) + { + QFile file(local_file); + if (!file.open(QFile::ReadOnly)) + return; + + QCryptographicHash hash(QCryptographicHash::Sha256); + hash.addData(&file); + if (hash.result().toHex().toStdString() == it["sha256"]) + { + modified = false; + return; + } + } + + break; + } + } + }, true); + + return modified; +} diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/RemoteDock.h b/src/WBCLFZSystemModule/SqliteDBProcess/src/RemoteDock.h new file mode 100644 index 0000000..199a28f --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/RemoteDock.h @@ -0,0 +1,80 @@ +#ifndef REMOTEDOCK_H +#define REMOTEDOCK_H + +#include + +#include "RemoteDatabase.h" +#include "RemoteNetwork.h" + +class RemoteCommitsModel; +class RemoteLocalFilesModel; +class RemoteModel; +class SqliteDBMainWindow; + +namespace Ui { +class RemoteDock; +} + +class RemoteDock : public QDialog +{ + Q_OBJECT + +public: + explicit RemoteDock(SqliteDBMainWindow* parent); + ~RemoteDock() override; + + void reloadSettings(); + void enableButtons(); + + // This function should be called whenever a database file is opened. + // It checks whether the file is a checkout of a tracked remote database + // and updates some of the fields in the remote dock if it is. + // Call it with an empty file name if the database is closed. + void fileOpened(const QString& filename); + +public slots: + void reject() override; + +private slots: + void setNewIdentity(const QString& identity); + void fetchDatabase(const QModelIndex& idx); + void fetchDatabase(QString url = QString(), RemoteNetwork::RequestType request_type = RemoteNetwork::RequestTypeDatabase); + void fetchCommit(const QModelIndex& idx, RemoteNetwork::RequestType request_type = RemoteNetwork::RequestTypeDatabase); + void pushCurrentlyOpenedDatabase(); + void pushSelectedLocalDatabase(); + void newDirectoryNode(const QModelIndex& parent); + void switchToMainView(); + void openLocalFile(const QModelIndex& idx); + void deleteLocalDatabase(const QModelIndex& index); + void openCurrentDatabaseInBrowser() const; + void refresh(); + void pushFinished(const QString& filename, const QString& identity, const QUrl& url, const std::string& new_commit_id, + const std::string& branch, const QString& source_file); + void fetchFinished(const QString& filename, const QString& identity, const QUrl& url, const std::string& new_commit_id, + const std::string& branch, const QDateTime& last_modified, QIODevice* device); + +signals: + void openFile(QString file); + +private: + Ui::RemoteDock* ui; + + SqliteDBMainWindow* mainWindow; + + RemoteDatabase remoteDatabase; + RemoteModel* remoteModel; + RemoteLocalFilesModel* remoteLocalFilesModel; + RemoteCommitsModel* remoteCommitsModel; + + std::string current_commit_json; + RemoteDatabase::LocalFileInfo currently_opened_file_info; + + void refreshLocalFileList(); + void refreshMetadata(const QString& username, const QString& dbname); + + bool isLocalDatabaseModified(const QString& local_file, const QString& username, const QString& dbname, const QString& identity, const std::string& commit_id); + + void pushDatabase(const QString& path, const QString& branch); +}; + +#endif diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/RemoteDock.ui b/src/WBCLFZSystemModule/SqliteDBProcess/src/RemoteDock.ui new file mode 100644 index 0000000..e0e03c5 --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/RemoteDock.ui @@ -0,0 +1,684 @@ + + + RemoteDock + + + + 0 + 0 + 534 + 387 + + + + Remote + + + + + + 0 + + + + + + + + + Identity + + + comboUser + + + + + + + QComboBox::AdjustToContents + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Push currently opened database to server + + + + :/icons/push_database:/icons/push_database + + + + + + + + + 0 + + + + DBHub.io + + + + 2 + + + 0 + + + 2 + + + 0 + + + + + false + + + false + + + + + + + + + Qt::ActionsContextMenu + + + <html><head/><body><p>In this pane, remote databases from dbhub.io website can be added to DB Browser for SQLite. First you need an identity:</p><ol style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Login to the dbhub.io website (use your GitHub credentials or whatever you want)</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Click the button to &quot;Generate client certificate&quot; (that's your identity). That'll give you a certificate file (save it to your local disk).</li><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Go to the Remote tab in DB Browser for SQLite Preferences. Click the button to add a new certificate to DB Browser for SQLite and choose the just downloaded certificate file.</li></ol><p>Now the Remote panel shows your identity and you can add remote databases.</p></body></html> + + + + + + + + Local + + + + 2 + + + 0 + + + 2 + + + 0 + + + + + Qt::ActionsContextMenu + + + + + + + + Current Database + + + + 2 + + + 0 + + + 2 + + + 0 + + + + + false + + + false + + + + + + + + + + Clone + + + + 0 + + + + + User + + + editDatabaseUser + + + + + + + true + + + + + + + Database + + + editDatabaseFile + + + + + + + true + + + + + + + Branch + + + editDatabaseBranch + + + + + + + true + + + + + + + + + + Commits + + + + 2 + + + 0 + + + 2 + + + 0 + + + + + + + Commits for + + + + + + + + + + + + Qt::ActionsContextMenu + + + + + + + + + + + + + + + + + + Qt::Vertical + + + + 20 + 85 + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + <html><head/><body><p>You are currently using a built-in, read-only identity. For uploading your database, you need to configure and use your DBHub.io account.</p><p>No DBHub.io account yet? <a href="https://dbhub.io/"><span style=" text-decoration: underline; color:#007af4;">Create one now</span></a> and import your certificate <a href="#preferences"><span style=" text-decoration: underline; color:#007af4;">here</span></a> to share your databases.</p><p>For online help visit <a href="https://dbhub.io/about"><span style=" text-decoration: underline; color:#007af4;">here</span></a>.</p></body></html> + + + true + + + + + + + Back + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + Qt::Vertical + + + + 20 + 85 + + + + + + + + + + + + + :/icons/close:/icons/close + + + Delete Database + + + Delete the local clone of this database + + + + + + :/icons/browser_open:/icons/browser_open + + + Open in Web Browser + + + Open the web page for the current database in your browser + + + + + + :/icons/clone_database:/icons/clone_database + + + Clone from Link + + + Use this to download a remote database for local editing using a URL as provided on the web page of the database. + + + + + + :/icons/refresh:/icons/refresh + + + Refresh + + + Reload all data and update the views + + + F5 + + + + + + :/icons/clone_database:/icons/clone_database + + + Clone Database + + + + 75 + true + + + + + + + :/icons/db_open:/icons/db_open + + + Open Database + + + Open the local copy of this database + + + + 75 + true + + + + + + Check out Commit + + + Download and open this specific commit + + + + 75 + true + + + + + + + :/icons/db_revert:/icons/db_revert + + + Check out Latest Commit + + + Check out the latest commit of the current branch + + + + + Save Revision to File + + + Saves the selected revision of the database to another file + + + + + + :/icons/push_database:/icons/push_database + + + Upload Database + + + Upload this database as a new commit + + + + + comboUser + buttonPushDatabase + tabs + treeRemote + treeLocal + comboDatabaseBranch + treeDatabaseCommits + buttonNoCertBack + + + + + + + comboUser + currentTextChanged(QString) + RemoteDock + setNewIdentity(QString) + + + 134 + 25 + + + 419 + 24 + + + + + treeRemote + doubleClicked(QModelIndex) + RemoteDock + fetchDatabase(QModelIndex) + + + 215 + 148 + + + 204 + 37 + + + + + buttonPushDatabase + clicked() + RemoteDock + pushCurrentlyOpenedDatabase() + + + 530 + 25 + + + 287 + 154 + + + + + buttonNoCertBack + clicked() + RemoteDock + switchToMainView() + + + 93 + 23 + + + 266 + 148 + + + + + treeLocal + doubleClicked(QModelIndex) + RemoteDock + openLocalFile(QModelIndex) + + + 266 + 179 + + + 266 + 148 + + + + + actionCloneDatabaseLink + triggered() + RemoteDock + fetchDatabase() + + + -1 + -1 + + + 266 + 178 + + + + + actionDatabaseOpenBrowser + triggered() + RemoteDock + openCurrentDatabaseInBrowser() + + + -1 + -1 + + + 266 + 189 + + + + + actionRefresh + triggered() + RemoteDock + refresh() + + + -1 + -1 + + + 266 + 193 + + + + + treeDatabaseCommits + doubleClicked(QModelIndex) + RemoteDock + fetchCommit(QModelIndex) + + + 266 + 337 + + + 266 + 193 + + + + + actionPushLocalDatabase + triggered() + RemoteDock + pushSelectedLocalDatabase() + + + -1 + -1 + + + 266 + 193 + + + + + + setNewIdentity(QString) + fetchDatabase(QModelIndex) + pushCurrentlyOpenedDatabase() + pushSelectedLocalDatabase() + switchToMainView() + openLocalFile(QModelIndex) + fetchDatabase() + openCurrentDatabaseInBrowser() + refresh() + fetchCommit(QModelIndex) + + diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/RemoteLocalFilesModel.cpp b/src/WBCLFZSystemModule/SqliteDBProcess/src/RemoteLocalFilesModel.cpp new file mode 100644 index 0000000..0c7a342 --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/RemoteLocalFilesModel.cpp @@ -0,0 +1,191 @@ +#include +#include +#include +#include +#include + +#include "Data.h" +#include "RemoteDatabase.h" +#include "RemoteLocalFilesModel.h" +#include "RemoteNetwork.h" +#include "Settings.h" + +using json = nlohmann::json; + +RemoteLocalFilesModel::RemoteLocalFilesModel(QObject* parent, RemoteDatabase& remote) : + QAbstractItemModel(parent), + remoteDatabase(remote) +{ + QStringList header; + header << tr("Name") << tr("Branch") << tr("Last modified") << tr("Size") << tr("Commit") << tr("File"); + rootItem = new QTreeWidgetItem(header); +} + +RemoteLocalFilesModel::~RemoteLocalFilesModel() +{ + delete rootItem; +} + +void RemoteLocalFilesModel::setIdentity(const QString& cert_filename) +{ + current_cert_filename = cert_filename; + current_user_name = RemoteNetwork::get().getInfoFromClientCert(cert_filename, RemoteNetwork::CertInfoUser); + refresh(); +} + +void RemoteLocalFilesModel::refresh() +{ + beginResetModel(); + + // Remove all data except for the root item + while(rootItem->childCount()) + delete rootItem->child(0); + + // Get list of locally checked out databases + auto files = remoteDatabase.localGetLocalFiles(current_cert_filename); + + // Loop through that list + for(const auto& file : files) + { + QString user_name = file.user_name(); + + // Check if there is already a node for this user + QTreeWidgetItem* user_node = nullptr; + for(int i=0;ichildCount();i++) + { + if(rootItem->child(i)->text(ColumnName) == user_name) + { + user_node = rootItem->child(i); + break; + } + } + + // If there is no node for this user yet create one + if(user_node == nullptr) + { + user_node = new QTreeWidgetItem(rootItem); + user_node->setText(ColumnName, user_name); + user_node->setIcon(ColumnName, QIcon(user_name == current_user_name ? ":/icons/folder_user" : ":/icons/folder")); + } + + // Get file information + QFile file_info(Settings::getValue("remote", "clonedirectory").toString() + "/" + QString::fromStdString(file.file)); + + // Add file to user node + QTreeWidgetItem* file_node = new QTreeWidgetItem(user_node); + file_node->setText(ColumnName, QString::fromStdString(file.name)); + file_node->setIcon(ColumnName, QIcon(":/icons/database")); + file_node->setText(ColumnBranch, QString::fromStdString(file.branch)); + file_node->setText(ColumnLastModified, QLocale::system().toString(QFileInfo(file_info).lastModified().toLocalTime(), QLocale::ShortFormat)); + file_node->setText(ColumnSize, humanReadableSize(static_cast(file_info.size()))); + file_node->setText(ColumnCommit, QString::fromStdString(file.commit_id)); + file_node->setText(ColumnFile, QString::fromStdString(file.file)); + } + + // Refresh the view + endResetModel(); +} + +QModelIndex RemoteLocalFilesModel::index(int row, int column, const QModelIndex& parent) const +{ + if(!hasIndex(row, column, parent)) + return QModelIndex(); + + QTreeWidgetItem *parentItem; + if(!parent.isValid()) + parentItem = rootItem; + else + parentItem = static_cast(parent.internalPointer()); + + QTreeWidgetItem* childItem = parentItem->child(row); + if(childItem) + return createIndex(row, column, childItem); + else + return QModelIndex(); +} + +QModelIndex RemoteLocalFilesModel::parent(const QModelIndex& index) const +{ + if(!index.isValid()) + return QModelIndex(); + + QTreeWidgetItem* childItem = static_cast(index.internalPointer()); + QTreeWidgetItem* parentItem = childItem->parent(); + + if(parentItem == rootItem) + return QModelIndex(); + else + return createIndex(0, 0, parentItem); +} + +QVariant RemoteLocalFilesModel::data(const QModelIndex& index, int role) const +{ + if(!index.isValid()) + return QVariant(); + + // Get the item the index points at + QTreeWidgetItem* item = static_cast(index.internalPointer()); + + // Return data depending on the role + switch(role) + { + case Qt::DisplayRole: + case Qt::EditRole: + return item->text(index.column()); + case Qt::DecorationRole: + return item->icon(index.column()); + default: + return QVariant(); + } +} + +QVariant RemoteLocalFilesModel::headerData(int section, Qt::Orientation orientation, int role) const +{ + // Get the header string from the root item + if(orientation == Qt::Horizontal && role == Qt::DisplayRole) + return rootItem->data(section, role); + + return QVariant(); +} + +int RemoteLocalFilesModel::rowCount(const QModelIndex& parent) const +{ + if(parent.column() > 0) + return 0; + + if(!parent.isValid()) + return rootItem->childCount(); + else + return static_cast(parent.internalPointer())->childCount(); +} + +int RemoteLocalFilesModel::columnCount(const QModelIndex& /*parent*/) const +{ + return rootItem->columnCount(); +} + +bool RemoteLocalFilesModel::removeRows(int row, int count, const QModelIndex& parent) +{ + for(int i=0;i=0;i--) + { + auto item = static_cast(index(row + i, 0, parent).internalPointer()); + item->parent()->removeChild(item); + } + endRemoveRows(); + + // If parent node is empty, remove that one too. Make sure to not remove the root node + if(parent.isValid() && !index(0, 0, parent).isValid()) + { + beginRemoveRows(parent.parent(), 0, 0); + auto item = static_cast(parent.internalPointer()); + item->parent()->removeChild(item); + endRemoveRows(); + } + + return true; +} diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/RemoteLocalFilesModel.h b/src/WBCLFZSystemModule/SqliteDBProcess/src/RemoteLocalFilesModel.h new file mode 100644 index 0000000..ee6e478 --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/RemoteLocalFilesModel.h @@ -0,0 +1,56 @@ +#ifndef REMOTELOCALFILESMODEL_H +#define REMOTELOCALFILESMODEL_H + +#include + +#include + +class RemoteDatabase; + +class QTreeWidgetItem; + +class RemoteLocalFilesModel : public QAbstractItemModel +{ + Q_OBJECT + +public: + explicit RemoteLocalFilesModel(QObject* parent, RemoteDatabase& remote); + ~RemoteLocalFilesModel() override; + + void setIdentity(const QString& cert_filename); + void refresh(); + + QModelIndex index(int row, int column, const QModelIndex& parent = QModelIndex()) const override; + QModelIndex parent(const QModelIndex& index) const override; + + QVariant data(const QModelIndex& index, int role) const override; + QVariant headerData(int section, Qt::Orientation orientation, int role) const override; + + int rowCount(const QModelIndex& parent = QModelIndex()) const override; + int columnCount(const QModelIndex& parent = QModelIndex()) const override; + + bool removeRows(int row, int count, const QModelIndex& parent = QModelIndex()) override; + + enum Columns + { + ColumnName, + ColumnBranch, + ColumnLastModified, + ColumnSize, + ColumnCommit, + ColumnFile, + }; + +private: + // Pointer to the root item. This contains all the actual item data. + QTreeWidgetItem* rootItem; + + // Reference to the remote database object which is stored somewhere in the main window. + RemoteDatabase& remoteDatabase; + + // This stores the currently used network identity for further requests + QString current_cert_filename; + QString current_user_name; +}; + +#endif diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/RemoteModel.cpp b/src/WBCLFZSystemModule/SqliteDBProcess/src/RemoteModel.cpp new file mode 100644 index 0000000..1959776 --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/RemoteModel.cpp @@ -0,0 +1,344 @@ +#include + +#include "Data.h" +#include "RemoteModel.h" +#include "RemoteNetwork.h" + +using json = nlohmann::json; + +RemoteModelItem::RemoteModelItem(RemoteModelItem* parent) : + m_parent(parent), + m_fetchedDirectoryList(false) +{ +} + +RemoteModelItem::~RemoteModelItem() +{ + qDeleteAll(m_children); +} + +QVariant RemoteModelItem::value(RemoteModelColumns column) const +{ + return m_values[column]; +} + +void RemoteModelItem::setValue(RemoteModelColumns column, QVariant value) +{ + m_values[column] = value; +} + +void RemoteModelItem::appendChild(RemoteModelItem *item) +{ + m_children.push_back(item); +} + +RemoteModelItem* RemoteModelItem::child(int row) const +{ + return m_children[static_cast(row)]; +} + +RemoteModelItem* RemoteModelItem::parent() const +{ + return m_parent; +} + +int RemoteModelItem::childCount() const +{ + return static_cast(m_children.size()); +} + +int RemoteModelItem::row() const +{ + if(m_parent) + { + auto f = std::find( m_parent->m_children.begin(), m_parent->m_children.end(), const_cast(this)); + if(f == m_parent->m_children.end()) + return -1; + else + return static_cast(std::distance(m_parent->m_children.begin(), f)); + } + + return 0; +} + +bool RemoteModelItem::fetchedDirectoryList() const +{ + return m_fetchedDirectoryList; +} + +void RemoteModelItem::setFetchedDirectoryList(bool fetched) +{ + m_fetchedDirectoryList = fetched; +} + +std::vector RemoteModelItem::loadArray(const json& array, RemoteModelItem* parent) +{ + std::vector items; + + // Loop through all directory items + for(const auto& elem : array) + { + // Create a new model item with the specified parent + RemoteModelItem* item = new RemoteModelItem(parent); + + // Save all relevant values. Some of the values are only available for databases. + item->setValue(RemoteModelColumnName, QString::fromStdString(elem["name"])); + item->setValue(RemoteModelColumnType, QString::fromStdString(elem["type"])); + item->setValue(RemoteModelColumnUrl, QString::fromStdString(elem["url"])); + item->setValue(RemoteModelColumnLastModified, isoDateTimeStringToLocalDateTimeString(QString::fromStdString(elem["last_modified"]))); + if(item->value(RemoteModelColumnType).toString() == "database") + { + item->setValue(RemoteModelColumnCommitId, QString::fromStdString(elem["commit_id"])); + item->setValue(RemoteModelColumnSize, QString::number(static_cast(elem["size"]))); + item->setValue(RemoteModelColumnDefaultBranch, QString::fromStdString(elem["default_branch"])); + item->setValue(RemoteModelColumnLicence, QString::fromStdString(elem["licence"])); + item->setValue(RemoteModelColumnOneLineDescription, QString::fromStdString(elem["one_line_description"])); + item->setValue(RemoteModelColumnPublic, static_cast(elem["public"])); + item->setValue(RemoteModelColumnSha256, QString::fromStdString(elem["sha256"])); + item->setValue(RemoteModelColumnRepoModified, isoDateTimeStringToLocalDateTimeString(QString::fromStdString(elem["repo_modified"]))); + } + + items.push_back(item); + } + + return items; +} + +RemoteModel::RemoteModel(QObject* parent) : + QAbstractItemModel(parent), + headerList({tr("Name"), tr("Last modified"), tr("Size"), tr("Commit")}), + rootItem(new RemoteModelItem()) +{ +} + +RemoteModel::~RemoteModel() +{ + delete rootItem; +} + +void RemoteModel::setNewRootDir(const QString& url, const QString& cert) +{ + // Get user name from client cert + currentUserName = RemoteNetwork::get().getInfoFromClientCert(cert, RemoteNetwork::CertInfoUser); + + // Save settings + currentRootDirectory = url; + currentClientCert = cert; + + // Fetch root directory + refresh(); +} + +void RemoteModel::refresh() +{ + // Fetch root directory and put the reply data under the root item + RemoteNetwork::get().fetch(currentRootDirectory, RemoteNetwork::RequestTypeCustom, currentClientCert, [this](const QByteArray& reply) { + parseDirectoryListing(reply, QModelIndex()); + }); +} + +void RemoteModel::parseDirectoryListing(const QString& text, QModelIndex parent) +{ + // Load new JSON root document assuming it's an array + json array = json::parse(text.toStdString(), nullptr, false); + if(array.is_discarded() || !array.is_array()) + return; + + // Get model index to store the new data under + RemoteModelItem* parentItem = const_cast(modelIndexToItem(parent)); + + // An invalid model index indicates that this is a new root item. This means the old one needs to be entirely deleted first. + if(!parent.isValid()) + { + // Clear root item + beginResetModel(); + delete rootItem; + rootItem = new RemoteModelItem(); + endResetModel(); + + // Set parent model index and parent item to the new values + parent = QModelIndex(); + parentItem = rootItem; + } + + // Insert data + std::vector items = RemoteModelItem::loadArray(array, parentItem); + beginInsertRows(parent, 0, static_cast(items.size() - 1)); + for(RemoteModelItem* item : items) + parentItem->appendChild(item); + endInsertRows(); + + // Emit directory listing parsed signal + emit directoryListingParsed(parent); +} + +QModelIndex RemoteModel::index(int row, int column, const QModelIndex& parent) const +{ + if(!hasIndex(row, column, parent)) + return QModelIndex(); + + const RemoteModelItem* parentItem = modelIndexToItem(parent); + RemoteModelItem* childItem = parentItem->child(row); + + if(childItem) + return createIndex(row, column, childItem); + else + return QModelIndex(); +} + +QModelIndex RemoteModel::parent(const QModelIndex& index) const +{ + if(!index.isValid()) + return QModelIndex(); + + const RemoteModelItem* childItem = modelIndexToItem(index); + RemoteModelItem* parentItem = childItem->parent(); + + if(parentItem == rootItem) + return QModelIndex(); + + return createIndex(parentItem->row(), 0, parentItem); +} + +QVariant RemoteModel::data(const QModelIndex& index, int role) const +{ + // Don't return data for invalid indices + if(!index.isValid()) + return QVariant(); + + // Type of item + const RemoteModelItem* item = modelIndexToItem(index); + QString type = item->value(RemoteModelColumnType).toString(); + + // Decoration role? Only for first column! + if(role == Qt::DecorationRole && index.column() == 0) + { + // Use different icons depending on item type + if(type == "folder" && index.parent() == QModelIndex() && item->value(RemoteModelColumnName) == currentUserName) + return QImage(":/icons/folder_user"); + else if(type == "folder") + return QImage(":/icons/folder"); + else if(type == "database") + return QImage(":/icons/database"); + } else if(role == Qt::ToolTipRole) { + if(type == "database") + { + // Use URL to generate user name and database name. This avoids using the name of the parent item which + // might not contain the user name when the server sends a different directory structure. + QString result = "" + item->value(RemoteModelColumnUrl).toUrl().path().mid(1) + ""; + if(!item->value(RemoteModelColumnOneLineDescription).toString().isEmpty()) + result += "
" + item->value(RemoteModelColumnOneLineDescription).toString(); + result += "
" + tr("Size: ") + humanReadableSize(item->value(RemoteModelColumnSize).toULongLong()); + result += "
" + tr("Last Modified: ") + item->value(RemoteModelColumnLastModified).toString(); + result += "
" + tr("Licence: ") + item->value(RemoteModelColumnLicence).toString(); + result += "
" + tr("Default Branch: ") + item->value(RemoteModelColumnDefaultBranch).toString(); + return result; + } + } else if(role == Qt::DisplayRole) { + // Display role? + + // Return different value depending on column + switch(index.column()) + { + case 0: + { + return item->value(RemoteModelColumnName); + } + case 1: + { + return item->value(RemoteModelColumnLastModified); + } + case 2: + { + // Folders don't have a size + if(type == "folder") + return QVariant(); + + // Convert size to human readable format + unsigned int size = item->value(RemoteModelColumnSize).toUInt(); + return humanReadableSize(size); + } + case 3: + { + if(type == "folder") + return QVariant(); + return item->value(RemoteModelColumnCommitId); + } + } + } + + return QVariant(); +} + +QVariant RemoteModel::headerData(int section, Qt::Orientation orientation, int role) const +{ + // Call default implementation for vertical headers and for non-display roles + if(role != Qt::DisplayRole || orientation != Qt::Horizontal) + return QAbstractItemModel::headerData(section, orientation, role); + + // Return header string depending on column + return headerList.at(static_cast(section)); +} + +int RemoteModel::rowCount(const QModelIndex& parent) const +{ + if(parent.column() > 0) + return 0; + + const RemoteModelItem* parentItem = modelIndexToItem(parent); + return parentItem->childCount(); +} + +int RemoteModel::columnCount(const QModelIndex& /*parent*/) const +{ + return static_cast(headerList.size()); +} + +bool RemoteModel::hasChildren(const QModelIndex& parent) const +{ + if(!parent.isValid()) + return true; + + // If the item actually has children or is of type "folder" (and may have no children yet), we say that it actually has children + const RemoteModelItem* item = modelIndexToItem(parent); + return item->childCount() || item->value(RemoteModelColumnType) == "folder"; +} + +bool RemoteModel::canFetchMore(const QModelIndex& parent) const +{ + if(!parent.isValid()) + return false; + + // If the item is of type "folder" and we haven't tried fetching a directory listing yet, we indicate that there might be more data to load + const RemoteModelItem* item = modelIndexToItem(parent); + return item->value(RemoteModelColumnType) == "folder" && !item->fetchedDirectoryList(); +} + +void RemoteModel::fetchMore(const QModelIndex& parent) +{ + // Can we even fetch more data? + if(!canFetchMore(parent)) + return; + + // Get parent item + RemoteModelItem* item = static_cast(parent.internalPointer()); + + // Fetch item URL + item->setFetchedDirectoryList(true); + RemoteNetwork::get().fetch(item->value(RemoteModelColumnUrl).toUrl(), RemoteNetwork::RequestTypeCustom, currentClientCert, [this, parent](const QByteArray& reply) { + parseDirectoryListing(reply, parent); + }); +} + +const QString& RemoteModel::currentClientCertificate() const +{ + return currentClientCert; +} + +const RemoteModelItem* RemoteModel::modelIndexToItem(const QModelIndex& idx) const +{ + if(!idx.isValid()) + return rootItem; + else + return static_cast(idx.internalPointer()); +} diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/RemoteModel.h b/src/WBCLFZSystemModule/SqliteDBProcess/src/RemoteModel.h new file mode 100644 index 0000000..dacabeb --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/RemoteModel.h @@ -0,0 +1,118 @@ +#ifndef REMOTEMODEL_H +#define REMOTEMODEL_H + +#include +#include + +#include + +// List of fields stored in the JSON data +enum RemoteModelColumns +{ + RemoteModelColumnName, + RemoteModelColumnType, + RemoteModelColumnUrl, + RemoteModelColumnCommitId, + RemoteModelColumnSize, + RemoteModelColumnLastModified, + RemoteModelColumnDefaultBranch, + RemoteModelColumnLicence, + RemoteModelColumnOneLineDescription, + RemoteModelColumnPublic, + RemoteModelColumnRepoModified, + RemoteModelColumnSha256, + + RemoteModelColumnCount +}; + +class RemoteModelItem +{ +public: + explicit RemoteModelItem(RemoteModelItem* parent = nullptr); + ~RemoteModelItem(); + + QVariant value(RemoteModelColumns column) const; + void setValue(RemoteModelColumns column, QVariant value); + + bool fetchedDirectoryList() const; + void setFetchedDirectoryList(bool fetched); + + void appendChild(RemoteModelItem* item); + RemoteModelItem* child(int row) const; + RemoteModelItem* parent() const; + int childCount() const; + int row() const; + + // This function assumes the JSON value it's getting passed is an array ("[{...}, {...}, {...}, ...]"). It returns a list of model items, one + // per array entry and each with the specified parent set. + static std::vector loadArray(const nlohmann::json& array, RemoteModelItem* parent = nullptr); + +private: + // These are just the fields from the json objects returned by the dbhub.io server + QVariant m_values[RemoteModelColumnCount]; + + // Child items and parent item + std::vector m_children; + RemoteModelItem* m_parent; + + // Indicates whether we already tried fetching a directory listing for this item. This serves two purposes: + // 1) When having an empty directory this allows us to remove the expandable flag for this item. + // 2) Between sending a network request and getting the reply this flag is already set, avoiding a second or third request being sent in the meantime. + bool m_fetchedDirectoryList; +}; + +class RemoteModel : public QAbstractItemModel +{ + Q_OBJECT + +public: + explicit RemoteModel(QObject* parent); + ~RemoteModel() override; + + void setNewRootDir(const QString& url, const QString& cert); + void refresh(); + + QModelIndex index(int row, int column,const QModelIndex& parent = QModelIndex()) const override; + QModelIndex parent(const QModelIndex& index) const override; + + QVariant data(const QModelIndex& index, int role) const override; + QVariant headerData(int section, Qt::Orientation orientation, int role) const override; + + int rowCount(const QModelIndex& parent = QModelIndex()) const override; + int columnCount(const QModelIndex& parent = QModelIndex()) const override; + bool hasChildren(const QModelIndex& parent) const override; + + bool canFetchMore(const QModelIndex& parent) const override; + void fetchMore(const QModelIndex& parent) override; + + // This helper function takes a model index and returns the according model item. An invalid model index is used to indicate the + // root item, so if the index is invalid the root item is returned. This means that if you need to check for actual invalid indices + // this needs to be done prior to calling this function. + const RemoteModelItem* modelIndexToItem(const QModelIndex& idx) const; + + // Returns the current client certificate + const QString& currentClientCertificate() const; + +signals: + // This signal is emitted whenever a directory listing has been received and parsed + void directoryListingParsed(QModelIndex parent); + +private slots: + // This is called whenever a network reply containing a directory listing arrives + void parseDirectoryListing(const QString& text, QModelIndex parent); + +private: + // The header list is a list of column titles + const std::vector headerList; + + // Pointer to the root item. This contains all the actual item data. + RemoteModelItem* rootItem; + + // This stores the currently used network identity so it can be used for further requests, e.g. for + // lazy population. + QUrl currentRootDirectory; + QString currentClientCert; + QString currentUserName; +}; + +#endif diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/RemoteNetwork.cpp b/src/WBCLFZSystemModule/SqliteDBProcess/src/RemoteNetwork.cpp new file mode 100644 index 0000000..40642b3 --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/RemoteNetwork.cpp @@ -0,0 +1,571 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "FileDialog.h" +#include "RemoteNetwork.h" +#include "Settings.h" +#include "sqlite.h" +#include "version.h" + +using json = nlohmann::json; + +RemoteNetwork::RemoteNetwork() : + m_manager(new QNetworkAccessManager), + m_configurationManager(new QNetworkConfigurationManager), + m_progress(nullptr) +{ + // Update network configurations + connect(m_configurationManager, &QNetworkConfigurationManager::updateCompleted, [this]() { + m_manager->setConfiguration(m_configurationManager->defaultConfiguration()); + + emit networkReady(); + }); + + // Set up SSL configuration + m_sslConfiguration = QSslConfiguration::defaultConfiguration(); + m_sslConfiguration.setPeerVerifyMode(QSslSocket::VerifyPeer); + + // Load CA certs from resource file + QDir dirCaCerts(":/certs"); + QStringList caCertsList = dirCaCerts.entryList(); + QList caCerts; + for(const QString& caCertName : caCertsList) + caCerts += QSslCertificate::fromPath(":/certs/" + caCertName); + m_sslConfiguration.setCaCertificates(caCerts); + + // Load settings and set up some more stuff while doing so + reloadSettings(); + + // Set up signals + connect(m_manager, &QNetworkAccessManager::encrypted, this, &RemoteNetwork::gotEncrypted); + connect(m_manager, &QNetworkAccessManager::sslErrors, this, &RemoteNetwork::gotError); +} + +RemoteNetwork::~RemoteNetwork() +{ + delete m_manager; + delete m_progress; +} + +void RemoteNetwork::reloadSettings() +{ + // Load all configured client certificates + m_clientCertFiles.clear(); + auto client_certs = Settings::getValue("remote", "client_certificates").toStringList(); + for(const QString& path : client_certs) + { + QFile file(path); + file.open(QFile::ReadOnly); + QSslCertificate cert(&file); + file.close(); + m_clientCertFiles.insert({path, cert}); + } + + // Always add the default certificate for anonymous access to dbhub.io + { + QFile file(":/user_certs/public.cert.pem"); + file.open(QFile::ReadOnly); + QSslCertificate cert(&file); + file.close(); + m_clientCertFiles.insert({":/user_certs/public.cert.pem", cert}); + } + + // Configure proxy to use + { + QString type = Settings::getValue("proxy", "type").toString(); + + QNetworkProxy proxy; + if(type == "system") + { + // For system settings we have to get the system-wide proxy and use that + + // Get list of proxies for accessing dbhub.io via HTTPS and use the first one + auto list = QNetworkProxyFactory::systemProxyForQuery(QNetworkProxyQuery(QUrl("https://db4s.dbhub.io/"))); + proxy = list.front(); + } else { + // For any other type we have to set up our own proxy configuration + + // Retrieve the required settings + QString host = Settings::getValue("proxy", "host").toString(); + unsigned short port = static_cast(Settings::getValue("proxy", "port").toUInt()); + bool authentication = Settings::getValue("proxy", "authentication").toBool(); + + if(type == "http") + proxy.setType(QNetworkProxy::HttpProxy); + else if(type == "socks5") + proxy.setType(QNetworkProxy::Socks5Proxy); + else + proxy.setType(QNetworkProxy::NoProxy); + + proxy.setHostName(host); + proxy.setPort(port); + + // Only set authentication details when authentication is required + if(authentication) + { + QString user = Settings::getValue("proxy", "user").toString(); + QString password = Settings::getValue("proxy", "password").toString(); + + proxy.setUser(user); + proxy.setPassword(password); + } + } + + // Start using the new proxy configuration + QNetworkProxy::setApplicationProxy(proxy); + } +} + +void RemoteNetwork::gotEncrypted(QNetworkReply* reply) +{ +#ifdef Q_OS_MAC + // Temporary workaround for now, as Qt 5.8 and below doesn't support + // verifying certificates on OSX: https://bugreports.qt.io/browse/QTBUG-56973 + // Hopefully this is fixed in Qt 5.9 + return; +#else + // Verify the server's certificate using our CA certs + auto verificationErrors = reply->sslConfiguration().peerCertificate().verify(m_sslConfiguration.caCertificates()); + bool good = false; + if(verificationErrors.size() == 0) + { + good = true; + } else if(verificationErrors.size() == 1) { + // Ignore any self signed certificate errors + if(verificationErrors.at(0).error() == QSslError::SelfSignedCertificate || verificationErrors.at(0).error() == QSslError::SelfSignedCertificateInChain) + good = true; + } + + // If the server certificate didn't turn out to be good, abort the reply here + if(!good) + reply->abort(); +#endif +} + +void RemoteNetwork::gotReply(QNetworkReply* reply) +{ + // What type of data is this? + RequestType type = static_cast(reply->property("type").toInt()); + + // Hide progress dialog before opening a file dialog to make sure the progress dialog doesn't interfer with the file dialog + if(type == RequestTypeDatabase || type == RequestTypePush) + m_progress->reset(); + + // Handle the reply data + switch(type) + { + case RequestTypeDatabase: + { + // It's a database file. + + // Get last modified date as provided by the server + QDateTime last_modified; + QString content_disposition = reply->rawHeader("Content-Disposition"); + QRegExp regex("^.*modification-date=\"(.+)\";.*$"); + regex.setMinimal(true); // Set to non-greedy matching + if(regex.indexIn(content_disposition) != -1) + last_modified = QDateTime::fromString(regex.cap(1), Qt::ISODate); + + // Extract all other information from reply and send it to slots + emit fetchFinished(reply->url().fileName(), + reply->property("certfile").toString(), + reply->url(), + QUrlQuery(reply->url()).queryItemValue("commit").toStdString(), + QUrlQuery(reply->url()).queryItemValue("branch").toStdString(), + last_modified, + reply); + } + break; + case RequestTypePush: + { + // Read and check results + json obj = json::parse(reply->readAll(), nullptr, false); + if(obj.is_discarded() || !obj.is_object()) + break; + + // Extract all information from reply and send it to slots + emit pushFinished(reply->url().fileName(), + reply->property("certfile").toString(), + QString::fromStdString(obj["url"]), + obj["commit_id"], + QUrlQuery(QUrl(QString::fromStdString(obj["url"]))).queryItemValue("branch").toStdString(), + reply->property("source_file").toString()); + break; + } + case RequestTypeDownload: + { + // It's a download + + // Where should we save it? + QString path = FileDialog::getSaveFileName(FileDialogTypes::CreateDatabaseFile, + nullptr, + tr("Choose a location to save the file"), + QString(), + reply->url().fileName() + "_" + QUrlQuery(reply->url()).queryItemValue("commit") + ".db"); + if(path.isEmpty()) + break; + + // Save the downloaded data in that file + QFile file(path); + file.open(QIODevice::WriteOnly); + file.write(reply->readAll()); + file.close(); + } + break; + } + + // Delete reply later, i.e. after returning from this slot function + reply->deleteLater(); +} + +void RemoteNetwork::gotError(QNetworkReply* reply, const QList& errors) +{ + // Are there any errors in here that aren't about self-signed certificates and non-matching hostnames? + bool serious_errors = std::any_of(errors.begin(), errors.end(), [](const QSslError& error) { return error.error() != QSslError::SelfSignedCertificate; }); + + // Just stop the error checking here and accept the reply if there were no 'serious' errors + if(!serious_errors) + { + reply->ignoreSslErrors(errors); + return; + } + + // Build an error message and short it to the user + QString message = tr("Error opening remote file at %1.\n%2").arg(reply->url().toString(), errors.at(0).errorString()); + QMessageBox::warning(nullptr, qApp->applicationName(), message); + + // Delete reply later, i.e. after returning from this slot function + if(m_progress) + m_progress->reset(); + reply->deleteLater(); +} + +void RemoteNetwork::updateProgress(qint64 bytesTransmitted, qint64 bytesTotal) +{ + // Find out to which pending reply this progress update belongs + QNetworkReply* reply = qobject_cast(QObject::sender()); + + // Update progress dialog + if(bytesTotal == -1) + { + // We don't know anything about the current progress, but it's still downloading + m_progress->setMinimum(0); + m_progress->setMaximum(0); + m_progress->setValue(0); + } else if(bytesTransmitted == bytesTotal) { + // The download has finished + m_progress->reset(); + } else { + // It's still downloading and we know the current progress + + // Were using a range 0 to 10000 here, the progress dialog will calculate 0% to 100% values from that. The reason we're not using + // the byte counts as-is is that they're 64bit wide while the progress dialog takes only 32bit values, so for large files the values + // would lose precision. The reason why we're not using a range 0 to 100 is that our range increases the precision a bit and this way + // we're prepared if the progress dialog will show decimal numbers one day on one platform. + m_progress->setMinimum(0); + m_progress->setMaximum(10000); + m_progress->setValue(static_cast((static_cast(bytesTransmitted) / static_cast(bytesTotal)) * 10000.0f)); + } + + // Check if the Cancel button has been pressed + if(reply && m_progress->wasCanceled()) + { + reply->abort(); + m_progress->reset(); + } +} + +const QList& RemoteNetwork::caCertificates() const +{ + static QList certs = m_sslConfiguration.caCertificates(); + return certs; +} + +QString RemoteNetwork::getInfoFromClientCert(const QString& cert, CertInfo info) const +{ + // Get the common name of the certificate and split it into user name and server address + QString cn = m_clientCertFiles.at(cert).subjectInfo(QSslCertificate::CommonName).at(0); + QStringList cn_parts = cn.split("@"); + if(cn_parts.size() < 2) + return QString(); + + // Return requested part of the CN + if(info == CertInfoUser) + { + return cn_parts.first(); + } else if(info == CertInfoServer) { + // Assemble the full URL from the host name. We use port 443 by default but for + // local development purposes we use 5550 instead. + QString host = cn_parts.last(); + host = QString("https://%1%2/").arg(host).arg(host.contains("docker-dev") ? ":5550" : ""); + return host; + } + + return QString(); +} + +bool RemoteNetwork::prepareSsl(QNetworkRequest* request, const QString& clientCert) +{ + // Check if client cert exists + const QSslCertificate& cert = m_clientCertFiles[clientCert]; + if(cert.isNull()) + { + QMessageBox::warning(nullptr, qApp->applicationName(), tr("Error: Invalid client certificate specified.")); + return false; + } + + // Load private key for the client certificate + QFile fileClientCert(clientCert); + fileClientCert.open(QFile::ReadOnly); + QSslKey clientKey(&fileClientCert, QSsl::Rsa, QSsl::Pem, QSsl::PrivateKey); + while(clientKey.isNull()) + { + // If the private key couldn't be read, we assume it's password protected. So ask the user for the correct password and try reading it + // again. If the user cancels the password dialog, abort the whole process. + QString password = QInputDialog::getText(nullptr, qApp->applicationName(), tr("Please enter the passphrase for this client certificate in order to authenticate.")); + if(password.isEmpty()) + return false; + clientKey = QSslKey(&fileClientCert, QSsl::Rsa, QSsl::Pem, QSsl::PrivateKey, password.toUtf8()); + } + fileClientCert.close(); + + // Set client certificate (from the cache) and private key (just loaded) + m_sslConfiguration.setLocalCertificate(cert); + m_sslConfiguration.setPrivateKey(clientKey); + + // Apply SSL configuration + request->setSslConfiguration(m_sslConfiguration); + + return true; +} + +void RemoteNetwork::prepareProgressDialog(QNetworkReply* reply, bool upload, const QUrl& url) +{ + // Instantiate progress dialog and apply some basic settings + if(!m_progress) + m_progress = new QProgressDialog(); + m_progress->reset(); + m_progress->setWindowModality(Qt::NonModal); + m_progress->setCancelButtonText(tr("Cancel")); + + // Set dialog text + QString url_for_display = url.toString(QUrl::PrettyDecoded | QUrl::RemoveQuery); + if(upload) + m_progress->setLabelText(tr("Uploading remote database to\n%1").arg(url_for_display)); + else + m_progress->setLabelText(tr("Downloading remote database from\n%1").arg(url_for_display)); + + // Show dialog + m_progress->show(); + + // Make sure the dialog is updated + if(upload) + connect(reply, &QNetworkReply::uploadProgress, this, &RemoteNetwork::updateProgress); + else + connect(reply, &QNetworkReply::downloadProgress, this, &RemoteNetwork::updateProgress); +} + +void RemoteNetwork::fetch(const QUrl& url, RequestType type, const QString& clientCert, + std::function when_finished, bool synchronous, bool ignore_errors) +{ + // Check if network is accessible. If not, abort right here + if(m_manager->networkAccessible() == QNetworkAccessManager::NotAccessible) + { + QMessageBox::warning(nullptr, qApp->applicationName(), tr("Error: The network is not accessible.")); + return; + } + + // Build network request + QNetworkRequest request; + request.setUrl(url); + request.setRawHeader("User-Agent", QString("%1 %2").arg(qApp->organizationName(), APP_VERSION).toUtf8()); +#if QT_VERSION >= QT_VERSION_CHECK(5, 6, 0) + request.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true); +#endif + + // Set SSL configuration when trying to access a file via the HTTPS protocol. + // Skip this step when no client certificate was specified. In this case the default HTTPS configuration is used. + bool https = url.scheme().compare("https", Qt::CaseInsensitive) == 0; + if(https && !clientCert.isNull()) + { + // If configuring the SSL connection fails, abort the request here + if(!prepareSsl(&request, clientCert)) + return; + } + + // Clear access cache if necessary + clearAccessCache(clientCert); + + // Fetch database and prepare pending reply for future processing + QNetworkReply* reply = m_manager->get(request); + reply->setProperty("type", type); + reply->setProperty("certfile", clientCert); + reply->setProperty("ignore_errors", ignore_errors); + + // Hook up custom handler when there is one and global handler otherwise + if(when_finished) + { + connect(reply, &QNetworkReply::finished, reply, [this, when_finished, reply]() { + if(handleReply(reply)) + when_finished(reply->readAll()); + }); + } else { + connect(reply, &QNetworkReply::finished, this, [this, reply]() { + if(handleReply(reply)) + gotReply(reply); + }); + } + + // When the synchrounous flag is set we wait for the request to finish before continuing + if(synchronous) + { + QEventLoop loop; + connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit); + loop.exec(); + } + + // Initialise the progress dialog for this request, but only if this is a database file or a download. + // Directory listing and similar are small enough to be loaded without progress dialog. + if(type == RequestTypeDatabase || type == RequestTypeDownload) + prepareProgressDialog(reply, false, url); +} + +void RemoteNetwork::push(const QString& filename, const QUrl& url, const QString& clientCert, const QString& remotename, + const QString& commitMessage, const QString& licence, bool isPublic, const QString& branch, + bool forcePush, const QString& last_commit) +{ + // Check if network is accessible. If not, abort right here + if(m_manager->networkAccessible() == QNetworkAccessManager::NotAccessible) + { + QMessageBox::warning(nullptr, qApp->applicationName(), tr("Error: The network is not accessible.")); + return; + } + + // Open the file to send and check if it exists + QFile* file = new QFile(filename); + if(!file->open(QFile::ReadOnly)) + { + delete file; + QMessageBox::warning(nullptr, qApp->applicationName(), tr("Error: Cannot open the file for sending.")); + return; + } + + // Build network request + QNetworkRequest request; + request.setUrl(url); + request.setRawHeader("User-Agent", QString("%1 %2").arg(qApp->organizationName(), APP_VERSION).toUtf8()); + + // Get the last modified date of the file and prepare it for conversion into the ISO date format + QDateTime last_modified = QFileInfo(filename).lastModified().toOffsetFromUtc(0); + + // Prepare HTTP multi part data containing all the information about the commit we're about to push + QHttpMultiPart* multipart = new QHttpMultiPart(QHttpMultiPart::FormDataType); + addPart(multipart, "file", file, remotename); + addPart(multipart, "commitmsg", commitMessage); + addPart(multipart, "licence", licence); + addPart(multipart, "public", isPublic ? "true" : "false"); + addPart(multipart, "branch", branch); + addPart(multipart, "force", forcePush ? "true" : "false"); + addPart(multipart, "lastmodified", last_modified.toString("yyyy-MM-dd'T'HH:mm:ss'Z'")); + + // Only add commit id if one was provided + if(!last_commit.isEmpty()) + addPart(multipart, "commit", last_commit); + + // Set SSL configuration when trying to access a file via the HTTPS protocol + bool https = url.scheme().compare("https", Qt::CaseInsensitive) == 0; + if(https) + { + // If configuring the SSL connection fails, abort the request here + if(!prepareSsl(&request, clientCert)) + { + delete file; + return; + } + } + + // Clear access cache if necessary + clearAccessCache(clientCert); + + // Put database to remote server and save pending reply for future processing + QNetworkReply* reply = m_manager->post(request, multipart); + reply->setProperty("type", RequestTypePush); + reply->setProperty("certfile", clientCert); + reply->setProperty("source_file", filename); + multipart->setParent(reply); // Delete the multi-part object along with the reply + + // Connect reply handler + connect(reply, &QNetworkReply::finished, this, [this, reply]() { + if(handleReply(reply)) + gotReply(reply); + }); + + // Initialise the progress dialog for this request + prepareProgressDialog(reply, true, url); +} + +void RemoteNetwork::addPart(QHttpMultiPart* multipart, const QString& name, const QString& value) const +{ + QHttpPart part; + part.setHeader(QNetworkRequest::ContentDispositionHeader, QString("form-data; name=\"%1\"").arg(name)); + part.setBody(value.toUtf8()); + + multipart->append(part); +} + +void RemoteNetwork::addPart(QHttpMultiPart* multipart, const QString& name, QFile* file, const QString& filename) const +{ + QHttpPart part; + part.setHeader(QNetworkRequest::ContentDispositionHeader, QString("form-data; name=\"%1\"; filename=\"%2\"").arg(name, filename)); + part.setBodyDevice(file); + file->setParent(multipart); // Close the file and delete the file object as soon as the multi-part object is destroyed + + multipart->append(part); +} + +void RemoteNetwork::clearAccessCache(const QString& clientCert) +{ + // When the client certificate is different from the one before, clear the access and authentication cache. + // Otherwise Qt might use the old certificate again. + static QString lastClientCert; + if(lastClientCert != clientCert) + { + lastClientCert = clientCert; + m_manager->clearAccessCache(); + } +} + +bool RemoteNetwork::handleReply(QNetworkReply* reply) +{ + // Check if request was successful + if(reply->error() != QNetworkReply::NoError) + { + // Do not show error message when operation was cancelled on purpose + if(reply->error() != QNetworkReply::OperationCanceledError && !reply->property("ignore_errors").toBool()) + { + QMessageBox::warning(nullptr, qApp->applicationName(), + reply->errorString() + "\n" + reply->readAll()); + } + + reply->deleteLater(); + return false; + } + + return true; +} diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/RemoteNetwork.h b/src/WBCLFZSystemModule/SqliteDBProcess/src/RemoteNetwork.h new file mode 100644 index 0000000..1a8265a --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/RemoteNetwork.h @@ -0,0 +1,97 @@ +#ifndef REMOTENETWORK_H +#define REMOTENETWORK_H + +#include +#include + +#include +#include + +class QNetworkAccessManager; +class QNetworkConfigurationManager; +class QNetworkReply; +class QProgressDialog; +class QNetworkRequest; +class QHttpMultiPart; +class QFile; + +class RemoteNetwork : public QObject +{ + Q_OBJECT + +public: + static RemoteNetwork& get() + { + static RemoteNetwork instance; + return instance; + } + + void reloadSettings(); + + enum CertInfo + { + CertInfoUser, + CertInfoServer, + }; + + const QList& caCertificates() const; + const std::map& clientCertificates() const { return m_clientCertFiles; } + QString getInfoFromClientCert(const QString& cert, CertInfo info) const; + + enum RequestType + { + RequestTypeCustom, + RequestTypeDatabase, + RequestTypePush, + RequestTypeDownload, + }; + + void fetch(const QUrl& url, RequestType type, const QString& clientCert = QString(), + std::function when_finished = {}, bool synchronous = false, bool ignore_errors = false); + void push(const QString& filename, const QUrl& url, const QString& clientCert, const QString& remotename, + const QString& commitMessage = QString(), const QString& licence = QString(), bool isPublic = false, + const QString& branch = QString("master"), bool forcePush = false, const QString& last_commit = QString()); + +signals: + // As soon as you can safely open a network connection, this signal is emitted. This can be used to delay early network requests + // which might otherwise fail. + void networkReady(); + + // The fetchFinished() signal is emitted when a fetch() call for a database is finished + void fetchFinished(QString filename, QString identity, const QUrl& url, std::string new_commit_id, std::string branch, + QDateTime last_modified, QIODevice* device); + + // The pushFinished() signal is emitted when a push() call is finished, i.e. a database upload has completed. + void pushFinished(QString filename, QString identity, const QUrl& url, std::string new_commit_id, std::string branch, QString source_file); + +private: + RemoteNetwork(); + ~RemoteNetwork() override; + + void gotEncrypted(QNetworkReply* reply); + void gotReply(QNetworkReply* reply); + void gotError(QNetworkReply* reply, const QList& errors); + void updateProgress(qint64 bytesTransmitted, qint64 bytesTotal); + bool prepareSsl(QNetworkRequest* request, const QString& clientCert); + void prepareProgressDialog(QNetworkReply* reply, bool upload, const QUrl& url); + + // Helper functions for building multi-part HTTP requests + void addPart(QHttpMultiPart* multipart, const QString& name, const QString& value) const; + void addPart(QHttpMultiPart* multipart, const QString& name, QFile* file, const QString& filename) const; + + // Before using a new client certificate we need to clear the access and authentication cache of the network manager + // object. Otherwise Qt might reuse the old certificate if the requested URL has been used before. + void clearAccessCache(const QString& clientCert); + + // This function is called for all network replies we get whether they are handled globally or individually. + // It mainly does some error checking and returns true if the actual handler should be called. + bool handleReply(QNetworkReply* reply); + + QNetworkAccessManager* m_manager; + QNetworkConfigurationManager* m_configurationManager; + QProgressDialog* m_progress; + QSslConfiguration m_sslConfiguration; + std::map m_clientCertFiles; +}; + +#endif diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/RemotePushDialog.cpp b/src/WBCLFZSystemModule/SqliteDBProcess/src/RemotePushDialog.cpp new file mode 100644 index 0000000..e99db1d --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/RemotePushDialog.cpp @@ -0,0 +1,174 @@ +#include +#include +#include + +#include + +#include "RemotePushDialog.h" +#include "ui_RemotePushDialog.h" +#include "RemoteNetwork.h" + +using json = nlohmann::json; + +RemotePushDialog::RemotePushDialog(QWidget* parent, const QString& host, const QString& clientCert, + const QString& name, const QString& branch, const QString& user) : + QDialog(parent), + ui(new Ui::RemotePushDialog), + m_host(host), + m_clientCert(clientCert), + m_nameValidator(new QRegExpValidator(QRegExp("^[a-z,A-Z,0-9,\\.,\\-,\\_,\\(,\\),\\+,\\ ]+$"), this)), + m_branchValidator(new QRegExpValidator(QRegExp("^[a-z,A-Z,0-9,\\^,\\.,\\-,\\_,\\/,\\(,\\),\\:,\\&,\\ )]+$"), this)) +{ + // Create UI + ui->setupUi(this); + ui->editName->setValidator(m_nameValidator); + ui->comboBranch->setValidator(m_branchValidator); + ui->comboUser->setValidator(m_nameValidator); + + // Set start values + ui->editName->setText(name); + + // Fill in usernames + ui->comboUser->addItem(RemoteNetwork::get().getInfoFromClientCert(m_clientCert, RemoteNetwork::CertInfoUser)); + if(!user.isEmpty()) + ui->comboUser->addItem(user); + + // Enable/disable accept button + checkInput(); + + // Fetch list of available licences + RemoteNetwork::get().fetch(host + "licence/list", RemoteNetwork::RequestTypeCustom, clientCert, [this](const QByteArray& reply) { + // Clear licence list + ui->comboLicence->clear(); + + // Read and check results + json obj = json::parse(reply, nullptr, false); + if(obj.is_discarded() || !obj.is_object()) + return; + + // Parse data and build ordered licence map: order -> (short name, long name) + std::map> licences; + for(auto it=obj.cbegin();it!=obj.cend();++it) + licences.insert({it.value()["order"], {it.key(), it.value()["full_name"]}}); + + // Parse licence list and fill combo box. Show the full name to the user and use the short name as user data. + for(auto it=licences.begin();it!=licences.end();++it) + ui->comboLicence->addItem(QString::fromStdString(it->second.second), QString::fromStdString(it->second.first)); + }); + + // Fetch list of exsisting branches + reloadBranchList(branch); +} + +RemotePushDialog::~RemotePushDialog() +{ + delete ui; +} + +void RemotePushDialog::checkInput() +{ + // Update public/private check box text + if(ui->checkPublic->isChecked()) + ui->checkPublic->setText(tr("Database will be public. Everyone has read access to it.")); + else + ui->checkPublic->setText(tr("Database will be private. Only you have access to it.")); + + // Update the foce push check box text + if(ui->checkForce->isChecked()) + ui->checkForce->setText(tr("Use with care. This can cause remote commits to be deleted.")); + else + ui->checkForce->setText(" "); // The space character here is required to avoid annoying resizes when toggling the checkbox + + // Check input + bool valid = true; + + if(ui->editName->text().trimmed().isEmpty()) + valid = false; + + if(ui->editCommitMessage->toPlainText().size() > 1024) + valid = false; + + if(ui->comboBranch->currentText().size() < 1 || ui->comboBranch->currentText().size() > 32) + valid = false; + + if(ui->comboUser->currentText().trimmed().isEmpty()) + valid = false; + + ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(valid); +} + +void RemotePushDialog::accept() +{ + QDialog::accept(); +} + +QString RemotePushDialog::name() const +{ + return ui->editName->text().trimmed(); +} + +QString RemotePushDialog::commitMessage() const +{ + return ui->editCommitMessage->toPlainText().trimmed(); +} + +QString RemotePushDialog::licence() const +{ + return ui->comboLicence->currentData(Qt::UserRole).toString(); +} + +bool RemotePushDialog::isPublic() const +{ + return ui->checkPublic->isChecked(); +} + +QString RemotePushDialog::branch() const +{ + return ui->comboBranch->currentText(); +} + +QString RemotePushDialog::user() const +{ + return ui->comboUser->currentText(); +} + +bool RemotePushDialog::forcePush() const +{ + return ui->checkForce->isChecked(); +} + +void RemotePushDialog::reloadBranchList(const QString& select_branch) +{ + QUrl url(m_host + "branch/list"); + QUrlQuery query; + query.addQueryItem("username", ui->comboUser->currentText()); + query.addQueryItem("folder", "/"); + query.addQueryItem("dbname", ui->editName->text()); + url.setQuery(query); + RemoteNetwork::get().fetch(url.toString(), RemoteNetwork::RequestTypeCustom, m_clientCert, [this, select_branch](const QByteArray& reply) { + // Read and check results + json obj = json::parse(reply, nullptr, false); + if(obj.is_discarded() || !obj.is_object()) + return; + json obj_branches = obj["branches"]; + + // Get default branch + std::string default_branch = (obj.contains("default_branch") && !obj["default_branch"].empty()) ? obj["default_branch"] : "master"; + + // Clear branch list and add the default branch + ui->comboBranch->clear(); + ui->comboBranch->addItem(QString::fromStdString(default_branch)); + + // Parse data and assemble branch list + std::vector branches; + for(auto it=obj_branches.cbegin();it!=obj_branches.cend();++it) + { + if(it.key() != default_branch) + ui->comboBranch->addItem(QString::fromStdString(it.key())); + } + + // If a branch was suggested, select it now + if(!select_branch.isEmpty()) + ui->comboBranch->setCurrentIndex(ui->comboBranch->findText(select_branch)); + }, false, true); +} diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/RemotePushDialog.h b/src/WBCLFZSystemModule/SqliteDBProcess/src/RemotePushDialog.h new file mode 100644 index 0000000..e2c6b36 --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/RemotePushDialog.h @@ -0,0 +1,46 @@ +#ifndef REMOTEPUSHDIALOG_H +#define REMOTEPUSHDIALOG_H + +#include + +class QRegExpValidator; + +namespace Ui { +class RemotePushDialog; +} + +class RemotePushDialog : public QDialog +{ + Q_OBJECT + +public: + explicit RemotePushDialog(QWidget* parent, const QString& host, const QString& clientCert, + const QString& name = QString(), const QString& branch = QString(), const QString& user = QString()); + ~RemotePushDialog() override; + + QString name() const; + QString commitMessage() const; + QString licence() const; + bool isPublic() const; + QString branch() const; + QString user() const; + bool forcePush() const; + +private: + Ui::RemotePushDialog* ui; + + // Connection details + QString m_host; + QString m_clientCert; + + // Validators + QRegExpValidator* m_nameValidator; + QRegExpValidator* m_branchValidator; + +protected slots: + void checkInput(); + void reloadBranchList(const QString& select_branch = QString()); + void accept() override; +}; + +#endif diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/RemotePushDialog.ui b/src/WBCLFZSystemModule/SqliteDBProcess/src/RemotePushDialog.ui new file mode 100644 index 0000000..49dab0c --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/RemotePushDialog.ui @@ -0,0 +1,333 @@ + + + RemotePushDialog + + + + 0 + 0 + 583 + 315 + + + + Push database + + + + + + + + Database na&me to push to + + + editName + + + + + + + 256 + + + + + + + Commit message + + + editCommitMessage + + + + + + + <!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;"><br /></p></body></html> + + + false + + + + + + + Database licence + + + comboLicence + + + + + + + + 0 + 0 + + + + + + + + Public + + + checkPublic + + + + + + + + + + Branch + + + comboBranch + + + + + + + true + + + true + + + + + + + Force push + + + checkForce + + + + + + + + + + Username + + + comboUser + + + + + + + true + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + editName + editCommitMessage + comboBranch + checkPublic + comboLicence + comboUser + checkForce + + + + + buttonBox + accepted() + RemotePushDialog + accept() + + + 257 + 305 + + + 157 + 274 + + + + + buttonBox + rejected() + RemotePushDialog + reject() + + + 325 + 305 + + + 286 + 274 + + + + + editName + textChanged(QString) + RemotePushDialog + checkInput() + + + 201 + 25 + + + 217 + 3 + + + + + checkPublic + toggled(bool) + RemotePushDialog + checkInput() + + + 345 + 181 + + + 210 + 175 + + + + + editCommitMessage + textChanged() + RemotePushDialog + checkInput() + + + 175 + 113 + + + 91 + 111 + + + + + editName + textChanged(QString) + RemotePushDialog + reloadBranchList() + + + 176 + 25 + + + 77 + 3 + + + + + comboBranch + currentTextChanged(QString) + RemotePushDialog + checkInput() + + + 346 + 160 + + + 33 + 151 + + + + + checkForce + toggled(bool) + RemotePushDialog + checkInput() + + + 342 + 269 + + + 62 + 229 + + + + + comboUser + currentTextChanged(QString) + RemotePushDialog + reloadBranchList() + + + 373 + 235 + + + 291 + 157 + + + + + comboUser + currentTextChanged(QString) + RemotePushDialog + checkInput() + + + 373 + 235 + + + 291 + 157 + + + + + + checkInput() + reloadBranchList() + + diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/RowCache.h b/src/WBCLFZSystemModule/SqliteDBProcess/src/RowCache.h new file mode 100644 index 0000000..182c986 --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/RowCache.h @@ -0,0 +1,264 @@ +#ifndef ROW_CACHE_H +#define ROW_CACHE_H + +#include +#include +#include +#include + +/** + + cache structure adapted to the existing access patterns in + SqliteTableModel. handles many large segments with gaps in between + well. + + logical structure resembling a std::vector>, but + implementation avoids actually allocating space for the non-empty + optionals, and supports (hopefully) more efficient insertion / + deletion. + + actually, this is not even a "cache" - once set, elements are never + thrown away to make space for new elements. + + TODO introduce maximum segment size? + +**/ +template +class RowCache +{ +public: + using value_type = T; + + /// constructs an empty cache + explicit RowCache (); + + /// \returns number of cached rows + size_t numSet () const; + + /// \returns number of segments + size_t numSegments () const; + + /// \returns 1 if specified row is loaded, 0 otherwise + size_t count (size_t pos) const; + + /// \returns specified row. \throws if not available + const T & at (size_t pos) const; + T & at (size_t pos); + + /// assigns value to specified row; may increase numSet() by one + void set (size_t pos, T && value); + + /// insert new element; increases numSet() by one + void insert (size_t pos, T && value); + + /// delete element; decreases numSet() by one + void erase (size_t pos); + + /// reset to state after construction + void clear (); + + /// given a range of rows (end is exclusive), narrow it in order + /// to remove already-loaded rows from both ends. + void smallestNonAvailableRange (size_t & row_begin, size_t & row_end) const; + +private: + /// a single segment containing contiguous entries + struct Segment + { + size_t pos_begin; + std::vector entries; + + /// returns past-the-end position of this segment + size_t pos_end () const { return pos_begin + entries.size(); } + }; + + /// collection of non-overlapping segments, in order of increasing + /// position + using Segments = std::vector; + Segments segments; + + // ------------------------------------------------------------------------------ + + /// \returns first segment that definitely cannot contain 'pos', + /// because it starts at some later position. + typename Segments::const_iterator getSegmentBeyond (size_t pos) const { + // first segment whose pos_begin > pos (so can't contain pos itself): + return std::upper_bound(segments.begin(), segments.end(), pos, pred); + } + + typename Segments::iterator getSegmentBeyond (size_t pos) { + return std::upper_bound(segments.begin(), segments.end(), pos, pred); + } + + static bool pred (size_t pos, const Segment & s) { return pos < s.pos_begin; } + + // ------------------------------------------------------------------------------ + + /// \returns segment containing 'pos' + typename Segments::const_iterator getSegmentContaining (size_t pos) const + { + auto it = getSegmentBeyond(pos); + + if(it != segments.begin()) { + auto prev_it = it - 1; + if(pos < prev_it->pos_end()) + return prev_it; + } + + return segments.end(); + } + +}; + +template +RowCache::RowCache () +{ +} + +template +size_t RowCache::numSet () const +{ + return std::accumulate(segments.begin(), segments.end(), size_t(0), + [](size_t r, const Segment & s) { return r + s.entries.size(); }); +} + +template +size_t RowCache::numSegments () const +{ + return segments.size(); +} + +template +size_t RowCache::count (size_t pos) const +{ + return getSegmentContaining(pos) != segments.end(); +} + +template +const T & RowCache::at (size_t pos) const +{ + auto it = getSegmentContaining(pos); + + if(it != segments.end()) + return it->entries[pos - it->pos_begin]; + + throw std::out_of_range("no matching segment found"); +} + +template +T & RowCache::at (size_t pos) +{ + return const_cast(static_cast(*this).at(pos)); +} + +template +void RowCache::set (size_t pos, T && value) +{ + auto it = getSegmentBeyond(pos); + + if(it != segments.begin()) + { + auto prev_it = it - 1; + auto d = pos - prev_it->pos_begin; // distance from segment start (>=0) + + if(d < prev_it->entries.size()) + { + // replace value + prev_it->entries[d] = std::move(value); + return; + } + + if(d == prev_it->entries.size()) + { + // extend existing segment + prev_it->entries.insert(prev_it->entries.end(), std::move(value)); + return; + } + } + + // make new segment + segments.insert(it, { pos, { std::move(value) } }); +} + +template +void RowCache::insert (size_t pos, T && value) +{ + auto it = getSegmentBeyond(pos); + + if(it != segments.begin()) + { + auto prev_it = it - 1; + auto d = pos - prev_it->pos_begin; // distance from segment start (>=0) + + if(d <= prev_it->entries.size()) + { + // can extend existing segment + prev_it->entries.insert(prev_it->entries.begin() + d, std::move(value)); + goto push; + } + } + + // make new segment + it = segments.insert(it, { pos, { std::move(value) } }) + 1; + +push: + // push back all later segments + std::for_each(it, segments.end(), [](Segment &s){ s.pos_begin++; }); +} + +template +void RowCache::erase (size_t pos) +{ + auto it = getSegmentBeyond(pos); + + // if previous segment actually contains pos, shorten it + if(it != segments.begin()) + { + auto prev_it = it - 1; + auto d = pos - prev_it->pos_begin; // distance from segment start (>=0) + + if(d < prev_it->entries.size()) + { + prev_it->entries.erase(prev_it->entries.begin() + d); + if(prev_it->entries.empty()) + { + it = segments.erase(prev_it); + } + } + } + + // pull forward all later segments + std::for_each(it, segments.end(), [](Segment &s){ s.pos_begin--; }); +} + +template +void RowCache::clear () +{ + segments.clear(); +} + +template +void RowCache::smallestNonAvailableRange (size_t & row_begin, size_t & row_end) const +{ + if(row_end < row_begin) + throw std::invalid_argument("end must be >= begin"); + + while(row_begin < row_end) { + auto it = getSegmentContaining(row_begin); + if(it == segments.end()) + break; + row_begin = it->pos_end(); + } + + while(row_end > row_begin) { + auto it = getSegmentContaining(row_end - 1); + if(it == segments.end()) + break; + row_end = it->pos_begin; + } + + if(row_end < row_begin) + row_end = row_begin; +} + +#endif // SEGMENTING_CACHE_H diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/RowLoader.cpp b/src/WBCLFZSystemModule/SqliteDBProcess/src/RowLoader.cpp new file mode 100644 index 0000000..e7d4b2c --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/RowLoader.cpp @@ -0,0 +1,256 @@ +#include + +#include "RowLoader.h" +#include "sqlite.h" + +namespace { + + QString rtrimChar(const QString& s, QChar c) + { + QString r = s.trimmed(); + while(r.endsWith(c)) + r.chop(1); + return r; + } + +} // anon ns + + +RowLoader::RowLoader ( + std::function(void)> db_getter_, + std::function statement_logger_, + std::vector & headers_, + std::mutex & cache_mutex_, + Cache & cache_data_ + ) + : db_getter(db_getter_), statement_logger(statement_logger_), headers(headers_) + , cache_mutex(cache_mutex_), cache_data(cache_data_) + , query() + , countQuery() + , num_tasks(0) + , pDb(nullptr) + , stop_requested(false) + , current_task(nullptr) + , next_task(nullptr) +{ +} + +void RowLoader::setQuery (const QString& new_query, const QString& newCountQuery) +{ + std::lock_guard lk(m); + query = new_query; + if (newCountQuery.isEmpty()) + // If it is a normal query - hopefully starting with SELECT - just do a COUNT on it and return the results + countQuery = QString("SELECT COUNT(*) FROM (%1);").arg(rtrimChar(query, ';')); + else + countQuery = newCountQuery; +} + +void RowLoader::triggerRowCountDetermination(int token) +{ + std::unique_lock lk(m); + + num_tasks++; + nosync_ensureDbAccess(); + + // do a count query to get the full row count in a fast manner + row_counter = std::async(std::launch::async, [this, token]() { + auto nrows = countRows(); + if(nrows >= 0) + emit rowCountComplete(token, nrows); + + std::lock_guard lk2(m); + nosync_taskDone(); + }); +} + +void RowLoader::nosync_ensureDbAccess () +{ + if(!pDb) + pDb = db_getter(); +} + +std::shared_ptr RowLoader::getDb () const +{ + std::lock_guard lk(m); + return pDb; +} + +int RowLoader::countRows() const +{ + int retval = -1; + + // Use a different approach of determining the row count when a EXPLAIN or a PRAGMA statement is used because a COUNT fails on these queries + if(query.startsWith("EXPLAIN", Qt::CaseInsensitive) || query.startsWith("PRAGMA", Qt::CaseInsensitive)) + { + // So just execute the statement as it is and fetch all results counting the rows + sqlite3_stmt* stmt; + QByteArray utf8Query = query.toUtf8(); + if(sqlite3_prepare_v2(pDb.get(), utf8Query, utf8Query.size(), &stmt, nullptr) == SQLITE_OK) + { + retval = 0; + while(sqlite3_step(stmt) == SQLITE_ROW) + retval++; + sqlite3_finalize(stmt); + return retval; + } + } else { + statement_logger(countQuery); + QByteArray utf8Query = countQuery.toUtf8(); + + sqlite3_stmt* stmt; + if(sqlite3_prepare_v2(pDb.get(), utf8Query, utf8Query.size(), &stmt, nullptr) == SQLITE_OK) + { + if(sqlite3_step(stmt) == SQLITE_ROW) + retval = sqlite3_column_int(stmt, 0); + sqlite3_finalize(stmt); + } else { + qWarning() << "Count query failed: " << countQuery; + } + } + + return retval; +} + +void RowLoader::triggerFetch (int token, size_t row_begin, size_t row_end) +{ + std::unique_lock lk(m); + + if(pDb) { + if(!row_counter.valid() || row_counter.wait_for(std::chrono::seconds(0)) == std::future_status::ready) { + // only if row count is complete, we can safely interrupt SQLite to speed up cancellation + sqlite3_interrupt(pDb.get()); + } + } + + if(current_task) + current_task->cancel = true; + + nosync_ensureDbAccess(); + + // (forget a possibly already existing "next task") + next_task.reset(new Task{ *this, token, row_begin, row_end }); + + lk.unlock(); + cv.notify_all(); +} + +void RowLoader::nosync_taskDone() +{ + if(--num_tasks == 0) { + pDb = nullptr; + } +} + +void RowLoader::cancel () +{ + std::unique_lock lk(m); + + if(pDb) + sqlite3_interrupt(pDb.get()); + + if(current_task) + current_task->cancel = true; + + next_task = nullptr; + cv.notify_all(); +} + +void RowLoader::stop () +{ + cancel(); + std::unique_lock lk(m); + stop_requested = true; + cv.notify_all(); +} + +bool RowLoader::readingData () const +{ + std::unique_lock lk(m); + return pDb != nullptr; +} + +void RowLoader::waitUntilIdle () const +{ + if(row_counter.valid()) + row_counter.wait(); + std::unique_lock lk(m); + cv.wait(lk, [this](){ return stop_requested || (!current_task && !next_task); }); +} + +void RowLoader::run () +{ + for(;;) + { + std::unique_lock lk(m); + current_task = nullptr; + cv.notify_all(); + + cv.wait(lk, [this](){ return stop_requested || next_task; }); + + if(stop_requested) + return; + + current_task = std::move(next_task); + lk.unlock(); + + process(*current_task); + } +} + +void RowLoader::process (Task & t) +{ + QString sLimitQuery; + if(query.startsWith("PRAGMA", Qt::CaseInsensitive) || query.startsWith("EXPLAIN", Qt::CaseInsensitive)) + { + sLimitQuery = query; + } else { + // Remove trailing trailing semicolon + QString queryTemp = rtrimChar(query, ';'); + + // If the query ends with a LIMIT statement or contains a compound operator take it as it is, + // if not append our own LIMIT part for lazy population. The compound operator test is a very + // weak check and does not detect whether the keyword is in a string or similar. This means + // that lazy population is disabled for more queries than necessary. We should fix this once + // we have a parser for SELECT statements but until then it is better to disable lazy population + // for more statements than required instead of failing to run some statements entirely. + if(queryTemp.contains(QRegExp("LIMIT\\s+.+\\s*((,|\\b(OFFSET)\\b)\\s*.+\\s*)?$", Qt::CaseInsensitive)) || + queryTemp.contains(QRegExp("\\s(UNION)|(INTERSECT)|(EXCEPT)\\s", Qt::CaseInsensitive))) + sLimitQuery = queryTemp; + else + sLimitQuery = queryTemp + QString(" LIMIT %1, %2;").arg(t.row_begin).arg(t.row_end-t.row_begin); + } + statement_logger(sLimitQuery); + + QByteArray utf8Query = sLimitQuery.toUtf8(); + sqlite3_stmt *stmt; + auto row = t.row_begin; + if(sqlite3_prepare_v2(pDb.get(), utf8Query, utf8Query.size(), &stmt, nullptr) == SQLITE_OK) + { + const size_t num_columns = headers.size(); + + while(!t.cancel && sqlite3_step(stmt) == SQLITE_ROW) + { + // Construct a new row object with the right number of columns + Cache::value_type rowdata(num_columns); + for(size_t i=0;i(i)) != SQLITE_NULL) + { + int bytes = sqlite3_column_bytes(stmt, static_cast(i)); + if(bytes) + rowdata[i] = QByteArray(static_cast(sqlite3_column_blob(stmt, static_cast(i))), bytes); + else + rowdata[i] = ""; + } + } + std::lock_guard lk(cache_mutex); + cache_data.set(row++, std::move(rowdata)); + } + + sqlite3_finalize(stmt); + } + + emit fetched(t.token, t.row_begin, row); +} diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/RowLoader.h b/src/WBCLFZSystemModule/SqliteDBProcess/src/RowLoader.h new file mode 100644 index 0000000..772834e --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/RowLoader.h @@ -0,0 +1,122 @@ +#ifndef ROW_LOADER_H +#define ROW_LOADER_H + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "RowCache.h" + +struct sqlite3; + +class RowLoader : public QThread +{ + Q_OBJECT + + void run() override; + +public: + using Cache = RowCache>; + + /// set up worker thread to handle row loading + explicit RowLoader ( + std::function(void)> db_getter, + std::function statement_logger, + std::vector & headers, + std::mutex & cache_mutex, + Cache & cache_data + ); + + void setQuery (const QString& new_query, const QString& newCountQuery = QString()); + + void triggerRowCountDetermination (int token); + + /// trigger asynchronous reading of specified row range, + /// cancelling previous tasks; 'row_end' is exclusive; \param + /// token is eventually returned through the 'fetched' + /// signal. depending on how and when tasks are cancelled, not + /// every triggerFetch() will result in a 'fetched' signal, or the + /// 'fetched' signal may be for a narrower row range. + void triggerFetch (int token, size_t row_begin, size_t row_end); + + /// cancel everything + void cancel (); + + /// cancel everything and terminate worker thread + void stop (); + + /// currently reading any data, or anything in "queue"? + bool readingData () const; + + /// wait until not reading any data + void waitUntilIdle () const; + + /// get current database - note that the worker thread might be + /// working on it, too... \returns current db, or nullptr. + std::shared_ptr getDb () const; + +signals: + void fetched(int token, size_t row_begin, size_t row_end); + void rowCountComplete(int token, int num_rows); + +private: + const std::function()> db_getter; + const std::function statement_logger; + std::vector & headers; + std::mutex & cache_mutex; + Cache & cache_data; + + mutable std::mutex m; + mutable std::condition_variable cv; + + QString query; + QString countQuery; + + mutable std::future row_counter; + + size_t num_tasks; + std::shared_ptr pDb; //< exclusive access while held... + + bool stop_requested; + + struct Task + { + RowLoader & row_loader; + int token; + size_t row_begin; + size_t row_end; //< exclusive + std::atomic cancel; + + Task(RowLoader & row_loader_, int t, size_t a, size_t b) + : row_loader(row_loader_), token(t), row_begin(a), row_end(b), cancel(false) + { + row_loader.num_tasks++; + } + + ~Task() + { + // (... mutex being held ...) + row_loader.nosync_taskDone(); + } + }; + + std::unique_ptr current_task; + std::unique_ptr next_task; + + int countRows () const; + + void process (Task &); + + void nosync_ensureDbAccess (); + void nosync_taskDone (); + +}; + +#endif // ROW_LOADER_H diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/RunSql.cpp b/src/WBCLFZSystemModule/SqliteDBProcess/src/RunSql.cpp new file mode 100644 index 0000000..b610b77 --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/RunSql.cpp @@ -0,0 +1,303 @@ +#include "RunSql.h" +#include "sqlite.h" +#include "sqlitedb.h" +#include "sqlitetablemodel.h" + +#include +#include +#include + +RunSql::RunSql(DBBrowserDB& _db, QString query, int execute_from_position, int _execute_to_position, bool _interrupt_after_statements) : + db(_db), + may_continue_with_execution(true), + interrupt_after_statements(_interrupt_after_statements), + execute_current_position(execute_from_position), + execute_to_position(_execute_to_position), + structure_updated(false), + savepoint_created(false), + was_dirty(db.getDirty()), + modified(false) +{ + // Get lock to set up everything + std::unique_lock lk(m); + + // Cancel if there is nothing to execute + if(query.trimmed().isEmpty() || query.trimmed() == ";" || execute_from_position == execute_to_position || + query.mid(execute_from_position, execute_to_position-execute_from_position).trimmed().isEmpty() || + query.mid(execute_from_position, execute_to_position-execute_from_position).trimmed() == ";") + return; + + // All replacements in the query should be made by the same amount of characters, so the positions in the file + // for error indicators and line and column logs are not displaced. + // Whitespace and comments are discarded by SQLite, so it is better to just let it ignore them. + query = query.replace(QRegExp("^(\\s*)BEGIN TRANSACTION;", Qt::CaseInsensitive), "\\1 "); + query = query.replace(QRegExp("COMMIT;(\\s*)$", Qt::CaseInsensitive), " \\1"); + + // Convert query to byte array which we will use from now on, starting from the determined start position and + // until the end of the SQL code. By doing so we go further than the determined end position because in Line + // mode the last statement might go beyond that point. + queries_left_to_execute = query.toUtf8().mid(execute_from_position); +} + +void RunSql::run() +{ + // Execute statement by statement + for(;;) + { + if(!executeNextStatement()) + break; + } + + // Execution finished + + // If the DB structure was changed by some command in this SQL script, send a signal + if(structure_updated) + emit structureUpdated(); +} + +void RunSql::startNextStatement() +{ + std::unique_lock lk(m); + may_continue_with_execution = true; + cv.notify_one(); +} + +void RunSql::stop() +{ + std::unique_lock lk(m); + + stopExecution(); + if(pDb) + sqlite3_interrupt(pDb.get()); + may_continue_with_execution = true; + cv.notify_all(); +} + +bool RunSql::executeNextStatement() +{ + std::unique_lock lk(m); + + // Is there anything left to do? + if(queries_left_to_execute.isEmpty()) + return false; + + // What type of query is this? + QString qtail = QString(queries_left_to_execute).trimmed(); + // Remove trailing comments so we don't get fooled by some trailing text at the end of the stream. + // Otherwise we'll pass them to SQLite and its execution will trigger a savepoint that wouldn't be + // reverted. + SqliteTableModel::removeCommentsFromQuery(qtail); + if (qtail.isEmpty()) + return false; + + StatementType query_type = getQueryType(qtail); + + // Check whether the DB structure is changed by this statement + if(!structure_updated && (query_type == AlterStatement || + query_type == CreateStatement || + query_type == DropStatement || + query_type == RollbackStatement)) + structure_updated = true; + + // Check whether this is trying to set a pragma or to vacuum the database + // TODO This is wrong. The '=' or the 'defer_foreign_keys' might be in a completely different statement of the queries string. + if((query_type == PragmaStatement && qtail.contains('=') && !qtail.contains("defer_foreign_keys", Qt::CaseInsensitive)) || query_type == VacuumStatement) + { + // We're trying to set a pragma. If the database has been modified it needs to be committed first. We'll need to ask the + // user about that + if(db.getDirty()) + { + lk.unlock(); + // Ask user, then check if we should abort execution or continue with it. We depend on a BlockingQueueConnection here which makes sure to + // block this worker thread until the slot function in the main thread is completed and could tell us about its decision. + emit confirmSaveBeforePragmaOrVacuum(); + if(!queries_left_to_execute.isEmpty()) + { + // Commit all changes + db.releaseAllSavepoints(); + } else { + // Abort + emit statementErrored(tr("Execution aborted by user"), execute_current_position, execute_current_position + (query_type == PragmaStatement ? 5 : 6)); + return false; + } + lk.lock(); + } + } else { + // We're not trying to set a pragma or to vacuum the database. In this case make sure a savepoint has been created in order to avoid committing + // all changes to the database immediately. Don't set more than one savepoint. + + if(!savepoint_created && !db.readOnly()) + { + // We have to start a transaction before we create the prepared statement otherwise every executed + // statement will get committed after the prepared statement gets finalized + db.setSavepoint(); + savepoint_created = true; + } + } + + // Start execution timer. We do that after opening any message boxes and after creating savepoints because both are not part of the actual + // query execution. + auto time_start = std::chrono::high_resolution_clock::now(); + + // Execute next statement + const char* tail = queries_left_to_execute.data(); + int tail_length = queries_left_to_execute.length(); + lk.unlock(); + const char* qbegin = tail; + acquireDbAccess(); + sqlite3_stmt* vm; + int sql3status = sqlite3_prepare_v2(pDb.get(), tail, tail_length, &vm, &tail); + QString queryPart = QString::fromUtf8(qbegin, static_cast(tail - qbegin)); + int tail_length_before = tail_length; + tail_length -= static_cast(tail - qbegin); + int end_of_current_statement_position = execute_current_position + tail_length_before - tail_length; + + // Save remaining statements + lk.lock(); + queries_left_to_execute = QByteArray(tail); + lk.unlock(); + + QString error; + if (sql3status == SQLITE_OK) + { + sql3status = sqlite3_step(vm); + sqlite3_finalize(vm); + + // Get type + StatementType query_part_type = getQueryType(queryPart.trimmed()); + + // SQLite returns SQLITE_DONE when a valid SELECT statement was executed but returned no results. To run into the branch that updates + // the status message and the table view anyway manipulate the status value here. This is also done for PRAGMA statements as they (sometimes) + // return rows just like SELECT statements, too. + if((query_part_type == SelectStatement || query_part_type == PragmaStatement) && sql3status == SQLITE_DONE) + sql3status = SQLITE_ROW; + + switch(sql3status) + { + case SQLITE_ROW: + { + // If we get here, the SQL statement returns some sort of data. So hand it over to the model for display. Don't set the modified flag + // because statements that display data don't change data as well. + + releaseDbAccess(); + + lk.lock(); + may_continue_with_execution = false; + + auto time_end = std::chrono::high_resolution_clock::now(); + auto time_in_ms = std::chrono::duration_cast(time_end - time_start); + emit statementReturnsRows(queryPart, execute_current_position, end_of_current_statement_position, time_in_ms.count()); + + // Make sure the next statement isn't executed until we're told to do so + if(interrupt_after_statements) + cv.wait(lk, [this](){ return may_continue_with_execution; }); + lk.unlock(); + break; + } + case SQLITE_DONE: + case SQLITE_OK: + { + // If we get here, the SQL statement doesn't return data and just executes. Don't run it again because it has already been executed. + // But do set the modified flag because statements that don't return data, often modify the database. + + QString stmtHasChangedDatabase; + if(query_part_type == InsertStatement || query_part_type == UpdateStatement || query_part_type == DeleteStatement) + stmtHasChangedDatabase = tr(", %1 rows affected").arg(sqlite3_changes(pDb.get())); + + releaseDbAccess(); + + lk.lock(); + + // Attach/Detach statements don't modify the original database + if(query_part_type != StatementType::AttachStatement && query_part_type != StatementType::DetachStatement) + modified = true; + + may_continue_with_execution = false; + + auto time_end = std::chrono::high_resolution_clock::now(); + auto time_in_ms = std::chrono::duration_cast(time_end - time_start); + emit statementExecuted(tr("query executed successfully. Took %1ms%2").arg(time_in_ms.count()).arg(stmtHasChangedDatabase), + execute_current_position, end_of_current_statement_position); + + // Make sure the next statement isn't executed until we're told to do so + if(interrupt_after_statements) + cv.wait(lk, [this](){ return may_continue_with_execution; }); + lk.unlock(); + break; + } + case SQLITE_MISUSE: + break; + default: + error = QString::fromUtf8(sqlite3_errmsg(pDb.get())); + } + } else { + error = QString::fromUtf8(sqlite3_errmsg(pDb.get())); + } + + // Release the database + lk.lock(); + releaseDbAccess(); + + // Revert to save point now if it wasn't needed. We need to do this here because there are some rare cases where the next statement might + // be affected by what is only a temporary and unnecessary savepoint. For example in this case: + // ATTACH 'xxx' AS 'db2' + // SELECT * FROM db2.xy; -- Savepoint created here + // DETACH db2; -- Savepoint makes this statement fail + if(!modified && !was_dirty && savepoint_created) + { + db.revertToSavepoint(); + savepoint_created = false; + } + + if(!error.isEmpty()) + { + emit statementErrored(error, execute_current_position, end_of_current_statement_position); + stopExecution(); + return false; + } + // Update the start position for the next statement and check if we are at + // the end of the part we want to execute. If so, stop the execution now. + execute_current_position = end_of_current_statement_position; + if(execute_current_position >= execute_to_position) + { + stopExecution(); + return false; + } + + return true; +} + +void RunSql::stopExecution() +{ + queries_left_to_execute.clear(); +} + +RunSql::StatementType RunSql::getQueryType(const QString& query) +{ + // Helper function for getting the type of a given query + + if(query.startsWith("SELECT", Qt::CaseInsensitive)) return SelectStatement; + if(query.startsWith("ALTER", Qt::CaseInsensitive)) return AlterStatement; + if(query.startsWith("DROP", Qt::CaseInsensitive)) return DropStatement; + if(query.startsWith("ROLLBACK", Qt::CaseInsensitive)) return RollbackStatement; + if(query.startsWith("PRAGMA", Qt::CaseInsensitive)) return PragmaStatement; + if(query.startsWith("VACUUM", Qt::CaseInsensitive)) return VacuumStatement; + if(query.startsWith("INSERT", Qt::CaseInsensitive)) return InsertStatement; + if(query.startsWith("UPDATE", Qt::CaseInsensitive)) return UpdateStatement; + if(query.startsWith("DELETE", Qt::CaseInsensitive)) return DeleteStatement; + if(query.startsWith("CREATE", Qt::CaseInsensitive)) return CreateStatement; + if(query.startsWith("ATTACH", Qt::CaseInsensitive)) return AttachStatement; + if(query.startsWith("DETACH", Qt::CaseInsensitive)) return DetachStatement; + + return OtherStatement; +} + +void RunSql::acquireDbAccess() +{ + pDb = db.get(tr("executing query"), true); +} + +void RunSql::releaseDbAccess() +{ + pDb = nullptr; +} diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/RunSql.h b/src/WBCLFZSystemModule/SqliteDBProcess/src/RunSql.h new file mode 100644 index 0000000..15eb615 --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/RunSql.h @@ -0,0 +1,89 @@ +#ifndef RUNSQL_H +#define RUNSQL_H + +#include +#include +#include +#include + +class DBBrowserDB; +struct sqlite3; + +class RunSql : public QThread +{ + Q_OBJECT + + void run() override; + +public: + /** + * @param db Reference to the database connection to execute the statements with + * @param query The query to execute + * @param execute_from_position The index of the first character to execute in the query parameter + * @param execute_to_position The index of the last character to execute in the query parameter (see exact_execute_to_position) + * @param interrupt_after_statements Set to true to stop execution after each statement until startNextStatement() is called. Set to false to execute all statements + * in one go. + */ + RunSql(DBBrowserDB& db, QString query, int execute_from_position, int execute_to_position, bool interrupt_after_statements = false); + ~RunSql() override = default; + + enum StatementType + { + SelectStatement, + AlterStatement, + DropStatement, + RollbackStatement, + PragmaStatement, + VacuumStatement, + InsertStatement, + UpdateStatement, + DeleteStatement, + CreateStatement, + AttachStatement, + DetachStatement, + OtherStatement, + }; + + static StatementType getQueryType(const QString& query); + + void startNextStatement(); + + void stop(); + +signals: + void statementErrored(QString message, int from_position, int to_position); + void statementExecuted(QString message, int from_position, int to_position); + void statementReturnsRows(QString query, int from_position, int to_position, qint64 time_in_ms); + void structureUpdated(); + + /** + * This signal must be connected with a Qt::BlockingQueuedConnection in order to work as expected! + */ + void confirmSaveBeforePragmaOrVacuum(); + +private: + DBBrowserDB& db; + std::shared_ptr pDb; + + mutable std::mutex m; + mutable std::condition_variable cv; + bool may_continue_with_execution; + + bool interrupt_after_statements; + + QByteArray queries_left_to_execute; + int execute_current_position; + int execute_to_position; + bool structure_updated; + bool savepoint_created; + bool was_dirty; + bool modified; + + void stopExecution(); + bool executeNextStatement(); + + void acquireDbAccess(); + void releaseDbAccess(); +}; + +#endif diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/SelectItemsPopup.cpp b/src/WBCLFZSystemModule/SqliteDBProcess/src/SelectItemsPopup.cpp new file mode 100644 index 0000000..6d054f1 --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/SelectItemsPopup.cpp @@ -0,0 +1,136 @@ +#include "SelectItemsPopup.h" +#include "ui_SelectItemsPopup.h" + +#include + +SelectItemsPopup::SelectItemsPopup(const std::vector& available, const std::vector& selected, QWidget* parent) : + QDialog(parent), + ui(new Ui::SelectItemsPopup) +{ + ui->setupUi(this); + setWindowFlags(Qt::Popup); + + // Load initial items + for(const auto& s : available) + { + if(std::find(selected.begin(), selected.end(), s) == selected.end()) + new QListWidgetItem(QString::fromStdString(s), ui->listAvailable); + } + for(const auto& s : selected) + new QListWidgetItem(QString::fromStdString(s), ui->listSelected); +} + +SelectItemsPopup::~SelectItemsPopup() +{ + delete ui; +} + +std::vector SelectItemsPopup::selectedItems() const +{ + std::vector result; + for(int i=0;ilistSelected->count();i++) + result.push_back(ui->listSelected->item(i)->text().toStdString()); + return result; +} + +void SelectItemsPopup::selectItem(const QModelIndex& idx) +{ + // Get currently selected iitem if none was provided + QListWidgetItem* item; + if(idx.isValid()) + item = ui->listAvailable->item(idx.row()); + else + item = ui->listAvailable->currentItem(); + + if(!item) + return; + + // Add it to the selected items list + new QListWidgetItem(item->text(), ui->listSelected); + + // Remove it from available items list + delete item; +} + +void SelectItemsPopup::unselectItem(const QModelIndex& idx) +{ + // Get currently selected iitem if none was provided + QListWidgetItem* item; + if(idx.isValid()) + item = ui->listSelected->item(idx.row()); + else + item = ui->listSelected->currentItem(); + + if(!item) + return; + + // Add it to the available items list + new QListWidgetItem(item->text(), ui->listAvailable); + + // Remove it from selected items list + delete item; +} + +void SelectItemsPopup::resizeEvent(QResizeEvent*) +{ + // We modify the shape of the dialog to add an arrow shaped edge. See the ascii art image below for details. The edges + // are numbered, their order is the same as in the polygon definition. + + /* + /3\ + / \ + 1---2 4--------5 + | | + | | + 7------------------6 + */ + + const int arrow_height = ui->spacer->geometry().height(); + const int arrow_width = arrow_height * 3; + const int arrow_position_div = 5; + + QPolygon poly; + poly << QPoint(rect().x(), rect().y() + arrow_height) + << QPoint(rect().x() + rect().width() / arrow_position_div - arrow_width / 2, rect().y() + arrow_height) + << QPoint(rect().x() + rect().width() / arrow_position_div, rect().y()) + << QPoint(rect().x() + rect().width() / arrow_position_div + arrow_width / 2, rect().y() + arrow_height) + << QPoint(rect().x() + rect().width(), rect().y() + arrow_height) + << QPoint(rect().x() + rect().width(), rect().y() + rect().height()) + << QPoint(rect().x(), rect().y() + rect().height()); + setMask(QRegion(poly)); +} + +void SelectItemsPopup::buttonBoxClicked(QAbstractButton* button) +{ + if(button == ui->buttonBox->button(QDialogButtonBox::Apply)) + accept(); +} + +void SelectItemsPopup::moveItemUp() +{ + moveCurrentItem(false); +} + +void SelectItemsPopup::moveItemDown() +{ + moveCurrentItem(true); +} + +void SelectItemsPopup::moveCurrentItem(bool down) +{ + // Get current row number and calculate row number after the movement. Check the values + int currentRow = ui->listSelected->currentRow(); + if(currentRow == -1) + return; + int newRow = currentRow + (down ? 1 : -1); + if(newRow < 0) + return; + if(newRow >= ui->listSelected->count()) + return; + + // Swap items + ui->listSelected->insertItem(newRow, ui->listSelected->takeItem(currentRow)); + + // Select old item at new position + ui->listSelected->setCurrentRow(newRow); +} diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/SelectItemsPopup.h b/src/WBCLFZSystemModule/SqliteDBProcess/src/SelectItemsPopup.h new file mode 100644 index 0000000..e7fb9e9 --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/SelectItemsPopup.h @@ -0,0 +1,44 @@ +#ifndef SELECTITEMS_H +#define SELECTITEMS_H + +#include +#include + +#include +#include + +class QAbstractButton; + +namespace Ui { +class SelectItemsPopup; +} + +class SelectItemsPopup : public QDialog +{ + Q_OBJECT + +public: + explicit SelectItemsPopup(const std::vector& available, const std::vector& selected = {}, QWidget* parent = nullptr); + ~SelectItemsPopup(); + + std::vector selectedItems() const; + +private slots: + void buttonBoxClicked(QAbstractButton* button); + + void selectItem(const QModelIndex& idx = QModelIndex()); + void unselectItem(const QModelIndex& idx = QModelIndex()); + + void moveItemUp(); + void moveItemDown(); + +protected: + void resizeEvent(QResizeEvent* ev); + +private: + Ui::SelectItemsPopup* ui; + + void moveCurrentItem(bool down); +}; + +#endif diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/SelectItemsPopup.ui b/src/WBCLFZSystemModule/SqliteDBProcess/src/SelectItemsPopup.ui new file mode 100644 index 0000000..89b0d4e --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/SelectItemsPopup.ui @@ -0,0 +1,331 @@ + + + SelectItemsPopup + + + + 0 + 0 + 537 + 290 + + + + + + + Qt::Vertical + + + + 0 + 15 + + + + + + + + + + + + A&vailable + + + listAvailable + + + + + + + QAbstractItemView::NoEditTriggers + + + false + + + true + + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + Qt::RightArrow + + + + + + + Qt::LeftArrow + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + Sele&cted + + + listSelected + + + + + + + QAbstractItemView::NoEditTriggers + + + false + + + QAbstractItemView::InternalMove + + + true + + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + Qt::UpArrow + + + + + + + Qt::DownArrow + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + QDialogButtonBox::Apply|QDialogButtonBox::Cancel + + + + + + + listAvailable + listSelected + buttonSelect + buttonUnselect + + + + + buttonSelect + clicked() + SelectItemsPopup + selectItem() + + + 263 + 115 + + + 2 + 203 + + + + + buttonUnselect + clicked() + SelectItemsPopup + unselectItem() + + + 257 + 159 + + + 515 + 186 + + + + + listAvailable + doubleClicked(QModelIndex) + SelectItemsPopup + selectItem(QModelIndex) + + + 124 + 45 + + + 115 + 0 + + + + + listSelected + doubleClicked(QModelIndex) + SelectItemsPopup + unselectItem(QModelIndex) + + + 377 + 96 + + + 383 + 4 + + + + + buttonBox + rejected() + SelectItemsPopup + reject() + + + 262 + 258 + + + 262 + 140 + + + + + buttonBox + clicked(QAbstractButton*) + SelectItemsPopup + buttonBoxClicked(QAbstractButton*) + + + 262 + 258 + + + 262 + 140 + + + + + buttonDown + clicked() + SelectItemsPopup + moveItemDown() + + + 513 + 153 + + + 268 + 144 + + + + + buttonUp + clicked() + SelectItemsPopup + moveItemUp() + + + 513 + 124 + + + 268 + 144 + + + + + + selectItem(QModelIndex) + unselectItem(QModelIndex) + selectItem() + unselectItem() + buttonBoxClicked(QAbstractButton*) + moveItemUp() + moveItemDown() + + diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/Settings.cpp b/src/WBCLFZSystemModule/SqliteDBProcess/src/Settings.cpp new file mode 100644 index 0000000..964d16a --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/Settings.cpp @@ -0,0 +1,488 @@ +#include "Settings.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +std::unordered_map Settings::m_hCache; +int Settings::m_defaultFontSize; + +static bool ends_with(const std::string& str, const std::string& with) +{ + return str.rfind(with) == str.size() - with.size(); +} + +QVariant Settings::getValue(const std::string& group, const std::string& name) +{ + // Have a look in the cache first + auto cacheIndex = m_hCache.find(group + name); + if(cacheIndex != m_hCache.end()) + { + return cacheIndex->second; + } else { + // Nothing found in the cache, so get the value from the settings file or get the default value if there is no value set yet + QSettings settings(QApplication::organizationName(), QApplication::organizationName()); + QVariant value = settings.value(QString::fromStdString(group + "/" + name), getDefaultValue(group, name)); + + // Store this value in the cache for further usage and return it afterwards + m_hCache.insert({group + name, value}); + return value; + } +} + +void Settings::setValue(const std::string& group, const std::string& name, const QVariant& value, bool dont_save_to_disk) +{ + // Sometime the value has to be saved for the current session only but get discarded when the application exits. + // In order to achieve this this flag can be set which disables the save to disk mechanism and only leaves the save to cache part active. + if(dont_save_to_disk == false) + { + // Set the group and save the given value + QSettings settings(QApplication::organizationName(), QApplication::organizationName()); + settings.beginGroup(QString::fromStdString(group)); + settings.setValue(QString::fromStdString(name), value); + settings.endGroup(); + } + + // Also change it in the cache + m_hCache[group + name] = value; +} + +QVariant Settings::getDefaultValue(const std::string& group, const std::string& name) +{ + // db/defaultencoding? + if(group == "db" && name == "defaultencoding") + return "UTF-8"; + + // db/savedefaultlocation? + if(group == "db" && name == "savedefaultlocation") + return 2; + + // db/defaultlocation? + if(group == "db" && name == "defaultlocation") + return QDir::homePath(); + + // db/lastlocation? + if(group == "db" && name == "lastlocation") + return getValue("db", "defaultlocation"); + + // db/hideschemalinebreaks? + if(group == "db" && name == "hideschemalinebreaks") + return true; + + // db/foreignkeys? + if(group == "db" && name == "foreignkeys") + return true; + + // db/prefetchsize? + if(group == "db" && name == "prefetchsize") + return 50000U; + + // db/defaultsqltext? + if(group == "db" && name == "defaultsqltext") + return QString(); + + // db/fontsize? + if(group == "db" && name == "fontsize") + return 10; + + // exportcsv/firstrowheader? + if(group == "exportcsv" && name == "firstrowheader") + return true; + + // exportcsv/separator? + if(group == "exportcsv" && name == "separator") + return ','; + + // exportcsv/quotecharacter? + if(group == "exportcsv" && name == "quotecharacter") + return '"'; + + // importcsv group? + if(group == "importcsv") + { + if(name == "firstrowheader") + return false; + if(name == "trimfields") + return true; + if(name == "separatetables") + return false; + if(name == "separator") + return ','; + if(name == "quotecharacter") + return '"'; + if(name == "encoding") + return "UTF-8"; + } + + // exportsql group? + if(group == "exportsql") + { + if(name == "insertcolnames" || name == "insertmultiple") + return false; + if(name == "oldschema") + return 0; + } + + // newline character + if (group == "exportcsv" && name == "newlinecharacters") +#ifdef Q_OS_WIN + return "\r\n"; +#else + return "\n"; +#endif + + // exportjson/prettyprint? + if(group == "exportjson" && name == "prettyprint") + return true; + + // MainWindow/geometry? + if(group == "MainWindow" && name == "geometry") + return QString(); + + // MainWindow/windowState? + if(group == "MainWindow" && name == "windowState") + return QString(); + + // MainWindow/openTabs? + if(group == "MainWindow" && name == "openTabs") + return QString(); + + // SQLLogDock/Log? + if(group == "SQLLogDock" && name == "Log") + return "Application"; + + // General/recentFileList? + if(group == "General" && name == "recentFileList") + return QStringList(); + + // General/language? + if(group == "General" && name == "language") + return QLocale::system().name(); + + // General/appStyle + if(group == "General" && name == "appStyle") + return static_cast(FollowDesktopStyle); + + // General/toolbarStyle + if(group == "General" && name == "toolbarStyle") + return static_cast(Qt::ToolButtonTextBesideIcon); + + // General/toolbarStyleStructure + if(group == "General" && name == "toolbarStyleStructure") + return static_cast(Qt::ToolButtonTextBesideIcon); + + // General/toolbarStyleBrowse + if(group == "General" && name == "toolbarStyleBrowse") + return static_cast(Qt::ToolButtonIconOnly); + + // General/toolbarStyleSql + if(group == "General" && name == "toolbarStyleSql") + return static_cast(Qt::ToolButtonIconOnly); + + // General/toolbarStyleEditCell + if(group == "General" && name == "toolbarStyleEditCell") + return static_cast(Qt::ToolButtonIconOnly); + + if(group == "General" && name == "DBFileExtensions") + return QObject::tr("SQLite database files (*.db *.sqlite *.sqlite3 *.db3)"); + + // General/fontsize + if(group == "General" && name == "fontsize") + return m_defaultFontSize; + + // checkversion group? + if(group == "checkversion") + { + if(name == "enabled") + return true; + if(name == "ignmajor") + return 999; + if(name == "ignminor" || name == "ignpatch") + return 0; + } + + // Data Browser/NULL Fields + if(group == "databrowser") + { + if(name == "font") + return QFont().defaultFamily(); + if(name == "fontsize") + return 10; + if(name == "symbol_limit") + return 5000; + if(name == "complete_threshold") + return 1000; + if(name == "image_preview") + return false; + if(name == "indent_compact") + return false; + if(name == "auto_switch_mode") + return true; + if(name == "editor_word_wrap") + return true; + if(name == "null_text") + return "NULL"; + if(name == "blob_text") + return "BLOB"; + if(name == "filter_escape") + return "\\"; + if(name == "filter_delay") + return 200; + if(ends_with(name, "colour")) + return getDefaultColorValue(group, name, FollowDesktopStyle); + } + + // syntaxhighlighter? + if(group == "syntaxhighlighter") + { + // Bold? Only tables, functions and keywords are bold by default + if(ends_with(name, "bold")) + return name == "keyword_bold" || name == "table_bold" || name == "function_bold"; + + // Italic? Nothing by default + if(ends_with(name, "italic")) + return false; + + // Underline? Nothing by default + if(ends_with(name, "underline")) + return false; + + // Colour? + if(ends_with(name, "colour")) + return getDefaultColorValue(group, name, FollowDesktopStyle); + } + + // editor/font? + if(group == "editor" && name == "font") + { + QFont font("Monospace"); + font.setStyleHint(QFont::TypeWriter); + return QFontInfo(font).family(); + } + + // editor/fontsize or log/fontsize? + if((group == "editor" || group == "log") && name == "fontsize") +#ifdef Q_OS_MAC + // Use 12 pt size as the default on OSX + return 12; +#else + return 9; +#endif + + if(group == "editor") + { + if(name == "tabsize") + { + return 4; + } + } + + // editor/wrap_lines + if(group == "editor" && name == "wrap_lines") + return 0; // QsciScintilla::WrapNone + + // editor/identifier_quotes + if(group == "editor" && name == "identifier_quotes") + return 0; // sqlb::DoubleQuotes + + // editor/auto_completion? + if(group == "editor" && name == "auto_completion") + return true; + + // editor/upper_keywords? + if(group == "editor" && name == "upper_keywords") + return true; + + // editor/error_indicators? + if(group == "editor" && name == "error_indicators") + return true; + + // editor/horizontal_tiling? + if(group == "editor" && name == "horizontal_tiling") + return false; + + // editor/splitter1_sizes? + if(group == "editor" && name == "splitter1_sizes") + return QVariant(); + + // editor/splitter2_sizes? + if(group == "editor" && name == "splitter2_sizes") + return QVariant(); + + // editor/close_button_on_tabs? + if(group == "editor" && name == "close_button_on_tabs") + return true; + + // extensions/list? + if(group == "extensions" && name == "list") + return QStringList(); + + // extensions/disableregex? + if(group == "extension" && name == "disableregex") + return false; + + // extensions/enable_load_extension? + if(group == "extension" && name == "enable_load_extension") + return false; + + // PlotDock/lineType or pointShape? + if(group == "PlotDock") + { + // QCPGraph::lsLine + if(name == "lineType") + return 1; + + // QCPScatterStyle::ssDisk + if(name == "pointShape") + return 4; + } + + + // SchemaDock Drag & drop settings + if(group == "SchemaDock") + { + if(name == "dropQualifiedNames") + return false; + + if(name == "dropEnquotedNames") + return true; + } + + // Remote settings? + if(group == "remote") + { + // Enable the File → Remote menu by default + if(name == "active") + return true; + + // Clone directory + if(name == "clonedirectory") +#if QT_VERSION >= QT_VERSION_CHECK(5, 4, 0) + return QStandardPaths::writableLocation(QStandardPaths::AppDataLocation); +#else + return QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation); +#endif + } + + // Proxy settings + if(group == "proxy") + { + // Use system settings by default + if(name == "type") + return "system"; + } + + // Unknown combination of group and name? Return an invalid QVariant! + return QVariant(); +} + +QColor Settings::getDefaultColorValue(const std::string& group, const std::string& name, AppStyle style) +{ + // Data Browser/NULL & Binary Fields + if(group == "databrowser") + { + switch (style) { + case FollowDesktopStyle : + if(name == "null_fg_colour") + return QColor(Qt::lightGray).name(); + if(name == "null_bg_colour") + return QPalette().color(QPalette::Active, QPalette::Base).name(); + if(name == "reg_fg_colour") + return QPalette().color(QPalette::Active, QPalette::Text).name(); + if(name == "reg_bg_colour") + return QPalette().color(QPalette::Active, QPalette::Base).name(); + if(name == "bin_fg_colour") + return QColor(Qt::lightGray).name(); + if(name == "bin_bg_colour") + return QPalette().color(QPalette::Active, QPalette::Base).name(); + break; + case DarkStyle : + if(name == "null_fg_colour") + return QColor("#787878"); + if(name == "null_bg_colour") + return QColor("#19232D"); + if(name == "reg_fg_colour") + return QColor("#F0F0F0"); + if(name == "reg_bg_colour") + return QColor("#19232D"); + if(name == "bin_fg_colour") + return QColor("#787878"); + if(name == "bin_bg_colour") + return QColor("#19232D"); + break; + } + } + + // syntaxhighlighter? + if(group == "syntaxhighlighter") + { + // Colour? + if(ends_with(name, "colour")) + { + QColor backgroundColour; + QColor foregroundColour; + switch (style) { + case FollowDesktopStyle : + backgroundColour = QPalette().color(QPalette::Active, QPalette::Base); + foregroundColour = QPalette().color(QPalette::Active, QPalette::Text); + break; + case DarkStyle : + foregroundColour = QColor("#F0F0F0"); + backgroundColour = QColor("#19232D"); + break; + } + if(name == "foreground_colour") + return foregroundColour; + else if(name == "background_colour") + return backgroundColour; + + // Detect and provide sensible defaults for dark themes + if (backgroundColour.value() < foregroundColour.value()) { + if(name == "keyword_colour") + return QColor(82, 148, 226); + else if(name == "function_colour") + return QColor(Qt::yellow); + else if(name == "table_colour") + return QColor(Qt::cyan); + else if(name == "comment_colour") + return QColor(Qt::green); + else if(name == "identifier_colour") + return QColor(Qt::magenta); + else if(name == "string_colour") + return QColor(Qt::lightGray); + else if(name == "currentline_colour") + return backgroundColour.lighter(150); + } else { + if(name == "keyword_colour") + return QColor(Qt::darkBlue); + else if(name == "function_colour") + return QColor(Qt::blue); + else if(name == "table_colour") + return QColor(Qt::darkCyan); + else if(name == "comment_colour") + return QColor(Qt::darkGreen); + else if(name == "identifier_colour") + return QColor(Qt::darkMagenta); + else if(name == "string_colour") + return QColor(Qt::red); + else if(name == "currentline_colour") + return QColor(236, 236, 245); + } + } + } + + // Unknown combination of group and name? Return an invalid QColor! + return QColor(); +} + +void Settings::restoreDefaults () +{ + QSettings settings(QApplication::organizationName(), QApplication::organizationName()); + settings.clear(); + m_hCache.clear(); +} diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/Settings.h b/src/WBCLFZSystemModule/SqliteDBProcess/src/Settings.h new file mode 100644 index 0000000..94f414b --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/Settings.h @@ -0,0 +1,40 @@ +#ifndef SETTINGS_H +#define SETTINGS_H + +#include +#include + +class Settings +{ + friend class PreferencesDialog; + +public: + + enum AppStyle { + FollowDesktopStyle, + DarkStyle + }; + static QVariant getValue(const std::string& group, const std::string& name); + static void setValue(const std::string& group, const std::string& name, const QVariant& value, bool dont_save_to_disk = false); + static void restoreDefaults(); + + static void rememberDefaultFontSize(int size) { m_defaultFontSize = size; } + +private: + Settings() = delete; // class is fully static + + // This works similar to getValue but returns the default value instead of the value set by the user + static QVariant getDefaultValue(const std::string& group, const std::string& name); + + // This works similar to getDefaultValue but returns the default color value based on the passed application style + // instead of the current palette. + static QColor getDefaultColorValue(const std::string& group, const std::string& name, AppStyle style); + + // Cache for storing the settings to avoid repeatedly reading the settings file all the time + static std::unordered_map m_hCache; + + // Default UI font size + static int m_defaultFontSize; +}; + +#endif diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/SqlExecutionArea.cpp b/src/WBCLFZSystemModule/SqliteDBProcess/src/SqlExecutionArea.cpp new file mode 100644 index 0000000..f5e3d83 --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/SqlExecutionArea.cpp @@ -0,0 +1,319 @@ +#include "SqlExecutionArea.h" +#include "ui_SqlExecutionArea.h" +#include "sqltextedit.h" +#include "sqlitetablemodel.h" +#include "sqlitedb.h" +#include "Settings.h" +#include "ExportDataDialog.h" +#include "FilterTableHeader.h" + +#include +#include +#include +#include + +SqlExecutionArea::SqlExecutionArea(DBBrowserDB& _db, QWidget* parent) : + QWidget(parent), + db(_db), + ui(new Ui::SqlExecutionArea), + m_columnsResized(false), + error_state(false) +{ + // Create UI + ui->setupUi(this); + + // Create model + model = new SqliteTableModel(db, this); + ui->tableResult->setModel(model); + connect(model, &SqliteTableModel::finishedFetch, this, &SqlExecutionArea::fetchedData); + connect(ui->tableResult->filterHeader(), &FilterTableHeader::sectionPressed, ui->tableResult, &QTableView::selectColumn); + + ui->findFrame->hide(); + + QShortcut* shortcutHideFind = new QShortcut(QKeySequence("ESC"), ui->findLineEdit); + connect(shortcutHideFind, &QShortcut::activated, this, &SqlExecutionArea::hideFindFrame); + + connect(ui->findLineEdit, &QLineEdit::textChanged, this, &SqlExecutionArea::findLineEdit_textChanged); + connect(ui->previousToolButton, &QToolButton::clicked, this, &SqlExecutionArea::findPrevious); + connect(ui->nextToolButton, &QToolButton::clicked, this, &SqlExecutionArea::findNext); + connect(ui->findLineEdit, &QLineEdit::returnPressed, this, &SqlExecutionArea::findNext); + connect(ui->hideFindButton, &QToolButton::clicked, this, &SqlExecutionArea::hideFindFrame); + + connect(&fileSystemWatch, &QFileSystemWatcher::fileChanged, this, &SqlExecutionArea::fileChanged); + + // Save to settings when sppliter is moved, but only to memory. + connect(ui->splitter, &QSplitter::splitterMoved, this, [this]() { + Settings::setValue("editor", "splitter1_sizes", ui->splitter->saveState(), /* dont_save_to_disk */ true); + }); + connect(ui->splitter_2, &QSplitter::splitterMoved, this, [this]() { + Settings::setValue("editor", "splitter2_sizes", ui->splitter_2->saveState(), /* dont_save_to_disk */ true); + }); + + // Set collapsible the editErrors panel + ui->splitter_2->setCollapsible(1, true); + + // Load settings + reloadSettings(); +} + +SqlExecutionArea::~SqlExecutionArea() +{ + delete ui; +} + +QString SqlExecutionArea::getSql() const +{ + return ui->editEditor->text(); +} + +QString SqlExecutionArea::getSelectedSql() const +{ + return ui->editEditor->selectedText().trimmed().replace(QChar(0x2029), '\n'); +} + +void SqlExecutionArea::setSql(const QString& sql) +{ + ui->editEditor->setText(sql); +} + +void SqlExecutionArea::finishExecution(const QString& result, const bool ok) +{ + error_state = !ok; + m_columnsResized = false; + ui->editErrors->setPlainText(result); + // Set reddish background when not ok + if (showErrorIndicators) + { + if (ok) + ui->editErrors->setStyleSheet(""); + else + ui->editErrors->setStyleSheet("QTextEdit {color: white; background-color: rgb(255, 102, 102)}"); + } + +} + +void SqlExecutionArea::fetchedData() +{ + // Don't resize the columns more than once to fit their contents. This is necessary because the finishedFetch signal of the model + // is emitted for each loaded prefetch block and we want to avoid resizes while scrolling down. + if(m_columnsResized) + return; + m_columnsResized = true; + + // Set column widths according to their contents but make sure they don't exceed a certain size + ui->tableResult->resizeColumnsToContents(); + for(int i = 0; i < model->columnCount(); i++) + { + if(ui->tableResult->columnWidth(i) > 300) + ui->tableResult->setColumnWidth(i, 300); + } +} + +SqlTextEdit *SqlExecutionArea::getEditor() +{ + return ui->editEditor; +} + +ExtendedTableWidget *SqlExecutionArea::getTableResult() +{ + return ui->tableResult; +} + +QTextEdit* SqlExecutionArea::getStatusEdit() +{ + return ui->editErrors; +} + +void SqlExecutionArea::saveAsCsv() +{ + ExportDataDialog dialog(db, ExportDataDialog::ExportFormatCsv, this, model->query()); + dialog.exec(); +} + +void SqlExecutionArea::reloadSettings() +{ + // Reload editor and table settings + ui->editEditor->reloadSettings(); + ui->tableResult->reloadSettings(); + + // Set font + QFont logfont(Settings::getValue("editor", "font").toString()); + logfont.setStyleHint(QFont::TypeWriter); + logfont.setPointSize(Settings::getValue("log", "fontsize").toInt()); + ui->editErrors->setFont(logfont); + + // Apply horizontal/vertical tiling option + if(Settings::getValue("editor", "horizontal_tiling").toBool()) + ui->splitter->setOrientation(Qt::Horizontal); + else + ui->splitter->setOrientation(Qt::Vertical); + + ui->splitter->restoreState(Settings::getValue("editor", "splitter1_sizes").toByteArray()); + ui->splitter_2->restoreState(Settings::getValue("editor", "splitter2_sizes").toByteArray()); + + // Reload model settings + model->reloadSettings(); + + // Check if error indicators are enabled for the not-ok background clue + showErrorIndicators = Settings::getValue("editor", "error_indicators").toBool(); + if (!showErrorIndicators) + ui->editErrors->setStyleSheet(""); + +} + +void SqlExecutionArea::find(QString expr, bool forward) +{ + + bool found = ui->editEditor->findText + (expr, + ui->regexpCheckBox->isChecked(), + ui->caseCheckBox->isChecked(), + ui->wholeWordsCheckBox->isChecked(), + /* wrap */ true, + forward); + + // Set reddish background when not found + if (found || expr.isEmpty()) + ui->findLineEdit->setStyleSheet(""); + else + ui->findLineEdit->setStyleSheet("QLineEdit {color: white; background-color: rgb(255, 102, 102)}"); + +} + +void SqlExecutionArea::findPrevious() +{ + find(ui->findLineEdit->text(), false); +} + +void SqlExecutionArea::findNext() +{ + find(ui->findLineEdit->text(), true); +} + +void SqlExecutionArea::findLineEdit_textChanged(const QString &) +{ + // When the text changes, perform an incremental search from cursor + // position, or from begin of the selection position. + + // For incremental search while typing we need to start from the + // begining of the current selection, otherwise we'd jump to the + // next occurrence + if (ui->editEditor->hasSelectedText()) { + int lineFrom; + int indexFrom; + int lineTo; + int indexTo; + ui->editEditor->getSelection(&lineFrom, &indexFrom, &lineTo, &indexTo); + ui->editEditor->setCursorPosition(lineFrom, indexFrom); + } + + find(ui->findLineEdit->text(), true); +} + +void SqlExecutionArea::hideFindFrame() +{ + ui->editEditor->setFocus(); + ui->findFrame->hide(); + emit findFrameVisibilityChanged(false); +} + +void SqlExecutionArea::setFindFrameVisibility(bool show) +{ + if (show) { + ui->findFrame->show(); + ui->findLineEdit->setFocus(); + ui->findLineEdit->selectAll(); + emit findFrameVisibilityChanged(true); + } else { + hideFindFrame(); + } +} + +void SqlExecutionArea::openFile(const QString& filename) +{ + // Open file for reading + QFile f(filename); + f.open(QIODevice::ReadOnly); + if(!f.isOpen()) + { + QMessageBox::warning(this, qApp->applicationName(), tr("Couldn't read file: %1.").arg(f.errorString())); + return; + } + + // Read in the entire file + ui->editEditor->setText(f.readAll()); + + // No modifications yet + ui->editEditor->setModified(false); + + // Remember file name + sqlFileName = filename; + + // Start watching this file for changes and unwatch the previously watched file, if any + if(!fileSystemWatch.files().empty()) + fileSystemWatch.removePaths(fileSystemWatch.files()); + fileSystemWatch.addPath(filename); +} + +void SqlExecutionArea::saveFile(const QString& filename) +{ + // Unwatch all files now. By unwathing them before the actual saving, we are not notified of our own changes + if(!fileSystemWatch.files().empty()) + fileSystemWatch.removePaths(fileSystemWatch.files()); + + // Open file for writing + QFile f(filename); + f.open(QIODevice::WriteOnly); + if(!f.isOpen()) + { + QMessageBox::warning(this, qApp->applicationName(), tr("Couldn't save file: %1.").arg(f.errorString())); + return; + } + + // Write to the file + if(f.write(getSql().toUtf8()) != -1) + { + // Close file now. If we let the destructor close it, we can get change notifications. + f.close(); + // Set modified to false so we can get control of unsaved changes when closing. + ui->editEditor->setModified(false); + + // Remember file name + sqlFileName = filename; + + // Start watching this file + fileSystemWatch.addPath(filename); + } else { + QMessageBox::warning(this, qApp->applicationName(), tr("Couldn't save file: %1.").arg(f.errorString())); + return; + } +} + +void SqlExecutionArea::fileChanged(const QString& filename) +{ + // Check if there are unsaved changes in the file + QString changes; + if(ui->editEditor->isModified()) + changes = QString(" ") + tr("Your changes will be lost when reloading it!"); + + // Ask user whether to realod the modified file + if(QMessageBox::question( + this, + qApp->applicationName(), + tr("The file \"%1\" was modified by another program. Do you want to reload it?%2").arg(filename, changes), + QMessageBox::Yes | QMessageBox::Ignore) == QMessageBox::Yes) + { + // Read in the file + openFile(filename); + } else { + // The file does not match the file on the disk anymore. So set the modified flag + ui->editEditor->setModified(true); + } +} + +void SqlExecutionArea::saveState() { + + // Save to disk last stored splitter sizes + Settings::setValue("editor", "splitter1_sizes", Settings::getValue("editor", "splitter1_sizes")); + Settings::setValue("editor", "splitter2_sizes", Settings::getValue("editor", "splitter2_sizes")); +} diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/SqlExecutionArea.h b/src/WBCLFZSystemModule/SqliteDBProcess/src/SqlExecutionArea.h new file mode 100644 index 0000000..fa67cf9 --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/SqlExecutionArea.h @@ -0,0 +1,76 @@ +#ifndef SQLEXECUTIONAREA_H +#define SQLEXECUTIONAREA_H + +#include +#include + +class SqlTextEdit; +class SqliteTableModel; +class DBBrowserDB; +class ExtendedTableWidget; + +class QTextEdit; + +namespace Ui { +class SqlExecutionArea; +} + +class SqlExecutionArea : public QWidget +{ + Q_OBJECT + +public: + explicit SqlExecutionArea(DBBrowserDB& _db, QWidget* parent = nullptr); + ~SqlExecutionArea() override; + + QString getSql() const; + QString getSelectedSql() const; + void setSql(const QString& sql); + + void openFile(const QString& filename); + void saveFile(const QString& filename); + + QString fileName() const { return sqlFileName; } + void setFileName(const QString& filename) { sqlFileName = filename; } + + SqliteTableModel* getModel() { return model; } + SqlTextEdit* getEditor(); + ExtendedTableWidget *getTableResult(); + QTextEdit* getStatusEdit(); + + bool inErrorState() const { return error_state; } + + // Save window state to settings + static void saveState(); + +public slots: + void finishExecution(const QString& result, const bool ok); + void saveAsCsv(); + void reloadSettings(); + void fetchedData(); + void setFindFrameVisibility(bool show); + +private slots: + void findPrevious(); + void findNext(); + void findLineEdit_textChanged(const QString& text); + void hideFindFrame(); + + void fileChanged(const QString& filename); + +signals: + void findFrameVisibilityChanged(bool visible); + +private: + void find(QString expr, bool forward); + DBBrowserDB& db; + SqliteTableModel* model; + QString sqlFileName; + QFileSystemWatcher fileSystemWatch; + Ui::SqlExecutionArea* ui; + bool m_columnsResized; // This is set to true if the columns of the table view were already adjusted to fit their contents + bool showErrorIndicators; + bool error_state; +}; + +#endif diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/SqlExecutionArea.ui b/src/WBCLFZSystemModule/SqliteDBProcess/src/SqlExecutionArea.ui new file mode 100644 index 0000000..1a187da --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/SqlExecutionArea.ui @@ -0,0 +1,296 @@ + + + SqlExecutionArea + + + + 0 + 0 + 579 + 482 + + + + Form + + + + 3 + + + 3 + + + 3 + + + 3 + + + 3 + + + + + Qt::Vertical + + + false + + + + + 0 + + + + + + + + + 16777215 + 31 + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + 1 + + + 1 + + + 1 + + + 1 + + + 3 + + + + + Find previous match [Shift+F3] + + + Find previous match with wrapping + + + + :/icons/up:/icons/up + + + Shift+F3 + + + + + + + Qt::Horizontal + + + + + + + The found pattern must be a whole word + + + Whole Words + + + + + + + Qt::DefaultContextMenu + + + Text pattern to find considering the checks in this frame + + + Find in editor + + + true + + + + + + + The found pattern must match in letter case + + + Case Sensitive + + + + + + + Find next match [Enter, F3] + + + Find next match with wrapping + + + + :/icons/down:/icons/down + + + F3 + + + + + + + Interpret search pattern as a regular expression + + + <html><head/><body><p>When checked, the pattern to find is interpreted as a UNIX regular expression. See <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>.</p></body></html> + + + Regular Expression + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Close Find Bar + + + Close Find Bar + + + + :/icons/close:/icons/close + + + true + + + + + + + + + + + Qt::Vertical + + + false + + + + QAbstractItemView::NoEditTriggers + + + + + + 0 + 120 + + + + + Monospace + 8 + + + + false + + + <html><head/><body><p>Results of the last executed statements.</p><p>You may want to collapse this panel and use the <span style=" font-style:italic;">SQL Log</span> dock with <span style=" font-style:italic;">User</span> selection instead.</p></body></html> + + + This field shows the results and status codes of the last executed statements. + + + QFrame::StyledPanel + + + QFrame::Sunken + + + true + + + false + + + true + + + Results of the last executed statements + + + + + + + + + + SqlTextEdit + QTextEdit +
sqltextedit.h
+ 1 +
+ + ExtendedTableWidget + QTableWidget +
ExtendedTableWidget.h
+ + foreignKeyClicked(QString,QString,QByteArray) + foreignKeyClicked(sqlb::ObjectIdentifier,QString,QByteArray) + +
+
+ + editEditor + findLineEdit + tableResult + editErrors + previousToolButton + nextToolButton + caseCheckBox + wholeWordsCheckBox + + + + + + + saveAsCsv() + saveAsView() + +
diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/SqlUiLexer.cpp b/src/WBCLFZSystemModule/SqliteDBProcess/src/SqlUiLexer.cpp new file mode 100644 index 0000000..5475047 --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/SqlUiLexer.cpp @@ -0,0 +1,224 @@ +#include + +#include "SqlUiLexer.h" +#include "Qsci/qsciapis.h" +#include "Settings.h" +#include "sqlitedb.h" + +SqlUiLexer::SqlUiLexer(QObject* parent) : + QsciLexerSQL(parent) +{ + // Setup auto completion + autocompleteApi = new QsciAPIs(this); + setupAutoCompletion(); + autocompleteApi->prepare(); + + // Setup folding + setFoldComments(true); + setFoldCompact(false); +} + +void SqlUiLexer::setupAutoCompletion() +{ + // Set keywords + keywordPatterns + // Keywords + << "ABORT" << "ACTION" << "ADD" << "AFTER" << "ALL" + << "ALTER" << "ALWAYS" << "ANALYZE" << "AND" << "AS" << "ASC" + << "ATTACH" << "AUTOINCREMENT" << "BEFORE" << "BEGIN" << "BETWEEN" + << "BY" << "CASCADE" << "CASE" << "CAST" << "CHECK" + << "COLLATE" << "COLUMN" << "COMMIT" << "CONFLICT" << "CONSTRAINT" + << "CREATE" << "CROSS" << "CURRENT" << "CURRENT_DATE" << "CURRENT_TIME" << "CURRENT_TIMESTAMP" + << "DATABASE" << "DEFAULT" << "DEFERRABLE" << "DEFERRED" << "DELETE" + << "DESC" << "DETACH" << "DISTINCT" << "DO" << "DROP" << "EACH" + << "ELSE" << "END" << "ESCAPE" << "EXCEPT" << "EXCLUSIVE" + << "EXISTS" << "EXPLAIN" << "FAIL" << "FILTER" << "FOLLOWING" << "FOR" << "FOREIGN" + << "FROM" << "FULL" << "GENERATED" << "GLOB" << "GROUP" << "HAVING" + << "IF" << "IGNORE" << "IMMEDIATE" << "IN" << "INDEX" + << "INDEXED" << "INITIALLY" << "INNER" << "INSERT" << "INSTEAD" + << "INTERSECT" << "INTO" << "IS" << "ISNULL" << "JOIN" + << "KEY" << "LEFT" << "LIKE" << "LIMIT" << "MATCH" + << "NATURAL" << "NO" << "NOT" << "NOTHING" << "NOTNULL" << "NULL" + << "OF" << "OFFSET" << "ON" << "OR" << "ORDER" + << "OUTER" << "OVER" << "PARTITION" << "PLAN" << "PRAGMA" << "PRECEDING" << "PRIMARY" << "QUERY" + << "RAISE" << "RANGE" << "RECURSIVE" << "REFERENCES" << "REGEXP" << "REINDEX" << "RELEASE" + << "RENAME" << "REPLACE" << "RESTRICT" << "RIGHT" << "ROLLBACK" + << "ROWID" << "ROW" << "ROWS" << "SAVEPOINT" << "SELECT" << "SET" << "STORED" << "TABLE" + << "TEMP" << "TEMPORARY" << "THEN" << "TO" << "TRANSACTION" + << "TRIGGER" << "UNBOUNDED" << "UNION" << "UNIQUE" << "UPDATE" << "USING" + << "VACUUM" << "VALUES" << "VIEW" << "VIRTUAL" << "WHEN" + << "WHERE" << "WINDOW" << "WITH" << "WITHOUT" + // Data types + << "INT" << "INTEGER" << "REAL" << "TEXT" << "BLOB" << "NUMERIC" << "CHAR"; + bool upperKeywords = Settings::getValue("editor", "upper_keywords").toBool(); + for(const QString& keyword : keywordPatterns) + { + if (upperKeywords) + autocompleteApi->add(keyword + "?" + QString::number(ApiCompleterIconIdKeyword)); + else + autocompleteApi->add(keyword.toLower() + "?" + QString::number(ApiCompleterIconIdKeyword)); + } + + // Functions + QStringList functionPatterns; + functionPatterns + // Core functions + << "abs" + tr("(X) The abs(X) function returns the absolute value of the numeric argument X.") + << "changes" + tr("() The changes() function returns the number of database rows that were changed or inserted or deleted by the most recently completed INSERT, DELETE, or UPDATE statement.") + << "char" + tr("(X1,X2,...) The char(X1,X2,...,XN) function returns a string composed of characters having the unicode code point values of integers X1 through XN, respectively. ") + << "coalesce" + tr("(X,Y,...) The coalesce() function returns a copy of its first non-NULL argument, or NULL if all arguments are NULL") + << "glob" + tr("(X,Y) The glob(X,Y) function is equivalent to the expression \"Y GLOB X\".") + << "ifnull" + tr("(X,Y) The ifnull() function returns a copy of its first non-NULL argument, or NULL if both arguments are NULL.") + << "instr" + tr("(X,Y) The instr(X,Y) function finds the first occurrence of string Y within string X and returns the number of prior characters plus 1, or 0 if Y is nowhere found within X.") + << "hex" + tr("(X) The hex() function interprets its argument as a BLOB and returns a string which is the upper-case hexadecimal rendering of the content of that blob.") + << "last_insert_rowid" + tr("() The last_insert_rowid() function returns the ROWID of the last row insert from the database connection which invoked the function.") + << "length" + tr("(X) For a string value X, the length(X) function returns the number of characters (not bytes) in X prior to the first NUL character.") + << "like" + tr("(X,Y) The like() function is used to implement the \"Y LIKE X\" expression.") + << "like" + tr("(X,Y,Z) The like() function is used to implement the \"Y LIKE X ESCAPE Z\" expression.") + << "load_extension" + tr("(X) The load_extension(X) function loads SQLite extensions out of the shared library file named X.\nUse of this function must be authorized from Preferences.") + << "load_extension" + tr("(X,Y) The load_extension(X) function loads SQLite extensions out of the shared library file named X using the entry point Y.\nUse of this function must be authorized from Preferences.") + << "lower" + tr("(X) The lower(X) function returns a copy of string X with all ASCII characters converted to lower case.") + << "ltrim" + tr("(X) ltrim(X) removes spaces from the left side of X.") + << "ltrim" + tr("(X,Y) The ltrim(X,Y) function returns a string formed by removing any and all characters that appear in Y from the left side of X.") + << "max" + tr("(X,Y,...) The multi-argument max() function returns the argument with the maximum value, or return NULL if any argument is NULL.") + << "min" + tr("(X,Y,...) The multi-argument min() function returns the argument with the minimum value.") + << "nullif" + tr("(X,Y) The nullif(X,Y) function returns its first argument if the arguments are different and NULL if the arguments are the same.") + << "printf" + tr("(FORMAT,...) The printf(FORMAT,...) SQL function works like the sqlite3_mprintf() C-language function and the printf() function from the standard C library.") + << "quote" + tr("(X) The quote(X) function returns the text of an SQL literal which is the value of its argument suitable for inclusion into an SQL statement.") + << "random" + tr("() The random() function returns a pseudo-random integer between -9223372036854775808 and +9223372036854775807.") + << "randomblob" + tr("(N) The randomblob(N) function return an N-byte blob containing pseudo-random bytes.") + << "replace" + tr("(X,Y,Z) The replace(X,Y,Z) function returns a string formed by substituting string Z for every occurrence of string Y in string X.") + << "round" + tr("(X) The round(X) function returns a floating-point value X rounded to zero digits to the right of the decimal point.") + << "round" + tr("(X,Y) The round(X,Y) function returns a floating-point value X rounded to Y digits to the right of the decimal point.") + << "rtrim" + tr("(X) rtrim(X) removes spaces from the right side of X.") + << "rtrim" + tr("(X,Y) The rtrim(X,Y) function returns a string formed by removing any and all characters that appear in Y from the right side of X.") + << "soundex" + tr("(X) The soundex(X) function returns a string that is the soundex encoding of the string X.") + << "substr" + tr("(X,Y) substr(X,Y) returns all characters through the end of the string X beginning with the Y-th.") + << "substr" + tr("(X,Y,Z) The substr(X,Y,Z) function returns a substring of input string X that begins with the Y-th character and which is Z characters long.") + << "total_changes" + tr("() The total_changes() function returns the number of row changes caused by INSERT, UPDATE or DELETE statements since the current database connection was opened.") + << "trim" + tr("(X) trim(X) removes spaces from both ends of X.") + << "trim" + tr("(X,Y) The trim(X,Y) function returns a string formed by removing any and all characters that appear in Y from both ends of X.") + << "typeof" + tr("(X) The typeof(X) function returns a string that indicates the datatype of the expression X.") + << "unicode" + tr("(X) The unicode(X) function returns the numeric unicode code point corresponding to the first character of the string X.") + << "upper" + tr("(X) The upper(X) function returns a copy of input string X in which all lower-case ASCII characters are converted to their upper-case equivalent.") + << "zeroblob" + tr("(N) The zeroblob(N) function returns a BLOB consisting of N bytes of 0x00.") + // Date and time functions + << "date" + tr("(timestring,modifier,modifier,...)") + << "time" + tr("(timestring,modifier,modifier,...)") + << "datetime" + tr("(timestring,modifier,modifier,...)") + << "julianday" + tr("(timestring,modifier,modifier,...)") + << "strftime" + tr("(format,timestring,modifier,modifier,...)") + // Aggregate functions + << "avg" + tr("(X) The avg() function returns the average value of all non-NULL X within a group.") + << "count" + tr("(X) The count(X) function returns a count of the number of times that X is not NULL in a group.") + << "group_concat" + tr("(X) The group_concat() function returns a string which is the concatenation of all non-NULL values of X.") + << "group_concat" + tr("(X,Y) The group_concat() function returns a string which is the concatenation of all non-NULL values of X. If parameter Y is present then it is used as the separator between instances of X.") + << "max" + tr("(X) The max() aggregate function returns the maximum value of all values in the group.") + << "min" + tr("(X) The min() aggregate function returns the minimum non-NULL value of all values in the group.") + << "sum" + tr("(X) The sum() and total() aggregate functions return sum of all non-NULL values in the group.") + << "total" + tr("(X) The sum() and total() aggregate functions return sum of all non-NULL values in the group.") + // Window functions + << "row_number" + tr("() The number of the row within the current partition. Rows are numbered starting from 1 in the order defined by the ORDER BY clause in the window definition, or in arbitrary order otherwise.") + << "rank" + tr("() The row_number() of the first peer in each group - the rank of the current row with gaps. If there is no ORDER BY clause, then all rows are considered peers and this function always returns 1.") + << "dense_rank" + tr("() The number of the current row's peer group within its partition - the rank of the current row without gaps. Partitions are numbered starting from 1 in the order defined by the ORDER BY clause in the window definition. If there is no ORDER BY clause, then all rows are considered peers and this function always returns 1. ") + << "percent_rank" + tr("() Despite the name, this function always returns a value between 0.0 and 1.0 equal to (rank - 1)/(partition-rows - 1), where rank is the value returned by built-in window function rank() and partition-rows is the total number of rows in the partition. If the partition contains only one row, this function returns 0.0. ") + << "cume_dist" + tr("() The cumulative distribution. Calculated as row-number/partition-rows, where row-number is the value returned by row_number() for the last peer in the group and partition-rows the number of rows in the partition.") + << "ntile" + tr("(N) Argument N is handled as an integer. This function divides the partition into N groups as evenly as possible and assigns an integer between 1 and N to each group, in the order defined by the ORDER BY clause, or in arbitrary order otherwise. If necessary, larger groups occur first. This function returns the integer value assigned to the group that the current row is a part of.") + << "lag" + tr("(expr) Returns the result of evaluating expression expr against the previous row in the partition. Or, if there is no previous row (because the current row is the first), NULL.") + << "lag" + tr("(expr,offset) If the offset argument is provided, then it must be a non-negative integer. In this case the value returned is the result of evaluating expr against the row offset rows before the current row within the partition. If offset is 0, then expr is evaluated against the current row. If there is no row offset rows before the current row, NULL is returned.") + << "lag" + tr("(expr,offset,default) If default is also provided, then it is returned instead of NULL if the row identified by offset does not exist.") + << "lead" + tr("(expr) Returns the result of evaluating expression expr against the next row in the partition. Or, if there is no next row (because the current row is the last), NULL.") + << "lead" + tr("(expr,offset) If the offset argument is provided, then it must be a non-negative integer. In this case the value returned is the result of evaluating expr against the row offset rows after the current row within the partition. If offset is 0, then expr is evaluated against the current row. If there is no row offset rows after the current row, NULL is returned.") + << "lead" + tr("(expr,offset,default) If default is also provided, then it is returned instead of NULL if the row identified by offset does not exist.") + << "first_value" + tr("(expr) This built-in window function calculates the window frame for each row in the same way as an aggregate window function. It returns the value of expr evaluated against the first row in the window frame for each row.") + << "last_value" + tr("(expr) This built-in window function calculates the window frame for each row in the same way as an aggregate window function. It returns the value of expr evaluated against the last row in the window frame for each row.") + << "nth_value" + tr("(expr,N) This built-in window function calculates the window frame for each row in the same way as an aggregate window function. It returns the value of expr evaluated against the row N of the window frame. Rows are numbered within the window frame starting from 1 in the order defined by the ORDER BY clause if one is present, or in arbitrary order otherwise. If there is no Nth row in the partition, then NULL is returned.") + ; + + listFunctions.clear(); + for(const QString& keyword : functionPatterns) + { + QString fn = keyword.left(keyword.indexOf('(')); + QString descr = keyword.mid(keyword.indexOf('(')); + + autocompleteApi->add(fn + "?" + QString::number(ApiCompleterIconIdFunction) + descr); + autocompleteApi->add(fn.toUpper() + "?" + QString::number(ApiCompleterIconIdFunction) + descr); + + // Store all function names in order to highlight them in a different colour + listFunctions.append(fn); + } +} + +void SqlUiLexer::setTableNames(const QualifiedTablesMap& tables) +{ + // Update list for auto completion + autocompleteApi->clear(); + listTables.clear(); + setupAutoCompletion(); + for(const auto& itSchemas : tables) + { + for(const auto& itTables : itSchemas.second) + { + // Completion for schema.table + autocompleteApi->add(itSchemas.first + "?" + QString::number(SqlUiLexer::ApiCompleterIconIdSchema) + "." + + itTables.first + "?" + QString::number(SqlUiLexer::ApiCompleterIconIdTable)); + + for(const QString& field : itTables.second) { + // Completion for table.field + autocompleteApi->add(itTables.first + "?" + QString::number(SqlUiLexer::ApiCompleterIconIdTable) + "." + + field + "?" + QString::number(SqlUiLexer::ApiCompleterIconIdColumn)); + + // Completion for isolated field + autocompleteApi->add(field + "?" + QString::number(SqlUiLexer::ApiCompleterIconIdColumn)); + } + // Store the table name list in order to highlight them in a different colour + listTables.append(itTables.first); + } + } + autocompleteApi->prepare(); +} + +const char* SqlUiLexer::keywords(int set) const +{ + // Function and table names are generated automatically but need to be returned to the calling functions. + // In order to not have them deleted after this function ends they are stored as static variables. Because + // the keywords and functions lists don't change after the first call it's initialised here whereas the tables + // list, which can change, is updated for each call + static std::string sqliteKeywords = keywordPatterns.join(" ").toLower().toUtf8().constData(); + static std::string functions = listFunctions.join(" ").toUtf8().constData(); + static std::string tables; + + if(set == 1) { // This corresponds to the QsciLexerSQL::Keyword style in SqlTextEdit + return sqliteKeywords.c_str(); + } else if(set == 6) // This corresponds to the QsciLexerSQL::KeywordSet6 style in SqlTextEdit + { + tables = listTables.join(" ").toLower().toUtf8().constData(); + return tables.c_str(); + } else if(set == 7) { // This corresponds to the QsciLexerSQL::KeywordSet7 style in SqlTextEdit + return functions.c_str(); + } else { + // For all other keyword sets simply call the parent implementation + return QsciLexerSQL::keywords(set); + } +} + +QStringList SqlUiLexer::autoCompletionWordSeparators() const +{ + // The only word separator for auto completion in SQL is "." as in "tablename.columnname". + // Because this isn't implemented in the default QScintilla SQL lexer for some reason we add it here. + // We also need to consider quoted identifiers as in "tablename"."columnname" with whatever quote character + // is configured. + QStringList wl; + + QString escapeSeparator = sqlb::escapeIdentifier(QString(".")); + // Case for non symetric quotes, e.g. "[.]" to "].[" + std::reverse(escapeSeparator.begin(), escapeSeparator.end()); + + wl << "." << escapeSeparator; + return wl; +} + +bool SqlUiLexer::caseSensitive() const +{ + return false; +} diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/SqlUiLexer.h b/src/WBCLFZSystemModule/SqliteDBProcess/src/SqlUiLexer.h new file mode 100644 index 0000000..6cda07e --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/SqlUiLexer.h @@ -0,0 +1,47 @@ +#ifndef SQLUILEXER_H +#define SQLUILEXER_H + +#include "Qsci/qscilexersql.h" + +#include + +class QsciAPIs; + +class SqlUiLexer : public QsciLexerSQL +{ + Q_OBJECT + +public: + explicit SqlUiLexer(QObject *parent = nullptr); + + enum ApiCompleterIconId + { + ApiCompleterIconIdKeyword = 1, + ApiCompleterIconIdFunction, + ApiCompleterIconIdTable, + ApiCompleterIconIdColumn, + ApiCompleterIconIdSchema, + }; + + using TablesAndColumnsMap = std::map>; + using QualifiedTablesMap = std::map; + + void setTableNames(const QualifiedTablesMap& tables); + + const char* keywords(int set) const override; + + QStringList autoCompletionWordSeparators() const override; + + bool caseSensitive() const override; + +private: + QsciAPIs* autocompleteApi; + + void setupAutoCompletion(); + + QStringList listTables; + QStringList listFunctions; + QStringList keywordPatterns; +}; + +#endif diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/SqliteDBMainWindow.cpp b/src/WBCLFZSystemModule/SqliteDBProcess/src/SqliteDBMainWindow.cpp new file mode 100644 index 0000000..abad297 --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/SqliteDBMainWindow.cpp @@ -0,0 +1,3473 @@ +#include "SqliteDBMainWindow.h" +#include "ui_SqliteDBMainWindow.h" + +#include "Application.h" +#include "EditIndexDialog.h" +#include "AboutDialog.h" +#include "EditTableDialog.h" +#include "ImportCsvDialog.h" +#include "ExportDataDialog.h" +#include "Settings.h" +#include "PreferencesDialog.h" +#include "EditDialog.h" +#include "sqlitetablemodel.h" +#include "SqlExecutionArea.h" +#include "VacuumDialog.h" +#include "DbStructureModel.h" +#include "version.h" +#include "sqlite.h" +#include "CipherDialog.h" +#include "ExportSqlDialog.h" +#include "SqlUiLexer.h" +#include "FileDialog.h" +#include "FilterTableHeader.h" +//#include "remoteDock.h" +#include "FindReplaceDialog.h" +#include "RunSql.h" +#include "ExtendedTableWidget.h" +#include "Data.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include // This include seems to only be necessary for the Windows build +#include +#include +#include + +#ifdef Q_OS_MACX //Needed only on macOS + #include +#endif + +#include + +const int SqliteDBMainWindow::MaxRecentFiles; + +// These are needed for reading and writing object files +QDataStream& operator>>(QDataStream& ds, sqlb::ObjectIdentifier& objid) +{ + // Read in the item + QVariant v; + ds >> v; + + // If it is a string list, we can treat it as an object identifier. If it isn't, we assume it's just a + // single string and use interpret it as the table name in the main schema. This is done for backwards + // compatability with old project file formats. + QStringList str = v.toStringList(); + if(str.isEmpty()) + { + objid = sqlb::ObjectIdentifier("main", v.toString().toStdString()); + } else { + objid.setSchema(str.first().toStdString()); + if(str.size() >= 2) + objid.setName(str.last().toStdString()); + } + return ds; +} + +// This is a temporary helper function. Delete it once we clean up the project file loading. +static std::vector toSortOrderVector(int index, Qt::SortOrder mode) +{ + std::vector vector; + vector.emplace_back(index, mode == Qt::AscendingOrder ? sqlb::Ascending : sqlb::Descending); + return vector; +} + +SqliteDBMainWindow::SqliteDBMainWindow(QWidget* parent) + : QMainWindow(parent), + ui(new Ui::SqliteDBMainWindow), + db(), + editDock(new EditDialog(this)), + plotDock(new PlotDock(this)), + ////remoteDock(new remoteDock(this)), // ²Ã¼ô³öµÄ¹¦ÄÜÖ»ÊÊÓñ¾µØ£¬²»¿¼ÂÇÔ¶³ÌÊý¾Ý¿âÁ¬½Ó¹¦ÄÜ + findReplaceDialog(new FindReplaceDialog(this)), + execute_sql_worker(nullptr), + isProjectModified(false) +{ + ui->setupUi(this); + init(); + ui->dockRemote->close(); + activateFields(false); + updateRecentFileActions(); +} + +SqliteDBMainWindow::~SqliteDBMainWindow() +{ + delete ui; +} + +void SqliteDBMainWindow::init() +{ + // Load window settings + tabifyDockWidget(ui->dockLog, ui->dockPlot); + tabifyDockWidget(ui->dockLog, ui->dockSchema); + tabifyDockWidget(ui->dockLog, ui->dockRemote); + +#ifdef Q_OS_MACX + // Add OpenGL Context for macOS + QOpenGLWidget *ogl = new QOpenGLWidget(this); + ui->verticalLayout->addWidget(ogl); + ogl->setHidden(true); +#endif + + // Automatic update check +#ifdef CHECKNEWVERSION + connect(&RemoteNetwork::get(), &RemoteNetwork::networkReady, [this]() { + // Check for a new version if automatic update check aren't disabled in the settings dialog + if(Settings::getValue("checkversion", "enabled").toBool()) + { + RemoteNetwork::get().fetch(QUrl("https://download.sqlitebrowser.org/currentrelease"), RemoteNetwork::RequestTypeCustom, + QString(), [this](const QByteArray& reply) { + QList info = reply.split('\n'); + if(info.size() >= 2) + { + QString version = info.at(0).trimmed(); + QString url = info.at(1).trimmed(); + checkNewVersion(version, url); + } + }); + } + }); +#endif + + // Connect SQL logging and database state setting to main window + connect(&db, &DBBrowserDB::dbChanged, this, &SqliteDBMainWindow::dbState, Qt::QueuedConnection); + connect(&db, &DBBrowserDB::sqlExecuted, this, &SqliteDBMainWindow::logSql, Qt::QueuedConnection); + connect(&db, &DBBrowserDB::requestCollation, this, &SqliteDBMainWindow::requestCollation); + + // Initialise table browser first + ui->tableBrowser->init(&db); + + // Set project modified flag when the settings in the table browser were changed + connect(ui->tableBrowser, &TableBrowser::projectModified, this, [this]() { + isProjectModified = true; + }); + + connect(ui->tableBrowser->model(), &SqliteTableModel::dataChanged, this, &SqliteDBMainWindow::dataTableSelectionChanged); + connect(ui->tableBrowser, &TableBrowser::selectionChanged, this, &SqliteDBMainWindow::dataTableSelectionChanged); + connect(ui->tableBrowser, &TableBrowser::selectionChangedByDoubleClick, this, &SqliteDBMainWindow::doubleClickTable); + connect(ui->tableBrowser, &TableBrowser::updatePlot, this, &SqliteDBMainWindow::attachPlot); + connect(ui->tableBrowser, &TableBrowser::createView, this, &SqliteDBMainWindow::saveAsView); + connect(ui->tableBrowser, &TableBrowser::requestFileOpen, this, [this](const QString& file) { + fileOpen(file); + }); + connect(ui->tableBrowser, &TableBrowser::statusMessageRequested, ui->statusbar, [this](const QString& message) { + ui->statusbar->showMessage(message); + }); + + m_currentTabTableModel = ui->tableBrowser->model(); + + // Set up DB structure tab + dbStructureModel = new DbStructureModel(db, this); + connect(&db, &DBBrowserDB::structureUpdated, this, [this]() { + sqlb::ObjectIdentifier old_table = ui->tableBrowser->currentlyBrowsedTableName(); + dbStructureModel->reloadData(); + populateStructure(old_table); + }); + ui->dbTreeWidget->setModel(dbStructureModel); + ui->dbTreeWidget->setColumnWidth(DbStructureModel::ColumnName, 300); + ui->dbTreeWidget->setColumnHidden(DbStructureModel::ColumnObjectType, true); + ui->dbTreeWidget->setColumnHidden(DbStructureModel::ColumnSchema, true); + + // Set up DB schema dock + ui->treeSchemaDock->setModel(dbStructureModel); + ui->treeSchemaDock->setColumnHidden(DbStructureModel::ColumnObjectType, true); + ui->treeSchemaDock->setColumnHidden(DbStructureModel::ColumnSchema, true); + + // Set up the table combo box in the Browse Data tab + ui->tableBrowser->setStructure(dbStructureModel); + + // Create docks + ui->dockEdit->setWidget(editDock); + ui->dockPlot->setWidget(plotDock); + //ui->dockRemote->setWidget(//remoteDock); + + // Set up edit dock + editDock->setReadOnly(true); + + // Restore window geometry + restoreGeometry(Settings::getValue("SqliteDBMainWindow", "geometry").toByteArray()); + + // Save default and restore window state + defaultWindowState = saveState(); + restoreState(Settings::getValue("SqliteDBMainWindow", "windowState").toByteArray()); + + // Save default and restore open tab order if the openTabs setting is saved. + defaultOpenTabs = saveOpenTabs(); + restoreOpenTabs(Settings::getValue("SqliteDBMainWindow", "openTabs").toString()); + + // Restore dock state settings + ui->comboLogSubmittedBy->setCurrentIndex(ui->comboLogSubmittedBy->findText(Settings::getValue("SQLLogDock", "Log").toString())); + + // Add keyboard shortcuts + QShortcut* shortcutBrowseRefreshF5 = new QShortcut(QKeySequence("F5"), this); + connect(shortcutBrowseRefreshF5, &QShortcut::activated, this, &SqliteDBMainWindow::refresh); + QShortcut* shortcutBrowseRefreshCtrlR = new QShortcut(QKeySequence("Ctrl+R"), this); + connect(shortcutBrowseRefreshCtrlR, &QShortcut::activated, this, &SqliteDBMainWindow::refresh); + + // Add print shortcut for the DB Structure tab (dbTreeWidget) with context to the widget, so other print shortcuts aren't eclipsed. + QShortcut* shortcutPrint = new QShortcut(QKeySequence(QKeySequence::Print), ui->dbTreeWidget, nullptr, nullptr, Qt::WidgetShortcut); + connect(shortcutPrint, &QShortcut::activated, this, &SqliteDBMainWindow::printDbStructure); + + QShortcut* closeTabShortcut = new QShortcut(tr("Ctrl+W"), ui->tabSqlAreas, nullptr, nullptr, Qt::WidgetWithChildrenShortcut); + connect(closeTabShortcut, &QShortcut::activated, this, [this]() { + if(ui->tabSqlAreas->currentIndex() >= 0) + closeSqlTab(ui->tabSqlAreas->currentIndex()); + }); + + // Create the actions for the recently opened dbs list + for(int i = 0; i < MaxRecentFiles; ++i) { + recentFileActs[i] = new QAction(this); + recentFileActs[i]->setVisible(false); + connect(recentFileActs[i], &QAction::triggered, this, &SqliteDBMainWindow::openRecentFile); + } + for(int i = 0; i < MaxRecentFiles; ++i) + ui->fileMenu->insertAction(ui->fileExitAction, recentFileActs[i]); + recentSeparatorAct = ui->fileMenu->insertSeparator(ui->fileExitAction); + + // Create popup menus + popupTableMenu = new QMenu(this); + popupTableMenu->addAction(ui->actionEditBrowseTable); + popupTableMenu->addAction(ui->editModifyObjectAction); + popupTableMenu->addAction(ui->editDeleteObjectAction); + popupTableMenu->addSeparator(); + popupTableMenu->addAction(ui->actionEditCopyCreateStatement); + popupTableMenu->addAction(ui->actionExportCsvPopup); + + popupSchemaDockMenu = new QMenu(this); + popupSchemaDockMenu->addAction(ui->actionPopupSchemaDockBrowseTable); + popupSchemaDockMenu->addSeparator(); + popupSchemaDockMenu->addAction(ui->actionDropQualifiedCheck); + popupSchemaDockMenu->addAction(ui->actionEnquoteNamesCheck); + + popupOpenDbMenu = new QMenu(this); + popupOpenDbMenu->addAction(ui->fileOpenAction); + popupOpenDbMenu->addAction(ui->fileOpenReadOnlyAction); + ui->fileOpenActionPopup->setMenu(popupOpenDbMenu); + + popupSaveSqlFileMenu = new QMenu(this); + popupSaveSqlFileMenu->addAction(ui->actionSqlSaveFile); + popupSaveSqlFileMenu->addAction(ui->actionSqlSaveFileAs); + ui->actionSqlSaveFilePopup->setMenu(popupSaveSqlFileMenu); + + popupSaveSqlResultsMenu = new QMenu(this); + popupSaveSqlResultsMenu->addAction(ui->actionSqlResultsExportCsv); + popupSaveSqlResultsMenu->addAction(ui->actionSqlResultsSaveAsView); + ui->actionSqlResultsSave->setMenu(popupSaveSqlResultsMenu); + qobject_cast(ui->toolbarSql->widgetForAction(ui->actionSqlResultsSave))->setPopupMode(QToolButton::InstantPopup); + + // Add menu item for log dock + ui->viewMenu->insertAction(ui->viewDBToolbarAction, ui->dockLog->toggleViewAction()); + ui->viewMenu->actions().at(0)->setShortcut(QKeySequence(tr("Ctrl+L"))); + ui->viewMenu->actions().at(0)->setIcon(QIcon(":/icons/log_dock")); + + // Add menu item for plot dock + ui->viewMenu->insertAction(ui->viewDBToolbarAction, ui->dockPlot->toggleViewAction()); + ui->viewMenu->actions().at(1)->setShortcut(QKeySequence(tr("Ctrl+D"))); + ui->viewMenu->actions().at(1)->setIcon(QIcon(":/icons/log_dock")); + + // Add menu item for schema dock + ui->viewMenu->insertAction(ui->viewDBToolbarAction, ui->dockSchema->toggleViewAction()); + ui->viewMenu->actions().at(2)->setShortcut(QKeySequence(tr("Ctrl+I"))); + ui->viewMenu->actions().at(2)->setIcon(QIcon(":/icons/log_dock")); + + // Add menu item for edit dock + ui->viewMenu->insertAction(ui->viewDBToolbarAction, ui->dockEdit->toggleViewAction()); + ui->viewMenu->actions().at(3)->setShortcut(QKeySequence(tr("Ctrl+E"))); + ui->viewMenu->actions().at(3)->setIcon(QIcon(":/icons/log_dock")); + + // Add menu item for plot dock + ui->viewMenu->insertAction(ui->viewDBToolbarAction, ui->dockRemote->toggleViewAction()); + ui->viewMenu->actions().at(4)->setIcon(QIcon(":/icons/log_dock")); + + // Set checked state if toolbar is visible + ui->viewDBToolbarAction->setChecked(!ui->toolbarDB->isHidden()); + ui->viewExtraDBToolbarAction->setChecked(!ui->toolbarExtraDB->isHidden()); + ui->viewProjectToolbarAction->setChecked(!ui->toolbarProject->isHidden()); + + // Add separator between docks and toolbars + ui->viewMenu->insertSeparator(ui->viewDBToolbarAction); + + // Connect the tabCloseRequested to the actual closeTab function. + // This must be done before the connections for checking the actions in the View menu so + // they are updated accordingly. + connect(ui->mainTab, &QTabWidget::tabCloseRequested, this, &SqliteDBMainWindow::closeTab); + + // Add entries for toggling the visibility of main tabs + for (QWidget* widget : {ui->structure, ui->browser, ui->pragmas, ui->query}) { + QAction* action = ui->viewMenu->addAction(QIcon(":/icons/open_sql"), widget->accessibleName()); + action->setObjectName(widget->accessibleName()); + action->setCheckable(true); + action->setChecked(ui->mainTab->indexOf(widget) != -1); + connect(action, &QAction::toggled, [=](bool show) { toggleTabVisible(widget, show); }); + // Connect tabCloseRequested for setting checked the appropiate menu entry. + // Note these are called after the actual tab is closed only because they are connected + // after connecting closeTab. + connect(ui->mainTab, &QTabWidget::tabCloseRequested, [=](int /*index*/) { + action->setChecked(ui->mainTab->indexOf(widget) != -1); + }); + } + + ui->viewMenu->addSeparator(); + + QMenu* layoutMenu = new QMenu(tr("Window Layout"), this); + ui->viewMenu->addMenu(layoutMenu); + + QAction* resetLayoutAction = layoutMenu->addAction(tr("Reset Window Layout")); + resetLayoutAction->setShortcut(QKeySequence(tr("Alt+0"))); + connect(resetLayoutAction, &QAction::triggered, [=]() { + restoreState(defaultWindowState); + restoreOpenTabs(defaultOpenTabs); + ui->viewDBToolbarAction->setChecked(!ui->toolbarDB->isHidden()); + ui->viewExtraDBToolbarAction->setChecked(!ui->toolbarExtraDB->isHidden()); + ui->viewProjectToolbarAction->setChecked(!ui->toolbarProject->isHidden()); + }); + QAction* simplifyLayoutAction = layoutMenu->addAction(tr("Simplify Window Layout")); + simplifyLayoutAction->setShortcut(QKeySequence(tr("Shift+Alt+0"))); + connect(simplifyLayoutAction, &QAction::triggered, [=]() { + ui->viewMenu->findChild(ui->pragmas->accessibleName())->activate(QAction::Trigger); + ui->dockLog->hide(); + ui->dockPlot->hide(); + ui->dockSchema->hide(); + ui->dockEdit->hide(); + ui->dockRemote->hide(); + }); + QAction* atBottomLayoutAction = layoutMenu->addAction(tr("Dock Windows at Bottom")); + connect(atBottomLayoutAction, &QAction::triggered, [=]() { + moveDocksTo(Qt::BottomDockWidgetArea); + }); + QAction* atLeftLayoutAction = layoutMenu->addAction(tr("Dock Windows at Left Side")); + connect(atLeftLayoutAction, &QAction::triggered, [=]() { + moveDocksTo(Qt::LeftDockWidgetArea); + }); + QAction* atTopLayoutAction = layoutMenu->addAction(tr("Dock Windows at Top")); + connect(atTopLayoutAction, &QAction::triggered, [=]() { + moveDocksTo(Qt::TopDockWidgetArea); + }); + + // Set Alt+[1-4] shortcuts for opening the corresponding tab in that position. + // Note that it is safe to call setCurrentIndex with a tab that is currently closed, + // since setCurrentIndex does nothing in that case. + QShortcut* setTab1Shortcut = new QShortcut(QKeySequence("Alt+1"), this); + connect(setTab1Shortcut, &QShortcut::activated, [this]() { ui->mainTab->setCurrentIndex(0); }); + QShortcut* setTab2Shortcut = new QShortcut(QKeySequence("Alt+2"), this); + connect(setTab2Shortcut, &QShortcut::activated, [this]() { ui->mainTab->setCurrentIndex(1); }); + QShortcut* setTab3Shortcut = new QShortcut(QKeySequence("Alt+3"), this); + connect(setTab3Shortcut, &QShortcut::activated, [this]() { ui->mainTab->setCurrentIndex(2); }); + QShortcut* setTab4Shortcut = new QShortcut(QKeySequence("Alt+4"), this); + connect(setTab4Shortcut, &QShortcut::activated, [this]() { ui->mainTab->setCurrentIndex(3); }); + + // If we're not compiling in SQLCipher, hide its FAQ link in the help menu +#ifndef ENABLE_SQLCIPHER + ui->actionSqlCipherFaq->setVisible(false); +#endif + + // Set statusbar fields + statusBusyLabel = new QLabel(ui->statusbar); + statusBusyLabel->setEnabled(false); + statusBusyLabel->setVisible(false); + statusBusyLabel->setToolTip(tr("The database is currenctly busy.")); + ui->statusbar->addPermanentWidget(statusBusyLabel); + + statusStopButton = new QToolButton(ui->statusbar); + statusStopButton->setVisible(false); + statusStopButton->setIcon(QIcon(":icons/cancel")); + statusStopButton->setToolTip(tr("Click here to interrupt the currently running query.")); + statusStopButton->setMaximumSize(ui->statusbar->geometry().height() - 6, ui->statusbar->geometry().height() - 6); + statusStopButton->setAutoRaise(true); + ui->statusbar->addPermanentWidget(statusStopButton); + + statusEncryptionLabel = new QLabel(ui->statusbar); + statusEncryptionLabel->setEnabled(false); + statusEncryptionLabel->setVisible(false); + statusEncryptionLabel->setText(tr("Encrypted")); + statusEncryptionLabel->setToolTip(tr("Database is encrypted using SQLCipher")); + ui->statusbar->addPermanentWidget(statusEncryptionLabel); + + statusReadOnlyLabel = new QLabel(ui->statusbar); + statusReadOnlyLabel->setEnabled(false); + statusReadOnlyLabel->setVisible(false); + statusReadOnlyLabel->setText(tr("Read only")); + statusReadOnlyLabel->setToolTip(tr("Database file is read only. Editing the database is disabled.")); + ui->statusbar->addPermanentWidget(statusReadOnlyLabel); + + statusEncodingLabel = new QLabel(ui->statusbar); + statusEncodingLabel->setEnabled(false); + statusEncodingLabel->setText("UTF-8"); + statusEncodingLabel->setToolTip(tr("Database encoding")); + ui->statusbar->addPermanentWidget(statusEncodingLabel); + + // When changing the text of the toolbar actions, also automatically change their icon text and their tooltip text + connect(ui->editModifyObjectAction, &QAction::changed, [=]() { + ui->editModifyObjectAction->setIconText(ui->editModifyObjectAction->text()); + ui->editModifyObjectAction->setToolTip(ui->editModifyObjectAction->text()); + }); + connect(ui->editDeleteObjectAction, &QAction::changed, [=]() { + ui->editDeleteObjectAction->setIconText(ui->editDeleteObjectAction->text()); + ui->editDeleteObjectAction->setToolTip(ui->editDeleteObjectAction->text()); + }); + + // When clicking the interrupt query button in the status bar, ask SQLite to interrupt the current query + connect(statusStopButton, &QToolButton::clicked, [this]() { + db.interruptQuery(); + }); + + // Connect some more signals and slots + connect(editDock, &EditDialog::recordTextUpdated, this, &SqliteDBMainWindow::updateRecordText); + connect(editDock, &EditDialog::requestUrlOrFileOpen, this, &SqliteDBMainWindow::openUrlOrFile); + connect(ui->dbTreeWidget->selectionModel(), &QItemSelectionModel::currentChanged, this, &SqliteDBMainWindow::changeTreeSelection); + connect(ui->dockEdit, &QDockWidget::visibilityChanged, this, &SqliteDBMainWindow::toggleEditDock); + //connect(//remoteDock, SIGNAL(openFile(QString)), this, SLOT(fileOpen(QString))); + connect(ui->actionDropQualifiedCheck, &QAction::toggled, dbStructureModel, &DbStructureModel::setDropQualifiedNames); + connect(ui->actionEnquoteNamesCheck, &QAction::toggled, dbStructureModel, &DbStructureModel::setDropEnquotedNames); + connect(&db, &DBBrowserDB::databaseInUseChanged, this, &SqliteDBMainWindow::updateDatabaseBusyStatus); + + ui->actionDropQualifiedCheck->setChecked(Settings::getValue("SchemaDock", "dropQualifiedNames").toBool()); + ui->actionEnquoteNamesCheck->setChecked(Settings::getValue("SchemaDock", "dropEnquotedNames").toBool()); + + connect(ui->tableBrowser->model(), &SqliteTableModel::finishedFetch, [this](){ + auto& settings = ui->tableBrowser->settings(ui->tableBrowser->currentlyBrowsedTableName()); + plotDock->updatePlot(ui->tableBrowser->model(), &settings, true, false); + }); + + connect(ui->actionSqlStop, &QAction::triggered, [this]() { + if(execute_sql_worker && execute_sql_worker->isRunning()) + execute_sql_worker->stop(); + }); + + // Connect tool pragmas + connect(ui->actionIntegrityCheck, &QAction::triggered, [this]() { + runSqlNewTab("PRAGMA integrity_check;", ui->actionIntegrityCheck->text(), "https://www.sqlite.org/pragma.html#pragma_integrity_check"); + }); + connect(ui->actionQuickCheck, &QAction::triggered, [this]() { + runSqlNewTab("PRAGMA quick_check;", ui->actionQuickCheck->text(), "https://www.sqlite.org/pragma.html#pragma_quick_check"); + }); + connect(ui->actionForeignKeyCheck, &QAction::triggered, [this]() { + runSqlNewTab("PRAGMA foreign_key_check;", ui->actionForeignKeyCheck->text(), "https://www.sqlite.org/pragma.html#pragma_foreign_key_check"); + }); + connect(ui->actionOptimize, &QAction::triggered, [this]() { + runSqlNewTab("PRAGMA optimize;", ui->actionOptimize->text(), "https://www.sqlite.org/pragma.html#pragma_optimize"); + }); + + // Action for switching the table via the Database Structure tab + connect(ui->actionPopupSchemaDockBrowseTable, &QAction::triggered, [this]() { + sqlb::ObjectIdentifier obj(ui->treeSchemaDock->model()->data(ui->treeSchemaDock->currentIndex().sibling(ui->treeSchemaDock->currentIndex().row(), DbStructureModel::ColumnSchema), Qt::EditRole).toString().toStdString(), + ui->treeSchemaDock->model()->data(ui->treeSchemaDock->currentIndex().sibling(ui->treeSchemaDock->currentIndex().row(), DbStructureModel::ColumnName), Qt::EditRole).toString().toStdString()); + switchToBrowseDataTab(obj); + refresh(); // Required in case the Browse Data tab already was the active main tab + }); + + // Set other window settings + setAcceptDrops(true); + setWindowTitle(QApplication::applicationName()); + + // Add the documentation of shortcuts, which aren't otherwise visible in the user interface, to some buttons. + addShortcutsTooltip(ui->actionDbPrint); + addShortcutsTooltip(ui->actionSqlOpenTab); + addShortcutsTooltip(ui->actionSqlPrint); + addShortcutsTooltip(ui->actionExecuteSql, {shortcutBrowseRefreshF5->key(), shortcutBrowseRefreshCtrlR->key()}); + addShortcutsTooltip(ui->actionSqlExecuteLine); + addShortcutsTooltip(ui->actionSqlFind); + addShortcutsTooltip(ui->actionSqlFindReplace); + addShortcutsTooltip(ui->actionSqlToggleComment); + + // Load all settings + reloadSettings(); + +#ifndef ENABLE_SQLCIPHER + // Only show encryption menu action when SQLCipher support is enabled + ui->actionEncryption->setVisible(false); +#endif + + /* Remove all the '&' signs from the dock titles. On at least Windows and + * OSX, Qt doesn't seem to support them properly, so they end up being + * visible instead of creating a keyboard shortcut + */ + ui->dockEdit->setWindowTitle(ui->dockEdit->windowTitle().remove('&')); + ui->dockLog->setWindowTitle(ui->dockLog->windowTitle().remove('&')); + ui->dockPlot->setWindowTitle(ui->dockPlot->windowTitle().remove('&')); + ui->dockSchema->setWindowTitle(ui->dockSchema->windowTitle().remove('&')); + ui->dockRemote->setWindowTitle(ui->dockRemote->windowTitle().remove('&')); +} + +bool SqliteDBMainWindow::fileOpen(const QString& fileName, bool openFromProject, bool readOnly) +{ + bool retval = false; + + QString wFile = fileName; + // QFile::exist will produce error message if passed empty string. + // Test string length before usage w/ QFile to silence warning + if (wFile.isEmpty() || !QFile::exists(wFile)) + { + wFile = FileDialog::getOpenFileName( + OpenDatabaseFile, + this, + tr("Choose a database file") +#ifndef Q_OS_MAC // Filters on OS X are buggy + , FileDialog::getSqlDatabaseFileFilter() +#endif + ); + } + // catch situation where user has canceled file selection from dialog + if(!wFile.isEmpty() && QFile::exists(wFile) ) + { + // Close the database. If the user didn't want to close it, though, stop here + if (db.isOpen()) + if(!fileClose()) + return false; + + // Try opening it as a project file first + if(loadProject(wFile, readOnly)) + { + retval = true; + } else { + // No project file; so it should be a database file + if(db.open(wFile, readOnly)) + { + // Close all open but empty SQL tabs + for(int i=ui->tabSqlAreas->count()-1;i>=0;i--) + { + if(qobject_cast(ui->tabSqlAreas->widget(i))->getSql().trimmed().isEmpty()) + closeSqlTab(i, true); + } + + statusEncodingLabel->setText(db.getPragma("encoding")); + statusEncryptionLabel->setVisible(db.encrypted()); + statusReadOnlyLabel->setVisible(db.readOnly()); + setCurrentFile(wFile); + if(!openFromProject) { + addToRecentFilesMenu(wFile, readOnly); + // When a new DB file has been open while a project is open, set the project modified. + if(!currentProjectFilename.isEmpty()) + isProjectModified = true; + } + if(ui->tabSqlAreas->count() == 0) + openSqlTab(true); + if(ui->mainTab->currentWidget() == ui->browser) + populateTable(); + else if(ui->mainTab->currentWidget() == ui->pragmas) + loadPragmas(); + + // Update remote dock + //remoteDock->fileOpened(wFile); + + retval = true; + } else { + QMessageBox::warning(this, qApp->applicationName(), tr("Could not open database file.\nReason: %1").arg(db.lastError())); + return false; + } + } + } + + return retval; +} + +void SqliteDBMainWindow::fileNew() +{ + QString fileName = FileDialog::getSaveFileName( + CreateDatabaseFile, + this, + tr("Choose a filename to save under"), + FileDialog::getSqlDatabaseFileFilter()); + if(!fileName.isEmpty()) + { + if(QFile::exists(fileName)) + QFile::remove(fileName); + db.create(fileName); + setCurrentFile(fileName); + addToRecentFilesMenu(fileName); + statusEncodingLabel->setText(db.getPragma("encoding")); + statusEncryptionLabel->setVisible(false); + statusReadOnlyLabel->setVisible(false); + populateTable(); + if(ui->tabSqlAreas->count() == 0) + openSqlTab(true); + createTable(); + } +} + +void SqliteDBMainWindow::fileNewInMemoryDatabase() +{ + db.create(":memory:"); + setCurrentFile(tr("In-Memory database")); + statusEncodingLabel->setText(db.getPragma("encoding")); + statusEncryptionLabel->setVisible(false); + statusReadOnlyLabel->setVisible(false); + ////remoteDock->fileOpened(":memory:"); + populateTable(); + if(ui->tabSqlAreas->count() == 0) + openSqlTab(true); + createTable(); +} + +void SqliteDBMainWindow::populateStructure(const sqlb::ObjectIdentifier& old_table) +{ + // Refresh the structure tab + ui->dbTreeWidget->setRootIndex(dbStructureModel->index(1, 0)); // Show the 'All' part of the db structure + ui->dbTreeWidget->expandToDepth(0); + ui->treeSchemaDock->setRootIndex(dbStructureModel->index(1, 0)); // Show the 'All' part of the db structure + ui->treeSchemaDock->expandToDepth(0); + + // Refresh the browse data tab + ui->tableBrowser->setStructure(dbStructureModel, old_table); + + // Cancel here if no database is opened + if(!db.isOpen()) + return; + + // Update table and column names for syntax highlighting + SqlUiLexer::QualifiedTablesMap qualifiedTablesMap; + for(const auto& it : db.schemata) + { + SqlUiLexer::TablesAndColumnsMap tablesToColumnsMap; + + for(const auto& jt : it.second) + { + if(jt.second->type() == sqlb::Object::Types::Table || jt.second->type() == sqlb::Object::Types::View) + { + QString objectname = QString::fromStdString(jt.second->name()); + + sqlb::FieldInfoList fi = jt.second->fieldInformation(); + for(const sqlb::FieldInfo& f : fi) + tablesToColumnsMap[objectname].push_back(QString::fromStdString(f.name)); + } + } + + qualifiedTablesMap[QString::fromStdString(it.first)] = tablesToColumnsMap; + } + SqlTextEdit::sqlLexer->setTableNames(qualifiedTablesMap); + ui->editLogApplication->reloadKeywords(); + ui->editLogUser->reloadKeywords(); + for(int i=0;itabSqlAreas->count();i++) + qobject_cast(ui->tabSqlAreas->widget(i))->getEditor()->reloadKeywords(); + + // Resize SQL column to fit contents + ui->dbTreeWidget->resizeColumnToContents(DbStructureModel::ColumnSQL); + ui->treeSchemaDock->resizeColumnToContents(DbStructureModel::ColumnSQL); + // Resize also the Name column in the Dock since it has usually + // short content and there is little space there. + ui->treeSchemaDock->resizeColumnToContents(DbStructureModel::ColumnName); + + +} + +void SqliteDBMainWindow::populateTable() +{ + // Early exit if the Browse Data tab isn't visible as there is no need to update it in this case + if(ui->mainTab->currentWidget() != ui->browser) + return; + + QApplication::setOverrideCursor(Qt::WaitCursor); + ui->tableBrowser->updateTable(); + QApplication::restoreOverrideCursor(); +} + +bool SqliteDBMainWindow::fileClose() +{ + // Stop any running SQL statements before closing the database + if(execute_sql_worker && execute_sql_worker->isRunning()) + { + if(QMessageBox::warning(this, qApp->applicationName(), + tr("You are still executing SQL statements. Closing the database now will stop their execution, possibly " + "leaving the database in an inconsistent state. Are you sure you want to close the database?"), + QMessageBox::Yes, QMessageBox::Cancel | QMessageBox::Default | QMessageBox::Escape) == QMessageBox::Cancel) + return false; + + execute_sql_worker->stop(); + execute_sql_worker->wait(); + } + + // Close the database but stop the closing process here if the user pressed the cancel button in there + if(!db.close()) + return false; + + setCurrentFile(QString()); + loadPragmas(); + statusEncryptionLabel->setVisible(false); + statusReadOnlyLabel->setVisible(false); + + // Reset the table browser of the Browse Data tab + ui->tableBrowser->reset(); + + // Clear edit dock + editDock->setCurrentIndex(QModelIndex()); + + // Clear the SQL Log + ui->editLogApplication->clear(); + ui->editLogUser->clear(); + ui->editLogErrorLog->clear(); + + // Remove completion and highlighting for identifiers + SqlTextEdit::sqlLexer->setTableNames(SqlUiLexer::QualifiedTablesMap()); + for(int i=0; i < ui->tabSqlAreas->count(); i++) + qobject_cast(ui->tabSqlAreas->widget(i))->getEditor()->reloadKeywords(); + + // Clear remote dock + //remoteDock->fileOpened(QString()); + + return true; +} + +void SqliteDBMainWindow::closeEvent( QCloseEvent* event ) +{ + if(closeFiles()) + { + Settings::setValue("SqliteDBMainWindow", "geometry", saveGeometry()); + Settings::setValue("SqliteDBMainWindow", "windowState", saveState()); + Settings::setValue("SqliteDBMainWindow", "openTabs", saveOpenTabs()); + + Settings::setValue("SQLLogDock", "Log", ui->comboLogSubmittedBy->currentText()); + Settings::setValue("SchemaDock", "dropQualifiedNames", ui->actionDropQualifiedCheck->isChecked()); + Settings::setValue("SchemaDock", "dropEnquotedNames", ui->actionEnquoteNamesCheck->isChecked()); + + SqlExecutionArea::saveState(); + + QMainWindow::closeEvent(event); + } else { + event->ignore(); + } +} + +bool SqliteDBMainWindow::closeFiles() +{ + bool ignoreUnattachedBuffers = false; + // Ask for saving all modified open SQL files in their files and all the unattached tabs in a project file. + for(int i=0; itabSqlAreas->count(); i++) + // Ask for saving and comply with cancel answer. + if(!askSaveSqlTab(i, ignoreUnattachedBuffers)) + return false; + return closeProject(); +} + +bool SqliteDBMainWindow::closeProject() +{ + if(!currentProjectFilename.isEmpty() && isProjectModified) { + QMessageBox::StandardButton reply = QMessageBox::question + (nullptr, + QApplication::applicationName(), + tr("Do you want to save the changes made to the project file '%1'?"). + arg(QFileInfo(currentProjectFilename).fileName()), + QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel); + switch(reply) { + case QMessageBox::Save: + saveProject(); + break; + case QMessageBox::Cancel: + return false; + default: + break; + } + } + currentProjectFilename.clear(); + return db.close(); +} + +void SqliteDBMainWindow::attachPlot(ExtendedTableWidget* tableWidget, SqliteTableModel* model, BrowseDataTableSettings* settings, bool keepOrResetSelection) +{ + plotDock->updatePlot(model, settings, true, keepOrResetSelection); + // Disconnect previous connection + disconnect(plotDock, SIGNAL(pointsSelected(int,int)), nullptr, nullptr); + if(tableWidget) { + // Connect plot selection to the current table results widget. + connect(plotDock, SIGNAL(pointsSelected(int,int)), tableWidget, SLOT(selectTableLines(int, int))); + connect(tableWidget, &ExtendedTableWidget::destroyed, plotDock, &PlotDock::resetPlot); + // Disconnect requestUrlOrFileOpen in order to make sure that there is only one connection. Otherwise we can open it several times. + disconnect(tableWidget, &ExtendedTableWidget::requestUrlOrFileOpen, this, &SqliteDBMainWindow::openUrlOrFile); + connect(tableWidget, &ExtendedTableWidget::requestUrlOrFileOpen, this, &SqliteDBMainWindow::openUrlOrFile); + } +} + +void SqliteDBMainWindow::refresh() +{ + // What the Refresh function does depends on the currently active tab. This way the keyboard shortcuts (F5 and Ctrl+R) + // always perform some meaningful task; they just happen to be context dependent in the function they trigger. + QWidget* currentTab = ui->mainTab->currentWidget(); + if (currentTab == ui->structure) { + // Refresh the schema + db.updateSchema(); + } else if (currentTab == ui->browser) { + // Refresh the schema and reload the current table + populateTable(); + } else if (currentTab == ui->pragmas) { + // Reload pragma values + loadPragmas(); + } else if (currentTab == ui->query) { + // (Re-)Run the current SQL query + executeQuery(); + } +} + +void SqliteDBMainWindow::createTable() +{ + EditTableDialog dialog(db, sqlb::ObjectIdentifier(), true, this); + if(dialog.exec()) + { + populateTable(); + } +} + +void SqliteDBMainWindow::createIndex() +{ + EditIndexDialog dialog(db, sqlb::ObjectIdentifier(), true, this); + if(dialog.exec()) + populateTable(); +} + +void SqliteDBMainWindow::compact() +{ + VacuumDialog dialog(&db, this); + dialog.exec(); +} + +void SqliteDBMainWindow::deleteObject() +{ + // Get name and type of object to delete + sqlb::ObjectIdentifier name(ui->dbTreeWidget->model()->data(ui->dbTreeWidget->currentIndex().sibling(ui->dbTreeWidget->currentIndex().row(), DbStructureModel::ColumnSchema), Qt::EditRole).toString().toStdString(), + ui->dbTreeWidget->model()->data(ui->dbTreeWidget->currentIndex().sibling(ui->dbTreeWidget->currentIndex().row(), DbStructureModel::ColumnName), Qt::EditRole).toString().toStdString()); + QString type = ui->dbTreeWidget->model()->data(ui->dbTreeWidget->currentIndex().sibling(ui->dbTreeWidget->currentIndex().row(), DbStructureModel::ColumnObjectType), Qt::EditRole).toString(); + + // Due to different grammar in languages (e.g. gender or declension), each message must be given separately to translation. + QString message; + if (type == "table") + message = tr("Are you sure you want to delete the table '%1'?\nAll data associated with the table will be lost."); + else if (type == "view") + message = tr("Are you sure you want to delete the view '%1'?"); + else if (type == "trigger") + message = tr("Are you sure you want to delete the trigger '%1'?"); + else if (type == "index") + message = tr("Are you sure you want to delete the index '%1'?"); + + // Ask user if he really wants to delete that table + if(QMessageBox::warning(this, QApplication::applicationName(), message.arg(QString::fromStdString(name.name())), + QMessageBox::Yes | QMessageBox::No, QMessageBox::No) == QMessageBox::Yes) + { + // Delete the table + QString statement = QString("DROP %1 %2;").arg(type.toUpper(), QString::fromStdString(name.toString())); + if(!db.executeSQL(statement.toStdString())) + { + if (type == "table") + message = tr("Error: could not delete the table."); + else if (type == "view") + message = tr("Error: could not delete the view."); + else if (type == "trigger") + message = tr("Error: could not delete the trigger."); + else if (type == "index") + message = tr("Error: could not delete the index."); + + QString error = tr("Message from database engine:\n%1").arg(db.lastError()); + QMessageBox::warning(this, QApplication::applicationName(), message + " " + error); + } else { + populateTable(); + changeTreeSelection(); + } + } +} + +void SqliteDBMainWindow::editObject() +{ + if(!ui->dbTreeWidget->selectionModel()->hasSelection()) + return; + + // Get name and type of the object to edit + sqlb::ObjectIdentifier name(ui->dbTreeWidget->model()->data(ui->dbTreeWidget->currentIndex().sibling(ui->dbTreeWidget->currentIndex().row(), DbStructureModel::ColumnSchema), Qt::EditRole).toString().toStdString(), + ui->dbTreeWidget->model()->data(ui->dbTreeWidget->currentIndex().sibling(ui->dbTreeWidget->currentIndex().row(), DbStructureModel::ColumnName), Qt::EditRole).toString().toStdString()); + QString type = ui->dbTreeWidget->model()->data(ui->dbTreeWidget->currentIndex().sibling(ui->dbTreeWidget->currentIndex().row(), DbStructureModel::ColumnObjectType), Qt::EditRole).toString(); + + if(type == "table") + { + // For a safe and possibly complex table modification we must follow the steps documented in + // https://www.sqlite.org/lang_altertable.html + // Paragraph (first procedure): Making Other Kinds Of Table Schema Changes + + QString foreign_keys = db.getPragma("foreign_keys"); + if (foreign_keys == "1") { + if(db.getDirty() && QMessageBox::question(this, + QApplication::applicationName(), + tr("Editing the table requires to save all pending changes now.\nAre you sure you want to save the database?"), + QMessageBox::Save | QMessageBox::Default, + QMessageBox::Cancel | QMessageBox::Escape) != QMessageBox::Save) + return; + // Commit all changes so the foreign_keys can be effective. + fileSave(); + db.setPragma("foreign_keys", "0"); + } + + EditTableDialog dialog(db, name, false, this); + bool ok = dialog.exec(); + + // If foreign_keys were enabled, we must commit or rollback the transaction so the foreign_keys pragma can be restored. + if (foreign_keys == "1") { + if (!db.querySingleValueFromDb("PRAGMA " + sqlb::escapeIdentifier(name.schema()) + ".foreign_key_check").isNull()) { + // Raise warning for accepted modification. When rejected, warn user also since we know now that the table has problems, + // but it wasn't our fault. + if (ok) + QMessageBox::warning(this, QApplication::applicationName(), + tr("Error checking foreign keys after table modification. The changes will be reverted.")); + else + QMessageBox::warning(this, QApplication::applicationName(), + tr("This table did not pass a foreign-key check.
" + "You should run 'Tools | Foreign-Key Check' and fix the reported issues.")); + db.revertAll(); + } else { + // Commit all changes so the foreign_keys can be effective. + fileSave(); + } + db.setPragma("foreign_keys", foreign_keys); + } + if(ok) { + ui->tableBrowser->clearFilters(); + populateTable(); + } + } else if(type == "index") { + EditIndexDialog dialog(db, name, false, this); + if(dialog.exec()) + populateTable(); + } else if(type == "view") { + sqlb::ViewPtr view = db.getObjectByName(name); + runSqlNewTab(QString("DROP VIEW %1;\n%2").arg(QString::fromStdString(name.toString())).arg(QString::fromStdString(view->sql())), + tr("Edit View %1").arg(QString::fromStdString(name.toDisplayString())), + "https://www.sqlite.org/lang_createview.html", + /* autoRun */ false); + } else if(type == "trigger") { + sqlb::TriggerPtr trigger = db.getObjectByName(name); + runSqlNewTab(QString("DROP TRIGGER %1;\n%2").arg(QString::fromStdString(name.toString())).arg(QString::fromStdString(trigger->sql())), + tr("Edit Trigger %1").arg(QString::fromStdString(name.toDisplayString())), + "https://www.sqlite.org/lang_createtrigger.html", + /* autoRun */ false); + } +} + +void SqliteDBMainWindow::helpWhatsThis() +{ + QWhatsThis::enterWhatsThisMode (); +} + +void SqliteDBMainWindow::helpAbout() +{ + AboutDialog dialog(this); + dialog.exec(); +} + +void SqliteDBMainWindow::updateRecordText(const QPersistentModelIndex& idx, const QByteArray& text, bool isBlob) +{ + m_currentTabTableModel->setTypedData(idx, isBlob, text); +} + +void SqliteDBMainWindow::toggleEditDock(bool visible) +{ + if (!visible) { + // Update main window + ui->tableBrowser->setFocus(); + } else { + // fill edit dock with actual data, when the current index has changed while the dock was invisible. + // (note that this signal is also emitted when the widget is docked or undocked, so we have to avoid + // reloading data when the user is editing and (un)docks the editor). + if (editDock->currentIndex() != ui->tableBrowser->currentIndex()) + editDock->setCurrentIndex(ui->tableBrowser->currentIndex()); + } +} + +void SqliteDBMainWindow::doubleClickTable(const QModelIndex& index) +{ + // Cancel on invalid index + if (!index.isValid()) { + return; + } + + // * Don't allow editing of other objects than tables and editable views + bool isEditingAllowed = !db.readOnly() && m_currentTabTableModel == ui->tableBrowser->model() && + ui->tableBrowser->model()->isEditable(index); + + // Enable or disable the Apply, Null, & Import buttons in the Edit Cell + // dock depending on the value of the "isEditingAllowed" bool above + editDock->setReadOnly(!isEditingAllowed); + + editDock->setCurrentIndex(index); + + // Show the edit dock + ui->dockEdit->setVisible(true); + + // Set focus on the edit dock + editDock->setFocus(); +} + +void SqliteDBMainWindow::dataTableSelectionChanged(const QModelIndex& index) +{ + // Cancel on invalid index + if(!index.isValid()) { + editDock->setCurrentIndex(QModelIndex()); + return; + } + + bool editingAllowed = !db.readOnly() && (m_currentTabTableModel == ui->tableBrowser->model()) && + ui->tableBrowser->model()->isEditable(index); + + // Don't allow editing of other objects than tables and editable views + editDock->setReadOnly(!editingAllowed); + + // If the Edit Cell dock is visible, load the new value into it + if (editDock->isVisible()) { + editDock->setCurrentIndex(index); + } +} + +/* + * I'm still not happy how the results are represented to the user + * right now you only see the result of the last executed statement. + * A better experience would be tabs on the bottom with query results + * for all the executed statements. + */ +void SqliteDBMainWindow::executeQuery() +{ + // Make sure a database is opened. This is necessary because we allow opened SQL editor tabs even if no database is loaded. Hitting F5 or similar + // then might call this function. + if(!db.isOpen()) + return; + + // Check if other task is still running and stop it if necessary + if(execute_sql_worker && execute_sql_worker->isRunning()) + { + // Ask the user and do nothing if he/she doesn't want to interrupt the running query + if(QMessageBox::warning(this, qApp->applicationName(), + tr("You are already executing SQL statements. Do you want to stop them in order to execute the current " + "statements instead? Note that this might leave the database in an inconsistent state."), + QMessageBox::Yes, QMessageBox::Cancel | QMessageBox::Default | QMessageBox::Escape) == QMessageBox::Cancel) + return; + + // Stop the running query + execute_sql_worker->stop(); + execute_sql_worker->wait(); + } + + // Get current SQL tab and editor + SqlExecutionArea* sqlWidget = qobject_cast(ui->tabSqlAreas->currentWidget()); + SqlTextEdit* editor = sqlWidget->getEditor(); + auto* current_tab = ui->tabSqlAreas->currentWidget(); + const QString tabName = ui->tabSqlAreas->tabText(ui->tabSqlAreas->currentIndex()).remove('&'); + + // Remove any error indicators + editor->clearErrorIndicators(); + + // Determine execution mode: execute all, execute selection or execute current line + enum executionMode + { + All, + Selection, + Line + } mode; + if(sender() && sender()->objectName() == "actionSqlExecuteLine") + mode = Line; + else if(!sqlWidget->getSelectedSql().isEmpty()) + mode = Selection; + else + mode = All; + + // Get SQL code to execute. This depends on the execution mode. + int execute_from_position = 0; // Where we want to start the execution in the query string + int execute_to_position = 0; // Where we roughly want to end the execution in the query string + + switch(mode) + { + case Selection: + { + // Start and end positions are start and end positions from the selection + int execute_from_line, execute_from_index, execute_to_line, execute_to_index; + editor->getSelection(&execute_from_line, &execute_from_index, &execute_to_line, &execute_to_index); + execute_from_position = editor->positionFromLineIndex(execute_from_line, execute_from_index); + execute_to_position = editor->positionFromLineIndex(execute_to_line, execute_to_index); + + db.logSQL(tr("-- EXECUTING SELECTION IN '%1'\n--").arg(tabName), kLogMsg_User); + } break; + case Line: + { + // Start position is the first character of the current line, except for those cases where we're in the middle of a + // statement which started on one the previous line. In that case the start position is actually a bit earlier. For + // the end position we set the last character of the current line. If the statement(s) continue(s) into the next line, + // SQLite will execute it/them anyway and we'll stop afterwards. + int execute_from_line, dummy; + editor->getCursorPosition(&execute_from_line, &dummy); + execute_from_position = editor->positionFromLineIndex(execute_from_line, 0); + + // Need to set the end position here before adjusting the start line + int execute_to_line = execute_from_line; + int execute_to_index = editor->text(execute_to_line).remove('\n').remove('\r').length(); // This chops the line break at the end of the line + execute_to_position = editor->positionFromLineIndex(execute_to_line, execute_to_index); + + QByteArray firstPartEntireSQL = sqlWidget->getSql().toUtf8().left(execute_from_position); + if(firstPartEntireSQL.lastIndexOf(';') != -1) + execute_from_position -= firstPartEntireSQL.length() - firstPartEntireSQL.lastIndexOf(';') - 1; + + db.logSQL(tr("-- EXECUTING LINE IN '%1'\n--").arg(tabName), kLogMsg_User); + } break; + case All: + { + // Start position is the first byte, end position the last. + // Note that we use byte positions that might differ from character positions. + execute_to_position = editor->length(); + + db.logSQL(tr("-- EXECUTING ALL IN '%1'\n--").arg(tabName), kLogMsg_User); + } break; + } + + // Prepare a lambda function for logging the results of a query + auto query_logger = [this, sqlWidget, editor](bool ok, const QString& status_message, int from_position, int to_position) { + int execute_from_line, execute_from_index; + editor->lineIndexFromPosition(from_position, &execute_from_line, &execute_from_index); + + // Special case: if the start position is at the end of a line, then move to the beginning of next line. + // Otherwise for the typical case, the line reference is one less than expected. + // Note that execute_from_index uses character positions and not byte positions, so at() can be used. + QChar char_at_index = editor->text(execute_from_line).at(execute_from_index); + if (char_at_index == '\r' || char_at_index == '\n') { + execute_from_line++; + // The next lines could be empty, so skip all of them too. + while(editor->text(execute_from_line).trimmed().isEmpty()) + execute_from_line++; + execute_from_index = 0; + } + + // If there was an error highlight the erroneous SQL statement + if(!ok) + { + int end_of_current_statement_line, end_of_current_statement_index; + editor->lineIndexFromPosition(to_position, &end_of_current_statement_line, &end_of_current_statement_index); + editor->setErrorIndicator(execute_from_line, execute_from_index, end_of_current_statement_line, end_of_current_statement_index); + + editor->setCursorPosition(execute_from_line, execute_from_index); + } + + // Log the query and the result message. + // The query takes the last placeholder as it may itself contain the sequence '%' + number. + QString query = editor->text(from_position, to_position); + QString log_message = "-- " + tr("At line %1:").arg(execute_from_line+1) + "\n" + query.trimmed() + "\n-- " + tr("Result: %1").arg(status_message); + db.logSQL(log_message, kLogMsg_User); + + log_message = tr("Result: %2").arg(status_message) + "\n" + tr("At line %1:").arg(execute_from_line+1) + "\n" + query.trimmed(); + // Update the execution area + sqlWidget->finishExecution(log_message, ok); + }; + + // Get the statement(s) to execute. When in selection mode crop the query string at exactly the end of the selection to make sure SQLite has + // no chance to execute any further. + QString sql = sqlWidget->getSql(); + if(mode == Selection) + sql = sql.toUtf8().left(execute_to_position); // We have to convert to a QByteArray here because QScintilla gives us the position in bytes, not in characters. + + // Prepare the SQL worker to run the query. We set the context of each signal-slot connection to the current SQL execution area. + // This means that if the tab is closed all these signals are automatically disconnected so the lambdas won't be called for a not + // existing execution area. + execute_sql_worker.reset(new RunSql(db, sql, execute_from_position, execute_to_position, true)); + + connect(execute_sql_worker.get(), &RunSql::structureUpdated, sqlWidget, [this]() { + db.updateSchema(); + }, Qt::QueuedConnection); + connect(execute_sql_worker.get(), &RunSql::statementErrored, sqlWidget, [query_logger, this, sqlWidget](const QString& status_message, int from_position, int to_position) { + sqlWidget->getModel()->reset(); + ui->actionSqlResultsSave->setEnabled(false); + ui->actionSqlResultsSaveAsView->setEnabled(false); + attachPlot(sqlWidget->getTableResult(), sqlWidget->getModel()); + + query_logger(false, status_message, from_position, to_position); + }, Qt::QueuedConnection); + connect(execute_sql_worker.get(), &RunSql::statementExecuted, sqlWidget, [query_logger, this, sqlWidget](const QString& status_message, int from_position, int to_position) { + sqlWidget->getModel()->reset(); + ui->actionSqlResultsSave->setEnabled(false); + ui->actionSqlResultsSaveAsView->setEnabled(false); + attachPlot(sqlWidget->getTableResult(), sqlWidget->getModel()); + + query_logger(true, status_message, from_position, to_position); + execute_sql_worker->startNextStatement(); + }, Qt::QueuedConnection); + connect(execute_sql_worker.get(), &RunSql::statementReturnsRows, sqlWidget, [query_logger, this, sqlWidget](const QString& query, int from_position, int to_position, qint64 time_in_ms_so_far) { + auto time_start = std::chrono::high_resolution_clock::now(); + + ui->actionSqlResultsSave->setEnabled(true); + ui->actionSqlResultsSaveAsView->setEnabled(!db.readOnly()); + + auto * model = sqlWidget->getModel(); + model->setQuery(query); + + // Wait until the initial loading of data (= first chunk and row count) has been performed + auto conn = std::make_shared(); + *conn = connect(model, &SqliteTableModel::finishedFetch, [=](int fetched_row_begin, int fetched_row_end) { + // Avoid attaching the plot when the signal is notifying the row count, since the + // data wouldn't be available yet. + if(fetched_row_begin != fetched_row_end && fetched_row_begin != model->rowCount()) { + // Disconnect this connection right now. This avoids calling this slot multiple times + disconnect(*conn); + + attachPlot(sqlWidget->getTableResult(), sqlWidget->getModel()); + } else { + connect(sqlWidget->getTableResult()->selectionModel(), &QItemSelectionModel::currentChanged, this, &SqliteDBMainWindow::dataTableSelectionChanged); + connect(sqlWidget->getTableResult(), &QTableView::doubleClicked, this, &SqliteDBMainWindow::doubleClickTable); + + auto time_end = std::chrono::high_resolution_clock::now(); + auto time_in_ms = std::chrono::duration_cast(time_end-time_start); + query_logger(true, tr("%1 rows returned in %2ms").arg(model->rowCount()).arg(time_in_ms.count()+time_in_ms_so_far), from_position, to_position); + execute_sql_worker->startNextStatement(); + } + }); + }, Qt::QueuedConnection); + connect(execute_sql_worker.get(), &RunSql::confirmSaveBeforePragmaOrVacuum, sqlWidget, [this]() { + if(QMessageBox::question(nullptr, QApplication::applicationName(), + tr("Setting PRAGMA values or vacuuming will commit your current transaction.\nAre you sure?"), + QMessageBox::Yes | QMessageBox::Default, + QMessageBox::No | QMessageBox::Escape) == QMessageBox::No) + execute_sql_worker->stop(); + + }, Qt::BlockingQueuedConnection); + connect(execute_sql_worker.get(), &RunSql::finished, sqlWidget, [this, current_tab, sqlWidget]() { + // We work with a pointer to the current tab here instead of its index because the user might reorder the tabs in the meantime. + // We set different icons for general tabs, which are either new or loaded from the project file, and for tabs loaded from a file. + if(sqlWidget->fileName().isEmpty()) + ui->tabSqlAreas->setTabIcon(ui->tabSqlAreas->indexOf(current_tab), QIcon(":/icons/open_sql")); + else + ui->tabSqlAreas->setTabIcon(ui->tabSqlAreas->indexOf(current_tab), QIcon(":/icons/document_open")); + + // Set no-running-query state + ui->tabSqlAreas->tabBar()->setTabData(ui->tabSqlAreas->indexOf(current_tab), QVariant(false)); + + // We don't need to check for the current SQL tab here because two concurrently running queries are not allowed + ui->actionSqlExecuteLine->setEnabled(true); + ui->actionExecuteSql->setEnabled(true); + ui->actionSqlStop->setEnabled(false); + sqlWidget->getEditor()->setReadOnly(false); + + // Show Done message + if(sqlWidget->inErrorState()) + sqlWidget->getStatusEdit()->setPlainText(tr("Execution finished with errors.") + "\n" + sqlWidget->getStatusEdit()->toPlainText()); + else + sqlWidget->getStatusEdit()->setPlainText(tr("Execution finished without errors.") + "\n" + sqlWidget->getStatusEdit()->toPlainText()); + }); + + // Add an hourglass icon to the current tab to indicate that there's a running execution in there. + ui->tabSqlAreas->setTabIcon(ui->tabSqlAreas->currentIndex(), QIcon(":icons/hourglass")); + // We use the tab data to check whether a specific SQL tab is currently running a query or not. + ui->tabSqlAreas->tabBar()->setTabData(ui->tabSqlAreas->currentIndex(), QVariant(true)); + + // Deactivate the buttons to start a query and activate the button to stop the query + ui->actionSqlExecuteLine->setEnabled(false); + ui->actionExecuteSql->setEnabled(false); + ui->actionSqlStop->setEnabled(true); + + // Make the SQL editor widget read-only. We do this because the error indicators would be misplaced if the user changed the SQL text during execution + sqlWidget->getEditor()->setReadOnly(true); + + // Start the execution + execute_sql_worker->start(); +} + +void SqliteDBMainWindow::mainTabSelected(int /*tabindex*/) +{ + editDock->setReadOnly(true); + + if(ui->mainTab->currentWidget() == ui->browser) + { + m_currentTabTableModel = ui->tableBrowser->model(); + populateTable(); + } else if(ui->mainTab->currentWidget() == ui->pragmas) { + loadPragmas(); + } else if(ui->mainTab->currentWidget() == ui->query) { + SqlExecutionArea* sqlWidget = qobject_cast(ui->tabSqlAreas->currentWidget()); + + if (sqlWidget) { + m_currentTabTableModel = sqlWidget->getModel(); + + dataTableSelectionChanged(sqlWidget->getTableResult()->currentIndex()); + } + } +} + +void SqliteDBMainWindow::importTableFromCSV() +{ + QStringList file_filter; + file_filter << FILE_FILTER_CSV + << FILE_FILTER_TSV + << FILE_FILTER_DSV + << FILE_FILTER_TXT + << FILE_FILTER_DAT + << FILE_FILTER_ALL; + + QStringList wFiles = FileDialog::getOpenFileNames( + OpenCSVFile, + this, + tr("Choose text files"), + file_filter.join(";;")); + + std::vector validFiles; + for(const auto& file : wFiles) { + if (QFile::exists(file)) + validFiles.push_back(file); + } + + if (!validFiles.empty()) + { + ImportCsvDialog dialog(validFiles, &db, this); + if (dialog.exec()) + populateTable(); + } +} + +void SqliteDBMainWindow::exportTableToCSV() +{ + // Get the current table name if we are in the Browse Data tab + sqlb::ObjectIdentifier current_table; + if(ui->mainTab->currentWidget() == ui->structure) + { + QString type = ui->dbTreeWidget->model()->data(ui->dbTreeWidget->currentIndex().sibling(ui->dbTreeWidget->currentIndex().row(), DbStructureModel::ColumnObjectType)).toString(); + if(type == "table" || type == "view") + { + QString schema = ui->dbTreeWidget->model()->data(ui->dbTreeWidget->currentIndex().sibling(ui->dbTreeWidget->currentIndex().row(), DbStructureModel::ColumnSchema)).toString(); + QString name = ui->dbTreeWidget->model()->data(ui->dbTreeWidget->currentIndex().sibling(ui->dbTreeWidget->currentIndex().row(), DbStructureModel::ColumnName)).toString(); + current_table = sqlb::ObjectIdentifier(schema.toStdString(), name.toStdString()); + } + } else if(ui->mainTab->currentWidget() == ui->browser) { + current_table = ui->tableBrowser->currentlyBrowsedTableName(); + } + + // Open dialog + ExportDataDialog dialog(db, ExportDataDialog::ExportFormatCsv, this, "", current_table); + dialog.exec(); +} + +void SqliteDBMainWindow::exportTableToJson() +{ + // Get the current table name if we are in the Browse Data tab + sqlb::ObjectIdentifier current_table; + if(ui->mainTab->currentWidget() == ui->structure) + { + QString type = ui->dbTreeWidget->model()->data(ui->dbTreeWidget->currentIndex().sibling(ui->dbTreeWidget->currentIndex().row(), DbStructureModel::ColumnObjectType)).toString(); + if(type == "table" || type == "view") + { + QString schema = ui->dbTreeWidget->model()->data(ui->dbTreeWidget->currentIndex().sibling(ui->dbTreeWidget->currentIndex().row(), DbStructureModel::ColumnSchema)).toString(); + QString name = ui->dbTreeWidget->model()->data(ui->dbTreeWidget->currentIndex().sibling(ui->dbTreeWidget->currentIndex().row(), DbStructureModel::ColumnName)).toString(); + current_table = sqlb::ObjectIdentifier(schema.toStdString(), name.toStdString()); + } + } else if(ui->mainTab->currentWidget() == ui->browser) { + current_table = ui->tableBrowser->currentlyBrowsedTableName(); + } + + // Open dialog + ExportDataDialog dialog(db, ExportDataDialog::ExportFormatJson, this, "", current_table); + dialog.exec(); +} + +void SqliteDBMainWindow::dbState(bool dirty) +{ + ui->fileSaveAction->setEnabled(dirty); + ui->fileRevertAction->setEnabled(dirty); + ui->fileAttachAction->setEnabled(db.isOpen() && !dirty); +} + +void SqliteDBMainWindow::fileSave() +{ + if(db.isOpen()) + { + if(!db.releaseAllSavepoints()) + { + QMessageBox::warning(this, QApplication::applicationName(), tr("Error while saving the database file. This means that not all changes to the database were " + "saved. You need to resolve the following error first.\n\n%1").arg(db.lastError())); + } + } +} + +void SqliteDBMainWindow::fileRevert() +{ + if (db.isOpen()){ + QString msg = tr("Are you sure you want to undo all changes made to the database file '%1' since the last save?").arg(db.currentFile()); + if(QMessageBox::question(this, QApplication::applicationName(), msg, QMessageBox::Yes | QMessageBox::Default, QMessageBox::No | QMessageBox::Escape) == QMessageBox::Yes) + { + db.revertAll(); + populateTable(); + } + } +} + +void SqliteDBMainWindow::exportDatabaseToSQL() +{ + QString current_table; + if(ui->mainTab->currentWidget() == ui->browser) + current_table = QString::fromStdString(ui->tableBrowser->currentlyBrowsedTableName().name()); + + ExportSqlDialog dialog(&db, this, current_table); + dialog.exec(); +} + +void SqliteDBMainWindow::importDatabaseFromSQL() +{ + QStringList file_filter; + file_filter << FILE_FILTER_SQL + << FILE_FILTER_TXT + << FILE_FILTER_ALL; + + // Get file name to import + QString fileName = FileDialog::getOpenFileName( + OpenSQLFile, + this, + tr("Choose a file to import"), + file_filter.join(";;")); + + // Cancel when file doesn't exist + if(!QFile::exists(fileName)) + return; + + // If there is already a database file opened ask the user whether to import into + // this one or a new one. If no DB is opened just ask for a DB name directly + QString newDbFile; + if((db.isOpen() && QMessageBox::question(this, + QApplication::applicationName(), + tr("Do you want to create a new database file to hold the imported data?\n" + "If you answer no we will attempt to import the data in the SQL file to the current database."), + QMessageBox::Yes, QMessageBox::No) == QMessageBox::Yes) || !db.isOpen()) + { + newDbFile = FileDialog::getSaveFileName( + CreateDatabaseFile, + this, + tr("Choose a filename to save under"), + FileDialog::getSqlDatabaseFileFilter()); + if(QFile::exists(newDbFile)) + { + QMessageBox::information(this, QApplication::applicationName(), tr("File %1 already exists. Please choose a different name.").arg(newDbFile)); + return; + } else if(newDbFile.size() == 0) { + return; + } + + // Create the new file and open it in the browser + db.create(newDbFile); + db.close(); + fileOpen(newDbFile); + } + + // Defer foreign keys. Just deferring them instead of disabling them should work fine because in the import we only expect CREATE and INSERT + // statements which unlike in the Edit Table dialog shouldn't trigger any problems. + QString foreignKeysOldSettings = db.getPragma("defer_foreign_keys"); + db.setPragma("defer_foreign_keys", "1"); + + // Open, read, execute and close file + QApplication::setOverrideCursor(Qt::WaitCursor); + QFile f(fileName); + f.open(QIODevice::ReadOnly); + QByteArray data = f.readAll(); + removeBom(data); + bool ok = db.executeMultiSQL(data, newDbFile.size() == 0); + // Restore cursor before asking the user to accept the message + QApplication::restoreOverrideCursor(); + if(!ok) + QMessageBox::warning(this, QApplication::applicationName(), tr("Error importing data: %1").arg(db.lastError())); + else if(db.getPragma("foreign_keys") == "1" && !db.querySingleValueFromDb("PRAGMA foreign_key_check").isNull()) + QMessageBox::warning(this, QApplication::applicationName(), tr("Import completed. Some foreign key constraints are violated. Please fix them before saving.")); + else + QMessageBox::information(this, QApplication::applicationName(), tr("Import completed.")); + f.close(); + + // Restore the former foreign key settings + db.setPragma("defer_foreign_keys", foreignKeysOldSettings); + + // Refresh views + db.updateSchema(); + populateTable(); +} + +void SqliteDBMainWindow::openPreferences() +{ + PreferencesDialog dialog(this); + if(dialog.exec()) + reloadSettings(); +} + +//** Db Tree Context Menu +void SqliteDBMainWindow::createTreeContextMenu(const QPoint &qPoint) +{ + if(!ui->dbTreeWidget->selectionModel()->hasSelection()) + return; + + QString type = ui->dbTreeWidget->model()->data(ui->dbTreeWidget->currentIndex().sibling(ui->dbTreeWidget->currentIndex().row(), 1)).toString(); + + if(type == "table" || type == "view" || type == "trigger" || type == "index") + popupTableMenu->exec(ui->dbTreeWidget->mapToGlobal(qPoint)); +} + +//** DB Schema Dock Context Menu +void SqliteDBMainWindow::createSchemaDockContextMenu(const QPoint &qPoint) +{ + bool enable_browse_table = false; + if(ui->treeSchemaDock->selectionModel()->hasSelection()) + { + QString type = ui->treeSchemaDock->model()->data(ui->treeSchemaDock->currentIndex().sibling(ui->treeSchemaDock->currentIndex().row(), DbStructureModel::ColumnObjectType), Qt::EditRole).toString(); + if(type == "table" || type == "view") + enable_browse_table = true; + } + ui->actionPopupSchemaDockBrowseTable->setEnabled(enable_browse_table); + + popupSchemaDockMenu->exec(ui->treeSchemaDock->mapToGlobal(qPoint)); +} + +void SqliteDBMainWindow::changeTreeSelection() +{ + // Just assume first that something's selected that can not be edited at all + ui->editDeleteObjectAction->setEnabled(false); + ui->editModifyObjectAction->setEnabled(false); + ui->actionEditBrowseTable->setEnabled(false); + + if(!ui->dbTreeWidget->currentIndex().isValid()) + return; + + // Change the text and tooltips of the actions + QString type = ui->dbTreeWidget->model()->data(ui->dbTreeWidget->currentIndex().sibling(ui->dbTreeWidget->currentIndex().row(), 1)).toString(); + + if (type.isEmpty()) + { + ui->editDeleteObjectAction->setIcon(QIcon(":icons/table_delete")); + ui->editModifyObjectAction->setIcon(QIcon(":icons/table_modify")); + } else { + ui->editDeleteObjectAction->setIcon(QIcon(QString(":icons/%1_delete").arg(type))); + ui->editModifyObjectAction->setIcon(QIcon(QString(":icons/%1_modify").arg(type))); + } + + if (type == "view") { + ui->editDeleteObjectAction->setText(tr("Delete View")); + ui->editModifyObjectAction->setText(tr("Modify View")); + } else if(type == "trigger") { + ui->editDeleteObjectAction->setText(tr("Delete Trigger")); + ui->editModifyObjectAction->setText(tr("Modify Trigger")); + } else if(type == "index") { + ui->editDeleteObjectAction->setText(tr("Delete Index")); + ui->editModifyObjectAction->setText(tr("Modify Index")); + } else if(type == "table") { + ui->editDeleteObjectAction->setText(tr("Delete Table")); + ui->editModifyObjectAction->setText(tr("Modify Table")); + } else { + // Nothing to do for other types. Set the buttons not visible and return. + ui->editDeleteObjectAction->setVisible(false); + ui->editModifyObjectAction->setVisible(false); + return; + } + + ui->editDeleteObjectAction->setVisible(true); + ui->editModifyObjectAction->setVisible(true); + + // Activate actions + ui->editDeleteObjectAction->setEnabled(!db.readOnly()); + ui->editModifyObjectAction->setEnabled(!db.readOnly()); + + if(type == "table" || type == "view") + { + ui->actionEditBrowseTable->setEnabled(true); + ui->actionExportCsvPopup->setEnabled(true); + } +} + +void SqliteDBMainWindow::openRecentFile() +{ + QAction *action = qobject_cast(sender()); + if (action) + { + QString file = action->data().toString(); + bool read_only = false; + if(file.startsWith("[ro]")) // Check if file is in read-only + { + file = file.mid(4); + read_only = true; + } + + if(fileOpen(file, false, read_only)) + if(read_only) + ui->statusbar->showMessage(tr("Opened '%1' in read-only mode from recent file list").arg(file)); + else + ui->statusbar->showMessage(tr("Opened '%1' from recent file list").arg(file)); + } +} + +void SqliteDBMainWindow::updateRecentFileActions() +{ + // Get recent files list from settings + QStringList files = Settings::getValue("General", "recentFileList").toStringList(); + + // Check if files still exist and remove any non-existent file + for(int i=0;isetText(text); + recentFileActs[i]->setData(files[i]); + recentFileActs[i]->setVisible(true); + + // Add shortcut for opening the file using the keyboard. However, if the application is configured to store + // more than nine recently opened files don't set shortcuts for the later ones which wouldn't be single digit anymore. + if(i < 9) + recentFileActs[i]->setShortcut(QKeySequence(static_cast(Qt::CTRL + (Qt::Key_1+static_cast(i))))); + } + for (int j = numRecentFiles; j < MaxRecentFiles; ++j) + recentFileActs[j]->setVisible(false); + + recentSeparatorAct->setVisible(numRecentFiles > 0); +} + +void SqliteDBMainWindow::setCurrentFile(const QString &fileName) +{ + setWindowFilePath(fileName); + if(currentProjectFilename.isEmpty() && fileName.isEmpty()) + setWindowTitle(QApplication::applicationName()); + else if(currentProjectFilename.isEmpty()) + setWindowTitle(QApplication::applicationName() + " - " + QDir::toNativeSeparators(fileName)); + else { + QFileInfo projectFileInfo(currentProjectFilename); + QFileInfo dbFileInfo(fileName); + QString dbFileName; + if(dbFileInfo.path() == projectFileInfo.path()) + dbFileName = dbFileInfo.fileName(); + else + dbFileName = QDir::toNativeSeparators(fileName); + setWindowTitle(QApplication::applicationName() + " - " + QDir::toNativeSeparators(currentProjectFilename) + " [" + dbFileName + "]"); + } + activateFields(!fileName.isEmpty()); + if(!fileName.isEmpty()) + dbState(db.getDirty()); +} + +void SqliteDBMainWindow::addToRecentFilesMenu(const QString& filename, bool read_only) +{ + QFileInfo info(filename); + QString path = info.absoluteFilePath(); + if(read_only) + path = "[ro]" + path; + + QStringList files = Settings::getValue("General", "recentFileList").toStringList(); + + files.removeAll(path); + files.prepend(path); + while (files.size() > MaxRecentFiles) + files.removeLast(); + + Settings::setValue("General", "recentFileList", files); + + for(QWidget* widget : QApplication::topLevelWidgets()) { + SqliteDBMainWindow *mainWin = qobject_cast(widget); + if (mainWin) + mainWin->updateRecentFileActions(); + } +} + +void SqliteDBMainWindow::dragEnterEvent(QDragEnterEvent *event) +{ + if( event->mimeData()->hasFormat("text/uri-list") ) + event->acceptProposedAction(); +} + +void SqliteDBMainWindow::dropEvent(QDropEvent *event) +{ + QList urls = event->mimeData()->urls(); + + if( urls.isEmpty() ) + return; + + QString fileName = urls.first().toLocalFile(); + + if(!fileName.isEmpty()) { + + // If there is no open database, the only possible option is to open the file. + if (!db.isOpen()) { + fileOpen(fileName); + return; + } + bool ok; + const QString open = tr("Open Database or Project"); + const QString attach = tr("Attach Database..."); + const QString import = tr("Import CSV file(s)..."); + QString action = QInputDialog::getItem(this, + qApp->applicationName(), + tr("Select the action to apply to the dropped file(s).
" + "Note: only 'Import' will process more than one file.", "", urls.count()), + {open, attach, import}, + 0, + false, + &ok); + if(ok) { + if (action == open) { + fileOpen(fileName); + } else if (action == attach) { + fileAttach(fileName); + } else if (action == import) { + + std::vector validFiles; + for(const auto& url : urls) { + if (QFile::exists(url.toLocalFile())) + validFiles.push_back(url.toLocalFile()); + } + ImportCsvDialog dialog(validFiles, &db, this); + if (dialog.exec()) + populateTable(); + } + } + } +} + +void SqliteDBMainWindow::activateFields(bool enable) +{ + bool write = !db.readOnly(); + bool tempDb = db.currentFile() == ":memory:"; + + ui->tableBrowser->setEnabled(enable); + ui->fileCloseAction->setEnabled(enable); + ui->fileAttachAction->setEnabled(enable); + ui->fileCompactAction->setEnabled(enable && write); + ui->fileExportJsonAction->setEnabled(enable); + ui->fileExportCSVAction->setEnabled(enable); + ui->fileExportSQLAction->setEnabled(enable); + ui->fileImportCSVAction->setEnabled(enable && write); + ui->editCreateTableAction->setEnabled(enable && write); + ui->editCreateIndexAction->setEnabled(enable && write); + ui->actionDbPrint->setEnabled(enable); + ui->scrollAreaWidgetContents->setEnabled(enable); + ui->buttonBoxPragmas->setEnabled(enable && write); + ui->actionExecuteSql->setEnabled(enable); + ui->actionLoadExtension->setEnabled(enable); + ui->actionSqlExecuteLine->setEnabled(enable); + ui->actionSaveProject->setEnabled(enable && !tempDb); + ui->actionSaveProjectAs->setEnabled(enable && !tempDb); + ui->actionSaveAll->setEnabled(enable && !tempDb); + ui->actionEncryption->setEnabled(enable && write && !tempDb); + ui->actionIntegrityCheck->setEnabled(enable); + ui->actionQuickCheck->setEnabled(enable); + ui->actionForeignKeyCheck->setEnabled(enable); + ui->actionOptimize->setEnabled(enable); + ui->dockEdit->setEnabled(enable); + ui->dockPlot->setEnabled(enable); + + if(!enable) + ui->actionSqlResultsSave->setEnabled(false); + + //remoteDock->enableButtons(); +} + +void SqliteDBMainWindow::resizeEvent(QResizeEvent*) +{ + ui->tableBrowser->updateRecordsetLabel(); +} + +void SqliteDBMainWindow::loadPragmas() +{ + pragmaValues.autovacuum = db.getPragma("auto_vacuum").toInt(); + pragmaValues.automatic_index = db.getPragma("automatic_index").toInt(); + pragmaValues.checkpoint_fullsync = db.getPragma("checkpoint_fullfsync").toInt(); + pragmaValues.foreign_keys = db.getPragma("foreign_keys").toInt(); + pragmaValues.fullfsync = db.getPragma("fullfsync").toInt(); + pragmaValues.ignore_check_constraints = db.getPragma("ignore_check_constraints").toInt(); + pragmaValues.journal_mode = db.getPragma("journal_mode").toUpper(); + pragmaValues.journal_size_limit = db.getPragma("journal_size_limit").toInt(); + pragmaValues.locking_mode = db.getPragma("locking_mode").toUpper(); + pragmaValues.max_page_count = db.getPragma("max_page_count").toInt(); + pragmaValues.page_size = db.getPragma("page_size").toInt(); + pragmaValues.recursive_triggers = db.getPragma("recursive_triggers").toInt(); + pragmaValues.secure_delete = db.getPragma("secure_delete").toInt(); + pragmaValues.synchronous = db.getPragma("synchronous").toInt(); + pragmaValues.temp_store = db.getPragma("temp_store").toInt(); + pragmaValues.user_version = db.getPragma("user_version").toInt(); + pragmaValues.wal_autocheckpoint = db.getPragma("wal_autocheckpoint").toInt(); + pragmaValues.case_sensitive_like = db.getPragma("case_sensitive_like").toInt(); + + updatePragmaUi(); +} + +void SqliteDBMainWindow::updatePragmaUi() +{ + ui->comboboxPragmaAutoVacuum->setCurrentIndex(pragmaValues.autovacuum); + ui->checkboxPragmaAutomaticIndex->setChecked(pragmaValues.automatic_index); + ui->checkboxPragmaCheckpointFullFsync->setChecked(pragmaValues.checkpoint_fullsync); + ui->checkboxPragmaForeignKeys->setChecked(pragmaValues.foreign_keys); + ui->checkboxPragmaFullFsync->setChecked(pragmaValues.fullfsync); + ui->checkboxPragmaIgnoreCheckConstraints->setChecked(pragmaValues.ignore_check_constraints); + ui->comboboxPragmaJournalMode->setCurrentIndex(ui->comboboxPragmaJournalMode->findText(pragmaValues.journal_mode, Qt::MatchFixedString)); + ui->spinPragmaJournalSizeLimit->setValue(pragmaValues.journal_size_limit); + ui->comboboxPragmaLockingMode->setCurrentIndex(ui->comboboxPragmaLockingMode->findText(pragmaValues.locking_mode, Qt::MatchFixedString)); + ui->spinPragmaMaxPageCount->setValue(pragmaValues.max_page_count); + ui->comboPragmaPageSize->setCurrentIndex(ui->comboPragmaPageSize->findText(QString::number(pragmaValues.page_size), Qt::MatchFixedString)); + ui->checkboxPragmaRecursiveTriggers->setChecked(pragmaValues.recursive_triggers); + ui->checkboxPragmaSecureDelete->setChecked(pragmaValues.secure_delete); + ui->comboboxPragmaSynchronous->setCurrentIndex(pragmaValues.synchronous); + ui->comboboxPragmaTempStore->setCurrentIndex(pragmaValues.temp_store); + ui->spinPragmaUserVersion->setValue(pragmaValues.user_version); + ui->spinPragmaWalAutoCheckpoint->setValue(pragmaValues.wal_autocheckpoint); + ui->checkboxPragmaCaseSensitiveLike->setChecked(pragmaValues.case_sensitive_like); +} + +void SqliteDBMainWindow::savePragmas() +{ + if( db.getDirty() ) + { + QString msg = tr("Setting PRAGMA values will commit your current transaction.\nAre you sure?"); + if(QMessageBox::question(this, QApplication::applicationName(), msg, QMessageBox::Yes | QMessageBox::Default, QMessageBox::No | QMessageBox::Escape) == QMessageBox::No) + { + return; // abort + } + } + db.setPragma("auto_vacuum", ui->comboboxPragmaAutoVacuum->currentIndex(), pragmaValues.autovacuum); + db.setPragma("automatic_index", ui->checkboxPragmaAutomaticIndex->isChecked(), pragmaValues.automatic_index); + db.setPragma("checkpoint_fullfsync", ui->checkboxPragmaCheckpointFullFsync->isChecked(), pragmaValues.checkpoint_fullsync); + db.setPragma("foreign_keys", ui->checkboxPragmaForeignKeys->isChecked(), pragmaValues.foreign_keys); + db.setPragma("fullfsync", ui->checkboxPragmaFullFsync->isChecked(), pragmaValues.fullfsync); + db.setPragma("ignore_check_constraints", ui->checkboxPragmaIgnoreCheckConstraints->isChecked(), pragmaValues.ignore_check_constraints); + db.setPragma("journal_mode", ui->comboboxPragmaJournalMode->currentText().toUpper(), pragmaValues.journal_mode); + db.setPragma("journal_size_limit", ui->spinPragmaJournalSizeLimit->value(), pragmaValues.journal_size_limit); + db.setPragma("locking_mode", ui->comboboxPragmaLockingMode->currentText().toUpper(), pragmaValues.locking_mode); + db.setPragma("max_page_count", ui->spinPragmaMaxPageCount->value(), pragmaValues.max_page_count); + db.setPragma("page_size", ui->comboPragmaPageSize->currentText().toInt(), pragmaValues.page_size); + db.setPragma("recursive_triggers", ui->checkboxPragmaRecursiveTriggers->isChecked(), pragmaValues.recursive_triggers); + db.setPragma("secure_delete", ui->checkboxPragmaSecureDelete->isChecked(), pragmaValues.secure_delete); + db.setPragma("synchronous", ui->comboboxPragmaSynchronous->currentIndex(), pragmaValues.synchronous); + db.setPragma("temp_store", ui->comboboxPragmaTempStore->currentIndex(), pragmaValues.temp_store); + db.setPragma("user_version", ui->spinPragmaUserVersion->value(), pragmaValues.user_version); + db.setPragma("wal_autocheckpoint", ui->spinPragmaWalAutoCheckpoint->value(), pragmaValues.wal_autocheckpoint); + db.setPragma("case_sensitive_like", ui->checkboxPragmaCaseSensitiveLike->isChecked(), pragmaValues.case_sensitive_like); + isProjectModified = true; + + updatePragmaUi(); +} + +void SqliteDBMainWindow::logSql(const QString& sql, int msgtype) +{ + if(msgtype == kLogMsg_User) + { + ui->editLogUser->append(sql + "\n"); + ui->editLogUser->verticalScrollBar()->setValue(ui->editLogUser->verticalScrollBar()->maximum()); + } else if(msgtype == kLogMsg_App) { + ui->editLogApplication->append(sql + "\n"); + ui->editLogApplication->verticalScrollBar()->setValue(ui->editLogApplication->verticalScrollBar()->maximum()); + } else if(msgtype == kLogMsg_ErrorLog) { + ui->editLogErrorLog->append(sql + "\n"); + ui->editLogErrorLog->verticalScrollBar()->setValue(ui->editLogErrorLog->verticalScrollBar()->maximum()); + } +} + +// Ask user to save the buffer in the specified tab index. +// ignoreUnattachedBuffers is used to store answer about buffers not linked to files, so user is only asked once about them. +// Return true unless user wants to cancel the invoking action. +bool SqliteDBMainWindow::askSaveSqlTab(int index, bool& ignoreUnattachedBuffers) +{ + SqlExecutionArea* sqlExecArea = qobject_cast(ui->tabSqlAreas->widget(index)); + + if(sqlExecArea->getEditor()->isModified()) { + if(sqlExecArea->fileName().isEmpty() && !ignoreUnattachedBuffers) { + // Once the project is saved, remaining SQL tabs will not be modified, so this is only expected to be asked once. + QString message = currentProjectFilename.isEmpty() ? + tr("Do you want to save the changes made to SQL tabs in a new project file?") : + tr("Do you want to save the changes made to SQL tabs in the project file '%1'?"). + arg(QFileInfo(currentProjectFilename).fileName()); + QMessageBox::StandardButton reply = QMessageBox::question(nullptr, + QApplication::applicationName(), + message, + QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel); + switch(reply) { + case QMessageBox::Save: + saveProject(); + break; + case QMessageBox::Cancel: + return false; + default: + ignoreUnattachedBuffers = true; + break; + } + } else if(!sqlExecArea->fileName().isEmpty()) { + QMessageBox::StandardButton reply = + QMessageBox::question(nullptr, + QApplication::applicationName(), + tr("Do you want to save the changes made to the SQL file %1?"). + arg(QFileInfo(sqlExecArea->fileName()).fileName()), + QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel); + switch(reply) { + case QMessageBox::Save: + saveSqlFile(index); + break; + case QMessageBox::Cancel: + return false; + default: + break; + } + } + } + return true; +} + +void SqliteDBMainWindow::closeSqlTab(int index, bool force) +{ + // Check if we're still executing statements from this tab and stop them before proceeding + if(ui->tabSqlAreas->tabBar()->tabData(index).toBool()) + { + if(QMessageBox::warning(this, qApp->applicationName(), tr("The statements in this tab are still executing. Closing the tab will stop the " + "execution. This might leave the database in an inconsistent state. Are you sure " + "you want to close the tab?"), + QMessageBox::Yes, + QMessageBox::Cancel | QMessageBox::Default | QMessageBox::Escape) == QMessageBox::Cancel) + return; + + execute_sql_worker->stop(); + execute_sql_worker->wait(); + } + // Ask for saving and comply with cancel answer. + bool ignoreUnattachedBuffers = false; + if (!askSaveSqlTab(index, ignoreUnattachedBuffers)) + return; + // Remove the tab and delete the widget + QWidget* w = ui->tabSqlAreas->widget(index); + ui->tabSqlAreas->removeTab(index); + delete w; + + // Don't let an empty tab widget + if(ui->tabSqlAreas->count() == 0 && !force) + openSqlTab(true); + + // Set focus to the currently selected editor tab. + SqlExecutionArea* sqlarea = qobject_cast(ui->tabSqlAreas->currentWidget()); + if(sqlarea) + sqlarea->getEditor()->setFocus(); +} + +int SqliteDBMainWindow::openSqlTab(bool resetCounter) +{ + static int tabNumber = 0; + + if(resetCounter) + tabNumber = 0; + + // Create new tab, add it to the tab widget and select it + SqlExecutionArea* w = new SqlExecutionArea(db, this); + int index = ui->tabSqlAreas->addTab(w, QString("SQL %1").arg(++tabNumber)); + ui->tabSqlAreas->setCurrentIndex(index); + w->setFindFrameVisibility(ui->actionSqlFind->isChecked()); + // Disable the find dialog in the SQL tabs, since the shortcut + // would interfere with the search bar and it'd be anyway redundant. + w->getEditor()->setEnabledFindDialog(false); + w->getEditor()->setFocus(); + connect(w, &SqlExecutionArea::findFrameVisibilityChanged, ui->actionSqlFind, &QAction::setChecked); + + // Connect now the find shortcut to the editor with widget context, so it isn't ambiguous with other Scintilla Widgets. + QShortcut* shortcutFind = new QShortcut(ui->actionSqlFind->shortcut(), w->getEditor(), nullptr, nullptr, Qt::WidgetShortcut); + connect(shortcutFind, &QShortcut::activated, ui->actionSqlFind, &QAction::toggle); + ui->tabSqlAreas->setTabIcon(index, QIcon(":icons/open_sql")); + // The new tab is not currently running a query + ui->tabSqlAreas->tabBar()->setTabData(index, false); + + return index; +} + +void SqliteDBMainWindow::changeSqlTab(int index) +{ + // Instead of figuring out if there are some execution results in the new tab and which statement was used to generate them, + // we just disable the export buttons in the toolbar. + ui->actionSqlResultsSave->setEnabled(false); + + // Check if the new tab is currently running a query or not + if(!ui->tabSqlAreas->tabBar()->tabData(index).toBool()) + { + // Not running a query + + ui->actionSqlExecuteLine->setEnabled(db.isOpen()); + ui->actionExecuteSql->setEnabled(db.isOpen()); + ui->actionSqlStop->setEnabled(false); + } else { + // Running a query + + ui->actionSqlExecuteLine->setEnabled(false); + ui->actionExecuteSql->setEnabled(false); + ui->actionSqlStop->setEnabled(true); + } +} + +void SqliteDBMainWindow::openSqlFile() +{ + QStringList wfiles = FileDialog::getOpenFileNames( + OpenSQLFile, + this, + tr("Select SQL file to open"), + tr("Text files(*.sql *.txt);;All files(*)")); + + for(QString file: wfiles) + { + if(QFile::exists(file)) + { + // Decide whether to open a new tab or take the current one + int index; + SqlExecutionArea* current_tab = qobject_cast(ui->tabSqlAreas->currentWidget()); + if(current_tab && current_tab->getSql().isEmpty() && current_tab->getModel()->rowCount() == 0) + index = ui->tabSqlAreas->currentIndex(); + else + index = openSqlTab(); + + SqlExecutionArea* sqlarea = qobject_cast(ui->tabSqlAreas->widget(index)); + sqlarea->openFile(file); + + QFileInfo fileinfo(file); + ui->tabSqlAreas->setTabText(index, fileinfo.fileName()); + ui->tabSqlAreas->setTabIcon(index, QIcon(":/icons/document_open")); + } + } +} + +void SqliteDBMainWindow::saveSqlFile(int tabIndex) +{ + SqlExecutionArea* sqlarea = qobject_cast(ui->tabSqlAreas->widget(tabIndex)); + if(!sqlarea) + return; + + // If this SQL file hasn't been saved before open the Save As dialog. Otherwise just use the old file name for saving + if(sqlarea->fileName().isEmpty()) + { + saveSqlFileAs(); + } else { + sqlarea->saveFile(sqlarea->fileName()); + } +} + +void SqliteDBMainWindow::saveSqlFile() +{ + saveSqlFile(ui->tabSqlAreas->currentIndex()); +} + +void SqliteDBMainWindow::saveSqlFileAs() +{ + SqlExecutionArea* sqlarea = qobject_cast(ui->tabSqlAreas->currentWidget()); + if(!sqlarea) + return; + + QStringList file_filter; + file_filter << FILE_FILTER_SQL + << FILE_FILTER_TXT + << FILE_FILTER_ALL; + QString file = FileDialog::getSaveFileName( + CreateSQLFile, + this, + tr("Select file name"), + file_filter.join(";;")); + + if(!file.isEmpty()) + { + sqlarea->saveFile(file); + + QFileInfo fileinfo(file); + ui->tabSqlAreas->setTabText(ui->tabSqlAreas->currentIndex(), fileinfo.fileName()); + ui->tabSqlAreas->setTabIcon(ui->tabSqlAreas->currentIndex(), QIcon(":/icons/document_open")); + } +} + +void SqliteDBMainWindow::saveSqlResultsAsCsv() +{ + qobject_cast(ui->tabSqlAreas->currentWidget())->saveAsCsv(); +} + +void SqliteDBMainWindow::saveSqlResultsAsView() +{ + saveAsView(qobject_cast(ui->tabSqlAreas->currentWidget())->getModel()->query()); +} + +void SqliteDBMainWindow::loadExtension() +{ + QStringList file_filter; + file_filter << FILE_FILTER_DYN + << FILE_FILTER_ALL; + + QString file = FileDialog::getOpenFileName( + OpenExtensionFile, + this, + tr("Select extension file"), + file_filter.join(";;")); + + if(file.isEmpty()) + return; + + if(db.loadExtension(file)) + QMessageBox::information(this, QApplication::applicationName(), tr("Extension successfully loaded.")); + else + QMessageBox::warning(this, QApplication::applicationName(), tr("Error loading extension: %1").arg(db.lastError())); +} + +void SqliteDBMainWindow::reloadSettings() +{ + // Set default application font size + qobject_cast(qApp)->reloadSettings(); + + // Set data browser font + ui->tableBrowser->reloadSettings(); + + switch (static_cast(Settings::getValue("General", "appStyle").toInt())) { + case Settings::FollowDesktopStyle : + qApp->setStyleSheet(""); + + break; + case Settings::DarkStyle : + QFile f(":qdarkstyle/style.qss"); + if (!f.exists()) { + QMessageBox::warning(this, qApp->applicationName(), + tr("Could not find resource file: %1").arg(f.fileName())); + } else { + f.open(QFile::ReadOnly | QFile::Text); + QTextStream ts(&f); + qApp->setStyleSheet(ts.readAll()); + } + break; + } + + setToolButtonStyle(static_cast(Settings::getValue("General", "toolbarStyle").toInt())); + ui->dbToolbar->setToolButtonStyle(static_cast(Settings::getValue("General", "toolbarStyleStructure").toInt())); + ui->toolbarSql->setToolButtonStyle(static_cast(Settings::getValue("General", "toolbarStyleSql").toInt())); + + // Set prefetch sizes for lazy population of table models + for(int i=0;itabSqlAreas->count();++i) + qobject_cast(ui->tabSqlAreas->widget(i))->reloadSettings(); + + // Prepare log font + QFont logfont("Monospace"); + logfont.setStyleHint(QFont::TypeWriter); + logfont.setPointSize(Settings::getValue("log", "fontsize").toInt()); + + // Set font for SQL logs and edit dialog + ui->editLogApplication->reloadSettings(); + ui->editLogUser->reloadSettings(); + ui->editLogErrorLog->reloadSettings(); + ui->editLogApplication->setFont(logfont); + ui->editLogUser->setFont(logfont); + ui->editLogErrorLog->setFont(logfont); + editDock->reloadSettings(); + + // Set font for database structure views + QFont structure_font = ui->dbTreeWidget->font(); + structure_font.setPointSize(Settings::getValue("db", "fontsize").toInt()); + ui->dbTreeWidget->setFont(structure_font); + ui->treeSchemaDock->setFont(structure_font); + + // Load extensions + db.loadExtensionsFromSettings(); + + // Refresh view + dbStructureModel->reloadData(); + populateStructure(); + populateTable(); + + // Hide or show the remote dock as needed + bool showRemoteActions = Settings::getValue("remote", "active").toBool(); + ui->viewMenu->actions().at(4)->setVisible(showRemoteActions); + if(!showRemoteActions) + ui->dockRemote->setHidden(true); + + // Reload remote dock settings + //remoteDock->reloadSettings(); + + sqlb::setIdentifierQuoting(static_cast(Settings::getValue("editor", "identifier_quotes").toInt())); + + ui->tabSqlAreas->setTabsClosable(Settings::getValue("editor", "close_button_on_tabs").toBool()); +} + +void SqliteDBMainWindow::checkNewVersion(const QString& versionstring, const QString& url) +{ + // versionstring contains a major.minor.patch version string + QStringList versiontokens = versionstring.split("."); + if(versiontokens.size() < 3) + return; + + int major = versiontokens[0].toInt(); + int minor = versiontokens[1].toInt(); + int patch = versiontokens[2].toInt(); + + bool newversion = false; + if(major > MAJOR_VERSION) + newversion = true; + else if(major == MAJOR_VERSION) + { + if(minor > MINOR_VERSION) + newversion = true; + else if(minor == MINOR_VERSION) + { + if(patch > PATCH_VERSION) + newversion = true; + } + } + + if(newversion) + { + int ignmajor = Settings::getValue("checkversion", "ignmajor").toInt(); + int ignminor = Settings::getValue("checkversion", "ignminor").toInt(); + int ignpatch = Settings::getValue("checkversion", "ignpatch").toInt(); + + // check if the user doesn't care about the current update + if(!(ignmajor == major && ignminor == minor && ignpatch == patch)) + { + QMessageBox msgBox; + QPushButton *idontcarebutton = msgBox.addButton(tr("Don't show again"), QMessageBox::ActionRole); + msgBox.addButton(QMessageBox::Ok); + msgBox.setTextFormat(Qt::RichText); + msgBox.setWindowTitle(tr("New version available.")); + msgBox.setText(tr("A new DB Browser for SQLite version is available (%1.%2.%3).

" + "Please download at %4.").arg(major).arg(minor).arg(patch). + arg(url)); + msgBox.exec(); + + if(msgBox.clickedButton() == idontcarebutton) + { + // save that the user don't want to get bothered about this update + Settings::setValue("checkversion", "ignmajor", major); + Settings::setValue("checkversion", "ignminor", minor); + Settings::setValue("checkversion", "ignpatch", patch); + } + } + } +} + +void SqliteDBMainWindow::on_actionWiki_triggered() const +{ + QDesktopServices::openUrl(QUrl("https://github.com/sqlitebrowser/sqlitebrowser/wiki")); +} + +// 'Help | Bug Report...' link will set an appropiate body, add the system information and set the label 'bug' automatically to the issue +void SqliteDBMainWindow::on_actionBug_report_triggered() const +{ + const QString version = Application::versionString(); + const QString os = QSysInfo::prettyProductName(); + const QString kernelType = QSysInfo::kernelType(); + const QString kernelVersion = QSysInfo::kernelVersion(); + const QString arch = QSysInfo::currentCpuArchitecture(); + const QString built_for = QSysInfo::buildAbi(); + + QString sqlite_version, sqlcipher_version; + DBBrowserDB::getSqliteVersion(sqlite_version, sqlcipher_version); + if(sqlcipher_version.isNull()) + sqlite_version = QString("SQLite Version ") + sqlite_version; + else + sqlite_version = QString("SQLCipher Version ") + sqlcipher_version + QString(" (based on SQLite %1)").arg(sqlite_version); + + const QString body = + QString("Details for the issue\n" + "--------------------\n\n" + "#### What did you do?\n\n\n" + "#### What did you expect to see?\n\n\n" + "#### What did you see instead?\n\n\n" + "Useful extra information\n" + "-------------------------\n" + "> DB4S v%1 [built for %2] on %3 (%4/%5) [%6]\n" + "> using %7\n" + "> and Qt %8") + .arg(version, built_for, os, kernelType, kernelVersion, arch, sqlite_version, QT_VERSION_STR); + + QUrlQuery query; + query.addQueryItem("labels", "bug"); + query.addQueryItem("body", body); + + QUrl url("https://github.com/sqlitebrowser/sqlitebrowser/issues/new"); + url.setQuery(query); + QDesktopServices::openUrl(url); +} + +// 'Help | Feature Request...' link will set an appropiate body and add the label 'enhancement' automatically to the issue +void SqliteDBMainWindow::on_actionFeature_Request_triggered() const +{ + QUrlQuery query; + + // Add the label enhancement and use the Feature request template that + // we have in GitHub. + query.addQueryItem("labels", "enhancement"); + query.addQueryItem("template", "Feature_request.md"); + + QUrl url("https://github.com/sqlitebrowser/sqlitebrowser/issues/new"); + url.setQuery(query); + QDesktopServices::openUrl(url); +} + +void SqliteDBMainWindow::on_actionSqlCipherFaq_triggered() const +{ + QDesktopServices::openUrl(QUrl("https://discuss.zetetic.net/c/sqlcipher/sqlcipher-faq")); +} + +void SqliteDBMainWindow::on_actionWebsite_triggered() const +{ + QDesktopServices::openUrl(QUrl("https://sqlitebrowser.org")); +} + +void SqliteDBMainWindow::on_actionDonatePatreon_triggered() const +{ + QDesktopServices::openUrl(QUrl("https://www.patreon.com/bePatron?u=11578749")); +} + +static void loadCondFormatMap(BrowseDataTableSettings::CondFormatMap& condFormats, QXmlStreamReader& xml, const QString& encoding) +{ + const QStringRef name = xml.name(); + + while(xml.readNext() != QXmlStreamReader::EndElement && xml.name() != name) { + if (xml.name() == "column") { + size_t index = xml.attributes().value("index").toUInt(); + while(xml.readNext() != QXmlStreamReader::EndElement && xml.name() != "column") { + if(xml.name() == "format") { + QFont font; + if (xml.attributes().hasAttribute("font")) + font.fromString(xml.attributes().value("font").toString()); + else + Settings::getValue("databrowser", "font").toString(); + + CondFormat::Alignment align; + if (xml.attributes().hasAttribute("align")) + align = static_cast(xml.attributes().value("align").toInt()); + else + align = CondFormat::AlignLeft; + + condFormats[index].emplace_back(xml.attributes().value("condition").toString(), + QColor(xml.attributes().value("foreground").toString()), + QColor(xml.attributes().value("background").toString()), + font, align, encoding); + xml.skipCurrentElement(); + } + } + } + } +} + +static void loadBrowseDataTableSettings(BrowseDataTableSettings& settings, QXmlStreamReader& xml) +{ + // TODO Remove this in the near future. This file format was only created temporarily by the nightlies from the late 3.11 development period. + if(xml.attributes().hasAttribute("sort_order_index")) + { + int sortOrderIndex = xml.attributes().value("sort_order_index").toInt(); + Qt::SortOrder sortOrderMode = static_cast(xml.attributes().value("sort_order_mode").toInt()); + settings.query.setOrderBy(toSortOrderVector(sortOrderIndex, sortOrderMode)); + } + + settings.showRowid = xml.attributes().value("show_row_id").toInt(); + settings.encoding = xml.attributes().value("encoding").toString(); + settings.plotXAxis = xml.attributes().value("plot_x_axis").toString(); + settings.unlockViewPk = xml.attributes().value("unlock_view_pk").toString(); + + while(xml.readNext() != QXmlStreamReader::EndElement && xml.name() != "table") { + if(xml.name() == "sort") + { + while(xml.readNext() != QXmlStreamReader::EndElement && xml.name() != "sort") + { + if(xml.name() == "column") + { + int index = xml.attributes().value("index").toInt(); + int mode = xml.attributes().value("mode").toInt(); + settings.query.orderBy().emplace_back(index, mode == Qt::AscendingOrder ? sqlb::Ascending : sqlb::Descending); + xml.skipCurrentElement(); + } + } + } else if(xml.name() == "column_widths") { + while(xml.readNext() != QXmlStreamReader::EndElement && xml.name() != "column_widths") { + if (xml.name() == "column") { + int index = xml.attributes().value("index").toInt(); + settings.columnWidths[index] = xml.attributes().value("value").toInt(); + xml.skipCurrentElement(); + } + } + } else if(xml.name() == "filter_values") { + while(xml.readNext() != QXmlStreamReader::EndElement && xml.name() != "filter_values") { + if (xml.name() == "column") { + int index = xml.attributes().value("index").toInt(); + QString value = xml.attributes().value("value").toString(); + if(!value.isEmpty()) + settings.filterValues[index] = value; + + xml.skipCurrentElement(); + } + } + } else if(xml.name() == "conditional_formats") { + loadCondFormatMap(settings.condFormats, xml, settings.encoding); + } else if(xml.name() == "row_id_formats") { + loadCondFormatMap(settings.rowIdFormats, xml, settings.encoding); + } else if(xml.name() == "display_formats") { + while(xml.readNext() != QXmlStreamReader::EndElement && xml.name() != "display_formats") { + if (xml.name() == "column") { + int index = xml.attributes().value("index").toInt(); + settings.displayFormats[index] = xml.attributes().value("value").toString(); + xml.skipCurrentElement(); + } + } + } else if(xml.name() == "hidden_columns") { + while(xml.readNext() != QXmlStreamReader::EndElement && xml.name() != "hidden_columns") { + if (xml.name() == "column") { + int index = xml.attributes().value("index").toInt(); + settings.hiddenColumns[index] = xml.attributes().value("value").toInt(); + xml.skipCurrentElement(); + } + } + } else if(xml.name() == "plot_y_axes") { + while(xml.readNext() != QXmlStreamReader::EndElement && xml.name() != "plot_y_axes") { + QString y1AxisName; + QString y2AxisName; + PlotDock::PlotSettings y1AxisSettings; + PlotDock::PlotSettings y2AxisSettings; + if (xml.name() == "y_axis") { + y1AxisName = xml.attributes().value("name").toString(); + y1AxisSettings.lineStyle = xml.attributes().value("line_style").toInt(); + y1AxisSettings.pointShape = xml.attributes().value("point_shape").toInt(); + y1AxisSettings.colour = QColor (xml.attributes().value("colour").toString()); + y1AxisSettings.active = xml.attributes().value("active").toInt(); + xml.skipCurrentElement(); + } + settings.plotYAxes[0][y1AxisName] = y1AxisSettings; + if (xml.name() == "y2_axis") { + y2AxisName = xml.attributes().value("name").toString(); + y2AxisSettings.lineStyle = xml.attributes().value("line_style").toInt(); + y2AxisSettings.pointShape = xml.attributes().value("point_shape").toInt(); + y2AxisSettings.colour = QColor (xml.attributes().value("colour").toString()); + y2AxisSettings.active = xml.attributes().value("active").toInt(); + xml.skipCurrentElement(); + } + settings.plotYAxes[1][y2AxisName] = y2AxisSettings; + } + } else if(xml.name() == "global_filter") { + while(xml.readNext() != QXmlStreamReader::EndElement && xml.name() != "global_filter") + { + if(xml.name() == "filter") + { + QString value = xml.attributes().value("value").toString(); + settings.globalFilters.push_back(value); + xml.skipCurrentElement(); + } + } + } + } +} +bool SqliteDBMainWindow::loadProject(QString filename, bool readOnly) +{ + // Show the open file dialog when no filename was passed as parameter + if(filename.isEmpty()) + { + filename = FileDialog::getOpenFileName( + OpenProjectFile, + this, + tr("Choose a project file to open"), + tr("DB Browser for SQLite project file (*.sqbpro)")); + } + + if(!filename.isEmpty()) + { + QFile file(filename); + file.open(QFile::ReadOnly | QFile::Text); + + QXmlStreamReader xml(&file); + xml.readNext(); // token == QXmlStreamReader::StartDocument + xml.readNext(); // name == sqlb_project + if(xml.name() != "sqlb_project") + return false; + + // We are going to open a new project, so close the possible current one before opening another. + // Stop the opening process here if the user pressed the cancel button in there. + if(!closeProject()) + return false; + + addToRecentFilesMenu(filename, readOnly); + currentProjectFilename = filename; + + QString currentTable; + while(!xml.atEnd() && !xml.hasError()) + { + // Read next token + QXmlStreamReader::TokenType token = xml.readNext(); + + // Handle element start + if(token == QXmlStreamReader::StartElement) + { + if(xml.name() == "db") + { + // Read only? + if(xml.attributes().hasAttribute("readonly") && xml.attributes().value("readonly").toInt()) + readOnly = true; + + // DB file + QString dbfilename = xml.attributes().value("path").toString(); + if(!QFile::exists(dbfilename)) { + dbfilename = QFileInfo(filename).absolutePath() + QDir::separator() + dbfilename; + // New DB filename is pending to be saved + isProjectModified = true; + } + fileOpen(dbfilename, true, readOnly); + ui->dbTreeWidget->collapseAll(); + + // PRAGMAs + if(xml.attributes().hasAttribute("foreign_keys")) + db.setPragma("foreign_keys", xml.attributes().value("foreign_keys").toString()); + if(xml.attributes().hasAttribute("case_sensitive_like")) + db.setPragma("case_sensitive_like", xml.attributes().value("case_sensitive_like").toString()); + if(xml.attributes().hasAttribute("temp_store")) + db.setPragma("temp_store", xml.attributes().value("temp_store").toString()); + if(xml.attributes().hasAttribute("wal_autocheckpoint")) + db.setPragma("wal_autocheckpoint", xml.attributes().value("wal_autocheckpoint").toString()); + if(xml.attributes().hasAttribute("synchronous")) + db.setPragma("synchronous", xml.attributes().value("synchronous").toString()); + loadPragmas(); + } else if(xml.name() == "attached") { + while(xml.readNext() != QXmlStreamReader::EndElement && xml.name() != "attached") + { + if(xml.name() == "db") + { + db.attach(xml.attributes().value("path").toString(), xml.attributes().value("schema").toString()); + xml.skipCurrentElement(); + } + } + } else if(xml.name() == "window") { + // Window settings + while(xml.readNext() != QXmlStreamReader::EndElement && xml.name() != "window") + { + if(xml.name() == "main_tabs") { + // Currently open tabs + restoreOpenTabs(xml.attributes().value("open").toString()); + // Currently selected open tab + ui->mainTab->setCurrentIndex(xml.attributes().value("current").toString().toInt()); + xml.skipCurrentElement(); + } else if(xml.name() == "current_tab") { + // Currently selected tab (3.11 or older format, first restore default open tabs) + restoreOpenTabs(defaultOpenTabs); + ui->mainTab->setCurrentIndex(xml.attributes().value("id").toString().toInt()); + xml.skipCurrentElement(); + } + } + } else if(xml.name() == "tab_structure") { + // Database Structure tab settings + while(xml.readNext() != QXmlStreamReader::EndElement && xml.name() != "tab_structure") + { + if(xml.name() == "column_width") + { + // Tree view column widths + ui->dbTreeWidget->setColumnWidth(xml.attributes().value("id").toString().toInt(), + xml.attributes().value("width").toString().toInt()); + xml.skipCurrentElement(); + } else if(xml.name() == "expanded_item") { + // Tree view expanded items + int parent = xml.attributes().value("parent").toString().toInt(); + QModelIndex idx; + if(parent == -1) + idx = ui->dbTreeWidget->model()->index(xml.attributes().value("id").toString().toInt(), 0); + else + idx = ui->dbTreeWidget->model()->index(xml.attributes().value("id").toString().toInt(), 0, ui->dbTreeWidget->model()->index(parent, 0)); + ui->dbTreeWidget->expand(idx); + xml.skipCurrentElement(); + } + } + } else if(xml.name() == "tab_browse") { + // Browse Data tab settings + while(xml.readNext() != QXmlStreamReader::EndElement && xml.name() != "tab_browse") + { + if(xml.name() == "current_table") + { + // Currently selected table + currentTable = xml.attributes().value("name").toString(); + xml.skipCurrentElement(); + } else if(xml.name() == "default_encoding") { + // Default text encoding + ui->tableBrowser->setDefaultEncoding(xml.attributes().value("codec").toString()); + xml.skipCurrentElement(); + } else if(xml.name() == "browsetable_info") { + // This tag is only found in old project files. In newer versions (>= 3.11) it is replaced by a new implementation. + // We still support loading it though we might decide to drop that support later. But for now we show a warning to the + // user when loading an old file. + if(!Settings::getValue("idontcare", "projectBrowseTable").toBool()) + { + QMessageBox msgBox; + QPushButton* idontcarebutton = msgBox.addButton(tr("Don't show again"), QMessageBox::ActionRole); + msgBox.addButton(QMessageBox::Ok); + msgBox.setTextFormat(Qt::RichText); + msgBox.setWindowTitle(qApp->applicationName()); + msgBox.setText(tr("This project file is using an old file format because it was created using DB Browser for SQLite " + "version 3.10 or lower. Loading this file format is still fully supported but we advice you to convert " + "all your project files to the new file format because support for older formats might be dropped " + "at some point in the future. You can convert your files by simply opening and re-saving them.")); + msgBox.exec(); + if(msgBox.clickedButton() == idontcarebutton) + Settings::setValue("idontcare", "projectBrowseTable", true); + } + + QString attrData = xml.attributes().value("data").toString(); + QByteArray temp = QByteArray::fromBase64(attrData.toUtf8()); + QDataStream stream(temp); + QMap settings; + stream >> settings; + for(auto it=settings.begin();it!=settings.end();++it) + ui->tableBrowser->setSettings(it.key(), it.value()); + + xml.skipCurrentElement(); + } else if(xml.name() == "browse_table_settings") { + + while(xml.readNext() != QXmlStreamReader::EndElement && xml.name() != "browse_table_settings") { + if (xml.name() == "table") { + + sqlb::ObjectIdentifier tableIdentifier = + sqlb::ObjectIdentifier (xml.attributes().value("schema").toString().toStdString(), + xml.attributes().value("name").toString().toStdString()); + BrowseDataTableSettings settings; + loadBrowseDataTableSettings(settings, xml); + ui->tableBrowser->setSettings(tableIdentifier, settings); + } + } + } + + } + } else if(xml.name() == "tab_sql") { + // Close all open tabs first + for(int i=ui->tabSqlAreas->count()-1;i>=0;i--) + closeSqlTab(i, true); + + // Execute SQL tab data + while(xml.readNext() != QXmlStreamReader::EndElement && xml.name() != "tab_sql") + { + if(xml.name() == "sql") + { + // SQL editor tab + int index = openSqlTab(); + ui->tabSqlAreas->setTabText(index, xml.attributes().value("name").toString()); + SqlTextEdit* sqlEditor = qobject_cast(ui->tabSqlAreas->widget(index))->getEditor(); + sqlEditor->setText(xml.readElementText()); + sqlEditor->setModified(false); + } else if(xml.name() == "current_tab") { + // Currently selected tab + ui->tabSqlAreas->setCurrentIndex(xml.attributes().value("id").toString().toInt()); + xml.skipCurrentElement(); + } + } + } + } + } + + file.close(); + + if(ui->mainTab->currentWidget() == ui->browser) { + if (!currentTable.isEmpty()) + { + sqlb::ObjectIdentifier obj; + if(!obj.fromSerialised(currentTable.toStdString())) + { + // This is an old project file format which doesn't yet contain serialised table identifiers. This means + // we have to try our best to unserialise this one manually. The only problem is when the name of an + // attached database or of a table contains a dot character. In that case the name becomes ambigious and + // we just try to split it at the first dot. I don't think it affects many (if any) project files. But if + // it turn out to be wrong, we can always add a loop here which checks for any possible combination of schema + // and table name whether an object with that combination exists. + // TODO: Delete this code in the future when we don't expect there to be any project files in the old format anymore. + if(currentTable.contains('.')) + { + obj.setSchema(currentTable.left(currentTable.indexOf('.')).toStdString()); + obj.setName(currentTable.mid(currentTable.indexOf('.')+1).toStdString()); + } else { + obj.setName(currentTable.toStdString()); + } + } + switchToBrowseDataTab(obj); + } + populateTable(); // Refresh view + } + + isProjectModified = false; + + return !xml.hasError(); + } else { + // No project was opened + return false; + } +} + +static void saveDbTreeState(const QTreeView* tree, QXmlStreamWriter& xml, QModelIndex index = QModelIndex(), int parent_row = -1) +{ + for(int i=0;imodel()->rowCount(index);i++) + { + if(tree->isExpanded(tree->model()->index(i, 0, index))) + { + xml.writeStartElement("expanded_item"); + xml.writeAttribute("id", QString::number(i)); + xml.writeAttribute("parent", QString::number(parent_row)); + xml.writeEndElement(); + } + + saveDbTreeState(tree, xml, tree->model()->index(i, 0, index), i); + } +} + +static void saveCondFormatMap(const QString& elementName, const BrowseDataTableSettings::CondFormatMap& condFormats, QXmlStreamWriter& xml) +{ + xml.writeStartElement(elementName); + for(auto iter=condFormats.constBegin(); iter!=condFormats.constEnd(); ++iter) { + xml.writeStartElement("column"); + xml.writeAttribute("index", QString::number(iter.key())); + for(auto format : iter.value()) { + xml.writeStartElement("format"); + xml.writeAttribute("condition", format.filter()); + xml.writeAttribute("background", format.backgroundColor().name()); + xml.writeAttribute("foreground", format.foregroundColor().name()); + xml.writeAttribute("font", format.font().toString()); + xml.writeAttribute("align", QString().setNum(format.alignment())); + xml.writeEndElement(); + } + xml.writeEndElement(); + } + xml.writeEndElement(); +} + +static void saveBrowseDataTableSettings(const BrowseDataTableSettings& object, QXmlStreamWriter& xml) +{ + xml.writeAttribute("show_row_id", QString::number(object.showRowid)); + xml.writeAttribute("encoding", object.encoding); + xml.writeAttribute("plot_x_axis", object.plotXAxis); + xml.writeAttribute("unlock_view_pk", object.unlockViewPk); + + xml.writeStartElement("sort"); + for(const auto& column : object.query.orderBy()) + { + xml.writeStartElement("column"); + xml.writeAttribute("index", QString::number(column.column)); + xml.writeAttribute("mode", QString::number(column.direction)); + xml.writeEndElement(); + } + xml.writeEndElement(); + + xml.writeStartElement("column_widths"); + for(auto iter=object.columnWidths.constBegin(); iter!=object.columnWidths.constEnd(); ++iter) { + xml.writeStartElement("column"); + xml.writeAttribute("index", QString::number(iter.key())); + xml.writeAttribute("value", QString::number(iter.value())); + xml.writeEndElement(); + } + xml.writeEndElement(); + xml.writeStartElement("filter_values"); + for(auto iter=object.filterValues.constBegin(); iter!=object.filterValues.constEnd(); ++iter) { + xml.writeStartElement("column"); + xml.writeAttribute("index", QString::number(iter.key())); + xml.writeAttribute("value", iter.value()); + xml.writeEndElement(); + } + xml.writeEndElement(); + saveCondFormatMap("conditional_formats", object.condFormats, xml); + saveCondFormatMap("row_id_formats", object.rowIdFormats, xml); + xml.writeStartElement("display_formats"); + for(auto iter=object.displayFormats.constBegin(); iter!=object.displayFormats.constEnd(); ++iter) { + xml.writeStartElement("column"); + xml.writeAttribute("index", QString::number(iter.key())); + xml.writeAttribute("value", iter.value()); + xml.writeEndElement(); + } + xml.writeEndElement(); + xml.writeStartElement("hidden_columns"); + for(auto iter=object.hiddenColumns.constBegin(); iter!=object.hiddenColumns.constEnd(); ++iter) { + xml.writeStartElement("column"); + xml.writeAttribute("index", QString::number(iter.key())); + xml.writeAttribute("value", QString::number(iter.value())); + xml.writeEndElement(); + } + xml.writeEndElement(); + xml.writeStartElement("plot_y_axes"); + for(auto iter=object.plotYAxes[0].constBegin(); iter!=object.plotYAxes[0].constEnd(); ++iter) { + PlotDock::PlotSettings plotSettings = iter.value(); + xml.writeStartElement("y_axis"); + xml.writeAttribute("name", iter.key()); + xml.writeAttribute("line_style", QString::number(plotSettings.lineStyle)); + xml.writeAttribute("point_shape", QString::number(plotSettings.pointShape)); + xml.writeAttribute("colour", plotSettings.colour.name()); + xml.writeAttribute("active", QString::number(plotSettings.active)); + xml.writeEndElement(); + } + for(auto iter=object.plotYAxes[1].constBegin(); iter!=object.plotYAxes[1].constEnd(); ++iter) { + PlotDock::PlotSettings plotSettings = iter.value(); + xml.writeStartElement("y2_axis"); + xml.writeAttribute("name", iter.key()); + xml.writeAttribute("line_style", QString::number(plotSettings.lineStyle)); + xml.writeAttribute("point_shape", QString::number(plotSettings.pointShape)); + xml.writeAttribute("colour", plotSettings.colour.name()); + xml.writeAttribute("active", QString::number(plotSettings.active)); + xml.writeEndElement(); + } + xml.writeEndElement(); + xml.writeStartElement("global_filter"); + for(const auto& v : object.globalFilters) + { + xml.writeStartElement("filter"); + xml.writeAttribute("value", v); + xml.writeEndElement(); + } + xml.writeEndElement(); +} + +void SqliteDBMainWindow::saveProject(const QString& currentFilename) +{ + QString filename; + if(currentFilename.isEmpty()) { + QString basePathName = db.currentFile(); + // Remove database suffix + basePathName.chop(QFileInfo(basePathName).suffix().size()+1); + filename = FileDialog::getSaveFileName( + CreateProjectFile, + this, + tr("Choose a filename to save under"), + FILE_FILTER_SQLPRJ, + basePathName); + } else + filename = currentFilename; + + if(!filename.isEmpty()) + { + // Make sure the file has got a .sqbpro ending + if(!filename.endsWith(FILE_EXT_SQLPRJ_DEFAULT, Qt::CaseInsensitive)) + filename.append(FILE_EXT_SQLPRJ_DEFAULT); + + QFile file(filename); + bool opened = file.open(QFile::WriteOnly | QFile::Text); + if(!opened) { + QMessageBox::warning(this, qApp->applicationName(), + tr("Could not open project file for writing.\nReason: %1").arg(file.errorString())); + currentProjectFilename.clear(); + return; + } + currentProjectFilename = filename; + QApplication::setOverrideCursor(Qt::WaitCursor); + + QXmlStreamWriter xml(&file); + xml.writeStartDocument(); + xml.writeStartElement("sqlb_project"); + + // Database file name + xml.writeStartElement("db"); + xml.writeAttribute("path", db.currentFile()); + xml.writeAttribute("readonly", QString::number(db.readOnly())); + xml.writeAttribute("foreign_keys", db.getPragma("foreign_keys")); + xml.writeAttribute("case_sensitive_like", db.getPragma("case_sensitive_like")); + xml.writeAttribute("temp_store", db.getPragma("temp_store")); + xml.writeAttribute("wal_autocheckpoint", db.getPragma("wal_autocheckpoint")); + xml.writeAttribute("synchronous", db.getPragma("synchronous")); + xml.writeEndElement(); + + // Attached databases + xml.writeStartElement("attached"); + db.executeSQL("PRAGMA database_list;", false, true, [&xml](int, std::vector values, std::vector) -> bool { + auto schema = values.at(1); + if(schema != "main" && schema != "temp") + { + auto path = values.at(2); + xml.writeStartElement("db"); + xml.writeAttribute("schema", schema); + xml.writeAttribute("path", path); + xml.writeEndElement(); + } + return false; + }); + xml.writeEndElement(); + + // Window settings + xml.writeStartElement("window"); + xml.writeStartElement("main_tabs"); // Currently open tabs + xml.writeAttribute("open", saveOpenTabs()); + xml.writeAttribute("current", QString::number(ui->mainTab->currentIndex())); + xml.writeEndElement(); + xml.writeEndElement(); + + // Database Structure tab settings + xml.writeStartElement("tab_structure"); + for(int i=0;idbTreeWidget->model()->columnCount();i++) // Widths of tree view columns + { + xml.writeStartElement("column_width"); + xml.writeAttribute("id", QString::number(i)); + xml.writeAttribute("width", QString::number(ui->dbTreeWidget->columnWidth(i))); + xml.writeEndElement(); + } + saveDbTreeState(ui->dbTreeWidget, xml); // Expanded tree items + xml.writeEndElement(); + + // Browse Data tab settings + xml.writeStartElement("tab_browse"); + xml.writeStartElement("current_table"); // Currently selected table + xml.writeAttribute("name", QString::fromStdString(ui->tableBrowser->currentlyBrowsedTableName().toSerialised())); + xml.writeEndElement(); + xml.writeStartElement("default_encoding"); // Default encoding for text stored in tables + xml.writeAttribute("codec", ui->tableBrowser->defaultEncoding()); + xml.writeEndElement(); + + xml.writeStartElement("browse_table_settings"); + const auto settings = ui->tableBrowser->allSettings(); + for(auto tableIt=settings.constBegin(); tableIt!=settings.constEnd(); ++tableIt) { + + xml.writeStartElement("table"); + xml.writeAttribute("schema", QString::fromStdString(tableIt.key().schema())); + xml.writeAttribute("name", QString::fromStdString(tableIt.key().name())); + saveBrowseDataTableSettings(tableIt.value(), xml); + xml.writeEndElement(); + } + // + xml.writeEndElement(); + // + xml.writeEndElement(); + + // Execute SQL tab data + xml.writeStartElement("tab_sql"); + for(int i=0;itabSqlAreas->count();i++) // All SQL tabs content + { + SqlExecutionArea* sqlArea = qobject_cast(ui->tabSqlAreas->widget(i)); + xml.writeStartElement("sql"); + xml.writeAttribute("name", ui->tabSqlAreas->tabText(i)); + xml.writeCharacters(sqlArea->getSql()); + sqlArea->getEditor()->setModified(false); + xml.writeEndElement(); + } + xml.writeStartElement("current_tab"); // Currently selected tab + xml.writeAttribute("id", QString::number(ui->tabSqlAreas->currentIndex())); + xml.writeEndElement(); + xml.writeEndElement(); + + xml.writeEndElement(); + xml.writeEndDocument(); + file.close(); + + addToRecentFilesMenu(filename); + setCurrentFile(db.currentFile()); + isProjectModified = false; + showStatusMessage5s(tr("Project saved to file '%1'").arg(currentProjectFilename)); + QApplication::restoreOverrideCursor(); + } +} + +void SqliteDBMainWindow::saveProject() +{ + saveProject(currentProjectFilename); +} + +void SqliteDBMainWindow::saveProjectAs() +{ + saveProject(QString()); +} + +void SqliteDBMainWindow::fileAttach(const QString& fileName) +{ + QString file; + if (fileName.isEmpty()) { + + // Get file name of database to attach + file = FileDialog::getOpenFileName( + OpenDatabaseFile, + this, + tr("Choose a database file"), + FileDialog::getSqlDatabaseFileFilter()); + } else + file = fileName; + + if(!QFile::exists(file)) + return; + + // Attach it + db.attach(file); + isProjectModified = true; +} + +void SqliteDBMainWindow::editEncryption() +{ +#ifdef ENABLE_SQLCIPHER + CipherDialog cipherDialog(this, true); + if(cipherDialog.exec()) + { + // Show progress dialog even though we can't provide any detailed progress information but this + // process might take some time. + QProgressDialog progress(this); + progress.setCancelButton(nullptr); + progress.setWindowModality(Qt::ApplicationModal); + progress.show(); + qApp->processEvents(); + + // Apply all unsaved changes + bool ok = db.releaseAllSavepoints(); + qApp->processEvents(); + + // Create the new file first or it won't work + if(ok) + { + QFile file(db.currentFile() + ".enctemp"); + file.open(QFile::WriteOnly); + file.close(); + } + + CipherSettings cipherSettings = cipherDialog.getCipherSettings(); + + // Attach a new database using the new settings + qApp->processEvents(); + if(ok) + ok = db.executeSQL("ATTACH DATABASE '" + db.currentFile().toStdString() + ".enctemp' AS sqlitebrowser_edit_encryption KEY " + cipherSettings.getPassword() + ";", + false, false); + qApp->processEvents(); + if(ok) + ok = db.executeSQL("PRAGMA sqlitebrowser_edit_encryption.cipher_page_size = " + std::to_string(cipherSettings.getPageSize()), false, false); + if(ok) + ok = db.executeSQL("PRAGMA sqlitebrowser_edit_encryption.cipher_hmac_algorithm = " + cipherSettings.getHmacAlgorithm(), false, false); + if(ok) + ok = db.executeSQL("PRAGMA sqlitebrowser_edit_encryption.cipher_kdf_algorithm = " + cipherSettings.getKdfAlgorithm(), false, false); + if(ok) + ok = db.executeSQL("PRAGMA sqlitebrowser_edit_encryption.kdf_iter = " + std::to_string(cipherSettings.getKdfIterations()), false, false); + if (ok) + ok = db.executeSQL("PRAGMA sqlitebrowser_edit_encryption.cipher_plaintext_header_size = " + std::to_string(cipherSettings.getPlaintextHeaderSize()), false, false); + + // Export the current database to the new one + qApp->processEvents(); + if(ok) + ok = db.executeSQL("SELECT sqlcipher_export('sqlitebrowser_edit_encryption');", false, false); + + // Set user version of the new database + qApp->processEvents(); + if (ok) + ok = db.executeSQL("PRAGMA sqlitebrowser_edit_encryption.user_version = " + std::to_string(db.getPragma("user_version").toInt()) + ";", false, false); + + // We need to detach the database before proceeding + qApp->processEvents(); + if (ok) + ok = db.executeSQL("DETACH sqlitebrowser_edit_encryption;", false, false); + + // Check for errors + qApp->processEvents(); + if(ok) + { + // No errors: Then close the current database, switch names, open the new one and if that succeeded delete the old one + + fileClose(); + QFile::rename(db.currentFile(), db.currentFile() + ".enctempold"); + QFile::rename(db.currentFile() + ".enctemp", db.currentFile()); + if(fileOpen(db.currentFile())) + QFile::remove(db.currentFile() + ".enctempold"); + } else { + QMessageBox::warning(this, qApp->applicationName(), db.lastError()); + } + } +#endif +} + +void SqliteDBMainWindow::switchToBrowseDataTab(sqlb::ObjectIdentifier tableToBrowse) +{ + // If no table name was provided get the currently selected table fromt he structure tab + if(tableToBrowse.isEmpty()) + { + // Cancel here if there is no selection + if(!ui->dbTreeWidget->selectionModel()->hasSelection()) + return; + + tableToBrowse.setSchema(ui->dbTreeWidget->model()->data(ui->dbTreeWidget->currentIndex().sibling(ui->dbTreeWidget->currentIndex().row(), DbStructureModel::ColumnSchema), Qt::EditRole).toString().toStdString()); + tableToBrowse.setName(ui->dbTreeWidget->model()->data(ui->dbTreeWidget->currentIndex().sibling(ui->dbTreeWidget->currentIndex().row(), DbStructureModel::ColumnName), Qt::EditRole).toString().toStdString()); + } + + ui->tableBrowser->setCurrentTable(tableToBrowse); + if (ui->mainTab->indexOf(ui->browser) == -1) + ui->mainTab->addTab(ui->browser, ui->browser->accessibleName()); + ui->mainTab->setCurrentWidget(ui->browser); +} + +void SqliteDBMainWindow::copyCurrentCreateStatement() +{ + // Cancel if no field is currently selected + if(!ui->dbTreeWidget->selectionModel()->hasSelection()) + return; + + // Get the CREATE statement from the Schema column + QString stmt = ui->dbTreeWidget->model()->data(ui->dbTreeWidget->currentIndex().sibling(ui->dbTreeWidget->currentIndex().row(), 3), Qt::EditRole).toString(); + + // Copy the statement to the global application clipboard + QApplication::clipboard()->setText(stmt); +} + +void SqliteDBMainWindow::fileOpenReadOnly() +{ + // Redirect to 'standard' fileOpen(), with the read only flag set + fileOpen(QString(), false, true); +} + +void SqliteDBMainWindow::requestCollation(const QString& name, int eTextRep) +{ + QMessageBox::StandardButton reply = QMessageBox::question( + this, + tr("Collation needed! Proceed?"), + tr("A table in this database requires a special collation function '%1' " + "that this application can't provide without further knowledge.\n" + "If you choose to proceed, be aware bad things can happen to your database.\n" + "Create a backup!").arg(name), QMessageBox::Yes | QMessageBox::No); + if(reply == QMessageBox::Yes) { + auto pDb = db.get(tr("creating collation")); + sqlite3_create_collation(pDb.get(), name.toUtf8(), eTextRep, nullptr, collCompare); + } +} + +void SqliteDBMainWindow::renameSqlTab(int index) +{ + QString new_name = QInputDialog::getText(this, + qApp->applicationName(), + tr("Set a new name for the SQL tab. Use the '&&' character to allow using the following character as a keyboard shortcut."), + QLineEdit::EchoMode::Normal, + ui->tabSqlAreas->tabText(index)); + + if(!new_name.isNull()) // Don't do anything if the Cancel button was clicked + ui->tabSqlAreas->setTabText(index, new_name); +} + +void SqliteDBMainWindow::setFindFrameVisibility(bool show) +{ + // Set the find frame visibility for all tabs, but leave the + // current as the last, to retain there the focus. + for(int i=0;itabSqlAreas->count();i++) + if (i != ui->tabSqlAreas->currentIndex()) + qobject_cast(ui->tabSqlAreas->widget(i))->setFindFrameVisibility(show); + if (ui->tabSqlAreas->count()>0) + qobject_cast(ui->tabSqlAreas->currentWidget())->setFindFrameVisibility(show); +} + +void SqliteDBMainWindow::openFindReplaceDialog() +{ + // The slot for the shortcut must discover which sqltexedit widget has the focus and then open its dialog. + SqlExecutionArea* sqlWidget = qobject_cast(ui->tabSqlAreas->currentWidget()); + + if (sqlWidget) + sqlWidget->getEditor()->openFindReplaceDialog(); +} + +void SqliteDBMainWindow::toggleSqlBlockComment() +{ + // The slot for the shortcut must discover which sqltexedit widget has the focus + SqlExecutionArea* sqlWidget = qobject_cast(ui->tabSqlAreas->currentWidget()); + + if (sqlWidget) + sqlWidget->getEditor()->toggleBlockComment(); +} + +void SqliteDBMainWindow::openSqlPrintDialog() +{ + // The slot for the shortcut must discover which sqltexedit widget has the focus and then open its dialog. + SqlExecutionArea* sqlWidget = qobject_cast(ui->tabSqlAreas->currentWidget()); + + if (sqlWidget) + sqlWidget->getEditor()->openPrintDialog(); +} + +void SqliteDBMainWindow::saveAsView(const std::string& query) +{ + // Let the user select a name for the new view and make sure it doesn't already exist + QString name; + while(true) + { + name = QInputDialog::getText(this, qApp->applicationName(), tr("Please specify the view name")).trimmed(); + if(name.isNull()) + return; + if(db.getObjectByName(sqlb::ObjectIdentifier("main", name.toStdString())) != nullptr) + QMessageBox::warning(this, qApp->applicationName(), tr("There is already an object with that name. Please choose a different name.")); + else + break; + } + + // Create the view + if(db.executeSQL("CREATE VIEW " + sqlb::escapeIdentifier(name.toStdString()) + " AS " + query + ";")) + QMessageBox::information(this, qApp->applicationName(), tr("View successfully created.")); + else + QMessageBox::warning(this, qApp->applicationName(), tr("Error creating view: %1").arg(db.lastError())); +} + +void SqliteDBMainWindow::runSqlNewTab(const QString& query, const QString& title, const QString& helpUrl, const bool autoRun) +{ + QString message; + + if(autoRun) + message = tr("This action will open a new SQL tab for running:"); + else + message = tr("This action will open a new SQL tab with the following statements for you to edit and run:"); + + message += QString("
%1
").arg(query) + + tr("Press Help for opening the corresponding SQLite reference page."); + + QString windowTitle = title; + windowTitle.remove('&'); + + switch (QMessageBox::information(this, windowTitle, message, QMessageBox::Ok | QMessageBox::Default, QMessageBox::Cancel | QMessageBox::Escape, QMessageBox::Help)) + { + case QMessageBox::Ok: { + if (ui->mainTab->indexOf(ui->query) == -1) + ui->mainTab->addTab(ui->query, ui->query->accessibleName()); + ui->mainTab->setCurrentWidget(ui->query); + int index = openSqlTab(); + ui->tabSqlAreas->setTabText(index, title); + qobject_cast(ui->tabSqlAreas->widget(index))->getEditor()->setText(query); + if(autoRun) + executeQuery(); + break; + } + case QMessageBox::Help: { + QDesktopServices::openUrl(QUrl(helpUrl)); + break; + } + default: + return; + } +} + +void SqliteDBMainWindow::printDbStructure () +{ + const QTreeView* treeView = ui->dbTreeWidget; + const QAbstractItemModel* model = treeView->model(); + + const int rowCount = model->rowCount(treeView->rootIndex()); + const int columnCount = model->columnCount(treeView->rootIndex()); + + QString strStream; + QTextStream out(&strStream); + + out << "" + << QString("%1").arg(treeView->windowTitle()) + << ""; + + for (int row = 0; row < rowCount; row++) { + + QModelIndex headerIndex = model->index(row, 0, treeView->rootIndex()); + QString strData = model->data(headerIndex).toString().toHtmlEscaped(); + out << QString("

%1

").arg(strData); + + // Open a new table for each group of objects + out << ""; + + for (int column = 0; column < columnCount; column++) { + // Headers + if (!treeView->isColumnHidden(column)) + out << QString("").arg(model->headerData(column, Qt::Horizontal).toString().toHtmlEscaped()); + } + out << ""; + + for (int column = 0; column < columnCount; column++) { + QModelIndex groupIndex = model->index(row, column, treeView->rootIndex()); + + // A row for the object name + for (int rowChild = 0; rowChild < model->rowCount(groupIndex); rowChild++) { + QModelIndex objectIndex = model->index(rowChild, column, groupIndex); + out << ""; + for (int column2 = 0; column2 < columnCount; column2++) { + if (!treeView->isColumnHidden(column2)) { + QModelIndex cellIndex = model->index(rowChild, column2, groupIndex); + QString header_data = model->data(cellIndex).toString().toHtmlEscaped(); + if (column2 != DbStructureModel::ColumnSQL) + out << QString("").arg((!header_data.isEmpty()) ? header_data : QString(" ")); + else + out << QString("").arg((!header_data.isEmpty()) ? header_data : QString(" ")); + } + } + out << ""; + + // One row for each object's fields + for (int rowChild2 = 0; rowChild2 < model->rowCount(objectIndex); rowChild2++) { + out << ""; + for (int column2 = 0; column2 < columnCount; column2++) { + if (!treeView->isColumnHidden(column2)) { + QModelIndex fieldIndex = model->index(rowChild2, column2, objectIndex); + QString field_data = model->data(fieldIndex).toString().toHtmlEscaped(); + out << QString("").arg((!field_data.isEmpty()) ? field_data : QString(" ")); + } + } + out << ""; + } + } + } + out << "
%1

%1

%1
%1
"; + } + out << ""; + + QPrinter printer; + printer.setDocName(treeView->windowTitle()); + + QPrintPreviewDialog *dialog = new QPrintPreviewDialog(&printer); + connect(dialog, &QPrintPreviewDialog::paintRequested, [strStream](QPrinter *previewPrinter) { + QTextDocument document; + document.setHtml(strStream); + document.print(previewPrinter); + }); + + dialog->exec(); + delete dialog; + +} + +void SqliteDBMainWindow::updateDatabaseBusyStatus(bool busy, const QString& user) +{ + statusBusyLabel->setText(tr("Busy (%1)").arg(user)); + statusBusyLabel->setVisible(busy); + statusStopButton->setVisible(busy); +} + + +void SqliteDBMainWindow::closeTab(int index) +{ + ui->mainTab->removeTab(index); +} + +void SqliteDBMainWindow::toggleTabVisible(QWidget* tabWidget, bool show) +{ + if (show) + ui->mainTab->addTab(tabWidget, tabWidget->accessibleName()); + else + ui->mainTab->removeTab(ui->mainTab->indexOf(tabWidget)); +} + +void SqliteDBMainWindow::restoreOpenTabs(QString tabs) +{ + // Split the tab list, skiping the empty parts so the empty string turns to an empty list + // and not a list of one empty string. + QStringList tabList = tabs.split(' ', QString::SkipEmptyParts); + + // Clear the tabs and then add them in the order specified by the setting. + // Use the accessibleName attribute for restoring the tab label. + if (!tabList.isEmpty()) { + // Avoid flickering while clearing and adding tabs. + ui->mainTab->setUpdatesEnabled(false); + ui->mainTab->clear(); + for (const auto& objectName : tabList) { + for (QWidget* widget : {ui->structure, ui->browser, ui->pragmas, ui->query}) + if (widget->objectName() == objectName) { + ui->mainTab->addTab(widget, widget->accessibleName()); + break; + } + } + ui->mainTab->setUpdatesEnabled(true); + // Force the update of the View menu toggable entries + // (it doesn't seem to be a better way) + emit ui->mainTab->tabCloseRequested(-1); + } +} + +QString SqliteDBMainWindow::saveOpenTabs() +{ + QString openTabs; + for (int i=0; i < ui->mainTab->count(); i++) + openTabs.append(ui->mainTab->widget(i)->objectName() + ' '); + openTabs.chop(1); + return openTabs; +} + +void SqliteDBMainWindow::showStatusMessage5s(QString message) +{ + ui->statusbar->showMessage(message, 5000); +} + +void SqliteDBMainWindow::saveAll() +{ + for(int i=0; itabSqlAreas->count(); i++) { + SqlExecutionArea* sqlExecArea = qobject_cast(ui->tabSqlAreas->widget(i)); + if(sqlExecArea->getEditor()->isModified() && !sqlExecArea->fileName().isEmpty()) + saveSqlFile(i); + } + if(!currentProjectFilename.isEmpty()) + saveProject(); + fileSave(); + +} + +void SqliteDBMainWindow::showContextMenuSqlTabBar(const QPoint& pos) +{ + // Don't show context menu if the mouse click was outside of all the tabs + int tab = ui->tabSqlAreas->tabBar()->tabAt(pos); + if(tab == -1) + return; + + // Prepare all menu actions + QAction* actionRename = new QAction(this); + actionRename->setText(tr("Rename Tab")); + connect(actionRename, &QAction::triggered, [this, tab]() { + renameSqlTab(tab); + }); + + QAction* actionDuplicate = new QAction(this); + actionDuplicate->setText(tr("Duplicate Tab")); + connect(actionDuplicate, &QAction::triggered, [this, tab]() { + QString tab_name = ui->tabSqlAreas->tabText(tab).remove("&").remove(QRegExp(" \\(\\d+\\)$")); + QString new_tab_name; + for(int i=1;;i++) + { + new_tab_name = tab_name + QString(" (%1)").arg(i); + bool name_already_exists = false; + for(int j=0;jtabSqlAreas->count();j++) + { + if(ui->tabSqlAreas->tabText(j).remove("&") == new_tab_name) + { + name_already_exists = true; + break; + } + } + + if(!name_already_exists) + break; + } + + int new_tab = openSqlTab(); + ui->tabSqlAreas->setTabText(new_tab, new_tab_name); + + SqlExecutionArea* old_area = qobject_cast(ui->tabSqlAreas->widget(tab)); + SqlExecutionArea* new_area = qobject_cast(ui->tabSqlAreas->widget(new_tab)); + new_area->setSql(old_area->getSql()); + }); + + QAction* actionClose = new QAction(this); + actionClose->setText(tr("Close Tab")); + actionClose->setShortcut(tr("Ctrl+W")); + connect(actionClose, &QAction::triggered, [this, tab]() { + closeSqlTab(tab); + }); + + // Show menu + QMenu* menuTabs = new QMenu(this); + menuTabs->addAction(actionRename); + menuTabs->addAction(actionDuplicate); + menuTabs->addAction(actionClose); + menuTabs->exec(ui->tabSqlAreas->mapToGlobal(pos)); +} + +void SqliteDBMainWindow::openUrlOrFile(const QString& urlString) +{ + QUrl url = QUrl::fromUserInput(urlString, QFileInfo(db.currentFile()).path(), QUrl::AssumeLocalFile); + if(url.isValid()) { + if(QDesktopServices::openUrl(url)) + showStatusMessage5s(tr("Opening '%1'...").arg(url.toDisplayString())); + else + showStatusMessage5s(tr("There was an error opening '%1'...").arg(url.toDisplayString())); + + } else + showStatusMessage5s(tr("Value is not a valid URL or filename: %1").arg(url.errorString())); +} + +void SqliteDBMainWindow::focusSqlEditor() +{ + SqlExecutionArea* sqlArea = qobject_cast(ui->tabSqlAreas->currentWidget()); + if(sqlArea) + sqlArea->getEditor()->setFocus(); +} + +void SqliteDBMainWindow::moveDocksTo(Qt::DockWidgetArea area) +{ + addDockWidget(area, ui->dockEdit); + addDockWidget(area, ui->dockLog); + tabifyDockWidget(ui->dockLog, ui->dockPlot); + tabifyDockWidget(ui->dockLog, ui->dockSchema); + tabifyDockWidget(ui->dockLog, ui->dockRemote); +} diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/SqliteDBMainWindow.h b/src/WBCLFZSystemModule/SqliteDBProcess/src/SqliteDBMainWindow.h new file mode 100644 index 0000000..5bcae4f --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/SqliteDBMainWindow.h @@ -0,0 +1,208 @@ +#ifndef MAINWINDOW_H +#define MAINWINDOW_H + +#include "sqlitedb.h" + +#include +#include + +struct BrowseDataTableSettings; +class DbStructureModel; +class EditDialog; +class ExtendedTableWidget; +class FindReplaceDialog; +class PlotDock; +class RemoteDock; +class RunSql; +class SqliteTableModel; + +class QDragEnterEvent; +class QModelIndex; +class QLabel; +class QPersistentModelIndex; +class QToolButton; + +namespace Ui { +class SqliteDBMainWindow; +} + +class SqliteDBMainWindow : public QMainWindow +{ + Q_OBJECT + +public: + explicit SqliteDBMainWindow(QWidget* parent = nullptr); + ~SqliteDBMainWindow() override; + + DBBrowserDB& getDb() { return db; } + +private: + struct PragmaValues + { + int autovacuum; + int automatic_index; + int checkpoint_fullsync; + int foreign_keys; + int fullfsync; + int ignore_check_constraints; + QString journal_mode; + int journal_size_limit; + QString locking_mode; + int max_page_count; + int page_size; + int recursive_triggers; + int secure_delete; + int synchronous; + int temp_store; + int user_version; + int wal_autocheckpoint; + int case_sensitive_like; + } pragmaValues; + + Ui::SqliteDBMainWindow* ui; + + DBBrowserDB db; + + SqliteTableModel* m_currentTabTableModel; + + QMenu* popupTableMenu; + QMenu* popupSchemaDockMenu; + QMenu* recentFilesMenu; + QMenu* popupOpenDbMenu; + QMenu* popupSaveSqlFileMenu; + QMenu* popupSaveSqlResultsMenu; + + QLabel* statusEncodingLabel; + QLabel* statusEncryptionLabel; + QLabel* statusReadOnlyLabel; + QToolButton* statusStopButton; + QLabel* statusBusyLabel; + + DbStructureModel* dbStructureModel; + + static const int MaxRecentFiles = 5; + QAction *recentFileActs[MaxRecentFiles]; + QAction *recentSeparatorAct; + + EditDialog* editDock; + PlotDock* plotDock; + //RemoteDock* remoteDock; + FindReplaceDialog* findReplaceDialog; + + std::unique_ptr execute_sql_worker; + + QString defaultOpenTabs; + QByteArray defaultWindowState; + + QString currentProjectFilename; + bool isProjectModified; + + void init(); + void clearCompleterModelsFields(); + + void updateRecentFileActions(); + void setCurrentFile(const QString& fileName); + void addToRecentFilesMenu(const QString& filename, bool read_only = false); + void activateFields(bool enable = true); + void saveAsView(const std::string& query); + void attachPlot(ExtendedTableWidget* tableWidget, SqliteTableModel* model, BrowseDataTableSettings* settings = nullptr, bool keepOrResetSelection = true); + + void toggleTabVisible(QWidget* tabWidget, bool show); + void restoreOpenTabs(QString tabs); + QString saveOpenTabs(); + void saveProject(const QString& currentFilename); + bool closeFiles(); + bool closeProject(); + bool askSaveSqlTab(int index, bool& ignoreUnattachedBuffers); + void focusSqlEditor(); + void moveDocksTo(Qt::DockWidgetArea area); + +protected: + void closeEvent(QCloseEvent *) override; + void dragEnterEvent(QDragEnterEvent *event) override; + void dropEvent(QDropEvent *event) override; + void resizeEvent(QResizeEvent *event) override; + +public slots: + bool fileOpen(const QString& fileName = QString(), bool openFromProject = false, bool readOnly = false); + void logSql(const QString &sql, int msgtype); + void dbState(bool dirty); + void refresh(); + void switchToBrowseDataTab(sqlb::ObjectIdentifier tableToBrowse = sqlb::ObjectIdentifier()); + void populateStructure(const sqlb::ObjectIdentifier& old_table = sqlb::ObjectIdentifier{}); + void reloadSettings(); + +private slots: + void createTreeContextMenu(const QPoint & qPoint); + void createSchemaDockContextMenu(const QPoint & qPoint); + void changeTreeSelection(); + void fileNew(); + void fileNewInMemoryDatabase(); + void populateTable(); + bool fileClose(); + void createTable(); + void createIndex(); + void compact(); + void deleteObject(); + void editObject(); + void helpWhatsThis(); + void helpAbout(); + void updateRecordText(const QPersistentModelIndex& idx, const QByteArray& text, bool isBlob); + void toggleEditDock(bool visible); + void dataTableSelectionChanged(const QModelIndex& index); + void doubleClickTable(const QModelIndex& index); + void executeQuery(); + void importTableFromCSV(); + void exportTableToCSV(); + void exportTableToJson(); + void fileSave(); + void fileRevert(); + void exportDatabaseToSQL(); + void importDatabaseFromSQL(); + void openRecentFile(); + void loadPragmas(); + void updatePragmaUi(); + void savePragmas(); + void mainTabSelected( int tabindex ); + int openSqlTab(bool resetCounter = false); + void closeSqlTab(int index, bool force = false); + void changeSqlTab(int index); + void openSqlFile(); + void saveSqlFile(); + void saveSqlFileAs(); + void saveSqlResultsAsCsv(); + void saveSqlResultsAsView(); + void loadExtension(); + void checkNewVersion(const QString& versionstring, const QString& url); + void on_actionWiki_triggered() const; + void on_actionBug_report_triggered() const; + void on_actionFeature_Request_triggered() const; + void on_actionSqlCipherFaq_triggered() const; + void on_actionWebsite_triggered() const; + void on_actionDonatePatreon_triggered() const; + bool loadProject(QString filename = QString(), bool readOnly = false); + void saveProject(); + void saveProjectAs(); + void fileAttach(const QString& fileName = QString()); + void editEncryption(); + void copyCurrentCreateStatement(); + void fileOpenReadOnly(); + void requestCollation(const QString& name, int eTextRep); + void renameSqlTab(int index); + void setFindFrameVisibility(bool show); + void openFindReplaceDialog(); + void toggleSqlBlockComment(); + void openSqlPrintDialog(); + void runSqlNewTab(const QString& query, const QString& title, const QString& helpUrl, const bool autoRun = true); + void printDbStructure(); + void updateDatabaseBusyStatus(bool busy, const QString& user); + void openPreferences(); + void closeTab(int index); + void showStatusMessage5s(QString message); + void saveSqlFile(int tabIndex); + void saveAll(); + void showContextMenuSqlTabBar(const QPoint& pos); + void openUrlOrFile(const QString& urlString); +}; + +#endif diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/SqliteDBMainWindow.ui b/src/WBCLFZSystemModule/SqliteDBProcess/src/SqliteDBMainWindow.ui new file mode 100644 index 0000000..49a4af5 --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/SqliteDBMainWindow.ui @@ -0,0 +1,3601 @@ + + + SqliteDBMainWindow + + + + 0 + 0 + 1037 + 630 + + + + DB Browser for SQLite + + + + :/icons/appicon:/icons/appicon + + + + + 3 + + + 3 + + + 3 + + + 3 + + + 3 + + + + + 3 + + + true + + + true + + + + Database Structure + + + æ•°æ®åº“æŽ¥å£ + + + + 3 + + + 3 + + + 3 + + + 3 + + + 3 + + + + + toolBar1 + + + Qt::ToolButtonTextBesideIcon + + + + + + + + + + + + + Qt::CustomContextMenu + + + This is the structure of the opened database. +You can drag SQL statements from an object row and drop them into other applications or into another instance of 'DB Browser for SQLite'. + + + + true + + + QAbstractItemView::DragDrop + + + true + + + QAbstractItemView::ScrollPerPixel + + + true + + + + + + + + Browse Data + + + æ•°æ®æµè§ˆ + + + + 3 + + + 3 + + + 3 + + + 3 + + + 3 + + + + + + + + + Edit Pragmas + + + 傿•°ç¼–辑 + + + + 3 + + + 3 + + + 3 + + + 3 + + + 3 + + + + + true + + + + + 0 + 0 + 739 + 489 + + + + + QFormLayout::ExpandingFieldsGrow + + + + + <html><head/><body><p>è‡ªåŠ¨æ¸…ç† <a href="http://www.sqlite.org/pragma.html#pragma_auto_vacuum"><img src=":/icons/whatis"/></a></p></body></html> + + + true + + + Qt::LinksAccessibleByMouse + + + comboboxPragmaAutoVacuum + + + + + + + + None + + + + + Full + + + + + Incremental + + + + + + + + <html><head/><body><p>自动索引 <a href="http://www.sqlite.org/pragma.html#pragma_automatic_index"><img src=":/icons/whatis"/></a></p></body></html> + + + true + + + checkboxPragmaAutomaticIndex + + + + + + + + + + + + + + <html><head/><body><p>LIKE检索是å¦åŒºåˆ†å¤§å°å†™ <a href="https://www.sqlite.org/pragma.html#pragma_case_sensitive_like"><img src=":/icons/whatis"/></a></p></body></html> + + + true + + + checkboxPragmaCaseSensitiveLike + + + + + + + Warning: this pragma is not readable and this value has been inferred. Writing the pragma might overwrite a redefined LIKE provided by an SQLite extension. + + + + + + + + + + <html><head/><body><p>Checkpoint Full FSYNC <a href="https://www.sqlite.org/pragma.html#pragma_checkpoint_fullfsync"><img src=":/icons/whatis"/></a></a></p></body></html> + + + true + + + checkboxPragmaCheckpointFullFsync + + + + + + + + + + + + + + <html><head/><body><p>Foreign Keys <a href="https://www.sqlite.org/pragma.html#pragma_foreign_keys"><img src=":/icons/whatis"/></a></a></p></body></html> + + + true + + + checkboxPragmaForeignKeys + + + + + + + + + + + + + + <html><head/><body><p>Full FSYNC <a href="https://www.sqlite.org/pragma.html#pragma_fullfsync"><img src=":/icons/whatis"/></a></a></p></body></html> + + + true + + + checkboxPragmaFullFsync + + + + + + + + + + + + + + <html><head/><body><p>Ignore Check Constraints <a href="https://www.sqlite.org/pragma.html#pragma_ignore_check_constraints"><img src=":/icons/whatis"/></a></a></p></body></html> + + + true + + + checkboxPragmaIgnoreCheckConstraints + + + + + + + + + + + + + + <html><head/><body><p>Journal Mode <a href="https://www.sqlite.org/pragma.html#pragma_journal_mode"><img src=":/icons/whatis"/></a></a></p></body></html> + + + true + + + comboboxPragmaJournalMode + + + + + + + + Delete + + + + + Truncate + + + + + Persist + + + + + Memory + + + + + WAL + + + + + Off + + + + + + + + <html><head/><body><p>Journal Size Limit <a href="https://www.sqlite.org/pragma.html#pragma_journal_size_limit"><img src=":/icons/whatis"/></a></a></p></body></html> + + + true + + + spinPragmaJournalSizeLimit + + + + + + + -1 + + + 100000 + + + + + + + <html><head/><body><p>Locking Mode <a href="https://www.sqlite.org/pragma.html#pragma_locking_mode"><img src=":/icons/whatis"/></a></a></p></body></html> + + + true + + + comboboxPragmaLockingMode + + + + + + + + Normal + + + + + Exclusive + + + + + + + + <html><head/><body><p>Max Page Count <a href="https://www.sqlite.org/pragma.html#pragma_max_page_count"><img src=":/icons/whatis"/></a></a></p></body></html> + + + true + + + spinPragmaMaxPageCount + + + + + + + 2000000000 + + + + + + + <html><head/><body><p>Page Size <a href="https://www.sqlite.org/pragma.html#pragma_page_size"><img src=":/icons/whatis"/></a></a></p></body></html> + + + true + + + comboPragmaPageSize + + + + + + + + 512 + + + + + 1024 + + + + + 2048 + + + + + 4096 + + + + + 8192 + + + + + 16384 + + + + + 32768 + + + + + 65536 + + + + + + + + <html><head/><body><p>Recursive Triggers <a href="https://www.sqlite.org/pragma.html#pragma_recursive_triggers"><img src=":/icons/whatis"/></a></a></p></body></html> + + + true + + + checkboxPragmaRecursiveTriggers + + + + + + + + + + + + + + <html><head/><body><p>Secure Delete <a href="https://www.sqlite.org/pragma.html#pragma_secure_delete"><img src=":/icons/whatis"/></a></a></p></body></html> + + + true + + + checkboxPragmaSecureDelete + + + + + + + + + + + + + + <html><head/><body><p>Synchronous <a href="https://www.sqlite.org/pragma.html#pragma_synchronous"><img src=":/icons/whatis"/></a></a></p></body></html> + + + true + + + comboboxPragmaSynchronous + + + + + + + + Off + + + + + Normal + + + + + Full + + + + + + + + <html><head/><body><p>Temp Store <a href="https://www.sqlite.org/pragma.html#pragma_temp_store"><img src=":/icons/whatis"/></a></a></p></body></html> + + + true + + + comboboxPragmaTempStore + + + + + + + + Default + + + + + File + + + + + Memory + + + + + + + + <html><head/><body><p>User Version <a href="https://www.sqlite.org/pragma.html#pragma_user_version"><img src=":/icons/whatis"/></a></a></p></body></html> + + + true + + + spinPragmaUserVersion + + + + + + + 2147483647 + + + + + + + <html><head/><body><p>WAL Auto Checkpoint <a href="https://www.sqlite.org/pragma.html#pragma_wal_autocheckpoint"><img src=":/icons/whatis"/></a></a></p></body></html> + + + true + + + spinPragmaWalAutoCheckpoint + + + + + + + 10000 + + + + + + + + + + + QDialogButtonBox::Cancel|QDialogButtonBox::Save + + + false + + + + + + + + Execute SQL + + + SQL编辑器 + + + + 3 + + + 3 + + + 3 + + + 3 + + + 3 + + + + + toolBar1 + + + + + + + + + + + + + + + + + + + + + + Qt::CustomContextMenu + + + -1 + + + true + + + + + + + + + + + + + 0 + 0 + 1037 + 22 + + + + + &文件 + + + + &导入 + + + + + + + &导出 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + &编辑 + + + + + + + + + + + + &查看 + + + + + + + + + &工具 + + + + + + + + + + + + + + + + + + + + DB Toolbar + + + Qt::ToolButtonTextBesideIcon + + + TopToolBarArea + + + false + + + + + + + + + + 编辑å•å…ƒ + + + 2 + + + + + + QDockWidget::AllDockWidgetFeatures + + + 执行日志 + + + 2 + + + + + + + + + + 0 + 30 + + + + 排åºä¾æ® + + + comboLogSubmittedBy + + + + + + + + 0 + 30 + + + + + User + + + + + Application + + + + + Error Log + + + + + + + + Qt::Horizontal + + + + 20 + 20 + + + + + + + + + 0 + 30 + + + + This button clears the contents of the SQL logs + + + &Clear + + + + + + + + + This panel lets you examine a log of all SQL commands issued by the application or by yourself + + + 0 + + + + + Monospace + 8 + + + + true + + + + + + Monospace + 8 + + + + true + + + + + + Monospace + 8 + + + + true + + + + + + + + + + QDockWidget::AllDockWidgetFeatures + + + &绘图 + + + 2 + + + + + + + + æ•°æ®æ¨¡å¼ + + + 2 + + + + + + + Qt::CustomContextMenu + + + This is the structure of the opened database. +You can drag multiple object names from the Name column and drop them into the SQL editor and you can adjust the properties of the dropped names using the context menu. This would help you in composing SQL statements. +You can drag SQL statements from the Schema column and drop them into the SQL editor or into other applications. + + + + true + + + QAbstractItemView::DragDrop + + + true + + + QAbstractItemView::ExtendedSelection + + + QAbstractItemView::SelectItems + + + QAbstractItemView::ScrollPerPixel + + + true + + + + + + + + + &Remote + + + 2 + + + + + + Project Toolbar + + + Qt::ToolButtonTextBesideIcon + + + TopToolBarArea + + + false + + + + + + + true + + + Extra DB toolbar + + + Close the current database file + + + Qt::ToolButtonTextBesideIcon + + + TopToolBarArea + + + false + + + + + + + + :/icons/db_new:/icons/db_new + + + &创建新属性表库 + + + Create a new database file + + + Create a new database file + + + This option is used to create a new database file. + + + Ctrl+N + + + QAction::NoRole + + + + + + :/icons/db_open:/icons/db_open + + + &打开属性库 + + + Open an existing database file + + + Open an existing database file + + + This option is used to open an existing database file. + + + Ctrl+O + + + QAction::NoRole + + + + + false + + + + :/icons/close:/icons/close + + + &关闭数æ®åº“ + + + Close the current database file + + + Close the current database file + + + This button closes the connection to the currently open database file + + + Ctrl+F4 + + + QAction::NoRole + + + + + false + + + + :/icons/db_revert:/icons/db_revert + + + &撤销更改 + + + Revert database to last saved state + + + Revert database to last saved state + + + This option is used to revert the current database file to its last saved state. All changes made since the last save operation are lost. + + + QAction::NoRole + + + + + false + + + + :/icons/db_save:/icons/db_save + + + &ä¿å­˜æ›´æ”¹ + + + Write changes to the database file + + + Write changes to the database file + + + This option is used to save changes to the database file. + + + Ctrl+S + + + QAction::NoRole + + + + + false + + + åŽ‹ç¼©ä¸Žä¿®å¤æ•°æ®åº“ + + + Compact the database file, removing space wasted by deleted records + + + Compact the database file, removing space wasted by deleted records. + + + Compact the database file, removing space wasted by deleted records. + + + QAction::NoRole + + + + + E&xit + + + Ctrl+Q + + + QAction::QuitRole + + + + + &从SQL + + + Import data from an .sql dump text file into a new or existing database. + + + This option lets you import data from an .sql dump text file into a new or existing database. SQL dump files can be created on most database engines, including MySQL and PostgreSQL. + + + QAction::NoRole + + + + + &从CSV + + + Open a wizard that lets you import data from a comma separated text file into a database table. + + + Open a wizard that lets you import data from a comma separated text file into a database table. CSV files can be created on most database and spreadsheet applications. + + + QAction::NoRole + + + + + &到SQL + + + Export a database to a .sql dump text file. + + + This option lets you export a database to a .sql dump text file. SQL dump files contain all data necessary to recreate the database on most database engines, including MySQL and PostgreSQL. + + + QAction::NoRole + + + + + &导出到CSV + + + Export a database table as a comma separated text file. + + + Export a database table as a comma separated text file, ready to be imported into other database or spreadsheet applications. + + + QAction::NoRole + + + + + false + + + + :/icons/table_create:/icons/table_create + + + &创建表 + + + Open the Create Table wizard, where it is possible to define the name and fields for a new table in the database + + + QAction::NoRole + + + + + false + + + + :/icons/table_delete:/icons/table_delete + + + &删除表 + + + Delete Table + + + Open the Delete Table wizard, where you can select a database table to be dropped. + + + QAction::NoRole + + + + + false + + + + :/icons/table_modify:/icons/table_modify + + + &修改表 + + + Open the Modify Table wizard, where it is possible to rename an existing table. It is also possible to add or delete fields form a table, as well as modify field names and types. + + + QAction::NoRole + + + + + false + + + + :/icons/index_create:/icons/index_create + + + 创建索引 + + + Open the Create Index wizard, where it is possible to define a new index on an existing database table. + + + QAction::NoRole + + + + + + :/icons/settings:/icons/settings + + + &设置 + + + Open the preferences window. + + + Open the preferences window. + + + QAction::PreferencesRole + + + + + true + + + + :/icons/toolbar:/icons/toolbar + + + &æ•°æ®åº“å·¥å…·æ¡ + + + Shows or hides the Database toolbar. + + + QAction::NoRole + + + + + + :/icons/whatis:/icons/whatis + + + W&hat's This? + + + Shift+F1 + + + QAction::NoRole + + + + + &About + + + QAction::AboutRole + + + + + &Recently opened + + + + + + :/icons/open_tab:/icons/open_tab + + + Open &tab + + + This button opens a new tab for the SQL editor + + + Ctrl+T + + + + + + :/icons/run:/icons/run + + + &Execute SQL + + + Execute all/selected SQL + + + This button executes the currently selected SQL statements. If no text is selected, all SQL statements are executed. + + + Ctrl+Return + + + + + + :/icons/document_open:/icons/document_open + + + Open SQL file(s) + + + This button opens files containing SQL statements and loads them in new editor tabs + + + + + + :/icons/save_sql:/icons/save_sql + + + Save SQL file + + + + + false + + + + :/icons/load_extension:/icons/load_extension + + + &Load Extension... + + + false + + + QAction::NoRole + + + + + + :/icons/run_line:/icons/run_line + + + Execute current line + + + Execute line + + + Execute current line + + + This button executes the SQL statement present in the current editor line + + + Shift+F5 + + + + + false + + + Export as CSV file + + + Export table as comma separated values file + + + + + + :/icons/browser_open:/icons/browser_open + + + &Wiki + + + F1 + + + QAction::NoRole + + + + + + :/icons/browser_open:/icons/browser_open + + + Bug &Report... + + + QAction::NoRole + + + + + + :/icons/browser_open:/icons/browser_open + + + Feature Re&quest... + + + QAction::NoRole + + + + + + :/icons/browser_open:/icons/browser_open + + + Web&site + + + QAction::NoRole + + + + + + :/icons/browser_open:/icons/browser_open + + + &Donate on Patreon... + + + QAction::NoRole + + + + + + :/icons/project_save:/icons/project_save + + + ä¿å­˜åŠŸèƒ½ + + + Save the current session to a file + + + Save the current session to a file + + + This button lets you save all the settings associated to the open DB to a DB Browser for SQLite project file + + + QAction::NoRole + + + + + + :/icons/project_open:/icons/project_open + + + 打开工程 + + + Load a working session from a file + + + Load a working session from a file + + + This button lets you open a DB Browser for SQLite project file + + + QAction::NoRole + + + + + false + + + + :/icons/db_attach:/icons/db_attach + + + & 附加数æ®åº“ + + + Add another database file to the current database connection + + + Add another database file to the current database connection + + + This button lets you add another database file to the current database connection + + + false + + + QAction::NoRole + + + + + + :/icons/encryption:/icons/encryption + + + &加密 + + + QAction::NoRole + + + + + + :/icons/save_sql:/icons/save_sql + + + Save SQL file as + + + Save SQL file as + + + + + + :/icons/save_sql:/icons/save_sql + + + Save SQL file + + + Save SQL file + + + This button saves the content of the current SQL editor tab to a file + + + + + + :/icons/table:/icons/table + + + &Browse Table + + + + + + :/icons/copy:/icons/copy + + + Copy Create statement + + + Copy the CREATE statement of the item to the clipboard + + + + + + :/icons/browser_open:/icons/browser_open + + + SQLCipher &FAQ + + + Opens the SQLCipher FAQ in a browser window + + + + + 导出JSON + + + Export one or more table(s) to a JSON file + + + QAction::NoRole + + + + + + :/icons/db_open:/icons/db_open + + + Open Data&base Read Only... + + + Open an existing database file in read only mode + + + Open an existing database file + + + This option is used to open an existing database file. + + + Ctrl+Shift+O + + + false + + + QAction::NoRole + + + + + + :/icons/save_table:/icons/save_table + + + Save results + + + Save the results view + + + This button lets you save the results of the last executed query + + + + + true + + + + :/icons/find:/icons/find + + + Find text in SQL editor + + + Find + + + Find text in SQL editor + + + This button opens the search bar of the editor + + + Ctrl+F + + + Qt::WidgetShortcut + + + + + false + + + + :/icons/text_replace:/icons/text_replace + + + Find or replace text in SQL editor + + + Find or replace + + + Find or replace text in SQL editor + + + This button opens the find/replace dialog for the current editor tab + + + Ctrl+H + + + Qt::WidgetShortcut + + + + + Export to &CSV + + + + + Save as &view + + + Save as view + + + + + true + + + false + + + + :/icons/toolbar:/icons/toolbar + + + é¡¹ç›®å·¥å…·æ¡ + + + Shows or hides the Project toolbar. + + + QAction::NoRole + + + + + true + + + + :/icons/toolbar:/icons/toolbar + + + 扩展数æ®å·¥å…·æ¡ + + + + + + :/icons/db_open:/icons/db_open + + + &打开已有属性表库 + + + Open an existing database file + + + Open an existing database file + + + This option is used to open an existing database file. + + + QAction::TextHeuristicRole + + + + + false + + + New In-&Memory Database + + + false + + + + + true + + + Drag && Drop Qualified Names + + + Use qualified names (e.g. "Table"."Field") when dragging the objects and dropping them into the editor + + + Use qualified names (e.g. "Table"."Field") when dragging the objects and dropping them into the editor + + + + + true + + + Drag && Drop Enquoted Names + + + Use escaped identifiers (e.g. "Table1") when dragging the objects and dropping them into the editor + + + Use escaped identifiers (e.g. "Table1") when dragging the objects and dropping them into the editor + + + + + &完整性检查 + + + Runs the integrity_check pragma over the opened database and returns the results in the Execute SQL tab. This pragma does an integrity check of the entire database. + + + + + &外键检查 + + + Runs the foreign_key_check pragma over the opened database and returns the results in the Execute SQL tab + + + + + &快速完整性检查 + + + Run a quick integrity check over the open DB + + + Runs the quick_check pragma over the opened database and returns the results in the Execute SQL tab. This command does most of the checking of PRAGMA integrity_check but runs much faster. + + + + + &优化 + + + Attempt to optimize the database + + + Runs the optimize pragma over the opened database. This pragma might perform optimizations that will improve the performance of future queries. + + + + + + :/icons/print:/icons/print + + + Print + + + Print text from current SQL editor tab + + + + + + Open a dialog for printing the text in the current SQL editor tab + + + Ctrl+P + + + Qt::WidgetShortcut + + + + + false + + + + :/icons/print:/icons/print + + + Print + + + Print the structure of the opened database + + + + + + Open a dialog for printing the structure of the opened database + + + Ctrl+P + + + Qt::WidgetShortcut + + + false + + + + + + :/icons/comment_block:/icons/comment_block + + + Un/comment block of SQL code + + + Un/comment block + + + Comment or uncomment current line or selected block of code + + + Comment or uncomment the selected lines or the current line, when there is no selection. All the block is toggled according to the first line. + + + Ctrl+/ + + + Qt::WidgetShortcut + + + + + + :/icons/cancel:/icons/cancel + + + Stop SQL execution + + + Stop execution + + + Stop the currently running SQL script + + + + + + :/icons/project_save_as:/icons/project_save_as + + + &工程å¦å­˜ä¸º + + + Save the project in a file selected in a dialog + + + Save the project in a file selected in a dialog + + + Save the project in a file selected in a dialog + + + + + + :/icons/save_all:/icons/save_all + + + Save A&ll + + + Save DB file, project file and opened SQL files + + + Save DB file, project file and opened SQL files + + + Save DB file, project file and opened SQL files + + + Ctrl+Shift+S + + + + + + :/icons/table:/icons/table + + + Browse Table + + + + + + SqlTextEdit + QTextEdit +
sqltextedit.h
+ 1 +
+ + ExtendedScintilla + QTextEdit +
ExtendedScintilla.h
+ 1 +
+ + TableBrowser + QWidget +
TableBrowser.h
+ 1 +
+
+ + mainTab + dbTreeWidget + comboLogSubmittedBy + buttonLogClear + treeSchemaDock + scrollareaPragmas + comboboxPragmaAutoVacuum + checkboxPragmaAutomaticIndex + checkboxPragmaCaseSensitiveLike + checkboxPragmaCheckpointFullFsync + checkboxPragmaForeignKeys + checkboxPragmaFullFsync + checkboxPragmaIgnoreCheckConstraints + comboboxPragmaJournalMode + spinPragmaJournalSizeLimit + comboboxPragmaLockingMode + spinPragmaMaxPageCount + comboPragmaPageSize + checkboxPragmaSecureDelete + checkboxPragmaRecursiveTriggers + comboboxPragmaSynchronous + comboboxPragmaTempStore + spinPragmaUserVersion + spinPragmaWalAutoCheckpoint + tabSqlAreas + + + + + + + fileExitAction + triggered() + SqliteDBMainWindow + close() + + + -1 + -1 + + + 399 + 299 + + + + + fileOpenAction + triggered() + SqliteDBMainWindow + fileOpen() + + + -1 + -1 + + + 399 + 299 + + + + + fileNewAction + triggered() + SqliteDBMainWindow + fileNew() + + + -1 + -1 + + + 399 + 299 + + + + + fileCloseAction + triggered() + SqliteDBMainWindow + fileClose() + + + -1 + -1 + + + 399 + 299 + + + + + fileCompactAction + triggered() + SqliteDBMainWindow + compact() + + + -1 + -1 + + + 399 + 299 + + + + + helpWhatsThisAction + triggered() + SqliteDBMainWindow + helpWhatsThis() + + + -1 + -1 + + + 399 + 299 + + + + + helpAboutAction + triggered() + SqliteDBMainWindow + helpAbout() + + + -1 + -1 + + + 399 + 299 + + + + + mainTab + currentChanged(int) + SqliteDBMainWindow + mainTabSelected(int) + + + 399 + 315 + + + 399 + 299 + + + + + fileImportCSVAction + triggered() + SqliteDBMainWindow + importTableFromCSV() + + + -1 + -1 + + + 399 + 299 + + + + + fileExportCSVAction + triggered() + SqliteDBMainWindow + exportTableToCSV() + + + -1 + -1 + + + 399 + 299 + + + + + fileRevertAction + triggered() + SqliteDBMainWindow + fileRevert() + + + -1 + -1 + + + 399 + 299 + + + + + fileSaveAction + triggered() + SqliteDBMainWindow + fileSave() + + + -1 + -1 + + + 399 + 299 + + + + + editCreateIndexAction + triggered() + SqliteDBMainWindow + createIndex() + + + -1 + -1 + + + 399 + 299 + + + + + editDeleteObjectAction + triggered() + SqliteDBMainWindow + deleteObject() + + + -1 + -1 + + + 399 + 299 + + + + + editModifyObjectAction + triggered() + SqliteDBMainWindow + editObject() + + + -1 + -1 + + + 399 + 299 + + + + + fileExportSQLAction + triggered() + SqliteDBMainWindow + exportDatabaseToSQL() + + + -1 + -1 + + + 399 + 299 + + + + + fileImportSQLAction + triggered() + SqliteDBMainWindow + importDatabaseFromSQL() + + + -1 + -1 + + + 399 + 299 + + + + + viewPreferencesAction + triggered() + SqliteDBMainWindow + openPreferences() + + + -1 + -1 + + + 399 + 299 + + + + + dbTreeWidget + customContextMenuRequested(QPoint) + SqliteDBMainWindow + createTreeContextMenu(QPoint) + + + 111 + 261 + + + 399 + 299 + + + + + treeSchemaDock + customContextMenuRequested(QPoint) + SqliteDBMainWindow + createSchemaDockContextMenu(QPoint) + + + 111 + 261 + + + 399 + 299 + + + + + viewDBToolbarAction + toggled(bool) + toolbarDB + setVisible(bool) + + + -1 + -1 + + + 399 + 34 + + + + + actionSqlFind + toggled(bool) + SqliteDBMainWindow + setFindFrameVisibility(bool) + + + -1 + -1 + + + 399 + 34 + + + + + actionSqlFindReplace + triggered() + SqliteDBMainWindow + openFindReplaceDialog() + + + -1 + -1 + + + 399 + 34 + + + + + editCreateTableAction + triggered() + SqliteDBMainWindow + createTable() + + + -1 + -1 + + + 399 + 299 + + + + + buttonBoxPragmas + rejected() + SqliteDBMainWindow + loadPragmas() + + + 111 + 540 + + + -1 + 470 + + + + + buttonBoxPragmas + accepted() + SqliteDBMainWindow + savePragmas() + + + 111 + 540 + + + 802 + 522 + + + + + buttonLogClear + clicked() + editLogApplication + clear() + + + 989 + 126 + + + 632 + 173 + + + + + buttonLogClear + clicked() + editLogUser + clear() + + + 989 + 126 + + + 1028 + 230 + + + + + buttonLogClear + clicked() + editLogErrorLog + clear() + + + 989 + 126 + + + 632 + 173 + + + + + comboLogSubmittedBy + currentIndexChanged(int) + stackLog + setCurrentIndex(int) + + + 772 + 135 + + + 1028 + 230 + + + + + tabSqlAreas + tabCloseRequested(int) + SqliteDBMainWindow + closeSqlTab(int) + + + 91 + 259 + + + -1 + 51 + + + + + tabSqlAreas + currentChanged(int) + SqliteDBMainWindow + changeSqlTab(int) + + + 91 + 259 + + + -1 + 51 + + + + + actionExecuteSql + triggered() + SqliteDBMainWindow + executeQuery() + + + -1 + -1 + + + 399 + 299 + + + + + actionSqlOpenTab + triggered() + SqliteDBMainWindow + openSqlTab() + + + -1 + -1 + + + 399 + 299 + + + + + actionSqlOpenFile + triggered() + SqliteDBMainWindow + openSqlFile() + + + -1 + -1 + + + 399 + 299 + + + + + actionSqlSaveFile + triggered() + SqliteDBMainWindow + saveSqlFile() + + + -1 + -1 + + + 399 + 299 + + + + + actionLoadExtension + triggered() + SqliteDBMainWindow + loadExtension() + + + -1 + -1 + + + 399 + 299 + + + + + actionSqlExecuteLine + triggered() + SqliteDBMainWindow + executeQuery() + + + -1 + -1 + + + 399 + 299 + + + + + actionExportCsvPopup + triggered() + SqliteDBMainWindow + exportTableToCSV() + + + -1 + -1 + + + 399 + 299 + + + + + actionOpenProject + triggered() + SqliteDBMainWindow + loadProject() + + + -1 + -1 + + + 399 + 299 + + + + + actionSaveProject + triggered() + SqliteDBMainWindow + saveProject() + + + -1 + -1 + + + 399 + 299 + + + + + fileAttachAction + triggered() + SqliteDBMainWindow + fileAttach() + + + -1 + -1 + + + 499 + 314 + + + + + actionEncryption + triggered() + SqliteDBMainWindow + editEncryption() + + + -1 + -1 + + + 499 + 314 + + + + + actionSqlSaveFilePopup + triggered() + SqliteDBMainWindow + saveSqlFile() + + + -1 + -1 + + + 499 + 314 + + + + + actionSqlSaveFileAs + triggered() + SqliteDBMainWindow + saveSqlFileAs() + + + -1 + -1 + + + 499 + 314 + + + + + actionEditBrowseTable + triggered() + SqliteDBMainWindow + switchToBrowseDataTab() + + + -1 + -1 + + + 499 + 314 + + + + + actionEditCopyCreateStatement + triggered() + SqliteDBMainWindow + copyCurrentCreateStatement() + + + -1 + -1 + + + 499 + 314 + + + + + fileExportJsonAction + triggered() + SqliteDBMainWindow + exportTableToJson() + + + -1 + -1 + + + 518 + 314 + + + + + fileOpenReadOnlyAction + triggered() + SqliteDBMainWindow + fileOpenReadOnly() + + + -1 + -1 + + + 518 + 314 + + + + + actionSqlResultsExportCsv + triggered() + SqliteDBMainWindow + saveSqlResultsAsCsv() + + + -1 + -1 + + + 518 + 314 + + + + + actionSqlResultsSaveAsView + triggered() + SqliteDBMainWindow + saveSqlResultsAsView() + + + -1 + -1 + + + 518 + 314 + + + + + tabSqlAreas + tabBarDoubleClicked(int) + SqliteDBMainWindow + renameSqlTab(int) + + + 330 + 372 + + + 518 + 314 + + + + + viewProjectToolbarAction + toggled(bool) + toolbarProject + setVisible(bool) + + + -1 + -1 + + + 887 + 44 + + + + + viewExtraDBToolbarAction + toggled(bool) + toolbarExtraDB + setVisible(bool) + + + -1 + -1 + + + 737 + 44 + + + + + SqliteDBMainWindow + toolButtonStyleChanged(Qt::ToolButtonStyle) + toolbarDB + setToolButtonStyle(Qt::ToolButtonStyle) + + + 518 + 314 + + + 296 + 44 + + + + + SqliteDBMainWindow + toolButtonStyleChanged(Qt::ToolButtonStyle) + toolbarExtraDB + setToolButtonStyle(Qt::ToolButtonStyle) + + + 518 + 314 + + + 737 + 44 + + + + + SqliteDBMainWindow + toolButtonStyleChanged(Qt::ToolButtonStyle) + toolbarProject + setToolButtonStyle(Qt::ToolButtonStyle) + + + 518 + 314 + + + 959 + 44 + + + + + fileOpenActionPopup + triggered() + SqliteDBMainWindow + fileOpen() + + + -1 + -1 + + + 518 + 314 + + + + + fileNewInMemoryDatabaseAction + triggered() + SqliteDBMainWindow + fileNewInMemoryDatabase() + + + -1 + -1 + + + 20 + 20 + + + + + actionSqlPrint + triggered() + SqliteDBMainWindow + openSqlPrintDialog() + + + -1 + -1 + + + 518 + 314 + + + + + actionDbPrint + triggered() + SqliteDBMainWindow + printDbStructure() + + + -1 + -1 + + + 518 + 314 + + + + + actionSqlToggleComment + triggered() + SqliteDBMainWindow + toggleSqlBlockComment() + + + -1 + -1 + + + 518 + 314 + + + + + labelPragmaAutomaticIndex + linkHovered(QString) + SqliteDBMainWindow + showStatusMessage5s(QString) + + + 85 + 133 + + + 518 + 314 + + + + + labelPragmaCaseSensitiveLike + linkHovered(QString) + SqliteDBMainWindow + showStatusMessage5s(QString) + + + 85 + 133 + + + 518 + 314 + + + + + labelPragmaCheckpointFullFsync + linkHovered(QString) + SqliteDBMainWindow + showStatusMessage5s(QString) + + + 85 + 133 + + + 518 + 314 + + + + + labelPragmaForeignKeys + linkHovered(QString) + SqliteDBMainWindow + showStatusMessage5s(QString) + + + 85 + 133 + + + 518 + 314 + + + + + labelPragmaFullFsync + linkHovered(QString) + SqliteDBMainWindow + showStatusMessage5s(QString) + + + 85 + 133 + + + 518 + 314 + + + + + labelPragmaIgnoreCheckConstraints + linkHovered(QString) + SqliteDBMainWindow + showStatusMessage5s(QString) + + + 85 + 133 + + + 518 + 314 + + + + + labelPragmaJournalMode + linkHovered(QString) + SqliteDBMainWindow + showStatusMessage5s(QString) + + + 85 + 133 + + + 518 + 314 + + + + + labelPragmaLockingMode + linkHovered(QString) + SqliteDBMainWindow + showStatusMessage5s(QString) + + + 85 + 133 + + + 518 + 314 + + + + + labelPragmaMaxPageCount + linkHovered(QString) + SqliteDBMainWindow + showStatusMessage5s(QString) + + + 85 + 133 + + + 518 + 314 + + + + + labelPragmaPageSize + linkHovered(QString) + SqliteDBMainWindow + showStatusMessage5s(QString) + + + 85 + 133 + + + 518 + 314 + + + + + labelPragmaRecursiveTriggers + linkHovered(QString) + SqliteDBMainWindow + showStatusMessage5s(QString) + + + 85 + 133 + + + 518 + 314 + + + + + labelPragmaSecureDelete + linkHovered(QString) + SqliteDBMainWindow + showStatusMessage5s(QString) + + + 85 + 133 + + + 518 + 314 + + + + + labelPragmaSynchronous + linkHovered(QString) + SqliteDBMainWindow + showStatusMessage5s(QString) + + + 85 + 133 + + + 518 + 314 + + + + + labelPragmaTempStore + linkHovered(QString) + SqliteDBMainWindow + showStatusMessage5s(QString) + + + 85 + 133 + + + 518 + 314 + + + + + labelPragmaUserVersion + linkHovered(QString) + SqliteDBMainWindow + showStatusMessage5s(QString) + + + 85 + 133 + + + 518 + 314 + + + + + labelPragmaWalAutoCheckpoint + linkHovered(QString) + SqliteDBMainWindow + showStatusMessage5s(QString) + + + 85 + 133 + + + 518 + 314 + + + + + labelPragmaAutoVacuum + linkHovered(QString) + SqliteDBMainWindow + showStatusMessage5s(QString) + + + 85 + 133 + + + 518 + 314 + + + + + labelPragmaAutoVacuum + linkHovered(QString) + SqliteDBMainWindow + showStatusMessage5s(QString) + + + 85 + 133 + + + 518 + 314 + + + + + labelJournalSizeLimit + linkHovered(QString) + SqliteDBMainWindow + showStatusMessage5s(QString) + + + 99 + 345 + + + 518 + 314 + + + + + actionSaveProjectAs + triggered() + SqliteDBMainWindow + saveProjectAs() + + + -1 + -1 + + + 518 + 314 + + + + + actionSaveAll + triggered() + SqliteDBMainWindow + saveAll() + + + -1 + -1 + + + 518 + 314 + + + + + tabSqlAreas + customContextMenuRequested(QPoint) + SqliteDBMainWindow + showContextMenuSqlTabBar(QPoint) + + + -1 + -1 + + + 20 + 20 + + + + + + fileOpen() + fileClose() + browseFind(bool) + refresh() + compact() + helpWhatsThis() + mainTabSelected(int) + executeQuery() + importTableFromCSV() + exportTableToCSV() + fileRevert() + fileSave() + deleteIndex() + createIndex() + createTable() + deleteObject() + editObject() + editTablePopup() + addField() + editField() + exportDatabaseToSQL() + importDatabaseFromSQL() + openPreferences() + createTreeContextMenu(QPoint) + changeTreeSelection() + fileNew() + helpAbout() + deleteField() + loadPragmas() + savePragmas() + copy() + closeSqlTab(int) + openSqlTab() + openSqlFile() + saveSqlFile() + loadExtension() + loadProject() + saveProject() + fileAttach() + editEncryption() + saveSqlFileAs() + switchToBrowseDataTab() + copyCurrentCreateStatement() + browseDataFetchAllData() + exportTableToJson() + fileOpenReadOnly() + saveSqlResultsAsCsv() + saveSqlResultsAsView() + changeSqlTab(int) + renameSqlTab(int) + fileNewInMemoryDatabase() + showContextMenuSqlTabBar(QPoint) + +
diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/SqliteDBProcessmain.cpp b/src/WBCLFZSystemModule/SqliteDBProcess/src/SqliteDBProcessmain.cpp new file mode 100644 index 0000000..4e5b6ee --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/SqliteDBProcessmain.cpp @@ -0,0 +1,59 @@ +// +//#include "Application.h" +//#include "sqlite.h" +// +//#include +// +//static QString message = QString(); +// +//void db4sMessageOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg) +//{ +// QByteArray localMsg = msg.toLocal8Bit(); +// +// // Emulate the default Qt treatment. This might not work in some OS, like Windows. +// fprintf(stderr, "%s\n", localMsg.constData()); +// +// const char *file = context.file ? context.file : ""; +// const char *function = context.function ? context.function : ""; +// localMsg = QString("%1 (%2, %3:%4)\n").arg(msg).arg(function).arg(file).arg(context.line).toLocal8Bit(); +// +// // Log using the SQLite log mechanism, so it gets the same treatment than messages +// // reported by SQLite itself. This will allow these messages to be seen in our Log window. +// // Error code will be the type +// sqlite3_log(static_cast(type), localMsg.constData()); +//} +// +//void boxMessageOutput(QtMsgType, const QMessageLogContext &, const QString &msg) +//{ +// message += msg + "\n"; +//} +// +//int main( int argc, char ** argv ) +//{ +// +//#ifdef Q_OS_WIN +// // In Windows, there is no output to terminal for a graphical application, so we install +// // the output to message box, until the main window is shown or the application exits. +// qInstallMessageHandler(boxMessageOutput); +//#endif +// +// // Create application object. All the initialisation stuff happens in there +// Application a(argc, argv); +// +// // If there has been invocations to the message handler, show it to user in a message box. +// if(!message.isEmpty()) { +// QMessageBox messageBox; +// messageBox.setTextFormat(Qt::RichText); +// messageBox.setText("
" + message.toHtmlEscaped() + "
"); +// messageBox.exec(); +// } +// +// // Quit application now if user doesn't want to see the UI +// if(a.dontShowMainWindow()) +// return 0; +// +// qInstallMessageHandler(db4sMessageOutput); +// +// // Run application +// return a.exec(); +//} diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/TableBrowser.cpp b/src/WBCLFZSystemModule/SqliteDBProcess/src/TableBrowser.cpp new file mode 100644 index 0000000..27475b9 --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/TableBrowser.cpp @@ -0,0 +1,1603 @@ +#include "AddRecordDialog.h" +#include "Application.h" +#include "ColumnDisplayFormatDialog.h" +#include "CondFormatManager.h" +#include "Data.h" +#include "DbStructureModel.h" +#include "ExportDataDialog.h" +#include "FilterTableHeader.h" +#include "TableBrowser.h" +#include "Settings.h" +#include "sqlitedb.h" +#include "sqlitetablemodel.h" +#include "ui_TableBrowser.h" + +#include +#include +#include +#include +#include +#include +#include + +QMap TableBrowser::m_settings; +QString TableBrowser::m_defaultEncoding; + +TableBrowser::TableBrowser(QWidget* parent) : + QWidget(parent), + ui(new Ui::TableBrowser), + gotoValidator(new QIntValidator(0, 0, this)), + db(nullptr), + dbStructureModel(nullptr), + m_model(nullptr), + m_adjustRows(false), + m_columnsResized(false) +{ + ui->setupUi(this); + + // Set the validator for the goto line edit + ui->editGoto->setValidator(gotoValidator); + + // Set custom placeholder text for global filter field and disable conditional formats + ui->editGlobalFilter->setPlaceholderText(tr("Filter in any column")); + ui->editGlobalFilter->setConditionFormatContextMenuEnabled(false); + + // Set up popup menus + popupNewRecordMenu = new QMenu(this); + popupNewRecordMenu->addAction(ui->newRecordAction); + popupNewRecordMenu->addAction(ui->insertValuesAction); + ui->actionNewRecord->setMenu(popupNewRecordMenu); + + popupSaveFilterAsMenu = new QMenu(this); + popupSaveFilterAsMenu->addAction(ui->actionFilteredTableExportCsv); + popupSaveFilterAsMenu->addAction(ui->actionFilterSaveAsView); + ui->actionSaveFilterAsPopup->setMenu(popupSaveFilterAsMenu); + qobject_cast(ui->browseToolbar->widgetForAction(ui->actionSaveFilterAsPopup))->setPopupMode(QToolButton::InstantPopup); + + popupHeaderMenu = new QMenu(this); + popupHeaderMenu->addAction(ui->actionShowRowidColumn); + popupHeaderMenu->addAction(ui->actionHideColumns); + popupHeaderMenu->addAction(ui->actionShowAllColumns); + popupHeaderMenu->addAction(ui->actionSelectColumn); + popupHeaderMenu->addSeparator(); + popupHeaderMenu->addAction(ui->actionUnlockViewEditing); + popupHeaderMenu->addAction(ui->actionBrowseTableEditDisplayFormat); + popupHeaderMenu->addSeparator(); + popupHeaderMenu->addAction(ui->actionSetTableEncoding); + popupHeaderMenu->addAction(ui->actionSetAllTablesEncoding); + + connect(ui->actionSelectColumn, &QAction::triggered, [this]() { + ui->dataTable->selectColumn(ui->actionBrowseTableEditDisplayFormat->property("clicked_column").toInt()); + }); + + // Set up shortcuts + QShortcut* dittoRecordShortcut = new QShortcut(QKeySequence("Ctrl+\""), this); + connect(dittoRecordShortcut, &QShortcut::activated, [this]() { + int currentRow = ui->dataTable->currentIndex().row(); + duplicateRecord(currentRow); + }); + + // Lambda function for keyboard shortcuts for selecting next/previous table in Browse Data tab + connect(ui->dataTable, &ExtendedTableWidget::switchTable, [this](bool next) { + int index = ui->comboBrowseTable->currentIndex(); + int num_items = ui->comboBrowseTable->count(); + if(next) + { + if(++index >= num_items) + index = 0; + } else { + if(--index < 0) + index = num_items - 1; + } + ui->comboBrowseTable->setCurrentIndex(index); + updateTable(); + }); + + // This is a workaround needed for QDarkStyleSheet. + // See https://github.com/ColinDuquesnoy/QDarkStyleSheet/issues/169 + QStyledItemDelegate* styledItemDelegate = new QStyledItemDelegate(ui->comboBrowseTable); + ui->comboBrowseTable->setItemDelegate(styledItemDelegate); + + // Add the documentation of shortcuts, which aren't otherwise visible in the user interface, to some buttons. + addShortcutsTooltip(ui->actionRefresh, {QKeySequence(tr("Ctrl+R"))}); + addShortcutsTooltip(ui->actionPrintTable); + + // Set up filters + connect(ui->dataTable->filterHeader(), &FilterTableHeader::filterChanged, this, &TableBrowser::updateFilter); + connect(ui->dataTable->filterHeader(), &FilterTableHeader::addCondFormat, this, &TableBrowser::addCondFormatFromFilter); + connect(ui->dataTable->filterHeader(), &FilterTableHeader::allCondFormatsCleared, this, &TableBrowser::clearAllCondFormats); + connect(ui->dataTable->filterHeader(), &FilterTableHeader::condFormatsEdited, this, &TableBrowser::editCondFormats); + connect(ui->dataTable, &ExtendedTableWidget::editCondFormats, this, &TableBrowser::editCondFormats); + + // Set up global filter + connect(ui->editGlobalFilter, &FilterLineEdit::delayedTextChanged, this, [this](const QString& value) { + // Split up filter values + QStringList values = value.trimmed().split(" ", QString::SkipEmptyParts); + std::vector filters; + for(const auto& s : values) + filters.push_back(s); + + // Have they changed? + BrowseDataTableSettings& settings = m_settings[currentlyBrowsedTableName()]; + if(filters != settings.globalFilters) + { + // Set global filters + m_model->updateGlobalFilter(filters); + updateRecordsetLabel(); + + // Save them + settings.globalFilters = filters; + emit projectModified(); + } + }); + + connect(ui->dataTable, &ExtendedTableWidget::doubleClicked, this, &TableBrowser::selectionChangedByDoubleClick); + connect(ui->dataTable->filterHeader(), &FilterTableHeader::sectionClicked, this, &TableBrowser::headerClicked); + connect(ui->dataTable->filterHeader(), &QHeaderView::sectionDoubleClicked, ui->dataTable, &QTableView::selectColumn); + connect(ui->dataTable->verticalScrollBar(), &QScrollBar::valueChanged, this, &TableBrowser::updateRecordsetLabel); + connect(ui->dataTable->horizontalHeader(), &QHeaderView::sectionResized, this, &TableBrowser::updateRecordsetLabel); + connect(ui->dataTable->verticalHeader(), &QHeaderView::sectionResized, this, &TableBrowser::updateRecordsetLabel); + connect(ui->dataTable->horizontalHeader(), &QHeaderView::sectionResized, this, &TableBrowser::updateColumnWidth); + connect(ui->dataTable->horizontalHeader(), &QHeaderView::customContextMenuRequested, this, &TableBrowser::showDataColumnPopupMenu); + connect(ui->dataTable->verticalHeader(), &QHeaderView::customContextMenuRequested, this, &TableBrowser::showRecordPopupMenu); + connect(ui->dataTable, &ExtendedTableWidget::openFileFromDropEvent, this, &TableBrowser::requestFileOpen); + connect(ui->dataTable, &ExtendedTableWidget::selectedRowsToBeDeleted, this, &TableBrowser::deleteRecord); + + connect(ui->fontComboBox, &QFontComboBox::currentFontChanged, this, [this](const QFont &font) { + modifyFormat([font](CondFormat& format) { format.setFontFamily(font.family()); }); + }); + connect(ui->fontSizeBox, static_cast(&QSpinBox::valueChanged), this, + [this](int pointSize) { + modifyFormat([pointSize](CondFormat& format) { format.setFontPointSize(pointSize); }); + }); + + connect(ui->actionFontColor, &QAction::triggered, this, [this]() { + QColor color = QColorDialog::getColor(QColor(m_model->data(currentIndex(), Qt::ForegroundRole).toString())); + if(color.isValid()) + modifyFormat([color](CondFormat& format) { format.setForegroundColor(color); }); + }); + connect(ui->actionBackgroundColor, &QAction::triggered, this, [this]() { + QColor color = QColorDialog::getColor(QColor(m_model->data(currentIndex(), Qt::BackgroundRole).toString())); + if(color.isValid()) + modifyFormat([color](CondFormat& format) { format.setBackgroundColor(color); }); + }); + + connect(ui->actionBold, &QAction::toggled, this, [this](bool checked) { + modifyFormat([checked](CondFormat& format) { format.setBold(checked); }); + }); + connect(ui->actionItalic, &QAction::toggled, this, [this](bool checked) { + modifyFormat([checked](CondFormat& format) { format.setItalic(checked); }); + }); + connect(ui->actionUnderline, &QAction::toggled, this, [this](bool checked) { + modifyFormat([checked](CondFormat& format) { format.setUnderline(checked); }); + }); + + connect(ui->actionLeftAlign, &QAction::triggered, this, [this]() { + ui->actionLeftAlign->setChecked(true); + ui->actionRightAlign->setChecked(false); + ui->actionCenter->setChecked(false); + ui->actionJustify->setChecked(false); + modifyFormat([](CondFormat& format) { format.setAlignment(CondFormat::AlignLeft); }); + }); + connect(ui->actionRightAlign, &QAction::triggered, this, [this]() { + ui->actionLeftAlign->setChecked(false); + ui->actionRightAlign->setChecked(true); + ui->actionCenter->setChecked(false); + ui->actionJustify->setChecked(false); + modifyFormat([](CondFormat& format) { format.setAlignment(CondFormat::AlignRight); }); + }); + connect(ui->actionCenter, &QAction::triggered, this, [this]() { + ui->actionLeftAlign->setChecked(false); + ui->actionRightAlign->setChecked(false); + ui->actionCenter->setChecked(true); + ui->actionJustify->setChecked(false); + modifyFormat([](CondFormat& format) { format.setAlignment(CondFormat::AlignCenter); }); + }); + connect(ui->actionJustify, &QAction::triggered, this, [this]() { + ui->actionLeftAlign->setChecked(false); + ui->actionRightAlign->setChecked(false); + ui->actionCenter->setChecked(false); + ui->actionJustify->setChecked(true); + modifyFormat([](CondFormat& format) { format.setAlignment(CondFormat::AlignJustify); }); + }); + + connect(ui->actionEditCondFormats, &QAction::triggered, this, [this]() { editCondFormats(static_cast(currentIndex().column())); }); + connect(ui->actionClearFormat, &QAction::triggered, this, [this]() { + for (const size_t column : ui->dataTable->selectedCols()) + clearAllCondFormats(column); + for (const QModelIndex& index : ui->dataTable->selectionModel()->selectedIndexes()) + clearRowIdFormats(index); + + }); + + connect(ui->dataTable, &ExtendedTableWidget::currentIndexChanged, this, [this](const QModelIndex ¤t, const QModelIndex &) { + // Get cell current format for updating the format toolbar values. Block signals, so the format change is not reapplied. + QString font_string = m_model->data(current, Qt::FontRole).toString(); + QFont font; + if(!font_string.isEmpty()) + font.fromString(font_string); + + ui->fontComboBox->blockSignals(true); + ui->fontComboBox->setCurrentFont(font); + ui->fontComboBox->blockSignals(false); + + ui->fontSizeBox->blockSignals(true); + ui->fontSizeBox->setValue(font.pointSize()); + ui->fontSizeBox->blockSignals(false); + + ui->actionBold->blockSignals(true); + ui->actionBold->setChecked(font.bold()); + ui->actionBold->blockSignals(false); + + ui->actionItalic->blockSignals(true); + ui->actionItalic->setChecked(font.italic()); + ui->actionItalic->blockSignals(false); + + ui->actionUnderline->blockSignals(true); + ui->actionUnderline->setChecked(font.underline()); + ui->actionUnderline->blockSignals(false); + + Qt::Alignment align = Qt::Alignment(m_model->data(current, Qt::TextAlignmentRole).toInt()); + ui->actionLeftAlign->blockSignals(true); + ui->actionLeftAlign->setChecked(align.testFlag(Qt::AlignLeft)); + ui->actionLeftAlign->blockSignals(false); + + ui->actionRightAlign->blockSignals(true); + ui->actionRightAlign->setChecked(align.testFlag(Qt::AlignRight)); + ui->actionRightAlign->blockSignals(false); + + ui->actionCenter->blockSignals(true); + ui->actionCenter->setChecked(align.testFlag(Qt::AlignCenter)); + ui->actionCenter->blockSignals(false); + + ui->actionJustify->blockSignals(true); + ui->actionJustify->setChecked(align.testFlag(Qt::AlignJustify)); + ui->actionJustify->blockSignals(false); + }); + + connect(ui->actionToggleFormatToolbar, &QAction::toggled, ui->formatFrame, &QFrame::setVisible); + ui->actionToggleFormatToolbar->setChecked(false); + ui->formatFrame->setVisible(false); + + // Set up find frame + ui->frameFind->hide(); + + QShortcut* shortcutHideFindFrame = new QShortcut(QKeySequence("ESC"), ui->editFindExpression); + connect(shortcutHideFindFrame, &QShortcut::activated, ui->buttonFindClose, &QToolButton::click); + + QShortcut* shortcutActionFind = new QShortcut(QKeySequence("Ctrl+F"), this, nullptr, nullptr, Qt::WidgetWithChildrenShortcut); + connect(shortcutActionFind, &QShortcut::activated, ui->actionFind, &QAction::trigger); + connect(ui->actionFind, &QAction::triggered, [this](bool checked) { + if(checked) + { + ui->widgetReplace->hide(); + ui->frameFind->show(); + ui->editFindExpression->setFocus(); + ui->actionReplace->setChecked(false); + } else { + ui->buttonFindClose->click(); + } + }); + + QShortcut* shortcutActionReplace = new QShortcut(QKeySequence("Ctrl+H"), this, nullptr, nullptr, Qt::WidgetWithChildrenShortcut); + connect(shortcutActionReplace, &QShortcut::activated, ui->actionReplace, &QAction::trigger); + connect(ui->actionReplace, &QAction::triggered, [this](bool checked) { + if(checked) + { + ui->widgetReplace->show(); + ui->frameFind->show(); + ui->editFindExpression->setFocus(); + ui->actionFind->setChecked(false); + } else { + ui->buttonFindClose->click(); + } + }); + + connect(ui->editFindExpression, &QLineEdit::returnPressed, ui->buttonFindNext, &QToolButton::click); + connect(ui->editFindExpression, &QLineEdit::textChanged, this, [this]() { + // When the text has changed but neither Return nor F3 or similar nor any buttons were pressed, we want to include the current + // cell in the search as well. This makes sure the selected cell does not jump around every time the text is changed but only + // when the current cell does not match the search expression anymore. + find(ui->editFindExpression->text(), true, true); + }); + connect(ui->buttonFindClose, &QToolButton::clicked, this, [this](){ + ui->dataTable->setFocus(); + ui->frameFind->hide(); + ui->actionFind->setChecked(false); + ui->actionReplace->setChecked(false); + }); + connect(ui->buttonFindPrevious, &QToolButton::clicked, this, [this](){ + find(ui->editFindExpression->text(), false); + }); + connect(ui->buttonFindNext, &QToolButton::clicked, this, [this](){ + find(ui->editFindExpression->text(), true); + }); + connect(ui->buttonReplaceNext, &QToolButton::clicked, this, [this](){ + find(ui->editFindExpression->text(), true, true, ReplaceMode::ReplaceNext); + }); + connect(ui->buttonReplaceAll, &QToolButton::clicked, this, [this](){ + find(ui->editFindExpression->text(), true, true, ReplaceMode::ReplaceAll); + }); +} + +TableBrowser::~TableBrowser() +{ + delete gotoValidator; + delete ui; +} + +void TableBrowser::init(DBBrowserDB* _db) +{ + db = _db; + + if(m_model) + delete m_model; + m_model = new SqliteTableModel(*db, this); + + connect(m_model, &SqliteTableModel::finishedFetch, this, &TableBrowser::fetchedData); + +} + +void TableBrowser::reset() +{ + // Reset the model + m_model->reset(); + + // Remove all stored table information browse data tab + m_settings.clear(); + m_defaultEncoding = QString(); + + // Reset the recordset label inside the Browse tab now + updateRecordsetLabel(); + + // Clear filters + clearFilters(); + + // Reset the plot dock model and connection + emit updatePlot(nullptr, nullptr, nullptr, true); +} + +sqlb::ObjectIdentifier TableBrowser::currentlyBrowsedTableName() const +{ + return sqlb::ObjectIdentifier(dbStructureModel->index(ui->comboBrowseTable->currentIndex(), + DbStructureModel::ColumnSchema, + ui->comboBrowseTable->rootModelIndex()).data().toString().toStdString(), + ui->comboBrowseTable->currentData(Qt::EditRole).toString().toStdString()); // Use the edit role here to make sure we actually get the + // table name without the schema bit in front of it. +} + +BrowseDataTableSettings& TableBrowser::settings(const sqlb::ObjectIdentifier& object) +{ + return m_settings[object]; +} + +void TableBrowser::setSettings(const sqlb::ObjectIdentifier& table, const BrowseDataTableSettings& table_settings) +{ + m_settings[table] = table_settings; +} + +void TableBrowser::setStructure(QAbstractItemModel* model, const sqlb::ObjectIdentifier& old_table) +{ + dbStructureModel = model; + ui->comboBrowseTable->setModel(model); + + ui->comboBrowseTable->setRootModelIndex(dbStructureModel->index(0, 0)); // Show the 'browsable' section of the db structure tree + int old_table_index = ui->comboBrowseTable->findText(QString::fromStdString(old_table.toDisplayString())); + if(old_table_index == -1 && ui->comboBrowseTable->count()) // If the old table couldn't be found anymore but there is another table, select that + ui->comboBrowseTable->setCurrentIndex(0); + else if(old_table_index == -1) // If there aren't any tables to be selected anymore, clear the table view + clear(); + else // Under normal circumstances just select the old table again + ui->comboBrowseTable->setCurrentIndex(old_table_index); +} + +QModelIndex TableBrowser::currentIndex() const +{ + return ui->dataTable->currentIndex(); +} + +void TableBrowser::setEnabled(bool enable) +{ + ui->browseToolbar->setEnabled(enable); + ui->editGlobalFilter->setEnabled(enable); + ui->formatFrame->setEnabled(enable); + ui->frameFind->setEnabled(enable); + + ui->buttonNext->setEnabled(enable); + ui->buttonPrevious->setEnabled(enable); + ui->buttonBegin->setEnabled(enable); + ui->buttonEnd->setEnabled(enable); + ui->buttonGoto->setEnabled(enable); + ui->editGoto->setEnabled(enable); + + updateInsertDeleteRecordButton(); +} + +void TableBrowser::updateTable() +{ + // Remove the model-view link if the table name is empty in order to remove any data from the view + if(ui->comboBrowseTable->model()->rowCount(ui->comboBrowseTable->rootModelIndex()) == 0) + { + clear(); + return; + } + + // Update the schema first + db->updateSchema(); + + // Reset the minimum width of the vertical header which could have been modified in updateFilter + // or in headerClicked. + ui->dataTable->verticalHeader()->setMinimumWidth(0); + + // Get current table name + sqlb::ObjectIdentifier tablename = currentlyBrowsedTableName(); + + // Set model + bool reconnectSelectionSignals = false; + if(ui->dataTable->model() == nullptr) + reconnectSelectionSignals = true; + ui->dataTable->setModel(m_model); + if(reconnectSelectionSignals) + { + connect(ui->dataTable->selectionModel(), &QItemSelectionModel::currentChanged, this, &TableBrowser::selectionChanged); + connect(ui->dataTable->selectionModel(), &QItemSelectionModel::selectionChanged, [this](const QItemSelection&, const QItemSelection&) { + updateInsertDeleteRecordButton(); + + const QModelIndexList& sel = ui->dataTable->selectionModel()->selectedIndexes(); + QString statusMessage; + if (sel.count() > 1) { + int rows = sel.last().row() - sel.first().row() + 1; + statusMessage = tr("%n row(s)", "", rows); + int columns = sel.last().column() - sel.first().column() + 1; + statusMessage += tr(", %n column(s)", "", columns); + + if (sel.count() < Settings::getValue("databrowser", "complete_threshold").toInt()) { + double sum = 0; + double first = m_model->data(sel.first(), Qt::EditRole).toDouble(); + double min = first; + double max = first; + for (const QModelIndex& index : sel) { + double dblData = m_model->data(index, Qt::EditRole).toDouble(); + sum += dblData; + min = std::min(min, dblData); + max = std::max(max, dblData); + } + statusMessage += tr(". Sum: %1; Average: %2; Min: %3; Max: %4").arg(sum).arg(sum/sel.count()).arg(min).arg(max); + } + } + emit statusMessageRequested(statusMessage); + }); + } + // Search stored table settings for this table + bool storedDataFound = m_settings.contains(tablename); + + // Set new table + if(!storedDataFound) + { + // No stored settings found. + + // Set table name and apply default display format settings + m_model->setQuery(sqlb::Query(tablename)); + + // There aren't any information stored for this table yet, so use some default values + + // Hide rowid column. Needs to be done before the column widths setting because of the workaround in there + showRowidColumn(false); + + // Unhide all columns by default + on_actionShowAllColumns_triggered(); + + // Enable editing in general, but lock view editing + unlockViewEditing(false); + + // Prepare for setting an initial column width based on the content. + m_columnsResized = false; + + // Encoding + m_model->setEncoding(m_defaultEncoding); + + // Global filter + ui->editGlobalFilter->clear(); + + updateRecordsetLabel(); + + // Plot + emit updatePlot(ui->dataTable, m_model, &m_settings[tablename], true); + + // The filters can be left empty as they are + } else { + // Stored settings found. Retrieve them and assemble a query from them. + BrowseDataTableSettings storedData = m_settings[tablename]; + sqlb::Query query(tablename); + + // Sorting + query.setOrderBy(storedData.query.orderBy()); + + // Filters + for(auto it=storedData.filterValues.constBegin();it!=storedData.filterValues.constEnd();++it) + query.where().insert({it.key(), CondFormat::filterToSqlCondition(it.value(), m_model->encoding())}); + + // Global filter + for(const auto& f : storedData.globalFilters) + query.globalWhere().push_back(CondFormat::filterToSqlCondition(f, m_model->encoding())); + + // Display formats + bool only_defaults = true; + if(db->getObjectByName(tablename)) + { + const sqlb::FieldInfoList& tablefields = db->getObjectByName(tablename)->fieldInformation(); + for(size_t i=0; i(i)+1]; + if(format.size()) + { + query.selectedColumns().emplace_back(tablefields.at(i).name, format.toStdString()); + only_defaults = false; + } else { + query.selectedColumns().emplace_back(tablefields.at(i).name, tablefields.at(i).name); + } + } + } + if(only_defaults) + query.selectedColumns().clear(); + + // Unlock view editing + query.setRowIdColumn(storedData.unlockViewPk.toStdString()); + + // Apply query + m_model->setQuery(query); + + // There is information stored for this table, so extract it and apply it + applySettings(storedData); + + updateRecordsetLabel(); + + // Plot + emit updatePlot(ui->dataTable, m_model, &m_settings[tablename], false); + } + + + // Show/hide menu options depending on whether this is a table or a view + if(db->getObjectByName(currentlyBrowsedTableName()) && db->getObjectByName(currentlyBrowsedTableName())->type() == sqlb::Object::Table) + { + // Table + sqlb::TablePtr table = db->getObjectByName(currentlyBrowsedTableName()); + ui->actionUnlockViewEditing->setVisible(false); + ui->actionShowRowidColumn->setVisible(!table->withoutRowidTable()); + } else { + // View + ui->actionUnlockViewEditing->setVisible(true); + ui->actionShowRowidColumn->setVisible(false); + } + + updateInsertDeleteRecordButton(); +} + +void TableBrowser::clearFilters() +{ + ui->dataTable->filterHeader()->clearFilters(); + ui->editGlobalFilter->clear(); +} + +void TableBrowser::reloadSettings() +{ + ui->dataTable->reloadSettings(); + + ui->browseToolbar->setToolButtonStyle(static_cast(Settings::getValue("General", "toolbarStyleBrowse").toInt())); + m_model->reloadSettings(); +} + +void TableBrowser::setCurrentTable(const sqlb::ObjectIdentifier& name) +{ + int index = ui->comboBrowseTable->findText(QString::fromStdString(name.toDisplayString())); + if(index != -1) + ui->comboBrowseTable->setCurrentIndex(index); +} + +void TableBrowser::clear() +{ + if (!ui->dataTable->model()) + return; + + ui->dataTable->setModel(nullptr); + if(qobject_cast(ui->dataTable->horizontalHeader())) + qobject_cast(ui->dataTable->horizontalHeader())->generateFilters(0); + + ui->editGlobalFilter->blockSignals(true); + ui->editGlobalFilter->clear(); + ui->editGlobalFilter->blockSignals(false); +} + +void TableBrowser::updateFilter(size_t column, const QString& value) +{ + // Set minimum width to the vertical header in order to avoid flickering while a filter is being updated. + ui->dataTable->verticalHeader()->setMinimumWidth(ui->dataTable->verticalHeader()->width()); + + m_model->updateFilter(column, value); + BrowseDataTableSettings& settings = m_settings[currentlyBrowsedTableName()]; + if(value.isEmpty() && settings.filterValues.remove(static_cast(column)) > 0) + { + emit projectModified(); + } else { + if (settings.filterValues[static_cast(column)] != value) { + settings.filterValues[static_cast(column)] = value; + emit projectModified(); + } + } + + updateRecordsetLabel(); + + // Reapply the view settings. This seems to be necessary as a workaround for newer Qt versions. + applySettings(settings, true); +} + +void TableBrowser::addCondFormatFromFilter(size_t column, const QString& value) +{ + QFont font = QFont(Settings::getValue("databrowser", "font").toString()); + font.setPointSize(Settings::getValue("databrowser", "fontsize").toInt()); + + // Create automatically a new conditional format with the next serial background color according to the theme and the regular foreground + // color and font in the settings. + CondFormat newCondFormat(value, QColor(Settings::getValue("databrowser", "reg_fg_colour").toString()), + m_condFormatPalette.nextSerialColor(Palette::appHasDarkTheme()), + font, + CondFormat::AlignLeft, + m_model->encoding()); + addCondFormat(false, column, newCondFormat); +} + +void TableBrowser::addCondFormat(bool isRowIdFormat, size_t column, const CondFormat& newCondFormat) +{ + BrowseDataTableSettings& settings = m_settings[currentlyBrowsedTableName()]; + std::vector& formats = isRowIdFormat ? settings.rowIdFormats[column] : settings.condFormats[column]; + m_model->addCondFormat(isRowIdFormat, column, newCondFormat); + // Conditionless formats are pushed back and others inserted at the begining, so they aren't eclipsed. + if (newCondFormat.filter().isEmpty()) + formats.push_back(newCondFormat); + else + formats.insert(formats.begin(), newCondFormat); +} + +void TableBrowser::clearAllCondFormats(size_t column) +{ + std::vector emptyCondFormatVector = std::vector(); + m_model->setCondFormats(false, column, emptyCondFormatVector); + m_settings[currentlyBrowsedTableName()].condFormats[column].clear(); + emit projectModified(); +} + +void TableBrowser::clearRowIdFormats(const QModelIndex index) +{ + + std::vector& rowIdFormats = m_settings[currentlyBrowsedTableName()].rowIdFormats[static_cast(index.column())]; + rowIdFormats.erase(std::remove_if(rowIdFormats.begin(), rowIdFormats.end(), [&](const CondFormat& format) { + return format.filter() == QString("=%1").arg(m_model->data(index.sibling(index.row(), 0)).toString()); + }), rowIdFormats.end()); + m_model->setCondFormats(true, static_cast(index.column()), rowIdFormats); + emit projectModified(); + +} + +void TableBrowser::editCondFormats(size_t column) +{ + CondFormatManager condFormatDialog(m_settings[currentlyBrowsedTableName()].condFormats[column], + m_model->encoding(), this); + condFormatDialog.setWindowTitle(tr("Conditional formats for \"%1\""). + arg(m_model->headerData(static_cast(column), Qt::Horizontal, Qt::EditRole).toString())); + if (condFormatDialog.exec()) { + std::vector condFormatVector = condFormatDialog.getCondFormats(); + m_model->setCondFormats(false, column, condFormatVector); + m_settings[currentlyBrowsedTableName()].condFormats[column] = condFormatVector; + emit projectModified(); + } +} +void TableBrowser::modifySingleFormat(const bool isRowIdFormat, const QString& filter, const QModelIndex refIndex, std::function changeFunction) +{ + const size_t column = static_cast(refIndex.column()); + BrowseDataTableSettings& settings = m_settings[currentlyBrowsedTableName()]; + std::vector& formats = isRowIdFormat ? settings.rowIdFormats[column] : settings.condFormats[column]; + auto it = std::find_if(formats.begin(), formats.end(), [&filter](const CondFormat& format) { + return format.filter() == filter; + }); + if(it != formats.end()) { + changeFunction(*it); + m_model->addCondFormat(isRowIdFormat, column, *it); + } else { + // Create a new conditional format based on the current reference index and then modify it as requested using the passed function. + CondFormat newCondFormat(filter, m_model, refIndex, m_model->encoding()); + changeFunction(newCondFormat); + addCondFormat(isRowIdFormat, column, newCondFormat); + } +} + +void TableBrowser::modifyFormat(std::function changeFunction) +{ + // Modify the conditional formats from entirely selected columns having the current filter value, + // or modify the row-id formats of selected cells, when the selection does not cover entire columns. + const std::unordered_set& columns = ui->dataTable->selectedCols(); + if (columns.size() > 0) { + for (size_t column : columns) { + const QString& filter = m_settings[currentlyBrowsedTableName()].filterValues.value(static_cast(column)); + modifySingleFormat(false, filter, currentIndex().sibling(currentIndex().row(), static_cast(column)), changeFunction); + } + } else { + for(const QModelIndex& index : ui->dataTable->selectionModel()->selectedIndexes()) { + const QString filter = QString("=%1").arg(m_model->data(index.sibling(index.row(), 0)).toString()); + modifySingleFormat(true, filter, index, changeFunction); + } + } + emit projectModified(); +} + +void TableBrowser::updateRecordsetLabel() +{ + // Get all the numbers, i.e. the number of the first row and the last row as well as the total number of rows + int from = ui->dataTable->verticalHeader()->visualIndexAt(0) + 1; + int total = m_model->rowCount(); + int to = from + ui->dataTable->numVisibleRows() - 1; + if(to < 0) + to = 0; + + // Update the validator of the goto row field + gotoValidator->setRange(0, total); + + // When there is no query for this table (i.e. no table is selected), there is no row count query either which in turn means + // that the row count query will never finish. And because of this the row count will be forever unknown. To avoid always showing + // a misleading "determining row count" text in the UI we set the row count status to complete here for empty queries. + auto row_count_available = m_model->rowCountAvailable(); + if(m_model->query().empty()) + row_count_available = SqliteTableModel::RowCount::Complete; + + // Update the label showing the current position + QString txt; + switch(row_count_available) + { + case SqliteTableModel::RowCount::Unknown: + txt = tr("determining row count..."); + break; + case SqliteTableModel::RowCount::Partial: + txt = tr("%1 - %2 of >= %3").arg(from).arg(to).arg(total); + break; + case SqliteTableModel::RowCount::Complete: + txt = tr("%1 - %2 of %3").arg(from).arg(to).arg(total); + break; + } + ui->labelRecordset->setText(txt); + + // Enable editing only for tables or views with editing unlocked for which the row count is already available + sqlb::ObjectIdentifier current_table = currentlyBrowsedTableName(); + bool is_table_or_unlocked_view = !current_table.isEmpty() && !m_model->query().empty() && db->getObjectByName(current_table) && ( + (db->getObjectByName(current_table)->type() == sqlb::Object::View && m_model->hasPseudoPk()) || + (db->getObjectByName(current_table)->type() == sqlb::Object::Table)); + enableEditing(m_model->rowCountAvailable() != SqliteTableModel::RowCount::Unknown && is_table_or_unlocked_view); +} + +void TableBrowser::applySettings(const BrowseDataTableSettings& storedData, bool skipFilters) +{ + // We don't want to pass storedData by reference because the functions below would change the referenced data in their original + // place, thus modifiying the data this function can use. To have a static description of what the view should look like we want + // a copy here. + + // Show rowid column. Needs to be done before the column widths setting because of the workaround in there and before the filter setting + // because of the filter row generation. + showRowidColumn(storedData.showRowid, skipFilters); + + // Enable editing in general and (un)lock view editing depending on the settings + unlockViewEditing(!storedData.unlockViewPk.isEmpty() && storedData.unlockViewPk != "_rowid_", storedData.unlockViewPk); + + // Column hidden status + on_actionShowAllColumns_triggered(); + for(auto hiddenIt=storedData.hiddenColumns.constBegin();hiddenIt!=storedData.hiddenColumns.constEnd();++hiddenIt) + hideColumns(hiddenIt.key(), hiddenIt.value()); + + // Column widths + for(auto widthIt=storedData.columnWidths.constBegin();widthIt!=storedData.columnWidths.constEnd();++widthIt) + ui->dataTable->setColumnWidth(widthIt.key(), widthIt.value()); + m_columnsResized = true; + + // Filters + if(!skipFilters) + { + // Set filters blocking signals, since the filter is already applied to the browse table model + FilterTableHeader* filterHeader = qobject_cast(ui->dataTable->horizontalHeader()); + bool oldState = filterHeader->blockSignals(true); + for(auto filterIt=storedData.filterValues.constBegin();filterIt!=storedData.filterValues.constEnd();++filterIt) + filterHeader->setFilter(static_cast(filterIt.key()), filterIt.value()); + + // Regular conditional formats + for(auto formatIt=storedData.condFormats.constBegin(); formatIt!=storedData.condFormats.constEnd(); ++formatIt) + m_model->setCondFormats(false, formatIt.key(), formatIt.value()); + + // Row Id formats + for(auto formatIt=storedData.rowIdFormats.constBegin(); formatIt!=storedData.rowIdFormats.constEnd(); ++formatIt) + m_model->setCondFormats(true, formatIt.key(), formatIt.value()); + + filterHeader->blockSignals(oldState); + + ui->editGlobalFilter->blockSignals(true); + QString text; + for(const auto& f : storedData.globalFilters) + text += f + " "; + text.chop(1); + ui->editGlobalFilter->setText(text); + ui->editGlobalFilter->blockSignals(false); + } + + // Encoding + m_model->setEncoding(storedData.encoding); +} + +void TableBrowser::enableEditing(bool enable_edit) +{ + // Don't enable anything if this is a read only database + bool edit = enable_edit && !db->readOnly(); + + // Apply settings + ui->dataTable->setEditTriggers(edit ? QAbstractItemView::SelectedClicked | QAbstractItemView::AnyKeyPressed | QAbstractItemView::EditKeyPressed : QAbstractItemView::NoEditTriggers); + updateInsertDeleteRecordButton(); +} + +void TableBrowser::showRowidColumn(bool show, bool skipFilters) +{ + // Block all signals from the horizontal header. Otherwise the QHeaderView::sectionResized signal causes us trouble + ui->dataTable->horizontalHeader()->blockSignals(true); + + // WORKAROUND + // Set the opposite hidden/visible status of what we actually want for the rowid column. This is to work around a Qt bug which + // is present in at least version 5.7.1. The problem is this: when you browse a table/view with n colums, then switch to a table/view + // with less than n columns, you'll be able to resize the first (hidden!) column by resizing the section to the left of the first visible + // column. By doing so the table view gets messed up. But even when not resizing the first hidden column, tab-ing through the fields + // will stop at the not-so-much-hidden rowid column, too. All this can be fixed by this line. I haven't managed to find another workaround + // or way to fix this yet. + ui->dataTable->setColumnHidden(0, show); + + // Show/hide rowid column + ui->dataTable->setColumnHidden(0, !show); + + // Update checked status of the popup menu action + ui->actionShowRowidColumn->setChecked(show); + + // Save settings for this table + sqlb::ObjectIdentifier current_table = currentlyBrowsedTableName(); + if (m_settings[current_table].showRowid != show) { + emit projectModified(); + m_settings[current_table].showRowid = show; + } + + // Update the filter row + if(!skipFilters) + qobject_cast(ui->dataTable->horizontalHeader())->generateFilters(static_cast(m_model->columnCount()), show); + + // Re-enable signals + ui->dataTable->horizontalHeader()->blockSignals(false); + + ui->dataTable->update(); +} + +void TableBrowser::unlockViewEditing(bool unlock, QString pk) +{ + sqlb::ObjectIdentifier currentTable = currentlyBrowsedTableName(); + + if(currentTable.isEmpty()) + return; + + // If this isn't a view just unlock editing and return + if(db->getObjectByName(currentTable) && db->getObjectByName(currentTable)->type() != sqlb::Object::View) + { + m_model->setPseudoPk(m_model->pseudoPk()); + enableEditing(true); + return; + } + + sqlb::ViewPtr obj = db->getObjectByName(currentTable); + + // If the view gets unlocked for editing and we don't have a 'primary key' for this view yet, then ask for one + if(unlock && pk.isEmpty()) + { + while(true) + { + bool ok; + + QStringList options; + for(const auto& n : obj->fieldNames()) + options.push_back(QString::fromStdString(n)); + + // Ask for a PK + pk = QInputDialog::getItem(this, + qApp->applicationName(), + tr("Please enter a pseudo-primary key in order to enable editing on this view. " + "This should be the name of a unique column in the view."), + options, + 0, + false, + &ok); + + // Cancelled? + if(!ok || pk.isEmpty()) { + ui->actionUnlockViewEditing->setChecked(false); + return; + } + + // Do some basic testing of the input and if the input appears to be good, go on + if(db->executeSQL("SELECT " + sqlb::escapeIdentifier(pk.toStdString()) + " FROM " + currentTable.toString() + " LIMIT 1;", false, true)) + break; + } + } else if(!unlock) { + // Locking the view is done by unsetting the pseudo-primary key + pk = "_rowid_"; + } + + // (De)activate editing + enableEditing(unlock); + m_model->setPseudoPk({pk.toStdString()}); + + // Update checked status of the popup menu action + ui->actionUnlockViewEditing->blockSignals(true); + ui->actionUnlockViewEditing->setChecked(unlock); + ui->actionUnlockViewEditing->blockSignals(false); + + // If the settings didn't change, do not try to reapply them. + // This avoids an infinite mutual recursion. + BrowseDataTableSettings& settings = m_settings[currentTable]; + + if(settings.unlockViewPk != pk) { + // Save settings for this table + settings.unlockViewPk = pk; + // Reapply the view settings. This seems to be necessary as a workaround for newer Qt versions. + applySettings(settings); + emit projectModified(); + } +} + +void TableBrowser::hideColumns(int column, bool hide) +{ + sqlb::ObjectIdentifier tableName = currentlyBrowsedTableName(); + + // Select columns to (un)hide + std::unordered_set columns; + if(column == -1) + { + if(ui->dataTable->selectedCols().size() == 0) + columns.insert(ui->actionBrowseTableEditDisplayFormat->property("clicked_column").toInt()); + else { + auto cols = ui->dataTable->selectedCols(); + columns.insert(cols.begin(), cols.end()); + } + } else { + columns.insert(column); + } + + // (Un)hide requested column(s) + for(int col : columns) + { + ui->dataTable->setColumnHidden(col, hide); + if(!hide) + ui->dataTable->setColumnWidth(col, ui->dataTable->horizontalHeader()->defaultSectionSize()); + m_settings[tableName].hiddenColumns[col] = hide; + } + + // check to see if all the columns are hidden + bool allHidden = true; + for(int col = 1; col < ui->dataTable->model()->columnCount(); col++) + { + if(!ui->dataTable->isColumnHidden(col)) + { + allHidden = false; + break; + } + } + + if(allHidden && ui->dataTable->model()->columnCount() > 1) + hideColumns(1, false); + emit projectModified(); +} + +void TableBrowser::on_actionShowAllColumns_triggered() +{ + for(int col = 1; col < ui->dataTable->model()->columnCount(); col++) + { + if(ui->dataTable->isColumnHidden(col)) + hideColumns(col, false); + } +} + +void TableBrowser::updateInsertDeleteRecordButton() +{ + // Update the delete record button to reflect number of selected records + + // NOTE: We're assuming here that the selection is always contiguous, i.e. that there are never two selected + // rows with a non-selected row in between. + int rows = 0; + + // If there is no model yet (because e.g. no database file is opened) there is no selection model either. So we need to check for that here + // in order to avoid null pointer dereferences. If no selection model exists we will just continue as if no row is selected because without a + // model you could argue there actually is no row to be selected. + if(ui->dataTable->selectionModel()) + { + const auto & sel = ui->dataTable->selectionModel()->selectedIndexes(); + if(sel.count()) + rows = sel.last().row() - sel.first().row() + 1; + } + + // Enable the insert and delete buttons only if the currently browsed table or view is editable. For the delete button we additionally require + // at least one row to be selected. For the insert button there is an extra rule to disable it when we are browsing a view because inserting + // into a view isn't supported yet. + bool isEditable = m_model->isEditable() && !db->readOnly(); + ui->actionNewRecord->setEnabled(isEditable); + ui->actionDeleteRecord->setEnabled(isEditable && rows != 0); + + if(rows > 1) + ui->actionDeleteRecord->setText(tr("Delete Records")); + else + ui->actionDeleteRecord->setText(tr("Delete Record")); +} + +void TableBrowser::duplicateRecord(int currentRow) +{ + auto row = m_model->dittoRecord(currentRow); + if (row.isValid()) + ui->dataTable->setCurrentIndex(row); + else + QMessageBox::warning(this, qApp->applicationName(), db->lastError()); +} + +void TableBrowser::headerClicked(int logicalindex) +{ + BrowseDataTableSettings& settings = m_settings[currentlyBrowsedTableName()]; + + // Abort if there is more than one column selected because this tells us that the user pretty sure wants to do a range selection + // instead of sorting data. But restore before the sort indicator automatically changed by Qt so it still indicates the last + // use sort action. + // This check is disabled when the Control key is pressed. This is done because we use the Control key for sorting by multiple columns and + // Qt seems to pretty much always select multiple columns when the Control key is pressed. + if(!QApplication::keyboardModifiers().testFlag(Qt::ControlModifier) && ui->dataTable->selectionModel()->selectedColumns().count() > 1) { + applySettings(settings); + return; + } + + // Set minimum width to the vertical header in order to avoid flickering when sorting. + ui->dataTable->verticalHeader()->setMinimumWidth(ui->dataTable->verticalHeader()->width()); + + // Get the current list of sort columns + auto& columns = settings.query.orderBy(); + + // Before sorting, first check if the Control key is pressed. If it is, we want to append this column to the list of sort columns. If it is not, + // we want to sort only by the new column. + if(QApplication::keyboardModifiers().testFlag(Qt::ControlModifier)) + { + // Multi column sorting + + // If the column was control+clicked again, change its sort order. + // If not already in the sort order, add the column as a new sort column to the list. + bool present = false; + for(sqlb::SortedColumn& sortedCol : columns) { + + if(sortedCol.column == static_cast(logicalindex)) { + sortedCol.direction = (sortedCol.direction == sqlb::Ascending ? sqlb::Descending : sqlb::Ascending); + present = true; + break; + } + } + if(!present) + columns.emplace_back(logicalindex, sqlb::Ascending); + } else { + // Single column sorting + + // If we have exactly one sort column and it is the column which was just clicked, change its sort order. + // If not, clear the list of sorting columns and replace it by a single new sort column. + if(columns.size() == 1 && columns.front().column == static_cast(logicalindex)) + { + columns.front().direction = (columns.front().direction == sqlb::Ascending ? sqlb::Descending : sqlb::Ascending); + } else { + columns.clear(); + columns.emplace_back(logicalindex, sqlb::Ascending); + } + } + + // Do the actual sorting + ui->dataTable->sortByColumns(columns); + + // select the first item in the column so the header is bold + // we might try to select the last selected item + ui->dataTable->setCurrentIndex(ui->dataTable->currentIndex().sibling(0, logicalindex)); + + emit updatePlot(ui->dataTable, m_model, &m_settings[currentlyBrowsedTableName()], true); + + // Reapply the view settings. This seems to be necessary as a workaround for newer Qt versions. + applySettings(settings); + + emit projectModified(); +} + +void TableBrowser::updateColumnWidth(int section, int /*old_size*/, int new_size) +{ + std::unordered_set selectedCols = ui->dataTable->selectedCols(); + sqlb::ObjectIdentifier tableName = currentlyBrowsedTableName(); + + if (selectedCols.find(static_cast(section)) == selectedCols.end()) + { + if (m_settings[tableName].columnWidths[section] != new_size) { + emit projectModified(); + m_settings[tableName].columnWidths[section] = new_size; + } + } + else + { + ui->dataTable->blockSignals(true); + for(size_t col : selectedCols) + { + ui->dataTable->setColumnWidth(static_cast(col), new_size); + if (m_settings[tableName].columnWidths[static_cast(col)] != new_size) { + emit projectModified(); + m_settings[tableName].columnWidths[static_cast(col)] = new_size; + } + } + ui->dataTable->blockSignals(false); + } +} + +void TableBrowser::showDataColumnPopupMenu(const QPoint& pos) +{ + // Get the index of the column which the user has clicked on and store it in the action. This is sort of hack-ish and it might be the heat in my room + // but I haven't come up with a better solution so far + int logical_index = ui->dataTable->horizontalHeader()->logicalIndexAt(pos); + if(logical_index == -1) // Don't open the popup menu if the user hasn't clicked on a column header + return; + ui->actionBrowseTableEditDisplayFormat->setProperty("clicked_column", logical_index); + + // Calculate the proper position for the context menu and display it + popupHeaderMenu->exec(ui->dataTable->horizontalHeader()->mapToGlobal(pos)); +} + +void TableBrowser::showRecordPopupMenu(const QPoint& pos) +{ + int row = ui->dataTable->verticalHeader()->logicalIndexAt(pos); + if (row == -1) + return; + + QMenu popupRecordMenu(this); + + // "Delete and duplicate records" can only be done on writable objects + if(db->getObjectByName(currentlyBrowsedTableName())->type() == sqlb::Object::Types::Table && !db->readOnly()) { + + // Select the row if it is not already in the selection. + QModelIndexList rowList = ui->dataTable->selectionModel()->selectedRows(); + bool found = false; + for (QModelIndex index : rowList) { + if (row == index.row()) { + found = true; + break; + } + } + if (!found) + ui->dataTable->selectRow(row); + + rowList = ui->dataTable->selectionModel()->selectedRows(); + + QString duplicateText = rowList.count() > 1 ? tr("Duplicate records") : tr("Duplicate record"); + + QAction* action = new QAction(duplicateText, &popupRecordMenu); + // Set shortcut for documentation purposes (the actual functional shortcut is not set here) + action->setShortcut(QKeySequence(tr("Ctrl+\""))); + popupRecordMenu.addAction(action); + + connect(action, &QAction::triggered, [rowList, this]() { + for (const QModelIndex& index : rowList) + duplicateRecord(index.row()); + }); + + QAction* deleteRecordAction = new QAction(QIcon(":icons/delete_record"), ui->actionDeleteRecord->text(), &popupRecordMenu); + popupRecordMenu.addAction(deleteRecordAction); + + connect(deleteRecordAction, &QAction::triggered, [&]() { + deleteRecord(); + }); + + popupRecordMenu.addSeparator(); + } + + // "Adjust rows" can be done on any object + QAction* adjustRowHeightAction = new QAction(tr("Adjust rows to contents"), &popupRecordMenu); + adjustRowHeightAction->setCheckable(true); + adjustRowHeightAction->setChecked(m_adjustRows); + popupRecordMenu.addAction(adjustRowHeightAction); + + connect(adjustRowHeightAction, &QAction::toggled, [&](bool checked) { + m_adjustRows = checked; + if(m_adjustRows) + ui->dataTable->resizeRowsToContents(); + else + updateTable(); + }); + + popupRecordMenu.exec(ui->dataTable->verticalHeader()->mapToGlobal(pos)); +} + +void TableBrowser::addRecord() +{ + int row = m_model->rowCount(); + + // If table has pseudo_pk, then it must be an editable view. Jump straight to inserting by pop-up dialog. + if(!m_model->hasPseudoPk() && m_model->insertRow(row)) + { + selectTableLine(row); + } else { + // Error inserting empty row. + // User has to provide values acomplishing the constraints. Open Add Record Dialog. + insertValues(); + } +} + +void TableBrowser::insertValues() +{ + std::vector pseudo_pk = m_model->hasPseudoPk() ? m_model->pseudoPk() : std::vector(); + AddRecordDialog dialog(*db, currentlyBrowsedTableName(), this, pseudo_pk); + if (dialog.exec()) + updateTable(); +} + +void TableBrowser::deleteRecord() +{ + if(ui->dataTable->selectionModel()->hasSelection()) + { + // If only filter header is selected + if(ui->dataTable->selectionModel()->selectedIndexes().isEmpty()) + return; + + int old_row = ui->dataTable->currentIndex().row(); + while(ui->dataTable->selectionModel()->hasSelection()) + { + int first_selected_row = ui->dataTable->selectionModel()->selectedIndexes().first().row(); + int last_selected_row = ui->dataTable->selectionModel()->selectedIndexes().last().row(); + int selected_rows_count = last_selected_row - first_selected_row + 1; + if(!m_model->removeRows(first_selected_row, selected_rows_count)) + { + QMessageBox::warning(this, QApplication::applicationName(), tr("Error deleting record:\n%1").arg(db->lastError())); + break; + } + } + + if(old_row > m_model->rowCount()) + old_row = m_model->rowCount(); + selectTableLine(old_row); + } else { + QMessageBox::information( this, QApplication::applicationName(), tr("Please select a record first")); + } +} + +void TableBrowser::navigatePrevious() +{ + int curRow = ui->dataTable->currentIndex().row(); + curRow -= ui->dataTable->numVisibleRows() - 1; + if(curRow < 0) + curRow = 0; + selectTableLine(curRow); +} + +void TableBrowser::navigateNext() +{ + int curRow = ui->dataTable->currentIndex().row(); + curRow += ui->dataTable->numVisibleRows() - 1; + if(curRow >= m_model->rowCount()) + curRow = m_model->rowCount() - 1; + selectTableLine(curRow); +} + +void TableBrowser::navigateBegin() +{ + selectTableLine(0); +} + +void TableBrowser::navigateEnd() +{ + selectTableLine(m_model->rowCount()-1); +} + +void TableBrowser::navigateGoto() +{ + int row = ui->editGoto->text().toInt(); + if(row <= 0) + row = 1; + if(row > m_model->rowCount()) + row = m_model->rowCount(); + + selectTableLine(row - 1); + ui->editGoto->setText(QString::number(row)); +} + +void TableBrowser::selectTableLine(int lineToSelect) +{ + ui->dataTable->selectTableLine(lineToSelect); +} + +void TableBrowser::on_actionClearFilters_triggered() +{ + ui->dataTable->filterHeader()->clearFilters(); +} + +void TableBrowser::on_actionClearSorting_triggered() +{ + // Get the current list of sort columns + auto& columns = m_settings[currentlyBrowsedTableName()].query.orderBy(); + columns.clear(); + // Set cleared vector of sort-by columns + m_model->sort(columns); +} + +void TableBrowser::editDisplayFormat() +{ + // Get the current table name and fetch its table object, then retrieve the fields of that table and look up the index of the clicked table header + // section using it as the table field array index. Subtract one from the header index to get the column index because in the the first (though hidden) + // column is always the rowid column. Ultimately, get the column name from the column object + sqlb::ObjectIdentifier current_table = currentlyBrowsedTableName(); + int field_number = sender()->property("clicked_column").toInt(); + QString field_name; + if (db->getObjectByName(current_table)->type() == sqlb::Object::Table) + field_name = QString::fromStdString(db->getObjectByName(current_table)->fields.at(static_cast(field_number)-1).name()); + else + field_name = QString::fromStdString(db->getObjectByName(current_table)->fieldNames().at(static_cast(field_number)-1)); + // Get the current display format of the field + QString current_displayformat = m_settings[current_table].displayFormats[field_number]; + + // Open the dialog + ColumnDisplayFormatDialog dialog(*db, current_table, field_name, current_displayformat, this); + if(dialog.exec()) + { + // Set the newly selected display format + QString new_format = dialog.selectedDisplayFormat(); + if(new_format.size()) + m_settings[current_table].displayFormats[field_number] = new_format; + else + m_settings[current_table].displayFormats.remove(field_number); + emit projectModified(); + + // Refresh view + updateTable(); + } +} + +void TableBrowser::exportFilteredTable() +{ + ExportDataDialog dialog(*db, ExportDataDialog::ExportFormatCsv, this, m_model->customQuery(false)); + dialog.exec(); +} + +void TableBrowser::saveFilterAsView() +{ + if (m_model->filterCount() > 0) + // Save as view a custom query without rowid + emit createView(m_model->customQuery(false)); + else + QMessageBox::information(this, qApp->applicationName(), tr("There is no filter set for this table. View will not be created.")); +} + +void TableBrowser::setTableEncoding(bool forAllTables) +{ + // Get the old encoding + QString encoding = m_model->encoding(); + + // Ask the user for a new encoding + bool ok; + QString question; + QStringList availableCodecs = toStringList(QTextCodec::availableCodecs()); + availableCodecs.removeDuplicates(); + int currentItem = availableCodecs.indexOf(encoding); + + if(forAllTables) + question = tr("Please choose a new encoding for all tables."); + else + question = tr("Please choose a new encoding for this table."); + encoding = QInputDialog::getItem(this, + tr("Set encoding"), + tr("%1\nLeave the field empty for using the database encoding.").arg(question), + availableCodecs, + currentItem, + true, // editable + &ok); + + // Only set the new encoding if the user clicked the OK button + if(ok) + { + // Check if encoding is valid + if(!encoding.isEmpty() && !QTextCodec::codecForName(encoding.toUtf8())) + { + QMessageBox::warning(this, qApp->applicationName(), tr("This encoding is either not valid or not supported.")); + return; + } + + // Set encoding for current table + m_model->setEncoding(encoding); + + // Save encoding for this table + m_settings[currentlyBrowsedTableName()].encoding = encoding; + + // Set default encoding if requested to and change all stored table encodings + if(forAllTables) + { + m_defaultEncoding = encoding; + + for(auto it=m_settings.begin();it!=m_settings.end();++it) + it.value().encoding = encoding; + } + + emit projectModified(); + } +} + +void TableBrowser::setDefaultTableEncoding() +{ + setTableEncoding(true); +} + +void TableBrowser::jumpToRow(const sqlb::ObjectIdentifier& table, std::string column, const QByteArray& value) +{ + // First check if table exists + sqlb::TablePtr obj = db->getObjectByName(table); + if(!obj) + return; + + // If no column name is set, assume the primary key is meant + if(!column.size()) + column = obj->primaryKey()->columnList().front(); + + // If column doesn't exist don't do anything + auto column_index = sqlb::findField(obj, column); + if(column_index == obj->fields.end()) + return; + + // Jump to table + setCurrentTable(table); + + // Set filter + ui->dataTable->filterHeader()->setFilter(static_cast(column_index-obj->fields.begin()+1), QString("=") + value); + updateTable(); +} + +static QString replaceInValue(QString value, const QString& find, const QString& replace, Qt::MatchFlags flags) +{ + // Helper function which replaces a string in another string by a third string. It uses regular expressions if told so. + if(flags.testFlag(Qt::MatchRegExp)) + { + QRegularExpression reg_exp(find, (flags.testFlag(Qt::MatchCaseSensitive) ? QRegularExpression::NoPatternOption : QRegularExpression::CaseInsensitiveOption)); + if(!flags.testFlag(Qt::MatchContains)) + { +#if QT_VERSION < QT_VERSION_CHECK(5, 12, 0) + reg_exp.setPattern("\\A(" + reg_exp.pattern() + ")\\Z"); +#else + reg_exp.setPattern(QRegularExpression::anchoredPattern(reg_exp.pattern())); +#endif + } + + return value.replace(reg_exp, replace); + } else { + return value.replace(find, replace, flags.testFlag(Qt::MatchCaseSensitive) ? Qt::CaseSensitive : Qt::CaseInsensitive); + } +} + +void TableBrowser::find(const QString& expr, bool forward, bool include_first, ReplaceMode replace) +{ + // Reset the colour of the line edit, assuming there is no error. + ui->editFindExpression->setStyleSheet(""); + + // You are not allowed to search for an ampty string + if(expr.isEmpty()) + return; + + // Get the cell from which the search should be started. If there is a selected cell, use that. If there is no selected cell, start at the first cell. + QModelIndex start; + if(ui->dataTable->selectionModel()->hasSelection()) + start = ui->dataTable->selectionModel()->selectedIndexes().front(); + else + start = m_model->index(0, 0); + + // Prepare the match flags with all the search settings + Qt::MatchFlags flags = Qt::MatchWrap; + + if(ui->checkFindCaseSensitive->isChecked()) + flags |= Qt::MatchCaseSensitive; + + if(ui->checkFindWholeCell->isChecked()) + flags |= Qt::MatchFixedString; + else + flags |= Qt::MatchContains; + + if(ui->checkFindRegEx->isChecked()) + flags |= Qt::MatchRegExp; + + // Prepare list of columns to search in. We only search in non-hidden rows + std::vector column_list; + sqlb::ObjectIdentifier tableName = currentlyBrowsedTableName(); + if(m_settings[tableName].showRowid) + column_list.push_back(0); + for(int i=1;icolumnCount();i++) + { + if(m_settings[tableName].hiddenColumns.contains(i) == false) + column_list.push_back(i); + else if(m_settings[tableName].hiddenColumns[i] == false) + column_list.push_back(i); + } + + // Are we only searching for text or are we supposed to replace text? + switch(replace) + { + case ReplaceMode::NoReplace: { + // Perform the actual search using the model class + const auto match = m_model->nextMatch(start, column_list, expr, flags, !forward, include_first); + + // Select the next match if we found one + if(match.isValid()) + ui->dataTable->setCurrentIndex(match); + + // Make the expression control red if no results were found + if(!match.isValid()) + ui->editFindExpression->setStyleSheet("QLineEdit {color: white; background-color: rgb(255, 102, 102)}"); + } break; + case ReplaceMode::ReplaceNext: { + // Find the next match + const auto match = m_model->nextMatch(start, column_list, expr, flags, !forward, include_first); + + // If there was a match, perform the replacement on the cell and select it + if(match.isValid()) + { + m_model->setData(match, replaceInValue(match.data(Qt::EditRole).toString(), expr, ui->editReplaceExpression->text(), flags)); + ui->dataTable->setCurrentIndex(match); + } + + // Make the expression control red if no results were found + if(!match.isValid()) + ui->editFindExpression->setStyleSheet("QLineEdit {color: white; background-color: rgb(255, 102, 102)}"); + } break; + case ReplaceMode::ReplaceAll: { + // Find all matches + std::set all_matches; + while(true) + { + // Find the next match + const auto match = m_model->nextMatch(start, column_list, expr, flags, !forward, include_first); + + // If there was a match, perform the replacement and continue from that position. If there was no match, stop looking for other matches. + // Additionally, keep track of all the matches so far in order to avoid running over them again indefinitely, e.g. when replacing "1" by "10". + if(match.isValid() && all_matches.find(match) == all_matches.end()) + { + all_matches.insert(match); + m_model->setData(match, replaceInValue(match.data(Qt::EditRole).toString(), expr, ui->editReplaceExpression->text(), flags)); + + // Start searching from the last match onwards in order to not search through the same cells over and over again. + start = match; + include_first = false; + } else { + break; + } + } + + // Make the expression control red if no results were found + if(!all_matches.empty()) + QMessageBox::information(this, qApp->applicationName(), tr("%1 replacement(s) made.").arg(all_matches.size())); + else + ui->editFindExpression->setStyleSheet("QLineEdit {color: white; background-color: rgb(255, 102, 102)}"); + } break; + } +} + +void TableBrowser::fetchedData() +{ + updateRecordsetLabel(); + + // Adjust row height to contents. This has to be done each time new data is fetched. + if(m_adjustRows) + ui->dataTable->resizeRowsToContents(); + + // Don't resize the columns more than once to fit their contents. This is necessary because the finishedFetch signal of the model + // is emitted for each loaded prefetch block and we want to avoid column resizes while scrolling down. + if(m_columnsResized) + return; + m_columnsResized = true; + + // Set column widths according to their contents but make sure they don't exceed a certain size + ui->dataTable->resizeColumnsToContents(); + for(int i = 0; i < m_model->columnCount(); i++) + { + if(ui->dataTable->columnWidth(i) > 300) + ui->dataTable->setColumnWidth(i, 300); + } +} diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/TableBrowser.h b/src/WBCLFZSystemModule/SqliteDBProcess/src/TableBrowser.h new file mode 100644 index 0000000..9d94aa6 --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/TableBrowser.h @@ -0,0 +1,197 @@ +#ifndef TABLEBROWSER_H +#define TABLEBROWSER_H + +#include "CondFormat.h" +#include "PlotDock.h" +#include "sql/Query.h" + +#include +#include +#include + +#include +#include + +class DBBrowserDB; +class ExtendedTableWidget; +class SqliteTableModel; + +class QAbstractItemModel; +class QIntValidator; + +namespace Ui { +class TableBrowser; +} + +struct BrowseDataTableSettings +{ + using CondFormatMap = QMap>; + sqlb::Query query; // NOTE: We only store the sort order in here (for now) + QMap columnWidths; + QMap filterValues; + CondFormatMap condFormats; + CondFormatMap rowIdFormats; + QMap displayFormats; + bool showRowid; + QString encoding; + QString plotXAxis; + QList> plotYAxes; + QString unlockViewPk; + QMap hiddenColumns; + std::vector globalFilters; + + BrowseDataTableSettings() : + showRowid(false), + unlockViewPk("_rowid_") + { + plotYAxes = {QMap(), QMap()}; + } + + friend QDataStream& operator>>(QDataStream& stream, BrowseDataTableSettings& object) + { + int sortOrderIndex, sortOrderMode; + stream >> sortOrderIndex; + stream >> sortOrderMode; + object.query.orderBy().emplace_back(sortOrderIndex, sortOrderMode == Qt::AscendingOrder ? sqlb::Ascending : sqlb::Descending); + stream >> object.columnWidths; + stream >> object.filterValues; + stream >> object.displayFormats; + stream >> object.showRowid; + stream >> object.encoding; + + // Versions pre 3.10.0 didn't store the following information in their project files. + // To be absolutely sure that nothing strange happens when we read past the stream for + // those cases, check for the end of the stream here. + if(stream.atEnd()) + return stream; + stream >> object.plotXAxis; + stream >> object.plotYAxes[0]; + stream >> object.unlockViewPk; + + // Project files from versions before 3.11.0 didn't have these fields + if(stream.atEnd()) + return stream; + stream >> object.hiddenColumns; + + return stream; + } +}; + +class TableBrowser : public QWidget +{ + Q_OBJECT + +public: + explicit TableBrowser(QWidget* parent = nullptr); + ~TableBrowser(); + void init(DBBrowserDB* _db); + void reset(); + + sqlb::ObjectIdentifier currentlyBrowsedTableName() const; + + QMap allSettings() const { return m_settings; } + BrowseDataTableSettings& settings(const sqlb::ObjectIdentifier& object); + void setSettings(const sqlb::ObjectIdentifier& table, const BrowseDataTableSettings& table_settings); + + void setStructure(QAbstractItemModel* model, const sqlb::ObjectIdentifier& old_table = sqlb::ObjectIdentifier{}); + + SqliteTableModel* model() { return m_model; } + + QModelIndex currentIndex() const; + + void setDefaultEncoding(const QString& encoding) { m_defaultEncoding = encoding; } + QString defaultEncoding() const { return m_defaultEncoding; } + +public slots: + void setEnabled(bool enable); + void updateTable(); + void clearFilters(); + void reloadSettings(); + void setCurrentTable(const sqlb::ObjectIdentifier& name); + void updateRecordsetLabel(); + void jumpToRow(const sqlb::ObjectIdentifier& table, std::string column, const QByteArray& value); + +signals: + void projectModified(); + void selectionChanged(QModelIndex index); + void selectionChangedByDoubleClick(QModelIndex index); + void statusMessageRequested(QString message); + void updatePlot(ExtendedTableWidget* tableWidget, SqliteTableModel* model, BrowseDataTableSettings* settings, bool keepOrResetSelection); + void createView(std::string sql); + void requestFileOpen(QString file); + +private slots: + void clear(); + void updateFilter(size_t column, const QString& value); + void addCondFormatFromFilter(size_t column, const QString& value); + void addCondFormat(bool isRowIdFormat, size_t column, const CondFormat& newCondFormat); + void clearAllCondFormats(size_t column); + void clearRowIdFormats(const QModelIndex index); + void editCondFormats(size_t column); + void applySettings(const BrowseDataTableSettings& storedData, bool skipFilters = false); + void enableEditing(bool enable_edit); + void showRowidColumn(bool show, bool skipFilters = false); + void unlockViewEditing(bool unlock, QString pk = QString()); + void hideColumns(int column = -1, bool hide = true); + void on_actionShowAllColumns_triggered(); + void updateInsertDeleteRecordButton(); + void duplicateRecord(int currentRow); + void headerClicked(int logicalindex); + void updateColumnWidth(int section, int /*old_size*/, int new_size); + void showDataColumnPopupMenu(const QPoint& pos); + void showRecordPopupMenu(const QPoint& pos); + void addRecord(); + void insertValues(); + void deleteRecord(); + void navigatePrevious(); + void navigateNext(); + void navigateBegin(); + void navigateEnd(); + void navigateGoto(); + void selectTableLine(int lineToSelect); + void on_actionClearFilters_triggered(); + void on_actionClearSorting_triggered(); + void editDisplayFormat(); + void exportFilteredTable(); + void saveFilterAsView(); + void setTableEncoding(bool forAllTables = false); + void setDefaultTableEncoding(); + void fetchedData(); + +private: + enum class ReplaceMode + { + NoReplace, + ReplaceNext, + ReplaceAll, + }; + void find(const QString& expr, bool forward, bool include_first = false, ReplaceMode replace = ReplaceMode::NoReplace); + +private: + Ui::TableBrowser* ui; + QIntValidator* gotoValidator; + QMenu* popupNewRecordMenu; + QMenu* popupSaveFilterAsMenu; + QMenu* popupHeaderMenu; + + DBBrowserDB* db; + + QAbstractItemModel* dbStructureModel; + + /// the table model used in the "Browse Data" page (re-used and + /// re-initialized when switching to another table) + SqliteTableModel* m_model; + + static QMap m_settings; // This is static, so settings are shared between instances + static QString m_defaultEncoding; + + Palette m_condFormatPalette; + bool m_adjustRows; + bool m_columnsResized; + + void modifySingleFormat(const bool isRowIdFormat, const QString& filter, const QModelIndex refIndex, + std::function changeFunction); + void modifyFormat(std::function changeFunction); +}; + +#endif diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/TableBrowser.ui b/src/WBCLFZSystemModule/SqliteDBProcess/src/TableBrowser.ui new file mode 100644 index 0000000..ea82b1f --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/TableBrowser.ui @@ -0,0 +1,1475 @@ + + + TableBrowser + + + + 0 + 0 + 695 + 400 + + + + Browse Data + + + + 1 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 2 + + + 2 + + + + + &Table: + + + comboBrowseTable + + + + + + + + 150 + 0 + + + + Select a table to browse data + + + Use this list to select a table to be displayed in the database view + + + 30 + + + QComboBox::AdjustToContents + + + + + + + Qt::ToolButtonIconOnly + + + + + + + + + + + + + + + + + + + + + + + Qt::Horizontal + + + QSizePolicy::MinimumExpanding + + + + 0 + 20 + + + + + + + + + + + 5 + + + 2 + + + 0 + + + 2 + + + 0 + + + + + + + + + 50 + 16777215 + + + + 1 + + + + + + + Qt::ToolButtonIconOnly + + + + + + + + + + + + + + + + + + + + + + + + true + + + This is the database table view. You can do the following actions: + - Start writing for editing inline the value. + - Double-click any record to edit its contents in the cell editor window. + - Alt+Del for deleting the cell content to NULL. + - Ctrl+" for duplicating the current record. + - Ctrl+' for copying the value from the cell above. + - Standard selection and copy/paste operations. + + + QAbstractItemView::NoEditTriggers + + + QAbstractItemView::DragDrop + + + Qt::CopyAction + + + QAbstractItemView::ContiguousSelection + + + + + + + + 16777215 + 62 + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + 1 + + + 1 + + + 1 + + + 1 + + + 1 + + + + + + 3 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Qt::DefaultContextMenu + + + Text pattern to find considering the checks in this frame + + + Find in table + + + true + + + + + + + Find previous match [Shift+F3] + + + Find previous match with wrapping + + + + :/icons/up:/icons/up + + + Shift+F3 + + + + + + + Find next match [Enter, F3] + + + Find next match with wrapping + + + + :/icons/down:/icons/down + + + F3 + + + + + + + The found pattern must match in letter case + + + Case Sensitive + + + + + + + The found pattern must be a whole word + + + Whole Cell + + + + + + + Interpret search pattern as a regular expression + + + <html><head/><body><p>When checked, the pattern to find is interpreted as a UNIX regular expression. See <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>.</p></body></html> + + + Regular Expression + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Close Find Bar + + + Close Find Bar + + + + :/icons/close:/icons/close + + + true + + + + + + + + + + + 3 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Qt::DefaultContextMenu + + + Text to replace with + + + Replace with + + + true + + + + + + + Replace next match + + + Replace + + + + + + + Replace all matches + + + Replace all + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + + 2 + + + 2 + + + 2 + + + 2 + + + + + false + + + <html><head/><body><p>Scroll to the beginning</p></body></html> + + + <html><head/><body><p>Clicking this button navigates to the beginning in the table view above.</p></body></html> + + + |< + + + + :/icons/resultset_first.png:/icons/resultset_first.png + + + + + + + false + + + Scroll one page upwards + + + <html><head/><body><p>Clicking this button navigates one page of records upwards in the table view above.</p></body></html> + + + < + + + + :/icons/resultset_previous.png:/icons/resultset_previous.png + + + + + + + 0 - 0 of 0 + + + + + + + false + + + Scroll one page downwards + + + <html><head/><body><p>Clicking this button navigates one page of records downwards in the table view above.</p></body></html> + + + > + + + + :/icons/run:/icons/run + + + + + + + false + + + Scroll to the end + + + <html><head/><body><p>Clicking this button navigates up to the end in the table view above.</p></body></html> + + + >| + + + + :/icons/run_line:/icons/run_line + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + <html><head/><body><p>Click here to jump to the specified record</p></body></html> + + + <html><head/><body><p>This button is used to navigate to the record number specified in the Go to area.</p></body></html> + + + Go to: + + + + + + + Enter record number to browse + + + Type a record number in this area and click the Go to: button to display the record in the database view + + + 1 + + + + + + + + + true + + + Show rowid column + + + Toggle the visibility of the rowid column + + + + + true + + + Unlock view editing + + + This unlocks the current view for editing. However, you will need appropriate triggers for editing. + + + + + Edit display format + + + Edit the display format of the data in this column + + + + + + :/icons/add_record:/icons/add_record + + + New Record + + + Insert a new record in the current table + + + Insert a new record in the current table + + + <html><head/><body><p>This button creates a new record in the database. Hold the mouse button to open a pop-up menu of different options:</p><ul><li><span style=" font-weight:600;">New Record</span>: insert a new record with default values in the database.</li><li><span style=" font-weight:600;">Insert Values...</span>: open a dialog for entering values before they are inserted in the database. This allows to enter values acomplishing the different constraints. This dialog is also open if the <span style=" font-weight:600;">New Record</span> option fails due to these constraints.</li></ul></body></html> + + + + + + :/icons/delete_record:/icons/delete_record + + + Delete Record + + + Delete the current record + + + This button deletes the record or records currently selected in the table + + + This button deletes the record or records currently selected in the table + + + + + + :/icons/add_record:/icons/add_record + + + New Record + + + Insert new record using default values in browsed table + + + Insert new record using default values in browsed table + + + + + Insert Values... + + + Open a dialog for inserting values in a new record + + + Open a dialog for inserting values in a new record + + + + + Export to &CSV + + + Export the filtered data to CSV + + + Export the filtered data to CSV + + + This button exports the data of the browsed table as currently displayed (after filters, display formats and order column) as a CSV file. + + + + + Save as &view + + + Save the current filter, sort column and display formats as a view + + + Save the current filter, sort column and display formats as a view + + + This button saves the current setting of the browsed table (filters, display formats and order column) as an SQL view that you can later browse or use in SQL statements. + + + + + + :/icons/save_table:/icons/save_table + + + Save Table As... + + + Save the table as currently displayed + + + Save the table as currently displayed + + + <html><head/><body><p>This popup menu provides the following options applying to the currently browsed and filtered table:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Export to CSV: this option exports the data of the browsed table as currently displayed (after filters, display formats and order column) to a CSV file.</li><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Save as view: this option saves the current setting of the browsed table (filters, display formats and order column) as an SQL view that you can later browse or use in SQL statements.</li></ul></body></html> + + + + + Hide column(s) + + + Hide selected column(s) + + + + + Show all columns + + + Show all columns that were hidden + + + + + Set encoding + + + Change the encoding of the text in the table cells + + + + + Set encoding for all tables + + + Change the default encoding assumed for all tables in the database + + + + + + :/icons/clear_filters:/icons/clear_filters + + + Clear Filters + + + Clear all filters + + + This button clears all the filters set in the header input fields for the currently browsed table. + + + This button clears all the filters set in the header input fields for the currently browsed table. + + + + + + :/icons/clear_sorting:/icons/clear_sorting + + + Clear Sorting + + + Reset the order of rows to the default + + + This button clears the sorting columns specified for the currently browsed table and returns to the default order. + + + This button clears the sorting columns specified for the currently browsed table and returns to the default order. + + + + + + :/icons/print:/icons/print + + + Print + + + Print currently browsed table data + + + + + + Print currently browsed table data. Print selection if more than one cell is selected. + + + Ctrl+P + + + Qt::WidgetShortcut + + + + + + :/icons/refresh:/icons/refresh + + + Refresh + + + Refresh the data in the selected table + + + This button refreshes the data in the currently selected table. + + + F5 + + + Qt::WidgetShortcut + + + + + true + + + + :/icons/find:/icons/find + + + Find in cells + + + Open the find tool bar which allows you to search for values in the table view below. + + + + + true + + + + :/icons/text_bold.png:/icons/text_bold.png + + + Bold + + + Bold + + + Ctrl+B + + + + + true + + + + :/icons/text_italic.png:/icons/text_italic.png + + + Italic + + + Italic + + + + + true + + + + :/icons/text_underline.png:/icons/text_underline.png + + + Underline + + + Underline + + + Ctrl+U + + + + + true + + + + :/icons/text_align_right.png:/icons/text_align_right.png + + + Align Right + + + Align Right + + + + + true + + + + :/icons/text_align_left.png:/icons/text_align_left.png + + + Align Left + + + Align Left + + + + + true + + + + :/icons/text_align_center.png:/icons/text_align_center.png + + + Center Horizontally + + + Center Horizontally + + + + + true + + + + :/icons/text_align_justify.png:/icons/text_align_justify.png + + + Justify + + + Justify + + + + + + :/icons/edit_cond_formats:/icons/edit_cond_formats + + + Edit Conditional Formats... + + + Edit Conditional Formats... + + + Edit conditional formats for the current column + + + + + + :/icons/clear_cond_formats:/icons/clear_cond_formats + + + Clear Format + + + Clear All Formats + + + Clear all cell formatting from selected cells and all conditional formats from selected columns + + + Clear all cell formatting from selected cells and all conditional formats from selected columns + + + + + + :/icons/foreground_color:/icons/foreground_color + + + Font Color + + + Font Color + + + + + + :/icons/background_color:/icons/background_color + + + Background Color + + + Background Color + + + + + true + + + + :/icons/cond_formats:/icons/cond_formats + + + Toggle Format Toolbar + + + Show/hide format toolbar + + + This button shows or hides the formatting toolbar of the Data Browser + + + This button shows or hides the formatting toolbar of the Data Browser + + + + + Select column + + + Ctrl+Space + + + + + true + + + + :/icons/text_replace:/icons/text_replace + + + Replace + + + Replace text in cells + + + + + + ExtendedTableWidget + QTableWidget +
ExtendedTableWidget.h
+ + foreignKeyClicked(QString,QString,QByteArray) + foreignKeyClicked(sqlb::ObjectIdentifier,QString,QByteArray) + +
+ + FilterLineEdit + QLineEdit +
FilterLineEdit.h
+
+
+ + comboBrowseTable + editGlobalFilter + fontComboBox + fontSizeBox + dataTable + editFindExpression + editReplaceExpression + buttonFindPrevious + buttonFindNext + checkFindCaseSensitive + checkFindWholeCell + checkFindRegEx + buttonFindClose + buttonReplaceNext + buttonReplaceAll + buttonBegin + buttonPrevious + buttonNext + buttonEnd + buttonGoto + editGoto + + + + + + + comboBrowseTable + activated(QString) + TableBrowser + updateTable() + + + 159 + 31 + + + 399 + 299 + + + + + buttonPrevious + clicked() + TableBrowser + navigatePrevious() + + + 55 + 395 + + + 399 + 299 + + + + + buttonNext + clicked() + TableBrowser + navigateNext() + + + 140 + 395 + + + 399 + 299 + + + + + buttonGoto + clicked() + TableBrowser + navigateGoto() + + + 452 + 397 + + + 399 + 299 + + + + + editGoto + returnPressed() + TableBrowser + navigateGoto() + + + 648 + 397 + + + 399 + 299 + + + + + buttonEnd + clicked() + TableBrowser + navigateEnd() + + + 170 + 395 + + + 499 + 314 + + + + + buttonBegin + clicked() + TableBrowser + navigateBegin() + + + 25 + 395 + + + 499 + 314 + + + + + dataTable + foreignKeyClicked(sqlb::ObjectIdentifier,std::string,QByteArray) + TableBrowser + jumpToRow(sqlb::ObjectIdentifier,std::string,QByteArray) + + + 70 + 242 + + + 518 + 314 + + + + + actionShowRowidColumn + triggered(bool) + TableBrowser + showRowidColumn(bool) + + + -1 + -1 + + + 518 + 314 + + + + + actionUnlockViewEditing + toggled(bool) + TableBrowser + unlockViewEditing(bool) + + + -1 + -1 + + + 518 + 314 + + + + + actionBrowseTableEditDisplayFormat + triggered() + TableBrowser + editDisplayFormat() + + + -1 + -1 + + + 518 + 314 + + + + + actionNewRecord + triggered() + TableBrowser + addRecord() + + + -1 + -1 + + + 518 + 314 + + + + + actionDeleteRecord + triggered() + TableBrowser + deleteRecord() + + + -1 + -1 + + + 399 + 299 + + + + + newRecordAction + triggered() + TableBrowser + addRecord() + + + -1 + -1 + + + 518 + 314 + + + + + insertValuesAction + triggered() + TableBrowser + insertValues() + + + -1 + -1 + + + 20 + 20 + + + + + actionFilteredTableExportCsv + triggered() + TableBrowser + exportFilteredTable() + + + -1 + -1 + + + 518 + 314 + + + + + actionFilterSaveAsView + triggered() + TableBrowser + saveFilterAsView() + + + -1 + -1 + + + 518 + 314 + + + + + actionSetTableEncoding + triggered() + TableBrowser + setTableEncoding() + + + -1 + -1 + + + 518 + 314 + + + + + actionSetAllTablesEncoding + triggered() + TableBrowser + setDefaultTableEncoding() + + + -1 + -1 + + + 518 + 314 + + + + + actionHideColumns + triggered() + TableBrowser + hideColumns() + + + -1 + -1 + + + 518 + 314 + + + + + actionRefresh + triggered() + TableBrowser + updateTable() + + + -1 + -1 + + + 518 + 314 + + + + + actionPrintTable + triggered() + dataTable + openPrintDialog() + + + -1 + -1 + + + 326 + 291 + + + + + + updateTable() + selectionChanged(QModelIndex) + navigatePrevious() + navigateNext() + navigateBegin() + navigateEnd() + navigateGoto() + jumpToRow(sqlb::ObjectIdentifier,std::string,QByteArray) + showRowidColumn(bool) + unlockViewEditing(bool) + editDisplayFormat() + addRecord() + deleteRecord() + insertValues() + exportFilteredTable + saveFilterAsView + setDefaultTableEncoding() + hideColumns() + setTableEncoding() + +
diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/VacuumDialog.cpp b/src/WBCLFZSystemModule/SqliteDBProcess/src/VacuumDialog.cpp new file mode 100644 index 0000000..c2a622a --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/VacuumDialog.cpp @@ -0,0 +1,53 @@ +#include "VacuumDialog.h" +#include "ui_VacuumDialog.h" +#include "sqlitedb.h" + +#include + +VacuumDialog::VacuumDialog(DBBrowserDB* _db, QWidget* parent) : + QDialog(parent), + ui(new Ui::VacuumDialog), + db(_db) +{ + // Create UI + ui->setupUi(this); + + // Show warning if DB is dirty + ui->labelSavepointWarning->setVisible(db->getDirty()); + + // Populate list of objects to compact. We just support vacuuming the different schemas here. + for(const auto& it : db->schemata) + { + QTreeWidgetItem* item = new QTreeWidgetItem(ui->treeDatabases); + item->setText(0, QString::fromStdString(it.first)); + item->setIcon(0, QIcon(QString(":icons/database"))); + ui->treeDatabases->addTopLevelItem(item); + } + + // Select the first item which should always be the main schema + ui->treeDatabases->setCurrentItem(ui->treeDatabases->topLevelItem(0)); +} + +VacuumDialog::~VacuumDialog() +{ + delete ui; +} + +void VacuumDialog::accept() +{ + if(ui->treeDatabases->selectedItems().count() == 0) + return QDialog::reject(); + + QApplication::setOverrideCursor(Qt::WaitCursor); + + // Commit all changes first + db->releaseAllSavepoints(); + + // Loop through all selected databases and vacuum them individually + QList selection = ui->treeDatabases->selectedItems(); + for(const QTreeWidgetItem* item : selection) + db->executeSQL("VACUUM " + sqlb::escapeIdentifier(item->text(0).toStdString()), false); + + QApplication::restoreOverrideCursor(); + QDialog::accept(); +} diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/VacuumDialog.h b/src/WBCLFZSystemModule/SqliteDBProcess/src/VacuumDialog.h new file mode 100644 index 0000000..3248388 --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/VacuumDialog.h @@ -0,0 +1,28 @@ +#ifndef VACUUMDIALOG_H +#define VACUUMDIALOG_H + +#include + +namespace Ui { +class VacuumDialog; +} + +class DBBrowserDB; + +class VacuumDialog : public QDialog +{ + Q_OBJECT + +public: + explicit VacuumDialog(DBBrowserDB* _db, QWidget* parent = nullptr); + ~VacuumDialog() override; + +private: + Ui::VacuumDialog* ui; + DBBrowserDB* db; + +protected slots: + void accept() override; +}; + +#endif diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/VacuumDialog.ui b/src/WBCLFZSystemModule/SqliteDBProcess/src/VacuumDialog.ui new file mode 100644 index 0000000..e1bf215 --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/VacuumDialog.ui @@ -0,0 +1,127 @@ + + + VacuumDialog + + + + 0 + 0 + 475 + 439 + + + + Compact Database + + + + + + + 75 + true + + + + Warning: Compacting the database will commit all of your changes. + + + true + + + 5 + + + + + + + Please select the databases to co&mpact: + + + treeDatabases + + + + + + + QAbstractItemView::NoEditTriggers + + + false + + + QAbstractItemView::ExtendedSelection + + + false + + + false + + + false + + + false + + + + 1 + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + treeDatabases + buttonBox + + + + + buttonBox + accepted() + VacuumDialog + accept() + + + 222 + 374 + + + 157 + 274 + + + + + buttonBox + rejected() + VacuumDialog + reject() + + + 290 + 380 + + + 286 + 274 + + + + + diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/app.plist b/src/WBCLFZSystemModule/SqliteDBProcess/src/app.plist new file mode 100644 index 0000000..03023c3 --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/app.plist @@ -0,0 +1,82 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleDocumentTypes + + + CFBundleTypeExtensions + + db + db3 + sqlite + sqlite3 + + CFBundleTypeName + Database Document + CFBundleTypeOSTypes + + **** + + CFBundleTypeRole + Editor + + + CFBundleTypeExtensions + + sqbpro + + CFBundleTypeName + DB Browser for SQLite Project + CFBundleTypeOSTypes + + **** + + CFBundleTypeRole + Editor + + + CFBundleTypeExtensions + + * + + CFBundleTypeName + Other Document Type + CFBundleTypeOSTypes + + **** + + CFBundleTypeRole + Editor + + + CFBundleExecutable + @EXECUTABLE@ + CFBundleGetInfoString + 3.12.2 + CFBundleIconFile + @ICON@ + CFBundleIdentifier + net.sourceforge.sqlitebrowser + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + DB Browser for SQLite + CFBundlePackageType + APPL + CFBundleShortVersionString + 3.12.2 + CFBundleSignature + SqLB + CFBundleVersion + 3.12.2 + NSPrincipalClass + NSApplication + NSHighResolutionCapable + + NSSupportsAutomaticGraphicsSwitching + + + diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/csvparser.cpp b/src/WBCLFZSystemModule/SqliteDBProcess/src/csvparser.cpp new file mode 100644 index 0000000..212a053 --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/csvparser.cpp @@ -0,0 +1,324 @@ +#include "csvparser.h" + +#include + +CSVParser::CSVParser(bool trimfields, char32_t fieldseparator, char32_t quotechar) + : m_bTrimFields(trimfields) + , m_iNumExtraBytesFieldSeparator(0) + , m_iNumExtraBytesQuoteChar(0) + , m_pCSVProgress(nullptr) + , m_nBufferSize(4096) +{ + for(int i=0;i<4;i++) + { + m_cFieldSeparator[i] = static_cast((fieldseparator >> i*8) & 0xFF); + m_cQuoteChar[i] = static_cast((quotechar >> i*8) & 0xFF); + + if(i && m_cFieldSeparator[i]) + m_iNumExtraBytesFieldSeparator = i; + if(i && m_cQuoteChar[i]) + m_iNumExtraBytesQuoteChar = i; + } +} + +CSVParser::~CSVParser() +{ + delete m_pCSVProgress; +} + +namespace { +// This function adds a character to an existing field structure. If necessary, it extends the buffer size. +inline void addChar(CSVField* field, char c) +{ + // Increase buffer size if it is too small + if(field->buffer_length >= field->buffer_max_length) + { + field->buffer_max_length += 64; + field->buffer = static_cast(realloc(field->buffer, field->buffer_max_length)); + } + + // Add char to the end of the buffer and increase length by one + field->buffer[field->buffer_length++] = c; +} + +// This function increases the size of the field list of an existing row. However, it only does so if the field list is currently full. +inline void increaseRowSize(CSVRow& r) +{ + // Check if field list is full + if(r.num_fields >= r.max_num_fields) + { + // Increase field list size + r.max_num_fields += 5; + r.fields = static_cast(realloc(r.fields, r.max_num_fields*sizeof(CSVField))); + + // Initialise the newly created field structures + for(size_t i=r.num_fields;idata = field->buffer; + field->data_length = field->buffer_length; + + // If we have to trim the field, do this by manipulating the data start and data length variables + if(trim) + { + // Check for trailing spaces and omit them + while(field->data_length && isspace(*field->data)) + { + field->data++; + field->data_length--; + } + + // Check for pending spaces and omit them + while(field->data_length && isspace(field->data[field->data_length-1])) + field->data_length--; + } + + // We assume here that the field object has been constructed in-place. So all we need to do for adding it to the row structure + // is increasing the field count by one to make sure the newly constructed field object is used. + r.num_fields++; + + // Clear field buffer for next use + field->buffer_length = 0; + + // Increase field list size if it is too small + increaseRowSize(r); + + // Return pointer to the next field + return &r.fields[r.num_fields]; +} + +// This function takes a parsed CSV row and hands it back to the caller of the CSV parser. It returns a null pointer if the parsing should be +// aborted, otherwise it returns a pointer to a new field object that can be used for storing the contents of the first field of the next row. +inline CSVField* addRow(CSVParser::csvRowFunction& f, CSVRow& r, size_t& rowCount) +{ + // Call row function + if(!f(rowCount, r)) + return nullptr; + + // Reset the field list by setting the field count to 0. No need to deconstruct anything else. + r.num_fields = 0; + + // Increase row count by one, as we're now starting to parse the next row + rowCount++; + + // Return a pointer to the first field in the row object because we're starting with the first field of the next row now + return r.fields; +} +} + +CSVParser::ParserResult CSVParser::parse(csvRowFunction insertFunction, QTextStream& stream, size_t nMaxRecords) +{ + ParseStates state = StateNormal; // State of the parser + QByteArray sBuffer; // Buffer for reading the file + CSVRow record; // Buffer for parsing the current row + size_t parsedRows = 0; // Number of rows parsed so far + CSVField* field; // Buffer for parsing the current field + + if(m_pCSVProgress) + m_pCSVProgress->start(); + + // Initialise row buffer and get pointer to the first field + record = { nullptr, 0, 0 }; + increaseRowSize(record); + field = record.fields; + + // Make sure all buffers are freed when we're done here + class FieldBufferDealloc + { + public: + explicit FieldBufferDealloc(CSVRow& row) : m_row(row) {} + ~FieldBufferDealloc() + { + for(size_t i=0;i 0 && parsedRows >= nMaxRecords) + return ParserResult::ParserResultSuccess; + } + + if(m_pCSVProgress && parsedRows % 100 == 0) + { + if(!m_pCSVProgress->update(bufferPos)) + return ParserResult::ParserResultCancelled; + } + } + + if(record.num_fields || record.fields->buffer_length) + { + addColumn(record, field, m_bTrimFields); + + if(!(field = addRow(insertFunction, record, parsedRows))) + return ParserResult::ParserResultError; + } + + if(m_pCSVProgress) + m_pCSVProgress->end(); + + // Check if we are in StateNormal or StateEndQuote state. The first is what we should be in for unquoted data and all files which + // end with a line break. The latter is what we are in for quoted data with no final line break. + return (state == StateNormal || state == StateEndQuote) ? ParserResult::ParserResultSuccess : ParserResult::ParserResultError; +} + +bool CSVParser::look_ahead(QTextStream& stream, QByteArray& sBuffer, const char** it, const char** sBufferEnd, char expected) +{ + // look ahead for next byte + auto nit = *it + 1; + + // In order to check what the next byte is we must make sure that that byte is already loaded. Assume we're at an m_nBufferSize + // boundary but not at the end of the file when we hit a \r character. Now we're going to be at the end of the sBuffer string + // because of the m_nBufferSize boundary. But this means that the following check won't work properly because we can't check the + // next byte when we really should be able to do so because there's more data coming. To fix this we'll check for this particular + // case and, if this is what's happening, we'll just load an extra byte. + if(nit == *sBufferEnd && !stream.atEnd()) + { + // Load one more byte + sBuffer.append(stream.read(1)); + *sBufferEnd = sBuffer.constEnd(); + + // Restore both iterators. sBufferEnd points to the imagined char after the last one in the string. So the extra byte we've + // just loaded is the one before that, i.e. the actual last one, and the original last char is the one before that. + *it = *sBufferEnd - 2; + nit = *sBufferEnd - 1; + } + + // Check whether there actually is one more byte and it is the expected one + return nit != *sBufferEnd && *nit == expected; +} diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/csvparser.h b/src/WBCLFZSystemModule/SqliteDBProcess/src/csvparser.h new file mode 100644 index 0000000..8687ff9 --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/csvparser.h @@ -0,0 +1,99 @@ +#ifndef CSVPARSER_H +#define CSVPARSER_H + +#include +#include +#include + +class QByteArray; +class QTextStream; + +/*! + * \brief The CSVProgress class + * + * This is an abstract class, an implementation of which you can pass to the CSVParser to get progress updates. + */ +class CSVProgress +{ +public: + virtual ~CSVProgress() = default; + + virtual void start() = 0; + virtual bool update(int64_t pos) = 0; + virtual void end() = 0; +}; + +/* + * This structure represents one parsed column in a CSV row + */ +struct CSVField +{ + // These variables are used internally by the parser. Usually there should be no need to access them from outside the parser + char* buffer; // Start of the field buffer + uint64_t buffer_length; // Current length of the buffer content. The content is NOT null-terminated + uint64_t buffer_max_length; // Size of the entire buffer + + // These variables point to the parsed contents of the field and can be directly passed to SQLite functions + char* data; // Pointer to the start of the field contents + uint64_t data_length; // Length of the field contents +}; + +/* + * This structure holds all columns of a single parsed CSV row + */ +struct CSVRow +{ + CSVField* fields; // Pointer to the field list/the first element in the list + size_t num_fields; // Number of fields in the row + size_t max_num_fields; // Size of the field list. Used internally by the parser only +}; + +class CSVParser +{ +public: + using csvRowFunction = std::function; + + CSVParser(bool trimfields = true, char32_t fieldseparator = ',', char32_t quotechar = '"'); + ~CSVParser(); + + enum ParserResult + { + ParserResultSuccess, + ParserResultCancelled, + ParserResultError + }; + + /*! + * \brief parse the given stream + * @param insertFunction A function pointer that is called for each parsed row. It is passed two parameters, the row number and a list of all parsed columns + * in the row. The called function may return false if an error ocurred to stop the import process. Otherwise it should return true. + * \param stream Stream with the CSV parser + * \param nMaxRecords Max records too read, 0 if unlimited + * \return ParserResult value that indicated whether action finished normally, was cancelled or errored. + */ + ParserResult parse(csvRowFunction insertFunction, QTextStream& stream, size_t nMaxRecords = 0); + + void setCSVProgress(CSVProgress* csvp) { m_pCSVProgress = csvp; } + +private: + enum ParseStates + { + StateNormal, + StateInQuote, + StateEndQuote + }; + +private: + bool m_bTrimFields; + char m_cFieldSeparator[4]; + char m_cQuoteChar[4]; + int m_iNumExtraBytesFieldSeparator; + int m_iNumExtraBytesQuoteChar; + CSVProgress* m_pCSVProgress; + + int64_t m_nBufferSize; //! internal buffer read size + + bool look_ahead(QTextStream& stream, QByteArray& sBuffer, const char** it, const char** sBufferEnd, char expected); +}; + +#endif diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/docktextedit.cpp b/src/WBCLFZSystemModule/SqliteDBProcess/src/docktextedit.cpp new file mode 100644 index 0000000..39c40f9 --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/docktextedit.cpp @@ -0,0 +1,115 @@ +#include "docktextedit.h" +#include "Settings.h" + +#include +#include +#include + +QsciLexerJSON* DockTextEdit::jsonLexer = nullptr; +QsciLexerXML* DockTextEdit::xmlLexer = nullptr; + +DockTextEdit::DockTextEdit(QWidget* parent) : + ExtendedScintilla(parent) +{ + // Create lexer objects if not done yet + if(jsonLexer == nullptr) + jsonLexer = new QsciLexerJSON(this); + if(xmlLexer == nullptr) + xmlLexer = new QsciLexerXML(this); + + // Set plain text as default + setLanguage(PlainText); + + jsonLexer->setFoldCompact(false); + jsonLexer->setHighlightComments(true); + + // Do rest of initialisation + reloadSettings(); +} + +void DockTextEdit::reloadSettings() +{ + // Set the parent settings for both lexers + reloadLexerSettings(jsonLexer); + reloadLexerSettings(xmlLexer); + + // Set the databrowser font for the plain text editor. + plainTextFont = QFont(Settings::getValue("databrowser", "font").toString()); + plainTextFont.setPointSize(Settings::getValue("databrowser", "fontsize").toInt()); + setFont(plainTextFont); + + setupSyntaxHighlightingFormat(jsonLexer, "comment", QsciLexerJSON::CommentLine); + setupSyntaxHighlightingFormat(jsonLexer, "comment", QsciLexerJSON::CommentBlock); + setupSyntaxHighlightingFormat(jsonLexer, "keyword", QsciLexerJSON::Keyword); + setupSyntaxHighlightingFormat(jsonLexer, "keyword", QsciLexerJSON::KeywordLD); + setupSyntaxHighlightingFormat(jsonLexer, "function", QsciLexerJSON::Operator); + setupSyntaxHighlightingFormat(jsonLexer, "string", QsciLexerJSON::String); + setupSyntaxHighlightingFormat(jsonLexer, "table", QsciLexerJSON::Number); + setupSyntaxHighlightingFormat(jsonLexer, "identifier", QsciLexerJSON::Property); + + // The default style for invalid JSON or unclosed strings uses red + // background and white foreground, but the current line has + // precedence, so it is by default white over gray. We change the + // default to something more readable for the current line at + // invalid JSON. + QColor stringColor = QColor(Settings::getValue("syntaxhighlighter", "string_colour").toString()); + jsonLexer->setColor(stringColor, QsciLexerJSON::Error); + jsonLexer->setColor(stringColor, QsciLexerJSON::UnclosedString); + QFont errorFont(Settings::getValue("editor", "font").toString()); + errorFont.setPointSize(Settings::getValue("editor", "fontsize").toInt()); + errorFont.setItalic(true); + jsonLexer->setFont(errorFont, QsciLexerJSON::Error); + jsonLexer->setFont(errorFont, QsciLexerJSON::UnclosedString); + jsonLexer->setPaper(jsonLexer->defaultPaper(QsciLexerJSON::String), QsciLexerJSON::Error); + jsonLexer->setPaper(jsonLexer->defaultPaper(QsciLexerJSON::String), QsciLexerJSON::UnclosedString); + + xmlLexer->setColor(QColor(Settings::getValue("syntaxhighlighter", "foreground_colour").toString())); + setupSyntaxHighlightingFormat(xmlLexer, "comment", QsciLexerHTML::HTMLComment); + setupSyntaxHighlightingFormat(xmlLexer, "keyword", QsciLexerHTML::Tag); + setupSyntaxHighlightingFormat(xmlLexer, "keyword", QsciLexerHTML::XMLTagEnd); + setupSyntaxHighlightingFormat(xmlLexer, "keyword", QsciLexerHTML::XMLStart); + setupSyntaxHighlightingFormat(xmlLexer, "keyword", QsciLexerHTML::XMLEnd); + setupSyntaxHighlightingFormat(xmlLexer, "string", QsciLexerHTML::HTMLDoubleQuotedString); + setupSyntaxHighlightingFormat(xmlLexer, "string", QsciLexerHTML::HTMLSingleQuotedString); + setupSyntaxHighlightingFormat(xmlLexer, "table", QsciLexerHTML::HTMLNumber); + setupSyntaxHighlightingFormat(xmlLexer, "identifier", QsciLexerHTML::Attribute); +} + +void DockTextEdit::setLanguage(Language lang) +{ + m_language = lang; + switch (lang) { + case PlainText: { + setLexer(nullptr); + setFolding(QsciScintilla::NoFoldStyle); + // This appears to be reset by setLexer + setFont(plainTextFont); + break; + } + case JSON: + setLexer(jsonLexer); + setFolding(QsciScintilla::BoxedTreeFoldStyle); + break; + case XML: + setLexer(xmlLexer); + setFolding(QsciScintilla::BoxedTreeFoldStyle); + break; + } +} + +void DockTextEdit::setTextInMargin(const QString& text) +{ + clearMarginText(); + setMarginType(0, QsciScintilla::TextMargin); + setMarginText(0, text, QsciStyle(QsciScintillaBase::STYLE_LINENUMBER)); + setMarginWidth(0, text); + reloadCommonSettings(); +} + +void DockTextEdit::clearTextInMargin() +{ + clearMarginText(); + setMarginLineNumbers(0, true); + reloadCommonSettings(); + emit linesChanged(); +} diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/docktextedit.h b/src/WBCLFZSystemModule/SqliteDBProcess/src/docktextedit.h new file mode 100644 index 0000000..c5d3236 --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/docktextedit.h @@ -0,0 +1,48 @@ +#ifndef DOCKTEXTEDIT_H +#define DOCKTEXTEDIT_H + +#include "ExtendedScintilla.h" + +class QsciLexerJSON; +class QsciLexerXML; + +/** + * @brief The DockTextEdit class + * This class is based on our Extended QScintilla widget + */ +class DockTextEdit : public ExtendedScintilla +{ + Q_OBJECT + +public: + explicit DockTextEdit(QWidget *parent = nullptr); + + // Enumeration of supported languages + enum Language + { + PlainText, + JSON, + XML + }; + + void setLanguage(Language lang); + Language language() const { return m_language; } + + // Disables the line-number margin and sets this text in the first line. + void setTextInMargin(const QString& text); + + // Resets margin to their original line-number mode + void clearTextInMargin(); + +public slots: + void reloadSettings(); + +protected: + static QsciLexerJSON* jsonLexer; + static QsciLexerXML* xmlLexer; +private: + Language m_language; + QFont plainTextFont; +}; + +#endif diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/extensions/extension-formats.c b/src/WBCLFZSystemModule/SqliteDBProcess/src/extensions/extension-formats.c new file mode 100644 index 0000000..53306b1 --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/extensions/extension-formats.c @@ -0,0 +1,971 @@ +/*** Extension-formats + * + * This file adds the following file format support to SQLite. + * + * Plist - An XML like encoding + * Base64 - Standard binary to text conversion + * + * Compile using: + * + * gcc -g -fPIC -shared extension-formats.c -o libsqlite-formats.so + */ + +#include +#include +#include +#include +#include +#include +#include + +#define COMPILE_SQLITE_EXTENSIONS_AS_LOADABLE_MODULE 1 +#include "sqlite3ext.h" +SQLITE_EXTENSION_INIT1 + +#define INDENT_INCREMENT 4 + +#define ERROR_NONE 0 +#define ERROR_INSUFFICIENT_MEMORY 1 +#define ERROR_INVALID_HEADER 2 +#define ERROR_INVALID_TRAILER 3 +#define ERROR_INVALID_OFFSET 4 +#define ERROR_INVALID_OBJECT_LENGTH 5 +#define ERROR_INVALID_REFERENCE 6 +#define ERROR_INVALID_CHARACTER 7 + +typedef struct KEY { + struct OBJECT *key; + struct OBJECT *value; +} KEY; + +typedef struct OBJECT { + int type; + int length; + union { + time_t date; + double real; + long integer; + unsigned long uid; + unsigned char binary[1]; + char text[1]; + short int utf16[1]; + int refs[1]; + KEY keys[1]; + struct OBJECT *objects[1]; + } data; +} OBJECT; + +typedef struct CONFIG { + int bytesPerOffset; + int bytesPerReference; + int objectCount; + int rootObjectReference; + int offsetTableOffset; + size_t bufferLength; + size_t outputBufferLength; + size_t outputBufferIn; + long *offsetTable; + unsigned char *buffer; + unsigned char *outputBuffer; +} CONFIG; + +int createObject(int type, int length, int extra, OBJECT **ptr2); +int readObject(CONFIG *cfg, long offset, OBJECT **ptr2); + +static int indent = 2; + +int outputText(CONFIG *cfg, const char *text) +{ + size_t textLength = strlen(text); + size_t availableSpace = cfg->outputBufferLength - cfg->outputBufferIn; + while (textLength >= availableSpace) { + unsigned char *tmp = cfg->outputBuffer; + cfg->outputBufferLength += textLength + 1024; + cfg->outputBuffer = (unsigned char *)realloc(cfg->outputBuffer, cfg->outputBufferLength); + if (cfg->outputBuffer == NULL) { + if (tmp != NULL) + free(tmp); + return ERROR_INSUFFICIENT_MEMORY; + } + availableSpace = cfg->outputBufferLength - cfg->outputBufferIn; + } + strcpy((char *)(cfg->outputBuffer+cfg->outputBufferIn), text); + cfg->outputBufferIn += textLength; + return ERROR_NONE; +} + +int printWithIndent(CONFIG *cfg, const char *text, int newline) +{ + int err = ERROR_NONE; + char spaces[9] = " "; + int n = indent; + while ((n > 8) && (err == ERROR_NONE)) { + err = outputText(cfg, spaces); + n -= 8; + } + if ((n > 0) && (err == ERROR_NONE)) + err = outputText(cfg, spaces + 8 - n); + if (err == ERROR_NONE) + err = outputText(cfg, text); + if (newline && (err == ERROR_NONE)) + err = outputText(cfg, "\n"); + return err; +} + +int readHeader(CONFIG *cfg) +{ + if ((cfg->bufferLength < 40) || + (strncmp((const char *)(cfg->buffer), "bplist0", 7) != 0) || + ((cfg->buffer[7] != '0') && (cfg->buffer[7] != '1'))) + return ERROR_INVALID_HEADER; + return ERROR_NONE; +} + +int readTrailer(CONFIG *cfg) +{ + int i, j; + int objectCount = 0; + int rootObjectReference = 0; + int offsetTableOffset = 0; + unsigned char *ptr; + unsigned char *buffer = cfg->buffer + cfg->bufferLength - 32; + + // Extract the relevant fields + for (i=12; i < 16; i++) + objectCount = (objectCount << 8) + buffer[i]; + for (i=20; i < 24; i++) + rootObjectReference = (rootObjectReference << 8) + buffer[i]; + for (i=28; i < 32; i++) + offsetTableOffset = (offsetTableOffset << 8) + buffer[i]; + + // Populate the configurartion structure + cfg->bytesPerOffset = buffer[6]; + cfg->bytesPerReference = buffer[7]; + cfg->objectCount = objectCount; + cfg->rootObjectReference = rootObjectReference; + cfg->offsetTableOffset = offsetTableOffset; + cfg->offsetTable = (long *)malloc((size_t)objectCount * sizeof(long)); + if (cfg->offsetTable == NULL) + return ERROR_INSUFFICIENT_MEMORY; + ptr = cfg->buffer + offsetTableOffset; + for (i=0; i < objectCount; i++) { + long n = 0; + for (j=0; j < cfg->bytesPerOffset; j++) + n = (n << 8) | *(ptr++); + cfg->offsetTable[i] = n; + } + return ERROR_NONE; +} + +int createObject(int type, int length, int extra, OBJECT **ptr2) +{ + *ptr2 = NULL; + OBJECT *ptr = (OBJECT *)malloc(sizeof(OBJECT) + (size_t)extra); + if (ptr == NULL) + return ERROR_INSUFFICIENT_MEMORY; + ptr->type = type; + ptr->length = length; + *ptr2 = ptr; + return ERROR_NONE; +} + +long readInteger(unsigned char *ptr, int desc) +{ + long value = 0L; + int n = 1 << (desc & 0x03); + while (n--) + value = (value << 8) | (long)(*(ptr++)); + return value; +} + +unsigned long readUid(unsigned char *ptr, int desc) +{ + unsigned long value = 0L; + int n = 1 << (desc & 0x03); + while (n--) + value = (value << 8) | (unsigned long)(*(ptr++)); + return value; +} + +double readDouble(unsigned char *ptr, int desc) +{ + union { + double v; + float f[2]; + unsigned char b[8]; + } value; + int n = 1 << (desc & 0x03); + for (int i=0; i < n; i++) + value.b[7-i] = *(ptr++); + if (n == 4) + value.v = (double)(value.f[1]); + return value.v; +} + +int readArray(CONFIG *cfg, unsigned char *ptr, int type, int length, OBJECT **array2) +{ + int i; + long offset; + OBJECT *array; + int err = createObject(type, length, ((length-1) * (int)sizeof(OBJECT)), &array); + *array2 = NULL; + for (i=0; (i < length) && (err == ERROR_NONE); i++) { + offset = 0L; + for (int j=0; j < cfg->bytesPerReference; j++) + offset = (offset << 8) | (long)(*(ptr++)); + if (offset >= cfg->objectCount) + return ERROR_INVALID_REFERENCE; + offset = cfg->offsetTable[offset]; + err = readObject(cfg, offset, &(array->data.objects[i])); + } + if (err == ERROR_NONE) + *array2 = array; + return err; +} + +int readDictionary(CONFIG *cfg, unsigned char *ptr, int type, int length, OBJECT **dict2) +{ + int i; + long offset; + OBJECT *dict; + int err = createObject(type, length, ((length-1) * (int)sizeof(KEY)), &dict); + *dict2 = NULL; + if (err != ERROR_NONE) + return err; + for (i=0; (i < length) && (err == ERROR_NONE); i++) { + offset = 0L; + for (int j=0; j < cfg->bytesPerReference; j++) + offset = (offset << 8) | (long)(*(ptr++)); + if (offset >= cfg->objectCount) + return ERROR_INVALID_REFERENCE; + offset = cfg->offsetTable[offset]; + err = readObject(cfg, offset, &(dict->data.keys[i].key)); + } + for (i=0; (i < length) && (err == ERROR_NONE); i++) { + offset = 0L; + for (int j=0; j < cfg->bytesPerReference; j++) + offset = (offset << 8) | (long)(*(ptr++)); + if (offset >= cfg->objectCount) + return ERROR_INVALID_REFERENCE; + offset = cfg->offsetTable[offset]; + err = readObject(cfg, offset, &(dict->data.keys[i].value)); + } + if (err == ERROR_NONE) + *dict2 = dict; + return err; +} + +int readObject(CONFIG *cfg, long offset, OBJECT **ptr2) +{ + int i; + int length; + int type; + int err = ERROR_NONE; + OBJECT *obj; + unsigned char *ptr; + + *ptr2 = NULL; + if ((size_t)offset >= cfg->bufferLength) + return ERROR_INVALID_OFFSET; + ptr = cfg->buffer + offset; + type = *(ptr++); + length = (type & 0x0F); + type >>= 4; + if ((type != 0) && (length == 0x0F)) { + length = *(ptr++); + if ((length >> 4) != 0x01) + return ERROR_INVALID_OBJECT_LENGTH; + i = (int)readInteger(ptr, length); + ptr += (1 << (length & 0x03)); + length = i; + } + switch (type) { + case 0x00: // Singleton + err = createObject(type, length, 5, &obj); + if (err != ERROR_NONE) + return err; + switch(length) { + case 0: // NULL + strcpy(obj->data.text, ""); + break; + case 8: // False + strcpy(obj->data.text, ""); + break; + case 9: // True + strcpy(obj->data.text, ""); + break; + case 15: // Fill + strcpy(obj->data.text, ""); + break; + default: // Illegal + strcpy(obj->data.text, "***Error***"); + break; + } + break; + case 0x01: // Integer + err = createObject(type, length, 0, &obj); + if (err != ERROR_NONE) + return err; + obj->data.integer = readInteger(ptr, length); + break; + case 0x02: // Float + err = createObject(type, length, 0, &obj); + if (err != ERROR_NONE) + return err; + obj->data.real = readDouble(ptr, length); + break; + case 0x03: // Date in Elapsed seconds + err = createObject(type, length, 0, &obj); + if (err != ERROR_NONE) + return err; + obj->data.date = (time_t)readDouble(ptr, length); + break; + case 0x04: // binary data + err = createObject(type, length, length, &obj); + if (err != ERROR_NONE) + return err; + for (i=0; i < length; i++) + obj->data.binary[i] = *(ptr++); + break; + case 0x05: // ASCII string + err = createObject(type, length, length, &obj); + if (err != ERROR_NONE) + return err; + for (i=0; i < length; i++) + obj->data.text[i] = (char)*(ptr++); + obj->data.text[length] = '\0'; + break; + case 0x06: // UTF16 string + err = createObject(type, length, 2 * length, &obj); + if (err != ERROR_NONE) + return err; + for (i=0; i < length; i++) { + short int d = *(ptr++); + obj->data.utf16[i] = (short int)((d << 8) | *(ptr++)); + } + obj->data.utf16[length] = '\0'; + break; + case 0x08: // UID + err = createObject(type, length, 0, &obj); + if (err != ERROR_NONE) + return err; + obj->data.uid = readUid(ptr, length); + break; + case 0x0A: // Array + err = readArray(cfg, ptr, type, length, &obj); + break; + case 0x0D: // Dictionary + err = readDictionary(cfg, ptr, type, length, &obj); + break; + default: + fprintf(stderr, "Unknown object type: %d\n", type); + err = createObject(type, length, 0, &obj); + break; + } + if (err == ERROR_NONE) + *ptr2 = obj; + return err; +} + +void displayHex(CONFIG *cfg, int data) +{ + static int in = 0; + static char buffer[76]; + static long offset = 0L; + static char hex[] = "0123456789ABCDEF"; + char *tmp; + + // If -ve then flush buffer + if (data < 0) { + if (in > 0) { + tmp = buffer + in * 3 + 8 + 2 * (in / 8); + while (tmp < buffer+59) + *(tmp++) = ' '; + buffer[in+59] = '\0'; + printWithIndent(cfg, buffer, 1); + } + offset = 0L; + in = 0; + return; + } + + // If start of line add offset + if (in == 0) { + sprintf((char *)buffer, "%06lX ", offset); + offset += 16; + buffer[8] = '\0'; + } + + // Add Byte in hex + tmp = buffer + in * 3 + 8 + 2 * (in / 8); + *(tmp++) = hex[(data >> 4) & 0x0F]; + *(tmp++) = hex[data & 0x0F]; + *(tmp++) = ' '; + + // Add to character buffer + buffer[in+59] = (char)data; + + // Check if midpoint of buffer + if (++in == 8) { + *(tmp++) = '-'; + *(tmp++) = ' '; + } + + // Check if buffer full + if (in == 16) { + buffer[75] = '\0'; + printWithIndent(cfg, buffer, 1); + in = 0; + } + return; +} + +int displayObject(CONFIG *cfg, OBJECT *obj, int raw) +{ + char text[32]; + switch (obj->type) { + case 0x00: // Singleton + printWithIndent(cfg, obj->data.text, 1); + break; + case 0x01: // Integer + if (raw == 0) + printWithIndent(cfg, "", 0); + sprintf(text, "%ld", obj->data.integer); + outputText(cfg, text); + if (raw == 0) + outputText(cfg, "\n"); + break; + case 0x02: // Float + if (raw == 0) + printWithIndent(cfg, "", 0); + sprintf(text, "%f", obj->data.real); + outputText(cfg, text); + if (raw == 0) + outputText(cfg, "\n"); + break; + case 0x03: // Date + if (raw == 0) + printWithIndent(cfg, "", 0); + outputText(cfg, ctime(&(obj->data.date))); + if (raw == 0) + outputText(cfg, "\n"); + break; + case 0x04: // Binary data + if (raw == 0) + printWithIndent(cfg, "", 1); + indent += INDENT_INCREMENT; + for (int i=0; i < obj->length; i++) + displayHex(cfg, obj->data.binary[i]); + displayHex(cfg, -1); + indent -= INDENT_INCREMENT; + if (raw == 0) + printWithIndent(cfg, "", 1); + break; + case 0x05: // String + if (raw == 0) + printWithIndent(cfg, "", 0); + outputText(cfg, (obj->data.text)); + if (raw == 0) + outputText(cfg, "\n"); + break; + case 0x06: // UTF16 string + if (raw == 0) + printWithIndent(cfg, "", 1); + indent += INDENT_INCREMENT; + for (int i=0; i < obj->length; i++) + displayHex(cfg, obj->data.binary[i]); + displayHex(cfg, -1); + indent -= INDENT_INCREMENT; + if (raw == 0) + printWithIndent(cfg, "", 1); + break; + case 0x08: // UID + if (raw == 0) + printWithIndent(cfg, "", 0); + sprintf(text, "%lu", obj->data.uid); + outputText(cfg, text); + if (raw == 0) + outputText(cfg, "\n"); + break; + case 0x0A: // Array + printWithIndent(cfg, "", 1); + indent += INDENT_INCREMENT; + for (int i=0; i < obj->length; i++) + displayObject(cfg, obj->data.objects[i], 0); + indent -= INDENT_INCREMENT; + printWithIndent(cfg, "", 1); + break; + case 0x0D: // Dictionary + printWithIndent(cfg, "", 1); + indent += INDENT_INCREMENT; + for (int i=0; i < obj->length; i++) { + printWithIndent(cfg, "", 0); + displayObject(cfg, obj->data.keys[i].key, 1); + outputText(cfg, "\n"); + displayObject(cfg, obj->data.keys[i].value, 0); + } + indent -= INDENT_INCREMENT; + printWithIndent(cfg, "", 1); + break; + default: + sprintf(text, "Cannot display type: %d\n", obj->type); + outputText(cfg, text); + break; + } + return ERROR_NONE; +} + +int releaseObject(OBJECT *obj) +{ + int i; + switch (obj->type) { + case 0x00: // Singleton + case 0x01: // Int + case 0x02: // Float + case 0x03: // Date + case 0x04: // Binary + case 0x05: // ASCII + case 0x06: // UTF16 + case 0x08: // UID + break; + case 0x0A: // Array + for (i=0; i < obj->length; i++) + releaseObject(obj->data.objects[i]); + break; + case 0x0D: // Dictionary + for (i=0; i < obj->length; i++) { + releaseObject(obj->data.keys[i].key); + releaseObject(obj->data.keys[i].value); + } + break; + } + free(obj); + return ERROR_NONE; +} + +int parsePlist(char **result, const char *data, int dataLength) +{ + CONFIG cfg; + char *ptr; + OBJECT *obj; + int err = ERROR_NONE; + int version; + long offset; + long length; + char text[32]; + + // Determine the file size and save + cfg.buffer = (unsigned char *)data; + cfg.bufferLength = dataLength; + + // Preset the output buffer + cfg.outputBufferLength = 0; + cfg.outputBufferIn = 0; + cfg.outputBuffer = NULL; + + // Read the header + err = readHeader(&cfg); + if (err != ERROR_NONE) + return err; + version = (int)(cfg.buffer[7] - '0'); + + // Read the trailer + err = readTrailer(&cfg); + if (err != ERROR_NONE) + return err; // ERROR_INVALID_TRAILER; + + // Locate and read the root object + offset = cfg.offsetTable[cfg.rootObjectReference]; + err = readObject(&cfg, offset, &obj); + + // If no error display the root object and hence the whole object tree + if (err != ERROR_NONE) + return err; + + sprintf(text, "\n", version); + outputText(&cfg, text); + displayObject(&cfg, obj, 0); + outputText(&cfg, "\n"); + + // Create return data + length = strlen((const char *)(cfg.outputBuffer)); + ptr = malloc(length + 1); + *result = ptr; + if (ptr != NULL) { + for (int i=0; i < length; i++) + *(ptr++) = cfg.outputBuffer[i]; + *ptr = '\0'; + } + else + err = ERROR_INSUFFICIENT_MEMORY; + + // Release assigned memory + releaseObject(obj); + free(cfg.offsetTable); + free(cfg.outputBuffer); + return err; +} + +static char map[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + +/** Encode Base64 + * + */ + +int encodeBase64(char **result, const unsigned char *data, int dataLength) +{ + unsigned char d; + int b; + int bitsLeft = 0; + int in = 0; + int out = 0; + int encodedLength = dataLength * 4 / 3 + 4; + char *encoded = malloc(encodedLength); + *result = encoded; + if (encoded == NULL) + return ERROR_INSUFFICIENT_MEMORY; + + while (out < dataLength) { + d = data[out++]; + switch (bitsLeft) { + case 0: + encoded[in++] = map[d >> 2]; + b = d & 0x03; + bitsLeft = 2; + break; + case 2: + b = (b << 8) | d; + encoded[in++] = map[b >> 4]; + b &= 0x0F; + bitsLeft = 4; + break; + case 4: + b = (b << 8) | d; + encoded[in++] = map[b >> 6]; + encoded[in++] = map[b & 0x03F]; + bitsLeft = 0; + break; + } + } + + /* Flush remaining bits */ + switch (bitsLeft) { + case 2: + encoded[in++] = map[b << 4]; + encoded[in++] = '='; + encoded[in++] = '='; + break; + case 4: + encoded[in++] = map[b << 2]; + encoded[in++] = '='; + break; + default: + break; + } + + /* Terminate as string */ + encoded[in] = '\0'; + return ERROR_NONE; +} + +static unsigned char unmap[256] = { 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 00 - 07 + 0x81, 0x80, 0x81, 0x80, 0x80, 0x81, 0x80, 0x80, // 08 - 0F + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 10 - 17 + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 18 - 1F + 0x80, 0x81, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 20 - 27 + 0x80, 0x80, 0x80, 0x3E, 0x80, 0x80, 0x80, 0x3F, // 28 - 2F + 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, // 30 - 37 + 0x3C, 0x3D, 0x80, 0x80, 0x80, 0x40, 0x80, 0x80, // 38 - 3F + 0x80, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, // 40 - 47 + 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, // 48 - 4F + 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, // 50 - 57 + 0x17, 0x18, 0x19, 0x80, 0x80, 0x80, 0x80, 0x80, // 58 - 5F + 0x80, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, // 60 - 67 + 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, // 68 - 6F + 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, // 70 - 77 + 0x31, 0x32, 0x33, 0x80, 0x80, 0x80, 0x80, 0x80, // 78 - 7F + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 80 - 87 + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 88 - 8F + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 90 - 97 + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // 98 - 9F + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // A0 - A7 + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // A8 - AF + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // B0 - B7 + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // B8 - BF + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // C0 - C7 + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // C8 - CF + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // D0 - D7 + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // D8 - DF + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // E0 - E7 + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // E8 - EF + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // F0 - F7 + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // F8 - FF +}; + +/*** decodeBase64 + * + * Returns decoded data and length. + */ + +int decodeBase64(unsigned char **result, int *resultLength, const char *data, int dataLength) +{ + int bitsLeft = 8; + int in = 0; + unsigned char b; + unsigned char d; + unsigned char *decoded = malloc(dataLength * 3 / 4 + 3); + *result = decoded; + *resultLength = 0; + if (decoded == NULL) + return ERROR_INSUFFICIENT_MEMORY; + + while (*data != '\0') { + // Get character and check valid + d = unmap[*(data++)]; + if (d > 0x3F) { + if (d == 0x80) { + free(decoded); + return ERROR_INVALID_CHARACTER; + } + break; // padding space + } + + switch (bitsLeft) { + case 8: + decoded[in] = d; + bitsLeft = 2; + break; + case 2: + decoded[in] = (decoded[in] << 2) | (d >> 4); + decoded[++in] = d & 0x0F; + bitsLeft = 4; + break; + case 4: + decoded[in] = (decoded[in] << 4) | (d >> 2); + decoded[++in] = d & 0x03; + bitsLeft = 6; + break; + case 6: + decoded[in] = (decoded[in] << 6) | d; + in++; + bitsLeft = 8; + break; + } + } + *resultLength = in; + return ERROR_NONE; +} + +/** Wrapper functions + * + */ + +void freeResult(void *ptr) +{ + if (ptr != NULL) + free(ptr); + return; +} + +static void plistFunc(sqlite3_context *context, int argc, sqlite3_value **argv){ + int resultLength; + int errorCode = 0; + char *result = NULL; + assert( argc==1 ); + switch( sqlite3_value_type(argv[0]) ){ + case SQLITE_TEXT: + case SQLITE_BLOB: { + const char *data = sqlite3_value_text(argv[0]); + const int dataLength = sqlite3_value_bytes(argv[0]); + errorCode = parsePlist(&result, data, dataLength); + if (errorCode == ERROR_NONE) { + resultLength = strlen(result); + sqlite3_result_text(context, result, resultLength, &freeResult); + } else { + if (sqlite3_value_type(argv[0]) == SQLITE_TEXT) + sqlite3_result_text(context, data, dataLength, NULL); + else + sqlite3_result_blob(context, data, dataLength, NULL); + } + break; + } + default: { + sqlite3_result_null(context); + break; + } + } +} + +static void encodeBase64Func(sqlite3_context *context, int argc, sqlite3_value **argv){ + int resultLength; + int errorCode = 0; + int dataLength; + const unsigned char *data; + char *result = NULL; + assert( argc==1 ); + switch( sqlite3_value_type(argv[0]) ){ + case SQLITE_BLOB: + data = sqlite3_value_blob(argv[0]); + dataLength = sqlite3_value_bytes(argv[0]); + errorCode = encodeBase64(&result, data, dataLength); + if (errorCode == ERROR_NONE) { + resultLength = strlen(result); + sqlite3_result_text(context, result, resultLength, &freeResult); + } else { + sqlite3_result_blob(context, data, dataLength, NULL); + } + break; + case SQLITE_TEXT: { + data = sqlite3_value_text(argv[0]); + dataLength = sqlite3_value_bytes(argv[0]); + sqlite3_result_text(context, data, dataLength, NULL); + errorCode = encodeBase64(&result, data, dataLength); + if (errorCode == ERROR_NONE) { + resultLength = strlen(result); + sqlite3_result_text(context, result, resultLength, &freeResult); + } else { + sqlite3_result_text(context, data, dataLength, NULL); + } + break; + } + default: { + sqlite3_result_null(context); + break; + } + } +} + + +/*** isText + * + * Returns zero if supplied data is entirely + * ASCII printable characters or white space. + */ + +int isText(unsigned char *data, int dataLength) +{ + static unsigned char map[256] = { + 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 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, 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, 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, 0, 0, 0, 0, 0, 0, 0, 0, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 + }; + int result = 0; + for (int i=0; i < dataLength; i++) + result |= map[*(data++)]; + return result; +} + +/** isUTF8 + * + * Returns one if the characters conform to UTF8 format in so + * far as all the byte lengths are consistent. It does not + * check for overlong encodings or invalid characters. A zero + * is returned if the format is not consistent. + * Note that a file of all zeros will be returned as UTF8. + */ + +int isUTF8(unsigned char *data, int length) +{ + int count = 0; + while (length-- > 0) { + unsigned char d = *(data++); + switch (count) { + case 0: /* First character */ + if ((d & 0x80) == 0) + continue; /* 7 bit ASCII */ + if ((d & 0xE0) == 0xC0) { + count = 1; /* 2 byte code */ + break; + } + if ((d & 0xF0) == 0xE0) { + count = 2; /* 3 byte code */ + break; + } + if ((d & 0xF8) == 0xF0) { + count = 3; /* 4 byte code */ + break; + } + return 0; + default: + count--; + if ((d & 0xC0) != 0x80) + return 0; + break; + } + } + return (count == 0) ? 1 : 0; +} + +static void decodeBase64Func(sqlite3_context *context, int argc, sqlite3_value **argv){ + int resultLength; + int errorCode = 0; + unsigned char *result = NULL; + assert( argc==1 ); + switch( sqlite3_value_type(argv[0]) ){ + case SQLITE_BLOB: + case SQLITE_TEXT: { + const char *data = sqlite3_value_text(argv[0]); + int dataLength = sqlite3_value_bytes(argv[0]); + errorCode = decodeBase64(&result, &resultLength, data, dataLength); + if (errorCode == ERROR_NONE) { + if (isUTF8(result, resultLength)) + sqlite3_result_text(context, result, resultLength, &freeResult); + else + sqlite3_result_blob(context, result, resultLength, &freeResult); + } else { + if (sqlite3_value_type(argv[0]) == SQLITE_TEXT) + sqlite3_result_text(context, data, dataLength, NULL); + else + sqlite3_result_blob(context, data, dataLength, NULL); + } + break; + } + default: { + sqlite3_result_null(context); + break; + } + } +} + +/** RegisterExtensionFormats + * + * Register the parsing functions with sqlite + */ + +int RegisterExtensionFormats(sqlite3 *db) +{ + sqlite3_create_function(db, "plist", 1, 0, db, plistFunc, 0, 0); + sqlite3_create_function(db, "unBase64", 1, 0, db, decodeBase64Func, 0, 0); + sqlite3_create_function(db, "toBase64", 1, 0, db, encodeBase64Func, 0, 0); +} + +#ifdef COMPILE_SQLITE_EXTENSIONS_AS_LOADABLE_MODULE + +#ifdef _WIN32 +__declspec(dllexport) +#endif + +int sqlite3_extension_init(sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi) +{ + int rc = SQLITE_OK; + SQLITE_EXTENSION_INIT2(pApi); + RegisterExtensionFormats(db); + return rc; +} + +#endif + + diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/extensions/extension-formats.def b/src/WBCLFZSystemModule/SqliteDBProcess/src/extensions/extension-formats.def new file mode 100644 index 0000000..2bfb84f --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/extensions/extension-formats.def @@ -0,0 +1,5 @@ +EXPORTS + RegisterExtensionFormats + sqlite3_api + sqlite3_extension_init + freeResult diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/extensions/extension-functions.c b/src/WBCLFZSystemModule/SqliteDBProcess/src/extensions/extension-functions.c new file mode 100644 index 0000000..2bdd194 --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/extensions/extension-functions.c @@ -0,0 +1,1947 @@ +/* +This library will provide common mathematical and string functions in +SQL queries using the operating system libraries or provided +definitions. It includes the following functions: + +Math: acos, asin, atan, atn2, atan2, acosh, asinh, atanh, difference, +degrees, radians, cos, sin, tan, cot, cosh, sinh, tanh, coth, exp, +log, log10, power, sign, sqrt, square, ceil, floor, pi. + +String: replicate, charindex, leftstr, rightstr, ltrim, rtrim, trim, +replace, reverse, proper, padl, padr, padc, strfilter. + +Aggregate: stdev, variance, mode, median, lower_quartile, +upper_quartile. + +The string functions ltrim, rtrim, trim, replace are included in +recent versions of SQLite and so by default do not build. + +Compilation instructions: + Compile this C source file into a dynamic library as follows: + * Linux: + gcc -fPIC -lm -shared extension-functions.c -o libsqlitefunctions.so + * Mac OS X: + gcc -fno-common -dynamiclib extension-functions.c -o libsqlitefunctions.dylib + (You may need to add flags + -I /opt/local/include/ -L/opt/local/lib -lsqlite3 + if your sqlite3 is installed from Mac ports, or + -I /sw/include/ -L/sw/lib -lsqlite3 + if installed with Fink.) + * Windows: + 1. Install MinGW (http://www.mingw.org/) and you will get the gcc + (gnu compiler collection) + 2. add the path to your path variable (isn't done during the + installation!) + 3. compile: + gcc -shared -I "path" -o libsqlitefunctions.so extension-functions.c + (path = path of sqlite3ext.h; i.e. C:\programs\sqlite) + +Usage instructions for applications calling the sqlite3 API functions: + In your application, call sqlite3_enable_load_extension(db,1) to + allow loading external libraries. Then load the library libsqlitefunctions + using sqlite3_load_extension; the third argument should be 0. + See http://www.sqlite.org/cvstrac/wiki?p=LoadableExtensions. + Select statements may now use these functions, as in + SELECT cos(radians(inclination)) FROM satsum WHERE satnum = 25544; + +Usage instructions for the sqlite3 program: + If the program is built so that loading extensions is permitted, + the following will work: + sqlite> SELECT load_extension('./libsqlitefunctions.so'); + sqlite> select cos(radians(45)); + 0.707106781186548 + Note: Loading extensions is by default prohibited as a + security measure; see "Security Considerations" in + http://www.sqlite.org/cvstrac/wiki?p=LoadableExtensions. + If the sqlite3 program and library are built this + way, you cannot use these functions from the program, you + must write your own program using the sqlite3 API, and call + sqlite3_enable_load_extension as described above, or else + rebuilt the sqlite3 program to allow loadable extensions. + +Alterations: +The instructions are for Linux, Mac OS X, and Windows; users of other +OSes may need to modify this procedure. In particular, if your math +library lacks one or more of the needed trig or log functions, comment +out the appropriate HAVE_ #define at the top of file. If you do not +wish to make a loadable module, comment out the define for +COMPILE_SQLITE_EXTENSIONS_AS_LOADABLE_MODULE. If you are using a +version of SQLite without the trim functions and replace, comment out +the HAVE_TRIM #define. + +Liam Healy + +History: +2010-01-06 Correct check for argc in squareFunc, and add Windows +compilation instructions. +2009-06-24 Correct check for argc in properFunc. +2008-09-14 Add check that memory was actually allocated after +sqlite3_malloc or sqlite3StrDup, call sqlite3_result_error_nomem if +not. Thanks to Robert Simpson. +2008-06-13 Change to instructions to indicate use of the math library +and that program might work. +2007-10-01 Minor clarification to instructions. +2007-09-29 Compilation as loadable module is optional with +COMPILE_SQLITE_EXTENSIONS_AS_LOADABLE_MODULE. +2007-09-28 Use sqlite3_extension_init and macros +SQLITE_EXTENSION_INIT1, SQLITE_EXTENSION_INIT2, so that it works with +sqlite3_load_extension. Thanks to Eric Higashino and Joe Wilson. +New instructions for Mac compilation. +2007-09-17 With help from Joe Wilson and Nuno Luca, made use of +external interfaces so that compilation is no longer dependent on +SQLite source code. Merged source, header, and README into a single +file. Added casts so that Mac will compile without warnings (unsigned +and signed char). +2007-09-05 Included some definitions from sqlite 3.3.13 so that this +will continue to work in newer versions of sqlite. Completed +description of functions available. +2007-03-27 Revised description. +2007-03-23 Small cleanup and a bug fix on the code. This was mainly +letting errno flag errors encountered in the math library and checking +the result, rather than pre-checking. This fixes a bug in power that +would cause an error if any non-positive number was raised to any +power. +2007-02-07 posted by Mikey C to sqlite mailing list. +Original code 2006 June 05 by relicoder. + +*/ + +//#include "config.h" + +#define COMPILE_SQLITE_EXTENSIONS_AS_LOADABLE_MODULE 1 +#define HAVE_ACOSH 1 +#define HAVE_ASINH 1 +#define HAVE_ATANH 1 +#define HAVE_SINH 1 +#define HAVE_COSH 1 +#define HAVE_TANH 1 +#define HAVE_LOG10 1 +#define HAVE_ISBLANK 1 +#define SQLITE_SOUNDEX 1 +#define HAVE_TRIM 1 /* LMH 2007-03-25 if sqlite has trim functions */ + +#ifdef COMPILE_SQLITE_EXTENSIONS_AS_LOADABLE_MODULE +#include "sqlite3ext.h" +SQLITE_EXTENSION_INIT1 +#else +#include "sqlite3.h" +#endif + +#include +/* relicoder */ +#include +#include +#include +#include /* LMH 2007-03-25 */ + +#include +#include + +#ifndef _MAP_H_ +#define _MAP_H_ + +#include + +/* +** Simple binary tree implementation to use in median, mode and quartile calculations +** Tree is not necessarily balanced. That would require something like red&black trees of AVL +*/ + +typedef int(*cmp_func)(const void *, const void *); +typedef void(*map_iterator)(void*, int64_t, void*); + +typedef struct node{ + struct node *l; + struct node *r; + void* data; + int64_t count; +} node; + +typedef struct map{ + node *base; + cmp_func cmp; + short free; +} map; + +/* +** creates a map given a comparison function +*/ +map map_make(cmp_func cmp); + +/* +** inserts the element e into map m +*/ +void map_insert(map *m, void *e); + +/* +** executes function iter over all elements in the map, in key increasing order +*/ +void map_iterate(map *m, map_iterator iter, void* p); + +/* +** frees all memory used by a map +*/ +void map_destroy(map *m); + +/* +** compares 2 integers +** to use with map_make +*/ +int int_cmp(const void *a, const void *b); + +/* +** compares 2 doubles +** to use with map_make +*/ +int double_cmp(const void *a, const void *b); + +#endif /* _MAP_H_ */ + +typedef uint8_t u8; +typedef uint16_t u16; +typedef int64_t i64; + +static char *sqlite3StrDup( const char *z ) { + char *res = sqlite3_malloc( strlen(z)+1 ); + return strcpy( res, z ); +} + +/* +** These are copied verbatim from fun.c so as to not have the names exported +*/ + +/* LMH from sqlite3 3.3.13 */ +/* +** This table maps from the first byte of a UTF-8 character to the number +** of trailing bytes expected. A value '4' indicates that the table key +** is not a legal first byte for a UTF-8 character. +*/ +static const u8 xtra_utf8_bytes[256] = { +/* 0xxxxxxx */ +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, 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, 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, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + +/* 10wwwwww */ +4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, +4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, +4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, +4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + +/* 110yyyyy */ +1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, +1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + +/* 1110zzzz */ +2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + +/* 11110yyy */ +3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, +}; + + +/* +** This table maps from the number of trailing bytes in a UTF-8 character +** to an integer constant that is effectively calculated for each character +** read by a naive implementation of a UTF-8 character reader. The code +** in the READ_UTF8 macro explains things best. +*/ +static const int xtra_utf8_bits[] = { + 0, + 12416, /* (0xC0 << 6) + (0x80) */ + 925824, /* (0xE0 << 12) + (0x80 << 6) + (0x80) */ + 63447168 /* (0xF0 << 18) + (0x80 << 12) + (0x80 << 6) + 0x80 */ +}; + +/* +** If a UTF-8 character contains N bytes extra bytes (N bytes follow +** the initial byte so that the total character length is N+1) then +** masking the character with utf8_mask[N] must produce a non-zero +** result. Otherwise, we have an (illegal) overlong encoding. +*/ +static const int utf_mask[] = { + 0x00000000, + 0xffffff80, + 0xfffff800, + 0xffff0000, +}; + +/* LMH salvaged from sqlite3 3.3.13 source code src/utf.c */ +#define READ_UTF8(zIn, c) { \ + int xtra; \ + c = *(zIn)++; \ + xtra = xtra_utf8_bytes[c]; \ + switch( xtra ){ \ + case 4: c = (int)0xFFFD; break; \ + case 3: c = (c<<6) + *(zIn)++; \ + case 2: c = (c<<6) + *(zIn)++; \ + case 1: c = (c<<6) + *(zIn)++; \ + c -= xtra_utf8_bits[xtra]; \ + if( (utf_mask[xtra]&c)==0 \ + || (c&0xFFFFF800)==0xD800 \ + || (c&0xFFFFFFFE)==0xFFFE ){ c = 0xFFFD; } \ + } \ +} + +static int sqlite3ReadUtf8(const unsigned char *z){ + int c; + READ_UTF8(z, c); + return c; +} + +#define SKIP_UTF8(zIn) { \ + zIn += (xtra_utf8_bytes[*(u8 *)zIn] + 1); \ +} + +/* +** pZ is a UTF-8 encoded unicode string. If nByte is less than zero, +** return the number of unicode characters in pZ up to (but not including) +** the first 0x00 byte. If nByte is not less than zero, return the +** number of unicode characters in the first nByte of pZ (or up to +** the first 0x00, whichever comes first). +*/ +static int sqlite3Utf8CharLen(const char *z, int nByte){ + int r = 0; + const char *zTerm; + if( nByte>=0 ){ + zTerm = &z[nByte]; + }else{ + zTerm = (const char *)(-1); + } + assert( z<=zTerm ); + while( *z!=0 && z 0) ? 1: ( iVal < 0 ) ? -1: 0; + sqlite3_result_int64(context, iVal); + break; + } + case SQLITE_NULL: { + sqlite3_result_null(context); + break; + } + default: { + /* 2nd change below. Line for abs was: if( rVal<0 ) rVal = rVal * -1.0; */ + + rVal = sqlite3_value_double(argv[0]); + rVal = ( rVal > 0) ? 1: ( rVal < 0 ) ? -1: 0; + sqlite3_result_double(context, rVal); + break; + } + } +} + + +/* +** smallest integer value not less than argument +*/ +static void ceilFunc(sqlite3_context *context, int argc, sqlite3_value **argv){ + double rVal=0.0; + i64 iVal=0; + assert( argc==1 ); + switch( sqlite3_value_type(argv[0]) ){ + case SQLITE_INTEGER: { + i64 iVal = sqlite3_value_int64(argv[0]); + sqlite3_result_int64(context, iVal); + break; + } + case SQLITE_NULL: { + sqlite3_result_null(context); + break; + } + default: { + rVal = sqlite3_value_double(argv[0]); + sqlite3_result_int64(context, (i64) ceil(rVal)); + break; + } + } +} + +/* +** largest integer value not greater than argument +*/ +static void floorFunc(sqlite3_context *context, int argc, sqlite3_value **argv){ + double rVal=0.0; + i64 iVal=0; + assert( argc==1 ); + switch( sqlite3_value_type(argv[0]) ){ + case SQLITE_INTEGER: { + i64 iVal = sqlite3_value_int64(argv[0]); + sqlite3_result_int64(context, iVal); + break; + } + case SQLITE_NULL: { + sqlite3_result_null(context); + break; + } + default: { + rVal = sqlite3_value_double(argv[0]); + sqlite3_result_int64(context, (i64) floor(rVal)); + break; + } + } +} + +/* +** Given a string (s) in the first argument and an integer (n) in the second returns the +** string that constains s contatenated n times +*/ +static void replicateFunc(sqlite3_context *context, int argc, sqlite3_value **argv){ + unsigned char *z; /* input string */ + unsigned char *zo; /* result string */ + i64 iCount; /* times to repeat */ + i64 nLen; /* length of the input string (no multibyte considerations) */ + i64 nTLen; /* length of the result string (no multibyte considerations) */ + i64 i=0; + + if( argc!=2 || SQLITE_NULL==sqlite3_value_type(argv[0]) ) + return; + + iCount = sqlite3_value_int64(argv[1]); + + if( iCount<0 ){ + sqlite3_result_error(context, "domain error", -1); + }else{ + + nLen = sqlite3_value_bytes(argv[0]); + nTLen = nLen*iCount; + z=sqlite3_malloc(nTLen+1); + zo=sqlite3_malloc(nLen+1); + if (!z || !zo){ + sqlite3_result_error_nomem(context); + if (z) sqlite3_free(z); + if (zo) sqlite3_free(zo); + return; + } + strcpy((char*)zo, (char*)sqlite3_value_text(argv[0])); + + for(i=0; i=n it's a NOP +** padl(NULL) = NULL +*/ +static void padlFunc(sqlite3_context *context, int argc, sqlite3_value **argv){ + i64 ilen; /* length to pad to */ + i64 zl; /* length of the input string (UTF-8 chars) */ + int i = 0; + const char *zi; /* input string */ + char *zo; /* output string */ + char *zt; + + assert( argc==2 ); + + if( sqlite3_value_type(argv[0]) == SQLITE_NULL ){ + sqlite3_result_null(context); + }else{ + zi = (char *)sqlite3_value_text(argv[0]); + ilen = sqlite3_value_int64(argv[1]); + /* check domain */ + if(ilen<0){ + sqlite3_result_error(context, "domain error", -1); + return; + } + zl = sqlite3Utf8CharLen(zi, -1); + if( zl>=ilen ){ + /* string is longer than the requested pad length, return the same string (dup it) */ + zo = sqlite3StrDup(zi); + if (!zo){ + sqlite3_result_error_nomem(context); + return; + } + sqlite3_result_text(context, zo, -1, SQLITE_TRANSIENT); + }else{ + zo = sqlite3_malloc(strlen(zi)+ilen-zl+1); + if (!zo){ + sqlite3_result_error_nomem(context); + return; + } + zt = zo; + for(i=1; i+zl<=ilen; ++i){ + *(zt++)=' '; + } + /* no need to take UTF-8 into consideration here */ + strcpy(zt,zi); + } + sqlite3_result_text(context, zo, -1, SQLITE_TRANSIENT); + sqlite3_free(zo); + } +} + +/* +** given an input string (s) and an integer (n) appends spaces at the end of s +** until it has a length of n characters. +** When s has a length >=n it's a NOP +** padl(NULL) = NULL +*/ +static void padrFunc(sqlite3_context *context, int argc, sqlite3_value **argv){ + i64 ilen; /* length to pad to */ + i64 zl; /* length of the input string (UTF-8 chars) */ + i64 zll; /* length of the input string (bytes) */ + int i = 0; + const char *zi; /* input string */ + char *zo; /* output string */ + char *zt; + + assert( argc==2 ); + + if( sqlite3_value_type(argv[0]) == SQLITE_NULL ){ + sqlite3_result_null(context); + }else{ + zi = (char *)sqlite3_value_text(argv[0]); + ilen = sqlite3_value_int64(argv[1]); + /* check domain */ + if(ilen<0){ + sqlite3_result_error(context, "domain error", -1); + return; + } + zl = sqlite3Utf8CharLen(zi, -1); + if( zl>=ilen ){ + /* string is longer than the requested pad length, return the same string (dup it) */ + zo = sqlite3StrDup(zi); + if (!zo){ + sqlite3_result_error_nomem(context); + return; + } + sqlite3_result_text(context, zo, -1, SQLITE_TRANSIENT); + }else{ + zll = strlen(zi); + zo = sqlite3_malloc(zll+ilen-zl+1); + if (!zo){ + sqlite3_result_error_nomem(context); + return; + } + zt = strcpy(zo,zi)+zll; + for(i=1; i+zl<=ilen; ++i){ + *(zt++) = ' '; + } + *zt = '\0'; + } + sqlite3_result_text(context, zo, -1, SQLITE_TRANSIENT); + sqlite3_free(zo); + } +} + +/* +** given an input string (s) and an integer (n) appends spaces at the end of s +** and adds spaces at the begining of s until it has a length of n characters. +** Tries to add has many characters at the left as at the right. +** When s has a length >=n it's a NOP +** padl(NULL) = NULL +*/ +static void padcFunc(sqlite3_context *context, int argc, sqlite3_value **argv){ + i64 ilen; /* length to pad to */ + i64 zl; /* length of the input string (UTF-8 chars) */ + i64 zll; /* length of the input string (bytes) */ + int i = 0; + const char *zi; /* input string */ + char *zo; /* output string */ + char *zt; + + assert( argc==2 ); + + if( sqlite3_value_type(argv[0]) == SQLITE_NULL ){ + sqlite3_result_null(context); + }else{ + zi = (char *)sqlite3_value_text(argv[0]); + ilen = sqlite3_value_int64(argv[1]); + /* check domain */ + if(ilen<0){ + sqlite3_result_error(context, "domain error", -1); + return; + } + zl = sqlite3Utf8CharLen(zi, -1); + if( zl>=ilen ){ + /* string is longer than the requested pad length, return the same string (dup it) */ + zo = sqlite3StrDup(zi); + if (!zo){ + sqlite3_result_error_nomem(context); + return; + } + sqlite3_result_text(context, zo, -1, SQLITE_TRANSIENT); + }else{ + zll = strlen(zi); + zo = sqlite3_malloc(zll+ilen-zl+1); + if (!zo){ + sqlite3_result_error_nomem(context); + return; + } + zt = zo; + for(i=1; 2*i+zl<=ilen; ++i){ + *(zt++) = ' '; + } + strcpy(zt, zi); + zt+=zll; + for(; i+zl<=ilen; ++i){ + *(zt++) = ' '; + } + *zt = '\0'; + } + sqlite3_result_text(context, zo, -1, SQLITE_TRANSIENT); + sqlite3_free(zo); + } +} + +/* +** given 2 string (s1,s2) returns the string s1 with the characters NOT in s2 removed +** assumes strings are UTF-8 encoded +*/ +static void strfilterFunc(sqlite3_context *context, int argc, sqlite3_value **argv){ + const char *zi1; /* first parameter string (searched string) */ + const char *zi2; /* second parameter string (vcontains valid characters) */ + const char *z1; + const char *z21; + const char *z22; + char *zo; /* output string */ + char *zot; + int c1 = 0; + int c2 = 0; + + assert( argc==2 ); + + if( sqlite3_value_type(argv[0]) == SQLITE_NULL || sqlite3_value_type(argv[1]) == SQLITE_NULL ){ + sqlite3_result_null(context); + }else{ + zi1 = (char *)sqlite3_value_text(argv[0]); + zi2 = (char *)sqlite3_value_text(argv[1]); + /* + ** maybe I could allocate less, but that would imply 2 passes, rather waste + ** (possibly) some memory + */ + zo = sqlite3_malloc(strlen(zi1)+1); + if (!zo){ + sqlite3_result_error_nomem(context); + return; + } + zot = zo; + z1 = zi1; + while( (c1=sqliteCharVal((unsigned char *)z1))!=0 ){ + z21=zi2; + while( (c2=sqliteCharVal((unsigned char *)z21))!=0 && c2!=c1 ){ + sqliteNextChar(z21); + } + if( c2!=0){ + z22=z21; + sqliteNextChar(z22); + strncpy(zot, z21, z22-z21); + zot+=z22-z21; + } + sqliteNextChar(z1); + } + *zot = '\0'; + + sqlite3_result_text(context, zo, -1, SQLITE_TRANSIENT); + sqlite3_free(zo); + } +} + +/* +** Given a string z1, retutns the (0 based) index of it's first occurence +** in z2 after the first s characters. +** Returns -1 when there isn't a match. +** updates p to point to the character where the match occured. +** This is an auxiliary function. +*/ +static int _substr(const char* z1, const char* z2, int s, const char** p){ + int c = 0; + int rVal=-1; + const char* zt1; + const char* zt2; + int c1,c2; + + if( '\0'==*z1 ){ + return -1; + } + + while( (sqliteCharVal((unsigned char *)z2) != 0) && (c++)=0 ? rVal+s : rVal; +} + +/* +** given 2 input strings (s1,s2) and an integer (n) searches from the nth character +** for the string s1. Returns the position where the match occured. +** Characters are counted from 1. +** 0 is returned when no match occurs. +*/ + +static void charindexFunc(sqlite3_context *context, int argc, sqlite3_value **argv){ + const u8 *z1; /* s1 string */ + u8 *z2; /* s2 string */ + int s=0; + int rVal=0; + + assert( argc==3 ||argc==2); + + if( SQLITE_NULL==sqlite3_value_type(argv[0]) || SQLITE_NULL==sqlite3_value_type(argv[1])){ + sqlite3_result_null(context); + return; + } + + z1 = sqlite3_value_text(argv[0]); + if( z1==0 ) return; + z2 = (u8*) sqlite3_value_text(argv[1]); + if(argc==3){ + s = sqlite3_value_int(argv[2])-1; + if(s<0){ + s=0; + } + }else{ + s = 0; + } + + rVal = _substr((char *)z1,(char *)z2,s,NULL); + sqlite3_result_int(context, rVal+1); +} + +/* +** given a string (s) and an integer (n) returns the n leftmost (UTF-8) characters +** if the string has a length<=n or is NULL this function is NOP +*/ +static void leftFunc(sqlite3_context *context, int argc, sqlite3_value **argv){ + int c=0; + int cc=0; + int l=0; + const unsigned char *z; /* input string */ + const unsigned char *zt; + unsigned char *rz; /* output string */ + + assert( argc==2); + + if( SQLITE_NULL==sqlite3_value_type(argv[0]) || SQLITE_NULL==sqlite3_value_type(argv[1])){ + sqlite3_result_null(context); + return; + } + + z = sqlite3_value_text(argv[0]); + l = sqlite3_value_int(argv[1]); + zt = z; + + while( sqliteCharVal(zt) && c++ 0 ){ + sqliteNextChar(zt); + } + + rz = sqlite3_malloc(ze-zt+1); + if (!rz){ + sqlite3_result_error_nomem(context); + return; + } + strcpy((char*) rz, (char*) (zt)); + sqlite3_result_text(context, (char*)rz, -1, SQLITE_TRANSIENT); + sqlite3_free(rz); +} + +#ifndef HAVE_TRIM +/* +** removes the whitespaces at the begining of a string. +*/ +const char* ltrim(const char* s){ + while( *s==' ' ) + ++s; + return s; +} + +/* +** removes the whitespaces at the end of a string. +** !mutates the input string! +*/ +void rtrim(char* s){ + char* ss = s+strlen(s)-1; + while( ss>=s && *ss==' ' ) + --ss; + *(ss+1)='\0'; +} + +/* +** Removes the whitespace at the begining of a string +*/ +static void ltrimFunc(sqlite3_context *context, int argc, sqlite3_value **argv){ + const char *z; + + assert( argc==1); + + if( SQLITE_NULL==sqlite3_value_type(argv[0]) ){ + sqlite3_result_null(context); + return; + } + z = sqlite3_value_text(argv[0]); + sqlite3_result_text(context, ltrim(z), -1, SQLITE_TRANSIENT); +} + +/* +** Removes the whitespace at the end of a string +*/ +static void rtrimFunc(sqlite3_context *context, int argc, sqlite3_value **argv){ + const char *z; + char *rz; + /* try not to change data in argv */ + + assert( argc==1); + + if( SQLITE_NULL==sqlite3_value_type(argv[0]) ){ + sqlite3_result_null(context); + return; + } + z = sqlite3_value_text(argv[0]); + rz = sqlite3StrDup(z); + rtrim(rz); + sqlite3_result_text(context, rz, -1, SQLITE_TRANSIENT); + sqlite3_free(rz); +} + +/* +** Removes the whitespace at the begining and end of a string +*/ +static void trimFunc(sqlite3_context *context, int argc, sqlite3_value **argv){ + const char *z; + char *rz; + /* try not to change data in argv */ + + assert( argc==1); + + if( SQLITE_NULL==sqlite3_value_type(argv[0]) ){ + sqlite3_result_null(context); + return; + } + z = sqlite3_value_text(argv[0]); + rz = sqlite3StrDup(z); + rtrim(rz); + sqlite3_result_text(context, ltrim(rz), -1, SQLITE_TRANSIENT); + sqlite3_free(rz); +} +#endif + +/* +** given a pointer to a string s1, the length of that string (l1), a new string (s2) +** and it's length (l2) appends s2 to s1. +** All lengths in bytes. +** This is just an auxiliary function +*/ +// static void _append(char **s1, int l1, const char *s2, int l2){ +// *s1 = realloc(*s1, (l1+l2+1)*sizeof(char)); +// strncpy((*s1)+l1, s2, l2); +// *(*(s1)+l1+l2) = '\0'; +// } + +#ifndef HAVE_TRIM + +/* +** given strings s, s1 and s2 replaces occurrences of s1 in s by s2 +*/ +static void replaceFunc(sqlite3_context *context, int argc, sqlite3_value **argv){ + const char *z1; /* string s (first parameter) */ + const char *z2; /* string s1 (second parameter) string to look for */ + const char *z3; /* string s2 (third parameter) string to replace occurrences of s1 with */ + int lz1; + int lz2; + int lz3; + int lzo=0; + char *zo=0; + int ret=0; + const char *zt1; + const char *zt2; + + assert( 3==argc ); + + if( SQLITE_NULL==sqlite3_value_type(argv[0]) ){ + sqlite3_result_null(context); + return; + } + + z1 = sqlite3_value_text(argv[0]); + z2 = sqlite3_value_text(argv[1]); + z3 = sqlite3_value_text(argv[2]); + /* handle possible null values */ + if( 0==z2 ){ + z2=""; + } + if( 0==z3 ){ + z3=""; + } + + lz1 = strlen(z1); + lz2 = strlen(z2); + lz3 = strlen(z3); + +#if 0 + /* special case when z2 is empty (or null) nothing will be changed */ + if( 0==lz2 ){ + sqlite3_result_text(context, z1, -1, SQLITE_TRANSIENT); + return; + } +#endif + + zt1=z1; + zt2=z1; + + while(1){ + ret=_substr(z2,zt1 , 0, &zt2); + + if( ret<0 ) + break; + + _append(&zo, lzo, zt1, zt2-zt1); + lzo+=zt2-zt1; + _append(&zo, lzo, z3, lz3); + lzo+=lz3; + + zt1=zt2+lz2; + } + _append(&zo, lzo, zt1, lz1-(zt1-z1)); + sqlite3_result_text(context, zo, -1, SQLITE_TRANSIENT); + sqlite3_free(zo); +} +#endif + +/* +** given a string returns the same string but with the characters in reverse order +*/ +static void reverseFunc(sqlite3_context *context, int argc, sqlite3_value **argv){ + const char *z; + const char *zt; + char *rz; + char *rzt; + int l = 0; + int i = 0; + + assert( 1==argc ); + + if( SQLITE_NULL==sqlite3_value_type(argv[0]) ){ + sqlite3_result_null(context); + return; + } + z = (char *)sqlite3_value_text(argv[0]); + l = strlen(z); + rz = sqlite3_malloc(l+1); + if (!rz){ + sqlite3_result_error_nomem(context); + return; + } + rzt = rz+l; + *(rzt--) = '\0'; + + zt=z; + while( sqliteCharVal((unsigned char *)zt)!=0 ){ + z=zt; + sqliteNextChar(zt); + for(i=1; zt-i>=z; ++i){ + *(rzt--)=*(zt-i); + } + } + + sqlite3_result_text(context, rz, -1, SQLITE_TRANSIENT); + sqlite3_free(rz); +} + +/* +** An instance of the following structure holds the context of a +** stdev() or variance() aggregate computation. +** implementaion of http://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Algorithm_II +** less prone to rounding errors +*/ +typedef struct StdevCtx StdevCtx; +struct StdevCtx { + double rM; + double rS; + i64 cnt; /* number of elements */ +}; + +/* +** An instance of the following structure holds the context of a +** mode() or median() aggregate computation. +** Depends on structures defined in map.c (see map & map) +** These aggregate functions only work for integers and floats although +** they could be made to work for strings. This is usually considered meaningless. +** Only usuall order (for median), no use of collation functions (would this even make sense?) +*/ +typedef struct ModeCtx ModeCtx; +struct ModeCtx { + i64 riM; /* integer value found so far */ + double rdM; /* double value found so far */ + i64 cnt; /* number of elements so far */ + double pcnt; /* number of elements smaller than a percentile */ + i64 mcnt; /* maximum number of occurrences (for mode) */ + i64 mn; /* number of occurrences (for mode and percentiles) */ + i64 is_double; /* whether the computation is being done for doubles (>0) or integers (=0) */ + map* m; /* map structure used for the computation */ + int done; /* whether the answer has been found */ +}; + +/* +** called for each value received during a calculation of stdev or variance +*/ +static void varianceStep(sqlite3_context *context, int argc, sqlite3_value **argv){ + StdevCtx *p; + + double delta; + double x; + + assert( argc==1 ); + p = sqlite3_aggregate_context(context, sizeof(*p)); + /* only consider non-null values */ + if( SQLITE_NULL != sqlite3_value_numeric_type(argv[0]) ){ + p->cnt++; + x = sqlite3_value_double(argv[0]); + delta = (x-p->rM); + p->rM += delta/p->cnt; + p->rS += delta*(x-p->rM); + } +} + +/* +** called for each value received during a calculation of mode of median +*/ +static void modeStep(sqlite3_context *context, int argc, sqlite3_value **argv){ + ModeCtx *p; + i64 xi=0; + double xd=0.0; + i64 *iptr; + double *dptr; + int type; + + assert( argc==1 ); + type = sqlite3_value_numeric_type(argv[0]); + + if( type == SQLITE_NULL) + return; + + p = sqlite3_aggregate_context(context, sizeof(*p)); + + if( 0==(p->m) ){ + p->m = calloc(1, sizeof(map)); + if( type==SQLITE_INTEGER ){ + /* map will be used for integers */ + *(p->m) = map_make(int_cmp); + p->is_double = 0; + }else{ + p->is_double = 1; + /* map will be used for doubles */ + *(p->m) = map_make(double_cmp); + } + } + + ++(p->cnt); + + if( 0==p->is_double ){ + xi = sqlite3_value_int64(argv[0]); + iptr = (i64*)calloc(1,sizeof(i64)); + *iptr = xi; + map_insert(p->m, iptr); + }else{ + xd = sqlite3_value_double(argv[0]); + dptr = (double*)calloc(1,sizeof(double)); + *dptr = xd; + map_insert(p->m, dptr); + } +} + +/* +** Auxiliary function that iterates all elements in a map and finds the mode +** (most frequent value) +*/ +static void modeIterate(void* e, i64 c, void* pp){ + i64 ei; + double ed; + ModeCtx *p = (ModeCtx*)pp; + + if( 0==p->is_double ){ + ei = *(int*)(e); + + if( p->mcnt==c ){ + ++p->mn; + }else if( p->mcntriM = ei; + p->mcnt = c; + p->mn=1; + } + }else{ + ed = *(double*)(e); + + if( p->mcnt==c ){ + ++p->mn; + }else if(p->mcntrdM = ed; + p->mcnt = c; + p->mn=1; + } + } +} + +/* +** Auxiliary function that iterates all elements in a map and finds the median +** (the value such that the number of elements smaller is equal the the number of +** elements larger) +*/ +static void medianIterate(void* e, i64 c, void* pp){ + i64 ei; + double ed; + double iL; + double iR; + int il; + int ir; + ModeCtx *p = (ModeCtx*)pp; + + if(p->done>0) + return; + + iL = p->pcnt; + iR = p->cnt - p->pcnt; + il = p->mcnt + c; + ir = p->cnt - p->mcnt; + + if( il >= iL ){ + if( ir >= iR ){ + ++p->mn; + if( 0==p->is_double ){ + ei = *(int*)(e); + p->riM += ei; + }else{ + ed = *(double*)(e); + p->rdM += ed; + } + }else{ + p->done=1; + } + } + p->mcnt+=c; +} + +/* +** Returns the mode value +*/ +static void modeFinalize(sqlite3_context *context){ + ModeCtx *p; + p = sqlite3_aggregate_context(context, 0); + if( p && p->m ){ + map_iterate(p->m, modeIterate, p); + map_destroy(p->m); + free(p->m); + + if( 1==p->mn ){ + if( 0==p->is_double ) + sqlite3_result_int64(context, p->riM); + else + sqlite3_result_double(context, p->rdM); + } + } +} + +/* +** auxiliary function for percentiles +*/ +static void _medianFinalize(sqlite3_context *context){ + ModeCtx *p; + p = (ModeCtx*) sqlite3_aggregate_context(context, 0); + if( p && p->m ){ + p->done=0; + map_iterate(p->m, medianIterate, p); + map_destroy(p->m); + free(p->m); + + if( 0==p->is_double ) + if( 1==p->mn ) + sqlite3_result_int64(context, p->riM); + else + sqlite3_result_double(context, p->riM*1.0/p->mn); + else + sqlite3_result_double(context, p->rdM/p->mn); + } +} + +/* +** Returns the median value +*/ +static void medianFinalize(sqlite3_context *context){ + ModeCtx *p; + p = (ModeCtx*) sqlite3_aggregate_context(context, 0); + if( p!=0 ){ + p->pcnt = (p->cnt)/2.0; + _medianFinalize(context); + } +} + +/* +** Returns the lower_quartile value +*/ +static void lower_quartileFinalize(sqlite3_context *context){ + ModeCtx *p; + p = (ModeCtx*) sqlite3_aggregate_context(context, 0); + if( p!=0 ){ + p->pcnt = (p->cnt)/4.0; + _medianFinalize(context); + } +} + +/* +** Returns the upper_quartile value +*/ +static void upper_quartileFinalize(sqlite3_context *context){ + ModeCtx *p; + p = (ModeCtx*) sqlite3_aggregate_context(context, 0); + if( p!=0 ){ + p->pcnt = (p->cnt)*3/4.0; + _medianFinalize(context); + } +} + +/* +** Returns the stdev value +*/ +static void stdevFinalize(sqlite3_context *context){ + StdevCtx *p; + p = sqlite3_aggregate_context(context, 0); + if( p && p->cnt>1 ){ + sqlite3_result_double(context, sqrt(p->rS/(p->cnt-1))); + }else{ + sqlite3_result_double(context, 0.0); + } +} + +/* +** Returns the variance value +*/ +static void varianceFinalize(sqlite3_context *context){ + StdevCtx *p; + p = sqlite3_aggregate_context(context, 0); + if( p && p->cnt>1 ){ + sqlite3_result_double(context, p->rS/(p->cnt-1)); + }else{ + sqlite3_result_double(context, 0.0); + } +} + +#ifdef SQLITE_SOUNDEX + +/* relicoder factored code */ +/* +** Calculates the soundex value of a string +*/ + +static void soundex(const u8 *zIn, char *zResult){ + int i, j; + static const unsigned char iCode[] = { + 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, 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, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 2, 3, 0, 1, 2, 0, 0, 2, 2, 4, 5, 5, 0, + 1, 2, 6, 2, 3, 0, 1, 0, 2, 0, 2, 0, 0, 0, 0, 0, + 0, 0, 1, 2, 3, 0, 1, 2, 0, 0, 2, 2, 4, 5, 5, 0, + 1, 2, 6, 2, 3, 0, 1, 0, 2, 0, 2, 0, 0, 0, 0, 0, + }; + + for(i=0; zIn[i] && !isalpha(zIn[i]); i++){} + if( zIn[i] ){ + zResult[0] = toupper(zIn[i]); + for(j=1; j<4 && zIn[i]; i++){ + int code = iCode[zIn[i]&0x7f]; + if( code>0 ){ + zResult[j++] = code + '0'; + } + } + while( j<4 ){ + zResult[j++] = '0'; + } + zResult[j] = 0; + }else{ + strcpy(zResult, "?000"); + } +} + +/* +** computes the number of different characters between the soundex value fo 2 strings +*/ +static void differenceFunc(sqlite3_context *context, int argc, sqlite3_value **argv){ + char zResult1[8]; + char zResult2[8]; + char *zR1 = zResult1; + char *zR2 = zResult2; + int rVal = 0; + int i = 0; + const u8 *zIn1; + const u8 *zIn2; + + assert( argc==2 ); + + if( sqlite3_value_type(argv[0])==SQLITE_NULL || sqlite3_value_type(argv[1])==SQLITE_NULL ){ + sqlite3_result_null(context); + return; + } + + zIn1 = (u8*)sqlite3_value_text(argv[0]); + zIn2 = (u8*)sqlite3_value_text(argv[1]); + + soundex(zIn1, zR1); + soundex(zIn2, zR2); + + for(i=0; i<4; ++i){ + if( sqliteCharVal((unsigned char *)zR1)==sqliteCharVal((unsigned char *)zR2) ) + ++rVal; + sqliteNextChar(zR1); + sqliteNextChar(zR2); + } + sqlite3_result_int(context, rVal); +} +#endif + +/* +** This function registered all of the above C functions as SQL +** functions. This should be the only routine in this file with +** external linkage. +*/ +int RegisterExtensionFunctions(sqlite3 *db){ + static const struct FuncDef { + char *zName; + signed char nArg; + u8 argType; /* 0: none. 1: db 2: (-1) */ + u8 eTextRep; /* 1: UTF-16. 0: UTF-8 */ + u8 needCollSeq; + void (*xFunc)(sqlite3_context*,int,sqlite3_value **); + } aFuncs[] = { + /* math.h */ + { "acos", 1, 0, SQLITE_UTF8, 0, acosFunc }, + { "asin", 1, 0, SQLITE_UTF8, 0, asinFunc }, + { "atan", 1, 0, SQLITE_UTF8, 0, atanFunc }, + { "atn2", 2, 0, SQLITE_UTF8, 0, atn2Func }, + /* XXX alias */ + { "atan2", 2, 0, SQLITE_UTF8, 0, atn2Func }, + { "acosh", 1, 0, SQLITE_UTF8, 0, acoshFunc }, + { "asinh", 1, 0, SQLITE_UTF8, 0, asinhFunc }, + { "atanh", 1, 0, SQLITE_UTF8, 0, atanhFunc }, + + { "difference", 2, 0, SQLITE_UTF8, 0, differenceFunc}, + { "degrees", 1, 0, SQLITE_UTF8, 0, rad2degFunc }, + { "radians", 1, 0, SQLITE_UTF8, 0, deg2radFunc }, + + { "cos", 1, 0, SQLITE_UTF8, 0, cosFunc }, + { "sin", 1, 0, SQLITE_UTF8, 0, sinFunc }, + { "tan", 1, 0, SQLITE_UTF8, 0, tanFunc }, + { "cot", 1, 0, SQLITE_UTF8, 0, cotFunc }, + { "cosh", 1, 0, SQLITE_UTF8, 0, coshFunc }, + { "sinh", 1, 0, SQLITE_UTF8, 0, sinhFunc }, + { "tanh", 1, 0, SQLITE_UTF8, 0, tanhFunc }, + { "coth", 1, 0, SQLITE_UTF8, 0, cothFunc }, + + { "exp", 1, 0, SQLITE_UTF8, 0, expFunc }, + { "log", 1, 0, SQLITE_UTF8, 0, logFunc }, + { "log10", 1, 0, SQLITE_UTF8, 0, log10Func }, + { "power", 2, 0, SQLITE_UTF8, 0, powerFunc }, + { "sign", 1, 0, SQLITE_UTF8, 0, signFunc }, + { "sqrt", 1, 0, SQLITE_UTF8, 0, sqrtFunc }, + { "square", 1, 0, SQLITE_UTF8, 0, squareFunc }, + + { "ceil", 1, 0, SQLITE_UTF8, 0, ceilFunc }, + { "floor", 1, 0, SQLITE_UTF8, 0, floorFunc }, + + { "pi", 0, 0, SQLITE_UTF8, 1, piFunc }, + + + /* string */ + { "replicate", 2, 0, SQLITE_UTF8, 0, replicateFunc }, + { "charindex", 2, 0, SQLITE_UTF8, 0, charindexFunc }, + { "charindex", 3, 0, SQLITE_UTF8, 0, charindexFunc }, + { "leftstr", 2, 0, SQLITE_UTF8, 0, leftFunc }, + { "rightstr", 2, 0, SQLITE_UTF8, 0, rightFunc }, +#ifndef HAVE_TRIM + { "ltrim", 1, 0, SQLITE_UTF8, 0, ltrimFunc }, + { "rtrim", 1, 0, SQLITE_UTF8, 0, rtrimFunc }, + { "trim", 1, 0, SQLITE_UTF8, 0, trimFunc }, + { "replace", 3, 0, SQLITE_UTF8, 0, replaceFunc }, +#endif + { "reverse", 1, 0, SQLITE_UTF8, 0, reverseFunc }, + { "proper", 1, 0, SQLITE_UTF8, 0, properFunc }, + { "padl", 2, 0, SQLITE_UTF8, 0, padlFunc }, + { "padr", 2, 0, SQLITE_UTF8, 0, padrFunc }, + { "padc", 2, 0, SQLITE_UTF8, 0, padcFunc }, + { "strfilter", 2, 0, SQLITE_UTF8, 0, strfilterFunc }, + + }; + /* Aggregate functions */ + static const struct FuncDefAgg { + char *zName; + signed char nArg; + u8 argType; + u8 needCollSeq; + void (*xStep)(sqlite3_context*,int,sqlite3_value**); + void (*xFinalize)(sqlite3_context*); + } aAggs[] = { + { "stdev", 1, 0, 0, varianceStep, stdevFinalize }, + { "variance", 1, 0, 0, varianceStep, varianceFinalize }, + { "mode", 1, 0, 0, modeStep, modeFinalize }, + { "median", 1, 0, 0, modeStep, medianFinalize }, + { "lower_quartile", 1, 0, 0, modeStep, lower_quartileFinalize }, + { "upper_quartile", 1, 0, 0, modeStep, upper_quartileFinalize }, + }; + int i; + + for(i=0; ineedCollSeq = 1; + } + } +#endif + } + + for(i=0; ineedCollSeq = 1; + } + } +#endif + } + return 0; +} + +#ifdef COMPILE_SQLITE_EXTENSIONS_AS_LOADABLE_MODULE +int sqlite3_extension_init( + sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi){ + SQLITE_EXTENSION_INIT2(pApi); + RegisterExtensionFunctions(db); + return 0; +} +#endif /* COMPILE_SQLITE_EXTENSIONS_AS_LOADABLE_MODULE */ + +map map_make(cmp_func cmp){ + map r; + r.cmp=cmp; + r.base = 0; + + return r; +} + +void* xcalloc(size_t nmemb, size_t size, char* s){ + void* ret = calloc(nmemb, size); + return ret; +} + +void xfree(void* p){ + free(p); +} + +void node_insert(node** n, cmp_func cmp, void *e){ + int c; + node* nn; + if(*n==0){ + nn = (node*)xcalloc(1,sizeof(node), "for node"); + nn->data = e; + nn->count = 1; + *n=nn; + }else{ + c=cmp((*n)->data,e); + if(0==c){ + ++((*n)->count); + xfree(e); + }else if(c>0){ + /* put it right here */ + node_insert(&((*n)->l), cmp, e); + }else{ + node_insert(&((*n)->r), cmp, e); + } + } +} + +void map_insert(map *m, void *e){ + node_insert(&(m->base), m->cmp, e); +} + +void node_iterate(node *n, map_iterator iter, void* p){ + if(n){ + if(n->l) + node_iterate(n->l, iter, p); + iter(n->data, n->count, p); + if(n->r) + node_iterate(n->r, iter, p); + } +} + +void map_iterate(map *m, map_iterator iter, void* p){ + node_iterate(m->base, iter, p); +} + +void node_destroy(node *n){ + if(0!=n){ + xfree(n->data); + if(n->l) + node_destroy(n->l); + if(n->r) + node_destroy(n->r); + + xfree(n); + } +} + +void map_destroy(map *m){ + node_destroy(m->base); +} + +int int_cmp(const void *a, const void *b){ + int64_t aa = *(int64_t *)(a); + int64_t bb = *(int64_t *)(b); + /* printf("cmp %d <=> %d\n",aa,bb); */ + if(aa==bb) + return 0; + else if(aa %d\n",aa,bb); */ + if(aa==bb) + return 0; + else if(aa %lld\n", ee,c); +} + diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/extensions/extension-functions.def b/src/WBCLFZSystemModule/SqliteDBProcess/src/extensions/extension-functions.def new file mode 100644 index 0000000..df979a4 --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/extensions/extension-functions.def @@ -0,0 +1,16 @@ +EXPORTS + RegisterExtensionFunctions + double_cmp + int_cmp + map_destroy + map_insert + map_iterate + map_make + node_destroy + node_insert + node_iterate + print_elem + sqlite3_api + sqlite3_extension_init + xcalloc + xfree diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/i18n.pri b/src/WBCLFZSystemModule/SqliteDBProcess/src/i18n.pri new file mode 100644 index 0000000..5f201e5 --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/i18n.pri @@ -0,0 +1,48 @@ +# This file is taken from the project https://gitorious.org/qop/qop/. +# For autocompiling qm-files. + +#rules to generate ts +isEmpty(QMAKE_LUPDATE) { + win32: QMAKE_LUPDATE = $$[QT_INSTALL_BINS]/lupdate.exe + unix { + QMAKE_LUPDATE = $$[QT_INSTALL_BINS]/lupdate + !exists($$QMAKE_LUPDATE) { QMAKE_LUPDATE = lupdate-qt4 } + } else { + !exists($$QMAKE_LUPDATE) { QMAKE_LUPDATE = lupdate } + } +} +#limitation: only on ts can be generated +updatets.name = Creating or updating ts-files... +updatets.input = _PRO_FILE_ +updatets.output = $$TRANSLATIONS +updatets.commands = $$QMAKE_LUPDATE ${QMAKE_FILE_IN} +updatets.CONFIG += no_link no_clean +QMAKE_EXTRA_COMPILERS += updatets + +#rules for ts->qm +isEmpty(QMAKE_LRELEASE) { +#a qm generated by lrelease-qt3 can be used for qt2, qt3, qt4! + win32: QMAKE_LRELEASE = $$[QT_INSTALL_BINS]/lrelease.exe + unix { + QMAKE_LRELEASE = lrelease-qt3 + !exists($$QMAKE_LRELEASE) { QMAKE_LRELEASE = $$[QT_INSTALL_BINS]/lrelease } + !exists($$QMAKE_LRELEASE) { QMAKE_LRELEASE = lrelease } + !exists($$QMAKE_LRELEASE) { QMAKE_LRELEASE = lrelease-qt4 } + } else { + !exists($$QMAKE_LRELEASE) { QMAKE_LRELEASE = lrelease } + } +} +updatets.name = Compiling qm-files... +updateqm.input = TRANSLATIONS +updateqm.output = ${QMAKE_FILE_PATH}/${QMAKE_FILE_BASE}.qm +updateqm.commands = $$QMAKE_LRELEASE ${QMAKE_FILE_IN} -qm ${QMAKE_FILE_PATH}/${QMAKE_FILE_BASE}.qm +updateqm.CONFIG += no_link no_clean target_predeps +updateqm.variable_out = copytranslations.files +QMAKE_EXTRA_COMPILERS += updateqm + +# Copy translations into the bundle when one is created +mac:contains(CONFIG, "app_bundle") { + copytranslations.path = Contents/MacOS/translations + copytranslations.depends = updateqm + QMAKE_BUNDLE_DATA += copytranslations +} diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/icons/application_go.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/icons/application_go.png new file mode 100644 index 0000000000000000000000000000000000000000..5cc2b0dd36978513f3ca009c68ebc4150976fc80 GIT binary patch literal 634 zcmV-=0)_pFP)cA1hmXWM zDZ#H?v3PJ5$Hq5OmbDN{wJ%9%wAR zT-Qu9!vIN`896F;t~rD&@Nfe0`Nv1rEgogE>hi36i1p_V%rE6ZqX5JdGmz-z3Rm#{ z+Z*c0z*?bg!mefM79{Zs`zK3~u)rkEuD#mHG}dlY@$@R6?<^o~D%1C9AK Udps;mZ~y=R07*qoM6N<$f`qvmMgRZ+ literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/icons/application_link.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/icons/application_link.png new file mode 100644 index 0000000000000000000000000000000000000000..f8fbb3ed94ca7686a3acc052b06f2d8ea4034a4b GIT binary patch literal 701 zcmV;u0z&gFy@`WU!f)*0Mw4O9TnqBr{Y-GHDVuib)O%q7o!E zKlFxCD=Me;C78Guop0xOj_&HYpW_Dm*t+3@`&{>Re&;#QbB+dp=6|HIxRxBDrUi@fE_t7hH*d!sYoQrtW@#bM76y@j{#K^yGu+Y%mKB@Gh?6AT=?YQ30NZKe^FU`jD8!o`SZhpef2|bb8oqiKx}PSX=Ml zPpyStYfYXXpH2?}Y{RJJ!2oi<&p};TK}S+S+g$})Z3*j525N|?ZghFxdh>+}pxvhG zGk`)6rXB-{4Ai03Fi?wD)KO4x$=GO0Jb&iKa}_{G#Q{4z9Iy-OF-d*(m3BeRA&BbK z^=B$Txc7MvKx%ipc$rQk6bd1cNFW#tVzpdGZF38^haSzwg)nqF-C@mC?4t@`l4KbR zED(uAP_0%`sZ@~5<@oh{JdRSS#JxhHz`fDY(Oa5JbMN<#=5;m;pU;Ql$_i!!0hrBZ z*ladLqfvM~9^R7|U^9XUg3!=7qi^>B;cyr;Gcz0@NfL}kBQlu`ip3)G`8-mo6!&OG z0KeZa(!a2D?#>(jWtk`Zu%CBwz)9;x96LS&gTVlc#ll5Bc_&U^-~hYbUf=g;9bv_m z_?>N1J()~yE-x=57K_24C(^PW7KQHHYn09vi~kY2ApYBHIAPfkv@9S(=c)EgTc jvoejazDXXYzD4Pju@vH55i-<8yBPEX7)KWiaTUbm3&cSX z(aq6K!9ftabZ9K1N$zpDZ;Gu_&^*iG9=OkWp7X~df>lrfZ10V3wcA%79{sE@x`eqS zvnC3Y;c`p@2{TwvKx`q%2y>2aFbo_hMVxp@XA=fbm64jWHKS8#8{i`Z$LyYP0aH`uvS;7 zGECr2<9`XF*|K|JRVcmH7_o2vA1%TD#%5F93(IbN$51ia5yBT#FNoQpx5gGu+zNf zvsodCMuD4^ZR1b*0E5ARR;$J1AG^H21F=|6p}B|Te(u)v`+Wd*n|IC`iwL&&M$duk z5|~u>-wji_2}yWem*|dM$en}FUq-g-HHsDS3+eu@JEN|IH2?qr07*qoM6N<$f->Xd Ang9R* literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/icons/bullet_arrow_bottom.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/icons/bullet_arrow_bottom.png new file mode 100644 index 0000000000000000000000000000000000000000..1a28d8250035963143465ead45faaae79de6dcbd GIT binary patch literal 229 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!60wlNoGJgf6SkfJR9T^zbpD<_bdI{u9mbgZg z1m~xflqVLYGB~E>C#5QQ<|d}62BjvZR2H60wE-$B_jGX#(Kw&{<9vg>5sw;c`@i>p z_kaC=>wowE^MCGt=k0FV8~^>E{g3+d|7HJ+|I4@QcRd)^xi$V8^Vx_G`+r6+RSGlL znKt8REw4uuU$^wNG<`ek&pG#xJ(Hh0`*ZlR^+%Epor$llpY=cF-^u@z|Ed2wufXdW aBfwxkOHd_T*GCNK1O`u6KbLh*2~7Ys?Or1Q literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/icons/bullet_arrow_down.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/icons/bullet_arrow_down.png new file mode 100644 index 0000000000000000000000000000000000000000..9b23c06d7b4f4689dc8c9fd4e9d4d1f199fe376f GIT binary patch literal 201 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!60wlNoGJgf6SkfJR9T^zbpD<_bdI{u9mbgZg z1m~xflqVLYGB~E>C#5QQ<|d}62BjvZR2H60wE-%M_H=O!(Kw&{<9vg>5sxM-`@i?U z_W%6<>VNmY^FQu?=k0EK8(;qS{{MRQfQxhfe|^4DBSLrMi_=~IrT?G*6aRH>fZ%Fr xHSdzT`JeW`iC!n;=N{%MvhUm!=_W-^hCUIl<$=usRzPbQJYD@<);T3K0RSKzPZ9tC literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/icons/bullet_arrow_top.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/icons/bullet_arrow_top.png new file mode 100644 index 0000000000000000000000000000000000000000..0ce86d2b2bc8eb047ca749fff00716b15c5bd9a8 GIT binary patch literal 230 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!60wlNoGJgf6SkfJR9T^zbpD<_bdI{u9mbgZg z1m~xflqVLYGB~E>C#5QQ<|d}62BjvZR2H60wE-%s@N{tu(Kvs0!a}YF0}=J!QSUY7M7z;-RJ$7n8*6-IkwdUVS%nn(+HZ=IM>KhySVgJojLZytKsQlJks9 zg>q@PUpbdv;&|+P!{NQ{65)mBh3B(*yP58!PISKz-O48F^~6K0e}RJHfr*NaZ|Z(M akrr=d7xdAvd!`9=1B0ilpUXO@geCyB6I2-h literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/icons/bullet_arrow_up.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/icons/bullet_arrow_up.png new file mode 100644 index 0000000000000000000000000000000000000000..24df0f42129c291ddb3dd50c8ba2884dc23a2c43 GIT binary patch literal 201 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!60wlNoGJgf6SkfJR9T^zbpD<_bdI{u9mbgZg z1m~xflqVLYGB~E>C#5QQ<|d}62BjvZR2H60wE-%M_H=O!(Kw&{<9vg>5sxM7Y}K&+ zaVqV>2dg?$?}z`N|7UG5-|D8TLf!k;{Mi5T|C#@x_qjwjYRvdu`ttwR|Kb1QzwCco x|Ef}l>({^Sf7bts|6%{R{?h*$`OZ2jjF;IsFRaMi76-J3!PC{xWt~$(698OLQAz*+ literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/icons/cancel.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/icons/cancel.png new file mode 100644 index 0000000000000000000000000000000000000000..c149c2bc017d5ce5a8ae9330dd7dbd012482e0f4 GIT binary patch literal 587 zcmV-R0<`^!P)FS^-G}e*;M)Q6>s#cP zI`Y#S($G6W`W@NI5g|L-MKl0Zmu$m^(0~^Lwo5OO~d#(vPfzRLq zBa83f%q*uO+hkn-px3iWUBhj*zEtZ=#J?K1BwoS4fri4we+W?%x_!2UEjG9A57v+ddMu0 zbbp6n;=LcDNq6gD2L9C2J@8#y?*rTbgTj6Ps|^D5|MCj{`@<*H#t`wKg(3XGf2QyU zf0@G{{9_BdAC4aSKNVGeAq>dh`~N>9tN(u{wmT>x9B`-HYmvir?8JeOFVbz5u> zH|V#x^ai*A`gyzm|72hZ`OUy04pZPY)6&ahrsWHdS>_MiW?QUvoolwwWxnYbrv=9G zAbFr`rQinWXqscE(MN|a!$l4~hCDEFhknBjyGi=*G17r<_V)jl zB|4H8rP?#iOLZRs>9-bTIvMExwy4+UuxQe`XV#)U8P$NSZU2ojH2n=T)ZNqrEM0*# zI5i4uc*w#O3aL7Q*+%*5QW{Y@8K%V=Ja7ZFGq?QL&e;54D`OK7Z~U*7wgHIO|JMZJ s)OG(gKsaSB6tDTOk-Qp=;RaBG0e_Hjj63iYg#Z8m07*qoM6N<$g46R|L;wH) literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/icons/clear_filters.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/icons/clear_filters.png new file mode 100644 index 0000000000000000000000000000000000000000..16288fdbe5ab8a336acc2d0814f628db5b88611a GIT binary patch literal 791 zcmV+y1L*vTP)e(>1_G{PXecQXNhsZfK(Z-hSzN1&6yhQq zyXYTap*uGr5>!Iz!djZv5Go3#nJ%X7%%n_>1`V1YZ{ECl^X@&jn`EdOSAO9v&*ywN z=fGRW0a#mGQzG)Qwf3xtoDq@JBJ#e7WUaM`$a4{SBqD!_NYNPcP(;?Irlzz45Rv(0 zGC7w>Bv4AV>DF2t#{uXTk?t@Ihk_trZ*Px!y?zzA5<39Q_4oIa&1P|3mnez|f&kz5 zsn_cSL4b&mPN(VZ?PYj)7!jERPzRG*+uPgmTrNi{mBL!vt|*EK!;mP7NF)-Z(`m}( zG9uCfI5ZfmR;zkzYYW$P0Wii8h9N-^&}=q|#bRVK8Or4{rBX>7W5(Km(b3U+A~LeE zv7t9NH&IHVwWiT%;CUWeYqHral}d$DsiZ~Z{LIYEy*2<~e0==AF=nJvspwj*MkAOEzfc^{(0Zvvlz_gQcaV!%zA^DMhQ*vhwf-AD)}!c=czv{yE8izN2s|>srTN zRIdW2r>FJG%1Upu+4SS_IG*Qu$9A5*bNt;N`0NtSfwr3O#ucX!J4%0OXy_5}Nfbp4 z3=Hhs6DMi>{yofh6V5v9%sT8p-Nv}~$&rALj*bYRtE-D#F8A#3jz0eQb(O7Vl706W zJ1-n6j~!#-+8dX+xVZR*=Xu|X$ZwsUonOCq^Ky^>;>iWqIH!zjA6xk5)4S%Y{{Ss7 VZm>T!3--}$18ofm>e75iG#yxhDO4;Cz@Bi0tc<%xKTI8}ruh*+8rM^fh zZ#No^pO^g^v&?R{TNOfl2XKvZK4`bw%X0%dolaE2HH`UKx+aNYfNjN+_j}Wf}53U&DW?sTy6^)p?#H z%Q7gXAf-f_rnq|Oo-ZBjj3-H2E2usO@ak^A*q+KjN|{nhE4FQeF$U8#VIO>iqlcyS zN6(kb&MnB#yS1--{TI6z-;${o;yAt$1VIvpA(T?^eILgDJH2-2J~2HPY&M$#=iKo; z@0So_y`cIe-Twe=Eg{<^_`OLGg{LT}_Q^a+?`>S)VpkTP))ptFl5q@iI>C>S7UxPo wBlFhvX`}WyIrAUVf~*u&pJ?Fqy?*iX51-E1Y^HW0uK)l507*qoM6N<$f*&&TdjJ3c literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/icons/cog.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/icons/cog.png new file mode 100644 index 0000000000000000000000000000000000000000..67de2c6ccbeac17742f56cf7391e72b2bf5033ba GIT binary patch literal 512 zcmV+b0{{JqP)CQDsH?WF>AIFt zQuJ}i;w2$ZUU#3SZ6RY0Gw;kZ&ol1~2ky^QZ(fom$=jNJZt!z7w_pH~wdQ;R)Gh%BbQFCx+Nm!4SuS-vkr`vhhrX zM*>w%e+v~?m@q~ImPAgtLkR_3U<2F8LP3W5=LJ*ZN|S5p#sf4YFr$p~Q~Z*0Ngxf2 zjk#J#<7EAlhzlrV53~GF&pIzcCN_lz9@05UeoUXiK%N z#x+4o*i_c|6_Uu1+&TIho?3@y4k-#b8Y_o94zW*B3a1ne2-Y5s0uke$$|@=}OP-i= zNYZQA=>PrZu0MfSL=b8UhD_={W4IY1{b{)U)*gc45xtL%IYLY&hF;d`@GzI&7H&D# zh;z_BX$#hqh@q?AY3sJTod2%*Yd)_>YM0#q&ixGuh+PQsneK)F0000-)HU~Z@BQ7|ITsWqFPt%czwZJk^u%JZL0Ogu z7-JwwQn0tTclx3}?kvID+L{XidsxQ^&e&|W7P?hu`JbU6)Keq zD2hUaNxZkB72a$%4^2)^`UtC|A7te-nGAX1Xrjep5qO>_@7ffX%SGn`-ED7gLpU5( zk(@u5K{Og2Z)$29rKuELp-_NyIt_Job>MI~K&R7bgynLX>`sh~jA#lt3}_YQwqglZ ztJPR4mEiF3kO&v?|I7ONdO%xaZnyg`4MVH2u&{85WF^F8xkx0!oK7d7&*!07ENT-s zHZ~xYO7;1CzImGB_xm6GXq~MiVV0C|gzZGQ)-QC?rN*&h*fy7fxUu2>pgCsM)-Q?tMb$Vds z*E@*sEW?$R-d!Zlo`yI#H#gqa);3B?D6pBWXVBO67?`R6Qy3_qLZ+|_MxhlJx8`9r z{Xs@mdTouNQ0N7+J#TJqhNGh+O#w+J@OC~45~`3D2_z=L-&zrFU%dy%Qdzg0ic~cM z%s{~na19L&^isj*=4PpCtqL-e!E)J#V5X7%DWt(#}Pq3W$oGSy^Pc4j%jrk7_ z4xV5*S(C}slXQfB*Dx$m5ut)=uA6Vdoof#vmX1Pr{o_H2ueAT3P;2Ktrs3gX7h2gv zE62G1jK||?p|odbXLH|f%y4eoeRKHd`|tRw^&nXM?`u5!c)i}iTrM|2E9N*Z__gcJ lE2dmBR}@y4olxbIzJJd{=EC=vF*^VN002ovPDHLkV1lGDi4On( literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/icons/color_swatch.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/icons/color_swatch.png new file mode 100644 index 0000000000000000000000000000000000000000..6e6e85212b85b7ba0918570c2ebede3047596237 GIT binary patch literal 209 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Ea{HEjtmUzPnffIy#(?lOI#yL zg7ec#$`gxH85~pclTsBta}(23gHjVyDhp4h+5iLZjC;k_h{kHThqfC`(hFmxSO zSd?`bB$R({-*5T0gITA{|Fu6pn0eqpx>}JTL$UWimE@yNe}L98c)I$ztaD0e0sx43 BPNV<; literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/icons/comment_block.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/icons/comment_block.png new file mode 100644 index 0000000000000000000000000000000000000000..3b3ee4c4861e100109712776801fb18ffcc2710e GIT binary patch literal 210 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Gd*1#Lo5W7|NQ^|zn+bYL727b zV3ej=1M4%Umy3H6o~54M&a>-!YvLh`m&>mS%r_2_Vw2FTNch(6_)tVTYuEoyT++I zn$b9r%cFfhHe2K68PkBu*@^<$y+7xQ$wJ~;c5aBx$R=xq*41Wo zhwQus_VOgm0hughj}MhOvs#{>Vg09Y8WxjWUJY5YW zJ?&8eG!59Cz=|E%Ns@013KLWOLV)CObIIj_5{>{#k%TEAMs_GbdDV`x-iYsGH z#=Z{USAQA>NY(}X7=3{K8#;1k*-!zk~CMF9Bv_3(^PCOq;$< zN?sD2BV4j9Yl`*+fsWQD?H_4>L?~r48B=l;Spkuc)A?yA6iP)R5d;DO`2BwH_g=3D z!!XcjG|+Ch%jCP5&1Rc|$N`LEvA9yN*EyX%X^loByIQT_h>#+l_9wi@{(Z?D2RE zUDq)j4#hY2{Z&BrR!Yn$4g z^!3C0RHpz#W@n--_jThHPEAe2R834DnuV#1kUlxXv}=C^n7~&>f1RO6h@8fUuT`wRE91*{Z%LW-oO8KckjTdf s77ewwyuEar+*b)ffn+a07*qoM6N<$f>LlT?EnA( literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/icons/database_go.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/icons/database_go.png new file mode 100644 index 0000000000000000000000000000000000000000..61a8556c403a1b56cb7719f4916d07ed82cd55ff GIT binary patch literal 698 zcmV;r0!96aP)U4c>+hFP*|&0tGt{!YG|5fRw@-UpUxK})gOY{KjH!sGG4?RHzSe!mY<6j86&kw_%0+>rt+UvTG zPNxG!QLHl_`>TN6lhf(69Pnfg>e~`ot!6OL_K}%<0mC@>2*2;ZcEFQ4iGwF{@R*{j z7!M|qd3hZgQye2(un7;}EWl(MRHj3v{mH--l93DO%KKRTaX^3MX`58z^<+{ z6<23&!!Q{PW`ItyBW>gC_$Bnz0p8cvrP&8U;E(_Zug)QpWlpZPzmjE&ksHm>&{4WL zcWMqjtuMUYDzy&;xOM)i=ubqW(I5dCx}hU{e1gb^CAKTo5EzT#!}bO?zL#36j`?8+ z3*~b8c`}*w$6_%IbOkHrWx4~^auW|u<6?Xs@2VxNZ5G?Ij>|hs<|oJSYs}?xlO%MH zkQM~t1b+*>9q#P0c*i_HG3Qv{e6_1E^9qr_9C}QDj%+r2jL4@6j4t)_BWY1InA104 gM*QcJxn<}50%n)c1HutrKL7v#07*qoM6N<$f)5Qpt^fc4 literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/icons/database_link.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/icons/database_link.png new file mode 100644 index 0000000000000000000000000000000000000000..4c8204af156dcaa93fb80143717c8894a586774f GIT binary patch literal 679 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 literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/icons/document-open.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/icons/document-open.png new file mode 100644 index 0000000000000000000000000000000000000000..ab940462fd45f9bf1cc6068fe7947ebffdf2aba0 GIT binary patch literal 672 zcmV;R0$=@!P)(v5I2X42Kx^LBZUY}D`;qn5FxciLM_ej_ug~QY53}!mSE3t?zxwHpXWK} z-YY{xLmWiP&4!4S?k*w%Kv5JTBDA%&eg3uGxLj4$`u_gV)z$UX-EZzMEG>UI@$AWS zilRV7*e4MYCSOdRpPrujfO8S}0T9e=aBy(2)6B>@GdBL1m6a8m%_acuPRe$zP^sC?ptQ@-QuCrdb+y-7#+PUpcUVtdz^5edX(lyb1*!_e$Blc8obQwH#$sup8JB=Bvc!Ow=G z*-6b@?P)Q3Dah>_TagQ-m$d(v0_V(!m)T)O474U6d~*>kR~*)xB_j-*@iEJ@Ahu z%5AitAFf!-oAbG^qQ)(`G8mfwRB7l(wXFuX>x$Ys%Ui=jJ-F)K#hDvoWjVU4O7+Cs zFCnDlZL-(QJGo(5rn_o5bQZJu0#XJL2;!}M7~y>#z5-5Fidt(3Ei7;*?^Dc9Q_N2P zm^7em2tVgqYY5HAv+g{>T{ZZaUL+K*C;R0COfSF z>~WSU%)F$jdt3lWU+2siYQsj4w2_^7O<`u1#-H$x0=auV{0;7pKKk=Ncs3AIiHjoy z!z;ed+XO}~n`Sho&mCwPWMTFxacliIIF`Bg3mWL~gfxI+(49+k-es3w!BldRbiTyi zgUu8sQhZ-nBys(fP`#*~^71k;WPookZelf5qS7|$+oL$|KT{nU_1}eaE!C>;{7ItL z3DyYkE_H{(lFg~XDN)ukbsn!#x|AGitRfOJ(Ccgug=cS+DiZc93CECXsvgHAW);x2(IfQiXtebP%IWP91j0UUY_xHHJiFKFzwOZx*d>%QD1FbbY&x@whsabi1 zN~LlQU{6Z9=wR>Y=;-^(fNVA^0bqT79hPN%0f5?yq c=Rz>% literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/icons/folder.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/icons/folder.png new file mode 100644 index 0000000000000000000000000000000000000000..784e8fa48234f4f64b6922a6758f254ee0ca08ec GIT binary patch literal 537 zcmV+!0_OdRP)x(K@^6+>g^d@v4;gkbWsEoXE%32*i1tcpTNXd5CcIl)ECgqz|2rE6EW}s7R?kl za1q`0GCkMruC6-2LANtwVlsgzsp4?{@7$`KBv!G66>Vie3h?3OmEEkjwdLG0PgLVi z`!N((f$A@n17Ldj#`};0I3@iHJ5M{#IZz|UIYRm4(!uV7eYIYIwQf&}_2J~}>pQ^n z6o8--^T(=hkBNQ_k{-_GWE;FMW7!p}f{NG3nHZ{D5<3d8&tLh%a4AqqnjMkr3m&fkMdECD3N5}Unig5wy40;>lo4j~k+e}v)` zR6)J8Mk*u=SpB`p6o)7j?S0T@9?bz#m@l>gc*zk__|*!FMcHwP!gwLJvS~9c0px8E zW>`eEHOekrZG3#;v?6H6fhbs1c-xE%qmL1FD6Pgsp z%Q7MO@KoovHHK8U1J?_FIzK;SjKg2b`K_PgZHE@VJXO=*(cIEX$#{4s+#sCnPFUw_rU#+IR6UWkSw_(UZ&g zlAKBNq7_M($idCjGh@|$KtL56ha|q=$XgYMs^AIOw1Qr{*Wn)N-{9ma}x2(<~`9Go1=*>YR!KZvrBS zCd!u}@M0og%Ev@_;Z?Kk>Wwv=%h_57zmt2<_1msz_niYE=YRNPpd%02TK9oK1z z>ooPno}v^sikz_|1XHFx_L%~;ljh7i(jiay5F0x*+(9aXXFCl?AdQj5XlQ65%sEv+ ztfe?|YcjPN*@yYtE~ImQh{l|#A6Z8iu>pf43Rj52CzU_dMQm|S2xR62YjQOn+z8WH zaK=!}ggOZi{4pB7SQ=xC0n|vXP_Bkx_a)FeNd}w8U97BNbSWxa^QW-li9BZ#M1!_xE*?wzt^GcoeoL*JGLSe_+l-JT2#2tz!z&^ z_s5anq&^nBklIMwRvcoP3%qs%%Ea?1c{_*V*Xj&~uLu-2Dp1fUN4<0zMo$EH>*U83 zm_9;Vt%-bE{_J_!If!1y=c+`QVZ>0_BPy z+%^pgnv`f8H)Z%0&Tp8&u*MCIC4igNW5MeWM_DHpDNi)Zxz|9XboOnitwFq$ETN=X zj-tkCJnz**Y4k#6_Ty^B=hWo~L!47r`HoP=x&3T1)JLr2t2+#fHP)9Rl#FaScf1rbdiwsJlF($-D2a$MB1QH?*P$(@5T4@;&OA53{ z62x9;g=MzM@3B}Z6q2JnuH-? zUBh=^5nso`tIMpW;}SD*?>znX))|eYdi7(c&C5YW8_t?tIU z>Ny7&^Pebhjth`srpO|asbD=?gpU+WKXx%hg}DA%|J1=w1E3bQW2brAk)glQS%iL- z`SP4IjX^57**EKJK0N;yU_Z*GguxzUVD)Dq(FOHK%^eAtSc;pSVFoq==$r8wjtx+n z;uq8_iQsA|i!@V3bf!VptWTH>59QQ$XGs&d#Zun48g&^nWN z^4`U@k2?PS6UX#XYTlj3cBYJ6iA9-|t1JhG+#TUO+}j1X$SI>}h@{JnYgEm?zE + + database_add.png + database_go.png + database_refresh.png + database_save.png + table_add.png + table_delete.png + table_edit.png + tag_blue_add.png + tag_blue_delete.png + page_edit.png + page_delete.png + page_add.png + page_green.png + table.png + tag_blue.png + view-refresh.png + picture_delete.png + picture.png + picture_add.png + script.png + script_add.png + script_delete.png + wrench.png + help.png + tab_add.png + resultset_next.png + page_save.png + page_white_database.png + plugin_add.png + plugin_delete.png + table_save.png + resultset_last.png + layout_sidebar.png + bullet_arrow_down.png + bullet_arrow_up.png + sqlitebrowser.png + internet-web-browser.png + package.png + package_go.png + page_key.png + key.png + document-open.png + chart_curve.png + cog.png + clear_filters.png + page_copy.png + resultset_previous.png + resultset_first.png + picture_edit.png + script_edit.png + tag_blue_edit.png + folder.png + database.png + cog_go.png + page_paste.png + folder_user.png + server_go.png + page_find.png + cross.png + page_white_copy.png + page_copy_sql.png + text_replace.png + picture_save.png + application_side_list.png + database_link.png + text_indent.png + printer.png + package_save.png + cancel.png + comment_block.png + hourglass.png + table_row_delete.png + table_row_insert.png + textfield_delete.png + filter.png + tab.png + package_rename.png + page_foreign_key.png + save_all.png + page_white_text.png + color_swatch.png + edit_cond_formats.png + clear_sorting.png + bullet_arrow_bottom.png + bullet_arrow_top.png + text_bold.png + text_italic.png + text_underline.png + text_align_center.png + text_align_justify.png + text_align_left.png + text_align_right.png + page_paintbrush.png + text_paintbrush.png + style.png + style_edit.png + style_delete.png + style_add.png + application_link.png + document-link.png + application_go.png + server_add.png + + diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/icons/internet-web-browser.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/icons/internet-web-browser.png new file mode 100644 index 0000000000000000000000000000000000000000..ac5957ad62d73408cd754a27453b4ce601a2b042 GIT binary patch literal 928 zcmV;R17G}!P)Mh53JODVWnpw>WFU8GbZ8({Xk{Qr zNlj3Y*^6%g00QhuL_t(I%dL}LXj^3*hoASH_nc#sG-;dWqm6CW(4s83b+X9Bt0|~3 z6mOI%-9=?M5O0K`ptn*G#rs`|6-PnD>5WW=H?uIcvzCo^E3WHYKeL=HA5C(SbCR6b z3)#f&*5~^FdoKR`eu4)${@&~<;4NLs{R%AQ`wgX7&~)wW+|1M$58jLW!S}zMGrL#P4P+<|J^kR=q!LjUR<=1mzj7BLp1miL0MTgZr{|x^iYGDyl!|!#OL6OV`f;PXlOge)!c#$#{SGXl@)s^XbSCXaYk@OhXc|B#CG* zL-81~z96~mqojuij=b@~*=YbR90{B}oE@c7E^@~W5Fg%$Qs65I} literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/icons/key.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/icons/key.png new file mode 100644 index 0000000000000000000000000000000000000000..4ec1a928140311ff30a0a9120e958096c77f446e GIT binary patch literal 612 zcmV-q0-ODbP)nmX^MrbE*gmZ6|p*GkKoxa?X?hD9M+@sRvFH{EqYA??u6x z2pu{uGnrwz*>rh zfvUA@7b#acN?M*mBG3rQV?e^+0R5m3YXWyRZL5Bt@3vAw{9JaEW$}=f4bXO52yBH{ z;G~ZN|GLn>k~{On3Swd-Sy(gFkOdyw-RP%&exwl01RJRp))TI*SsngruhZksQ*NT%!X?K00008-A}AUJ z9n=u2d+#~lZ^M1x`+D&$6(2a9;XLPazR&kLPq58Rq6P3`{qr&~0Xzd9gN+HuWLY2! zAPFT-`&$0`@c!*5$h@3=6tK5TQ^(M5v$(QKVE?W+9X! z*o}&~6c?_FreF)9NJB7b5Nbn{G0n4+%uJhR9(V5R|NFTpb|HgjefT!tIhLx@DR+N) zV+fHiR5Yt19}k|KnCsND{tH-`IMJ)3AE?OtyZ4>Un|6(d%h#JK`i&a7^xW9>`yBy` zS4SOHeOpC7$?hH5-#7Rswiue_8Ju*2N@$58=a#2OTA3png`w3v->gWif7t%e$ z$NLVS!tFT#8WL|Wa&K~+{%4P2cRfwesYV1_!F=3OaRVHl(>=`%&{x*s30c}#CNE@&;ItrAv!f!)Oy$Q9t$uS=(sD$-J{T*^(8Eez1E-l3}} zPrfHZ1`qsIFe&gipuL8-IZbo2Yg{lFGKs?ZZWcOaOdk*3`5T;$?AjbG1#`B510Er^h2)2r3Y{!8_2Gj=$KzuN5 zaErtW8W_Y2iJJjY)5pmTVJoPJYpanPOEuYHclM^C1F>${hFRpdi8a<2H|Xudf78bm(zwJ9`K%6I?q*Ua~ fW9JvIbn5*B+_J)rUMBs>00000NkvXXu0mjfH&TkY literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/icons/package_go.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/icons/package_go.png new file mode 100644 index 0000000000000000000000000000000000000000..aace63ad6f91537268eb6e9bf328743da7c631c6 GIT binary patch literal 898 zcmV-|1AY97P)yqPWur#3F*- zi1-H*6GJgONgz~1E;+_Oe@~@VF-1Iy-=*@ zV9T!Kgk#%59lVt}Zj7B_)9wTKYBy6YEwPxKqOdeGuEw0%cVhe}Yj*hPSBMNYZ5yz{ z4STT*%d9TVV4NauDND$z(%QKb>=kMr>ckh0lFuesOioc=Nq^^8BQNYYbk1@M%M`O? zh?6H&UZR}Ol3%#RzJX5(MAktmg_e?7`2>w^4^!6w)4$9==U0)EV$}u1A)*bPRF?jv zHdar4EJB1b*f+rh!M+8R159x8%Qjd0I{0j+|69pUC)f(>!P(OTs8c~;XuVtXzfO>s`m zrjW9YI38*Yel_NvP&FVfNEx)sn-kxIx;WzEcpe*LJBYXLr(llS6I0o+c9O z0L_4N7u$0%Dx~ks;fjYRF0OIOR}1uPI!MtibK=J3pihiBTv)jD>R%(Llj(_XFa#mG z6Wg=#j7Q7*PFmM*W@B9!ftm;#qU}sCT;|&KtBZ%Fe#3()Pk+9@Sw&8%k=NQD>92qN zkFT*E2S*%i&!MYvH;;DpF?sU}zb4Mlls)au3~BX$XZr12Z?_sbts>8Fec~0Xl1q`9 zxyH%T#p<5UCqrY2(J4oGEHk9ens22BN3dYXATM07*qoM6N<$g3xBAZ~y=R literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/icons/package_rename.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/icons/package_rename.png new file mode 100644 index 0000000000000000000000000000000000000000..41bf2be9eb6df3b2e3d8da3471787b49db171e80 GIT binary patch literal 637 zcmV-@0)qXCP)+3jgIcLJ76PfQOYK1@``C-8grGyNc}isZIJJkU zmcUbjm%V#3vPXK;rOvpk740^&ZZpr*p_IyTlYa0X-iJTG_jz7;1UBLA z({qg=y2r#-Oms7N>G_yfPW)ZapPjE|;u}oVzEina?b^%uH2b2!#823zjHhSB?{u(6*Zwq z-NDPKtT_O13C`ztm>Ei7U+@H^ZTqqMEr+E{8u{Fm#;%(PUmG0|nx-+zkV>VXC<+Y2 zKr9y97|=A09mgqq;_*F>E?BM?FW%n;(|Z~{QGy$P0OZQ7yy`z27h3lI!R zBKTziE1$!^_(LFk06>r=K$3oSvQ>cqP_nWR035+62|$3iE_mG0g#SU9rdjqGRaFrV zhoS2_R8`$57*9n4Omu}^>e`{4Y1n(D89vz$SQ&6}8B5dsaBUgecb|o07qKuof&9w& z91}kRQQ!JErF)OpGEpbHbiMxQh3fiHGw{8LuOCOi4#SvygOv}%1t#icqU5Q&GYg)} zG};qtWS3MXYE@2O6?S$Oi&GPD?D>8sPDJj!A1k|!YYaaKMwzG^L;)tcfAUslz$^Cy X0`@OY3MLOF00000NkvXXu0mjfq4E`> literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/icons/package_save.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/icons/package_save.png new file mode 100644 index 0000000000000000000000000000000000000000..35eb7632bacda95fcf0dbea9242d79478d9767ec GIT binary patch literal 888 zcmV-;1Bd*HP)B1zp*N zAK;>02vrJoqoRTfOQ9fQZ3MA|*n)ClX>&roAnuEbB`Xc*z9CnNijjCoikWQ5E@Q``+`l z8wOJ&!@CfDE7{V2Z^vCvlWN%n8WFGl%5S4bxUFv|PWpDjYKi5UNh+mFKdH4xcI+Sj z+DwfMe}>4Oww~Q4)w+eCvceywOW0_gdUc7U3E9}y3&ARhOczcnOL=LU<(WzR)ypSb zwesSfLm!xWWrg*nQ6wsp^h@~VCCUrGGqC$OUSktf=g{g5raaAt{8pM<;li2OXI&Mk zDyF$1l_cBRMXmG;>6RSt7WR=%!^u-IEg8#|VjIS3Ba_~VsA09-&Hcgoz*P|tz%<}B zZ^BDv35pZc{D21sdl??caQeqZ-hN^8Kic|yw8Yu*cQTGzK>@I!A-GMX+PC9}b*@!n z0KS`8z99@^D2Gs5i!erT)Y`u`YC-BCK4^&J7!nF~E4+7L01?HCl0ZniLKudWs}Zh> zG&-IKG(vn8Bm@aac@9BX=kUon90RcxdBd?V%eseIt?TMU~2T0%{)cEwm%e1At zFgTR_1@_%@42Kkc7~x*O?vDNAMc~cxBG67=JY6c|L1R-#TR>fC$3^Y%QEnYO1xHsf)+GU`3F<{J0kR(;pbF3)zyg$H+idfnl-wl5Wkh!vUH z4Z32YP=l_}1rZd1W_D&^$A($A+&a0e&P?xx0!ctY2}*<#p+qPVN*B(YzvAWXa*%bzq z7Fz41LKILT(GWohi9|LgIzSZBhb*Zf6R6O}WYQ4GOi&71s9lmll0x6;8&ILOl$j(c z0Z1T(6Tg09{?wd{moFHNN6PS?$|e>1MxSJ(0Z7o2)J-Zv|>acY@f`(Y@g7GwsEj5NLQo+q|HsxQ5}XSX_d@*^A9ZT9=A{W~j+$GyI1 zc4oqTHx@1FlRjw4XWyPN5i2~l_F3@aBk!0yu^aoRDvXy}8@HCjUVQUsuSH4$T5|r< zzZOn^?Wfa6y|Q($Hx4{ws+)wX6-HP4zo!S?4KJ@7PG@G3G{CjXs(p*kIrj6rHs7_y z+=<-=Q62s9FuWa^X~WKgJIAAZJR&XBB002ovPDHLkV1jCMPILeO literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/icons/page_copy.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/icons/page_copy.png new file mode 100644 index 0000000000000000000000000000000000000000..195dc6d6c365d298e466026b37c1959d96119ea7 GIT binary patch literal 663 zcmV;I0%-k-P)^@R5;6Z z(>-WZK@^7J_sq=QY_e{46@P+~LNG}sRzZsxQHvCsN*h5ir6^j7pq-$xu$N#V1gx}9 zClV7;5)7zih-s3DB)G=7|99>ji@So7-P24n=VQ(@GctDX!^_@$bj%oviY6e4Dh;od zooe%Wvs8LEKQ&&bL&@bwi=STIAI@!-gB2jC5+?y?VR~VkrNxam-`6*8&po|RZ5LpS zNKdJ%c4bTX`XjKsnecf%W>1%6WT?pKNdLLq{=(f(Col?P1+oq@R>)W(n=x!|*BIIh z6DJGw_w`)u6yN|vAhMteYK5#b%r5^v+VCFl1IGssaclZZMS{vs-LJ2$)n7DAr6==K z<29#%AXsBsDoO}SBaXR#_Ap!JKx)(1)3O2pj0_dYWz5By*X74fRT01$Fk%P_RzOMDtV?GU{nsYq#K8iy zb6qzLYDj`_f5$BwC*WE(t0m#xYJ*=jC2|HQYHh=pf#QG7oowi`h!L!{DB$8|qY{~X zu8@sU1tWq;n$XThR0%;45mdqXM892|{CJ@0DS*}>?ami06Q_^tvM~Y3K(_-`#m!8f z8f!QIrH4y#61;0Ym0cCoLl8{IPombPHtnn7%SbTdI&G-d>ZQo!_wBMF9nzX!g8HVY xYTJPGciz9XMh3w2fmZ(7v{)r*QZD48?mrio{~IaoqYQb8gJ!3$Mw+U>R#t#)^2FEiiFIJ1dFSZ8K3 zneUtP|IYcHb6Dk_?M=B}UkL{v;W&;31~LZIGIT8+zm^;_FWugGGv%&kGgf`S`hDY? zM*mM^P-5h0J2r$RATtS%I-2pe^W)RrX#bw39XAr$1UP5h7c*m0BpE>uJzaVi+G1az zDn85|Hx~;^$}0kSYHc=Wca1x67>PjP3S{nqN0Q-{6%1$tD9V|Dl@r&ZC~xe>{|U(M zhLJYdo9A!6p@N_lE)AQCuV|wv49K60S5iATrH?&B%)_a}UoFz6% zseFC;o_pu+6(~N%>1gZp%$YyOIDfQZMEjR^wZu0SElp3ccWVurFFo?qY}xNwIC;@X zOGz)*?8K}Ii^C6ON&%X#@ro4{$-=_XmhCu*cK3QVAKQTCrK`~u@5alIFQA!me2ukX z-q`XC8&y_UJ<(cDb1EH9o;mrm{&0P;@zjNUGi@@T-){?HVQ6p&xvC$1k$!N_|6!x% z_;+(g0LK>>i-xNWKl-A5vJisBhhyBaY&>j!i2mqzgeQlozyzAuM2#MN7<>m!Xpjjw zm0OYyRPPT7#fD)RERYwlm#kcxxP0Pj?zEyAP=hK7Oah&R)3tS!u!E{2yFhLLMK7Ca zL$AMZ7P_8bIjYxjPujMrQXe;e6oy`D`1JV`dcH+){QL=6j(}wgq^vX;3A$pkaI9$U z<3po_ZRR^b((Pn=!|(B;uCflTuUiou8OnsqAyMOSfO^(V$K@wqS$A=n+Y5hNRdcmz z3rjAWT}Cl+*mV7Aj-YSiM{?PX*vKOJ-x-2PrO01mnNG|mkw_&5xlak@T2dxgw_5J7 zWp47~iUf+#$P8~bfz7wJwo>h<5Uer8ME}jk{g>95ZCP5t8&H1%e*`~Eqa4q&00000 LNkvXXu0mjfjK6$i literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/icons/page_delete.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/icons/page_delete.png new file mode 100644 index 0000000000000000000000000000000000000000..3141467c678d2b53f79deb22086a9cb3a576a08d GIT binary patch literal 740 zcmVP z|1Ep}yDQG09bP~E^Dk?@JiKQJ z6-pO(3~IOP)IYisL6D6;oAEd;E%zR}{U$rMRNuD6nQV7nesKS>)yLo7JuDCrD>Abi zbj3uW23?^GA}9jQ{M^8v?ejL?HaT7AX5WPZNkBmfN`w-jL?{tT7ykZt$%Yln?p_m~ z-?>&d(LD(jAd}h=LPltPQbO$*Wbyl@G-_k5jXbb#qffHY03>M1jfEqoPJQ6Mr=Byp=^jfzePZV1 zLjCmNi31hdIJHa%e;5g=1(`u3BRzfeExY%=VCu{loOr{`%2hUR*x>tL^W_TTaj);0 zpPR6CUD1+0>4TQ6zVfH3TQ;%l6#(_%yspK@3gcmG#Q4!WCPyLU93nMKk7E2pcA=l45({2jNho>sdF*A~bA zxX?-cp~y_z_kFf+yqu3m#QiB}03?Z&9vvR5TNgj<)($Vm)xq5G>|o2sFMag&6aNF+ WAT1?sQBYt20000iHtsh1EzPArg^Q zIZrOk#rNsfjaSbMAL;<4h;Z=jvu8dzyz8N&Nb7=z03ZUw?9z%8KQEa6yM5=kUnka& z3?FJk2}L7q>na=T#;<7U*P91xfF`;`6%pVgWgRy0?1ZryL@%z52=-!fGXWGEn4M351L4<+7eDgwo|moqXT+s1&Kmn>-uQQ8mL7XY)w5Zk*(g+<3Y3tmkR!bL zOUKaUtj_pX26sH+=Iorwu}MGd`_%O-_sS}8VpG#fJA)Fcs#ezwtZf?q?Ac70mDv`rVs{$od?VPKeqf<-kUjNtS6ecB*mq<&M97K^6IVsDO zt2$Ru!b+>2S<}_H>$RcInusU_8PMNdf(W{sNlJ3FkrwMJPeBPO#d}Y^a{9TH(#{Y) l0D?dWAV4eUJX#h`!2gmISk&ZKd4B)^002ovPDHLkV1g&sd|Lnj literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/icons/page_find.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/icons/page_find.png new file mode 100644 index 0000000000000000000000000000000000000000..2f193889f7ea091c292acdd684c595dcb206b5c4 GIT binary patch literal 879 zcmV-#1CacQP)@+1&aazfGU7ezSm^v zpACwO+tu0su66!(dT=`e05DeeCnCFJW(8|RKtKa{4LGONnx2V85A4m%PEQ?MEtR-esdM$pB-`H542D0)N2zSC6Imf)4L8?>%ZrW+H>xCKi$unm zvGZq-*Q%Aahx;C*=l+K%-?>XB)6TB$-L$r*`RUvlA`xP1NG2?)ge8@TQ4EN|Jks0u zcDg;oFC#-#R`YbWB`D?Q`1#y7l$LXhjSLf8AvQuB84}i#j0^!#g{VE#(K7h@5pFHy zSenl=@XBEdxp`h2Ji>CR%=qXJ7!e|?paKet-~;#ok#jETyeB(5&Bkhp;!+;51~G=) zH?L7xmDUu_h+a$+xuWom;AWW!mS$%%+436Rjc@}y?l1134kgD0AOf$OmjOR zstUlshZk$ZC!bAyIg{Y29z#&@3SJ;6D4+_eFume9^#TmMccC5u0J!ZCTnO6m$lnD| z5JeFHf`Xs~1vP>RLKI1GKDY<~pjr2&bi(fX;6Nj-ss@Ds0CcoO0H{JsEQku7X{9v}TBwioCtAe_YGX`Fn?y~UynF814sQCY3-+EISbMFr zmH_O1<;0=3O8S%v13(!NSl%XJkr3m=+!Z?}f6cx$diX$-WeC8duZ@2D;d2AqRb`EV z!)U<_z_|QR#_*Xr{`_s}+V>YOcGM3aSOV|>>SSBVyEWr8I2D27D7i&KFs^4g4|T7m zy47DrRE`O3=o z0kjZUSW!R)ROJ8TgsH37*|aKSM~CqA?ptt)d!l9GhF9-E5KM%a8>rwNluY^giqVXL z7@ItBM~Zk2Hx(GnOi%IMu}^sStyd8^KY9-pL98H2R7kv1a*ot1v6T+!$jHc(Tf_NMZ*LFvdYv>)X)kAd@$m7Ff;b; z>Eo-nz3^Y@;s-KcJSc9K5m`g z#?HN$}qsc!p19o TDeYh%00000NkvXXu0mjfp>d2S literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/icons/page_green.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/icons/page_green.png new file mode 100644 index 0000000000000000000000000000000000000000..de8e003f9fb8752c09e7f3655d5d8664b5c62fc3 GIT binary patch literal 621 zcmV-z0+RiSP)QqUjAtB;_Vvt6}AS_5YgM`Uqu`yva+H8^=4U$e4gHb}u zAQ2N{V3A%pO|?Pv?tb6z=jC}SiRa$G^v3q?*6XcYz$p|cq{uLj@#~Fi`J(>5{@&&N zy%T^+;>8cXx%|o77anP?&W1?1A(>-T49z9pyeCl@7YI+Si zKti7=B~``}TImz(G{0PnlQA3P#MAd}sorMjkP!50B7$nAkU^%#nl{Q9lW0@}9fE-> zN(q7tRuiC_T1r|BBtVBTlQ2+70$Rf;eF`Z;lx46Cpu-rEgb)EBKq(b^W8l<^We(`D z43?0=01z<3G6+UUv6`CsWCk6^93!#+<;ws7007{zS3k2k9-zZKFO~(k`>s0y006+1 zgF_jyIhsL-`FMf~JL~C=cV75(CrJ|q;MVO961G=O zm9d)YpJg5g(4i_HKL75eSE}mq$Y}r}hyVdcV~p>6a}oXr80q`oj%+s700000NkvXX Hu0mjfPs|!l literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/icons/page_key.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/icons/page_key.png new file mode 100644 index 0000000000000000000000000000000000000000..d6626cb09eb11a298b90a8a27b0d8eab41f49a82 GIT binary patch literal 801 zcmV++1K#|JP)$lC4gU2-`f*>nhR-;k6IP7e>YO!0^w)WK%3$w02v-#>5Ep64PCP| zJihT#O|N+nT7XR2h7dAB?UEAOhJF^mol1i`QtQB`HSY}RE7=r! z)zaVIHr5?>v2Gz&fdYw&2ug$!p+txby(aWZ7(4QT)l2`jX7eMQ{>)lG6ev(fWKxmH zOr%mM5$6B%u~qGtCf40#`mbGj3s!n+^%wnJ&#rl>g<4Z)lB5J6f!?|AP275)Zswr* z%T}4~{;_(?waU!#?JabbF3Cy-kf0{R{z}6$e=5yMQKt3BPcl2>zoTPMqMwF;3!_n|>sT?~bK_-2O_m+o>GJ6h zt=+g$4n7y%1qVJI7*5Yw(hqM=JusY{d}*?U(Oj*gT655eZ>Ksn(qrd7v3}DX1}C>` z+X+8@+4-pVq_fxG zlU}~Ye!0+%>J+pPk+0wV{GM$QaYM?5ux)w2z59=S&H2+K?;gH$bZGzL&g5>G ft+noNiyiPkP9r@8gT|RZ00000NkvXXu0mjfuqTIu literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/icons/page_paintbrush.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/icons/page_paintbrush.png new file mode 100644 index 0000000000000000000000000000000000000000..246a2f0b426faa0c7f5ba009e32b1deaf88d1288 GIT binary patch literal 813 zcmV+|1JeA7P)otxGRZMDZ!_a~nK|b_-`n%VosaL{KDuPV10`(1LIen8kX2Xff$3BE zah#djvFGJ&eE^89Pk*-O^+&d>FC~^GjRYVQ(uuPJyS|-v?9lxA-+tM5>1Qu*n+Ir1 z6KhA>X4$XDH6?-|E5oe1E?pQ5-M;2xw_ex!x}I2+b=}mPFW$U%^;o(Zg*LP!K^1kP%8ynsD^= z1y^6xD1#GLjO{VLdh@0GKY7;d$+NGukV)GRLPn^=q=dF%B#XaJrNP`0E6=}e&Gj3d zKJbQre*WXt!60_DnIzgMQc6S#fvjXxsE1v7;T;njHkdy2miIqAS(nX~o%cO+q+b#h z5tIleLWvL=dQE8OC#{%y*Tnku&K`Tuub&_ELI0t_ea{@3f>Jv&sYqld(%}3_GY3Dm z;O{3*Y?v^A`a|D;^qrM=ykI)U6QHd%WhO~VF!SGjGn0GOZrc3mGZudNl9{Q#X5&-F zuGwVReFLBjE5jr!!^-5*L%!I%PkYH#Hs5rMrEBl^)9)9XTD;xjHFxVZMc3~Dw6#k$ z(-S}RE$bgMHv6Z`mS5|u$$78sp4G-8b@lVkl`HtEv+MGn!F&bKcHPi$$oP_;=BrPf z$(~b3&p3CsuQxhoV$%jIR;`lB-s7FDX)xCTXuJ7ZyIQk96uIR=HBt%-P?N*bp`)EF zq14c}QM+O70NTOa@V~_)&GMZ$^cQDlkyOCa(H3Mf+6xhCuZh`VSN{cQBl5Ys9{cp( rh`2H3A^=GuC6HjQ*7|*0>;m{7QlnX3z3MSD00000NkvXXu0mjfR5FYo literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/icons/page_paste.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/icons/page_paste.png new file mode 100644 index 0000000000000000000000000000000000000000..968f073fdddc1cc0f0800b1ac4001cd9a55f053d GIT binary patch literal 703 zcmV;w0zmzVP)AVs!l4K}n~L(tL`6d4Up4iSWnZ3Qg~4n+_J zDGk-qQdogO5JUtO-d5pRp7Nd7_r1^a|M&Zq%mn9Oe((|e0sw%Ur!K7T1pojj=U#f? zQM`qbQrM^DPkwa?DK_be^~z<~RgSMIa<`xP_4P7gg2jCwJ{9^k!fsU=#Ti|%I3p;>90Qd+7|~0h&mIklA#nb>ATL2+v$&u)OBgB z;nsHb)I&QRKeX40H~~cIZxCd}5C} z=79lXoXK%6YlyLtsV$~bSm?Upq|DJh#{|*a7XMm`4QJWZ>s6nL2R1|&J z0VPEwJ9?!n`o5PKAjc->P1Gi8BY*%!5&FVp=#)$mMJYul1Jton}gujiUf??eOy!x&!tsjxy;=Q3_DdcXx=a^OBhW0N~`A@4xB0a*%F? l+@c^sQA%W+?pa#c`9H5UNfS6T{e=Jk002ovPDHLkV1grvM=byV literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/icons/page_save.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/icons/page_save.png new file mode 100644 index 0000000000000000000000000000000000000000..caea546af549a0302848f4f478c5bd4aae15bc01 GIT binary patch literal 774 zcmV+h1Nr=kP)SV2@MRD}JQ4(c%G%=dG@_vxH?>gcH#*Ue2HC}9sapf8X?R$Z;XEnm&g zW99mh)5jNw008mK8)r^`_{yH0rNn%u1|SpC(tjf#om=+r#lh+?Kb>DVb9`|C0Bvbv zN3U(>f4-tAC1hosRoA7p(b(hL*V}(j>ug<`&U)|l$6o$)!>PBQ9RQSwn9asj2p*|xhU*R^vq?*Twb0t!lm5}`yW5lRy-U0ZYK?8to!;o!r!XeOE$ z0HB3T+6EEoI4PlR=wonwqJ+TvCoWh&$?CAPVYcU= zD{DS0?AkOtb@-hh^ZLq~FMjxYf19X?pa_YqtgZGvv2TaxcF#KT?O%=_*a-kW_;N|D zakkWsOe!)HsT5WRBiC+p;N-c>0Qwy(1D2MDBC595oXSiR07)sKNk-%9*rDBOO^HUD zZW#;)R&EZpqha<(HK$(tZYU#V29<@0qCXgU{gXeGpc_|pTqQD-WO|}%yKZbeX7k*H z2W~CK$v8NBAq~czrc5A(v51g0Wma7`G8}f=ZcuAiYYxZan@gP(;Ku66M6?bquGiHe z3Q0ya)%Lvk@kLixZfZyU@#UFbv+>pYhcj8TRKSr_sWG8i^X~UA**LvbD3(_Lba3xm ziYcpup*A9qJ$?AA=Og05lndxfwr`!C+O~h|B~4 z01q8H`StcY);%&mId7_+)76ovRpeNWRp&4M?#jx@|E-)x%P*A6t^fc407*qoM6N<$ Ef@ddc(f|Me literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/icons/page_white_copy.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/icons/page_white_copy.png new file mode 100644 index 0000000000000000000000000000000000000000..a9f31a278e17993d8d4e13beac2f9d5f7b42d08f GIT binary patch literal 309 zcmV-50m}Y~P)>s`J(VpX#y^kqzQ;#=2x({YMw9Q&ndHT&`BD$#%Ql?{+)-OuSA`r}MWJ zVg+2Gc(GW}a=BERPNy^;kEz$|38dTYlFQ{%5S!g@|8f8D_!Nu9_Ni2glF1}xG8xi! zorc39&F6EPOeWOt_XS`W2H_Bo$MXugy}SEctJQj=(TLXTHL(jRXfzs>NF=0SHk;94 zF!&HjdZNX(3U3;LY64IMX__Xv%_wjLC!J2`0Jw?X=zPK$C$`&dYPDKaC={e16bcE@ zgun^<0k;ak*=xLE)@(Lqu~MmsFoMCLY&0Qog`NO(h@kyxaA%EbwJLy8sU*Vi`~52K zX0wrqW;_LmMq@evX4iAM9Od(Q0eHP$1%L|xAh@vrqB`HPQLon}f3aAka=9!3hr=O- z5F9`#J_7Jhah=U(4RjaRhkS4Xkk98kDz-`i!r|~~AQ1TFcDw(@<8g{aBE)l)PNxNE zI(RPyc>9e{@WGSMU%i7*v{!&P$WLz25)0oc=Dl-yy%xYZAm4b-rttL7UjR#%`#j_F R;_mC#5QQ<|d}62BjvZR2H60wE-%6;pyTSA|c6o&@eC9QG)Hj&ExYL zO&oVL^)+cM^qd@ApywS>pwx0H@RDN}hq;7mU-SKczYQ-hnrr=;iDAQMZQ+*g=YOM= z!QlMQEn7FbaD->uKAYgo_j9)W&$$zS*W9}m(ey0q$&7l-XEWO0Y(9M=SnhLbwy;d>@~SY$Ku*0xPvIOQeV1x7u_z-2-X>_74(yfh7C znXL|3GZ+d2`3re2hs?MKQ2rnAt>LM%-F zK|rtwgcU)}7x~z1Hrcs5bH*ZO$!>xO8K#?==bZPQ_ecnV>#P`H`QzGaRhd62G_&rC zTLU$c7_x*nFP_dW#Q+*);mMHE?j)HexK784D4x9l_tfpz2$@1y}9rkF+ zI+J5NMWeZyObc!d+rUc=>D+uOdAOg#%+Ej6h+wn5^xPmVVH*Eu446Y0A_@ zo$rlds-+sL10DbwHdg4=I}KDOKH)5`dDSD>$*Y+lYhxmAcGuF-%MWsHUJr4IgaCsM{ig0 zSSBT=s4DwP*iI5?#me_ElhaWObR8DO+&EW-R6_iOTG;>$!^9AfH5RBU`HBdsS8XyAx|wUq)E7h=Ss)mVnuwi!$R3b1!m9&Tc8e2Ah* z93dsPSIWMcb|P*JsnqXhvE^WDxdW*bQYjAj-)O1aj{;`q7kRbTjhQIKR1t1J@W^=H z&KKSDw_e_z=&`ic2;k(#VF6&)C&;9iap&Jt(%M18^cYK-DUQ?~rD9htLzB%~biuWVi^wq=sbuS+r^MZt^XM4mKhUNn@-HDRMN|w*p+XTw5ejxoBfqGYGMX z(mxA;rQ{;Eh;XXz5&+jv+-LAZKk(eOLY8>^WN4-(D|NlrfBplBR3bVVA7LUsOjp|g zy{|9gnht;`^xt0nqUO%>o{FmI&DMtF)b45G)516-?}wS2P4@j4U=z{{Tmg0fDWHG! bUcBoE0(26M^-PUO00000NkvXXu0mjfKPpmF literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/icons/picture_delete.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/icons/picture_delete.png new file mode 100644 index 0000000000000000000000000000000000000000..cca9f535d9a699716b2c735d0d72374472b9e1ea GIT binary patch literal 744 zcmVP)hQkw$4DenXv_1k19q1k|i7>6Y(!p>Gs}5>iPV z&!aPy~rgIO_{C4dkZ zsR>k_stj1H2h_AgX+YF5TH#m%V^&Vp0x+fl@M)z~j$m*Jv?7oSAwrZ(QKF$u*tP{m zthQiG!$Q<-Z$2x93SWCz>;N z@|O=~WGn`>v{S8}AU&TvrXK^HBjlLS_A2{fi z9kE7URXC0c#|c`x8VSriV9%*u{Le%1vY)0{oXs5_c45r)I=(B4=z47DhP@!fFO>QH z0C=0v;craC(Thvo`;ypNY<5D9c=%{=VqZ;}9mcGE1D(-CbLGP`EAr$5!D5yQP@1<< zHq*lVt!kNGcenM0nj_az3F$c2B&EFMYtB~ns=5AO0D$4{_RHnM^m$u}4rQAu1Gf)n a7BV67Uig7b0z_wp2kkRjeX{OGU(8H$_BnrJxI2 zYgf8Z1aYIHLaSgAOBf`OQi|_q z1L^n?A4@G9O#>X0iwC~zJ`7+;C3bJy(9+;Iju1lU|Kv%CqmXNNU;Y5h0cL$^+qNTq zyZ;7{DN16HOnRJzStL@D{B(k6FI}qC3Jg*l-I*blLd-*rAOcO((F6qA7@7KUY-@y~ zUm}Vl4BMu?WeM5gYHF=|q+ICA0FZ#D34AqyWxkIeO+9pNK>MVS5NOzoBR(E$7F1q?VDFq+r9-q zcNwcnFw!?b=mk?=WoG?52ZK`wiKQf#k}v!TdRp2LW|5}OF5IPG7i_ZcJ}<$N=fj|Qmw<{WlS3PTs~E*h30u3Wu0+!MsALn%mSe|2{r`kBGYM;ZG4 zA$DsgUOp#BS`W{b9~5FkFJNk1ng@Oy8aBjAUQTxD9n1zdX_3 z|EYp~1lYByuF~C}HrA}jpiKW^Wqe}awv&Gif3Bf#0dDv^qSF@P-T(jq07*qoM6N<$ Ef^;Qtp#T5? literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/icons/picture_save.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/icons/picture_save.png new file mode 100644 index 0000000000000000000000000000000000000000..777fb5d2e6a8418c573972246582c21d2c4984e4 GIT binary patch literal 755 zcmVe)^Pp+~01yB`w`9=u(Ho~0 z&q0|Zy>{}2gZl=9K}x9u0000cnYNkw{OYaOaSqCHmHYkvAYHn)ZsML%y6Mn?Rm1M4 zCbIimL%-gdGZROY_IT&jL)x4YKv_2wMMsgSixr3VuIl&xwpoodZKLe>9X|MwKbLly z@9mW{08m0kQ6yEY>2=p_>};yqiMnYtv8~_l+pdQ83=1I;07}RxQW8y8wNsO(vNNsJ zxzT2%smQIeNFo9Nln_CYl7W3j+smTUwfx(8yZemmMmgIvlXtBAH}d|cf5_39J9FWB zT>bgZGbKb&6v=F7!JU=6<_61l#uG1|c+xA2v%dWPU+)_++yuBPsf8gS*uy8tE)TNP^?wUn|FBDi_)Ep5))oIO#kS?(pBVA^IE&o0V2 z1UkY@NmW(0wrgcXNO*bi9DvTz4L^KUm{e2mUH(gvXxc2dSs)?^X1ZCKKmdStIIqc} zY8#!Ri;%QZN+O4dtZAm|x={|gX;Yrg9Xs$WDG3lp>Fmkfnp~qGh?EV=o(rGc zc5iE2*(=lK&%R!Iu5ROK1ORQ0xsI-E$A>rGws+=HNnvgLk2jzGKw)59)ygxcj-Lkr zfNySo7mq#2f!UFlj-4>yTcBWLvS9zN#!QbgB`G2R0KijcuYCLXBg5zC`|}3n1DZUQ la+ac%)7bB~m#l70{SP&gLHlD?H{SpN002ovPDHLkV1hOfWCQ>J literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/icons/plugin_add.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/icons/plugin_add.png new file mode 100644 index 0000000000000000000000000000000000000000..ae43690ecefe7952ef9b0a410614d014299bd3c0 GIT binary patch literal 691 zcmV;k0!;mhP)!C{kgV#7nZ!}+IFwq-SXfjo|dBU;$2A*R+N`fo=|&GUYL?n@~UJ} zRwmI}jPAB8^01Y3C+^Ijd+pCXe>~g?4Jqg4)T#41=X}pOfxGiRR{6W&>CB0&nI=@t zRrSu<^!c5C0)&<(_cUQ7TI*VgHN*l@P5-TfC4f_@-VY11P%L?g;zAJ-8T%U`aCgp( zo^&%s)zGr{_QtkAOc?cV zQv@Ya7h%t}T`nSsD7Oy`1i{aDaBT3P$D8A1r!%M-=8CwXt~6AISyR6jGsiIoM;>tZ z&|vV(9f&CEifGyEVzQcIGxNN8`GVQmBE|UvZp9xX9KCnIMU)jaD^N2^UMg#1ikMNI zccRNH*tm5QYno!*e}0qU>_gJsE$2etD<@XAvnsrb$ z6AdYytGA&+iFC(ifFqRvB@qNA^X?fNqMb~-l0^}rXPZ}>v4 Z=Nr{rY9&UI$M^sM002ovPDHLkV1hoZLv;WE literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/icons/plugin_delete.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/icons/plugin_delete.png new file mode 100644 index 0000000000000000000000000000000000000000..d9c3376d4593e666a148192e2527219c09402b0b GIT binary patch literal 692 zcmV;l0!#ggP)o z8!8gf>Ps&qN+foRRaLf2cODK~N?MJ?TqgM?^Zm{DGc$p^^FI-u@A2&5i4il6tD39o z?eiNi?f9EO!QA5G6&UfRk|r9;8Uj(>xKIak1WvVG9G{lyOwMy;rZb4h@InHCyK`>n zq?;+KhUT-kM4JOKVJJ2HSwvM;3q*vgyRJv)Fi=w(iyJUE%pJ!9HNzcZ)v<`W;%+<{ zeL6oxRYlz}HD~zzLxP}i?Y1B1u$G@Yd z2ufv1CA+WfbP+*B>1^)`g5USxNTS1I)iFjs4x(n5E8>Q_QdSsYW$7x+9LGrXJ>c$v zMDWKRh$!lcXg=#qv6|BO>?Lal?hs0ik&TuzSreVLaQI%kizwwq<)|4s&*hnzB4)Hb zOR*_kK=a9qwZ3!*05_6dnry{5ig?1;u$aIZCXe_18qqjr!gMP5Vz%^zuIR zoMTC(oHezz^gs8bVSt#mV?pSB(TAuq zGoo*^V8sSj*929MdxF}E#e_qJeEA@}eix|YmxF&j=SO>19nXv>J3<=NYRKO@T-n+s a7k&VT=yiY6-x8nz0000^msfbTI z9jQ^EwMRD5xNEm*sJPjH^k)@gXT@kl5ii6#6jNXX`Yb0kVgq(zut?ZfbRr+DS= z>q{33dTpWN$tl6c7nxE)4Qur1GCxuUnp5Y z5HK(>u&W4&EXz<>UtfnPivJ`O3Zb4K8yl-}7K;Uh5XR!-B2uXo6E#Dr&Ck!D<$0b5 zXEK?PNF*3;w;Rc15`MqGDN4rSaGd2kJ3GNmOiaM%^D*ppJL2&;mX?;95{t!PwOY^e z?d|R0=pOKTy$qMj1$rk8qtS@b(NQ*LUtb@(y1JlNtJzsS-`3U!Ze(Pn>hXBkfzr6} z{3Vv(2AlG1;RQN6I#_mYZVs)jt>6p>!_3go(6&ye1Mdo>SRyz&A^1T#%t=UROW6Bf zz^9CeqErU&3`3<-Da~6HQ^UW&yCT)$Cu literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/icons/resultset_first.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/icons/resultset_first.png new file mode 100644 index 0000000000000000000000000000000000000000..b03eaf8b5416fa6878165d95116e73003f8445f5 GIT binary patch literal 522 zcmV+l0`>igP)ufs8f5Kzx*fI63}@)AAFXgQp7K#X5)&2^7g z_9O9^7^ARqyc%qAP{1M7?|}io8xW>dotf=a%%ZSXBBI&Rf<-t`#(~H!2g~*8&15{# zVXjXMwHZYVJ6lk!gb6?r$g;SuO>QI;yeQ51#0H@Z6sk_ajqECPZEqLq!PMf5MQ5gS1i(Owi(ut_CY*w|Psf-Iy6=08Y` zHnsuDs6h)+OwcBqopImX_v1c`5LkrSCWWWFUvW71z%eN$cB714YVYtd`}$X<%JbQ) zM;;CHJDu;#-swg0iul07{S&4s!M>4O+`c|6_tW_i^y+I%|aPsIlEx5K=^ki~8LwqDy-)t}thx1D9 zB6|#ECQ%2a60OQQ<{6-)5|okv)6E>1Xpv+@iIv@MJ8v15 zR{N~1_2z$e&R$WgNhIQelIl1rK}5XruIN#GDZA_4bJqcqID*^mXXFcgt1K5iK7HPL zwLW*@#tu()#Cyd@CHc^75Ul6pYT4PCpSeBE)hh4bY>IO8de(|Ml<%@O-40!dwX61{2C5s-llVw2V@@N0oo_PPieZ!0Y2~+R( zk!(QTf=B;X9DnzJ@u9c>OP4(U@7{849!UlyO@H`*;lVfmCvAW6f9CF&{}ZR*{jXDW zb_vl21ozzrYJBy-Vb$aRjjJF3@7nm}zjw#A|58cE9uZ}LbIY~=6ShA8U$XeY|MDdd zfQCH!?_7WRzhvaG%|sbsT7Kz&`}!yUix%Do#>T_{_Ei`DO9UTSBkH=Hg(w4*^UnUS zTk-IJ<+2C=ZObqG7Z2FGlB7VCN;>(!bn*TFHYMl(i+Sx`L~=ArL>~EXU3lidsO!!J pWF;gqzXSh89JkLNxXeT<1_12n>%V}Y6R`jQ002ovPDHLkV1iLCz99er literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/icons/resultset_previous.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/icons/resultset_previous.png new file mode 100644 index 0000000000000000000000000000000000000000..18f9cc10948f025fde708328fa704b520161e5f6 GIT binary patch literal 389 zcmV;00eb$4P)K{b{Xc8(tN&i@ zH%T)fYQpV#rAr?FpSkE_eXe+_wJd|K3f{{%aMTC(eL? z&YO?2=RWv9b;pbUjjJF3FIss2fAiYM|D{t;5@!?n%vQ}6um-u(1``H~0!(`ViJ zU$yMvf616*#2KJfaGFIu@9Y|n)@%Q3RzCcnHskjH!iD$#iw7MbEf6JRj;ypTzwkeA z{@wqXv+w*Db>B;RG>UocU1Xkp@_*9QTmMBIcK#Mp1s9+pgH&L-pkdi_{i83|RX>c;RL+;F-`+euQkVYzs&;C5`%i%Qu z^?E&0)sw3Fw1_;Qss~j>L+R{>x|12-dpY62JM;7No_}EK_4|j*!_{h)a=A>Y zR6D>Hjv+Orc9zXrc+HHcBm6c0VQ&Y#r$Hy_o@NYQhSYKb~#DRp}3_Dy>$FIF5;; zh(e)&s*y>k3B!;$jx8E+YCqhNC%F6Lq$GZ z`yCTJ$mP`|h#Iz&Nsjeb`&LBu67xLAIfpTZUfSo;xhbBU9pba^e&g)I^ld-+;Oi|e zet&K#xFzu3b?EFy{mAxgC5#IJ{VeDFN52vna9$8ED4?pKP$~$4^Ezm^ z+f*tQqA2=%JfdXY5e5Z}u^2*(2|)u?4Y_j+1`aEtr@sAW_2cQ8L(#;<1W^=WjG>#h zC>YC`$A@t;00K}@BgD4IYs*dkNOrNOpLzDe($doO)hmtjSAJ|fWx`@qDwXh3C8U7R z#go#!8VgMgSc8(;wz7Z-m47J!9|Z=IO)9nM*M_QZWv7#-?z{Ky<5 z#To?A>DRcY>?jq%8iV<-?LYG3Cs)VD_Row&BgFO&oa7i0jC#bRTx)J{Gs*cA8AFn& Tz}6~h00000NkvXXu0mjfriO>R literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/icons/script.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/icons/script.png new file mode 100644 index 0000000000000000000000000000000000000000..0f9ed4d48301ffdce04cdb17dbf8acbad8372d11 GIT binary patch literal 748 zcmVrG{ z$cl-P=->hx6#}NAmbP5myY~I>{qOhtLMa7Y{qE64eE#g}(xpY)TeQ8l?;Upi4EuP3 zj9qNwYy4OP^j-JLi)W5q`snr30AQZ_=_2*h-J^Uqwd^<9gC_@m_YruehOwSPa9@O%#PST ztn>RnbQXoQ3&2p_*N2(YI zkrMO}==(rnxsJAW59QQs0L07JZk*~;x_q%%{cN7dr3j%I4jC^oS!R20 zp-X8Kpw211iFbazd*AM1?Vu^zTr_Qvx?Y!ieJR$aQy;v2#^ddUoYEFRo!j>1ci(tn z{K@;T0)Sj-bCEg}zP!0%dBFa`LT=k_fI7GB{l`yczPWYR>anra$&%HTk?G3F@#Ue> zFdEg-dzaUZYPNRv<+lA7pzgcw+uL{UoxOeM-g%tFNu0n5OqYg(!P3&eWMyo1vh4Ri e9{q`*0R9JiiaRV3rbYDt00009Gp0rM-&EhljN^i}(|Pq=@5XF~~)>U!;+BT;WiZ;-?olqd>fK_MstEkar}b9uop zSG%(%K&q)D8CgaWKtPPtDOv9I8!SQz&9K@qF)=0vTF8Vz6y!_@T)cF~Uzb0()L$?a z`$c#8#_Jq>ql8oq?5#4M^3MAs_Mj^9a~&q%&y!>ZY?Ffij=buvY#%T_TY|PQcQN;bwCQWy*nR;m&;UD z`|<407yq%aQd%Bnb;^cyP&KV4wU)a7>4a6Dx$h-#bpLzK{Pr$B8!J;?KlH*=4~)Nd zXfFUrnL1@v!}G_xF3kSm{Oos*9r(bTXJ0f{jKZMUxbxsWQRhe^WR#$JvyI#9! z6)lXSPy)q8C1lZ}g3^41=HNKqnYs7QJ?H%A@B2c|8SMY^(nC0W>$>q>gSs`STXowS zHf;~fxQ2v9EZ{R7D*@W3dHBBBHM?GWY!d+JSMBtmYNr=h)3&N+d6b;Lw&L5f{XIBX z0<=xDd8!-0r5i~n1ZAKo8S6whk3~g{It4qoP1rg;x#5%3mk&jNRM%6JB~8n674&Lu zjOeY>TV-L${7M3Ee16fcxk-1=bT*X$sjfGy?MD3({naGKphQs+3kpFIXc5wqAI~j1 zbFp{11V~l2d3vJI8#V@`EXJ&e#1s^fLRJ*Wg{w;=M~?r!g#9HzQ&rnHPj&QGvj#Fn z3Svg0kd--VGpUm_RWo<=l}E2ffK-jP&rXl&S6PS@A&7_wfRM?VW;BwjQGycozWv=q zS;X#GC#q5sWn>vi00A*lr(~r+Xs`q&G^1+MA;g07I7@NDx@V8^d@28HxbNq=; zzxe*f?K5pkhju@>PI%T6esG3%jS_iIPFg`oSQ?CLj-`b*R!!2d1>j$2D{N9N- z_dNmtQl?H>)o|vgtp>k-WAdw)jfVdjV0o#K3YUx7d-mS8etPnmh2`4C`M&w3RZD|f z-DE|Kx}BgKTK}9nDt3ap=<6+H=dQ$*8t;dl`wq|GAhu&8Hex;2V|u*X>5Pwe>`ABX pxbn5N{RLGS=ZoANdGc8E?*HisN=owtMsNTC002ovPDHLkV1hpQeRTi; literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/icons/script_edit.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/icons/script_edit.png new file mode 100644 index 0000000000000000000000000000000000000000..b4d31ce282f378e5b94cd40680d283842229e491 GIT binary patch literal 880 zcmV-$1CRWPP)dH?P zU9(eZs5A|8t5v?eTRRMlZU=heApt;c-QWm;Ex@uN>_}2!i6teD1%o>y^d_S1XRa-N zEVlrobv$Z==R-vaN*dOiP;xh}(13rd27nL8<{3^$d8*UtvbO>4tszOR2{qRsrN9O( z3#0`W0!x4o2vg>#nIhNcON;jbrFs$(i&Dd*-VBg3z>*-1z>;7Qu%r9~e~*90+noc{ zCV%7=ogDig@RaK7i93|s01qGl%Lrt!v323f)kR;ImtNTS&iSm|tlwheV@t5403k8+mq?kbBz7Iez4s~7(WvsntW4bC^upoW zL+_1G1IUA;W1XH-C-(17v0M(ATQQWfmq_ZL>3(tqwR{#U6woa9k)QmX+`va6fx$W7fs9{PlZoQqK^zXeF6_0Y=) zo``&Le1wy)J;oj`vgg^i2qA2Pi2L&&MfZ)$Tym*VCU=T$Q;z6Ze zJ$g#19)u*6U}?pjN9Q`P1faW_&ZrhEh`zTzI_Q+4udtc{7?20{`>0tzC%6 z<4$0NFD@aX1`EXFfryb1uLICn5nxWaVpGCkj6kwT4ni1iOhPYO8V+7ZA`uje zMd-SYjtzD?ftn&>m3S@d6_=&B-;Cz zF*bAv13UKN-Iq6*nUCUQI(Jw5*Xv9h7Nm56LZ>KDJd8b9y7n953x!Z9A}LY;0000< KMNUMnLSTZ#4=Y0e literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/icons/server_go.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/icons/server_go.png new file mode 100644 index 0000000000000000000000000000000000000000..540c8e2689b19cd661d3f07ec6d5c69a48ee79b7 GIT binary patch literal 706 zcmV;z0zLhSP)7<1w@I`*?5OI84*T|9oBhH}d)X zV_ny$7-LpT(?ounOeSx1Bq$b(0RlV<27^hr+Y6OI;2f4ea@pG(#Qc2bI;{>8 z6bgmQ0vry9qduPxrLScOb?OXyK&ctFdYopOnzzF=IxIzTH9TSNw zRv8@$M2+3u-KbWpO=ZKt@W_~@Zno4#v;XQqFdGCChs31_>&3!5%7&#b{zWFQc68tn zplmj4#^Z6+YBf55z<5&3{|y;v7;9uv%2$5X>rHda_}~n%R!c9`2Bty_PB{afo|wH(i1~} z&mbZJ35Q%B^!cO6Z!BTy%i>mD!&!%IJ)KTZ(mdRYL?UO7ODFJPbqWeO)2I~TMhXw( zyp+KE^<^xqJ^!icxKx=jKRWim##AbmAfj1{QTs88yd0gw>A`WlSX(G-+yZ}U&%wWZ o(p|@%!Cl@4H>AxOvt;l80V><8&-M2O*#H0l07*qoM6N<$f@GaWM*si- literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/icons/sqlitebrowser.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/icons/sqlitebrowser.png new file mode 100644 index 0000000000000000000000000000000000000000..7897a11e5a55c58d79e6bd147590886011712e24 GIT binary patch literal 15047 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 literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/icons/style.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/icons/style.png new file mode 100644 index 0000000000000000000000000000000000000000..81e41de7d3a9bcc50267b34d0005487d5c7cc7c0 GIT binary patch literal 813 zcmV+|1JeA7P)%S8Yz4}?d^ZEOv#Sc!)mtIgHXaEQ+_ullV zJO1Y8v8UhuAAS7ozvIlitK{;}YszGvVI*jPQs)gu{RuZGF1qsJqxF>Ai*mOY zeUVJ^Xn04=g+vNN2-6q_7DHe6!8fa@! z^ZEB_2Vebf-umoI@{HTtK!PIfdyIp7Zk$|p=*|D=N%#IIE_w1_EaGe}ST5wWclgx% z|Fx4ZY{8likTKA?G12oM|4&}@o+);3yYs=L?ao)At-(S*$63Le zJ&q^>ZEbL?y!O>L=h9<7rvvdA2Do?L{p8zs_rGt?o&P=^cm5ltT|5S~l@laqmU8i; rSIv!oK>XjU`o@3v@@qdCD9z3Q7_5=EFk?|V00000NkvXXu0mjffa;^e literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/icons/style_add.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/icons/style_add.png new file mode 100644 index 0000000000000000000000000000000000000000..e0369c6be9d36e994b0de011069494460d96a837 GIT binary patch literal 844 zcmV-S1GD^zP)e0@+Julu(JNEkTghQ`>*6)1&K56lT)AFSk6p+=zFou9~?@f=o z<8N*rd;0DF(Z}EZJI=hjN-qDrrcCA;MuG+?b>3jqpKx>HqAMRhT2HyXD0l0#iaLPj_0@CCfwX2oqfq#v-#E>^WJ+0O*-%H zHfg=H+pP80LCw-@%MhBYE~}R8d~tQ=>345r($1Jk$Dh=ha`5$Q|0%Z*NM~MfR<5`? z*=OG4&)FMa{LftT;=fMmjdkL&7s}uU7`0rTx%v91Kl4t$`!M0as~0m4zJ7b)=BNL$ zv+kY|^Ex1>-*9Vvz`RHQoOC>ZM%CJXsdg~+{gcAqR#h%!vGjSdf96p zUz&8_)hmghBZe>+iF)o;PnvP(V#cg{58Ni-fA2Qo-b=Bl^VUFHgCb`>{I8mLVHwzf zj-AiHPdoVPfAiL7Uy^6s-UbpBao=Mc+;ijPvO{nFM^C!rXeXPW->+%GCcCp6&YIzdP%Hc)#v{<8+;QI1SLuzO*J`-lP9w z!6%zz+g-kIygcFm#%q)QgFw%o)c^f^(*K)hOZ~vm2n-}+(aVjYFP!CqB_qTX zOJ&0en^&%FY~D`yo5wuXrqeuThwbe*!4lN!gNF~E?|Yv2;o&s_0FxcK)F4Mv>u0z* zJhiT>SNoIRsri=6U06{-CYN%OHJ$srT8APibiLY-K*7FMO` zu!-u4!CmVjT89blRPxkIDKC*hn?y-keBB&eC_)C&se#e8D!|7|Y1Eu$<>Pfv>N49K>6fy0A2YR8!Poer$)vwrolN$#@;q4<}Pej2{e%3 zI=@b?o@g_YM+14D#L_V#yK@oZ%9M~)Hw)Nk$>Z&}>!Pcq%1JmymbL7=2fKmBjgNb+ z0y1kBXpaiveUuCEe9fUL91qlp8>1G%-IfQ7F?q0R5`%pM_H zlBZRaI3ut~u@Y3I*su)iBl3JP27{y#cAw>392ogM27x8WYUncrLQ548Qmg=v)c#(M zKW28lmJEQ3zM`w6LouCZ2JeDx41XWS7nLH=8uZMsJl-Y~+6d*|L+TPovcw00000NkvXXu0mjf$UutB literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/icons/style_edit.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/icons/style_edit.png new file mode 100644 index 0000000000000000000000000000000000000000..25bb5b677f89b1071fa44f29a006ed0be8fca098 GIT binary patch literal 927 zcmV;Q17Q4#P)4 za;GYM@Zfsyfm)fD&Ry41qf>=r$+ULd=aUgoB$PD=lkdf_7Ilg?zyQOl7->rK6-vac z;TV_Zv*2yTAsc({lxwkakt#&M=^sjC#7^AUP&&Nl19N&`|TDi=7JD}Yd0Ws1C z>4Cn`%K-NAO-Gb$R zVwgTXc$E4*bT1D$0aYNf*Tq)K^tV$NSHqh(`FgCPo#PoB*clz&@Zz?t*3^<<*(b1GSS=liGL+!XKb`BrUt80E|` zL^nZdavGLlE*g6AK5q89fuGJSBa^o|%9F?I)(M}uC9Y*LTOPY~cz<|nclXlE}xo*2>>r;3Jd?&=tr_!Iww zFvhUfzU@K1>#kb5wJi!Jl*ja3{?P6ZuOx9B{{rz!RGKb8<;DO2002ovPDHLkV1j*g BxhDVs literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/icons/tab.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/icons/tab.png new file mode 100644 index 0000000000000000000000000000000000000000..3d8207fd74e73ed0a61793834ecbd358a209b9c9 GIT binary patch literal 323 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Ea{HEjtmUzPnffIy#(?lOI#yL zg7ec#$`gxH85~pclTsBta}(23gHjVyDhp4h+5i<@^>lFzu{fRl=l_3uX4QtyMkj+0 zY#SOnetv##&Ac*9!Aw2qzO90ukB`rtBTS+*)~sK@Qd3Wl>6w91lc$EXqw|d(p7rtj zL#=9mJql4^&ui$IAYgxZvAe!x-T!~wAEkwbV}v;l|IpFV;kk6_P=alNz5|0Yv$3)9 z;rsjlKkS;w>nL%6C&hSi8{-+bv^22=Ol%^&FHDS$JJJrBFsN`$`tyH2>+-h(-T}M` zbIkMa)w8ljvf0|^RyP)a!RbZ^nygOjY zvaEgmwz2N_`+TjfUI2su5O03fI=3GN zO-DxyfY)uofj}vRZ5#J+ElHI?A*K4L!FxreG+Of^;j>jrB82=(AcRCIi81=y>WNH@ z%WRC|bAfWDj8}GRun?h8$n^AdF*G#bidPlPiBA#-q@JRT_(tjU^l_TnC4PNQQ?cK< zK{}l!ozDLFW@ou==4Pg`rH#LBisPFd#s??Z*^7WN=GQg5GHfE(Tc#HK$)FiqXft*F z#C#!FO5Mi@99aMa4lQnTNq|ya1TW@gEuM_gfac(8lLn!QCe8qYqTX>HUu+Km^FSj| e1UBOv_sg$~0hzRbE)Q}50000>q?GuNnCdgP^*Bj5V_b?dAq2Ppn9^MBB^YUM zad0N-T{Ujg*A6d~mYV4na=hT4Nz+_}SGTgW|Iir!%$ z;@OGkWI6+j0H}~K4RYR%!7y|zM`O@*K>rL{*&}x3lR**HrMXC1->#slU>X|w!U1xQ zqc^@R5;6} zlTS!gQ5431?~i{f-N>j^(nf@gnz4vsG~1*?ZHy3tqD@4b(p4K*Q47IE5Jb6XVMKux zSz4`PETXXnBWf%+CAA199Uoz1qRzYL-WG3|8Cw}$xO|**x!?Kjch9kmG5pVR0q(w9 zyl4z(#pnjDHKIXjjfh6HL5VKef+&M%{dV9~Q`7~}#`N_>t3&@%`O>}Fa6y4+9Re8t zdK;w`N)*0U_~I8)RN<_@bpYR&iV}jrhm*U`Y^eJ3s=`-N^gu)dFp|h@h@g9a4Y^VR zl_vl=(O$>>$$5?+s4wJ3lk@b%im{hnU9Z3wjW!0?fzdY^9LMHiGJ|DuWY zbD??rW^(>tPcVS%SR9MiGCsAy(P-T|1*P$9I*U?zy#k}bwc+Wz1so?p2yy^dAKl^m z`~=G@i>&!Ma%=m5);xjI7-J}N;PBpB;wg{LNU<%hjSaIT2|5l&X{c%9#mpGVPmhW9 z4qve$=sEz$wuq-Z0OBc+c*^7Xw8#6;4`|sLL2MziwF|L)Vtd*E&Ibfa1s>SY842M! z0d_`0914f#Z3A& zsdR$=u3HQ~J58li0kE3?1v7bhwSU`zl2002ovPDHLkV1n}7B%A;M literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/icons/table_delete.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/icons/table_delete.png new file mode 100644 index 0000000000000000000000000000000000000000..b85916d921ec08675f9e41f18c0fbfd7f2124d8c GIT binary patch literal 660 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 literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/icons/tag_blue_edit.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/icons/tag_blue_edit.png new file mode 100644 index 0000000000000000000000000000000000000000..2a9f6266ebbfb023c9965cac87924611d3242a2d GIT binary patch literal 748 zcmVPQ541JUvS~ZL`~zygnz)KVWCC?F5D=Ikq8U?h>6CXAjX9uM6jBuQEWg2V^GsJ zMH;n{ex$Xn{j#O)Obd}(%Ft$twTjfv*iMJzn?agT3X8Y7bI9*=`z7{p>R zM59qeA`yhcVT3{<1cSld0H~b~Mbk7SN!oHUnT!JQ`FuM-Mr_<>gM6Qt( zaJ${xLMS=1+$_7vg+L$>Di(_nMNz5CK(E&ehr`hjLdmWhjYM1~ky$|ykSmI?Ev+X> zrBZOYT(H?}TOgF|yb-xttwI)mFG;vNvxdGefR$bUmP{rQusp)t#2L&_^&>KR9MLCD z9Tb_7&*$?>Q>9V?N1O-4YZzjH;W(g~S%>_|OoFp_Vo~nZx7psL70cE|*gv zi60^cLK3tjfhp`nfw={VcZ2_S1%<#>%)aa*Bb!S4U!4hV~9@te7c zr1k{t#!*?UQf{ICTBfI`)#g`y<;2J9B=#o=3tjljp2G@BGXJy%7Sn6!^?Ft98tVbi zF7NG%f9OTj`~Vq$8%hi9C`5Yjb(qASn%E?62+$241y<9T8$Jzt?;d!xt#E0M!D1ZW zB5nxiyU-+-y^m4$KZL*kFm#s=z^osIPN!2fe9HBOw&q>Joz8=zZJ<@O-aq0r4)vTO e;(gowO#c9xAttCU0DR;C0000C#5QQ<|d}62BjvZR2H60wE-%s@pN$v(Kw&{=X`^_fnmU^23D6T z|NkHVz|K?O{7~QE-_Z@zCpI>Iv^P{UFnE&ke;(6i-d4-w%bHR;j1|AyZ#v6S(amDc zlKy{I(;D%Nuye{ncOLwezxwWez>k>{<_3S*oiFG7{Xgq}=)co{r~lFaH2=T-_xf)+ f9X!fMH*zv8ak(u6{1-oD!MC#5QQ<|d}62BjvZR2H60wE-$h_H=O!(Kw&{=X`^_fnmU^23D6T z|NkHVz|K?O{7~QE-_Z@zCpI>Iv^P`}`P2Tg^+n4;W0%&Nn`h_oB zXMCTNA-w1R;@9m5&b!P``2Amf(pd!#&g=F^W;hsZV)z*wDqmKyKNDyjgQu&X%Q~lo FCIDq2QD*=E literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/icons/text_align_left.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/icons/text_align_left.png new file mode 100644 index 0000000000000000000000000000000000000000..6c8fcc1165a433617355ac5e182d015b389e9296 GIT binary patch literal 209 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!60wlNoGJgf6SkfJR9T^zbpD<_bdI{u9mbgZg z1m~xflqVLYGB~E>C#5QQ<|d}62BjvZR2H60wE-$h_H=O!(Kw&{=X`^_fnmU^23D6T z|NkHVz|K?O{7~QE-_Z@zCpI>Iv^P`}`P2Tg^~Il~8@dITHCPA-{a3!-)3Cjx%=yXx z_>8LclV7mqn+PY^{qor&o%8>H%d3``{~Y#6bGV5yoI2touNPXs5@;QRr>mdKI;Vst E04%Lf&j0`b literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/icons/text_align_right.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/icons/text_align_right.png new file mode 100644 index 0000000000000000000000000000000000000000..a1502571c99fb92b1579c3658bcc50c5976b8e7d GIT binary patch literal 209 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!60wlNoGJgf6SkfJR9T^zbpD<_bdI{u9mbgZg z1m~xflqVLYGB~E>C#5QQ<|d}62BjvZR2H60wE-$h_H=O!(Kw&{=X`^_fnmU^23D6T z|NkHVz|K?O{7~QE-_Z@zCpI>Iv^P|9aJcmUe!yIVina{lp#RFZdm6TTlr;aYZ;9)u zJl|<{@VEV{yZaY@Fz(E|@awb^}|6b=Y6y(;Y{!a!g z@UQp#@Aw}>L3(}s|7f5BUjeuKZvQRjV<2U7yvu*H{aAbvQ6K!@3oKzW z-{Qa8d3gae1^)HE{~f^!v<1}u>;4xnKvUpW540I-w9J3a{{r=B3T*2g{_BH1CtaZO zpZ`6V0*V5g1e5i;`_=Z#_e=H*@8|93RG@lX;D!K7TKswwko8{x0000A?80v9Z^YZA8as&YaOiG2qAVzYLj+o?N|k`)kPFX7%epMT)pIgD?z$ zz0k7x#eWfQHil2%e>0rE^YzTbTVLW%P1UySD{rve8ZZphV4}^gtsg#oV8j^<1D2Tp2_^}JGDwbz00000NkvXXu0mjfU=gFa literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/icons/text_italic.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/icons/text_italic.png new file mode 100644 index 0000000000000000000000000000000000000000..8482ac8cb1eb8bc8edbf64085108f0fbd204fadb GIT binary patch literal 223 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!60wlNoGJgf6SkfJR9T^zbpD<_bdI{u9mbgZg z1m~xflqVLYGB~E>C#5QQ<|d}62BjvZR2H60wE-$B^mK6y(Kw&{<9vg>Q9!g~ne(gm zmj4swoA@7?D86%i^8WzK9JM17E&sp&Z#dpHfz$E-U9ks&4?Z9Gyg!%0k2Q{M-Tz#> z2OnD>vrPZ*#{EHKLq)>Jcx{H|Ovdb&|4aQZWSipI{El%e^Cxx{^9vSw28s;a3IDB= TS1%U=TF&6<>gTe~DWM4fm>N^1 literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/icons/text_paintbrush.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/icons/text_paintbrush.png new file mode 100644 index 0000000000000000000000000000000000000000..61876930c4bfdd37d1f8759bacf0a829d3cab9b6 GIT binary patch literal 880 zcmV-$1CRWPP)IMUm8pNTsacVC@HkyaNDlS)vn+`Eo>(J?v0G>&9`S zr%OJ9IPx)LbR3&G#%y@>PP+f#S>GB}q@CZz4%hmI3E2l{Q-v)gLjhw;ni(^P+!PBD zc3t;ZOdS(9CETxsHIW9o&t&S}vcypi*ZO)#T8@37=K`q0Sbn%blWD=eT<7MJE8XS3 zrr>c4$CxZJtW7t@xV&YFqaChw&xN!cyC&X5{heECMCKL`0+RQ>OkF<9Uep_m2EX=( zFKQwcow39kOIY)qgi5EwwXR-BciVWT8l8=Gh{)XTyyBk9!53^MwrF0GDg9%RibboE zZWtMccL_1Jw&pj(wqyrR3F+@Av$Vn&|cU2SPGGi-;IeT(g{m*g09EuM3 z{a*?X&ZJDsM0ZOUx|%*M$S?JIeoi6*01cX>O^!Vlud?pB(^D`h*#Ie&it2m8 zw~d~wf)pZ!zY_xhIaG1p5RPhjs)S{H>LlE*_v3hF6n0}6kzh*GWYIFGptQyRr!J77 z$XsNIDbHYcAT+>2RIQL$GhV%I>>qB>b`%`_vlsx#=P&XyNe)5|cOx8Dp(qr5O#B@y zFP}bBvc2`6+IXX44}l(?0i9+;i=Kc^B|z1etSt}y4e$-7e_J6FGenR80000%W!&uf*aR7m=b*g|(kUJU9 zp=n%1olDSG6tD^6Pm#c6n|B4fFQ*MV1`x;`99zMDR*0#E+F^m|oe836+P7h!>#yE1 zfI!Pp|0)RN)PgnUO$R@72rPJU`eo0n-Y3TD?vS-`EG)AfK{?SrAt%}ba;()aIZ6Qp z@}w&6x|k9*7g8`rL*Kdi8;ED#;QEIV91l(YIPowK+e{Jd0T~0&6kK`z6@7djhdf!w zwp#S^9d~>P!TC5WQwj!Wi!>p*WY}^u%h{eQ=zmnefl-ky`!{2#b7T1JN1S<4gx>S% z7mb%u>(n#eMi%C6?_t0)6t-JzDG!NaVz^b*qE`c@Om0%1= zpr*5B14!3kn2^D}|Au;ZM%_q;bhY%VI5ex^Fx52YQ--nur0X!-_-*q03322ghy(&cNNX?2}d-6ZV@ORut;!KHNq*K6#He9hTK Z<~I`7qRvC#5QQ<|d}62BjvZR2H60wE-$x?CIhdqH#X?$N2_%BY~9*Y!?2h z{rUe=9fy8l?U(-(m`sFEeV_iPeWNmK)A{6xz&-Zw?GGia|0}^&^gUfcv*1X`gnjmc zo{g-_np*x&^x*npDC+Wt-z8{4+sXs`@BiMP%+Rv-k;3)Ae_+S0!x%EHv-|4^N|MkDje{TP~{@MQ}vm3aX7|tvG V&AV6mZa&bt44$rjF6*2UngI1lb~69~ literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/icons/textfield_delete.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/icons/textfield_delete.png new file mode 100644 index 0000000000000000000000000000000000000000..c7bd58b21797817803b49d3b2b53323e17fda625 GIT binary patch literal 335 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

VLTtlkF#mO)M=-(sgp8c2K?G`Fe*fnJ< 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ʊ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 +// +//static QString message = QString(); +// +//void db4sMessageOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg) +//{ +// QByteArray localMsg = msg.toLocal8Bit(); +// +// // Emulate the default Qt treatment. This might not work in some OS, like Windows. +// fprintf(stderr, "%s\n", localMsg.constData()); +// +// const char *file = context.file ? context.file : ""; +// const char *function = context.function ? context.function : ""; +// localMsg = QString("%1 (%2, %3:%4)\n").arg(msg).arg(function).arg(file).arg(context.line).toLocal8Bit(); +// +// // Log using the SQLite log mechanism, so it gets the same treatment than messages +// // reported by SQLite itself. This will allow these messages to be seen in our Log window. +// // Error code will be the type +// sqlite3_log(static_cast(type), localMsg.constData()); +//} +// +//void boxMessageOutput(QtMsgType, const QMessageLogContext &, const QString &msg) +//{ +// message += msg + "\n"; +//} +// +//int main( int argc, char ** argv ) +//{ +// +//#ifdef Q_OS_WIN +// // In Windows, there is no output to terminal for a graphical application, so we install +// // the output to message box, until the main window is shown or the application exits. +// qInstallMessageHandler(boxMessageOutput); +//#endif +// +// // Create application object. All the initialisation stuff happens in there +// Application a(argc, argv); +// +// // If there has been invocations to the message handler, show it to user in a message box. +// if(!message.isEmpty()) { +// QMessageBox messageBox; +// messageBox.setTextFormat(Qt::RichText); +// messageBox.setText("

" + message.toHtmlEscaped() + "
"); +// messageBox.exec(); +// } +// +// // Quit application now if user doesn't want to see the UI +// if(a.dontShowMainWindow()) +// return 0; +// +// qInstallMessageHandler(db4sMessageOutput); +// +// // Run application +// return a.exec(); +//} diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/os2app.rc b/src/WBCLFZSystemModule/SqliteDBProcess/src/os2app.rc new file mode 100644 index 0000000..0519ecb --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/os2app.rc @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/LICENSE.md b/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/LICENSE.md new file mode 100644 index 0000000..f8714d0 --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/LICENSE.md @@ -0,0 +1,185 @@ +# License + +This is the license of [QDarkStyleSheet](https://github.com/ColinDuquesnoy/QDarkStyleSheet). + +## The MIT License (MIT) - Code + +Copyright (c) 2013-2018 Colin Duquesnoy + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +## Creative Commons Attribution International 4.0 - Images + +QDarkStyle (c) 2013-2018 Colin Duquesnoy + +Creative Commons Corporation (“Creative Commonsâ€) is not a law firm and does not provide legal services or legal advice. Distribution of Creative Commons public licenses does not create a lawyer-client or other relationship. Creative Commons makes its licenses and related information available on an “as-is†basis. Creative Commons gives no warranties regarding its licenses, any material licensed under their terms and conditions, or any related information. Creative Commons disclaims all liability for damages resulting from their use to the fullest extent possible. + +### Using Creative Commons Public Licenses + +Creative Commons public licenses provide a standard set of terms and conditions that creators and other rights holders may use to share original works of authorship and other material subject to copyright and certain other rights specified in the public license below. The following considerations are for informational purposes only, are not exhaustive, and do not form part of our licenses. + +* __Considerations for licensors:__ Our public licenses are intended for use by those authorized to give the public permission to use material in ways otherwise restricted by copyright and certain other rights. Our licenses are irrevocable. Licensors should read and understand the terms and conditions of the license they choose before applying it. Licensors should also secure all rights necessary before applying our licenses so that the public can reuse the material as expected. Licensors should clearly mark any material not subject to the license. This includes other CC-licensed material, or material used under an exception or limitation to copyright. [More considerations for licensors](http://wiki.creativecommons.org/Considerations_for_licensors_and_licensees#Considerations_for_licensors). + +* __Considerations for the public:__ By using one of our public licenses, a licensor grants the public permission to use the licensed material under specified terms and conditions. If the licensor’s permission is not necessary for any reason–for example, because of any applicable exception or limitation to copyright–then that use is not regulated by the license. Our licenses grant only permissions under copyright and certain other rights that a licensor has authority to grant. Use of the licensed material may still be restricted for other reasons, including because others have copyright or other rights in the material. A licensor may make special requests, such as asking that all changes be marked or described. Although not required by our licenses, you are encouraged to respect those requests where reasonable. [More considerations for the public](http://wiki.creativecommons.org/Considerations_for_licensors_and_licensees#Considerations_for_licensees). + +## Creative Commons Attribution 4.0 International Public License + +By exercising the Licensed Rights (defined below), You accept and agree to be bound by the terms and conditions of this Creative Commons Attribution 4.0 International Public License ("Public License"). To the extent this Public License may be interpreted as a contract, You are granted the Licensed Rights in consideration of Your acceptance of these terms and conditions, and the Licensor grants You such rights in consideration of benefits the Licensor receives from making the Licensed Material available under these terms and conditions. + +### Section 1 – Definitions + +a. __Adapted Material__ means material subject to Copyright and Similar Rights that is derived from or based upon the Licensed Material and in which the Licensed Material is translated, altered, arranged, transformed, or otherwise modified in a manner requiring permission under the Copyright and Similar Rights held by the Licensor. For purposes of this Public License, where the Licensed Material is a musical work, performance, or sound recording, Adapted Material is always produced where the Licensed Material is synched in timed relation with a moving image. + +b. __Adapter's License__ means the license You apply to Your Copyright and Similar Rights in Your contributions to Adapted Material in accordance with the terms and conditions of this Public License. + +c. __Copyright and Similar Rights__ means copyright and/or similar rights closely related to copyright including, without limitation, performance, broadcast, sound recording, and Sui Generis Database Rights, without regard to how the rights are labeled or categorized. For purposes of this Public License, the rights specified in Section 2(b)(1)-(2) are not Copyright and Similar Rights. + +d. __Effective Technological Measures__ means those measures that, in the absence of proper authority, may not be circumvented under laws fulfilling obligations under Article 11 of the WIPO Copyright Treaty adopted on December 20, 1996, and/or similar international agreements. + +e. __Exceptions and Limitations__ means fair use, fair dealing, and/or any other exception or limitation to Copyright and Similar Rights that applies to Your use of the Licensed Material. + +f. __Licensed Material__ means the artistic or literary work, database, or other material to which the Licensor applied this Public License. + +g. __Licensed Rights__ means the rights granted to You subject to the terms and conditions of this Public License, which are limited to all Copyright and Similar Rights that apply to Your use of the Licensed Material and that the Licensor has authority to license. + +h. __Licensor__ means the individual(s) or entity(ies) granting rights under this Public License. + +i. __Share__ means to provide material to the public by any means or process that requires permission under the Licensed Rights, such as reproduction, public display, public performance, distribution, dissemination, communication, or importation, and to make material available to the public including in ways that members of the public may access the material from a place and at a time individually chosen by them. + +j. __Sui Generis Database Rights__ means rights other than copyright resulting from Directive 96/9/EC of the European Parliament and of the Council of 11 March 1996 on the legal protection of databases, as amended and/or succeeded, as well as other essentially equivalent rights anywhere in the world. + +k. __You__ means the individual or entity exercising the Licensed Rights under this Public License. Your has a corresponding meaning. + +### Section 2 – Scope + +a. ___License grant.___ + + 1. Subject to the terms and conditions of this Public License, the Licensor hereby grants You a worldwide, royalty-free, non-sublicensable, non-exclusive, irrevocable license to exercise the Licensed Rights in the Licensed Material to: + + A. reproduce and Share the Licensed Material, in whole or in part; and + + B. produce, reproduce, and Share Adapted Material. + + 2. __Exceptions and Limitations.__ For the avoidance of doubt, where Exceptions and Limitations apply to Your use, this Public License does not apply, and You do not need to comply with its terms and conditions. + + 3. __Term.__ The term of this Public License is specified in Section 6(a). + + 4. __Media and formats; technical modifications allowed.__ The Licensor authorizes You to exercise the Licensed Rights in all media and formats whether now known or hereafter created, and to make technical modifications necessary to do so. The Licensor waives and/or agrees not to assert any right or authority to forbid You from making technical modifications necessary to exercise the Licensed Rights, including technical modifications necessary to circumvent Effective Technological Measures. For purposes of this Public License, simply making modifications authorized by this Section 2(a)(4) never produces Adapted Material. + + 5. __Downstream recipients.__ + + A. __Offer from the Licensor – Licensed Material.__ Every recipient of the Licensed Material automatically receives an offer from the Licensor to exercise the Licensed Rights under the terms and conditions of this Public License. + + B. __No downstream restrictions.__ You may not offer or impose any additional or different terms or conditions on, or apply any Effective Technological Measures to, the Licensed Material if doing so restricts exercise of the Licensed Rights by any recipient of the Licensed Material. + + 6. __No endorsement.__ Nothing in this Public License constitutes or may be construed as permission to assert or imply that You are, or that Your use of the Licensed Material is, connected with, or sponsored, endorsed, or granted official status by, the Licensor or others designated to receive attribution as provided in Section 3(a)(1)(A)(i). + +b. ___Other rights.___ + + 1. Moral rights, such as the right of integrity, are not licensed under this Public License, nor are publicity, privacy, and/or other similar personality rights; however, to the extent possible, the Licensor waives and/or agrees not to assert any such rights held by the Licensor to the limited extent necessary to allow You to exercise the Licensed Rights, but not otherwise. + + 2. Patent and trademark rights are not licensed under this Public License. + + 3. To the extent possible, the Licensor waives any right to collect royalties from You for the exercise of the Licensed Rights, whether directly or through a collecting society under any voluntary or waivable statutory or compulsory licensing scheme. In all other cases the Licensor expressly reserves any right to collect such royalties. + +### Section 3 – License Conditions + +Your exercise of the Licensed Rights is expressly made subject to the following conditions. + +a. ___Attribution.___ + + 1. If You Share the Licensed Material (including in modified form), You must: + + A. retain the following if it is supplied by the Licensor with the Licensed Material: + + i. identification of the creator(s) of the Licensed Material and any others designated to receive attribution, in any reasonable manner requested by the Licensor (including by pseudonym if designated); + + ii. a copyright notice; + + iii. a notice that refers to this Public License; + + iv. a notice that refers to the disclaimer of warranties; + + v. a URI or hyperlink to the Licensed Material to the extent reasonably practicable; + + B. indicate if You modified the Licensed Material and retain an indication of any previous modifications; and + + C. indicate the Licensed Material is licensed under this Public License, and include the text of, or the URI or hyperlink to, this Public License. + + 2. You may satisfy the conditions in Section 3(a)(1) in any reasonable manner based on the medium, means, and context in which You Share the Licensed Material. For example, it may be reasonable to satisfy the conditions by providing a URI or hyperlink to a resource that includes the required information. + + 3. If requested by the Licensor, You must remove any of the information required by Section 3(a)(1)(A) to the extent reasonably practicable. + + 4. If You Share Adapted Material You produce, the Adapter's License You apply must not prevent recipients of the Adapted Material from complying with this Public License. + +### Section 4 – Sui Generis Database Rights + +Where the Licensed Rights include Sui Generis Database Rights that apply to Your use of the Licensed Material: + +a. for the avoidance of doubt, Section 2(a)(1) grants You the right to extract, reuse, reproduce, and Share all or a substantial portion of the contents of the database; + +b. if You include all or a substantial portion of the database contents in a database in which You have Sui Generis Database Rights, then the database in which You have Sui Generis Database Rights (but not its individual contents) is Adapted Material; and + +c. You must comply with the conditions in Section 3(a) if You Share all or a substantial portion of the contents of the database. + +For the avoidance of doubt, this Section 4 supplements and does not replace Your obligations under this Public License where the Licensed Rights include other Copyright and Similar Rights. + +### Section 5 – Disclaimer of Warranties and Limitation of Liability + +a. __Unless otherwise separately undertaken by the Licensor, to the extent possible, the Licensor offers the Licensed Material as-is and as-available, and makes no representations or warranties of any kind concerning the Licensed Material, whether express, implied, statutory, or other. This includes, without limitation, warranties of title, merchantability, fitness for a particular purpose, non-infringement, absence of latent or other defects, accuracy, or the presence or absence of errors, whether or not known or discoverable. Where disclaimers of warranties are not allowed in full or in part, this disclaimer may not apply to You.__ + +b. __To the extent possible, in no event will the Licensor be liable to You on any legal theory (including, without limitation, negligence) or otherwise for any direct, special, indirect, incidental, consequential, punitive, exemplary, or other losses, costs, expenses, or damages arising out of this Public License or use of the Licensed Material, even if the Licensor has been advised of the possibility of such losses, costs, expenses, or damages. Where a limitation of liability is not allowed in full or in part, this limitation may not apply to You.__ + +c. The disclaimer of warranties and limitation of liability provided above shall be interpreted in a manner that, to the extent possible, most closely approximates an absolute disclaimer and waiver of all liability. + +### Section 6 – Term and Termination + +a. This Public License applies for the term of the Copyright and Similar Rights licensed here. However, if You fail to comply with this Public License, then Your rights under this Public License terminate automatically. + +b. Where Your right to use the Licensed Material has terminated under Section 6(a), it reinstates: + + 1. automatically as of the date the violation is cured, provided it is cured within 30 days of Your discovery of the violation; or + + 2. upon express reinstatement by the Licensor. + + For the avoidance of doubt, this Section 6(b) does not affect any right the Licensor may have to seek remedies for Your violations of this Public License. + +c. For the avoidance of doubt, the Licensor may also offer the Licensed Material under separate terms or conditions or stop distributing the Licensed Material at any time; however, doing so will not terminate this Public License. + +d. Sections 1, 5, 6, 7, and 8 survive termination of this Public License. + +### Section 7 – Other Terms and Conditions + +a. The Licensor shall not be bound by any additional or different terms or conditions communicated by You unless expressly agreed. + +b. Any arrangements, understandings, or agreements regarding the Licensed Material not stated herein are separate from and independent of the terms and conditions of this Public License. + +### Section 8 – Interpretation + +a. For the avoidance of doubt, this Public License does not, and shall not be interpreted to, reduce, limit, restrict, or impose conditions on any use of the Licensed Material that could lawfully be made without permission under this Public License. + +b. To the extent possible, if any provision of this Public License is deemed unenforceable, it shall be automatically reformed to the minimum extent necessary to make it enforceable. If the provision cannot be reformed, it shall be severed from this Public License without affecting the enforceability of the remaining terms and conditions. + +c. No term or condition of this Public License will be waived and no failure to comply consented to unless expressly agreed to by the Licensor. + +d. Nothing in this Public License constitutes or may be interpreted as a limitation upon, or waiver of, any privileges and immunities that apply to the Licensor or You, including from the legal processes of any jurisdiction or authority. + +> Creative Commons is not a party to its public licenses. Notwithstanding, Creative Commons may elect to apply one of its public licenses to material it publishes and in those instances will be considered the “Licensor.†Except for the limited purpose of indicating that material is shared under a Creative Commons public license or as otherwise permitted by the Creative Commons policies published at [creativecommons.org/policies](http://creativecommons.org/policies), Creative Commons does not authorize the use of the trademark “Creative Commons†or any other trademark or logo of Creative Commons without its prior written consent including, without limitation, in connection with any unauthorized modifications to any of its public licenses or any other arrangements, understandings, or agreements concerning use of licensed material. For the avoidance of doubt, this paragraph does not form part of the public licenses. +> +> Creative Commons may be contacted at creativecommons.org diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/Hmovetoolbar.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/Hmovetoolbar.png new file mode 100644 index 0000000000000000000000000000000000000000..cead99ed108a83715a939fc293dd7692008ac6b2 GIT binary patch literal 220 zcmeAS@N?(olHy`uVBq!ia0vp^0zmA*!3HFSYrjteQfx`y?k)_Q87dhn@7xXk0~Fyb z@Q5sCVBi)8VMc~ob0mO*>?NMQuI%?&Bn5OO*L%Ib02GqV42dXl&d<$F%_{+N85o?4 zQWHy3QxwWGOEMJPJ$(aG^itV@;trlJjv*0;-<~t%Vo=~=cKEuuHadP)@WGQuU7r}S zO7(3kn;EC7l=k(^o8K==q_@k14TBON%sx1ZaXWETh=#i?0*QIL`njxgN@xNAL{>as literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/Hsepartoolbar.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/Hsepartoolbar.png new file mode 100644 index 0000000000000000000000000000000000000000..7f183c8b3ee5ffaa6157867cb88ebb7e67f9c0fa GIT binary patch literal 172 zcmeAS@N?(olHy`uVBq!ia0vp^>_BYK!3HFCsxJuxDYhhUcNd1u43!L(ckTxN0g7-I zctjR6FmMB9xrG@SX3dcR3bL1Y`ns~;XOR@p6Zv)R$U2~qrKgKyh{fsT1O>Ju$B!EW z@!}4{#Nd`-q4nn`YMg93@~{6$nhfv4z>`4eS;NZqID=!NmZu#9Lx(rZWlOyY_CP}z NJYD@<);T3K0RUVxGDiRa literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/Vmovetoolbar.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/Vmovetoolbar.png new file mode 100644 index 0000000000000000000000000000000000000000..ac6a655e28a82d9a2a228f8242c36526e8a4c07f GIT binary patch literal 2847 zcmeAS@N?(olHy`uVBq!ia0vp^4nQox!3HFkJ+IURQteeC5hX#1CLR`%d#7cHnS%A2Lzs$J-54gd?|2;R~vB$Ugni`as5(-z;zMpLbmE z7ID(uN9924^5y%qec~iGYk0q()m=P0`zC(aps>X~A>r_{)a!Sz zY)R|Bb*k3wpXa*!-`+fZnf8m(zFJ4%hSAg`3=CXMnLsB+`1)8S=jZArrsOB3>Q&?x z0Nu*KU}IlVkeHmETB4AYnx2_wtMq>NekFy>6kDZmQ(pt$0_W6>OpmIf)Zi+=kmRcD zWXlvKdpj8?tx|+4B-HR8jh3>Am7x}#W5t}@Y|~!c^M2iSPV}rI&*A^=WN+~?=&Vl ygu8D0*FJNn=jr!(^S^Lg%ww3~C^^Nk!Gr(UTn_G4$)y^gMx>{!pUXO@geCyvkrMU* literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/Vsepartoolbar.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/Vsepartoolbar.png new file mode 100644 index 0000000000000000000000000000000000000000..7bf62f16850863c2320aaefe25370cc58b830b54 GIT binary patch literal 2839 zcmeAS@N?(olHy`uVBq!ia0vp^_CUCLR`!4bxG2n3iKl72Bf`gC5@>NnV&31g`pAwdPzkQ=l%7Vw==YG+Y z;*R{@$Y8N?!vx*44_b}PABGv17W(DBeA4HcDtV+}TlK|re->%8Et_p^RrY4m+oBaK zmV^avE!r#CpZ)pQi@BTkpMJ^jp{V2iw(i&y1_myMOrVn@e0{8v^K+E%t*2Y zFB~FoF6n8tTD=uT(Qdxx)a<0eU@)!M>o01x+Iiqws#D0Hbb*o{kH_P?{eC|=sA#T0 z5Cji_`{}&}Tmkb(#+V25=I;9fd4|K`+eV|YBWX1i)lngwb6(cvlI|H}x`)*t8USE4 z8hvOso1cMo{`ACwAyRVzQ|H{BFbtm@rN8jzwpy(<=iGDPbQ-|Ulw{$4NxE%}d9{e{ zQr+eI{&h(&fip89GV`C3){HS*i)t?2-tBh#sH0W z;0o{txRgHn0<45#I9^t(@FBCYv2oG!ysy9~YwgWmulKE}R!K=o$%*nC0efZw0)NMZ&S%`vY+%zRZlbP!x@4?Hw zJMm>Q^Ag+pTb?uLa{lMux%ZwKuvjb>i^XEGSS%Kc#bU8MTu9y!hT$i`$AAlDfF5^J z6(fKHq`;?2sc6voh#{aao?hUCg3GqH9R+xh1eU^7fU{cb|NF8ZqNnL>-afPk04yvl zOlMhk5qLa5h=^qMq*xga!@Aai*OgM&@(&ve01$@Z3&4-SkwN<*FM>(@8Ze`jx?u_^ zEC4_d1jil6xdI#;v>(zUn8g2@W!Y;kAtj8>f>bSs!(v zJSQ8c*${`AAl!wt};b1-R}MdPAa9YmrQYp z%6F?E2%hcr4@YyZk&93;^S|}(^*5`?vrpys`6Nkh_WFlAIoC-2LxK1^TI)vD;`>R} z!ra{4Q?Bb?He8rs`}^F^L`00&YOVDzj^oV4ar{>udDhm^EiW(s>HGdP&^EYDLQO~V zHQ)EA>knbb2)dv z0C~=Np7(YXMfdB@Z!E2ByWP&3&E};vO`iZ>-tAef_2<6te-K5{&^}QI<7{C8WPX1B zBN6$mz`vlBQjGCu%-BC>bi3W38;!;vB64QHtbzBHQeTWap9A@t)9rR|G#ZUZMdTUa zo`}4wlsbP9xmYX~i^XEGSS%Kc#bU8o9yb03nOZ1NxYy>({(Zd@U~gmV20(u| z9(gT~c;me`!~EvV+}y<2#`t64G6ER`1O3Zsg&D|&M$dcW8&{WWwY6;(09dZo*1Cm! z8T2TO=47@dWIA)qB6H(mw~)UQH{TWjV5L%7pDIjT7c3cIl9Q1-gfNSGEm)d5lE1N1 zsjUCGE=kymvkP|(Zik-((1`8uWe?5owd&P73~6O9N#0DSFycz5jNsZWNL!;%_9LI|Asndu{LHXFf%zv++M+p{yJMa(L| z0feyF)$&B)x=7cWjo{fRx~Yb%c(HWBWKV&ETS5qjAJm^X7MriCuSeBPJ>AnYrD{KfwBO_x^`2}>tr}J)8PNx6>002ovPDHLkV1iU?`kMd% literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/arrow_down_disabled@2x.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/arrow_down_disabled@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..5f3ab00dacfd65db0d5cabaee6b78340ef903674 GIT binary patch literal 1040 zcmV+r1n>KaP)pQmUd$h(julvh(!=P8Qet6OsgR_ zLlFu^7cNu;{{g8AMT!dQLJ`~+1VK=wSe$7>Lps+MS50QrO`FukV3ml*P1|UiX5Mj; zNt}6e(@tjIdr9g2EYErO-tW1;-Z>W>4u`|xa5x+ehr{7;I2`vE5;UaJ*>_a*ghE2W z7tqZR78VL3;0aVj<=rWhJ6Y@RXlPIk9zej0OK4QAuCPJ^(Gx)31l;ohwoAhVh{}81 zIC-4R-**;Gxls`kVoF*7X1?;724dB-C3u_I2FwRE|uUoC$tyodAGjW^@o3 z2YP}duvI5P)k7MBp9e;Yh5WRw$+{B&kjjh<_;?c_4+Td8*=m#E(HPIK9+ly#!uZUc z8m-GzVSFZ0=^O&C)O$p93tgaU5B^G`((%-tg2&Rx%3wO%qoQL#%HpmxCo?h<4Hnf) zf_He@OP<+2NEys60Zr9y79RjsvzdRS8jvrqb}XMqO-u2$*?TXy%i?|IMtIQiYBRy76* z{kBRT7~MyL31CmHePcVJaoY?0rWJ;Z7xI@w6H5g7eDOm5vWgA~%+}hgTe+F>Y{Acx zkfE@Hul5}cj}H$&*m1ja3`kns>(vjozfw_`{gKkevA@Do_dk(UbU&Xv_h)Cfp8@^e z;UzZ(U0Y@xuAJ%UBps+JLb>RhL%wm-KBCq7ipSe3ve~WQ>v&$$OOfJ^H$U68xOf7$1t;`$(2wSp*KW*4~dS07@4TWjJO8^X*1nBI@ zXA+!R!;1}t>AnE%aqpV z1A~>IEdS{4;Lx?vqxhRHQH|EOF6i%jHCm6S-krx<0)YsiaVnv%zQ9_Fr`}%p-8@^g zJ+=z9Mip@_ok?KmN~Goh+>9%w8%W#k9eA>0tv+vbH;a`9`5PhAl{MeGQo1)N=|CoH zjf=wffr$YjGV_k5%d3^r!$I0Z_qMRun8SVy>;oD6YX~V|3;2$7Hm;PGhtVDBausWD zP8yy72at@@5Iys@63?|3W}XkLIr8l;-fkXuNLGNu-AW`%Wj-qjr&|lr>rwQ^dT5Gw zn#YnPc_ugtVE7P1m~EA#_oHf!{n8a~y*k3go{vDC&W|(k)f1n_)ym1q$=OwY0?7`c Ur_iO;&Hw-a07*qoM6N<$f+cnF!~g&Q literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/arrow_down_focus@2x.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/arrow_down_focus@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..cef37e872a89ef74131161425be50dc07ca89b3b GIT binary patch literal 1025 zcmV+c1pfPpP)5SJ6%k_ z=DnNDWahn@YVU7(&%NiI|GDqJ`vDe<#bU8oEEbE!VzF2(mIn)oHn_Fx5P{Z_ShRzto zpWDIuWIOS9U37pucO^$={Uq>$!A&rL?Q^rGc!nVRsy92<=)_6KYuTF}YYaDX2SoTG zZq*Fh$4^1c;srhNNOtFePQ_z#vK0%Jk+r22{}7_bV@AON=|d4jnz5qIdVJ~0-w*vc zHF{%P-nz;`RovR8InWt{H6*q5AOdQdw4+|Ba2VPC0j{SR%UA2~3CzU|Dj|~eCCV&b zVb(7fk9O^~x1_+WUVIbeD`Lwj$(y86d?+e!EzK0-%W*rNdl`J2$7&Z3hAQ6y*@!8L zqq9Ri&viv!_sfM7J^D`W&z=9Q{-OvcfrlcdUW#B6zpA3I_@&)vy7bvXqJQoDvEQC` zLgzb-t>YIJ3IHMb8q9W!c}p{ZPq;)PSgjokh;#X}z+HWn%)YhJ@Y zDDZ8oMQ+D8o$kKzR{Yl%DkE!Y=hwd*+!1x$+QG zpFmiB0@=nQiAmfomQA@9ilv2?+FRHtNXCBy!m7!fEi#FNnq(#`YcoF>xD02$?>qON zxeyW(67tSSV=q7A@uQQr@3W0&N^w-nz=u~us2D^A_=Cudl}&8>(G4_Qu~czV4Zl(PQ511Q zG&&b-QH@t}i~D{x15bA>Qr_6ROfHu6Klg7>PnL=&C4hs6xS`!Ve> zGjCeqev;X|@4e@q@0pwT&b{DpI2;a#!{Kl^91e%W;dr!=@Plk&b_!!Y0!;xH(7~tG zR|GI14XpjxtLCTg7t@j9M(&!YIq_jZQ%!FK3h)pa?2c#wtR6t+|Gw>`s3=wsgda!V z0RY)TZ49F)fycvPK+_0 zZ{Fk(1jK|_6y*4m>lb%<)#6g;p&pc}v+3-Ot4DxhR8$K|_Ym4NAEn~`IlP~*UvE4} zv@ZWOm27GL5a>HGVuI&~Hs*!H-qDHoyD5H8+cs02dsl=*(Wq(@=q6i-njosY=T~xv zdkNYT**r30Gj9dnx>e3qdJWt&PfgCfW|gmip^(&juMpqb{-fv{emQ@< zr`YtV005cE+RLJP0(dMSD2jA*eh@(88l2mz?Di|UGu>w!T%~VhinZsB=(h@)kkrji zh?p1ft>{kwX#RXJd4^*4mrQB?Il-O=Hieeb=4Y}4;8iW&FI`!4k*(H4Eb5b?|V zF4eWZ4Y(Xs+J3*o!{W?eZW!6tZ}X7QjnE&J($!Sji~<*fiV7^-I;W7xarR=mVPE)t zX5w0Zvuu)R`?}%HFP|{$|2+lrVo*`QGy*S1jqU5t*}v1TE*#stm{g95-U%)o+q*bY zX9voupdz#`UZwSmF|Q{_>bf&Y^LH~zo~g6xjW@286`AN{xGHo0=BFo_9;+vv+F)*l zr^o8IHeD$oe753P)ldD+zZM5!9tO1o{zGMBY5oI6KZ#Y95B+WG`-ZS17B=41TU#vzh4u`|xa5x+ehr{7; dI2?{gjXQmzEi=bH?(F~o002ovPDHLkV1jTe=kWjl literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/arrow_left.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/arrow_left.png new file mode 100644 index 0000000000000000000000000000000000000000..bd7d54f20fd162b458d8a9a2af9deb9ef41d4842 GIT binary patch literal 546 zcmV+-0^R+IP)zfNl)H7_+0Qw*W-M>3#_|0$_}} zs;c+)w~fpj17umYt*Vcp${f$Kw*ttr?3{=^17bj%X5I*3I2@i4kv-rrRn}fNz7@b= zFgWd;djT8`WnLR#G#Z_Xp_(CrLDUwS&*$%>C^`>(3kl&RGMmlbs_HiI0}xeh4dE?dt$nSkmw{5M zv8UBo*C+#P?VgBSKcLYVqHziHJb$99JHK_L?hqIX0Ki&%UqtQ#sA?mK)|V*H^V=fw z5WqR-4H2T1bhTRD1fGfrzMT=ImzT?BnWpJA;H7VDuorDInfzR@*O!1de+2+wu~>XB kisB;GYxy;#_P@J+0pK>C2{!7NY5)KL07*qoM6N<$f`iEK8~^|S literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/arrow_left@2x.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/arrow_left@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..aa3fcfec5726fc1c6594948ffc7295dec9c189c3 GIT binary patch literal 1072 zcmV-01kd}4P)k7RCt{2n@?yYMHGj>Hxp8diXiGm)RQRQgvFzv=&Fc|e?U(n zih>?Q197H0QF@!5WV(}p2NB)i#e<7_S^~Nny$FKfK@h})AmTw04^ae{ZPxDRA=#z3 zY|JiHbrEyQ+HzW}0cH|Ffj;1kP91+7x(2RYgQ5d7dBkaovHBi-gwF z($bwk3e1Vf5O~$swW9|x8jTLrb-l&8-RdpxIbRnFp(IIeQPmT`<&IVR8Y9{c7>~y{ zsOmOwb&IXO#)%R@k|fuN$To0&=&_;$FdB`n06qe4?qa;C0HkSp$zU)zuBrzd%UjF4 ziUvTMrgLRk9s}-jEXCtZ&s8h{q%6y$z{5^FXz>sU0BdalJne*4M1mF%5dg5(j)9k3 ztXehL(m$(S0VGNCERef#5vjV$p*H~5+DBFOtrn}3nLndm09b4929C9iUlZ_=*QU+^ zj7Fo|f#bluV|89UbbJ^}lH^w4gsNWVSiKYv9d^L-^74(Ux~-~LIaY7QLq`A>7Z+j@c<5jWjK||EMdV}Pre<7s-);3;JOu85g@uJnMPv)Otr_1dKKL&0d=v~o znx=EcnD>A?94ngQArOExO$TLJz6~65tl)>63sndJQkLZg@MJTnyW6{{iiZFIthGzP zf*X&i?VIunz*_qpFln(mJKS8TyaBM*=D?dRR+KY;Mm{^heW3vnY;^XMPXN)j`G3h9 z09AdFf6sRBZ=Cj%w*-r#_&`-(Xt9PO@qUE%IzvTKyrHV88&}n#&vAUpdy5uDaYRI3 zcjKxW<#Gs-l+Mr3zXZJ749f00hz>%Kgt9EFcXoE30zPysiLDcYC9}D?dD4+7sb<1s-9oqe^gajLV)vkH4QfnT7TB^;XS}F z&G=py^a`P~Hk?c*KMn?idx76ua_9|0r|WQab@f{jc>p-sl1DEPI=>N3r_(Q0^%3B7 zOD>&5=;cma6vZdN6SN)`pt0DvsZYGceZz*aNf#R)PB003E*{cVhS9QfR^ zf;yr;IU&RP}4e3U)Jy3IITsWq(#xbwBWZ7vn_-0AOQd z09aXB`AI|$ipWlj?QKa!3jkm`oqo5s9R6}FZ+S-z0AOux?JM9RJ@?m>7yn;on#%M1 qGvJ7-R_uO)Tj@EanP!^lBGEs1+BIzV?hVEO0000=G`P)q$gGR9J=Omc46}Q5431Pmb=;YE5JGcnNK^JwgP-vUxeH@yAgW!AfUKI3f2kv>! z?|j_Lh5y|YTk!JS+{wLeaSIo`_9i*;yYr=($T literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/arrow_left_disabled@2x.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/arrow_left_disabled@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..56a1c0f52a69e5a09af346416f6bf969cbc50244 GIT binary patch literal 1126 zcmV-s1eyDZP)ko)jqQZ9G?Z#Xfa z9M+}DZxC`fpi-@0C&Cgin&cH?(R>#VIU7*kKYLAIwGEV#ydts5{{Bo* z%qvj2I(LP{(g7|^2_mtmI$1pAQ~}q{%v>VKhrp#tUWFKki-#O4U}AcDk8Y2?kLr~v zK~Yy_pM=#4*t_?RbG3iYGOFd2peT~>ad$dcGawAZ;-6!iZv&GlLDieZgDnFV7J}cT z^ae1WQ53P?-=7I=>;W=X29&Gy2N4eL zR;2HIyFU$#88A_;9TL^olAN;B<(Z0M1I7$c-St8PAQs#u)AaFG}sMU8h*eJIOI&c~zEv$z+v4g*i`Rw?HEu#x1&VBTIE0I+(j@wqCukeD0P;13qw8vw8t sH9rzKAkY`+2g>uVa~fiZA^scq3;bj?fgFFSZU6uP07*qoM6N<$f-|lDC;$Ke literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/arrow_left_focus.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/arrow_left_focus.png new file mode 100644 index 0000000000000000000000000000000000000000..e7fad8f5ef7f4c17a2160f48a6f90413c770f91d GIT binary patch literal 565 zcmV-50?Pe~P)_?X2v~B?lIQh$Mx%yCMmK3b((-3bFI;dy9fjH}K~F z|M_Qj-@^YMmKtz)xpQpD`wueIpPM-PyYCOABtOw?AM)Nm7aTEVt8vNLZ*_*evuA=c zF=c54v|6Rg;lX2xDKd7RPJm>UPoodPE+GN6^%puDtk8FU{2!$a)!L*#Ox(rix~dIW$hH#y{Rpt`hvR?q@UfUtPme~l;y zs*9aT!76Z&&~?~Ls6z4?oqhzMu$h&Kxr(p_;!c23a)a!%ZUg?S%FJp(0 z?pnP)_T711G{IP)^@RCt{2nq6pIMHI(>=k8i9X4Q5#Rq*?vR7!W#LhwVqHcZqne=Qq$}l zA2xlMyHOIDxp&n4Kb}9#IrE#@xo7TO=&7fk{?C%M3s|WN<1-c1yoex}XkW8je96VQ z{|W$w@%nbq&r$8vtC(iFlyNb3*2N$`RhXC=#F$C!#fn^w?`$9+%8%7ArxY~EF-~bf%f1g|YGy4&+DT#bR0l2Pm z{30?7hY$v1ma{D%S2zGFN3y3cX&nS^w&H>U&JMk}!T_Ku`CR^hDtFt4DC%$W5J(?T z7_aXK9*%_-)a&FSfE|z@tvv@?UdHl1c}N*RVYIeegb_Qc0PUn|NDaV-@#%XJ-s&>c zU6;2Kr2-&7TD!%l9PG-kVwO(*#FRLI{KR)Rif{;66SEBBuEkxc5(Th+tiD-HbQrkU zcEsSZ+4(0W2H>)>W7kHQDPVofGA=JSt5qTZE+3uVkfr@8aHZ{}xAN!Z9l*MgZ!c|& zd3a{j$%>13z1*x;egIT7 z>d)oh26kC-5k>v?_p6b60IE{R&5S8LXvKx#CJ!C}^iR~D2liOO&RG}Sb^hgMt>kf0#=E9TL`a~HH0?gRPK zHdMUkU8TGh@>_NA%wlHoPGCA_1p~o*5%YVt&5Ma{2Y!rMLI6!dBCF7NcFXS>)mwpI zZAYWDAtbg9Pm~9aw^eTgPT7t|XnGJ5{T-ev57dov2f`W4kn|uVeh|%-OJ7H7?g7qO zMyE$e96~B5@yX$>pNPla} zjgUV;EW};}K_xlXB$XGi2^MN+Wf{^2#6kFfA@XW(|l%OV=A-krJ$DgW|5owe0L(7%w7mChNSrb z%y%n|+QEjzY-p+jfUHsb`Uvbg2q62T0QF@39Oxf9l{MFw@~kCyl1A%82g?OK_b1?c*ip4fI}~cV1Zs|=`B(V7y*Wr zTk8tlpx=qNCB*=Uh!VSH;Svry@ur!roX{x*QL2Z%)%HV)`#-f53{iTB2A%d@;Biq1 zhhNFmAD+4mdOq%g1!?*`C|j*je>k;h#_P~jzh`x;^*uU_t{J@hI{?7v&BcRnI=U)j fUoiC4{&(XCWl)g;$Agj`00000NkvXXu0mjf^_=c@ literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/arrow_left_pressed@2x.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/arrow_left_pressed@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..295558105563b6ff3cff91cbe17a87e9deb12356 GIT binary patch literal 1120 zcmV-m1fTnfP)CSO41K+=)W;!QuH zQ~(TAT91dy;U4)zTz2210P7kUX+0vUM}Zq+mhN~L*lxD~#A zq<&u@!3?l5W~J6VIGTVvc28}}lKmbSiWrh^^Wb0tHjIwl*6oDfB0LZ=R(5%*HV>93 z;O;#~Zq9@^P6H1|9XGqYwa6ZT>hbKQ3rk-Dk46nqSG&Bm$PR#NH5fc|s*bQT<|yJ% z^I!#lN^bW4PZTLc`+#<%uvd}K5{8<4qia$YiV~e4`s)qg zP%JDaUu&C^oq}q$upL}3B77Y+R8YLSG1~h@4(?iBCzoGD`6&_?1k{^Juv*AJ2X`%X zy7~+vCt}u>Nl0JTi&&g2F3NKF6!2%n5Cjj_f|FliZnF4qhTsWcwnzR{Avhbuv-SMR zt_Dv6=MyzZdJvqh!}E>&Z(%4;14|J@)0+h6H=>1!!q0&O&jZWJTGTm&RPMy*#`E6^ z@(MiWh@M$zExH>na z4gf^kcb$Aw&{j0==J4bJ0H9V2=Y}?yQKqAY3YKg10{}p6TW5V&UjqFx=2(T`4*=lQ zWbsn?-@2W^uQAKobHOVB01Jm+zL3cVJAgl23q5ROOTt?K01M61@2au`xEQmpk56U*<{O1yRODGS@`~-+|72#h=En;^fbK=< muKbNwK1{o&zWVCx+R*>gDKCq$x1GfR0000?^9wqP)M=`nxz!)>6#&9@ZwCxbSboJ zhvLQfBttPK!|A*zq|iBp4uO!(l$MSiGI#ILsnDgxLm^kwdl_OCktLQQ&O`D|65PA@ z8csjZ&)P6>uFv@<1u| z+$$hM0LTzWaU8e20&)%kup}at;w77Iga@PDG$+p(|OVK$>Zvjb)NB{sL@-j)1ahZ9_uE781Bs<2K z_a)~k1z@gjUu%6>ws~Pde%S%MOOj-8o8~~lGaw=XNsv4V!|*k(zWujK;VmHfDGb9G z!{N}~Jo@Goy#?pf>GY}A`fnA@ivT77XsvCfY5J$C=Jx@BOG|*7bWCSFrT_o{07*qo IM6N<$g0`;cy8r+H literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/arrow_right@2x.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/arrow_right@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..efbc8de3c3cb297fa56a0785f70ce9e7ce14ddd6 GIT binary patch literal 1062 zcmV+>1ljwEP)d}b)>grtQo+}TzY;+2(dCV zGvnFP+zr+YAff`@>%zg2k&!RsI3BX4+b_1KK$i(bG~I5uKZU_V*n?nw4IrYTJROMW ztsn@bZS9?4-2i6Znhx6_B0q{E-?sjL;c6EE5#{C2m|2Bk__nJYbT~7hGYg8+Yyg1I zq9~enl}8z826SM}bP&w^RTzdZIL>8LyaG)|ci%7!V8!?SXI&>#g#m!xggrut?|k2X z%4H%|835=_c&yVr?Q@kxl?DL%HDPa_=j(HGbC0`7plSoQdWQ1Wu)oo0ti^HssBQhq z4d|ddG9SpYY&DMKM{Ek$#QyC2)G|5<_v&-r9-cw3_<0_9bE?aXAdmQ3A|AEQ@lK=n!07*qoM6N<$f)6C<+yDRo literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/arrow_right_disabled.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/arrow_right_disabled.png new file mode 100644 index 0000000000000000000000000000000000000000..1e59a58c1221c50a25418cd853bd88c8f3bc70f4 GIT binary patch literal 553 zcmV+^0@nSBP)FbLS00h9JGxt4$51kEi|!< zytoLuI!ONlk>Ecd3eF-9LU1W*FfEdRL$^1$ICXFmgran)v^IGkhdYa7@+MpdeWn}k zp5KSN<2d-&OT$d6%+-FNOy$zx!e+bueUgA^xM_A8)2aRaV)OFC!iggQ_!8HP2c>tH zlH}OY09-9jZSTHLlB5tEV2~LY={IP)^@RCt{2n_q}jRUF5^-#fdjvFyGi`XFM2Xub$Lv+9Ge-dS>M z{-m*p_z(n@6!?^cU_`d0kOVyx^pAobq^Kvey}L5H&ea|&?2Z~lAU!M+qCv!J%WjNw ze?9CV>pgd=SB$djAjnVLN>EMcjYTH1L#53&b7_kKK(l$GvO7GC49*S=7uVa$qiqHN07TME zSnCNZTSi7!+eo3k1^|GFB>M&dHg?s!C$|?0{ifyHZvYnh2B_~7vh{hM_I-b)No^+# zXp&+Aciv|2mnNGhmka=a7@}0d?iu!ef}=-`w85bZa?ifOt%1RDh^QT;j8+I`Ik&G&ikc)Bs6oZU}tcAI~0u1Cs~LUX)bY zS^>g7ncW|T;ayX@tzz<`Wb%Ap>scA^3Bz#Sl;(1R9J=W)<1|7K@`XF?{5-R5dXj>9B3nABWyUav#^wF&Pv2a z(AGi@lG9F(VC8ucQLvW7LQd?0D3%s>LQF~vZ3JDT+#Q01%RGzS1nhP<%UI~EwwO1+ z&%B*t;9oCgSv1#q|3ijG&K=)wM&HW>xGalg90m^U^}aiQx3@nyU{VHWcIBS4I@t49 z02l~ctQ{C{u(??Y4*-ua(52d^lMgY=bcf0V2*YH_DC}Boz26QC0Kg37F+kj^ulJS% z0}=(2Pe1O@b^4b>1DH+%klEu}r@s^!FhO8I1+!=Mwcgpl004Z7*k?}N`r6=BXh4Dx z1{^f!U)JvpPJ{-4O%e0n``5KQ?~a58Ob~$J7?tXa@PI#SAv{3Ieg+>I?;g$4QY|sw zVF>u*oI4kOJJEF{3kv`Yy&CT53hm@EGHd1f1%kI#^A~7GqcXxF`vkU3Xe76^ h-Hd*g75={fegk)El~b(2fJOiS002ovPDHLkV1mN7@^b(H literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/arrow_right_focus@2x.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/arrow_right_focus@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..e24c3baab9acf3c4ac88eeb9d579da883973ec51 GIT binary patch literal 1139 zcmV-(1dRKMP)jPNJ?V0o1n91li+%nIqgrEp~C^uGmO4v(HTwIZu0VG3MK!l^Y-QPYYZAU(U z8eBUf>$pQ{^=ahk|pzlv7+N06Q|o(rTh$l0Vs;iX4(~ump0jy@-qOS7J^wV0*t+#h2rzJWc&>PNUatD5QE;cCE<4f zH-)Sni=GESK#E5q{=k-kH(zH>2moi2tqk5=8R*_)OU2^=%)x`OBeFPnz{@2-0FmK~ zi6<)k;ZECX9?k$(;KaKH#z)cgBYi1l^1SgZ08&7*+~rRy?bTN>nD#++{`j;6%)t}B zT&S+TfK5GBhoWAfU_RF=#?_e(=lUPN?o!x?B|tC-|FdeNb(MV2CD-Cjo&iKD9)4}h z#B0vK8U8Neposwx0mes;i(2WmzxAy=E9IhD0i+H7swRGVs(;0Il1AhM;M8ef)tY*z z2D-nJwj&!r?fqa?%(N{U3=ar; zFp!!7rVe9wl<#W#GZ}#Z$f)ud_^^@>^DZtojp8-{O0Dldj;5p6d>B07HURTl3!Geh zIr}0;o}6{4+Yl}{!Q@~5l)i1zvu8){`@^AT!$@s{KV>wppL*kg%R+j$jKnc`E}m6u zDqFhF3urZr#Q=y>-T_8BLu)VQyMD2!V;6f%fQ>5eiiTPr^@TrJ({O;rf0?=ACoCdn z;^(4#*VoqicZ9_mfL$QO0Aet|9SwAUZmsVYEn2j2#9s~PGV2o(qKyCm002ovPDHLk FV1hVO1_uBD literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/arrow_right_pressed.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/arrow_right_pressed.png new file mode 100644 index 0000000000000000000000000000000000000000..4f4fc8efb41497bd51eb03c09a0339ad716e5d63 GIT binary patch literal 544 zcmV+*0^j|KP)Ws^3hE%@uB(Hibg7fXF4hEl z862d4fk^Nl5CxYeZIgD87Pn9oM+awjhfabfDh*UL^zP?yNnP)9$D2W)?S*^Z-{+q9 zJvjK+%hEhFA8!3HWFtjahVAfskpM5vLk8!;%5zrgEv$6UItNTjaN~F`dQElr)Jy;X zhAjr=qb}85-#x$-g9&UoDF1u`N_B^d1IUC)^9v30E95&@#1l%(OGi~m>@_H zlAg_noqKKp6UG=}Xe(%RmRtiS2mwCQUM1YT=^6mZ6a<`>S+COAyzUy1AcPR-Bzsd? z-M;D?!1&7$un-fy3m&vDxCJDYTuS3IerbOefWIYOn+3p2vN<4*E~aTH6&!BB7Z3kd zf2006ZBzczN%)}`M~nUT%BQrg`2oViFyNP=+g~?UKW1sqcLYhW0TE`^{(Aj=)-7^O zKsFvd!s>(dT5p`$Sbo)$q1SjEOPy4Of^J&8&^8{p|;WF8oZSN%%|kCOjGmjDByw}auC8qH>$HykqF0fP_zZ~qQ^cSl8prw5o0h1n=R iUK(zPM@5DIFMvPFm6uy&so_rm0000 zBuX&SXCP$2>;cr}7Y5!Ci)|1&13=Sb5kTkt!r)rD_+}6^08#9B6M*mi_R?xW4RIt5 zV9hfhDsyphu78=Jjwq4_%*Ha6QNu6qIOSW=sv8>y0KhAg(ftd4d#TBi-kdRK04J8j zIw1;>&Evvaa6i-2uH8o)#F`v!m%dgo^CJh4s z5Q7pXJg11i%NB;#*vup)1E5_F3}gw>#TW9$<+jpD&wv`bny|zpZ}_F1LoeD$AZ-JH zTGtRiD6OhaMHd!-aAJ{ZaTg4jrEkEi>e$^19>yM2?1`rTIff9rNwxaH}qq{qKCJ?|O16Vis%k!HSY(sD7q$yQb3`kCU zqMxej-aDg*w@sK9PM6wSkH7if6yJY)ytng?Y58;wAkc%NH=RE`k2l;ZcKl@{g)|M& z4SqZ#Z2Yq)H)1P^ve}qVX+S*I-H3QoSls@LpoTbd22B45l8KqICG5*x6^m~OIRlsu08|B| n3h=(L6#O6-yFr5n4Gi%gkp(5TEJoOo00000NkvXXu0mjf&UX1l literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/arrow_up.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/arrow_up.png new file mode 100644 index 0000000000000000000000000000000000000000..9f45d8e4cbe3e712854fc309a31bc9ce692880bc GIT binary patch literal 512 zcmV+b0{{JqP)|o3*lVbAQ0$RU%wt zWh-d4B(qzD>10c>vb3_W5=FRfVbTa&S&LU$ij|OsnP;(C&E4+l8a+kG4+5E&H}CuA zV+gdgw6y$Vr0K@dXtd?Me+~3P2wUUv_+yhfQIk!B!QiU*-T^&;D2j?K%dY$t1H<9) zdZ*KIz;>;?4Y)K-d#7r^7_$>Xm;jdm1$^}=a9Knq#+aQ`F<^|@Q`H0Dd?grapF>sK zRMmqtO>eC`x3f-Dnx=Pw=fK7a@de8KQlAx({Uk}=JLlg0wgF?z1K=t1v`!NLWH=PV8S*%=0{&&1R2P^?p@a zOZ=D-QPssAdlJX-Lu>6)dP@o9dA?DWGF05)suM!)G*91F2umgOOE;g5>6w6wJRw|oVEqMoFksH@rl0000`~c6R0fK@bE%5ClOG1VIo4;r)WPYGAGPDFEL9P(*Yi48tp1 zQAcGf2K9aa0)X!U>;|wCz{if`{ArANTy`y`8=$rJ0DO(??EAb{tNmw;`L)b?$~1sH z&-;pquC8;>amR6X7-N1et*9~v34&l-6h+?=(HA{-xmB%JFE*RaSA`aa5)24}V0#or zKM~PMOE~U)D@*KdwOT#fY&N3;%PZD^AP9CxQFM=pj#$F&)V1w#T#V!RWUJNsr-1SR z6lj3&`+J#r4!}p2a9TWw2+W)@fruUg_$&;=zX~X`7y~@d+ebw60QPscGcyxWoYO72 zM-frFu4k1><@nUp)bnB2I&=eE*FC6|ng{S%L>Pv@52MZm+v3wV zTI<6~sRtN9JOB_;%*>o>9%p9by6&Mt>+EJ|1~eLtV*nNb>`8?-B|ag?ggr{BC9U<* zKFiE76a#$UKOM*MeXMS4-_Q}TY4Hi2^&)M;P5^VAv&6s*yc6_&|2#AQ0AO2pdrtBF zkmTrI6Dk1CIF9qe81rP1i3CSt@f`m=C^(m_GUzR)oDYmK3&TjZA)S5ww?uT_5-wUiuv)Wi?Yg647Z(xD4?LRuh={&dSQl*_oM{mzzn{6Rzv-QcB$eV0#6XDLx_3gau|k)$948 zr`KS;ULUJeDvPj-Z=-zi0Ki0KJ5wA}N-fmu^|4-(Y&ZiZCnv|-?e;u?18YX_VP9V& z3Rx{r<2asZwOTLM>$t7~zV9Dk=6L|)-R&bLJ~>I+O!%W?!n54Ic>&jT4=JVQ0IZox zqb5Fu&4j-Jd^$Zn{V1UlBSB7*w;k$eTSLZx?Eet&4mNGJHQ-AOaD*LU rVytQt1VIo4K@bE%5ClOG-fLb1RDv!28%yT>00000NkvXXu0mjfe;m12 literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/arrow_up_disabled.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/arrow_up_disabled.png new file mode 100644 index 0000000000000000000000000000000000000000..a77807c572c7649c21ee11962886844543103328 GIT binary patch literal 538 zcmV+#0_FXQP)^V*xB2qva_*B!ig9g7cPx(XsyLrnG_--l0v=xT5ML5Tr`)}#AZL$Ff;Fc zzw>xA0|f;I1^*e#8(6s-jg+LPKt%(kk=HL4Kjg{d@&r|{L}yD<3#b6tkM6P`TsyNb z2C6}$>PobLvH+#iWm&g1UXLn!YQUciC!ARfItj?2YtR*v!6`$rKN(K!i2*-oL?kQ$ zM?nITY|XHQv=~DqEY<2^_)iV^L3jtVd0-Gpq=H+?ObiMZ{2;pBPwvuA8*25&UCibH zhY+@{c!o%CmczJydUWj5YUkanyasH%9^MCg03ai=Up@CnBm)C8m>M2EXDgkz@$L-F z&N|;6d1!DCKv=)xsq@XlV7NSXVrAymbKkST91JXm&4v7O4zLgW(x zEKB(LT5k zI=)dUUt5k+Pm~7GR@o0pyt~J5jvX2u@2ixr{Suj|C^k__b*;1aGk~u*xa7+Lx%+0Z zSiBdiFhtM+N~!L3tM@yAuX$raIs^p%gNSe9z%%2AAH7g6mqRrn)DCz)ogVmS!#WQl zsR?g;zH1JHmwL9WSC*H5xD$pxAVdS=FQgx4mz4*Q(1g9k@1pC-Rk`P6t}Nwm1*h&m zLNOrmV(xL-#sVPYo{#`=_E~QEb@6I!J9cbk@xqPZR8}(wozR}jKFt^w1bEDST>#6H390{xCIEQ-m2X9gcyKV9~m9{>t?xhrJeL` z8DJ+fZ(nzvO0XeTot0DRvc3BLH9v|1AY zU}pHpSWo48>0+ySn?fnob%%YQ3UEe~&H*Iw;@!y3$@}hILVoeYV9#4~b942EEGGX^={|XANl-dqq!P3;ONog4{aQ9&I96m1PSOc~$Vste@mZDjPNbUkdyr7Mr-aS|z>%7OK)}`qoN&;+Kj2Rb+cT?$ zpRd+iRo8&H%1n^V0~qq|gf^zTFcHAgJSJ}gcEY2ar&2C0x&xYl0`JvH@}R?N zZ8i7|VAN0Z2+`H1y9b<;`}lv}D%G0Kby|nPU@#aA27|$1Fc=I5gQ3&>3n0o8p2LzV QasU7T07*qoM6N<$f}eNu0{{R3 literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/arrow_up_focus.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/arrow_up_focus.png new file mode 100644 index 0000000000000000000000000000000000000000..b3970bd22e2fc9a93f2e4e61975aba338193e2a4 GIT binary patch literal 530 zcmV+t0`2{YP)_e)ZW5To=?k*>NaRq3R3E@DR)QE+q+ z6>)HknS>-QSo{No3N8)`6|q~vZh|J4T_;8DP!t^6=KDG1&Yq^B=2~^RXZnu!``+L4 zz1$t-YdXcvh;CT4u$nM$MEhIFae-KaV4DV9L>^e z=m~`N&Ph4{5;*i*>60@z{rUFs)-e5snm|}@P09J?UbqS90$mINhrRrASZ_`J6@g$j znvt_5U_T&`|5+41mZ-?tQqYLb@2SApY;+mvDKOd#$ModKNU>m-a*;Y(zIq zS^x?I!?#Ez3c#bV8C}mVAX(6C*JQfidp5sAcuK-NfY5x5po%=hnkp800q?*og)VzF2(7K_DVu~;k?%l``*)WWVG%!ufRfTM73 zB|m;_5IP1Dfah0_Ae;f5J5TjUEk7~eZ!J#yF3IBh)dIrV=-P75Emhy?x1Rp(09Ely z)%Ov}-@T*wwb^G2h-g1#^(TO0CFADYvjVSm(p}->mDQCun44NpTUzP?>?vN|aVxj_ zDX_n_ML`{dD4g8|0Sur1ahJ39=XsE+=*m(@_4aR29g3Oa z0`=_vT48K8Esd!K@Yv}eM%LFd3&8U+%hnY7#fZFeV|MSgq_rjo>%jrvvlQ>|-EO21gzE);kqUCZo1NVgb12rI!VB zLBS0*HO+4qHG~pVa4}kO{iT<>SK3M<0l1~$fT(;0>pHhZ>#8hbRIEm6!}EZW}usK zRP`gT9JD!F-<|HNfU0=q-~;gjTAw(4% zsrT7>E2=|C#Kw0Iu(t2F{A8`&@U{UAmxED9brBc~jcnBTL7H#q03~{KRxTN%(>Dqe zzqT8`C2pxYCa?&MwvG}-HHjLZAmTvi5+(e?x=z;$6IZqzwN-<6DwxEu0P2OBdOh8x zhv1-LPf`PYwU!_MK5j_tLC7mFPhqrjPnidrcaG3UsUA@A{NTm7A(0*6m8-{qxoDF2 zIF0|TVr_Q(z0HrKJ3zH~-zyHTk42I)_mSM42 nEEbE!VzF2(7K_DV88rU_>&iA)V))lv00000NkvXXu0mjf(TwT} literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/arrow_up_pressed.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/arrow_up_pressed.png new file mode 100644 index 0000000000000000000000000000000000000000..8f9dcf4900443a161231c1912e4724cc39f37f1a GIT binary patch literal 518 zcmV+h0{Q)kP);?q^q4HxG4pYt!acIaKGB8Y>6BJCEie?b2Nby1WKodV@@_jTx{q$Uw_iMZSc-sS!Ad_V8Q z%N>-Il$88utmwho-PW9?d_by`rE}Y>jc-NjI7JTm&1jxPpOESRGI!H&teq)RYwQmA zVRTlqb>QT0OFx_}UHrM)*czwaSRL?#XhB#z4;PT;L%^xbaoc_nE&LM!FKjId+dv%4 z1GB#63?ZN@Y{P5Bm!~RF3tBgk-U73EP&Tm1$a1k+jCWob-4R07*qo IM6N<$g8Ys3X#fBK literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/arrow_up_pressed@2x.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/arrow_up_pressed@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..40c7f20c102d02167fb9ea9f75a38f7f9d3c24f7 GIT binary patch literal 998 zcmV+LWk%02oz1 zT%DUfu@ySDqyT;p2B@3`%=$%@pfUGqW!PGB!=BI!YR5%+pJ?%g=XV{Pymjl+;@88} zGsF&1@q^kals7lNPfj-~uN()_VW=8T0cPuY@7k4f0);fUt4MYA(S5IRa=e+fw9E^z ze>&Xx$9?h%%49sMwk^R#BLbh_-_&D2%@_X4QeUP8*z?jy51NtYBFcDoL;=%U`)tcl z&BfKo3br}fsFr@uN@HdPc%)DrZRX4p@MJ=`)gvuwQT{gHvd{e*7JnO@x_`-}01wa9 z_T?tXTgptTOX0A6|F3BfJ{k42`^wcmUS6obUH zT~(tKtLF+o3`A&~*y7UKoM@9Go*xeOS6u}aEm}yXeSP_8T zf?4u{+SI1RM(Dc$qviRMAQylgk&s<8-#1C)>=4yYM@wO`-@*Gj3;5;mEs!(B7t^FC zHwdKbyT}V82Pbd-d1>*R%?`N94p8xf`S(ChCB(8auZbNcoE|NO??QCzOvjxk&DQh& zwJT?VQbIH<^PLFE53bU5uGVjbX@!xJDUlVW!{3Od`U6yEN< zn9u<-%m2?jfV91JG0^`5?naV2;2jvqDQ>%A+uj@whr{7;I2;a#!{Kl^9QQQ00WQ!O U`vgegPXGV_07*qoM6N<$f**q7B>(^b literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/base_icon.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/base_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..bb00857a4e170543e97fc60ae991b409ca94fb6d GIT binary patch literal 1256 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 literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/branch_closed.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/branch_closed.png new file mode 100644 index 0000000000000000000000000000000000000000..caa34ce5be5d70f49ef9483e0e960300ee3aa2a5 GIT binary patch literal 350 zcmV-k0iphhP)r1F+*b z?si@G87ja&$wg7j0Biu*$+GMg{uc-n$n#v6v8o=6$YoT4KR6eW)3pc?k(38d7yIiFU@YE)H|N}TYyp~< zW#+@SZC|4a5D`uL=KzlCx_(}zPRJPYBywhqd0MqjXbY~Irnw0z;3Y5&!}sSyMEAy+ wi;%;;1^T|91Nb1K7i;Ya7W1D-BoaY<0gQM{BKod;VgLXD07*qoM6N<$f*atAbN~PV literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/branch_closed@2x.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/branch_closed@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..bc87d011240a18487ae14e6f049db1d5cf1190fa GIT binary patch literal 704 zcmV;x0zdtUP)8Pm_{ot z7AypXGfaXI0vC6)$<;)Xpu9{ z<#J~_oz54XxvOw={&ClJkNt7;08pCG=WklA)(M@ttI%3NsZ^S0Ts}9MOkR4PSJ0V# zSXvAC8)m*#E|(v}z#eoED+TPksg!D3%m-k%007ulN?o@(fawA_HPoz zb{dVwrtaW%DF6VH?+wJvf$q?CDj-YN$~aQ%R6uIyC!(jiL)WE%)Eq=~&-eYF@n8!a zBp!K0^vL)99aG`fFmvkW0lXfKMt70@;&kL}7C?#PG7!;+*=%-gFc@T=Bxzx*0LsYz zOhlJ^z1|O#gXB$y0efHj{?cD!=5Nfr5d^_k)AJZ#0m+*OFm)VfGYrE|re^`n7m)RW zbHn%j_lD-YOpo!N(_wSXv!ekP8+#&H~PwA=0PI&)W{_3Ujp9LCjZH4oqdfC)2S4a0D# mGgAm5gb+dqA%qa(Ain{*MXymegB2$L0000KP)R9J=W)GoZ0m$rjo+s(~U3jPRj z690pXZo0XMAt0#z1Fg{6MbJfDBpnn?K8K_#I3vS#XPNUsDvvL7@%ed_=P zR7e3-5P){tp44vORo9R!IL3r#}l zU>2QpC^!f@2qKO}94rnlF4{?#2x6PGkfFwIMK6jD4nh$`q#!5-+uFYSgDHx-;9MwE%x~ z)Z-7IfBuoPnu*-QFXx_p(wW;1N9(UIeCx#4k~<=|S?wPh>e8Cq2CW6GG!ZFZGLEjT zI8S`v_jG3OmfjVx4I-T3uI~FVum|nLN&y=#W^;ub7V`nvEdU^lWpl;zHb*dB04v`R zPxR%AIm2^ovatf<#Ah!iewsa5IAUQID+Mq>$rAPgmF|k zHaNJ~`@y)@ zPvx(eNKZil0IB-{02=pm#Sz`vsVHDW^0|SSa9ek1iVA3P$`iL(8UI#_3SedDC*Yy( z)KnC}E#@G?wP3b-M|XA_3UDZ~{t37j%vQ&ZgqsN29y?G^{>k10ombK7!AS#a1uzi- zlsx!XO)orGE|=9eNt#$HfQXor*&jV8Q+!*i{V+L+YcdR2e-tDr2mc)r^7GFp7fsJ& zd9oMk5cnOBC^?##v1?+L5zS$wX^E$W`1VN}Xd$;tS0=@f}vGreGZN_naer9G# zYi=8~zI*!;1aWuIA(tHI1PE&coPATD4s>P;A%qY@2qA3dckeNxI!uzUM+;{HxZt`*gkH_=hVWw)y zRHDW`j5-6Qp2^ng#7j{Dld1afG9Xc*IR5zhd<-eu0}2b=J?Y~tEL5WAwp)R3klGxK z>Pzkg1OT+D#zA?nG3!>~-9o8EV2nK*+HY1J3#1Z+0QOqh^YU(e)Uf~n!2%S35fkvl zy}(yy{zAY2B7j?)Xw0zy34nk)Mx1MJRBy5-bQNnZ10b>1%*VCxDo;w0Z)gC3;!3*~ zUgS;5H-U5mNZg6n!=t>-fvgi4?)zLm#OcG@)K-z^*#(xT6M(V6>;6*rB1rvy$>Z^O ae&!9eu~jR|G6!> z%vf=s*Et&ae*#o$kt-=g@1-Y-yS>jshynzKSP2`c>cg#9irv1)3A6@itOSAWwTe!6 zkIk<0IZ41pP?hL{AmpnecbJ+=`kEr>R{*FHUlk9gU+kLj^&cU00RXl7y6~I8iOhI$ z&_{SX6aY$eQ3M!I7v_3hN4G}-b;J}S0ZSd_*#CQlVl}mXfCwIJencE7tufRaQ zqRIuJib@%kLyKqjzH*vrj4{R-V~jDz7_)-!VCkn1iKF|Y00000NkvXXu0mjfbyiSD literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/branch_closed_pressed.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/branch_closed_pressed.png new file mode 100644 index 0000000000000000000000000000000000000000..17b7784c34b07c94f6fa3e60fbff37e517595ccf GIT binary patch literal 372 zcmV-)0gL{LP)K@>*MolO%^)T{`iVrgk%Z)ss`Cqlwz(askT zEAa_zL^ewTYG-NVJJ?v;2#O$^U@#zp*=vynf4a@UZsDA%1}@({b75w{;c)zSBwx82 zzuA64%wVS4U%5Zo|F9J>xvF<>JrVH*U4DI^ia~Q8z*b=XO}{s~?T4MCVg>#na4_5K zge3`RIn5Jwcas6(b6q{>k00j1WapPv( z6pIOf!f_HcS~eN^Ch$D@L?rFSeD{>=%v!iDU|=}YT;92atmZ7n z<@oUIXzwSdxiyGf{&*8jyVl)2K!c>BSNl62?{S%13#SF7)0C6f1dgT}m!C5*oN<}G zT}})58-){DZMYBWd=J`6kOBZiwf8`7{CcSTKY|qipfK3nKh_a)2G0eEf>vHqMw@e^ z$NkQ+Ccp}iIB_8Z@*K}4e4u4C(`fDOOQtB%Wmu1*RNP_5qim4~jA z>!bjpss*52EspfuaUUF-5+#p3MeY?xx`%wkr+tKMB1-&Y1j@^q`Nk{BqtV>}p{(3^ za^b&A{fy4?>`c`^Nv;GcKxJj=ue+jrj3}L)e$@5d=Oq3M5EYPQ?l&ZA{Zi~UcFw!Z zt%ci1;K7BGM$t{6jIxMwdbZH{*=eRR#u#IaF~%5U%octDC(xqlE`lUt00000NkvXX Hu0mjf{A^Ov literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/branch_end.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/branch_end.png new file mode 100644 index 0000000000000000000000000000000000000000..05cf7b6de7bd467fe08bacf7f158002215aa4f67 GIT binary patch literal 142 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz&H|6fVg?4jBOuH;Rhv&5DCpqn z;usRq`u6HZUIqo8BL~`7*4vmhEA~t|c3pkbB^Ab7_qI)cb0g&kJ2Q{L0S0Cs3I2$b m8T%f!#6P&e;5o_U9pe&X4pDZKA0a@q7(8A5T-G@yGywo%Xe+h= literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/branch_end@2x.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/branch_end@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..6df213e35bc14e65d3a8c90fcfb9b2c34cd9ed0f GIT binary patch literal 220 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=oCO|{#S9F5M?jcysy3fAP_WO_ z#WAE}&fA+Cd7TVJSRCzlEoGkmAS#o|sKtfxH>>eX<@sUfY_vChudADP-ZJ>j4$BbU=CT9Gry3oybQXo<`^6i@)=RWYW2skh>vIuOD nE0~k`UDW#-YgAPp(1-~0i&5-ip=_&IfE)%-S3j3^P6db48^jOBK0g)j|IWt!$v&ID_n*H- zrEh#37E`6lbcH#K9DK6>jl}c&4^Q3S-(Yay&hFjzhZv53))E9d1_XYT=KH_pwBuhe Q;V+2m>FVdQ&MBb@0P%%R4*&oF literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/branch_end_focus.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/branch_end_focus.png new file mode 100644 index 0000000000000000000000000000000000000000..3227c78c32367921c16c633185154da13e98f353 GIT binary patch literal 146 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz&H|6fVg?4jBOuH;Rhv&5DCpwp z;usRq`u3_LFM|OG%fW0@1?j-64T=JVzCYglQIxjxXgl%hL{|Fo(zbeq1_mY$g@%T& o4Uc(tuaEeo|KSeMgbjHNMprqE|2jBs0P+|-UHx3vIVCg!0GgC6a{vGU literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/branch_end_focus@2x.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/branch_end_focus@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..331af9c5fd1aee2fe7628afbf9725ace05c91a34 GIT binary patch literal 226 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=oCO|{#S9F5M?jcysy3fAP;iQ; zi(^Q|oVPbO@-i8UupZ3MTEO>9X?f4;J|h8J8A+!_4Ymh;o}KX5PLC6|%>VxP^PfGj zVH+QZ#8jy;U18252cPVJbLRW|f~W7}9V8zJ-upX^^+tN^a|J=5Ye3*fss4*N&W~4i RUH$;#db;|#taD0e0syV_PGvzCYglQIxjxXgl%hL{|Fo(zbeq1_mY$g@%T& o4Uc(tuaEeo|KSeMgbjHN(y!T7=Tw~F1o9X>UHx3vIVCg!0D%ZA&Hw-a literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/branch_end_pressed@2x.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/branch_end_pressed@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..e5e4bce40cdd6763057f2d8671f007e9d59ce233 GIT binary patch literal 225 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=oCO|{#S9F5M?jcysy3fAP;j!R zi(^Q|oVPbO@-i8UupX?x;?T&V@}-3Ft74Ubq|>4X+k-yOPWWr5-%~5vcklZ1pF88X zB^_V6R literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/branch_line.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/branch_line.png new file mode 100644 index 0000000000000000000000000000000000000000..36c7ddf2ab33959b88daca7116263d90675de3c3 GIT binary patch literal 130 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz&H|6fVg?4jBOuH;Rhv&5C}`s8 z;usRq`u5yLK?VaJCd2q;Y1P#nL9ePU&WfnsRJmQVC+&|iP#qFzVD`Gk%6mxhu?a}f M)78&qol`;+06TymRR910 literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/branch_line@2x.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/branch_line@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..573c55152f05a9c0ae7a7e8171010076226c0591 GIT binary patch literal 242 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=oCO|{#S9F5M?jcysy3fAP;iN- zi(^Q|oVOP?3N|hYeEyt11Ko-hDlpb7aw)d28mKJ$}1Kp9!cK3H&gA$-MJ^ RKGP16n5V0s%Q~loCIEn*B|-oI literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/branch_line_disabled@2x.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/branch_line_disabled@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..cf615a5c9385786501aa6b87a05649bcc97d0819 GIT binary patch literal 248 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=oCO|{#S9F5M?jcysy3fANY2y6 zF{EP7+Y5%G4F(KH0=kx1CAjGu^KA$Tlc{M-+5Pg9k=YTOb6@YCujPHXvHP-pAcO7# z%?7axA`aXcTnkuDST8WmV#;9jW!%!Rj3LS)m{!uySOY(@G#Eele+KAk22WQ%mvv4F FO#te?Oe+8Y literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/branch_line_focus.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/branch_line_focus.png new file mode 100644 index 0000000000000000000000000000000000000000..b81bc5b0920ed1dab32babd37f14cec9fbe24716 GIT binary patch literal 134 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz&H|6fVg?4jBOuH;Rhv&5C}`p7 z;usRq`u3cmAcFx1i=&#zopr0HKQ^KL7v# literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/branch_line_focus@2x.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/branch_line_focus@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..c474ed9022d4b4f72ce4b2aed0173a025e1222fd GIT binary patch literal 249 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=oCO|{#S9F5M?jcysy3fAP;j-U zi(^Q|oVOPYMH>tljs$eIy>gH>3TWrEnIg(QU-4$%u01`xhU=?qzZc6nSG;-j#b3mM zJA-Qhs|o7`rddoGjJ}Lp8kR9cIRrE4F3@ZcyFfGPO2$}2mIi@#lSe>jGkCiCxvX
%J;m-0N^*nQbPkU@8W zW`o!T5eM!Jt_7?ntQVMOF=a6NGHz*D#t`KYOe^VUtl<+`8qWSvoCtI^gQu&X%Q~lo FCIF~2OCA6K literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/branch_more.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/branch_more.png new file mode 100644 index 0000000000000000000000000000000000000000..1b91df3e9c2d6b25f0dcd8d22f56be8263631fc4 GIT binary patch literal 155 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz&H|6fVg?4jBOuH;Rhv&5DCq0y z;usRq`u6HUUZ85{Koh>Zf;XhfH>gzn*gJjC7pE3MPt}!kq;G4Mvj9~CfdsqG@;Cb) pb?}Q>$hsSSt~~jX6(Z44c!2eb6(`@-k|L0844$rjF6*2UngFojEB^oh literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/branch_more@2x.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/branch_more@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..2e1bebe00497ed0113de56267af7facb52241a20 GIT binary patch literal 257 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=oCO|{#S9F5M?jcysy3fAP;j%S zi(^Q|oVT|QayA$UFdWnnn=5o_>pqr)Ol}3=r(f4S{a5d{!x_u-&#TvN~2BR literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/branch_more_disabled.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/branch_more_disabled.png new file mode 100644 index 0000000000000000000000000000000000000000..72ec42b22354a3e12feaf36b8e8dbf8db1929554 GIT binary patch literal 162 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz&H|6fVg?4jBOuH;Rhv&5C>Y}D z;usRq`u6HZUIqmo=7SA0I(UPO^-ZNW2)$`gZhdsu+G=O#%n9!vm&m*C44hiz0@MQp y4J8hNr(S8B{Z42UD@u<5#KMjk=W=8xt7)3)FsJIY%u6{1-oD!M<#{5?$ literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/branch_more_focus.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/branch_more_focus.png new file mode 100644 index 0000000000000000000000000000000000000000..9ff3921ce883b0403ae635080e85dab01ec1edbd GIT binary patch literal 162 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz&H|6fVg?4jBOuH;Rhv&5C>Y}D z;usRq`u3_LFM|S)^F_xA4SZJ=lV4qEY=77|sps(fy{EnPjfF4Ox_%cu)w^m+JPS}0 w5O}bQEM2oNX*0iAhJN20%XQOz;vo`185yesoJ!~1Jp4f-p00i_>zopr0HIYb;{X5v literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/branch_more_focus@2x.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/branch_more_focus@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..95ac204e55fdaf433aa5f0cd2ad7c0d30e55a0bd GIT binary patch literal 266 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=oCO|{#S9F5M?jcysy3fAP;if@ zi(^Q|oVT|Qa<(`KFdPi!dH86@3!cL-dJfC%x!#z-pnBu)?dv9I|D-K%{E_p!vR3|e zxscpuiC-#Q3s_B9FEGtw%3$>gV+TT2ks0U(u(3Y4c}c)Jo?&v p0Z_x{j7Iyv0*-jp<1y|t^TGKXja$xy-U9lA!PC{xWt~$(69C@4S&9Gv literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/branch_more_pressed.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/branch_more_pressed.png new file mode 100644 index 0000000000000000000000000000000000000000..a4f20e0e1195b2a456774de9fb9158def1b904ea GIT binary patch literal 162 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz&H|6fVg?4jBOuH;Rhv&5C>Y}D z;usRq`u6HZUIqmo=7S9qjf|QS-A#-)72h-{w?4XSZMCy=<^;R#-*?9D44hiz0@MQp y4J8hNr(S8B{Z42UD}1u%a*N(U);c!!m{_hhPTX1)2?F7epMmGjK>Nir+MRcRlgwYx4y_ n4VyC>?f(im;!%&sxX;W!FE|=^@?ZQ9^ag{ctDnm{r-UW|IEz)a literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/branch_open-on.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/branch_open-on.png new file mode 100644 index 0000000000000000000000000000000000000000..ec372b27d1adc1268321a1ffaa9a884daf6de7e6 GIT binary patch literal 150 zcmeAS@N?(olHy`uVBq!ia0vp^oIuRR!2%?ApR4f$QcOwS?k)_Mw}vl>0ZA8lL>4nJ za0`PlBg3pY5H=O_B-6{JiOAS{|sjWh15M=978y+r}k{*WnkcFe(-;BX~D)* rS0)5haD*y~YzrxP=F!`JhM)Jr2M#8aN7~DQS{OWC{an^LB{Ts5zf35P literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/branch_open.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/branch_open.png new file mode 100644 index 0000000000000000000000000000000000000000..eee8188b7b5d436f97db3d673ce34466542f9885 GIT binary patch literal 354 zcmV-o0iFJdP)&LUCO2bPp}mjGzwi?NB9Kv|=%Y`=yOc7f@#!B!1f4#;+1^Kk%dBWbg0E~^@tOeXubZx*hmz~_?l-PHC&p64BY zX%Dbb6<|Cb$8NWK8)Mv-bjb2=6F-Hn+U@r7a5#Lg@>lM_B1KW0O1c0t+mhz=t;T;wq_ybo(Pm|)U{Fo zfWctUi7`F{FSdJSSw61nS_iR4i9{liNc;)D08k8CPw`L?zyJUM07*qoM6N<$g8A!@ AZU6uP literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/branch_open@2x.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/branch_open@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..bcfdc84d16ec6c3e41e6722777c14c80a0a13c24 GIT binary patch literal 657 zcmV;C0&e|@P)jq>!iu3WdU&s&1<4SrO?2=*N)jFlPXy0Qjm}@;q-n zO0mcduq^8rfD2LU%tBSQ*Xy0H)oOoct&xZ!N8~0hQ{)B&LGT2?D26Q4QW05?vim?x zyH_k0uZ%{cw*amkm_Q^@Rh_lAswPBaUrrJE31H1}oYt&$cWXs0up^((Uo;G(0pMQ9 zZ~$Q1CJ4e$=ob-LbsXo@v>C&kilYbswA<~ibUMA6OeU`axG^?7ZKEeG{-cOw9mn}L zQ^*jpH2?rQosOT)W*ffmCjs0Y8gRH~m%i_>0Jt^bu@A%H@P4II`M#)J%ecpj zWmz@=d+(R3`f4y3Jg!!&TZ;^{uoJLXv)O!~$z(1AxQXqzK_!(+J#$@mxQskYW83y= r+qP57&Ot;(L_|bHL_|bHbVB?Cq`0i=X1ozi00000NkvXXu0mjfW3(z7 literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/branch_open_disabled.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/branch_open_disabled.png new file mode 100644 index 0000000000000000000000000000000000000000..b6d2d47432369ef250850f672187b174e8bb6f7a GIT binary patch literal 375 zcmV--0f_#IP)^@R9J=WlCeqyK@>&L-K-H}E23oz8w0Rj=KgU4v8y>_dyOU8N06#$@8TZ=F|0!kQWGK2*54YoUR^B|8ecL0Ee zYJEuxnqX6(TQ8E<+ZT=Vysn`F0L-sM<*<<4fjt;O)QKBc!@5R6jL?L~@ zo_pqZ&cobiz!+nUF~%5Uj4{R-V~jEX3kh4GvAwffU=U?LLJCMlkSmvcAmym0MY!!x zjP`{o7J2|p?VVqNgJJ9JiK6mjsnYlTmA#g5B8U-sh{Y6o0D(#`upU8{f1@al_Juip zi0JfAwRIgWaWxKFpSh+G2xy4%4jDNWmR*AGR}=B4A?p4q9@?A9;rX)CwR6B^=9*+_ zU^f&Iz|HdPT;OO+6wUMd3nH;FJNvWZ__4wAb*TeRW-QA_Kf9wKlKpUA=z4JRbt3*T zOxCR;8vwxa%uIT*w`Zv8{ijkvS~HeK6%on(bJ*CDrFmsYD&=Z&eC%74ne+ArZ))$n z4h*n;$O;5G@@#Kjw7>3f#jRK@mX0(edA`CLFLZQ>Ix(PP>*oq88ADKTWP2VJm79KI zq(5I7^L~dnw{09O^fqy6IHeK zM+8m-fe3f}*5(@vcL&yrk*8=p&nxjfue{hfj4{R-V~jDz7-Nhv#+d)aFLe{HCa?(= QQUCw|07*qoM6N<$f*y`GA^-pY literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/branch_open_focus.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/branch_open_focus.png new file mode 100644 index 0000000000000000000000000000000000000000..1f7bfdc0350cc9a63f6c042ca4583aea649b92bc GIT binary patch literal 367 zcmV-#0g(QQP)w^U`W^T8g;w@0)cFUgfzjB z0)huXArM#$hG*EKFc=)P7{EYxE@GFYA;A7966Q-r%;e6w=iC_x1OkD;e@8_H(P46H zXcc%DSQ$|>glNbZk9zS6lK-i;Q78sYWk#E2ngi%FmY6N7bwvep?sd)JV(Q2P>9@~j{Z=Gh&OpxM(QsSF3EAX~ zY#QWyWxd%ScjH~8Qvaor0f1?w=F-5=b{B9wM-cJc#P#I40c9}wcQTm)@zWdXrKwLWLTah>6>SL4syTeqfyKepbP+tKB^ z8Q^%spo)v=TALuCPLqfq5O*k_Jov87s5QJl1FDwB;)R~B=t*FvVNldzEzMTsZ?=X@ zUPZdfNBp{Z@UZ~^^P_u9`C{U%h~8{bYc=%*X`ClQrn9(w;>+maoadl5#R3vbXDgn?fX2^D#V(IzP^R9vl1>W}J2VBNI!%xd(ayP!XnbONnb-mlnt4 z|0?w?vOD#$d%a^AV~jDz7-Nhv#u#IaF&o4mJ71=UC|Epq00000NkvXXu0mjf-MBzWE z`~v-q%|=9mQlrsol^TtXT?tD_%)F}^W}ESLRwdq-yyoTP+;iT$;BYt`j{lC>1VPlk zQI!SYLqv5LQ&kZ}YoheJadRHTlxb^rGwLELKz*3u03zQx$8B2ACYYG=7ZpwmcMOn~ z95bN1Ofzl#)E;2W7U22nBz+5)&it3@NnnMtZxe)~&|&wK@?_*D)75Nvgp@yt0e zn_u;fVf8WDxTxwiQUHLtsME+Wx4@levhY4>U61PZ3smywcQ_ml$KT}>vd&n9NM!|a P00000NkvXXu0mjfHrScz literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/branch_open_pressed@2x.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/branch_open_pressed@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..bdf8b2d2038f3c62eeb2f1bd0ddfcb254120b5b6 GIT binary patch literal 661 zcmV;G0&4wTfp%j!T%6@$@c&@(G;*5K$Z@Pf-dRp%+2`Tq~tQq89;L;ckYz{)oJbTI5~npb@hcfHd=H4hLAst`cs z<(j)OezG+1eK-l6YgiT(L3X$jgqF<fEHB6w}` zG&QfP%j?yF>#R<>LFWwh5jHws98=X*V4z`J1+5=~;`}}P^+!eI+UIO)IjoGKKf_1o zil@+t`rNAdUn(-ao=ug)%ooW^%x&r>Wct1Hh_#>l8s@1Y0&yr4J@`Wa=KNN$08qUGG|4Il@&z^16)T0i{uQq;}&-r|$^ v(V4q_y^djwF~%5Uj4{R-V~jDz>=J(fSTn4(pLU~*00000NkvXXu0mjf&;vAy literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/checkbox_checked.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/checkbox_checked.png new file mode 100644 index 0000000000000000000000000000000000000000..5acad089c0032c7ef3602f92e4ead43bf2bfcebe GIT binary patch literal 452 zcmV;#0XzPQP)Zn4u59cxbAs|-P77dQj5&9K4>zMUO&{9r u_6?R3@-D*Nj^+SviRjE2a~-JWAJIF(Ds=KIT)3P70000i0F@-9%R?MTh@)KK<4VX~VE%UG-5*{m1v$?S1CBW1FHI6T=2^S&gN0 z4j(=|pVRuB?Df+1Q-b=;_AbBP%ObGvIeWyk(rFu_vr>#^2Ipo)ukXCgIQydG_S<_s zg0y@~%9mcT-K(b8urR-(``ecJZ4%!n=C3bgTqAOAjeSCWeY~n-QTVH`zt;YnCwctT zdj?^Ktqi7W3|Wj>J`7iwuFPOq!MehbF@QTDnQ4L8f@3TWx(>aZ4N(nJL?}Fa<}c&s zfA#ZbO})=p$oS);F>Y)@_x+TAHDmJ>Hmw3oD2eAtN!NRY2CPfN7?ST zH@CfIzA@p4n`9HBsN%9KHi( tH%j*w9DjD``yb0?7G~)N5@ECV*ZzDbIXNVJDKIZEc)I$ztaD0e0sysye_8+l literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/checkbox_checked_disabled.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/checkbox_checked_disabled.png new file mode 100644 index 0000000000000000000000000000000000000000..bad9677cc4f4a9ba26e86e1bd35dedeabd704201 GIT binary patch literal 467 zcmV;^0WAKBP){y%|5A(0corT_4Ei=P>zuR57S>V5m zeg;{qDpp$24W7pI zv2KsO&|+NjHxvSd03kpK5CVh%A;83WVAB75T6uS%1GocZP-f{&F7B?VJqWHW3<943kb>A!xnU0z3&CB^ zfrm-Nn|*zGzFAyat}-J55_14%{PCqWm}`Rgpw%d!`_uEU=o8VUgC_z4p4I>W002ov JPDHLkV1f&9!|nh8 literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/checkbox_checked_disabled@2x.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/checkbox_checked_disabled@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..3c3ea0b45e6520062ec5dd12ce13cc39d62df0c0 GIT binary patch literal 845 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=oCO|{#S9F5M?jcysy3fA0|V24 zPZ!6KiaBp*J9x3YuYR!xT*(urlZbjU3v;MWuE6!LE;MM<^ zeQAYY{=te1%c?f89{ln^(Y2a$QOlPAMFE4eY5V22q|WtOq&E9+lJWW6w0*qi_uagE zbAqJ9;)^^+kJMZ*W?Wg*G0~zyl|hg}nBm>mpf$`{41SDnm?LQ=$ZbtA0a!!wB+8dVw<|%;Yiesa+!^qrSly-!nf&edU)Z($6L3e z4i{h5^H33LJpAeBlFT3;m(vVxcOSPoo)6jX9LxZ6ri3#4CENd*Cpc8T7tP%C{nb6= z?4!=5%QrGTSh;$)z>-(OKM!V{U=Kgyai{hZ%b!i{ug^(~H_-!A&G*z*-@4D%T7CKUYORLGLvOw@1O57>)nj?h z?Q{2DeD~32`^R;Gv4Fc^G4lhl2X5>KbPx3MHAFW^%Q9?dFt=jJW6UdIxWjbk1;Y;3 z9T$mEShCk{!R`OgcS`=yb`W(qdlwi|Z?6e|H|6?13+TiLSMFNq%=fR-e5%g%T^QuV zeY+E9iF^(^<7a0?#Gn{ybV{4H{Wx13eeg=xAyv~1#e~IfpP9 LS3j3^P6(c1vXwO+0S`~=`bK$Qhk_w%ms z9*1k@et4QxQYJ_nK!z1x>zhdEBEd-&5E4*j<`g?|7;6Ow>Db-43b>lQ&l|Q$Fz2!p3egJ|87uU5%>8pM=3zm5uOKhnPm2JJsA*NI3eCLDaUCF z!cV}8T*Y!jkhbj&$e&x?l^*UOr5hvLO8I3HdH|qUk*jl2gNcjdJq8EnDaO jdj6Lh1JsWi&5XVQeF1vToxTwd00000NkvXXu0mjfH|DU^ literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/checkbox_checked_focus@2x.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/checkbox_checked_focus@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..1c30bd1dbcc9181d26314fcd0b0139c7d1c0c522 GIT binary patch literal 823 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=oCO|{#S9F5M?jcysy3fA0|V1b zPZ!6KiaBp*8+u0viX8v{{O1CZS&qVI6D|g7_455<_1fC~=)yt1ug)y1nkA(~x?0mb zme(axzKPl@S>vOMMY=MCGSgCOnF}W{pyT8-~DplI0qc+cM^g=c*Ilr! z6aKsLx+GgI$8lY&jt`$cen0)|{9XO~TR!hf0vXm=KIN0C@x9v*-d_4}Qu5jJde*$# ze63FYpGs0zFwRmuq}34jeG7Bd(%)7U%qQO6>{S1#{B+a*teaZ`{FZw)cDEmJ*f*m@ zY7bw+sZhIhS5`fK)qAm+zvH-2@u^4at7hD{n{t%d!E&xvq?s7O|5mrDMMF5q5JmmQ+uNz=>Z-Sez|y@uNF3m9i{ z25EW8Y)YGYsqxlh&IU*6cZPyt?4ORN9LQT}JV9Sga?c}>r%f0`vZwkQ)a~%v>(_i; zK8R!8*-P(aA0NLOl^XnZ@Aa}urc~XsZB~`L_c&jBb5{NSqq3jUzlz)cA8q7hNLc1m zs=0O9?9a7)J8I0g9rKy_VT)3uWW+i>yZoq0Pgg&ebxsLQ0OUe`cmMzZ literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/checkbox_checked_pressed.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/checkbox_checked_pressed.png new file mode 100644 index 0000000000000000000000000000000000000000..4ca57646ab5cb5a2d36bb2154cbaec79c53308ac GIT binary patch literal 418 zcmV;T0bTxyP)Koo$#SD-ssSl}v>XuJT%BOr#xB`bqxsEG?% zLsH}nT)@NxuELLrx+|g2g&oo;KZ~|*?6;b{nauk-GfCfr|Bn0&)I0uJDBJ@Lpq5ge z1u(S~Z$50l?iHwZ{5yn)U1BK_0=?y+{rF3ub~`%PP+x#|Rqd|XOg@J0TN+s_oxw?o zLQ_QgK*drn%t;i@A`P_%h^ls1!<%s$i4D<*j2+h(fl+kDR{&OQT?1gvW|C&|I6)w0 z?^6?t3)Et^neh31y^4l)6D#gnyQS*-nk4CR&_4K}twWQ4K`xLBD{#7|%W-vwk=$;z#f6AkCP1f~Eb3eBtpY+KFVGZWihfu(q%a48~v$Mq!$WD=|4 z5>alA9NX5Wz!MN!if86_H6|X}J+BL=YOxhzB~KZ zz6Q6&nW-yQ1$KTd2v4hSaqws0Vd`Mq@o0GjuLwg5Lykd(ru^&ZgJ1SOa%GQ|IAHqu zuru=)z5}`ZD$UIsLX+xt&ae9Sb5CMhwRmvV%=V(< z_CC4KVRH_y|GSZ!PwCG7s_)eg&u{mSpZa%I($7u)w@~KHeCUW%PRMc6paG zDO*~$xiawkb+@eD``Y~djr^XzY6qZiSf)W zu7tz4G>rHwHAPiatt7WiHG7*Z!)Q=(@|N18nH@8Gs@^=a7BrSjU6z@B*3R5P(82E7 zcBTi*mtKic|yDe$XhR}J@tka|P{Eu)pJFo8D6SL1n{qR%c_{T**jclJC zs^6H%#4tnf{CVFqtA54YXRcd*EPbZncYkex83%)Z?o7|W!xpkVv+ISf#NT_ne)>$E zy)5gdnR!F~>UGkEx9{jRoIRa0`*McK+OzRxc8_!>1wHZr<_88(S3j3^P6T&6n^0%gls) z1Kf6TJP-uIBN5R6)&Z>4YKx^G1`AI}Bl~UW*+F=~W=XJPuyWIz#=WRIW_DS9&`8Z#Rr4b3a2Y^bcZDY() z9mct`7dg^e6TsVSi=P63D&(yLfVFm5r+HCIsl4{uC{~zXDbUVE#+Yx}@Zn7W3(=C3HHSyT0#7B%g`M{fc$J12|06R1XG&A2R{?zHb2Rh)6|m06-JKPNUKI3EF49g4+Xd23$9g^D+y9 zU^yF}-UM(A0G{V<%nQIdm)AbYW5upG5|Jm)xqYoQl~Th(4>yy7AXv`K-vDqVqml1e z;;x89nBUoO0QSN#e4Ph=yBQ@(@}=Ewf53Hz+(do1qf-DMNxlff@O@1+{}KHHS{a;V Ts6Y(Q00000NkvXXu0mjfKve?1 literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/checkbox_indeterminate@2x.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/checkbox_indeterminate@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..0d8feb94bff6c19c6bc39fcd6c154fc3abcc4394 GIT binary patch literal 1081 zcmV-91jhS`P)q$gGRCt{2o6Tz!Nf^eTYJ0lpYCv*O14~#(y?BU-hQ6tLS@AZT z!)C#Y$DnvfLkDbHu#=ey3z9#;54>b^6TP^5l8&bpc2|fDB8Vsw5AkZxN4*}>hMu0D zab~J!D%tc8=FnB|y#3TO)m=436_AmUv7ceR1i7xO*J`!P0A`5jG=ReZ%%LjlpAf(Y z#@OEgRt>{=dtdsl0rT_o7d1`01K@-Nk)vdTbAG*CF8|pr=s=e`X4|%-Y1%yi zhonjy4Tl(Gzgd=53xZ(1Q&2|(Y}n3a2#ixbN&#(g;?>1X_}{!FGel-<>+m{(|E?%R-@7Qb+0rY0DRxy)HH1t z+r9Q1C!@Bt&}IODnfL_}xy#GTpCoG>I==635|NuIo=L{F84!*0JLtOpM6$M#k;~;C zCyJ($F=;*EaQvcLt-g~fYLq0k6VZ`mOqu~LGrZmQw(o}&?QOHyGz0b(nE|Q=s3tQ& zwE)#*2B;RGn#=&z0#u{RN))Xd-XNkY0DeG^>y3Rt0Nygj?iz;idoSyKy&$Cr*tR_p zhT$_JDq;JtbROH&PMM!Pfa63|3d8W(!otE)8QO&na9vktjI9DVCqYlIoNG3le-w+w zZflx7A#6YxhSva`70ojMXD25ouZt#;@d#X%kVDzMWf<_IgdBr%Of-QE15^&B!XwST zp9f?Hs1~3a83vGq9LkVkz#9oU27)mrd~aa`i0Hm(jzQs^-xJLtY(PGrF9Y~jG*7<} z(Ld3>g%CEt^SoNK*(?HhDVnPfUUJTV@jS04nn=nhP^na2o2GdNz#@Q;GIDm{BY;KI zG|yBjmDe&7N?Q-`Jnstt2Y@p-H)oEGjY(Y(*xK5nm6erHW==q&0da;QbXa5)A=Ls@ zlNq2|fNC-WR0~i|W`Jq|s!21TWfCJ}?Ohcq+S?{*X$E|VUla<337MisNm4sw?0qt( z&46gX{SMLI+dWCWUcZzmdXbDt>jA5Y>syZFj7w8BA{@sVXN-A?;$+*}4KNJj5r9{* zqJy0ChkMC{*kCTrT%`H*c4(*Xx&}Uw*Ld^56I$9hd+BXK86^ zF|DHG5VyX*9$1zY0ysZ3S;L2j$SIXdrA`4|$M_%!g6Zk$=Zvu_?7eeC8=Ujma=HAV zTTtJ}<^W7ZyRLWLvAJlRe}O)Z&1Ga{>~FpTm~Kgr%6Yec00000NkvXXu0mjf_J;4l literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/checkbox_indeterminate_disabled.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/checkbox_indeterminate_disabled.png new file mode 100644 index 0000000000000000000000000000000000000000..04d7da1d63db438fb27daf4af08c7b38adf3f358 GIT binary patch literal 614 zcmV-s0-61ZP)3zAtjc0@g(#MluA_;+t@=12|_=B zpx{9~vUhM@I- z8s@!u|KIM+?9RY(m;BywK9Rg^RWgWN1mYq2?4r75M00PS7he7mVDwt*zA6t}frTV1 z%G|b_f7AppI+4DjqA!3w6`dJyD*58t+Ltg~FHKFIE|nuGQCR?@27A?e6MbHiV&_0a zMQ7e^tgeJ%?5Xx3D?O!h|)B&Wy?Q3it)RoEBN<^6umd?*wSIs%B6%mZNd zD4#}w7%H=aB`UzZ!*YG6K;h;Qynm5JZu#Z-0tm#~1qd>>=ZnxEK-g=yxFTOW1`uVr zT>yjn{?vQ{PLxh&fJKFGL5*vjp0S7wm%L1h5O$17x?%#wMqSsx8@R22kAsD3v3rZUK~SxmsK8Yp<`q z3yf&aB56@s7)hkXF;4#H8Ll&pO->J$Z8;_AW562GoEK|#G0D-rwb67ji8Mw(eSH7w z?787}RpN+=0jI+8l^s+!jOgucclAj)HUAa;0Jhk&K=5S;`~Uy|07*qoM6N<$f{CgV A!T0R;w2oi7seM zJVg&%!HZ|bV-8ysq;wAp`xmUcc}xJJj$^v9U# zE`WVfrL~5A%ygxrJG7e3EIh0hRMmiEXZm9R?leVOYYBIBhl<(E!nE5(*H@r7eBqpB z(S)P=9f*D^m1ry!Y=0S#$4%){1&BtYzGu0WE?wt-Fy98S*M42o_y@Pwp~3*eF!a3U zf9!bY|8CQKgENzfoP6o>=?h1KYnFKrz*$>$I>3da&W=%Y-kc|Y#QyLMye+k@{kUBo z9sp)06S+3cHwfUJt@_CNNVb6r15h67zCc7nk0&NxOV-$QW+oFkCJZ^MFFWJh4Cu8N zN+lYTDXf*4B`xWw>T$-n8PI7jgo5oaWr}JgF534yW84hbFvHtwy?rCNXs?*Px*4#e z@C;BbKsBBLss*UVGeETf)p!P|7N8nkR-*E{;hviyz6wS+>RfMZ00xi&=(hlW_@$op zzIu@I3+OpJ(3OXO3gD6TztZg}PdjCP+5vnA@JJs1spF?F9+073*Z{*YbT%;x!YLVo z>Vj~}^qGG~qtRMxnsp&;zB%Wi_ zZ66lRAfpphIg|>IG&_DC;2EG=fNEqIz!GvOLxus*CFD@nwuE^A|1O$CpzXV&IfM-; ze&hccz`vq-8ij!Q^|pl&HXt33uUaNWL3kpXt8NHSOp`990M!Ci<7U8y*_Mp8cU8D(ub4@? z8Su(pc$Qn~k}0Z{xM*K?#<&?UYcJ?J_sbO3N_@IC;Ha8&#<&?Ux}n5;yDuCGO4QX7 z`ofVQF>X1kN1bsM1_Zc}0O6^vYVVq5-rG(l*fvYscZ{b4Tu3-$8`>_> zCS_P9x+o7w%@s-w5IXk+&}mKs1>xCV{<(y@4DWK$L5w%9_s2oHs|5tv9tLE XL!w5%9m2vM00000NkvXXu0mjf*z*Hw literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/checkbox_indeterminate_focus.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/checkbox_indeterminate_focus.png new file mode 100644 index 0000000000000000000000000000000000000000..f7f6d714ccb84189bc57aaf5ee57b127429226e7 GIT binary patch literal 576 zcmV-G0>Ax)@f11p^egEIi zzRAvm%Pu)TkzL$;V2!${&LB)C;-c&zvSzG!)#B8b3juDGz7;#sOEJ*QZVY<`? zF!}!LL&bas4iw3s7^xi2Pwge)I`Lui=BU-2pk-jfSo0{{iIFf!xmE-fMe@6a>6Ijm zLj^Cgk|}M7sC=?UUEnEzX+^2d0Gt@9Bx!zDe!~fJ>%DO96d)+Lq_(}2e!afC8w|7U z07KFhz|a9kq5^K0zo+*7-yZNx&>J!H9xAe&cCNcW@^>120o45ZJAt{F#-Y-J&eagQ@Y5CKx7SI)M{=}08Yvea?5%+*E$8pif4^J5wx5sZHV7+DrfF+eQA7Q zE90d6oTz*Rtg+&SYn>VskHOW(#f?d*R%_P0I%m(X_oyn!dZ*UxN`C>C6Q#_Cf9+NP O0000}b0K^TVLZ?hnRTg1KO3ME1CH{=W^8nDK zfd|c7))g?9{Gw}0Rn!^BQVhCQ8Ew^r2>aK+%Fq0Ke*a})eNb>?uXRuZ4|>8sm~mAH zKg%_~pFmgFoOHD!WV1E#&pR55puEE=VfOpNAjN>%>u(!$-Fd=5 zhxBeQW+wqR>J0Pf+->W`^o7J1(S+i!Kzc~mb*G`IE}kuV7I8SxzIo-Jb**d`&za@j7LK!yP-r&8e|cg?Q@A_G(l zP>l=&SV9hE$S~legdEDAEo=Y*k3@3_Jo}+&4q*fG1??t)QPDi*!>{L`Erj?hkZGPJ zXYM!ymT<0+Fkq46bRp9`E1FBnERet4I&Ktec!)PT2bS;yrGl-AgJx{{B}JER?%|K^u@Tz;Oq-qHW!!UO;?Q_8-S z=n1MTxemx**xkcSsmjT!3e3P2`(pF;QVqggngaI$Xp$?) k`wC#BoNIFt5fN*f-|6%;oEhcX%K!iX07*qoM6N<$g54zT6951J literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/checkbox_indeterminate_pressed.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/checkbox_indeterminate_pressed.png new file mode 100644 index 0000000000000000000000000000000000000000..31220be5dcdad4f369e6bb2b48329d935bd80464 GIT binary patch literal 563 zcmV-30?hr1P)gz_*Cp=llS9AMIFl+gACGjBv#judRAWJP4Tcj^v+SO2m``2@w0 z!hfqSi=md#B1-ns01@t;_#%t|pocN)_hJJmPW!UyiiG~uLIKilx{Bx;a56&n38HIh zH(d=ghHk^p@1J}FmRMbV0S_atnN35jW}-Ml0nSyc8HiSN6#Wmo;0gik!LI}4xWe3p zR&F@#1_5jX%rI3L7eFedw)T#lJKqJ4;u+zQh}3iCru6&L@txsf$z5pWQYkG6d;pB2 zc=lRQW8yKswQ+G{V&!Yi=J1_fW2y`61hr<@`U%JamVQIIcQpV2002ovPDHLkV1nm$ B`w;*D literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/checkbox_indeterminate_pressed@2x.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/checkbox_indeterminate_pressed@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..8d112b16f5940cf2ea0a41fb4b0a74bb75298b45 GIT binary patch literal 1087 zcmV-F1i<@=P)B8ZQuQ7*=4j2w-R3x*qb z(5Q{Yn~!*-2OCTb>cRN9NGJjc7vN$HUeJWZc!c;$@SrBt(3nz-7!&1D`gx$@c6X~w zXW9YTU&3L&nf>-Z|L*P#lNrFp#bq@^j#`C=^s?w!J%LUD*bkr*z}kEY%YhjHQ2@gX z?oCu~d5o4r$$wq+PXjgtI*)3gy8w1e5Lq|~qbcUglVShUzctgcS21}5-9ZgBh?UlP z0ASQ;puw_pUCjVz{h>YCD!hShK?YyXkGjG^gv0ChzMlE{^3e<1db?oyu^%*rzcSNR zo#;vIThS-f;%fj(jnygeF}v5nYCvd6FONpvAoH<*reW^X zM7Sv?TX#OF2(bey z_6(Rp`z&p2uB$W_V&95B$rM#cY_wOI+t?Y9Im26SU;CwC)oz)+{$(PxI&ck8EkHG{ z0jdS4#x+2-0M)n#s1~3aU0SBlkX|+(xk7}q0Jg&EdZTj~z!)<+6IGjUJ6Z2@f|Mtq z^n7=E9-QVk5e70%@l2Hui~8`0l5E1FBnC=hS+zb{Vm0V1>l z_$(u57CsZ9wK&NK;%)x-G7?H#4;bt6PXh=72yVY{Z*B5>vDEbdz4$wSxPNg50OB(9 zO3by$Z=ovzcOs-(fNER=R0~jzYk+D2s&NfaEkHGP24qfRB&@wF!>ZjfL9;U;YApCl zrmJOYDkL`A$IWf*3>Y>RlFW57MHP}1%^x>~M$Bz21~9nSSSI3Y6@hl2WNmq;BGB$* zrWRw&+&93+fJEh%#{k|LLZvCJ=~+o87&c4)*)dKSP4_K>C2f}{;*iFkf#tkiK1K7# z)4zO<+vU@E1Kt0{fe8R$MljKFw$-jK>pUPHKHbWUVE$wk1ZHq^qT|esYz>?pnj*Rb zMvYu;dB)+Psa%fD?Zd*Z>*aWCZXCeKQjX2JxVWrtegQ6dG>^RSEz literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/checkbox_unchecked.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/checkbox_unchecked.png new file mode 100644 index 0000000000000000000000000000000000000000..4e68c78c7eaadd2e3c696d2a96602d307dd65663 GIT binary patch literal 397 zcmV;80doF{P)0#3jQH~}Z%R|`oypz{lv0kEw;PFu3f%)%&&dQBxC{~elH zb|D~X3ABCRUpFB!olb9#ZF#FK%T-nXGMFSu@&r5p2O#I8fvkf72!R&Y29t_7jt8FS rjgPH!_k90{Y|Shy%W`!-nmOJ9Bb0qej2bl$00000NkvXXu0mjfRwbrq literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/checkbox_unchecked@2x.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/checkbox_unchecked@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..c0c4ec9c5575c62fde28ab6a9ff5de0a89d9ef9d GIT binary patch literal 828 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=oCO|{#S9F5M?jcysy3fA0|V1L zPZ!6KiaBp*AN0EtAky|f_?D=(mSDkqw&Us(whQ#A9LnoZThOgoZpGh_You)`cync^ z+JWc?!Uj8v&MxRoJ-*7fzdQ5et(OKJCFe};={`aKMjc$t#GjD$@|6}=izs~8Z9b31SM$LL6l(98x zv*#ok#vPN}b`{FpKVL7g_D^@;V;#re4-7w_UM0%Uu<}`WRK~e&Z;#f*&1ZZWI{l*O z_FC1Cwf~J9`oyI27^=S498)~@|4cmF;&A6l-=j zmpcA-)o#8j-rDPR6B)O2B{ytg$n0Uf#I(ea&4YWwF$o1-2PtX@cJXwyuLO$SMS!bUGaUODO z3VOx4VqWl_Eq{B|+EcQvXV0FUxh2_VvGnne18*L6ZaWY<^@X6+V?7=M_><1EW)mi1mE(!Z}F#5p# z+j0zLHTUZqoAy0-6jqjLd${ZMt`jo@m;;no9dg@|@chl29A@TO``Y<@HJ8p4oY?=0 z*SB=$&E4NFO!2dF-P94c|F2C|?DfYMX5~%yLbuBw|M)NT*fU^ieEZD2`~HLPE89IK Qf!Tq<)78&qol`;+0PC1@x&QzG literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/checkbox_unchecked_disabled.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/checkbox_unchecked_disabled.png new file mode 100644 index 0000000000000000000000000000000000000000..9fb0036caa99a6b2cdf74c0637c1ed6814416243 GIT binary patch literal 386 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz&H|6fVg?4jBOuH;Rhv(mfq~J) z)5S3)qV?_djeds$B-$Q+Hy3d`)pY$rtBc1gu8Sc`$D|)^bU3tt^T>@E8_F-V zEd74KNp_>k@rAl(TP4-qv}}Q z`Ta~)e`l{0D&>E}!qi%&zc_ZnGA8Z}jT!saPUFANaQEL=fr;u5QuAFNZ+)J7O2hwh z;hZvEBe4Uj20s3eR1TLk#)>{=$UcAjO>YKI4MX0pf2}F_)yk`I3 zQi~_v!h3m0JTt|K$ zeVb`C?Rw+Sg{HqR-AwqRVW22Cw>hOjM=?q0{hqonNt4v}&3Y)*e{Suc&+%#AHE%xu dx$5&=_{fHMm-9T)tAK&Z;OXk;vd$@?2>|bZq7VQ8 literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/checkbox_unchecked_disabled@2x.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/checkbox_unchecked_disabled@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..8d6c0edd4af7b755b73cad183dde103b8163b43e GIT binary patch literal 875 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=oCO|{#S9F5M?jcysy3fA0|T?H zr;B4q#hkaZ4|+>GiX7W7el3PYf33vVd*0a&(=U0qwm5MGRt0&t-iltzn%ni-|qKkb?*P3aq@`) zzkvkLb;(^P7Nn?M&RqF}#kgOvfZai!K|3b%e-BeYQo{6(Yg0nwG@lfypH(w8Zg_L$ zgoyAxh8KHtQY`SQq z_Reb$^M^m@HM-9HkYeUredMaP*su5_Gm=6T99w=T@Kgj{zB84fL7XFkvr#+2z}Cw3 z0sp)U{!HhsqNU@T?1T(Y_@&P`$Y4Cs8#Tf4eA%{Z_P^L(H-g+7YPIii&H4WdODFl& zeO53zshGfT|0eac7Q>F0ZC}d7IeY(s^|#hmFcf^6&7M&8mh)?5 zYIcnLbK{1Y$6x8UEZY6%_N4sVuje~zT)Q`O#ZJa|mhaCw$X&euxxV?X6axdxoonnr zcn;j0Kj&7<;t4HVdDgbo*~+Il{LSdO6<990MXKg_-2}$#T*(bv7&3bpFEK4KWb@#j za7;o$*FlOJf=xUDUsZx{OE0;)pyp?T<xx>i496Dis$%yzcY>F(55nHT-i)i283ZhTWx_G!urh6TID zQZCd4aQiN9%FwX=Bv-YaVf9+h~(m>7{ggTYYW^0u_TV8Q#HfyX&6 ze|*?;JF_tF(9L#s35LQgV$8qg&M7=o{bM!jYxERDIEGyuax0tYuz2v-X!< zo-!R2y;Ii~s!5fvpYvULR&Mcco;QM@S9Ptv+P&qhBv0Gxv-vW?PyaN%<2D869tKZW KKbLh*2~7a&iiP1giJ-b)0#o?|5sBR^n|n+is9H1|eq@=;&_0hb z$w^i*^FQB|wk;19q^tL%U9WAi$%w_#KH5~g1f?iA=ydwlio z*Vmp0cJ7zpy2C7eL160npjWQv9by(V8vXgOPL8|b^v6BRJNGc;Ps^%*xix(0l;xSd z&-`?ZSo5+}_Wt#}vPo8pIU(59^1!9+^*UGWHuP>}`~8(?!|r0<)f)CL3=0>`Wn$Ri zz5Da~MJ^7XB_8-EF|Z}TPyt6r+2!n`f;kDX3>^XuJJw#jvvQU7-|eeC0$4JP*rYa| z*uvHF`OiJCSxWYVdVamZz1?jlp7eh44$rjF6*2UngIP8qz3>1 literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/checkbox_unchecked_focus@2x.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/checkbox_unchecked_focus@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..ed63aaa3267497c11edcb5114bde7b45eedc80e3 GIT binary patch literal 866 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=oCO|{#S9F5M?jcysy3fA0|T>& zr;B4q#hkaZef@<4McVEgYe+AWUN)_NFZa?7g_{4F3?_A0cd9*LpKw6`LWBde+Mys{ z6~=$8dN;QO-`TP3M#_x|8w7W(?{>1DE2$yWcKK9oSoyoXm-l^tSyNKTpRh4vopI4T z&zCvt&N{Sl@EmaD@6cl~7drQCy^K>pi=$&hDSM2r@7K52tzYIaF4=PasXNOjF^A`= zs(Y2nH0Io^z5JV3$tL&GOQvb&`Mavub_?{V3B6yXFzxT{`eO#a9w_8l{4-KJI`^}k zA}tpUDmH{#SStxe)HP?;pID*``15w>1Zf1yI!X9iF;~wT+Nm(Uw*BB z|5iof_oYJnKW~m)43t|?eJ3ok(p=mL!N_c?Lz|_x!45@B67W~W=4d& zzm?h{E7#9upb;|r4SVIfSxs#%BFx{y`%|@TRFxbWzB*V>o~6&DDrS&)=jNZq56%@9 zZV;O%Ecl>dHG@`lbLNhU=ZmkGY&^zMIqNRJ6W@|n^WqK zyk^PU(s%s8PQl>Yb6RfxOI*UO^I3y^2A{O?@`P6hv@WgKz4oroBy0Z98uwilgt&q{ z85@Gi%K!PA#4$Ww&rmPKy@3IS8e$J9&5ZlpJ4498pV4Io!@ldBclPYs>-S*MD{U)J zW`o)X8d1j|+X&=kKT%DtyeOFd;pXnim#;n6ePO!6NyUfl#C>-k&QN&`xtbX{OW!V# v%Dm$1_WaYo@A7HuUK|lj-|*jLb0zyT(;U5*w~hA$Lz%(T)z4*}Q$iB}(}}4> literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/checkbox_unchecked_pressed@2x.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/checkbox_unchecked_pressed@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..2a4b99a3e4e306d15d0c20555282a7dbbe6c5380 GIT binary patch literal 861 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=oCO|{#S9F5M?jcysy3fA0|PU^ zr;B4q#hkaZ&-(>CiX7W-%<6S$Qg`dF^5(CcPjp$7J)b%2$!YgAr#X)CkBo!N0f!Bj{>{v0P;Kzzs9B+vwLiuqwyb(ZH>1zunKfM<_DnM>B<9*a zp3^wBdu|D%!aI>GHyc{dI<~i8JGe!nV^5spo|l*2tLEtb`xyOhL+?zPz27AdIGxrB zP2D8pC<+$;gCD!2crr)LS ze&^oSlrgZJc}H3)Dmh_`CHE5jvS**tN@gtI-KOU*! z;}G7@Xz_Jr(2_;-X3D#z+O1ez#deQh?(^?DZ#jlLYoAzh$lC-L+Q!T^dwh#$MQmxW zVb|8&`}23)ewoiBBE5fRXgTw%?=`s-e`@?m|7X^bZD}&oM7f5?VUJ-#fF(!d-X*5& zby@3vOJ3L`b-3*6U3TU6ZQ1wFH@LT&Iz%;?Tw};&ycEH_gw-RNcY>HgFEs?~*ka7t z*8IM&pxmBad{_TqP_n~=2!Taap4ogQY3qJVIH>ndRGY>0!_SuWVav*C&Xa?U7oBBb zlE2q8QR4KobfzG2i*q&awr($);~_u8Fqdsb*Ddx7Yk1Q>{F?lx?7nR4#+`Qy4c1mJ z^LnLq>25=jV(G~PUEgD+nqAd5Ti=#H-gxrln{%HSWSJ$h&oQm8(>0M5N-BC*9DgQH zkgcohXNTj{4WSb^wJ8<&2>Wg|@wsxNp#0MNKd#a0!N%MhlfER6N5#L z>J=7)6Yu5k7KEnm48B*46_;-xxqcU4 w;%%9^j25bw*k5TC6-?h|*?siWj-TB3x4rv$=2mndFuyQ(y85}Sb4q9e0Bt9Do&W#< literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/close-hover.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/close-hover.png new file mode 100644 index 0000000000000000000000000000000000000000..657943a668b734138256aa7bb178661030fd4a1f GIT binary patch literal 598 zcmV-c0;&CpP)WFU8GbZ8()Nlj2>E@cM*00Fv5L_t(|+U=WLk^&(N zMNQT>E=U)k3)21RpJh4PJd%48X!1Rk<{TbF5DteGD^~0|g!!@C>GY`iyW{mLQwXR9 zjuawUp;Cior+G8=rW1YKL<346a~6o?i6 z?{azNxS!7yQSaX@eYYe*y&Lw~I5fO96fyKs5_ zy6%Wq@1q*&nfKd*=(Y$VMgp?uA^!zDB{1N>P63ZikG1hg_|Ito*$P`m0;}iYwLp&q zHaxr-YLO5D|8EUI6+I<5HvIcKKq-fN*91m!MLQ2@g<(~e)B}-PC>A_jKn)xdK16_J zA27UtS~#Wz%?8hwpwaM*^Mp_VHSm!VAk|=R&oeeflxnaSCSoLLra2!WK{LTeNN_t8 zMa*IEe9%Kt!~(_`37Qq2CE;g++G)V5=dIuQ^&@G>nP7%|MFEzZSE$DJ=G|h^>^+ap zZ@wUrJxU{aU6H9xwr+_{8tbBDYw}%RmCY=Ic3C>3gpljWFU8GbZ8()Nlj2>E@cM*00Fv5L_t(|+U=WLk^&(N zMNJl_8_?B`8_ zy6%Wq@1q*&nfKd*=(Y$VMgp?uA^!zDB{1N>P63ZikG1hg_|Ito*$P`m0;}iYwLp&q zHaxr-YLO5D|8EUI6+I<5HvIcKKq-fN*91m!MLQ2@g<(~e)B}-PC>A_jKn)xdK16_J zA27UtS~#Wz%?8hwpwaM*^Mp_VHSm!VAk|=R&oeeflxnaSCSoLLra2!WK{LTeNN_t8 zMa*IEe9%Kt!~(_`37Qq2CE;g++G)V5=dIuQ^&@G>nP7%|MFEzZSE$DJ=G|h^>^+ap zZ@wUrJxU{aU6H9xwr+_{8tbBDYw}%RmCY=Ic3C>3gpljWFU8GbZ8()Nlj2>E@cM*00FK^L_t(|+U=W3lEWYj zMI&9@_Q}(`u2cpl>3<1~)?G61A!s1*ckDcfFZ2UV}LO?5Uq!7sp&5|Lr zfTKjnjPRZkWJYjL5i&cxRf5b8ZWSRb!H-Cg)!=(2=w1ph*!w+IAXfO}IR0~7*F_Qa z`pw#RYZBDEVegGY!&^fUrH_&@lDEd7sB!Nt!IH1UVjcpe@#iI>l*c;nh*$5U8tIw$ z+l1&g2_h;1+4GS90-h2W@Lz|3$D+sDcqIJ$Fn}zDEtSCPdH7ynL;@Qgz8UI~5CQ)& z2cR}RH8?i>>pVc&4v)?WjLjA8JfIhbwX>uih_phn;OPQd;F$0s0xau*=>@dHF(qg= zc(w$MhG(27gbHYZkCXt}4UYCaV^Kue4UWP@RDxz2^AQp>6MTdOw?k3H81~KwJrqSu zV2n!8tne%eQYe>aG`#0`e*H)qaweD|UsZtR<`t^3qj^g#n!V@I`OOz3vPZ3w_Z69r zWc!xbim@+B4kW+tRoToUXqTlkN(i|wpGAW8(Zqf-18CSiA59@;O!aKeLkRQXw z1e^Sc1@brxJR*x37`TN&n2}-D90{Nxdx@v7EBhS|ac(A-+!@lDKp{;}7sn8e>&XcR z7pulY;Wn^IBG(*7A%~?b^VC!N=hHC=sm-IdEdjT~uc)I$ztaD0e F0ssj2CNKa1 literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/down_arrow_disabled.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/down_arrow_disabled.png new file mode 100644 index 0000000000000000000000000000000000000000..5805d9842bb3c8bdf9ae741ebabc690a4929585a GIT binary patch literal 166 zcmeAS@N?(olHy`uVBq!ia0vp^oIuRR!2%?ApR4f$QjEnx?oJHr&dIz4a+s35-CY>| zxA&jf59DzcctjR6FmMZlFeAgPITAoY_7YEDSN1y`;vAyZcdU741BJ9aT^vI=t|uoP zVCdoDDYjGKUczBuWT3#kjKjddz-flSK@mm~;ef4+85xf4WSF7(8A5T-G@y GGywodVJqnX literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/left_arrow_disabled.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/left_arrow_disabled.png new file mode 100644 index 0000000000000000000000000000000000000000..f5b9af8a34edb5f8dd767bf6afa303b89a31d38f GIT binary patch literal 166 zcmeAS@N?(olHy`uVBq!ia0vp^Y(UJ(!2%?APo63Uq!^2X+?^QKos)S9gTe~DWM4f7*8Mr literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/line_horizontal@2x.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/line_horizontal@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..3c6899f149812308978d4924c719a3a179c1059a GIT binary patch literal 135 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=oCO|{#S9F5M?jcysy3fAP|(uT z#WAE}&f5!(oD2#A%p0$-+`ZRNk=0YpA`he$2paycRaq{3am#JST(&LD5HW@ad$|=J VGUfZu`YR6-@pScbS?83{1OOY{BDeqm literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/line_horizontal_disabled.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/line_horizontal_disabled.png new file mode 100644 index 0000000000000000000000000000000000000000..b89b2c927890c87b738e4ee2f227048c5ff0bac9 GIT binary patch literal 121 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz&H|6fVg?4jBOuH;Rhv&5D5&k} z;usRq`u3b5BZC6Zkpp6$7B710Z519%zT;5|WpIdiZ)tA1VNxN(18#l}J;sAs(r=uA P+88`t{an^LB{Ts5Qt%%+ literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/line_horizontal_disabled@2x.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/line_horizontal_disabled@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..027a03064f74c50c100789a78a3dd4ef00c3d041 GIT binary patch literal 139 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=oCO|{#S9F5M?jcysy3fAP|()X z#WAE}&f5!toD2#AtOqZ9n0>hYuX2ybCx z;usRq`u3b7BZC6Zkqx}OC+1o4H1<56D3P(6p<%YApr^6ygfs^$h!_LI Yz3kE=rpme$bt907r>mdKI;Vst0AyVvA^-pY literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/line_horizontal_pressed.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/line_horizontal_pressed.png new file mode 100644 index 0000000000000000000000000000000000000000..c4587b843c4460ad11ee30a1339420264ba7b560 GIT binary patch literal 120 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz&H|6fVg?4jBOuH;Rhv&5D5&M> z;usRq`u3b7BZC6Zkqx}O9&-%lH1#~5D3P(6p<%9ULYjjWM2vyq ZUUumQCiyk{^nZXvJYD@<);T3K0RTsjBAx&M literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/line_vertical.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/line_vertical.png new file mode 100644 index 0000000000000000000000000000000000000000..36c7ddf2ab33959b88daca7116263d90675de3c3 GIT binary patch literal 130 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz&H|6fVg?4jBOuH;Rhv&5C}`s8 z;usRq`u5yLK?VaJCd2q;Y1P#nL9ePU&WfnsRJmQVC+&|iP#qFzVD`Gk%6mxhu?a}f M)78&qol`;+06TymRR910 literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/line_vertical@2x.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/line_vertical@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..573c55152f05a9c0ae7a7e8171010076226c0591 GIT binary patch literal 242 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=oCO|{#S9F5M?jcysy3fAP;iN- zi(^Q|oVOP?3N|hYeEyt11Ko-hDlpb7aw)d28mKJ$}1Kp9!cK3H&gA$-MJ^ RKGP16n5V0s%Q~loCIEn*B|-oI literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/line_vertical_disabled@2x.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/line_vertical_disabled@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..cf615a5c9385786501aa6b87a05649bcc97d0819 GIT binary patch literal 248 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=oCO|{#S9F5M?jcysy3fANY2y6 zF{EP7+Y5%G4F(KH0=kx1CAjGu^KA$Tlc{M-+5Pg9k=YTOb6@YCujPHXvHP-pAcO7# z%?7axA`aXcTnkuDST8WmV#;9jW!%!Rj3LS)m{!uySOY(@G#Eele+KAk22WQ%mvv4F FO#te?Oe+8Y literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/line_vertical_focus.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/line_vertical_focus.png new file mode 100644 index 0000000000000000000000000000000000000000..b81bc5b0920ed1dab32babd37f14cec9fbe24716 GIT binary patch literal 134 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz&H|6fVg?4jBOuH;Rhv&5C}`p7 z;usRq`u3cmAcFx1i=&#zopr0HKQ^KL7v# literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/line_vertical_focus@2x.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/line_vertical_focus@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..c474ed9022d4b4f72ce4b2aed0173a025e1222fd GIT binary patch literal 249 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=oCO|{#S9F5M?jcysy3fAP;j-U zi(^Q|oVOPYMH>tljs$eIy>gH>3TWrEnIg(QU-4$%u01`xhU=?qzZc6nSG;-j#b3mM zJA-Qhs|o7`rddoGjJ}Lp8kR9cIRrE4F3@ZcyFfGPO2$}2mIi@#lSe>jGkCiCxvX%J;m-0N^*nQbPkU@8W zW`o!T5eM!Jt_7?ntQVMOF=a6NGHz*D#t`KYOe^VUtl<+`8qWSvoCtI^gQu&X%Q~lo FCIF~2OCA6K literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/radio_checked.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/radio_checked.png new file mode 100644 index 0000000000000000000000000000000000000000..3521990bf5fa9df28896603370425b2ff2dc2f41 GIT binary patch literal 1224 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 URTF31YybcN07*qoM6N<$f{#ECzyJUM literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/radio_checked_disabled.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/radio_checked_disabled.png new file mode 100644 index 0000000000000000000000000000000000000000..6bf1e26640aa11e642e4eabc3339aae6723ec710 GIT binary patch literal 1325 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 literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/radio_checked_focus.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/radio_checked_focus.png new file mode 100644 index 0000000000000000000000000000000000000000..a74da487f7dfd56b182ee3966a00f05dd6eeb152 GIT binary patch literal 1293 zcmV+o1@iidP)E+CA+N|*%1kQfrKFmZtiD2W8Flt37Cg8Rk8!q8mD^Dt`G-0w&a-d(3ua?**2|OdUY8!f{*Wsx_*o z<9_!TlQsIELMviVR?Ey4Wf4dT0Ln2dOP1gMr2N*f1r&JwQ#4|ZAUq3npm>7ao!?P6 zD?I3sJZd@PeD8s521*gGTUZNkSGg}{EMTJ7S89x$0d)`#o2)S(cCDFucTnOKOlfQz zbtm+2kHB)^zKD4xQ1yJvkOJ}=+j6bY!(V|iMRs-GbFZaN%y7u#P?h{0{#p^;0<>eh zW(Gek>qrc7rS`Ex4|ao;fi$Nh&ueHcwp3T3%tx367~mShQ7qT~BmxobRIPU!{H35P zh=dQKItLL=I|Gilbp}Syq68w5(9}D%GyaY{J!<9W_}7c*7r^KN#(ZB?J`1dKf1OBz z$Di$tGZ%qrB2)&drXPzBIH|kQtx@5!DV5yGX+02|%7MrM#;WKpr@^-e)xN>ixkHM4 z9;Ki@(H9rs?7aLq@CMKoxF`FPW@cRLMuZOrAx?k-vbvzbw`}07Awpj0Z(8p=%=+ zfL>2*1w%cB017vIFSx$Zsr4s-r973C0**04C{|KmmzYujLE3w5eF8*J#hmj}l6*t- zx*aY;E;aiT4WedlEbGbs0>a_uD4|rc?_B)Yb**z>Mra&1y~vhZ)fIgwN>vmV0*JAi z`UwcGfAJ=864c4>&RUU}E0`0iK{Hrh3 zTmE+Hb39@DMYl_2wZeR064A^5nj$|+#Ow{OulPM>I>g!0x))&;a4J|;K6_9Bu{!WK zU>b@y*j-*dU_o-|Q1qNHSrSR>SC#yR)@p%mz)d3ImtspDN7|CC!0Vr)#+(821pR?A z_Oigo?(VcC1Ht3Zc5=;bl$8h%5P2=Qw)|Xb*nmZ;({SNw)H(t@1Kbc5PoO(^Ad{lB zAjkiX3Y$Tv0__-G6s)N@pDujRvV8o`mhpDj{#Jx{W2Sagn!y}5wq6b6>ae88*b%$X z#*`SWdB7rK?}rE{h*--4HSWI#;>hS@lDFOWvL)05uVxYtv=}3`T{Yz=h6)_k*Q{`7 z%j9s_T8v2aYX(Jt4YVuLj&d5&rp|TKuM8*eqm6$7&ZORc@EJ*n00000NkvXXu0mjf D{zF*^ literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/radio_checked_focus@2x.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/radio_checked_focus@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..3282d3e7045e50e1b107a9ed7fcc473fbe3d2ed6 GIT binary patch literal 2736 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 Tag0vA00000NkvXXu0mjfm#8n< literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/radio_unchecked.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/radio_unchecked.png new file mode 100644 index 0000000000000000000000000000000000000000..342825717338cc38dd3ddd985ea36dab4b4feb29 GIT binary patch literal 963 zcmV;!13dhRP)h)CP`<=jGLa-;okGk@4J_G?>QH)cauSa=jZ1qTdmeH5jhA<0tLVT%RpU3F1A{& zg<7rl<4^&L#o~SuiAChGKJ#8S#spCmeZ3=qQmJ&4h`bFvmkl+5MG-kGB1@{;0GxAf zH?UVk4gu4^o-Fy3|(zXhBGR)L4&IKFaC0BdbN zNs@1Xdx1AR&wDitLpO+ccYfdZeINqr#+dz46g9d7%*HR0BsralFYZtrK;t-$f%kxd zbM7NHEc!nH#bWUR;5hKRsvh5=_&S8=d9MIhfdfGhJh3H!F{TWls;^fnl|P3d4nP=& zsff&HxnsI^VI5#@ZtgbVaS{0=m&?5~Eb)$&%jE^yyKrBrRJy+hz&UpW5LNv=48wHT z0D!9M82}M^ss{jgG>iIj1ma}EUuEur%>X6=j4?lr3IJFFP}Ra_0EKL_!H8^ib+rK? zBDa(Mh&}hf|7F(N9)M+ltgwv4^7(ux_e$rESqBi2UjU3TcZ>=^Ri`qy-WlsYh8HsT z@CX480f@-?9spHc%-knuW@c_2fxf8f(F|ar2cTN5t^ntOT@w=%FAiHh2!bQDi`)-U z6s`9L8&83s5n5|)epuqx+A&q_)R_R#O#$LKz6^W}+?piGht}F*98*ct^iA5Uzfh@E zKI@+B5m41m>6~sho3$N6NDu_Csp`wXigWIHx>gTcw`BW782&wo zvbA=s*=(K`k(YpfoO6#`e{m=&F0f0atgSUb}Kd= zMbUSg#c$h|TWfDllH^_BnQW*oB8$$sv%pfCrj2|)@6t5g?VQ^qB8O?W<(&)X+}hgO ziCV4p>sA_lJxqcicrfc^9_}X|xB~cb9G|;Z;6P6^-}m>5$T3wt2uzAdK~-;{y)$)H ly(l6J<#PGzAbGEE`xk5uU>P-3q3i$v002ovPDHLkV1gFhwaNeh literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/radio_unchecked@2x.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/radio_unchecked@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..b34782bfa60d4caa9e78e978743050c4babe43d8 GIT binary patch literal 2195 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 V00>-870Uns002ovPDHLkV1kw*8D#(f literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/radio_unchecked_disabled.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/radio_unchecked_disabled.png new file mode 100644 index 0000000000000000000000000000000000000000..1205d7fe6aa3390aaeb546ce2b8d1e67a0bd15df GIT binary patch literal 1040 zcmV+r1n>KaP)b-KVq)|OBMJrF9MG``Ls%)sxL{0>Xh$_JOJ7w}nI0gJ;Qnvoe*iiJ20>^y5(&a_-J>Ww0y~+9`uW|OQ-3fekeYe-&rRduNF_Oun zk;~`fs}s!nE0z}>=KvR~{kwz%Xk;|hts{eu0l3=Jvjn^WU`4xGbr&)M?)sJofJTKI ziG3v>sY;*5GGm!pt6>0CTJj}eQ_>8eFp?#p1+e!CXA1QgnUceZZvuIZ2NsSBK4}7(#C7oBpJ@Y#u zy8?m2qU#IifLDM8RedTN9=x(X&#}?P@!6km9C+yAuZ@~!px!CVon@7e+6JD4i4G!9O-*Z0pCQrqTbTSnURmZzms-s6ba_By{19 zsoN@;j>Dd3Dvfb;pfrJ2C{ixq5Qr(n1i6IL8wrP|cT)H6j(-828(x}aCljOq0000< KMNUMnLSTYJpx%f8 literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/radio_unchecked_disabled@2x.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/radio_unchecked_disabled@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..e050feeb047fe6cb6d615aaf4ad05e7400a331b4 GIT binary patch literal 2294 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 M07*qoM6N<$f=c}?+5i9m literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/radio_unchecked_pressed.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/radio_unchecked_pressed.png new file mode 100644 index 0000000000000000000000000000000000000000..21711dc7fd865b552afd6f4bfb4e99aa8ca2646f GIT binary patch literal 1022 zcmVQ)RM;j+Gibfr{a1$B;FW>SKMDq@4jtd1k{Jb_1mcK>laDqG(X%v0lylX*?A=r`eE4s>jHyK)^RQZKG4tY4bSfB6L0>tr11i6c;{g0 z)qmF>7S$jyBP!1&20Jd_6QHtfxZISbzeU-os-L84e|eXl9$Sd{9jR1>qTM2V1jI1T zreuG6JU7EEe8rSy4xwxW##UwyAetKN=miFVTC5!goj2%t0KVX{XHabi5*c%|eP!l% zAd=V0-Uh}&w^Z*r`tqUx7<&LfL_fURzxUe8&0U>pomKRG0E_hIeudirzOLhs051X4 zi9a9cE1J2h)PR2k7#DbIT`=-=9soA80}w>Mn97VHCg`^J+c-yqE>CUl-pz zD^>fA3$rC3K&b<;YJOfV08fcbxR14Y0O|(4UK?kX^q}YOxxUxWO~kx?;D1y2gZTg= zOajcNsaY-0pEdViWb6wBn z188~-K#^DI>hl!eUPVQB0th;i2at?}ra;aCzA9U~r`Yzs&gc&Jkoz%l#DBXsn70a4 zY(iS_l-ll{T(@0Pw~Szh5Es&GoAU!cVe#egwXPg^4sX`7CljAI=yHI6#<7P}p#nQS$T z2xqvZ9f_lX-xu>(*2SbU7=6|l?FF7+PCjtiTDqqr{xkPVEa+-h^VU#9I?XObwz|i6 sE#Lq#MPsO3z|oOZe_*_je(!Jn2OJ?@GFZm_F8}}l07*qoM6N<$f@RRwn*aa+ literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/radio_unchecked_pressed@2x.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/radio_unchecked_pressed@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..1a1b9c2e3713ac8789eec43adb736e2685890bb1 GIT binary patch literal 2197 zcmV;G2x|9Kp2q7ui1Q=i>s0 z!_a4dIbOv~2USjjtnFy1+~Gx!7;*y2YPV0Y$a@xeD1*!beh+dGwT`RL_nskUCp}#B ziJBH#sD{7D6001TAu6{bdqBT%b)Kw?&Bv9tAR#@LL`NWf~TW4h(I{O5K!$xUa`BSQ_an)Er zqlJH6XJpCgtm6& z-rTb%|K`7RiEtPH>CH37i-ew6XtHwx+k^Fuv-`WY z-vk6k@eDB8Mzvv?_nwSacV}-kR}j4+KfXedKiJ3sma(1i0e_||GbW(4zWH`hU1p=y zLcbnstZ5sH-CW?^7rx!&$~=n z2tPgBRP+8&4dxmrqt)Fa>by~^kM=b;NSlDtP}4+|FWabuXyPgFY~~j2=L>eCykny# zmlb#4l}?*B0h(tl#x_Y(^wr+y>l(rCMW%}Gwo{f`Rq3SZ9|6?`jL4>kdlC_Bj#;(&Jup*t-IW#W72y^0ei14Dj9eA7Pl@X0m*>%1t4If{(Np*)hV}b z#G`j@z>V#$HzBu-D#(3#v}<0<+wjlmsZ&jShiW@3=MB3Vep?^saiN zTa%gqWtyXG$%udV_XSNjy$h7PHEG@gMxjeE?BDucp}^%`q0p^KlK^#!)XZv)Z6x7j zG}HqmZB&4YR{H>-W)O5Qk{JFG@y(wrq?-s`bd*$6y3MtMX`$#Sz`h=Eh24v;*fl8$ zu+X@(OmS}P zVcoo>Tb4cnmeoSOFm7h2XzFAxo`GhA9bBT)90Lu66lqwt3b$`f^fR2W$ zSH(FP27LI}df_pbC>eLT9_MFor>ME5FMWo60Z~OCcQ8U_ur`{qt~OFIss3j{5q-i% z{~*>_lQISV7#a5lW0C5Ei0pLf_mtIcpD+ZUxj{v1AYt|V0_Pc`zs8K7O_?t1cX!z5 zlgDtbu1+-xy!fe=o7{(^{;LQUbv+MqhmA_8N?m`4D*H{qnXQ#)E%a+Z&&Qmgx1H-Q z+6+1@XN~(qNnP_Jz{7SIdLg^f6G z=5w(~Xw^U>WOWCFbjY|IclUW9hHT5h_{(!J@9sK#ju<`s6Y868$|lxOFyY}HWx;V>zs1#f;B7O>0|RY54CbI@ zMXN7Z-1TD=cNa@2Z1MYz^=GzLp3OS$05D}$Ykv2|e|-yN4RC{_QhC|*^*nfP+wu$9 z#2oY>R$3daQP=|HxvDOKK5Jdh+mOwH#f%6a@CQ$y3L&}{=Xs@GsBVbG3s$pxk(q7i zA&ugtHPN{UFDjIzsXiyL4`iQt*|$IIWK^^UN{TPfMRkE7_kgCGh9?A8v`0b>gK7XC z9G4$o-8j|f^F62NeHmm4;E*5(MD*{N=DSIiPIL6AOTM_8QfL-xk6C0GMmaD;gGnL`A9`xGAwOwpK{`NgZV!|e;Agj z?D*=&sp2!{i7*R`nJSbE6anMt-MP5{#6|drr5p#2t7#qTY^pvsQjX(Z$8}uC|0ezo X>KDm@)a|J<00000NkvXXu0mjfW?(ph literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/right_arrow.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/right_arrow.png new file mode 100644 index 0000000000000000000000000000000000000000..9b0a4e6a7a8097818d9c0626c84f19f4d690dd31 GIT binary patch literal 160 zcmeAS@N?(olHy`uVBq!ia0vp^Y(UJ(!2%?APo63Uq!^2X+?^QKos)S9wUkJ;l%oZHT?}(3D>Wp7T%b9XV|~Y(T_!;F44$rjF6*2UngIS-C?Eg; literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/sizegrip.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/sizegrip.png new file mode 100644 index 0000000000000000000000000000000000000000..350583aaac4aa474ac449eaea2cc7ddd060276b9 GIT binary patch literal 129 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!D3?x-;bCrM;TYyi9E0A8dZe4lyHC-T!u_VYZ zn8D%MjWi%f)6>Nz(!sM1rC-2ha+zM<2rMwpeI*@Z@PO%TWH}e*?iSqXK(y9 XcW6R37#&FAr-gY z-rUH`puoZ4SQyZj9Qd}kRkgExspwA+*PdmovgYQ`l$1@M%Pi(EdF8VmvF&CX@A%e}M=bpY`_UHx3vIVCg!0H#+y$^ZZW literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/stylesheet-branch-more.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/stylesheet-branch-more.png new file mode 100644 index 0000000000000000000000000000000000000000..62711409d7ed69ec98979394795822630458d9eb GIT binary patch literal 182 zcmeAS@N?(olHy`uVBq!ia0vp^5PiX%b9eR9<JS%C8jVk7;fc! UBk#RM6lem2r>mdKI;Vst0ANBkrT_o{ literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/stylesheet-vline.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/stylesheet-vline.png new file mode 100644 index 0000000000000000000000000000000000000000..87536cce16aabb3710663f720f8d354b1bb0b757 GIT binary patch literal 239 zcmeAS@N?(olHy`uVBq!ia0vp^fk14@;zM~Ln>~) zy|9s&!GMF=@x%h2%0*w(^im#r>mdKI;Vst0C#6A-v9sr literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/toolbar_move_horizontal@2x.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/toolbar_move_horizontal@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..e775854a376ac8ecd0e2d94b246f55cc0392eff1 GIT binary patch literal 304 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=oCO|{#S9F5M?jcysy3fAQ1Fqb zi(^Q|oVOP?3LY{LVY&EQw;d literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/toolbar_move_horizontal_disabled.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/toolbar_move_horizontal_disabled.png new file mode 100644 index 0000000000000000000000000000000000000000..0563329a672659d8b2e1e3912e1148ba26a7224b GIT binary patch literal 155 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz&H|6fVg?4jBOuH;Rhv&5DCq0y z;usRq`u6%pP6h=5mV?1LC-_XZr9O<_%>4C8fw@h^j4!H2t7~1}D(8IFVdQ&MBb@0By!EQ2+n{ literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/toolbar_move_horizontal_disabled@2x.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/toolbar_move_horizontal_disabled@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..42eed67f8f9fac4f8a0ca83c73ac3a509115cc89 GIT binary patch literal 308 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=oCO|{#S9F5M?jcysy3fAQ1F?j zi(^Q|oVOP?@*Xl^V7>UBXQJbchFN{0D`sd!UkKdH=)5F}JDA04#hWJ+cBm^#p7g5I zoA~AYsayIt-tr$`;&Xa`)xP`drqBBx&6{mk6S!%6K&sbzp3CLYd^pGZvJM+ zhWlv@RSahtzA(&Ue8FhKe1SQGZ2|iQ9tZvfk_~bW#tgO%)KQSz&Csv^JnsAKHF60a mmZ~!+pIKjg{r99Rk2v@0D_HPbUw;ksF@vY8pUXO@geCwxByiCH literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/toolbar_move_horizontal_focus.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/toolbar_move_horizontal_focus.png new file mode 100644 index 0000000000000000000000000000000000000000..d870747e7748d9b2271c54b30fb1f286b0e7a6c7 GIT binary patch literal 154 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz&H|6fVg?4jBOuH;Rhv&5DCpzq z;usRq`u6%kPM~VH#7?(@1#Bft4#>_~!K<_MarJTemiMbTM1#4*x$E!dpKVJN{l4X* m3DJeqrCX{PjMg`IA%pWZxaXyY%_bu-U5d^HkQK=J9O%eza;{{?>{H8~x8OcV7Rg zmd)}blWhU}1s(_f1(FSN4#o_&4QUKj3}+d>FwA0n!DzyKfjNUZ3a)V!{Qh+3b|qFEE*~Env;yap1l{9R-qt5B{aT+j{>p00i_>zopr0A?+1vH$=8 literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/toolbar_move_vertical.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/toolbar_move_vertical.png new file mode 100644 index 0000000000000000000000000000000000000000..4450862aa205c1d5683a3f388696f8d6f72667fc GIT binary patch literal 137 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz&H|6fVg?4jBOuH;Rhv&5C}{2J z;usRq`u6fdK?VgLmV?cw48BYe3KB8i(&m)ZyfgH@pRLCvyXC0V4{|#L1r_=UL1RBHO>FVdQ&MBb@05R7oq5uE@ literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/toolbar_move_vertical@2x.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/toolbar_move_vertical@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..3f0618f72d86f2d3256830f359337eb198619860 GIT binary patch literal 201 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=oCO|{#S9F5M?jcysy3fAP_Ww5 z#WAE}&fDu7c@H@VupF@Ma=7Bk?K0(qXboqHldqWXj3bPDl21>v6<(*eV|R`)PzwXY zxy8p8Y%QDr{O8msyAIn$&sz2BVs-uhw&{hh793YUnY;7t`B#kTo2wi`Z70{1-AK*8 rTqMolAQbB$eu4FvgE-g-h6gkDd1|WhzmSb*1POS$`njxgN@xNA`WHr@ literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/toolbar_move_vertical_disabled.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/toolbar_move_vertical_disabled.png new file mode 100644 index 0000000000000000000000000000000000000000..1369e4446a190fe4c0e6602ca9ea0d2ddf8d38be GIT binary patch literal 140 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz&H|6fVg?4jBOuH;Rhv&5C}`*D z;usRq`u6fdK?VgLmV^AV7a2K3zCN1a$$q89DM`3^^}V@OoD37r+*?t*%Tss7?*8?P jo~jxgH6NK67%s)`y2-^}-IrzsG>O5})z4*}Q$iB}eQ+rf literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/toolbar_move_vertical_disabled@2x.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/toolbar_move_vertical_disabled@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..58209624c315ad23928dde8351fcb66f248e091e GIT binary patch literal 212 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=oCO|{#S9F5M?jcysy3fAP_WI@ z#WAE}&fDu71)Bl{ST6h(c^J_yD>3_Klc4Cuj^r$6kwXzJGps%YA8Gu4XfF3Rz1=K8 zT?`F>H7-9W*%veUlIr8cUMFs;SyQ6_@3G%^IL&VR$)}T_{5W^R_wXskZ%d0BHu|1= z{XJC7+(h&3Emekw{}07yoX;)#c|bYa zmp$9dC?}SQ;fH)(V_DYn)9Q7N_x~_~Ok!XtdBm)KL54qZO3_;o*VEO{Wt~$(696~B BOH=>= literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/toolbar_move_vertical_pressed.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/toolbar_move_vertical_pressed.png new file mode 100644 index 0000000000000000000000000000000000000000..2b413d30552e654fe120e4e1392dc443ee760834 GIT binary patch literal 143 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz&H|6fVg?4jBOuH;Rhv&5DCp?v z;usRq`u6fd!2=2+EEij)G&m;P2~27AP@K7Np-7`s($BQ{R@+}WOcK#~8~Dq*v1;Y- mzl&`deg*|tePW%Y(i+XVfs4Ju_U{CsVGN$GelF{r5}E*CL@b>E literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/toolbar_move_vertical_pressed@2x.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/toolbar_move_vertical_pressed@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..4e80a0bebf0082b5c49e424c5d91a6312c833e54 GIT binary patch literal 204 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=oCO|{#S9F5M?jcysy3fAP_WL^ z#WAE}&fDu7c@G8fuv{?KR#1GF#LU7gd{JQ|tFf!Wk>wuD_N5}4mFsPGZnzuE1k}TD zpe#iG&HD4fOW%3&albKMzVMRX{Nq2rO27NHa;n^XmE&gjzNLR^SUb~Z!P2{v_K4p| v&2#SE&d8v0k+p;|b^(70Bgha2hHEdmJr~LG@7Lb-9K`i>^>bP0l+XkKU6@6S literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/toolbar_separator_horizontal.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/toolbar_separator_horizontal.png new file mode 100644 index 0000000000000000000000000000000000000000..a1e84c1d852b2e941235fcb4eea586301438c181 GIT binary patch literal 145 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz&H|6fVg?4jBOuH;Rhv&5DCq3z z;usRq`u6%pUIqo8BL_GPC6fOF73w&N+PNRk`)=NvnRPJKNfv z|6F-{TlAzJ!*!=O-8tGfxx&Qr+j)P_W#t@=tS4T7p8wAIB!m4z#xD$OX^ef@Dr$D} oA7$z>)bqTi^13cORQ4UG!8MTp?k_WBfqrA~boFyt=akR{0L0a7O8@`> literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/toolbar_separator_horizontal_disabled.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/toolbar_separator_horizontal_disabled.png new file mode 100644 index 0000000000000000000000000000000000000000..bedbab447947681f0f6a28358e3ca00893cd6279 GIT binary patch literal 151 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz&H|6fVg?4jBOuH;Rhv&5DCp_w z;usRq`u6%pUIqn$!w$_69lQ(DQdPo|J1!)CuZ;bj;8?rv@^h<`z0-QQds6rVE;BQ+ sa0nqd{(g zs0056t_AEFtQVNKFuh=mV*J9emZ7R4jKS7Hn_}sc4EOin*`375w|UR`Gr4Jb->p5% azB99^353Kx4qpiLA%mx@pUXO@geCxy>1;^= literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/toolbar_separator_horizontal_focus.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/toolbar_separator_horizontal_focus.png new file mode 100644 index 0000000000000000000000000000000000000000..1632c597926a312e55089ca991dc5679fc4fc618 GIT binary patch literal 149 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz&H|6fVg?4jBOuH;Rhv&5DCq9# z;usRq`u4gbFM|Tl(F?5#iA@3>Dw8T_D7j3Lep_q*eisMx(|4!tx|*q(=v2rz^Kl3$ qI5aRYGO>Ud483)3&pRKz)|>E_*dT+4w*GI+ZBxvXbP0l+XkKa%5=z literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/toolbar_separator_horizontal_pressed.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/toolbar_separator_horizontal_pressed.png new file mode 100644 index 0000000000000000000000000000000000000000..e03fb8096ec7e709ad718bdfb06897da03f15495 GIT binary patch literal 149 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz&H|6fVg?4jBOuH;Rhv&5DCq9# z;usRq`u4gbFM|Tl(F?5#iA@5=i5!YEOjG_ p4h;;9Oe`Pt&nP9=5WD4kXK0BAVfkAzft31q&jn2ap=`o^JJ3wLk`wH>jip`!PC{xWt~$(699`oT?7CC literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/toolbar_separator_vertical.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/toolbar_separator_vertical.png new file mode 100644 index 0000000000000000000000000000000000000000..86688ee38c360327cdcaa21e34b74ce0046cc00d GIT binary patch literal 133 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz&H|6fVg?4jBOuH;Rhv&5C}{5K z;usRq`u6NXK?Vh$0|ySINR++eknOS#b5`7F`Xn^QVbYTOTcrgzHU@r)ooUHfbunO) c%FCAw`Y%{nR-|og02;yI>FVdQ&MBb@0GO^P`~Uy| literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/toolbar_separator_vertical@2x.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/toolbar_separator_vertical@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..e4efe8c7d388ed9e68d57e5e6f9830dcdef551f4 GIT binary patch literal 191 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=oCO|{#S9F5M?jcysy3fAP_WR` z#WAE}&f5zcc@H@VupF@Ma=7Bk?K0(qXboqHldqWXjZWqb$)|T$-8NS{gxXH7@q1CUCG#%G c86d!u#&~3{Fvo3+W!FJmPgg&ebxsLQ0JAwhoB#j- literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/toolbar_separator_vertical_disabled.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/toolbar_separator_vertical_disabled.png new file mode 100644 index 0000000000000000000000000000000000000000..244536844ffdeb3912ef97ec67ea6fb6894db8c3 GIT binary patch literal 135 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz&H|6fVg?4jBOuH;Rhv&5C}`>F z;usRq`u6NXQ3e49hKtF{(gG@^%G4Z>f_y$Fo7-n0bqy=K8Oz lb@J9|-o2&@(ag~BwU%LDH9yC;wY>j9LY}UEF6*2UngB=XPC*=SD literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/toolbar_separator_vertical_pressed@2x.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/toolbar_separator_vertical_pressed@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..08d83e1e75409cadec4c3fa73cf526038aa3b0f6 GIT binary patch literal 193 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=oCO|{#S9F5M?jcysy3fAP_Wq3 z#WAE}&f5zcc@H@VupF?Ba&Wrh%FZFArR2DXJ8P4Vp#KAwH#asNIp4CHyG)-Es09eB z0zN0y*Ur-_^)I@y;QXvMuibm(pIgTe~DWM4fTi`($ literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/transparent.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/transparent.png new file mode 100644 index 0000000000000000000000000000000000000000..67753617fec23bbc57360e16d16bdd82ab984743 GIT binary patch literal 104 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz&H|6fVg?4jBOuH;Rhv&5C@AIW t;usRq`t~3rBaqjm@PB=thXaWDo=rf3fzh3DK?jh-;OXk;vd$@?2>=W@7CHa` literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/transparent@2x.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/transparent@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..4012944b58252423bd3c84fbf6f5e698b1a39bf0 GIT binary patch literal 117 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=oCO|{#S9F5M?jcysy3fAP*B~| w#WAE}&f9~Gyg=Te1>gO1`OFspnaH4_oY}#FfwBM7$v}{>r>mdKI;Vst07yI;1ONa4 literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/transparent_disabled.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/transparent_disabled.png new file mode 100644 index 0000000000000000000000000000000000000000..67753617fec23bbc57360e16d16bdd82ab984743 GIT binary patch literal 104 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz&H|6fVg?4jBOuH;Rhv&5C@AIW t;usRq`t~3rBaqjm@PB=thXaWDo=rf3fzh3DK?jh-;OXk;vd$@?2>=W@7CHa` literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/transparent_disabled@2x.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/transparent_disabled@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..4012944b58252423bd3c84fbf6f5e698b1a39bf0 GIT binary patch literal 117 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=oCO|{#S9F5M?jcysy3fAP*B~| w#WAE}&f9~Gyg=Te1>gO1`OFspnaH4_oY}#FfwBM7$v}{>r>mdKI;Vst07yI;1ONa4 literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/transparent_focus.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/transparent_focus.png new file mode 100644 index 0000000000000000000000000000000000000000..67753617fec23bbc57360e16d16bdd82ab984743 GIT binary patch literal 104 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz&H|6fVg?4jBOuH;Rhv&5C@AIW t;usRq`t~3rBaqjm@PB=thXaWDo=rf3fzh3DK?jh-;OXk;vd$@?2>=W@7CHa` literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/transparent_focus@2x.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/transparent_focus@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..4012944b58252423bd3c84fbf6f5e698b1a39bf0 GIT binary patch literal 117 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=oCO|{#S9F5M?jcysy3fAP*B~| w#WAE}&f9~Gyg=Te1>gO1`OFspnaH4_oY}#FfwBM7$v}{>r>mdKI;Vst07yI;1ONa4 literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/transparent_pressed.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/transparent_pressed.png new file mode 100644 index 0000000000000000000000000000000000000000..67753617fec23bbc57360e16d16bdd82ab984743 GIT binary patch literal 104 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz&H|6fVg?4jBOuH;Rhv&5C@AIW t;usRq`t~3rBaqjm@PB=thXaWDo=rf3fzh3DK?jh-;OXk;vd$@?2>=W@7CHa` literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/transparent_pressed@2x.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/transparent_pressed@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..4012944b58252423bd3c84fbf6f5e698b1a39bf0 GIT binary patch literal 117 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=oCO|{#S9F5M?jcysy3fAP*B~| w#WAE}&f9~Gyg=Te1>gO1`OFspnaH4_oY}#FfwBM7$v}{>r>mdKI;Vst07yI;1ONa4 literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/undock.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/undock.png new file mode 100644 index 0000000000000000000000000000000000000000..88691d779507c9b809391396407f5cb4a6497c40 GIT binary patch literal 578 zcmV-I0=@l-P)WFU8GbZ8()Nlj2>E@cM*00E{+L_t(|+U=X$4#OY} zLz`&--S*43w`rPoNlWaQLS8pfd~hg*uq-oX%osV0`LJ!+SPR{}9r(JUC& zi*OVO>rs3r1nW_FCJ5_Yd@BU&U3e=9yOQ`b5bSE=k3zUrc5+?UXD9c4F9B>-qyH)% z1tH=BQxRVU!7FWl=67leWRLz4ahXo| zoe{&T7oZ-FMxDSsBBvjZ{}acq6e%f?_~rzJ_LzyflS`(bcuN3?R&llQTw-2U8((=NC3B QV*mgE07*qoM6N<$f{lRZzyJUM literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/up_arrow.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/up_arrow.png new file mode 100644 index 0000000000000000000000000000000000000000..abcc7245212f19a5dbff1bb19647b1dd4bb05b6a GIT binary patch literal 158 zcmeAS@N?(olHy`uVBq!ia0vp^oIuRR!2%?ApR4f$QjEnx?oJHr&dIz4a+s35-CY>| zxA&jf59DzcctjR6FmMZlFeAgPITAoY_7YEDSN1y`;vAy| zxA&jf59DzcctjR6FmMZlFeAgPITAoY_7YEDSN1y`;v6FKKb3EC1BH}5T^vI=t|uoP z;C)upuu)h7(gY#2QZoT z30juyT=+*61Tj9vbPp=vANZH(8>kyNE@-d4z3sida5u)Yn#@ek_syBfF-O(t3|TCh?|1!W&j1gRhqI=kTY+xm^Oegzx(wMWjc< z_x-nNn)a2j)?O2lwI=XN0f013Usp+pNUNVj4P5KswF0?>F=ii_Y$6ec;Z+fNRso-_ zgZC8xaL(0A7-ROFbGtbl7#dC?Y2UEc-Vl)$x=-{Wa6N1Hz(r&(j^ihTayJsFlMs<3 zRiz}>7!CurpcrYIzVdzlpmZ>W?nMj*A4;Ggv0swtz*TiVNs`8J=q_EO5RqRZq7_5x zdEU=q^9@yjFbvzkdd+tNw1Xhn&Hs*(3Pe%V0ycoLLU&$?;*Hrh#_Txf_L}5vv<2B? zq6aP_H&u1MAOgpW+Q_OkFa}m248tklc@;d4O7s<|g9EpcBw5Kj zoO5*&Eo01XKZ#m_0r1D=`Odj*W6YOfB`O7?D4GN|o5BkcTXhma5L9kQk3bYfli35Z zyyv(3!HW_>5PSu$lqA|!5?un;+6mxA6+DjPM}y!ek?06mYcGq)%hSS(62_QsRT94M zZ>4GaKJPdl@x0|S99TFBJdY$v9s&z=-xFiNa);ZYsTQB)3M^y^P8C%WB68Rx;CbF6 wZ~*)ek-1U8ixR3j3w&4APr%}+a{v4B2L`lzfwmJ`umAu607*qoM6N<$f?9f4&;S4c literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/window_close@2x.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/window_close@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..b11aa0818567dc9adcc05071e37e053391310329 GIT binary patch literal 1690 zcmV;L24(q)P)f zAPBw%ECNURE`2yLF>!Ksc6P0I(ex*1G#UYe<^hhV>OvTXla*Clv34*I@a)FMM%ceN z06q*(rhjb!fQUReVz0xhy5M=kpXW506Lw{9B{*7?>&c5#5}Op>2!Y9zc>J3et!NV zYwcOwA?(RGc%FAcL`JrKt~G1z)cpMXNBtLuo&)j?UNpum0*4(oxB>hiNs>P}#Ez{X z2wqUtB@ubpA^fJb_H34A*N0u)769x|2vwSg5ddI+L8#h140#6hE6cLqi^y4EZB#6q z^SGG5mMT>gMb86^uI5E#YLt0!=zy-mFq~A?1sprUT6-qTvJYJI@1!V-p10O60gpI@ z-^`Ef@4Mu71_0oB-nWf0*Vsh}Ma`?~t7)44);0gg5$IKxW!J5>Q@~A!@FOBJ);JV2 zf2*i@DA)mA<(;qqJTxj+RsSs_XOblOW05^dn4c$z z?7E0Jjf03htg1^v5WFxdwy1d#Dctt=)mHY#uEH>UNmZ{=K_`?k-)gm7KD=$Ku>k=1 zzW*H&xrze>;9tg=GjSaMsdq65g5x5xq^d_9a@MscPHN{O$Z{KelRee28)Ay>Zt5>xGfGr4D zfkOpvt=&BA0sz>8umFtu%Dt<*`SG?^^DxFyxQH5!#u~8U8ZROn`8~C(b^uWnJ!7q1 z#_ii%VDq)8s_iI>o~yAmpymg0rZ%E+#&pqF=l!v^Ii2oxZ{xbF>7tx z_x-0GVuz~K2>8DLl!&b0X8x`*=3E@d?IL^R#VUu;>e3B#!4zZP~XeX%ZsWeUh-hW{Lz{QIfzuxI|J^-F{ zNW3TJy9$Ef4DbuwApEn@Xq>ow`SL${7Y9bbTKg0J2h0QH58G+n#^H%hr}NYP#bLh| zf7v0~x~k6XrTMOsBw4c7p2q=#h@9$Q8}<%g1)$$VG&8)$}|AzbZW7yw|5nG=zZhupjlyqP4)K$88Ud?bfLP}NUFWUha` z(Z8^|x_W1Fa`LTavw4Wk*Wd=wHpcv@u76Qisnylhk58UFdBs}$q=-BMd=9*2jQL@! k)%tX=>pRea4z$1YC5@3j+@Cc*@&Et;07*qoM6N<$f(+9)*Z=?k literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/window_close_disabled.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/window_close_disabled.png new file mode 100644 index 0000000000000000000000000000000000000000..d60edac2fe90e092985987ac51b826664ecf20da GIT binary patch literal 838 zcmV-M1G)T(P)pGbtr%@uv6I)wi}ShrlYb`dM)y>NP>h2 zk4W$VNPGh&9R;rl5)y(^;n2lt=pYG?B;WfCgU*vS!!bwb$SVajTip>^*1i z%+3z{?;&pE_^5dz1~*U+0arIG<<)+IjJ!DsTm!zxXk30)dGZt>=1zzyw@{7&M}QS0 zSDfw_d^l&$04w{sk2Z+iY;ryG4tm-#L>K!ZF`P4JL|ABH9c~j)^a{}Er-YF!P6xmn zB3yAh18$>kTYK@Lv?a&{zxRe9OeB)ow~k%i=@pLXVk;bFcC%7mY7+pc*R0n860u$- z_TdXH`G3JT%J;o<2WW|U&3ZkUO1~pWB9(sQ*j7ggBVU+8Sd0P>6aa8+>s6oxGTBMO z$QPzSTHzW74;64F63Og)gz+d6BctXikOu+qvtjU#0>31xp%Q~bnLVdw?YeMPdWPdk z+A)lrc?Mw~|Bn74!fAjYxQfnht*_ndmOGL_n1mt?P{c1584g{Rz#EQjy-XxC9}t=w zQ$WQ35>bW#E8k*sVnK6BVHpPo;P2wzU@}Z=@yIzf82jMLDm?Is8j9 zAjtA?zEFyiyK4oE(c%Q~FbMv9qdZ@?t1kwV85>~?ZzYgOmFOs7j20(QZG)qFVRK_` z-W_mkD@9fj-?6P1iDddCB0Wh23XJ56_)a%?Q=(RlEYTDg z$(yDitA7jkO2ku{&k`gtl-+h})v7zNPvUwjTw(4{;BIVH%C{Bf@ShV0MD@Dc`F#+H z?@F!;b6b`2?LUQgl2G{3CLqEk-~-^O=xjgWUI~=5z!!lU(zw*G-2Z<31pAGHLH={# QVgLXD07*qoM6N<$f<}LI6951J literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/window_close_disabled@2x.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/window_close_disabled@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..b571b12e89465d6493e81b05acf66f95d8e5970c GIT binary patch literal 1724 zcmV;t21EIYP)FnkDBWdRE&3pRX>ZdgI|l33Q2aDlW`mYni344qCE48shig*XkigY_I1wp>M$ zrRPfb+Gg;7dG5LAIsc!|xsqkUsZMpO|7Xdd;FX1i^Jo8a_WP=u$H+O9JG*W3llRwd z-aG0B$I+Gf{8!FI?3)O$V|5!SZgc*pf2{xP)85=Z09UUrJ-PKc`%6@#J(unay0~5| zy&G2JL1-qG|GKfZ0$k|1bocBzJO6IEyxAQzy#=w7c@--e4bq zjkUrDMq~kZ2*v&m zr3wK;HVwF92`=VFh^7A^l&f z`o_2re478%3X6Ws!x#X-KLp@fvsPU9bH-7a2Zx8?AT{gdcTl?kJa9;V3RvBLf;%ZT zpN<}dc^DG_>_Jc?iv$cIHlL2#h^gXe-e7(0e6Pk@fo?@px!1+&Z30+_am+VrWtTtR z4%OHb&{3;exMPLuxKBc5|2_RN#pct|cEmW3y{M!oH4gzyKu0sl>^F^a8~CC_`aebF z+PYV00?foSGa^zIc*f!0hoW+Qy=7SCSxV_po|M!isPd8IYQWbgrD zHnntRvTi?9AkTnUJbT#+HGG&~uNG_F!Du4?ZNZj+FF4fr7!yf0tG{@EoPN7CF#x~j z5u0mzWp8k;T-=HlIYI~%t-!u{=dmAV9-vV#)Qw6O$92HACtioKC!ovx^A71-isW0h zLe;HyE^b9jjQ+U}z(1s|$@R6;?_6s4YAgWLiTukEYz;T_+lu5|&3ANE5PYw|QJ9Cl zbr3@q*m6jJP9x&Y&1YWmdycOO*fXyl=nD?%W1H{RTq>JTOA*IOFiN6PFaF-OzB2&d z=9PS_UR-spKTNa9bP_cMLV)130?}0Z(s7vwXnJK2u{j*q!3wolJbT%t_DBHHRQi(G zNX^x}F}f6_`Hq@i*;6EsI|R=K!q62M$9$t&syO71t!N^b60`vQzxo`YkBpKWwho6* zKs1%Ugf-4%FCxofn+Iss3ROjNz_vsB^H%Vt6Zw}9OBgr-9rFSg9S+$Mk)?I7u;P## znEXyc8Mcae^R!kF+DP_tt*?m+ola z3Pe z003=|sIvnsH*3Y)jy;C1MzvINfgsT5tsj6g>{Z=C^*blYd`FFHsUjlF41r*gTfMP9 z0B0gk+yFitaQ~k9da19-NzuAjSUC)Wz&&=`H+tid-oRh){b}njK^_5B z5&2%T7S6w@gVf*d{rSU-FMYKrh8GoiTHs^gE#0->ZM|Lo=(zhk)u~Q(vh-iC4k=6A S>t~Aq0000v-oD7@#eXQmUqZQrYdo zH6X`BH-@$}{ci&ZiEH2j67R5q)YL05P`?Zzk!w3~9C<-}lYM;rK94^i*$4RFi~WOX z*Smisy&-T{;49xYKI921HN1I3uL=BOPy1M!;-P2zL9|1_A=^gzhOwI?Y3(?6em_o`hK-?!^R(lno%rQ=;N}wHO=-2-q=! zE6aQjXgNXRWD<#r>(wNkM&TmsU8~xP2>`&gZJs4a6thbFg~y&;WZk!ngR1OTAqddrlWNfJF$0vxRSwsDk}J(j=-iJ%vu@YvY!OadW^!x8so zf&-E7Kw9~haV&BLgc9M@Y8H5A0RSi>_z5vlpdkFnnwLpn+HEfc;(6qq53&TFR~qfd zSu)38guVay1%Rp0aK97boSOnw>-}5OYpf0og9};{wHguufMOtCOuOxcTm(vvH#ZFK z+h)_Z%tJwIlS+&fC^_C7smmyw#JX>r&HjLIo6R8-=V=l{1xCTUR`nn{-?z;siS>xY zRGLKMA}lpJj|jBJg@>!+c2*_qN3wqltR-!9V;vX@7dF!10MNCn2NX6C=>(yRQp1~% z&cD@xlGAxe;$0$qyZSZ_9KT2NJHgE@?L^0crkv+x!IF z+A3=&1}8Tsg#$p>GWJPsBJw&w?(|PWYk=X6Xb)}~`;)>`ByQpYQT8CBu0000ykg(wnffpiggk%|^~&F={ERa?|Y(=VrOT9Bd&6bOPK$R-v=rk3N{RKt6^ zFexZAl6Z%lkyupk^3Iua&-?J4ncur;%K4rNXy7H%4LP40ykr-Z`{gd zKHcvEd(mj2^8J>`s|x1??j!P^9F@7+&yrtxV|@S;zxwB+#5O+wPI(U9R@I4mF7xN8 z3J*i^YpYKPwgepa9IDud9{x$=l^<+uUo_qX8vDj67a>Lag<^eLX z&3ixhF8Tl%^vWK492-;!UCaZZ%9MA_-vRJ&m%Sc9D3+fLUS>2(6su>tnFl~P>Rs{y z5S2eV?0HPADGdUIM6r4Xs|$2951{zG`2e6_Uj=SE?0w)60-1*m(bntUMIV4#{?x~6 z>_yxm9LPAd&3AA62imZr6Se%QkG%(Wd=3DJ7t2qIH6`Gf!v?n%^L%|K`B#V7zLmJP z@;I;nJmwI7$BJHTWHTS`bZ}PyFqja+G!I<>z+gcL+dS-a5%j1&J@yw>y$Eb{iv^Ag zwv;GV&p5;eQew7p8YtmvUYY1-9vnKLqj;fmRz&7;>;#NlSf5UP6=F667HQ) zYTwhpp|*MFnHTH}{hEgmI-sMGx$4ta^#<@Ahwv}4dSN}E`8&Yy?CO{ry9f+9oO@TW zmufR(f9R*)jzR+fy+IIS_Mpr|$N(TH1la%uw+E}x%|iqL07hn4pRvYX$E_1wbXTmt zP|Ih2A5y+8MFIdqg%Fu}h!6n4@U`-f74sWDu7_- zxrcH|;3C4my9F!6qks_FHQ+>{l8lL2b~Z2OrS)ub86Z(y`6AQoh$Bd5O znod_;a(mTN2MiU2M~QK%$c^E-9G(6!Yc8SFAa%;(Yzu0^;gUZ{+V$h(Bx30(mMHE)qC zjhR%*AvUn$bCu^rzI?%2d?m z0qWVzqKZxe_qzrQ!!cxOs8~L^d&myjW`5M6rlz%WrIAm~JH&>jpq*f2_IzV{>>u7k zJ^=Az`Fmo`N5FR->NpVd9mNYP7esgm7YMLsMb0#`sn54B`u{B5GOzJJU>=~JOE0K$ z8JBT@5u^OlyXe0L2+uksYZ~m-L7MNVo=Y!Sb~wK&MqjQ? zXM9NpMU8xFeh&zr9y!vw>Rt2!xbur2){n6Hl)$e+KLgf)x3T*4Ae--~kx$KwHRpi0 yfLoxS3G(K*9{T$17q6VI9dvz%I@F;COaBF*o-8Y7UJqRW0000BaP!xv0lXL(~lXL|g!Uos^1E8f%DX5McTV(;2 zSOde(kQ&EvAL$Da5^G=^FaxP+roe#YXFwes$9Xtpf;b~PzW4vWoO>i2{`a!@V%cxr z@2T+G;I`1qZo_@INKnZOR}Fh*@WaH5tDyD~pb#(Us}LC616B;Xtawp%QSh=KZW?w8 ztO)M*jYj-zARuuov8N!^UW7#14>ysWBw4_n5rJZXJ)plxiHa9hGvIxb_C^G*4r*_K z=NS?w^GH;@s4CP>!-YAWz`Yz10Jv_{PBSEmc_nV(BmZ2O(``7%$+bpCmFwXaW=E-j zo*7%6gWAPJxZm24XamJ*@Ua5(N{oR^*mf42RQOO`2W}fAHgr+MKs2>_J5=((XNO9CJhE;-%6J(`w1lfVRt_;`}P z%?!^akdQc>urC)JCJbR#bsNsHux&t@aH!>h=N14cn!aZW7%E`j^5*3dSoT|MeQ}n# zPZWgCDqi#?PiBrG3|9?12bPAg7@%ZMuV7Sf-YrvWrVfmQOXdpI7(S9>Uz{)dt+iRQ zr*@#^M~_Xq$bxqRCjuzdBgaf(DsQGvOzgloxS4ihI6yaWBFS7vJ8?Fx6JrG?!8-?T zE4{uOIFXrlQW8tkBr=bnR1Y7S+2yS8WL5mICRsC;{Zpu#^`Sc=FcuE=PNNo1f)6CT zmMaKmkr)yvdC@~dZ~g|JS7Pw6TyH(Vc)tkvK%yS*$gGi;Kw7;H+z*f(LSugfE_w69 z0Xl)(G|3}1n3(OyH-7{)^yTv#9=OeU;Zr1f83MKod;-2oauxwkO5D6fzW|>_e|J&Y b|9<@f<_Uyz{zSKl00000NkvXXu0mjfk|jfJ literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/window_close_pressed@2x.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/window_close_pressed@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..749009c00a3e870536530f42c1d25b2756217f41 GIT binary patch literal 1679 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 R$EW}R002ovPDHLkV1f{ZMhgG{ literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/window_grip_disabled.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/window_grip_disabled.png new file mode 100644 index 0000000000000000000000000000000000000000..3c0d86e823ca647c8ad984df051e1ba98c6e62e5 GIT binary patch literal 447 zcmV;w0YLtVP)dks(p z_ZGkwKOYW{n`!HwmHC=Kj{D$Y61w0@s~N^z7@?J~9~8h9H*f~LWJ+J3$J+4&WPi3J?MZX!yjtgHfAItZ}e70T*1avY89M zH$W8}Sf)z%%5bMi7y>Vwgr#@FAYZOkV%BxPCgDaCI^pYE?oPben8jff6^os4LkC!@ zs8QN*HjOEzFLlIi>b9NG`UK)Q(k7c)TqZD@lOSho%T2>^)U2w}1FCKJbkNDE=H p1K+5#nFkQZ5q6_lJlFm0^9>c)^|Bb>meT+L002ovPDHLkV1m<3yZZnD literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/window_grip_disabled@2x.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/window_grip_disabled@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..f57b353aac352b6b2059f2d0e868dbb0b75741ba GIT binary patch literal 768 zcmV+b1ONPqP)6!@u5F&c~#4N+Tc- zJd{L0UU(>hfJNZJa{-IOgU14Nz=Nj(bisp%0(8QIX99G?gGT~Pz=J0OOu>T(0!+e# z;{r^>gTn%Bz=NX#Y{7$r0(8R%+l@OSJO@Cjhr{mi=gHrl+7QtVUke*e5srWjU;~kt z@iEQ_Fae*?Hx(xYSb{$Vc^n^GxBzSLqV5lS(TDi>LKi`+@crY%q;m=r-~v1pB)}DT zC_sQq@L*YhYw%!EfQ#?|m8^f9C$``faxm<7-eu`Beg)WsAM~P3@L*Vg>+oPufDiCs zNPsW!U_gLR@Ss_MZ}6Z|fRFH?Nr12Lph18wcu~?Cb)$CHz8hQhyP%!{`u7B#hYuSq zP;E@?33>sqc*P9HTmsyO-`!7u*Rv<+2fVzF_i5P^^cp_p6?yL0Vb|el*fjk)X yqxY`#rRMt1&RP%ztFHEiVR%_*-!jWw;QR#u%+9O6n5j7c0000Plo@#q)sdxCQ+8^NYIzpe)j?( zs1^Uv32>swLB3y0fG=EVqdW&qIm^$yU%>{xC%yUQ(X5sLWw_S>Cb+i%rnr{?Hn{Tu zwz$&(Rd8nkO!4UEAzX;ufxf@>yD>NzM3(p%I7VpY`^}p1LxIO2<2*mBdOg{L~U!Ak>F#HS6_ z-ZtE75_-bTCZQ*M0(90V;YJ6n@Z~FaCms%yX!WnyISH+Cp$$xfro>f0O!-ml8egd^ z>d^8E1{y35DShiwcA=&woxkiANLQ;rtsWX`eFwg+i^3kj+ dPV4@9eFE=T^_JdW17iRH002ovPDHLkV1i9fx48fS literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/window_grip_focus@2x.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/window_grip_focus@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..d92f09b0d0650b348cf31591fa0cd37344a8facf GIT binary patch literal 738 zcmV<80v-K{P)(u9ILUNrm^qNcTV2%{Q9SR9yyoO>0nvQ zTGk?$lsy5{RqqV$3cOJ8bG62!ACH4!{P}8G6SGl`sNVv5Kuv%@6W#!K;ytx8CT61= zQNM*qj~HVOZYKLGDIg0T_&ZTNP4-q!z%+Of+T$?zlI*Y4B6u16`IF#N);pCEkOv+r zA|Nk3R6sxxc<@|6QF!oJfDU-@RDdpc@KAtGc<@YsZg}uWfC+f;M1U!H@IZh`cyL^R zX?Sp0fDL$XRDdmba8Q75_~zl@o|^C)Kp}hMaPxEgxl;!sy5Sp9zoir>2u*~hpt{K( zX9Spl&&W%a69O#3PXyUd_LeTd7Ci9qJly=4>@Rf@v!H@u7;K6_ZpWs2W z0N>z2qW~Y_L6ZPq;X#7{dpkU}J381po;R-<4Yw8Q6&N@ZbRE8aINVjDj*XlN`T#FV zy=4YtuA8E+!#6sE9n$c6&IG-Hhj-~b4QGNr!xugibRIq$+(&qy%A4`mc_jf=g@-E$ zu(!!kJEL&xWd6MT@GwI_)#2e10nWpB`fZR8sk}LVMwtQ@1s-4}Ina!T+XzQ!f}fI? z8-8kD&IR=UFQ9w6*0{Jf25!Vg^WV(K&dUw2J&(jraN~P@1z3*_6}py^kymK4y7M3* z;OzOWU!o)geghYRY8APYlgd-lE;3o&c~k55%dhKnPuE<{+j#cvy3V|1Eo*`6AFs^5 Ue};D~CjbBd07*qoM6N<$g2j1AhX4Qo literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/window_grip_pressed.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/window_grip_pressed.png new file mode 100644 index 0000000000000000000000000000000000000000..89d5908828634379a3fa053484ecc318275a74bf GIT binary patch literal 444 zcmV;t0YmB0^W@*BXXh#K-yf+HYhLtQi4N~X)a%>e z>;yp7iW7|x>1dtoX6v;C_{O0PyeL^5W$(Nn!5YrII~!b1YY9+>dktWMdkbKSdkJ8J zI}c!sI}K0;cNV}DZ(ZFsmy6^9;p4r3-UA1N$Pym{2WT4EdRQ~QFYu&7b)3Dcd<0wI zhtr$W*;WBu;ZWfStng(r0``FCJRB@LV2$e(4?@+;!>t1NzySi6c>2eqjBzmNfE6y$ z&;~CJPze_%L7=*MxYZ=|gqux5FZkCdxjG5gE}<2k)@{UdF6OU!pb9oM#oGuIrRTX9 z&g5cB?xvQwNnKHg(hkJ2S`s~$;h-fUx-Y|5>x%H70BI|BG>kX?$;8)!NJGQ87+5P)*S2~@vr-Ra;~GJ3#(eys+PH= z>;>4ajotXRMDko!zOO}-N8jFbz9jFjm9;PzRqw`4RE|+1LHRX_UIVw1JyA((vtIw; z6O0jhBi&a?0a@_C?+NlO-CH>Uv*1OwH9pumP4`!76TAri?6C7G>zT?3$O8`*5s()i zDj=W;JOnPFC_Dr#zyv%5D!>#x1Sr5HJOn1dG&}?(zy>@7BES|r1R%gBJa{g^HavJN zzy&;bD!>&ycqqU$d}BAhqav>WROI2fzwZR$Y500KZmP%$&;S~u+DrF%BftiH zM&49;A;1y*M1;rb-qHoQf=768)^C4I_m{c}x`ZF~+s9eYlqSFjcqmDLFYr);0H5H& zu>jxT!Jz;j;lYsrXYi``M~9sci)2|B;4?f}7T`NPSQHQfJXjJC3Ora45E48X77!Xd z7!(j9JQxxXDm)kv;0zwNM+fcUqIr$(;I1k!!NN??cleFHqit1&*q8~1059kfa~N|8 z@EyM19c*R5o0$oQ0FUx^D$m4BFl6|`GePg+cjJ4Ayqn6K^Xa^lfU3g7CH4S!lN{Z0 z4G(kP0H^T%&dI`g1>xZW0p7#!4O+nask{Y$MwtSZ1s*a4{Qd7d#1Q<9yxj0J^Kx#W z{|ngft=A{DF>pO`HUG(s?7ZCY#`8#h1vbyGUIA)}ONEZ5WaJfEtm!;R3HUnb{1kW! zoC7}uX%;z?GnFT_iY(T2-psoBbq1_P0nhw*nE3#83AZYXRiQH*ulu%V32Txe7C5iJ3cH$Jm|?^5P}*VWL` z;gNdQI68Z`J@?#Vae;W|9z*2~%!lVQH!%3z`^~)ItlTxGrwq0mmR_in5u3;#(XiPe ly~FUFX2|~*B_*Y+ce_`Mvz;@Nw*gwu;OXk;vd$@?2>_REK+FID literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/window_minimize@2x.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/window_minimize@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..83b82b6ee6192bdf92ed12ed674086f858516558 GIT binary patch literal 316 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=oCO|{#S9F5M?jcysy3fAQ1G3n zi(^Q|oVV8uy^cDFv_3ReZcIpAx>s62=T5WUfzlf(jE7A$nev6dO>5FSEE~c3$%=cX ziTO68#Su^K4E~4DoBimCNhb@?APC5D`tf>RkX2FUCb`p=xATw7vrDu+-12(Y+$GVT z$Fog~gH&v1-Mnk!oBwsAq{7k?qw}A;mlU@b&HH9}th-R={{Hrjb*rXK`uaaEZqm6k zIpOVR85CQx=i9Lt2D6`Kh`!9TLFe>m#V(7=Rn2J)``%Ap65eli4ybn_-)zRBbMlHU w+MeGh+1buoyT+r+VDsr;+zKC+ksNnayxYute)*9EIgo2TUHx3vIVCg!0F{DysQ>@~ literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/window_minimize_disabled.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/window_minimize_disabled.png new file mode 100644 index 0000000000000000000000000000000000000000..d66d0703980b539279b536ea5d5588bb92f6cc61 GIT binary patch literal 206 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz&H|6fVg?4jBOuH;Rhv&5DA?fX z;usRq`u5UB-ev=lmWTgm$||My^L$`SXcx(p=xnl5R`BvaAT{xZV%^FG3PN)i?p$wu z`%-M8fS};c8E-f5HaF!iJ{Pa>kIiP!*QAeZ?@ZYnbX_XXRnB3!R29>+ug=opj)C;G zDSh+iB}z|d;`?!B{T9}W+|2swZ|WjIBku73Fq7uqw{?v&&@Bv}u6{1-oD!M%>7QrKVk4qRhWIFd($`{yTd< z10DTuPY*4bx_gSri#2n5qlz}0eGl*detG(j89W76a_>#I)=w(QxOncuvJW>eR+-lR zmHYK$<+H=#zv}h%J=uMK%sG;1)UfBA&#Ro{l`>11zxY@=TqxqUU8D0zL2|(jUh_%w zbZ<%A7O~sicQ~ctYt6rDzvl`s{}y&>x98TptCMzTe|}@}kICZ?2P4dt47DFw=Zl!~ T*UZ&71&MjO`njxgN@xNA0q%`D literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/window_minimize_focus.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/window_minimize_focus.png new file mode 100644 index 0000000000000000000000000000000000000000..f533977ed0828714b50bbd4763fbe23f675928e4 GIT binary patch literal 208 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz&H|6fVg?4jBOuH;Rhv&5DA?rb z;usRq`u5UB-a`%|%@6NS7Znf+PHD|?a&$h+@-kAvH7jkw89tuIDQ6tyLLD@OV&6&C z&-M4;)Xi*cy!p_V$x1HPA+yc4o#oaHV=lYy-u#G7#!QxBagfY%?^T*7(PH_RN{CYUa47vg{7oyfQ%7FnGH9xvX=!;V%u7}d)VNu<{Ub-!(w1|~8CRsH zwurVK%1cxKe)-hi7tivN{_X!%6FkTAY!3_24hSe|`de9QKKH(^$g4|}{;p^|dVifg z-v-M)@%c5GPY(7!iOO6bBN$x1dz;1U{d3>hEkB;qu(kVm=xTL-wOrAa;a%A>TCexY zeUICBT(MT~j9PR3_fL~jZguqbU$T&P2xNEVI@{>ko;i*Gg5ggF$L+;00$aSzGpF$i ztbS@deO{M|)=5*o?y^b8ZZf?8`?i1Ax^HLR1}!^p^ft=0bi4M^H1)qs9)CC(VUA^p Z{m6P@l1t~5#Rr2yVxF#kF6*2UngGs{i(vo& literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/window_minimize_pressed.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/window_minimize_pressed.png new file mode 100644 index 0000000000000000000000000000000000000000..ac050a040440ea02a91486f819777bc4aa537e03 GIT binary patch literal 202 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz&H|6fVg?4jBOuH;Rhv&5C|Kj^ z;usRq`u36`Uz3A~>&4&4bp?dV4*T^?Y>E{qOI*0In0MN{V<|DrHCh76PRD&d`+Z-& zbG?Lspy0_fb^hkNt|wkkisw)GXTBigo#_qc6=kvv7w`1Xzx|R^VBhmdKI;Vst01OjIKL7v# literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/window_minimize_pressed@2x.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/window_minimize_pressed@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..b701572b4685b184d2f9445f3d52c84eeeb42ee8 GIT binary patch literal 336 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=oCO|{#S9F5M?jcysy3fA0|O(I zr;B4q#hka-6#bY3MOq(zX7kWk)YNcbBjY5lZw%ZkwEG&4Y-mUmyC7@A!DOMrxg)Pp zc7cZ%CljM@`Y*j{dn5~rJ!kx%{JhVi_)HHA&=v^T;`HNhj^p8zUH(&-`7HWm^RHyB zY{K&|X{&p>CwkU;O81t2HZ;E+yW#20*GE4VSFPdMV7cQ}+t*KqEN^#R`D}bT(pw!p7PVarqc6PUzGIH#8d`PcD~eqE))1JugPl&TPgkE;NDi@$?q<&F>?45 zBRlKm$)yw5M=pD0!>i4_Csuy1e%A*1CElL$dRJ$enqOY~Xw&pMMwPl2m@^p~w*6q5 Wdd?v{r{_OANYK;O&t;ucLK6V)+l9#h literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/window_undock.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/window_undock.png new file mode 100644 index 0000000000000000000000000000000000000000..fab0e72e24850a8ad8d7af3fe9d6454926b0c39d GIT binary patch literal 510 zcmVKcZzGltOSS&dd6b#MU4 z3MA!iBc8MP zj;iQ=uBTE{N~vny{qZ1{43KQc3D7l7vlItFpX7!2 zMhtk`uaxoyzG$<6H-^^=9BMir@g=HBGw@YCHi*Boa9Q&k+E~YPI?p)Od1n za9#J+vaB1DNdTJwj1WOdvI`*BXf&=ue76!l0Z{FM^DegZn*aa+07*qoM6N<$g1!LT AQ~&?~ literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/window_undock@2x.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/window_undock@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..9574d4ab9a0ee9e390abd8c554379f41b3ea92e5 GIT binary patch literal 875 zcmV-x1C;!UP)HN$)24FIb`h)3me`G>C7 zen|`<2!iWT6fFZd+A`QvkeSC)dKw3CerIQA&iDP9TCMgjrCuUke*#iU#mq0zy7)mu zM5CVP)uohoP1cDGKuUQ7K+$C3eKG`K(f9pxrV4ZfAf-G7;IXNK8VnK9lTxWPY(hM4 z1Oxz#6w`%>M#C_?V?sMFfNLfSWq=W1aRL0RTiix`>1>Fc&fLWw`#0sJ{Gzq`A;xUjJBGpTdOR&xgTS|bqA=SrnAp0#e=9PlmcB3Z!9nl zT?Ysu?lbc<69xN)h*Y&&eQ8QR_MM@%wKXmj3eTI(<`#ep-TE13i0p(({RH zu~Ph{00Kw*p~F=TNMBR002ovPDHLkV1jYT Bc;o;8 literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/window_undock_disabled.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/window_undock_disabled.png new file mode 100644 index 0000000000000000000000000000000000000000..a2e164970dfdc13c33365a103d13aa6b6d32f2ba GIT binary patch literal 541 zcmV+&0^!j&bB!18yi3yF(0r%g z-MxF?&+qqp_wEP(yTt3^!|CZ*^!LCjFb9lv=~WeUlbDe&6^obm0^FD%0*Nk-ovKJo zCYun3Thz_Wdue+nhVCU2?fV~Be(lakqS#v@Kk}#!_=!aY`7YPhtsJ!gh*a7jq_Up0VaC^4e z*7an=zpKsyBY$!k3E(gg0FM7cdAI0VbWWM6ETD@vfQav}EA-E>56}k)9ia2B=Oxv3 zGnH{|-9WWD2xSEX-3$|;Ld?jA0ZL>|g|DBt-}#AcSpoUf z3v-|ztq<(^4YmOyjmR=k>(*VAS6}u&p7@Qo4-P-7$3I8o6Ytf~I4}wf2JlsZiYm+H fy{)$a-s_7iJ>Px-gj^~i00000NkvXXu0mjfS%vv( literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/window_undock_disabled@2x.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/window_undock_disabled@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..b6d5c6cb278b87e28b79493e1f26d328a01f2988 GIT binary patch literal 910 zcmV;919AL`P)FUT$nCF;VIeUCt z=X@^Tz571j^WE7w5AS&o;Ns%qWXP^SOQ5^18Y}%o=myXVpxVAITciQZFk>{0+Tk~e z(dA;3Z3S?kz4JKdXoP_VJ33MjkRpwHUrdZWDm2GqRooYh^n&RYfGt)vHh_9&>hbQ{ z^KoHrcG_ryr8A%{6g|PraR8bvdmBeq(>QE&CYTPOCD2`0Lo06q>?n)14T6Bw53b#t ze@!s`3sz&L9~E}+0Kh=Qn)kmj9l+Yvz9KR5ZskARS_Utw(0Q-2AX4-`pPY=@?k()# z4@S7i$2#woaupZD4M4R4)wltuHlP|e0M!Om|7NEZPk0JcgS$%lYB=3GxQ5r1apdnGzSU8h>` zFVGf>3=(h`3Jx9s7-$4(Pko_ipJW}w0Q`aIDP{~v7G5VFVjl7b!iS{_=mOXuIJpzV zH>3($z(b_nJQNPsONi?N(8zNUfJiZ`FwnUAlg>+M>jEI4Q=*Vv7$o9L7r;Nf#4X~> z{DKI3ngx6S$TWc{USxvELW}7Dl8JkE8l8gp16=^J64FI+d@Jk*pxS_H+yGP?P>maa zY6Gfq15j;1HEsZ^4XDNqK(ztYSlJ(-iruAFeAhubf52&Hz)b#tqXJ;YX#SXE0w5rj zM(uF^xKjeilE%G8`-YtmKo&&j3hfuJq`QD={%n?x72GWSKL+r7yL@Kz>d@=)@$bbZ z>z10!aIcl(eR49^RBlnDYrvOs7bz2q5~4m=#a~KD8}; z8pNf8bWmujL-7fmEc6Ln1Q8rfl+Kn81&xAQ9BP~6P}4uQNt3pk!G6Eqz2xLOD2S16;)Yz z&&>fK^f@#TGcPOwDrx^E5wDv=zfDxbp6l|QZN0RUsA$}3Zkr7JjrsshH865?KPC8i z1>lDJqj7D=au#C4XZX~|nam9~Hp(3Xh>1HHY#g=%BSO-88iFAh5OcFvILU14yTQCu zfa(^AiW&xUyp_3QF_vMJ&XG#_Tmt~u>)7}Q#P~yS(P?GJ#-_5u0;o&$8=^=w3hq^M{%t(&vv$eRo> zrM(1D1BGJL0|3r~aa{jL4Aiw>QPExj4EMwewDl}YXHH_P8DOT1UYG+YG2zl_a1B7f zE4vGQhWB4(qa%aQW^(*B5rRgVinId}ROt002ov JPDHLkV1l0u<%IwM literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/window_undock_focus@2x.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/window_undock_focus@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..62de7badaf550a6bb2085ccefe7b0baccc3c98df GIT binary patch literal 877 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=oCO|{#S9F5M?jcysy3fA0|T?X zr;B4q#hkaZY%_ubMUMY}t`?wkRPou*Mp>P0&6Aex*!i2$YKP~+wXA`f9J#?>?&_=6 z#Fjdiym%2LE*Rx_SLV(VPXR~Q_6B)R=BQqg+0`;Ste@lJX5G1SZ`u2Q$7ati{`Y=< z^?U0(G6#}2vPcH;K3Gy5yGh5rqd?Aq$Dw_fj%pa=lNpBkR<64Ygnqv?k38AnVN~ta z@SLG!^^uDnaZPRBo&VCes&%9(Td#bxfx-Uhx7rGZ7h(@wpNFNbxYn{P%;8Dew=DvD zI9Qpt&*);A`!R}>R~lr=pXhz81shZ^ZR@jnE9AcFd`nxsW8^gDjQ#EG4ev_d{=c|^ z@%8fB=toQU&a{=uZWIgNv88=B$D`l#^wl1n+SF{Q26t}HWudT@;NHHOPfKFPcW zx(7_aOyLUVS7J^VXPUEb*jCocsm^gDyu8lnbDSeT^NHq4$Fh=p`mt|+FBHfQ{t=dY z@yaF3q*=)c{dtOVHB*j=dp%}eFZDBMuGfXomDlbt`Dq#RE<4^PC&y65a`|+IQFUax zkU#UBkg^GqldXjFCkY(bJn_n30~m7W}5y>jyGFb&%N?k!ZT4UHjXXldUTxbE~$M2ii*EVI2g6|>SSKj-`cl^ zS2{qVd!>k#X<^=T1`pYVwVXAYIS3CT`4x$I*{8lilkfWOk9S#CUuAZTX59Iz(LwS+ z&(BvI6(lE!&sB=Gz2TSMz$MBlrC0fdmpzd+q@!?S*!~ZG@r?gxEmhAl_kQofY;o#w}YI z%f=yO&hY2r#5Iu|5pEVW{_Z)`8SfuU_CB!f1@Dc9neAPR-R)m@yp3cR3IFxp;Dd+z zAveW@T^5EPT*7PKJH3!P`E=?(M}}mB?XvrXFDEDp&c8Hs$vgXX)xkR%PZkOFOjfY4 wI=W^u`vw8N&~^2aw%;TpS@E^0*-F#j-ky85}Sb4q9e0A90n^8f$< literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/window_undock_pressed.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/window_undock_pressed.png new file mode 100644 index 0000000000000000000000000000000000000000..4ccf8a5400100d632d6bd41708ce37ec0352c514 GIT binary patch literal 523 zcmV+m0`&cfP){4i2J=xJbp+PAYu@7eNY+_7RFhL1RIOB5Lk&C@E>{Z4(>KVE^gn=H&d}J@?*2 zfd4LP^l~VA-eY!&T`qFgZWzT*P`<-vSt|04!$?N?pVU%&`?Va3dg&!&*B2qUk93o$YW4sC N002ovPDHLkV1oPC;6nfa literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/window_undock_pressed@2x.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/rc/window_undock_pressed@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..fba29fc99ad720a150aff2d7d88f9f90d4ba7f20 GIT binary patch literal 880 zcmV-$1CRWPP)5euiWVSpAdjcCj!(%x3{~0oW>UONu1`b4)ZPT3Sc4chCLw znk*GSD3LlYK;r-+GIbP^vB9x?GWx301W|8gE1rr8&`WIGiwA&+0L@s5bhOfhx>i6a zmOdc_W*`yZI#aU2C*4*;%>h{blkNQX_Xhxb8)9w!$k3LygXMcd&A*^sEDWIeE*=0P zE8hR3<^Wc9`=-Rrdp-AXR|CB0!r?twM-k8Gd@k7|-CM{IPNdo6V~6)<*~OJ%0?=(h zHzokx26STr&}~3Bz7L>kBNVmJZ%?R9^@ZiT9l}@ zCOo^gaBunyF~%9#q1uQG^EUWGJ{f&i%a^Kjf{sqL;w@msQ$t`p*L3j!&>=u?!@a3K zl_IVISc!+{nP^a@@EQq#X*iTf9abga2w-<#Y9AAisuHY&fB-!SU3|1nMR7*}%gb~F z3?*U`bcojCH5G;3Zh=!OgybP5zT5)XsBd|d_^SDZ2yx(m3M0UBClk$hNvlw;Ie_d~ zw@jl`5i33cproR-C%$imO#r$L=*9$~+kkFN0J;t6#sr|-fNo3xx((>Y1fbi1Zt6K7 zpo{(0-uSM8rSbv4t$?}m0bd2cL{sHsehMHXT3ScS2b*aRkfCIQV|kZz!+ux+B?5XY zofqEhE1>FO>CG6x>T&tt9~#b0T>j-X+3~8m0nb`he99$zIvZWoZ4bycTBH#$=$neV zZUMYjAtVa{Z&cKE1R(6vEdWIoV)a764+wEjMQuj_-^b(c!Pp3A16E(1ENAzK6n0UQHhsWh`f2EcSM$Tz> + + rc/arrow_down.png + rc/arrow_down@2x.png + rc/arrow_down_disabled.png + rc/arrow_down_disabled@2x.png + rc/arrow_down_focus.png + rc/arrow_down_focus@2x.png + rc/arrow_down_pressed.png + rc/arrow_down_pressed@2x.png + rc/arrow_left.png + rc/arrow_left@2x.png + rc/arrow_left_disabled.png + rc/arrow_left_disabled@2x.png + rc/arrow_left_focus.png + rc/arrow_left_focus@2x.png + rc/arrow_left_pressed.png + rc/arrow_left_pressed@2x.png + rc/arrow_right.png + rc/arrow_right@2x.png + rc/arrow_right_disabled.png + rc/arrow_right_disabled@2x.png + rc/arrow_right_focus.png + rc/arrow_right_focus@2x.png + rc/arrow_right_pressed.png + rc/arrow_right_pressed@2x.png + rc/arrow_up.png + rc/arrow_up@2x.png + rc/arrow_up_disabled.png + rc/arrow_up_disabled@2x.png + rc/arrow_up_focus.png + rc/arrow_up_focus@2x.png + rc/arrow_up_pressed.png + rc/arrow_up_pressed@2x.png + rc/base_icon.png + rc/base_icon@2x.png + rc/base_icon_disabled.png + rc/base_icon_disabled@2x.png + rc/base_icon_focus.png + rc/base_icon_focus@2x.png + rc/base_icon_pressed.png + rc/base_icon_pressed@2x.png + rc/branch_closed.png + rc/branch_closed@2x.png + rc/branch_closed_disabled.png + rc/branch_closed_disabled@2x.png + rc/branch_closed_focus.png + rc/branch_closed_focus@2x.png + rc/branch_closed_pressed.png + rc/branch_closed_pressed@2x.png + rc/branch_end.png + rc/branch_end@2x.png + rc/branch_end_disabled.png + rc/branch_end_disabled@2x.png + rc/branch_end_focus.png + rc/branch_end_focus@2x.png + rc/branch_end_pressed.png + rc/branch_end_pressed@2x.png + rc/branch_line.png + rc/branch_line@2x.png + rc/branch_line_disabled.png + rc/branch_line_disabled@2x.png + rc/branch_line_focus.png + rc/branch_line_focus@2x.png + rc/branch_line_pressed.png + rc/branch_line_pressed@2x.png + rc/branch_more.png + rc/branch_more@2x.png + rc/branch_more_disabled.png + rc/branch_more_disabled@2x.png + rc/branch_more_focus.png + rc/branch_more_focus@2x.png + rc/branch_more_pressed.png + rc/branch_more_pressed@2x.png + rc/branch_open.png + rc/branch_open@2x.png + rc/branch_open_disabled.png + rc/branch_open_disabled@2x.png + rc/branch_open_focus.png + rc/branch_open_focus@2x.png + rc/branch_open_pressed.png + rc/branch_open_pressed@2x.png + rc/checkbox_checked.png + rc/checkbox_checked@2x.png + rc/checkbox_checked_disabled.png + rc/checkbox_checked_disabled@2x.png + rc/checkbox_checked_focus.png + rc/checkbox_checked_focus@2x.png + rc/checkbox_checked_pressed.png + rc/checkbox_checked_pressed@2x.png + rc/checkbox_indeterminate.png + rc/checkbox_indeterminate@2x.png + rc/checkbox_indeterminate_disabled.png + rc/checkbox_indeterminate_disabled@2x.png + rc/checkbox_indeterminate_focus.png + rc/checkbox_indeterminate_focus@2x.png + rc/checkbox_indeterminate_pressed.png + rc/checkbox_indeterminate_pressed@2x.png + rc/checkbox_unchecked.png + rc/checkbox_unchecked@2x.png + rc/checkbox_unchecked_disabled.png + rc/checkbox_unchecked_disabled@2x.png + rc/checkbox_unchecked_focus.png + rc/checkbox_unchecked_focus@2x.png + rc/checkbox_unchecked_pressed.png + rc/checkbox_unchecked_pressed@2x.png + rc/line_horizontal.png + rc/line_horizontal@2x.png + rc/line_horizontal_disabled.png + rc/line_horizontal_disabled@2x.png + rc/line_horizontal_focus.png + rc/line_horizontal_focus@2x.png + rc/line_horizontal_pressed.png + rc/line_horizontal_pressed@2x.png + rc/line_vertical.png + rc/line_vertical@2x.png + rc/line_vertical_disabled.png + rc/line_vertical_disabled@2x.png + rc/line_vertical_focus.png + rc/line_vertical_focus@2x.png + rc/line_vertical_pressed.png + rc/line_vertical_pressed@2x.png + rc/radio_checked.png + rc/radio_checked@2x.png + rc/radio_checked_disabled.png + rc/radio_checked_disabled@2x.png + rc/radio_checked_focus.png + rc/radio_checked_focus@2x.png + rc/radio_checked_pressed.png + rc/radio_checked_pressed@2x.png + rc/radio_unchecked.png + rc/radio_unchecked@2x.png + rc/radio_unchecked_disabled.png + rc/radio_unchecked_disabled@2x.png + rc/radio_unchecked_focus.png + rc/radio_unchecked_focus@2x.png + rc/radio_unchecked_pressed.png + rc/radio_unchecked_pressed@2x.png + rc/toolbar_move_horizontal.png + rc/toolbar_move_horizontal@2x.png + rc/toolbar_move_horizontal_disabled.png + rc/toolbar_move_horizontal_disabled@2x.png + rc/toolbar_move_horizontal_focus.png + rc/toolbar_move_horizontal_focus@2x.png + rc/toolbar_move_horizontal_pressed.png + rc/toolbar_move_horizontal_pressed@2x.png + rc/toolbar_move_vertical.png + rc/toolbar_move_vertical@2x.png + rc/toolbar_move_vertical_disabled.png + rc/toolbar_move_vertical_disabled@2x.png + rc/toolbar_move_vertical_focus.png + rc/toolbar_move_vertical_focus@2x.png + rc/toolbar_move_vertical_pressed.png + rc/toolbar_move_vertical_pressed@2x.png + rc/toolbar_separator_horizontal.png + rc/toolbar_separator_horizontal@2x.png + rc/toolbar_separator_horizontal_disabled.png + rc/toolbar_separator_horizontal_disabled@2x.png + rc/toolbar_separator_horizontal_focus.png + rc/toolbar_separator_horizontal_focus@2x.png + rc/toolbar_separator_horizontal_pressed.png + rc/toolbar_separator_horizontal_pressed@2x.png + rc/toolbar_separator_vertical.png + rc/toolbar_separator_vertical@2x.png + rc/toolbar_separator_vertical_disabled.png + rc/toolbar_separator_vertical_disabled@2x.png + rc/toolbar_separator_vertical_focus.png + rc/toolbar_separator_vertical_focus@2x.png + rc/toolbar_separator_vertical_pressed.png + rc/toolbar_separator_vertical_pressed@2x.png + rc/transparent.png + rc/transparent@2x.png + rc/transparent_disabled.png + rc/transparent_disabled@2x.png + rc/transparent_focus.png + rc/transparent_focus@2x.png + rc/transparent_pressed.png + rc/transparent_pressed@2x.png + rc/window_close.png + rc/window_close@2x.png + rc/window_close_disabled.png + rc/window_close_disabled@2x.png + rc/window_close_focus.png + rc/window_close_focus@2x.png + rc/window_close_pressed.png + rc/window_close_pressed@2x.png + rc/window_grip.png + rc/window_grip@2x.png + rc/window_grip_disabled.png + rc/window_grip_disabled@2x.png + rc/window_grip_focus.png + rc/window_grip_focus@2x.png + rc/window_grip_pressed.png + rc/window_grip_pressed@2x.png + rc/window_minimize.png + rc/window_minimize@2x.png + rc/window_minimize_disabled.png + rc/window_minimize_disabled@2x.png + rc/window_minimize_focus.png + rc/window_minimize_focus@2x.png + rc/window_minimize_pressed.png + rc/window_minimize_pressed@2x.png + rc/window_undock.png + rc/window_undock@2x.png + rc/window_undock_disabled.png + rc/window_undock_disabled@2x.png + rc/window_undock_focus.png + rc/window_undock_focus@2x.png + rc/window_undock_pressed.png + rc/window_undock_pressed@2x.png + + + style.qss + + diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/style.qrc.depends b/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/style.qrc.depends new file mode 100644 index 0000000..e301854 --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/style.qrc.depends @@ -0,0 +1,216 @@ + + + + rc/arrow_down.png + rc/arrow_down@2x.png + rc/arrow_down_disabled.png + rc/arrow_down_disabled@2x.png + rc/arrow_down_focus.png + rc/arrow_down_focus@2x.png + rc/arrow_down_pressed.png + rc/arrow_down_pressed@2x.png + rc/arrow_left.png + rc/arrow_left@2x.png + rc/arrow_left_disabled.png + rc/arrow_left_disabled@2x.png + rc/arrow_left_focus.png + rc/arrow_left_focus@2x.png + rc/arrow_left_pressed.png + rc/arrow_left_pressed@2x.png + rc/arrow_right.png + rc/arrow_right@2x.png + rc/arrow_right_disabled.png + rc/arrow_right_disabled@2x.png + rc/arrow_right_focus.png + rc/arrow_right_focus@2x.png + rc/arrow_right_pressed.png + rc/arrow_right_pressed@2x.png + rc/arrow_up.png + rc/arrow_up@2x.png + rc/arrow_up_disabled.png + rc/arrow_up_disabled@2x.png + rc/arrow_up_focus.png + rc/arrow_up_focus@2x.png + rc/arrow_up_pressed.png + rc/arrow_up_pressed@2x.png + rc/base_icon.png + rc/base_icon@2x.png + rc/base_icon_disabled.png + rc/base_icon_disabled@2x.png + rc/base_icon_focus.png + rc/base_icon_focus@2x.png + rc/base_icon_pressed.png + rc/base_icon_pressed@2x.png + rc/branch_closed.png + rc/branch_closed@2x.png + rc/branch_closed_disabled.png + rc/branch_closed_disabled@2x.png + rc/branch_closed_focus.png + rc/branch_closed_focus@2x.png + rc/branch_closed_pressed.png + rc/branch_closed_pressed@2x.png + rc/branch_end.png + rc/branch_end@2x.png + rc/branch_end_disabled.png + rc/branch_end_disabled@2x.png + rc/branch_end_focus.png + rc/branch_end_focus@2x.png + rc/branch_end_pressed.png + rc/branch_end_pressed@2x.png + rc/branch_line.png + rc/branch_line@2x.png + rc/branch_line_disabled.png + rc/branch_line_disabled@2x.png + rc/branch_line_focus.png + rc/branch_line_focus@2x.png + rc/branch_line_pressed.png + rc/branch_line_pressed@2x.png + rc/branch_more.png + rc/branch_more@2x.png + rc/branch_more_disabled.png + rc/branch_more_disabled@2x.png + rc/branch_more_focus.png + rc/branch_more_focus@2x.png + rc/branch_more_pressed.png + rc/branch_more_pressed@2x.png + rc/branch_open.png + rc/branch_open@2x.png + rc/branch_open_disabled.png + rc/branch_open_disabled@2x.png + rc/branch_open_focus.png + rc/branch_open_focus@2x.png + rc/branch_open_pressed.png + rc/branch_open_pressed@2x.png + rc/checkbox_checked.png + rc/checkbox_checked@2x.png + rc/checkbox_checked_disabled.png + rc/checkbox_checked_disabled@2x.png + rc/checkbox_checked_focus.png + rc/checkbox_checked_focus@2x.png + rc/checkbox_checked_pressed.png + rc/checkbox_checked_pressed@2x.png + rc/checkbox_indeterminate.png + rc/checkbox_indeterminate@2x.png + rc/checkbox_indeterminate_disabled.png + rc/checkbox_indeterminate_disabled@2x.png + rc/checkbox_indeterminate_focus.png + rc/checkbox_indeterminate_focus@2x.png + rc/checkbox_indeterminate_pressed.png + rc/checkbox_indeterminate_pressed@2x.png + rc/checkbox_unchecked.png + rc/checkbox_unchecked@2x.png + rc/checkbox_unchecked_disabled.png + rc/checkbox_unchecked_disabled@2x.png + rc/checkbox_unchecked_focus.png + rc/checkbox_unchecked_focus@2x.png + rc/checkbox_unchecked_pressed.png + rc/checkbox_unchecked_pressed@2x.png + rc/line_horizontal.png + rc/line_horizontal@2x.png + rc/line_horizontal_disabled.png + rc/line_horizontal_disabled@2x.png + rc/line_horizontal_focus.png + rc/line_horizontal_focus@2x.png + rc/line_horizontal_pressed.png + rc/line_horizontal_pressed@2x.png + rc/line_vertical.png + rc/line_vertical@2x.png + rc/line_vertical_disabled.png + rc/line_vertical_disabled@2x.png + rc/line_vertical_focus.png + rc/line_vertical_focus@2x.png + rc/line_vertical_pressed.png + rc/line_vertical_pressed@2x.png + rc/radio_checked.png + rc/radio_checked@2x.png + rc/radio_checked_disabled.png + rc/radio_checked_disabled@2x.png + rc/radio_checked_focus.png + rc/radio_checked_focus@2x.png + rc/radio_checked_pressed.png + rc/radio_checked_pressed@2x.png + rc/radio_unchecked.png + rc/radio_unchecked@2x.png + rc/radio_unchecked_disabled.png + rc/radio_unchecked_disabled@2x.png + rc/radio_unchecked_focus.png + rc/radio_unchecked_focus@2x.png + rc/radio_unchecked_pressed.png + rc/radio_unchecked_pressed@2x.png + rc/toolbar_move_horizontal.png + rc/toolbar_move_horizontal@2x.png + rc/toolbar_move_horizontal_disabled.png + rc/toolbar_move_horizontal_disabled@2x.png + rc/toolbar_move_horizontal_focus.png + rc/toolbar_move_horizontal_focus@2x.png + rc/toolbar_move_horizontal_pressed.png + rc/toolbar_move_horizontal_pressed@2x.png + rc/toolbar_move_vertical.png + rc/toolbar_move_vertical@2x.png + rc/toolbar_move_vertical_disabled.png + rc/toolbar_move_vertical_disabled@2x.png + rc/toolbar_move_vertical_focus.png + rc/toolbar_move_vertical_focus@2x.png + rc/toolbar_move_vertical_pressed.png + rc/toolbar_move_vertical_pressed@2x.png + rc/toolbar_separator_horizontal.png + rc/toolbar_separator_horizontal@2x.png + rc/toolbar_separator_horizontal_disabled.png + rc/toolbar_separator_horizontal_disabled@2x.png + rc/toolbar_separator_horizontal_focus.png + rc/toolbar_separator_horizontal_focus@2x.png + rc/toolbar_separator_horizontal_pressed.png + rc/toolbar_separator_horizontal_pressed@2x.png + rc/toolbar_separator_vertical.png + rc/toolbar_separator_vertical@2x.png + rc/toolbar_separator_vertical_disabled.png + rc/toolbar_separator_vertical_disabled@2x.png + rc/toolbar_separator_vertical_focus.png + rc/toolbar_separator_vertical_focus@2x.png + rc/toolbar_separator_vertical_pressed.png + rc/toolbar_separator_vertical_pressed@2x.png + rc/transparent.png + rc/transparent@2x.png + rc/transparent_disabled.png + rc/transparent_disabled@2x.png + rc/transparent_focus.png + rc/transparent_focus@2x.png + rc/transparent_pressed.png + rc/transparent_pressed@2x.png + rc/window_close.png + rc/window_close@2x.png + rc/window_close_disabled.png + rc/window_close_disabled@2x.png + rc/window_close_focus.png + rc/window_close_focus@2x.png + rc/window_close_pressed.png + rc/window_close_pressed@2x.png + rc/window_grip.png + rc/window_grip@2x.png + rc/window_grip_disabled.png + rc/window_grip_disabled@2x.png + rc/window_grip_focus.png + rc/window_grip_focus@2x.png + rc/window_grip_pressed.png + rc/window_grip_pressed@2x.png + rc/window_minimize.png + rc/window_minimize@2x.png + rc/window_minimize_disabled.png + rc/window_minimize_disabled@2x.png + rc/window_minimize_focus.png + rc/window_minimize_focus@2x.png + rc/window_minimize_pressed.png + rc/window_minimize_pressed@2x.png + rc/window_undock.png + rc/window_undock@2x.png + rc/window_undock_disabled.png + rc/window_undock_disabled@2x.png + rc/window_undock_focus.png + rc/window_undock_focus@2x.png + rc/window_undock_pressed.png + rc/window_undock_pressed@2x.png + + + style.qss + + diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/style.qss b/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/style.qss new file mode 100644 index 0000000..55dfe09 --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/qdarkstyle/style.qss @@ -0,0 +1,2165 @@ +/* --------------------------------------------------------------------------- + + Created by the qtsass compiler v0.1.1 + + The definitions are in the "qdarkstyle.qss._styles.scss" module + + WARNING! All changes made in this file will be lost! + +--------------------------------------------------------------------------- */ +/* QDarkStyleSheet ----------------------------------------------------------- + +This is the main style sheet, the palette has nine colors. + +It is based on three selecting colors, three greyish (background) colors +plus three whitish (foreground) colors. Each set of widgets of the same +type have a header like this: + + ------------------ + GroupName -------- + ------------------ + +And each widget is separated with a header like this: + + QWidgetName ------ + +This makes more easy to find and change some css field. The basic +configuration is described bellow. + + BACKGROUND ----------- + + Light (unpressed) + Normal (border, disabled, pressed, checked, toolbars, menus) + Dark (background) + + FOREGROUND ----------- + + Light (texts/labels) + Normal (not used yet) + Dark (disabled texts) + + SELECTION ------------ + + Light (selection/hover/active) + Normal (selected) + Dark (selected disabled) + +If a stranger configuration is required because of a bugfix or anything +else, keep the comment on the line above so nobody changes it, including the +issue number. + +*/ +/* + +See Qt documentation: + + - https://doc.qt.io/qt-5/stylesheet.html + - https://doc.qt.io/qt-5/stylesheet-reference.html + - https://doc.qt.io/qt-5/stylesheet-examples.html + +--------------------------------------------------------------------------- */ +/* QWidget ---------------------------------------------------------------- + +--------------------------------------------------------------------------- */ +QWidget { + background-color: #19232D; + border: 0px solid #32414B; + padding: 0px; + color: #F0F0F0; + selection-background-color: #1464A0; + selection-color: #F0F0F0; +} + +QWidget:disabled { + background-color: #19232D; + color: #787878; + selection-background-color: #14506E; + selection-color: #787878; +} + +QWidget::item:selected { + background-color: #1464A0; +} + +QWidget::item:hover { + background-color: #148CD2; + color: #32414B; +} + +/* QMainWindow ------------------------------------------------------------ + +This adjusts the splitter in the dock widget, not qsplitter +https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qmainwindow + +--------------------------------------------------------------------------- */ +QMainWindow::separator { + background-color: #32414B; + border: 0px solid #19232D; + spacing: 0px; + padding: 2px; +} + +QMainWindow::separator:hover { + background-color: #505F69; + border: 0px solid #148CD2; +} + +QMainWindow::separator:horizontal { + width: 5px; + margin-top: 2px; + margin-bottom: 2px; + image: url(":/qss_icons/rc/toolbar_separator_vertical.png"); +} + +QMainWindow::separator:vertical { + height: 5px; + margin-left: 2px; + margin-right: 2px; + image: url(":/qss_icons/rc/toolbar_separator_horizontal.png"); +} + +/* QToolTip --------------------------------------------------------------- + +https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qtooltip + +--------------------------------------------------------------------------- */ +QToolTip { + background-color: #148CD2; + border: 1px solid #19232D; + color: #19232D; + /* Remove padding, for fix combo box tooltip */ + padding: 0px; + /* Remove opacity, fix #174 - may need to use RGBA */ +} + +/* QStatusBar ------------------------------------------------------------- + +https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qstatusbar + +--------------------------------------------------------------------------- */ +QStatusBar { + border: 1px solid #32414B; + /* Fixes Spyder #9120, #9121 */ + background: #32414B; + /* Fixes #205, white vertical borders separating items */ +} + +QStatusBar::item { + border: none; +} + +QStatusBar QToolTip { + background-color: #148CD2; + border: 1px solid #19232D; + color: #19232D; + /* Remove padding, for fix combo box tooltip */ + padding: 0px; + /* Reducing transparency to read better */ + opacity: 230; +} + +QStatusBar QLabel { + /* Fixes Spyder #9120, #9121 */ + background: transparent; +} + +/* QCheckBox -------------------------------------------------------------- + +https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qcheckbox + +--------------------------------------------------------------------------- */ +QCheckBox { + background-color: #19232D; + color: #F0F0F0; + spacing: 4px; + outline: none; + padding-top: 4px; + padding-bottom: 4px; +} + +QCheckBox:focus { + border: none; +} + +QCheckBox QWidget:disabled { + background-color: #19232D; + color: #787878; +} + +QCheckBox::indicator { + margin-left: 4px; + height: 16px; + width: 16px; +} + +QCheckBox::indicator:unchecked { + image: url(":/qss_icons/rc/checkbox_unchecked.png"); +} + +QCheckBox::indicator:unchecked:hover, QCheckBox::indicator:unchecked:focus, QCheckBox::indicator:unchecked:pressed { + border: none; + image: url(":/qss_icons/rc/checkbox_unchecked_focus.png"); +} + +QCheckBox::indicator:unchecked:disabled { + image: url(":/qss_icons/rc/checkbox_unchecked_disabled.png"); +} + +QCheckBox::indicator:checked { + image: url(":/qss_icons/rc/checkbox_checked.png"); +} + +QCheckBox::indicator:checked:hover, QCheckBox::indicator:checked:focus, QCheckBox::indicator:checked:pressed { + border: none; + image: url(":/qss_icons/rc/checkbox_checked_focus.png"); +} + +QCheckBox::indicator:checked:disabled { + image: url(":/qss_icons/rc/checkbox_checked_disabled.png"); +} + +QCheckBox::indicator:indeterminate { + image: url(":/qss_icons/rc/checkbox_indeterminate.png"); +} + +QCheckBox::indicator:indeterminate:disabled { + image: url(":/qss_icons/rc/checkbox_indeterminate_disabled.png"); +} + +QCheckBox::indicator:indeterminate:focus, QCheckBox::indicator:indeterminate:hover, QCheckBox::indicator:indeterminate:pressed { + image: url(":/qss_icons/rc/checkbox_indeterminate_focus.png"); +} + +/* QGroupBox -------------------------------------------------------------- + +https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qgroupbox + +--------------------------------------------------------------------------- */ +QGroupBox { + font-weight: bold; + border: 1px solid #32414B; + border-radius: 4px; + padding: 4px; + margin-top: 16px; +} + +QGroupBox::title { + subcontrol-origin: margin; + subcontrol-position: top left; + left: 3px; + padding-left: 3px; + padding-right: 5px; + padding-top: 8px; + padding-bottom: 16px; +} + +QGroupBox::indicator { + margin-left: 2px; + height: 12px; + width: 12px; +} + +QGroupBox::indicator:unchecked:hover, QGroupBox::indicator:unchecked:focus, QGroupBox::indicator:unchecked:pressed { + border: none; + image: url(":/qss_icons/rc/checkbox_unchecked_focus.png"); +} + +QGroupBox::indicator:unchecked:disabled { + image: url(":/qss_icons/rc/checkbox_unchecked_disabled.png"); +} + +QGroupBox::indicator:checked:hover, QGroupBox::indicator:checked:focus, QGroupBox::indicator:checked:pressed { + border: none; + image: url(":/qss_icons/rc/checkbox_checked_focus.png"); +} + +QGroupBox::indicator:checked:disabled { + image: url(":/qss_icons/rc/checkbox_checked_disabled.png"); +} + +/* QRadioButton ----------------------------------------------------------- + +https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qradiobutton + +--------------------------------------------------------------------------- */ +QRadioButton { + background-color: #19232D; + color: #F0F0F0; + spacing: 4px; + padding: 0px; + border: none; + outline: none; +} + +QRadioButton:focus { + border: none; +} + +QRadioButton:disabled { + background-color: #19232D; + color: #787878; + border: none; + outline: none; +} + +QRadioButton QWidget { + background-color: #19232D; + color: #F0F0F0; + spacing: 0px; + padding: 0px; + outline: none; + border: none; +} + +QRadioButton::indicator { + border: none; + outline: none; + margin-left: 4px; + height: 16px; + width: 16px; +} + +QRadioButton::indicator:unchecked { + image: url(":/qss_icons/rc/radio_unchecked.png"); +} + +QRadioButton::indicator:unchecked:hover, QRadioButton::indicator:unchecked:focus, QRadioButton::indicator:unchecked:pressed { + border: none; + outline: none; + image: url(":/qss_icons/rc/radio_unchecked_focus.png"); +} + +QRadioButton::indicator:unchecked:disabled { + image: url(":/qss_icons/rc/radio_unchecked_disabled.png"); +} + +QRadioButton::indicator:checked { + border: none; + outline: none; + image: url(":/qss_icons/rc/radio_checked.png"); +} + +QRadioButton::indicator:checked:hover, QRadioButton::indicator:checked:focus, QRadioButton::indicator:checked:pressed { + border: none; + outline: none; + image: url(":/qss_icons/rc/radio_checked_focus.png"); +} + +QRadioButton::indicator:checked:disabled { + outline: none; + image: url(":/qss_icons/rc/radio_checked_disabled.png"); +} + +/* QMenuBar --------------------------------------------------------------- + +https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qmenubar + +--------------------------------------------------------------------------- */ +QMenuBar { + background-color: #32414B; + padding: 2px; + border: 1px solid #19232D; + color: #F0F0F0; +} + +QMenuBar:focus { + border: 1px solid #148CD2; +} + +QMenuBar::item { + background: transparent; + padding: 4px; +} + +QMenuBar::item:selected { + padding: 4px; + background: transparent; + border: 0px solid #32414B; +} + +QMenuBar::item:pressed { + padding: 4px; + border: 0px solid #32414B; + background-color: #148CD2; + color: #F0F0F0; + margin-bottom: 0px; + padding-bottom: 0px; +} + +/* QMenu ------------------------------------------------------------------ + +https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qmenu + +--------------------------------------------------------------------------- */ +QMenu { + border: 0px solid #32414B; + color: #F0F0F0; + margin: 0px; +} + +QMenu::separator { + height: 1px; + background-color: #505F69; + color: #F0F0F0; +} + +QMenu::icon { + margin: 0px; + padding-left: 8px; +} + +QMenu::item { + background-color: #32414B; + padding: 4px 24px 4px 24px; + /* Reserve space for selection border */ + border: 1px transparent #32414B; +} + +QMenu::item:selected { + color: #F0F0F0; +} + +QMenu::indicator { + width: 12px; + height: 12px; + padding-left: 6px; + /* non-exclusive indicator = check box style indicator (see QActionGroup::setExclusive) */ + /* exclusive indicator = radio button style indicator (see QActionGroup::setExclusive) */ +} + +QMenu::indicator:non-exclusive:unchecked { + image: url(":/qss_icons/rc/checkbox_unchecked.png"); +} + +QMenu::indicator:non-exclusive:unchecked:selected { + image: url(":/qss_icons/rc/checkbox_unchecked_disabled.png"); +} + +QMenu::indicator:non-exclusive:checked { + image: url(":/qss_icons/rc/checkbox_checked.png"); +} + +QMenu::indicator:non-exclusive:checked:selected { + image: url(":/qss_icons/rc/checkbox_checked_disabled.png"); +} + +QMenu::indicator:exclusive:unchecked { + image: url(":/qss_icons/rc/radio_unchecked.png"); +} + +QMenu::indicator:exclusive:unchecked:selected { + image: url(":/qss_icons/rc/radio_unchecked_disabled.png"); +} + +QMenu::indicator:exclusive:checked { + image: url(":/qss_icons/rc/radio_checked.png"); +} + +QMenu::indicator:exclusive:checked:selected { + image: url(":/qss_icons/rc/radio_checked_disabled.png"); +} + +QMenu::right-arrow { + margin: 5px; + image: url(":/qss_icons/rc/arrow_right.png"); + height: 12px; + width: 12px; +} + +/* QAbstractItemView ------------------------------------------------------ + +https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qcombobox + +--------------------------------------------------------------------------- */ +QAbstractItemView { + alternate-background-color: #19232D; + color: #F0F0F0; + border: 1px solid #32414B; + border-radius: 4px; +} + +QAbstractItemView QLineEdit { + padding: 2px; +} + +/* QAbstractScrollArea ---------------------------------------------------- + +https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qabstractscrollarea + +--------------------------------------------------------------------------- */ +QAbstractScrollArea { + background-color: #19232D; + border: 1px solid #32414B; + border-radius: 4px; + padding: 2px; + /* fix #159 */ + min-height: 1.25em; + /* fix #159 */ + color: #F0F0F0; +} + +QAbstractScrollArea:disabled { + color: #787878; +} + +/* QScrollArea ------------------------------------------------------------ + +--------------------------------------------------------------------------- */ +QScrollArea QWidget QWidget:disabled { + background-color: #19232D; +} + +/* QScrollBar ------------------------------------------------------------- + +https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qscrollbar + +--------------------------------------------------------------------------- */ +QScrollBar:horizontal { + height: 16px; + margin: 2px 16px 2px 16px; + border: 1px solid #32414B; + border-radius: 4px; + background-color: #19232D; +} + +QScrollBar:vertical { + background-color: #19232D; + width: 16px; + margin: 16px 2px 16px 2px; + border: 1px solid #32414B; + border-radius: 4px; +} + +QScrollBar::handle:horizontal { + background-color: #787878; + border: 1px solid #32414B; + border-radius: 4px; + min-width: 8px; +} + +QScrollBar::handle:horizontal:hover { + background-color: #148CD2; + border: 1px solid #148CD2; + border-radius: 4px; + min-width: 8px; +} + +QScrollBar::handle:horizontal:focus { + border: 1px solid #1464A0; +} + +QScrollBar::handle:vertical { + background-color: #787878; + border: 1px solid #32414B; + min-height: 8px; + border-radius: 4px; +} + +QScrollBar::handle:vertical:hover { + background-color: #148CD2; + border: 1px solid #148CD2; + border-radius: 4px; + min-height: 8px; +} + +QScrollBar::handle:vertical:focus { + border: 1px solid #1464A0; +} + +QScrollBar::add-line:horizontal { + margin: 0px 0px 0px 0px; + border-image: url(":/qss_icons/rc/arrow_right_disabled.png"); + height: 12px; + width: 12px; + subcontrol-position: right; + subcontrol-origin: margin; +} + +QScrollBar::add-line:horizontal:hover, QScrollBar::add-line:horizontal:on { + border-image: url(":/qss_icons/rc/arrow_right.png"); + height: 12px; + width: 12px; + subcontrol-position: right; + subcontrol-origin: margin; +} + +QScrollBar::add-line:vertical { + margin: 3px 0px 3px 0px; + border-image: url(":/qss_icons/rc/arrow_down_disabled.png"); + height: 12px; + width: 12px; + subcontrol-position: bottom; + subcontrol-origin: margin; +} + +QScrollBar::add-line:vertical:hover, QScrollBar::add-line:vertical:on { + border-image: url(":/qss_icons/rc/arrow_down.png"); + height: 12px; + width: 12px; + subcontrol-position: bottom; + subcontrol-origin: margin; +} + +QScrollBar::sub-line:horizontal { + margin: 0px 3px 0px 3px; + border-image: url(":/qss_icons/rc/arrow_left_disabled.png"); + height: 12px; + width: 12px; + subcontrol-position: left; + subcontrol-origin: margin; +} + +QScrollBar::sub-line:horizontal:hover, QScrollBar::sub-line:horizontal:on { + border-image: url(":/qss_icons/rc/arrow_left.png"); + height: 12px; + width: 12px; + subcontrol-position: left; + subcontrol-origin: margin; +} + +QScrollBar::sub-line:vertical { + margin: 3px 0px 3px 0px; + border-image: url(":/qss_icons/rc/arrow_up_disabled.png"); + height: 12px; + width: 12px; + subcontrol-position: top; + subcontrol-origin: margin; +} + +QScrollBar::sub-line:vertical:hover, QScrollBar::sub-line:vertical:on { + border-image: url(":/qss_icons/rc/arrow_up.png"); + height: 12px; + width: 12px; + subcontrol-position: top; + subcontrol-origin: margin; +} + +QScrollBar::up-arrow:horizontal, QScrollBar::down-arrow:horizontal { + background: none; +} + +QScrollBar::up-arrow:vertical, QScrollBar::down-arrow:vertical { + background: none; +} + +QScrollBar::add-page:horizontal, QScrollBar::sub-page:horizontal { + background: none; +} + +QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical { + background: none; +} + +/* QTextEdit -------------------------------------------------------------- + +https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-specific-widgets + +--------------------------------------------------------------------------- */ +QTextEdit { + background-color: #19232D; + color: #F0F0F0; + border-radius: 4px; + border: 1px solid #32414B; +} + +QTextEdit:hover { + border: 1px solid #148CD2; + color: #F0F0F0; +} + +QTextEdit:focus { + border: 1px solid #1464A0; +} + +QTextEdit:selected { + background: #1464A0; + color: #32414B; +} + +/* QPlainTextEdit --------------------------------------------------------- + +--------------------------------------------------------------------------- */ +QPlainTextEdit { + background-color: #19232D; + color: #F0F0F0; + border-radius: 4px; + border: 1px solid #32414B; +} + +QPlainTextEdit:hover { + border: 1px solid #148CD2; + color: #F0F0F0; +} + +QPlainTextEdit:focus { + border: 1px solid #1464A0; +} + +QPlainTextEdit:selected { + background: #1464A0; + color: #32414B; +} + +/* QSizeGrip -------------------------------------------------------------- + +https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qsizegrip + +--------------------------------------------------------------------------- */ +QSizeGrip { + background: transparent; + width: 12px; + height: 12px; + image: url(":/qss_icons/rc/window_grip.png"); +} + +/* QStackedWidget --------------------------------------------------------- + +--------------------------------------------------------------------------- */ +QStackedWidget { + padding: 2px; + border: 1px solid #32414B; + border: 1px solid #19232D; +} + +/* QToolBar --------------------------------------------------------------- + +https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qtoolbar + +--------------------------------------------------------------------------- */ +QToolBar { + background-color: #32414B; + border-bottom: 1px solid #19232D; + padding: 2px; + font-weight: bold; + spacing: 2px; +} + +QToolBar QToolButton { + background-color: #32414B; + border: 1px solid #32414B; +} + +QToolBar QToolButton:hover { + border: 1px solid #148CD2; +} + +QToolBar QToolButton:checked { + border: 1px solid #19232D; + background-color: #19232D; +} + +QToolBar QToolButton:checked:hover { + border: 1px solid #148CD2; +} + +QToolBar::handle:horizontal { + width: 16px; + image: url(":/qss_icons/rc/toolbar_move_horizontal.png"); +} + +QToolBar::handle:vertical { + height: 16px; + image: url(":/qss_icons/rc/toolbar_move_vertical.png"); +} + +QToolBar::separator:horizontal { + width: 16px; + image: url(":/qss_icons/rc/toolbar_separator_horizontal.png"); +} + +QToolBar::separator:vertical { + height: 16px; + image: url(":/qss_icons/rc/toolbar_separator_vertical.png"); +} + +QToolButton#qt_toolbar_ext_button { + background: #32414B; + border: 0px; + color: #F0F0F0; + image: url(":/qss_icons/rc/arrow_right.png"); +} + +/* QAbstractSpinBox ------------------------------------------------------- + +--------------------------------------------------------------------------- */ +QAbstractSpinBox { + background-color: #19232D; + border: 1px solid #32414B; + color: #F0F0F0; + /* This fixes 103, 111 */ + padding-top: 2px; + /* This fixes 103, 111 */ + padding-bottom: 2px; + padding-left: 4px; + padding-right: 4px; + border-radius: 4px; + /* min-width: 5px; removed to fix 109 */ +} + +QAbstractSpinBox:up-button { + background-color: transparent #19232D; + subcontrol-origin: border; + subcontrol-position: top right; + border-left: 1px solid #32414B; + border-bottom: 1px solid #32414B; + border-top-left-radius: 0; + border-bottom-left-radius: 0; + margin: 1px; + width: 12px; + margin-bottom: -1px; +} + +QAbstractSpinBox::up-arrow, QAbstractSpinBox::up-arrow:disabled, QAbstractSpinBox::up-arrow:off { + image: url(":/qss_icons/rc/arrow_up_disabled.png"); + height: 8px; + width: 8px; +} + +QAbstractSpinBox::up-arrow:hover { + image: url(":/qss_icons/rc/arrow_up.png"); +} + +QAbstractSpinBox:down-button { + background-color: transparent #19232D; + subcontrol-origin: border; + subcontrol-position: bottom right; + border-left: 1px solid #32414B; + border-top: 1px solid #32414B; + border-top-left-radius: 0; + border-bottom-left-radius: 0; + margin: 1px; + width: 12px; + margin-top: -1px; +} + +QAbstractSpinBox::down-arrow, QAbstractSpinBox::down-arrow:disabled, QAbstractSpinBox::down-arrow:off { + image: url(":/qss_icons/rc/arrow_down_disabled.png"); + height: 8px; + width: 8px; +} + +QAbstractSpinBox::down-arrow:hover { + image: url(":/qss_icons/rc/arrow_down.png"); +} + +QAbstractSpinBox:hover { + border: 1px solid #148CD2; + color: #F0F0F0; +} + +QAbstractSpinBox:focus { + border: 1px solid #1464A0; +} + +QAbstractSpinBox:selected { + background: #1464A0; + color: #32414B; +} + +/* ------------------------------------------------------------------------ */ +/* DISPLAYS --------------------------------------------------------------- */ +/* ------------------------------------------------------------------------ */ +/* QLabel ----------------------------------------------------------------- + +https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qframe + +--------------------------------------------------------------------------- */ +QLabel { + background-color: #19232D; + border: 0px solid #32414B; + padding: 2px; + margin: 0px; + color: #F0F0F0; +} + +QLabel:disabled { + background-color: #19232D; + border: 0px solid #32414B; + color: #787878; +} + +/* QTextBrowser ----------------------------------------------------------- + +https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qabstractscrollarea + +--------------------------------------------------------------------------- */ +QTextBrowser { + background-color: #19232D; + border: 1px solid #32414B; + color: #F0F0F0; + border-radius: 4px; +} + +QTextBrowser:disabled { + background-color: #19232D; + border: 1px solid #32414B; + color: #787878; + border-radius: 4px; +} + +QTextBrowser:hover, QTextBrowser:!hover, QTextBrowser:selected, QTextBrowser:pressed { + border: 1px solid #32414B; +} + +/* QGraphicsView ---------------------------------------------------------- + +--------------------------------------------------------------------------- */ +QGraphicsView { + background-color: #19232D; + border: 1px solid #32414B; + color: #F0F0F0; + border-radius: 4px; +} + +QGraphicsView:disabled { + background-color: #19232D; + border: 1px solid #32414B; + color: #787878; + border-radius: 4px; +} + +QGraphicsView:hover, QGraphicsView:!hover, QGraphicsView:selected, QGraphicsView:pressed { + border: 1px solid #32414B; +} + +/* QCalendarWidget -------------------------------------------------------- + +--------------------------------------------------------------------------- */ +QCalendarWidget { + border: 1px solid #32414B; + border-radius: 4px; +} + +QCalendarWidget:disabled { + background-color: #19232D; + color: #787878; +} + +/* QLCDNumber ------------------------------------------------------------- + +--------------------------------------------------------------------------- */ +QLCDNumber { + background-color: #19232D; + color: #F0F0F0; +} + +QLCDNumber:disabled { + background-color: #19232D; + color: #787878; +} + +/* QProgressBar ----------------------------------------------------------- + +https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qprogressbar + +--------------------------------------------------------------------------- */ +QProgressBar { + background-color: #19232D; + border: 1px solid #32414B; + color: #F0F0F0; + border-radius: 4px; + text-align: center; +} + +QProgressBar:disabled { + background-color: #19232D; + border: 1px solid #32414B; + color: #787878; + border-radius: 4px; + text-align: center; +} + +QProgressBar::chunk { + background-color: #1464A0; + color: #19232D; + border-radius: 4px; +} + +QProgressBar::chunk:disabled { + background-color: #14506E; + color: #787878; + border-radius: 4px; +} + +/* ------------------------------------------------------------------------ */ +/* BUTTONS ---------------------------------------------------------------- */ +/* ------------------------------------------------------------------------ */ +/* QPushButton ------------------------------------------------------------ + +https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qpushbutton + +--------------------------------------------------------------------------- */ +QPushButton { + background-color: #505F69; + border: 1px solid #32414B; + color: #F0F0F0; + border-radius: 4px; + padding: 3px; + outline: none; + /* Issue #194 - Special case of QPushButton inside dialogs, for better UI */ + min-width: 80px; +} + +QPushButton:disabled { + background-color: #32414B; + border: 1px solid #32414B; + color: #787878; + border-radius: 4px; + padding: 3px; +} + +QPushButton:checked { + background-color: #32414B; + border: 1px solid #32414B; + border-radius: 4px; + padding: 3px; + outline: none; +} + +QPushButton:checked:disabled { + background-color: #19232D; + border: 1px solid #32414B; + color: #787878; + border-radius: 4px; + padding: 3px; + outline: none; +} + +QPushButton:checked:selected { + background: #1464A0; + color: #32414B; +} + +QPushButton::menu-indicator { + subcontrol-origin: padding; + subcontrol-position: bottom right; + bottom: 4px; +} + +QPushButton:pressed { + background-color: #19232D; + border: 1px solid #19232D; +} + +QPushButton:pressed:hover { + border: 1px solid #148CD2; +} + +QPushButton:hover { + border: 1px solid #148CD2; + color: #F0F0F0; +} + +QPushButton:selected { + background: #1464A0; + color: #32414B; +} + +QPushButton:hover { + border: 1px solid #148CD2; + color: #F0F0F0; +} + +QPushButton:focus { + border: 1px solid #1464A0; +} + +/* QToolButton ------------------------------------------------------------ + +https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qtoolbutton + +--------------------------------------------------------------------------- */ +QToolButton { + background-color: transparent; + border: 1px solid transparent; + border-radius: 4px; + margin: 0px; + padding: 2px; + /* The subcontrols below are used only in the DelayedPopup mode */ + /* The subcontrols below are used only in the MenuButtonPopup mode */ + /* The subcontrol below is used only in the InstantPopup or DelayedPopup mode */ +} + +QToolButton:checked { + background-color: transparent; + border: 1px solid #1464A0; +} + +QToolButton:checked:disabled { + border: 1px solid #14506E; +} + +QToolButton:pressed { + margin: 1px; + background-color: transparent; + border: 1px solid #1464A0; +} + +QToolButton:disabled { + border: none; +} + +QToolButton:hover { + border: 1px solid #148CD2; +} + +QToolButton[popupMode="0"] { + /* Only for DelayedPopup */ + padding-right: 2px; +} + +QToolButton[popupMode="1"] { + /* Only for MenuButtonPopup */ + padding-right: 20px; +} + +QToolButton[popupMode="1"]::menu-button { + border: none; +} + +QToolButton[popupMode="1"]::menu-button:hover { + border: none; + border-left: 1px solid #148CD2; + border-radius: 0; +} + +QToolButton[popupMode="2"] { + /* Only for InstantPopup */ + padding-right: 2px; +} + +QToolButton::menu-button { + padding: 2px; + border-radius: 4px; + border: 1px solid #32414B; + width: 12px; + outline: none; +} + +QToolButton::menu-button:hover { + border: 1px solid #148CD2; +} + +QToolButton::menu-button:checked:hover { + border: 1px solid #148CD2; +} + +QToolButton::menu-indicator { + image: url(":/qss_icons/rc/arrow_down.png"); + height: 8px; + width: 8px; + top: 0; + /* Exclude a shift for better image */ + left: -2px; + /* Shift it a bit */ +} + +QToolButton::menu-arrow { + image: url(":/qss_icons/rc/arrow_down.png"); + height: 8px; + width: 8px; +} + +QToolButton::menu-arrow:hover { + image: url(":/qss_icons/rc/arrow_down_focus.png"); +} + +/* QCommandLinkButton ----------------------------------------------------- + +--------------------------------------------------------------------------- */ +QCommandLinkButton { + background-color: transparent; + border: 1px solid #32414B; + color: #F0F0F0; + border-radius: 4px; + padding: 0px; + margin: 0px; +} + +QCommandLinkButton:disabled { + background-color: transparent; + color: #787878; +} + +/* ------------------------------------------------------------------------ */ +/* INPUTS - NO FIELDS ----------------------------------------------------- */ +/* ------------------------------------------------------------------------ */ +/* QComboBox -------------------------------------------------------------- + +https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qcombobox + +--------------------------------------------------------------------------- */ +QComboBox { + border: 1px solid #32414B; + border-radius: 4px; + selection-background-color: #1464A0; + padding-left: 4px; + padding-right: 36px; + /* 4 + 16*2 See scrollbar size */ + /* Fixes #103, #111 */ + min-height: 1.5em; + /* padding-top: 2px; removed to fix #132 */ + /* padding-bottom: 2px; removed to fix #132 */ + /* min-width: 75px; removed to fix #109 */ + /* Needed to remove indicator - fix #132 */ +} + +QComboBox QAbstractItemView { + border: 1px solid #32414B; + border-radius: 0; + background-color: #19232D; + selection-background-color: #1464A0; +} + +QComboBox QAbstractItemView:hover { + background-color: #19232D; + color: #F0F0F0; +} + +QComboBox QAbstractItemView:selected { + background: #1464A0; + color: #32414B; +} + +QComboBox QAbstractItemView:alternate { + background: #19232D; +} + +QComboBox:disabled { + background-color: #19232D; + color: #787878; +} + +QComboBox:hover { + border: 1px solid #148CD2; +} + +QComboBox:focus { + border: 1px solid #1464A0; +} + +QComboBox:on { + selection-background-color: #1464A0; +} + +QComboBox::indicator { + border: none; + border-radius: 0; + background-color: transparent; + selection-background-color: transparent; + color: transparent; + selection-color: transparent; + /* Needed to remove indicator - fix #132 */ +} + +QComboBox::indicator:alternate { + background: #19232D; +} + +QComboBox::item:alternate { + background: #19232D; +} + +QComboBox::item:checked { + font-weight: bold; +} + +QComboBox::item:selected { + border: 0px solid transparent; +} + +QComboBox::drop-down { + subcontrol-origin: padding; + subcontrol-position: top right; + width: 12px; + border-left: 1px solid #32414B; +} + +QComboBox::down-arrow { + image: url(":/qss_icons/rc/arrow_down_disabled.png"); + height: 8px; + width: 8px; +} + +QComboBox::down-arrow:on, QComboBox::down-arrow:hover, QComboBox::down-arrow:focus { + image: url(":/qss_icons/rc/arrow_down.png"); +} + +/* QSlider ---------------------------------------------------------------- + +https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qslider + +--------------------------------------------------------------------------- */ +QSlider:disabled { + background: #19232D; +} + +QSlider:focus { + border: none; +} + +QSlider::groove:horizontal { + background: #32414B; + border: 1px solid #32414B; + height: 4px; + margin: 0px; + border-radius: 4px; +} + +QSlider::groove:vertical { + background: #32414B; + border: 1px solid #32414B; + width: 4px; + margin: 0px; + border-radius: 4px; +} + +QSlider::add-page:vertical { + background: #1464A0; + border: 1px solid #32414B; + width: 4px; + margin: 0px; + border-radius: 4px; +} + +QSlider::add-page:vertical :disabled { + background: #14506E; +} + +QSlider::sub-page:horizontal { + background: #1464A0; + border: 1px solid #32414B; + height: 4px; + margin: 0px; + border-radius: 4px; +} + +QSlider::sub-page:horizontal:disabled { + background: #14506E; +} + +QSlider::handle:horizontal { + background: #787878; + border: 1px solid #32414B; + width: 8px; + height: 8px; + margin: -8px 0px; + border-radius: 4px; +} + +QSlider::handle:horizontal:hover { + background: #148CD2; + border: 1px solid #148CD2; +} + +QSlider::handle:horizontal:focus { + border: 1px solid #1464A0; +} + +QSlider::handle:vertical { + background: #787878; + border: 1px solid #32414B; + width: 8px; + height: 8px; + margin: 0 -8px; + border-radius: 4px; +} + +QSlider::handle:vertical:hover { + background: #148CD2; + border: 1px solid #148CD2; +} + +QSlider::handle:vertical:focus { + border: 1px solid #1464A0; +} + +/* QLineEdit -------------------------------------------------------------- + +https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qlineedit + +--------------------------------------------------------------------------- */ +QLineEdit { + background-color: #19232D; + padding-top: 2px; + /* This QLineEdit fix 103, 111 */ + padding-bottom: 2px; + /* This QLineEdit fix 103, 111 */ + padding-left: 4px; + padding-right: 4px; + border-style: solid; + border: 1px solid #32414B; + border-radius: 4px; + color: #F0F0F0; +} + +QLineEdit:disabled { + background-color: #19232D; + color: #787878; +} + +QLineEdit:hover { + border: 1px solid #148CD2; + color: #F0F0F0; +} + +QLineEdit:focus { + border: 1px solid #1464A0; +} + +QLineEdit:selected { + background-color: #1464A0; + color: #32414B; +} + +/* QTabWiget -------------------------------------------------------------- + +https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qtabwidget-and-qtabbar + +--------------------------------------------------------------------------- */ +QTabWidget { + padding: 2px; + selection-background-color: #32414B; +} + +QTabWidget QWidget { + /* Fixes #189 */ + border-radius: 4px; +} + +QTabWidget::pane { + border: 1px solid #32414B; + border-radius: 4px; + margin: 0px; + /* Fixes double border inside pane with pyqt5 */ + padding: 0px; +} + +QTabWidget::pane:selected { + background-color: #32414B; + border: 1px solid #1464A0; +} + +/* QTabBar ---------------------------------------------------------------- + +https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qtabwidget-and-qtabbar + +--------------------------------------------------------------------------- */ +QTabBar { + qproperty-drawBase: 0; + border-radius: 4px; + margin: 0px; + padding: 2px; + border: 0; + /* left: 5px; move to the right by 5px - removed for fix */ +} + +QTabBar::close-button { + border: 0; + margin: 2px; + padding: 2px; + image: url(":/qss_icons/rc/window_close.png"); +} + +QTabBar::close-button:hover { + image: url(":/qss_icons/rc/window_close_focus.png"); +} + +QTabBar::close-button:pressed { + image: url(":/qss_icons/rc/window_close_pressed.png"); +} + +/* QTabBar::tab - selected ------------------------------------------------ + +https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qtabwidget-and-qtabbar + +--------------------------------------------------------------------------- */ +QTabBar::tab { + /* !selected and disabled ----------------------------------------- */ + /* selected ------------------------------------------------------- */ +} + +QTabBar::tab:top:selected:disabled { + border-bottom: 3px solid #14506E; + color: #787878; + background-color: #32414B; +} + +QTabBar::tab:bottom:selected:disabled { + border-top: 3px solid #14506E; + color: #787878; + background-color: #32414B; +} + +QTabBar::tab:left:selected:disabled { + border-right: 3px solid #14506E; + color: #787878; + background-color: #32414B; +} + +QTabBar::tab:right:selected:disabled { + border-left: 3px solid #14506E; + color: #787878; + background-color: #32414B; +} + +QTabBar::tab:top:!selected:disabled { + border-bottom: 3px solid #19232D; + color: #787878; + background-color: #19232D; +} + +QTabBar::tab:bottom:!selected:disabled { + border-top: 3px solid #19232D; + color: #787878; + background-color: #19232D; +} + +QTabBar::tab:left:!selected:disabled { + border-right: 3px solid #19232D; + color: #787878; + background-color: #19232D; +} + +QTabBar::tab:right:!selected:disabled { + border-left: 3px solid #19232D; + color: #787878; + background-color: #19232D; +} + +QTabBar::tab:top:!selected { + border-bottom: 2px solid #19232D; + margin-top: 2px; +} + +QTabBar::tab:bottom:!selected { + border-top: 2px solid #19232D; + margin-bottom: 3px; +} + +QTabBar::tab:left:!selected { + border-left: 2px solid #19232D; + margin-right: 2px; +} + +QTabBar::tab:right:!selected { + border-right: 2px solid #19232D; + margin-left: 2px; +} + +QTabBar::tab:top { + background-color: #32414B; + color: #F0F0F0; + margin-left: 2px; + padding-left: 4px; + padding-right: 4px; + padding-top: 2px; + padding-bottom: 2px; + min-width: 5px; + border-bottom: 3px solid #32414B; + border-top-left-radius: 3px; + border-top-right-radius: 3px; +} + +QTabBar::tab:top:selected { + background-color: #505F69; + color: #F0F0F0; + border-bottom: 3px solid #1464A0; + border-top-left-radius: 3px; + border-top-right-radius: 3px; +} + +QTabBar::tab:top:!selected:hover { + border: 1px solid #148CD2; + border-bottom: 3px solid #148CD2; + /* Fixes spyder-ide/spyder#9766 */ + padding-left: 4px; + padding-right: 4px; +} + +QTabBar::tab:bottom { + color: #F0F0F0; + border-top: 3px solid #32414B; + background-color: #32414B; + margin-left: 2px; + padding-left: 4px; + padding-right: 4px; + padding-top: 2px; + padding-bottom: 2px; + border-bottom-left-radius: 3px; + border-bottom-right-radius: 3px; + min-width: 5px; +} + +QTabBar::tab:bottom:selected { + color: #F0F0F0; + background-color: #505F69; + border-top: 3px solid #1464A0; + border-bottom-left-radius: 3px; + border-bottom-right-radius: 3px; +} + +QTabBar::tab:bottom:!selected:hover { + border: 1px solid #148CD2; + border-top: 3px solid #148CD2; + /* Fixes spyder-ide/spyder#9766 */ + padding-left: 4px; + padding-right: 4px; +} + +QTabBar::tab:left { + color: #F0F0F0; + background-color: #32414B; + margin-top: 2px; + padding-left: 2px; + padding-right: 2px; + padding-top: 4px; + padding-bottom: 4px; + border-top-left-radius: 3px; + border-bottom-left-radius: 3px; + min-height: 5px; +} + +QTabBar::tab:left:selected { + color: #F0F0F0; + background-color: #505F69; + border-right: 3px solid #1464A0; +} + +QTabBar::tab:left:!selected:hover { + border: 1px solid #148CD2; + border-right: 3px solid #148CD2; + padding: 0px; +} + +QTabBar::tab:right { + color: #F0F0F0; + background-color: #32414B; + margin-top: 2px; + padding-left: 2px; + padding-right: 2px; + padding-top: 4px; + padding-bottom: 4px; + border-top-right-radius: 3px; + border-bottom-right-radius: 3px; + min-height: 5px; +} + +QTabBar::tab:right:selected { + color: #F0F0F0; + background-color: #505F69; + border-left: 3px solid #1464A0; +} + +QTabBar::tab:right:!selected:hover { + border: 1px solid #148CD2; + border-left: 3px solid #148CD2; + padding: 0px; +} + +QTabBar QToolButton { + /* Fixes #136 */ + background-color: #32414B; + height: 12px; + width: 12px; +} + +QTabBar QToolButton:pressed { + background-color: #32414B; +} + +QTabBar QToolButton:pressed:hover { + border: 1px solid #148CD2; +} + +QTabBar QToolButton::left-arrow:enabled { + image: url(":/qss_icons/rc/arrow_left.png"); +} + +QTabBar QToolButton::left-arrow:disabled { + image: url(":/qss_icons/rc/arrow_left_disabled.png"); +} + +QTabBar QToolButton::right-arrow:enabled { + image: url(":/qss_icons/rc/arrow_right.png"); +} + +QTabBar QToolButton::right-arrow:disabled { + image: url(":/qss_icons/rc/arrow_right_disabled.png"); +} + +/* QDockWiget ------------------------------------------------------------- + +--------------------------------------------------------------------------- */ +QDockWidget { + outline: 1px solid #32414B; + background-color: #19232D; + border: 1px solid #32414B; + border-radius: 4px; + titlebar-close-icon: url(":/qss_icons/rc/window_close.png"); + titlebar-normal-icon: url(":/qss_icons/rc/window_undock.png"); +} + +QDockWidget::title { + /* Better size for title bar */ + padding: 6px; + spacing: 4px; + border: none; + background-color: #32414B; +} + +QDockWidget::close-button { + background-color: #32414B; + border-radius: 4px; + border: none; +} + +QDockWidget::close-button:hover { + image: url(":/qss_icons/rc/window_close_focus.png"); +} + +QDockWidget::close-button:pressed { + image: url(":/qss_icons/rc/window_close_pressed.png"); +} + +QDockWidget::float-button { + background-color: #32414B; + border-radius: 4px; + border: none; +} + +QDockWidget::float-button:hover { + image: url(":/qss_icons/rc/window_undock_focus.png"); +} + +QDockWidget::float-button:pressed { + image: url(":/qss_icons/rc/window_undock_pressed.png"); +} + +/* QTreeView QListView QTableView ----------------------------------------- + +https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qtreeview +https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qlistview +https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qtableview + +--------------------------------------------------------------------------- */ +QTreeView:branch:selected, QTreeView:branch:hover { + background: url(":/qss_icons/rc/transparent.png"); +} + +QTreeView:branch:has-siblings:!adjoins-item { + border-image: url(":/qss_icons/rc/branch_line.png") 0; +} + +QTreeView:branch:has-siblings:adjoins-item { + border-image: url(":/qss_icons/rc/branch_more.png") 0; +} + +QTreeView:branch:!has-children:!has-siblings:adjoins-item { + border-image: url(":/qss_icons/rc/branch_end.png") 0; +} + +QTreeView:branch:has-children:!has-siblings:closed, QTreeView:branch:closed:has-children:has-siblings { + border-image: none; + image: url(":/qss_icons/rc/branch_closed.png"); +} + +QTreeView:branch:open:has-children:!has-siblings, QTreeView:branch:open:has-children:has-siblings { + border-image: none; + image: url(":/qss_icons/rc/branch_open.png"); +} + +QTreeView:branch:has-children:!has-siblings:closed:hover, QTreeView:branch:closed:has-children:has-siblings:hover { + image: url(":/qss_icons/rc/branch_closed_focus.png"); +} + +QTreeView:branch:open:has-children:!has-siblings:hover, QTreeView:branch:open:has-children:has-siblings:hover { + image: url(":/qss_icons/rc/branch_open_focus.png"); +} + +QTreeView::indicator:checked, +QListView::indicator:checked { + image: url(":/qss_icons/rc/checkbox_checked.png"); +} + +QTreeView::indicator:checked:hover, QTreeView::indicator:checked:focus, QTreeView::indicator:checked:pressed, +QListView::indicator:checked:hover, +QListView::indicator:checked:focus, +QListView::indicator:checked:pressed { + image: url(":/qss_icons/rc/checkbox_checked_focus.png"); +} + +QTreeView::indicator:unchecked, +QListView::indicator:unchecked { + image: url(":/qss_icons/rc/checkbox_unchecked.png"); +} + +QTreeView::indicator:unchecked:hover, QTreeView::indicator:unchecked:focus, QTreeView::indicator:unchecked:pressed, +QListView::indicator:unchecked:hover, +QListView::indicator:unchecked:focus, +QListView::indicator:unchecked:pressed { + image: url(":/qss_icons/rc/checkbox_unchecked_focus.png"); +} + +QTreeView::indicator:indeterminate, +QListView::indicator:indeterminate { + image: url(":/qss_icons/rc/checkbox_indeterminate.png"); +} + +QTreeView::indicator:indeterminate:hover, QTreeView::indicator:indeterminate:focus, QTreeView::indicator:indeterminate:pressed, +QListView::indicator:indeterminate:hover, +QListView::indicator:indeterminate:focus, +QListView::indicator:indeterminate:pressed { + image: url(":/qss_icons/rc/checkbox_indeterminate_focus.png"); +} + +QTreeView, +QListView, +QTableView, +QColumnView { + background-color: #19232D; + border: 1px solid #32414B; + color: #F0F0F0; + gridline-color: #32414B; + border-radius: 4px; +} + +QTreeView:disabled, +QListView:disabled, +QTableView:disabled, +QColumnView:disabled { + background-color: #19232D; + color: #787878; +} + +QTreeView:selected, +QListView:selected, +QTableView:selected, +QColumnView:selected { + background-color: #1464A0; + color: #32414B; +} + +QTreeView:hover, +QListView:hover, +QTableView:hover, +QColumnView:hover { + background-color: #19232D; + border: 1px solid #148CD2; +} + +QTreeView::item:pressed, +QListView::item:pressed, +QTableView::item:pressed, +QColumnView::item:pressed { + background-color: #1464A0; +} + +QTreeView::item:selected:hover, +QListView::item:selected:hover, +QTableView::item:selected:hover, +QColumnView::item:selected:hover { + background: #1464A0; + color: #19232D; +} + +QTreeView::item:selected:active, +QListView::item:selected:active, +QTableView::item:selected:active, +QColumnView::item:selected:active { + background-color: #1464A0; +} + +QTreeView::item:!selected:hover, +QListView::item:!selected:hover, +QTableView::item:!selected:hover, +QColumnView::item:!selected:hover { + outline: 0; + color: #148CD2; + background-color: #32414B; +} + +QTableCornerButton::section { + background-color: #19232D; + border: 1px transparent #32414B; + border-radius: 0px; +} + +/* QHeaderView ------------------------------------------------------------ + +https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qheaderview + +--------------------------------------------------------------------------- */ +QHeaderView { + background-color: #32414B; + border: 0px transparent #32414B; + padding: 0px; + margin: 0px; + border-radius: 0px; +} + +QHeaderView:disabled { + background-color: #32414B; + border: 1px transparent #32414B; + padding: 2px; +} + +QHeaderView::section { + background-color: #32414B; + color: #F0F0F0; + padding: 2px; + border-radius: 0px; + text-align: left; +} + +QHeaderView::section:checked { + color: #F0F0F0; + background-color: #1464A0; +} + +QHeaderView::section:checked:disabled { + color: #787878; + background-color: #14506E; +} + +QHeaderView::section::horizontal { + padding-left: 4px; + padding-right: 4px; + border-left: 1px solid #19232D; +} + +QHeaderView::section::horizontal::first, QHeaderView::section::horizontal::only-one { + border-left: 1px solid #32414B; +} + +QHeaderView::section::horizontal:disabled { + color: #787878; +} + +QHeaderView::section::vertical { + padding-left: 4px; + padding-right: 4px; + border-top: 1px solid #19232D; +} + +QHeaderView::section::vertical::first, QHeaderView::section::vertical::only-one { + border-top: 1px solid #32414B; +} + +QHeaderView::section::vertical:disabled { + color: #787878; +} + +QHeaderView::down-arrow { + /* Those settings (border/width/height/background-color) solve bug */ + /* transparent arrow background and size */ + background-color: #32414B; + border: none; + height: 12px; + width: 12px; + padding-left: 2px; + padding-right: 2px; + image: url(":/qss_icons/rc/arrow_down.png"); +} + +QHeaderView::up-arrow { + background-color: #32414B; + border: none; + height: 12px; + width: 12px; + padding-left: 2px; + padding-right: 2px; + image: url(":/qss_icons/rc/arrow_up.png"); +} + +/* QToolBox -------------------------------------------------------------- + +https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qtoolbox + +--------------------------------------------------------------------------- */ +QToolBox { + padding: 0px; + border: 0px; + border: 1px solid #32414B; +} + +QToolBox:selected { + padding: 0px; + border: 2px solid #1464A0; +} + +QToolBox::tab { + background-color: #19232D; + border: 1px solid #32414B; + color: #F0F0F0; + border-top-left-radius: 4px; + border-top-right-radius: 4px; +} + +QToolBox::tab:disabled { + color: #787878; +} + +QToolBox::tab:selected { + background-color: #505F69; + border-bottom: 2px solid #1464A0; +} + +QToolBox::tab:selected:disabled { + background-color: #32414B; + border-bottom: 2px solid #14506E; +} + +QToolBox::tab:!selected { + background-color: #32414B; + border-bottom: 2px solid #32414B; +} + +QToolBox::tab:!selected:disabled { + background-color: #19232D; +} + +QToolBox::tab:hover { + border-color: #148CD2; + border-bottom: 2px solid #148CD2; +} + +QToolBox QScrollArea QWidget QWidget { + padding: 0px; + border: 0px; + background-color: #19232D; +} + +/* QFrame ----------------------------------------------------------------- + +https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qframe +https://doc.qt.io/qt-5/qframe.html#-prop +https://doc.qt.io/qt-5/qframe.html#details +https://stackoverflow.com/questions/14581498/qt-stylesheet-for-hline-vline-color + +--------------------------------------------------------------------------- */ +/* (dot) .QFrame fix #141, #126, #123 */ +.QFrame { + border-radius: 4px; + border: 1px solid #32414B; + /* No frame */ + /* HLine */ + /* HLine */ +} + +.QFrame[frameShape="0"] { + border-radius: 4px; + border: 1px transparent #32414B; +} + +.QFrame[frameShape="4"] { + max-height: 2px; + border: none; + background-color: #32414B; +} + +.QFrame[frameShape="5"] { + max-width: 2px; + border: none; + background-color: #32414B; +} + +/* QSplitter -------------------------------------------------------------- + +https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qsplitter + +--------------------------------------------------------------------------- */ +QSplitter { + background-color: #32414B; + spacing: 0px; + padding: 0px; + margin: 0px; +} + +QSplitter::handle { + background-color: #32414B; + border: 0px solid #19232D; + spacing: 0px; + padding: 1px; + margin: 0px; +} + +QSplitter::handle:hover { + background-color: #787878; +} + +QSplitter::handle:horizontal { + width: 5px; + image: url(":/qss_icons/rc/line_vertical.png"); +} + +QSplitter::handle:vertical { + height: 5px; + image: url(":/qss_icons/rc/line_horizontal.png"); +} + +/* QDateEdit -------------------------------------------------------------- + +--------------------------------------------------------------------------- */ +QDateEdit { + selection-background-color: #1464A0; + border-style: solid; + border: 1px solid #32414B; + border-radius: 4px; + /* This fixes 103, 111 */ + padding-top: 2px; + /* This fixes 103, 111 */ + padding-bottom: 2px; + padding-left: 4px; + padding-right: 4px; + min-width: 10px; +} + +QDateEdit:on { + selection-background-color: #1464A0; +} + +QDateEdit::drop-down { + subcontrol-origin: padding; + subcontrol-position: top right; + width: 12px; + border-left: 1px solid #32414B; +} + +QDateEdit::down-arrow { + image: url(":/qss_icons/rc/arrow_down_disabled.png"); + height: 8px; + width: 8px; +} + +QDateEdit::down-arrow:on, QDateEdit::down-arrow:hover, QDateEdit::down-arrow:focus { + image: url(":/qss_icons/rc/arrow_down.png"); +} + +QDateEdit QAbstractItemView { + background-color: #19232D; + border-radius: 4px; + border: 1px solid #32414B; + selection-background-color: #1464A0; +} + +/* QAbstractView ---------------------------------------------------------- + +--------------------------------------------------------------------------- */ +QAbstractView:hover { + border: 1px solid #148CD2; + color: #F0F0F0; +} + +QAbstractView:selected { + background: #1464A0; + color: #32414B; +} + +/* PlotWidget ------------------------------------------------------------- + +--------------------------------------------------------------------------- */ +PlotWidget { + /* Fix cut labels in plots #134 */ + padding: 0px; +} diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/sql/ObjectIdentifier.cpp b/src/WBCLFZSystemModule/SqliteDBProcess/src/sql/ObjectIdentifier.cpp new file mode 100644 index 0000000..d94aa1c --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/sql/ObjectIdentifier.cpp @@ -0,0 +1,80 @@ +#include "ObjectIdentifier.h" + +static std::string duplicate_char(std::string str, char to_replace) +{ + size_t pos = 0; + while((pos = str.find(to_replace, pos)) != std::string::npos) + { + str.insert(pos, 1, to_replace); + pos += 2; // Advance by two characters in order to avoid escaping a character multiple times + } + return str; +} + +namespace sqlb { + +static escapeQuoting customQuoting = DoubleQuotes; + +void setIdentifierQuoting(escapeQuoting toQuoting) +{ + customQuoting = toQuoting; +} + +char getIdentifierQuoteChar() +{ + switch(customQuoting) { + case GraveAccents: + return '`'; + case SquareBrackets: + return '['; + case DoubleQuotes: + return '"'; + } + + return '"'; +} + +std::string escapeIdentifier(const std::string& id) +{ + switch(customQuoting) { + case GraveAccents: + return '`' + duplicate_char(id, '`') + '`'; + case SquareBrackets: + // There aren't any escaping possibilities for square brackets inside the identifier, + // so we rely on the user to not enter these characters when this kind of quoting is + // selected. + return '[' + id + ']'; + case DoubleQuotes: + default: + // This may produce a 'control reaches end of non-void function' warning if the + // default branch is removed, even though we have covered all possibilities in the + // switch statement. + return '"' + duplicate_char(id, '"') + '"'; + } +} + +std::string escapeString(const std::string& literal) +{ + return '\'' + duplicate_char(literal, '\'') + '\''; +} + +bool ObjectIdentifier::fromSerialised(const std::string& serialised) +{ + auto pos_comma = serialised.find(","); + auto pos_colon = serialised.find(":"); + if(pos_comma == serialised.npos || pos_colon == serialised.npos) + return false; + + size_t size_schema, size_name; + size_schema = std::stoul(serialised.substr(0, pos_comma)); + size_name = std::stoul(serialised.substr(pos_comma+1, pos_colon-pos_comma)); + if(pos_colon + size_schema + size_name + 1 != serialised.size()) + return false; + + m_schema = serialised.substr(pos_colon + 1, size_schema); + m_name = serialised.substr(pos_colon + size_schema + 1, size_name); + + return true; +} + +} diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/sql/ObjectIdentifier.h b/src/WBCLFZSystemModule/SqliteDBProcess/src/sql/ObjectIdentifier.h new file mode 100644 index 0000000..8d2f528 --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/sql/ObjectIdentifier.h @@ -0,0 +1,104 @@ +#ifndef OBJECTIDENTIFIER_H +#define OBJECTIDENTIFIER_H + +#include + +namespace sqlb { + +enum escapeQuoting { + DoubleQuotes, + GraveAccents, + SquareBrackets +}; + +// Set quoting style for escapeIdentifier +void setIdentifierQuoting(escapeQuoting toQuoting); + +// Get currently configured quote char +char getIdentifierQuoteChar(); + +// Add quotes to an identifier +std::string escapeIdentifier(const std::string& id); + +// Add SQL quotes to a string literal and escape any single quote character +std::string escapeString(const std::string& literal); + +// Object identifier consisting of schema name and object name +class ObjectIdentifier +{ +public: + ObjectIdentifier(const std::string& schema, const std::string& name) + : m_schema(schema), + m_name(name) + { + } + + ObjectIdentifier() + : m_schema("main") + { + } + + explicit ObjectIdentifier(const std::string& variant) + { + // Try to unserialise the parameter first. If that does not work, just assume it's an object name for the main schema + clear(); + if(!fromSerialised(variant)) + m_name = variant; + } + + bool operator==(const ObjectIdentifier& rhs) const + { + return (rhs.m_schema == m_schema && rhs.m_name == m_name); + } + + bool operator<(const ObjectIdentifier& rhs) const + { + return toDisplayString() < rhs.toDisplayString(); + } + + const std::string& schema() const { return m_schema; } + const std::string& name() const { return m_name; } + void setSchema(const std::string& schema) { m_schema = schema; } + void setName(const std::string& name) { m_name = name; } + + void clear() + { + m_schema = "main"; + m_name.clear(); + } + + bool isEmpty() const { return m_name.empty(); } + + // This returns a string which can be used in SQL statements + std::string toString(bool shortName = false) const + { + if(shortName && m_schema == "main") + return sqlb::escapeIdentifier(m_name); + else + return sqlb::escapeIdentifier(m_schema) + "." + sqlb::escapeIdentifier(m_name); + } + + // This returns a string which can be used in the user interface + std::string toDisplayString() const + { + if(m_schema == "main") + return m_name; + else + return m_schema + "." + m_name; + } + + std::string toSerialised() const + { + return std::to_string(m_schema.size()) + "," + std::to_string(m_name.size()) + ":" + m_schema + m_name; + } + + bool fromSerialised(const std::string& serialised); + +private: + std::string m_schema; + std::string m_name; +}; + +} + +#endif diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/sql/Query.cpp b/src/WBCLFZSystemModule/SqliteDBProcess/src/sql/Query.cpp new file mode 100644 index 0000000..b35fb66 --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/sql/Query.cpp @@ -0,0 +1,148 @@ +#include "Query.h" + +#include + +namespace sqlb +{ + +void Query::clear() +{ + m_table.clear(); + m_rowid_columns = {"_rowid_"}; + m_selected_columns.clear(); + m_where.clear(); + m_sort.clear(); +} + +std::string Query::buildWherePart() const +{ + if(m_where.empty() && m_global_where.empty()) + return std::string(); + + std::string where = "WHERE "; + + if(m_where.size()) + { + for(auto i=m_where.cbegin();i!=m_where.cend();++i) + { + const auto it = findSelectedColumnByName(m_column_names.at(i->first)); + std::string column = sqlb::escapeIdentifier(m_column_names.at(i->first)); + if(it != m_selected_columns.cend() && it->selector != column) + column = it->selector; + where += column + " " + i->second + " AND "; + } + + // Remove last ' AND ' + where.erase(where.size() - 5); + } + + if(m_global_where.size()) + { + // Connect to previous conditions if there are any + if(m_where.size()) + where += " AND "; + + // For each condition + for(const auto& w : m_global_where) + { + where += "("; + + // For each selected column + for(const auto& c : m_column_names) + { + const auto it = findSelectedColumnByName(c); + std::string column = sqlb::escapeIdentifier(c); + if(it != m_selected_columns.cend() && it->selector != column) + column = it->selector; + + where += column + " " + w + " OR "; + } + + // Remove last ' OR ' + where.erase(where.size() - 4); + + where += ") AND "; + } + + // Remove last ' AND ' + where.erase(where.size() - 5); + } + + return where; +} + +std::string Query::buildQuery(bool withRowid) const +{ + // Selector and display formats + std::string selector; + if (withRowid) + { + // We select the rowid data into a JSON array in case there are multiple rowid columns in order to have all values at hand. + // If there is only one rowid column, we leave it as is. + if(m_rowid_columns.size() == 1) + { + selector = sqlb::escapeIdentifier(m_rowid_columns.at(0)) + ","; + } else { + selector += "sqlb_make_single_value("; + for(size_t i=0;i::iterator Query::findSelectedColumnByName(const std::string& name) +{ + return std::find_if(m_selected_columns.begin(), m_selected_columns.end(), [name](const SelectedColumn& c) { + return name == c.original_column; + }); +} + +std::vector::const_iterator Query::findSelectedColumnByName(const std::string& name) const +{ + return std::find_if(m_selected_columns.cbegin(), m_selected_columns.cend(), [name](const SelectedColumn& c) { + return name == c.original_column; + }); +} + +} diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/sql/Query.h b/src/WBCLFZSystemModule/SqliteDBProcess/src/sql/Query.h new file mode 100644 index 0000000..112f675 --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/sql/Query.h @@ -0,0 +1,99 @@ +#ifndef QUERY_H +#define QUERY_H + +#include "ObjectIdentifier.h" + +#include +#include +#include + +namespace sqlb +{ + +enum SortDirection +{ + Ascending, + Descending +}; + +struct SortedColumn +{ + SortedColumn(size_t column_, SortDirection direction_) : + column(column_), + direction(direction_) + {} + + bool operator==(const SortedColumn& rhs) const + { + return column == rhs.column && direction == rhs.direction; + } + + size_t column; + SortDirection direction; +}; + +struct SelectedColumn +{ + SelectedColumn(const std::string& original_column_, const std::string& selector_) : + original_column(original_column_), + selector(selector_) + {} + + std::string original_column; + std::string selector; +}; + +class Query +{ +public: + Query() {} + explicit Query(const sqlb::ObjectIdentifier& table) : + m_table(table) + {} + + void clear(); + std::string buildQuery(bool withRowid) const; + std::string buildCountQuery() const; + + void setColumNames(const std::vector& column_names) { m_column_names = column_names; } + std::vector columnNames() const { return m_column_names; } + + void setTable(const sqlb::ObjectIdentifier& table) { m_table = table; } + sqlb::ObjectIdentifier table() const { return m_table; } + + void setRowIdColumns(const std::vector& rowids) { m_rowid_columns = rowids; } + std::vector rowIdColumns() const { return m_rowid_columns; } + void setRowIdColumn(const std::string& rowid) { m_rowid_columns = {rowid}; } + bool hasCustomRowIdColumn() const { return m_rowid_columns.size() != 1 || (m_rowid_columns.at(0) != "rowid" && m_rowid_columns.at(0) != "_rowid_"); } + + const std::vector& selectedColumns() const { return m_selected_columns; } + std::vector& selectedColumns() { return m_selected_columns; } + + const std::unordered_map& where() const { return m_where; } + std::unordered_map& where() { return m_where; } + + const std::vector& globalWhere() const { return m_global_where; } + std::vector& globalWhere() { return m_global_where; } + void setGlobalWhere(const std::vector& w) { m_global_where = w; } + + const std::vector& orderBy() const { return m_sort; } + std::vector& orderBy() { return m_sort; } + void setOrderBy(const std::vector& columns) { m_sort = columns; } + +private: + std::vector m_column_names; + sqlb::ObjectIdentifier m_table; + std::vector m_rowid_columns; + std::vector m_selected_columns; + std::unordered_map m_where; // TODO The two where variables should be merged into a single variable which ... + std::vector m_global_where; // ... holds some sort of general tree structure for all sorts of where conditions. + std::vector m_sort; + + std::vector::iterator findSelectedColumnByName(const std::string& name); + std::vector::const_iterator findSelectedColumnByName(const std::string& name) const; + std::string buildWherePart() const; +}; + +} + +#endif diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/sql/parser/ParserDriver.cpp b/src/WBCLFZSystemModule/SqliteDBProcess/src/sql/parser/ParserDriver.cpp new file mode 100644 index 0000000..d2dae0f --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/sql/parser/ParserDriver.cpp @@ -0,0 +1,31 @@ +#include "ParserDriver.h" + +namespace sqlb +{ +namespace parser +{ + +ParserDriver::ParserDriver() : + result(nullptr), + trace_scanner(false), + trace_parser(false), + scanner(nullptr), + buffer(nullptr) +{ +} + +int ParserDriver::parse(const std::string& s) +{ + source = s; + begin_scan(); + + sqlb::parser::parser parse(scanner, *this); + parse.set_debug_level(trace_parser); + int res = parse(); + + end_scan(); + return res; +} + +} +} diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/sql/parser/ParserDriver.h b/src/WBCLFZSystemModule/SqliteDBProcess/src/sql/parser/ParserDriver.h new file mode 100644 index 0000000..66796da --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/sql/parser/ParserDriver.h @@ -0,0 +1,59 @@ +#ifndef PARSER_DRIVER_H +#define PARSER_DRIVER_H + +#include +#include "sqlite3_parser.hpp" +#include "../sqlitetypes.h" + +// Give Flex the prototype of yylex we want and declare it for the parser +typedef void* yyscan_t; +namespace sqlb { namespace parser { class ParserDriver; } } +#define YY_DECL sqlb::parser::parser::symbol_type yylex(yyscan_t yyscanner, sqlb::parser::ParserDriver& drv) +YY_DECL; + +namespace sqlb +{ +namespace parser +{ + +class ParserDriver +{ +public: + ParserDriver(); + + void setScannerDebug(bool on) { trace_scanner = on; } + void setParserDebug(bool on) { trace_parser = on; } + + // Run the parser on string s. Returns 0 on success + int parse(const std::string& s); + + // Result returned by the parsing process + sqlb::ObjectPtr result; + + // The token's location used by the scanner + sqlb::parser::location location; + +private: + // The string to be parsed + std::string source; + + // Handling the scanner + void begin_scan(); + void end_scan(); + + // Debug flags for both scanner and parser + bool trace_scanner; + bool trace_parser; + + // Scanner state + yyscan_t scanner; + + // Scanner buffer + typedef struct yy_buffer_state* YY_BUFFER_STATE; + YY_BUFFER_STATE buffer; +}; + +} +} + +#endif diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/sql/parser/README b/src/WBCLFZSystemModule/SqliteDBProcess/src/sql/parser/README new file mode 100644 index 0000000..71adf65 --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/sql/parser/README @@ -0,0 +1,9 @@ +This directory contains the SQLite lexer and parser files. + +For convenience and to not have extra dependencies in the build process, +the generated C++ files are included here. Please don't edit them by hand. +To modify the lexer or parser, edit the sqlite3_lexer.ll or sqlite3_parser.yy +files and rerun flex or bison like this: + +flex sqlite3_lexer.ll +bison sqlite3_parser.yy diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/sql/parser/sqlite3_lexer.cpp b/src/WBCLFZSystemModule/SqliteDBProcess/src/sql/parser/sqlite3_lexer.cpp new file mode 100644 index 0000000..5ff6e45 --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/sql/parser/sqlite3_lexer.cpp @@ -0,0 +1,3623 @@ +#line 2 "sqlite3_lexer.cpp" + +#line 4 "sqlite3_lexer.cpp" + +#define YY_INT_ALIGNED short int + +/* A lexical scanner generated by flex */ + +/* %not-for-header */ +/* %if-c-only */ +/* %if-not-reentrant */ +/* %endif */ +/* %endif */ +/* %ok-for-header */ + +#define FLEX_SCANNER +#define YY_FLEX_MAJOR_VERSION 2 +#define YY_FLEX_MINOR_VERSION 6 +#define YY_FLEX_SUBMINOR_VERSION 4 +#if YY_FLEX_SUBMINOR_VERSION > 0 +#define FLEX_BETA +#endif + +/* %if-c++-only */ +/* %endif */ + +/* %if-c-only */ + +/* %endif */ + +/* %if-c-only */ + +/* %endif */ + +/* First, we deal with platform-specific or compiler-specific issues. */ + +/* begin standard C headers. */ +/* %if-c-only */ +#include +#include +#include +#include +/* %endif */ + +/* %if-tables-serialization */ +/* %endif */ +/* end standard C headers. */ + +/* %if-c-or-c++ */ +/* flex integer type definitions */ + +#ifndef FLEXINT_H +#define FLEXINT_H + +/* C99 systems have . Non-C99 systems may or may not. */ + +#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L + +/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h, + * if you want the limit (max/min) macros for int types. + */ +#ifndef __STDC_LIMIT_MACROS +#define __STDC_LIMIT_MACROS 1 +#endif + +#include +typedef int8_t flex_int8_t; +typedef uint8_t flex_uint8_t; +typedef int16_t flex_int16_t; +typedef uint16_t flex_uint16_t; +typedef int32_t flex_int32_t; +typedef uint32_t flex_uint32_t; +#else +typedef signed char flex_int8_t; +typedef short int flex_int16_t; +typedef int flex_int32_t; +typedef unsigned char flex_uint8_t; +typedef unsigned short int flex_uint16_t; +typedef unsigned int flex_uint32_t; + +/* Limits of integral types. */ +#ifndef INT8_MIN +#define INT8_MIN (-128) +#endif +#ifndef INT16_MIN +#define INT16_MIN (-32767-1) +#endif +#ifndef INT32_MIN +#define INT32_MIN (-2147483647-1) +#endif +#ifndef INT8_MAX +#define INT8_MAX (127) +#endif +#ifndef INT16_MAX +#define INT16_MAX (32767) +#endif +#ifndef INT32_MAX +#define INT32_MAX (2147483647) +#endif +#ifndef UINT8_MAX +#define UINT8_MAX (255U) +#endif +#ifndef UINT16_MAX +#define UINT16_MAX (65535U) +#endif +#ifndef UINT32_MAX +#define UINT32_MAX (4294967295U) +#endif + +#ifndef SIZE_MAX +#define SIZE_MAX (~(size_t)0) +#endif + +#endif /* ! C99 */ + +#endif /* ! FLEXINT_H */ + +/* %endif */ + +/* begin standard C++ headers. */ +/* %if-c++-only */ +/* %endif */ + +/* TODO: this is always defined, so inline it */ +#define yyconst const + +#if defined(__GNUC__) && __GNUC__ >= 3 +#define yynoreturn __attribute__((__noreturn__)) +#else +#define yynoreturn +#endif + +/* %not-for-header */ +/* Returned upon end-of-file. */ +#define YY_NULL 0 +/* %ok-for-header */ + +/* %not-for-header */ +/* Promotes a possibly negative, possibly signed char to an + * integer in range [0..255] for use as an array index. + */ +#define YY_SC_TO_UI(c) ((YY_CHAR) (c)) +/* %ok-for-header */ + +/* %if-reentrant */ + +/* An opaque pointer. */ +#ifndef YY_TYPEDEF_YY_SCANNER_T +#define YY_TYPEDEF_YY_SCANNER_T +typedef void* yyscan_t; +#endif + +/* For convenience, these vars (plus the bison vars far below) + are macros in the reentrant scanner. */ +#define yyin yyg->yyin_r +#define yyout yyg->yyout_r +#define yyextra yyg->yyextra_r +#define yyleng yyg->yyleng_r +#define yytext yyg->yytext_r +#define yylineno (YY_CURRENT_BUFFER_LVALUE->yy_bs_lineno) +#define yycolumn (YY_CURRENT_BUFFER_LVALUE->yy_bs_column) +#define yy_flex_debug yyg->yy_flex_debug_r + +/* %endif */ + +/* %if-not-reentrant */ +/* %endif */ + +/* Enter a start condition. This macro really ought to take a parameter, + * but we do it the disgusting crufty way forced on us by the ()-less + * definition of BEGIN. + */ +#define BEGIN yyg->yy_start = 1 + 2 * +/* Translate the current start state into a value that can be later handed + * to BEGIN to return to the state. The YYSTATE alias is for lex + * compatibility. + */ +#define YY_START ((yyg->yy_start - 1) / 2) +#define YYSTATE YY_START +/* Action number for EOF rule of a given start state. */ +#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1) +/* Special action meaning "start processing a new file". */ +#define YY_NEW_FILE yyrestart( yyin , yyscanner ) +#define YY_END_OF_BUFFER_CHAR 0 + +/* Size of default input buffer. */ +#ifndef YY_BUF_SIZE +#ifdef __ia64__ +/* On IA-64, the buffer size is 16k, not 8k. + * Moreover, YY_BUF_SIZE is 2*YY_READ_BUF_SIZE in the general case. + * Ditto for the __ia64__ case accordingly. + */ +#define YY_BUF_SIZE 32768 +#else +#define YY_BUF_SIZE 16384 +#endif /* __ia64__ */ +#endif + +/* The state buf must be large enough to hold one state per character in the main buffer. + */ +#define YY_STATE_BUF_SIZE ((YY_BUF_SIZE + 2) * sizeof(yy_state_type)) + +#ifndef YY_TYPEDEF_YY_BUFFER_STATE +#define YY_TYPEDEF_YY_BUFFER_STATE +typedef struct yy_buffer_state *YY_BUFFER_STATE; +#endif + +#ifndef YY_TYPEDEF_YY_SIZE_T +#define YY_TYPEDEF_YY_SIZE_T +typedef size_t yy_size_t; +#endif + +/* %if-not-reentrant */ +/* %endif */ + +/* %if-c-only */ +/* %if-not-reentrant */ +/* %endif */ +/* %endif */ + +#define EOB_ACT_CONTINUE_SCAN 0 +#define EOB_ACT_END_OF_FILE 1 +#define EOB_ACT_LAST_MATCH 2 + + #define YY_LESS_LINENO(n) + #define YY_LINENO_REWIND_TO(ptr) + +/* Return all but the first "n" matched characters back to the input stream. */ +#define yyless(n) \ + do \ + { \ + /* Undo effects of setting up yytext. */ \ + int yyless_macro_arg = (n); \ + YY_LESS_LINENO(yyless_macro_arg);\ + *yy_cp = yyg->yy_hold_char; \ + YY_RESTORE_YY_MORE_OFFSET \ + yyg->yy_c_buf_p = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \ + YY_DO_BEFORE_ACTION; /* set up yytext again */ \ + } \ + while ( 0 ) +#define unput(c) yyunput( c, yyg->yytext_ptr , yyscanner ) + +#ifndef YY_STRUCT_YY_BUFFER_STATE +#define YY_STRUCT_YY_BUFFER_STATE +struct yy_buffer_state + { +/* %if-c-only */ + FILE *yy_input_file; +/* %endif */ + +/* %if-c++-only */ +/* %endif */ + + char *yy_ch_buf; /* input buffer */ + char *yy_buf_pos; /* current position in input buffer */ + + /* Size of input buffer in bytes, not including room for EOB + * characters. + */ + int yy_buf_size; + + /* Number of characters read into yy_ch_buf, not including EOB + * characters. + */ + int yy_n_chars; + + /* Whether we "own" the buffer - i.e., we know we created it, + * and can realloc() it to grow it, and should free() it to + * delete it. + */ + int yy_is_our_buffer; + + /* Whether this is an "interactive" input source; if so, and + * if we're using stdio for input, then we want to use getc() + * instead of fread(), to make sure we stop fetching input after + * each newline. + */ + int yy_is_interactive; + + /* Whether we're considered to be at the beginning of a line. + * If so, '^' rules will be active on the next match, otherwise + * not. + */ + int yy_at_bol; + + int yy_bs_lineno; /**< The line count. */ + int yy_bs_column; /**< The column count. */ + + /* Whether to try to fill the input buffer when we reach the + * end of it. + */ + int yy_fill_buffer; + + int yy_buffer_status; + +#define YY_BUFFER_NEW 0 +#define YY_BUFFER_NORMAL 1 + /* When an EOF's been seen but there's still some text to process + * then we mark the buffer as YY_EOF_PENDING, to indicate that we + * shouldn't try reading from the input source any more. We might + * still have a bunch of tokens to match, though, because of + * possible backing-up. + * + * When we actually see the EOF, we change the status to "new" + * (via yyrestart()), so that the user can continue scanning by + * just pointing yyin at a new input file. + */ +#define YY_BUFFER_EOF_PENDING 2 + + }; +#endif /* !YY_STRUCT_YY_BUFFER_STATE */ + +/* %if-c-only Standard (non-C++) definition */ +/* %not-for-header */ +/* %if-not-reentrant */ +/* %endif */ +/* %ok-for-header */ + +/* %endif */ + +/* We provide macros for accessing buffer states in case in the + * future we want to put the buffer states in a more general + * "scanner state". + * + * Returns the top of the stack, or NULL. + */ +#define YY_CURRENT_BUFFER ( yyg->yy_buffer_stack \ + ? yyg->yy_buffer_stack[yyg->yy_buffer_stack_top] \ + : NULL) +/* Same as previous macro, but useful when we know that the buffer stack is not + * NULL or when we need an lvalue. For internal use only. + */ +#define YY_CURRENT_BUFFER_LVALUE yyg->yy_buffer_stack[yyg->yy_buffer_stack_top] + +/* %if-c-only Standard (non-C++) definition */ + +/* %if-not-reentrant */ +/* %not-for-header */ +/* %ok-for-header */ + +/* %endif */ + +void yyrestart ( FILE *input_file , yyscan_t yyscanner ); +void yy_switch_to_buffer ( YY_BUFFER_STATE new_buffer , yyscan_t yyscanner ); +YY_BUFFER_STATE yy_create_buffer ( FILE *file, int size , yyscan_t yyscanner ); +void yy_delete_buffer ( YY_BUFFER_STATE b , yyscan_t yyscanner ); +void yy_flush_buffer ( YY_BUFFER_STATE b , yyscan_t yyscanner ); +void yypush_buffer_state ( YY_BUFFER_STATE new_buffer , yyscan_t yyscanner ); +void yypop_buffer_state ( yyscan_t yyscanner ); + +static void yyensure_buffer_stack ( yyscan_t yyscanner ); +static void yy_load_buffer_state ( yyscan_t yyscanner ); +static void yy_init_buffer ( YY_BUFFER_STATE b, FILE *file , yyscan_t yyscanner ); +#define YY_FLUSH_BUFFER yy_flush_buffer( YY_CURRENT_BUFFER , yyscanner) + +YY_BUFFER_STATE yy_scan_buffer ( char *base, yy_size_t size , yyscan_t yyscanner ); +YY_BUFFER_STATE yy_scan_string ( const char *yy_str , yyscan_t yyscanner ); +YY_BUFFER_STATE yy_scan_bytes ( const char *bytes, int len , yyscan_t yyscanner ); + +/* %endif */ + +void *yyalloc ( yy_size_t , yyscan_t yyscanner ); +void *yyrealloc ( void *, yy_size_t , yyscan_t yyscanner ); +void yyfree ( void * , yyscan_t yyscanner ); + +#define yy_new_buffer yy_create_buffer +#define yy_set_interactive(is_interactive) \ + { \ + if ( ! YY_CURRENT_BUFFER ){ \ + yyensure_buffer_stack (yyscanner); \ + YY_CURRENT_BUFFER_LVALUE = \ + yy_create_buffer( yyin, YY_BUF_SIZE , yyscanner); \ + } \ + YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \ + } +#define yy_set_bol(at_bol) \ + { \ + if ( ! YY_CURRENT_BUFFER ){\ + yyensure_buffer_stack (yyscanner); \ + YY_CURRENT_BUFFER_LVALUE = \ + yy_create_buffer( yyin, YY_BUF_SIZE , yyscanner); \ + } \ + YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \ + } +#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol) + +/* %% [1.0] yytext/yyin/yyout/yy_state_type/yylineno etc. def's & init go here */ +/* Begin user sect3 */ + +#define yywrap(yyscanner) (/*CONSTCOND*/1) +#define YY_SKIP_YYWRAP + +#define FLEX_DEBUG +typedef flex_uint8_t YY_CHAR; + +typedef int yy_state_type; + +#define yytext_ptr yytext_r + +/* %% [1.5] DFA */ + +/* %if-c-only Standard (non-C++) definition */ + +static yy_state_type yy_get_previous_state ( yyscan_t yyscanner ); +static yy_state_type yy_try_NUL_trans ( yy_state_type current_state , yyscan_t yyscanner); +static int yy_get_next_buffer ( yyscan_t yyscanner ); +static void yynoreturn yy_fatal_error ( const char* msg , yyscan_t yyscanner ); + +/* %endif */ + +/* Done after the current pattern has been matched and before the + * corresponding action - sets up yytext. + */ +#define YY_DO_BEFORE_ACTION \ + yyg->yytext_ptr = yy_bp; \ +/* %% [2.0] code to fiddle yytext and yyleng for yymore() goes here \ */\ + yyleng = (int) (yy_cp - yy_bp); \ + yyg->yy_hold_char = *yy_cp; \ + *yy_cp = '\0'; \ +/* %% [3.0] code to copy yytext_ptr to yytext[] goes here, if %array \ */\ + yyg->yy_c_buf_p = yy_cp; +/* %% [4.0] data tables for the DFA and the user's section 1 definitions go here */ +#define YY_NUM_RULES 123 +#define YY_END_OF_BUFFER 124 +/* This struct is not used in this scanner, + but its presence is necessary. */ +struct yy_trans_info + { + flex_int32_t yy_verify; + flex_int32_t yy_nxt; + }; +static const flex_int16_t yy_accept[467] = + { 0, + 0, 0, 0, 0, 124, 122, 1, 2, 2, 122, + 122, 109, 108, 122, 98, 99, 105, 103, 101, 104, + 100, 106, 94, 94, 122, 102, 116, 112, 114, 96, + 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, + 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, + 89, 89, 122, 122, 110, 107, 122, 122, 122, 89, + 1, 2, 118, 0, 92, 0, 93, 3, 94, 4, + 94, 94, 0, 0, 97, 120, 117, 119, 113, 115, + 121, 96, 89, 89, 89, 89, 89, 11, 89, 0, + 0, 0, 89, 89, 89, 89, 89, 89, 89, 89, + + 89, 89, 89, 89, 89, 89, 89, 89, 89, 42, + 89, 89, 45, 49, 89, 89, 89, 54, 89, 58, + 59, 89, 89, 89, 89, 89, 89, 89, 89, 89, + 89, 89, 89, 89, 89, 89, 89, 89, 89, 0, + 0, 91, 0, 90, 111, 89, 0, 0, 89, 94, + 0, 94, 94, 96, 89, 89, 89, 6, 12, 89, + 0, 0, 89, 89, 89, 89, 89, 89, 89, 89, + 89, 89, 89, 89, 32, 89, 89, 89, 89, 89, + 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, + 51, 89, 89, 55, 89, 89, 89, 89, 89, 89, + + 89, 89, 89, 89, 89, 89, 89, 89, 74, 89, + 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, + 89, 95, 0, 0, 5, 89, 89, 89, 89, 0, + 89, 89, 15, 16, 89, 89, 89, 89, 89, 89, + 89, 89, 89, 29, 89, 31, 89, 89, 35, 89, + 89, 89, 89, 89, 41, 89, 89, 89, 89, 89, + 89, 52, 89, 89, 57, 60, 89, 89, 89, 89, + 89, 89, 89, 89, 89, 89, 89, 72, 89, 89, + 89, 77, 79, 80, 89, 89, 89, 89, 89, 86, + 89, 89, 8, 89, 89, 89, 89, 89, 17, 89, + + 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, + 36, 89, 89, 89, 89, 89, 89, 46, 89, 89, + 89, 53, 89, 89, 89, 89, 64, 65, 89, 89, + 89, 89, 89, 71, 89, 89, 76, 89, 89, 89, + 89, 84, 89, 87, 89, 9, 10, 89, 89, 89, + 89, 89, 89, 21, 89, 89, 89, 28, 89, 33, + 34, 37, 89, 89, 89, 43, 89, 89, 48, 50, + 89, 89, 89, 89, 89, 67, 89, 89, 89, 73, + 75, 89, 89, 82, 83, 89, 89, 89, 7, 14, + 18, 89, 89, 89, 25, 89, 89, 89, 89, 39, + + 89, 89, 89, 56, 89, 89, 63, 89, 68, 89, + 89, 89, 89, 85, 88, 89, 19, 89, 89, 89, + 27, 30, 89, 89, 89, 89, 89, 89, 89, 69, + 70, 89, 89, 89, 89, 89, 89, 89, 38, 40, + 44, 47, 61, 62, 89, 78, 81, 89, 20, 89, + 89, 26, 66, 89, 89, 89, 89, 22, 23, 13, + 89, 89, 89, 89, 24, 0 + } ; + +static const YY_CHAR yy_ec[256] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, + 1, 2, 4, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 2, 5, 6, 1, 1, 7, 8, 9, 10, + 11, 12, 13, 14, 15, 16, 17, 18, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 20, 21, 22, + 23, 24, 25, 20, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, + 42, 43, 44, 45, 46, 47, 48, 49, 50, 35, + 51, 1, 52, 1, 53, 54, 55, 56, 57, 58, + + 59, 60, 61, 62, 63, 35, 64, 65, 66, 67, + 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, + 78, 35, 1, 79, 1, 80, 1, 81, 81, 81, + 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, + 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, + 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, + 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, + 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, + 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, + 81, 1, 1, 82, 82, 82, 82, 82, 82, 82, + + 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, + 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, + 82, 82, 82, 83, 83, 83, 83, 83, 83, 83, + 83, 83, 83, 83, 83, 83, 83, 83, 83, 84, + 84, 84, 84, 84, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1 + } ; + +static const YY_CHAR yy_meta[85] = + { 0, + 1, 1, 2, 1, 1, 1, 1, 1, 3, 1, + 1, 1, 1, 1, 1, 1, 1, 4, 4, 1, + 1, 1, 1, 1, 1, 5, 5, 5, 5, 5, + 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 1, 1, 7, 1, 5, 5, 5, 5, 5, 5, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 1, 1, + 1, 7, 7, 7 + } ; + +static const flex_int16_t yy_base[475] = + { 0, + 0, 0, 59, 60, 283, 2424, 279, 84, 86, 255, + 260, 2424, 2424, 256, 2424, 2424, 2424, 2424, 2424, 244, + 73, 242, 77, 81, 0, 2424, 79, 229, 81, 229, + 128, 64, 187, 76, 124, 94, 157, 34, 241, 68, + 135, 98, 163, 221, 251, 227, 267, 311, 276, 141, + 294, 247, 192, 189, 159, 2424, 155, 153, 151, 369, + 227, 105, 2424, 222, 220, 212, 196, 2424, 111, 2424, + 232, 345, 366, 0, 0, 2424, 2424, 2424, 2424, 2424, + 2424, 94, 49, 306, 327, 338, 369, 355, 346, 118, + 116, 111, 372, 387, 402, 410, 405, 192, 435, 419, + + 432, 415, 439, 399, 471, 474, 494, 485, 480, 60, + 499, 504, 517, 535, 529, 508, 548, 551, 557, 216, + 285, 567, 571, 593, 581, 626, 623, 601, 629, 634, + 653, 642, 646, 687, 664, 446, 680, 672, 693, 181, + 136, 2424, 132, 129, 2424, 319, 98, 90, 675, 586, + 103, 119, 0, 196, 696, 710, 706, 443, 526, 700, + 85, 83, 724, 757, 753, 760, 773, 765, 779, 769, + 799, 803, 793, 829, 596, 838, 823, 789, 826, 844, + 832, 860, 864, 847, 856, 874, 895, 887, 904, 890, + 729, 907, 923, 914, 918, 932, 937, 956, 961, 950, + + 976, 965, 982, 986, 973, 989, 1018, 1023, 796, 992, + 1013, 1039, 1044, 1054, 1047, 1050, 1059, 1073, 1079, 1105, + 1083, 2424, 136, 44, 817, 1101, 1109, 1097, 1076, 38, + 1123, 1142, 946, 1035, 1134, 1145, 1149, 1128, 1157, 1160, + 1163, 1152, 1175, 1167, 1204, 1170, 1214, 1211, 1178, 1233, + 1240, 1236, 1243, 1229, 1182, 1258, 1249, 1226, 1271, 1278, + 1291, 1197, 1281, 1284, 1207, 1253, 1313, 1318, 1324, 1321, + 1327, 1301, 1310, 1343, 1346, 1363, 1383, 1331, 1392, 1340, + 1401, 1395, 1350, 1354, 1370, 1412, 1398, 1407, 1418, 1373, + 1429, 1447, 1415, 1454, 1460, 1466, 1476, 1481, 1425, 1472, + + 1484, 1491, 1494, 1502, 1514, 1509, 1531, 1542, 1552, 1545, + 1443, 1559, 1523, 1555, 1568, 1573, 1538, 1562, 1578, 1586, + 1582, 1589, 1611, 1604, 1624, 1620, 1596, 1601, 1637, 1640, + 1661, 1664, 1671, 1617, 1667, 1676, 1631, 1685, 1690, 1680, + 1702, 1653, 1715, 1693, 1706, 1699, 1709, 1737, 1740, 1757, + 1766, 1772, 1775, 1720, 1760, 1763, 1805, 1727, 1809, 1730, + 1744, 1769, 1798, 1795, 1822, 1786, 1839, 1834, 1790, 1801, + 1849, 1856, 1862, 1825, 1859, 1818, 1890, 1896, 1899, 1828, + 1846, 1908, 1918, 1853, 1868, 1921, 1912, 1926, 1877, 1882, + 1905, 1939, 1936, 1945, 1931, 1950, 1978, 1966, 1985, 1958, + + 1995, 1990, 2000, 1961, 2007, 2014, 1973, 2023, 2003, 2019, + 2030, 2033, 2040, 2026, 2036, 2070, 2043, 2054, 2099, 2093, + 2049, 2057, 2102, 2106, 2112, 2096, 2120, 2130, 2138, 2065, + 2083, 2123, 2141, 2160, 2155, 2185, 2182, 2188, 2126, 2147, + 2150, 2166, 2169, 2172, 2191, 2175, 2178, 2246, 2195, 2235, + 2243, 2200, 2203, 2249, 2261, 2264, 2267, 2213, 2270, 2216, + 2289, 2281, 2255, 2300, 2219, 2424, 2384, 2391, 2394, 2397, + 2404, 2411, 2415, 2418 + } ; + +static const flex_int16_t yy_def[475] = + { 0, + 466, 1, 1, 1, 466, 466, 466, 466, 466, 466, + 467, 466, 466, 468, 466, 466, 466, 466, 466, 466, + 466, 466, 466, 466, 469, 466, 466, 466, 466, 466, + 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, + 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, + 470, 470, 471, 472, 466, 466, 466, 466, 466, 35, + 466, 466, 466, 467, 466, 468, 466, 466, 466, 466, + 466, 466, 466, 473, 469, 466, 466, 466, 466, 466, + 466, 466, 470, 470, 470, 470, 470, 470, 470, 466, + 466, 466, 470, 470, 470, 470, 470, 470, 470, 470, + + 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, + 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, + 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, + 470, 470, 470, 470, 470, 470, 470, 470, 470, 474, + 471, 466, 472, 466, 466, 470, 466, 466, 470, 466, + 466, 466, 473, 466, 470, 470, 470, 470, 470, 470, + 466, 466, 470, 470, 470, 470, 470, 470, 470, 470, + 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, + 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, + 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, + + 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, + 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, + 470, 466, 474, 466, 470, 470, 470, 470, 470, 466, + 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, + 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, + 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, + 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, + 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, + 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, + 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, + + 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, + 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, + 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, + 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, + 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, + 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, + 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, + 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, + 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, + 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, + + 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, + 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, + 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, + 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, + 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, + 470, 470, 470, 470, 470, 470, 470, 470, 470, 470, + 470, 470, 470, 470, 470, 0, 466, 466, 466, 466, + 466, 466, 466, 466 + } ; + +static const flex_int16_t yy_nxt[2509] = + { 0, + 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, + 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, + 36, 37, 38, 39, 38, 40, 41, 42, 43, 44, + 45, 38, 46, 47, 48, 49, 50, 51, 52, 38, + 53, 6, 38, 54, 31, 32, 33, 34, 35, 36, + 37, 38, 39, 40, 41, 42, 43, 44, 45, 38, + 46, 47, 48, 49, 50, 51, 52, 38, 55, 56, + 6, 57, 58, 59, 60, 60, 62, 62, 62, 62, + 69, 69, 71, 93, 72, 72, 71, 115, 72, 72, + + 76, 77, 78, 80, 81, 99, 73, 62, 62, 100, + 73, 154, 154, 60, 60, 90, 91, 92, 83, 105, + 152, 152, 93, 117, 146, 74, 115, 106, 69, 69, + 90, 91, 92, 107, 99, 73, 152, 152, 100, 73, + 73, 90, 91, 92, 222, 90, 91, 92, 105, 90, + 91, 92, 117, 74, 84, 85, 106, 90, 91, 92, + 101, 107, 102, 230, 86, 83, 87, 103, 116, 73, + 224, 88, 104, 89, 137, 90, 91, 92, 146, 90, + 91, 92, 143, 84, 85, 144, 108, 142, 101, 222, + 102, 162, 86, 109, 87, 103, 161, 116, 83, 88, + + 104, 89, 118, 137, 66, 90, 91, 92, 119, 90, + 91, 92, 94, 154, 154, 108, 90, 91, 92, 95, + 67, 109, 90, 91, 92, 64, 96, 65, 61, 97, + 118, 148, 98, 147, 169, 146, 119, 145, 90, 91, + 92, 94, 144, 142, 90, 91, 92, 82, 95, 150, + 150, 79, 125, 70, 96, 140, 126, 97, 68, 120, + 98, 73, 169, 121, 67, 65, 127, 122, 90, 91, + 92, 110, 111, 90, 91, 92, 123, 63, 112, 113, + 61, 125, 466, 466, 114, 126, 466, 120, 466, 466, + 73, 121, 466, 124, 127, 122, 128, 90, 91, 92, + + 110, 111, 90, 91, 92, 123, 112, 113, 90, 91, + 92, 129, 114, 466, 134, 466, 135, 466, 466, 136, + 466, 124, 90, 91, 92, 128, 138, 139, 90, 91, + 92, 466, 90, 91, 92, 466, 130, 466, 466, 129, + 131, 466, 134, 132, 135, 155, 466, 136, 90, 91, + 92, 466, 466, 133, 466, 138, 139, 90, 91, 92, + 71, 466, 72, 72, 466, 130, 90, 91, 92, 131, + 466, 156, 132, 155, 73, 90, 91, 92, 151, 466, + 151, 133, 159, 152, 152, 157, 466, 90, 91, 92, + 160, 466, 90, 91, 92, 84, 85, 158, 466, 156, + + 90, 91, 92, 73, 466, 86, 466, 149, 90, 91, + 92, 159, 88, 157, 89, 466, 163, 83, 160, 90, + 91, 92, 466, 466, 84, 85, 158, 90, 91, 92, + 164, 165, 177, 86, 168, 149, 90, 91, 92, 466, + 88, 466, 89, 175, 163, 83, 166, 466, 167, 466, + 90, 91, 92, 90, 91, 92, 466, 466, 164, 466, + 165, 177, 173, 168, 466, 170, 176, 466, 90, 91, + 92, 171, 175, 466, 166, 174, 167, 466, 172, 218, + 90, 91, 92, 90, 91, 92, 90, 91, 92, 466, + 173, 90, 91, 92, 170, 176, 90, 91, 92, 171, + + 90, 91, 92, 174, 178, 466, 172, 179, 218, 466, + 180, 466, 466, 90, 91, 92, 90, 91, 92, 184, + 90, 91, 92, 183, 90, 91, 92, 90, 91, 92, + 181, 466, 466, 178, 466, 179, 182, 185, 180, 466, + 466, 186, 466, 192, 466, 187, 466, 184, 466, 466, + 188, 183, 90, 91, 92, 90, 91, 92, 181, 466, + 189, 90, 91, 92, 182, 185, 90, 91, 92, 186, + 466, 192, 466, 190, 187, 90, 91, 92, 191, 188, + 90, 91, 92, 466, 466, 90, 91, 92, 189, 90, + 91, 92, 193, 195, 466, 194, 196, 466, 90, 91, + + 92, 190, 466, 150, 150, 466, 191, 90, 91, 92, + 90, 91, 92, 197, 200, 73, 90, 91, 92, 201, + 193, 195, 198, 194, 466, 196, 199, 466, 466, 90, + 91, 92, 90, 91, 92, 466, 466, 208, 90, 91, + 92, 197, 466, 200, 73, 209, 466, 201, 90, 91, + 92, 198, 90, 91, 92, 199, 202, 203, 466, 206, + 211, 466, 90, 91, 92, 208, 204, 466, 210, 205, + 207, 213, 466, 209, 90, 91, 92, 90, 91, 92, + 466, 466, 90, 91, 92, 202, 203, 206, 466, 211, + 212, 214, 217, 466, 204, 466, 210, 205, 207, 466, + + 213, 220, 466, 225, 90, 91, 92, 90, 91, 92, + 90, 91, 92, 215, 466, 90, 91, 92, 212, 214, + 216, 217, 219, 90, 91, 92, 466, 90, 91, 92, + 220, 228, 225, 466, 90, 91, 92, 221, 226, 229, + 466, 466, 215, 227, 466, 90, 91, 92, 466, 216, + 219, 466, 466, 90, 91, 92, 90, 91, 92, 466, + 228, 90, 91, 92, 466, 221, 226, 229, 90, 91, + 92, 231, 227, 466, 90, 91, 92, 90, 91, 92, + 235, 90, 91, 92, 232, 466, 233, 90, 91, 92, + 239, 90, 91, 92, 241, 466, 236, 466, 242, 231, + + 466, 234, 466, 237, 466, 90, 91, 92, 466, 235, + 90, 91, 92, 232, 466, 233, 238, 466, 466, 239, + 466, 240, 466, 241, 236, 249, 466, 242, 243, 234, + 244, 466, 237, 466, 90, 91, 92, 245, 90, 91, + 92, 90, 91, 92, 238, 466, 90, 91, 92, 240, + 90, 91, 92, 249, 90, 91, 92, 243, 246, 244, + 90, 91, 92, 247, 466, 245, 248, 466, 252, 250, + 90, 91, 92, 255, 90, 91, 92, 90, 91, 92, + 90, 91, 92, 466, 90, 91, 92, 246, 251, 253, + 466, 466, 247, 254, 248, 256, 252, 250, 90, 91, + + 92, 466, 255, 257, 90, 91, 92, 90, 91, 92, + 90, 91, 92, 90, 91, 92, 251, 466, 253, 90, + 91, 92, 254, 256, 258, 90, 91, 92, 90, 91, + 92, 259, 257, 260, 466, 261, 262, 90, 91, 92, + 466, 90, 91, 92, 466, 90, 91, 92, 466, 466, + 263, 466, 264, 258, 265, 90, 91, 92, 466, 259, + 466, 466, 260, 261, 466, 262, 466, 466, 90, 91, + 92, 90, 91, 92, 266, 466, 90, 91, 92, 263, + 264, 267, 265, 268, 466, 90, 91, 92, 90, 91, + 92, 466, 466, 270, 272, 90, 91, 92, 269, 90, + + 91, 92, 266, 466, 90, 91, 92, 271, 466, 267, + 466, 273, 268, 90, 91, 92, 466, 275, 90, 91, + 92, 270, 274, 272, 466, 276, 269, 90, 91, 92, + 466, 90, 91, 92, 280, 466, 271, 90, 91, 92, + 273, 466, 90, 91, 92, 275, 90, 91, 92, 281, + 274, 277, 279, 276, 90, 91, 92, 90, 91, 92, + 466, 278, 280, 90, 91, 92, 466, 90, 91, 92, + 90, 91, 92, 90, 91, 92, 466, 281, 466, 282, + 277, 279, 283, 284, 287, 466, 285, 466, 466, 278, + 466, 286, 466, 466, 90, 91, 92, 466, 466, 90, + + 91, 92, 466, 466, 90, 91, 92, 282, 466, 296, + 283, 288, 284, 287, 285, 292, 90, 91, 92, 286, + 90, 91, 92, 289, 466, 90, 91, 92, 90, 91, + 92, 90, 91, 92, 466, 90, 91, 92, 296, 288, + 90, 91, 92, 290, 292, 293, 295, 291, 294, 466, + 466, 289, 297, 466, 90, 91, 92, 90, 91, 92, + 90, 91, 92, 466, 90, 91, 92, 298, 466, 299, + 300, 290, 302, 293, 295, 291, 294, 466, 90, 91, + 92, 297, 90, 91, 92, 301, 90, 91, 92, 304, + 90, 91, 92, 466, 306, 466, 298, 299, 466, 300, + + 302, 303, 466, 466, 90, 91, 92, 466, 305, 90, + 91, 92, 466, 301, 466, 90, 91, 92, 304, 307, + 466, 466, 306, 90, 91, 92, 90, 91, 92, 303, + 90, 91, 92, 90, 91, 92, 305, 308, 90, 91, + 92, 90, 91, 92, 90, 91, 92, 307, 90, 91, + 92, 90, 91, 92, 309, 310, 90, 91, 92, 90, + 91, 92, 311, 90, 91, 92, 308, 466, 466, 312, + 466, 315, 466, 466, 318, 313, 314, 317, 90, 91, + 92, 466, 309, 310, 466, 90, 91, 92, 90, 91, + 92, 311, 90, 91, 92, 90, 91, 92, 312, 315, + + 316, 466, 318, 313, 319, 314, 317, 90, 91, 92, + 90, 91, 92, 322, 90, 91, 92, 90, 91, 92, + 320, 90, 91, 92, 90, 91, 92, 321, 316, 323, + 90, 91, 92, 319, 90, 91, 92, 466, 466, 90, + 91, 92, 322, 329, 466, 466, 324, 325, 320, 326, + 327, 466, 90, 91, 92, 321, 328, 323, 330, 90, + 91, 92, 90, 91, 92, 90, 91, 92, 331, 336, + 466, 329, 90, 91, 92, 324, 325, 466, 326, 327, + 466, 466, 90, 91, 92, 328, 330, 466, 332, 333, + 466, 90, 91, 92, 90, 91, 92, 331, 336, 90, + + 91, 92, 90, 91, 92, 90, 91, 92, 90, 91, + 92, 334, 90, 91, 92, 339, 332, 466, 333, 335, + 466, 90, 91, 92, 90, 91, 92, 90, 91, 92, + 337, 90, 91, 92, 338, 90, 91, 92, 342, 466, + 334, 466, 341, 339, 90, 91, 92, 466, 335, 466, + 466, 90, 91, 92, 90, 91, 92, 340, 344, 337, + 466, 466, 338, 343, 90, 91, 92, 342, 466, 466, + 341, 466, 466, 90, 91, 92, 90, 91, 92, 90, + 91, 92, 90, 91, 92, 340, 345, 344, 90, 91, + 92, 343, 346, 90, 91, 92, 90, 91, 92, 90, + + 91, 92, 466, 347, 348, 349, 90, 91, 92, 350, + 90, 91, 92, 466, 345, 466, 351, 352, 466, 466, + 346, 466, 466, 354, 90, 91, 92, 466, 90, 91, + 92, 347, 348, 353, 349, 90, 91, 92, 350, 466, + 355, 90, 91, 92, 351, 466, 352, 90, 91, 92, + 356, 357, 354, 90, 91, 92, 466, 90, 91, 92, + 358, 353, 90, 91, 92, 90, 91, 92, 355, 466, + 363, 367, 90, 91, 92, 90, 91, 92, 356, 357, + 359, 360, 466, 90, 91, 92, 364, 466, 361, 358, + 90, 91, 92, 365, 466, 90, 91, 92, 363, 466, + + 367, 362, 366, 368, 90, 91, 92, 466, 359, 466, + 360, 466, 90, 91, 92, 364, 361, 466, 370, 90, + 91, 92, 365, 90, 91, 92, 90, 91, 92, 362, + 369, 366, 368, 90, 91, 92, 90, 91, 92, 466, + 90, 91, 92, 90, 91, 92, 370, 371, 372, 90, + 91, 92, 373, 466, 90, 91, 92, 466, 369, 90, + 91, 92, 374, 90, 91, 92, 375, 90, 91, 92, + 90, 91, 92, 466, 466, 371, 372, 90, 91, 92, + 376, 373, 90, 91, 92, 90, 91, 92, 377, 466, + 374, 466, 90, 91, 92, 375, 379, 378, 90, 91, + + 92, 90, 91, 92, 381, 90, 91, 92, 376, 384, + 466, 380, 90, 91, 92, 466, 466, 377, 90, 91, + 92, 90, 91, 92, 466, 379, 378, 382, 383, 466, + 466, 385, 466, 381, 90, 91, 92, 466, 384, 380, + 386, 466, 90, 91, 92, 90, 91, 92, 90, 91, + 92, 387, 90, 91, 92, 382, 383, 90, 91, 92, + 385, 90, 91, 92, 388, 466, 90, 91, 92, 386, + 466, 90, 91, 92, 90, 91, 92, 466, 389, 387, + 90, 91, 92, 90, 91, 92, 390, 90, 91, 92, + 90, 91, 92, 388, 466, 391, 90, 91, 92, 392, + + 393, 90, 91, 92, 394, 466, 389, 395, 90, 91, + 92, 90, 91, 92, 466, 390, 466, 466, 90, 91, + 92, 90, 91, 92, 391, 90, 91, 92, 392, 393, + 396, 399, 394, 400, 397, 395, 398, 466, 90, 91, + 92, 90, 91, 92, 90, 91, 92, 90, 91, 92, + 90, 91, 92, 90, 91, 92, 90, 91, 92, 396, + 399, 400, 466, 397, 402, 398, 401, 90, 91, 92, + 403, 90, 91, 92, 407, 466, 90, 91, 92, 90, + 91, 92, 90, 91, 92, 404, 90, 91, 92, 405, + 90, 91, 92, 402, 401, 406, 466, 408, 403, 90, + + 91, 92, 407, 90, 91, 92, 90, 91, 92, 90, + 91, 92, 466, 404, 466, 90, 91, 92, 405, 409, + 90, 91, 92, 410, 406, 408, 411, 90, 91, 92, + 90, 91, 92, 412, 90, 91, 92, 90, 91, 92, + 90, 91, 92, 90, 91, 92, 413, 466, 409, 90, + 91, 92, 410, 466, 466, 411, 415, 414, 90, 91, + 92, 466, 412, 90, 91, 92, 466, 466, 416, 418, + 466, 90, 91, 92, 466, 413, 420, 90, 91, 92, + 90, 91, 92, 417, 415, 414, 90, 91, 92, 90, + 91, 92, 466, 90, 91, 92, 416, 419, 418, 90, + + 91, 92, 90, 91, 92, 420, 421, 90, 91, 92, + 422, 417, 90, 91, 92, 466, 466, 90, 91, 92, + 90, 91, 92, 423, 424, 466, 90, 91, 92, 466, + 466, 90, 91, 92, 425, 421, 426, 466, 422, 90, + 91, 92, 90, 91, 92, 466, 427, 90, 91, 92, + 429, 423, 428, 424, 90, 91, 92, 466, 466, 90, + 91, 92, 425, 430, 426, 431, 90, 91, 92, 433, + 466, 90, 91, 92, 427, 432, 90, 91, 92, 429, + 428, 90, 91, 92, 90, 91, 92, 466, 90, 91, + 92, 430, 435, 431, 466, 90, 91, 92, 433, 434, + + 90, 91, 92, 432, 90, 91, 92, 90, 91, 92, + 466, 90, 91, 92, 90, 91, 92, 90, 91, 92, + 435, 90, 91, 92, 90, 91, 92, 436, 434, 438, + 90, 91, 92, 439, 440, 90, 91, 92, 90, 91, + 92, 441, 466, 437, 466, 442, 90, 91, 92, 466, + 466, 90, 91, 92, 466, 466, 436, 438, 443, 466, + 466, 444, 439, 440, 90, 91, 92, 445, 466, 447, + 441, 437, 446, 442, 90, 91, 92, 90, 91, 92, + 90, 91, 92, 90, 91, 92, 443, 90, 91, 92, + 444, 466, 466, 90, 91, 92, 445, 448, 447, 449, + + 446, 90, 91, 92, 90, 91, 92, 90, 91, 92, + 450, 90, 91, 92, 466, 451, 466, 452, 466, 90, + 91, 92, 90, 91, 92, 448, 466, 449, 90, 91, + 92, 90, 91, 92, 453, 466, 90, 91, 92, 450, + 466, 90, 91, 92, 451, 466, 452, 90, 91, 92, + 90, 91, 92, 90, 91, 92, 90, 91, 92, 90, + 91, 92, 453, 90, 91, 92, 90, 91, 92, 90, + 91, 92, 90, 91, 92, 454, 90, 91, 92, 455, + 456, 90, 91, 92, 90, 91, 92, 457, 466, 466, + 458, 466, 464, 459, 90, 91, 92, 90, 91, 92, + + 90, 91, 92, 466, 454, 466, 463, 455, 456, 466, + 466, 460, 466, 461, 466, 457, 90, 91, 92, 458, + 464, 466, 459, 466, 90, 91, 92, 90, 91, 92, + 90, 91, 92, 462, 466, 463, 90, 91, 92, 460, + 465, 461, 90, 91, 92, 90, 91, 92, 90, 91, + 92, 90, 91, 92, 466, 466, 466, 466, 466, 466, + 466, 462, 90, 91, 92, 466, 466, 466, 465, 466, + 90, 91, 92, 466, 466, 466, 466, 466, 466, 466, + 466, 90, 91, 92, 64, 466, 64, 64, 64, 64, + 64, 66, 466, 66, 66, 66, 66, 66, 75, 75, + + 83, 83, 83, 83, 141, 466, 141, 141, 141, 141, + 141, 143, 466, 143, 143, 143, 143, 143, 153, 153, + 223, 223, 223, 5, 466, 466, 466, 466, 466, 466, + 466, 466, 466, 466, 466, 466, 466, 466, 466, 466, + 466, 466, 466, 466, 466, 466, 466, 466, 466, 466, + 466, 466, 466, 466, 466, 466, 466, 466, 466, 466, + 466, 466, 466, 466, 466, 466, 466, 466, 466, 466, + 466, 466, 466, 466, 466, 466, 466, 466, 466, 466, + 466, 466, 466, 466, 466, 466, 466, 466, 466, 466, + 466, 466, 466, 466, 466, 466, 466, 466, 466, 466, + + 466, 466, 466, 466, 466, 466, 466, 466 + } ; + +static const flex_int16_t yy_chk[2509] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 3, 4, 8, 8, 9, 9, + 21, 21, 23, 32, 23, 23, 24, 40, 24, 24, + + 27, 27, 27, 29, 29, 34, 23, 62, 62, 34, + 24, 82, 82, 3, 4, 38, 38, 38, 230, 36, + 151, 151, 32, 42, 224, 23, 40, 36, 69, 69, + 83, 83, 83, 36, 34, 23, 152, 152, 34, 24, + 69, 110, 110, 110, 223, 32, 32, 32, 36, 40, + 40, 40, 42, 23, 31, 31, 36, 34, 34, 34, + 35, 36, 35, 162, 31, 161, 31, 35, 41, 69, + 148, 31, 35, 31, 50, 36, 36, 36, 147, 42, + 42, 42, 144, 31, 31, 143, 37, 141, 35, 140, + 35, 92, 31, 37, 31, 35, 91, 41, 90, 31, + + 35, 31, 43, 50, 67, 35, 35, 35, 43, 31, + 31, 31, 33, 154, 154, 37, 41, 41, 41, 33, + 66, 37, 50, 50, 50, 65, 33, 64, 61, 33, + 43, 59, 33, 58, 98, 57, 43, 55, 37, 37, + 37, 33, 54, 53, 43, 43, 43, 30, 33, 71, + 71, 28, 46, 22, 33, 52, 46, 33, 20, 44, + 33, 71, 98, 44, 14, 11, 46, 44, 33, 33, + 33, 39, 39, 98, 98, 98, 45, 10, 39, 39, + 7, 46, 5, 0, 39, 46, 0, 44, 0, 0, + 71, 44, 0, 45, 46, 44, 47, 120, 120, 120, + + 39, 39, 44, 44, 44, 45, 39, 39, 46, 46, + 46, 47, 39, 0, 49, 0, 49, 0, 0, 49, + 0, 45, 39, 39, 39, 47, 51, 51, 52, 52, + 52, 0, 45, 45, 45, 0, 48, 0, 0, 47, + 48, 0, 49, 48, 49, 84, 0, 49, 47, 47, + 47, 0, 0, 48, 0, 51, 51, 49, 49, 49, + 72, 0, 72, 72, 0, 48, 121, 121, 121, 48, + 0, 85, 48, 84, 72, 51, 51, 51, 73, 0, + 73, 48, 88, 73, 73, 86, 0, 84, 84, 84, + 89, 0, 48, 48, 48, 60, 60, 87, 0, 85, + + 146, 146, 146, 72, 0, 60, 0, 60, 85, 85, + 85, 88, 60, 86, 60, 0, 93, 60, 89, 86, + 86, 86, 0, 0, 60, 60, 87, 89, 89, 89, + 94, 95, 104, 60, 97, 60, 88, 88, 88, 0, + 60, 0, 60, 102, 93, 60, 96, 0, 96, 0, + 87, 87, 87, 93, 93, 93, 0, 0, 94, 0, + 95, 104, 100, 97, 0, 99, 103, 0, 94, 94, + 94, 99, 102, 0, 96, 101, 96, 0, 99, 136, + 104, 104, 104, 95, 95, 95, 97, 97, 97, 0, + 100, 96, 96, 96, 99, 103, 102, 102, 102, 99, + + 100, 100, 100, 101, 105, 0, 99, 105, 136, 0, + 106, 0, 0, 101, 101, 101, 99, 99, 99, 109, + 103, 103, 103, 108, 158, 158, 158, 136, 136, 136, + 107, 0, 0, 105, 0, 105, 107, 111, 106, 0, + 0, 112, 0, 116, 0, 113, 0, 109, 0, 0, + 113, 108, 105, 105, 105, 106, 106, 106, 107, 0, + 113, 109, 109, 109, 107, 111, 108, 108, 108, 112, + 0, 116, 0, 114, 113, 107, 107, 107, 115, 113, + 111, 111, 111, 0, 0, 112, 112, 112, 113, 116, + 116, 116, 117, 119, 0, 118, 122, 0, 113, 113, + + 113, 114, 0, 150, 150, 0, 115, 159, 159, 159, + 115, 115, 115, 123, 125, 150, 114, 114, 114, 125, + 117, 119, 124, 118, 0, 122, 124, 0, 0, 117, + 117, 117, 118, 118, 118, 0, 0, 128, 119, 119, + 119, 123, 0, 125, 150, 128, 0, 125, 122, 122, + 122, 124, 123, 123, 123, 124, 126, 126, 0, 127, + 130, 0, 125, 125, 125, 128, 126, 0, 129, 126, + 127, 132, 0, 128, 124, 124, 124, 175, 175, 175, + 0, 0, 128, 128, 128, 126, 126, 127, 0, 130, + 131, 133, 135, 0, 126, 0, 129, 126, 127, 0, + + 132, 138, 0, 149, 127, 127, 127, 126, 126, 126, + 129, 129, 129, 134, 0, 130, 130, 130, 131, 133, + 134, 135, 137, 132, 132, 132, 0, 133, 133, 133, + 138, 157, 149, 0, 131, 131, 131, 139, 155, 160, + 0, 0, 134, 156, 0, 135, 135, 135, 0, 134, + 137, 0, 0, 138, 138, 138, 149, 149, 149, 0, + 157, 137, 137, 137, 0, 139, 155, 160, 134, 134, + 134, 163, 156, 0, 139, 139, 139, 155, 155, 155, + 165, 160, 160, 160, 164, 0, 164, 157, 157, 157, + 168, 156, 156, 156, 170, 0, 166, 0, 170, 163, + + 0, 164, 0, 167, 0, 163, 163, 163, 0, 165, + 191, 191, 191, 164, 0, 164, 167, 0, 0, 168, + 0, 169, 0, 170, 166, 178, 0, 170, 171, 164, + 172, 0, 167, 0, 165, 165, 165, 173, 164, 164, + 164, 166, 166, 166, 167, 0, 168, 168, 168, 169, + 170, 170, 170, 178, 167, 167, 167, 171, 174, 172, + 169, 169, 169, 176, 0, 173, 177, 0, 181, 179, + 178, 178, 178, 184, 173, 173, 173, 209, 209, 209, + 171, 171, 171, 0, 172, 172, 172, 174, 180, 182, + 0, 0, 176, 183, 177, 185, 181, 179, 225, 225, + + 225, 0, 184, 186, 177, 177, 177, 179, 179, 179, + 174, 174, 174, 181, 181, 181, 180, 0, 182, 176, + 176, 176, 183, 185, 187, 180, 180, 180, 184, 184, + 184, 188, 186, 189, 0, 190, 192, 185, 185, 185, + 0, 182, 182, 182, 0, 183, 183, 183, 0, 0, + 193, 0, 194, 187, 195, 186, 186, 186, 0, 188, + 0, 0, 189, 190, 0, 192, 0, 0, 188, 188, + 188, 190, 190, 190, 196, 0, 187, 187, 187, 193, + 194, 197, 195, 198, 0, 189, 189, 189, 192, 192, + 192, 0, 0, 200, 202, 194, 194, 194, 199, 195, + + 195, 195, 196, 0, 193, 193, 193, 201, 0, 197, + 0, 203, 198, 196, 196, 196, 0, 205, 197, 197, + 197, 200, 204, 202, 0, 206, 199, 233, 233, 233, + 0, 200, 200, 200, 210, 0, 201, 198, 198, 198, + 203, 0, 199, 199, 199, 205, 202, 202, 202, 211, + 204, 207, 208, 206, 205, 205, 205, 201, 201, 201, + 0, 207, 210, 203, 203, 203, 0, 204, 204, 204, + 206, 206, 206, 210, 210, 210, 0, 211, 0, 212, + 207, 208, 213, 214, 217, 0, 215, 0, 0, 207, + 0, 216, 0, 0, 211, 211, 211, 0, 0, 207, + + 207, 207, 0, 0, 208, 208, 208, 212, 0, 229, + 213, 218, 214, 217, 215, 221, 234, 234, 234, 216, + 212, 212, 212, 219, 0, 213, 213, 213, 215, 215, + 215, 216, 216, 216, 0, 214, 214, 214, 229, 218, + 217, 217, 217, 220, 221, 226, 228, 220, 227, 0, + 0, 219, 231, 0, 218, 218, 218, 229, 229, 229, + 219, 219, 219, 0, 221, 221, 221, 232, 0, 235, + 236, 220, 238, 226, 228, 220, 227, 0, 228, 228, + 228, 231, 226, 226, 226, 237, 220, 220, 220, 240, + 227, 227, 227, 0, 242, 0, 232, 235, 0, 236, + + 238, 239, 0, 0, 231, 231, 231, 0, 241, 238, + 238, 238, 0, 237, 0, 235, 235, 235, 240, 243, + 0, 0, 242, 232, 232, 232, 236, 236, 236, 239, + 237, 237, 237, 242, 242, 242, 241, 245, 239, 239, + 239, 240, 240, 240, 241, 241, 241, 243, 244, 244, + 244, 246, 246, 246, 247, 248, 243, 243, 243, 249, + 249, 249, 250, 255, 255, 255, 245, 0, 0, 251, + 0, 254, 0, 0, 258, 252, 253, 257, 262, 262, + 262, 0, 247, 248, 0, 245, 245, 245, 265, 265, + 265, 250, 248, 248, 248, 247, 247, 247, 251, 254, + + 256, 0, 258, 252, 259, 253, 257, 258, 258, 258, + 254, 254, 254, 263, 250, 250, 250, 252, 252, 252, + 260, 251, 251, 251, 253, 253, 253, 261, 256, 264, + 257, 257, 257, 259, 266, 266, 266, 0, 0, 256, + 256, 256, 263, 272, 0, 0, 267, 268, 260, 269, + 270, 0, 259, 259, 259, 261, 271, 264, 273, 260, + 260, 260, 263, 263, 263, 264, 264, 264, 274, 280, + 0, 272, 261, 261, 261, 267, 268, 0, 269, 270, + 0, 0, 272, 272, 272, 271, 273, 0, 275, 276, + 0, 273, 273, 273, 267, 267, 267, 274, 280, 268, + + 268, 268, 270, 270, 270, 269, 269, 269, 271, 271, + 271, 277, 278, 278, 278, 285, 275, 0, 276, 279, + 0, 280, 280, 280, 274, 274, 274, 275, 275, 275, + 281, 283, 283, 283, 282, 284, 284, 284, 288, 0, + 277, 0, 287, 285, 276, 276, 276, 0, 279, 0, + 0, 285, 285, 285, 290, 290, 290, 286, 291, 281, + 0, 0, 282, 289, 277, 277, 277, 288, 0, 0, + 287, 0, 0, 279, 279, 279, 282, 282, 282, 287, + 287, 287, 281, 281, 281, 286, 292, 291, 288, 288, + 288, 289, 294, 286, 286, 286, 293, 293, 293, 289, + + 289, 289, 0, 295, 296, 297, 299, 299, 299, 298, + 291, 291, 291, 0, 292, 0, 300, 301, 0, 0, + 294, 0, 0, 303, 311, 311, 311, 0, 292, 292, + 292, 295, 296, 302, 297, 294, 294, 294, 298, 0, + 304, 295, 295, 295, 300, 0, 301, 296, 296, 296, + 305, 306, 303, 300, 300, 300, 0, 297, 297, 297, + 307, 302, 298, 298, 298, 301, 301, 301, 304, 0, + 313, 317, 302, 302, 302, 303, 303, 303, 305, 306, + 308, 309, 0, 304, 304, 304, 314, 0, 310, 307, + 306, 306, 306, 315, 0, 305, 305, 305, 313, 0, + + 317, 312, 316, 319, 313, 313, 313, 0, 308, 0, + 309, 0, 307, 307, 307, 314, 310, 0, 321, 317, + 317, 317, 315, 308, 308, 308, 310, 310, 310, 312, + 320, 316, 319, 309, 309, 309, 314, 314, 314, 0, + 312, 312, 312, 318, 318, 318, 321, 323, 324, 315, + 315, 315, 325, 0, 316, 316, 316, 0, 320, 319, + 319, 319, 326, 321, 321, 321, 329, 320, 320, 320, + 322, 322, 322, 0, 0, 323, 324, 327, 327, 327, + 330, 325, 328, 328, 328, 324, 324, 324, 331, 0, + 326, 0, 323, 323, 323, 329, 333, 332, 334, 334, + + 334, 326, 326, 326, 336, 325, 325, 325, 330, 340, + 0, 335, 337, 337, 337, 0, 0, 331, 329, 329, + 329, 330, 330, 330, 0, 333, 332, 338, 339, 0, + 0, 341, 0, 336, 342, 342, 342, 0, 340, 335, + 343, 0, 331, 331, 331, 332, 332, 332, 335, 335, + 335, 345, 333, 333, 333, 338, 339, 336, 336, 336, + 341, 340, 340, 340, 348, 0, 338, 338, 338, 343, + 0, 339, 339, 339, 344, 344, 344, 0, 349, 345, + 346, 346, 346, 341, 341, 341, 350, 345, 345, 345, + 347, 347, 347, 348, 0, 351, 343, 343, 343, 352, + + 353, 354, 354, 354, 355, 0, 349, 356, 358, 358, + 358, 360, 360, 360, 0, 350, 0, 0, 348, 348, + 348, 349, 349, 349, 351, 361, 361, 361, 352, 353, + 357, 363, 355, 364, 357, 356, 359, 0, 350, 350, + 350, 355, 355, 355, 356, 356, 356, 351, 351, 351, + 362, 362, 362, 352, 352, 352, 353, 353, 353, 357, + 363, 364, 0, 357, 367, 359, 365, 366, 366, 366, + 368, 369, 369, 369, 374, 0, 364, 364, 364, 363, + 363, 363, 370, 370, 370, 371, 357, 357, 357, 372, + 359, 359, 359, 367, 365, 373, 0, 375, 368, 376, + + 376, 376, 374, 365, 365, 365, 374, 374, 374, 380, + 380, 380, 0, 371, 0, 368, 368, 368, 372, 377, + 367, 367, 367, 378, 373, 375, 379, 381, 381, 381, + 371, 371, 371, 382, 384, 384, 384, 372, 372, 372, + 375, 375, 375, 373, 373, 373, 383, 0, 377, 385, + 385, 385, 378, 0, 0, 379, 387, 386, 389, 389, + 389, 0, 382, 390, 390, 390, 0, 0, 388, 393, + 0, 377, 377, 377, 0, 383, 396, 378, 378, 378, + 379, 379, 379, 392, 387, 386, 391, 391, 391, 382, + 382, 382, 0, 387, 387, 387, 388, 394, 393, 383, + + 383, 383, 386, 386, 386, 396, 397, 388, 388, 388, + 398, 392, 395, 395, 395, 0, 0, 393, 393, 393, + 392, 392, 392, 399, 401, 0, 394, 394, 394, 0, + 0, 396, 396, 396, 402, 397, 403, 0, 398, 400, + 400, 400, 404, 404, 404, 0, 405, 398, 398, 398, + 408, 399, 406, 401, 407, 407, 407, 0, 0, 397, + 397, 397, 402, 410, 403, 411, 399, 399, 399, 413, + 0, 402, 402, 402, 405, 412, 401, 401, 401, 408, + 406, 403, 403, 403, 409, 409, 409, 0, 405, 405, + 405, 410, 418, 411, 0, 406, 406, 406, 413, 416, + + 410, 410, 410, 412, 408, 408, 408, 414, 414, 414, + 0, 411, 411, 411, 412, 412, 412, 415, 415, 415, + 418, 413, 413, 413, 417, 417, 417, 419, 416, 420, + 421, 421, 421, 423, 424, 418, 418, 418, 422, 422, + 422, 425, 0, 419, 0, 426, 430, 430, 430, 0, + 0, 416, 416, 416, 0, 0, 419, 420, 427, 0, + 0, 428, 423, 424, 431, 431, 431, 429, 0, 433, + 425, 419, 432, 426, 420, 420, 420, 426, 426, 426, + 419, 419, 419, 423, 423, 423, 427, 424, 424, 424, + 428, 0, 0, 425, 425, 425, 429, 434, 433, 435, + + 432, 427, 427, 427, 432, 432, 432, 439, 439, 439, + 436, 428, 428, 428, 0, 437, 0, 438, 0, 429, + 429, 429, 433, 433, 433, 434, 0, 435, 440, 440, + 440, 441, 441, 441, 445, 0, 435, 435, 435, 436, + 0, 434, 434, 434, 437, 0, 438, 442, 442, 442, + 443, 443, 443, 444, 444, 444, 446, 446, 446, 447, + 447, 447, 445, 437, 437, 437, 436, 436, 436, 438, + 438, 438, 445, 445, 445, 448, 449, 449, 449, 450, + 451, 452, 452, 452, 453, 453, 453, 454, 0, 0, + 455, 0, 463, 456, 458, 458, 458, 460, 460, 460, + + 465, 465, 465, 0, 448, 0, 462, 450, 451, 0, + 0, 457, 0, 459, 0, 454, 450, 450, 450, 455, + 463, 0, 456, 0, 451, 451, 451, 448, 448, 448, + 454, 454, 454, 461, 0, 462, 463, 463, 463, 457, + 464, 459, 455, 455, 455, 456, 456, 456, 457, 457, + 457, 459, 459, 459, 0, 0, 0, 0, 0, 0, + 0, 461, 462, 462, 462, 0, 0, 0, 464, 0, + 461, 461, 461, 0, 0, 0, 0, 0, 0, 0, + 0, 464, 464, 464, 467, 0, 467, 467, 467, 467, + 467, 468, 0, 468, 468, 468, 468, 468, 469, 469, + + 470, 470, 470, 470, 471, 0, 471, 471, 471, 471, + 471, 472, 0, 472, 472, 472, 472, 472, 473, 473, + 474, 474, 474, 466, 466, 466, 466, 466, 466, 466, + 466, 466, 466, 466, 466, 466, 466, 466, 466, 466, + 466, 466, 466, 466, 466, 466, 466, 466, 466, 466, + 466, 466, 466, 466, 466, 466, 466, 466, 466, 466, + 466, 466, 466, 466, 466, 466, 466, 466, 466, 466, + 466, 466, 466, 466, 466, 466, 466, 466, 466, 466, + 466, 466, 466, 466, 466, 466, 466, 466, 466, 466, + 466, 466, 466, 466, 466, 466, 466, 466, 466, 466, + + 466, 466, 466, 466, 466, 466, 466, 466 + } ; + +static const flex_int16_t yy_rule_linenum[123] = + { 0, + 80, 81, 83, 89, 113, 114, 115, 117, 118, 119, + 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, + 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, + 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, + 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, + 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, + 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, + 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, + 190, 191, 192, 193, 194, 195, 196, 197, 199, 200, + 201, 202, 203, 204, 205, 206, 207, 209, 210, 211, + + 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, + 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, + 232, 234 + } ; + +/* The intent behind this definition is that it'll catch + * any uses of REJECT which flex missed. + */ +#define REJECT reject_used_but_not_detected +#define yymore() yymore_used_but_not_detected +#define YY_MORE_ADJ 0 +#define YY_RESTORE_YY_MORE_OFFSET +#line 1 "sqlite3_lexer.ll" +#line 2 "sqlite3_lexer.ll" +#include +#include "ParserDriver.h" +#include "sqlite3_parser.hpp" +#line 1235 "sqlite3_lexer.cpp" +#define YY_NO_UNISTD_H 1 +#line 12 "sqlite3_lexer.ll" + #define TOKEN(n) sqlb::parser::parser::symbol_type(sqlb::parser::parser::token::TOK_##n, yytext, loc) + + std::string unquote_string(std::string s, char quote_char) + { + if(s.size() < 2) + return s; + + if(quote_char == '[') + { + if(s.front() == '[' && s.back() == ']') + s = s.substr(1, s.size()-2); + } else { + if(s.front() == quote_char && s.back() == quote_char) + { + s = s.substr(1, s.size()-2); + auto pos = s.npos; + while((pos = s.find(std::string(2, quote_char))) != s.npos) + s = s.replace(pos, 2, std::string(1, quote_char)); + } + } + + return s; + } +#line 1261 "sqlite3_lexer.cpp" +#line 55 "sqlite3_lexer.ll" + /* TODO Add $ bind parameters */ + // Code run each time a pattern is matched. + #define YY_USER_ACTION loc.columns(yyleng); +#line 1266 "sqlite3_lexer.cpp" + +#line 1268 "sqlite3_lexer.cpp" + +#define INITIAL 0 +#define BETWEEN_MODE 1 + +#ifndef YY_NO_UNISTD_H +/* Special case for "unistd.h", since it is non-ANSI. We include it way + * down here because we want the user's section 1 to have been scanned first. + * The user has a chance to override it with an option. + */ +/* %if-c-only */ +#include +/* %endif */ +/* %if-c++-only */ +/* %endif */ +#endif + +#ifndef YY_EXTRA_TYPE +#define YY_EXTRA_TYPE void * +#endif + +/* %if-c-only Reentrant structure and macros (non-C++). */ +/* %if-reentrant */ + +/* Holds the entire state of the reentrant scanner. */ +struct yyguts_t + { + + /* User-defined. Not touched by flex. */ + YY_EXTRA_TYPE yyextra_r; + + /* The rest are the same as the globals declared in the non-reentrant scanner. */ + FILE *yyin_r, *yyout_r; + size_t yy_buffer_stack_top; /**< index of top of stack. */ + size_t yy_buffer_stack_max; /**< capacity of stack. */ + YY_BUFFER_STATE * yy_buffer_stack; /**< Stack as an array. */ + char yy_hold_char; + int yy_n_chars; + int yyleng_r; + char *yy_c_buf_p; + int yy_init; + int yy_start; + int yy_did_buffer_switch_on_eof; + int yy_start_stack_ptr; + int yy_start_stack_depth; + int *yy_start_stack; + yy_state_type yy_last_accepting_state; + char* yy_last_accepting_cpos; + + int yylineno_r; + int yy_flex_debug_r; + + char *yytext_r; + int yy_more_flag; + int yy_more_len; + + }; /* end struct yyguts_t */ + +/* %if-c-only */ + +static int yy_init_globals ( yyscan_t yyscanner ); + +/* %endif */ + +/* %if-reentrant */ + +int yylex_init (yyscan_t* scanner); + +int yylex_init_extra ( YY_EXTRA_TYPE user_defined, yyscan_t* scanner); + +/* %endif */ + +/* %endif End reentrant structures and macros. */ + +/* Accessor methods to globals. + These are made visible to non-reentrant scanners for convenience. */ + +int yylex_destroy ( yyscan_t yyscanner ); + +int yyget_debug ( yyscan_t yyscanner ); + +void yyset_debug ( int debug_flag , yyscan_t yyscanner ); + +YY_EXTRA_TYPE yyget_extra ( yyscan_t yyscanner ); + +void yyset_extra ( YY_EXTRA_TYPE user_defined , yyscan_t yyscanner ); + +FILE *yyget_in ( yyscan_t yyscanner ); + +void yyset_in ( FILE * _in_str , yyscan_t yyscanner ); + +FILE *yyget_out ( yyscan_t yyscanner ); + +void yyset_out ( FILE * _out_str , yyscan_t yyscanner ); + + int yyget_leng ( yyscan_t yyscanner ); + +char *yyget_text ( yyscan_t yyscanner ); + +int yyget_lineno ( yyscan_t yyscanner ); + +void yyset_lineno ( int _line_number , yyscan_t yyscanner ); + +int yyget_column ( yyscan_t yyscanner ); + +void yyset_column ( int _column_no , yyscan_t yyscanner ); + +/* %if-bison-bridge */ +/* %endif */ + +/* Macros after this point can all be overridden by user definitions in + * section 1. + */ + +#ifndef YY_SKIP_YYWRAP +#ifdef __cplusplus +extern "C" int yywrap ( yyscan_t yyscanner ); +#else +extern int yywrap ( yyscan_t yyscanner ); +#endif +#endif + +/* %not-for-header */ +#ifndef YY_NO_UNPUT + +#endif +/* %ok-for-header */ + +/* %endif */ + +#ifndef yytext_ptr +static void yy_flex_strncpy ( char *, const char *, int , yyscan_t yyscanner); +#endif + +#ifdef YY_NEED_STRLEN +static int yy_flex_strlen ( const char * , yyscan_t yyscanner); +#endif + +#ifndef YY_NO_INPUT +/* %if-c-only Standard (non-C++) definition */ +/* %not-for-header */ +#ifdef __cplusplus +static int yyinput ( yyscan_t yyscanner ); +#else +static int input ( yyscan_t yyscanner ); +#endif +/* %ok-for-header */ + +/* %endif */ +#endif + +/* %if-c-only */ + +/* %endif */ + +/* Amount of stuff to slurp up with each read. */ +#ifndef YY_READ_BUF_SIZE +#ifdef __ia64__ +/* On IA-64, the buffer size is 16k, not 8k */ +#define YY_READ_BUF_SIZE 16384 +#else +#define YY_READ_BUF_SIZE 8192 +#endif /* __ia64__ */ +#endif + +/* Copy whatever the last rule matched to the standard output. */ +#ifndef ECHO +/* %if-c-only Standard (non-C++) definition */ +/* This used to be an fputs(), but since the string might contain NUL's, + * we now use fwrite(). + */ +#define ECHO do { if (fwrite( yytext, (size_t) yyleng, 1, yyout )) {} } while (0) +/* %endif */ +/* %if-c++-only C++ definition */ +/* %endif */ +#endif + +/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL, + * is returned in "result". + */ +#ifndef YY_INPUT +#define YY_INPUT(buf,result,max_size) \ +/* %% [5.0] fread()/read() definition of YY_INPUT goes here unless we're doing C++ \ */\ + if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \ + { \ + int c = '*'; \ + int n; \ + for ( n = 0; n < max_size && \ + (c = getc( yyin )) != EOF && c != '\n'; ++n ) \ + buf[n] = (char) c; \ + if ( c == '\n' ) \ + buf[n++] = (char) c; \ + if ( c == EOF && ferror( yyin ) ) \ + YY_FATAL_ERROR( "input in flex scanner failed" ); \ + result = n; \ + } \ + else \ + { \ + errno=0; \ + while ( (result = (int) fread(buf, 1, (yy_size_t) max_size, yyin)) == 0 && ferror(yyin)) \ + { \ + if( errno != EINTR) \ + { \ + YY_FATAL_ERROR( "input in flex scanner failed" ); \ + break; \ + } \ + errno=0; \ + clearerr(yyin); \ + } \ + }\ +\ +/* %if-c++-only C++ definition \ */\ +/* %endif */ + +#endif + +/* No semi-colon after return; correct usage is to write "yyterminate();" - + * we don't want an extra ';' after the "return" because that will cause + * some compilers to complain about unreachable statements. + */ +#ifndef yyterminate +#define yyterminate() return YY_NULL +#endif + +/* Number of entries by which start-condition stack grows. */ +#ifndef YY_START_STACK_INCR +#define YY_START_STACK_INCR 25 +#endif + +/* Report a fatal error. */ +#ifndef YY_FATAL_ERROR +/* %if-c-only */ +#define YY_FATAL_ERROR(msg) yy_fatal_error( msg , yyscanner) +/* %endif */ +/* %if-c++-only */ +/* %endif */ +#endif + +/* %if-tables-serialization structures and prototypes */ +/* %not-for-header */ +/* %ok-for-header */ + +/* %not-for-header */ +/* %tables-yydmap generated elements */ +/* %endif */ +/* end tables serialization structures and prototypes */ + +/* %ok-for-header */ + +/* Default declaration of generated scanner - a define so the user can + * easily add parameters. + */ +#ifndef YY_DECL +#define YY_DECL_IS_OURS 1 +/* %if-c-only Standard (non-C++) definition */ + +extern int yylex (yyscan_t yyscanner); + +#define YY_DECL int yylex (yyscan_t yyscanner) +/* %endif */ +/* %if-c++-only C++ definition */ +/* %endif */ +#endif /* !YY_DECL */ + +/* Code executed at the beginning of each rule, after yytext and yyleng + * have been set up. + */ +#ifndef YY_USER_ACTION +#define YY_USER_ACTION +#endif + +/* Code executed at the end of each rule. */ +#ifndef YY_BREAK +#define YY_BREAK /*LINTED*/break; +#endif + +/* %% [6.0] YY_RULE_SETUP definition goes here */ +#define YY_RULE_SETUP \ + YY_USER_ACTION + +/* %not-for-header */ +/** The main scanner function which does all the work. + */ +YY_DECL +{ + yy_state_type yy_current_state; + char *yy_cp, *yy_bp; + int yy_act; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + if ( !yyg->yy_init ) + { + yyg->yy_init = 1; + +#ifdef YY_USER_INIT + YY_USER_INIT; +#endif + + if ( ! yyg->yy_start ) + yyg->yy_start = 1; /* first start state */ + + if ( ! yyin ) +/* %if-c-only */ + yyin = stdin; +/* %endif */ +/* %if-c++-only */ +/* %endif */ + + if ( ! yyout ) +/* %if-c-only */ + yyout = stdout; +/* %endif */ +/* %if-c++-only */ +/* %endif */ + + if ( ! YY_CURRENT_BUFFER ) { + yyensure_buffer_stack (yyscanner); + YY_CURRENT_BUFFER_LVALUE = + yy_create_buffer( yyin, YY_BUF_SIZE , yyscanner); + } + + yy_load_buffer_state( yyscanner ); + } + + { +/* %% [7.0] user's declarations go here */ +#line 69 "sqlite3_lexer.ll" + + + +#line 73 "sqlite3_lexer.ll" + // Shortcut to the location held by the driver + sqlb::parser::location& loc = drv.location; + + // Code run each time yylex is called. + loc.step(); + + +#line 1606 "sqlite3_lexer.cpp" + + while ( /*CONSTCOND*/1 ) /* loops until end-of-file is reached */ + { +/* %% [8.0] yymore()-related code goes here */ + yy_cp = yyg->yy_c_buf_p; + + /* Support of yytext. */ + *yy_cp = yyg->yy_hold_char; + + /* yy_bp points to the position in yy_ch_buf of the start of + * the current run. + */ + yy_bp = yy_cp; + +/* %% [9.0] code to set up and find next match goes here */ + yy_current_state = yyg->yy_start; +yy_match: + do + { + YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)] ; + if ( yy_accept[yy_current_state] ) + { + yyg->yy_last_accepting_state = yy_current_state; + yyg->yy_last_accepting_cpos = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 467 ) + yy_c = yy_meta[yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; + ++yy_cp; + } + while ( yy_current_state != 466 ); + yy_cp = yyg->yy_last_accepting_cpos; + yy_current_state = yyg->yy_last_accepting_state; + +yy_find_action: +/* %% [10.0] code to find the action number goes here */ + yy_act = yy_accept[yy_current_state]; + + YY_DO_BEFORE_ACTION; + +/* %% [11.0] code for yylineno update goes here */ + +do_action: /* This label is used only to access EOF actions. */ + +/* %% [12.0] debug code goes here */ + if ( yy_flex_debug ) + { + if ( yy_act == 0 ) + fprintf( stderr, "--scanner backing up\n" ); + else if ( yy_act < 123 ) + fprintf( stderr, "--accepting rule at line %ld (\"%s\")\n", + (long)yy_rule_linenum[yy_act], yytext ); + else if ( yy_act == 123 ) + fprintf( stderr, "--accepting default rule (\"%s\")\n", + yytext ); + else if ( yy_act == 124 ) + fprintf( stderr, "--(end of buffer or a NUL)\n" ); + else + fprintf( stderr, "--EOF (start condition %d)\n", YY_START ); + } + + switch ( yy_act ) + { /* beginning of action switch */ +/* %% [13.0] actions go here */ + case 0: /* must back up */ + /* undo the effects of YY_DO_BEFORE_ACTION */ + *yy_cp = yyg->yy_hold_char; + yy_cp = yyg->yy_last_accepting_cpos; + yy_current_state = yyg->yy_last_accepting_state; + goto yy_find_action; + +case 1: +YY_RULE_SETUP +#line 80 "sqlite3_lexer.ll" +loc.step(); + YY_BREAK +case 2: +/* rule 2 can match eol */ +YY_RULE_SETUP +#line 81 "sqlite3_lexer.ll" +loc.lines(yyleng); loc.step(); + YY_BREAK +case 3: +YY_RULE_SETUP +#line 83 "sqlite3_lexer.ll" +{ + int c; + while((c = yyinput(yyscanner)) != '\n' && c != EOF) + ; /* eat up text of comment */ + } + YY_BREAK +case 4: +YY_RULE_SETUP +#line 89 "sqlite3_lexer.ll" +{ + int c; + + for(;;) + { + while((c = yyinput(yyscanner)) != '*' && c != EOF) + ; /* eat up text of comment */ + + if(c == '*') + { + while((c = yyinput(yyscanner)) == '*') + ; + if(c == '/') + break; /* found the end */ + } + + if(c == EOF) + throw sqlb::parser::parser::syntax_error(loc, "EOF in comment"); + } + } + YY_BREAK +/* For lack of a better idea, we need this hack to avoid reduce/reduce conflicts in the rules for parsing BETWEEN expressions. + * What we do here is distinguish two types of AND operators: the regular one and the special case when the AND follows a BETWEEN keyword. + */ +case 5: +YY_RULE_SETUP +#line 113 "sqlite3_lexer.ll" +{ BEGIN INITIAL; return TOKEN(AND_BETWEEN); } + YY_BREAK +case 6: +YY_RULE_SETUP +#line 114 "sqlite3_lexer.ll" +return TOKEN(AND); + YY_BREAK +case 7: +YY_RULE_SETUP +#line 115 "sqlite3_lexer.ll" +{ BEGIN BETWEEN_MODE; return TOKEN(BETWEEN); } + YY_BREAK +case 8: +YY_RULE_SETUP +#line 117 "sqlite3_lexer.ll" +return TOKEN(ABORT); + YY_BREAK +case 9: +YY_RULE_SETUP +#line 118 "sqlite3_lexer.ll" +return TOKEN(ACTION); + YY_BREAK +case 10: +YY_RULE_SETUP +#line 119 "sqlite3_lexer.ll" +return TOKEN(ALWAYS); + YY_BREAK +case 11: +YY_RULE_SETUP +#line 120 "sqlite3_lexer.ll" +return TOKEN(AS); + YY_BREAK +case 12: +YY_RULE_SETUP +#line 121 "sqlite3_lexer.ll" +return TOKEN(ASC); + YY_BREAK +case 13: +YY_RULE_SETUP +#line 122 "sqlite3_lexer.ll" +return TOKEN(AUTOINCREMENT); + YY_BREAK +case 14: +YY_RULE_SETUP +#line 123 "sqlite3_lexer.ll" +return TOKEN(CASCADE); + YY_BREAK +case 15: +YY_RULE_SETUP +#line 124 "sqlite3_lexer.ll" +return TOKEN(CASE); + YY_BREAK +case 16: +YY_RULE_SETUP +#line 125 "sqlite3_lexer.ll" +return TOKEN(CAST); + YY_BREAK +case 17: +YY_RULE_SETUP +#line 126 "sqlite3_lexer.ll" +return TOKEN(CHECK); + YY_BREAK +case 18: +YY_RULE_SETUP +#line 127 "sqlite3_lexer.ll" +return TOKEN(COLLATE); + YY_BREAK +case 19: +YY_RULE_SETUP +#line 128 "sqlite3_lexer.ll" +return TOKEN(CONFLICT); + YY_BREAK +case 20: +YY_RULE_SETUP +#line 129 "sqlite3_lexer.ll" +return TOKEN(CONSTRAINT); + YY_BREAK +case 21: +YY_RULE_SETUP +#line 130 "sqlite3_lexer.ll" +return TOKEN(CREATE); + YY_BREAK +case 22: +YY_RULE_SETUP +#line 131 "sqlite3_lexer.ll" +return TOKEN(CURRENT_DATE); + YY_BREAK +case 23: +YY_RULE_SETUP +#line 132 "sqlite3_lexer.ll" +return TOKEN(CURRENT_TIME); + YY_BREAK +case 24: +YY_RULE_SETUP +#line 133 "sqlite3_lexer.ll" +return TOKEN(CURRENT_TIMESTAMP); + YY_BREAK +case 25: +YY_RULE_SETUP +#line 134 "sqlite3_lexer.ll" +return TOKEN(DEFAULT); + YY_BREAK +case 26: +YY_RULE_SETUP +#line 135 "sqlite3_lexer.ll" +return TOKEN(DEFERRABLE); + YY_BREAK +case 27: +YY_RULE_SETUP +#line 136 "sqlite3_lexer.ll" +return TOKEN(DEFERRED); + YY_BREAK +case 28: +YY_RULE_SETUP +#line 137 "sqlite3_lexer.ll" +return TOKEN(DELETE); + YY_BREAK +case 29: +YY_RULE_SETUP +#line 138 "sqlite3_lexer.ll" +return TOKEN(DESC); + YY_BREAK +case 30: +YY_RULE_SETUP +#line 139 "sqlite3_lexer.ll" +return TOKEN(DISTINCT); + YY_BREAK +case 31: +YY_RULE_SETUP +#line 140 "sqlite3_lexer.ll" +return TOKEN(ELSE); + YY_BREAK +case 32: +YY_RULE_SETUP +#line 141 "sqlite3_lexer.ll" +return TOKEN(END); + YY_BREAK +case 33: +YY_RULE_SETUP +#line 142 "sqlite3_lexer.ll" +return TOKEN(ESCAPE); + YY_BREAK +case 34: +YY_RULE_SETUP +#line 143 "sqlite3_lexer.ll" +return TOKEN(EXISTS); + YY_BREAK +case 35: +YY_RULE_SETUP +#line 144 "sqlite3_lexer.ll" +return TOKEN(FAIL); + YY_BREAK +case 36: +YY_RULE_SETUP +#line 145 "sqlite3_lexer.ll" +return TOKEN(FALSE); + YY_BREAK +case 37: +YY_RULE_SETUP +#line 146 "sqlite3_lexer.ll" +return TOKEN(FILTER); + YY_BREAK +case 38: +YY_RULE_SETUP +#line 147 "sqlite3_lexer.ll" +return TOKEN(FOLLOWING); + YY_BREAK +case 39: +YY_RULE_SETUP +#line 148 "sqlite3_lexer.ll" +return TOKEN(FOREIGN); + YY_BREAK +case 40: +YY_RULE_SETUP +#line 149 "sqlite3_lexer.ll" +return TOKEN(GENERATED); + YY_BREAK +case 41: +YY_RULE_SETUP +#line 150 "sqlite3_lexer.ll" +return TOKEN(GLOB); + YY_BREAK +case 42: +YY_RULE_SETUP +#line 151 "sqlite3_lexer.ll" +return TOKEN(IF); + YY_BREAK +case 43: +YY_RULE_SETUP +#line 152 "sqlite3_lexer.ll" +return TOKEN(IGNORE); + YY_BREAK +case 44: +YY_RULE_SETUP +#line 153 "sqlite3_lexer.ll" +return TOKEN(IMMEDIATE); + YY_BREAK +case 45: +YY_RULE_SETUP +#line 154 "sqlite3_lexer.ll" +return TOKEN(IN); + YY_BREAK +case 46: +YY_RULE_SETUP +#line 155 "sqlite3_lexer.ll" +return TOKEN(INDEX); + YY_BREAK +case 47: +YY_RULE_SETUP +#line 156 "sqlite3_lexer.ll" +return TOKEN(INITIALLY); + YY_BREAK +case 48: +YY_RULE_SETUP +#line 157 "sqlite3_lexer.ll" +return TOKEN(INSERT); + YY_BREAK +case 49: +YY_RULE_SETUP +#line 158 "sqlite3_lexer.ll" +return TOKEN(IS); + YY_BREAK +case 50: +YY_RULE_SETUP +#line 159 "sqlite3_lexer.ll" +return TOKEN(ISNULL); + YY_BREAK +case 51: +YY_RULE_SETUP +#line 160 "sqlite3_lexer.ll" +return TOKEN(KEY); + YY_BREAK +case 52: +YY_RULE_SETUP +#line 161 "sqlite3_lexer.ll" +return TOKEN(LIKE); + YY_BREAK +case 53: +YY_RULE_SETUP +#line 162 "sqlite3_lexer.ll" +return TOKEN(MATCH); + YY_BREAK +case 54: +YY_RULE_SETUP +#line 163 "sqlite3_lexer.ll" +return TOKEN(NO); + YY_BREAK +case 55: +YY_RULE_SETUP +#line 164 "sqlite3_lexer.ll" +return TOKEN(NOT); + YY_BREAK +case 56: +YY_RULE_SETUP +#line 165 "sqlite3_lexer.ll" +return TOKEN(NOTNULL); + YY_BREAK +case 57: +YY_RULE_SETUP +#line 166 "sqlite3_lexer.ll" +return TOKEN(NULL); + YY_BREAK +case 58: +YY_RULE_SETUP +#line 167 "sqlite3_lexer.ll" +return TOKEN(ON); + YY_BREAK +case 59: +YY_RULE_SETUP +#line 168 "sqlite3_lexer.ll" +return TOKEN(OR); + YY_BREAK +case 60: +YY_RULE_SETUP +#line 169 "sqlite3_lexer.ll" +return TOKEN(OVER); + YY_BREAK +case 61: +YY_RULE_SETUP +#line 170 "sqlite3_lexer.ll" +return TOKEN(PARTITION); + YY_BREAK +case 62: +YY_RULE_SETUP +#line 171 "sqlite3_lexer.ll" +return TOKEN(PRECEDING); + YY_BREAK +case 63: +YY_RULE_SETUP +#line 172 "sqlite3_lexer.ll" +return TOKEN(PRIMARY); + YY_BREAK +case 64: +YY_RULE_SETUP +#line 173 "sqlite3_lexer.ll" +return TOKEN(RAISE); + YY_BREAK +case 65: +YY_RULE_SETUP +#line 174 "sqlite3_lexer.ll" +return TOKEN(RANGE); + YY_BREAK +case 66: +YY_RULE_SETUP +#line 175 "sqlite3_lexer.ll" +return TOKEN(REFERENCES); + YY_BREAK +case 67: +YY_RULE_SETUP +#line 176 "sqlite3_lexer.ll" +return TOKEN(REGEXP); + YY_BREAK +case 68: +YY_RULE_SETUP +#line 177 "sqlite3_lexer.ll" +return TOKEN(REPLACE); + YY_BREAK +case 69: +YY_RULE_SETUP +#line 178 "sqlite3_lexer.ll" +return TOKEN(RESTRICT); + YY_BREAK +case 70: +YY_RULE_SETUP +#line 179 "sqlite3_lexer.ll" +return TOKEN(ROLLBACK); + YY_BREAK +case 71: +YY_RULE_SETUP +#line 180 "sqlite3_lexer.ll" +return TOKEN(ROWID); + YY_BREAK +case 72: +YY_RULE_SETUP +#line 181 "sqlite3_lexer.ll" +return TOKEN(ROWS); + YY_BREAK +case 73: +YY_RULE_SETUP +#line 182 "sqlite3_lexer.ll" +return TOKEN(SELECT); + YY_BREAK +case 74: +YY_RULE_SETUP +#line 183 "sqlite3_lexer.ll" +return TOKEN(SET); + YY_BREAK +case 75: +YY_RULE_SETUP +#line 184 "sqlite3_lexer.ll" +return TOKEN(STORED); + YY_BREAK +case 76: +YY_RULE_SETUP +#line 185 "sqlite3_lexer.ll" +return TOKEN(TABLE); + YY_BREAK +case 77: +YY_RULE_SETUP +#line 186 "sqlite3_lexer.ll" +return TOKEN(TEMP); + YY_BREAK +case 78: +YY_RULE_SETUP +#line 187 "sqlite3_lexer.ll" +return TOKEN(TEMPORARY); + YY_BREAK +case 79: +YY_RULE_SETUP +#line 188 "sqlite3_lexer.ll" +return TOKEN(THEN); + YY_BREAK +case 80: +YY_RULE_SETUP +#line 189 "sqlite3_lexer.ll" +return TOKEN(TRUE); + YY_BREAK +case 81: +YY_RULE_SETUP +#line 190 "sqlite3_lexer.ll" +return TOKEN(UNBOUNDED); + YY_BREAK +case 82: +YY_RULE_SETUP +#line 191 "sqlite3_lexer.ll" +return TOKEN(UNIQUE); + YY_BREAK +case 83: +YY_RULE_SETUP +#line 192 "sqlite3_lexer.ll" +return TOKEN(UPDATE); + YY_BREAK +case 84: +YY_RULE_SETUP +#line 193 "sqlite3_lexer.ll" +return TOKEN(USING); + YY_BREAK +case 85: +YY_RULE_SETUP +#line 194 "sqlite3_lexer.ll" +return TOKEN(VIRTUAL); + YY_BREAK +case 86: +YY_RULE_SETUP +#line 195 "sqlite3_lexer.ll" +return TOKEN(WHEN); + YY_BREAK +case 87: +YY_RULE_SETUP +#line 196 "sqlite3_lexer.ll" +return TOKEN(WHERE); + YY_BREAK +case 88: +YY_RULE_SETUP +#line 197 "sqlite3_lexer.ll" +return TOKEN(WITHOUT); + YY_BREAK +case 89: +YY_RULE_SETUP +#line 199 "sqlite3_lexer.ll" +return sqlb::parser::parser::make_IDENTIFIER(yytext, loc); + YY_BREAK +case 90: +YY_RULE_SETUP +#line 200 "sqlite3_lexer.ll" +return sqlb::parser::parser::make_IDENTIFIER(unquote_string(yytext, '`'), loc); + YY_BREAK +case 91: +YY_RULE_SETUP +#line 201 "sqlite3_lexer.ll" +return sqlb::parser::parser::make_IDENTIFIER(unquote_string(yytext, '['), loc); + YY_BREAK +case 92: +YY_RULE_SETUP +#line 202 "sqlite3_lexer.ll" +return sqlb::parser::parser::make_QUOTEDLITERAL(unquote_string(yytext, '"'), loc); + YY_BREAK +case 93: +YY_RULE_SETUP +#line 203 "sqlite3_lexer.ll" +return sqlb::parser::parser::make_STRINGLITERAL(yytext, loc); + YY_BREAK +case 94: +YY_RULE_SETUP +#line 204 "sqlite3_lexer.ll" +return sqlb::parser::parser::make_NUMERIC(yytext, loc); + YY_BREAK +case 95: +YY_RULE_SETUP +#line 205 "sqlite3_lexer.ll" +return sqlb::parser::parser::make_BLOBLITERAL(yytext, loc); + YY_BREAK +case 96: +YY_RULE_SETUP +#line 206 "sqlite3_lexer.ll" +return sqlb::parser::parser::make_BINDPARAMETER(yytext, loc); + YY_BREAK +case 97: +YY_RULE_SETUP +#line 207 "sqlite3_lexer.ll" +return sqlb::parser::parser::make_BINDPARAMETER(yytext, loc); + YY_BREAK +case 98: +YY_RULE_SETUP +#line 209 "sqlite3_lexer.ll" +return sqlb::parser::parser::make_LPAREN(loc); + YY_BREAK +case 99: +YY_RULE_SETUP +#line 210 "sqlite3_lexer.ll" +return sqlb::parser::parser::make_RPAREN(loc); + YY_BREAK +case 100: +YY_RULE_SETUP +#line 211 "sqlite3_lexer.ll" +return sqlb::parser::parser::make_DOT(loc); + YY_BREAK +case 101: +YY_RULE_SETUP +#line 212 "sqlite3_lexer.ll" +return sqlb::parser::parser::make_COMMA(loc); + YY_BREAK +case 102: +YY_RULE_SETUP +#line 213 "sqlite3_lexer.ll" +return sqlb::parser::parser::make_SEMI(loc); + YY_BREAK +case 103: +YY_RULE_SETUP +#line 214 "sqlite3_lexer.ll" +return sqlb::parser::parser::make_PLUS(loc); + YY_BREAK +case 104: +YY_RULE_SETUP +#line 215 "sqlite3_lexer.ll" +return sqlb::parser::parser::make_MINUS(loc); + YY_BREAK +case 105: +YY_RULE_SETUP +#line 216 "sqlite3_lexer.ll" +return sqlb::parser::parser::make_STAR(loc); + YY_BREAK +case 106: +YY_RULE_SETUP +#line 217 "sqlite3_lexer.ll" +return sqlb::parser::parser::make_SLASH(loc); + YY_BREAK +case 107: +YY_RULE_SETUP +#line 218 "sqlite3_lexer.ll" +return sqlb::parser::parser::make_TILDE(loc); + YY_BREAK +case 108: +YY_RULE_SETUP +#line 219 "sqlite3_lexer.ll" +return sqlb::parser::parser::make_AMPERSAND(loc); + YY_BREAK +case 109: +YY_RULE_SETUP +#line 220 "sqlite3_lexer.ll" +return sqlb::parser::parser::make_PERCENT(loc); + YY_BREAK +case 110: +YY_RULE_SETUP +#line 221 "sqlite3_lexer.ll" +return sqlb::parser::parser::make_BITOR(loc); + YY_BREAK +case 111: +YY_RULE_SETUP +#line 222 "sqlite3_lexer.ll" +return sqlb::parser::parser::make_OROP(loc); + YY_BREAK +case 112: +YY_RULE_SETUP +#line 223 "sqlite3_lexer.ll" +return sqlb::parser::parser::make_EQUAL(loc); + YY_BREAK +case 113: +YY_RULE_SETUP +#line 224 "sqlite3_lexer.ll" +return sqlb::parser::parser::make_EQUAL2(loc); + YY_BREAK +case 114: +YY_RULE_SETUP +#line 225 "sqlite3_lexer.ll" +return sqlb::parser::parser::make_GREATER(loc); + YY_BREAK +case 115: +YY_RULE_SETUP +#line 226 "sqlite3_lexer.ll" +return sqlb::parser::parser::make_GREATEREQUAL(loc); + YY_BREAK +case 116: +YY_RULE_SETUP +#line 227 "sqlite3_lexer.ll" +return sqlb::parser::parser::make_LOWER(loc); + YY_BREAK +case 117: +YY_RULE_SETUP +#line 228 "sqlite3_lexer.ll" +return sqlb::parser::parser::make_LOWEREQUAL(loc); + YY_BREAK +case 118: +YY_RULE_SETUP +#line 229 "sqlite3_lexer.ll" +return sqlb::parser::parser::make_UNEQUAL(loc); + YY_BREAK +case 119: +YY_RULE_SETUP +#line 230 "sqlite3_lexer.ll" +return sqlb::parser::parser::make_UNEQUAL2(loc); + YY_BREAK +case 120: +YY_RULE_SETUP +#line 231 "sqlite3_lexer.ll" +return sqlb::parser::parser::make_BITWISELEFT(loc); + YY_BREAK +case 121: +YY_RULE_SETUP +#line 232 "sqlite3_lexer.ll" +return sqlb::parser::parser::make_BITWISERIGHT(loc); + YY_BREAK +case 122: +YY_RULE_SETUP +#line 234 "sqlite3_lexer.ll" +throw sqlb::parser::parser::syntax_error(loc, "Invalid character: " + std::string(yytext)); + YY_BREAK +case YY_STATE_EOF(INITIAL): +case YY_STATE_EOF(BETWEEN_MODE): +#line 236 "sqlite3_lexer.ll" +return sqlb::parser::parser::make_EOF(loc); + YY_BREAK +case 123: +YY_RULE_SETUP +#line 238 "sqlite3_lexer.ll" +YY_FATAL_ERROR( "flex scanner jammed" ); + YY_BREAK +#line 2329 "sqlite3_lexer.cpp" + + case YY_END_OF_BUFFER: + { + /* Amount of text matched not including the EOB char. */ + int yy_amount_of_matched_text = (int) (yy_cp - yyg->yytext_ptr) - 1; + + /* Undo the effects of YY_DO_BEFORE_ACTION. */ + *yy_cp = yyg->yy_hold_char; + YY_RESTORE_YY_MORE_OFFSET + + if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW ) + { + /* We're scanning a new file or input source. It's + * possible that this happened because the user + * just pointed yyin at a new source and called + * yylex(). If so, then we have to assure + * consistency between YY_CURRENT_BUFFER and our + * globals. Here is the right place to do so, because + * this is the first action (other than possibly a + * back-up) that will match for the new input source. + */ + yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; +/* %if-c-only */ + YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin; +/* %endif */ +/* %if-c++-only */ +/* %endif */ + YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL; + } + + /* Note that here we test for yy_c_buf_p "<=" to the position + * of the first EOB in the buffer, since yy_c_buf_p will + * already have been incremented past the NUL character + * (since all states make transitions on EOB to the + * end-of-buffer state). Contrast this with the test + * in input(). + */ + if ( yyg->yy_c_buf_p <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] ) + { /* This was really a NUL. */ + yy_state_type yy_next_state; + + yyg->yy_c_buf_p = yyg->yytext_ptr + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state( yyscanner ); + + /* Okay, we're now positioned to make the NUL + * transition. We couldn't have + * yy_get_previous_state() go ahead and do it + * for us because it doesn't know how to deal + * with the possibility of jamming (and we don't + * want to build jamming into it because then it + * will run more slowly). + */ + + yy_next_state = yy_try_NUL_trans( yy_current_state , yyscanner); + + yy_bp = yyg->yytext_ptr + YY_MORE_ADJ; + + if ( yy_next_state ) + { + /* Consume the NUL. */ + yy_cp = ++yyg->yy_c_buf_p; + yy_current_state = yy_next_state; + goto yy_match; + } + + else + { +/* %% [14.0] code to do back-up for compressed tables and set up yy_cp goes here */ + yy_cp = yyg->yy_last_accepting_cpos; + yy_current_state = yyg->yy_last_accepting_state; + goto yy_find_action; + } + } + + else switch ( yy_get_next_buffer( yyscanner ) ) + { + case EOB_ACT_END_OF_FILE: + { + yyg->yy_did_buffer_switch_on_eof = 0; + + if ( yywrap( yyscanner ) ) + { + /* Note: because we've taken care in + * yy_get_next_buffer() to have set up + * yytext, we can now set up + * yy_c_buf_p so that if some total + * hoser (like flex itself) wants to + * call the scanner after we return the + * YY_NULL, it'll still work - another + * YY_NULL will get returned. + */ + yyg->yy_c_buf_p = yyg->yytext_ptr + YY_MORE_ADJ; + + yy_act = YY_STATE_EOF(YY_START); + goto do_action; + } + + else + { + if ( ! yyg->yy_did_buffer_switch_on_eof ) + YY_NEW_FILE; + } + break; + } + + case EOB_ACT_CONTINUE_SCAN: + yyg->yy_c_buf_p = + yyg->yytext_ptr + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state( yyscanner ); + + yy_cp = yyg->yy_c_buf_p; + yy_bp = yyg->yytext_ptr + YY_MORE_ADJ; + goto yy_match; + + case EOB_ACT_LAST_MATCH: + yyg->yy_c_buf_p = + &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars]; + + yy_current_state = yy_get_previous_state( yyscanner ); + + yy_cp = yyg->yy_c_buf_p; + yy_bp = yyg->yytext_ptr + YY_MORE_ADJ; + goto yy_find_action; + } + break; + } + + default: + YY_FATAL_ERROR( + "fatal flex scanner internal error--no action found" ); + } /* end of action switch */ + } /* end of scanning one token */ + } /* end of user's declarations */ +} /* end of yylex */ +/* %ok-for-header */ + +/* %if-c++-only */ +/* %not-for-header */ +/* %ok-for-header */ + +/* %endif */ + +/* yy_get_next_buffer - try to read in a new buffer + * + * Returns a code representing an action: + * EOB_ACT_LAST_MATCH - + * EOB_ACT_CONTINUE_SCAN - continue scanning from current position + * EOB_ACT_END_OF_FILE - end of file + */ +/* %if-c-only */ +static int yy_get_next_buffer (yyscan_t yyscanner) +/* %endif */ +/* %if-c++-only */ +/* %endif */ +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf; + char *source = yyg->yytext_ptr; + int number_to_move, i; + int ret_val; + + if ( yyg->yy_c_buf_p > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] ) + YY_FATAL_ERROR( + "fatal flex scanner internal error--end of buffer missed" ); + + if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 ) + { /* Don't try to fill the buffer, so this is an EOF. */ + if ( yyg->yy_c_buf_p - yyg->yytext_ptr - YY_MORE_ADJ == 1 ) + { + /* We matched a single character, the EOB, so + * treat this as a final EOF. + */ + return EOB_ACT_END_OF_FILE; + } + + else + { + /* We matched some text prior to the EOB, first + * process it. + */ + return EOB_ACT_LAST_MATCH; + } + } + + /* Try to read more data. */ + + /* First move last chars to start of buffer. */ + number_to_move = (int) (yyg->yy_c_buf_p - yyg->yytext_ptr - 1); + + for ( i = 0; i < number_to_move; ++i ) + *(dest++) = *(source++); + + if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING ) + /* don't do the read, it's not guaranteed to return an EOF, + * just force an EOF + */ + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars = 0; + + else + { + int num_to_read = + YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1; + + while ( num_to_read <= 0 ) + { /* Not enough room in the buffer - grow it. */ + + /* just a shorter name for the current buffer */ + YY_BUFFER_STATE b = YY_CURRENT_BUFFER_LVALUE; + + int yy_c_buf_p_offset = + (int) (yyg->yy_c_buf_p - b->yy_ch_buf); + + if ( b->yy_is_our_buffer ) + { + int new_size = b->yy_buf_size * 2; + + if ( new_size <= 0 ) + b->yy_buf_size += b->yy_buf_size / 8; + else + b->yy_buf_size *= 2; + + b->yy_ch_buf = (char *) + /* Include room in for 2 EOB chars. */ + yyrealloc( (void *) b->yy_ch_buf, + (yy_size_t) (b->yy_buf_size + 2) , yyscanner ); + } + else + /* Can't grow it, we don't own it. */ + b->yy_ch_buf = NULL; + + if ( ! b->yy_ch_buf ) + YY_FATAL_ERROR( + "fatal error - scanner input buffer overflow" ); + + yyg->yy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset]; + + num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size - + number_to_move - 1; + + } + + if ( num_to_read > YY_READ_BUF_SIZE ) + num_to_read = YY_READ_BUF_SIZE; + + /* Read in more data. */ + YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]), + yyg->yy_n_chars, num_to_read ); + + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars; + } + + if ( yyg->yy_n_chars == 0 ) + { + if ( number_to_move == YY_MORE_ADJ ) + { + ret_val = EOB_ACT_END_OF_FILE; + yyrestart( yyin , yyscanner); + } + + else + { + ret_val = EOB_ACT_LAST_MATCH; + YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = + YY_BUFFER_EOF_PENDING; + } + } + + else + ret_val = EOB_ACT_CONTINUE_SCAN; + + if ((yyg->yy_n_chars + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) { + /* Extend the array by 50%, plus the number we really need. */ + int new_size = yyg->yy_n_chars + number_to_move + (yyg->yy_n_chars >> 1); + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) yyrealloc( + (void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf, (yy_size_t) new_size , yyscanner ); + if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" ); + /* "- 2" to take care of EOB's */ + YY_CURRENT_BUFFER_LVALUE->yy_buf_size = (int) (new_size - 2); + } + + yyg->yy_n_chars += number_to_move; + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] = YY_END_OF_BUFFER_CHAR; + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR; + + yyg->yytext_ptr = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0]; + + return ret_val; +} + +/* yy_get_previous_state - get the state just before the EOB char was reached */ + +/* %if-c-only */ +/* %not-for-header */ + static yy_state_type yy_get_previous_state (yyscan_t yyscanner) +/* %endif */ +/* %if-c++-only */ +/* %endif */ +{ + yy_state_type yy_current_state; + char *yy_cp; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + +/* %% [15.0] code to get the start state into yy_current_state goes here */ + yy_current_state = yyg->yy_start; + + for ( yy_cp = yyg->yytext_ptr + YY_MORE_ADJ; yy_cp < yyg->yy_c_buf_p; ++yy_cp ) + { +/* %% [16.0] code to find the next state goes here */ + YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1); + if ( yy_accept[yy_current_state] ) + { + yyg->yy_last_accepting_state = yy_current_state; + yyg->yy_last_accepting_cpos = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 467 ) + yy_c = yy_meta[yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; + } + + return yy_current_state; +} + +/* yy_try_NUL_trans - try to make a transition on the NUL character + * + * synopsis + * next_state = yy_try_NUL_trans( current_state ); + */ +/* %if-c-only */ + static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state , yyscan_t yyscanner) +/* %endif */ +/* %if-c++-only */ +/* %endif */ +{ + int yy_is_jam; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; /* This var may be unused depending upon options. */ +/* %% [17.0] code to find the next state, and perhaps do backing up, goes here */ + char *yy_cp = yyg->yy_c_buf_p; + + YY_CHAR yy_c = 1; + if ( yy_accept[yy_current_state] ) + { + yyg->yy_last_accepting_state = yy_current_state; + yyg->yy_last_accepting_cpos = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 467 ) + yy_c = yy_meta[yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; + yy_is_jam = (yy_current_state == 466); + + (void)yyg; + return yy_is_jam ? 0 : yy_current_state; +} + +#ifndef YY_NO_UNPUT +/* %if-c-only */ + +/* %endif */ +#endif + +/* %if-c-only */ +#ifndef YY_NO_INPUT +#ifdef __cplusplus + static int yyinput (yyscan_t yyscanner) +#else + static int input (yyscan_t yyscanner) +#endif + +/* %endif */ +/* %if-c++-only */ +/* %endif */ +{ + int c; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + *yyg->yy_c_buf_p = yyg->yy_hold_char; + + if ( *yyg->yy_c_buf_p == YY_END_OF_BUFFER_CHAR ) + { + /* yy_c_buf_p now points to the character we want to return. + * If this occurs *before* the EOB characters, then it's a + * valid NUL; if not, then we've hit the end of the buffer. + */ + if ( yyg->yy_c_buf_p < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] ) + /* This was really a NUL. */ + *yyg->yy_c_buf_p = '\0'; + + else + { /* need more input */ + int offset = (int) (yyg->yy_c_buf_p - yyg->yytext_ptr); + ++yyg->yy_c_buf_p; + + switch ( yy_get_next_buffer( yyscanner ) ) + { + case EOB_ACT_LAST_MATCH: + /* This happens because yy_g_n_b() + * sees that we've accumulated a + * token and flags that we need to + * try matching the token before + * proceeding. But for input(), + * there's no matching to consider. + * So convert the EOB_ACT_LAST_MATCH + * to EOB_ACT_END_OF_FILE. + */ + + /* Reset buffer status. */ + yyrestart( yyin , yyscanner); + + /*FALLTHROUGH*/ + + case EOB_ACT_END_OF_FILE: + { + if ( yywrap( yyscanner ) ) + return 0; + + if ( ! yyg->yy_did_buffer_switch_on_eof ) + YY_NEW_FILE; +#ifdef __cplusplus + return yyinput(yyscanner); +#else + return input(yyscanner); +#endif + } + + case EOB_ACT_CONTINUE_SCAN: + yyg->yy_c_buf_p = yyg->yytext_ptr + offset; + break; + } + } + } + + c = *(unsigned char *) yyg->yy_c_buf_p; /* cast for 8-bit char's */ + *yyg->yy_c_buf_p = '\0'; /* preserve yytext */ + yyg->yy_hold_char = *++yyg->yy_c_buf_p; + +/* %% [19.0] update BOL and yylineno */ + + return c; +} +/* %if-c-only */ +#endif /* ifndef YY_NO_INPUT */ +/* %endif */ + +/** Immediately switch to a different input stream. + * @param input_file A readable stream. + * @param yyscanner The scanner object. + * @note This function does not reset the start condition to @c INITIAL . + */ +/* %if-c-only */ + void yyrestart (FILE * input_file , yyscan_t yyscanner) +/* %endif */ +/* %if-c++-only */ +/* %endif */ +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + if ( ! YY_CURRENT_BUFFER ){ + yyensure_buffer_stack (yyscanner); + YY_CURRENT_BUFFER_LVALUE = + yy_create_buffer( yyin, YY_BUF_SIZE , yyscanner); + } + + yy_init_buffer( YY_CURRENT_BUFFER, input_file , yyscanner); + yy_load_buffer_state( yyscanner ); +} + +/* %if-c++-only */ +/* %endif */ + +/** Switch to a different input buffer. + * @param new_buffer The new input buffer. + * @param yyscanner The scanner object. + */ +/* %if-c-only */ + void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner) +/* %endif */ +/* %if-c++-only */ +/* %endif */ +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + /* TODO. We should be able to replace this entire function body + * with + * yypop_buffer_state(); + * yypush_buffer_state(new_buffer); + */ + yyensure_buffer_stack (yyscanner); + if ( YY_CURRENT_BUFFER == new_buffer ) + return; + + if ( YY_CURRENT_BUFFER ) + { + /* Flush out information for old buffer. */ + *yyg->yy_c_buf_p = yyg->yy_hold_char; + YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p; + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars; + } + + YY_CURRENT_BUFFER_LVALUE = new_buffer; + yy_load_buffer_state( yyscanner ); + + /* We don't actually know whether we did this switch during + * EOF (yywrap()) processing, but the only time this flag + * is looked at is after yywrap() is called, so it's safe + * to go ahead and always set it. + */ + yyg->yy_did_buffer_switch_on_eof = 1; +} + +/* %if-c-only */ +static void yy_load_buffer_state (yyscan_t yyscanner) +/* %endif */ +/* %if-c++-only */ +/* %endif */ +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; + yyg->yytext_ptr = yyg->yy_c_buf_p = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos; +/* %if-c-only */ + yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file; +/* %endif */ +/* %if-c++-only */ +/* %endif */ + yyg->yy_hold_char = *yyg->yy_c_buf_p; +} + +/** Allocate and initialize an input buffer state. + * @param file A readable stream. + * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE. + * @param yyscanner The scanner object. + * @return the allocated buffer state. + */ +/* %if-c-only */ + YY_BUFFER_STATE yy_create_buffer (FILE * file, int size , yyscan_t yyscanner) +/* %endif */ +/* %if-c++-only */ +/* %endif */ +{ + YY_BUFFER_STATE b; + + b = (YY_BUFFER_STATE) yyalloc( sizeof( struct yy_buffer_state ) , yyscanner ); + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); + + b->yy_buf_size = size; + + /* yy_ch_buf has to be 2 characters longer than the size given because + * we need to put in 2 end-of-buffer characters. + */ + b->yy_ch_buf = (char *) yyalloc( (yy_size_t) (b->yy_buf_size + 2) , yyscanner ); + if ( ! b->yy_ch_buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); + + b->yy_is_our_buffer = 1; + + yy_init_buffer( b, file , yyscanner); + + return b; +} + +/* %if-c++-only */ +/* %endif */ + +/** Destroy the buffer. + * @param b a buffer created with yy_create_buffer() + * @param yyscanner The scanner object. + */ +/* %if-c-only */ + void yy_delete_buffer (YY_BUFFER_STATE b , yyscan_t yyscanner) +/* %endif */ +/* %if-c++-only */ +/* %endif */ +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + if ( ! b ) + return; + + if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */ + YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0; + + if ( b->yy_is_our_buffer ) + yyfree( (void *) b->yy_ch_buf , yyscanner ); + + yyfree( (void *) b , yyscanner ); +} + +/* Initializes or reinitializes a buffer. + * This function is sometimes called more than once on the same buffer, + * such as during a yyrestart() or at EOF. + */ +/* %if-c-only */ + static void yy_init_buffer (YY_BUFFER_STATE b, FILE * file , yyscan_t yyscanner) +/* %endif */ +/* %if-c++-only */ +/* %endif */ + +{ + int oerrno = errno; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + yy_flush_buffer( b , yyscanner); + +/* %if-c-only */ + b->yy_input_file = file; +/* %endif */ +/* %if-c++-only */ +/* %endif */ + b->yy_fill_buffer = 1; + + /* If b is the current buffer, then yy_init_buffer was _probably_ + * called from yyrestart() or through yy_get_next_buffer. + * In that case, we don't want to reset the lineno or column. + */ + if (b != YY_CURRENT_BUFFER){ + b->yy_bs_lineno = 1; + b->yy_bs_column = 0; + } + +/* %if-c-only */ + + b->yy_is_interactive = 0; + +/* %endif */ +/* %if-c++-only */ +/* %endif */ + errno = oerrno; +} + +/** Discard all buffered characters. On the next scan, YY_INPUT will be called. + * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER. + * @param yyscanner The scanner object. + */ +/* %if-c-only */ + void yy_flush_buffer (YY_BUFFER_STATE b , yyscan_t yyscanner) +/* %endif */ +/* %if-c++-only */ +/* %endif */ +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + if ( ! b ) + return; + + b->yy_n_chars = 0; + + /* We always need two end-of-buffer characters. The first causes + * a transition to the end-of-buffer state. The second causes + * a jam in that state. + */ + b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR; + b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR; + + b->yy_buf_pos = &b->yy_ch_buf[0]; + + b->yy_at_bol = 1; + b->yy_buffer_status = YY_BUFFER_NEW; + + if ( b == YY_CURRENT_BUFFER ) + yy_load_buffer_state( yyscanner ); +} + +/* %if-c-or-c++ */ +/** Pushes the new state onto the stack. The new state becomes + * the current state. This function will allocate the stack + * if necessary. + * @param new_buffer The new state. + * @param yyscanner The scanner object. + */ +/* %if-c-only */ +void yypush_buffer_state (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner) +/* %endif */ +/* %if-c++-only */ +/* %endif */ +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + if (new_buffer == NULL) + return; + + yyensure_buffer_stack(yyscanner); + + /* This block is copied from yy_switch_to_buffer. */ + if ( YY_CURRENT_BUFFER ) + { + /* Flush out information for old buffer. */ + *yyg->yy_c_buf_p = yyg->yy_hold_char; + YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p; + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars; + } + + /* Only push if top exists. Otherwise, replace top. */ + if (YY_CURRENT_BUFFER) + yyg->yy_buffer_stack_top++; + YY_CURRENT_BUFFER_LVALUE = new_buffer; + + /* copied from yy_switch_to_buffer. */ + yy_load_buffer_state( yyscanner ); + yyg->yy_did_buffer_switch_on_eof = 1; +} +/* %endif */ + +/* %if-c-or-c++ */ +/** Removes and deletes the top of the stack, if present. + * The next element becomes the new top. + * @param yyscanner The scanner object. + */ +/* %if-c-only */ +void yypop_buffer_state (yyscan_t yyscanner) +/* %endif */ +/* %if-c++-only */ +/* %endif */ +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + if (!YY_CURRENT_BUFFER) + return; + + yy_delete_buffer(YY_CURRENT_BUFFER , yyscanner); + YY_CURRENT_BUFFER_LVALUE = NULL; + if (yyg->yy_buffer_stack_top > 0) + --yyg->yy_buffer_stack_top; + + if (YY_CURRENT_BUFFER) { + yy_load_buffer_state( yyscanner ); + yyg->yy_did_buffer_switch_on_eof = 1; + } +} +/* %endif */ + +/* %if-c-or-c++ */ +/* Allocates the stack if it does not exist. + * Guarantees space for at least one push. + */ +/* %if-c-only */ +static void yyensure_buffer_stack (yyscan_t yyscanner) +/* %endif */ +/* %if-c++-only */ +/* %endif */ +{ + yy_size_t num_to_alloc; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + if (!yyg->yy_buffer_stack) { + + /* First allocation is just for 2 elements, since we don't know if this + * scanner will even need a stack. We use 2 instead of 1 to avoid an + * immediate realloc on the next call. + */ + num_to_alloc = 1; /* After all that talk, this was set to 1 anyways... */ + yyg->yy_buffer_stack = (struct yy_buffer_state**)yyalloc + (num_to_alloc * sizeof(struct yy_buffer_state*) + , yyscanner); + if ( ! yyg->yy_buffer_stack ) + YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" ); + + memset(yyg->yy_buffer_stack, 0, num_to_alloc * sizeof(struct yy_buffer_state*)); + + yyg->yy_buffer_stack_max = num_to_alloc; + yyg->yy_buffer_stack_top = 0; + return; + } + + if (yyg->yy_buffer_stack_top >= (yyg->yy_buffer_stack_max) - 1){ + + /* Increase the buffer to prepare for a possible push. */ + yy_size_t grow_size = 8 /* arbitrary grow size */; + + num_to_alloc = yyg->yy_buffer_stack_max + grow_size; + yyg->yy_buffer_stack = (struct yy_buffer_state**)yyrealloc + (yyg->yy_buffer_stack, + num_to_alloc * sizeof(struct yy_buffer_state*) + , yyscanner); + if ( ! yyg->yy_buffer_stack ) + YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" ); + + /* zero only the new slots.*/ + memset(yyg->yy_buffer_stack + yyg->yy_buffer_stack_max, 0, grow_size * sizeof(struct yy_buffer_state*)); + yyg->yy_buffer_stack_max = num_to_alloc; + } +} +/* %endif */ + +/* %if-c-only */ +/** Setup the input buffer state to scan directly from a user-specified character buffer. + * @param base the character buffer + * @param size the size in bytes of the character buffer + * @param yyscanner The scanner object. + * @return the newly allocated buffer state object. + */ +YY_BUFFER_STATE yy_scan_buffer (char * base, yy_size_t size , yyscan_t yyscanner) +{ + YY_BUFFER_STATE b; + + if ( size < 2 || + base[size-2] != YY_END_OF_BUFFER_CHAR || + base[size-1] != YY_END_OF_BUFFER_CHAR ) + /* They forgot to leave room for the EOB's. */ + return NULL; + + b = (YY_BUFFER_STATE) yyalloc( sizeof( struct yy_buffer_state ) , yyscanner ); + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" ); + + b->yy_buf_size = (int) (size - 2); /* "- 2" to take care of EOB's */ + b->yy_buf_pos = b->yy_ch_buf = base; + b->yy_is_our_buffer = 0; + b->yy_input_file = NULL; + b->yy_n_chars = b->yy_buf_size; + b->yy_is_interactive = 0; + b->yy_at_bol = 1; + b->yy_fill_buffer = 0; + b->yy_buffer_status = YY_BUFFER_NEW; + + yy_switch_to_buffer( b , yyscanner ); + + return b; +} +/* %endif */ + +/* %if-c-only */ +/** Setup the input buffer state to scan a string. The next call to yylex() will + * scan from a @e copy of @a str. + * @param yystr a NUL-terminated string to scan + * @param yyscanner The scanner object. + * @return the newly allocated buffer state object. + * @note If you want to scan bytes that may contain NUL values, then use + * yy_scan_bytes() instead. + */ +YY_BUFFER_STATE yy_scan_string (const char * yystr , yyscan_t yyscanner) +{ + + return yy_scan_bytes( yystr, (int) strlen(yystr) , yyscanner); +} +/* %endif */ + +/* %if-c-only */ +/** Setup the input buffer state to scan the given bytes. The next call to yylex() will + * scan from a @e copy of @a bytes. + * @param yybytes the byte buffer to scan + * @param _yybytes_len the number of bytes in the buffer pointed to by @a bytes. + * @param yyscanner The scanner object. + * @return the newly allocated buffer state object. + */ +YY_BUFFER_STATE yy_scan_bytes (const char * yybytes, int _yybytes_len , yyscan_t yyscanner) +{ + YY_BUFFER_STATE b; + char *buf; + yy_size_t n; + int i; + + /* Get memory for full buffer, including space for trailing EOB's. */ + n = (yy_size_t) (_yybytes_len + 2); + buf = (char *) yyalloc( n , yyscanner ); + if ( ! buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" ); + + for ( i = 0; i < _yybytes_len; ++i ) + buf[i] = yybytes[i]; + + buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR; + + b = yy_scan_buffer( buf, n , yyscanner); + if ( ! b ) + YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" ); + + /* It's okay to grow etc. this buffer, and we should throw it + * away when we're done. + */ + b->yy_is_our_buffer = 1; + + return b; +} +/* %endif */ + +#ifndef YY_EXIT_FAILURE +#define YY_EXIT_FAILURE 2 +#endif + +/* %if-c-only */ +static void yynoreturn yy_fatal_error (const char* msg , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + (void)yyg; + fprintf( stderr, "%s\n", msg ); + exit( YY_EXIT_FAILURE ); +} +/* %endif */ +/* %if-c++-only */ +/* %endif */ + +/* Redefine yyless() so it works in section 3 code. */ + +#undef yyless +#define yyless(n) \ + do \ + { \ + /* Undo effects of setting up yytext. */ \ + int yyless_macro_arg = (n); \ + YY_LESS_LINENO(yyless_macro_arg);\ + yytext[yyleng] = yyg->yy_hold_char; \ + yyg->yy_c_buf_p = yytext + yyless_macro_arg; \ + yyg->yy_hold_char = *yyg->yy_c_buf_p; \ + *yyg->yy_c_buf_p = '\0'; \ + yyleng = yyless_macro_arg; \ + } \ + while ( 0 ) + +/* Accessor methods (get/set functions) to struct members. */ + +/* %if-c-only */ +/* %if-reentrant */ + +/** Get the user-defined data for this scanner. + * @param yyscanner The scanner object. + */ +YY_EXTRA_TYPE yyget_extra (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yyextra; +} + +/* %endif */ + +/** Get the current line number. + * @param yyscanner The scanner object. + */ +int yyget_lineno (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + if (! YY_CURRENT_BUFFER) + return 0; + + return yylineno; +} + +/** Get the current column number. + * @param yyscanner The scanner object. + */ +int yyget_column (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + if (! YY_CURRENT_BUFFER) + return 0; + + return yycolumn; +} + +/** Get the input stream. + * @param yyscanner The scanner object. + */ +FILE *yyget_in (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yyin; +} + +/** Get the output stream. + * @param yyscanner The scanner object. + */ +FILE *yyget_out (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yyout; +} + +/** Get the length of the current token. + * @param yyscanner The scanner object. + */ +int yyget_leng (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yyleng; +} + +/** Get the current token. + * @param yyscanner The scanner object. + */ + +char *yyget_text (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yytext; +} + +/* %if-reentrant */ + +/** Set the user-defined data. This data is never touched by the scanner. + * @param user_defined The data to be associated with this scanner. + * @param yyscanner The scanner object. + */ +void yyset_extra (YY_EXTRA_TYPE user_defined , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yyextra = user_defined ; +} + +/* %endif */ + +/** Set the current line number. + * @param _line_number line number + * @param yyscanner The scanner object. + */ +void yyset_lineno (int _line_number , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + /* lineno is only valid if an input buffer exists. */ + if (! YY_CURRENT_BUFFER ) + YY_FATAL_ERROR( "yyset_lineno called with no buffer" ); + + yylineno = _line_number; +} + +/** Set the current column. + * @param _column_no column number + * @param yyscanner The scanner object. + */ +void yyset_column (int _column_no , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + /* column is only valid if an input buffer exists. */ + if (! YY_CURRENT_BUFFER ) + YY_FATAL_ERROR( "yyset_column called with no buffer" ); + + yycolumn = _column_no; +} + +/** Set the input stream. This does not discard the current + * input buffer. + * @param _in_str A readable stream. + * @param yyscanner The scanner object. + * @see yy_switch_to_buffer + */ +void yyset_in (FILE * _in_str , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yyin = _in_str ; +} + +void yyset_out (FILE * _out_str , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yyout = _out_str ; +} + +int yyget_debug (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yy_flex_debug; +} + +void yyset_debug (int _bdebug , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yy_flex_debug = _bdebug ; +} + +/* %endif */ + +/* %if-reentrant */ +/* Accessor methods for yylval and yylloc */ + +/* %if-bison-bridge */ +/* %endif */ + +/* User-visible API */ + +/* yylex_init is special because it creates the scanner itself, so it is + * the ONLY reentrant function that doesn't take the scanner as the last argument. + * That's why we explicitly handle the declaration, instead of using our macros. + */ +int yylex_init(yyscan_t* ptr_yy_globals) +{ + if (ptr_yy_globals == NULL){ + errno = EINVAL; + return 1; + } + + *ptr_yy_globals = (yyscan_t) yyalloc ( sizeof( struct yyguts_t ), NULL ); + + if (*ptr_yy_globals == NULL){ + errno = ENOMEM; + return 1; + } + + /* By setting to 0xAA, we expose bugs in yy_init_globals. Leave at 0x00 for releases. */ + memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t)); + + return yy_init_globals ( *ptr_yy_globals ); +} + +/* yylex_init_extra has the same functionality as yylex_init, but follows the + * convention of taking the scanner as the last argument. Note however, that + * this is a *pointer* to a scanner, as it will be allocated by this call (and + * is the reason, too, why this function also must handle its own declaration). + * The user defined value in the first argument will be available to yyalloc in + * the yyextra field. + */ +int yylex_init_extra( YY_EXTRA_TYPE yy_user_defined, yyscan_t* ptr_yy_globals ) +{ + struct yyguts_t dummy_yyguts; + + yyset_extra (yy_user_defined, &dummy_yyguts); + + if (ptr_yy_globals == NULL){ + errno = EINVAL; + return 1; + } + + *ptr_yy_globals = (yyscan_t) yyalloc ( sizeof( struct yyguts_t ), &dummy_yyguts ); + + if (*ptr_yy_globals == NULL){ + errno = ENOMEM; + return 1; + } + + /* By setting to 0xAA, we expose bugs in + yy_init_globals. Leave at 0x00 for releases. */ + memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t)); + + yyset_extra (yy_user_defined, *ptr_yy_globals); + + return yy_init_globals ( *ptr_yy_globals ); +} + +/* %endif if-c-only */ + +/* %if-c-only */ +static int yy_init_globals (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + /* Initialization is the same as for the non-reentrant scanner. + * This function is called from yylex_destroy(), so don't allocate here. + */ + + yyg->yy_buffer_stack = NULL; + yyg->yy_buffer_stack_top = 0; + yyg->yy_buffer_stack_max = 0; + yyg->yy_c_buf_p = NULL; + yyg->yy_init = 0; + yyg->yy_start = 0; + + yyg->yy_start_stack_ptr = 0; + yyg->yy_start_stack_depth = 0; + yyg->yy_start_stack = NULL; + +/* Defined in main.c */ +#ifdef YY_STDINIT + yyin = stdin; + yyout = stdout; +#else + yyin = NULL; + yyout = NULL; +#endif + + /* For future reference: Set errno on error, since we are called by + * yylex_init() + */ + return 0; +} +/* %endif */ + +/* %if-c-only SNIP! this currently causes conflicts with the c++ scanner */ +/* yylex_destroy is for both reentrant and non-reentrant scanners. */ +int yylex_destroy (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + /* Pop the buffer stack, destroying each element. */ + while(YY_CURRENT_BUFFER){ + yy_delete_buffer( YY_CURRENT_BUFFER , yyscanner ); + YY_CURRENT_BUFFER_LVALUE = NULL; + yypop_buffer_state(yyscanner); + } + + /* Destroy the stack itself. */ + yyfree(yyg->yy_buffer_stack , yyscanner); + yyg->yy_buffer_stack = NULL; + + /* Destroy the start condition stack. */ + yyfree( yyg->yy_start_stack , yyscanner ); + yyg->yy_start_stack = NULL; + + /* Reset the globals. This is important in a non-reentrant scanner so the next time + * yylex() is called, initialization will occur. */ + yy_init_globals( yyscanner); + +/* %if-reentrant */ + /* Destroy the main struct (reentrant only). */ + yyfree ( yyscanner , yyscanner ); + yyscanner = NULL; +/* %endif */ + return 0; +} +/* %endif */ + +/* + * Internal utility routines. + */ + +#ifndef yytext_ptr +static void yy_flex_strncpy (char* s1, const char * s2, int n , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + (void)yyg; + + int i; + for ( i = 0; i < n; ++i ) + s1[i] = s2[i]; +} +#endif + +#ifdef YY_NEED_STRLEN +static int yy_flex_strlen (const char * s , yyscan_t yyscanner) +{ + int n; + for ( n = 0; s[n]; ++n ) + ; + + return n; +} +#endif + +void *yyalloc (yy_size_t size , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + (void)yyg; + return malloc(size); +} + +void *yyrealloc (void * ptr, yy_size_t size , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + (void)yyg; + + /* The cast to (char *) in the following accommodates both + * implementations that use char* generic pointers, and those + * that use void* generic pointers. It works with the latter + * because both ANSI C and C++ allow castless assignment from + * any pointer type to void*, and deal with argument conversions + * as though doing an assignment. + */ + return realloc(ptr, size); +} + +void yyfree (void * ptr , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + (void)yyg; + free( (char *) ptr ); /* see yyrealloc() for (char *) cast */ +} + +/* %if-tables-serialization definitions */ +/* %define-yytables The name for this specific scanner's tables. */ +#define YYTABLES_NAME "yytables" +/* %endif */ + +/* %ok-for-header */ + +#line 238 "sqlite3_lexer.ll" + + +namespace sqlb +{ +namespace parser +{ + +void ParserDriver::begin_scan() +{ + yylex_init(&scanner); + location.initialize(); + yyset_debug(trace_scanner, scanner); + buffer = yy_scan_string(source.c_str(), scanner); +} + +void ParserDriver::end_scan() +{ + yy_delete_buffer(buffer, scanner); + yylex_destroy(scanner); +} + +} +} + diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/sql/parser/sqlite3_lexer.h b/src/WBCLFZSystemModule/SqliteDBProcess/src/sql/parser/sqlite3_lexer.h new file mode 100644 index 0000000..88d59cf --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/sql/parser/sqlite3_lexer.h @@ -0,0 +1,610 @@ +#ifndef yyHEADER_H +#define yyHEADER_H 1 +#define yyIN_HEADER 1 + +#line 6 "sqlite3_lexer.h" + +#line 8 "sqlite3_lexer.h" + +#define YY_INT_ALIGNED short int + +/* A lexical scanner generated by flex */ + +/* %not-for-header */ + +#define FLEX_SCANNER +#define YY_FLEX_MAJOR_VERSION 2 +#define YY_FLEX_MINOR_VERSION 6 +#define YY_FLEX_SUBMINOR_VERSION 4 +#if YY_FLEX_SUBMINOR_VERSION > 0 +#define FLEX_BETA +#endif + +/* %if-c++-only */ +/* %endif */ + +/* %if-c-only */ + +/* %endif */ + +/* %if-c-only */ + +/* %endif */ + +/* First, we deal with platform-specific or compiler-specific issues. */ + +/* begin standard C headers. */ +/* %if-c-only */ +#include +#include +#include +#include +/* %endif */ + +/* %if-tables-serialization */ +/* %endif */ +/* end standard C headers. */ + +/* %if-c-or-c++ */ +/* flex integer type definitions */ + +#ifndef FLEXINT_H +#define FLEXINT_H + +/* C99 systems have . Non-C99 systems may or may not. */ + +#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L + +/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h, + * if you want the limit (max/min) macros for int types. + */ +#ifndef __STDC_LIMIT_MACROS +#define __STDC_LIMIT_MACROS 1 +#endif + +#include +typedef int8_t flex_int8_t; +typedef uint8_t flex_uint8_t; +typedef int16_t flex_int16_t; +typedef uint16_t flex_uint16_t; +typedef int32_t flex_int32_t; +typedef uint32_t flex_uint32_t; +#else +typedef signed char flex_int8_t; +typedef short int flex_int16_t; +typedef int flex_int32_t; +typedef unsigned char flex_uint8_t; +typedef unsigned short int flex_uint16_t; +typedef unsigned int flex_uint32_t; + +/* Limits of integral types. */ +#ifndef INT8_MIN +#define INT8_MIN (-128) +#endif +#ifndef INT16_MIN +#define INT16_MIN (-32767-1) +#endif +#ifndef INT32_MIN +#define INT32_MIN (-2147483647-1) +#endif +#ifndef INT8_MAX +#define INT8_MAX (127) +#endif +#ifndef INT16_MAX +#define INT16_MAX (32767) +#endif +#ifndef INT32_MAX +#define INT32_MAX (2147483647) +#endif +#ifndef UINT8_MAX +#define UINT8_MAX (255U) +#endif +#ifndef UINT16_MAX +#define UINT16_MAX (65535U) +#endif +#ifndef UINT32_MAX +#define UINT32_MAX (4294967295U) +#endif + +#ifndef SIZE_MAX +#define SIZE_MAX (~(size_t)0) +#endif + +#endif /* ! C99 */ + +#endif /* ! FLEXINT_H */ + +/* %endif */ + +/* begin standard C++ headers. */ +/* %if-c++-only */ +/* %endif */ + +/* TODO: this is always defined, so inline it */ +#define yyconst const + +#if defined(__GNUC__) && __GNUC__ >= 3 +#define yynoreturn __attribute__((__noreturn__)) +#else +#define yynoreturn +#endif + +/* %not-for-header */ + +/* %not-for-header */ + +/* %if-reentrant */ + +/* An opaque pointer. */ +#ifndef YY_TYPEDEF_YY_SCANNER_T +#define YY_TYPEDEF_YY_SCANNER_T +typedef void* yyscan_t; +#endif + +/* For convenience, these vars (plus the bison vars far below) + are macros in the reentrant scanner. */ +#define yyin yyg->yyin_r +#define yyout yyg->yyout_r +#define yyextra yyg->yyextra_r +#define yyleng yyg->yyleng_r +#define yytext yyg->yytext_r +#define yylineno (YY_CURRENT_BUFFER_LVALUE->yy_bs_lineno) +#define yycolumn (YY_CURRENT_BUFFER_LVALUE->yy_bs_column) +#define yy_flex_debug yyg->yy_flex_debug_r + +/* %endif */ + +/* %if-not-reentrant */ +/* %endif */ + +/* Size of default input buffer. */ +#ifndef YY_BUF_SIZE +#ifdef __ia64__ +/* On IA-64, the buffer size is 16k, not 8k. + * Moreover, YY_BUF_SIZE is 2*YY_READ_BUF_SIZE in the general case. + * Ditto for the __ia64__ case accordingly. + */ +#define YY_BUF_SIZE 32768 +#else +#define YY_BUF_SIZE 16384 +#endif /* __ia64__ */ +#endif + +#ifndef YY_TYPEDEF_YY_BUFFER_STATE +#define YY_TYPEDEF_YY_BUFFER_STATE +typedef struct yy_buffer_state *YY_BUFFER_STATE; +#endif + +#ifndef YY_TYPEDEF_YY_SIZE_T +#define YY_TYPEDEF_YY_SIZE_T +typedef size_t yy_size_t; +#endif + +/* %if-not-reentrant */ +/* %endif */ + +/* %if-c-only */ +/* %if-not-reentrant */ +/* %endif */ +/* %endif */ + +#ifndef YY_STRUCT_YY_BUFFER_STATE +#define YY_STRUCT_YY_BUFFER_STATE +struct yy_buffer_state + { +/* %if-c-only */ + FILE *yy_input_file; +/* %endif */ + +/* %if-c++-only */ +/* %endif */ + + char *yy_ch_buf; /* input buffer */ + char *yy_buf_pos; /* current position in input buffer */ + + /* Size of input buffer in bytes, not including room for EOB + * characters. + */ + int yy_buf_size; + + /* Number of characters read into yy_ch_buf, not including EOB + * characters. + */ + int yy_n_chars; + + /* Whether we "own" the buffer - i.e., we know we created it, + * and can realloc() it to grow it, and should free() it to + * delete it. + */ + int yy_is_our_buffer; + + /* Whether this is an "interactive" input source; if so, and + * if we're using stdio for input, then we want to use getc() + * instead of fread(), to make sure we stop fetching input after + * each newline. + */ + int yy_is_interactive; + + /* Whether we're considered to be at the beginning of a line. + * If so, '^' rules will be active on the next match, otherwise + * not. + */ + int yy_at_bol; + + int yy_bs_lineno; /**< The line count. */ + int yy_bs_column; /**< The column count. */ + + /* Whether to try to fill the input buffer when we reach the + * end of it. + */ + int yy_fill_buffer; + + int yy_buffer_status; + + }; +#endif /* !YY_STRUCT_YY_BUFFER_STATE */ + +/* %if-c-only Standard (non-C++) definition */ +/* %not-for-header */ + +/* %endif */ + +/* %if-c-only Standard (non-C++) definition */ + +/* %if-not-reentrant */ +/* %not-for-header */ + +/* %endif */ + +void yyrestart ( FILE *input_file , yyscan_t yyscanner ); +void yy_switch_to_buffer ( YY_BUFFER_STATE new_buffer , yyscan_t yyscanner ); +YY_BUFFER_STATE yy_create_buffer ( FILE *file, int size , yyscan_t yyscanner ); +void yy_delete_buffer ( YY_BUFFER_STATE b , yyscan_t yyscanner ); +void yy_flush_buffer ( YY_BUFFER_STATE b , yyscan_t yyscanner ); +void yypush_buffer_state ( YY_BUFFER_STATE new_buffer , yyscan_t yyscanner ); +void yypop_buffer_state ( yyscan_t yyscanner ); + +YY_BUFFER_STATE yy_scan_buffer ( char *base, yy_size_t size , yyscan_t yyscanner ); +YY_BUFFER_STATE yy_scan_string ( const char *yy_str , yyscan_t yyscanner ); +YY_BUFFER_STATE yy_scan_bytes ( const char *bytes, int len , yyscan_t yyscanner ); + +/* %endif */ + +void *yyalloc ( yy_size_t , yyscan_t yyscanner ); +void *yyrealloc ( void *, yy_size_t , yyscan_t yyscanner ); +void yyfree ( void * , yyscan_t yyscanner ); + +/* %% [1.0] yytext/yyin/yyout/yy_state_type/yylineno etc. def's & init go here */ +/* Begin user sect3 */ + +#define yywrap(yyscanner) (/*CONSTCOND*/1) +#define YY_SKIP_YYWRAP + +#define FLEX_DEBUG + +#define yytext_ptr yytext_r + +/* %if-c-only Standard (non-C++) definition */ + +/* %endif */ + +#ifdef YY_HEADER_EXPORT_START_CONDITIONS +#define INITIAL 0 +#define BETWEEN_MODE 1 + +#endif + +#ifndef YY_NO_UNISTD_H +/* Special case for "unistd.h", since it is non-ANSI. We include it way + * down here because we want the user's section 1 to have been scanned first. + * The user has a chance to override it with an option. + */ +/* %if-c-only */ +#include +/* %endif */ +/* %if-c++-only */ +/* %endif */ +#endif + +#ifndef YY_EXTRA_TYPE +#define YY_EXTRA_TYPE void * +#endif + +/* %if-c-only Reentrant structure and macros (non-C++). */ +/* %if-reentrant */ + +/* %if-c-only */ + +/* %endif */ + +/* %if-reentrant */ + +int yylex_init (yyscan_t* scanner); + +int yylex_init_extra ( YY_EXTRA_TYPE user_defined, yyscan_t* scanner); + +/* %endif */ + +/* %endif End reentrant structures and macros. */ + +/* Accessor methods to globals. + These are made visible to non-reentrant scanners for convenience. */ + +int yylex_destroy ( yyscan_t yyscanner ); + +int yyget_debug ( yyscan_t yyscanner ); + +void yyset_debug ( int debug_flag , yyscan_t yyscanner ); + +YY_EXTRA_TYPE yyget_extra ( yyscan_t yyscanner ); + +void yyset_extra ( YY_EXTRA_TYPE user_defined , yyscan_t yyscanner ); + +FILE *yyget_in ( yyscan_t yyscanner ); + +void yyset_in ( FILE * _in_str , yyscan_t yyscanner ); + +FILE *yyget_out ( yyscan_t yyscanner ); + +void yyset_out ( FILE * _out_str , yyscan_t yyscanner ); + + int yyget_leng ( yyscan_t yyscanner ); + +char *yyget_text ( yyscan_t yyscanner ); + +int yyget_lineno ( yyscan_t yyscanner ); + +void yyset_lineno ( int _line_number , yyscan_t yyscanner ); + +int yyget_column ( yyscan_t yyscanner ); + +void yyset_column ( int _column_no , yyscan_t yyscanner ); + +/* %if-bison-bridge */ +/* %endif */ + +/* Macros after this point can all be overridden by user definitions in + * section 1. + */ + +#ifndef YY_SKIP_YYWRAP +#ifdef __cplusplus +extern "C" int yywrap ( yyscan_t yyscanner ); +#else +extern int yywrap ( yyscan_t yyscanner ); +#endif +#endif + +/* %not-for-header */ + +/* %endif */ + +#ifndef yytext_ptr +static void yy_flex_strncpy ( char *, const char *, int , yyscan_t yyscanner); +#endif + +#ifdef YY_NEED_STRLEN +static int yy_flex_strlen ( const char * , yyscan_t yyscanner); +#endif + +#ifndef YY_NO_INPUT +/* %if-c-only Standard (non-C++) definition */ +/* %not-for-header */ + +/* %endif */ +#endif + +/* %if-c-only */ + +/* %endif */ + +/* Amount of stuff to slurp up with each read. */ +#ifndef YY_READ_BUF_SIZE +#ifdef __ia64__ +/* On IA-64, the buffer size is 16k, not 8k */ +#define YY_READ_BUF_SIZE 16384 +#else +#define YY_READ_BUF_SIZE 8192 +#endif /* __ia64__ */ +#endif + +/* Number of entries by which start-condition stack grows. */ +#ifndef YY_START_STACK_INCR +#define YY_START_STACK_INCR 25 +#endif + +/* %if-tables-serialization structures and prototypes */ +/* %not-for-header */ + +/* %not-for-header */ + +/* Default declaration of generated scanner - a define so the user can + * easily add parameters. + */ +#ifndef YY_DECL +#define YY_DECL_IS_OURS 1 +/* %if-c-only Standard (non-C++) definition */ + +extern int yylex (yyscan_t yyscanner); + +#define YY_DECL int yylex (yyscan_t yyscanner) +/* %endif */ +/* %if-c++-only C++ definition */ +/* %endif */ +#endif /* !YY_DECL */ + +/* %not-for-header */ + +/* %if-c++-only */ +/* %not-for-header */ + +/* %endif */ + +/* yy_get_previous_state - get the state just before the EOB char was reached */ + +/* %if-c-only */ +/* %not-for-header */ + +#undef YY_NEW_FILE +#undef YY_FLUSH_BUFFER +#undef yy_set_bol +#undef yy_new_buffer +#undef yy_set_interactive +#undef YY_DO_BEFORE_ACTION + +#ifdef YY_DECL_IS_OURS +#undef YY_DECL_IS_OURS +#undef YY_DECL +#endif + +#ifndef yy_create_buffer_ALREADY_DEFINED +#undef yy_create_buffer +#endif +#ifndef yy_delete_buffer_ALREADY_DEFINED +#undef yy_delete_buffer +#endif +#ifndef yy_scan_buffer_ALREADY_DEFINED +#undef yy_scan_buffer +#endif +#ifndef yy_scan_string_ALREADY_DEFINED +#undef yy_scan_string +#endif +#ifndef yy_scan_bytes_ALREADY_DEFINED +#undef yy_scan_bytes +#endif +#ifndef yy_init_buffer_ALREADY_DEFINED +#undef yy_init_buffer +#endif +#ifndef yy_flush_buffer_ALREADY_DEFINED +#undef yy_flush_buffer +#endif +#ifndef yy_load_buffer_state_ALREADY_DEFINED +#undef yy_load_buffer_state +#endif +#ifndef yy_switch_to_buffer_ALREADY_DEFINED +#undef yy_switch_to_buffer +#endif +#ifndef yypush_buffer_state_ALREADY_DEFINED +#undef yypush_buffer_state +#endif +#ifndef yypop_buffer_state_ALREADY_DEFINED +#undef yypop_buffer_state +#endif +#ifndef yyensure_buffer_stack_ALREADY_DEFINED +#undef yyensure_buffer_stack +#endif +#ifndef yylex_ALREADY_DEFINED +#undef yylex +#endif +#ifndef yyrestart_ALREADY_DEFINED +#undef yyrestart +#endif +#ifndef yylex_init_ALREADY_DEFINED +#undef yylex_init +#endif +#ifndef yylex_init_extra_ALREADY_DEFINED +#undef yylex_init_extra +#endif +#ifndef yylex_destroy_ALREADY_DEFINED +#undef yylex_destroy +#endif +#ifndef yyget_debug_ALREADY_DEFINED +#undef yyget_debug +#endif +#ifndef yyset_debug_ALREADY_DEFINED +#undef yyset_debug +#endif +#ifndef yyget_extra_ALREADY_DEFINED +#undef yyget_extra +#endif +#ifndef yyset_extra_ALREADY_DEFINED +#undef yyset_extra +#endif +#ifndef yyget_in_ALREADY_DEFINED +#undef yyget_in +#endif +#ifndef yyset_in_ALREADY_DEFINED +#undef yyset_in +#endif +#ifndef yyget_out_ALREADY_DEFINED +#undef yyget_out +#endif +#ifndef yyset_out_ALREADY_DEFINED +#undef yyset_out +#endif +#ifndef yyget_leng_ALREADY_DEFINED +#undef yyget_leng +#endif +#ifndef yyget_text_ALREADY_DEFINED +#undef yyget_text +#endif +#ifndef yyget_lineno_ALREADY_DEFINED +#undef yyget_lineno +#endif +#ifndef yyset_lineno_ALREADY_DEFINED +#undef yyset_lineno +#endif +#ifndef yyget_column_ALREADY_DEFINED +#undef yyget_column +#endif +#ifndef yyset_column_ALREADY_DEFINED +#undef yyset_column +#endif +#ifndef yywrap_ALREADY_DEFINED +#undef yywrap +#endif +#ifndef yyget_lval_ALREADY_DEFINED +#undef yyget_lval +#endif +#ifndef yyset_lval_ALREADY_DEFINED +#undef yyset_lval +#endif +#ifndef yyget_lloc_ALREADY_DEFINED +#undef yyget_lloc +#endif +#ifndef yyset_lloc_ALREADY_DEFINED +#undef yyset_lloc +#endif +#ifndef yyalloc_ALREADY_DEFINED +#undef yyalloc +#endif +#ifndef yyrealloc_ALREADY_DEFINED +#undef yyrealloc +#endif +#ifndef yyfree_ALREADY_DEFINED +#undef yyfree +#endif +#ifndef yytext_ALREADY_DEFINED +#undef yytext +#endif +#ifndef yyleng_ALREADY_DEFINED +#undef yyleng +#endif +#ifndef yyin_ALREADY_DEFINED +#undef yyin +#endif +#ifndef yyout_ALREADY_DEFINED +#undef yyout +#endif +#ifndef yy_flex_debug_ALREADY_DEFINED +#undef yy_flex_debug +#endif +#ifndef yylineno_ALREADY_DEFINED +#undef yylineno +#endif +#ifndef yytables_fload_ALREADY_DEFINED +#undef yytables_fload +#endif +#ifndef yytables_destroy_ALREADY_DEFINED +#undef yytables_destroy +#endif +#ifndef yyTABLES_NAME_ALREADY_DEFINED +#undef yyTABLES_NAME +#endif + +#line 238 "sqlite3_lexer.ll" + + +#line 609 "sqlite3_lexer.h" +#undef yyIN_HEADER +#endif /* yyHEADER_H */ diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/sql/parser/sqlite3_lexer.ll b/src/WBCLFZSystemModule/SqliteDBProcess/src/sql/parser/sqlite3_lexer.ll new file mode 100644 index 0000000..6c52487 --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/sql/parser/sqlite3_lexer.ll @@ -0,0 +1,259 @@ +%{ +#include +#include "ParserDriver.h" +#include "sqlite3_parser.hpp" +%} + +%option noyywrap nounput batch debug case-insensitive 8bit never-interactive nodefault nounistd reentrant warn +%option header-file="sqlite3_lexer.h" +%option outfile="sqlite3_lexer.cpp" + +%{ + #define TOKEN(n) sqlb::parser::parser::symbol_type(sqlb::parser::parser::token::TOK_##n, yytext, loc) + + std::string unquote_string(std::string s, char quote_char) + { + if(s.size() < 2) + return s; + + if(quote_char == '[') + { + if(s.front() == '[' && s.back() == ']') + s = s.substr(1, s.size()-2); + } else { + if(s.front() == quote_char && s.back() == quote_char) + { + s = s.substr(1, s.size()-2); + auto pos = s.npos; + while((pos = s.find(std::string(2, quote_char))) != s.npos) + s = s.replace(pos, 2, std::string(1, quote_char)); + } + } + + return s; + } +%} + +U [\x80-\xbf] +U2 [\xc2-\xdf] +U3 [\xe0-\xef] +U4 [\xf0-\xf4] +UNICODE {U2}{U}|{U3}{U}{U}|{U4}{U}{U}{U} + +ID ([a-z_]|{UNICODE})([a-z0-9_]|{UNICODE})* + +GRAVEQUOTEDID `([^\n`]|(``))*` +SQUAREBRACKETID \[([^\n\]])*\] + +QUOTEDLITERAL \"([^\n\"]|(\"\"))*\" +STRINGLITERAL \'([^\n\']|(\'\'))*\' +BLOBLITERAL X\'[0-9a-f]*\' + +BINDPARAMETER_NUM \?([1-9]{DIGIT}*)? +BINDPARAMETER_STR [:@][a-z]+ + /* TODO Add $ bind parameters */ + +DIGIT [0-9] +NUMERIC (({DIGIT}+(\.{DIGIT}*)?|(\.{DIGIT}+))(e[\+\-]?{DIGIT}+)?)|(0x[0-9a-f]+) + +NL [\r\n] +WS [ \t\f] + +%{ + // Code run each time a pattern is matched. + #define YY_USER_ACTION loc.columns(yyleng); +%} + +%s BETWEEN_MODE + +%% + +%{ + // Shortcut to the location held by the driver + sqlb::parser::location& loc = drv.location; + + // Code run each time yylex is called. + loc.step(); +%} + +{WS}+ loc.step(); +{NL}+ loc.lines(yyleng); loc.step(); + +"--" { + int c; + while((c = yyinput(yyscanner)) != '\n' && c != EOF) + ; /* eat up text of comment */ + } + +"/*" { + int c; + + for(;;) + { + while((c = yyinput(yyscanner)) != '*' && c != EOF) + ; /* eat up text of comment */ + + if(c == '*') + { + while((c = yyinput(yyscanner)) == '*') + ; + if(c == '/') + break; /* found the end */ + } + + if(c == EOF) + throw sqlb::parser::parser::syntax_error(loc, "EOF in comment"); + } + } + + /* For lack of a better idea, we need this hack to avoid reduce/reduce conflicts in the rules for parsing BETWEEN expressions. + * What we do here is distinguish two types of AND operators: the regular one and the special case when the AND follows a BETWEEN keyword. + */ +"AND" { BEGIN INITIAL; return TOKEN(AND_BETWEEN); } +"AND" return TOKEN(AND); +"BETWEEN" { BEGIN BETWEEN_MODE; return TOKEN(BETWEEN); } + +"ABORT" return TOKEN(ABORT); +"ACTION" return TOKEN(ACTION); +"ALWAYS" return TOKEN(ALWAYS); +"AS" return TOKEN(AS); +"ASC" return TOKEN(ASC); +"AUTOINCREMENT" return TOKEN(AUTOINCREMENT); +"CASCADE" return TOKEN(CASCADE); +"CASE" return TOKEN(CASE); +"CAST" return TOKEN(CAST); +"CHECK" return TOKEN(CHECK); +"COLLATE" return TOKEN(COLLATE); +"CONFLICT" return TOKEN(CONFLICT); +"CONSTRAINT" return TOKEN(CONSTRAINT); +"CREATE" return TOKEN(CREATE); +"CURRENT_DATE" return TOKEN(CURRENT_DATE); +"CURRENT_TIME" return TOKEN(CURRENT_TIME); +"CURRENT_TIMESTAMP" return TOKEN(CURRENT_TIMESTAMP); +"DEFAULT" return TOKEN(DEFAULT); +"DEFERRABLE" return TOKEN(DEFERRABLE); +"DEFERRED" return TOKEN(DEFERRED); +"DELETE" return TOKEN(DELETE); +"DESC" return TOKEN(DESC); +"DISTINCT" return TOKEN(DISTINCT); +"ELSE" return TOKEN(ELSE); +"END" return TOKEN(END); +"ESCAPE" return TOKEN(ESCAPE); +"EXISTS" return TOKEN(EXISTS); +"FAIL" return TOKEN(FAIL); +"FALSE" return TOKEN(FALSE); +"FILTER" return TOKEN(FILTER); +"FOLLOWING" return TOKEN(FOLLOWING); +"FOREIGN" return TOKEN(FOREIGN); +"GENERATED" return TOKEN(GENERATED); +"GLOB" return TOKEN(GLOB); +"IF" return TOKEN(IF); +"IGNORE" return TOKEN(IGNORE); +"IMMEDIATE" return TOKEN(IMMEDIATE); +"IN" return TOKEN(IN); +"INDEX" return TOKEN(INDEX); +"INITIALLY" return TOKEN(INITIALLY); +"INSERT" return TOKEN(INSERT); +"IS" return TOKEN(IS); +"ISNULL" return TOKEN(ISNULL); +"KEY" return TOKEN(KEY); +"LIKE" return TOKEN(LIKE); +"MATCH" return TOKEN(MATCH); +"NO" return TOKEN(NO); +"NOT" return TOKEN(NOT); +"NOTNULL" return TOKEN(NOTNULL); +"NULL" return TOKEN(NULL); +"ON" return TOKEN(ON); +"OR" return TOKEN(OR); +"OVER" return TOKEN(OVER); +"PARTITION" return TOKEN(PARTITION); +"PRECEDING" return TOKEN(PRECEDING); +"PRIMARY" return TOKEN(PRIMARY); +"RAISE" return TOKEN(RAISE); +"RANGE" return TOKEN(RANGE); +"REFERENCES" return TOKEN(REFERENCES); +"REGEXP" return TOKEN(REGEXP); +"REPLACE" return TOKEN(REPLACE); +"RESTRICT" return TOKEN(RESTRICT); +"ROLLBACK" return TOKEN(ROLLBACK); +"ROWID" return TOKEN(ROWID); +"ROWS" return TOKEN(ROWS); +"SELECT" return TOKEN(SELECT); +"SET" return TOKEN(SET); +"STORED" return TOKEN(STORED); +"TABLE" return TOKEN(TABLE); +"TEMP" return TOKEN(TEMP); +"TEMPORARY" return TOKEN(TEMPORARY); +"THEN" return TOKEN(THEN); +"TRUE" return TOKEN(TRUE); +"UNBOUNDED" return TOKEN(UNBOUNDED); +"UNIQUE" return TOKEN(UNIQUE); +"UPDATE" return TOKEN(UPDATE); +"USING" return TOKEN(USING); +"VIRTUAL" return TOKEN(VIRTUAL); +"WHEN" return TOKEN(WHEN); +"WHERE" return TOKEN(WHERE); +"WITHOUT" return TOKEN(WITHOUT); + +{ID} return sqlb::parser::parser::make_IDENTIFIER(yytext, loc); +{GRAVEQUOTEDID} return sqlb::parser::parser::make_IDENTIFIER(unquote_string(yytext, '`'), loc); +{SQUAREBRACKETID} return sqlb::parser::parser::make_IDENTIFIER(unquote_string(yytext, '['), loc); +{QUOTEDLITERAL} return sqlb::parser::parser::make_QUOTEDLITERAL(unquote_string(yytext, '"'), loc); +{STRINGLITERAL} return sqlb::parser::parser::make_STRINGLITERAL(yytext, loc); +{NUMERIC} return sqlb::parser::parser::make_NUMERIC(yytext, loc); +{BLOBLITERAL} return sqlb::parser::parser::make_BLOBLITERAL(yytext, loc); +{BINDPARAMETER_NUM} return sqlb::parser::parser::make_BINDPARAMETER(yytext, loc); +{BINDPARAMETER_STR} return sqlb::parser::parser::make_BINDPARAMETER(yytext, loc); + +"(" return sqlb::parser::parser::make_LPAREN(loc); +")" return sqlb::parser::parser::make_RPAREN(loc); +"." return sqlb::parser::parser::make_DOT(loc); +"," return sqlb::parser::parser::make_COMMA(loc); +";" return sqlb::parser::parser::make_SEMI(loc); +"+" return sqlb::parser::parser::make_PLUS(loc); +"-" return sqlb::parser::parser::make_MINUS(loc); +"*" return sqlb::parser::parser::make_STAR(loc); +"/" return sqlb::parser::parser::make_SLASH(loc); +"~" return sqlb::parser::parser::make_TILDE(loc); +"&" return sqlb::parser::parser::make_AMPERSAND(loc); +"%" return sqlb::parser::parser::make_PERCENT(loc); +"|" return sqlb::parser::parser::make_BITOR(loc); +"||" return sqlb::parser::parser::make_OROP(loc); +"=" return sqlb::parser::parser::make_EQUAL(loc); +"==" return sqlb::parser::parser::make_EQUAL2(loc); +">" return sqlb::parser::parser::make_GREATER(loc); +">=" return sqlb::parser::parser::make_GREATEREQUAL(loc); +"<" return sqlb::parser::parser::make_LOWER(loc); +"<=" return sqlb::parser::parser::make_LOWEREQUAL(loc); +"!=" return sqlb::parser::parser::make_UNEQUAL(loc); +"<>" return sqlb::parser::parser::make_UNEQUAL2(loc); +"<<" return sqlb::parser::parser::make_BITWISELEFT(loc); +">>" return sqlb::parser::parser::make_BITWISERIGHT(loc); + +. throw sqlb::parser::parser::syntax_error(loc, "Invalid character: " + std::string(yytext)); + +<> return sqlb::parser::parser::make_EOF(loc); + +%% + +namespace sqlb +{ +namespace parser +{ + +void ParserDriver::begin_scan() +{ + yylex_init(&scanner); + location.initialize(); + yyset_debug(trace_scanner, scanner); + buffer = yy_scan_string(source.c_str(), scanner); +} + +void ParserDriver::end_scan() +{ + yy_delete_buffer(buffer, scanner); + yylex_destroy(scanner); +} + +} +} diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/sql/parser/sqlite3_location.h b/src/WBCLFZSystemModule/SqliteDBProcess/src/sql/parser/sqlite3_location.h new file mode 100644 index 0000000..ecfeb72 --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/sql/parser/sqlite3_location.h @@ -0,0 +1,334 @@ +// A Bison parser, made by GNU Bison 3.5.1. + +// Locations for Bison parsers in C++ + +// Copyright (C) 2002-2015, 2018-2020 Free Software Foundation, Inc. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, 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 . + +// As a special exception, you may create a larger work that contains +// part or all of the Bison parser skeleton and distribute that work +// under terms of your choice, so long as that work isn't itself a +// parser generator using the skeleton or a modified version thereof +// as a parser skeleton. Alternatively, if you modify or redistribute +// the parser skeleton itself, you may (at your option) remove this +// special exception, which will cause the skeleton and the resulting +// Bison output files to be licensed under the GNU General Public +// License without this special exception. + +// This special exception was added by the Free Software Foundation in +// version 2.2 of Bison. + +/** + ** \file sqlite3_location.h + ** Define the sqlb::parser ::location class. + */ + +#ifndef YY_YY_SQLITE3_LOCATION_H_INCLUDED +# define YY_YY_SQLITE3_LOCATION_H_INCLUDED + +# include +# include + +# ifndef YY_NULLPTR +# if defined __cplusplus +# if 201103L <= __cplusplus +# define YY_NULLPTR nullptr +# else +# define YY_NULLPTR 0 +# endif +# else +# define YY_NULLPTR ((void*)0) +# endif +# endif + +#line 10 "sqlite3_parser.yy" +namespace sqlb { namespace parser { +#line 59 "sqlite3_location.h" + + /// A point in a source file. + class position + { + public: + /// Type for line and column numbers. + typedef int counter_type; + + /// Construct a position. + explicit position (std::string* f = YY_NULLPTR, + counter_type l = 1, + counter_type c = 1) + : filename (f) + , line (l) + , column (c) + {} + + + /// Initialization. + void initialize (std::string* fn = YY_NULLPTR, + counter_type l = 1, + counter_type c = 1) + { + filename = fn; + line = l; + column = c; + } + + /** \name Line and Column related manipulators + ** \{ */ + /// (line related) Advance to the COUNT next lines. + void lines (counter_type count = 1) + { + if (count) + { + column = 1; + line = add_ (line, count, 1); + } + } + + /// (column related) Advance to the COUNT next columns. + void columns (counter_type count = 1) + { + column = add_ (column, count, 1); + } + /** \} */ + + /// File name to which this position refers. + std::string* filename; + /// Current line number. + counter_type line; + /// Current column number. + counter_type column; + + private: + /// Compute max (min, lhs+rhs). + static counter_type add_ (counter_type lhs, counter_type rhs, counter_type min) + { + return lhs + rhs < min ? min : lhs + rhs; + } + }; + + /// Add \a width columns, in place. + inline position& + operator+= (position& res, position::counter_type width) + { + res.columns (width); + return res; + } + + /// Add \a width columns. + inline position + operator+ (position res, position::counter_type width) + { + return res += width; + } + + /// Subtract \a width columns, in place. + inline position& + operator-= (position& res, position::counter_type width) + { + return res += -width; + } + + /// Subtract \a width columns. + inline position + operator- (position res, position::counter_type width) + { + return res -= width; + } + + /// Compare two position objects. + inline bool + operator== (const position& pos1, const position& pos2) + { + return (pos1.line == pos2.line + && pos1.column == pos2.column + && (pos1.filename == pos2.filename + || (pos1.filename && pos2.filename + && *pos1.filename == *pos2.filename))); + } + + /// Compare two position objects. + inline bool + operator!= (const position& pos1, const position& pos2) + { + return !(pos1 == pos2); + } + + /** \brief Intercept output stream redirection. + ** \param ostr the destination output stream + ** \param pos a reference to the position to redirect + */ + template + std::basic_ostream& + operator<< (std::basic_ostream& ostr, const position& pos) + { + if (pos.filename) + ostr << *pos.filename << ':'; + return ostr << pos.line << '.' << pos.column; + } + + /// Two points in a source file. + class location + { + public: + /// Type for line and column numbers. + typedef position::counter_type counter_type; + + /// Construct a location from \a b to \a e. + location (const position& b, const position& e) + : begin (b) + , end (e) + {} + + /// Construct a 0-width location in \a p. + explicit location (const position& p = position ()) + : begin (p) + , end (p) + {} + + /// Construct a 0-width location in \a f, \a l, \a c. + explicit location (std::string* f, + counter_type l = 1, + counter_type c = 1) + : begin (f, l, c) + , end (f, l, c) + {} + + + /// Initialization. + void initialize (std::string* f = YY_NULLPTR, + counter_type l = 1, + counter_type c = 1) + { + begin.initialize (f, l, c); + end = begin; + } + + /** \name Line and Column related manipulators + ** \{ */ + public: + /// Reset initial location to final location. + void step () + { + begin = end; + } + + /// Extend the current location to the COUNT next columns. + void columns (counter_type count = 1) + { + end += count; + } + + /// Extend the current location to the COUNT next lines. + void lines (counter_type count = 1) + { + end.lines (count); + } + /** \} */ + + + public: + /// Beginning of the located region. + position begin; + /// End of the located region. + position end; + }; + + /// Join two locations, in place. + inline location& + operator+= (location& res, const location& end) + { + res.end = end.end; + return res; + } + + /// Join two locations. + inline location + operator+ (location res, const location& end) + { + return res += end; + } + + /// Add \a width columns to the end position, in place. + inline location& + operator+= (location& res, location::counter_type width) + { + res.columns (width); + return res; + } + + /// Add \a width columns to the end position. + inline location + operator+ (location res, location::counter_type width) + { + return res += width; + } + + /// Subtract \a width columns to the end position, in place. + inline location& + operator-= (location& res, location::counter_type width) + { + return res += -width; + } + + /// Subtract \a width columns to the end position. + inline location + operator- (location res, location::counter_type width) + { + return res -= width; + } + + /// Compare two location objects. + inline bool + operator== (const location& loc1, const location& loc2) + { + return loc1.begin == loc2.begin && loc1.end == loc2.end; + } + + /// Compare two location objects. + inline bool + operator!= (const location& loc1, const location& loc2) + { + return !(loc1 == loc2); + } + + /** \brief Intercept output stream redirection. + ** \param ostr the destination output stream + ** \param loc a reference to the location to redirect + ** + ** Avoid duplicate information. + */ + template + std::basic_ostream& + operator<< (std::basic_ostream& ostr, const location& loc) + { + location::counter_type end_col + = 0 < loc.end.column ? loc.end.column - 1 : 0; + ostr << loc.begin; + if (loc.end.filename + && (!loc.begin.filename + || *loc.begin.filename != *loc.end.filename)) + ostr << '-' << loc.end.filename << ':' << loc.end.line << '.' << end_col; + else if (loc.begin.line < loc.end.line) + ostr << '-' << loc.end.line << '.' << end_col; + else if (loc.begin.column < end_col) + ostr << '-' << end_col; + return ostr; + } + +#line 10 "sqlite3_parser.yy" +} } // sqlb::parser +#line 333 "sqlite3_location.h" + +#endif // !YY_YY_SQLITE3_LOCATION_H_INCLUDED diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/sql/parser/sqlite3_parser.cpp b/src/WBCLFZSystemModule/SqliteDBProcess/src/sql/parser/sqlite3_parser.cpp new file mode 100644 index 0000000..f6d1328 --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/sql/parser/sqlite3_parser.cpp @@ -0,0 +1,4726 @@ +// A Bison parser, made by GNU Bison 3.5.1. + +// Skeleton implementation for Bison LALR(1) parsers in C++ + +// Copyright (C) 2002-2015, 2018-2020 Free Software Foundation, Inc. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, 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 . + +// As a special exception, you may create a larger work that contains +// part or all of the Bison parser skeleton and distribute that work +// under terms of your choice, so long as that work isn't itself a +// parser generator using the skeleton or a modified version thereof +// as a parser skeleton. Alternatively, if you modify or redistribute +// the parser skeleton itself, you may (at your option) remove this +// special exception, which will cause the skeleton and the resulting +// Bison output files to be licensed under the GNU General Public +// License without this special exception. + +// This special exception was added by the Free Software Foundation in +// version 2.2 of Bison. + +// Undocumented macros, especially those whose name start with YY_, +// are private implementation details. Do not rely on them. + + + + + +#include "sqlite3_parser.hpp" + + +// Unqualified %code blocks. +#line 88 "sqlite3_parser.yy" + + #include "ParserDriver.h" + + static std::string unquote_text(std::string str, char quote_char) + { + if(str.front() != quote_char || str.back() != quote_char) + return str; + + str = str.substr(1, str.size()-2); + + std::string quote(2, quote_char); + + size_t pos = 0; + while((pos = str.find(quote, pos)) != std::string::npos) + { + str.erase(pos, 1); + pos += 1; // Don't remove the other quote char too + } + return str; + } + +#line 67 "sqlite3_parser.cpp" + + +#ifndef YY_ +# if defined YYENABLE_NLS && YYENABLE_NLS +# if ENABLE_NLS +# include // FIXME: INFRINGES ON USER NAME SPACE. +# define YY_(msgid) dgettext ("bison-runtime", msgid) +# endif +# endif +# ifndef YY_ +# define YY_(msgid) msgid +# endif +#endif + +// Whether we are compiled with exception support. +#ifndef YY_EXCEPTIONS +# if defined __GNUC__ && !defined __EXCEPTIONS +# define YY_EXCEPTIONS 0 +# else +# define YY_EXCEPTIONS 1 +# endif +#endif + +#define YYRHSLOC(Rhs, K) ((Rhs)[K].location) +/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N]. + If N is 0, then set CURRENT to the empty location which ends + the previous symbol: RHS[0] (always defined). */ + +# ifndef YYLLOC_DEFAULT +# define YYLLOC_DEFAULT(Current, Rhs, N) \ + do \ + if (N) \ + { \ + (Current).begin = YYRHSLOC (Rhs, 1).begin; \ + (Current).end = YYRHSLOC (Rhs, N).end; \ + } \ + else \ + { \ + (Current).begin = (Current).end = YYRHSLOC (Rhs, 0).end; \ + } \ + while (false) +# endif + + +// Enable debugging if requested. +#if YYDEBUG + +// A pseudo ostream that takes yydebug_ into account. +# define YYCDEBUG if (yydebug_) (*yycdebug_) + +# define YY_SYMBOL_PRINT(Title, Symbol) \ + do { \ + if (yydebug_) \ + { \ + *yycdebug_ << Title << ' '; \ + yy_print_ (*yycdebug_, Symbol); \ + *yycdebug_ << '\n'; \ + } \ + } while (false) + +# define YY_REDUCE_PRINT(Rule) \ + do { \ + if (yydebug_) \ + yy_reduce_print_ (Rule); \ + } while (false) + +# define YY_STACK_PRINT() \ + do { \ + if (yydebug_) \ + yystack_print_ (); \ + } while (false) + +#else // !YYDEBUG + +# define YYCDEBUG if (false) std::cerr +# define YY_SYMBOL_PRINT(Title, Symbol) YYUSE (Symbol) +# define YY_REDUCE_PRINT(Rule) static_cast (0) +# define YY_STACK_PRINT() static_cast (0) + +#endif // !YYDEBUG + +#define yyerrok (yyerrstatus_ = 0) +#define yyclearin (yyla.clear ()) + +#define YYACCEPT goto yyacceptlab +#define YYABORT goto yyabortlab +#define YYERROR goto yyerrorlab +#define YYRECOVERING() (!!yyerrstatus_) + +#line 10 "sqlite3_parser.yy" +namespace sqlb { namespace parser { +#line 159 "sqlite3_parser.cpp" + + + /* Return YYSTR after stripping away unnecessary quotes and + backslashes, so that it's suitable for yyerror. The heuristic is + that double-quoting is unnecessary unless the string contains an + apostrophe, a comma, or backslash (other than backslash-backslash). + YYSTR is taken from yytname. */ + std::string + parser::yytnamerr_ (const char *yystr) + { + if (*yystr == '"') + { + std::string yyr; + char const *yyp = yystr; + + for (;;) + switch (*++yyp) + { + case '\'': + case ',': + goto do_not_strip_quotes; + + case '\\': + if (*++yyp != '\\') + goto do_not_strip_quotes; + else + goto append; + + append: + default: + yyr += *yyp; + break; + + case '"': + return yyr; + } + do_not_strip_quotes: ; + } + + return yystr; + } + + + /// Build a parser object. + parser::parser (yyscan_t yyscanner_yyarg, ParserDriver& drv_yyarg) +#if YYDEBUG + : yydebug_ (false), + yycdebug_ (&std::cerr), +#else + : +#endif + yyscanner (yyscanner_yyarg), + drv (drv_yyarg) + {} + + parser::~parser () + {} + + parser::syntax_error::~syntax_error () YY_NOEXCEPT YY_NOTHROW + {} + + /*---------------. + | Symbol types. | + `---------------*/ + + + + // by_state. + parser::by_state::by_state () YY_NOEXCEPT + : state (empty_state) + {} + + parser::by_state::by_state (const by_state& that) YY_NOEXCEPT + : state (that.state) + {} + + void + parser::by_state::clear () YY_NOEXCEPT + { + state = empty_state; + } + + void + parser::by_state::move (by_state& that) + { + state = that.state; + that.clear (); + } + + parser::by_state::by_state (state_type s) YY_NOEXCEPT + : state (s) + {} + + parser::symbol_number_type + parser::by_state::type_get () const YY_NOEXCEPT + { + if (state == empty_state) + return empty_symbol; + else + return yystos_[+state]; + } + + parser::stack_symbol_type::stack_symbol_type () + {} + + parser::stack_symbol_type::stack_symbol_type (YY_RVREF (stack_symbol_type) that) + : super_type (YY_MOVE (that.state), YY_MOVE (that.location)) + { + switch (that.type_get ()) + { + case 158: // columnconstraint + value.YY_MOVE_OR_COPY< ColumnConstraintInfo > (YY_MOVE (that.value)); + break; + + case 159: // columnconstraint_list + value.YY_MOVE_OR_COPY< ColumnConstraintInfoVector > (YY_MOVE (that.value)); + break; + + case 160: // columndef + value.YY_MOVE_OR_COPY< ColumndefData > (YY_MOVE (that.value)); + break; + + case 142: // optional_if_not_exists + case 144: // optional_unique + case 152: // optional_temporary + case 153: // optional_withoutrowid + case 157: // optional_always_generated + value.YY_MOVE_OR_COPY< bool > (YY_MOVE (that.value)); + break; + + case 168: // tableconstraint + value.YY_MOVE_OR_COPY< sqlb::ConstraintPtr > (YY_MOVE (that.value)); + break; + + case 169: // tableconstraint_list + case 170: // optional_tableconstraint_list + value.YY_MOVE_OR_COPY< sqlb::ConstraintSet > (YY_MOVE (that.value)); + break; + + case 149: // createindex_stmt + value.YY_MOVE_OR_COPY< sqlb::IndexPtr > (YY_MOVE (that.value)); + break; + + case 147: // indexed_column + value.YY_MOVE_OR_COPY< sqlb::IndexedColumn > (YY_MOVE (that.value)); + break; + + case 148: // indexed_column_list + value.YY_MOVE_OR_COPY< sqlb::IndexedColumnVector > (YY_MOVE (that.value)); + break; + + case 163: // columnid_list + case 164: // optional_columnid_with_paren_list + value.YY_MOVE_OR_COPY< sqlb::StringVector > (YY_MOVE (that.value)); + break; + + case 151: // createvirtualtable_stmt + case 171: // createtable_stmt + value.YY_MOVE_OR_COPY< sqlb::TablePtr > (YY_MOVE (that.value)); + break; + + case 27: // "ABORT" + case 28: // "ACTION" + case 29: // "ALWAYS" + case 30: // "AND" + case 31: // "AND BETWEEN" + case 32: // "AS" + case 33: // "ASC" + case 34: // "AUTOINCREMENT" + case 35: // "BETWEEN" + case 36: // "CASCADE" + case 37: // "CASE" + case 38: // "CAST" + case 39: // "CHECK" + case 40: // "COLLATE" + case 41: // "CONFLICT" + case 42: // "CONSTRAINT" + case 43: // "CREATE" + case 44: // "CURRENT_DATE" + case 45: // "CURRENT_TIME" + case 46: // "CURRENT_TIMESTAMP" + case 47: // "DEFAULT" + case 48: // "DEFERRABLE" + case 49: // "DEFERRED" + case 50: // "DELETE" + case 51: // "DESC" + case 52: // "DISTINCT" + case 53: // "ELSE" + case 54: // "END" + case 55: // "ESCAPE" + case 56: // "EXISTS" + case 57: // "FAIL" + case 58: // "FALSE" + case 59: // "FILTER" + case 60: // "FOLLOWING" + case 61: // "FOREIGN" + case 62: // "GENERATED" + case 63: // "GLOB" + case 64: // "IF" + case 65: // "IGNORE" + case 66: // "IMMEDIATE" + case 67: // "IN" + case 68: // "INDEX" + case 69: // "INITIALLY" + case 70: // "INSERT" + case 71: // "IS" + case 72: // "ISNULL" + case 73: // "KEY" + case 74: // "LIKE" + case 75: // "MATCH" + case 76: // "NO" + case 77: // "NOT" + case 78: // "NOTNULL" + case 79: // "NULL" + case 80: // "ON" + case 81: // "OR" + case 82: // "OVER" + case 83: // "PARTITION" + case 84: // "PRECEDING" + case 85: // "PRIMARY" + case 86: // "RAISE" + case 87: // "RANGE" + case 88: // "REFERENCES" + case 89: // "REGEXP" + case 90: // "REPLACE" + case 91: // "RESTRICT" + case 92: // "ROLLBACK" + case 93: // "ROWID" + case 94: // "ROWS" + case 95: // "SELECT" + case 96: // "SET" + case 97: // "STORED" + case 98: // "TABLE" + case 99: // "TEMP" + case 100: // "TEMPORARY" + case 101: // "THEN" + case 102: // "TRUE" + case 103: // "UNBOUNDED" + case 104: // "UNIQUE" + case 105: // "UPDATE" + case 106: // "USING" + case 107: // "VIRTUAL" + case 108: // "WHEN" + case 109: // "WHERE" + case 110: // "WITHOUT" + case 111: // "identifier" + case 112: // "numeric" + case 113: // "string literal" + case 114: // "quoted literal" + case 115: // "blob literal" + case 116: // "bind parameter" + case 120: // literalvalue + case 121: // id + case 122: // allowed_keywords_as_identifier + case 123: // tableid + case 124: // columnid + case 125: // signednumber + case 126: // signednumber_or_numeric + case 127: // typename_namelist + case 128: // type_name + case 129: // unary_expr + case 130: // binary_expr + case 131: // like_expr + case 132: // exprlist_expr + case 133: // function_expr + case 134: // isnull_expr + case 135: // between_expr + case 136: // in_expr + case 137: // whenthenlist_expr + case 138: // case_expr + case 139: // raise_expr + case 140: // expr + case 141: // select_stmt + case 143: // optional_sort_order + case 145: // optional_where + case 146: // tableid_with_uninteresting_schema + case 150: // optional_exprlist_with_paren + case 154: // optional_conflictclause + case 155: // optional_typename + case 156: // optional_storage_identifier + case 162: // optional_constraintname + case 165: // fk_clause_part + case 166: // fk_clause_part_list + case 167: // optional_fk_clause + value.YY_MOVE_OR_COPY< std::string > (YY_MOVE (that.value)); + break; + + case 161: // columndef_list + value.YY_MOVE_OR_COPY< std::vector > (YY_MOVE (that.value)); + break; + + default: + break; + } + +#if 201103L <= YY_CPLUSPLUS + // that is emptied. + that.state = empty_state; +#endif + } + + parser::stack_symbol_type::stack_symbol_type (state_type s, YY_MOVE_REF (symbol_type) that) + : super_type (s, YY_MOVE (that.location)) + { + switch (that.type_get ()) + { + case 158: // columnconstraint + value.move< ColumnConstraintInfo > (YY_MOVE (that.value)); + break; + + case 159: // columnconstraint_list + value.move< ColumnConstraintInfoVector > (YY_MOVE (that.value)); + break; + + case 160: // columndef + value.move< ColumndefData > (YY_MOVE (that.value)); + break; + + case 142: // optional_if_not_exists + case 144: // optional_unique + case 152: // optional_temporary + case 153: // optional_withoutrowid + case 157: // optional_always_generated + value.move< bool > (YY_MOVE (that.value)); + break; + + case 168: // tableconstraint + value.move< sqlb::ConstraintPtr > (YY_MOVE (that.value)); + break; + + case 169: // tableconstraint_list + case 170: // optional_tableconstraint_list + value.move< sqlb::ConstraintSet > (YY_MOVE (that.value)); + break; + + case 149: // createindex_stmt + value.move< sqlb::IndexPtr > (YY_MOVE (that.value)); + break; + + case 147: // indexed_column + value.move< sqlb::IndexedColumn > (YY_MOVE (that.value)); + break; + + case 148: // indexed_column_list + value.move< sqlb::IndexedColumnVector > (YY_MOVE (that.value)); + break; + + case 163: // columnid_list + case 164: // optional_columnid_with_paren_list + value.move< sqlb::StringVector > (YY_MOVE (that.value)); + break; + + case 151: // createvirtualtable_stmt + case 171: // createtable_stmt + value.move< sqlb::TablePtr > (YY_MOVE (that.value)); + break; + + case 27: // "ABORT" + case 28: // "ACTION" + case 29: // "ALWAYS" + case 30: // "AND" + case 31: // "AND BETWEEN" + case 32: // "AS" + case 33: // "ASC" + case 34: // "AUTOINCREMENT" + case 35: // "BETWEEN" + case 36: // "CASCADE" + case 37: // "CASE" + case 38: // "CAST" + case 39: // "CHECK" + case 40: // "COLLATE" + case 41: // "CONFLICT" + case 42: // "CONSTRAINT" + case 43: // "CREATE" + case 44: // "CURRENT_DATE" + case 45: // "CURRENT_TIME" + case 46: // "CURRENT_TIMESTAMP" + case 47: // "DEFAULT" + case 48: // "DEFERRABLE" + case 49: // "DEFERRED" + case 50: // "DELETE" + case 51: // "DESC" + case 52: // "DISTINCT" + case 53: // "ELSE" + case 54: // "END" + case 55: // "ESCAPE" + case 56: // "EXISTS" + case 57: // "FAIL" + case 58: // "FALSE" + case 59: // "FILTER" + case 60: // "FOLLOWING" + case 61: // "FOREIGN" + case 62: // "GENERATED" + case 63: // "GLOB" + case 64: // "IF" + case 65: // "IGNORE" + case 66: // "IMMEDIATE" + case 67: // "IN" + case 68: // "INDEX" + case 69: // "INITIALLY" + case 70: // "INSERT" + case 71: // "IS" + case 72: // "ISNULL" + case 73: // "KEY" + case 74: // "LIKE" + case 75: // "MATCH" + case 76: // "NO" + case 77: // "NOT" + case 78: // "NOTNULL" + case 79: // "NULL" + case 80: // "ON" + case 81: // "OR" + case 82: // "OVER" + case 83: // "PARTITION" + case 84: // "PRECEDING" + case 85: // "PRIMARY" + case 86: // "RAISE" + case 87: // "RANGE" + case 88: // "REFERENCES" + case 89: // "REGEXP" + case 90: // "REPLACE" + case 91: // "RESTRICT" + case 92: // "ROLLBACK" + case 93: // "ROWID" + case 94: // "ROWS" + case 95: // "SELECT" + case 96: // "SET" + case 97: // "STORED" + case 98: // "TABLE" + case 99: // "TEMP" + case 100: // "TEMPORARY" + case 101: // "THEN" + case 102: // "TRUE" + case 103: // "UNBOUNDED" + case 104: // "UNIQUE" + case 105: // "UPDATE" + case 106: // "USING" + case 107: // "VIRTUAL" + case 108: // "WHEN" + case 109: // "WHERE" + case 110: // "WITHOUT" + case 111: // "identifier" + case 112: // "numeric" + case 113: // "string literal" + case 114: // "quoted literal" + case 115: // "blob literal" + case 116: // "bind parameter" + case 120: // literalvalue + case 121: // id + case 122: // allowed_keywords_as_identifier + case 123: // tableid + case 124: // columnid + case 125: // signednumber + case 126: // signednumber_or_numeric + case 127: // typename_namelist + case 128: // type_name + case 129: // unary_expr + case 130: // binary_expr + case 131: // like_expr + case 132: // exprlist_expr + case 133: // function_expr + case 134: // isnull_expr + case 135: // between_expr + case 136: // in_expr + case 137: // whenthenlist_expr + case 138: // case_expr + case 139: // raise_expr + case 140: // expr + case 141: // select_stmt + case 143: // optional_sort_order + case 145: // optional_where + case 146: // tableid_with_uninteresting_schema + case 150: // optional_exprlist_with_paren + case 154: // optional_conflictclause + case 155: // optional_typename + case 156: // optional_storage_identifier + case 162: // optional_constraintname + case 165: // fk_clause_part + case 166: // fk_clause_part_list + case 167: // optional_fk_clause + value.move< std::string > (YY_MOVE (that.value)); + break; + + case 161: // columndef_list + value.move< std::vector > (YY_MOVE (that.value)); + break; + + default: + break; + } + + // that is emptied. + that.type = empty_symbol; + } + +#if YY_CPLUSPLUS < 201103L + parser::stack_symbol_type& + parser::stack_symbol_type::operator= (const stack_symbol_type& that) + { + state = that.state; + switch (that.type_get ()) + { + case 158: // columnconstraint + value.copy< ColumnConstraintInfo > (that.value); + break; + + case 159: // columnconstraint_list + value.copy< ColumnConstraintInfoVector > (that.value); + break; + + case 160: // columndef + value.copy< ColumndefData > (that.value); + break; + + case 142: // optional_if_not_exists + case 144: // optional_unique + case 152: // optional_temporary + case 153: // optional_withoutrowid + case 157: // optional_always_generated + value.copy< bool > (that.value); + break; + + case 168: // tableconstraint + value.copy< sqlb::ConstraintPtr > (that.value); + break; + + case 169: // tableconstraint_list + case 170: // optional_tableconstraint_list + value.copy< sqlb::ConstraintSet > (that.value); + break; + + case 149: // createindex_stmt + value.copy< sqlb::IndexPtr > (that.value); + break; + + case 147: // indexed_column + value.copy< sqlb::IndexedColumn > (that.value); + break; + + case 148: // indexed_column_list + value.copy< sqlb::IndexedColumnVector > (that.value); + break; + + case 163: // columnid_list + case 164: // optional_columnid_with_paren_list + value.copy< sqlb::StringVector > (that.value); + break; + + case 151: // createvirtualtable_stmt + case 171: // createtable_stmt + value.copy< sqlb::TablePtr > (that.value); + break; + + case 27: // "ABORT" + case 28: // "ACTION" + case 29: // "ALWAYS" + case 30: // "AND" + case 31: // "AND BETWEEN" + case 32: // "AS" + case 33: // "ASC" + case 34: // "AUTOINCREMENT" + case 35: // "BETWEEN" + case 36: // "CASCADE" + case 37: // "CASE" + case 38: // "CAST" + case 39: // "CHECK" + case 40: // "COLLATE" + case 41: // "CONFLICT" + case 42: // "CONSTRAINT" + case 43: // "CREATE" + case 44: // "CURRENT_DATE" + case 45: // "CURRENT_TIME" + case 46: // "CURRENT_TIMESTAMP" + case 47: // "DEFAULT" + case 48: // "DEFERRABLE" + case 49: // "DEFERRED" + case 50: // "DELETE" + case 51: // "DESC" + case 52: // "DISTINCT" + case 53: // "ELSE" + case 54: // "END" + case 55: // "ESCAPE" + case 56: // "EXISTS" + case 57: // "FAIL" + case 58: // "FALSE" + case 59: // "FILTER" + case 60: // "FOLLOWING" + case 61: // "FOREIGN" + case 62: // "GENERATED" + case 63: // "GLOB" + case 64: // "IF" + case 65: // "IGNORE" + case 66: // "IMMEDIATE" + case 67: // "IN" + case 68: // "INDEX" + case 69: // "INITIALLY" + case 70: // "INSERT" + case 71: // "IS" + case 72: // "ISNULL" + case 73: // "KEY" + case 74: // "LIKE" + case 75: // "MATCH" + case 76: // "NO" + case 77: // "NOT" + case 78: // "NOTNULL" + case 79: // "NULL" + case 80: // "ON" + case 81: // "OR" + case 82: // "OVER" + case 83: // "PARTITION" + case 84: // "PRECEDING" + case 85: // "PRIMARY" + case 86: // "RAISE" + case 87: // "RANGE" + case 88: // "REFERENCES" + case 89: // "REGEXP" + case 90: // "REPLACE" + case 91: // "RESTRICT" + case 92: // "ROLLBACK" + case 93: // "ROWID" + case 94: // "ROWS" + case 95: // "SELECT" + case 96: // "SET" + case 97: // "STORED" + case 98: // "TABLE" + case 99: // "TEMP" + case 100: // "TEMPORARY" + case 101: // "THEN" + case 102: // "TRUE" + case 103: // "UNBOUNDED" + case 104: // "UNIQUE" + case 105: // "UPDATE" + case 106: // "USING" + case 107: // "VIRTUAL" + case 108: // "WHEN" + case 109: // "WHERE" + case 110: // "WITHOUT" + case 111: // "identifier" + case 112: // "numeric" + case 113: // "string literal" + case 114: // "quoted literal" + case 115: // "blob literal" + case 116: // "bind parameter" + case 120: // literalvalue + case 121: // id + case 122: // allowed_keywords_as_identifier + case 123: // tableid + case 124: // columnid + case 125: // signednumber + case 126: // signednumber_or_numeric + case 127: // typename_namelist + case 128: // type_name + case 129: // unary_expr + case 130: // binary_expr + case 131: // like_expr + case 132: // exprlist_expr + case 133: // function_expr + case 134: // isnull_expr + case 135: // between_expr + case 136: // in_expr + case 137: // whenthenlist_expr + case 138: // case_expr + case 139: // raise_expr + case 140: // expr + case 141: // select_stmt + case 143: // optional_sort_order + case 145: // optional_where + case 146: // tableid_with_uninteresting_schema + case 150: // optional_exprlist_with_paren + case 154: // optional_conflictclause + case 155: // optional_typename + case 156: // optional_storage_identifier + case 162: // optional_constraintname + case 165: // fk_clause_part + case 166: // fk_clause_part_list + case 167: // optional_fk_clause + value.copy< std::string > (that.value); + break; + + case 161: // columndef_list + value.copy< std::vector > (that.value); + break; + + default: + break; + } + + location = that.location; + return *this; + } + + parser::stack_symbol_type& + parser::stack_symbol_type::operator= (stack_symbol_type& that) + { + state = that.state; + switch (that.type_get ()) + { + case 158: // columnconstraint + value.move< ColumnConstraintInfo > (that.value); + break; + + case 159: // columnconstraint_list + value.move< ColumnConstraintInfoVector > (that.value); + break; + + case 160: // columndef + value.move< ColumndefData > (that.value); + break; + + case 142: // optional_if_not_exists + case 144: // optional_unique + case 152: // optional_temporary + case 153: // optional_withoutrowid + case 157: // optional_always_generated + value.move< bool > (that.value); + break; + + case 168: // tableconstraint + value.move< sqlb::ConstraintPtr > (that.value); + break; + + case 169: // tableconstraint_list + case 170: // optional_tableconstraint_list + value.move< sqlb::ConstraintSet > (that.value); + break; + + case 149: // createindex_stmt + value.move< sqlb::IndexPtr > (that.value); + break; + + case 147: // indexed_column + value.move< sqlb::IndexedColumn > (that.value); + break; + + case 148: // indexed_column_list + value.move< sqlb::IndexedColumnVector > (that.value); + break; + + case 163: // columnid_list + case 164: // optional_columnid_with_paren_list + value.move< sqlb::StringVector > (that.value); + break; + + case 151: // createvirtualtable_stmt + case 171: // createtable_stmt + value.move< sqlb::TablePtr > (that.value); + break; + + case 27: // "ABORT" + case 28: // "ACTION" + case 29: // "ALWAYS" + case 30: // "AND" + case 31: // "AND BETWEEN" + case 32: // "AS" + case 33: // "ASC" + case 34: // "AUTOINCREMENT" + case 35: // "BETWEEN" + case 36: // "CASCADE" + case 37: // "CASE" + case 38: // "CAST" + case 39: // "CHECK" + case 40: // "COLLATE" + case 41: // "CONFLICT" + case 42: // "CONSTRAINT" + case 43: // "CREATE" + case 44: // "CURRENT_DATE" + case 45: // "CURRENT_TIME" + case 46: // "CURRENT_TIMESTAMP" + case 47: // "DEFAULT" + case 48: // "DEFERRABLE" + case 49: // "DEFERRED" + case 50: // "DELETE" + case 51: // "DESC" + case 52: // "DISTINCT" + case 53: // "ELSE" + case 54: // "END" + case 55: // "ESCAPE" + case 56: // "EXISTS" + case 57: // "FAIL" + case 58: // "FALSE" + case 59: // "FILTER" + case 60: // "FOLLOWING" + case 61: // "FOREIGN" + case 62: // "GENERATED" + case 63: // "GLOB" + case 64: // "IF" + case 65: // "IGNORE" + case 66: // "IMMEDIATE" + case 67: // "IN" + case 68: // "INDEX" + case 69: // "INITIALLY" + case 70: // "INSERT" + case 71: // "IS" + case 72: // "ISNULL" + case 73: // "KEY" + case 74: // "LIKE" + case 75: // "MATCH" + case 76: // "NO" + case 77: // "NOT" + case 78: // "NOTNULL" + case 79: // "NULL" + case 80: // "ON" + case 81: // "OR" + case 82: // "OVER" + case 83: // "PARTITION" + case 84: // "PRECEDING" + case 85: // "PRIMARY" + case 86: // "RAISE" + case 87: // "RANGE" + case 88: // "REFERENCES" + case 89: // "REGEXP" + case 90: // "REPLACE" + case 91: // "RESTRICT" + case 92: // "ROLLBACK" + case 93: // "ROWID" + case 94: // "ROWS" + case 95: // "SELECT" + case 96: // "SET" + case 97: // "STORED" + case 98: // "TABLE" + case 99: // "TEMP" + case 100: // "TEMPORARY" + case 101: // "THEN" + case 102: // "TRUE" + case 103: // "UNBOUNDED" + case 104: // "UNIQUE" + case 105: // "UPDATE" + case 106: // "USING" + case 107: // "VIRTUAL" + case 108: // "WHEN" + case 109: // "WHERE" + case 110: // "WITHOUT" + case 111: // "identifier" + case 112: // "numeric" + case 113: // "string literal" + case 114: // "quoted literal" + case 115: // "blob literal" + case 116: // "bind parameter" + case 120: // literalvalue + case 121: // id + case 122: // allowed_keywords_as_identifier + case 123: // tableid + case 124: // columnid + case 125: // signednumber + case 126: // signednumber_or_numeric + case 127: // typename_namelist + case 128: // type_name + case 129: // unary_expr + case 130: // binary_expr + case 131: // like_expr + case 132: // exprlist_expr + case 133: // function_expr + case 134: // isnull_expr + case 135: // between_expr + case 136: // in_expr + case 137: // whenthenlist_expr + case 138: // case_expr + case 139: // raise_expr + case 140: // expr + case 141: // select_stmt + case 143: // optional_sort_order + case 145: // optional_where + case 146: // tableid_with_uninteresting_schema + case 150: // optional_exprlist_with_paren + case 154: // optional_conflictclause + case 155: // optional_typename + case 156: // optional_storage_identifier + case 162: // optional_constraintname + case 165: // fk_clause_part + case 166: // fk_clause_part_list + case 167: // optional_fk_clause + value.move< std::string > (that.value); + break; + + case 161: // columndef_list + value.move< std::vector > (that.value); + break; + + default: + break; + } + + location = that.location; + // that is emptied. + that.state = empty_state; + return *this; + } +#endif + + template + void + parser::yy_destroy_ (const char* yymsg, basic_symbol& yysym) const + { + if (yymsg) + YY_SYMBOL_PRINT (yymsg, yysym); + } + +#if YYDEBUG + template + void + parser::yy_print_ (std::ostream& yyo, + const basic_symbol& yysym) const + { + std::ostream& yyoutput = yyo; + YYUSE (yyoutput); + symbol_number_type yytype = yysym.type_get (); +#if defined __GNUC__ && ! defined __clang__ && ! defined __ICC && __GNUC__ * 100 + __GNUC_MINOR__ <= 408 + // Avoid a (spurious) G++ 4.8 warning about "array subscript is + // below array bounds". + if (yysym.empty ()) + std::abort (); +#endif + yyo << (yytype < yyntokens_ ? "token" : "nterm") + << ' ' << yytname_[yytype] << " (" + << yysym.location << ": "; + YYUSE (yytype); + yyo << ')'; + } +#endif + + void + parser::yypush_ (const char* m, YY_MOVE_REF (stack_symbol_type) sym) + { + if (m) + YY_SYMBOL_PRINT (m, sym); + yystack_.push (YY_MOVE (sym)); + } + + void + parser::yypush_ (const char* m, state_type s, YY_MOVE_REF (symbol_type) sym) + { +#if 201103L <= YY_CPLUSPLUS + yypush_ (m, stack_symbol_type (s, std::move (sym))); +#else + stack_symbol_type ss (s, sym); + yypush_ (m, ss); +#endif + } + + void + parser::yypop_ (int n) + { + yystack_.pop (n); + } + +#if YYDEBUG + std::ostream& + parser::debug_stream () const + { + return *yycdebug_; + } + + void + parser::set_debug_stream (std::ostream& o) + { + yycdebug_ = &o; + } + + + parser::debug_level_type + parser::debug_level () const + { + return yydebug_; + } + + void + parser::set_debug_level (debug_level_type l) + { + yydebug_ = l; + } +#endif // YYDEBUG + + parser::state_type + parser::yy_lr_goto_state_ (state_type yystate, int yysym) + { + int yyr = yypgoto_[yysym - yyntokens_] + yystate; + if (0 <= yyr && yyr <= yylast_ && yycheck_[yyr] == yystate) + return yytable_[yyr]; + else + return yydefgoto_[yysym - yyntokens_]; + } + + bool + parser::yy_pact_value_is_default_ (int yyvalue) + { + return yyvalue == yypact_ninf_; + } + + bool + parser::yy_table_value_is_error_ (int yyvalue) + { + return yyvalue == yytable_ninf_; + } + + int + parser::operator() () + { + return parse (); + } + + int + parser::parse () + { + int yyn; + /// Length of the RHS of the rule being reduced. + int yylen = 0; + + // Error handling. + int yynerrs_ = 0; + int yyerrstatus_ = 0; + + /// The lookahead symbol. + symbol_type yyla; + + /// The locations where the error started and ended. + stack_symbol_type yyerror_range[3]; + + /// The return value of parse (). + int yyresult; + +#if YY_EXCEPTIONS + try +#endif // YY_EXCEPTIONS + { + YYCDEBUG << "Starting parse\n"; + + + /* Initialize the stack. The initial state will be set in + yynewstate, since the latter expects the semantical and the + location values to have been already stored, initialize these + stacks with a primary value. */ + yystack_.clear (); + yypush_ (YY_NULLPTR, 0, YY_MOVE (yyla)); + + /*-----------------------------------------------. + | yynewstate -- push a new symbol on the stack. | + `-----------------------------------------------*/ + yynewstate: + YYCDEBUG << "Entering state " << int (yystack_[0].state) << '\n'; + + // Accept? + if (yystack_[0].state == yyfinal_) + YYACCEPT; + + goto yybackup; + + + /*-----------. + | yybackup. | + `-----------*/ + yybackup: + // Try to take a decision without lookahead. + yyn = yypact_[+yystack_[0].state]; + if (yy_pact_value_is_default_ (yyn)) + goto yydefault; + + // Read a lookahead token. + if (yyla.empty ()) + { + YYCDEBUG << "Reading a token: "; +#if YY_EXCEPTIONS + try +#endif // YY_EXCEPTIONS + { + symbol_type yylookahead (yylex (yyscanner, drv)); + yyla.move (yylookahead); + } +#if YY_EXCEPTIONS + catch (const syntax_error& yyexc) + { + YYCDEBUG << "Caught exception: " << yyexc.what() << '\n'; + error (yyexc); + goto yyerrlab1; + } +#endif // YY_EXCEPTIONS + } + YY_SYMBOL_PRINT ("Next token is", yyla); + + /* If the proper action on seeing token YYLA.TYPE is to reduce or + to detect an error, take that action. */ + yyn += yyla.type_get (); + if (yyn < 0 || yylast_ < yyn || yycheck_[yyn] != yyla.type_get ()) + { + goto yydefault; + } + + // Reduce or error. + yyn = yytable_[yyn]; + if (yyn <= 0) + { + if (yy_table_value_is_error_ (yyn)) + goto yyerrlab; + yyn = -yyn; + goto yyreduce; + } + + // Count tokens shifted since error; after three, turn off error status. + if (yyerrstatus_) + --yyerrstatus_; + + // Shift the lookahead token. + yypush_ ("Shifting", state_type (yyn), YY_MOVE (yyla)); + goto yynewstate; + + + /*-----------------------------------------------------------. + | yydefault -- do the default action for the current state. | + `-----------------------------------------------------------*/ + yydefault: + yyn = yydefact_[+yystack_[0].state]; + if (yyn == 0) + goto yyerrlab; + goto yyreduce; + + + /*-----------------------------. + | yyreduce -- do a reduction. | + `-----------------------------*/ + yyreduce: + yylen = yyr2_[yyn]; + { + stack_symbol_type yylhs; + yylhs.state = yy_lr_goto_state_ (yystack_[yylen].state, yyr1_[yyn]); + /* Variants are always initialized to an empty instance of the + correct type. The default '$$ = $1' action is NOT applied + when using variants. */ + switch (yyr1_[yyn]) + { + case 158: // columnconstraint + yylhs.value.emplace< ColumnConstraintInfo > (); + break; + + case 159: // columnconstraint_list + yylhs.value.emplace< ColumnConstraintInfoVector > (); + break; + + case 160: // columndef + yylhs.value.emplace< ColumndefData > (); + break; + + case 142: // optional_if_not_exists + case 144: // optional_unique + case 152: // optional_temporary + case 153: // optional_withoutrowid + case 157: // optional_always_generated + yylhs.value.emplace< bool > (); + break; + + case 168: // tableconstraint + yylhs.value.emplace< sqlb::ConstraintPtr > (); + break; + + case 169: // tableconstraint_list + case 170: // optional_tableconstraint_list + yylhs.value.emplace< sqlb::ConstraintSet > (); + break; + + case 149: // createindex_stmt + yylhs.value.emplace< sqlb::IndexPtr > (); + break; + + case 147: // indexed_column + yylhs.value.emplace< sqlb::IndexedColumn > (); + break; + + case 148: // indexed_column_list + yylhs.value.emplace< sqlb::IndexedColumnVector > (); + break; + + case 163: // columnid_list + case 164: // optional_columnid_with_paren_list + yylhs.value.emplace< sqlb::StringVector > (); + break; + + case 151: // createvirtualtable_stmt + case 171: // createtable_stmt + yylhs.value.emplace< sqlb::TablePtr > (); + break; + + case 27: // "ABORT" + case 28: // "ACTION" + case 29: // "ALWAYS" + case 30: // "AND" + case 31: // "AND BETWEEN" + case 32: // "AS" + case 33: // "ASC" + case 34: // "AUTOINCREMENT" + case 35: // "BETWEEN" + case 36: // "CASCADE" + case 37: // "CASE" + case 38: // "CAST" + case 39: // "CHECK" + case 40: // "COLLATE" + case 41: // "CONFLICT" + case 42: // "CONSTRAINT" + case 43: // "CREATE" + case 44: // "CURRENT_DATE" + case 45: // "CURRENT_TIME" + case 46: // "CURRENT_TIMESTAMP" + case 47: // "DEFAULT" + case 48: // "DEFERRABLE" + case 49: // "DEFERRED" + case 50: // "DELETE" + case 51: // "DESC" + case 52: // "DISTINCT" + case 53: // "ELSE" + case 54: // "END" + case 55: // "ESCAPE" + case 56: // "EXISTS" + case 57: // "FAIL" + case 58: // "FALSE" + case 59: // "FILTER" + case 60: // "FOLLOWING" + case 61: // "FOREIGN" + case 62: // "GENERATED" + case 63: // "GLOB" + case 64: // "IF" + case 65: // "IGNORE" + case 66: // "IMMEDIATE" + case 67: // "IN" + case 68: // "INDEX" + case 69: // "INITIALLY" + case 70: // "INSERT" + case 71: // "IS" + case 72: // "ISNULL" + case 73: // "KEY" + case 74: // "LIKE" + case 75: // "MATCH" + case 76: // "NO" + case 77: // "NOT" + case 78: // "NOTNULL" + case 79: // "NULL" + case 80: // "ON" + case 81: // "OR" + case 82: // "OVER" + case 83: // "PARTITION" + case 84: // "PRECEDING" + case 85: // "PRIMARY" + case 86: // "RAISE" + case 87: // "RANGE" + case 88: // "REFERENCES" + case 89: // "REGEXP" + case 90: // "REPLACE" + case 91: // "RESTRICT" + case 92: // "ROLLBACK" + case 93: // "ROWID" + case 94: // "ROWS" + case 95: // "SELECT" + case 96: // "SET" + case 97: // "STORED" + case 98: // "TABLE" + case 99: // "TEMP" + case 100: // "TEMPORARY" + case 101: // "THEN" + case 102: // "TRUE" + case 103: // "UNBOUNDED" + case 104: // "UNIQUE" + case 105: // "UPDATE" + case 106: // "USING" + case 107: // "VIRTUAL" + case 108: // "WHEN" + case 109: // "WHERE" + case 110: // "WITHOUT" + case 111: // "identifier" + case 112: // "numeric" + case 113: // "string literal" + case 114: // "quoted literal" + case 115: // "blob literal" + case 116: // "bind parameter" + case 120: // literalvalue + case 121: // id + case 122: // allowed_keywords_as_identifier + case 123: // tableid + case 124: // columnid + case 125: // signednumber + case 126: // signednumber_or_numeric + case 127: // typename_namelist + case 128: // type_name + case 129: // unary_expr + case 130: // binary_expr + case 131: // like_expr + case 132: // exprlist_expr + case 133: // function_expr + case 134: // isnull_expr + case 135: // between_expr + case 136: // in_expr + case 137: // whenthenlist_expr + case 138: // case_expr + case 139: // raise_expr + case 140: // expr + case 141: // select_stmt + case 143: // optional_sort_order + case 145: // optional_where + case 146: // tableid_with_uninteresting_schema + case 150: // optional_exprlist_with_paren + case 154: // optional_conflictclause + case 155: // optional_typename + case 156: // optional_storage_identifier + case 162: // optional_constraintname + case 165: // fk_clause_part + case 166: // fk_clause_part_list + case 167: // optional_fk_clause + yylhs.value.emplace< std::string > (); + break; + + case 161: // columndef_list + yylhs.value.emplace< std::vector > (); + break; + + default: + break; + } + + + // Default location. + { + stack_type::slice range (yystack_, yylen); + YYLLOC_DEFAULT (yylhs.location, range, yylen); + yyerror_range[1].location = yylhs.location; + } + + // Perform the reduction. + YY_REDUCE_PRINT (yyn); +#if YY_EXCEPTIONS + try +#endif // YY_EXCEPTIONS + { + switch (yyn) + { + case 4: +#line 314 "sqlite3_parser.yy" + { drv.result = yystack_[0].value.as < sqlb::IndexPtr > (); } +#line 1492 "sqlite3_parser.cpp" + break; + + case 5: +#line 315 "sqlite3_parser.yy" + { drv.result = yystack_[0].value.as < sqlb::TablePtr > (); } +#line 1498 "sqlite3_parser.cpp" + break; + + case 6: +#line 316 "sqlite3_parser.yy" + { drv.result = yystack_[0].value.as < sqlb::TablePtr > (); } +#line 1504 "sqlite3_parser.cpp" + break; + + case 7: +#line 324 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } +#line 1510 "sqlite3_parser.cpp" + break; + + case 8: +#line 325 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } +#line 1516 "sqlite3_parser.cpp" + break; + + case 9: +#line 326 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } +#line 1522 "sqlite3_parser.cpp" + break; + + case 10: +#line 327 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } +#line 1528 "sqlite3_parser.cpp" + break; + + case 11: +#line 328 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } +#line 1534 "sqlite3_parser.cpp" + break; + + case 12: +#line 329 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } +#line 1540 "sqlite3_parser.cpp" + break; + + case 13: +#line 330 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } +#line 1546 "sqlite3_parser.cpp" + break; + + case 14: +#line 331 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } +#line 1552 "sqlite3_parser.cpp" + break; + + case 15: +#line 332 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } +#line 1558 "sqlite3_parser.cpp" + break; + + case 16: +#line 336 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } +#line 1564 "sqlite3_parser.cpp" + break; + + case 17: +#line 337 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } +#line 1570 "sqlite3_parser.cpp" + break; + + case 18: +#line 342 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } +#line 1576 "sqlite3_parser.cpp" + break; + + case 19: +#line 343 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } +#line 1582 "sqlite3_parser.cpp" + break; + + case 20: +#line 344 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } +#line 1588 "sqlite3_parser.cpp" + break; + + case 21: +#line 345 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } +#line 1594 "sqlite3_parser.cpp" + break; + + case 22: +#line 346 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } +#line 1600 "sqlite3_parser.cpp" + break; + + case 23: +#line 347 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } +#line 1606 "sqlite3_parser.cpp" + break; + + case 24: +#line 348 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } +#line 1612 "sqlite3_parser.cpp" + break; + + case 25: +#line 349 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } +#line 1618 "sqlite3_parser.cpp" + break; + + case 26: +#line 350 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } +#line 1624 "sqlite3_parser.cpp" + break; + + case 27: +#line 351 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } +#line 1630 "sqlite3_parser.cpp" + break; + + case 28: +#line 352 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } +#line 1636 "sqlite3_parser.cpp" + break; + + case 29: +#line 353 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } +#line 1642 "sqlite3_parser.cpp" + break; + + case 30: +#line 354 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } +#line 1648 "sqlite3_parser.cpp" + break; + + case 31: +#line 355 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } +#line 1654 "sqlite3_parser.cpp" + break; + + case 32: +#line 356 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } +#line 1660 "sqlite3_parser.cpp" + break; + + case 33: +#line 357 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } +#line 1666 "sqlite3_parser.cpp" + break; + + case 34: +#line 358 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } +#line 1672 "sqlite3_parser.cpp" + break; + + case 35: +#line 359 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } +#line 1678 "sqlite3_parser.cpp" + break; + + case 36: +#line 360 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } +#line 1684 "sqlite3_parser.cpp" + break; + + case 37: +#line 361 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } +#line 1690 "sqlite3_parser.cpp" + break; + + case 38: +#line 362 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } +#line 1696 "sqlite3_parser.cpp" + break; + + case 39: +#line 363 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } +#line 1702 "sqlite3_parser.cpp" + break; + + case 40: +#line 364 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } +#line 1708 "sqlite3_parser.cpp" + break; + + case 41: +#line 365 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } +#line 1714 "sqlite3_parser.cpp" + break; + + case 42: +#line 366 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } +#line 1720 "sqlite3_parser.cpp" + break; + + case 43: +#line 367 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } +#line 1726 "sqlite3_parser.cpp" + break; + + case 44: +#line 368 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } +#line 1732 "sqlite3_parser.cpp" + break; + + case 45: +#line 369 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } +#line 1738 "sqlite3_parser.cpp" + break; + + case 46: +#line 370 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } +#line 1744 "sqlite3_parser.cpp" + break; + + case 47: +#line 371 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } +#line 1750 "sqlite3_parser.cpp" + break; + + case 48: +#line 372 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } +#line 1756 "sqlite3_parser.cpp" + break; + + case 49: +#line 373 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } +#line 1762 "sqlite3_parser.cpp" + break; + + case 50: +#line 374 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } +#line 1768 "sqlite3_parser.cpp" + break; + + case 51: +#line 375 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } +#line 1774 "sqlite3_parser.cpp" + break; + + case 52: +#line 376 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } +#line 1780 "sqlite3_parser.cpp" + break; + + case 53: +#line 377 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } +#line 1786 "sqlite3_parser.cpp" + break; + + case 54: +#line 378 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } +#line 1792 "sqlite3_parser.cpp" + break; + + case 55: +#line 379 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } +#line 1798 "sqlite3_parser.cpp" + break; + + case 56: +#line 380 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } +#line 1804 "sqlite3_parser.cpp" + break; + + case 57: +#line 384 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } +#line 1810 "sqlite3_parser.cpp" + break; + + case 58: +#line 385 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } +#line 1816 "sqlite3_parser.cpp" + break; + + case 59: +#line 386 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } +#line 1822 "sqlite3_parser.cpp" + break; + + case 60: +#line 387 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } +#line 1828 "sqlite3_parser.cpp" + break; + + case 61: +#line 388 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } +#line 1834 "sqlite3_parser.cpp" + break; + + case 62: +#line 389 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = unquote_text(yystack_[0].value.as < std::string > (), '\''); } +#line 1840 "sqlite3_parser.cpp" + break; + + case 63: +#line 393 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } +#line 1846 "sqlite3_parser.cpp" + break; + + case 64: +#line 394 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } +#line 1852 "sqlite3_parser.cpp" + break; + + case 65: +#line 395 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } +#line 1858 "sqlite3_parser.cpp" + break; + + case 66: +#line 396 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } +#line 1864 "sqlite3_parser.cpp" + break; + + case 67: +#line 397 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } +#line 1870 "sqlite3_parser.cpp" + break; + + case 68: +#line 398 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } +#line 1876 "sqlite3_parser.cpp" + break; + + case 69: +#line 399 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = unquote_text(yystack_[0].value.as < std::string > (), '\''); } +#line 1882 "sqlite3_parser.cpp" + break; + + case 70: +#line 403 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = "+" + yystack_[0].value.as < std::string > (); } +#line 1888 "sqlite3_parser.cpp" + break; + + case 71: +#line 404 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = "-" + yystack_[0].value.as < std::string > (); } +#line 1894 "sqlite3_parser.cpp" + break; + + case 72: +#line 408 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } +#line 1900 "sqlite3_parser.cpp" + break; + + case 73: +#line 409 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } +#line 1906 "sqlite3_parser.cpp" + break; + + case 74: +#line 413 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } +#line 1912 "sqlite3_parser.cpp" + break; + + case 75: +#line 414 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[1].value.as < std::string > () + " " + yystack_[0].value.as < std::string > (); } +#line 1918 "sqlite3_parser.cpp" + break; + + case 76: +#line 418 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } +#line 1924 "sqlite3_parser.cpp" + break; + + case 77: +#line 419 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[3].value.as < std::string > () + "(" + yystack_[1].value.as < std::string > () + ")"; } +#line 1930 "sqlite3_parser.cpp" + break; + + case 78: +#line 420 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[5].value.as < std::string > () + "(" + yystack_[3].value.as < std::string > () + ", " + yystack_[1].value.as < std::string > () + ")"; } +#line 1936 "sqlite3_parser.cpp" + break; + + case 79: +#line 424 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = "-" + yystack_[0].value.as < std::string > (); } +#line 1942 "sqlite3_parser.cpp" + break; + + case 80: +#line 425 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = "+" + yystack_[0].value.as < std::string > (); } +#line 1948 "sqlite3_parser.cpp" + break; + + case 81: +#line 426 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = "~" + yystack_[0].value.as < std::string > (); } +#line 1954 "sqlite3_parser.cpp" + break; + + case 82: +#line 427 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = "NOT " + yystack_[0].value.as < std::string > (); } +#line 1960 "sqlite3_parser.cpp" + break; + + case 83: +#line 431 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[2].value.as < std::string > () + " || " + yystack_[0].value.as < std::string > (); } +#line 1966 "sqlite3_parser.cpp" + break; + + case 84: +#line 432 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[2].value.as < std::string > () + " * " + yystack_[0].value.as < std::string > (); } +#line 1972 "sqlite3_parser.cpp" + break; + + case 85: +#line 433 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[2].value.as < std::string > () + " / " + yystack_[0].value.as < std::string > (); } +#line 1978 "sqlite3_parser.cpp" + break; + + case 86: +#line 434 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[2].value.as < std::string > () + " % " + yystack_[0].value.as < std::string > (); } +#line 1984 "sqlite3_parser.cpp" + break; + + case 87: +#line 435 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[2].value.as < std::string > () + " + " + yystack_[0].value.as < std::string > (); } +#line 1990 "sqlite3_parser.cpp" + break; + + case 88: +#line 436 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[2].value.as < std::string > () + " - " + yystack_[0].value.as < std::string > (); } +#line 1996 "sqlite3_parser.cpp" + break; + + case 89: +#line 437 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[2].value.as < std::string > () + " << " + yystack_[0].value.as < std::string > (); } +#line 2002 "sqlite3_parser.cpp" + break; + + case 90: +#line 438 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[2].value.as < std::string > () + " >> " + yystack_[0].value.as < std::string > (); } +#line 2008 "sqlite3_parser.cpp" + break; + + case 91: +#line 439 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[2].value.as < std::string > () + " & " + yystack_[0].value.as < std::string > (); } +#line 2014 "sqlite3_parser.cpp" + break; + + case 92: +#line 440 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[2].value.as < std::string > () + " | " + yystack_[0].value.as < std::string > (); } +#line 2020 "sqlite3_parser.cpp" + break; + + case 93: +#line 441 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[2].value.as < std::string > () + " < " + yystack_[0].value.as < std::string > (); } +#line 2026 "sqlite3_parser.cpp" + break; + + case 94: +#line 442 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[2].value.as < std::string > () + " <= " + yystack_[0].value.as < std::string > (); } +#line 2032 "sqlite3_parser.cpp" + break; + + case 95: +#line 443 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[2].value.as < std::string > () + " > " + yystack_[0].value.as < std::string > (); } +#line 2038 "sqlite3_parser.cpp" + break; + + case 96: +#line 444 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[2].value.as < std::string > () + " >= " + yystack_[0].value.as < std::string > (); } +#line 2044 "sqlite3_parser.cpp" + break; + + case 97: +#line 445 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[2].value.as < std::string > () + " = " + yystack_[0].value.as < std::string > (); } +#line 2050 "sqlite3_parser.cpp" + break; + + case 98: +#line 446 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[2].value.as < std::string > () + " == " + yystack_[0].value.as < std::string > (); } +#line 2056 "sqlite3_parser.cpp" + break; + + case 99: +#line 447 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[2].value.as < std::string > () + " != " + yystack_[0].value.as < std::string > (); } +#line 2062 "sqlite3_parser.cpp" + break; + + case 100: +#line 448 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[2].value.as < std::string > () + " <> " + yystack_[0].value.as < std::string > (); } +#line 2068 "sqlite3_parser.cpp" + break; + + case 101: +#line 449 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[2].value.as < std::string > () + " IS " + yystack_[0].value.as < std::string > (); } +#line 2074 "sqlite3_parser.cpp" + break; + + case 102: +#line 450 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[2].value.as < std::string > () + " AND " + yystack_[0].value.as < std::string > (); } +#line 2080 "sqlite3_parser.cpp" + break; + + case 103: +#line 451 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[2].value.as < std::string > () + " OR " + yystack_[0].value.as < std::string > (); } +#line 2086 "sqlite3_parser.cpp" + break; + + case 104: +#line 455 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[2].value.as < std::string > () + " LIKE " + yystack_[0].value.as < std::string > (); } +#line 2092 "sqlite3_parser.cpp" + break; + + case 105: +#line 456 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[2].value.as < std::string > () + " GLOB " + yystack_[0].value.as < std::string > (); } +#line 2098 "sqlite3_parser.cpp" + break; + + case 106: +#line 457 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[2].value.as < std::string > () + " MATCH " + yystack_[0].value.as < std::string > (); } +#line 2104 "sqlite3_parser.cpp" + break; + + case 107: +#line 458 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[2].value.as < std::string > () + " REGEXP " + yystack_[0].value.as < std::string > (); } +#line 2110 "sqlite3_parser.cpp" + break; + + case 108: +#line 459 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[3].value.as < std::string > () + " NOT LIKE " + yystack_[0].value.as < std::string > (); } +#line 2116 "sqlite3_parser.cpp" + break; + + case 109: +#line 460 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[3].value.as < std::string > () + " NOT GLOB " + yystack_[0].value.as < std::string > (); } +#line 2122 "sqlite3_parser.cpp" + break; + + case 110: +#line 461 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[3].value.as < std::string > () + " NOT MATCH " + yystack_[0].value.as < std::string > (); } +#line 2128 "sqlite3_parser.cpp" + break; + + case 111: +#line 462 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[3].value.as < std::string > () + " NOT REGEXP " + yystack_[0].value.as < std::string > (); } +#line 2134 "sqlite3_parser.cpp" + break; + + case 112: +#line 463 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[4].value.as < std::string > () + " LIKE " + yystack_[2].value.as < std::string > () + " ESCAPE " + yystack_[0].value.as < std::string > (); } +#line 2140 "sqlite3_parser.cpp" + break; + + case 113: +#line 464 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[4].value.as < std::string > () + " GLOB " + yystack_[2].value.as < std::string > () + " ESCAPE " + yystack_[0].value.as < std::string > (); } +#line 2146 "sqlite3_parser.cpp" + break; + + case 114: +#line 465 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[4].value.as < std::string > () + " MATCH " + yystack_[2].value.as < std::string > () + " ESCAPE " + yystack_[0].value.as < std::string > (); } +#line 2152 "sqlite3_parser.cpp" + break; + + case 115: +#line 466 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[4].value.as < std::string > () + " REGEXP " + yystack_[2].value.as < std::string > () + " ESCAPE " + yystack_[0].value.as < std::string > (); } +#line 2158 "sqlite3_parser.cpp" + break; + + case 116: +#line 467 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[5].value.as < std::string > () + " NOT LIKE " + yystack_[3].value.as < std::string > () + " ESCAPE " + yystack_[0].value.as < std::string > (); } +#line 2164 "sqlite3_parser.cpp" + break; + + case 117: +#line 468 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[5].value.as < std::string > () + " NOT GLOB " + yystack_[3].value.as < std::string > () + " ESCAPE " + yystack_[0].value.as < std::string > (); } +#line 2170 "sqlite3_parser.cpp" + break; + + case 118: +#line 469 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[5].value.as < std::string > () + " NOT MATCH " + yystack_[3].value.as < std::string > () + " ESCAPE " + yystack_[0].value.as < std::string > (); } +#line 2176 "sqlite3_parser.cpp" + break; + + case 119: +#line 470 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[5].value.as < std::string > () + " NOT REGEXP " + yystack_[3].value.as < std::string > () + " ESCAPE " + yystack_[0].value.as < std::string > (); } +#line 2182 "sqlite3_parser.cpp" + break; + + case 120: +#line 474 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } +#line 2188 "sqlite3_parser.cpp" + break; + + case 121: +#line 475 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[2].value.as < std::string > () + ", " + yystack_[0].value.as < std::string > (); } +#line 2194 "sqlite3_parser.cpp" + break; + + case 122: +#line 479 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[3].value.as < std::string > () + "(" + yystack_[1].value.as < std::string > () + ")"; } +#line 2200 "sqlite3_parser.cpp" + break; + + case 123: +#line 480 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[4].value.as < std::string > () + "(DISTINCT " + yystack_[1].value.as < std::string > () + ")"; } +#line 2206 "sqlite3_parser.cpp" + break; + + case 124: +#line 481 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[2].value.as < std::string > () + "()"; } +#line 2212 "sqlite3_parser.cpp" + break; + + case 125: +#line 482 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[3].value.as < std::string > () + "(*)"; } +#line 2218 "sqlite3_parser.cpp" + break; + + case 126: +#line 486 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[1].value.as < std::string > () + " ISNULL"; } +#line 2224 "sqlite3_parser.cpp" + break; + + case 127: +#line 487 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[1].value.as < std::string > () + " NOTNULL"; } +#line 2230 "sqlite3_parser.cpp" + break; + + case 128: +#line 488 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[2].value.as < std::string > () + " NOT NULL"; } +#line 2236 "sqlite3_parser.cpp" + break; + + case 129: +#line 492 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[4].value.as < std::string > () + " BETWEEN " + yystack_[2].value.as < std::string > () + " AND " + yystack_[0].value.as < std::string > (); } +#line 2242 "sqlite3_parser.cpp" + break; + + case 130: +#line 493 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[5].value.as < std::string > () + " NOT BETWEEN " + yystack_[2].value.as < std::string > () + " AND " + yystack_[0].value.as < std::string > (); } +#line 2248 "sqlite3_parser.cpp" + break; + + case 131: +#line 497 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[3].value.as < std::string > () + " IN ()"; } +#line 2254 "sqlite3_parser.cpp" + break; + + case 132: +#line 498 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[4].value.as < std::string > () + " IN (" + yystack_[1].value.as < std::string > () + ")"; } +#line 2260 "sqlite3_parser.cpp" + break; + + case 133: +#line 499 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[4].value.as < std::string > () + " IN (" + yystack_[1].value.as < std::string > () + ")"; } +#line 2266 "sqlite3_parser.cpp" + break; + + case 134: +#line 500 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[4].value.as < std::string > () + " IN " + sqlb::escapeIdentifier(yystack_[2].value.as < std::string > ()) + "." + sqlb::escapeIdentifier(yystack_[0].value.as < std::string > ()); } +#line 2272 "sqlite3_parser.cpp" + break; + + case 135: +#line 501 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[2].value.as < std::string > () + " IN " + sqlb::escapeIdentifier(yystack_[0].value.as < std::string > ()); } +#line 2278 "sqlite3_parser.cpp" + break; + + case 136: +#line 502 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[6].value.as < std::string > () + " IN " + sqlb::escapeIdentifier(yystack_[4].value.as < std::string > ()) + "." + yystack_[2].value.as < std::string > () + "()"; } +#line 2284 "sqlite3_parser.cpp" + break; + + case 137: +#line 503 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[7].value.as < std::string > () + " IN " + sqlb::escapeIdentifier(yystack_[5].value.as < std::string > ()) + "." + yystack_[3].value.as < std::string > () + "(" + yystack_[1].value.as < std::string > () + ")"; } +#line 2290 "sqlite3_parser.cpp" + break; + + case 138: +#line 504 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[5].value.as < std::string > () + " IN " + yystack_[3].value.as < std::string > () + "(" + yystack_[1].value.as < std::string > () + ")"; } +#line 2296 "sqlite3_parser.cpp" + break; + + case 139: +#line 505 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[4].value.as < std::string > () + " NOT IN ()"; } +#line 2302 "sqlite3_parser.cpp" + break; + + case 140: +#line 506 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[5].value.as < std::string > () + " NOT IN (" + yystack_[1].value.as < std::string > () + ")"; } +#line 2308 "sqlite3_parser.cpp" + break; + + case 141: +#line 507 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[5].value.as < std::string > () + " NOT IN (" + yystack_[1].value.as < std::string > () + ")"; } +#line 2314 "sqlite3_parser.cpp" + break; + + case 142: +#line 508 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[5].value.as < std::string > () + " NOT IN " + sqlb::escapeIdentifier(yystack_[2].value.as < std::string > ()) + "." + sqlb::escapeIdentifier(yystack_[0].value.as < std::string > ()); } +#line 2320 "sqlite3_parser.cpp" + break; + + case 143: +#line 509 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[3].value.as < std::string > () + " NOT IN " + sqlb::escapeIdentifier(yystack_[0].value.as < std::string > ()); } +#line 2326 "sqlite3_parser.cpp" + break; + + case 144: +#line 510 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[7].value.as < std::string > () + " NOT IN " + sqlb::escapeIdentifier(yystack_[4].value.as < std::string > ()) + "." + yystack_[2].value.as < std::string > () + "()"; } +#line 2332 "sqlite3_parser.cpp" + break; + + case 145: +#line 511 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[8].value.as < std::string > () + " NOT IN " + sqlb::escapeIdentifier(yystack_[5].value.as < std::string > ()) + "." + yystack_[3].value.as < std::string > () + "(" + yystack_[1].value.as < std::string > () + ")"; } +#line 2338 "sqlite3_parser.cpp" + break; + + case 146: +#line 512 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[6].value.as < std::string > () + " NOT IN " + yystack_[3].value.as < std::string > () + "(" + yystack_[1].value.as < std::string > () + ")"; } +#line 2344 "sqlite3_parser.cpp" + break; + + case 147: +#line 516 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = "WHEN " + yystack_[2].value.as < std::string > () + " THEN " + yystack_[0].value.as < std::string > (); } +#line 2350 "sqlite3_parser.cpp" + break; + + case 148: +#line 517 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[4].value.as < std::string > () + " WHEN" + yystack_[2].value.as < std::string > () + " THEN " + yystack_[0].value.as < std::string > (); } +#line 2356 "sqlite3_parser.cpp" + break; + + case 149: +#line 521 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = "CASE " + yystack_[4].value.as < std::string > () + " " + yystack_[3].value.as < std::string > () + " ELSE " + yystack_[1].value.as < std::string > () + " END"; } +#line 2362 "sqlite3_parser.cpp" + break; + + case 150: +#line 522 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = "CASE " + yystack_[2].value.as < std::string > () + " " + yystack_[1].value.as < std::string > () + " END"; } +#line 2368 "sqlite3_parser.cpp" + break; + + case 151: +#line 523 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = "CASE " + yystack_[3].value.as < std::string > () + " ELSE " + yystack_[1].value.as < std::string > () + " END"; } +#line 2374 "sqlite3_parser.cpp" + break; + + case 152: +#line 524 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = "CASE " + yystack_[1].value.as < std::string > () + " END"; } +#line 2380 "sqlite3_parser.cpp" + break; + + case 153: +#line 528 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = "RAISE(IGNORE)"; } +#line 2386 "sqlite3_parser.cpp" + break; + + case 154: +#line 529 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = "RAISE(ROLLBACK, " + yystack_[1].value.as < std::string > () + ")"; } +#line 2392 "sqlite3_parser.cpp" + break; + + case 155: +#line 530 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = "RAISE(ABORT, " + yystack_[1].value.as < std::string > () + ")"; } +#line 2398 "sqlite3_parser.cpp" + break; + + case 156: +#line 531 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = "RAISE(FAIL, " + yystack_[1].value.as < std::string > () + ")"; } +#line 2404 "sqlite3_parser.cpp" + break; + + case 157: +#line 535 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } +#line 2410 "sqlite3_parser.cpp" + break; + + case 158: +#line 536 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = sqlb::escapeIdentifier(yystack_[0].value.as < std::string > ()); } +#line 2416 "sqlite3_parser.cpp" + break; + + case 159: +#line 537 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } +#line 2422 "sqlite3_parser.cpp" + break; + + case 160: +#line 538 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = sqlb::escapeIdentifier(yystack_[4].value.as < std::string > ()) + "." + sqlb::escapeIdentifier(yystack_[2].value.as < std::string > ()) + "." + sqlb::escapeIdentifier(yystack_[0].value.as < std::string > ()); } +#line 2428 "sqlite3_parser.cpp" + break; + + case 161: +#line 539 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = sqlb::escapeIdentifier(yystack_[2].value.as < std::string > ()) + "." + sqlb::escapeIdentifier(yystack_[0].value.as < std::string > ()); } +#line 2434 "sqlite3_parser.cpp" + break; + + case 162: +#line 540 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = sqlb::escapeIdentifier(yystack_[0].value.as < std::string > ()); } +#line 2440 "sqlite3_parser.cpp" + break; + + case 163: +#line 541 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } +#line 2446 "sqlite3_parser.cpp" + break; + + case 164: +#line 542 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } +#line 2452 "sqlite3_parser.cpp" + break; + + case 165: +#line 543 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } +#line 2458 "sqlite3_parser.cpp" + break; + + case 166: +#line 544 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = "(" + yystack_[1].value.as < std::string > () + ")"; } +#line 2464 "sqlite3_parser.cpp" + break; + + case 167: +#line 545 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = "CAST(" + yystack_[3].value.as < std::string > () + " AS " + yystack_[1].value.as < std::string > () + ")"; } +#line 2470 "sqlite3_parser.cpp" + break; + + case 168: +#line 546 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[2].value.as < std::string > () + " COLLATE " + yystack_[0].value.as < std::string > (); } +#line 2476 "sqlite3_parser.cpp" + break; + + case 169: +#line 547 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } +#line 2482 "sqlite3_parser.cpp" + break; + + case 170: +#line 548 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } +#line 2488 "sqlite3_parser.cpp" + break; + + case 171: +#line 549 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } +#line 2494 "sqlite3_parser.cpp" + break; + + case 172: +#line 550 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } +#line 2500 "sqlite3_parser.cpp" + break; + + case 173: +#line 551 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } +#line 2506 "sqlite3_parser.cpp" + break; + + case 174: +#line 552 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } +#line 2512 "sqlite3_parser.cpp" + break; + + case 175: +#line 561 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = "SELECT"; } +#line 2518 "sqlite3_parser.cpp" + break; + + case 176: +#line 569 "sqlite3_parser.yy" + { yylhs.value.as < bool > () = false; } +#line 2524 "sqlite3_parser.cpp" + break; + + case 177: +#line 570 "sqlite3_parser.yy" + { yylhs.value.as < bool > () = true; } +#line 2530 "sqlite3_parser.cpp" + break; + + case 178: +#line 574 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = ""; } +#line 2536 "sqlite3_parser.cpp" + break; + + case 179: +#line 575 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = "ASC"; } +#line 2542 "sqlite3_parser.cpp" + break; + + case 180: +#line 576 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = "DESC"; } +#line 2548 "sqlite3_parser.cpp" + break; + + case 181: +#line 584 "sqlite3_parser.yy" + { yylhs.value.as < bool > () = false; } +#line 2554 "sqlite3_parser.cpp" + break; + + case 182: +#line 585 "sqlite3_parser.yy" + { yylhs.value.as < bool > () = true; } +#line 2560 "sqlite3_parser.cpp" + break; + + case 183: +#line 589 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = ""; } +#line 2566 "sqlite3_parser.cpp" + break; + + case 184: +#line 590 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } +#line 2572 "sqlite3_parser.cpp" + break; + + case 185: +#line 594 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } +#line 2578 "sqlite3_parser.cpp" + break; + + case 186: +#line 595 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } +#line 2584 "sqlite3_parser.cpp" + break; + + case 187: +#line 596 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } +#line 2590 "sqlite3_parser.cpp" + break; + + case 188: +#line 600 "sqlite3_parser.yy" + { + // If the expression is only one column name and nothing else, treat it as a column name; otherwise as an expression. + char quote = getIdentifierQuoteChar(); + if((quote == '[' && std::count(yystack_[1].value.as < std::string > ().begin(), yystack_[1].value.as < std::string > ().end(), quote) == 1 && yystack_[1].value.as < std::string > ().front() == '[' && yystack_[1].value.as < std::string > ().back() == ']') || + (quote != '[' && std::count(yystack_[1].value.as < std::string > ().begin(), yystack_[1].value.as < std::string > ().end(), quote) == 2 && yystack_[1].value.as < std::string > ().front() == quote && yystack_[1].value.as < std::string > ().back() == quote)) + { + yylhs.value.as < sqlb::IndexedColumn > () = sqlb::IndexedColumn(unquote_text(yystack_[1].value.as < std::string > (), quote), false, yystack_[0].value.as < std::string > ()); + } else { + yylhs.value.as < sqlb::IndexedColumn > () = sqlb::IndexedColumn(yystack_[1].value.as < std::string > (), true, yystack_[0].value.as < std::string > ()); + } + } +#line 2606 "sqlite3_parser.cpp" + break; + + case 189: +#line 614 "sqlite3_parser.yy" + { yylhs.value.as < sqlb::IndexedColumnVector > () = sqlb::IndexedColumnVector(1, yystack_[0].value.as < sqlb::IndexedColumn > ()); } +#line 2612 "sqlite3_parser.cpp" + break; + + case 190: +#line 615 "sqlite3_parser.yy" + { yylhs.value.as < sqlb::IndexedColumnVector > () = yystack_[2].value.as < sqlb::IndexedColumnVector > (); yylhs.value.as < sqlb::IndexedColumnVector > ().push_back(yystack_[0].value.as < sqlb::IndexedColumn > ()); } +#line 2618 "sqlite3_parser.cpp" + break; + + case 191: +#line 619 "sqlite3_parser.yy" + { + yylhs.value.as < sqlb::IndexPtr > () = sqlb::IndexPtr(new sqlb::Index(yystack_[6].value.as < std::string > ())); + yylhs.value.as < sqlb::IndexPtr > ()->setTable(yystack_[4].value.as < std::string > ()); + yylhs.value.as < sqlb::IndexPtr > ()->setUnique(yystack_[9].value.as < bool > ()); + yylhs.value.as < sqlb::IndexPtr > ()->setWhereExpr(yystack_[0].value.as < std::string > ()); + yylhs.value.as < sqlb::IndexPtr > ()->fields = yystack_[2].value.as < sqlb::IndexedColumnVector > (); + yylhs.value.as < sqlb::IndexPtr > ()->setFullyParsed(true); + } +#line 2631 "sqlite3_parser.cpp" + break; + + case 192: +#line 634 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = {}; } +#line 2637 "sqlite3_parser.cpp" + break; + + case 193: +#line 635 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = {}; } +#line 2643 "sqlite3_parser.cpp" + break; + + case 194: +#line 636 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[1].value.as < std::string > (); } +#line 2649 "sqlite3_parser.cpp" + break; + + case 195: +#line 640 "sqlite3_parser.yy" + { + yylhs.value.as < sqlb::TablePtr > () = sqlb::TablePtr(new sqlb::Table(yystack_[3].value.as < std::string > ())); + yylhs.value.as < sqlb::TablePtr > ()->setVirtualUsing(yystack_[1].value.as < std::string > ()); + yylhs.value.as < sqlb::TablePtr > ()->setFullyParsed(false); + } +#line 2659 "sqlite3_parser.cpp" + break; + + case 196: +#line 652 "sqlite3_parser.yy" + { yylhs.value.as < bool > () = false; } +#line 2665 "sqlite3_parser.cpp" + break; + + case 197: +#line 653 "sqlite3_parser.yy" + { yylhs.value.as < bool > () = true; } +#line 2671 "sqlite3_parser.cpp" + break; + + case 198: +#line 654 "sqlite3_parser.yy" + { yylhs.value.as < bool > () = true; } +#line 2677 "sqlite3_parser.cpp" + break; + + case 199: +#line 658 "sqlite3_parser.yy" + { yylhs.value.as < bool > () = false; } +#line 2683 "sqlite3_parser.cpp" + break; + + case 200: +#line 659 "sqlite3_parser.yy" + { yylhs.value.as < bool > () = true; } +#line 2689 "sqlite3_parser.cpp" + break; + + case 201: +#line 663 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = ""; } +#line 2695 "sqlite3_parser.cpp" + break; + + case 202: +#line 664 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } +#line 2701 "sqlite3_parser.cpp" + break; + + case 203: +#line 665 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } +#line 2707 "sqlite3_parser.cpp" + break; + + case 204: +#line 666 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } +#line 2713 "sqlite3_parser.cpp" + break; + + case 205: +#line 667 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } +#line 2719 "sqlite3_parser.cpp" + break; + + case 206: +#line 668 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } +#line 2725 "sqlite3_parser.cpp" + break; + + case 207: +#line 672 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = ""; } +#line 2731 "sqlite3_parser.cpp" + break; + + case 208: +#line 673 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } +#line 2737 "sqlite3_parser.cpp" + break; + + case 209: +#line 677 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = "VIRTUAL"; } +#line 2743 "sqlite3_parser.cpp" + break; + + case 210: +#line 678 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = "STORED"; } +#line 2749 "sqlite3_parser.cpp" + break; + + case 211: +#line 679 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = "VIRTUAL"; } +#line 2755 "sqlite3_parser.cpp" + break; + + case 212: +#line 683 "sqlite3_parser.yy" + { yylhs.value.as < bool > () = false; } +#line 2761 "sqlite3_parser.cpp" + break; + + case 213: +#line 684 "sqlite3_parser.yy" + { yylhs.value.as < bool > () = true; } +#line 2767 "sqlite3_parser.cpp" + break; + + case 214: +#line 688 "sqlite3_parser.yy" + { + yylhs.value.as < ColumnConstraintInfo > ().type = ColumnConstraintInfo::PrimaryKey; + yylhs.value.as < ColumnConstraintInfo > ().is_table_constraint = true; + sqlb::PrimaryKeyConstraint* pk = new sqlb::PrimaryKeyConstraint({sqlb::IndexedColumn("", false, yystack_[1].value.as < std::string > ())}); + pk->setName(yystack_[4].value.as < std::string > ()); + pk->setConflictAction(yystack_[0].value.as < std::string > ()); + yylhs.value.as < ColumnConstraintInfo > ().table_constraint = sqlb::ConstraintPtr(pk); + yylhs.value.as < ColumnConstraintInfo > ().fully_parsed = true; + } +#line 2781 "sqlite3_parser.cpp" + break; + + case 215: +#line 697 "sqlite3_parser.yy" + { + yylhs.value.as < ColumnConstraintInfo > ().type = ColumnConstraintInfo::PrimaryKey; + yylhs.value.as < ColumnConstraintInfo > ().is_table_constraint = true; + sqlb::PrimaryKeyConstraint* pk = new sqlb::PrimaryKeyConstraint({sqlb::IndexedColumn("", false, yystack_[2].value.as < std::string > ())}); + pk->setName(yystack_[5].value.as < std::string > ()); + pk->setConflictAction(yystack_[1].value.as < std::string > ()); + pk->setAutoIncrement(true); + yylhs.value.as < ColumnConstraintInfo > ().table_constraint = sqlb::ConstraintPtr(pk); + yylhs.value.as < ColumnConstraintInfo > ().fully_parsed = true; + } +#line 2796 "sqlite3_parser.cpp" + break; + + case 216: +#line 707 "sqlite3_parser.yy" + { + yylhs.value.as < ColumnConstraintInfo > ().type = ColumnConstraintInfo::NotNull; + yylhs.value.as < ColumnConstraintInfo > ().is_table_constraint = false; + yylhs.value.as < ColumnConstraintInfo > ().fully_parsed = (yystack_[3].value.as < std::string > () == "" && yystack_[0].value.as < std::string > () == ""); + } +#line 2806 "sqlite3_parser.cpp" + break; + + case 217: +#line 712 "sqlite3_parser.yy" + { + yylhs.value.as < ColumnConstraintInfo > ().type = ColumnConstraintInfo::None; + yylhs.value.as < ColumnConstraintInfo > ().is_table_constraint = false; + yylhs.value.as < ColumnConstraintInfo > ().fully_parsed = true; + } +#line 2816 "sqlite3_parser.cpp" + break; + + case 218: +#line 717 "sqlite3_parser.yy" + { + yylhs.value.as < ColumnConstraintInfo > ().type = ColumnConstraintInfo::Unique; + yylhs.value.as < ColumnConstraintInfo > ().is_table_constraint = false; + yylhs.value.as < ColumnConstraintInfo > ().fully_parsed = (yystack_[2].value.as < std::string > () == "" && yystack_[0].value.as < std::string > () == ""); + } +#line 2826 "sqlite3_parser.cpp" + break; + + case 219: +#line 722 "sqlite3_parser.yy" + { + yylhs.value.as < ColumnConstraintInfo > ().type = ColumnConstraintInfo::Check; + yylhs.value.as < ColumnConstraintInfo > ().is_table_constraint = false; + yylhs.value.as < ColumnConstraintInfo > ().text = yystack_[1].value.as < std::string > (); + yylhs.value.as < ColumnConstraintInfo > ().fully_parsed = (yystack_[4].value.as < std::string > () == ""); + } +#line 2837 "sqlite3_parser.cpp" + break; + + case 220: +#line 728 "sqlite3_parser.yy" + { + yylhs.value.as < ColumnConstraintInfo > ().type = ColumnConstraintInfo::Default; + yylhs.value.as < ColumnConstraintInfo > ().is_table_constraint = false; + yylhs.value.as < ColumnConstraintInfo > ().text = yystack_[0].value.as < std::string > (); + yylhs.value.as < ColumnConstraintInfo > ().fully_parsed = (yystack_[2].value.as < std::string > () == ""); + } +#line 2848 "sqlite3_parser.cpp" + break; + + case 221: +#line 734 "sqlite3_parser.yy" + { + yylhs.value.as < ColumnConstraintInfo > ().type = ColumnConstraintInfo::Default; + yylhs.value.as < ColumnConstraintInfo > ().is_table_constraint = false; + yylhs.value.as < ColumnConstraintInfo > ().text = yystack_[0].value.as < std::string > (); + yylhs.value.as < ColumnConstraintInfo > ().fully_parsed = (yystack_[2].value.as < std::string > () == ""); + } +#line 2859 "sqlite3_parser.cpp" + break; + + case 222: +#line 740 "sqlite3_parser.yy" + { + yylhs.value.as < ColumnConstraintInfo > ().type = ColumnConstraintInfo::Default; + yylhs.value.as < ColumnConstraintInfo > ().is_table_constraint = false; + yylhs.value.as < ColumnConstraintInfo > ().text = yystack_[0].value.as < std::string > (); + yylhs.value.as < ColumnConstraintInfo > ().fully_parsed = (yystack_[2].value.as < std::string > () == ""); + } +#line 2870 "sqlite3_parser.cpp" + break; + + case 223: +#line 746 "sqlite3_parser.yy" + { // We must allow the same keywords as unquoted default values as in the columnid context. + // But we do not use columnid here in order to avoid reduce/reduce conflicts. + yylhs.value.as < ColumnConstraintInfo > ().type = ColumnConstraintInfo::Default; + yylhs.value.as < ColumnConstraintInfo > ().is_table_constraint = false; + yylhs.value.as < ColumnConstraintInfo > ().text = yystack_[0].value.as < std::string > (); + yylhs.value.as < ColumnConstraintInfo > ().fully_parsed = (yystack_[2].value.as < std::string > () == ""); + } +#line 2882 "sqlite3_parser.cpp" + break; + + case 224: +#line 753 "sqlite3_parser.yy" + { // Same as above. + yylhs.value.as < ColumnConstraintInfo > ().type = ColumnConstraintInfo::Default; + yylhs.value.as < ColumnConstraintInfo > ().is_table_constraint = false; + yylhs.value.as < ColumnConstraintInfo > ().text = yystack_[0].value.as < std::string > (); + yylhs.value.as < ColumnConstraintInfo > ().fully_parsed = (yystack_[2].value.as < std::string > () == ""); + } +#line 2893 "sqlite3_parser.cpp" + break; + + case 225: +#line 759 "sqlite3_parser.yy" + { + yylhs.value.as < ColumnConstraintInfo > ().type = ColumnConstraintInfo::Default; + yylhs.value.as < ColumnConstraintInfo > ().is_table_constraint = false; + yylhs.value.as < ColumnConstraintInfo > ().text = "(" + yystack_[1].value.as < std::string > () + ")"; + yylhs.value.as < ColumnConstraintInfo > ().fully_parsed = (yystack_[4].value.as < std::string > () == ""); + } +#line 2904 "sqlite3_parser.cpp" + break; + + case 226: +#line 765 "sqlite3_parser.yy" + { + yylhs.value.as < ColumnConstraintInfo > ().type = ColumnConstraintInfo::Collate; + yylhs.value.as < ColumnConstraintInfo > ().is_table_constraint = false; + yylhs.value.as < ColumnConstraintInfo > ().text = yystack_[0].value.as < std::string > (); + yylhs.value.as < ColumnConstraintInfo > ().fully_parsed = (yystack_[2].value.as < std::string > () == ""); + } +#line 2915 "sqlite3_parser.cpp" + break; + + case 227: +#line 771 "sqlite3_parser.yy" + { // TODO Solve shift/reduce conflict. It is not super important though as shifting seems to be right here. + yylhs.value.as < ColumnConstraintInfo > ().type = ColumnConstraintInfo::ForeignKey; + yylhs.value.as < ColumnConstraintInfo > ().is_table_constraint = true; + sqlb::ForeignKeyClause* fk = new sqlb::ForeignKeyClause(); + fk->setName(yystack_[4].value.as < std::string > ()); + fk->setTable(yystack_[2].value.as < std::string > ()); + fk->setColumns(yystack_[1].value.as < sqlb::StringVector > ()); + fk->setConstraint(yystack_[0].value.as < std::string > ()); + yylhs.value.as < ColumnConstraintInfo > ().table_constraint = sqlb::ConstraintPtr(fk); + yylhs.value.as < ColumnConstraintInfo > ().fully_parsed = true; + } +#line 2931 "sqlite3_parser.cpp" + break; + + case 228: +#line 782 "sqlite3_parser.yy" + { // TODO Solve shift/reduce conflict. + yylhs.value.as < ColumnConstraintInfo > ().type = ColumnConstraintInfo::Generated; + yylhs.value.as < ColumnConstraintInfo > ().is_table_constraint = false; + yylhs.value.as < ColumnConstraintInfo > ().generated_constraint.setExpression(yystack_[2].value.as < std::string > ()); + yylhs.value.as < ColumnConstraintInfo > ().generated_constraint.setStorage(yystack_[0].value.as < std::string > ()); + yylhs.value.as < ColumnConstraintInfo > ().generated_constraint.setName(yystack_[6].value.as < std::string > ()); + yylhs.value.as < ColumnConstraintInfo > ().fully_parsed = true; + } +#line 2944 "sqlite3_parser.cpp" + break; + + case 229: +#line 793 "sqlite3_parser.yy" + { yylhs.value.as < ColumnConstraintInfoVector > () = { yystack_[0].value.as < ColumnConstraintInfo > () }; } +#line 2950 "sqlite3_parser.cpp" + break; + + case 230: +#line 794 "sqlite3_parser.yy" + { yylhs.value.as < ColumnConstraintInfoVector > () = yystack_[1].value.as < ColumnConstraintInfoVector > (); yylhs.value.as < ColumnConstraintInfoVector > ().push_back(yystack_[0].value.as < ColumnConstraintInfo > ()); } +#line 2956 "sqlite3_parser.cpp" + break; + + case 231: +#line 798 "sqlite3_parser.yy" + { + sqlb::Field f(yystack_[2].value.as < std::string > (), yystack_[1].value.as < std::string > ()); + bool fully_parsed = true; + sqlb::ConstraintSet table_constraints{}; + for(auto c : yystack_[0].value.as < ColumnConstraintInfoVector > ()) + { + if(c.fully_parsed == false) + fully_parsed = false; + + if(c.type == ColumnConstraintInfo::None) + continue; + + if(c.is_table_constraint) + { + if(c.table_constraint->columnList().empty()) + c.table_constraint->setColumnList({yystack_[2].value.as < std::string > ()}); + else + c.table_constraint->replaceInColumnList("", yystack_[2].value.as < std::string > ()); + table_constraints.insert(c.table_constraint); + } else { + if(c.type == ColumnConstraintInfo::NotNull) { + f.setNotNull(true); + } else if(c.type == ColumnConstraintInfo::Unique) { + f.setUnique(true); + } else if(c.type == ColumnConstraintInfo::Check) { + f.setCheck(c.text); + } else if(c.type == ColumnConstraintInfo::Default) { + f.setDefaultValue(c.text); + } else if(c.type == ColumnConstraintInfo::Collate) { + f.setCollation(c.text); + } else if(c.type == ColumnConstraintInfo::Generated) { + f.setGenerated(c.generated_constraint); + + // This is a hack which removes any "GENERATED ALWAYS" from the end of the type name. + // As of now these are shifted to the type instead of reducing the type when seeing the GENERATED identifier. + // TODO Remove this once the grammar is conflict free + const std::string generated_always = "GENERATED ALWAYS"; + if(f.type().size() >= generated_always.size() && f.type().compare(f.type().size() - generated_always.size(), generated_always.size(), generated_always) == 0) + { + std::string type = f.type().substr(0, f.type().size()-generated_always.size()); + if(type.back() == ' ') + type.pop_back(); + f.setType(type); + } + } else { + fully_parsed = false; + } + } + } + + yylhs.value.as < ColumndefData > () = std::make_tuple(f, table_constraints, fully_parsed); + } +#line 3013 "sqlite3_parser.cpp" + break; + + case 232: +#line 850 "sqlite3_parser.yy" + { yylhs.value.as < ColumndefData > () = std::make_tuple(sqlb::Field(yystack_[1].value.as < std::string > (), yystack_[0].value.as < std::string > ()), sqlb::ConstraintSet{}, true); } +#line 3019 "sqlite3_parser.cpp" + break; + + case 233: +#line 854 "sqlite3_parser.yy" + { yylhs.value.as < std::vector > () = {yystack_[0].value.as < ColumndefData > ()}; } +#line 3025 "sqlite3_parser.cpp" + break; + + case 234: +#line 855 "sqlite3_parser.yy" + { yylhs.value.as < std::vector > () = yystack_[2].value.as < std::vector > (); yylhs.value.as < std::vector > ().push_back(yystack_[0].value.as < ColumndefData > ()); } +#line 3031 "sqlite3_parser.cpp" + break; + + case 235: +#line 859 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = ""; } +#line 3037 "sqlite3_parser.cpp" + break; + + case 236: +#line 860 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } +#line 3043 "sqlite3_parser.cpp" + break; + + case 237: +#line 864 "sqlite3_parser.yy" + { yylhs.value.as < sqlb::StringVector > () = sqlb::StringVector(1, yystack_[0].value.as < std::string > ()); } +#line 3049 "sqlite3_parser.cpp" + break; + + case 238: +#line 865 "sqlite3_parser.yy" + { yylhs.value.as < sqlb::StringVector > () = yystack_[2].value.as < sqlb::StringVector > (); yylhs.value.as < sqlb::StringVector > ().push_back(yystack_[0].value.as < std::string > ()); } +#line 3055 "sqlite3_parser.cpp" + break; + + case 239: +#line 869 "sqlite3_parser.yy" + { yylhs.value.as < sqlb::StringVector > () = sqlb::StringVector(); } +#line 3061 "sqlite3_parser.cpp" + break; + + case 240: +#line 870 "sqlite3_parser.yy" + { yylhs.value.as < sqlb::StringVector > () = yystack_[1].value.as < sqlb::StringVector > (); } +#line 3067 "sqlite3_parser.cpp" + break; + + case 241: +#line 874 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[3].value.as < std::string > () + " " + yystack_[2].value.as < std::string > () + " " + yystack_[1].value.as < std::string > () + " " + yystack_[0].value.as < std::string > (); } +#line 3073 "sqlite3_parser.cpp" + break; + + case 242: +#line 875 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[3].value.as < std::string > () + " " + yystack_[2].value.as < std::string > () + " " + yystack_[1].value.as < std::string > () + " " + yystack_[0].value.as < std::string > (); } +#line 3079 "sqlite3_parser.cpp" + break; + + case 243: +#line 876 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[2].value.as < std::string > () + " " + yystack_[1].value.as < std::string > () + " " + yystack_[0].value.as < std::string > (); } +#line 3085 "sqlite3_parser.cpp" + break; + + case 244: +#line 877 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[2].value.as < std::string > () + " " + yystack_[1].value.as < std::string > () + " " + yystack_[0].value.as < std::string > (); } +#line 3091 "sqlite3_parser.cpp" + break; + + case 245: +#line 878 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[3].value.as < std::string > () + " " + yystack_[2].value.as < std::string > () + " " + yystack_[1].value.as < std::string > () + " " + yystack_[0].value.as < std::string > (); } +#line 3097 "sqlite3_parser.cpp" + break; + + case 246: +#line 879 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[3].value.as < std::string > () + " " + yystack_[2].value.as < std::string > () + " " + yystack_[1].value.as < std::string > () + " " + yystack_[0].value.as < std::string > (); } +#line 3103 "sqlite3_parser.cpp" + break; + + case 247: +#line 880 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[3].value.as < std::string > () + " " + yystack_[2].value.as < std::string > () + " " + yystack_[1].value.as < std::string > () + " " + yystack_[0].value.as < std::string > (); } +#line 3109 "sqlite3_parser.cpp" + break; + + case 248: +#line 881 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[2].value.as < std::string > () + " " + yystack_[1].value.as < std::string > () + " " + yystack_[0].value.as < std::string > (); } +#line 3115 "sqlite3_parser.cpp" + break; + + case 249: +#line 882 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[2].value.as < std::string > () + " " + yystack_[1].value.as < std::string > () + " " + yystack_[0].value.as < std::string > (); } +#line 3121 "sqlite3_parser.cpp" + break; + + case 250: +#line 883 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[3].value.as < std::string > () + " " + yystack_[2].value.as < std::string > () + " " + yystack_[1].value.as < std::string > () + " " + yystack_[0].value.as < std::string > (); } +#line 3127 "sqlite3_parser.cpp" + break; + + case 251: +#line 884 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[3].value.as < std::string > () + " " + yystack_[2].value.as < std::string > () + " " + yystack_[1].value.as < std::string > () + " " + yystack_[0].value.as < std::string > (); } +#line 3133 "sqlite3_parser.cpp" + break; + + case 252: +#line 885 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[3].value.as < std::string > () + " " + yystack_[2].value.as < std::string > () + " " + yystack_[1].value.as < std::string > () + " " + yystack_[0].value.as < std::string > (); } +#line 3139 "sqlite3_parser.cpp" + break; + + case 253: +#line 886 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[2].value.as < std::string > () + " " + yystack_[1].value.as < std::string > () + " " + yystack_[0].value.as < std::string > (); } +#line 3145 "sqlite3_parser.cpp" + break; + + case 254: +#line 887 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[2].value.as < std::string > () + " " + yystack_[1].value.as < std::string > () + " " + yystack_[0].value.as < std::string > (); } +#line 3151 "sqlite3_parser.cpp" + break; + + case 255: +#line 888 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[3].value.as < std::string > () + " " + yystack_[2].value.as < std::string > () + " " + yystack_[1].value.as < std::string > () + " " + yystack_[0].value.as < std::string > (); } +#line 3157 "sqlite3_parser.cpp" + break; + + case 256: +#line 889 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[1].value.as < std::string > () + " " + yystack_[0].value.as < std::string > (); } +#line 3163 "sqlite3_parser.cpp" + break; + + case 257: +#line 893 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } +#line 3169 "sqlite3_parser.cpp" + break; + + case 258: +#line 894 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[1].value.as < std::string > () + " " + yystack_[0].value.as < std::string > (); } +#line 3175 "sqlite3_parser.cpp" + break; + + case 259: +#line 898 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = ""; } +#line 3181 "sqlite3_parser.cpp" + break; + + case 260: +#line 899 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } +#line 3187 "sqlite3_parser.cpp" + break; + + case 261: +#line 900 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[3].value.as < std::string > () + " " + yystack_[2].value.as < std::string > () + " " + yystack_[1].value.as < std::string > () + " " + yystack_[0].value.as < std::string > (); } +#line 3193 "sqlite3_parser.cpp" + break; + + case 262: +#line 901 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[3].value.as < std::string > () + " " + yystack_[2].value.as < std::string > () + " " + yystack_[1].value.as < std::string > () + " " + yystack_[0].value.as < std::string > (); } +#line 3199 "sqlite3_parser.cpp" + break; + + case 263: +#line 902 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[1].value.as < std::string > () + " " + yystack_[0].value.as < std::string > (); } +#line 3205 "sqlite3_parser.cpp" + break; + + case 264: +#line 903 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[4].value.as < std::string > () + " " + yystack_[3].value.as < std::string > () + " " + yystack_[2].value.as < std::string > () + " " + yystack_[1].value.as < std::string > () + " " + yystack_[0].value.as < std::string > (); } +#line 3211 "sqlite3_parser.cpp" + break; + + case 265: +#line 904 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[4].value.as < std::string > () + " " + yystack_[3].value.as < std::string > () + " " + yystack_[2].value.as < std::string > () + " " + yystack_[1].value.as < std::string > () + " " + yystack_[0].value.as < std::string > (); } +#line 3217 "sqlite3_parser.cpp" + break; + + case 266: +#line 905 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[2].value.as < std::string > () + " " + yystack_[1].value.as < std::string > () + " " + yystack_[0].value.as < std::string > (); } +#line 3223 "sqlite3_parser.cpp" + break; + + case 267: +#line 906 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[2].value.as < std::string > () + " " + yystack_[1].value.as < std::string > () + " " + yystack_[0].value.as < std::string > (); } +#line 3229 "sqlite3_parser.cpp" + break; + + case 268: +#line 907 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[2].value.as < std::string > () + " " + yystack_[1].value.as < std::string > () + " " + yystack_[0].value.as < std::string > (); } +#line 3235 "sqlite3_parser.cpp" + break; + + case 269: +#line 908 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } +#line 3241 "sqlite3_parser.cpp" + break; + + case 270: +#line 909 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[3].value.as < std::string > () + " " + yystack_[2].value.as < std::string > () + " " + yystack_[1].value.as < std::string > () + " " + yystack_[0].value.as < std::string > (); } +#line 3247 "sqlite3_parser.cpp" + break; + + case 271: +#line 910 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[3].value.as < std::string > () + " " + yystack_[2].value.as < std::string > () + " " + yystack_[1].value.as < std::string > () + " " + yystack_[0].value.as < std::string > (); } +#line 3253 "sqlite3_parser.cpp" + break; + + case 272: +#line 911 "sqlite3_parser.yy" + { yylhs.value.as < std::string > () = yystack_[1].value.as < std::string > () + " " + yystack_[0].value.as < std::string > (); } +#line 3259 "sqlite3_parser.cpp" + break; + + case 273: +#line 915 "sqlite3_parser.yy" + { + sqlb::PrimaryKeyConstraint* pk = new sqlb::PrimaryKeyConstraint(yystack_[2].value.as < sqlb::IndexedColumnVector > ()); + pk->setName(yystack_[6].value.as < std::string > ()); + pk->setConflictAction(yystack_[0].value.as < std::string > ()); + yylhs.value.as < sqlb::ConstraintPtr > () = sqlb::ConstraintPtr(pk); + } +#line 3270 "sqlite3_parser.cpp" + break; + + case 274: +#line 921 "sqlite3_parser.yy" + { + sqlb::PrimaryKeyConstraint* pk = new sqlb::PrimaryKeyConstraint(yystack_[3].value.as < sqlb::IndexedColumnVector > ()); + pk->setName(yystack_[7].value.as < std::string > ()); + pk->setConflictAction(yystack_[0].value.as < std::string > ()); + pk->setAutoIncrement(true); + yylhs.value.as < sqlb::ConstraintPtr > () = sqlb::ConstraintPtr(pk); + } +#line 3282 "sqlite3_parser.cpp" + break; + + case 275: +#line 928 "sqlite3_parser.yy" + { + sqlb::UniqueConstraint* u = new sqlb::UniqueConstraint(yystack_[2].value.as < sqlb::IndexedColumnVector > ()); + u->setName(yystack_[5].value.as < std::string > ()); + u->setConflictAction(yystack_[0].value.as < std::string > ()); + yylhs.value.as < sqlb::ConstraintPtr > () = sqlb::ConstraintPtr(u); + } +#line 3293 "sqlite3_parser.cpp" + break; + + case 276: +#line 934 "sqlite3_parser.yy" + { + yylhs.value.as < sqlb::ConstraintPtr > () = sqlb::ConstraintPtr(new sqlb::CheckConstraint(yystack_[1].value.as < std::string > ())); + yylhs.value.as < sqlb::ConstraintPtr > ()->setName(yystack_[4].value.as < std::string > ()); + } +#line 3302 "sqlite3_parser.cpp" + break; + + case 277: +#line 938 "sqlite3_parser.yy" + { + yylhs.value.as < sqlb::ConstraintPtr > () = sqlb::ConstraintPtr(new sqlb::ForeignKeyClause(yystack_[2].value.as < std::string > (), yystack_[1].value.as < sqlb::StringVector > (), yystack_[0].value.as < std::string > ())); + yylhs.value.as < sqlb::ConstraintPtr > ()->setColumnList(yystack_[5].value.as < sqlb::StringVector > ()); + yylhs.value.as < sqlb::ConstraintPtr > ()->setName(yystack_[9].value.as < std::string > ()); + } +#line 3312 "sqlite3_parser.cpp" + break; + + case 278: +#line 946 "sqlite3_parser.yy" + { yylhs.value.as < sqlb::ConstraintSet > () = {yystack_[0].value.as < sqlb::ConstraintPtr > ()}; } +#line 3318 "sqlite3_parser.cpp" + break; + + case 279: +#line 947 "sqlite3_parser.yy" + { yylhs.value.as < sqlb::ConstraintSet > () = yystack_[2].value.as < sqlb::ConstraintSet > (); yylhs.value.as < sqlb::ConstraintSet > ().insert(yystack_[0].value.as < sqlb::ConstraintPtr > ()); } +#line 3324 "sqlite3_parser.cpp" + break; + + case 280: +#line 948 "sqlite3_parser.yy" + { yylhs.value.as < sqlb::ConstraintSet > () = yystack_[1].value.as < sqlb::ConstraintSet > (); yylhs.value.as < sqlb::ConstraintSet > ().insert(yystack_[0].value.as < sqlb::ConstraintPtr > ()); } +#line 3330 "sqlite3_parser.cpp" + break; + + case 281: +#line 952 "sqlite3_parser.yy" + { yylhs.value.as < sqlb::ConstraintSet > () = {}; } +#line 3336 "sqlite3_parser.cpp" + break; + + case 282: +#line 953 "sqlite3_parser.yy" + { yylhs.value.as < sqlb::ConstraintSet > () = yystack_[0].value.as < sqlb::ConstraintSet > (); } +#line 3342 "sqlite3_parser.cpp" + break; + + case 283: +#line 957 "sqlite3_parser.yy" + { + yylhs.value.as < sqlb::TablePtr > () = sqlb::TablePtr(new sqlb::Table(yystack_[2].value.as < std::string > ())); + yylhs.value.as < sqlb::TablePtr > ()->setFullyParsed(false); + } +#line 3351 "sqlite3_parser.cpp" + break; + + case 284: +#line 961 "sqlite3_parser.yy" + { + yylhs.value.as < sqlb::TablePtr > () = sqlb::TablePtr(new sqlb::Table(yystack_[5].value.as < std::string > ())); + yylhs.value.as < sqlb::TablePtr > ()->setWithoutRowidTable(yystack_[0].value.as < bool > ()); + yylhs.value.as < sqlb::TablePtr > ()->setConstraints(yystack_[2].value.as < sqlb::ConstraintSet > ()); + yylhs.value.as < sqlb::TablePtr > ()->setFullyParsed(true); + + for(const auto& column : yystack_[3].value.as < std::vector > ()) + { + sqlb::Field f; + sqlb::ConstraintSet c; + bool fully_parsed; + std::tie(f, c, fully_parsed) = column; + + if(fully_parsed == false) + yylhs.value.as < sqlb::TablePtr > ()->setFullyParsed(false); + yylhs.value.as < sqlb::TablePtr > ()->fields.push_back(f); + for(const auto& i : c) + yylhs.value.as < sqlb::TablePtr > ()->addConstraint(i); + } + } +#line 3376 "sqlite3_parser.cpp" + break; + + +#line 3380 "sqlite3_parser.cpp" + + default: + break; + } + } +#if YY_EXCEPTIONS + catch (const syntax_error& yyexc) + { + YYCDEBUG << "Caught exception: " << yyexc.what() << '\n'; + error (yyexc); + YYERROR; + } +#endif // YY_EXCEPTIONS + YY_SYMBOL_PRINT ("-> $$ =", yylhs); + yypop_ (yylen); + yylen = 0; + YY_STACK_PRINT (); + + // Shift the result of the reduction. + yypush_ (YY_NULLPTR, YY_MOVE (yylhs)); + } + goto yynewstate; + + + /*--------------------------------------. + | yyerrlab -- here on detecting error. | + `--------------------------------------*/ + yyerrlab: + // If not already recovering from an error, report this error. + if (!yyerrstatus_) + { + ++yynerrs_; + error (yyla.location, yysyntax_error_ (yystack_[0].state, yyla)); + } + + + yyerror_range[1].location = yyla.location; + if (yyerrstatus_ == 3) + { + /* If just tried and failed to reuse lookahead token after an + error, discard it. */ + + // Return failure if at end of input. + if (yyla.type_get () == yyeof_) + YYABORT; + else if (!yyla.empty ()) + { + yy_destroy_ ("Error: discarding", yyla); + yyla.clear (); + } + } + + // Else will try to reuse lookahead token after shifting the error token. + goto yyerrlab1; + + + /*---------------------------------------------------. + | yyerrorlab -- error raised explicitly by YYERROR. | + `---------------------------------------------------*/ + yyerrorlab: + /* Pacify compilers when the user code never invokes YYERROR and + the label yyerrorlab therefore never appears in user code. */ + if (false) + YYERROR; + + /* Do not reclaim the symbols of the rule whose action triggered + this YYERROR. */ + yypop_ (yylen); + yylen = 0; + goto yyerrlab1; + + + /*-------------------------------------------------------------. + | yyerrlab1 -- common code for both syntax error and YYERROR. | + `-------------------------------------------------------------*/ + yyerrlab1: + yyerrstatus_ = 3; // Each real token shifted decrements this. + { + stack_symbol_type error_token; + for (;;) + { + yyn = yypact_[+yystack_[0].state]; + if (!yy_pact_value_is_default_ (yyn)) + { + yyn += yy_error_token_; + if (0 <= yyn && yyn <= yylast_ && yycheck_[yyn] == yy_error_token_) + { + yyn = yytable_[yyn]; + if (0 < yyn) + break; + } + } + + // Pop the current state because it cannot handle the error token. + if (yystack_.size () == 1) + YYABORT; + + yyerror_range[1].location = yystack_[0].location; + yy_destroy_ ("Error: popping", yystack_[0]); + yypop_ (); + YY_STACK_PRINT (); + } + + yyerror_range[2].location = yyla.location; + YYLLOC_DEFAULT (error_token.location, yyerror_range, 2); + + // Shift the error token. + error_token.state = state_type (yyn); + yypush_ ("Shifting", YY_MOVE (error_token)); + } + goto yynewstate; + + + /*-------------------------------------. + | yyacceptlab -- YYACCEPT comes here. | + `-------------------------------------*/ + yyacceptlab: + yyresult = 0; + goto yyreturn; + + + /*-----------------------------------. + | yyabortlab -- YYABORT comes here. | + `-----------------------------------*/ + yyabortlab: + yyresult = 1; + goto yyreturn; + + + /*-----------------------------------------------------. + | yyreturn -- parsing is finished, return the result. | + `-----------------------------------------------------*/ + yyreturn: + if (!yyla.empty ()) + yy_destroy_ ("Cleanup: discarding lookahead", yyla); + + /* Do not reclaim the symbols of the rule whose action triggered + this YYABORT or YYACCEPT. */ + yypop_ (yylen); + while (1 < yystack_.size ()) + { + yy_destroy_ ("Cleanup: popping", yystack_[0]); + yypop_ (); + } + + return yyresult; + } +#if YY_EXCEPTIONS + catch (...) + { + YYCDEBUG << "Exception caught: cleaning lookahead and stack\n"; + // Do not try to display the values of the reclaimed symbols, + // as their printers might throw an exception. + if (!yyla.empty ()) + yy_destroy_ (YY_NULLPTR, yyla); + + while (1 < yystack_.size ()) + { + yy_destroy_ (YY_NULLPTR, yystack_[0]); + yypop_ (); + } + throw; + } +#endif // YY_EXCEPTIONS + } + + void + parser::error (const syntax_error& yyexc) + { + error (yyexc.location, yyexc.what ()); + } + + // Generate an error message. + std::string + parser::yysyntax_error_ (state_type yystate, const symbol_type& yyla) const + { + // Number of reported tokens (one for the "unexpected", one per + // "expected"). + std::ptrdiff_t yycount = 0; + // Its maximum. + enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 }; + // Arguments of yyformat. + char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM]; + + /* There are many possibilities here to consider: + - If this state is a consistent state with a default action, then + the only way this function was invoked is if the default action + is an error action. In that case, don't check for expected + tokens because there are none. + - The only way there can be no lookahead present (in yyla) is + if this state is a consistent state with a default action. + Thus, detecting the absence of a lookahead is sufficient to + determine that there is no unexpected or expected token to + report. In that case, just report a simple "syntax error". + - Don't assume there isn't a lookahead just because this state is + a consistent state with a default action. There might have + been a previous inconsistent state, consistent state with a + non-default action, or user semantic action that manipulated + yyla. (However, yyla is currently not documented for users.) + - Of course, the expected token list depends on states to have + correct lookahead information, and it depends on the parser not + to perform extra reductions after fetching a lookahead from the + scanner and before detecting a syntax error. Thus, state merging + (from LALR or IELR) and default reductions corrupt the expected + token list. However, the list is correct for canonical LR with + one exception: it will still contain any token that will not be + accepted due to an error action in a later state. + */ + if (!yyla.empty ()) + { + symbol_number_type yytoken = yyla.type_get (); + yyarg[yycount++] = yytname_[yytoken]; + + int yyn = yypact_[+yystate]; + if (!yy_pact_value_is_default_ (yyn)) + { + /* Start YYX at -YYN if negative to avoid negative indexes in + YYCHECK. In other words, skip the first -YYN actions for + this state because they are default actions. */ + int yyxbegin = yyn < 0 ? -yyn : 0; + // Stay within bounds of both yycheck and yytname. + int yychecklim = yylast_ - yyn + 1; + int yyxend = yychecklim < yyntokens_ ? yychecklim : yyntokens_; + for (int yyx = yyxbegin; yyx < yyxend; ++yyx) + if (yycheck_[yyx + yyn] == yyx && yyx != yy_error_token_ + && !yy_table_value_is_error_ (yytable_[yyx + yyn])) + { + if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM) + { + yycount = 1; + break; + } + else + yyarg[yycount++] = yytname_[yyx]; + } + } + } + + char const* yyformat = YY_NULLPTR; + switch (yycount) + { +#define YYCASE_(N, S) \ + case N: \ + yyformat = S; \ + break + default: // Avoid compiler warnings. + YYCASE_ (0, YY_("syntax error")); + YYCASE_ (1, YY_("syntax error, unexpected %s")); + YYCASE_ (2, YY_("syntax error, unexpected %s, expecting %s")); + YYCASE_ (3, YY_("syntax error, unexpected %s, expecting %s or %s")); + YYCASE_ (4, YY_("syntax error, unexpected %s, expecting %s or %s or %s")); + YYCASE_ (5, YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s")); +#undef YYCASE_ + } + + std::string yyres; + // Argument number. + std::ptrdiff_t yyi = 0; + for (char const* yyp = yyformat; *yyp; ++yyp) + if (yyp[0] == '%' && yyp[1] == 's' && yyi < yycount) + { + yyres += yytnamerr_ (yyarg[yyi++]); + ++yyp; + } + else + yyres += *yyp; + return yyres; + } + + + const short parser::yypact_ninf_ = -340; + + const short parser::yytable_ninf_ = -283; + + const short + parser::yypact_[] = + { + -8, 189, 39, 91, -340, -340, -340, -340, -340, -340, + 17, 53, 43, -340, -340, 73, 73, 73, 30, 2227, + 2227, 2227, 108, -340, -340, -340, -340, -340, -340, -340, + -340, -340, -340, -340, -340, -340, -340, -340, -340, -340, + -340, -340, -340, -340, -340, -340, -340, -340, -340, -340, + -340, -340, -340, -340, -340, -340, -340, -340, -340, -340, + 169, -340, -340, -340, -340, -340, -340, -340, 174, -340, + -340, 83, 112, 22, -340, 2315, 2315, -78, 2315, 2139, + 103, -340, -340, -340, -340, 209, 229, -340, -340, -340, + -340, -340, -340, -340, 2315, -340, 212, -340, -340, 951, + -340, 1407, -340, 1613, -340, 90, 2051, 235, 1407, -340, + 1407, 1407, 1407, 1065, 250, -340, -340, -340, -340, 1407, + -340, 274, -340, -340, -340, -340, -340, -340, 37, -340, + -340, -340, -340, 165, -340, -340, -340, -340, -340, -340, + 3208, 2746, -340, 171, 5, -340, -78, -340, 106, -9, + -340, -18, -340, 116, 134, 176, -340, -340, -340, 1407, + -35, 482, 1407, 3318, 7, 609, -78, -340, 1407, 1407, + 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, + 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, 1407, -78, + 1407, 1705, 1407, -340, 1407, 1407, 56, -340, 1407, 1407, + -340, -340, -340, 175, 1407, 179, 182, -340, -340, 193, + -340, -340, 280, -78, 1521, 273, 228, -340, 236, 2315, + 230, 276, 308, 239, 243, 315, 278, -340, 237, -340, + -340, 1904, 1407, -340, 1407, -31, 2823, 319, 334, 337, + 338, -340, 339, 1407, 231, 341, 3208, 232, 232, 4, + 4, 177, 4, 177, 307, 313, 313, 215, 215, 215, + 215, 313, 313, 177, 177, 3318, 2900, -340, 141, 723, + 233, -340, 313, 194, 260, 1407, 1407, 1797, 1407, 1407, + -340, 1407, 3285, 454, 1407, -340, -340, -340, -340, -340, + 5, 1407, -340, 1407, -340, -340, -340, -340, -340, -340, + 230, -1, 345, 309, -340, 346, 1407, 348, 349, 1407, + -340, -340, 1407, 2977, 1993, 1407, -340, 2315, 242, 244, + -340, 245, -340, 241, -340, -78, 1407, 1407, -340, 246, + 350, 1407, 2315, 1407, 1407, 3054, 1932, 837, 251, -340, + 2021, 2451, 2533, 1407, 3208, 355, 2423, 2505, -340, 230, + 2139, 49, -10, 1407, 2587, 2139, 1407, 253, 3208, -340, + 1407, 3131, 356, 357, 358, 359, -340, -340, 313, 313, + -340, -340, 256, 366, -340, 313, 313, 1407, 1407, -340, + 257, 367, 1407, 2315, 1407, 1407, 1407, 313, -340, -340, + -340, 343, -340, 261, 303, -78, 325, 1, -340, 63, + -340, -340, -340, -340, -340, -340, 2669, -340, 286, 110, + 230, 3208, -340, -340, -340, -340, -340, -340, 1179, 313, + 313, -340, -340, 291, 372, -340, 313, 313, 313, -340, + -340, 2139, -25, -340, 310, 9, 12, 13, 311, 330, + -340, 21, 293, 230, 378, -340, -340, 295, -340, 1293, + -340, -340, -340, -20, -340, 360, -340, 54, -340, 361, + -340, 55, -340, 362, -340, 89, 93, 314, -340, -340, + -340, 2315, -340, 230, -340, -340, 299, -340, -340, -340, + -340, -340, -340, -340, -340, -340, -340, -340, -340, -340, + 124, 345, -340, -340, -340, -340, 49, -340 + }; + + const short + parser::yydefact_[] = + { + 0, 181, 0, 2, 4, 5, 6, 197, 198, 182, + 0, 0, 0, 1, 3, 176, 176, 176, 0, 0, + 0, 0, 0, 18, 19, 20, 21, 22, 23, 24, + 59, 58, 60, 25, 26, 27, 28, 29, 30, 31, + 32, 35, 37, 36, 33, 34, 38, 39, 40, 41, + 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, + 53, 52, 54, 55, 56, 16, 62, 17, 61, 57, + 187, 0, 0, 0, 177, 0, 0, 0, 0, 0, + 0, 53, 61, 186, 185, 192, 0, 65, 64, 66, + 67, 69, 68, 63, 207, 233, 281, 175, 283, 0, + 195, 0, 74, 76, 208, 235, 235, 0, 0, 193, + 0, 0, 0, 0, 23, 14, 13, 15, 12, 0, + 10, 43, 11, 7, 8, 9, 159, 157, 162, 158, + 163, 164, 169, 0, 165, 170, 171, 172, 173, 174, + 120, 178, 189, 0, 0, 75, 0, 229, 235, 212, + 234, 0, 278, 235, 199, 0, 80, 79, 81, 0, + 0, 0, 0, 82, 0, 0, 0, 194, 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, 126, 0, 0, 0, 127, 0, 0, + 179, 180, 188, 183, 0, 0, 0, 73, 72, 0, + 236, 230, 0, 0, 0, 0, 0, 217, 0, 0, + 201, 0, 0, 0, 0, 0, 235, 280, 0, 284, + 166, 0, 0, 152, 0, 0, 0, 0, 0, 0, + 0, 124, 0, 0, 0, 161, 121, 87, 88, 84, + 85, 91, 86, 92, 83, 97, 98, 95, 96, 93, + 94, 99, 100, 89, 90, 102, 0, 168, 105, 0, + 61, 135, 101, 104, 106, 0, 0, 0, 0, 0, + 128, 0, 103, 107, 0, 191, 190, 70, 71, 77, + 0, 0, 226, 0, 224, 221, 222, 223, 220, 213, + 201, 178, 239, 0, 218, 0, 0, 0, 0, 0, + 279, 200, 0, 0, 0, 0, 150, 0, 0, 0, + 153, 0, 125, 0, 122, 0, 0, 0, 131, 0, + 0, 0, 0, 0, 0, 0, 109, 0, 61, 143, + 108, 110, 111, 0, 184, 0, 0, 0, 216, 201, + 0, 259, 0, 0, 0, 0, 0, 0, 147, 151, + 0, 0, 0, 0, 0, 0, 123, 160, 129, 113, + 133, 132, 0, 61, 134, 112, 114, 0, 0, 139, + 0, 0, 0, 0, 0, 0, 0, 115, 78, 219, + 225, 214, 237, 0, 269, 0, 0, 0, 257, 260, + 227, 203, 204, 205, 206, 202, 0, 276, 0, 0, + 201, 148, 149, 167, 155, 156, 154, 138, 0, 130, + 117, 141, 140, 0, 61, 142, 116, 118, 119, 215, + 240, 0, 0, 256, 272, 0, 0, 0, 263, 0, + 258, 209, 0, 201, 0, 275, 136, 0, 146, 0, + 238, 267, 268, 0, 243, 0, 244, 0, 253, 0, + 254, 0, 248, 0, 249, 0, 0, 266, 210, 211, + 228, 0, 273, 201, 137, 144, 0, 270, 271, 245, + 242, 241, 255, 252, 251, 250, 247, 246, 261, 262, + 0, 239, 274, 145, 264, 265, 259, 277 + }; + + const short + parser::yypgoto_[] = + { + -340, -340, -340, 170, -19, -13, -66, -339, 172, 95, + -340, 70, -340, -340, -340, -104, -340, -340, -340, -340, + 234, -340, -340, 255, -254, 167, 92, -340, -340, 201, + 187, -282, -340, -340, -340, -340, -340, -297, -340, -340, + -340, 248, -340, 288, -340, -79, 42, -99, 0, -340, + -98, -148, -340, -340, -340 + }; + + const short + parser::yydefgoto_[] = + { + -1, 2, 3, 127, 128, 129, 70, 94, 208, 209, + 103, 104, 130, 131, 132, 133, 134, 135, 136, 137, + 160, 138, 139, 140, 98, 19, 202, 11, 285, 71, + 142, 143, 4, 100, 5, 12, 229, 304, 105, 470, + 221, 147, 148, 95, 96, 151, 393, 351, 398, 399, + 400, 152, 153, 107, 6 + }; + + const short + parser::yytable_[] = + { + 68, 68, 68, 348, 155, 227, 69, 69, 69, 83, + 84, 392, 86, 205, 206, 330, 392, 401, 232, 233, + 176, 222, 315, 316, 451, 79, 149, 357, 102, 477, + 212, 213, 200, 65, 237, 1, 67, 145, 214, 13, + 165, 452, 166, 223, 189, 454, 478, 402, 458, 462, + 201, 435, 391, 215, 80, 403, 82, 82, 85, 82, + 92, 244, 69, 69, 238, 69, 93, 224, 216, 149, + 217, 436, 239, 234, 409, 82, 218, 234, 310, 219, + 404, 69, 405, 381, 82, 455, 225, 92, 459, 463, + 69, 275, 450, 93, -232, 220, -232, 394, 14, 240, + 456, 480, 483, 460, 464, 457, 437, 22, 461, 465, + -231, 438, -231, 445, 443, 15, 204, 207, 468, 276, + -282, 16, 226, 277, 395, 271, 396, 210, 469, 397, + 278, 279, 146, 481, 484, 280, 486, 18, 395, 323, + 439, 17, 488, 397, 444, 281, 472, 245, 146, 169, + 170, 171, 172, 302, 173, 174, 175, 176, 146, 489, + 179, 180, 181, 182, 74, 329, 185, 186, 487, 167, + 267, 168, 270, 494, 75, 203, 492, 204, 69, 76, + 230, 189, 168, 20, 21, 169, 170, 171, 172, 77, + 495, 174, 78, 176, 292, 296, 327, 289, 97, 290, + 82, 297, 169, 170, 171, 172, 69, 173, 174, 175, + 176, 339, 99, 179, 180, 181, 182, 189, 106, 185, + 186, 72, 73, 169, 170, 171, 172, 372, 173, 174, + 175, 176, 101, 380, 189, 324, 331, 168, 332, 154, + 185, 186, 171, 172, 228, 366, 174, 168, 176, 333, + 370, 102, 168, 162, 382, 189, 383, 410, 338, 204, + 417, 421, 168, 168, 69, 430, 374, 431, 169, 170, + 171, 172, 189, 173, 174, 175, 176, 164, 423, 179, + 180, 181, 182, 291, 284, 185, 186, -196, 7, 8, + 442, 287, 431, 9, 288, 448, 10, 168, 82, 474, + 189, 168, 299, 493, 69, 168, 367, 300, 305, 301, + 303, 306, 307, 373, 447, 334, 308, 425, 309, 69, + 146, 169, 170, 171, 172, 318, 173, 174, 175, 176, + 311, 92, 179, 180, 181, 182, 92, 93, 185, 186, + 319, 320, 93, 322, 321, 476, 325, 189, 350, 353, + 352, 355, 356, 189, 371, 363, 141, 364, 365, 388, + 413, 414, 415, 416, 424, 156, 157, 158, 161, 418, + 69, 422, 432, 434, 163, 449, 433, 429, 467, 453, + 466, 471, 473, 490, 295, 345, 298, 362, 479, 482, + 485, 286, 496, 349, 150, 235, 211, 408, 497, 440, + 0, 0, 0, 0, 0, 491, 0, 0, 0, 0, + 0, 0, 92, 0, 231, 0, 0, 236, 93, 0, + 0, 0, 0, 246, 247, 248, 249, 250, 251, 252, + 253, 254, 255, 256, 257, 258, 259, 260, 261, 262, + 263, 264, 265, 266, 0, 268, 0, 272, 0, 273, + 274, 0, 82, 282, 283, 0, 0, 0, 69, 141, + 0, 0, 169, 170, 171, 172, 0, 173, 174, 175, + 176, 0, 0, 179, 180, 181, 182, 0, 0, 185, + 186, 0, 0, 0, 0, 0, 0, 313, 0, 314, + 169, 170, 171, 172, 189, 173, 174, 175, 176, 177, + 178, 179, 180, 181, 182, 183, 184, 185, 186, 343, + 0, 0, 187, 0, 0, 0, 0, 188, 0, 0, + 0, 0, 189, 0, 0, 0, 0, 0, 0, 0, + 335, 336, 0, 340, 341, 0, 342, 0, 0, 344, + 0, 0, 0, 0, 0, 190, 346, 0, 347, 191, + 0, 0, 0, 192, 193, 0, 194, 195, 0, 196, + 197, 354, 0, 198, 141, 0, 0, 358, 0, 0, + 361, 199, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 368, 369, 0, 0, 0, 0, 0, 375, 376, + 159, 0, 0, 0, 0, 0, 0, 0, 387, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 406, 0, + 0, 141, 108, 241, 0, 411, 0, 110, 111, 242, + 0, 112, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 419, 420, 0, 0, 23, 24, 25, 426, + 427, 428, 26, 0, 0, 27, 113, 114, 0, 0, + 29, 0, 0, 115, 116, 117, 0, 0, 33, 0, + 34, 243, 0, 35, 0, 0, 36, 118, 37, 38, + 0, 39, 40, 0, 41, 42, 0, 0, 43, 0, + 0, 0, 44, 45, 46, 47, 119, 0, 120, 0, + 0, 48, 49, 50, 0, 121, 52, 0, 53, 54, + 55, 56, 57, 58, 0, 0, 59, 0, 81, 61, + 0, 122, 62, 0, 0, 0, 63, 0, 0, 64, + 65, 123, 124, 67, 125, 126, 108, 328, 0, 0, + 0, 110, 111, 0, 0, 112, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 23, 24, 25, 0, 0, 0, 26, 0, 0, 27, + 113, 114, 0, 0, 29, 0, 0, 115, 116, 117, + 0, 0, 33, 0, 34, 0, 0, 35, 0, 0, + 36, 118, 37, 38, 0, 39, 40, 0, 41, 42, + 0, 0, 43, 0, 0, 0, 44, 45, 46, 47, + 119, 0, 120, 0, 0, 48, 49, 50, 0, 121, + 52, 0, 53, 54, 55, 56, 57, 58, 97, 0, + 59, 0, 81, 61, 0, 122, 62, 0, 0, 0, + 63, 0, 0, 64, 65, 123, 124, 67, 125, 126, + 108, 379, 0, 0, 0, 110, 111, 0, 0, 112, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 23, 24, 25, 0, 0, 0, + 26, 0, 0, 27, 113, 114, 0, 0, 29, 0, + 0, 115, 116, 117, 0, 0, 33, 0, 34, 0, + 0, 35, 0, 0, 36, 118, 37, 38, 0, 39, + 40, 0, 41, 42, 0, 0, 43, 0, 0, 0, + 44, 45, 46, 47, 119, 0, 120, 0, 0, 48, + 49, 50, 0, 121, 52, 0, 53, 54, 55, 56, + 57, 58, 97, 0, 59, 0, 81, 61, 0, 122, + 62, 0, 0, 0, 63, 0, 0, 64, 65, 123, + 124, 67, 125, 126, 108, 109, 0, 0, 0, 110, + 111, 0, 0, 112, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 23, 24, + 25, 0, 0, 0, 26, 0, 0, 27, 113, 114, + 0, 0, 29, 0, 0, 115, 116, 117, 0, 0, + 33, 0, 34, 0, 0, 35, 0, 0, 36, 118, + 37, 38, 0, 39, 40, 0, 41, 42, 0, 0, + 43, 0, 0, 0, 44, 45, 46, 47, 119, 0, + 120, 0, 0, 48, 49, 50, 0, 121, 52, 0, + 53, 54, 55, 56, 57, 58, 0, 0, 59, 0, + 81, 61, 0, 122, 62, 0, 0, 0, 63, 0, + 0, 64, 65, 123, 124, 67, 125, 126, 108, 0, + 0, 0, 0, 110, 111, 0, 0, 112, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 23, 24, 25, 0, 0, 0, 26, 0, + 0, 27, 113, 114, 0, 0, 29, 0, 0, 115, + 116, 117, 0, 0, 33, 0, 34, 0, 0, 35, + 0, 0, 36, 118, 37, 38, 0, 39, 40, 0, + 41, 42, 0, 0, 43, 0, 0, 0, 44, 45, + 46, 47, 119, 0, 120, 0, 0, 48, 49, 50, + 0, 121, 52, 0, 53, 54, 55, 56, 57, 58, + 0, 0, 59, 0, 81, 61, 0, 122, 62, 0, + 0, 0, 63, 159, 0, 64, 65, 123, 124, 67, + 125, 126, 108, 446, 0, 0, 0, 110, 111, 0, + 0, 112, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 23, 24, 25, 0, + 0, 0, 26, 0, 0, 27, 113, 114, 0, 0, + 29, 0, 0, 115, 116, 117, 0, 0, 33, 0, + 34, 0, 0, 35, 0, 0, 36, 118, 37, 38, + 0, 39, 40, 0, 41, 42, 0, 0, 43, 0, + 0, 0, 44, 45, 46, 47, 119, 0, 120, 0, + 0, 48, 49, 50, 0, 121, 52, 0, 53, 54, + 55, 56, 57, 58, 0, 0, 59, 0, 81, 61, + 0, 122, 62, 0, 0, 0, 63, 0, 0, 64, + 65, 123, 124, 67, 125, 126, 108, 475, 0, 0, + 0, 110, 111, 0, 0, 112, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 23, 24, 25, 0, 0, 0, 26, 0, 0, 27, + 113, 114, 0, 0, 29, 0, 0, 115, 116, 117, + 0, 0, 33, 0, 34, 0, 0, 35, 0, 0, + 36, 118, 37, 38, 0, 39, 40, 0, 41, 42, + 0, 0, 43, 0, 0, 0, 44, 45, 46, 47, + 119, 0, 120, 0, 0, 48, 49, 50, 0, 121, + 52, 0, 53, 54, 55, 56, 57, 58, 0, 0, + 59, 0, 81, 61, 0, 122, 62, 0, 0, 0, + 63, 0, 0, 64, 65, 123, 124, 67, 125, 126, + 108, 0, 0, 0, 0, 110, 111, 0, 0, 112, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 23, 24, 25, 0, 0, 0, + 26, 0, 0, 27, 113, 114, 0, 0, 29, 0, + 0, 115, 116, 117, 0, 0, 33, 0, 34, 0, + 0, 35, 0, 0, 36, 118, 37, 38, 0, 39, + 40, 0, 41, 42, 0, 0, 43, 0, 0, 0, + 44, 45, 46, 47, 119, 0, 120, 0, 0, 48, + 49, 50, 0, 121, 52, 0, 53, 54, 55, 56, + 57, 58, 0, 0, 59, 0, 81, 61, 0, 122, + 62, 0, 0, 0, 63, 0, 0, 64, 65, 123, + 124, 67, 125, 126, 293, 0, 0, 0, 0, 205, + 206, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 23, 24, + 25, 0, 0, 0, 26, 0, 0, 27, 0, 28, + 0, 0, 29, 0, 0, 115, 116, 117, 0, 0, + 33, 0, 34, 0, 0, 35, 0, 0, 36, 118, + 37, 38, 0, 39, 40, 294, 41, 42, 0, 0, + 43, 0, 0, 0, 44, 45, 46, 47, 0, 0, + 120, 0, 0, 48, 49, 50, 0, 51, 52, 0, + 53, 54, 55, 56, 57, 58, 144, 0, 59, 0, + 81, 61, 0, 122, 62, 0, 0, 0, 63, 0, + 0, 64, 65, 123, 124, 67, 125, 0, 0, 0, + 23, 24, 25, 0, 0, 0, 26, 0, 0, 27, + 0, 28, 0, 0, 29, 0, 0, 30, 31, 32, + 0, 0, 33, 0, 34, 0, 0, 35, 0, 0, + 36, 0, 37, 38, 0, 39, 40, 0, 41, 42, + 0, 0, 43, 0, 0, 0, 44, 45, 46, 47, + 0, 0, 0, 0, 0, 48, 49, 50, 0, 51, + 52, 0, 53, 54, 55, 56, 57, 58, 269, 0, + 59, 0, 81, 61, 0, 0, 62, 0, 0, 0, + 63, 0, 0, 64, 65, 0, 66, 67, 0, 0, + 0, 0, 23, 24, 25, 0, 0, 0, 26, 0, + 0, 27, 0, 28, 0, 0, 29, 0, 0, 30, + 31, 32, 0, 0, 33, 0, 34, 0, 0, 35, + 0, 0, 36, 0, 37, 38, 0, 39, 40, 0, + 41, 42, 0, 0, 43, 0, 0, 0, 44, 45, + 46, 47, 0, 0, 0, 0, 0, 48, 49, 50, + 0, 51, 52, 0, 53, 54, 55, 56, 57, 58, + 337, 0, 59, 0, 81, 61, 0, 0, 62, 0, + 0, 0, 63, 0, 0, 64, 65, 0, 66, 67, + 0, 0, 0, 0, 23, 24, 25, 0, 0, 0, + 26, 0, 0, 27, 0, 28, 0, 0, 29, 0, + 0, 30, 31, 32, 0, 0, 33, 0, 34, 0, + 0, 35, 0, 0, 36, 0, 37, 38, 0, 39, + 40, 0, 41, 42, 0, 0, 43, 0, 0, 0, + 44, 45, 46, 47, 0, 0, 0, 0, 0, 48, + 49, 50, 0, 51, 52, 0, 53, 54, 55, 56, + 57, 58, 0, 0, 59, 0, 81, 61, 0, 0, + 62, 0, 0, 0, 63, 0, 0, 64, 65, 0, + 66, 67, 169, 170, 171, 172, 0, 173, 174, 175, + 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, + 186, 0, 0, 0, 187, 0, 0, 0, 0, 188, + 169, 170, 171, 172, 189, 173, 174, 175, 176, 0, + 0, 179, 180, 181, 182, 0, 0, 185, 186, 0, + 0, 0, 0, 0, 0, 0, 0, 190, 0, 0, + 0, 191, 189, 0, 0, 192, 193, 0, 194, 195, + 0, 196, 197, 0, 0, 198, 0, 378, 0, 0, + 0, 0, 0, 199, 0, 0, 0, 0, 0, 0, + 0, 169, 170, 171, 172, 312, 173, 174, 175, 176, + 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, + 0, 0, 0, 187, 0, 0, 0, 0, 188, 169, + 170, 171, 172, 189, 173, 174, 175, 176, 0, 0, + 179, 180, 181, 182, 0, 0, 185, 186, 0, 0, + 0, 0, 0, 0, 0, 0, 190, 0, 0, 0, + 191, 189, 0, 0, 192, 193, 0, 194, 195, 0, + 196, 197, 0, 0, 198, 0, 384, 0, 23, 24, + 25, 0, 199, 0, 26, 0, 0, 27, 0, 28, + 0, 0, 29, 146, 360, 87, 88, 89, 0, 0, + 33, 0, 34, 0, 0, 35, 0, 0, 36, 0, + 37, 38, 0, 39, 40, 90, 41, 42, 0, 0, + 43, 0, 0, 0, 44, 45, 46, 47, 0, 0, + 0, 0, 0, 48, 49, 50, 0, 51, 52, 0, + 53, 54, 55, 56, 57, 58, 0, 0, 59, 0, + 81, 61, 0, 0, 62, 0, 0, 0, 63, 0, + 0, 64, 65, 0, 91, 67, 23, 24, 25, 0, + 0, 0, 26, 0, 0, 27, 0, 28, 0, 0, + 29, 0, 0, 87, 88, 89, 0, 0, 33, 0, + 34, 0, 0, 35, 0, 0, 36, 0, 37, 38, + 0, 39, 40, 90, 41, 42, 0, 0, 43, 0, + 0, 0, 44, 45, 46, 47, 0, 0, 0, 0, + 0, 48, 49, 50, 0, 51, 52, 0, 53, 54, + 55, 56, 57, 58, 0, 0, 59, 0, 81, 61, + 0, 0, 62, 0, 0, 0, 63, 0, 0, 64, + 65, 0, 91, 67, 23, 24, 25, 0, 0, 0, + 26, 0, 0, 27, 0, 28, 0, 0, 29, 0, + 0, 30, 31, 32, 0, 0, 33, 0, 34, 0, + 0, 35, 0, 0, 36, 0, 37, 38, 0, 39, + 40, 0, 41, 42, 0, 0, 43, 0, 0, 0, + 44, 45, 46, 47, 0, 0, 0, 0, 0, 48, + 49, 50, 0, 51, 52, 0, 53, 54, 55, 56, + 57, 58, 0, 0, 59, 0, 60, 61, 0, 0, + 62, 0, 0, 0, 63, 0, 0, 64, 65, 0, + 66, 67, 23, 24, 25, 0, 0, 0, 26, 0, + 0, 27, 0, 28, 0, 0, 29, 0, 0, 30, + 31, 32, 0, 0, 33, 0, 34, 0, 0, 35, + 0, 0, 36, 0, 37, 38, 0, 39, 40, 0, + 41, 42, 0, 0, 43, 0, 0, 0, 44, 45, + 46, 47, 0, 0, 0, 0, 0, 48, 49, 50, + 0, 51, 52, 0, 53, 54, 55, 56, 57, 58, + 0, 0, 59, 0, 81, 61, 0, 0, 62, 0, + 0, 0, 63, 0, 0, 64, 65, 389, 66, 67, + 0, 169, 170, 171, 172, 0, 173, 174, 175, 176, + 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, + 0, 0, 0, 187, 0, 0, 0, 0, 188, 169, + 170, 171, 172, 189, 173, 174, 175, 176, 0, 0, + 179, 180, 181, 182, 0, 0, 185, 186, 0, 0, + 0, 0, 0, 0, 0, 0, 190, 0, 0, 0, + 191, 189, 0, 0, 192, 193, 0, 194, 195, 0, + 196, 197, 0, 0, 198, 0, 385, 0, 0, 390, + 0, 0, 199, 169, 170, 171, 172, 0, 173, 174, + 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, + 185, 186, 0, 0, 0, 187, 0, 0, 0, 0, + 188, 169, 170, 171, 172, 189, 173, 174, 175, 176, + 0, 0, 179, 180, 181, 182, 0, 0, 185, 186, + 0, 0, 0, 0, 0, 0, 0, 0, 190, 0, + 0, 0, 191, 189, 0, 0, 192, 193, 0, 194, + 195, 0, 196, 197, 0, 0, 198, 0, 386, 0, + 0, 407, 0, 0, 199, 169, 170, 171, 172, 0, + 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, + 183, 184, 185, 186, 0, 0, 0, 187, 0, 0, + 0, 0, 188, 0, 0, 0, 0, 189, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 190, 0, 0, 0, 191, 0, 0, 0, 192, 193, + 0, 194, 195, 0, 196, 197, 0, 0, 198, 0, + 0, 0, 0, 441, 0, 0, 199, 169, 170, 171, + 172, 0, 173, 174, 175, 176, 177, 178, 179, 180, + 181, 182, 183, 184, 185, 186, 0, 0, 0, 187, + 0, 0, 0, 0, 188, 0, 0, 0, 0, 189, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 190, 0, 0, 0, 191, 0, 0, 0, + 192, 193, 0, 194, 195, 0, 196, 197, 0, 0, + 198, 0, 0, 0, 169, 170, 171, 172, 199, 173, + 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, + 184, 185, 186, 0, 0, 0, 187, 0, 0, 200, + 0, 188, 0, 0, 0, 0, 189, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 201, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 190, + 0, 0, 0, 191, 0, 0, 0, 192, 193, 0, + 194, 195, 0, 196, 197, 0, 0, 198, 0, 0, + 0, 169, 170, 171, 172, 199, 173, 174, 175, 176, + 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, + 0, 0, 0, 187, 0, 317, 0, 0, 188, 0, + 0, 0, 0, 189, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 190, 0, 0, 0, + 191, 0, 0, 0, 192, 193, 0, 194, 195, 0, + 196, 197, 0, 0, 198, 0, 0, 0, 169, 170, + 171, 172, 199, 173, 174, 175, 176, 177, 178, 179, + 180, 181, 182, 183, 184, 185, 186, 0, 0, 0, + 187, 326, 0, 0, 0, 188, 0, 0, 0, 0, + 189, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 190, 0, 0, 0, 191, 0, 0, + 0, 192, 193, 0, 194, 195, 0, 196, 197, 0, + 0, 198, 0, 0, 0, 169, 170, 171, 172, 199, + 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, + 183, 184, 185, 186, 0, 0, 0, 187, 0, 0, + 0, 0, 188, 0, 0, 0, 0, 189, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 359, 0, 0, 0, 0, 0, 0, 0, 0, + 190, 0, 0, 0, 191, 0, 0, 0, 192, 193, + 0, 194, 195, 0, 196, 197, 0, 0, 198, 0, + 0, 0, 169, 170, 171, 172, 199, 173, 174, 175, + 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, + 186, 0, 0, 0, 187, 377, 0, 0, 0, 188, + 0, 0, 0, 0, 189, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 190, 0, 0, + 0, 191, 0, 0, 0, 192, 193, 0, 194, 195, + 0, 196, 197, 0, 0, 198, 0, 0, 0, 169, + 170, 171, 172, 199, 173, 174, 175, 176, 177, 178, + 179, 180, 181, 182, 183, 184, 185, 186, 0, 0, + 0, 187, 0, 0, 0, 0, 188, 0, 0, 0, + 0, 189, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 412, 0, 0, 0, 0, + 0, 0, 0, 0, 190, 0, 0, 0, 191, 0, + 0, 0, 192, 193, 0, 194, 195, 0, 196, 197, + 0, 0, 198, 0, 0, 0, 169, 170, 171, 172, + 199, 173, 174, 175, 176, 177, 178, 179, 180, 181, + 182, 183, 184, 185, 186, 0, 0, 0, 187, 0, + 0, 0, 0, 188, 0, 0, 0, 0, 189, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 190, 0, 0, 0, 191, 0, 0, 0, 192, + 193, 0, 194, 195, 0, 196, 197, 0, 0, 198, + 0, 0, 0, 169, 170, 171, 172, 199, 173, 174, + 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, + 185, 186, 0, 0, 0, 187, 0, 0, 0, 0, + 188, 0, 0, 0, 0, 189, 169, 170, 171, 172, + 0, 173, 174, 175, 176, 177, 178, 179, 180, 181, + 182, 183, 184, 185, 186, 0, 0, 0, 190, 0, + 0, 0, 191, 188, 0, 0, 192, 193, 189, 194, + 195, 0, 196, 197, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 199, 0, 0, 0, 0, 0, + 0, 190, 0, 0, 0, 191, 0, 0, 0, 192, + 193, 0, 194, 195, 0, 196, 197, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 199 + }; + + const short + parser::yycheck_[] = + { + 19, 20, 21, 300, 108, 153, 19, 20, 21, 75, + 76, 350, 78, 8, 9, 269, 355, 27, 53, 54, + 16, 39, 53, 54, 49, 3, 105, 309, 94, 49, + 39, 40, 33, 111, 27, 43, 114, 103, 47, 0, + 3, 66, 5, 61, 40, 36, 66, 57, 36, 36, + 51, 50, 349, 62, 32, 65, 75, 76, 77, 78, + 79, 165, 75, 76, 57, 78, 79, 85, 77, 148, + 79, 70, 65, 108, 356, 94, 85, 108, 226, 88, + 90, 94, 92, 337, 103, 76, 104, 106, 76, 76, + 103, 35, 431, 106, 4, 104, 6, 48, 7, 92, + 91, 47, 47, 91, 91, 96, 105, 77, 96, 96, + 4, 48, 6, 410, 4, 98, 6, 112, 97, 63, + 4, 68, 6, 67, 75, 191, 77, 146, 107, 80, + 74, 75, 42, 79, 79, 79, 47, 64, 75, 243, + 77, 98, 49, 80, 34, 89, 443, 166, 42, 8, + 9, 10, 11, 219, 13, 14, 15, 16, 42, 66, + 19, 20, 21, 22, 56, 269, 25, 26, 79, 4, + 189, 6, 191, 49, 5, 4, 473, 6, 191, 5, + 4, 40, 6, 16, 17, 8, 9, 10, 11, 106, + 66, 14, 80, 16, 213, 214, 55, 4, 95, 6, + 219, 214, 8, 9, 10, 11, 219, 13, 14, 15, + 16, 277, 3, 19, 20, 21, 22, 40, 6, 25, + 26, 20, 21, 8, 9, 10, 11, 331, 13, 14, + 15, 16, 3, 337, 40, 4, 3, 6, 5, 4, + 25, 26, 10, 11, 110, 4, 14, 6, 16, 55, + 4, 317, 6, 3, 3, 40, 5, 4, 277, 6, + 4, 4, 6, 6, 277, 4, 332, 6, 8, 9, + 10, 11, 40, 13, 14, 15, 16, 3, 382, 19, + 20, 21, 22, 3, 109, 25, 26, 98, 99, 100, + 4, 112, 6, 104, 112, 4, 107, 6, 317, 4, + 40, 6, 29, 4, 317, 6, 325, 79, 32, 73, + 80, 3, 73, 332, 418, 55, 73, 383, 3, 332, + 42, 8, 9, 10, 11, 6, 13, 14, 15, 16, + 93, 350, 19, 20, 21, 22, 355, 350, 25, 26, + 6, 4, 355, 4, 6, 449, 5, 40, 3, 3, + 41, 3, 3, 40, 4, 113, 101, 113, 113, 4, + 4, 4, 4, 4, 383, 110, 111, 112, 113, 3, + 383, 4, 69, 48, 119, 3, 395, 34, 48, 69, + 69, 88, 4, 69, 214, 290, 214, 317, 28, 28, + 28, 204, 491, 301, 106, 161, 148, 355, 496, 399, + -1, -1, -1, -1, -1, 471, -1, -1, -1, -1, + -1, -1, 431, -1, 159, -1, -1, 162, 431, -1, + -1, -1, -1, 168, 169, 170, 171, 172, 173, 174, + 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, + 185, 186, 187, 188, -1, 190, -1, 192, -1, 194, + 195, -1, 471, 198, 199, -1, -1, -1, 471, 204, + -1, -1, 8, 9, 10, 11, -1, 13, 14, 15, + 16, -1, -1, 19, 20, 21, 22, -1, -1, 25, + 26, -1, -1, -1, -1, -1, -1, 232, -1, 234, + 8, 9, 10, 11, 40, 13, 14, 15, 16, 17, + 18, 19, 20, 21, 22, 23, 24, 25, 26, 55, + -1, -1, 30, -1, -1, -1, -1, 35, -1, -1, + -1, -1, 40, -1, -1, -1, -1, -1, -1, -1, + 275, 276, -1, 278, 279, -1, 281, -1, -1, 284, + -1, -1, -1, -1, -1, 63, 291, -1, 293, 67, + -1, -1, -1, 71, 72, -1, 74, 75, -1, 77, + 78, 306, -1, 81, 309, -1, -1, 312, -1, -1, + 315, 89, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 326, 327, -1, -1, -1, -1, -1, 333, 334, + 108, -1, -1, -1, -1, -1, -1, -1, 343, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 353, -1, + -1, 356, 3, 4, -1, 360, -1, 8, 9, 10, + -1, 12, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 377, 378, -1, -1, 27, 28, 29, 384, + 385, 386, 33, -1, -1, 36, 37, 38, -1, -1, + 41, -1, -1, 44, 45, 46, -1, -1, 49, -1, + 51, 52, -1, 54, -1, -1, 57, 58, 59, 60, + -1, 62, 63, -1, 65, 66, -1, -1, 69, -1, + -1, -1, 73, 74, 75, 76, 77, -1, 79, -1, + -1, 82, 83, 84, -1, 86, 87, -1, 89, 90, + 91, 92, 93, 94, -1, -1, 97, -1, 99, 100, + -1, 102, 103, -1, -1, -1, 107, -1, -1, 110, + 111, 112, 113, 114, 115, 116, 3, 4, -1, -1, + -1, 8, 9, -1, -1, 12, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 27, 28, 29, -1, -1, -1, 33, -1, -1, 36, + 37, 38, -1, -1, 41, -1, -1, 44, 45, 46, + -1, -1, 49, -1, 51, -1, -1, 54, -1, -1, + 57, 58, 59, 60, -1, 62, 63, -1, 65, 66, + -1, -1, 69, -1, -1, -1, 73, 74, 75, 76, + 77, -1, 79, -1, -1, 82, 83, 84, -1, 86, + 87, -1, 89, 90, 91, 92, 93, 94, 95, -1, + 97, -1, 99, 100, -1, 102, 103, -1, -1, -1, + 107, -1, -1, 110, 111, 112, 113, 114, 115, 116, + 3, 4, -1, -1, -1, 8, 9, -1, -1, 12, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 27, 28, 29, -1, -1, -1, + 33, -1, -1, 36, 37, 38, -1, -1, 41, -1, + -1, 44, 45, 46, -1, -1, 49, -1, 51, -1, + -1, 54, -1, -1, 57, 58, 59, 60, -1, 62, + 63, -1, 65, 66, -1, -1, 69, -1, -1, -1, + 73, 74, 75, 76, 77, -1, 79, -1, -1, 82, + 83, 84, -1, 86, 87, -1, 89, 90, 91, 92, + 93, 94, 95, -1, 97, -1, 99, 100, -1, 102, + 103, -1, -1, -1, 107, -1, -1, 110, 111, 112, + 113, 114, 115, 116, 3, 4, -1, -1, -1, 8, + 9, -1, -1, 12, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 27, 28, + 29, -1, -1, -1, 33, -1, -1, 36, 37, 38, + -1, -1, 41, -1, -1, 44, 45, 46, -1, -1, + 49, -1, 51, -1, -1, 54, -1, -1, 57, 58, + 59, 60, -1, 62, 63, -1, 65, 66, -1, -1, + 69, -1, -1, -1, 73, 74, 75, 76, 77, -1, + 79, -1, -1, 82, 83, 84, -1, 86, 87, -1, + 89, 90, 91, 92, 93, 94, -1, -1, 97, -1, + 99, 100, -1, 102, 103, -1, -1, -1, 107, -1, + -1, 110, 111, 112, 113, 114, 115, 116, 3, -1, + -1, -1, -1, 8, 9, -1, -1, 12, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 27, 28, 29, -1, -1, -1, 33, -1, + -1, 36, 37, 38, -1, -1, 41, -1, -1, 44, + 45, 46, -1, -1, 49, -1, 51, -1, -1, 54, + -1, -1, 57, 58, 59, 60, -1, 62, 63, -1, + 65, 66, -1, -1, 69, -1, -1, -1, 73, 74, + 75, 76, 77, -1, 79, -1, -1, 82, 83, 84, + -1, 86, 87, -1, 89, 90, 91, 92, 93, 94, + -1, -1, 97, -1, 99, 100, -1, 102, 103, -1, + -1, -1, 107, 108, -1, 110, 111, 112, 113, 114, + 115, 116, 3, 4, -1, -1, -1, 8, 9, -1, + -1, 12, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 27, 28, 29, -1, + -1, -1, 33, -1, -1, 36, 37, 38, -1, -1, + 41, -1, -1, 44, 45, 46, -1, -1, 49, -1, + 51, -1, -1, 54, -1, -1, 57, 58, 59, 60, + -1, 62, 63, -1, 65, 66, -1, -1, 69, -1, + -1, -1, 73, 74, 75, 76, 77, -1, 79, -1, + -1, 82, 83, 84, -1, 86, 87, -1, 89, 90, + 91, 92, 93, 94, -1, -1, 97, -1, 99, 100, + -1, 102, 103, -1, -1, -1, 107, -1, -1, 110, + 111, 112, 113, 114, 115, 116, 3, 4, -1, -1, + -1, 8, 9, -1, -1, 12, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 27, 28, 29, -1, -1, -1, 33, -1, -1, 36, + 37, 38, -1, -1, 41, -1, -1, 44, 45, 46, + -1, -1, 49, -1, 51, -1, -1, 54, -1, -1, + 57, 58, 59, 60, -1, 62, 63, -1, 65, 66, + -1, -1, 69, -1, -1, -1, 73, 74, 75, 76, + 77, -1, 79, -1, -1, 82, 83, 84, -1, 86, + 87, -1, 89, 90, 91, 92, 93, 94, -1, -1, + 97, -1, 99, 100, -1, 102, 103, -1, -1, -1, + 107, -1, -1, 110, 111, 112, 113, 114, 115, 116, + 3, -1, -1, -1, -1, 8, 9, -1, -1, 12, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 27, 28, 29, -1, -1, -1, + 33, -1, -1, 36, 37, 38, -1, -1, 41, -1, + -1, 44, 45, 46, -1, -1, 49, -1, 51, -1, + -1, 54, -1, -1, 57, 58, 59, 60, -1, 62, + 63, -1, 65, 66, -1, -1, 69, -1, -1, -1, + 73, 74, 75, 76, 77, -1, 79, -1, -1, 82, + 83, 84, -1, 86, 87, -1, 89, 90, 91, 92, + 93, 94, -1, -1, 97, -1, 99, 100, -1, 102, + 103, -1, -1, -1, 107, -1, -1, 110, 111, 112, + 113, 114, 115, 116, 3, -1, -1, -1, -1, 8, + 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 27, 28, + 29, -1, -1, -1, 33, -1, -1, 36, -1, 38, + -1, -1, 41, -1, -1, 44, 45, 46, -1, -1, + 49, -1, 51, -1, -1, 54, -1, -1, 57, 58, + 59, 60, -1, 62, 63, 64, 65, 66, -1, -1, + 69, -1, -1, -1, 73, 74, 75, 76, -1, -1, + 79, -1, -1, 82, 83, 84, -1, 86, 87, -1, + 89, 90, 91, 92, 93, 94, 3, -1, 97, -1, + 99, 100, -1, 102, 103, -1, -1, -1, 107, -1, + -1, 110, 111, 112, 113, 114, 115, -1, -1, -1, + 27, 28, 29, -1, -1, -1, 33, -1, -1, 36, + -1, 38, -1, -1, 41, -1, -1, 44, 45, 46, + -1, -1, 49, -1, 51, -1, -1, 54, -1, -1, + 57, -1, 59, 60, -1, 62, 63, -1, 65, 66, + -1, -1, 69, -1, -1, -1, 73, 74, 75, 76, + -1, -1, -1, -1, -1, 82, 83, 84, -1, 86, + 87, -1, 89, 90, 91, 92, 93, 94, 3, -1, + 97, -1, 99, 100, -1, -1, 103, -1, -1, -1, + 107, -1, -1, 110, 111, -1, 113, 114, -1, -1, + -1, -1, 27, 28, 29, -1, -1, -1, 33, -1, + -1, 36, -1, 38, -1, -1, 41, -1, -1, 44, + 45, 46, -1, -1, 49, -1, 51, -1, -1, 54, + -1, -1, 57, -1, 59, 60, -1, 62, 63, -1, + 65, 66, -1, -1, 69, -1, -1, -1, 73, 74, + 75, 76, -1, -1, -1, -1, -1, 82, 83, 84, + -1, 86, 87, -1, 89, 90, 91, 92, 93, 94, + 3, -1, 97, -1, 99, 100, -1, -1, 103, -1, + -1, -1, 107, -1, -1, 110, 111, -1, 113, 114, + -1, -1, -1, -1, 27, 28, 29, -1, -1, -1, + 33, -1, -1, 36, -1, 38, -1, -1, 41, -1, + -1, 44, 45, 46, -1, -1, 49, -1, 51, -1, + -1, 54, -1, -1, 57, -1, 59, 60, -1, 62, + 63, -1, 65, 66, -1, -1, 69, -1, -1, -1, + 73, 74, 75, 76, -1, -1, -1, -1, -1, 82, + 83, 84, -1, 86, 87, -1, 89, 90, 91, 92, + 93, 94, -1, -1, 97, -1, 99, 100, -1, -1, + 103, -1, -1, -1, 107, -1, -1, 110, 111, -1, + 113, 114, 8, 9, 10, 11, -1, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, + 26, -1, -1, -1, 30, -1, -1, -1, -1, 35, + 8, 9, 10, 11, 40, 13, 14, 15, 16, -1, + -1, 19, 20, 21, 22, -1, -1, 25, 26, -1, + -1, -1, -1, -1, -1, -1, -1, 63, -1, -1, + -1, 67, 40, -1, -1, 71, 72, -1, 74, 75, + -1, 77, 78, -1, -1, 81, -1, 55, -1, -1, + -1, -1, -1, 89, -1, -1, -1, -1, -1, -1, + -1, 8, 9, 10, 11, 101, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, + -1, -1, -1, 30, -1, -1, -1, -1, 35, 8, + 9, 10, 11, 40, 13, 14, 15, 16, -1, -1, + 19, 20, 21, 22, -1, -1, 25, 26, -1, -1, + -1, -1, -1, -1, -1, -1, 63, -1, -1, -1, + 67, 40, -1, -1, 71, 72, -1, 74, 75, -1, + 77, 78, -1, -1, 81, -1, 55, -1, 27, 28, + 29, -1, 89, -1, 33, -1, -1, 36, -1, 38, + -1, -1, 41, 42, 101, 44, 45, 46, -1, -1, + 49, -1, 51, -1, -1, 54, -1, -1, 57, -1, + 59, 60, -1, 62, 63, 64, 65, 66, -1, -1, + 69, -1, -1, -1, 73, 74, 75, 76, -1, -1, + -1, -1, -1, 82, 83, 84, -1, 86, 87, -1, + 89, 90, 91, 92, 93, 94, -1, -1, 97, -1, + 99, 100, -1, -1, 103, -1, -1, -1, 107, -1, + -1, 110, 111, -1, 113, 114, 27, 28, 29, -1, + -1, -1, 33, -1, -1, 36, -1, 38, -1, -1, + 41, -1, -1, 44, 45, 46, -1, -1, 49, -1, + 51, -1, -1, 54, -1, -1, 57, -1, 59, 60, + -1, 62, 63, 64, 65, 66, -1, -1, 69, -1, + -1, -1, 73, 74, 75, 76, -1, -1, -1, -1, + -1, 82, 83, 84, -1, 86, 87, -1, 89, 90, + 91, 92, 93, 94, -1, -1, 97, -1, 99, 100, + -1, -1, 103, -1, -1, -1, 107, -1, -1, 110, + 111, -1, 113, 114, 27, 28, 29, -1, -1, -1, + 33, -1, -1, 36, -1, 38, -1, -1, 41, -1, + -1, 44, 45, 46, -1, -1, 49, -1, 51, -1, + -1, 54, -1, -1, 57, -1, 59, 60, -1, 62, + 63, -1, 65, 66, -1, -1, 69, -1, -1, -1, + 73, 74, 75, 76, -1, -1, -1, -1, -1, 82, + 83, 84, -1, 86, 87, -1, 89, 90, 91, 92, + 93, 94, -1, -1, 97, -1, 99, 100, -1, -1, + 103, -1, -1, -1, 107, -1, -1, 110, 111, -1, + 113, 114, 27, 28, 29, -1, -1, -1, 33, -1, + -1, 36, -1, 38, -1, -1, 41, -1, -1, 44, + 45, 46, -1, -1, 49, -1, 51, -1, -1, 54, + -1, -1, 57, -1, 59, 60, -1, 62, 63, -1, + 65, 66, -1, -1, 69, -1, -1, -1, 73, 74, + 75, 76, -1, -1, -1, -1, -1, 82, 83, 84, + -1, 86, 87, -1, 89, 90, 91, 92, 93, 94, + -1, -1, 97, -1, 99, 100, -1, -1, 103, -1, + -1, -1, 107, -1, -1, 110, 111, 4, 113, 114, + -1, 8, 9, 10, 11, -1, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, + -1, -1, -1, 30, -1, -1, -1, -1, 35, 8, + 9, 10, 11, 40, 13, 14, 15, 16, -1, -1, + 19, 20, 21, 22, -1, -1, 25, 26, -1, -1, + -1, -1, -1, -1, -1, -1, 63, -1, -1, -1, + 67, 40, -1, -1, 71, 72, -1, 74, 75, -1, + 77, 78, -1, -1, 81, -1, 55, -1, -1, 4, + -1, -1, 89, 8, 9, 10, 11, -1, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, -1, -1, -1, 30, -1, -1, -1, -1, + 35, 8, 9, 10, 11, 40, 13, 14, 15, 16, + -1, -1, 19, 20, 21, 22, -1, -1, 25, 26, + -1, -1, -1, -1, -1, -1, -1, -1, 63, -1, + -1, -1, 67, 40, -1, -1, 71, 72, -1, 74, + 75, -1, 77, 78, -1, -1, 81, -1, 55, -1, + -1, 4, -1, -1, 89, 8, 9, 10, 11, -1, + 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, + 23, 24, 25, 26, -1, -1, -1, 30, -1, -1, + -1, -1, 35, -1, -1, -1, -1, 40, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 63, -1, -1, -1, 67, -1, -1, -1, 71, 72, + -1, 74, 75, -1, 77, 78, -1, -1, 81, -1, + -1, -1, -1, 4, -1, -1, 89, 8, 9, 10, + 11, -1, 13, 14, 15, 16, 17, 18, 19, 20, + 21, 22, 23, 24, 25, 26, -1, -1, -1, 30, + -1, -1, -1, -1, 35, -1, -1, -1, -1, 40, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 63, -1, -1, -1, 67, -1, -1, -1, + 71, 72, -1, 74, 75, -1, 77, 78, -1, -1, + 81, -1, -1, -1, 8, 9, 10, 11, 89, 13, + 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, + 24, 25, 26, -1, -1, -1, 30, -1, -1, 33, + -1, 35, -1, -1, -1, -1, 40, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 51, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 63, + -1, -1, -1, 67, -1, -1, -1, 71, 72, -1, + 74, 75, -1, 77, 78, -1, -1, 81, -1, -1, + -1, 8, 9, 10, 11, 89, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, + -1, -1, -1, 30, -1, 32, -1, -1, 35, -1, + -1, -1, -1, 40, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 63, -1, -1, -1, + 67, -1, -1, -1, 71, 72, -1, 74, 75, -1, + 77, 78, -1, -1, 81, -1, -1, -1, 8, 9, + 10, 11, 89, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 25, 26, -1, -1, -1, + 30, 31, -1, -1, -1, 35, -1, -1, -1, -1, + 40, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 63, -1, -1, -1, 67, -1, -1, + -1, 71, 72, -1, 74, 75, -1, 77, 78, -1, + -1, 81, -1, -1, -1, 8, 9, 10, 11, 89, + 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, + 23, 24, 25, 26, -1, -1, -1, 30, -1, -1, + -1, -1, 35, -1, -1, -1, -1, 40, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 54, -1, -1, -1, -1, -1, -1, -1, -1, + 63, -1, -1, -1, 67, -1, -1, -1, 71, 72, + -1, 74, 75, -1, 77, 78, -1, -1, 81, -1, + -1, -1, 8, 9, 10, 11, 89, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, + 26, -1, -1, -1, 30, 31, -1, -1, -1, 35, + -1, -1, -1, -1, 40, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 63, -1, -1, + -1, 67, -1, -1, -1, 71, 72, -1, 74, 75, + -1, 77, 78, -1, -1, 81, -1, -1, -1, 8, + 9, 10, 11, 89, 13, 14, 15, 16, 17, 18, + 19, 20, 21, 22, 23, 24, 25, 26, -1, -1, + -1, 30, -1, -1, -1, -1, 35, -1, -1, -1, + -1, 40, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 54, -1, -1, -1, -1, + -1, -1, -1, -1, 63, -1, -1, -1, 67, -1, + -1, -1, 71, 72, -1, 74, 75, -1, 77, 78, + -1, -1, 81, -1, -1, -1, 8, 9, 10, 11, + 89, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 22, 23, 24, 25, 26, -1, -1, -1, 30, -1, + -1, -1, -1, 35, -1, -1, -1, -1, 40, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 63, -1, -1, -1, 67, -1, -1, -1, 71, + 72, -1, 74, 75, -1, 77, 78, -1, -1, 81, + -1, -1, -1, 8, 9, 10, 11, 89, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, -1, -1, -1, 30, -1, -1, -1, -1, + 35, -1, -1, -1, -1, 40, 8, 9, 10, 11, + -1, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 22, 23, 24, 25, 26, -1, -1, -1, 63, -1, + -1, -1, 67, 35, -1, -1, 71, 72, 40, 74, + 75, -1, 77, 78, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 89, -1, -1, -1, -1, -1, + -1, 63, -1, -1, -1, 67, -1, -1, -1, 71, + 72, -1, 74, 75, -1, 77, 78, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 89 + }; + + const unsigned char + parser::yystos_[] = + { + 0, 43, 118, 119, 149, 151, 171, 99, 100, 104, + 107, 144, 152, 0, 7, 98, 68, 98, 64, 142, + 142, 142, 77, 27, 28, 29, 33, 36, 38, 41, + 44, 45, 46, 49, 51, 54, 57, 59, 60, 62, + 63, 65, 66, 69, 73, 74, 75, 76, 82, 83, + 84, 86, 87, 89, 90, 91, 92, 93, 94, 97, + 99, 100, 103, 107, 110, 111, 113, 114, 121, 122, + 123, 146, 146, 146, 56, 5, 5, 106, 80, 3, + 32, 99, 121, 123, 123, 121, 123, 44, 45, 46, + 64, 113, 121, 122, 124, 160, 161, 95, 141, 3, + 150, 3, 123, 127, 128, 155, 6, 170, 3, 4, + 8, 9, 12, 37, 38, 44, 45, 46, 58, 77, + 79, 86, 102, 112, 113, 115, 116, 120, 121, 122, + 129, 130, 131, 132, 133, 134, 135, 136, 138, 139, + 140, 140, 147, 148, 3, 123, 42, 158, 159, 162, + 160, 162, 168, 169, 4, 132, 140, 140, 140, 108, + 137, 140, 3, 140, 3, 3, 5, 4, 6, 8, + 9, 10, 11, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 25, 26, 30, 35, 40, + 63, 67, 71, 72, 74, 75, 77, 78, 81, 89, + 33, 51, 143, 4, 6, 8, 9, 112, 125, 126, + 121, 158, 39, 40, 47, 62, 77, 79, 85, 88, + 104, 157, 39, 61, 85, 104, 6, 168, 110, 153, + 4, 140, 53, 54, 108, 137, 140, 27, 57, 65, + 92, 4, 10, 52, 132, 121, 140, 140, 140, 140, + 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, + 140, 140, 140, 140, 140, 140, 140, 121, 140, 3, + 121, 123, 140, 140, 140, 35, 63, 67, 74, 75, + 79, 89, 140, 140, 109, 145, 147, 112, 112, 4, + 6, 3, 121, 3, 64, 120, 121, 122, 125, 29, + 79, 73, 123, 80, 154, 32, 3, 73, 73, 3, + 168, 93, 101, 140, 140, 53, 54, 32, 6, 6, + 4, 6, 4, 132, 4, 5, 31, 55, 4, 132, + 141, 3, 5, 55, 55, 140, 140, 3, 121, 123, + 140, 140, 140, 55, 140, 126, 140, 140, 154, 143, + 3, 164, 41, 3, 140, 3, 3, 148, 140, 54, + 101, 140, 128, 113, 113, 113, 4, 121, 140, 140, + 4, 4, 132, 121, 123, 140, 140, 31, 55, 4, + 132, 141, 3, 5, 55, 55, 55, 140, 4, 4, + 4, 154, 124, 163, 48, 75, 77, 80, 165, 166, + 167, 27, 57, 65, 90, 92, 140, 4, 163, 148, + 4, 140, 54, 4, 4, 4, 4, 4, 3, 140, + 140, 4, 4, 132, 121, 123, 140, 140, 140, 34, + 4, 6, 69, 121, 48, 50, 70, 105, 48, 77, + 165, 4, 4, 4, 34, 154, 4, 132, 4, 3, + 124, 49, 66, 69, 36, 76, 91, 96, 36, 76, + 91, 96, 36, 76, 91, 96, 69, 48, 97, 107, + 156, 88, 154, 4, 4, 4, 132, 49, 66, 28, + 47, 79, 28, 47, 79, 28, 47, 79, 49, 66, + 69, 123, 154, 4, 49, 66, 164, 167 + }; + + const unsigned char + parser::yyr1_[] = + { + 0, 117, 118, 118, 119, 119, 119, 120, 120, 120, + 120, 120, 120, 120, 120, 120, 121, 121, 122, 122, + 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, + 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, + 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, + 122, 122, 122, 122, 122, 122, 122, 123, 123, 123, + 123, 123, 123, 124, 124, 124, 124, 124, 124, 124, + 125, 125, 126, 126, 127, 127, 128, 128, 128, 129, + 129, 129, 129, 130, 130, 130, 130, 130, 130, 130, + 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, + 130, 130, 130, 130, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 132, 132, 133, 133, 133, 133, 134, 134, 134, 135, + 135, 136, 136, 136, 136, 136, 136, 136, 136, 136, + 136, 136, 136, 136, 136, 136, 136, 137, 137, 138, + 138, 138, 138, 139, 139, 139, 139, 140, 140, 140, + 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, + 140, 140, 140, 140, 140, 141, 142, 142, 143, 143, + 143, 144, 144, 145, 145, 146, 146, 146, 147, 148, + 148, 149, 150, 150, 150, 151, 152, 152, 152, 153, + 153, 154, 154, 154, 154, 154, 154, 155, 155, 156, + 156, 156, 157, 157, 158, 158, 158, 158, 158, 158, + 158, 158, 158, 158, 158, 158, 158, 158, 158, 159, + 159, 160, 160, 161, 161, 162, 162, 163, 163, 164, + 164, 165, 165, 165, 165, 165, 165, 165, 165, 165, + 165, 165, 165, 165, 165, 165, 165, 166, 166, 167, + 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, + 167, 167, 167, 168, 168, 168, 168, 168, 169, 169, + 169, 170, 170, 171, 171 + }; + + const signed char + parser::yyr2_[] = + { + 0, 2, 1, 2, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 2, 2, 1, 1, 1, 2, 1, 4, 6, 2, + 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, + 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, + 1, 3, 4, 5, 3, 4, 2, 2, 3, 5, + 6, 4, 5, 5, 5, 3, 7, 8, 6, 5, + 6, 6, 6, 4, 8, 9, 7, 4, 5, 6, + 4, 5, 3, 4, 6, 6, 6, 1, 1, 1, + 5, 3, 1, 1, 1, 1, 3, 6, 3, 1, + 1, 1, 1, 1, 1, 1, 0, 3, 0, 1, + 1, 0, 1, 0, 2, 3, 3, 1, 2, 1, + 3, 11, 0, 2, 3, 8, 0, 1, 1, 0, + 2, 0, 3, 3, 3, 3, 3, 0, 1, 0, + 1, 1, 0, 2, 5, 6, 4, 2, 3, 5, + 3, 3, 3, 3, 3, 5, 3, 5, 7, 1, + 2, 3, 2, 1, 3, 0, 2, 1, 3, 0, + 3, 4, 4, 3, 3, 4, 4, 4, 3, 3, + 4, 4, 4, 3, 3, 4, 2, 1, 2, 0, + 1, 4, 4, 2, 5, 5, 3, 3, 3, 1, + 4, 4, 2, 7, 8, 6, 5, 10, 1, 3, + 2, 0, 2, 7, 10 + }; + + + + // YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. + // First, the terminals, then, starting at \a yyntokens_, nonterminals. + const char* + const parser::yytname_[] = + { + "\"end of file\"", "error", "$undefined", "\"(\"", "\")\"", "\".\"", + "\",\"", "\";\"", "\"+\"", "\"-\"", "\"*\"", "\"/\"", "\"~\"", "\"&\"", + "\"%\"", "\"|\"", "\"||\"", "\"=\"", "\"==\"", "\">\"", "\">=\"", + "\"<\"", "\"<=\"", "\"!=\"", "\"<>\"", "\"<<\"", "\">>\"", "\"ABORT\"", + "\"ACTION\"", "\"ALWAYS\"", "\"AND\"", "\"AND BETWEEN\"", "\"AS\"", + "\"ASC\"", "\"AUTOINCREMENT\"", "\"BETWEEN\"", "\"CASCADE\"", "\"CASE\"", + "\"CAST\"", "\"CHECK\"", "\"COLLATE\"", "\"CONFLICT\"", "\"CONSTRAINT\"", + "\"CREATE\"", "\"CURRENT_DATE\"", "\"CURRENT_TIME\"", + "\"CURRENT_TIMESTAMP\"", "\"DEFAULT\"", "\"DEFERRABLE\"", "\"DEFERRED\"", + "\"DELETE\"", "\"DESC\"", "\"DISTINCT\"", "\"ELSE\"", "\"END\"", + "\"ESCAPE\"", "\"EXISTS\"", "\"FAIL\"", "\"FALSE\"", "\"FILTER\"", + "\"FOLLOWING\"", "\"FOREIGN\"", "\"GENERATED\"", "\"GLOB\"", "\"IF\"", + "\"IGNORE\"", "\"IMMEDIATE\"", "\"IN\"", "\"INDEX\"", "\"INITIALLY\"", + "\"INSERT\"", "\"IS\"", "\"ISNULL\"", "\"KEY\"", "\"LIKE\"", "\"MATCH\"", + "\"NO\"", "\"NOT\"", "\"NOTNULL\"", "\"NULL\"", "\"ON\"", "\"OR\"", + "\"OVER\"", "\"PARTITION\"", "\"PRECEDING\"", "\"PRIMARY\"", "\"RAISE\"", + "\"RANGE\"", "\"REFERENCES\"", "\"REGEXP\"", "\"REPLACE\"", + "\"RESTRICT\"", "\"ROLLBACK\"", "\"ROWID\"", "\"ROWS\"", "\"SELECT\"", + "\"SET\"", "\"STORED\"", "\"TABLE\"", "\"TEMP\"", "\"TEMPORARY\"", + "\"THEN\"", "\"TRUE\"", "\"UNBOUNDED\"", "\"UNIQUE\"", "\"UPDATE\"", + "\"USING\"", "\"VIRTUAL\"", "\"WHEN\"", "\"WHERE\"", "\"WITHOUT\"", + "\"identifier\"", "\"numeric\"", "\"string literal\"", + "\"quoted literal\"", "\"blob literal\"", "\"bind parameter\"", + "$accept", "sql", "statement", "literalvalue", "id", + "allowed_keywords_as_identifier", "tableid", "columnid", "signednumber", + "signednumber_or_numeric", "typename_namelist", "type_name", + "unary_expr", "binary_expr", "like_expr", "exprlist_expr", + "function_expr", "isnull_expr", "between_expr", "in_expr", + "whenthenlist_expr", "case_expr", "raise_expr", "expr", "select_stmt", + "optional_if_not_exists", "optional_sort_order", "optional_unique", + "optional_where", "tableid_with_uninteresting_schema", "indexed_column", + "indexed_column_list", "createindex_stmt", + "optional_exprlist_with_paren", "createvirtualtable_stmt", + "optional_temporary", "optional_withoutrowid", "optional_conflictclause", + "optional_typename", "optional_storage_identifier", + "optional_always_generated", "columnconstraint", "columnconstraint_list", + "columndef", "columndef_list", "optional_constraintname", + "columnid_list", "optional_columnid_with_paren_list", "fk_clause_part", + "fk_clause_part_list", "optional_fk_clause", "tableconstraint", + "tableconstraint_list", "optional_tableconstraint_list", + "createtable_stmt", YY_NULLPTR + }; + +#if YYDEBUG + const short + parser::yyrline_[] = + { + 0, 309, 309, 310, 314, 315, 316, 324, 325, 326, + 327, 328, 329, 330, 331, 332, 336, 337, 342, 343, + 344, 345, 346, 347, 348, 349, 350, 351, 352, 353, + 354, 355, 356, 357, 358, 359, 360, 361, 362, 363, + 364, 365, 366, 367, 368, 369, 370, 371, 372, 373, + 374, 375, 376, 377, 378, 379, 380, 384, 385, 386, + 387, 388, 389, 393, 394, 395, 396, 397, 398, 399, + 403, 404, 408, 409, 413, 414, 418, 419, 420, 424, + 425, 426, 427, 431, 432, 433, 434, 435, 436, 437, + 438, 439, 440, 441, 442, 443, 444, 445, 446, 447, + 448, 449, 450, 451, 455, 456, 457, 458, 459, 460, + 461, 462, 463, 464, 465, 466, 467, 468, 469, 470, + 474, 475, 479, 480, 481, 482, 486, 487, 488, 492, + 493, 497, 498, 499, 500, 501, 502, 503, 504, 505, + 506, 507, 508, 509, 510, 511, 512, 516, 517, 521, + 522, 523, 524, 528, 529, 530, 531, 535, 536, 537, + 538, 539, 540, 541, 542, 543, 544, 545, 546, 547, + 548, 549, 550, 551, 552, 561, 569, 570, 574, 575, + 576, 584, 585, 589, 590, 594, 595, 596, 600, 614, + 615, 619, 634, 635, 636, 640, 652, 653, 654, 658, + 659, 663, 664, 665, 666, 667, 668, 672, 673, 677, + 678, 679, 683, 684, 688, 697, 707, 712, 717, 722, + 728, 734, 740, 746, 753, 759, 765, 771, 782, 793, + 794, 798, 850, 854, 855, 859, 860, 864, 865, 869, + 870, 874, 875, 876, 877, 878, 879, 880, 881, 882, + 883, 884, 885, 886, 887, 888, 889, 893, 894, 898, + 899, 900, 901, 902, 903, 904, 905, 906, 907, 908, + 909, 910, 911, 915, 921, 928, 934, 938, 946, 947, + 948, 952, 953, 957, 961 + }; + + // Print the state stack on the debug stream. + void + parser::yystack_print_ () + { + *yycdebug_ << "Stack now"; + for (stack_type::const_iterator + i = yystack_.begin (), + i_end = yystack_.end (); + i != i_end; ++i) + *yycdebug_ << ' ' << int (i->state); + *yycdebug_ << '\n'; + } + + // Report on the debug stream that the rule \a yyrule is going to be reduced. + void + parser::yy_reduce_print_ (int yyrule) + { + int yylno = yyrline_[yyrule]; + int yynrhs = yyr2_[yyrule]; + // Print the symbols being reduced, and their result. + *yycdebug_ << "Reducing stack by rule " << yyrule - 1 + << " (line " << yylno << "):\n"; + // The symbols being reduced. + for (int yyi = 0; yyi < yynrhs; yyi++) + YY_SYMBOL_PRINT (" $" << yyi + 1 << " =", + yystack_[(yynrhs) - (yyi + 1)]); + } +#endif // YYDEBUG + + +#line 10 "sqlite3_parser.yy" +} } // sqlb::parser +#line 4719 "sqlite3_parser.cpp" + +#line 983 "sqlite3_parser.yy" + + +void sqlb::parser::parser::error(const location_type& l, const std::string& m) +{ + std::cerr << l << ": " << m << std::endl; +} diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/sql/parser/sqlite3_parser.hpp b/src/WBCLFZSystemModule/SqliteDBProcess/src/sql/parser/sqlite3_parser.hpp new file mode 100644 index 0000000..db3f690 --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/sql/parser/sqlite3_parser.hpp @@ -0,0 +1,4097 @@ +// A Bison parser, made by GNU Bison 3.5.1. + +// Skeleton interface for Bison LALR(1) parsers in C++ + +// Copyright (C) 2002-2015, 2018-2020 Free Software Foundation, Inc. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, 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 . + +// As a special exception, you may create a larger work that contains +// part or all of the Bison parser skeleton and distribute that work +// under terms of your choice, so long as that work isn't itself a +// parser generator using the skeleton or a modified version thereof +// as a parser skeleton. Alternatively, if you modify or redistribute +// the parser skeleton itself, you may (at your option) remove this +// special exception, which will cause the skeleton and the resulting +// Bison output files to be licensed under the GNU General Public +// License without this special exception. + +// This special exception was added by the Free Software Foundation in +// version 2.2 of Bison. + + +/** + ** \file sqlite3_parser.hpp + ** Define the sqlb::parser ::parser class. + */ + +// C++ LALR(1) parser skeleton written by Akim Demaille. + +// Undocumented macros, especially those whose name start with YY_, +// are private implementation details. Do not rely on them. + +#ifndef YY_YY_SQLITE3_PARSER_HPP_INCLUDED +# define YY_YY_SQLITE3_PARSER_HPP_INCLUDED +// "%code requires" blocks. +#line 12 "sqlite3_parser.yy" + + #include + #include + #include "../sqlitetypes.h" + #include "../ObjectIdentifier.h" + namespace sqlb { namespace parser { class ParserDriver; } } + typedef void* yyscan_t; + + // Unfortunately we do not store column constraints in a systematic manner yet. + // Instead there is a variable for most column constraints directly inside the + // sqlb::Field class. This means that when parsing a column constraint we cannot + // just build a column constraint object with all the information and insert that + // into the Field object. Instead, the information needs to be passed upwards in + // some other way. This is what these declarations are for. We need to be able + // to pass information to the Field object as well as to the Table object too + // because some column constraints need to be transformed into Table constraints + // with our current layout. + class ColumnConstraintInfo + { + public: + ColumnConstraintInfo() : is_table_constraint(false), fully_parsed(false) {} + ~ColumnConstraintInfo() {} + ColumnConstraintInfo& operator=(const ColumnConstraintInfo& other) + { + type = other.type; + is_table_constraint = other.is_table_constraint; + fully_parsed = other.fully_parsed; + if(is_table_constraint) + table_constraint = other.table_constraint; + text = other.text; + generated_constraint = other.generated_constraint; + + return *this; + } + ColumnConstraintInfo(const ColumnConstraintInfo& other) + { + *this = other; + } + + enum ConstraintType + { + None, + AutoIncrement, + PrimaryKey, + NotNull, + Unique, + Check, + Default, + Collate, + ForeignKey, + Generated, + }; + + ConstraintType type; + bool is_table_constraint; + bool fully_parsed; + + sqlb::ConstraintPtr table_constraint; + std::string text; + sqlb::GeneratedColumnConstraint generated_constraint; + }; + using ColumnConstraintInfoVector = std::vector; + + // Colum definitions are a tuple of three elements: the Field object, a set of table constraints, and a bool to indicate whether parsing was complete + using ColumndefData = std::tuple; + +#line 115 "sqlite3_parser.hpp" + +# include +# include // std::abort +# include +# include +# include +# include + +#if defined __cplusplus +# define YY_CPLUSPLUS __cplusplus +#else +# define YY_CPLUSPLUS 199711L +#endif + +// Support move semantics when possible. +#if 201103L <= YY_CPLUSPLUS +# define YY_MOVE std::move +# define YY_MOVE_OR_COPY move +# define YY_MOVE_REF(Type) Type&& +# define YY_RVREF(Type) Type&& +# define YY_COPY(Type) Type +#else +# define YY_MOVE +# define YY_MOVE_OR_COPY copy +# define YY_MOVE_REF(Type) Type& +# define YY_RVREF(Type) const Type& +# define YY_COPY(Type) const Type& +#endif + +// Support noexcept when possible. +#if 201103L <= YY_CPLUSPLUS +# define YY_NOEXCEPT noexcept +# define YY_NOTHROW +#else +# define YY_NOEXCEPT +# define YY_NOTHROW throw () +#endif + +// Support constexpr when possible. +#if 201703 <= YY_CPLUSPLUS +# define YY_CONSTEXPR constexpr +#else +# define YY_CONSTEXPR +#endif +# include "sqlite3_location.h" +#include +#ifndef YY_ASSERT +# include +# define YY_ASSERT assert +#endif + + +#ifndef YY_ATTRIBUTE_PURE +# if defined __GNUC__ && 2 < __GNUC__ + (96 <= __GNUC_MINOR__) +# define YY_ATTRIBUTE_PURE __attribute__ ((__pure__)) +# else +# define YY_ATTRIBUTE_PURE +# endif +#endif + +#ifndef YY_ATTRIBUTE_UNUSED +# if defined __GNUC__ && 2 < __GNUC__ + (7 <= __GNUC_MINOR__) +# define YY_ATTRIBUTE_UNUSED __attribute__ ((__unused__)) +# else +# define YY_ATTRIBUTE_UNUSED +# endif +#endif + +/* Suppress unused-variable warnings by "using" E. */ +#if ! defined lint || defined __GNUC__ +# define YYUSE(E) ((void) (E)) +#else +# define YYUSE(E) /* empty */ +#endif + +#if defined __GNUC__ && ! defined __ICC && 407 <= __GNUC__ * 100 + __GNUC_MINOR__ +/* Suppress an incorrect diagnostic about yylval being uninitialized. */ +# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \ + _Pragma ("GCC diagnostic push") \ + _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"") \ + _Pragma ("GCC diagnostic ignored \"-Wmaybe-uninitialized\"") +# define YY_IGNORE_MAYBE_UNINITIALIZED_END \ + _Pragma ("GCC diagnostic pop") +#else +# define YY_INITIAL_VALUE(Value) Value +#endif +#ifndef YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN +# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN +# define YY_IGNORE_MAYBE_UNINITIALIZED_END +#endif +#ifndef YY_INITIAL_VALUE +# define YY_INITIAL_VALUE(Value) /* Nothing. */ +#endif + +#if defined __cplusplus && defined __GNUC__ && ! defined __ICC && 6 <= __GNUC__ +# define YY_IGNORE_USELESS_CAST_BEGIN \ + _Pragma ("GCC diagnostic push") \ + _Pragma ("GCC diagnostic ignored \"-Wuseless-cast\"") +# define YY_IGNORE_USELESS_CAST_END \ + _Pragma ("GCC diagnostic pop") +#endif +#ifndef YY_IGNORE_USELESS_CAST_BEGIN +# define YY_IGNORE_USELESS_CAST_BEGIN +# define YY_IGNORE_USELESS_CAST_END +#endif + +# ifndef YY_CAST +# ifdef __cplusplus +# define YY_CAST(Type, Val) static_cast (Val) +# define YY_REINTERPRET_CAST(Type, Val) reinterpret_cast (Val) +# else +# define YY_CAST(Type, Val) ((Type) (Val)) +# define YY_REINTERPRET_CAST(Type, Val) ((Type) (Val)) +# endif +# endif +# ifndef YY_NULLPTR +# if defined __cplusplus +# if 201103L <= __cplusplus +# define YY_NULLPTR nullptr +# else +# define YY_NULLPTR 0 +# endif +# else +# define YY_NULLPTR ((void*)0) +# endif +# endif + +/* Debug traces. */ +#ifndef YYDEBUG +# define YYDEBUG 1 +#endif + +#line 10 "sqlite3_parser.yy" +namespace sqlb { namespace parser { +#line 250 "sqlite3_parser.hpp" + + + + + /// A Bison parser. + class parser + { + public: +#ifndef YYSTYPE + /// A buffer to store and retrieve objects. + /// + /// Sort of a variant, but does not keep track of the nature + /// of the stored data, since that knowledge is available + /// via the current parser state. + class semantic_type + { + public: + /// Type of *this. + typedef semantic_type self_type; + + /// Empty construction. + semantic_type () YY_NOEXCEPT + : yybuffer_ () + , yytypeid_ (YY_NULLPTR) + {} + + /// Construct and fill. + template + semantic_type (YY_RVREF (T) t) + : yytypeid_ (&typeid (T)) + { + YY_ASSERT (sizeof (T) <= size); + new (yyas_ ()) T (YY_MOVE (t)); + } + + /// Destruction, allowed only if empty. + ~semantic_type () YY_NOEXCEPT + { + YY_ASSERT (!yytypeid_); + } + +# if 201103L <= YY_CPLUSPLUS + /// Instantiate a \a T in here from \a t. + template + T& + emplace (U&&... u) + { + YY_ASSERT (!yytypeid_); + YY_ASSERT (sizeof (T) <= size); + yytypeid_ = & typeid (T); + return *new (yyas_ ()) T (std::forward (u)...); + } +# else + /// Instantiate an empty \a T in here. + template + T& + emplace () + { + YY_ASSERT (!yytypeid_); + YY_ASSERT (sizeof (T) <= size); + yytypeid_ = & typeid (T); + return *new (yyas_ ()) T (); + } + + /// Instantiate a \a T in here from \a t. + template + T& + emplace (const T& t) + { + YY_ASSERT (!yytypeid_); + YY_ASSERT (sizeof (T) <= size); + yytypeid_ = & typeid (T); + return *new (yyas_ ()) T (t); + } +# endif + + /// Instantiate an empty \a T in here. + /// Obsolete, use emplace. + template + T& + build () + { + return emplace (); + } + + /// Instantiate a \a T in here from \a t. + /// Obsolete, use emplace. + template + T& + build (const T& t) + { + return emplace (t); + } + + /// Accessor to a built \a T. + template + T& + as () YY_NOEXCEPT + { + YY_ASSERT (yytypeid_); + YY_ASSERT (*yytypeid_ == typeid (T)); + YY_ASSERT (sizeof (T) <= size); + return *yyas_ (); + } + + /// Const accessor to a built \a T (for %printer). + template + const T& + as () const YY_NOEXCEPT + { + YY_ASSERT (yytypeid_); + YY_ASSERT (*yytypeid_ == typeid (T)); + YY_ASSERT (sizeof (T) <= size); + return *yyas_ (); + } + + /// Swap the content with \a that, of same type. + /// + /// Both variants must be built beforehand, because swapping the actual + /// data requires reading it (with as()), and this is not possible on + /// unconstructed variants: it would require some dynamic testing, which + /// should not be the variant's responsibility. + /// Swapping between built and (possibly) non-built is done with + /// self_type::move (). + template + void + swap (self_type& that) YY_NOEXCEPT + { + YY_ASSERT (yytypeid_); + YY_ASSERT (*yytypeid_ == *that.yytypeid_); + std::swap (as (), that.as ()); + } + + /// Move the content of \a that to this. + /// + /// Destroys \a that. + template + void + move (self_type& that) + { +# if 201103L <= YY_CPLUSPLUS + emplace (std::move (that.as ())); +# else + emplace (); + swap (that); +# endif + that.destroy (); + } + +# if 201103L <= YY_CPLUSPLUS + /// Move the content of \a that to this. + template + void + move (self_type&& that) + { + emplace (std::move (that.as ())); + that.destroy (); + } +#endif + + /// Copy the content of \a that to this. + template + void + copy (const self_type& that) + { + emplace (that.as ()); + } + + /// Destroy the stored \a T. + template + void + destroy () + { + as ().~T (); + yytypeid_ = YY_NULLPTR; + } + + private: + /// Prohibit blind copies. + self_type& operator= (const self_type&); + semantic_type (const self_type&); + + /// Accessor to raw memory as \a T. + template + T* + yyas_ () YY_NOEXCEPT + { + void *yyp = yybuffer_.yyraw; + return static_cast (yyp); + } + + /// Const accessor to raw memory as \a T. + template + const T* + yyas_ () const YY_NOEXCEPT + { + const void *yyp = yybuffer_.yyraw; + return static_cast (yyp); + } + + /// An auxiliary type to compute the largest semantic type. + union union_type + { + // columnconstraint + char dummy1[sizeof (ColumnConstraintInfo)]; + + // columnconstraint_list + char dummy2[sizeof (ColumnConstraintInfoVector)]; + + // columndef + char dummy3[sizeof (ColumndefData)]; + + // optional_if_not_exists + // optional_unique + // optional_temporary + // optional_withoutrowid + // optional_always_generated + char dummy4[sizeof (bool)]; + + // tableconstraint + char dummy5[sizeof (sqlb::ConstraintPtr)]; + + // tableconstraint_list + // optional_tableconstraint_list + char dummy6[sizeof (sqlb::ConstraintSet)]; + + // createindex_stmt + char dummy7[sizeof (sqlb::IndexPtr)]; + + // indexed_column + char dummy8[sizeof (sqlb::IndexedColumn)]; + + // indexed_column_list + char dummy9[sizeof (sqlb::IndexedColumnVector)]; + + // columnid_list + // optional_columnid_with_paren_list + char dummy10[sizeof (sqlb::StringVector)]; + + // createvirtualtable_stmt + // createtable_stmt + char dummy11[sizeof (sqlb::TablePtr)]; + + // "ABORT" + // "ACTION" + // "ALWAYS" + // "AND" + // "AND BETWEEN" + // "AS" + // "ASC" + // "AUTOINCREMENT" + // "BETWEEN" + // "CASCADE" + // "CASE" + // "CAST" + // "CHECK" + // "COLLATE" + // "CONFLICT" + // "CONSTRAINT" + // "CREATE" + // "CURRENT_DATE" + // "CURRENT_TIME" + // "CURRENT_TIMESTAMP" + // "DEFAULT" + // "DEFERRABLE" + // "DEFERRED" + // "DELETE" + // "DESC" + // "DISTINCT" + // "ELSE" + // "END" + // "ESCAPE" + // "EXISTS" + // "FAIL" + // "FALSE" + // "FILTER" + // "FOLLOWING" + // "FOREIGN" + // "GENERATED" + // "GLOB" + // "IF" + // "IGNORE" + // "IMMEDIATE" + // "IN" + // "INDEX" + // "INITIALLY" + // "INSERT" + // "IS" + // "ISNULL" + // "KEY" + // "LIKE" + // "MATCH" + // "NO" + // "NOT" + // "NOTNULL" + // "NULL" + // "ON" + // "OR" + // "OVER" + // "PARTITION" + // "PRECEDING" + // "PRIMARY" + // "RAISE" + // "RANGE" + // "REFERENCES" + // "REGEXP" + // "REPLACE" + // "RESTRICT" + // "ROLLBACK" + // "ROWID" + // "ROWS" + // "SELECT" + // "SET" + // "STORED" + // "TABLE" + // "TEMP" + // "TEMPORARY" + // "THEN" + // "TRUE" + // "UNBOUNDED" + // "UNIQUE" + // "UPDATE" + // "USING" + // "VIRTUAL" + // "WHEN" + // "WHERE" + // "WITHOUT" + // "identifier" + // "numeric" + // "string literal" + // "quoted literal" + // "blob literal" + // "bind parameter" + // literalvalue + // id + // allowed_keywords_as_identifier + // tableid + // columnid + // signednumber + // signednumber_or_numeric + // typename_namelist + // type_name + // unary_expr + // binary_expr + // like_expr + // exprlist_expr + // function_expr + // isnull_expr + // between_expr + // in_expr + // whenthenlist_expr + // case_expr + // raise_expr + // expr + // select_stmt + // optional_sort_order + // optional_where + // tableid_with_uninteresting_schema + // optional_exprlist_with_paren + // optional_conflictclause + // optional_typename + // optional_storage_identifier + // optional_constraintname + // fk_clause_part + // fk_clause_part_list + // optional_fk_clause + char dummy12[sizeof (std::string)]; + + // columndef_list + char dummy13[sizeof (std::vector)]; + }; + + /// The size of the largest semantic type. + enum { size = sizeof (union_type) }; + + /// A buffer to store semantic values. + union + { + /// Strongest alignment constraints. + long double yyalign_me; + /// A buffer large enough to store any of the semantic values. + char yyraw[size]; + } yybuffer_; + + /// Whether the content is built: if defined, the name of the stored type. + const std::type_info *yytypeid_; + }; + +#else + typedef YYSTYPE semantic_type; +#endif + /// Symbol locations. + typedef location location_type; + + /// Syntax errors thrown from user actions. + struct syntax_error : std::runtime_error + { + syntax_error (const location_type& l, const std::string& m) + : std::runtime_error (m) + , location (l) + {} + + syntax_error (const syntax_error& s) + : std::runtime_error (s.what ()) + , location (s.location) + {} + + ~syntax_error () YY_NOEXCEPT YY_NOTHROW; + + location_type location; + }; + + /// Tokens. + struct token + { + enum yytokentype + { + TOK_EOF = 0, + TOK_LPAREN = 258, + TOK_RPAREN = 259, + TOK_DOT = 260, + TOK_COMMA = 261, + TOK_SEMI = 262, + TOK_PLUS = 263, + TOK_MINUS = 264, + TOK_STAR = 265, + TOK_SLASH = 266, + TOK_TILDE = 267, + TOK_AMPERSAND = 268, + TOK_PERCENT = 269, + TOK_BITOR = 270, + TOK_OROP = 271, + TOK_EQUAL = 272, + TOK_EQUAL2 = 273, + TOK_GREATER = 274, + TOK_GREATEREQUAL = 275, + TOK_LOWER = 276, + TOK_LOWEREQUAL = 277, + TOK_UNEQUAL = 278, + TOK_UNEQUAL2 = 279, + TOK_BITWISELEFT = 280, + TOK_BITWISERIGHT = 281, + TOK_ABORT = 282, + TOK_ACTION = 283, + TOK_ALWAYS = 284, + TOK_AND = 285, + TOK_AND_BETWEEN = 286, + TOK_AS = 287, + TOK_ASC = 288, + TOK_AUTOINCREMENT = 289, + TOK_BETWEEN = 290, + TOK_CASCADE = 291, + TOK_CASE = 292, + TOK_CAST = 293, + TOK_CHECK = 294, + TOK_COLLATE = 295, + TOK_CONFLICT = 296, + TOK_CONSTRAINT = 297, + TOK_CREATE = 298, + TOK_CURRENT_DATE = 299, + TOK_CURRENT_TIME = 300, + TOK_CURRENT_TIMESTAMP = 301, + TOK_DEFAULT = 302, + TOK_DEFERRABLE = 303, + TOK_DEFERRED = 304, + TOK_DELETE = 305, + TOK_DESC = 306, + TOK_DISTINCT = 307, + TOK_ELSE = 308, + TOK_END = 309, + TOK_ESCAPE = 310, + TOK_EXISTS = 311, + TOK_FAIL = 312, + TOK_FALSE = 313, + TOK_FILTER = 314, + TOK_FOLLOWING = 315, + TOK_FOREIGN = 316, + TOK_GENERATED = 317, + TOK_GLOB = 318, + TOK_IF = 319, + TOK_IGNORE = 320, + TOK_IMMEDIATE = 321, + TOK_IN = 322, + TOK_INDEX = 323, + TOK_INITIALLY = 324, + TOK_INSERT = 325, + TOK_IS = 326, + TOK_ISNULL = 327, + TOK_KEY = 328, + TOK_LIKE = 329, + TOK_MATCH = 330, + TOK_NO = 331, + TOK_NOT = 332, + TOK_NOTNULL = 333, + TOK_NULL = 334, + TOK_ON = 335, + TOK_OR = 336, + TOK_OVER = 337, + TOK_PARTITION = 338, + TOK_PRECEDING = 339, + TOK_PRIMARY = 340, + TOK_RAISE = 341, + TOK_RANGE = 342, + TOK_REFERENCES = 343, + TOK_REGEXP = 344, + TOK_REPLACE = 345, + TOK_RESTRICT = 346, + TOK_ROLLBACK = 347, + TOK_ROWID = 348, + TOK_ROWS = 349, + TOK_SELECT = 350, + TOK_SET = 351, + TOK_STORED = 352, + TOK_TABLE = 353, + TOK_TEMP = 354, + TOK_TEMPORARY = 355, + TOK_THEN = 356, + TOK_TRUE = 357, + TOK_UNBOUNDED = 358, + TOK_UNIQUE = 359, + TOK_UPDATE = 360, + TOK_USING = 361, + TOK_VIRTUAL = 362, + TOK_WHEN = 363, + TOK_WHERE = 364, + TOK_WITHOUT = 365, + TOK_IDENTIFIER = 366, + TOK_NUMERIC = 367, + TOK_STRINGLITERAL = 368, + TOK_QUOTEDLITERAL = 369, + TOK_BLOBLITERAL = 370, + TOK_BINDPARAMETER = 371 + }; + }; + + /// (External) token type, as returned by yylex. + typedef token::yytokentype token_type; + + /// Symbol type: an internal symbol number. + typedef int symbol_number_type; + + /// The symbol type number to denote an empty symbol. + enum { empty_symbol = -2 }; + + /// Internal symbol number for tokens (subsumed by symbol_number_type). + typedef signed char token_number_type; + + /// A complete symbol. + /// + /// Expects its Base type to provide access to the symbol type + /// via type_get (). + /// + /// Provide access to semantic value and location. + template + struct basic_symbol : Base + { + /// Alias to Base. + typedef Base super_type; + + /// Default constructor. + basic_symbol () + : value () + , location () + {} + +#if 201103L <= YY_CPLUSPLUS + /// Move constructor. + basic_symbol (basic_symbol&& that); +#endif + + /// Copy constructor. + basic_symbol (const basic_symbol& that); + + /// Constructor for valueless symbols, and symbols from each type. +#if 201103L <= YY_CPLUSPLUS + basic_symbol (typename Base::kind_type t, location_type&& l) + : Base (t) + , location (std::move (l)) + {} +#else + basic_symbol (typename Base::kind_type t, const location_type& l) + : Base (t) + , location (l) + {} +#endif +#if 201103L <= YY_CPLUSPLUS + basic_symbol (typename Base::kind_type t, ColumnConstraintInfo&& v, location_type&& l) + : Base (t) + , value (std::move (v)) + , location (std::move (l)) + {} +#else + basic_symbol (typename Base::kind_type t, const ColumnConstraintInfo& v, const location_type& l) + : Base (t) + , value (v) + , location (l) + {} +#endif +#if 201103L <= YY_CPLUSPLUS + basic_symbol (typename Base::kind_type t, ColumnConstraintInfoVector&& v, location_type&& l) + : Base (t) + , value (std::move (v)) + , location (std::move (l)) + {} +#else + basic_symbol (typename Base::kind_type t, const ColumnConstraintInfoVector& v, const location_type& l) + : Base (t) + , value (v) + , location (l) + {} +#endif +#if 201103L <= YY_CPLUSPLUS + basic_symbol (typename Base::kind_type t, ColumndefData&& v, location_type&& l) + : Base (t) + , value (std::move (v)) + , location (std::move (l)) + {} +#else + basic_symbol (typename Base::kind_type t, const ColumndefData& v, const location_type& l) + : Base (t) + , value (v) + , location (l) + {} +#endif +#if 201103L <= YY_CPLUSPLUS + basic_symbol (typename Base::kind_type t, bool&& v, location_type&& l) + : Base (t) + , value (std::move (v)) + , location (std::move (l)) + {} +#else + basic_symbol (typename Base::kind_type t, const bool& v, const location_type& l) + : Base (t) + , value (v) + , location (l) + {} +#endif +#if 201103L <= YY_CPLUSPLUS + basic_symbol (typename Base::kind_type t, sqlb::ConstraintPtr&& v, location_type&& l) + : Base (t) + , value (std::move (v)) + , location (std::move (l)) + {} +#else + basic_symbol (typename Base::kind_type t, const sqlb::ConstraintPtr& v, const location_type& l) + : Base (t) + , value (v) + , location (l) + {} +#endif +#if 201103L <= YY_CPLUSPLUS + basic_symbol (typename Base::kind_type t, sqlb::ConstraintSet&& v, location_type&& l) + : Base (t) + , value (std::move (v)) + , location (std::move (l)) + {} +#else + basic_symbol (typename Base::kind_type t, const sqlb::ConstraintSet& v, const location_type& l) + : Base (t) + , value (v) + , location (l) + {} +#endif +#if 201103L <= YY_CPLUSPLUS + basic_symbol (typename Base::kind_type t, sqlb::IndexPtr&& v, location_type&& l) + : Base (t) + , value (std::move (v)) + , location (std::move (l)) + {} +#else + basic_symbol (typename Base::kind_type t, const sqlb::IndexPtr& v, const location_type& l) + : Base (t) + , value (v) + , location (l) + {} +#endif +#if 201103L <= YY_CPLUSPLUS + basic_symbol (typename Base::kind_type t, sqlb::IndexedColumn&& v, location_type&& l) + : Base (t) + , value (std::move (v)) + , location (std::move (l)) + {} +#else + basic_symbol (typename Base::kind_type t, const sqlb::IndexedColumn& v, const location_type& l) + : Base (t) + , value (v) + , location (l) + {} +#endif +#if 201103L <= YY_CPLUSPLUS + basic_symbol (typename Base::kind_type t, sqlb::IndexedColumnVector&& v, location_type&& l) + : Base (t) + , value (std::move (v)) + , location (std::move (l)) + {} +#else + basic_symbol (typename Base::kind_type t, const sqlb::IndexedColumnVector& v, const location_type& l) + : Base (t) + , value (v) + , location (l) + {} +#endif +#if 201103L <= YY_CPLUSPLUS + basic_symbol (typename Base::kind_type t, sqlb::StringVector&& v, location_type&& l) + : Base (t) + , value (std::move (v)) + , location (std::move (l)) + {} +#else + basic_symbol (typename Base::kind_type t, const sqlb::StringVector& v, const location_type& l) + : Base (t) + , value (v) + , location (l) + {} +#endif +#if 201103L <= YY_CPLUSPLUS + basic_symbol (typename Base::kind_type t, sqlb::TablePtr&& v, location_type&& l) + : Base (t) + , value (std::move (v)) + , location (std::move (l)) + {} +#else + basic_symbol (typename Base::kind_type t, const sqlb::TablePtr& v, const location_type& l) + : Base (t) + , value (v) + , location (l) + {} +#endif +#if 201103L <= YY_CPLUSPLUS + basic_symbol (typename Base::kind_type t, std::string&& v, location_type&& l) + : Base (t) + , value (std::move (v)) + , location (std::move (l)) + {} +#else + basic_symbol (typename Base::kind_type t, const std::string& v, const location_type& l) + : Base (t) + , value (v) + , location (l) + {} +#endif +#if 201103L <= YY_CPLUSPLUS + basic_symbol (typename Base::kind_type t, std::vector&& v, location_type&& l) + : Base (t) + , value (std::move (v)) + , location (std::move (l)) + {} +#else + basic_symbol (typename Base::kind_type t, const std::vector& v, const location_type& l) + : Base (t) + , value (v) + , location (l) + {} +#endif + + /// Destroy the symbol. + ~basic_symbol () + { + clear (); + } + + /// Destroy contents, and record that is empty. + void clear () + { + // User destructor. + symbol_number_type yytype = this->type_get (); + basic_symbol& yysym = *this; + (void) yysym; + switch (yytype) + { + default: + break; + } + + // Type destructor. +switch (yytype) + { + case 158: // columnconstraint + value.template destroy< ColumnConstraintInfo > (); + break; + + case 159: // columnconstraint_list + value.template destroy< ColumnConstraintInfoVector > (); + break; + + case 160: // columndef + value.template destroy< ColumndefData > (); + break; + + case 142: // optional_if_not_exists + case 144: // optional_unique + case 152: // optional_temporary + case 153: // optional_withoutrowid + case 157: // optional_always_generated + value.template destroy< bool > (); + break; + + case 168: // tableconstraint + value.template destroy< sqlb::ConstraintPtr > (); + break; + + case 169: // tableconstraint_list + case 170: // optional_tableconstraint_list + value.template destroy< sqlb::ConstraintSet > (); + break; + + case 149: // createindex_stmt + value.template destroy< sqlb::IndexPtr > (); + break; + + case 147: // indexed_column + value.template destroy< sqlb::IndexedColumn > (); + break; + + case 148: // indexed_column_list + value.template destroy< sqlb::IndexedColumnVector > (); + break; + + case 163: // columnid_list + case 164: // optional_columnid_with_paren_list + value.template destroy< sqlb::StringVector > (); + break; + + case 151: // createvirtualtable_stmt + case 171: // createtable_stmt + value.template destroy< sqlb::TablePtr > (); + break; + + case 27: // "ABORT" + case 28: // "ACTION" + case 29: // "ALWAYS" + case 30: // "AND" + case 31: // "AND BETWEEN" + case 32: // "AS" + case 33: // "ASC" + case 34: // "AUTOINCREMENT" + case 35: // "BETWEEN" + case 36: // "CASCADE" + case 37: // "CASE" + case 38: // "CAST" + case 39: // "CHECK" + case 40: // "COLLATE" + case 41: // "CONFLICT" + case 42: // "CONSTRAINT" + case 43: // "CREATE" + case 44: // "CURRENT_DATE" + case 45: // "CURRENT_TIME" + case 46: // "CURRENT_TIMESTAMP" + case 47: // "DEFAULT" + case 48: // "DEFERRABLE" + case 49: // "DEFERRED" + case 50: // "DELETE" + case 51: // "DESC" + case 52: // "DISTINCT" + case 53: // "ELSE" + case 54: // "END" + case 55: // "ESCAPE" + case 56: // "EXISTS" + case 57: // "FAIL" + case 58: // "FALSE" + case 59: // "FILTER" + case 60: // "FOLLOWING" + case 61: // "FOREIGN" + case 62: // "GENERATED" + case 63: // "GLOB" + case 64: // "IF" + case 65: // "IGNORE" + case 66: // "IMMEDIATE" + case 67: // "IN" + case 68: // "INDEX" + case 69: // "INITIALLY" + case 70: // "INSERT" + case 71: // "IS" + case 72: // "ISNULL" + case 73: // "KEY" + case 74: // "LIKE" + case 75: // "MATCH" + case 76: // "NO" + case 77: // "NOT" + case 78: // "NOTNULL" + case 79: // "NULL" + case 80: // "ON" + case 81: // "OR" + case 82: // "OVER" + case 83: // "PARTITION" + case 84: // "PRECEDING" + case 85: // "PRIMARY" + case 86: // "RAISE" + case 87: // "RANGE" + case 88: // "REFERENCES" + case 89: // "REGEXP" + case 90: // "REPLACE" + case 91: // "RESTRICT" + case 92: // "ROLLBACK" + case 93: // "ROWID" + case 94: // "ROWS" + case 95: // "SELECT" + case 96: // "SET" + case 97: // "STORED" + case 98: // "TABLE" + case 99: // "TEMP" + case 100: // "TEMPORARY" + case 101: // "THEN" + case 102: // "TRUE" + case 103: // "UNBOUNDED" + case 104: // "UNIQUE" + case 105: // "UPDATE" + case 106: // "USING" + case 107: // "VIRTUAL" + case 108: // "WHEN" + case 109: // "WHERE" + case 110: // "WITHOUT" + case 111: // "identifier" + case 112: // "numeric" + case 113: // "string literal" + case 114: // "quoted literal" + case 115: // "blob literal" + case 116: // "bind parameter" + case 120: // literalvalue + case 121: // id + case 122: // allowed_keywords_as_identifier + case 123: // tableid + case 124: // columnid + case 125: // signednumber + case 126: // signednumber_or_numeric + case 127: // typename_namelist + case 128: // type_name + case 129: // unary_expr + case 130: // binary_expr + case 131: // like_expr + case 132: // exprlist_expr + case 133: // function_expr + case 134: // isnull_expr + case 135: // between_expr + case 136: // in_expr + case 137: // whenthenlist_expr + case 138: // case_expr + case 139: // raise_expr + case 140: // expr + case 141: // select_stmt + case 143: // optional_sort_order + case 145: // optional_where + case 146: // tableid_with_uninteresting_schema + case 150: // optional_exprlist_with_paren + case 154: // optional_conflictclause + case 155: // optional_typename + case 156: // optional_storage_identifier + case 162: // optional_constraintname + case 165: // fk_clause_part + case 166: // fk_clause_part_list + case 167: // optional_fk_clause + value.template destroy< std::string > (); + break; + + case 161: // columndef_list + value.template destroy< std::vector > (); + break; + + default: + break; + } + + Base::clear (); + } + + /// Whether empty. + bool empty () const YY_NOEXCEPT; + + /// Destructive move, \a s is emptied into this. + void move (basic_symbol& s); + + /// The semantic value. + semantic_type value; + + /// The location. + location_type location; + + private: +#if YY_CPLUSPLUS < 201103L + /// Assignment operator. + basic_symbol& operator= (const basic_symbol& that); +#endif + }; + + /// Type access provider for token (enum) based symbols. + struct by_type + { + /// Default constructor. + by_type (); + +#if 201103L <= YY_CPLUSPLUS + /// Move constructor. + by_type (by_type&& that); +#endif + + /// Copy constructor. + by_type (const by_type& that); + + /// The symbol type as needed by the constructor. + typedef token_type kind_type; + + /// Constructor from (external) token numbers. + by_type (kind_type t); + + /// Record that this symbol is empty. + void clear (); + + /// Steal the symbol type from \a that. + void move (by_type& that); + + /// The (internal) type number (corresponding to \a type). + /// \a empty when empty. + symbol_number_type type_get () const YY_NOEXCEPT; + + /// The symbol type. + /// \a empty_symbol when empty. + /// An int, not token_number_type, to be able to store empty_symbol. + int type; + }; + + /// "External" symbols: returned by the scanner. + struct symbol_type : basic_symbol + { + /// Superclass. + typedef basic_symbol super_type; + + /// Empty symbol. + symbol_type () {} + + /// Constructor for valueless symbols, and symbols from each type. +#if 201103L <= YY_CPLUSPLUS + symbol_type (int tok, location_type l) + : super_type(token_type (tok), std::move (l)) + { + YY_ASSERT (tok == token::TOK_EOF || tok == token::TOK_LPAREN || tok == token::TOK_RPAREN || tok == token::TOK_DOT || tok == token::TOK_COMMA || tok == token::TOK_SEMI || tok == token::TOK_PLUS || tok == token::TOK_MINUS || tok == token::TOK_STAR || tok == token::TOK_SLASH || tok == token::TOK_TILDE || tok == token::TOK_AMPERSAND || tok == token::TOK_PERCENT || tok == token::TOK_BITOR || tok == token::TOK_OROP || tok == token::TOK_EQUAL || tok == token::TOK_EQUAL2 || tok == token::TOK_GREATER || tok == token::TOK_GREATEREQUAL || tok == token::TOK_LOWER || tok == token::TOK_LOWEREQUAL || tok == token::TOK_UNEQUAL || tok == token::TOK_UNEQUAL2 || tok == token::TOK_BITWISELEFT || tok == token::TOK_BITWISERIGHT); + } +#else + symbol_type (int tok, const location_type& l) + : super_type(token_type (tok), l) + { + YY_ASSERT (tok == token::TOK_EOF || tok == token::TOK_LPAREN || tok == token::TOK_RPAREN || tok == token::TOK_DOT || tok == token::TOK_COMMA || tok == token::TOK_SEMI || tok == token::TOK_PLUS || tok == token::TOK_MINUS || tok == token::TOK_STAR || tok == token::TOK_SLASH || tok == token::TOK_TILDE || tok == token::TOK_AMPERSAND || tok == token::TOK_PERCENT || tok == token::TOK_BITOR || tok == token::TOK_OROP || tok == token::TOK_EQUAL || tok == token::TOK_EQUAL2 || tok == token::TOK_GREATER || tok == token::TOK_GREATEREQUAL || tok == token::TOK_LOWER || tok == token::TOK_LOWEREQUAL || tok == token::TOK_UNEQUAL || tok == token::TOK_UNEQUAL2 || tok == token::TOK_BITWISELEFT || tok == token::TOK_BITWISERIGHT); + } +#endif +#if 201103L <= YY_CPLUSPLUS + symbol_type (int tok, std::string v, location_type l) + : super_type(token_type (tok), std::move (v), std::move (l)) + { + YY_ASSERT (tok == token::TOK_ABORT || tok == token::TOK_ACTION || tok == token::TOK_ALWAYS || tok == token::TOK_AND || tok == token::TOK_AND_BETWEEN || tok == token::TOK_AS || tok == token::TOK_ASC || tok == token::TOK_AUTOINCREMENT || tok == token::TOK_BETWEEN || tok == token::TOK_CASCADE || tok == token::TOK_CASE || tok == token::TOK_CAST || tok == token::TOK_CHECK || tok == token::TOK_COLLATE || tok == token::TOK_CONFLICT || tok == token::TOK_CONSTRAINT || tok == token::TOK_CREATE || tok == token::TOK_CURRENT_DATE || tok == token::TOK_CURRENT_TIME || tok == token::TOK_CURRENT_TIMESTAMP || tok == token::TOK_DEFAULT || tok == token::TOK_DEFERRABLE || tok == token::TOK_DEFERRED || tok == token::TOK_DELETE || tok == token::TOK_DESC || tok == token::TOK_DISTINCT || tok == token::TOK_ELSE || tok == token::TOK_END || tok == token::TOK_ESCAPE || tok == token::TOK_EXISTS || tok == token::TOK_FAIL || tok == token::TOK_FALSE || tok == token::TOK_FILTER || tok == token::TOK_FOLLOWING || tok == token::TOK_FOREIGN || tok == token::TOK_GENERATED || tok == token::TOK_GLOB || tok == token::TOK_IF || tok == token::TOK_IGNORE || tok == token::TOK_IMMEDIATE || tok == token::TOK_IN || tok == token::TOK_INDEX || tok == token::TOK_INITIALLY || tok == token::TOK_INSERT || tok == token::TOK_IS || tok == token::TOK_ISNULL || tok == token::TOK_KEY || tok == token::TOK_LIKE || tok == token::TOK_MATCH || tok == token::TOK_NO || tok == token::TOK_NOT || tok == token::TOK_NOTNULL || tok == token::TOK_NULL || tok == token::TOK_ON || tok == token::TOK_OR || tok == token::TOK_OVER || tok == token::TOK_PARTITION || tok == token::TOK_PRECEDING || tok == token::TOK_PRIMARY || tok == token::TOK_RAISE || tok == token::TOK_RANGE || tok == token::TOK_REFERENCES || tok == token::TOK_REGEXP || tok == token::TOK_REPLACE || tok == token::TOK_RESTRICT || tok == token::TOK_ROLLBACK || tok == token::TOK_ROWID || tok == token::TOK_ROWS || tok == token::TOK_SELECT || tok == token::TOK_SET || tok == token::TOK_STORED || tok == token::TOK_TABLE || tok == token::TOK_TEMP || tok == token::TOK_TEMPORARY || tok == token::TOK_THEN || tok == token::TOK_TRUE || tok == token::TOK_UNBOUNDED || tok == token::TOK_UNIQUE || tok == token::TOK_UPDATE || tok == token::TOK_USING || tok == token::TOK_VIRTUAL || tok == token::TOK_WHEN || tok == token::TOK_WHERE || tok == token::TOK_WITHOUT || tok == token::TOK_IDENTIFIER || tok == token::TOK_NUMERIC || tok == token::TOK_STRINGLITERAL || tok == token::TOK_QUOTEDLITERAL || tok == token::TOK_BLOBLITERAL || tok == token::TOK_BINDPARAMETER); + } +#else + symbol_type (int tok, const std::string& v, const location_type& l) + : super_type(token_type (tok), v, l) + { + YY_ASSERT (tok == token::TOK_ABORT || tok == token::TOK_ACTION || tok == token::TOK_ALWAYS || tok == token::TOK_AND || tok == token::TOK_AND_BETWEEN || tok == token::TOK_AS || tok == token::TOK_ASC || tok == token::TOK_AUTOINCREMENT || tok == token::TOK_BETWEEN || tok == token::TOK_CASCADE || tok == token::TOK_CASE || tok == token::TOK_CAST || tok == token::TOK_CHECK || tok == token::TOK_COLLATE || tok == token::TOK_CONFLICT || tok == token::TOK_CONSTRAINT || tok == token::TOK_CREATE || tok == token::TOK_CURRENT_DATE || tok == token::TOK_CURRENT_TIME || tok == token::TOK_CURRENT_TIMESTAMP || tok == token::TOK_DEFAULT || tok == token::TOK_DEFERRABLE || tok == token::TOK_DEFERRED || tok == token::TOK_DELETE || tok == token::TOK_DESC || tok == token::TOK_DISTINCT || tok == token::TOK_ELSE || tok == token::TOK_END || tok == token::TOK_ESCAPE || tok == token::TOK_EXISTS || tok == token::TOK_FAIL || tok == token::TOK_FALSE || tok == token::TOK_FILTER || tok == token::TOK_FOLLOWING || tok == token::TOK_FOREIGN || tok == token::TOK_GENERATED || tok == token::TOK_GLOB || tok == token::TOK_IF || tok == token::TOK_IGNORE || tok == token::TOK_IMMEDIATE || tok == token::TOK_IN || tok == token::TOK_INDEX || tok == token::TOK_INITIALLY || tok == token::TOK_INSERT || tok == token::TOK_IS || tok == token::TOK_ISNULL || tok == token::TOK_KEY || tok == token::TOK_LIKE || tok == token::TOK_MATCH || tok == token::TOK_NO || tok == token::TOK_NOT || tok == token::TOK_NOTNULL || tok == token::TOK_NULL || tok == token::TOK_ON || tok == token::TOK_OR || tok == token::TOK_OVER || tok == token::TOK_PARTITION || tok == token::TOK_PRECEDING || tok == token::TOK_PRIMARY || tok == token::TOK_RAISE || tok == token::TOK_RANGE || tok == token::TOK_REFERENCES || tok == token::TOK_REGEXP || tok == token::TOK_REPLACE || tok == token::TOK_RESTRICT || tok == token::TOK_ROLLBACK || tok == token::TOK_ROWID || tok == token::TOK_ROWS || tok == token::TOK_SELECT || tok == token::TOK_SET || tok == token::TOK_STORED || tok == token::TOK_TABLE || tok == token::TOK_TEMP || tok == token::TOK_TEMPORARY || tok == token::TOK_THEN || tok == token::TOK_TRUE || tok == token::TOK_UNBOUNDED || tok == token::TOK_UNIQUE || tok == token::TOK_UPDATE || tok == token::TOK_USING || tok == token::TOK_VIRTUAL || tok == token::TOK_WHEN || tok == token::TOK_WHERE || tok == token::TOK_WITHOUT || tok == token::TOK_IDENTIFIER || tok == token::TOK_NUMERIC || tok == token::TOK_STRINGLITERAL || tok == token::TOK_QUOTEDLITERAL || tok == token::TOK_BLOBLITERAL || tok == token::TOK_BINDPARAMETER); + } +#endif + }; + + /// Build a parser object. + parser (yyscan_t yyscanner_yyarg, ParserDriver& drv_yyarg); + virtual ~parser (); + + /// Parse. An alias for parse (). + /// \returns 0 iff parsing succeeded. + int operator() (); + + /// Parse. + /// \returns 0 iff parsing succeeded. + virtual int parse (); + +#if YYDEBUG + /// The current debugging stream. + std::ostream& debug_stream () const YY_ATTRIBUTE_PURE; + /// Set the current debugging stream. + void set_debug_stream (std::ostream &); + + /// Type for debugging levels. + typedef int debug_level_type; + /// The current debugging level. + debug_level_type debug_level () const YY_ATTRIBUTE_PURE; + /// Set the current debugging level. + void set_debug_level (debug_level_type l); +#endif + + /// Report a syntax error. + /// \param loc where the syntax error is found. + /// \param msg a description of the syntax error. + virtual void error (const location_type& loc, const std::string& msg); + + /// Report a syntax error. + void error (const syntax_error& err); + + // Implementation of make_symbol for each symbol type. +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_EOF (location_type l) + { + return symbol_type (token::TOK_EOF, std::move (l)); + } +#else + static + symbol_type + make_EOF (const location_type& l) + { + return symbol_type (token::TOK_EOF, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_LPAREN (location_type l) + { + return symbol_type (token::TOK_LPAREN, std::move (l)); + } +#else + static + symbol_type + make_LPAREN (const location_type& l) + { + return symbol_type (token::TOK_LPAREN, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_RPAREN (location_type l) + { + return symbol_type (token::TOK_RPAREN, std::move (l)); + } +#else + static + symbol_type + make_RPAREN (const location_type& l) + { + return symbol_type (token::TOK_RPAREN, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_DOT (location_type l) + { + return symbol_type (token::TOK_DOT, std::move (l)); + } +#else + static + symbol_type + make_DOT (const location_type& l) + { + return symbol_type (token::TOK_DOT, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_COMMA (location_type l) + { + return symbol_type (token::TOK_COMMA, std::move (l)); + } +#else + static + symbol_type + make_COMMA (const location_type& l) + { + return symbol_type (token::TOK_COMMA, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_SEMI (location_type l) + { + return symbol_type (token::TOK_SEMI, std::move (l)); + } +#else + static + symbol_type + make_SEMI (const location_type& l) + { + return symbol_type (token::TOK_SEMI, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_PLUS (location_type l) + { + return symbol_type (token::TOK_PLUS, std::move (l)); + } +#else + static + symbol_type + make_PLUS (const location_type& l) + { + return symbol_type (token::TOK_PLUS, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_MINUS (location_type l) + { + return symbol_type (token::TOK_MINUS, std::move (l)); + } +#else + static + symbol_type + make_MINUS (const location_type& l) + { + return symbol_type (token::TOK_MINUS, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_STAR (location_type l) + { + return symbol_type (token::TOK_STAR, std::move (l)); + } +#else + static + symbol_type + make_STAR (const location_type& l) + { + return symbol_type (token::TOK_STAR, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_SLASH (location_type l) + { + return symbol_type (token::TOK_SLASH, std::move (l)); + } +#else + static + symbol_type + make_SLASH (const location_type& l) + { + return symbol_type (token::TOK_SLASH, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_TILDE (location_type l) + { + return symbol_type (token::TOK_TILDE, std::move (l)); + } +#else + static + symbol_type + make_TILDE (const location_type& l) + { + return symbol_type (token::TOK_TILDE, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_AMPERSAND (location_type l) + { + return symbol_type (token::TOK_AMPERSAND, std::move (l)); + } +#else + static + symbol_type + make_AMPERSAND (const location_type& l) + { + return symbol_type (token::TOK_AMPERSAND, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_PERCENT (location_type l) + { + return symbol_type (token::TOK_PERCENT, std::move (l)); + } +#else + static + symbol_type + make_PERCENT (const location_type& l) + { + return symbol_type (token::TOK_PERCENT, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_BITOR (location_type l) + { + return symbol_type (token::TOK_BITOR, std::move (l)); + } +#else + static + symbol_type + make_BITOR (const location_type& l) + { + return symbol_type (token::TOK_BITOR, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_OROP (location_type l) + { + return symbol_type (token::TOK_OROP, std::move (l)); + } +#else + static + symbol_type + make_OROP (const location_type& l) + { + return symbol_type (token::TOK_OROP, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_EQUAL (location_type l) + { + return symbol_type (token::TOK_EQUAL, std::move (l)); + } +#else + static + symbol_type + make_EQUAL (const location_type& l) + { + return symbol_type (token::TOK_EQUAL, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_EQUAL2 (location_type l) + { + return symbol_type (token::TOK_EQUAL2, std::move (l)); + } +#else + static + symbol_type + make_EQUAL2 (const location_type& l) + { + return symbol_type (token::TOK_EQUAL2, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_GREATER (location_type l) + { + return symbol_type (token::TOK_GREATER, std::move (l)); + } +#else + static + symbol_type + make_GREATER (const location_type& l) + { + return symbol_type (token::TOK_GREATER, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_GREATEREQUAL (location_type l) + { + return symbol_type (token::TOK_GREATEREQUAL, std::move (l)); + } +#else + static + symbol_type + make_GREATEREQUAL (const location_type& l) + { + return symbol_type (token::TOK_GREATEREQUAL, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_LOWER (location_type l) + { + return symbol_type (token::TOK_LOWER, std::move (l)); + } +#else + static + symbol_type + make_LOWER (const location_type& l) + { + return symbol_type (token::TOK_LOWER, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_LOWEREQUAL (location_type l) + { + return symbol_type (token::TOK_LOWEREQUAL, std::move (l)); + } +#else + static + symbol_type + make_LOWEREQUAL (const location_type& l) + { + return symbol_type (token::TOK_LOWEREQUAL, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_UNEQUAL (location_type l) + { + return symbol_type (token::TOK_UNEQUAL, std::move (l)); + } +#else + static + symbol_type + make_UNEQUAL (const location_type& l) + { + return symbol_type (token::TOK_UNEQUAL, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_UNEQUAL2 (location_type l) + { + return symbol_type (token::TOK_UNEQUAL2, std::move (l)); + } +#else + static + symbol_type + make_UNEQUAL2 (const location_type& l) + { + return symbol_type (token::TOK_UNEQUAL2, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_BITWISELEFT (location_type l) + { + return symbol_type (token::TOK_BITWISELEFT, std::move (l)); + } +#else + static + symbol_type + make_BITWISELEFT (const location_type& l) + { + return symbol_type (token::TOK_BITWISELEFT, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_BITWISERIGHT (location_type l) + { + return symbol_type (token::TOK_BITWISERIGHT, std::move (l)); + } +#else + static + symbol_type + make_BITWISERIGHT (const location_type& l) + { + return symbol_type (token::TOK_BITWISERIGHT, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_ABORT (std::string v, location_type l) + { + return symbol_type (token::TOK_ABORT, std::move (v), std::move (l)); + } +#else + static + symbol_type + make_ABORT (const std::string& v, const location_type& l) + { + return symbol_type (token::TOK_ABORT, v, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_ACTION (std::string v, location_type l) + { + return symbol_type (token::TOK_ACTION, std::move (v), std::move (l)); + } +#else + static + symbol_type + make_ACTION (const std::string& v, const location_type& l) + { + return symbol_type (token::TOK_ACTION, v, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_ALWAYS (std::string v, location_type l) + { + return symbol_type (token::TOK_ALWAYS, std::move (v), std::move (l)); + } +#else + static + symbol_type + make_ALWAYS (const std::string& v, const location_type& l) + { + return symbol_type (token::TOK_ALWAYS, v, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_AND (std::string v, location_type l) + { + return symbol_type (token::TOK_AND, std::move (v), std::move (l)); + } +#else + static + symbol_type + make_AND (const std::string& v, const location_type& l) + { + return symbol_type (token::TOK_AND, v, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_AND_BETWEEN (std::string v, location_type l) + { + return symbol_type (token::TOK_AND_BETWEEN, std::move (v), std::move (l)); + } +#else + static + symbol_type + make_AND_BETWEEN (const std::string& v, const location_type& l) + { + return symbol_type (token::TOK_AND_BETWEEN, v, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_AS (std::string v, location_type l) + { + return symbol_type (token::TOK_AS, std::move (v), std::move (l)); + } +#else + static + symbol_type + make_AS (const std::string& v, const location_type& l) + { + return symbol_type (token::TOK_AS, v, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_ASC (std::string v, location_type l) + { + return symbol_type (token::TOK_ASC, std::move (v), std::move (l)); + } +#else + static + symbol_type + make_ASC (const std::string& v, const location_type& l) + { + return symbol_type (token::TOK_ASC, v, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_AUTOINCREMENT (std::string v, location_type l) + { + return symbol_type (token::TOK_AUTOINCREMENT, std::move (v), std::move (l)); + } +#else + static + symbol_type + make_AUTOINCREMENT (const std::string& v, const location_type& l) + { + return symbol_type (token::TOK_AUTOINCREMENT, v, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_BETWEEN (std::string v, location_type l) + { + return symbol_type (token::TOK_BETWEEN, std::move (v), std::move (l)); + } +#else + static + symbol_type + make_BETWEEN (const std::string& v, const location_type& l) + { + return symbol_type (token::TOK_BETWEEN, v, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_CASCADE (std::string v, location_type l) + { + return symbol_type (token::TOK_CASCADE, std::move (v), std::move (l)); + } +#else + static + symbol_type + make_CASCADE (const std::string& v, const location_type& l) + { + return symbol_type (token::TOK_CASCADE, v, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_CASE (std::string v, location_type l) + { + return symbol_type (token::TOK_CASE, std::move (v), std::move (l)); + } +#else + static + symbol_type + make_CASE (const std::string& v, const location_type& l) + { + return symbol_type (token::TOK_CASE, v, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_CAST (std::string v, location_type l) + { + return symbol_type (token::TOK_CAST, std::move (v), std::move (l)); + } +#else + static + symbol_type + make_CAST (const std::string& v, const location_type& l) + { + return symbol_type (token::TOK_CAST, v, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_CHECK (std::string v, location_type l) + { + return symbol_type (token::TOK_CHECK, std::move (v), std::move (l)); + } +#else + static + symbol_type + make_CHECK (const std::string& v, const location_type& l) + { + return symbol_type (token::TOK_CHECK, v, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_COLLATE (std::string v, location_type l) + { + return symbol_type (token::TOK_COLLATE, std::move (v), std::move (l)); + } +#else + static + symbol_type + make_COLLATE (const std::string& v, const location_type& l) + { + return symbol_type (token::TOK_COLLATE, v, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_CONFLICT (std::string v, location_type l) + { + return symbol_type (token::TOK_CONFLICT, std::move (v), std::move (l)); + } +#else + static + symbol_type + make_CONFLICT (const std::string& v, const location_type& l) + { + return symbol_type (token::TOK_CONFLICT, v, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_CONSTRAINT (std::string v, location_type l) + { + return symbol_type (token::TOK_CONSTRAINT, std::move (v), std::move (l)); + } +#else + static + symbol_type + make_CONSTRAINT (const std::string& v, const location_type& l) + { + return symbol_type (token::TOK_CONSTRAINT, v, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_CREATE (std::string v, location_type l) + { + return symbol_type (token::TOK_CREATE, std::move (v), std::move (l)); + } +#else + static + symbol_type + make_CREATE (const std::string& v, const location_type& l) + { + return symbol_type (token::TOK_CREATE, v, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_CURRENT_DATE (std::string v, location_type l) + { + return symbol_type (token::TOK_CURRENT_DATE, std::move (v), std::move (l)); + } +#else + static + symbol_type + make_CURRENT_DATE (const std::string& v, const location_type& l) + { + return symbol_type (token::TOK_CURRENT_DATE, v, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_CURRENT_TIME (std::string v, location_type l) + { + return symbol_type (token::TOK_CURRENT_TIME, std::move (v), std::move (l)); + } +#else + static + symbol_type + make_CURRENT_TIME (const std::string& v, const location_type& l) + { + return symbol_type (token::TOK_CURRENT_TIME, v, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_CURRENT_TIMESTAMP (std::string v, location_type l) + { + return symbol_type (token::TOK_CURRENT_TIMESTAMP, std::move (v), std::move (l)); + } +#else + static + symbol_type + make_CURRENT_TIMESTAMP (const std::string& v, const location_type& l) + { + return symbol_type (token::TOK_CURRENT_TIMESTAMP, v, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_DEFAULT (std::string v, location_type l) + { + return symbol_type (token::TOK_DEFAULT, std::move (v), std::move (l)); + } +#else + static + symbol_type + make_DEFAULT (const std::string& v, const location_type& l) + { + return symbol_type (token::TOK_DEFAULT, v, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_DEFERRABLE (std::string v, location_type l) + { + return symbol_type (token::TOK_DEFERRABLE, std::move (v), std::move (l)); + } +#else + static + symbol_type + make_DEFERRABLE (const std::string& v, const location_type& l) + { + return symbol_type (token::TOK_DEFERRABLE, v, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_DEFERRED (std::string v, location_type l) + { + return symbol_type (token::TOK_DEFERRED, std::move (v), std::move (l)); + } +#else + static + symbol_type + make_DEFERRED (const std::string& v, const location_type& l) + { + return symbol_type (token::TOK_DEFERRED, v, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_DELETE (std::string v, location_type l) + { + return symbol_type (token::TOK_DELETE, std::move (v), std::move (l)); + } +#else + static + symbol_type + make_DELETE (const std::string& v, const location_type& l) + { + return symbol_type (token::TOK_DELETE, v, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_DESC (std::string v, location_type l) + { + return symbol_type (token::TOK_DESC, std::move (v), std::move (l)); + } +#else + static + symbol_type + make_DESC (const std::string& v, const location_type& l) + { + return symbol_type (token::TOK_DESC, v, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_DISTINCT (std::string v, location_type l) + { + return symbol_type (token::TOK_DISTINCT, std::move (v), std::move (l)); + } +#else + static + symbol_type + make_DISTINCT (const std::string& v, const location_type& l) + { + return symbol_type (token::TOK_DISTINCT, v, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_ELSE (std::string v, location_type l) + { + return symbol_type (token::TOK_ELSE, std::move (v), std::move (l)); + } +#else + static + symbol_type + make_ELSE (const std::string& v, const location_type& l) + { + return symbol_type (token::TOK_ELSE, v, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_END (std::string v, location_type l) + { + return symbol_type (token::TOK_END, std::move (v), std::move (l)); + } +#else + static + symbol_type + make_END (const std::string& v, const location_type& l) + { + return symbol_type (token::TOK_END, v, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_ESCAPE (std::string v, location_type l) + { + return symbol_type (token::TOK_ESCAPE, std::move (v), std::move (l)); + } +#else + static + symbol_type + make_ESCAPE (const std::string& v, const location_type& l) + { + return symbol_type (token::TOK_ESCAPE, v, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_EXISTS (std::string v, location_type l) + { + return symbol_type (token::TOK_EXISTS, std::move (v), std::move (l)); + } +#else + static + symbol_type + make_EXISTS (const std::string& v, const location_type& l) + { + return symbol_type (token::TOK_EXISTS, v, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_FAIL (std::string v, location_type l) + { + return symbol_type (token::TOK_FAIL, std::move (v), std::move (l)); + } +#else + static + symbol_type + make_FAIL (const std::string& v, const location_type& l) + { + return symbol_type (token::TOK_FAIL, v, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_FALSE (std::string v, location_type l) + { + return symbol_type (token::TOK_FALSE, std::move (v), std::move (l)); + } +#else + static + symbol_type + make_FALSE (const std::string& v, const location_type& l) + { + return symbol_type (token::TOK_FALSE, v, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_FILTER (std::string v, location_type l) + { + return symbol_type (token::TOK_FILTER, std::move (v), std::move (l)); + } +#else + static + symbol_type + make_FILTER (const std::string& v, const location_type& l) + { + return symbol_type (token::TOK_FILTER, v, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_FOLLOWING (std::string v, location_type l) + { + return symbol_type (token::TOK_FOLLOWING, std::move (v), std::move (l)); + } +#else + static + symbol_type + make_FOLLOWING (const std::string& v, const location_type& l) + { + return symbol_type (token::TOK_FOLLOWING, v, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_FOREIGN (std::string v, location_type l) + { + return symbol_type (token::TOK_FOREIGN, std::move (v), std::move (l)); + } +#else + static + symbol_type + make_FOREIGN (const std::string& v, const location_type& l) + { + return symbol_type (token::TOK_FOREIGN, v, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_GENERATED (std::string v, location_type l) + { + return symbol_type (token::TOK_GENERATED, std::move (v), std::move (l)); + } +#else + static + symbol_type + make_GENERATED (const std::string& v, const location_type& l) + { + return symbol_type (token::TOK_GENERATED, v, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_GLOB (std::string v, location_type l) + { + return symbol_type (token::TOK_GLOB, std::move (v), std::move (l)); + } +#else + static + symbol_type + make_GLOB (const std::string& v, const location_type& l) + { + return symbol_type (token::TOK_GLOB, v, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_IF (std::string v, location_type l) + { + return symbol_type (token::TOK_IF, std::move (v), std::move (l)); + } +#else + static + symbol_type + make_IF (const std::string& v, const location_type& l) + { + return symbol_type (token::TOK_IF, v, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_IGNORE (std::string v, location_type l) + { + return symbol_type (token::TOK_IGNORE, std::move (v), std::move (l)); + } +#else + static + symbol_type + make_IGNORE (const std::string& v, const location_type& l) + { + return symbol_type (token::TOK_IGNORE, v, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_IMMEDIATE (std::string v, location_type l) + { + return symbol_type (token::TOK_IMMEDIATE, std::move (v), std::move (l)); + } +#else + static + symbol_type + make_IMMEDIATE (const std::string& v, const location_type& l) + { + return symbol_type (token::TOK_IMMEDIATE, v, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_IN (std::string v, location_type l) + { + return symbol_type (token::TOK_IN, std::move (v), std::move (l)); + } +#else + static + symbol_type + make_IN (const std::string& v, const location_type& l) + { + return symbol_type (token::TOK_IN, v, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_INDEX (std::string v, location_type l) + { + return symbol_type (token::TOK_INDEX, std::move (v), std::move (l)); + } +#else + static + symbol_type + make_INDEX (const std::string& v, const location_type& l) + { + return symbol_type (token::TOK_INDEX, v, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_INITIALLY (std::string v, location_type l) + { + return symbol_type (token::TOK_INITIALLY, std::move (v), std::move (l)); + } +#else + static + symbol_type + make_INITIALLY (const std::string& v, const location_type& l) + { + return symbol_type (token::TOK_INITIALLY, v, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_INSERT (std::string v, location_type l) + { + return symbol_type (token::TOK_INSERT, std::move (v), std::move (l)); + } +#else + static + symbol_type + make_INSERT (const std::string& v, const location_type& l) + { + return symbol_type (token::TOK_INSERT, v, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_IS (std::string v, location_type l) + { + return symbol_type (token::TOK_IS, std::move (v), std::move (l)); + } +#else + static + symbol_type + make_IS (const std::string& v, const location_type& l) + { + return symbol_type (token::TOK_IS, v, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_ISNULL (std::string v, location_type l) + { + return symbol_type (token::TOK_ISNULL, std::move (v), std::move (l)); + } +#else + static + symbol_type + make_ISNULL (const std::string& v, const location_type& l) + { + return symbol_type (token::TOK_ISNULL, v, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_KEY (std::string v, location_type l) + { + return symbol_type (token::TOK_KEY, std::move (v), std::move (l)); + } +#else + static + symbol_type + make_KEY (const std::string& v, const location_type& l) + { + return symbol_type (token::TOK_KEY, v, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_LIKE (std::string v, location_type l) + { + return symbol_type (token::TOK_LIKE, std::move (v), std::move (l)); + } +#else + static + symbol_type + make_LIKE (const std::string& v, const location_type& l) + { + return symbol_type (token::TOK_LIKE, v, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_MATCH (std::string v, location_type l) + { + return symbol_type (token::TOK_MATCH, std::move (v), std::move (l)); + } +#else + static + symbol_type + make_MATCH (const std::string& v, const location_type& l) + { + return symbol_type (token::TOK_MATCH, v, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_NO (std::string v, location_type l) + { + return symbol_type (token::TOK_NO, std::move (v), std::move (l)); + } +#else + static + symbol_type + make_NO (const std::string& v, const location_type& l) + { + return symbol_type (token::TOK_NO, v, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_NOT (std::string v, location_type l) + { + return symbol_type (token::TOK_NOT, std::move (v), std::move (l)); + } +#else + static + symbol_type + make_NOT (const std::string& v, const location_type& l) + { + return symbol_type (token::TOK_NOT, v, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_NOTNULL (std::string v, location_type l) + { + return symbol_type (token::TOK_NOTNULL, std::move (v), std::move (l)); + } +#else + static + symbol_type + make_NOTNULL (const std::string& v, const location_type& l) + { + return symbol_type (token::TOK_NOTNULL, v, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_NULL (std::string v, location_type l) + { + return symbol_type (token::TOK_NULL, std::move (v), std::move (l)); + } +#else + static + symbol_type + make_NULL (const std::string& v, const location_type& l) + { + return symbol_type (token::TOK_NULL, v, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_ON (std::string v, location_type l) + { + return symbol_type (token::TOK_ON, std::move (v), std::move (l)); + } +#else + static + symbol_type + make_ON (const std::string& v, const location_type& l) + { + return symbol_type (token::TOK_ON, v, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_OR (std::string v, location_type l) + { + return symbol_type (token::TOK_OR, std::move (v), std::move (l)); + } +#else + static + symbol_type + make_OR (const std::string& v, const location_type& l) + { + return symbol_type (token::TOK_OR, v, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_OVER (std::string v, location_type l) + { + return symbol_type (token::TOK_OVER, std::move (v), std::move (l)); + } +#else + static + symbol_type + make_OVER (const std::string& v, const location_type& l) + { + return symbol_type (token::TOK_OVER, v, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_PARTITION (std::string v, location_type l) + { + return symbol_type (token::TOK_PARTITION, std::move (v), std::move (l)); + } +#else + static + symbol_type + make_PARTITION (const std::string& v, const location_type& l) + { + return symbol_type (token::TOK_PARTITION, v, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_PRECEDING (std::string v, location_type l) + { + return symbol_type (token::TOK_PRECEDING, std::move (v), std::move (l)); + } +#else + static + symbol_type + make_PRECEDING (const std::string& v, const location_type& l) + { + return symbol_type (token::TOK_PRECEDING, v, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_PRIMARY (std::string v, location_type l) + { + return symbol_type (token::TOK_PRIMARY, std::move (v), std::move (l)); + } +#else + static + symbol_type + make_PRIMARY (const std::string& v, const location_type& l) + { + return symbol_type (token::TOK_PRIMARY, v, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_RAISE (std::string v, location_type l) + { + return symbol_type (token::TOK_RAISE, std::move (v), std::move (l)); + } +#else + static + symbol_type + make_RAISE (const std::string& v, const location_type& l) + { + return symbol_type (token::TOK_RAISE, v, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_RANGE (std::string v, location_type l) + { + return symbol_type (token::TOK_RANGE, std::move (v), std::move (l)); + } +#else + static + symbol_type + make_RANGE (const std::string& v, const location_type& l) + { + return symbol_type (token::TOK_RANGE, v, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_REFERENCES (std::string v, location_type l) + { + return symbol_type (token::TOK_REFERENCES, std::move (v), std::move (l)); + } +#else + static + symbol_type + make_REFERENCES (const std::string& v, const location_type& l) + { + return symbol_type (token::TOK_REFERENCES, v, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_REGEXP (std::string v, location_type l) + { + return symbol_type (token::TOK_REGEXP, std::move (v), std::move (l)); + } +#else + static + symbol_type + make_REGEXP (const std::string& v, const location_type& l) + { + return symbol_type (token::TOK_REGEXP, v, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_REPLACE (std::string v, location_type l) + { + return symbol_type (token::TOK_REPLACE, std::move (v), std::move (l)); + } +#else + static + symbol_type + make_REPLACE (const std::string& v, const location_type& l) + { + return symbol_type (token::TOK_REPLACE, v, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_RESTRICT (std::string v, location_type l) + { + return symbol_type (token::TOK_RESTRICT, std::move (v), std::move (l)); + } +#else + static + symbol_type + make_RESTRICT (const std::string& v, const location_type& l) + { + return symbol_type (token::TOK_RESTRICT, v, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_ROLLBACK (std::string v, location_type l) + { + return symbol_type (token::TOK_ROLLBACK, std::move (v), std::move (l)); + } +#else + static + symbol_type + make_ROLLBACK (const std::string& v, const location_type& l) + { + return symbol_type (token::TOK_ROLLBACK, v, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_ROWID (std::string v, location_type l) + { + return symbol_type (token::TOK_ROWID, std::move (v), std::move (l)); + } +#else + static + symbol_type + make_ROWID (const std::string& v, const location_type& l) + { + return symbol_type (token::TOK_ROWID, v, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_ROWS (std::string v, location_type l) + { + return symbol_type (token::TOK_ROWS, std::move (v), std::move (l)); + } +#else + static + symbol_type + make_ROWS (const std::string& v, const location_type& l) + { + return symbol_type (token::TOK_ROWS, v, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_SELECT (std::string v, location_type l) + { + return symbol_type (token::TOK_SELECT, std::move (v), std::move (l)); + } +#else + static + symbol_type + make_SELECT (const std::string& v, const location_type& l) + { + return symbol_type (token::TOK_SELECT, v, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_SET (std::string v, location_type l) + { + return symbol_type (token::TOK_SET, std::move (v), std::move (l)); + } +#else + static + symbol_type + make_SET (const std::string& v, const location_type& l) + { + return symbol_type (token::TOK_SET, v, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_STORED (std::string v, location_type l) + { + return symbol_type (token::TOK_STORED, std::move (v), std::move (l)); + } +#else + static + symbol_type + make_STORED (const std::string& v, const location_type& l) + { + return symbol_type (token::TOK_STORED, v, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_TABLE (std::string v, location_type l) + { + return symbol_type (token::TOK_TABLE, std::move (v), std::move (l)); + } +#else + static + symbol_type + make_TABLE (const std::string& v, const location_type& l) + { + return symbol_type (token::TOK_TABLE, v, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_TEMP (std::string v, location_type l) + { + return symbol_type (token::TOK_TEMP, std::move (v), std::move (l)); + } +#else + static + symbol_type + make_TEMP (const std::string& v, const location_type& l) + { + return symbol_type (token::TOK_TEMP, v, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_TEMPORARY (std::string v, location_type l) + { + return symbol_type (token::TOK_TEMPORARY, std::move (v), std::move (l)); + } +#else + static + symbol_type + make_TEMPORARY (const std::string& v, const location_type& l) + { + return symbol_type (token::TOK_TEMPORARY, v, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_THEN (std::string v, location_type l) + { + return symbol_type (token::TOK_THEN, std::move (v), std::move (l)); + } +#else + static + symbol_type + make_THEN (const std::string& v, const location_type& l) + { + return symbol_type (token::TOK_THEN, v, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_TRUE (std::string v, location_type l) + { + return symbol_type (token::TOK_TRUE, std::move (v), std::move (l)); + } +#else + static + symbol_type + make_TRUE (const std::string& v, const location_type& l) + { + return symbol_type (token::TOK_TRUE, v, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_UNBOUNDED (std::string v, location_type l) + { + return symbol_type (token::TOK_UNBOUNDED, std::move (v), std::move (l)); + } +#else + static + symbol_type + make_UNBOUNDED (const std::string& v, const location_type& l) + { + return symbol_type (token::TOK_UNBOUNDED, v, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_UNIQUE (std::string v, location_type l) + { + return symbol_type (token::TOK_UNIQUE, std::move (v), std::move (l)); + } +#else + static + symbol_type + make_UNIQUE (const std::string& v, const location_type& l) + { + return symbol_type (token::TOK_UNIQUE, v, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_UPDATE (std::string v, location_type l) + { + return symbol_type (token::TOK_UPDATE, std::move (v), std::move (l)); + } +#else + static + symbol_type + make_UPDATE (const std::string& v, const location_type& l) + { + return symbol_type (token::TOK_UPDATE, v, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_USING (std::string v, location_type l) + { + return symbol_type (token::TOK_USING, std::move (v), std::move (l)); + } +#else + static + symbol_type + make_USING (const std::string& v, const location_type& l) + { + return symbol_type (token::TOK_USING, v, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_VIRTUAL (std::string v, location_type l) + { + return symbol_type (token::TOK_VIRTUAL, std::move (v), std::move (l)); + } +#else + static + symbol_type + make_VIRTUAL (const std::string& v, const location_type& l) + { + return symbol_type (token::TOK_VIRTUAL, v, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_WHEN (std::string v, location_type l) + { + return symbol_type (token::TOK_WHEN, std::move (v), std::move (l)); + } +#else + static + symbol_type + make_WHEN (const std::string& v, const location_type& l) + { + return symbol_type (token::TOK_WHEN, v, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_WHERE (std::string v, location_type l) + { + return symbol_type (token::TOK_WHERE, std::move (v), std::move (l)); + } +#else + static + symbol_type + make_WHERE (const std::string& v, const location_type& l) + { + return symbol_type (token::TOK_WHERE, v, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_WITHOUT (std::string v, location_type l) + { + return symbol_type (token::TOK_WITHOUT, std::move (v), std::move (l)); + } +#else + static + symbol_type + make_WITHOUT (const std::string& v, const location_type& l) + { + return symbol_type (token::TOK_WITHOUT, v, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_IDENTIFIER (std::string v, location_type l) + { + return symbol_type (token::TOK_IDENTIFIER, std::move (v), std::move (l)); + } +#else + static + symbol_type + make_IDENTIFIER (const std::string& v, const location_type& l) + { + return symbol_type (token::TOK_IDENTIFIER, v, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_NUMERIC (std::string v, location_type l) + { + return symbol_type (token::TOK_NUMERIC, std::move (v), std::move (l)); + } +#else + static + symbol_type + make_NUMERIC (const std::string& v, const location_type& l) + { + return symbol_type (token::TOK_NUMERIC, v, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_STRINGLITERAL (std::string v, location_type l) + { + return symbol_type (token::TOK_STRINGLITERAL, std::move (v), std::move (l)); + } +#else + static + symbol_type + make_STRINGLITERAL (const std::string& v, const location_type& l) + { + return symbol_type (token::TOK_STRINGLITERAL, v, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_QUOTEDLITERAL (std::string v, location_type l) + { + return symbol_type (token::TOK_QUOTEDLITERAL, std::move (v), std::move (l)); + } +#else + static + symbol_type + make_QUOTEDLITERAL (const std::string& v, const location_type& l) + { + return symbol_type (token::TOK_QUOTEDLITERAL, v, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_BLOBLITERAL (std::string v, location_type l) + { + return symbol_type (token::TOK_BLOBLITERAL, std::move (v), std::move (l)); + } +#else + static + symbol_type + make_BLOBLITERAL (const std::string& v, const location_type& l) + { + return symbol_type (token::TOK_BLOBLITERAL, v, l); + } +#endif +#if 201103L <= YY_CPLUSPLUS + static + symbol_type + make_BINDPARAMETER (std::string v, location_type l) + { + return symbol_type (token::TOK_BINDPARAMETER, std::move (v), std::move (l)); + } +#else + static + symbol_type + make_BINDPARAMETER (const std::string& v, const location_type& l) + { + return symbol_type (token::TOK_BINDPARAMETER, v, l); + } +#endif + + + private: + /// This class is not copyable. + parser (const parser&); + parser& operator= (const parser&); + + /// Stored state numbers (used for stacks). + typedef short state_type; + + /// Generate an error message. + /// \param yystate the state where the error occurred. + /// \param yyla the lookahead token. + virtual std::string yysyntax_error_ (state_type yystate, + const symbol_type& yyla) const; + + /// Compute post-reduction state. + /// \param yystate the current state + /// \param yysym the nonterminal to push on the stack + static state_type yy_lr_goto_state_ (state_type yystate, int yysym); + + /// Whether the given \c yypact_ value indicates a defaulted state. + /// \param yyvalue the value to check + static bool yy_pact_value_is_default_ (int yyvalue); + + /// Whether the given \c yytable_ value indicates a syntax error. + /// \param yyvalue the value to check + static bool yy_table_value_is_error_ (int yyvalue); + + static const short yypact_ninf_; + static const short yytable_ninf_; + + /// Convert a scanner token number \a t to a symbol number. + /// In theory \a t should be a token_type, but character literals + /// are valid, yet not members of the token_type enum. + static token_number_type yytranslate_ (int t); + + // Tables. + // YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing + // STATE-NUM. + static const short yypact_[]; + + // YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM. + // Performed when YYTABLE does not specify something else to do. Zero + // means the default is an error. + static const short yydefact_[]; + + // YYPGOTO[NTERM-NUM]. + static const short yypgoto_[]; + + // YYDEFGOTO[NTERM-NUM]. + static const short yydefgoto_[]; + + // YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM. If + // positive, shift that token. If negative, reduce the rule whose + // number is the opposite. If YYTABLE_NINF, syntax error. + static const short yytable_[]; + + static const short yycheck_[]; + + // YYSTOS[STATE-NUM] -- The (internal number of the) accessing + // symbol of state STATE-NUM. + static const unsigned char yystos_[]; + + // YYR1[YYN] -- Symbol number of symbol that rule YYN derives. + static const unsigned char yyr1_[]; + + // YYR2[YYN] -- Number of symbols on the right hand side of rule YYN. + static const signed char yyr2_[]; + + + /// Convert the symbol name \a n to a form suitable for a diagnostic. + static std::string yytnamerr_ (const char *n); + + + /// For a symbol, its name in clear. + static const char* const yytname_[]; +#if YYDEBUG + // YYRLINE[YYN] -- Source line where rule number YYN was defined. + static const short yyrline_[]; + /// Report on the debug stream that the rule \a r is going to be reduced. + virtual void yy_reduce_print_ (int r); + /// Print the state stack on the debug stream. + virtual void yystack_print_ (); + + /// Debugging level. + int yydebug_; + /// Debug stream. + std::ostream* yycdebug_; + + /// \brief Display a symbol type, value and location. + /// \param yyo The output stream. + /// \param yysym The symbol. + template + void yy_print_ (std::ostream& yyo, const basic_symbol& yysym) const; +#endif + + /// \brief Reclaim the memory associated to a symbol. + /// \param yymsg Why this token is reclaimed. + /// If null, print nothing. + /// \param yysym The symbol. + template + void yy_destroy_ (const char* yymsg, basic_symbol& yysym) const; + + private: + /// Type access provider for state based symbols. + struct by_state + { + /// Default constructor. + by_state () YY_NOEXCEPT; + + /// The symbol type as needed by the constructor. + typedef state_type kind_type; + + /// Constructor. + by_state (kind_type s) YY_NOEXCEPT; + + /// Copy constructor. + by_state (const by_state& that) YY_NOEXCEPT; + + /// Record that this symbol is empty. + void clear () YY_NOEXCEPT; + + /// Steal the symbol type from \a that. + void move (by_state& that); + + /// The (internal) type number (corresponding to \a state). + /// \a empty_symbol when empty. + symbol_number_type type_get () const YY_NOEXCEPT; + + /// The state number used to denote an empty symbol. + /// We use the initial state, as it does not have a value. + enum { empty_state = 0 }; + + /// The state. + /// \a empty when empty. + state_type state; + }; + + /// "Internal" symbol: element of the stack. + struct stack_symbol_type : basic_symbol + { + /// Superclass. + typedef basic_symbol super_type; + /// Construct an empty symbol. + stack_symbol_type (); + /// Move or copy construction. + stack_symbol_type (YY_RVREF (stack_symbol_type) that); + /// Steal the contents from \a sym to build this. + stack_symbol_type (state_type s, YY_MOVE_REF (symbol_type) sym); +#if YY_CPLUSPLUS < 201103L + /// Assignment, needed by push_back by some old implementations. + /// Moves the contents of that. + stack_symbol_type& operator= (stack_symbol_type& that); + + /// Assignment, needed by push_back by other implementations. + /// Needed by some other old implementations. + stack_symbol_type& operator= (const stack_symbol_type& that); +#endif + }; + + /// A stack with random access from its top. + template > + class stack + { + public: + // Hide our reversed order. + typedef typename S::reverse_iterator iterator; + typedef typename S::const_reverse_iterator const_iterator; + typedef typename S::size_type size_type; + typedef typename std::ptrdiff_t index_type; + + stack (size_type n = 200) + : seq_ (n) + {} + + /// Random access. + /// + /// Index 0 returns the topmost element. + const T& + operator[] (index_type i) const + { + return seq_[size_type (size () - 1 - i)]; + } + + /// Random access. + /// + /// Index 0 returns the topmost element. + T& + operator[] (index_type i) + { + return seq_[size_type (size () - 1 - i)]; + } + + /// Steal the contents of \a t. + /// + /// Close to move-semantics. + void + push (YY_MOVE_REF (T) t) + { + seq_.push_back (T ()); + operator[] (0).move (t); + } + + /// Pop elements from the stack. + void + pop (std::ptrdiff_t n = 1) YY_NOEXCEPT + { + for (; 0 < n; --n) + seq_.pop_back (); + } + + /// Pop all elements from the stack. + void + clear () YY_NOEXCEPT + { + seq_.clear (); + } + + /// Number of elements on the stack. + index_type + size () const YY_NOEXCEPT + { + return index_type (seq_.size ()); + } + + std::ptrdiff_t + ssize () const YY_NOEXCEPT + { + return std::ptrdiff_t (size ()); + } + + /// Iterator on top of the stack (going downwards). + const_iterator + begin () const YY_NOEXCEPT + { + return seq_.rbegin (); + } + + /// Bottom of the stack. + const_iterator + end () const YY_NOEXCEPT + { + return seq_.rend (); + } + + /// Present a slice of the top of a stack. + class slice + { + public: + slice (const stack& stack, index_type range) + : stack_ (stack) + , range_ (range) + {} + + const T& + operator[] (index_type i) const + { + return stack_[range_ - i]; + } + + private: + const stack& stack_; + index_type range_; + }; + + private: + stack (const stack&); + stack& operator= (const stack&); + /// The wrapped container. + S seq_; + }; + + + /// Stack type. + typedef stack stack_type; + + /// The stack. + stack_type yystack_; + + /// Push a new state on the stack. + /// \param m a debug message to display + /// if null, no trace is output. + /// \param sym the symbol + /// \warning the contents of \a s.value is stolen. + void yypush_ (const char* m, YY_MOVE_REF (stack_symbol_type) sym); + + /// Push a new look ahead token on the state on the stack. + /// \param m a debug message to display + /// if null, no trace is output. + /// \param s the state + /// \param sym the symbol (for its value and location). + /// \warning the contents of \a sym.value is stolen. + void yypush_ (const char* m, state_type s, YY_MOVE_REF (symbol_type) sym); + + /// Pop \a n symbols from the stack. + void yypop_ (int n = 1); + + /// Some specific tokens. + static const token_number_type yy_error_token_ = 1; + static const token_number_type yy_undef_token_ = 2; + + /// Constants. + enum + { + yyeof_ = 0, + yylast_ = 3407, ///< Last index in yytable_. + yynnts_ = 55, ///< Number of nonterminal symbols. + yyfinal_ = 13, ///< Termination state number. + yyntokens_ = 117 ///< Number of tokens. + }; + + + // User arguments. + yyscan_t yyscanner; + ParserDriver& drv; + }; + + inline + parser::token_number_type + parser::yytranslate_ (int t) + { + // YYTRANSLATE[TOKEN-NUM] -- Symbol number corresponding to + // TOKEN-NUM as returned by yylex. + static + const token_number_type + translate_table[] = + { + 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 1, 2, 3, 4, + 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, + 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, + 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, + 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, + 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, + 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, + 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, + 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, + 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, + 115, 116 + }; + const int user_token_number_max_ = 371; + + if (t <= 0) + return yyeof_; + else if (t <= user_token_number_max_) + return translate_table[t]; + else + return yy_undef_token_; + } + + // basic_symbol. +#if 201103L <= YY_CPLUSPLUS + template + parser::basic_symbol::basic_symbol (basic_symbol&& that) + : Base (std::move (that)) + , value () + , location (std::move (that.location)) + { + switch (this->type_get ()) + { + case 158: // columnconstraint + value.move< ColumnConstraintInfo > (std::move (that.value)); + break; + + case 159: // columnconstraint_list + value.move< ColumnConstraintInfoVector > (std::move (that.value)); + break; + + case 160: // columndef + value.move< ColumndefData > (std::move (that.value)); + break; + + case 142: // optional_if_not_exists + case 144: // optional_unique + case 152: // optional_temporary + case 153: // optional_withoutrowid + case 157: // optional_always_generated + value.move< bool > (std::move (that.value)); + break; + + case 168: // tableconstraint + value.move< sqlb::ConstraintPtr > (std::move (that.value)); + break; + + case 169: // tableconstraint_list + case 170: // optional_tableconstraint_list + value.move< sqlb::ConstraintSet > (std::move (that.value)); + break; + + case 149: // createindex_stmt + value.move< sqlb::IndexPtr > (std::move (that.value)); + break; + + case 147: // indexed_column + value.move< sqlb::IndexedColumn > (std::move (that.value)); + break; + + case 148: // indexed_column_list + value.move< sqlb::IndexedColumnVector > (std::move (that.value)); + break; + + case 163: // columnid_list + case 164: // optional_columnid_with_paren_list + value.move< sqlb::StringVector > (std::move (that.value)); + break; + + case 151: // createvirtualtable_stmt + case 171: // createtable_stmt + value.move< sqlb::TablePtr > (std::move (that.value)); + break; + + case 27: // "ABORT" + case 28: // "ACTION" + case 29: // "ALWAYS" + case 30: // "AND" + case 31: // "AND BETWEEN" + case 32: // "AS" + case 33: // "ASC" + case 34: // "AUTOINCREMENT" + case 35: // "BETWEEN" + case 36: // "CASCADE" + case 37: // "CASE" + case 38: // "CAST" + case 39: // "CHECK" + case 40: // "COLLATE" + case 41: // "CONFLICT" + case 42: // "CONSTRAINT" + case 43: // "CREATE" + case 44: // "CURRENT_DATE" + case 45: // "CURRENT_TIME" + case 46: // "CURRENT_TIMESTAMP" + case 47: // "DEFAULT" + case 48: // "DEFERRABLE" + case 49: // "DEFERRED" + case 50: // "DELETE" + case 51: // "DESC" + case 52: // "DISTINCT" + case 53: // "ELSE" + case 54: // "END" + case 55: // "ESCAPE" + case 56: // "EXISTS" + case 57: // "FAIL" + case 58: // "FALSE" + case 59: // "FILTER" + case 60: // "FOLLOWING" + case 61: // "FOREIGN" + case 62: // "GENERATED" + case 63: // "GLOB" + case 64: // "IF" + case 65: // "IGNORE" + case 66: // "IMMEDIATE" + case 67: // "IN" + case 68: // "INDEX" + case 69: // "INITIALLY" + case 70: // "INSERT" + case 71: // "IS" + case 72: // "ISNULL" + case 73: // "KEY" + case 74: // "LIKE" + case 75: // "MATCH" + case 76: // "NO" + case 77: // "NOT" + case 78: // "NOTNULL" + case 79: // "NULL" + case 80: // "ON" + case 81: // "OR" + case 82: // "OVER" + case 83: // "PARTITION" + case 84: // "PRECEDING" + case 85: // "PRIMARY" + case 86: // "RAISE" + case 87: // "RANGE" + case 88: // "REFERENCES" + case 89: // "REGEXP" + case 90: // "REPLACE" + case 91: // "RESTRICT" + case 92: // "ROLLBACK" + case 93: // "ROWID" + case 94: // "ROWS" + case 95: // "SELECT" + case 96: // "SET" + case 97: // "STORED" + case 98: // "TABLE" + case 99: // "TEMP" + case 100: // "TEMPORARY" + case 101: // "THEN" + case 102: // "TRUE" + case 103: // "UNBOUNDED" + case 104: // "UNIQUE" + case 105: // "UPDATE" + case 106: // "USING" + case 107: // "VIRTUAL" + case 108: // "WHEN" + case 109: // "WHERE" + case 110: // "WITHOUT" + case 111: // "identifier" + case 112: // "numeric" + case 113: // "string literal" + case 114: // "quoted literal" + case 115: // "blob literal" + case 116: // "bind parameter" + case 120: // literalvalue + case 121: // id + case 122: // allowed_keywords_as_identifier + case 123: // tableid + case 124: // columnid + case 125: // signednumber + case 126: // signednumber_or_numeric + case 127: // typename_namelist + case 128: // type_name + case 129: // unary_expr + case 130: // binary_expr + case 131: // like_expr + case 132: // exprlist_expr + case 133: // function_expr + case 134: // isnull_expr + case 135: // between_expr + case 136: // in_expr + case 137: // whenthenlist_expr + case 138: // case_expr + case 139: // raise_expr + case 140: // expr + case 141: // select_stmt + case 143: // optional_sort_order + case 145: // optional_where + case 146: // tableid_with_uninteresting_schema + case 150: // optional_exprlist_with_paren + case 154: // optional_conflictclause + case 155: // optional_typename + case 156: // optional_storage_identifier + case 162: // optional_constraintname + case 165: // fk_clause_part + case 166: // fk_clause_part_list + case 167: // optional_fk_clause + value.move< std::string > (std::move (that.value)); + break; + + case 161: // columndef_list + value.move< std::vector > (std::move (that.value)); + break; + + default: + break; + } + + } +#endif + + template + parser::basic_symbol::basic_symbol (const basic_symbol& that) + : Base (that) + , value () + , location (that.location) + { + switch (this->type_get ()) + { + case 158: // columnconstraint + value.copy< ColumnConstraintInfo > (YY_MOVE (that.value)); + break; + + case 159: // columnconstraint_list + value.copy< ColumnConstraintInfoVector > (YY_MOVE (that.value)); + break; + + case 160: // columndef + value.copy< ColumndefData > (YY_MOVE (that.value)); + break; + + case 142: // optional_if_not_exists + case 144: // optional_unique + case 152: // optional_temporary + case 153: // optional_withoutrowid + case 157: // optional_always_generated + value.copy< bool > (YY_MOVE (that.value)); + break; + + case 168: // tableconstraint + value.copy< sqlb::ConstraintPtr > (YY_MOVE (that.value)); + break; + + case 169: // tableconstraint_list + case 170: // optional_tableconstraint_list + value.copy< sqlb::ConstraintSet > (YY_MOVE (that.value)); + break; + + case 149: // createindex_stmt + value.copy< sqlb::IndexPtr > (YY_MOVE (that.value)); + break; + + case 147: // indexed_column + value.copy< sqlb::IndexedColumn > (YY_MOVE (that.value)); + break; + + case 148: // indexed_column_list + value.copy< sqlb::IndexedColumnVector > (YY_MOVE (that.value)); + break; + + case 163: // columnid_list + case 164: // optional_columnid_with_paren_list + value.copy< sqlb::StringVector > (YY_MOVE (that.value)); + break; + + case 151: // createvirtualtable_stmt + case 171: // createtable_stmt + value.copy< sqlb::TablePtr > (YY_MOVE (that.value)); + break; + + case 27: // "ABORT" + case 28: // "ACTION" + case 29: // "ALWAYS" + case 30: // "AND" + case 31: // "AND BETWEEN" + case 32: // "AS" + case 33: // "ASC" + case 34: // "AUTOINCREMENT" + case 35: // "BETWEEN" + case 36: // "CASCADE" + case 37: // "CASE" + case 38: // "CAST" + case 39: // "CHECK" + case 40: // "COLLATE" + case 41: // "CONFLICT" + case 42: // "CONSTRAINT" + case 43: // "CREATE" + case 44: // "CURRENT_DATE" + case 45: // "CURRENT_TIME" + case 46: // "CURRENT_TIMESTAMP" + case 47: // "DEFAULT" + case 48: // "DEFERRABLE" + case 49: // "DEFERRED" + case 50: // "DELETE" + case 51: // "DESC" + case 52: // "DISTINCT" + case 53: // "ELSE" + case 54: // "END" + case 55: // "ESCAPE" + case 56: // "EXISTS" + case 57: // "FAIL" + case 58: // "FALSE" + case 59: // "FILTER" + case 60: // "FOLLOWING" + case 61: // "FOREIGN" + case 62: // "GENERATED" + case 63: // "GLOB" + case 64: // "IF" + case 65: // "IGNORE" + case 66: // "IMMEDIATE" + case 67: // "IN" + case 68: // "INDEX" + case 69: // "INITIALLY" + case 70: // "INSERT" + case 71: // "IS" + case 72: // "ISNULL" + case 73: // "KEY" + case 74: // "LIKE" + case 75: // "MATCH" + case 76: // "NO" + case 77: // "NOT" + case 78: // "NOTNULL" + case 79: // "NULL" + case 80: // "ON" + case 81: // "OR" + case 82: // "OVER" + case 83: // "PARTITION" + case 84: // "PRECEDING" + case 85: // "PRIMARY" + case 86: // "RAISE" + case 87: // "RANGE" + case 88: // "REFERENCES" + case 89: // "REGEXP" + case 90: // "REPLACE" + case 91: // "RESTRICT" + case 92: // "ROLLBACK" + case 93: // "ROWID" + case 94: // "ROWS" + case 95: // "SELECT" + case 96: // "SET" + case 97: // "STORED" + case 98: // "TABLE" + case 99: // "TEMP" + case 100: // "TEMPORARY" + case 101: // "THEN" + case 102: // "TRUE" + case 103: // "UNBOUNDED" + case 104: // "UNIQUE" + case 105: // "UPDATE" + case 106: // "USING" + case 107: // "VIRTUAL" + case 108: // "WHEN" + case 109: // "WHERE" + case 110: // "WITHOUT" + case 111: // "identifier" + case 112: // "numeric" + case 113: // "string literal" + case 114: // "quoted literal" + case 115: // "blob literal" + case 116: // "bind parameter" + case 120: // literalvalue + case 121: // id + case 122: // allowed_keywords_as_identifier + case 123: // tableid + case 124: // columnid + case 125: // signednumber + case 126: // signednumber_or_numeric + case 127: // typename_namelist + case 128: // type_name + case 129: // unary_expr + case 130: // binary_expr + case 131: // like_expr + case 132: // exprlist_expr + case 133: // function_expr + case 134: // isnull_expr + case 135: // between_expr + case 136: // in_expr + case 137: // whenthenlist_expr + case 138: // case_expr + case 139: // raise_expr + case 140: // expr + case 141: // select_stmt + case 143: // optional_sort_order + case 145: // optional_where + case 146: // tableid_with_uninteresting_schema + case 150: // optional_exprlist_with_paren + case 154: // optional_conflictclause + case 155: // optional_typename + case 156: // optional_storage_identifier + case 162: // optional_constraintname + case 165: // fk_clause_part + case 166: // fk_clause_part_list + case 167: // optional_fk_clause + value.copy< std::string > (YY_MOVE (that.value)); + break; + + case 161: // columndef_list + value.copy< std::vector > (YY_MOVE (that.value)); + break; + + default: + break; + } + + } + + + + template + bool + parser::basic_symbol::empty () const YY_NOEXCEPT + { + return Base::type_get () == empty_symbol; + } + + template + void + parser::basic_symbol::move (basic_symbol& s) + { + super_type::move (s); + switch (this->type_get ()) + { + case 158: // columnconstraint + value.move< ColumnConstraintInfo > (YY_MOVE (s.value)); + break; + + case 159: // columnconstraint_list + value.move< ColumnConstraintInfoVector > (YY_MOVE (s.value)); + break; + + case 160: // columndef + value.move< ColumndefData > (YY_MOVE (s.value)); + break; + + case 142: // optional_if_not_exists + case 144: // optional_unique + case 152: // optional_temporary + case 153: // optional_withoutrowid + case 157: // optional_always_generated + value.move< bool > (YY_MOVE (s.value)); + break; + + case 168: // tableconstraint + value.move< sqlb::ConstraintPtr > (YY_MOVE (s.value)); + break; + + case 169: // tableconstraint_list + case 170: // optional_tableconstraint_list + value.move< sqlb::ConstraintSet > (YY_MOVE (s.value)); + break; + + case 149: // createindex_stmt + value.move< sqlb::IndexPtr > (YY_MOVE (s.value)); + break; + + case 147: // indexed_column + value.move< sqlb::IndexedColumn > (YY_MOVE (s.value)); + break; + + case 148: // indexed_column_list + value.move< sqlb::IndexedColumnVector > (YY_MOVE (s.value)); + break; + + case 163: // columnid_list + case 164: // optional_columnid_with_paren_list + value.move< sqlb::StringVector > (YY_MOVE (s.value)); + break; + + case 151: // createvirtualtable_stmt + case 171: // createtable_stmt + value.move< sqlb::TablePtr > (YY_MOVE (s.value)); + break; + + case 27: // "ABORT" + case 28: // "ACTION" + case 29: // "ALWAYS" + case 30: // "AND" + case 31: // "AND BETWEEN" + case 32: // "AS" + case 33: // "ASC" + case 34: // "AUTOINCREMENT" + case 35: // "BETWEEN" + case 36: // "CASCADE" + case 37: // "CASE" + case 38: // "CAST" + case 39: // "CHECK" + case 40: // "COLLATE" + case 41: // "CONFLICT" + case 42: // "CONSTRAINT" + case 43: // "CREATE" + case 44: // "CURRENT_DATE" + case 45: // "CURRENT_TIME" + case 46: // "CURRENT_TIMESTAMP" + case 47: // "DEFAULT" + case 48: // "DEFERRABLE" + case 49: // "DEFERRED" + case 50: // "DELETE" + case 51: // "DESC" + case 52: // "DISTINCT" + case 53: // "ELSE" + case 54: // "END" + case 55: // "ESCAPE" + case 56: // "EXISTS" + case 57: // "FAIL" + case 58: // "FALSE" + case 59: // "FILTER" + case 60: // "FOLLOWING" + case 61: // "FOREIGN" + case 62: // "GENERATED" + case 63: // "GLOB" + case 64: // "IF" + case 65: // "IGNORE" + case 66: // "IMMEDIATE" + case 67: // "IN" + case 68: // "INDEX" + case 69: // "INITIALLY" + case 70: // "INSERT" + case 71: // "IS" + case 72: // "ISNULL" + case 73: // "KEY" + case 74: // "LIKE" + case 75: // "MATCH" + case 76: // "NO" + case 77: // "NOT" + case 78: // "NOTNULL" + case 79: // "NULL" + case 80: // "ON" + case 81: // "OR" + case 82: // "OVER" + case 83: // "PARTITION" + case 84: // "PRECEDING" + case 85: // "PRIMARY" + case 86: // "RAISE" + case 87: // "RANGE" + case 88: // "REFERENCES" + case 89: // "REGEXP" + case 90: // "REPLACE" + case 91: // "RESTRICT" + case 92: // "ROLLBACK" + case 93: // "ROWID" + case 94: // "ROWS" + case 95: // "SELECT" + case 96: // "SET" + case 97: // "STORED" + case 98: // "TABLE" + case 99: // "TEMP" + case 100: // "TEMPORARY" + case 101: // "THEN" + case 102: // "TRUE" + case 103: // "UNBOUNDED" + case 104: // "UNIQUE" + case 105: // "UPDATE" + case 106: // "USING" + case 107: // "VIRTUAL" + case 108: // "WHEN" + case 109: // "WHERE" + case 110: // "WITHOUT" + case 111: // "identifier" + case 112: // "numeric" + case 113: // "string literal" + case 114: // "quoted literal" + case 115: // "blob literal" + case 116: // "bind parameter" + case 120: // literalvalue + case 121: // id + case 122: // allowed_keywords_as_identifier + case 123: // tableid + case 124: // columnid + case 125: // signednumber + case 126: // signednumber_or_numeric + case 127: // typename_namelist + case 128: // type_name + case 129: // unary_expr + case 130: // binary_expr + case 131: // like_expr + case 132: // exprlist_expr + case 133: // function_expr + case 134: // isnull_expr + case 135: // between_expr + case 136: // in_expr + case 137: // whenthenlist_expr + case 138: // case_expr + case 139: // raise_expr + case 140: // expr + case 141: // select_stmt + case 143: // optional_sort_order + case 145: // optional_where + case 146: // tableid_with_uninteresting_schema + case 150: // optional_exprlist_with_paren + case 154: // optional_conflictclause + case 155: // optional_typename + case 156: // optional_storage_identifier + case 162: // optional_constraintname + case 165: // fk_clause_part + case 166: // fk_clause_part_list + case 167: // optional_fk_clause + value.move< std::string > (YY_MOVE (s.value)); + break; + + case 161: // columndef_list + value.move< std::vector > (YY_MOVE (s.value)); + break; + + default: + break; + } + + location = YY_MOVE (s.location); + } + + // by_type. + inline + parser::by_type::by_type () + : type (empty_symbol) + {} + +#if 201103L <= YY_CPLUSPLUS + inline + parser::by_type::by_type (by_type&& that) + : type (that.type) + { + that.clear (); + } +#endif + + inline + parser::by_type::by_type (const by_type& that) + : type (that.type) + {} + + inline + parser::by_type::by_type (token_type t) + : type (yytranslate_ (t)) + {} + + inline + void + parser::by_type::clear () + { + type = empty_symbol; + } + + inline + void + parser::by_type::move (by_type& that) + { + type = that.type; + that.clear (); + } + + inline + int + parser::by_type::type_get () const YY_NOEXCEPT + { + return type; + } + +#line 10 "sqlite3_parser.yy" +} } // sqlb::parser +#line 4092 "sqlite3_parser.hpp" + + + + + +#endif // !YY_YY_SQLITE3_PARSER_HPP_INCLUDED diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/sql/parser/sqlite3_parser.yy b/src/WBCLFZSystemModule/SqliteDBProcess/src/sql/parser/sqlite3_parser.yy new file mode 100644 index 0000000..81389d1 --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/sql/parser/sqlite3_parser.yy @@ -0,0 +1,988 @@ +%skeleton "lalr1.cc" +%require "3.4.1" +%defines + +%define api.token.constructor +%define api.value.type variant +%define parse.assert +%output "sqlite3_parser.cpp" +%define api.location.file "sqlite3_location.h" +%define api.namespace { sqlb::parser } + +%code requires { + #include + #include + #include "../sqlitetypes.h" + #include "../ObjectIdentifier.h" + namespace sqlb { namespace parser { class ParserDriver; } } + typedef void* yyscan_t; + + // Unfortunately we do not store column constraints in a systematic manner yet. + // Instead there is a variable for most column constraints directly inside the + // sqlb::Field class. This means that when parsing a column constraint we cannot + // just build a column constraint object with all the information and insert that + // into the Field object. Instead, the information needs to be passed upwards in + // some other way. This is what these declarations are for. We need to be able + // to pass information to the Field object as well as to the Table object too + // because some column constraints need to be transformed into Table constraints + // with our current layout. + class ColumnConstraintInfo + { + public: + ColumnConstraintInfo() : is_table_constraint(false), fully_parsed(false) {} + ~ColumnConstraintInfo() {} + ColumnConstraintInfo& operator=(const ColumnConstraintInfo& other) + { + type = other.type; + is_table_constraint = other.is_table_constraint; + fully_parsed = other.fully_parsed; + if(is_table_constraint) + table_constraint = other.table_constraint; + text = other.text; + generated_constraint = other.generated_constraint; + + return *this; + } + ColumnConstraintInfo(const ColumnConstraintInfo& other) + { + *this = other; + } + + enum ConstraintType + { + None, + AutoIncrement, + PrimaryKey, + NotNull, + Unique, + Check, + Default, + Collate, + ForeignKey, + Generated, + }; + + ConstraintType type; + bool is_table_constraint; + bool fully_parsed; + + sqlb::ConstraintPtr table_constraint; + std::string text; + sqlb::GeneratedColumnConstraint generated_constraint; + }; + using ColumnConstraintInfoVector = std::vector; + + // Colum definitions are a tuple of three elements: the Field object, a set of table constraints, and a bool to indicate whether parsing was complete + using ColumndefData = std::tuple; +} + +// The parsing context +%param { yyscan_t yyscanner } +%param { ParserDriver& drv } + +%locations + +%define parse.trace +%define parse.error verbose + +%code { + #include "ParserDriver.h" + + static std::string unquote_text(std::string str, char quote_char) + { + if(str.front() != quote_char || str.back() != quote_char) + return str; + + str = str.substr(1, str.size()-2); + + std::string quote(2, quote_char); + + size_t pos = 0; + while((pos = str.find(quote, pos)) != std::string::npos) + { + str.erase(pos, 1); + pos += 1; // Don't remove the other quote char too + } + return str; + } +} + +%define api.token.prefix {TOK_} +%token + EOF 0 "end of file" + LPAREN "(" + RPAREN ")" + DOT "." + COMMA "," + SEMI ";" + PLUS "+" + MINUS "-" + STAR "*" + SLASH "/" + TILDE "~" + AMPERSAND "&" + PERCENT "%" + BITOR "|" + OROP "||" + EQUAL "=" + EQUAL2 "==" + GREATER ">" + GREATEREQUAL ">=" + LOWER "<" + LOWEREQUAL "<=" + UNEQUAL "!=" + UNEQUAL2 "<>" + BITWISELEFT "<<" + BITWISERIGHT ">>" +; + +%token ABORT "ABORT" +%token ACTION "ACTION" +%token ALWAYS "ALWAYS" +%token AND "AND" +%token AND_BETWEEN "AND BETWEEN" +%token AS "AS" +%token ASC "ASC" +%token AUTOINCREMENT "AUTOINCREMENT" +%token BETWEEN "BETWEEN" +%token CASCADE "CASCADE" +%token CASE "CASE" +%token CAST "CAST" +%token CHECK "CHECK" +%token COLLATE "COLLATE" +%token CONFLICT "CONFLICT" +%token CONSTRAINT "CONSTRAINT" +%token CREATE "CREATE" +%token CURRENT_DATE "CURRENT_DATE" +%token CURRENT_TIME "CURRENT_TIME" +%token CURRENT_TIMESTAMP "CURRENT_TIMESTAMP" +%token DEFAULT "DEFAULT" +%token DEFERRABLE "DEFERRABLE" +%token DEFERRED "DEFERRED" +%token DELETE "DELETE" +%token DESC "DESC" +%token DISTINCT "DISTINCT" +%token ELSE "ELSE" +%token END "END" +%token ESCAPE "ESCAPE" +%token EXISTS "EXISTS" +%token FAIL "FAIL" +%token FALSE "FALSE" +%token FILTER "FILTER" +%token FOLLOWING "FOLLOWING" +%token FOREIGN "FOREIGN" +%token GENERATED "GENERATED" +%token GLOB "GLOB" +%token IF "IF" +%token IGNORE "IGNORE" +%token IMMEDIATE "IMMEDIATE" +%token IN "IN" +%token INDEX "INDEX" +%token INITIALLY "INITIALLY" +%token INSERT "INSERT" +%token IS "IS" +%token ISNULL "ISNULL" +%token KEY "KEY" +%token LIKE "LIKE" +%token MATCH "MATCH" +%token NO "NO" +%token NOT "NOT" +%token NOTNULL "NOTNULL" +%token NULL "NULL" +%token ON "ON" +%token OR "OR" +%token OVER "OVER" +%token PARTITION "PARTITION" +%token PRECEDING "PRECEDING" +%token PRIMARY "PRIMARY" +%token RAISE "RAISE" +%token RANGE "RANGE" +%token REFERENCES "REFERENCES" +%token REGEXP "REGEXP" +%token REPLACE "REPLACE" +%token RESTRICT "RESTRICT" +%token ROLLBACK "ROLLBACK" +%token ROWID "ROWID" +%token ROWS "ROWS" +%token SELECT "SELECT" +%token SET "SET" +%token STORED "STORED" +%token TABLE "TABLE" +%token TEMP "TEMP" +%token TEMPORARY "TEMPORARY" +%token THEN "THEN" +%token TRUE "TRUE" +%token UNBOUNDED "UNBOUNDED" +%token UNIQUE "UNIQUE" +%token UPDATE "UPDATE" +%token USING "USING" +%token VIRTUAL "VIRTUAL" +%token WHEN "WHEN" +%token WHERE "WHERE" +%token WITHOUT "WITHOUT" + +%token IDENTIFIER "identifier" +%token NUMERIC "numeric" +%token STRINGLITERAL "string literal" +%token QUOTEDLITERAL "quoted literal" +%token BLOBLITERAL "blob literal" +%token BINDPARAMETER "bind parameter" + +%type literalvalue +%type signednumber +%type signednumber_or_numeric +%type id +%type allowed_keywords_as_identifier +%type tableid +%type columnid +%type typename_namelist +%type type_name +%type unary_expr +%type binary_expr +%type like_expr +%type exprlist_expr +%type function_expr +%type isnull_expr +%type between_expr +%type in_expr +%type whenthenlist_expr +%type case_expr +%type raise_expr +%type expr +%type optional_if_not_exists +%type optional_unique +%type optional_temporary +%type optional_withoutrowid +%type optional_sort_order +%type optional_where +%type optional_constraintname +%type optional_conflictclause +%type tableid_with_uninteresting_schema +%type optional_exprlist_with_paren +%type select_stmt + +%type indexed_column +%type indexed_column_list +%type createindex_stmt +%type createvirtualtable_stmt + +%type optional_typename +%type optional_storage_identifier +%type optional_always_generated +%type columnconstraint_list +%type columnconstraint +%type columndef +%type > columndef_list +%type columnid_list +%type optional_columnid_with_paren_list +%type fk_clause_part +%type fk_clause_part_list +%type optional_fk_clause +%type tableconstraint +%type tableconstraint_list +%type optional_tableconstraint_list +%type createtable_stmt + +%% + +%left OR; +%left AND; +%right NOT; +%left IS MATCH LIKE BETWEEN IN UNEQUAL UNEQUAL2 EQUAL EQUAL2 GLOB REGEXP ISNULL NOTNULL; +%left GREATER LOWEREQUAL LOWER GREATEREQUAL; +%right ESCAPE; +%left AMPERSAND BITOR BITWISELEFT BITWISERIGHT; +%left PLUS MINUS; +%left STAR SLASH PERCENT; +%left OROP; +%left COLLATE; +%right TILDE; +%nonassoc ON; + +/* + * Statements + */ + +%start sql; + +sql: + statement + | statement ";" + ; + +statement: + createindex_stmt { drv.result = $1; } + | createvirtualtable_stmt { drv.result = $1; } + | createtable_stmt { drv.result = $1; } + ; + +/* + * Expressions + */ + +literalvalue: + NUMERIC + | STRINGLITERAL + | BLOBLITERAL + | NULL + | TRUE + | FALSE + | CURRENT_TIME + | CURRENT_DATE + | CURRENT_TIMESTAMP + ; + +id: + IDENTIFIER + | QUOTEDLITERAL + //| STRINGLITERAL + ; + +allowed_keywords_as_identifier: + ABORT + | ACTION + | ALWAYS + | ASC + | CASCADE + | CAST + | CONFLICT + | DEFERRED + | DESC + | END + | FAIL + | FILTER + | FOLLOWING + | GENERATED + | GLOB + | KEY + | LIKE + | IGNORE + | INITIALLY + | IMMEDIATE + | MATCH + | NO + | OVER + | PARTITION + | PRECEDING + | RAISE + | RANGE + | REGEXP + | REPLACE + | RESTRICT + | ROLLBACK + | ROWID + | ROWS + | STORED + | TEMPORARY + | TEMP + | UNBOUNDED + | VIRTUAL + | WITHOUT + ; + +tableid: + allowed_keywords_as_identifier + | CURRENT_TIME + | CURRENT_DATE + | CURRENT_TIMESTAMP + | id + | STRINGLITERAL { $$ = unquote_text($1, '\''); } + ; + +columnid: + allowed_keywords_as_identifier + | CURRENT_TIME + | CURRENT_DATE + | CURRENT_TIMESTAMP + | IF + | id + | STRINGLITERAL { $$ = unquote_text($1, '\''); } + ; + +signednumber: + "+" NUMERIC { $$ = "+" + $2; } // No NUMERIC without "+" or "-" here because that is just a literalvalue + | "-" NUMERIC { $$ = "-" + $2; } + ; + +signednumber_or_numeric: + signednumber + | NUMERIC + ; + +typename_namelist: + tableid { $$ = $1; } + | typename_namelist tableid { $$ = $1 + " " + $2; } + ; + +type_name: + typename_namelist { $$ = $1; } + | typename_namelist "(" signednumber_or_numeric ")" { $$ = $1 + "(" + $3 + ")"; } + | typename_namelist "(" signednumber_or_numeric "," signednumber_or_numeric ")" { $$ = $1 + "(" + $3 + ", " + $5 + ")"; } + ; + +unary_expr: + "-" expr %prec TILDE { $$ = "-" + $2; } + | "+" expr %prec TILDE { $$ = "+" + $2; } + | "~" expr { $$ = "~" + $2; } + | NOT expr { $$ = "NOT " + $2; } + ; + +binary_expr: + expr "||" expr { $$ = $1 + " || " + $3; } + | expr "*" expr { $$ = $1 + " * " + $3; } + | expr "/" expr { $$ = $1 + " / " + $3; } + | expr "%" expr { $$ = $1 + " % " + $3; } + | expr "+" expr { $$ = $1 + " + " + $3; } + | expr "-" expr { $$ = $1 + " - " + $3; } + | expr "<<" expr { $$ = $1 + " << " + $3; } + | expr ">>" expr { $$ = $1 + " >> " + $3; } + | expr "&" expr { $$ = $1 + " & " + $3; } + | expr "|" expr { $$ = $1 + " | " + $3; } + | expr "<" expr { $$ = $1 + " < " + $3; } + | expr "<=" expr { $$ = $1 + " <= " + $3; } + | expr ">" expr { $$ = $1 + " > " + $3; } + | expr ">=" expr { $$ = $1 + " >= " + $3; } + | expr "=" expr { $$ = $1 + " = " + $3; } + | expr "==" expr { $$ = $1 + " == " + $3; } + | expr "!=" expr { $$ = $1 + " != " + $3; } + | expr "<>" expr { $$ = $1 + " <> " + $3; } + | expr IS expr { $$ = $1 + " IS " + $3; } + | expr AND expr { $$ = $1 + " AND " + $3; } + | expr OR expr { $$ = $1 + " OR " + $3; } + ; + +like_expr: + expr LIKE expr { $$ = $1 + " LIKE " + $3; } + | expr GLOB expr { $$ = $1 + " GLOB " + $3; } + | expr MATCH expr { $$ = $1 + " MATCH " + $3; } + | expr REGEXP expr { $$ = $1 + " REGEXP " + $3; } + | expr NOT LIKE expr { $$ = $1 + " NOT LIKE " + $4; } + | expr NOT GLOB expr { $$ = $1 + " NOT GLOB " + $4; } + | expr NOT MATCH expr { $$ = $1 + " NOT MATCH " + $4; } + | expr NOT REGEXP expr { $$ = $1 + " NOT REGEXP " + $4; } + | expr LIKE expr ESCAPE expr %prec LIKE { $$ = $1 + " LIKE " + $3 + " ESCAPE " + $5; } + | expr GLOB expr ESCAPE expr %prec GLOB { $$ = $1 + " GLOB " + $3 + " ESCAPE " + $5; } + | expr MATCH expr ESCAPE expr %prec MATCH { $$ = $1 + " MATCH " + $3 + " ESCAPE " + $5; } + | expr REGEXP expr ESCAPE expr %prec REGEXP { $$ = $1 + " REGEXP " + $3 + " ESCAPE " + $5; } + | expr NOT LIKE expr ESCAPE expr %prec LIKE { $$ = $1 + " NOT LIKE " + $3 + " ESCAPE " + $6; } + | expr NOT GLOB expr ESCAPE expr %prec GLOB { $$ = $1 + " NOT GLOB " + $3 + " ESCAPE " + $6; } + | expr NOT MATCH expr ESCAPE expr %prec MATCH { $$ = $1 + " NOT MATCH " + $3 + " ESCAPE " + $6; } + | expr NOT REGEXP expr ESCAPE expr %prec REGEXP { $$ = $1 + " NOT REGEXP " + $3 + " ESCAPE " + $6; } + ; + +exprlist_expr: + expr { $$ = $1; } + | exprlist_expr "," expr { $$ = $1 + ", " + $3; } + ; + +function_expr: + id "(" exprlist_expr ")" { $$ = $1 + "(" + $3 + ")"; } + | id "(" DISTINCT exprlist_expr ")" { $$ = $1 + "(DISTINCT " + $4 + ")"; } + | id "(" ")" { $$ = $1 + "()"; } + | id "(" "*" ")" { $$ = $1 + "(*)"; } + ; + +isnull_expr: + expr ISNULL { $$ = $1 + " ISNULL"; } + | expr NOTNULL { $$ = $1 + " NOTNULL"; } + | expr NOT NULL %prec NOTNULL { $$ = $1 + " NOT NULL"; } + ; + +between_expr: + expr BETWEEN expr AND_BETWEEN expr %prec BETWEEN { $$ = $1 + " BETWEEN " + $3 + " AND " + $5; } + | expr NOT BETWEEN expr AND_BETWEEN expr %prec BETWEEN { $$ = $1 + " NOT BETWEEN " + $4 + " AND " + $6; } + ; + +in_expr: + expr IN "(" ")" { $$ = $1 + " IN ()"; } + | expr IN "(" select_stmt ")" { $$ = $1 + " IN (" + $4 + ")"; } + | expr IN "(" exprlist_expr ")" { $$ = $1 + " IN (" + $4 + ")"; } + | expr IN id "." tableid { $$ = $1 + " IN " + sqlb::escapeIdentifier($3) + "." + sqlb::escapeIdentifier($5); } + | expr IN tableid { $$ = $1 + " IN " + sqlb::escapeIdentifier($3); } + | expr IN id "." id "(" ")" { $$ = $1 + " IN " + sqlb::escapeIdentifier($3) + "." + $5 + "()"; } + | expr IN id "." id "(" exprlist_expr ")" { $$ = $1 + " IN " + sqlb::escapeIdentifier($3) + "." + $5 + "(" + $7 + ")"; } + | expr IN id "(" exprlist_expr ")" { $$ = $1 + " IN " + $3 + "(" + $5 + ")"; } + | expr NOT IN "(" ")" { $$ = $1 + " NOT IN ()"; } + | expr NOT IN "(" select_stmt ")" { $$ = $1 + " NOT IN (" + $5 + ")"; } + | expr NOT IN "(" exprlist_expr ")" { $$ = $1 + " NOT IN (" + $5 + ")"; } + | expr NOT IN id "." tableid { $$ = $1 + " NOT IN " + sqlb::escapeIdentifier($4) + "." + sqlb::escapeIdentifier($6); } + | expr NOT IN tableid { $$ = $1 + " NOT IN " + sqlb::escapeIdentifier($4); } + | expr NOT IN id "." id "(" ")" { $$ = $1 + " NOT IN " + sqlb::escapeIdentifier($4) + "." + $6 + "()"; } + | expr NOT IN id "." id "(" exprlist_expr ")" { $$ = $1 + " NOT IN " + sqlb::escapeIdentifier($4) + "." + $6 + "(" + $8 + ")"; } + | expr NOT IN id "(" exprlist_expr ")" { $$ = $1 + " NOT IN " + $4 + "(" + $6 + ")"; } + ; + +whenthenlist_expr: + WHEN expr THEN expr { $$ = "WHEN " + $2 + " THEN " + $4; } + | whenthenlist_expr WHEN expr THEN expr { $$ = $1 + " WHEN" + $3 + " THEN " + $5; } + ; + +case_expr: + CASE expr whenthenlist_expr ELSE expr END { $$ = "CASE " + $2 + " " + $3 + " ELSE " + $5 + " END"; } + | CASE expr whenthenlist_expr END { $$ = "CASE " + $2 + " " + $3 + " END"; } + | CASE whenthenlist_expr ELSE expr END { $$ = "CASE " + $2 + " ELSE " + $4 + " END"; } + | CASE whenthenlist_expr END { $$ = "CASE " + $2 + " END"; } + ; + +raise_expr: + RAISE "(" IGNORE ")" { $$ = "RAISE(IGNORE)"; } + | RAISE "(" ROLLBACK "," STRINGLITERAL ")" { $$ = "RAISE(ROLLBACK, " + $5 + ")"; } + | RAISE "(" ABORT "," STRINGLITERAL ")" { $$ = "RAISE(ABORT, " + $5 + ")"; } + | RAISE "(" FAIL "," STRINGLITERAL ")" { $$ = "RAISE(FAIL, " + $5 + ")"; } + ; + +expr: + literalvalue + | allowed_keywords_as_identifier { $$ = sqlb::escapeIdentifier($1); } + | BINDPARAMETER + | id "." id "." id { $$ = sqlb::escapeIdentifier($1) + "." + sqlb::escapeIdentifier($3) + "." + sqlb::escapeIdentifier($5); } + | id "." id { $$ = sqlb::escapeIdentifier($1) + "." + sqlb::escapeIdentifier($3); } + | id { $$ = sqlb::escapeIdentifier($1); } + | unary_expr + | binary_expr + | function_expr + | "(" exprlist_expr ")" { $$ = "(" + $2 + ")"; } + | CAST "(" expr AS type_name ")" { $$ = "CAST(" + $3 + " AS " + $5 + ")"; } + | expr COLLATE id { $$ = $1 + " COLLATE " + $3; } + | like_expr + | isnull_expr + | between_expr + | in_expr + | case_expr + | raise_expr + // TODO Window functions + ; + +/* + * SELECT + */ + +select_stmt: + SELECT { $$ = "SELECT"; } // TODO + ; + +/* + * Helper rules for CREATE statements + */ + +optional_if_not_exists: + %empty { $$ = false; } + | IF NOT EXISTS { $$ = true; } + ; + +optional_sort_order: + %empty { $$ = ""; } + | ASC { $$ = "ASC"; } + | DESC { $$ = "DESC"; } + ; + +/* + * CREATE INDEX + */ + +optional_unique: + %empty { $$ = false; } + | UNIQUE { $$ = true; } + ; + +optional_where: + %empty { $$ = ""; } + | WHERE expr { $$ = $2; } + ; + +tableid_with_uninteresting_schema: + id "." tableid { $$ = $3; } + | TEMP "." tableid { $$ = $3; } + | tableid { $$ = $1; } + ; + +indexed_column: + expr optional_sort_order { + // If the expression is only one column name and nothing else, treat it as a column name; otherwise as an expression. + char quote = getIdentifierQuoteChar(); + if((quote == '[' && std::count($1.begin(), $1.end(), quote) == 1 && $1.front() == '[' && $1.back() == ']') || + (quote != '[' && std::count($1.begin(), $1.end(), quote) == 2 && $1.front() == quote && $1.back() == quote)) + { + $$ = sqlb::IndexedColumn(unquote_text($1, quote), false, $2); + } else { + $$ = sqlb::IndexedColumn($1, true, $2); + } + } + ; + +indexed_column_list: + indexed_column { $$ = sqlb::IndexedColumnVector(1, $1); } + | indexed_column_list "," indexed_column { $$ = $1; $$.push_back($3); } + ; + +createindex_stmt: + CREATE optional_unique INDEX optional_if_not_exists tableid_with_uninteresting_schema ON tableid "(" indexed_column_list ")" optional_where { + $$ = sqlb::IndexPtr(new sqlb::Index($5)); + $$->setTable($7); + $$->setUnique($2); + $$->setWhereExpr($11); + $$->fields = $9; + $$->setFullyParsed(true); + } + ; + +/* + * CREATE VIRTUAL TABLE + */ + +optional_exprlist_with_paren: + %empty { $$ = {}; } + | "(" ")" { $$ = {}; } + | "(" exprlist_expr ")" { $$ = $2; } + ; + +createvirtualtable_stmt: + CREATE VIRTUAL TABLE optional_if_not_exists tableid_with_uninteresting_schema USING id optional_exprlist_with_paren { + $$ = sqlb::TablePtr(new sqlb::Table($5)); + $$->setVirtualUsing($7); + $$->setFullyParsed(false); + } + ; + +/* + * CREATE TABLE + */ + +optional_temporary: + %empty { $$ = false; } + | TEMP { $$ = true; } + | TEMPORARY { $$ = true; } + ; + +optional_withoutrowid: + %empty { $$ = false; } + | WITHOUT ROWID { $$ = true; } + ; + +optional_conflictclause: + %empty { $$ = ""; } + | ON CONFLICT ROLLBACK { $$ = $3; } + | ON CONFLICT ABORT { $$ = $3; } + | ON CONFLICT FAIL { $$ = $3; } + | ON CONFLICT IGNORE { $$ = $3; } + | ON CONFLICT REPLACE { $$ = $3; } + ; + +optional_typename: + %empty { $$ = ""; } + | type_name { $$ = $1; } + ; + +optional_storage_identifier: + %empty { $$ = "VIRTUAL"; } + | STORED { $$ = "STORED"; } + | VIRTUAL { $$ = "VIRTUAL"; } + ; + +optional_always_generated: + %empty { $$ = false; } + | GENERATED ALWAYS { $$ = true; } + ; + +columnconstraint: + optional_constraintname PRIMARY KEY optional_sort_order optional_conflictclause { + $$.type = ColumnConstraintInfo::PrimaryKey; + $$.is_table_constraint = true; + sqlb::PrimaryKeyConstraint* pk = new sqlb::PrimaryKeyConstraint({sqlb::IndexedColumn("", false, $4)}); + pk->setName($1); + pk->setConflictAction($5); + $$.table_constraint = sqlb::ConstraintPtr(pk); + $$.fully_parsed = true; + } + | optional_constraintname PRIMARY KEY optional_sort_order optional_conflictclause AUTOINCREMENT { + $$.type = ColumnConstraintInfo::PrimaryKey; + $$.is_table_constraint = true; + sqlb::PrimaryKeyConstraint* pk = new sqlb::PrimaryKeyConstraint({sqlb::IndexedColumn("", false, $4)}); + pk->setName($1); + pk->setConflictAction($5); + pk->setAutoIncrement(true); + $$.table_constraint = sqlb::ConstraintPtr(pk); + $$.fully_parsed = true; + } + | optional_constraintname NOT NULL optional_conflictclause { + $$.type = ColumnConstraintInfo::NotNull; + $$.is_table_constraint = false; + $$.fully_parsed = ($1 == "" && $4 == ""); + } + | optional_constraintname NULL { + $$.type = ColumnConstraintInfo::None; + $$.is_table_constraint = false; + $$.fully_parsed = true; + } + | optional_constraintname UNIQUE optional_conflictclause { + $$.type = ColumnConstraintInfo::Unique; + $$.is_table_constraint = false; + $$.fully_parsed = ($1 == "" && $3 == ""); + } + | optional_constraintname CHECK "(" expr ")" { + $$.type = ColumnConstraintInfo::Check; + $$.is_table_constraint = false; + $$.text = $4; + $$.fully_parsed = ($1 == ""); + } + | optional_constraintname DEFAULT signednumber { + $$.type = ColumnConstraintInfo::Default; + $$.is_table_constraint = false; + $$.text = $3; + $$.fully_parsed = ($1 == ""); + } + | optional_constraintname DEFAULT literalvalue { + $$.type = ColumnConstraintInfo::Default; + $$.is_table_constraint = false; + $$.text = $3; + $$.fully_parsed = ($1 == ""); + } + | optional_constraintname DEFAULT id { + $$.type = ColumnConstraintInfo::Default; + $$.is_table_constraint = false; + $$.text = $3; + $$.fully_parsed = ($1 == ""); + } + | optional_constraintname DEFAULT allowed_keywords_as_identifier { // We must allow the same keywords as unquoted default values as in the columnid context. + // But we do not use columnid here in order to avoid reduce/reduce conflicts. + $$.type = ColumnConstraintInfo::Default; + $$.is_table_constraint = false; + $$.text = $3; + $$.fully_parsed = ($1 == ""); + } + | optional_constraintname DEFAULT IF { // Same as above. + $$.type = ColumnConstraintInfo::Default; + $$.is_table_constraint = false; + $$.text = $3; + $$.fully_parsed = ($1 == ""); + } + | optional_constraintname DEFAULT "(" expr ")" { + $$.type = ColumnConstraintInfo::Default; + $$.is_table_constraint = false; + $$.text = "(" + $4 + ")"; + $$.fully_parsed = ($1 == ""); + } + | optional_constraintname COLLATE id { + $$.type = ColumnConstraintInfo::Collate; + $$.is_table_constraint = false; + $$.text = $3; + $$.fully_parsed = ($1 == ""); + } + | optional_constraintname REFERENCES tableid optional_columnid_with_paren_list optional_fk_clause { // TODO Solve shift/reduce conflict. It is not super important though as shifting seems to be right here. + $$.type = ColumnConstraintInfo::ForeignKey; + $$.is_table_constraint = true; + sqlb::ForeignKeyClause* fk = new sqlb::ForeignKeyClause(); + fk->setName($1); + fk->setTable($3); + fk->setColumns($4); + fk->setConstraint($5); + $$.table_constraint = sqlb::ConstraintPtr(fk); + $$.fully_parsed = true; + } + | optional_constraintname optional_always_generated AS "(" expr ")" optional_storage_identifier { // TODO Solve shift/reduce conflict. + $$.type = ColumnConstraintInfo::Generated; + $$.is_table_constraint = false; + $$.generated_constraint.setExpression($5); + $$.generated_constraint.setStorage($7); + $$.generated_constraint.setName($1); + $$.fully_parsed = true; + } + ; + +columnconstraint_list: + columnconstraint { $$ = { $1 }; } + | columnconstraint_list columnconstraint { $$ = $1; $$.push_back($2); } + ; + +columndef: + columnid optional_typename columnconstraint_list { + sqlb::Field f($1, $2); + bool fully_parsed = true; + sqlb::ConstraintSet table_constraints{}; + for(auto c : $3) + { + if(c.fully_parsed == false) + fully_parsed = false; + + if(c.type == ColumnConstraintInfo::None) + continue; + + if(c.is_table_constraint) + { + if(c.table_constraint->columnList().empty()) + c.table_constraint->setColumnList({$1}); + else + c.table_constraint->replaceInColumnList("", $1); + table_constraints.insert(c.table_constraint); + } else { + if(c.type == ColumnConstraintInfo::NotNull) { + f.setNotNull(true); + } else if(c.type == ColumnConstraintInfo::Unique) { + f.setUnique(true); + } else if(c.type == ColumnConstraintInfo::Check) { + f.setCheck(c.text); + } else if(c.type == ColumnConstraintInfo::Default) { + f.setDefaultValue(c.text); + } else if(c.type == ColumnConstraintInfo::Collate) { + f.setCollation(c.text); + } else if(c.type == ColumnConstraintInfo::Generated) { + f.setGenerated(c.generated_constraint); + + // This is a hack which removes any "GENERATED ALWAYS" from the end of the type name. + // As of now these are shifted to the type instead of reducing the type when seeing the GENERATED identifier. + // TODO Remove this once the grammar is conflict free + const std::string generated_always = "GENERATED ALWAYS"; + if(f.type().size() >= generated_always.size() && f.type().compare(f.type().size() - generated_always.size(), generated_always.size(), generated_always) == 0) + { + std::string type = f.type().substr(0, f.type().size()-generated_always.size()); + if(type.back() == ' ') + type.pop_back(); + f.setType(type); + } + } else { + fully_parsed = false; + } + } + } + + $$ = std::make_tuple(f, table_constraints, fully_parsed); + } + | columnid optional_typename { $$ = std::make_tuple(sqlb::Field($1, $2), sqlb::ConstraintSet{}, true); } + ; + +columndef_list: + columndef { $$ = {$1}; } + | columndef_list "," columndef { $$ = $1; $$.push_back($3); } + ; + +optional_constraintname: + %empty { $$ = ""; } + | CONSTRAINT id { $$ = $2; } + ; + +columnid_list: + columnid { $$ = sqlb::StringVector(1, $1); } + | columnid_list "," columnid { $$ = $1; $$.push_back($3); } + ; + +optional_columnid_with_paren_list: + %empty { $$ = sqlb::StringVector(); } + | "(" columnid_list ")" { $$ = $2; } + ; + +fk_clause_part: + ON DELETE SET NULL { $$ = $1 + " " + $2 + " " + $3 + " " + $4; } + | ON DELETE SET DEFAULT { $$ = $1 + " " + $2 + " " + $3 + " " + $4; } + | ON DELETE CASCADE { $$ = $1 + " " + $2 + " " + $3; } + | ON DELETE RESTRICT { $$ = $1 + " " + $2 + " " + $3; } + | ON DELETE NO ACTION { $$ = $1 + " " + $2 + " " + $3 + " " + $4; } + | ON UPDATE SET NULL { $$ = $1 + " " + $2 + " " + $3 + " " + $4; } + | ON UPDATE SET DEFAULT { $$ = $1 + " " + $2 + " " + $3 + " " + $4; } + | ON UPDATE CASCADE { $$ = $1 + " " + $2 + " " + $3; } + | ON UPDATE RESTRICT { $$ = $1 + " " + $2 + " " + $3; } + | ON UPDATE NO ACTION { $$ = $1 + " " + $2 + " " + $3 + " " + $4; } + | ON INSERT SET NULL { $$ = $1 + " " + $2 + " " + $3 + " " + $4; } + | ON INSERT SET DEFAULT { $$ = $1 + " " + $2 + " " + $3 + " " + $4; } + | ON INSERT CASCADE { $$ = $1 + " " + $2 + " " + $3; } + | ON INSERT RESTRICT { $$ = $1 + " " + $2 + " " + $3; } + | ON INSERT NO ACTION { $$ = $1 + " " + $2 + " " + $3 + " " + $4; } + | MATCH id { $$ = $1 + " " + $2; } + ; + +fk_clause_part_list: + fk_clause_part { $$ = $1; } + | fk_clause_part_list fk_clause_part { $$ = $1 + " " + $2; } + ; + +optional_fk_clause: + %empty { $$ = ""; } + | fk_clause_part_list { $$ = $1; } + | fk_clause_part_list DEFERRABLE INITIALLY DEFERRED { $$ = $1 + " " + $2 + " " + $3 + " " + $4; } + | fk_clause_part_list DEFERRABLE INITIALLY IMMEDIATE { $$ = $1 + " " + $2 + " " + $3 + " " + $4; } + | fk_clause_part_list DEFERRABLE { $$ = $1 + " " + $2; } + | fk_clause_part_list NOT DEFERRABLE INITIALLY DEFERRED { $$ = $1 + " " + $2 + " " + $3 + " " + $4 + " " + $5; } + | fk_clause_part_list NOT DEFERRABLE INITIALLY IMMEDIATE { $$ = $1 + " " + $2 + " " + $3 + " " + $4 + " " + $5; } + | fk_clause_part_list NOT DEFERRABLE { $$ = $1 + " " + $2 + " " + $3; } + | DEFERRABLE INITIALLY DEFERRED { $$ = $1 + " " + $2 + " " + $3; } + | DEFERRABLE INITIALLY IMMEDIATE { $$ = $1 + " " + $2 + " " + $3; } + | DEFERRABLE { $$ = $1; } + | NOT DEFERRABLE INITIALLY DEFERRED { $$ = $1 + " " + $2 + " " + $3 + " " + $4; } + | NOT DEFERRABLE INITIALLY IMMEDIATE { $$ = $1 + " " + $2 + " " + $3 + " " + $4; } + | NOT DEFERRABLE { $$ = $1 + " " + $2; } + ; + +tableconstraint: + optional_constraintname PRIMARY KEY "(" indexed_column_list ")" optional_conflictclause { + sqlb::PrimaryKeyConstraint* pk = new sqlb::PrimaryKeyConstraint($5); + pk->setName($1); + pk->setConflictAction($7); + $$ = sqlb::ConstraintPtr(pk); + } + | optional_constraintname PRIMARY KEY "(" indexed_column_list AUTOINCREMENT ")" optional_conflictclause { + sqlb::PrimaryKeyConstraint* pk = new sqlb::PrimaryKeyConstraint($5); + pk->setName($1); + pk->setConflictAction($8); + pk->setAutoIncrement(true); + $$ = sqlb::ConstraintPtr(pk); + } + | optional_constraintname UNIQUE "(" indexed_column_list ")" optional_conflictclause { + sqlb::UniqueConstraint* u = new sqlb::UniqueConstraint($4); + u->setName($1); + u->setConflictAction($6); + $$ = sqlb::ConstraintPtr(u); + } + | optional_constraintname CHECK "(" expr ")" { + $$ = sqlb::ConstraintPtr(new sqlb::CheckConstraint($4)); + $$->setName($1); + } + | optional_constraintname FOREIGN KEY "(" columnid_list ")" REFERENCES tableid optional_columnid_with_paren_list optional_fk_clause { + $$ = sqlb::ConstraintPtr(new sqlb::ForeignKeyClause($8, $9, $10)); + $$->setColumnList($5); + $$->setName($1); + } + ; + +tableconstraint_list: + tableconstraint { $$ = {$1}; } + | tableconstraint_list "," tableconstraint { $$ = $1; $$.insert($3); } + | tableconstraint_list tableconstraint { $$ = $1; $$.insert($2); } + ; + +optional_tableconstraint_list: + %empty { $$ = {}; } + | "," tableconstraint_list { $$ = $2; } + ; + +createtable_stmt: + CREATE optional_temporary TABLE optional_if_not_exists tableid_with_uninteresting_schema AS select_stmt { + $$ = sqlb::TablePtr(new sqlb::Table($5)); + $$->setFullyParsed(false); + } + | CREATE optional_temporary TABLE optional_if_not_exists tableid_with_uninteresting_schema "(" columndef_list optional_tableconstraint_list ")" optional_withoutrowid { + $$ = sqlb::TablePtr(new sqlb::Table($5)); + $$->setWithoutRowidTable($10); + $$->setConstraints($8); + $$->setFullyParsed(true); + + for(const auto& column : $7) + { + sqlb::Field f; + sqlb::ConstraintSet c; + bool fully_parsed; + std::tie(f, c, fully_parsed) = column; + + if(fully_parsed == false) + $$->setFullyParsed(false); + $$->fields.push_back(f); + for(const auto& i : c) + $$->addConstraint(i); + } + } + ; + +%% + +void sqlb::parser::parser::error(const location_type& l, const std::string& m) +{ + std::cerr << l << ": " << m << std::endl; +} diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/sql/sqlitetypes.cpp b/src/WBCLFZSystemModule/SqliteDBProcess/src/sql/sqlitetypes.cpp new file mode 100644 index 0000000..be915dd --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/sql/sqlitetypes.cpp @@ -0,0 +1,712 @@ +#include "sqlitetypes.h" +#include "ObjectIdentifier.h" +#include "parser/ParserDriver.h" + +#include +#include +#include + +namespace sqlb { + +StringVector escapeIdentifier(StringVector ids) +{ + std::transform(ids.begin(), ids.end(), ids.begin(), [](const std::string& id) { + return escapeIdentifier(id); + }); + return ids; +} + +std::string joinStringVector(const StringVector& vec, const std::string& delim) +{ + return std::accumulate(vec.begin(), vec.end(), std::string(), [delim](const std::string& so_far, const std::string& s) { + return so_far.empty() ? s : so_far + delim + s; + }); +} + +bool Object::operator==(const Object& rhs) const +{ + if(m_name != rhs.m_name) + return false; + if(m_fullyParsed != rhs.m_fullyParsed) // We check for the fully parsed flag to make sure not to lose anything in some corner cases + return false; + + // We don't care about the original SQL text + + return true; +} + +std::string Object::typeToString(Types type) +{ + switch(type) + { + case Types::Table: return "table"; + case Types::Index: return "index"; + case Types::View: return "view"; + case Types::Trigger: return "trigger"; + } + return std::string(); +} + +ConstraintPtr Constraint::makeConstraint(ConstraintTypes type) +{ + switch(type) + { + case PrimaryKeyConstraintType: + return std::make_shared(); + case UniqueConstraintType: + return std::make_shared(); + case ForeignKeyConstraintType: + return std::make_shared(); + case CheckConstraintType: + return std::make_shared(); + default: + return nullptr; + } +} + +void Constraint::replaceInColumnList(const std::string& from, const std::string& to) +{ + std::replace(column_list.begin(), column_list.end(), from, to); +} + +void Constraint::removeFromColumnList(const std::string& key) +{ + column_list.erase(std::remove(column_list.begin(), column_list.end(), key), column_list.end()); +} + +bool ForeignKeyClause::isSet() const +{ + return m_override.size() || m_table.size(); +} + +std::string ForeignKeyClause::toString() const +{ + if(!isSet()) + return std::string(); + + if(m_override.size()) + return m_override; + + std::string result = escapeIdentifier(m_table); + + if(m_columns.size()) + result += "(" + joinStringVector(escapeIdentifier(m_columns), ",") + ")"; + + if(m_constraint.size()) + result += " " + m_constraint; + + return result; +} + +void ForeignKeyClause::setFromString(const std::string& fk) +{ + m_override = fk; +} + +std::string ForeignKeyClause::toSql() const +{ + std::string result; + if(!m_name.empty()) + result = "CONSTRAINT " + escapeIdentifier(m_name) + " "; + result += "FOREIGN KEY(" + joinStringVector(escapeIdentifier(column_list), ",") + ") REFERENCES " + this->toString(); + + return result; +} + +UniqueConstraint::UniqueConstraint(const IndexedColumnVector& columns) : + m_columns(columns) +{ + // Extract column names and give them to the column list in the base class + for(const auto& c : columns) + column_list.push_back(c.name()); +} + +UniqueConstraint::UniqueConstraint(const StringVector& columns) : + Constraint(columns) +{ + setColumnList(columns); +} + +void UniqueConstraint::setColumnList(const StringVector& list) +{ + Constraint::setColumnList(list); + + // Create our own column list without sort orders etc + m_columns.clear(); + for(const auto& c : list) + m_columns.push_back(IndexedColumn(c, false)); +} + +void UniqueConstraint::addToColumnList(const std::string& key) +{ + Constraint::addToColumnList(key); + + // Also add to our own column list + m_columns.push_back(IndexedColumn(key, false)); +} + +void UniqueConstraint::replaceInColumnList(const std::string& from, const std::string& to) +{ + Constraint::replaceInColumnList(from, to); + + for(auto& c : m_columns) + { + if(c.name() == from) + c.setName(to); + } +} + +void UniqueConstraint::removeFromColumnList(const std::string& key) +{ + Constraint::removeFromColumnList(key); + + m_columns.erase(std::remove_if(m_columns.begin(), m_columns.end(), [key](const IndexedColumn& c) { + if(c.name() == key) + return true; + else + return false; + }), m_columns.end()); +} + +std::string UniqueConstraint::toSql() const +{ + std::string result; + if(!m_name.empty()) + result = "CONSTRAINT " + escapeIdentifier(m_name) + " "; + + std::vector u_columns; + for(const auto& c : m_columns) + u_columns.push_back(c.toString("", " ")); + result += "UNIQUE(" + joinStringVector(u_columns, ",") + ")"; + + if(!m_conflictAction.empty()) + result += " ON CONFLICT " + m_conflictAction; + + return result; +} + +PrimaryKeyConstraint::PrimaryKeyConstraint(const IndexedColumnVector& columns) : + UniqueConstraint(columns), + m_auto_increment(false) +{ +} + +PrimaryKeyConstraint::PrimaryKeyConstraint(const StringVector& columns) : + UniqueConstraint(columns), + m_auto_increment(false) +{ +} + +std::string PrimaryKeyConstraint::toSql() const +{ + std::string result; + if(!m_name.empty()) + result = "CONSTRAINT " + escapeIdentifier(m_name) + " "; + + std::vector pk_columns; + for(const auto& c : m_columns) + pk_columns.push_back(c.toString("", " ")); + result += "PRIMARY KEY(" + joinStringVector(pk_columns, ",") + (m_auto_increment ? " AUTOINCREMENT" : "") + ")"; + + if(!m_conflictAction.empty()) + result += " ON CONFLICT " + m_conflictAction; + + return result; +} + +std::string CheckConstraint::toSql() const +{ + std::string result; + if(!m_name.empty()) + result = "CONSTRAINT " + escapeIdentifier(m_name) + " "; + result += "CHECK(" + m_expression + ")"; + + return result; +} + +std::string GeneratedColumnConstraint::toSql() const +{ + std::string result; + if(!m_name.empty()) + result = "CONSTRAINT " + escapeIdentifier(m_name) + " "; + result += "GENERATED ALWAYS AS (" + m_expression + ")" + " " + storage(); + + return result; +} + +bool Field::operator==(const Field& rhs) const +{ + if(m_name != rhs.m_name) + return false; + if(m_type != rhs.m_type) + return false; + if(m_notnull != rhs.m_notnull) + return false; + if(m_check != rhs.m_check) + return false; + if(m_defaultvalue != rhs.m_defaultvalue) + return false; + if(m_unique != rhs.m_unique) + return false; + if(m_collation != rhs.m_collation) + return false; + + return true; +} + +std::string Field::toString(const std::string& indent, const std::string& sep) const +{ + std::string str = indent + escapeIdentifier(m_name) + sep + m_type; + if(m_notnull) + str += " NOT NULL"; + if(!m_defaultvalue.empty()) + str += " DEFAULT " + m_defaultvalue; + if(!m_check.empty()) + str += " CHECK(" + m_check + ")"; + if(m_unique) + str += " UNIQUE"; + if(!m_collation.empty()) + str += " COLLATE " + m_collation; + if(!m_generated.empty()) + str += " " + m_generated.toSql(); + return str; +} + +bool Field::isText() const +{ + if(starts_with_ci(m_type, "character")) return true; + if(starts_with_ci(m_type, "varchar")) return true; + if(starts_with_ci(m_type, "varying character")) return true; + if(starts_with_ci(m_type, "nchar")) return true; + if(starts_with_ci(m_type, "native character")) return true; + if(starts_with_ci(m_type, "nvarchar")) return true; + if(compare_ci(m_type, "text")) return true; + if(compare_ci(m_type, "clob")) return true; + return false; +} + +bool Field::isInteger() const +{ + if(compare_ci(m_type, "int")) return true; + if(compare_ci(m_type, "integer")) return true; + if(compare_ci(m_type, "tinyint")) return true; + if(compare_ci(m_type, "smallint")) return true; + if(compare_ci(m_type, "mediumint")) return true; + if(compare_ci(m_type, "bigint")) return true; + if(compare_ci(m_type, "unsigned big int")) return true; + if(compare_ci(m_type, "int2")) return true; + if(compare_ci(m_type, "int8")) return true; + return false; +} + +bool Field::isReal() const +{ + if(compare_ci(m_type, "real")) return true; + if(compare_ci(m_type, "double")) return true; + if(compare_ci(m_type, "double precision")) return true; + if(compare_ci(m_type, "float")) return true; + return false; +} + +bool Field::isNumeric() const +{ + if(starts_with_ci(m_type, "decimal")) return true; + if(compare_ci(m_type, "numeric")) return true; + if(compare_ci(m_type, "boolean")) return true; + if(compare_ci(m_type, "date")) return true; + if(compare_ci(m_type, "datetime")) return true; + return false; +} + +bool Field::isBlob() const +{ + if(m_type.empty()) return true; + if(compare_ci(m_type, "blob")) return true; + return false; +} + +Field::Affinity Field::affinity() const +{ + if (isInteger()) return IntegerAffinity; + + if (isText()) return TextAffinity; + + if (isBlob()) return BlobAffinity; + + if (isReal() || isNumeric()) return FloatAffinity; + + return BlobAffinity; +} + +Table::Table(const Table& table) + : Object(table.name()) +{ + *this = table; +} + +Table& Table::operator=(const Table& rhs) +{ + // Base class + Object::operator=(rhs); + + // Just assign the simple values + m_withoutRowid = rhs.m_withoutRowid; + m_virtual = rhs.m_virtual; + + // Clear the fields and the constraints first in order to avoid duplicates and/or old data in the next step + fields.clear(); + m_constraints.clear(); + + // Make copies of the fields and the constraints. This is necessary in order to avoid any unwanted changes to the application's main database + // schema representation just by modifying a reference to the fields or constraints and thinking it operates on a copy. + std::copy(rhs.fields.begin(), rhs.fields.end(), std::back_inserter(fields)); + m_constraints = rhs.m_constraints; + + return *this; +} + +bool Table::operator==(const Table& rhs) const +{ + if(!Object::operator==(rhs)) + return false; + + if(m_withoutRowid != rhs.m_withoutRowid) + return false; + if(m_virtual != rhs.m_virtual) + return false; + if(fields != rhs.fields) + return false; + if(m_constraints != rhs.m_constraints) + return false; + + return true; +} + +StringVector Table::fieldList() const +{ + StringVector sl; + + for(const Field& f : fields) + sl.push_back(f.toString()); + + return sl; +} + +StringVector Table::fieldNames() const +{ + StringVector sl; + + for(const Field& f : fields) + sl.push_back(f.name()); + + return sl; +} + +StringVector Table::rowidColumns() const +{ + // For WITHOUT ROWID tables this function returns the names of the primary key column. For ordinary tables with a rowid column, it returns "_rowid_" + if(m_withoutRowid) + return const_cast(this)->primaryKey()->columnList(); + else + return {"_rowid_"}; +} + +FieldInfoList Table::fieldInformation() const +{ + FieldInfoList result; + for(const Field& f : fields) + result.emplace_back(f.name(), f.type(), f.toString(" ", " ")); + return result; +} + +TablePtr Table::parseSQL(const std::string& sSQL) +{ + parser::ParserDriver drv; + if(!drv.parse(sSQL)) + { + TablePtr t = std::dynamic_pointer_cast(drv.result); + t->setOriginalSql(sSQL); + return t; + } else { + std::cerr << "Sqlite parse error: " << sSQL << std::endl; + return std::make_shared
(""); + } +} + +std::string Table::sql(const std::string& schema, bool ifNotExists) const +{ + // Special handling for virtual tables: just build an easy create statement and copy the using part in there + if(isVirtual()) + return "CREATE VIRTUAL TABLE " + ObjectIdentifier(schema, m_name).toString(true) + " USING " + m_virtual + ";"; + + // This is a normal table, not a virtual one + std::string sql = "CREATE TABLE "; + if(ifNotExists) + sql += "IF NOT EXISTS "; + sql += ObjectIdentifier(schema, m_name).toString(true); + sql += " (\n"; + + sql += joinStringVector(fieldList(), ",\n"); + + // Constraints + for(const auto& it : m_constraints) + { + // Ignore all constraints without any fields, except for check constraints which don't rely on a field vector + if(!it->columnList().empty() || it->type() == Constraint::CheckConstraintType) + { + sql += ",\n\t"; + sql += it->toSql(); + } + } + + sql += "\n)"; + + // without rowid + if(withoutRowidTable()) + sql += " WITHOUT ROWID"; + + return sql + ";"; +} + +void Table::addConstraint(ConstraintPtr constraint) +{ + m_constraints.insert(constraint); +} + +void Table::setConstraint(ConstraintPtr constraint) +{ + // Delete any old constraints of this type for these fields + removeConstraints(constraint->columnList(), constraint->type()); + + // Add the new constraint to the table, effectively overwriting all old constraints for that fields/type combination + addConstraint(constraint); +} + +void Table::removeConstraint(ConstraintPtr constraint) +{ + for(auto it = m_constraints.begin();it!=m_constraints.end();++it) + { + if((*it)->toSql() == constraint->toSql()) + { + m_constraints.erase(it); + + // Only remove the first constraint matching these criteria + return; + } + } +} + +void Table::removeConstraints(const StringVector& vStrFields, Constraint::ConstraintTypes type) +{ + for(auto it = m_constraints.begin();it!=m_constraints.end();) + { + if((*it)->columnList() == vStrFields && (*it)->type() == type) + m_constraints.erase(it++); + else + ++it; + } +} + +ConstraintPtr Table::constraint(const StringVector& vStrFields, Constraint::ConstraintTypes type) const +{ + auto list = constraints(vStrFields, type); + if(list.size()) + return list.at(0); + else + return ConstraintPtr(nullptr); +} + +std::vector Table::constraints(const StringVector& vStrFields, Constraint::ConstraintTypes type) const +{ + std::vector clist; + for(const auto& it : m_constraints) + { + if((type == Constraint::NoType || it->type() == type) && (vStrFields.empty() || it->columnList() == vStrFields)) + clist.push_back(it); + } + return clist; +} + +void Table::setConstraints(const ConstraintSet& constraints) +{ + m_constraints = constraints; +} + +void Table::replaceConstraint(ConstraintPtr from, ConstraintPtr to) +{ + auto it = m_constraints.find(from); + if(it == m_constraints.end()) + return; + + m_constraints.erase(it); // Erase old constraint + m_constraints.insert(to); // Insert new constraint +} + +std::shared_ptr Table::primaryKey() +{ + const auto c = constraint({}, Constraint::PrimaryKeyConstraintType); + if(c) + return std::dynamic_pointer_cast(c); + else + return nullptr; +} + +void Table::removeKeyFromAllConstraints(const std::string& key) +{ + // Update all constraints + for(auto it=m_constraints.begin();it!=m_constraints.end();) + { + // Check if they contain the old key name + if(contains((*it)->columnList(), key)) + { + // If so, remove it from the column list + (*it)->removeFromColumnList(key); + + // If the column list is empty now, remove the entire constraint. Otherwise save the updated column list + if((*it)->columnList().empty()) + it = m_constraints.erase(it); + else + ++it; + } else { + ++it; + } + } +} + +void Table::renameKeyInAllConstraints(const std::string& key, const std::string& to) +{ + // Do nothing if the key hasn't really changed + if(key == to) + return; + + // Find all occurrences of the key and change it to the new one + for(auto& it : m_constraints) + { + if(contains(it->columnList(), key)) + it->replaceInColumnList(key, to); + } +} + + + +std::string IndexedColumn::toString(const std::string& indent, const std::string& sep) const +{ + std::string name = m_isExpression ? m_name : escapeIdentifier(m_name); + std::string order = (m_order.empty() ? "" : (sep + m_order)); + return indent + name + order; +} + +Index& Index::operator=(const Index& rhs) +{ + // Base class + Object::operator=(rhs); + + // Just assign the easy stuff + m_unique = rhs.m_unique; + m_table = rhs.m_table; + m_whereExpr = rhs.m_whereExpr; + + // Make copies of the column + std::copy(rhs.fields.begin(), rhs.fields.end(), std::back_inserter(fields)); + + return *this; +} + +StringVector Index::columnSqlList() const +{ + StringVector sl; + + for(const IndexedColumn& c : fields) + sl.push_back(c.toString()); + + return sl; +} + +std::string Index::sql(const std::string& schema, bool ifNotExists) const +{ + // Start CREATE (UNIQUE) INDEX statement + std::string sql; + if(m_unique) + sql = "CREATE UNIQUE INDEX "; + else + sql = "CREATE INDEX "; + if(ifNotExists) + sql += "IF NOT EXISTS "; + sql += ObjectIdentifier(schema, m_name).toString(true); + sql += " ON "; + sql += sqlb::escapeIdentifier(m_table); + sql += " (\n"; + + // Add column list + sql += joinStringVector(columnSqlList(), ",\n"); + + // Add partial index bit + sql += "\n)"; + if(!m_whereExpr.empty()) + sql += " WHERE " + m_whereExpr; + + return sql + ";"; +} + +FieldInfoList Index::fieldInformation() const +{ + FieldInfoList result; + for(const IndexedColumn& c : fields) + result.emplace_back(c.name(), c.order(), c.toString(" ", " ")); + return result; +} + +IndexPtr Index::parseSQL(const std::string& sSQL) +{ + parser::ParserDriver drv; + if(!drv.parse(sSQL)) + { + IndexPtr i = std::dynamic_pointer_cast(drv.result); + i->setOriginalSql(sSQL); + return i; + } else { + std::cerr << "Sqlite parse error: " << sSQL << std::endl; + return std::make_shared(""); + } +} + + + +ViewPtr View::parseSQL(const std::string& sSQL) +{ + // TODO + + auto v = std::make_shared(""); + v->setOriginalSql(sSQL); + return v; +} + +StringVector View::fieldNames() const +{ + StringVector sl; + + for(const Field& f : fields) + sl.push_back(f.name()); + + return sl; +} + +FieldInfoList View::fieldInformation() const +{ + FieldInfoList result; + for(const Field& f : fields) + result.emplace_back(f.name(), f.type(), f.toString(" ", " ")); + return result; +} + + +TriggerPtr Trigger::parseSQL(const std::string& sSQL) +{ + // TODO + + auto t = std::make_shared(""); + t->setOriginalSql(sSQL); + return t; +} + +} //namespace sqlb diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/sql/sqlitetypes.h b/src/WBCLFZSystemModule/SqliteDBProcess/src/sql/sqlitetypes.h new file mode 100644 index 0000000..ea12158 --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/sql/sqlitetypes.h @@ -0,0 +1,618 @@ +#pragma once +#ifndef SQLITETYPES_H +#define SQLITETYPES_H + +#include +#include +#include +#include +#include +#include + +template +bool contains(const C& container, E element) +{ + return std::find(container.begin(), container.end(), element) != container.end(); +} + +template +bool compare_ci(const T& a, const T& b) +{ + // Note: This function does not have to be (actually it must not be) fully UTF-8 aware because SQLite itself is not either. + + if(a.length() != b.length()) + return false; + return std::equal(a.begin(), a.end(), b.begin(), [](unsigned char c1, unsigned char c2) { + return std::tolower(c1) == std::tolower(c2); + }); + + // TODO Replace the entire code above by the following once we have enabled C++14 support + /*return std::equal(a.begin(), a.end(), b.begin(), b.end(), [](unsigned char c1, unsigned char c2) { + return std::tolower(c1) == std::tolower(c2); + });*/ +} + +template +bool compare_ci(const T& a, const char* b) +{ + return compare_ci(a, std::string(b)); +} + +inline bool starts_with_ci(const std::string& str, const std::string& with) +{ + if(str.size() < with.size()) + return false; + else + return compare_ci(str.substr(0, with.size()), with); +} + +namespace sqlb { + +using StringVector = std::vector; + +StringVector escapeIdentifier(StringVector ids); +std::string joinStringVector(const StringVector& vec, const std::string& delim); + +class Object; +class Table; +class Index; +class View; +class Trigger; +class Field; +class Constraint; +class IndexedColumn; +struct FieldInfo; +using ObjectPtr = std::shared_ptr; +using TablePtr = std::shared_ptr
; +using IndexPtr = std::shared_ptr; +using ViewPtr = std::shared_ptr; +using TriggerPtr = std::shared_ptr; +using ConstraintPtr = std::shared_ptr; +using FieldVector = std::vector; +using IndexedColumnVector = std::vector; +using ConstraintSet = std::set; +using FieldInfoList = std::vector; + +struct FieldInfo +{ + FieldInfo(const std::string& name_, const std::string& type_, const std::string& sql_) + : name(name_), type(type_), sql(sql_) + {} + + std::string name; + std::string type; + std::string sql; +}; + +class Object +{ +public: + enum Types + { + Table, + Index, + View, + Trigger + }; + + explicit Object(const std::string& name): m_name(name), m_fullyParsed(false) {} + virtual ~Object() = default; + + bool operator==(const Object& rhs) const; + + virtual Types type() const = 0; + static std::string typeToString(Types type); + + void setName(const std::string& name) { m_name = name; } + const std::string& name() const { return m_name; } + + void setOriginalSql(const std::string& original_sql) { m_originalSql = original_sql; } + std::string originalSql() const { return m_originalSql; } + + virtual std::string baseTable() const { return std::string(); } + + void setFullyParsed(bool fully_parsed) { m_fullyParsed = fully_parsed; } + bool fullyParsed() const { return m_fullyParsed; } + + virtual FieldInfoList fieldInformation() const { return FieldInfoList(); } + + /** + * @brief Returns the CREATE statement for this object + * @param schema The schema name of the object + * @param ifNotExists If set to true the "IF NOT EXISTS" qualifier will be added to the create statement + * @return A std::string with the CREATE statement. + */ + virtual std::string sql(const std::string& schema = std::string("main"), bool ifNotExists = false) const = 0; + +protected: + std::string m_name; + std::string m_originalSql; + bool m_fullyParsed; +}; + +class Constraint +{ +public: + enum ConstraintTypes + { + PrimaryKeyConstraintType, + UniqueConstraintType, + ForeignKeyConstraintType, + CheckConstraintType, + GeneratedColumnConstraintType, + + NoType = 999, + }; + + explicit Constraint(const StringVector& columns = {}, const std::string& name = std::string()) + : column_list(columns), + m_name(name) + { + } + virtual ~Constraint() = default; + + static ConstraintPtr makeConstraint(ConstraintTypes type); + + virtual ConstraintTypes type() const = 0; + + void setName(const std::string& name) { m_name = name; } + const std::string& name() const { return m_name; } + + StringVector columnList() const { return column_list; } + virtual void setColumnList(const StringVector& list) { column_list = list; } + virtual void addToColumnList(const std::string& key) { column_list.push_back(key); } + virtual void replaceInColumnList(const std::string& from, const std::string& to); + virtual void removeFromColumnList(const std::string& key); + + virtual std::string toSql() const = 0; + +protected: + StringVector column_list; + std::string m_name; +}; + +class ForeignKeyClause : public Constraint +{ +public: + ForeignKeyClause(const std::string& table = std::string(), const StringVector& columns = {}, const std::string& constraint = std::string()) + : m_table(table), + m_columns(columns), + m_constraint(constraint) + { + } + + bool isSet() const; + std::string toString() const; + void setFromString(const std::string& fk); + + void setTable(const std::string& table) { m_override.clear(); m_table = table; } + const std::string& table() const { return m_table; } + + void setColumns(const StringVector& columns) { m_columns = columns; } + const StringVector& columns() const { return m_columns; } + + void setConstraint(const std::string& constraint) { m_constraint = constraint; } + const std::string& constraint() const { return m_constraint; } + + std::string toSql() const override; + + ConstraintTypes type() const override { return ForeignKeyConstraintType; } + +private: + std::string m_table; + StringVector m_columns; + std::string m_constraint; + + std::string m_override; +}; + +class UniqueConstraint : public Constraint +{ +public: + explicit UniqueConstraint(const IndexedColumnVector& columns = {}); + explicit UniqueConstraint(const StringVector& columns); + + void setConflictAction(const std::string& conflict) { m_conflictAction = conflict; } + const std::string& conflictAction() const { return m_conflictAction; } + + // We override these because we maintain our own copy of the column_list variable in m_columns. + // This needs to be done because in a unique constraint we can add expressions, sort order, etc. to the + // list of columns. + void setColumnList(const StringVector& list) override; + void addToColumnList(const std::string& key) override; + void replaceInColumnList(const std::string& from, const std::string& to) override; + void removeFromColumnList(const std::string& key) override; + + std::string toSql() const override; + + ConstraintTypes type() const override { return UniqueConstraintType; } + +protected: + IndexedColumnVector m_columns; + std::string m_conflictAction; +}; + +class PrimaryKeyConstraint : public UniqueConstraint +{ + // Primary keys are a sort of unique constraint for us. This matches quite nicely as both can have a conflict action + // and both need to maintain a copy of the column list with sort order information etc. + +public: + explicit PrimaryKeyConstraint(const IndexedColumnVector& columns = {}); + explicit PrimaryKeyConstraint(const StringVector& columns); + + void setAutoIncrement(bool ai) { m_auto_increment = ai; } + bool autoIncrement() const { return m_auto_increment; } + + std::string toSql() const override; + + ConstraintTypes type() const override { return PrimaryKeyConstraintType; } + +private: + bool m_auto_increment; +}; + +class CheckConstraint : public Constraint +{ +public: + explicit CheckConstraint(const std::string& expr = std::string()) + : m_expression(expr) + { + } + + void setExpression(const std::string& expr) { m_expression = expr; } + const std::string& expression() const { return m_expression; } + + std::string toSql() const override; + + ConstraintTypes type() const override { return CheckConstraintType; } + +private: + std::string m_expression; +}; + +class GeneratedColumnConstraint : public Constraint +{ +public: + explicit GeneratedColumnConstraint(const std::string& expr = std::string(), const std::string& storage = "VIRTUAL") + : m_expression(expr), + m_storage(storage) + { + } + + bool empty() const { return m_expression.empty(); } + + void setExpression(const std::string& expr) { m_expression = expr; } + const std::string& expression() const { return m_expression; } + + void setStorage(const std::string& storage) { m_storage = storage; } + std::string storage() const { return m_storage.empty() ? "VIRTUAL" : m_storage; } + + std::string toSql() const override; + + ConstraintTypes type() const override { return GeneratedColumnConstraintType; } + +private: + std::string m_expression; + std::string m_storage; +}; + +class Field +{ +public: + Field() + : m_notnull(false), + m_unique(false) + {} + + Field(const std::string& name, + const std::string& type, + bool notnull = false, + const std::string& defaultvalue = std::string(), + const std::string& check = std::string(), + bool unique = false, + const std::string& collation = std::string()) + : m_name(name) + , m_type(type) + , m_notnull(notnull) + , m_check(check) + , m_defaultvalue(defaultvalue) + , m_unique(unique) + , m_collation(collation) + {} + + bool operator==(const Field& rhs) const; + + std::string toString(const std::string& indent = "\t", const std::string& sep = "\t") const; + + void setName(const std::string& name) { m_name = name; } + void setType(const std::string& type) { m_type = type; } + void setNotNull(bool notnull = true) { m_notnull = notnull; } + void setCheck(const std::string& check) { m_check = check; } + void setDefaultValue(const std::string& defaultvalue) { m_defaultvalue = defaultvalue; } + void setUnique(bool u) { m_unique = u; } + void setCollation(const std::string& collation) { m_collation = collation; } + + bool isText() const; + bool isInteger() const; + bool isBlob() const; + bool isReal() const; + bool isNumeric() const; + + // Type affinity of the column according to SQLite3 rules. + // The Affinity enum values match the SQLITE_INTEGER, SQLITE_FLOAT, SQLITE_BLOB, and SQLITE_TEXT constants + enum Affinity + { + IntegerAffinity = 1, + FloatAffinity = 2, + TextAffinity = 3, + BlobAffinity = 4, + }; + Affinity affinity() const; + + const std::string& name() const { return m_name; } + const std::string& type() const { return m_type; } + bool notnull() const { return m_notnull; } + const std::string& check() const { return m_check; } + const std::string& defaultValue() const { return m_defaultvalue; } + bool unique() const { return m_unique; } + const std::string& collation() const { return m_collation; } + + const GeneratedColumnConstraint& generated() const { return m_generated; } + GeneratedColumnConstraint& generated() { return m_generated; } + void setGenerated(const GeneratedColumnConstraint& gen) { m_generated = gen; } + +private: + std::string m_name; + std::string m_type; + bool m_notnull; + std::string m_check; + std::string m_defaultvalue; + bool m_unique; + std::string m_collation; + GeneratedColumnConstraint m_generated; +}; + +class Table : public Object +{ +public: + explicit Table(const std::string& name): Object(name), m_withoutRowid(false) {} + explicit Table(const Table& table); + Table& operator=(const Table& rhs); + + bool operator==(const Table& rhs) const; + + Types type() const override { return Object::Table; } + + FieldVector fields; + using field_type = Field; + using field_iterator = FieldVector::iterator; + + /** + * @brief Returns the CREATE TABLE statement for this table object + * @return A std::string with the CREATE TABLE object. + */ + std::string sql(const std::string& schema = "main", bool ifNotExists = false) const override; + + StringVector fieldNames() const; + + StringVector rowidColumns() const; + void setWithoutRowidTable(bool without_rowid) { m_withoutRowid = without_rowid; } + bool withoutRowidTable() const { return m_withoutRowid; } + + void setVirtualUsing(const std::string& virt_using) { m_virtual = virt_using; } + const std::string& virtualUsing() const { return m_virtual; } + bool isVirtual() const { return !m_virtual.empty(); } + + FieldInfoList fieldInformation() const override; + + void addConstraint(ConstraintPtr constraint); + void setConstraint(ConstraintPtr constraint); + void removeConstraint(ConstraintPtr constraint); + void removeConstraints(const StringVector& vStrFields = StringVector(), Constraint::ConstraintTypes type = Constraint::NoType); + ConstraintPtr constraint(const StringVector& vStrFields = StringVector(), Constraint::ConstraintTypes type = Constraint::NoType) const; //! Only returns the first constraint, if any + std::vector constraints(const StringVector& vStrFields = StringVector(), Constraint::ConstraintTypes type = Constraint::NoType) const; + ConstraintSet allConstraints() const { return m_constraints; } + void setConstraints(const ConstraintSet& constraints); + void replaceConstraint(ConstraintPtr from, ConstraintPtr to); + std::shared_ptr primaryKey(); + void removeKeyFromAllConstraints(const std::string& key); + void renameKeyInAllConstraints(const std::string& key, const std::string& to); + + /** + * @brief parseSQL Parses the create Table statement in sSQL. + * @param sSQL The create table statement. + * @return The table object. The table object may be empty if parsing failed. + */ + static TablePtr parseSQL(const std::string& sSQL); +private: + StringVector fieldList() const; + +private: + bool m_withoutRowid; + ConstraintSet m_constraints; + std::string m_virtual; +}; + +class IndexedColumn +{ +public: + IndexedColumn() + : m_isExpression(false) + { + } + + IndexedColumn(const std::string& name, bool expr, const std::string& order = std::string()) + : m_name(name), + m_isExpression(expr), + m_order(order) + { + } + + void setName(const std::string& name) { m_name = name; } + const std::string& name() const { return m_name; } + + void setExpression(bool expr) { m_isExpression = expr; } + bool expression() const { return m_isExpression; } + + void setOrder(const std::string& order) { m_order = order; } + std::string order() const { return m_order; } + + std::string toString(const std::string& indent = "\t", const std::string& sep = "\t") const; + +private: + std::string m_name; + bool m_isExpression; + std::string m_order; +}; + +class Index : public Object +{ +public: + explicit Index(const std::string& name): Object(name), m_unique(false) {} + Index& operator=(const Index& rhs); + + Types type() const override { return Object::Index; } + + IndexedColumnVector fields; + using field_type = IndexedColumn; + using field_iterator = IndexedColumnVector::iterator; + + std::string baseTable() const override { return m_table; } + + void setUnique(bool unique) { m_unique = unique; } + bool unique() const { return m_unique; } + + void setTable(const std::string& table) { m_table = table; } + const std::string& table() const { return m_table; } + + void setWhereExpr(const std::string& expr) { m_whereExpr = expr; } + const std::string& whereExpr() const { return m_whereExpr; } + + /** + * @brief Returns the CREATE INDEX statement for this index object + * @return A std::string with the CREATE INDEX object. + */ + std::string sql(const std::string& schema = "main", bool ifNotExists = false) const override; + + /** + * @brief parseSQL Parses the CREATE INDEX statement in sSQL. + * @param sSQL The create index statement. + * @return The index object. The index object may be empty if the parsing failed. + */ + static IndexPtr parseSQL(const std::string& sSQL); + + FieldInfoList fieldInformation() const override; + +private: + StringVector columnSqlList() const; + + bool m_unique; + std::string m_table; + std::string m_whereExpr; +}; + +class View : public Object +{ +public: + explicit View(const std::string& name): Object(name) {} + + Types type() const override { return Object::View; } + + FieldVector fields; + + std::string sql(const std::string& /*schema*/ = "main", bool /*ifNotExists*/ = false) const override + { /* TODO */ return m_originalSql; } + + static ViewPtr parseSQL(const std::string& sSQL); + + StringVector fieldNames() const; + + FieldInfoList fieldInformation() const override; +}; + +class Trigger : public Object +{ +public: + explicit Trigger(const std::string& name): Object(name) {} + + Types type() const override { return Object::Trigger; } + + std::string sql(const std::string& /*schema*/ = "main", bool /*ifNotExists*/ = false) const override + { /* TODO */ return m_originalSql; } + + static TriggerPtr parseSQL(const std::string& sSQL); + + std::string baseTable() const override { return m_table; } + + void setTable(const std::string& table) { m_table = table; } + std::string table() const { return m_table; } + +private: + std::string m_table; +}; + +/** + * @brief findField Finds a field in the database object and returns an iterator to it. + * @param object + * @param name + * @return The iterator pointing to the field in the field container of the object if the field was found. + * object.fields.end() if the field couldn't be found. + */ +template +typename T::field_iterator findField(T* object, const std::string& name) +{ + return std::find_if(object->fields.begin(), object->fields.end(), [&name](const typename T::field_type& f) { + return compare_ci(name, f.name()); + }); +} +template +typename T::field_iterator findField(const T* object, const std::string& name) +{ + return findField(const_cast(object), name); +} +template +typename std::remove_reference::type::field_iterator findField(std::shared_ptr object, const std::string& name) +{ + return findField(object.get(), name); +} +template +typename std::remove_reference::type::field_iterator findField(T& object, const std::string& name) +{ + return findField(&object, name); +} + +template struct is_shared_ptr : std::false_type {}; +template struct is_shared_ptr> : std::true_type {}; + +/** + * @brief removeField Finds and removes a field in the database object + * @param object + * @param name + * @return true if sucessful, otherwise false + */ +template +bool removeField(T* object, const std::string& name) +{ + auto index = findField(object, name); + if(index != object->fields.end()) + { + object->fields.erase(index); + return true; + } + return false; +} +template::value>::type> +bool removeField(T object, const std::string& name) +{ + return removeField(object.get(), name); +} +template::value>::type> +bool removeField(T& object, const std::string& name) +{ + return removeField(&object, name); +} + +} //namespace sqlb + +#endif diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/sqlite.h b/src/WBCLFZSystemModule/SqliteDBProcess/src/sqlite.h new file mode 100644 index 0000000..335b069 --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/sqlite.h @@ -0,0 +1,23 @@ +#ifndef SQLITE_H +#define SQLITE_H + +#ifdef ENABLE_SQLCIPHER + #define SQLITE_TEMP_STORE 2 + #define SQLITE_HAS_CODEC +#ifdef Q_OS_WIN32 + #include +#else + #include +#endif +#else + #include +#endif + +// For older versions of the SQLite library which do not have the SQLITE_DETERMINISTIC flag +// yet (which introduced in this commit: https://www.sqlite.org/src/info/5716fc2341ddd8cf), we +// define it here with a value of 0. Because it is ORed with other constants a value of 0 is a no-op. +#ifndef SQLITE_DETERMINISTIC +#define SQLITE_DETERMINISTIC 0 +#endif + +#endif diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/sqlitedb.cpp b/src/WBCLFZSystemModule/SqliteDBProcess/src/sqlitedb.cpp new file mode 100644 index 0000000..2b63965 --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/sqlitedb.cpp @@ -0,0 +1,2130 @@ +#include "sqlitedb.h" +#include "sqlite.h" +#include "sqlitetablemodel.h" +#include "CipherDialog.h" +#include "CipherSettings.h" +#include "DotenvFormat.h" +#include "Settings.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +using json = nlohmann::json; + +QStringList DBBrowserDB::Datatypes = {"INTEGER", "TEXT", "BLOB", "REAL", "NUMERIC"}; + +// Helper template to allow turning member functions into a C-style function pointer +// See https://stackoverflow.com/questions/19808054/convert-c-function-pointer-to-c-function-pointer/19809787 +template +struct Callback; +template +struct Callback { + template + static Ret callback(Args... args) { return func(args...); } + static std::function func; +}; +template +std::function Callback::func; + +namespace sqlb { +QString escapeIdentifier(const QString& id) +{ + return QString::fromStdString(escapeIdentifier(id.toStdString())); +} +QString escapeString(const QString& literal) +{ + return QString::fromStdString(escapeString(literal.toStdString())); +} +} + +// collation callbacks +int collCompare(void* /*pArg*/, int sizeA, const void* sA, int sizeB, const void* sB) +{ + if(sizeA == sizeB) + return memcmp(sA, sB, static_cast(sizeA)); + return sizeA - sizeB; +} + +static int sqlite_compare_utf16( void* /*arg*/,int size1, const void *str1, int size2, const void* str2) +{ + const QString string1 = QString::fromRawData(reinterpret_cast(str1), static_cast(static_cast(size1) / sizeof(QChar))); + const QString string2 = QString::fromRawData(reinterpret_cast(str2), static_cast(static_cast(size2) / sizeof(QChar))); + + return QString::compare(string1, string2, Qt::CaseSensitive); +} + +static int sqlite_compare_utf16ci( void* /*arg*/,int size1, const void *str1, int size2, const void* str2) +{ + const QString string1 = QString::fromRawData(reinterpret_cast(str1), static_cast(static_cast(size1) / sizeof(QChar))); + const QString string2 = QString::fromRawData(reinterpret_cast(str2), static_cast(static_cast(size2) / sizeof(QChar))); + + return QString::compare(string1, string2, Qt::CaseInsensitive); +} + +static void sqlite_make_single_value(sqlite3_context* ctx, int num_arguments, sqlite3_value* arguments[]) +{ + json array; + for(int i=0;i(sqlite3_value_text(arguments[i]))); + + std::string output = array.dump(); + char* output_str = new char[output.size()+1]; + std::strcpy(output_str, output.c_str()); + + sqlite3_result_text(ctx, output_str, static_cast(output.length()), [](void* ptr) { + char* cptr = static_cast(ptr); + delete cptr; + }); +} + +DBBrowserDB::DBBrowserDB() : + _db(nullptr), + db_used(false), + isEncrypted(false), + isReadOnly(false), + dontCheckForStructureUpdates(false) +{ + // Register error log callback. This needs to be done before SQLite is first used + Callback::func = std::bind(&DBBrowserDB::errorLogCallback, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3); + void (*log_callback)(void*, int, const char*) = static_cast(Callback::callback); + sqlite3_config(SQLITE_CONFIG_LOG, log_callback, nullptr); +} + +void DBBrowserDB::collationNeeded(void* /*pData*/, sqlite3* /*db*/, int eTextRep, const char* sCollationName) +{ + QString name(sCollationName); + + // Don't request built-in collations. SQLite requests these collations even though they are built into + // the library. Since we have no need for overriding them, we just silently ignore these requests. + if(name.compare("BINARY", Qt::CaseInsensitive) && + name.compare("NOCASE", Qt::CaseInsensitive) && + name.compare("RTRIM", Qt::CaseInsensitive)) + { + emit requestCollation(name, eTextRep); + } +} + +void DBBrowserDB::errorLogCallback(void* /*user_data*/, int error_code, const char* message) +{ + QString msg = QString("(%1) %2").arg(error_code).arg(message); + + logSQL(msg, kLogMsg_ErrorLog); +} + +static void regexp(sqlite3_context* ctx, int /*argc*/, sqlite3_value* argv[]) +{ + // This is a cache for the last 50 regular expressions. Compiling them takes some time, so we want to cache the compiled + // regular expressions for performance purposes. + static std::array, 50> regex_cache; + + // Check if pattern is in cache + QString pattern{reinterpret_cast(sqlite3_value_text(argv[0]))}; + QRegularExpression regex; + const auto it = std::find_if(regex_cache.begin(), regex_cache.end(), [pattern](const std::pair& val) { + return val.first == pattern; + }); + if(it == regex_cache.end()) + { + // Pattern is not in cache. Create a new regular expressions object, compile it, and insert it into the cache + regex.setPattern(pattern); + regex.setPatternOptions(QRegularExpression::UseUnicodePropertiesOption); + if(!regex.isValid()) + return sqlite3_result_error(ctx, "invalid operand", -1); + regex.optimize(); + + static size_t regex_cache_size; + regex_cache_size = (regex_cache_size + 1) % regex_cache.size(); + regex_cache[regex_cache_size] = {pattern, regex}; + } else { + // Pattern is in the cache. Just retrieve it + regex = it->second; + } + + // Get arguments and check their values + QString arg2{reinterpret_cast(sqlite3_value_text(argv[1]))}; + + // Perform the actual matching and return the result. + // SQLite expects a 0 for not found and a 1 for found. + sqlite3_result_int(ctx, regex.match(arg2).hasMatch()); +} + +bool DBBrowserDB::isOpen ( ) const +{ + return _db != nullptr; +} + +bool DBBrowserDB::getDirty() const +{ + return !savepointList.empty(); +} + +bool DBBrowserDB::open(const QString& db, bool readOnly) +{ + if (isOpen()) close(); + + isEncrypted = false; + dontCheckForStructureUpdates = false; + + // Get encryption settings for database file + CipherSettings* cipherSettings = nullptr; + if(tryEncryptionSettings(db, &isEncrypted, cipherSettings) == false) + return false; + + // Open database file + if(sqlite3_open_v2(db.toUtf8(), &_db, readOnly ? SQLITE_OPEN_READONLY : SQLITE_OPEN_READWRITE, nullptr) != SQLITE_OK) + { + lastErrorMessage = QString::fromUtf8(sqlite3_errmsg(_db)); + return false; + } + + // Set encryption details if database is encrypted +#ifdef ENABLE_SQLCIPHER + if(isEncrypted && cipherSettings) + { + executeSQL("PRAGMA key = " + cipherSettings->getPassword(), false, false); + executeSQL("PRAGMA cipher_page_size = " + std::to_string(cipherSettings->getPageSize()), false, false); + executeSQL("PRAGMA kdf_iter = " + std::to_string(cipherSettings->getKdfIterations()), false, false); + executeSQL("PRAGMA cipher_hmac_algorithm = " + cipherSettings->getHmacAlgorithm(), false, false); + executeSQL("PRAGMA cipher_kdf_algorithm = " + cipherSettings->getKdfAlgorithm(), false, false); + executeSQL("PRAGMA cipher_plaintext_header_size = " + std::to_string(cipherSettings->getPlaintextHeaderSize()), false, false); + } +#endif + delete cipherSettings; + + if (_db) + { + // add UTF16 collation (comparison is performed by QString functions) + sqlite3_create_collation(_db, "UTF16", SQLITE_UTF16, nullptr, sqlite_compare_utf16); + // add UTF16CI (case insensitive) collation (comparison is performed by QString functions) + sqlite3_create_collation(_db, "UTF16CI", SQLITE_UTF16, nullptr, sqlite_compare_utf16ci); + + // register collation callback + Callback::func = std::bind(&DBBrowserDB::collationNeeded, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4); + void (*c_callback)(void*, sqlite3*, int, const char*) = static_cast(Callback::callback); + sqlite3_collation_needed(_db, nullptr, c_callback); + + // Set foreign key settings as requested in the preferences + bool foreignkeys = Settings::getValue("db", "foreignkeys").toBool(); + setPragma("foreign_keys", foreignkeys ? "1" : "0"); + + // Register REGEXP function + if(Settings::getValue("extensions", "disableregex").toBool() == false) + sqlite3_create_function(_db, "REGEXP", 2, SQLITE_UTF8, nullptr, regexp, nullptr, nullptr); + + // Register our internal helper function for putting multiple values into a single column + sqlite3_create_function_v2( + _db, + "sqlb_make_single_value", + -1, + SQLITE_UTF8 | SQLITE_DETERMINISTIC, + nullptr, + sqlite_make_single_value, + nullptr, + nullptr, + nullptr + ); + + // Check if file is read only. In-memory databases are never read only + if(db == ":memory:") + { + isReadOnly = false; + } else { + QFileInfo fi(db); + QFileInfo fid(fi.absoluteDir().absolutePath()); + isReadOnly = readOnly || !fi.isWritable() || !fid.isWritable(); + } + + // Load extensions + loadExtensionsFromSettings(); + + // Execute default SQL + if(!isReadOnly) + { + QByteArray default_sql = Settings::getValue("db", "defaultsqltext").toByteArray(); + if(!default_sql.isEmpty()) + executeMultiSQL(default_sql, false, true); + } + + curDBFilename = db; + + updateSchema(); + + return true; + } else { + return false; + } +} + +bool DBBrowserDB::attach(const QString& filePath, QString attach_as) +{ + if(!_db) + return false; + + waitForDbRelease(); + + // Check if this file has already been attached and abort if this is the case + QFileInfo fi(filePath); + bool ok = executeSQL("PRAGMA database_list", false, true, [fi](int, std::vector values, std::vector) -> bool { + QFileInfo path(values.at(2)); + if(fi == path) + { + QString schema = values.at(1); + QMessageBox::information(nullptr, qApp->applicationName(), tr("This database has already been attached. Its schema name is '%1'.").arg(schema)); + return true; + } + + return false; + }); + + if(ok == false) + return false; + + // Ask for name to be given to the attached database if none was provided + if(attach_as.isEmpty()) + attach_as = QInputDialog::getText(nullptr, + qApp->applicationName(), + tr("Please specify the database name under which you want to access the attached database"), + QLineEdit::Normal, + QFileInfo(filePath).baseName() + ).trimmed(); + if(attach_as.isNull()) + return false; + +#ifdef ENABLE_SQLCIPHER + // Try encryption settings + CipherSettings* cipherSettings = nullptr; + bool is_encrypted; + if(tryEncryptionSettings(filePath, &is_encrypted, cipherSettings) == false) + return false; + + // Attach database + std::string key; + if(cipherSettings && is_encrypted) + key = "KEY " + cipherSettings->getPassword(); + else + key = "KEY ''"; + + // Only apply cipher settings if the database is encrypted + if(cipherSettings && is_encrypted) + { + if(!executeSQL("PRAGMA cipher_default_page_size = " + std::to_string(cipherSettings->getPageSize()), false)) + { + QMessageBox::warning(nullptr, qApp->applicationName(), lastErrorMessage); + return false; + } + if(!executeSQL("PRAGMA cipher_default_kdf_iter = " + std::to_string(cipherSettings->getKdfIterations()), false)) + { + QMessageBox::warning(nullptr, qApp->applicationName(), lastErrorMessage); + return false; + } + if(!executeSQL("PRAGMA cipher_hmac_algorithm = " + cipherSettings->getHmacAlgorithm(), false)) + { + QMessageBox::warning(nullptr, qApp->applicationName(), lastErrorMessage); + return false; + } + if(!executeSQL("PRAGMA cipher_kdf_algorithm = " + cipherSettings->getKdfAlgorithm(), false)) + { + QMessageBox::warning(nullptr, qApp->applicationName(), lastErrorMessage); + return false; + } + if(!executeSQL("PRAGMA cipher_plaintext_header_size = " + std::to_string(cipherSettings->getPlaintextHeaderSize()), false)) + { + QMessageBox::warning(nullptr, qApp->applicationName(), lastErrorMessage); + return false; + } + } + + if(!executeSQL("ATTACH " + sqlb::escapeString(filePath.toStdString()) + " AS " + sqlb::escapeIdentifier(attach_as.toStdString()) + " " + key, false)) + { + QMessageBox::warning(nullptr, qApp->applicationName(), lastErrorMessage); + return false; + } + + // Clean up cipher settings + delete cipherSettings; +#else + // Attach database + if(!executeSQL("ATTACH " + sqlb::escapeString(filePath.toStdString()) + " AS " + sqlb::escapeIdentifier(attach_as.toStdString()), false)) + { + QMessageBox::warning(nullptr, qApp->applicationName(), lastErrorMessage); + return false; + } +#endif + + // Update schema to load database schema of the newly attached database + updateSchema(); + + return true; +} + +bool DBBrowserDB::tryEncryptionSettings(const QString& filePath, bool* encrypted, CipherSettings*& cipherSettings) const +{ + lastErrorMessage = tr("Invalid file format"); + + // Open database file + sqlite3* dbHandle; + if(sqlite3_open_v2(filePath.toUtf8(), &dbHandle, SQLITE_OPEN_READONLY, nullptr) != SQLITE_OK) + return false; + + // Try reading from database + +#ifdef ENABLE_SQLCIPHER + bool isDotenvChecked = false; + + // Determine default encryption settings depending on the SQLCipher version we use + QString sqlite_version, sqlcipher_version; + getSqliteVersion(sqlite_version, sqlcipher_version); + int enc_default_page_size, enc_default_kdf_iter; + int enc_default_plaintext_header_size = 0; + std::string enc_default_hmac_algorithm, enc_default_kdf_algorithm; + if(sqlcipher_version.startsWith('4')) + { + enc_default_page_size = 4096; + enc_default_kdf_iter = 256000; + enc_default_hmac_algorithm = "SHA512"; + enc_default_kdf_algorithm = "SHA512"; + } else { + enc_default_page_size = 1024; + enc_default_kdf_iter = 64000; + enc_default_hmac_algorithm = "SHA1"; + enc_default_kdf_algorithm = "SHA1"; + } +#endif + + *encrypted = false; + cipherSettings = nullptr; + while(true) + { + const std::string statement = "SELECT COUNT(*) FROM sqlite_master;"; + sqlite3_stmt* vm; + const char* tail; + int err = sqlite3_prepare_v2(dbHandle, statement.c_str(), static_cast(statement.size()), &vm, &tail); + if(err == SQLITE_BUSY || err == SQLITE_PERM || err == SQLITE_NOMEM || err == SQLITE_IOERR || err == SQLITE_CORRUPT || err == SQLITE_CANTOPEN) + { + lastErrorMessage = QString::fromUtf8(sqlite3_errmsg(dbHandle)); + sqlite3_close(dbHandle); + return false; + } + + if(sqlite3_step(vm) != SQLITE_ROW) + { + sqlite3_finalize(vm); +#ifdef ENABLE_SQLCIPHER + bool foundDotenvPassword = false; + + // Being in a while loop, we don't want to check the same file multiple times + if (!isDotenvChecked) { + QFile databaseFile(filePath); + QFileInfo databaseFileInfo(databaseFile); + + QString databaseDirectoryPath = databaseFileInfo.dir().path(); + QString databaseFileName(databaseFileInfo.fileName()); + + QString dotenvFilePath = databaseDirectoryPath + "/.env"; + static const QSettings::Format dotenvFormat = QSettings::registerFormat("env", &DotenvFormat::readEnvFile, nullptr); + QSettings dotenv(dotenvFilePath, dotenvFormat); + + QVariant passwordValue = dotenv.value(databaseFileName); + + foundDotenvPassword = !passwordValue.isNull(); + + isDotenvChecked = true; + + if (foundDotenvPassword) + { + std::string password = passwordValue.toString().toStdString(); + + QVariant keyFormatValue = dotenv.value(databaseFileName + "_keyFormat", QVariant(CipherSettings::KeyFormats::Passphrase)); + CipherSettings::KeyFormats keyFormat = CipherSettings::getKeyFormat(keyFormatValue.toInt()); + + int pageSize = dotenv.value(databaseFileName + "_pageSize", enc_default_page_size).toInt(); + int kdfIterations = dotenv.value(databaseFileName + "_kdfIter", enc_default_kdf_iter).toInt(); + int plaintextHeaderSize = dotenv.value(databaseFileName + "_plaintextHeaderSize", enc_default_plaintext_header_size).toInt(); + std::string hmacAlgorithm = dotenv.value(databaseFileName + "_hmacAlgorithm", QString::fromStdString(enc_default_hmac_algorithm)).toString().toStdString(); + std::string kdfAlgorithm = dotenv.value(databaseFileName + "_kdfAlgorithm", QString::fromStdString(enc_default_kdf_algorithm)).toString().toStdString(); + + delete cipherSettings; + cipherSettings = new CipherSettings(); + + cipherSettings->setKeyFormat(keyFormat); + cipherSettings->setPassword(password); + cipherSettings->setPageSize(pageSize); + cipherSettings->setKdfIterations(kdfIterations); + cipherSettings->setHmacAlgorithm("HMAC_" + hmacAlgorithm); + cipherSettings->setKdfAlgorithm("PBKDF2_HMAC_" + kdfAlgorithm); + cipherSettings->setPlaintextHeaderSize(plaintextHeaderSize); + } + } + + if(foundDotenvPassword) + { + // Skip the CipherDialog prompt for now to test if the dotenv settings are correct + } else { + CipherDialog *cipherDialog = new CipherDialog(nullptr, false); + if(cipherDialog->exec()) + { + delete cipherSettings; + cipherSettings = new CipherSettings(cipherDialog->getCipherSettings()); + } else { + sqlite3_close(dbHandle); + *encrypted = false; + delete cipherSettings; + cipherSettings = nullptr; + return false; + } + } + + // Close and reopen database first to be in a clean state after the failed read attempt from above + sqlite3_close(dbHandle); + if(sqlite3_open_v2(filePath.toUtf8(), &dbHandle, SQLITE_OPEN_READONLY, nullptr) != SQLITE_OK) + { + delete cipherSettings; + cipherSettings = nullptr; + return false; + } + + // Set the key + sqlite3_exec(dbHandle, ("PRAGMA key = " + cipherSettings->getPassword()).c_str(), nullptr, nullptr, nullptr); + + // Set the settings if they differ from the default values + if(cipherSettings->getPageSize() != enc_default_page_size) + sqlite3_exec(dbHandle, ("PRAGMA cipher_page_size = " + std::to_string(cipherSettings->getPageSize())).c_str(), nullptr, nullptr, nullptr); + if(cipherSettings->getKdfIterations() != enc_default_kdf_iter) + sqlite3_exec(dbHandle, ("PRAGMA kdf_iter = " + std::to_string(cipherSettings->getKdfIterations())).c_str(), nullptr, nullptr, nullptr); + if(cipherSettings->getHmacAlgorithm() != enc_default_hmac_algorithm) + sqlite3_exec(dbHandle, ("PRAGMA cipher_hmac_algorithm = " + cipherSettings->getHmacAlgorithm()).c_str(), nullptr, nullptr, nullptr); + if(cipherSettings->getKdfAlgorithm() != enc_default_kdf_algorithm) + sqlite3_exec(dbHandle, ("PRAGMA cipher_kdf_algorithm = " + cipherSettings->getKdfAlgorithm()).c_str(), nullptr, nullptr, nullptr); + if(cipherSettings->getPlaintextHeaderSize() != enc_default_plaintext_header_size) + sqlite3_exec(dbHandle, ("PRAGMA cipher_plaintext_header_size = " + std::to_string(cipherSettings->getPlaintextHeaderSize())).c_str(), nullptr, nullptr, nullptr); + + *encrypted = true; +#else + lastErrorMessage = QString::fromUtf8(sqlite3_errmsg(dbHandle)); + sqlite3_close(dbHandle); + return false; +#endif + } else { + sqlite3_finalize(vm); + sqlite3_close(dbHandle); + return true; + } + } +} + +void DBBrowserDB::getSqliteVersion(QString& sqlite, QString& sqlcipher) +{ + sqlite = QString(SQLITE_VERSION); + + // The SQLCipher version must be queried via a pragma and for a pragma we need a database connection. + // Because we want to be able to query the SQLCipher version without opening a database file first, we + // open a separate connection to an in-memory database here. + sqlcipher = QString(); +#ifdef ENABLE_SQLCIPHER + sqlite3* dummy; + if(sqlite3_open(":memory:", &dummy) == SQLITE_OK) + { + sqlite3_stmt* stmt; + if(sqlite3_prepare_v2(dummy, "PRAGMA cipher_version", -1, &stmt, nullptr) == SQLITE_OK) + { + if(sqlite3_step(stmt) == SQLITE_ROW) + sqlcipher = QByteArray(static_cast(sqlite3_column_blob(stmt, 0)), sqlite3_column_bytes(stmt, 0)); + + sqlite3_finalize(stmt); + } + + sqlite3_close(dummy); + } +#endif +} + +bool DBBrowserDB::setSavepoint(const std::string& pointname) +{ + if(!isOpen()) + return false; + if(isReadOnly) { + qWarning() << "setSavepoint: not done. DB is read-only"; + return false; + } + if(contains(savepointList, pointname)) + return true; + + executeSQL("SAVEPOINT " + sqlb::escapeIdentifier(pointname) + ";", false, true); + savepointList.push_back(pointname); + emit dbChanged(getDirty()); + + return true; +} + +bool DBBrowserDB::releaseSavepoint(const std::string& pointname) +{ + if(!isOpen()) + return false; + if(contains(savepointList, pointname) == false) + // If there is no such savepoint in the list, + // we have already released it, so in this case + // the operation should be successfull + return true; + + if(!executeSQL("RELEASE " + sqlb::escapeIdentifier(pointname) + ";", false, true)) + return false; + // SQLite releases all savepoints that were created between + // creation of given savepoint and releasing of it, + // so we should too + auto it = std::find(savepointList.rbegin(), savepointList.rend(), pointname).base() - 1; + savepointList.erase(it, savepointList.end()); + emit dbChanged(getDirty()); + + return true; +} + +bool DBBrowserDB::revertToSavepoint(const std::string& pointname) +{ + if(!isOpen() || contains(savepointList, pointname) == false) + return false; + + executeSQL("ROLLBACK TO SAVEPOINT " + sqlb::escapeIdentifier(pointname) + ";", false, true); + executeSQL("RELEASE " + sqlb::escapeIdentifier(pointname) + ";", false, true); + // SQLite releases all savepoints that were created between + // creation of given savepoint and releasing of it, + // so we should too + auto it = std::find(savepointList.rbegin(), savepointList.rend(), pointname).base() - 1; + savepointList.erase(it, savepointList.end()); + emit dbChanged(getDirty()); + + return true; +} + +bool DBBrowserDB::releaseAllSavepoints() +{ + if(!_db) + return false; + + waitForDbRelease(); + + while(!savepointList.empty()) + { + if(!releaseSavepoint(savepointList.front())) + return false; + } + + // When still in a transaction, commit that too + if(sqlite3_get_autocommit(_db) == 0) + executeSQL("COMMIT;", false, true); + + return true; +} + +bool DBBrowserDB::revertAll() +{ + while(!savepointList.empty()) + { + if(!revertToSavepoint(savepointList.front())) + return false; + } + return true; +} + +bool DBBrowserDB::create ( const QString & db) +{ + if (isOpen()) + close(); + + // read encoding from settings and open with sqlite3_open for utf8 and sqlite3_open16 for utf16 + QString sEncoding = Settings::getValue("db", "defaultencoding").toString(); + + int openresult = SQLITE_OK; + + if(sEncoding == "UTF-8" || sEncoding == "UTF8" || sEncoding == "Latin1") + openresult = sqlite3_open(db.toUtf8(), &_db); + else + openresult = sqlite3_open16(db.utf16(), &_db); + + if( openresult != SQLITE_OK ){ + lastErrorMessage = QString::fromUtf8(sqlite3_errmsg(_db)); + sqlite3_close(_db); + _db = nullptr; + return false; + } + + if (_db) + { + // force sqlite3 do write proper file header + // if we don't create and drop the table we might end up + // with a 0 byte file, if the user cancels the create table dialog + { + NoStructureUpdateChecks nup(*this); + executeSQL("CREATE TABLE notempty (id integer primary key);", false, false); + executeSQL("DROP TABLE notempty;", false, false); + } + + // Close database and open it through the code for opening existing database files. This is slightly less efficient but saves us some duplicate + // code. + sqlite3_close(_db); + return open(db); + } else { + return false; + } +} + +bool DBBrowserDB::close() +{ + waitForDbRelease(); + + if(_db) + { + if (getDirty()) + { + // In-memory databases can't be saved to disk. So the need another text than regular databases. + // Note that the QMessageBox::Yes option in the :memory: case and the QMessageBox::No option in the regular case are + // doing the same job: proceeding but not saving anything. + QMessageBox::StandardButton reply; + if(curDBFilename == ":memory:") + { + reply = QMessageBox::question(nullptr, + QApplication::applicationName(), + tr("Do you really want to close this temporary database? All data will be lost."), + QMessageBox::Yes | QMessageBox::Cancel); + } else { + reply = QMessageBox::question(nullptr, + QApplication::applicationName(), + tr("Do you want to save the changes made to the database file %1?").arg(curDBFilename), + QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel); + } + + // If the user clicked the cancel button stop here and return false + if(reply == QMessageBox::Cancel) + return false; + + // If he didn't it was either yes or no + if(reply == QMessageBox::Save) + releaseAllSavepoints(); + else + revertAll(); //not really necessary, I think... but will not hurt. + } + if(sqlite3_close(_db) != SQLITE_OK) + qWarning() << tr("Database didn't close correctly, probably still busy"); + _db = nullptr; + } + + schemata.clear(); + savepointList.clear(); + emit dbChanged(getDirty()); + emit structureUpdated(); + + // Return true to tell the calling function that the closing wasn't cancelled by the user + return true; +} + +DBBrowserDB::db_pointer_type DBBrowserDB::get(const QString& user, bool force_wait) +{ + if(!_db) + return nullptr; + + waitForDbRelease(force_wait ? Wait : Ask); + + db_user = user; + db_used = true; + emit databaseInUseChanged(true, user); + + return db_pointer_type(_db, DatabaseReleaser(this)); +} + +void DBBrowserDB::waitForDbRelease(ChoiceOnUse choice) const +{ + if(!_db) + return; + + // We can't show a message box from another thread than the main thread. So instead of crashing we + // just decide that we don't interrupt any running query in this case. + if(choice == Ask && QThread::currentThread() != QApplication::instance()->thread()) + choice = Wait; + + std::unique_lock lk(m); + while(db_used) { + // notify user, give him the opportunity to cancel that + auto str = db_user; + lk.unlock(); + + bool cancel = choice == CancelOther; + if(choice == Ask) { + QMessageBox msgBox; + msgBox.setText(tr("The database is currently busy: ") + str); + msgBox.setInformativeText(tr("Do you want to abort that other operation?")); + msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No); + msgBox.setDefaultButton(QMessageBox::No); + int ret = msgBox.exec(); + + cancel = ret == QMessageBox::Yes; + } + if(cancel) + sqlite3_interrupt(_db); + + lk.lock(); + cv.wait(lk, [this](){ return !db_used; }); + } +} + +bool DBBrowserDB::dump(const QString& filePath, + const std::vector& tablesToDump, + bool insertColNames, + bool insertNewSyntx, + bool exportSchema, + bool exportData, + bool keepOldSchema) const +{ + waitForDbRelease(); + + // Open file + QFile file(filePath); + if(file.open(QIODevice::WriteOnly|QIODevice::Text)) + { + QApplication::setOverrideCursor(Qt::WaitCursor); + + // Count the total number of all records in all tables for the progress dialog + size_t numRecordsTotal = 0; + objectMap objMap = schemata.at("main"); // We only always export the main database, not the attached databases + std::vector tables; + auto all_tables = objMap.equal_range("table"); + for(auto it=all_tables.first;it!=all_tables.second;++it) + { + // Never export the sqlite_stat1 and the sqlite_sequence tables if they exist. Also only export any tables which are selected for export. + if(it->second->name() != "sqlite_stat1" && it->second->name() != "sqlite_sequence" && contains(tablesToDump, it->second->name())) + { + // Get the number of records in this table and remember to export it + tables.push_back(it->second); + numRecordsTotal += querySingleValueFromDb("SELECT COUNT(*) FROM " + sqlb::ObjectIdentifier("main", it->second->name()).toString()).toUInt(); + } + } + + QProgressDialog progress(tr("Exporting database to SQL file..."), + tr("Cancel"), 0, static_cast(numRecordsTotal)); + progress.setWindowModality(Qt::ApplicationModal); + progress.show(); + qApp->processEvents(); + + // Open text stream to the file + QTextStream stream(&file); + + // Put the SQL commands in a transaction block + stream << "BEGIN TRANSACTION;\n"; + + // First export the schema of all selected tables. We need to export the schema of all tables before we export the first INSERT statement to + // make sure foreign keys are working properly. + if(exportSchema) + { + for(const auto& it : tables) + { + // Write the SQL string used to create this table to the output file + if(!keepOldSchema) + stream << QString("DROP TABLE IF EXISTS %1;\n").arg(QString::fromStdString(sqlb::escapeIdentifier(it->name()))); + + if(it->fullyParsed()) + stream << QString::fromStdString(it->sql("main", true)) << "\n"; + else + stream << QString::fromStdString(it->originalSql()) << ";\n"; + } + } + + // Now export the data as well + if(exportData) + { + for(const auto& it : tables) + { + // get columns + sqlb::StringVector cols = std::dynamic_pointer_cast(it)->fieldNames(); + + std::string sQuery = "SELECT * FROM " + sqlb::escapeIdentifier(it->name()); + sqlite3_stmt *stmt; + QString lineSep(QString(")%1\n").arg(insertNewSyntx?',':';')); + + int status = sqlite3_prepare_v2(_db, sQuery.c_str(), static_cast(sQuery.size()), &stmt, nullptr); + if(SQLITE_OK == status) + { + int columns = sqlite3_column_count(stmt); + size_t counter = 0; + size_t numRecordsCurrent = 0; + qApp->processEvents(); + while(sqlite3_step(stmt) == SQLITE_ROW) + { + if (counter) stream << lineSep; + + if (!insertNewSyntx || !counter) + { + stream << "INSERT INTO " << QString::fromStdString(sqlb::escapeIdentifier(it->name())); + if (insertColNames) + stream << " (" << QString::fromStdString(sqlb::joinStringVector(sqlb::escapeIdentifier(cols), ",")) << ")"; + stream << " VALUES ("; + } + else + { + stream << " ("; + } + + for (int i = 0; i < columns; ++i) + { + int fieldsize = sqlite3_column_bytes(stmt, i); + int fieldtype = sqlite3_column_type(stmt, i); + QByteArray bcontent( + reinterpret_cast(sqlite3_column_blob(stmt, i)), + fieldsize); + + if(bcontent.left(2048).contains('\0')) // binary check + { + stream << QString("X'%1'").arg(QString(bcontent.toHex())); + } + else + { + switch(fieldtype) + { + case SQLITE_TEXT: + case SQLITE_BLOB: + stream << sqlb::escapeString(bcontent); + break; + case SQLITE_NULL: + stream << "NULL"; + break; + case SQLITE_FLOAT: + if(bcontent.indexOf("Inf") != -1) + stream << "'" << bcontent << "'"; + else + stream << bcontent; + break; + default: + stream << bcontent; + } + } + if(i != columns - 1) + stream << ','; + } + + progress.setValue(static_cast(++numRecordsCurrent)); + if(counter % 5000 == 0) + qApp->processEvents(); + counter++; + + if(progress.wasCanceled()) + { + sqlite3_finalize(stmt); + file.close(); + file.remove(); + QApplication::restoreOverrideCursor(); + return false; + } + } + if (counter > 0) stream << ");\n"; + } + sqlite3_finalize(stmt); + } + } + + // Finally export all objects other than tables + if(exportSchema) + { + for(const auto& obj : objMap) + { + const auto& it = obj.second; + + // Make sure it's not a table again + if(it->type() == sqlb::Object::Types::Table) + continue; + + // If this object is based on a table (e.g. is an index for that table) it depends on the existence of this table. + // So if we didn't export the base table this depends on, don't export this object either. + if(!it->baseTable().empty() && !contains(tablesToDump, it->baseTable())) + continue; + + // Write the SQL string used to create this object to the output file + if(!it->originalSql().empty()) + { + if(!keepOldSchema) + stream << QString("DROP %1 IF EXISTS %2;\n").arg( + QString::fromStdString(sqlb::Object::typeToString(it->type())).toUpper(), + QString::fromStdString(sqlb::escapeIdentifier(it->name()))); + + if(it->fullyParsed()) + stream << QString::fromStdString(it->sql("main", true)) << "\n"; + else + stream << QString::fromStdString(it->originalSql()) << ";\n"; + } + } + } + + // Done + stream << "COMMIT;\n"; + file.close(); + + QApplication::restoreOverrideCursor(); + qApp->processEvents(); + return true; + } + return false; +} + +// Callback for sqlite3_exec. It receives the user callback in the first parameter. Converts parameters +// to C++ classes and calls user callback. +int DBBrowserDB::callbackWrapper (void* callback, int numberColumns, char** values, char** columnNames) +{ + std::vector valuesList; + std::vector namesList; + + for (int i=0; i(callback)); + return userCallback(numberColumns, valuesList, namesList); +} + +bool DBBrowserDB::executeSQL(const std::string& statement, bool dirtyDB, bool logsql, execCallback callback) +{ + waitForDbRelease(); + if(!_db) + { + lastErrorMessage = tr("No database file opened"); + return false; + } + + if (dirtyDB) setSavepoint(); + if (logsql) logSQL(QString::fromStdString(statement), kLogMsg_App); + + char* errmsg; + if (SQLITE_OK == sqlite3_exec(_db, statement.c_str(), callback ? callbackWrapper : nullptr, &callback, &errmsg)) + { + // Update DB structure after executing an SQL statement. But try to avoid doing unnecessary updates. + if(!dontCheckForStructureUpdates && (starts_with_ci(statement, "ALTER") || + starts_with_ci(statement, "CREATE") || + starts_with_ci(statement, "DROP") || + starts_with_ci(statement, "ROLLBACK"))) + updateSchema(); + + return true; + } else { + lastErrorMessage = QString("%1 (%2)").arg(QString::fromUtf8(errmsg), QString::fromStdString(statement)); + qWarning() << "executeSQL: " << lastErrorMessage; + sqlite3_free(errmsg); + + return false; + } +} + +bool DBBrowserDB::executeMultiSQL(QByteArray query, bool dirty, bool log) +{ + waitForDbRelease(); + if(!_db) + { + lastErrorMessage = tr("No database file opened"); + return false; + } + + // Log the statement if needed + if(log) + logSQL(query, kLogMsg_App); + + // Show progress dialog + QProgressDialog progress(tr("Executing SQL..."), + tr("Cancel"), 0, 100); + progress.setWindowModality(Qt::ApplicationModal); + progress.show(); + + // Execute the statement by looping until SQLite stops giving back a tail string + sqlite3_stmt* vm; + const char *tail = query.constData(); + const char * const tail_start = tail; + const char * const tail_end = tail + query.size() + 1; + size_t total_tail_length = static_cast(tail_end - tail_start); + unsigned int line = 0; + bool structure_updated = false; + int last_progress_value = -1; + std::string savepoint_name; + while(tail && *tail != 0) + { + line++; + + // Update progress dialog, keep UI responsive. Make sure to not spend too much time updating the progress dialog in case there are many small statements. + int progress_value = static_cast(static_cast(tail - tail_start) / static_cast(total_tail_length) * 100.0f); + if(progress_value > last_progress_value) + { + progress.setValue(progress_value); + qApp->processEvents(); + if(progress.wasCanceled()) + { + lastErrorMessage = tr("Action cancelled."); + return false; + } + last_progress_value = progress_value; + } + + // Check next statement + { + // Ignore all whitespace at the start of the current tail + const char* tail_ptr = tail; + while(std::isspace(*tail_ptr)) + tail_ptr++; + + // Convert the first couple of bytes of the tail to a C++ string for easier handling. We only need the first 8 bytes (in cae it's a ROLLBACK + // statement), so no need to convert the entire tail. If the tail is less than 8 bytes long, make sure not to read past its end. + size_t length = std::min(static_cast(tail_end - tail + 1), static_cast(8)); + std::string next_statement(tail_ptr, length); + std::transform(next_statement.begin(), next_statement.end(), next_statement.begin(), ::toupper); + + // Check for transaction statements and skip until the next semicolon + if(next_statement.compare(0, 6, "COMMIT") == 0 || + next_statement.compare(0, 4, "END ") == 0 || + next_statement.compare(0, 6, "BEGIN ") == 0) + { + while(tail != tail_end) + { + if(*tail++ == ';') + break; + } + + // Set DB to dirty and create a restore point if we haven't done that yet + if(savepoint_name.empty()) + { + savepoint_name = generateSavepointName("execmultisql"); + setSavepoint(savepoint_name); + dirty = true; + } + + // Don't just execute next statement. Start next statement with the same checks + continue; + } + + // Check whether the DB structure is changed by this statement + if(!dontCheckForStructureUpdates && !structure_updated) + { + // Check if it's a modifying statement + if(next_statement.compare(0, 5, "ALTER") == 0 || + next_statement.compare(0, 6, "CREATE") == 0 || + next_statement.compare(0, 4, "DROP") == 0 || + next_statement.compare(0, 8, "ROLLBACK") == 0) + structure_updated = true; + } + } + + // Execute next statement + if(sqlite3_prepare_v2(_db, tail, static_cast(tail_end - tail + 1), &vm, &tail) == SQLITE_OK) + { + switch(sqlite3_step(vm)) + { + case SQLITE_OK: + case SQLITE_ROW: + case SQLITE_DONE: + case SQLITE_MISUSE: // This is a workaround around problematic user scripts. If they lead to empty commands, + // SQLite will return a misuse error which we hereby ignore. + sqlite3_finalize(vm); + break; + default: + // In case of *any* error abort the execution and roll back the transaction + + // Make sure to save the error message first before any other function can mess around with it + lastErrorMessage = tr("Error in statement #%1: %2.\nAborting execution%3.").arg( + QString::number(line), + sqlite3_errmsg(_db), + dirty ? tr(" and rolling back") : ""); + qWarning() << lastErrorMessage; + + // Clean up + sqlite3_finalize(vm); + if(dirty) + revertToSavepoint(savepoint_name); + return false; + } + } else { + lastErrorMessage = tr("Error in statement #%1: %2.\nAborting execution%3.").arg( + QString::number(line), + sqlite3_errmsg(_db), + dirty ? tr(" and rolling back") : ""); + qWarning() << lastErrorMessage; + if(dirty) + revertToSavepoint(savepoint_name); + return false; + } + } + + // If the DB structure was changed by some command in this SQL script, update our schema representations + if(structure_updated) + updateSchema(); + + // Exit + return true; +} + +QByteArray DBBrowserDB::querySingleValueFromDb(const std::string& sql, bool log, ChoiceOnUse choice) const +{ + waitForDbRelease(choice); + if(!_db) + return QByteArray(); + + if(log) + logSQL(QString::fromStdString(sql), kLogMsg_App); + + QByteArray retval; + + sqlite3_stmt* stmt; + if(sqlite3_prepare_v2(_db, sql.c_str(), static_cast(sql.size()), &stmt, nullptr) == SQLITE_OK) + { + // Execute the statement. We distinguish three types of results: + // SQLITE_ROW in case some data was returned from the database. This data is then used as a return value. + // SQLITE_DONE in case the statement executed successfully but did not return any data. We do nothing in this case, leaving the return value empty. + // Any other case is an error, so we need to prepare an error message. + int result = sqlite3_step(stmt); + if(result == SQLITE_ROW) + { + if(sqlite3_column_count(stmt) > 0 && sqlite3_column_type(stmt, 0) != SQLITE_NULL) + { + int bytes = sqlite3_column_bytes(stmt, 0); + if(bytes) + retval = QByteArray(static_cast(sqlite3_column_blob(stmt, 0)), bytes); + else + retval = ""; + } + } else if(result != SQLITE_DONE) { + lastErrorMessage = tr("didn't receive any output from %1").arg(QString::fromStdString(sql)); + qWarning() << lastErrorMessage; + } + + sqlite3_finalize(stmt); + } else { + lastErrorMessage = tr("could not execute command: %1").arg(sqlite3_errmsg(_db)); + qWarning() << lastErrorMessage; + } + + return retval; +} + +bool DBBrowserDB::getRow(const sqlb::ObjectIdentifier& table, const QString& rowid, std::vector& rowdata) const +{ + waitForDbRelease(); + if(!_db) + return false; + + std::string query = "SELECT * FROM " + table.toString() + " WHERE "; + + // For a single rowid column we can use a simple WHERE condition, for multiple rowid columns we have to use sqlb_make_single_value to decode the composed rowid values. + sqlb::StringVector pks = getObjectByName(table)->rowidColumns(); + if(pks.size() == 1) + query += sqlb::escapeIdentifier(pks.front()) + "='" + rowid.toStdString() + "'"; + else + query += "sqlb_make_single_value(" + sqlb::joinStringVector(sqlb::escapeIdentifier(pks), ",") + ")=" + sqlb::escapeString(rowid.toStdString()); + + sqlite3_stmt *stmt; + bool ret = false; + if(sqlite3_prepare_v2(_db, query.c_str(), static_cast(query.size()), &stmt, nullptr) == SQLITE_OK) + { + // even this is a while loop, the statement should always only return 1 row + while(sqlite3_step(stmt) == SQLITE_ROW) + { + for (int i = 0; i < sqlite3_column_count(stmt); ++i) + { + if(sqlite3_column_type(stmt, i) == SQLITE_NULL) + { + rowdata.emplace_back(); + } else { + int bytes = sqlite3_column_bytes(stmt, i); + if(bytes) + rowdata.emplace_back(static_cast(sqlite3_column_blob(stmt, i)), bytes); + else + rowdata.emplace_back(""); + } + } + ret = true; + } + } + sqlite3_finalize(stmt); + + return ret; +} + +unsigned long DBBrowserDB::max(const sqlb::ObjectIdentifier& tableName, const std::string& field) const +{ + std::string query = "SELECT MAX(CAST(" + sqlb::escapeIdentifier(field) + " AS INTEGER)) FROM " + tableName.toString(); + return querySingleValueFromDb(query).toULong(); +} + +std::string DBBrowserDB::emptyInsertStmt(const std::string& schemaName, const sqlb::Table& t, const QString& pk_value) const +{ + std::string stmt = "INSERT INTO " + sqlb::escapeIdentifier(schemaName) + "." + sqlb::escapeIdentifier(t.name()); + + sqlb::StringVector vals; + sqlb::StringVector fields; + for(const sqlb::Field& f : t.fields) + { + // Never insert into a generated column + if(!f.generated().empty()) + continue; + + sqlb::ConstraintPtr pk = t.constraint({f.name()}, sqlb::Constraint::PrimaryKeyConstraintType); + if(pk) + { + fields.push_back(f.name()); + + if(!pk_value.isNull()) + { + vals.push_back(f.isText()? "'" + pk_value.toStdString() + "'" : pk_value.toStdString()); + } else { + if(f.notnull()) + { + unsigned long maxval = this->max(sqlb::ObjectIdentifier(schemaName, t.name()), f.name()); + std::string newval = std::to_string(maxval + 1); + vals.push_back(f.isText()? "'" + newval + "'" : newval); + } else { + vals.push_back("NULL"); + } + } + } else if(f.notnull() && f.defaultValue().length() == 0) { + fields.push_back(f.name()); + + if(f.isInteger()) + vals.push_back("0"); + else + vals.push_back("''"); + } else { + // don't insert into fields with a default value + // or we will never see it. + if(f.defaultValue().length() == 0) + { + fields.push_back(f.name()); + vals.push_back("NULL"); + } + } + } + + if(fields.empty()) + { + stmt.append(" DEFAULT VALUES;"); + } else { + stmt.append("("); + stmt.append(sqlb::joinStringVector(sqlb::escapeIdentifier(fields), ",")); + stmt.append(") VALUES ("); + stmt.append(sqlb::joinStringVector(vals, ",")); + stmt.append(");"); + } + + return stmt; +} + +QString DBBrowserDB::addRecord(const sqlb::ObjectIdentifier& tablename) +{ + waitForDbRelease(); + if(!_db) + return QString(); + + sqlb::TablePtr table = getObjectByName(tablename); + if(!table) + return QString(); + + // For tables without rowid we have to set the primary key by ourselves. We do so by querying for the largest value in the PK column + // and adding one to it. + std::string sInsertstmt; + QString pk_value; + if(table->withoutRowidTable()) + { + // For multiple rowid columns we just use the value of the last one and increase that one by one. If this doesn't yield a valid combination + // the insert record dialog should pop up automatically. + pk_value = QString::number(max(tablename, table->rowidColumns().back()) + 1); + sInsertstmt = emptyInsertStmt(tablename.schema(), *table, pk_value); + } else { + sInsertstmt = emptyInsertStmt(tablename.schema(), *table); + } + + if(!executeSQL(sInsertstmt)) + { + qWarning() << "addRecord: " << lastErrorMessage; + return QString(); + } else { + if(table->withoutRowidTable()) + return pk_value; + else + return QString::number(sqlite3_last_insert_rowid(_db)); + } +} + +bool DBBrowserDB::deleteRecords(const sqlb::ObjectIdentifier& table, const std::vector& rowids, const sqlb::StringVector& pseudo_pk) +{ + if (!isOpen()) return false; + + // Get primary key of the object to edit. + sqlb::StringVector pks = primaryKeyForEditing(table, pseudo_pk); + if(pks.empty()) + { + lastErrorMessage = tr("Cannot delete this object"); + return false; + } + + // Quote all values in advance + std::vector quoted_rowids; + for(QString rowid : rowids) + quoted_rowids.push_back(sqlb::escapeString(rowid.toStdString())); + + // For a single rowid column we can use a SELECT ... IN(...) statement which is faster. + // For multiple rowid columns we have to use sqlb_make_single_value to decode the composed rowid values. + std::string statement; + if(pks.size() == 1) + { + statement = "DELETE FROM " + table.toString() + " WHERE " + pks.at(0) + " IN ("+ sqlb::joinStringVector(quoted_rowids, ", ") + ");"; + } else { + statement = "DELETE FROM " + table.toString() + " WHERE "; + + statement += "sqlb_make_single_value("; + for(const auto& pk : pks) + statement += sqlb::escapeIdentifier(pk) + ","; + statement.erase(statement.end()-1); + statement += ") IN (" + sqlb::joinStringVector(quoted_rowids, ", ") + ")"; + } + + if(executeSQL(statement)) + { + return true; + } else { + qWarning() << "deleteRecord: " << lastErrorMessage; + return false; + } +} + +bool DBBrowserDB::updateRecord(const sqlb::ObjectIdentifier& table, const std::string& column, + const QString& rowid, const QByteArray& value, int force_type, const sqlb::StringVector& pseudo_pk) +{ + waitForDbRelease(); + if (!isOpen()) return false; + + // Get primary key of the object to edit. + sqlb::StringVector pks = primaryKeyForEditing(table, pseudo_pk); + if(pks.empty()) + { + lastErrorMessage = tr("Cannot set data on this object"); + return false; + } + + std::string sql = "UPDATE " + table.toString() + " SET " + sqlb::escapeIdentifier(column) + "=? WHERE "; + + // For a single rowid column we can use a simple WHERE condition, for multiple rowid columns we have to use sqlb_make_single_value to decode the composed rowid values. + if(pks.size() == 1) + sql += sqlb::escapeIdentifier(pks.front()) + "=" + sqlb::escapeString(rowid.toStdString()); + else + sql += "sqlb_make_single_value(" + sqlb::joinStringVector(sqlb::escapeIdentifier(pks), ",") + ")=" + sqlb::escapeString(rowid.toStdString()); + + setSavepoint(); + logSQL(QString::fromStdString(sql), kLogMsg_App); + + // If we get a NULL QByteArray we insert a NULL value, and for that + // we can pass NULL to sqlite3_bind_text() so that it behaves like sqlite3_bind_null() + const char *rawValue = value.isNull() ? nullptr : value.constData(); + + sqlite3_stmt* stmt; + int success = 1; + if(sqlite3_prepare_v2(_db, sql.c_str(), static_cast(sql.size()), &stmt, nullptr) != SQLITE_OK) + success = 0; + if(success == 1) { + if(force_type == SQLITE_BLOB) + { + if(sqlite3_bind_blob(stmt, 1, rawValue, value.length(), SQLITE_STATIC)) + success = -1; + } else if(force_type == SQLITE_INTEGER) { + if(sqlite3_bind_int64(stmt, 1, value.toLongLong())) + success = -1; + } else if(force_type == SQLITE_FLOAT) { + if(sqlite3_bind_double(stmt, 1, value.toDouble())) + success = -1; + } else { + if(sqlite3_bind_text(stmt, 1, rawValue, value.length(), SQLITE_STATIC)) + success = -1; + } + } + if(success == 1 && sqlite3_step(stmt) != SQLITE_DONE) + success = -1; + if(success != 0 && sqlite3_finalize(stmt) != SQLITE_OK) + success = -1; + + if(success == 1) + { + return true; + } else { + lastErrorMessage = sqlite3_errmsg(_db); + qWarning() << "updateRecord: " << lastErrorMessage; + return false; + } +} + +sqlb::StringVector DBBrowserDB::primaryKeyForEditing(const sqlb::ObjectIdentifier& table, const sqlb::StringVector& pseudo_pk) const +{ + // This function returns the primary key of the object to edit. For views we support 'pseudo' primary keys which must be specified manually. + // If no pseudo pk is specified we'll take the rowid column of the table instead. If this neither a table nor was a pseudo-PK specified, + // it is most likely a view that hasn't been configured for editing yet. In this case we return a null string to abort. + + if(pseudo_pk.empty()) + { + sqlb::TablePtr tbl = getObjectByName(table); + if(tbl) + return tbl->rowidColumns(); + } else { + return pseudo_pk; + } + + return sqlb::StringVector(); +} + +bool DBBrowserDB::createTable(const sqlb::ObjectIdentifier& name, const sqlb::FieldVector& structure) +{ + // Build SQL statement + sqlb::Table table(name.name()); + for(size_t i=0;i(tablename); + if(old_table_ptr == nullptr) + { + lastErrorMessage = tr("No table with name '%1' exists in schema '%2'.").arg(QString::fromStdString(tablename.name()), QString::fromStdString(tablename.schema())); + return false; + } + sqlb::Table old_table(*old_table_ptr); + + // Check if tracked fields actually exist in the old table + for(const auto& old_it : track_columns) + { + if(!old_it.first.isNull() && sqlb::findField(old_table, old_it.first.toStdString()) == old_table.fields.end()) + { + lastErrorMessage = tr("Cannot find column %1.").arg(old_it.first); + return false; + } + } + + // Check if there are any columns in the old table which are not mentioned in the tracked columns list. + // We do this before checking if all tracked fields are in the new table to make sure the following check includes them. + for(const auto& field : old_table.fields) + { + if(track_columns.find(QString::fromStdString(field.name())) == track_columns.end()) + { + // If a field isn't tracked, add it to the list and indicate explicitly that it has the same name in the new table + track_columns[QString::fromStdString(field.name())] = QString::fromStdString(field.name()); + } + } + + // Check if tracked fields actually exist in the new table + for(const auto& new_name_it : track_columns) + { + if(!new_name_it.second.isNull() && sqlb::findField(new_table, new_name_it.second.toStdString()) == new_table.fields.end()) + { + lastErrorMessage = tr("Cannot find column %1.").arg(new_name_it.second); + return false; + } + } + + // Check if any changes were made to the table schema + if(old_table == new_table) + return true; + + // Create savepoint to be able to go back to it in case of any error + std::string savepointName = generateSavepointName("renamecolumn"); + if(!setSavepoint(savepointName)) + { + lastErrorMessage = tr("Creating savepoint failed. DB says: %1").arg(lastErrorMessage); + return false; + } + + // No automatic schema updates from now on + NoStructureUpdateChecks nup(*this); + + // + // P A R T 2 + // + + // This variable is used to track whether something was changed by this part of the function + bool changed_something = false; + + // Rename table if necessary + if(newSchemaName == tablename.schema() && tablename.name() != new_table.name()) + { + if(!renameTable(tablename.schema(), old_table.name(), new_table.name())) + { + revertToSavepoint(savepointName); + return false; + } + + changed_something = true; + } + + // Add columns if necessary + for(const auto& field : new_table.fields) + { + // We loop through all the fields of the new table schema and check for each of them if they are new. + // If so, we add that field. The reason for looping through the new table schema instead of the track_columns + // map is that this way we make sure to preserve their order which increases our chances that we are done after + // this step. + if(std::any_of(track_columns.begin(), track_columns.end(), [&field](const std::pair& p) { + return p.first.isNull() && p.second.toStdString() == field.name(); + })) + { + if(!addColumn(sqlb::ObjectIdentifier(tablename.schema(), new_table.name()), field)) + { + revertToSavepoint(savepointName); + return false; + } + } + + changed_something = true; + } + + // Newer versions of SQLite add a better ALTER TABLE support which we can use +#if SQLITE_VERSION_NUMBER >= 3025000 + // If the name of a field should be changed do that by using SQLite's ALTER TABLE feature. We build a new + // map for tracking column names here which uses the update column names as the old names too. This is to + // make sure we are using the new table layout for later updates. + AlterTableTrackColumns new_track_columns; + for(const auto& old_name_it : track_columns) + { + QString old_name = old_name_it.first; + + QString new_name = track_columns[old_name]; + if(!old_name.isNull() && !new_name.isNull() && new_name != old_name) + { + if(!executeSQL("ALTER TABLE " + sqlb::ObjectIdentifier(tablename.schema(), new_table.name()).toString() + " RENAME COLUMN " + + sqlb::escapeIdentifier(old_name.toStdString()) + " TO " + sqlb::escapeIdentifier(new_name.toStdString()))) + { + QString error(tr("Renaming the column failed. DB says:\n%1").arg(lastErrorMessage)); + revertToSavepoint(savepointName); + lastErrorMessage = error; + return false; + } + + changed_something = true; + new_track_columns.insert({new_name, new_name}); + } else { + new_track_columns.insert({old_name, new_name}); + } + } + track_columns.swap(new_track_columns); +#endif + + // Update our schema representation to get the new table and all the changed triggers, views and indices + if(changed_something) + { + updateSchema(); + old_table = *getObjectByName(sqlb::ObjectIdentifier(tablename.schema(), new_table.name())); + } + + // Check if there's still more work to be done or if we are finished now + if(tablename.schema() == newSchemaName && old_table == new_table) + { + // Release the savepoint - everything went fine + if(!releaseSavepoint(savepointName)) + { + lastErrorMessage = tr("Releasing savepoint failed. DB says: %1").arg(lastErrorMessage); + return false; + } + + // Success, update the DB schema before returning + updateSchema(); + return true; + } + + // + // P A R T 3 + // + + // Create a new table with the desired schema and a name that doesn't exist yet + std::string new_table_name = new_table.name(); + sqlb::Table new_table_with_random_name(new_table); + new_table_with_random_name.setName(generateTemporaryTableName(newSchemaName)); + if(!executeSQL(new_table_with_random_name.sql(newSchemaName), true, true)) + { + QString error(tr("Creating new table failed. DB says: %1").arg(lastErrorMessage)); + revertToSavepoint(savepointName); + lastErrorMessage = error; + return false; + } + + // Assemble list of column names to copy from in the old table and list of column names to into into in the new table + sqlb::StringVector copy_values_from; + sqlb::StringVector copy_values_to; + for(const auto& from_it : track_columns) + { + const auto& from = from_it.first; + + // Ignore new fields + if(from.isNull()) + continue; + + // Ignore deleted fields + QString to = track_columns[from]; + if(to.isNull()) + continue; + + copy_values_from.push_back(from.toStdString()); + copy_values_to.push_back(to.toStdString()); + } + + // Copy the data from the old table to the new one + if(!executeSQL("INSERT INTO " + sqlb::escapeIdentifier(newSchemaName) + "." + sqlb::escapeIdentifier(new_table_with_random_name.name()) + + " (" + sqlb::joinStringVector(sqlb::escapeIdentifier(copy_values_to), ",") + ") SELECT " + + sqlb::joinStringVector(sqlb::escapeIdentifier(copy_values_from), ",") + " FROM " + + sqlb::escapeIdentifier(tablename.schema()) + "." + sqlb::escapeIdentifier(old_table.name()))) + { + QString error(tr("Copying data to new table failed. DB says:\n%1").arg(lastErrorMessage)); + revertToSavepoint(savepointName); + lastErrorMessage = error; + return false; + } + + // Save all indices, triggers and views associated with this table because SQLite deletes them when we drop the table in the next step + std::vector otherObjectsSql; + for(const auto& schema : schemata[tablename.schema()]) + { + const auto& it = schema.second; + + // If this object references the table and it's not the table itself save it's SQL string + if(it->baseTable() == old_table.name() && it->type() != sqlb::Object::Types::Table) + { + // If this is an index, update the fields first. This highly increases the chance that the SQL statement won't throw an + // error later on when we try to recreate it. + if(it->type() == sqlb::Object::Types::Index) + { + sqlb::IndexPtr idx = std::dynamic_pointer_cast(it); + + // Loop through all changes to the table schema. For indices only the column names are relevant, so it suffices to look at the + // list of tracked columns + for(const auto& from_it : track_columns) + { + const auto& from = from_it.first; + const auto& to = from_it.second; + + // Are we updating the field name or are we removing the field entirely? + if(!to.isNull()) + { + // We're updating the field name. So search for it in the index and replace it whereever it is found + for(size_t i=0;ifields.size();i++) + { + if(idx->fields[i].name() == from.toStdString()) + idx->fields[i].setName(to.toStdString()); + } + } else { + // We're removing a field. So remove it from any indices, too. + while(sqlb::removeField(idx, from.toStdString())) + ; + } + } + + // Only try to add the index later if it has any columns remaining. Also use the new schema name here, too, to basically move + // any index that references the table to the same new schema as the table. + if(idx->fields.size()) + otherObjectsSql.push_back(idx->sql(newSchemaName)); + } else { + // If it's a view or a trigger we don't have any chance to corrections yet. Just store the statement as is and + // hope for the best. + otherObjectsSql.push_back(it->originalSql() + ";"); + } + } + } + + // We need to disable foreign keys here. The reason is that in the next step the entire table will be dropped and there might be foreign keys + // in other tables that reference this table. These foreign keys would then cause the drop command in the next step to fail. However, we can't + // simply disable foreign keys here since that is not allowed from inside a transaction and we definitely are inside a transaction at that point. + // So what we do instead is defer foreign key enforcement until the end of the transaction which effectively disables foreign keys for us here. + // But because we don't really want to defer foreign keys, the former value of that pragma is saved here in order to restore the old value later. + QString foreignKeysOldSettings = getPragma("defer_foreign_keys"); + setPragma("defer_foreign_keys", "1"); + + // Delete the old table + if(!executeSQL("DROP TABLE " + sqlb::escapeIdentifier(tablename.schema()) + "." + sqlb::escapeIdentifier(old_table.name()), true, true)) + { + QString error(tr("Deleting old table failed. DB says: %1").arg(lastErrorMessage)); + revertToSavepoint(savepointName); + lastErrorMessage = error; + return false; + } + + // Rename the temporary table + if(!renameTable(newSchemaName, new_table_with_random_name.name(), new_table.name())) + { + revertToSavepoint(savepointName); + return false; + } + + // Restore the former foreign key settings + setPragma("defer_foreign_keys", foreignKeysOldSettings); + + // Restore the saved triggers, views and indices + std::string errored_sqls; + for(const std::string& sql : otherObjectsSql) + { + if(!executeSQL(sql, true, true)) + errored_sqls += sql + "\n"; + } + if(!errored_sqls.empty()) + { + QMessageBox::information(nullptr, qApp->applicationName(), tr("Restoring some of the objects associated with this table failed. " + "This is most likely because some column names changed. " + "Here's the SQL statement which you might want to fix and execute manually:\n\n") + + QString::fromStdString(errored_sqls)); + } + + // Release the savepoint - everything went fine + if(!releaseSavepoint(savepointName)) + { + lastErrorMessage = tr("Releasing savepoint failed. DB says: %1").arg(lastErrorMessage); + return false; + } + + // Success, update the DB schema before returning + updateSchema(); + return true; +} + +bool DBBrowserDB::renameTable(const std::string& schema, const std::string& from_table, const std::string& to_table) +{ + // Do nothing if table names are the same + if(from_table == to_table) + return true; + + // Check if table names only differ in case. If they do, we have to rename the table twice because SQLite can't rename 'table' to 'Table'. + // To solve this we rename 'table' to 'some temp name' and then 'some temp name' to 'Table'. + if(compare_ci(from_table, to_table)) + { + // Generate a temporary table name and rename the table via that by recusrively calling this function + std::string temp_name = generateTemporaryTableName(schema); + if(!renameTable(schema, from_table, temp_name)) + return false; + if(!renameTable(schema, temp_name, to_table)) + return false; + + // Exit here + return true; + } + + // The old and the new table names differ (and that not only in case) + + // Rename the table + std::string sql = "ALTER TABLE " + sqlb::escapeIdentifier(schema) + "." + sqlb::escapeIdentifier(from_table) + " RENAME TO " + sqlb::escapeIdentifier(to_table); + if(!executeSQL(sql)) + { + QString error = tr("Error renaming table '%1' to '%2'.\n" + "Message from database engine:\n%3").arg(QString::fromStdString(from_table), QString::fromStdString(to_table), lastErrorMessage); + lastErrorMessage = error; + qWarning() << lastErrorMessage; + return false; + } else { + return true; + } +} + +void DBBrowserDB::logSQL(const QString& statement, LogMessageType msgtype) const +{ + // Remove any leading and trailing spaces, tabs, or line breaks first + emit sqlExecuted(statement.trimmed(), msgtype); +} + +void DBBrowserDB::updateSchema() +{ + waitForDbRelease(); + + schemata.clear(); + + // Exit here is no DB is opened + if(!isOpen()) + return; + + // Get a list of all databases. This list always includes the main and the temp database but can include more items if there are attached databases + if(!executeSQL("PRAGMA database_list;", false, true, [this](int, std::vector db_values, std::vector) -> bool { + // Get the schema name which is in column 1 (counting starts with 0). 0 contains an ID and 2 the file path. + const std::string schema_name = db_values.at(1).toStdString(); + + // Always add the schema to the map. This makes sure it's even then added when there are no objects in the database + schemata[schema_name] = objectMap(); + + // Get a list of all the tables for the current database schema. We need to do this differently for normal databases and the temporary schema + // because SQLite doesn't understand the "temp.sqlite_master" notation. + std::string statement; + if(schema_name == "temp") + statement = "SELECT type,name,sql,tbl_name FROM sqlite_temp_master;"; + else + statement = "SELECT type,name,sql,tbl_name FROM " + sqlb::escapeIdentifier(schema_name) + ".sqlite_master;"; + + if(!executeSQL(statement, false, true, [this, schema_name](int, std::vector values, std::vector) -> bool { + const std::string val_type = values.at(0).toStdString(); + const std::string val_name = values.at(1).toStdString(); + std::string val_sql = values.at(2).toStdString(); + const std::string val_tblname = values.at(3).toStdString(); + + if(!val_sql.empty()) + { + val_sql.erase(std::remove(val_sql.begin(), val_sql.end(), '\r'), val_sql.end()); + + sqlb::ObjectPtr object; + if(val_type == "table") + object = sqlb::Table::parseSQL(val_sql); + else if(val_type == "index") + object = sqlb::Index::parseSQL(val_sql); + else if(val_type == "trigger") + object = sqlb::Trigger::parseSQL(val_sql); + else if(val_type == "view") + object = sqlb::View::parseSQL(val_sql); + else + return false; + + // If parsing wasn't successful set the object name manually, so that at least the name is going to be correct + if(!object->fullyParsed()) + object->setName(val_name); + + // For virtual tables and views query the column list using the SQLite pragma because for both we can't yet rely on our grammar parser + if((object->type() == sqlb::Object::Types::Table && std::dynamic_pointer_cast(object)->isVirtual()) || object->type() == sqlb::Object::Types::View) + { + const auto columns = queryColumnInformation(schema_name, val_name); + + if(object->type() == sqlb::Object::Types::Table) + { + sqlb::TablePtr tab = std::dynamic_pointer_cast(object); + for(const auto& column : columns) + tab->fields.emplace_back(column.first, column.second); + } else { + sqlb::ViewPtr view = std::dynamic_pointer_cast(object); + for(const auto& column : columns) + view->fields.emplace_back(column.first, column.second); + } + } else if(object->type() == sqlb::Object::Types::Trigger) { + // For triggers set the name of the table the trigger operates on here because we don't have a parser for trigger statements yet. + sqlb::TriggerPtr trg = std::dynamic_pointer_cast(object); + trg->setTable(val_tblname); + } + + schemata[schema_name].insert({val_type, object}); + } + + return false; + })) + { + qWarning() << tr("could not get list of db objects: %1").arg(sqlite3_errmsg(_db)); + } + + return false; + })) + { + qWarning() << tr("could not get list of databases: %1").arg(sqlite3_errmsg(_db)); + } + + emit structureUpdated(); +} + +QString DBBrowserDB::getPragma(const std::string& pragma) const +{ + if (pragma=="case_sensitive_like") + return querySingleValueFromDb("SELECT 'x' NOT LIKE 'X';"); + else + return querySingleValueFromDb("PRAGMA " + pragma + ";"); +} + +bool DBBrowserDB::setPragma(const std::string& pragma, const QString& value) +{ + // Set the pragma value + std::string sql = "PRAGMA " + pragma + " = '" + value.toStdString() + "';"; + + // In general, we want to commit changes before running pragmas because most of them can't be rolled back and some of them + // even fail when run in a transaction. However, the defer_foreign_keys pragma has neither problem and we need it to be settable + // inside transactions (see the renameColumn() function where it is set and reset at some point and where we don't want the changes + // to be committed just because of this pragma). + if(pragma != "defer_foreign_keys") + releaseSavepoint(); + + bool res = executeSQL(sql, false, true); // PRAGMA statements are usually not transaction bound, so we can't revert + if( !res ) + qWarning() << tr("Error setting pragma %1 to %2: %3").arg(QString::fromStdString(pragma), value, lastErrorMessage); + + // If this is the page_size or the auto_vacuum pragma being set, we need to execute the vacuum command right after the pragma statement or the new + // settings won't be saved. + if(res && (pragma == "page_size" || pragma == "auto_vacuum")) + res = executeSQL("VACUUM;", false, true); + + return res; +} + +bool DBBrowserDB::setPragma(const std::string& pragma, const QString& value, QString& originalvalue) +{ + if( originalvalue != value ) + { + if( setPragma(pragma, value)) + { + originalvalue = value; + return true; + } + } + return false; +} + +bool DBBrowserDB::setPragma(const std::string& pragma, int value, int& originalvalue) +{ + if( originalvalue != value ) + { + QString val = QString::number(value); + QString origval = QString::number(originalvalue); + if( setPragma(pragma, val, origval)) + { + originalvalue = value; + } + } + return false; +} + +bool DBBrowserDB::loadExtension(const QString& filePath) +{ + waitForDbRelease(); + if(!_db) + return false; + + // Check if file exists + if(!QFile::exists(filePath)) + { + lastErrorMessage = tr("File not found."); + return false; + } + + // Enable extension loading + sqlite3_enable_load_extension(_db, 1); + + // Try to load extension + char* error; + int result = sqlite3_load_extension(_db, filePath.toUtf8(), nullptr, &error); + + // Disable extension loading if so configured + // (we don't want to leave the possibility of calling load_extension() from SQL without user informed permission) + if (!Settings::getValue("extensions", "enable_load_extension").toBool()) + sqlite3_enable_load_extension(_db, 0); + + if (result == SQLITE_OK) + { + return true; + } else { + lastErrorMessage = QString::fromUtf8(error); + sqlite3_free(error); + return false; + } +} + + +void DBBrowserDB::loadExtensionsFromSettings() +{ + if(!_db) + return; + + sqlite3_enable_load_extension(_db, Settings::getValue("extensions", "enable_load_extension").toBool()); + + QStringList list = Settings::getValue("extensions", "list").toStringList(); + for(const QString& ext : list) + { + if(loadExtension(ext) == false) + QMessageBox::warning(nullptr, QApplication::applicationName(), tr("Error loading extension: %1").arg(lastError())); + } +} + +std::vector> DBBrowserDB::queryColumnInformation(const std::string& schema_name, const std::string& object_name) const +{ + waitForDbRelease(); + + std::vector> result; + std::string statement = "PRAGMA " + sqlb::escapeIdentifier(schema_name) + ".TABLE_INFO(" + sqlb::escapeIdentifier(object_name) + ");"; + logSQL(QString::fromStdString(statement), kLogMsg_App); + + sqlite3_stmt* vm; + const char* tail; + if(sqlite3_prepare_v2(_db, statement.c_str(), static_cast(statement.size()), &vm, &tail) == SQLITE_OK) + { + while(sqlite3_step(vm) == SQLITE_ROW) + { + std::string name = reinterpret_cast(sqlite3_column_text(vm, 1)); + std::string type = reinterpret_cast(sqlite3_column_text(vm, 2)); + + result.push_back(std::make_pair(name, type)); + } + sqlite3_finalize(vm); + } else{ + lastErrorMessage = tr("could not get column information"); + } + + return result; +} + +std::string DBBrowserDB::generateSavepointName(const std::string& identifier) const +{ + // Generate some sort of unique name for a savepoint for internal use. + return "db4s_" + identifier + "_" + std::to_string(std::chrono::system_clock::now().time_since_epoch().count()); +} + +std::string DBBrowserDB::generateTemporaryTableName(const std::string& schema) const +{ + // We're using a static variable as a counter here instead of checking from the beginning onwards every time. This has + // two reasons: 1) It makes the function thread-safe, and 2) it saves us some time because in case older temporary tables + // are still in use. Both reasons don't matter too much for now, but just in case... + static std::atomic_uint counter; + + while(true) + { + std::string table_name = "sqlb_temp_table_" + std::to_string(++counter); + if(!getObjectByName(sqlb::ObjectIdentifier(schema, table_name))) + return table_name; + } +} + +void DBBrowserDB::interruptQuery() +{ + if(!_db) + return; + + sqlite3_interrupt(_db); +} diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/sqlitedb.h b/src/WBCLFZSystemModule/SqliteDBProcess/src/sqlitedb.h new file mode 100644 index 0000000..87e5f91 --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/sqlitedb.h @@ -0,0 +1,292 @@ +#ifndef SQLITEDB_H +#define SQLITEDB_H + +#include "sql/ObjectIdentifier.h" +#include "sql/sqlitetypes.h" + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +struct sqlite3; +class CipherSettings; + +enum LogMessageType +{ + kLogMsg_User, + kLogMsg_App, + kLogMsg_ErrorLog +}; + +using objectMap = std::multimap; // Maps from object type (table, index, view, trigger) to a pointer to the object representation +using schemaMap = std::map; // Maps from the schema name (main, temp, attached schemas) to the object map for that schema + +int collCompare(void* pArg, int sizeA, const void* sA, int sizeB, const void* sB); + +namespace sqlb +{ +QString escapeIdentifier(const QString& id); +QString escapeString(const QString& literal); +} + +/// represents a single SQLite database. except when noted otherwise, +/// all member functions are to be called from the main UI thread +/// only. +class DBBrowserDB : public QObject +{ + Q_OBJECT + +private: + /// custom unique_ptr deleter releases database for further use by others + struct DatabaseReleaser + { + explicit DatabaseReleaser(DBBrowserDB * pParent_ = nullptr) : pParent(pParent_) {} + + DBBrowserDB * pParent; + + void operator() (sqlite3 * db) const + { + if(!db || !pParent) + return; + + std::unique_lock lk(pParent->m); + pParent->db_used = false; + lk.unlock(); + emit pParent->databaseInUseChanged(false, QString()); + pParent->cv.notify_one(); + } + }; + +public: + + explicit DBBrowserDB(); + ~DBBrowserDB () override = default; + + bool open(const QString& db, bool readOnly = false); + bool attach(const QString& filename, QString attach_as = QString()); + bool create ( const QString & db); + bool close(); + + // This returns the SQLite version as well as the SQLCipher if DB4S is compiled with encryption support + static void getSqliteVersion(QString& sqlite, QString& sqlcipher); + + using db_pointer_type = std::unique_ptr; + + /** + borrow exclusive address to the currently open database, until + releasing the returned unique_ptr. + + the intended use case is that the main UI thread can call this + any time, and then optionally pass the obtained pointer to a + background worker, or release it after doing work immediately. + + if database is currently used by somebody else, opens a dialog + box and gives user the opportunity to sqlite3_interrupt() the + operation of the current owner, then tries again. + + \param user a string that identifies the new user, and which + can be displayed in the dialog box. + + \param force_wait if set to true we won't ask the user to cancel + the running query but just wait until it is done. + + \returns a unique_ptr containing the SQLite database handle, or + nullptr in case no database is open. + **/ + db_pointer_type get (const QString& user, bool force_wait = false); + + bool setSavepoint(const std::string& pointname = "RESTOREPOINT"); + bool releaseSavepoint(const std::string& pointname = "RESTOREPOINT"); + bool revertToSavepoint(const std::string& pointname = "RESTOREPOINT"); + bool releaseAllSavepoints(); + bool revertAll(); + + bool dump(const QString& filename, const std::vector& tablesToDump, bool insertColNames, bool insertNew, bool exportSchema, bool exportData, bool keepOldSchema) const; + + enum ChoiceOnUse + { + Ask, + Wait, + CancelOther + }; + // Callback to get results from executeSQL(). It is invoked for + // each result row coming out of the evaluated SQL statements. If + // a callback returns true (abort), the executeSQL() method + // returns false (error) without invoking the callback again and + // without running any subsequent SQL statements. The 1st argument + // is the number of columns in the result. The 2nd argument to the + // callback is the text representation of the values, one for each + // column. The 3rd argument is a list of strings where each entry + // represents the name of corresponding result column. + using execCallback = std::function, std::vector)>; + bool executeSQL(const std::string& statement, bool dirtyDB = true, bool logsql = true, execCallback callback = nullptr); + bool executeMultiSQL(QByteArray query, bool dirty = true, bool log = false); + QByteArray querySingleValueFromDb(const std::string& sql, bool log = true, ChoiceOnUse choice = Ask) const; + + const QString& lastError() const { return lastErrorMessage; } + + /** + * @brief getRow Executes a sqlite statement to get the rowdata(columns) + * for the given rowid. + * @param schemaName Name of the database schema. + * @param sTableName Table to query. + * @param rowid The rowid to fetch. + * @param rowdata A list of QByteArray containing the row data. + * @return true if statement execution was ok, else false. + */ + bool getRow(const sqlb::ObjectIdentifier& table, const QString& rowid, std::vector& rowdata) const; + + /** + * @brief Interrupts the currenty running statement as soon as possible. + */ + void interruptQuery(); + +private: + /** + * @brief max Queries the table t for the max value of field. + * @param tableName Table to query + * @param field Name of the field to get the max value + * @return the max value of the field or 0 on error + */ + unsigned long max(const sqlb::ObjectIdentifier& tableName, const std::string& field) const; + + static int callbackWrapper (void* callback, int numberColumns, char** values, char** columnNames); + +public: + void updateSchema(); // Please don't call this from threads other than the main thread. + +private: + /** + * @brief Creates an empty insert statement. + * @param schemaName The name of the database schema in which to find the table + * @param pk_value This optional parameter can be used to manually set a specific value for the primary key column + * @return An sqlite conform INSERT INTO statement with empty values. (NULL,'',0) + */ + std::string emptyInsertStmt(const std::string& schemaName, const sqlb::Table& t, const QString& pk_value = QString()) const; + +public: + QString addRecord(const sqlb::ObjectIdentifier& tablename); + bool deleteRecords(const sqlb::ObjectIdentifier& table, const std::vector& rowids, const sqlb::StringVector& pseudo_pk = {}); + bool updateRecord(const sqlb::ObjectIdentifier& table, const std::string& column, const QString& rowid, const QByteArray& value, int force_type = 0, const sqlb::StringVector& pseudo_pk = {}); + + bool createTable(const sqlb::ObjectIdentifier& name, const sqlb::FieldVector& structure); + bool renameTable(const std::string& schema, const std::string& from_table, const std::string& to_table); + bool addColumn(const sqlb::ObjectIdentifier& tablename, const sqlb::Field& field); + + /** + * @brief This type maps from old column names to new column names. Given the old and the new table definition, this suffices to + * track fields between the two. + * USE CASES: + * 1) Don't specify a column at all or specify equal column names: Keep its name as-is. + * 2) Specify different column names: Rename the field. + * 3) Map from an existing column name to a Null string: Delete the column. + * 4) Map from a Null column name to a new column name: Add the column. + */ + using AlterTableTrackColumns = std::map; + + /** + * @brief alterTable Can be used to rename, modify or drop existing columns of a given table + * @param tablename Specifies the schema and name of the table to edit + * @param new_table Specifies the new table schema. This is exactly how the new table is going to look like. + * @param track_columns Maps old column names to new column names. This is used to copy the data from the old table to the new one. + * @param newSchema Set this to a non-empty string to move the table to a new schema + * @return true if renaming was successful, false if not. In the latter case also lastErrorMessage is set + */ + bool alterTable(const sqlb::ObjectIdentifier& tablename, const sqlb::Table& new_table, AlterTableTrackColumns track_columns, std::string newSchemaName = std::string()); + + template + const std::shared_ptr getObjectByName(const sqlb::ObjectIdentifier& name) const + { + for(auto& it : schemata.at(name.schema())) + { + if(it.second->name() == name.name()) + return std::dynamic_pointer_cast(it.second); + } + return std::shared_ptr(); + } + + bool isOpen() const; + bool encrypted() const { return isEncrypted; } + bool readOnly() const { return isReadOnly; } + bool getDirty() const; + QString currentFile() const { return curDBFilename; } + + /// log an SQL statement [thread-safe] + void logSQL(const QString& statement, LogMessageType msgtype) const; + + QString getPragma(const std::string& pragma) const; + bool setPragma(const std::string& pragma, const QString& value); + bool setPragma(const std::string& pragma, const QString& value, QString& originalvalue); + bool setPragma(const std::string& pragma, int value, int& originalvalue); + + bool loadExtension(const QString& filename); + void loadExtensionsFromSettings(); + + static QStringList Datatypes; + +private: + std::vector > queryColumnInformation(const std::string& schema_name, const std::string& object_name) const; + +public: + std::string generateSavepointName(const std::string& identifier = std::string()) const; + + // This function generates the name for a temporary table. It guarantees that there is no table with this name yet + std::string generateTemporaryTableName(const std::string& schema) const; + + schemaMap schemata; + +signals: + void sqlExecuted(QString sql, int msgtype) const; + void dbChanged(bool dirty); + void structureUpdated(); + void requestCollation(QString name, int eTextRep); + void databaseInUseChanged(bool busy, QString user); + +private: + /// external code needs to go through get() to obtain access to the database + sqlite3 * _db; + mutable std::mutex m; + mutable std::condition_variable cv; + bool db_used; + QString db_user; + + /// wait for release of the DB locked through a previous get(), + /// giving users the option to discard running task through a + /// message box. + void waitForDbRelease(ChoiceOnUse choice = Ask) const; + + QString curDBFilename; + mutable QString lastErrorMessage; + std::vector savepointList; + bool isEncrypted; + bool isReadOnly; + + sqlb::StringVector primaryKeyForEditing(const sqlb::ObjectIdentifier& table, const sqlb::StringVector& pseudo_pk) const; + + // SQLite Callbacks + void collationNeeded(void* pData, sqlite3* db, int eTextRep, const char* sCollationName); + void errorLogCallback(void* user_data, int error_code, const char* message); + + bool tryEncryptionSettings(const QString& filename, bool* encrypted, CipherSettings*& cipherSettings) const; + + bool dontCheckForStructureUpdates; + + class NoStructureUpdateChecks + { + public: + explicit NoStructureUpdateChecks(DBBrowserDB& db) : m_db(db) { m_db.dontCheckForStructureUpdates = true; } + ~NoStructureUpdateChecks() { m_db.dontCheckForStructureUpdates = false; } + + private: + DBBrowserDB& m_db; + }; +}; + +#endif diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/sqlitetablemodel.cpp b/src/WBCLFZSystemModule/SqliteDBProcess/src/sqlitetablemodel.cpp new file mode 100644 index 0000000..524bad0 --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/sqlitetablemodel.cpp @@ -0,0 +1,1193 @@ +#include "sqlitetablemodel.h" +#include "sqlitedb.h" +#include "sqlite.h" +#include "Settings.h" +#include "Data.h" +#include "CondFormat.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "RowLoader.h" + +using json = nlohmann::json; + +SqliteTableModel::SqliteTableModel(DBBrowserDB& db, QObject* parent, const QString& encoding) + : QAbstractTableModel(parent) + , m_db(db) + , m_lifeCounter(0) + , m_currentRowCount(0) + , m_encoding(encoding) +{ + // Load initial settings first + reloadSettings(); + + worker = new RowLoader( + [this](){ return m_db.get(tr("reading rows")); }, + [this](QString stmt){ return m_db.logSQL(stmt, kLogMsg_App); }, + m_headers, m_mutexDataCache, m_cache + ); + + worker->start(); + + // any UI updates must be performed in the UI thread, not in the worker thread: + connect(worker, &RowLoader::fetched, this, &SqliteTableModel::handleFinishedFetch, Qt::QueuedConnection); + connect(worker, &RowLoader::rowCountComplete, this, &SqliteTableModel::handleRowCountComplete, Qt::QueuedConnection); + + reset(); +} + +SqliteTableModel::~SqliteTableModel() +{ + worker->stop(); + worker->wait(); + worker->disconnect(); + delete worker; +} + +SqliteTableModel::RowCount SqliteTableModel::rowCountAvailable () const +{ + return m_rowCountAvailable; +} + +void SqliteTableModel::handleFinishedFetch (int life_id, unsigned int fetched_row_begin, unsigned int fetched_row_end) +{ + if(life_id < m_lifeCounter) + return; + + Q_ASSERT(fetched_row_end >= fetched_row_begin); + + auto old_row_count = m_currentRowCount; + + auto new_row_count = std::max(old_row_count, fetched_row_begin); + new_row_count = std::max(new_row_count, fetched_row_end); + Q_ASSERT(new_row_count >= old_row_count); + + if(new_row_count != old_row_count) + { + beginInsertRows(QModelIndex(), static_cast(old_row_count), static_cast(new_row_count - 1)); + m_currentRowCount = new_row_count; + endInsertRows(); + } + + if(fetched_row_end != fetched_row_begin) + { + // TODO optimize + size_t num_columns = m_headers.size(); + emit dataChanged(createIndex(static_cast(fetched_row_begin), 0), createIndex(static_cast(fetched_row_end) - 1, static_cast(num_columns) - 1)); + } + + if(m_rowCountAvailable != RowCount::Complete) + m_rowCountAvailable = RowCount::Partial; + + emit finishedFetch(static_cast(fetched_row_begin), static_cast(fetched_row_end)); +} + +void SqliteTableModel::handleRowCountComplete (int life_id, int num_rows) +{ + if(life_id < m_lifeCounter) + return; + + m_rowCountAvailable = RowCount::Complete; + handleFinishedFetch(life_id, static_cast(num_rows), static_cast(num_rows)); + + emit finishedRowCount(); +} + +void SqliteTableModel::reset() +{ + beginResetModel(); + clearCache(); + + m_sQuery.clear(); + m_query.clear(); + m_table_of_query.reset(); + m_headers.clear(); + m_vDataTypes.clear(); + m_mCondFormats.clear(); + m_mRowIdFormats.clear(); + + endResetModel(); +} + +void SqliteTableModel::setQuery(const sqlb::Query& query) +{ + // Unset all previous settings. When setting a table all information on the previously browsed data set is removed first. + reset(); + + // Save the query + m_query = query; + m_table_of_query = m_db.getObjectByName(query.table()); + + // The first column is the rowid column and therefore is always of type integer + m_vDataTypes.emplace_back(SQLITE_INTEGER); + + // Get the data types of all other columns as well as the column names + if(m_table_of_query && m_table_of_query->fields.size()) // It is a table and parsing was OK + { + sqlb::StringVector rowids = m_table_of_query->rowidColumns(); + m_query.setRowIdColumns(rowids); + m_headers.push_back(sqlb::joinStringVector(rowids, ",")); + + // Store field names and affinity data types + for(const sqlb::Field& fld : m_table_of_query->fields) + { + m_headers.push_back(fld.name()); + m_vDataTypes.push_back(fld.affinity()); + } + } else { + // If for one reason or another (either it's a view or we couldn't parse the table statement) we couldn't get the field + // information we retrieve it from SQLite using an extra query. + // NOTE: It would be nice to eventually get rid of this piece here. As soon as the grammar parser is good enough... + + std::string sColumnQuery = "SELECT * FROM " + query.table().toString() + ";"; + if(m_query.rowIdColumns().empty()) + m_query.setRowIdColumn("_rowid_"); + m_headers.emplace_back("_rowid_"); + auto columns = getColumns(nullptr, sColumnQuery, m_vDataTypes); + m_headers.insert(m_headers.end(), columns.begin(), columns.end()); + } + + // Tell the query object about the column names + m_query.setColumNames(m_headers); + + // Apply new query and update view + buildQuery(); +} + +void SqliteTableModel::setQuery(const QString& sQuery, const QString& sCountQuery, bool dontClearHeaders) +{ + // clear + if(!dontClearHeaders) + reset(); + else + clearCache(); + + if(!m_db.isOpen()) + return; + + m_sQuery = sQuery.trimmed(); + removeCommentsFromQuery(m_sQuery); + + worker->setQuery(m_sQuery, sCountQuery); + worker->triggerRowCountDetermination(m_lifeCounter); + + if(!dontClearHeaders) + { + auto columns = getColumns(worker->getDb(), sQuery.toStdString(), m_vDataTypes); + m_headers.insert(m_headers.end(), columns.begin(), columns.end()); + } + + // now fetch the first entries + triggerCacheLoad(static_cast(m_chunkSize / 2) - 1); + + emit layoutChanged(); +} + +int SqliteTableModel::rowCount(const QModelIndex&) const +{ + return static_cast(m_currentRowCount); +} + +int SqliteTableModel::columnCount(const QModelIndex&) const +{ + return static_cast(m_headers.size()); +} + +size_t SqliteTableModel::filterCount() const +{ + return m_query.where().size(); +} + +// Convert a number to string using the Unicode superscript characters +template +static QString toSuperScript(T number) +{ + QString superScript = QString::number(number); + superScript.replace("0", "?"); + superScript.replace("1", "?"); + superScript.replace("2", "?"); + superScript.replace("3", "?"); + superScript.replace("4", "?"); + superScript.replace("5", "?"); + superScript.replace("6", "?"); + superScript.replace("7", "?"); + superScript.replace("8", "?"); + superScript.replace("9", "?"); + return superScript; +} + +QVariant SqliteTableModel::headerData(int section, Qt::Orientation orientation, int role) const +{ + if (role != Qt::DisplayRole && role != Qt::EditRole) + return QVariant(); + + if (orientation == Qt::Horizontal) + { + // if we have a VIRTUAL table the model will not be valid, with no header data + if(static_cast(section) < m_headers.size()) { + const QString plainHeader = QString::fromStdString(m_headers.at(static_cast(section))); + // In the edit role, return a plain column name, but in the display role, add the sort indicator. + if (role == Qt::EditRole) + return plainHeader; + else { + QString sortIndicator; + for(size_t i = 0; i < m_query.orderBy().size(); i++) { + const sqlb::SortedColumn sortedColumn = m_query.orderBy()[i]; + // Append sort indicator with direction and ordinal number in superscript style + if (sortedColumn.column == static_cast(section)) { + sortIndicator = sortedColumn.direction == sqlb::Ascending ? " ?" : " ?"; + sortIndicator.append(toSuperScript(i+1)); + break; + } + } + return plainHeader + sortIndicator; + } + } + return QString::number(section + 1); + } + else + return QString::number(section + 1); +} + +QVariant SqliteTableModel::getMatchingCondFormat(const std::map>& mCondFormats, size_t column, const QString& value, int role) const +{ + if (!mCondFormats.count(column)) + return QVariant(); + + bool isNumber; + value.toDouble(&isNumber); + std::string sql; + + // For each conditional format for this column, + // if the condition matches the current data, return the associated format. + for (const CondFormat& eachCondFormat : mCondFormats.at(column)) { + if (isNumber && !contains(eachCondFormat.sqlCondition(), '\'')) + sql = "SELECT " + value.toStdString() + " " + eachCondFormat.sqlCondition(); + else + sql = "SELECT " + sqlb::escapeString(value.toStdString()) + " " + eachCondFormat.sqlCondition(); + + // Empty filter means: apply format to any row. + // Query the DB for the condition, waiting in case there is a loading in progress. + if (eachCondFormat.filter().isEmpty() || m_db.querySingleValueFromDb(sql, false, DBBrowserDB::Wait) == "1") + switch (role) { + case Qt::ForegroundRole: + return eachCondFormat.foregroundColor(); + case Qt::BackgroundRole: + return eachCondFormat.backgroundColor(); + case Qt::FontRole: + return eachCondFormat.font(); + case Qt::TextAlignmentRole: + return static_cast(eachCondFormat.alignmentFlag() | Qt::AlignVCenter); + } + } + return QVariant(); +} + +QVariant SqliteTableModel::getMatchingCondFormat(size_t row, size_t column, const QString& value, int role) const +{ + QVariant format; + // Check first for a row-id format and when there is none, for a conditional format. + if (m_mRowIdFormats.count(column)) + { + std::unique_lock lock(m_mutexDataCache); + const bool row_available = m_cache.count(row); + const QByteArray blank_data(""); + const QByteArray& row_id_data = row_available ? m_cache.at(row).at(0) : blank_data; + lock.unlock(); + + format = getMatchingCondFormat(m_mRowIdFormats, column, row_id_data, role); + if (format.isValid()) + return format; + } + if (m_mCondFormats.count(column)) + return getMatchingCondFormat(m_mCondFormats, column, value, role); + else + return QVariant(); +} + +QVariant SqliteTableModel::data(const QModelIndex &index, int role) const +{ + if (!index.isValid()) + return QVariant(); + + if (index.row() >= rowCount()) + return QVariant(); + + std::unique_lock lock(m_mutexDataCache); + + const size_t row = static_cast(index.row()); + const size_t column = static_cast(index.column()); + + const bool row_available = m_cache.count(row); + const QByteArray blank_data(""); + const QByteArray& data = row_available ? m_cache.at(row).at(column) : blank_data; + + if(role == Qt::DisplayRole) + { + if(!row_available) + return tr("loading..."); + if(data.isNull()) + { + return m_nullText; + } else if(isBinary(data)) { + return m_blobText; + } else { + if (data.length() > m_symbolLimit) { + // Add "..." to the end of truncated strings + return decode(data.left(m_symbolLimit).append(" ...")); + } else { + return decode(data); + } + } + } else if(role == Qt::EditRole) { + if(!row_available) + return QVariant(); + return decode(data); + } else if(role == Qt::FontRole) { + QFont font = m_font; + if(!row_available || data.isNull() || isBinary(data)) + font.setItalic(true); + else { + // Unlock before querying from DB + lock.unlock(); + QVariant condFormatFont = getMatchingCondFormat(row, column, data, role); + if (condFormatFont.isValid()) + return condFormatFont; + } + return font; + } else if(role == Qt::ForegroundRole) { + if(!row_available) + return QColor(100, 100, 100); + if(data.isNull()) + return m_nullFgColour; + else if (isBinary(data)) + return m_binFgColour; + else { + // Unlock before querying from DB + lock.unlock(); + QVariant condFormatColor = getMatchingCondFormat(row, column, data, role); + if (condFormatColor.isValid()) + return condFormatColor; + } + // Regular case (not null, not binary and no matching conditional format) + return m_regFgColour; + } else if (role == Qt::BackgroundRole) { + if(!row_available) + return QColor(255, 200, 200); + if(data.isNull()) + return m_nullBgColour; + else if (isBinary(data)) + return m_binBgColour; + else { + // Unlock before querying from DB + lock.unlock(); + QVariant condFormatColor = getMatchingCondFormat(row, column, data, role); + if (condFormatColor.isValid()) + return condFormatColor; + } + // Regular case (not null, not binary and no matching conditional format) + return m_regBgColour; + } else if(role == Qt::ToolTipRole) { + sqlb::ForeignKeyClause fk = getForeignKeyClause(column-1); + if(fk.isSet()) + return tr("References %1(%2)\nHold %3Shift and click to jump there").arg( + QString::fromStdString(fk.table()), + QString::fromStdString(sqlb::joinStringVector(fk.columns(), ",")), + QKeySequence(Qt::CTRL).toString(QKeySequence::NativeText)); + } else if (role == Qt::TextAlignmentRole) { + // Align horizontally according to conditional format or default (left for text and right for numbers) + // Align vertically to the center, which displays better. + lock.unlock(); + QVariant condFormat = getMatchingCondFormat(row, column, data, role); + if (condFormat.isValid()) + return condFormat; + bool isNumber = m_vDataTypes.at(column) == SQLITE_INTEGER || m_vDataTypes.at(column) == SQLITE_FLOAT; + return static_cast((isNumber ? Qt::AlignRight : Qt::AlignLeft) | Qt::AlignVCenter); + } else if(role == Qt::DecorationRole) { + if(!row_available) + return QVariant(); + + if(m_imagePreviewEnabled && !isImageData(data).isNull()) + { + QImage img; + if(img.loadFromData(data)) + return QPixmap::fromImage(img); + } + } + + + return QVariant(); +} + +sqlb::ForeignKeyClause SqliteTableModel::getForeignKeyClause(size_t column) const +{ + static const sqlb::ForeignKeyClause empty_foreign_key_clause; + + // No foreign keys when not browsing a table. This usually happens when executing custom SQL statements + // and browsing the result set instead of browsing an entire table. + if(m_query.table().isEmpty()) + return empty_foreign_key_clause; + + // Check if database object is a table. If it isn't stop here and don't return a foreign key. + // This happens for views which don't have foreign keys (though we might want to think about + // how we can check for foreign keys in the underlying tables for some purposes like tool tips). + // If it is a table, heck if the column number is in the valid range. + if(m_table_of_query && m_table_of_query->name().size() && column < m_table_of_query->fields.size()) + { + // Note that the rowid column has number -1 here, it can safely be excluded since there will never be a + // foreign key on that column. + + sqlb::ConstraintPtr ptr = m_table_of_query->constraint({m_table_of_query->fields.at(column).name()}, sqlb::Constraint::ForeignKeyConstraintType); + if(ptr) + return *(std::dynamic_pointer_cast(ptr)); + } + + return empty_foreign_key_clause; +} + +bool SqliteTableModel::setData(const QModelIndex& index, const QVariant& value, int role) +{ + // Don't even try setting any data if we're not browsing a table, i.e. the model data comes from a custom query + if(!isEditable(index)) + return false; + + // This function is for in-place editing. + // So, BLOB flag is false every times. + return setTypedData(index, false, value, role); +} + +bool SqliteTableModel::setTypedData(const QModelIndex& index, bool isBlob, const QVariant& value, int role) +{ + if(readingData()) { + // can't insert rows while reading data in background + return false; + } + + if(index.isValid() && role == Qt::EditRole) + { + std::unique_lock lock(m_mutexDataCache); + + auto & cached_row = m_cache.at(static_cast(index.row())); + const size_t column = static_cast(index.column()); + + QByteArray newValue = encode(value.toByteArray()); + QByteArray oldValue = cached_row.at(column); + + // Special handling for integer columns: instead of setting an integer column to an empty string, set it to '0' when it is also + // used in a primary key. Otherwise SQLite will always output an 'datatype mismatch' error. + if(newValue == "" && !newValue.isNull()) + { + if(m_table_of_query) + { + auto field = sqlb::findField(m_table_of_query, m_headers.at(column)); + const auto pk = m_table_of_query->primaryKey(); + if(pk && contains(pk->columnList(), field->name()) && field->isInteger()) + newValue = "0"; + } + } + + // Don't do anything if the data hasn't changed + // To differentiate NULL and empty byte arrays, we also compare the NULL flag + if(oldValue == newValue && oldValue.isNull() == newValue.isNull()) + return true; + + // Determine type. If the BLOB flag is set, it's always BLOB. If the affinity data type of the modified column is something numeric, + // we check if the new value is also numeric. In that case we can safely set the data type to INTEGER or FLOAT. In all other cases we + // default to TEXT. + int type = SQLITE_TEXT; + if(isBlob) + { + type = SQLITE_BLOB; + } else if(m_vDataTypes.at(column) == SQLITE_INTEGER) { + bool ok; + newValue.toLongLong(&ok); + if(ok) + type = SQLITE_INTEGER; + } else if(m_vDataTypes.at(column) == SQLITE_FLOAT) { + bool ok; + newValue.toDouble(&ok); + if(ok) + type = SQLITE_FLOAT; + } + + if(m_db.updateRecord(m_query.table(), m_headers.at(column), cached_row.at(0), newValue, type, m_query.rowIdColumns())) + { + cached_row[column] = newValue; + + // After updating the value itself in the cache, we need to check if we need to update the rowid too. + if(contains(m_query.rowIdColumns(), m_headers.at(column))) + { + // When the cached rowid column needs to be updated as well, we need to distinguish between single-column and multi-column primary keys. + // For the former ones, we can just overwrite the existing value with the new value. + // For the latter ones, we need to make a new JSON object of the values of all primary key columns, not just the updated one. + if(m_query.rowIdColumns().size() == 1) + { + cached_row[0] = newValue; + } else { + json array; + assert(m_headers.size() == cached_row.size()); + for(size_t i=0;i(std::distance(m_headers.begin(), it))]); + } + cached_row[0] = QByteArray::fromStdString(array.dump()); + } + const QModelIndex& rowidIndex = index.sibling(index.row(), 0); + lock.unlock(); + emit dataChanged(rowidIndex, rowidIndex); + } else { + lock.unlock(); + } + emit dataChanged(index, index); + return true; + } else { + lock.unlock(); + QMessageBox::warning(nullptr, qApp->applicationName(), tr("Error changing data:\n%1").arg(m_db.lastError())); + return false; + } + } + + return false; +} + +Qt::ItemFlags SqliteTableModel::flags(const QModelIndex& index) const +{ + if(!index.isValid()) + return Qt::ItemIsEnabled; + + Qt::ItemFlags ret = QAbstractTableModel::flags(index) | Qt::ItemIsDropEnabled; + + // Custom display format set? + bool custom_display_format = false; + if(m_query.selectedColumns().size()) + { + if(index.column() > 0) + custom_display_format = m_query.selectedColumns().at(static_cast(index.column())-1).selector != m_query.selectedColumns().at(static_cast(index.column())-1).original_column; + } + + if(!isBinary(index) && !custom_display_format && isEditable(index)) + ret |= Qt::ItemIsEditable; + return ret; +} + +void SqliteTableModel::sort(int column, Qt::SortOrder order) +{ + // Construct a sort order list from this item and forward it to the function to sort by lists + std::vector list; + list.emplace_back(column, order == Qt::AscendingOrder ? sqlb::Ascending : sqlb::Descending); + sort(list); +} + +void SqliteTableModel::sort(const std::vector& columns) +{ + // Don't do anything when the sort order hasn't changed + if(m_query.orderBy() == columns) + return; + + // Save sort order + m_query.orderBy() = columns; + + // Set the new query (but only if a table has already been set + if(!m_query.table().isEmpty()) + buildQuery(); +} + +SqliteTableModel::Row SqliteTableModel::makeDefaultCacheEntry () const +{ + Row blank_data; + + for(size_t i=0; i < m_headers.size(); ++i) + blank_data.emplace_back(""); + + return blank_data; +} + +bool SqliteTableModel::readingData() const +{ + return worker->readingData(); +} + +bool SqliteTableModel::insertRows(int row, int count, const QModelIndex& parent) +{ + if(!isEditable()) + return false; + + if(readingData()) { + // can't insert rows while reading data in background + return false; + } + + const auto blank_data = makeDefaultCacheEntry(); + + std::vector tempList; + for(int i=row; i < row + count; ++i) + { + QString rowid = m_db.addRecord(m_query.table()); + if(rowid.isNull()) + { + return false; + } + tempList.emplace_back(blank_data); + tempList.back()[0] = rowid.toUtf8(); + + // update column with default values + Row rowdata; + if(m_db.getRow(m_query.table(), rowid, rowdata)) + { + for(size_t j=1; j < m_headers.size(); ++j) + { + tempList.back()[j] = rowdata[j - 1]; + } + } + } + + beginInsertRows(parent, row, row + count - 1); + for(size_t i = 0; i < tempList.size(); ++i) + { + m_cache.insert(i + static_cast(row), std::move(tempList.at(i))); + m_currentRowCount++; + } + endInsertRows(); + + return true; +} + +bool SqliteTableModel::removeRows(int row, int count, const QModelIndex& parent) +{ + if(!isEditable()) + return false; + + if(readingData()) { + // can't delete rows while reading data in background + return false; + } + + std::vector rowids; + for(int i=count-1;i>=0;i--) + { + if(m_cache.count(static_cast(row+i))) { + rowids.push_back(m_cache.at(static_cast(row + i)).at(0)); + } + } + + bool ok = m_db.deleteRecords(m_query.table(), rowids, m_query.rowIdColumns()); + + if (ok) { + beginRemoveRows(parent, row, row + count - 1); + + for(int i=count-1;i>=0;i--) + { + m_cache.erase(static_cast(row + i)); + m_currentRowCount--; + } + + endRemoveRows(); + } + return ok; +} + +QModelIndex SqliteTableModel::dittoRecord(int old_row) +{ + if(!isEditable()) + return QModelIndex(); + + if (!insertRow(rowCount())) + return QModelIndex(); + + size_t firstEditedColumn = 0; + int new_row = rowCount() - 1; + + const auto pk = m_table_of_query->primaryKey(); + for (size_t col = 0; col < m_table_of_query->fields.size(); ++col) { + if(!pk || !contains(pk->columnList(), m_table_of_query->fields.at(col).name())) { + if (!firstEditedColumn) + firstEditedColumn = col + 1; + + QVariant value = data(index(old_row, static_cast(col + 1)), Qt::EditRole); + setData(index(new_row, static_cast(col + 1)), value); + } + } + + return index(new_row, static_cast(firstEditedColumn)); +} + +void SqliteTableModel::buildQuery() +{ + setQuery(QString::fromStdString(m_query.buildQuery(true)), QString::fromStdString(m_query.buildCountQuery()), true); +} + +void SqliteTableModel::removeCommentsFromQuery(QString& query) +{ + int oldSize = query.size(); + + // first remove block comments + { + QRegExp rxSQL("^((?:(?:[^'/]|/(?![*]))*|'[^']*')*)(/[*](?:[^*]|[*](?!/))*[*]/)(.*)$"); // set up regex to find block comment + QString result; + + while(query.size() != 0) + { + int pos = rxSQL.indexIn(query); + if(pos > -1) + { + result += rxSQL.cap(1) + " "; + query = rxSQL.cap(3); + } else { + result += query; + query.clear(); + } + } + query = result; + } + + // deal with end-of-line comments + { + /* The regular expression for removing end of line comments works like this: + * ^((?:(?:[^'-]|-(?!-))*|(?:'[^']*'))*)(--.*)$ + * ^ $ # anchor beginning and end of string so we use it all + * ( )( ) # two separate capture groups for code and comment + * --.* # comment starts with -- and consumes everything afterwards + * (?: | )* # code is none or many strings alternating with non-strings + * (?:'[^']*') # a string is a quote, followed by none or more non-quotes, followed by a quote + * (?:[^'-]|-(?!-))* # non-string is a sequence of characters which aren't quotes or hyphens, + */ + + QRegExp rxSQL("^((?:(?:[^'-]|-(?!-))*|(?:'[^']*'))*)(--[^\\r\\n]*)([\\r\\n]*)(.*)$"); // set up regex to find end-of-line comment + QString result; + + while(query.size() != 0) + { + int pos = rxSQL.indexIn(query); + if(pos > -1) + { + result += rxSQL.cap(1) + rxSQL.cap(3); + query = rxSQL.cap(4); + } else { + result += query; + query.clear(); + } + } + + query = result.trimmed(); + } + + if (oldSize != query.size()) { + // Remove multiple line breaks that might have been created by deleting comments till the end of the line but not including the line break + query.replace(QRegExp("\\n+"), "\n"); + + // Also remove any remaining whitespace at the end of each line + query.replace(QRegExp("[ \t]+\n"), "\n"); + } +} + +std::vector SqliteTableModel::getColumns(std::shared_ptr pDb, const std::string& sQuery, std::vector& fieldsTypes) const +{ + if(!pDb) + pDb = m_db.get(tr("retrieving list of columns")); + + sqlite3_stmt* stmt; + std::vector listColumns; + if(sqlite3_prepare_v2(pDb.get(), sQuery.c_str(), static_cast(sQuery.size()), &stmt, nullptr) == SQLITE_OK) + { + if(sqlite3_step(stmt) == SQLITE_ROW) + { + int columns = sqlite3_data_count(stmt); + for(int i = 0; i < columns; ++i) + { + listColumns.push_back(sqlite3_column_name(stmt, i)); + fieldsTypes.push_back(sqlite3_column_type(stmt, i)); + } + } + } + sqlite3_finalize(stmt); + + return listColumns; +} + +void addCondFormatToMap(std::map>& mCondFormats, size_t column, const CondFormat& condFormat) +{ + // If the condition is already present in the vector, update that entry and respect the order, since two entries with the same + // condition do not make sense. + auto it = std::find_if(mCondFormats[column].begin(), mCondFormats[column].end(), [condFormat](const CondFormat& format) { + return format.sqlCondition() == condFormat.sqlCondition(); + }); + // Replace cond-format if present. push it back if it's a conditionless format (apply to every cell in column) or insert + // as first element otherwise. + if(it != mCondFormats[column].end()) { + *it = condFormat; + } else if (condFormat.filter().isEmpty()) + mCondFormats[column].push_back(condFormat); + else + mCondFormats[column].insert(mCondFormats[column].begin(), condFormat); +} + +void SqliteTableModel::addCondFormat(const bool isRowIdFormat, size_t column, const CondFormat& condFormat) +{ + if(isRowIdFormat) + addCondFormatToMap(m_mRowIdFormats, column, condFormat); + else + addCondFormatToMap(m_mCondFormats, column, condFormat); + emit layoutChanged(); +} + +void SqliteTableModel::setCondFormats(const bool isRowIdFormat, size_t column, const std::vector& condFormats) +{ + if(isRowIdFormat) + m_mRowIdFormats[column] = condFormats; + else + m_mCondFormats[column] = condFormats; + emit layoutChanged(); +} + +void SqliteTableModel::updateFilter(size_t column, const QString& value) +{ + std::string whereClause = CondFormat::filterToSqlCondition(value, m_encoding); + + // If the value was set to an empty string remove any filter for this column. Otherwise insert a new filter rule or replace the old one if there is already one + if(whereClause.empty()) + m_query.where().erase(column); + else + m_query.where()[column] = whereClause; + + // Build the new query + buildQuery(); +} + +void SqliteTableModel::updateGlobalFilter(const std::vector& values) +{ + std::vector filters; + for(auto& v : values) + filters.push_back(CondFormat::filterToSqlCondition(v, m_encoding)); + m_query.setGlobalWhere(filters); + + // Build the new query + buildQuery(); +} + +void SqliteTableModel::clearCache() +{ + m_lifeCounter++; + + if(m_db.isOpen()) { + worker->cancel(); + worker->waitUntilIdle(); + } + + if(m_currentRowCount > 0) + { + beginRemoveRows(QModelIndex(), 0, static_cast(m_currentRowCount - 1)); + endRemoveRows(); + } + + m_cache.clear(); + m_currentRowCount = 0; + m_rowCountAvailable = RowCount::Unknown; +} + +bool SqliteTableModel::isBinary(const QModelIndex& index) const +{ + std::lock_guard lock(m_mutexDataCache); + + const size_t row = static_cast(index.row()); + if(!m_cache.count(row)) + return false; + + const auto & cached_row = m_cache.at(row); + return isBinary(cached_row.at(static_cast(index.column()))); +} + +bool SqliteTableModel::isBinary(const QByteArray& data) const +{ + return !isTextOnly(data, m_encoding, true); +} + +QByteArray SqliteTableModel::encode(const QByteArray& str) const +{ + return encodeString(str, m_encoding); +} + +QByteArray SqliteTableModel::decode(const QByteArray& str) const +{ + return decodeString(str, m_encoding); +} + +Qt::DropActions SqliteTableModel::supportedDropActions() const +{ + return Qt::CopyAction; +} + +bool SqliteTableModel::dropMimeData(const QMimeData* data, Qt::DropAction, int row, int column, const QModelIndex& parent) +{ + // What has been dropped on the widget? + if(data->hasUrls()) + { + // If it's a URL, open the file and paste the content in the current cell + QList urls = data->urls(); + QFile file(urls.first().toLocalFile()); + if(file.exists() && file.open(QFile::ReadOnly)) + { + setData(index(row, column, parent), file.readAll()); + return true; + } + } else if(data->hasText()) { + // If it's just text we can set the cell data directly + setData(index(row, column, parent), data->text()); + } + + return false; +} + +void SqliteTableModel::setPseudoPk(std::vector pseudoPk) +{ + if(pseudoPk.empty()) + pseudoPk.emplace_back("_rowid_"); + + // Do nothing if the value didn't change + if(m_query.rowIdColumns() == pseudoPk) + return; + + m_query.setRowIdColumns(pseudoPk); + if(m_headers.size()) + m_headers[0] = sqlb::joinStringVector(pseudoPk, ","); + + buildQuery(); +} + +bool SqliteTableModel::hasPseudoPk() const +{ + return m_query.hasCustomRowIdColumn(); +} + +bool SqliteTableModel::isEditable(const QModelIndex& index) const +{ + if(m_query.table().isEmpty()) + return false; + if(!m_db.isOpen()) + return false; + if(!m_table_of_query && !m_query.hasCustomRowIdColumn()) + return false; + + // Extra check when the index parameter is set and pointing to a generated column in a table + if(index.isValid() && m_table_of_query) + { + const auto field = sqlb::findField(m_table_of_query, m_headers.at(static_cast(index.column()))); + if(field != m_table_of_query->fields.cend() && !field->generated().empty()) + return false; + } + + return true; +} + +void SqliteTableModel::triggerCacheLoad (int row) const +{ + int halfChunk = static_cast( m_chunkSize / 2); + size_t row_begin = static_cast(std::max(0, row - halfChunk)); + size_t row_end = static_cast(row + halfChunk); + + if(rowCountAvailable() == RowCount::Complete) + { + row_end = std::min(row_end, static_cast(rowCount())); + } else { + // will be truncated by reader + } + + // avoid re-fetching data + std::lock_guard lk(m_mutexDataCache); + m_cache.smallestNonAvailableRange(row_begin, row_end); + + if(row_end != row_begin) + worker->triggerFetch(m_lifeCounter, row_begin, row_end); +} + +void SqliteTableModel::triggerCacheLoad (int row_begin, int row_end) const +{ + if(row_end == row_begin) + return; + + triggerCacheLoad((row_begin + row_end) / 2); +} + +bool SqliteTableModel::completeCache () const +{ + // Show progress dialog because fetching all data might take some time but only show + // cancel button if we allow cancellation here. This isn't + QProgressDialog progress(tr("Fetching data..."), + tr("Cancel"), 0, rowCount()); + + QPushButton* cancelButton = new QPushButton(tr("Cancel")); + // This is to prevent distracted cancelation of the fetching and avoid the + // Snap-To Windows optional feature. + cancelButton->setDefault(false); + cancelButton->setAutoDefault(false); + progress.setCancelButton(cancelButton); + + progress.setWindowModality(Qt::ApplicationModal); + progress.show(); + + waitUntilIdle(); + + // This loop fetches all data by loading it block by block into the cache + for(int i = 0; i < (rowCount() + static_cast( m_chunkSize / 2)); i += static_cast(m_chunkSize)) + { + progress.setValue(i); + qApp->processEvents(); + if(progress.wasCanceled()) + return false; + + triggerCacheLoad(i); + worker->waitUntilIdle(); + } + + return true; +} + +bool SqliteTableModel::isCacheComplete () const +{ + if(readingData()) + return false; + std::lock_guard lock(m_mutexDataCache); + return m_cache.numSet() == m_currentRowCount; +} + +void SqliteTableModel::waitUntilIdle () const +{ + worker->waitUntilIdle(); +} + +QModelIndex SqliteTableModel::nextMatch(const QModelIndex& start, const std::vector& column_list, const QString& value, Qt::MatchFlags flags, bool reverse, bool dont_skip_to_next_field) const +{ + // Extract flags + bool whole_cell = !(flags & Qt::MatchContains); + bool regex = flags & Qt::MatchRegExp; + Qt::CaseSensitivity case_sensitive = ((flags & Qt::MatchCaseSensitive) ? Qt::CaseSensitive : Qt::CaseInsensitive); + bool wrap = flags & Qt::MatchWrap; + int increment = (reverse ? -1 : 1); + + // Prepare the regular expression for regex mode + QRegularExpression reg_exp; + if(regex) + { + reg_exp = QRegularExpression(value, (case_sensitive ? QRegularExpression::NoPatternOption : QRegularExpression::CaseInsensitiveOption)); + if(!reg_exp.isValid()) + return QModelIndex(); + + if(whole_cell) + { +#if QT_VERSION < QT_VERSION_CHECK(5, 12, 0) + reg_exp.setPattern("\\A(" + reg_exp.pattern() + ")\\Z"); +#else + reg_exp.setPattern(QRegularExpression::anchoredPattern(reg_exp.pattern())); +#endif + } + } + + // Wait until the row count is there + waitUntilIdle(); + + // Stop right away if there is no data in the table + if(rowCount() == 0) + return QModelIndex(); + + // Make sure the start position starts in a column from the list of columns to search in + QModelIndex pos = start; + if(std::find(column_list.begin(), column_list.end(), pos.column()) == column_list.end()) + { + // If for some weird reason the start index is not in the column list, we simply use the first column of the column list instead + pos = pos.sibling(pos.row(), reverse ? column_list.back() : column_list.front()); + } + + // Get the last cell to search in. If wrapping is enabled, we search until we hit the start cell again. If wrapping is not enabled, we start at the last + // cell of the table. + QModelIndex end = (wrap ? pos : index(rowCount(), column_list.back())); + + // Loop through all cells for the search + while(true) + { + // Go to the next cell and skip all columns in between which we do not care about. This is done as the first step in order + // to skip the start index when matching the first cell is disabled. + if(dont_skip_to_next_field == false) + { + while(true) + { + // Next cell position + int next_row = pos.row(); + int next_column = pos.column() + increment; + + // Have we reached the end of the row? Then go to the next one + if(next_column < 0 || next_column >= static_cast(m_headers.size())) + { + next_row += increment; + next_column = (reverse ? column_list.back() : column_list.front()); + } + + // Have we reached the last row? Then wrap around to the first one + if(wrap && (next_row < 0 || next_row >= rowCount())) + next_row = (reverse ? rowCount()-1 : 0); + + // Set next index for search + pos = pos.sibling(next_row, next_column); + + // Have we hit the last column? We have not found anything then + if(pos == end) + return QModelIndex(); + + // Is this a column which we are supposed to search in? If so, stop looking for the next cell and start comparing + if(std::find(column_list.begin(), column_list.end(), next_column) != column_list.end()) + break; + } + } + + // Make sure the next time we hit the above check, we actuall move on to the next cell and do not skip the loop again. + dont_skip_to_next_field = false; + + // Get row from cache. If it is not in the cache, load the next chunk from the database + const size_t row = static_cast(pos.row()); + if(!m_cache.count(row)) + { + triggerCacheLoad(static_cast(row)); + waitUntilIdle(); + } + const Row* row_data = &m_cache.at(row); + + // Get cell data + const size_t column = static_cast(pos.column()); + QString data = row_data->at(column); + + // Perform comparison + if(whole_cell && !regex && data.compare(value, case_sensitive) == 0) + return pos; + else if(!whole_cell && !regex && data.contains(value, case_sensitive)) + return pos; + else if(regex && reg_exp.match(data).hasMatch()) + return pos; + } +} + +void SqliteTableModel::reloadSettings() +{ + m_nullText = Settings::getValue("databrowser", "null_text").toString(); + m_blobText = Settings::getValue("databrowser", "blob_text").toString(); + m_regFgColour = QColor(Settings::getValue("databrowser", "reg_fg_colour").toString()); + m_regBgColour = QColor(Settings::getValue("databrowser", "reg_bg_colour").toString()); + m_nullFgColour = QColor(Settings::getValue("databrowser", "null_fg_colour").toString()); + m_nullBgColour = QColor(Settings::getValue("databrowser", "null_bg_colour").toString()); + m_binFgColour = QColor(Settings::getValue("databrowser", "bin_fg_colour").toString()); + m_binBgColour = QColor(Settings::getValue("databrowser", "bin_bg_colour").toString()); + m_font = QFont(Settings::getValue("databrowser", "font").toString()); + m_font.setPointSize(Settings::getValue("databrowser", "fontsize").toInt()); + m_symbolLimit = Settings::getValue("databrowser", "symbol_limit").toInt(); + m_imagePreviewEnabled = Settings::getValue("databrowser", "image_preview").toBool(); + m_chunkSize = static_cast(Settings::getValue("db", "prefetchsize").toUInt()); +} diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/sqlitetablemodel.h b/src/WBCLFZSystemModule/SqliteDBProcess/src/sqlitetablemodel.h new file mode 100644 index 0000000..2d6fc58 --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/sqlitetablemodel.h @@ -0,0 +1,254 @@ +#ifndef SQLITETABLEMODEL_H +#define SQLITETABLEMODEL_H + +#include +#include +#include + +#include +#include +#include +#include + +#include "RowCache.h" +#include "sql/Query.h" +#include "sql/sqlitetypes.h" + +struct sqlite3; +class DBBrowserDB; +class CondFormat; + +class SqliteTableModel : public QAbstractTableModel +{ + Q_OBJECT + +#ifdef REGEX_UNIT_TEST + friend class TestRegex; +#endif + +public: + explicit SqliteTableModel(DBBrowserDB& db, QObject *parent = nullptr, const QString& encoding = QString()); + ~SqliteTableModel() override; + + /// reset to state after construction + void reset(); + + /// returns logical amount of rows, whether currently cached or not + int rowCount(const QModelIndex &parent = QModelIndex()) const override; + + int columnCount(const QModelIndex &parent = QModelIndex()) const override; + size_t filterCount() const; + QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override; + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; + bool setData(const QModelIndex& index, const QVariant& value, int role = Qt::EditRole) override; + bool setTypedData(const QModelIndex& index, bool isBlob, const QVariant& value, int role = Qt::EditRole); + + enum class RowCount + { + Unknown, //< still finding out in background... + Partial, //< some chunk was read and at least a lower bound is thus known + Complete //< total row count of table known + }; + + /// what kind of information is available through rowCount()? + RowCount rowCountAvailable () const; + + /// trigger asynchronous loading of (at least) the specified row + /// into cache. + void triggerCacheLoad (int single_row) const; + + /// trigger asynchronous loading of (at least) the specified rows + /// into cache. \param row_end is exclusive. + void triggerCacheLoad (int row_begin, int row_end) const; + + /// wait until not reading any data (that does not mean data is + /// complete, just that the background reader is idle) + void waitUntilIdle () const; + + /// load all rows into cache, return when done. Returns true if all data was loaded, false if the loading was cancelled. + bool completeCache() const; + + /// returns true if all rows are currently available in cache + /// [NOTE: potentially unsafe in case we have a limited-size + /// cache, where entries can vanish again -- however we can't do + /// this for the current implementation of the PlotDock] + bool isCacheComplete () const; + + bool insertRows(int row, int count, const QModelIndex& parent = QModelIndex()) override; + bool removeRows(int row, int count, const QModelIndex& parent = QModelIndex()) override; + + QModelIndex dittoRecord(int old_row); + + /// configure for browsing results of specified query + void setQuery(const QString& sQuery, const QString& sCountQuery = QString(), bool dontClearHeaders = false); + + std::string query() const { return m_sQuery.toStdString(); } + std::string customQuery(bool withRowid) const { return m_query.buildQuery(withRowid); } + + /// configure for browsing specified table + void setQuery(const sqlb::Query& query); + + void sort(int column, Qt::SortOrder order = Qt::AscendingOrder) override; + void sort(const std::vector& columns); + sqlb::ObjectIdentifier currentTableName() const { return m_query.table(); } + + Qt::ItemFlags flags(const QModelIndex& index) const override; + + bool isBinary(const QModelIndex& index) const; + + void setEncoding(const QString& encoding) { m_encoding = encoding; } + QString encoding() const { return m_encoding; } + + // The pseudo-primary key is exclusively for editing views + void setPseudoPk(std::vector pseudoPk); + bool hasPseudoPk() const; + std::vector pseudoPk() const { return m_query.rowIdColumns(); } + + sqlb::ForeignKeyClause getForeignKeyClause(size_t column) const; + + // This returns true if the model and, if set, the index can be edited. Not specifying the index parameter asks whether the model can + // be edited in general (i.e. inserting and deleting rows as well as updating some cells). Specifying the index parameter asks whether + // this specific index can be edited. + // The model is able to operate in more or less two different modes, table browsing and query browsing. We only support editing data + // in the table browsing mode but not for the query mode. This function returns true if the model is currently editable, i.e. it's + // running in the table mode and isn't browsing a view, unless this view is set up for editing by specifying a pseudo PK. + // When the index parameter is set, the same checks are performed but additionally the function checks whether this specific index + // can be edited. This makes a difference for generated columns which are in (editable) tables but cannot be modified anyway. + bool isEditable(const QModelIndex& index = QModelIndex()) const; + + // Helper function for removing all comments from a SQL query + static void removeCommentsFromQuery(QString& query); + + // Conditional formats are of two kinds: regular conditional formats (including condition-free formats applying to any value in the + // column) and formats applying to a particular row-id and which have always precedence over the first kind and whose filter apply + // to the row-id column. + void addCondFormat(const bool isRowIdFormat, size_t column, const CondFormat& condFormat); + void setCondFormats(const bool isRowIdFormat, size_t column, const std::vector& condFormats); + + // Search for the specified expression in the given cells. This intended as a replacement for QAbstractItemModel::match() even though + // it does not override it, which - because of the different parameters - is not possible. + // start contains the index to start with, column_list contains the ordered list of the columns to look in, value is the value to search for, + // flags allows to modify the search process (Qt::MatchContains, Qt::MatchRegExp, Qt::MatchCaseSensitive, and Qt::MatchWrap are understood), + // reverse can be set to true to progress through the cells in backwards direction, and dont_skip_to_next_field can be set to true if the current + // cell can be matched as well. + QModelIndex nextMatch(const QModelIndex& start, + const std::vector& column_list, + const QString& value, + Qt::MatchFlags flags = Qt::MatchFlags(Qt::MatchContains), + bool reverse = false, + bool dont_skip_to_next_field = false) const; + + DBBrowserDB& db() { return m_db; } + + void reloadSettings(); + +public slots: + void updateFilter(size_t column, const QString& value); + void updateGlobalFilter(const std::vector& values); + +signals: + void finishedFetch(int fetched_row_begin, int fetched_row_end); + void finishedRowCount(); + +protected: + Qt::DropActions supportedDropActions() const override; + bool dropMimeData(const QMimeData* data, Qt::DropAction action, int row, int column, const QModelIndex& parent) override; + +private: + friend class RowLoader; + class RowLoader * worker; + + /// clears the cache, resets row-count to unknown (but keeps table + /// & query info), increase life_counter + void clearCache(); + + void handleFinishedFetch(int life_id, unsigned int fetched_row_begin, unsigned int fetched_row_end); + void handleRowCountComplete(int life_id, int num_rows); + + void buildQuery(); + + /// \param pDb connection to query; if null, obtains it from 'm_db'. + std::vector getColumns(std::shared_ptr pDb, const std::string& sQuery, std::vector& fieldsTypes) const; + + QByteArray encode(const QByteArray& str) const; + QByteArray decode(const QByteArray& str) const; + + // Return matching conditional format color/font or invalid value, otherwise. + // Only format roles are expected in role (Qt::ItemDataRole) + QVariant getMatchingCondFormat(size_t row, size_t column, const QString& value, int role) const; + QVariant getMatchingCondFormat(const std::map>& mCondFormats, size_t column, const QString& value, int role) const; + + DBBrowserDB& m_db; + + /// counts numbers of clearCache() since instantiation; using this + /// to avoid processing of queued signals originating in an era + /// before the most recent reset(). + int m_lifeCounter; + + /// note: the row count can be determined by the row-count query + /// (which yields the "final" row count"), or, if it is faster, by + /// the first chunk reading actual data (in which case the row + /// count will be set to that chunk's size and later updated to + /// the full row count, when the row-count query returns) + RowCount m_rowCountAvailable; + unsigned int m_currentRowCount; + + std::vector m_headers; + + /// reading something in background right now? (either counting + /// rows or actually loading data, doesn't matter) + bool readingData() const; + + using Row = std::vector; + mutable RowCache m_cache; + + Row makeDefaultCacheEntry () const; + + bool isBinary(const QByteArray& index) const; + + QString m_sQuery; + std::vector m_vDataTypes; + std::map> m_mCondFormats; + std::map> m_mRowIdFormats; + + sqlb::Query m_query; + std::shared_ptr m_table_of_query; // This holds a pointer to the table object which is queried in the m_query object + + QString m_encoding; + + /** + * These are used for multi-threaded population of the table + */ + mutable std::mutex m_mutexDataCache; + +private: + /** + * Settings. These are stored here to avoid fetching and converting them every time we need them. Because this class + * uses a lot of settings and because some of its functions are called very often, this should speed things up noticeable. + * Call reloadSettings() to update these. + */ + + QString m_nullText; + QString m_blobText; + QColor m_regFgColour; + QColor m_regBgColour; + QColor m_nullFgColour; + QColor m_nullBgColour; + QColor m_binFgColour; + QColor m_binBgColour; + QFont m_font; + int m_symbolLimit; + bool m_imagePreviewEnabled; + + /** + * @brief m_chunkSize Size of the next chunk fetch more will try to fetch. + * This value should be rather high, because our query + * uses LIMIT and sqlite3 will still execute the whole query and + * just skip the not wanted rows, but the execution will + * still take nearly the same time as doing the query at all up + * to that row count. + */ + size_t m_chunkSize; +}; + +#endif diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/sqltextedit.cpp b/src/WBCLFZSystemModule/SqliteDBProcess/src/sqltextedit.cpp new file mode 100644 index 0000000..eabf43f --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/sqltextedit.cpp @@ -0,0 +1,135 @@ +#include "sql/ObjectIdentifier.h" +#include "sqltextedit.h" +#include "Settings.h" +#include "SqlUiLexer.h" + +#include +#include + +#include +#include + +SqlUiLexer* SqlTextEdit::sqlLexer = nullptr; + +SqlTextEdit::SqlTextEdit(QWidget* parent) : + ExtendedScintilla(parent) +{ + // Create lexer object if not done yet + if(sqlLexer == nullptr) + sqlLexer = new SqlUiLexer(this); + + // Set the SQL lexer + setLexer(sqlLexer); + + // Set icons for auto completion + registerImage(SqlUiLexer::ApiCompleterIconIdKeyword, QImage(":/icons/keyword")); + registerImage(SqlUiLexer::ApiCompleterIconIdFunction, QImage(":/icons/function")); + registerImage(SqlUiLexer::ApiCompleterIconIdTable, QImage(":/icons/table")); + registerImage(SqlUiLexer::ApiCompleterIconIdColumn, QImage(":/icons/field")); + registerImage(SqlUiLexer::ApiCompleterIconIdSchema, QImage(":/icons/database")); + + // Remove command bindings that would interfere with our shortcutToggleComment + QsciCommand * command = standardCommands()->boundTo(Qt::ControlModifier+Qt::Key_Slash); + command->setKey(0); + command = standardCommands()->boundTo(Qt::ControlModifier+Qt::ShiftModifier+Qt::Key_Slash); + command->setKey(0); + + // Change command binding for Ctrl+T so it doesn't interfere with "Open tab" + command = standardCommands()->boundTo(Qt::ControlModifier+Qt::Key_T); + command->setKey(Qt::ControlModifier+Qt::ShiftModifier+Qt::Key_Up); + + QShortcut* shortcutToggleComment = new QShortcut(QKeySequence(tr("Ctrl+/")), this, nullptr, nullptr, Qt::WidgetShortcut); + connect(shortcutToggleComment, &QShortcut::activated, this, &SqlTextEdit::toggleBlockComment); + + // Do rest of initialisation + reloadSettings(); +} + +void SqlTextEdit::reloadSettings() +{ + // Enable auto completion if it hasn't been disabled + if(Settings::getValue("editor", "auto_completion").toBool()) + { + setAutoCompletionThreshold(3); + setAutoCompletionCaseSensitivity(true); + setAutoCompletionShowSingle(true); + setAutoCompletionSource(QsciScintilla::AcsAPIs); + } else { + setAutoCompletionThreshold(0); + } + // Set wrap lines + setWrapMode(static_cast(Settings::getValue("editor", "wrap_lines").toInt())); + + ExtendedScintilla::reloadSettings(); + + setupSyntaxHighlightingFormat(sqlLexer, "comment", QsciLexerSQL::Comment); + setupSyntaxHighlightingFormat(sqlLexer, "comment", QsciLexerSQL::CommentLine); + setupSyntaxHighlightingFormat(sqlLexer, "comment", QsciLexerSQL::CommentDoc); + setupSyntaxHighlightingFormat(sqlLexer, "keyword", QsciLexerSQL::Keyword); + setupSyntaxHighlightingFormat(sqlLexer, "table", QsciLexerSQL::KeywordSet6); + setupSyntaxHighlightingFormat(sqlLexer, "function", QsciLexerSQL::KeywordSet7); + setupSyntaxHighlightingFormat(sqlLexer, "string", QsciLexerSQL::SingleQuotedString); + + // Highlight double quote strings as identifier or as literal string depending on user preference + switch(static_cast(Settings::getValue("editor", "identifier_quotes").toInt())) { + case sqlb::DoubleQuotes: + setupSyntaxHighlightingFormat(sqlLexer, "identifier", QsciLexerSQL::DoubleQuotedString); + sqlLexer->setQuotedIdentifiers(false); + break; + case sqlb::GraveAccents: + sqlLexer->setQuotedIdentifiers(true); + setupSyntaxHighlightingFormat(sqlLexer, "string", QsciLexerSQL::DoubleQuotedString); // treat quoted string as literal string + break; + case sqlb::SquareBrackets: + setupSyntaxHighlightingFormat(sqlLexer, "string", QsciLexerSQL::DoubleQuotedString); + break; + } + setupSyntaxHighlightingFormat(sqlLexer, "identifier", QsciLexerSQL::Identifier); + setupSyntaxHighlightingFormat(sqlLexer, "identifier", QsciLexerSQL::QuotedIdentifier); +} + + +void SqlTextEdit::toggleBlockComment() +{ + int lineFrom, indexFrom, lineTo, indexTo; + + // If there is no selection, select the current line + if (!hasSelectedText()) { + getCursorPosition(&lineFrom, &indexFrom); + + // Windows lines requires an adjustment, otherwise the selection would + // end in the next line. + indexTo = text(lineFrom).endsWith("\r\n") ? lineLength(lineFrom)-1 : lineLength(lineFrom); + + setSelection(lineFrom, 0, lineFrom, indexTo); + } + + getSelection(&lineFrom, &indexFrom, &lineTo, &indexTo); + + bool uncomment = text(lineFrom).contains(QRegExp("^[ \t]*--")); + + // If the selection ends before the first character of a line, don't + // take this line into account for un/commenting. + if (indexTo==0) + lineTo--; + + beginUndoAction(); + + // Iterate over the selected lines, get line text, make + // replacement depending on whether the first line was commented + // or uncommented, and replace the line text. All in a single undo action. + for (int line=lineFrom; line<=lineTo; line++) { + QString lineText = text(line); + + if (uncomment) + lineText.replace(QRegExp("^([ \t]*)-- ?"), "\\1"); + else + lineText.replace(QRegExp("^"), "-- "); + + indexTo = lineText.endsWith("\r\n") ? lineLength(line)-1 : lineLength(line); + + setSelection(line, 0, line, indexTo); + replaceSelectedText(lineText); + } + endUndoAction(); +} diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/sqltextedit.h b/src/WBCLFZSystemModule/SqliteDBProcess/src/sqltextedit.h new file mode 100644 index 0000000..ffcd6cf --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/sqltextedit.h @@ -0,0 +1,27 @@ +#ifndef SQLTEXTEDIT_H +#define SQLTEXTEDIT_H + +#include "ExtendedScintilla.h" + +class SqlUiLexer; + +/** + * @brief The SqlTextEdit class + * This class is based on the QScintilla widget + */ +class SqlTextEdit : public ExtendedScintilla +{ + Q_OBJECT + +public: + explicit SqlTextEdit(QWidget *parent = nullptr); + + static SqlUiLexer* sqlLexer; + +public slots: + void reloadSettings(); + void toggleBlockComment(); + +}; + +#endif diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/src.pro b/src/WBCLFZSystemModule/SqliteDBProcess/src/src.pro new file mode 100644 index 0000000..f5c2e58 --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/src.pro @@ -0,0 +1,303 @@ +TEMPLATE = app + +QT += core gui network widgets printsupport concurrent xml + +TARGET = sqlitebrowser + +CONFIG += debug_and_release +CONFIG += qt +CONFIG += warn_on + +QMAKE_CXXFLAGS += -std=c++11 + +# create a unittest option +CONFIG(unittest) { + QT += testlib + + HEADERS += tests/testsqlobjects.h tests/TestImport.h tests/TestRegex.h tests/TestRowCache.h + SOURCES += tests/testsqlobjects.cpp tests/TestImport.cpp tests/TestRegex.cpp tests/TestRowCache.cpp +} else { + SOURCES += main.cpp +} + +HEADERS += \ + RemoteCommitsModel.h \ + RemoteLocalFilesModel.h \ + RemoteNetwork.h \ + sqlitedb.h \ + MainWindow.h \ + EditIndexDialog.h \ + AboutDialog.h \ + EditTableDialog.h \ + AddRecordDialog.h \ + Settings.h \ + PreferencesDialog.h \ + EditDialog.h \ + ExportDataDialog.h \ + ImportCsvDialog.h \ + sqltextedit.h \ + sql/sqlitetypes.h \ + csvparser.h \ + ExtendedTableWidget.h \ + sqlitetablemodel.h \ + RowCache.h \ + RowLoader.h \ + FilterTableHeader.h \ + version.h \ + SqlExecutionArea.h \ + VacuumDialog.h \ + DbStructureModel.h \ + Application.h \ + sqlite.h \ + CipherDialog.h \ + ExportSqlDialog.h \ + SqlUiLexer.h \ + FileDialog.h \ + ColumnDisplayFormatDialog.h \ + FilterLineEdit.h \ + RemoteDatabase.h \ + ForeignKeyEditorDelegate.h \ + PlotDock.h \ + RemoteDock.h \ + RemoteModel.h \ + RemotePushDialog.h \ + docktextedit.h \ + FindReplaceDialog.h \ + ExtendedScintilla.h \ + FileExtensionManager.h \ + CondFormatManager.h \ + Data.h \ + CipherSettings.h \ + DotenvFormat.h \ + Palette.h \ + CondFormat.h \ + sql/Query.h \ + RunSql.h \ + sql/ObjectIdentifier.h \ + ProxyDialog.h \ + IconCache.h \ + SelectItemsPopup.h \ + TableBrowser.h \ + sql/parser/ParserDriver.h \ + sql/parser/sqlite3_lexer.h \ + sql/parser/sqlite3_location.h \ + sql/parser/sqlite3_parser.hpp + +SOURCES += \ + RemoteCommitsModel.cpp \ + RemoteLocalFilesModel.cpp \ + RemoteNetwork.cpp \ + sqlitedb.cpp \ + MainWindow.cpp \ + EditIndexDialog.cpp \ + EditTableDialog.cpp \ + AddRecordDialog.cpp \ + Settings.cpp \ + PreferencesDialog.cpp \ + AboutDialog.cpp \ + EditDialog.cpp \ + ExportDataDialog.cpp \ + ImportCsvDialog.cpp \ + sqltextedit.cpp \ + sql/sqlitetypes.cpp \ + csvparser.cpp \ + ExtendedTableWidget.cpp \ + sqlitetablemodel.cpp \ + RowLoader.cpp \ + FilterTableHeader.cpp \ + SqlExecutionArea.cpp \ + VacuumDialog.cpp \ + DbStructureModel.cpp \ + Application.cpp \ + CipherDialog.cpp \ + ExportSqlDialog.cpp \ + SqlUiLexer.cpp \ + FileDialog.cpp \ + ColumnDisplayFormatDialog.cpp \ + FilterLineEdit.cpp \ + RemoteDatabase.cpp \ + ForeignKeyEditorDelegate.cpp \ + PlotDock.cpp \ + RemoteDock.cpp \ + RemoteModel.cpp \ + RemotePushDialog.cpp \ + docktextedit.cpp \ + FindReplaceDialog.cpp \ + ExtendedScintilla.cpp \ + FileExtensionManager.cpp \ + CondFormatManager.cpp \ + Data.cpp \ + CipherSettings.cpp \ + DotenvFormat.cpp \ + Palette.cpp \ + CondFormat.cpp \ + sql/Query.cpp \ + RunSql.cpp \ + sql/ObjectIdentifier.cpp \ + ProxyDialog.cpp \ + IconCache.cpp \ + SelectItemsPopup.cpp \ + TableBrowser.cpp \ + sql/parser/ParserDriver.cpp \ + sql/parser/sqlite3_lexer.cpp \ + sql/parser/sqlite3_parser.cpp + +RESOURCES += icons/icons.qrc \ + translations/flags/flags.qrc \ + translations/translations.qrc \ + certs/CaCerts.qrc \ + qdarkstyle/style.qrc + +FORMS += \ + MainWindow.ui \ + EditIndexDialog.ui \ + AboutDialog.ui \ + EditTableDialog.ui \ + AddRecordDialog.ui \ + PreferencesDialog.ui \ + EditDialog.ui \ + ExportDataDialog.ui \ + ImportCsvDialog.ui \ + SqlExecutionArea.ui \ + VacuumDialog.ui \ + CipherDialog.ui \ + ExportSqlDialog.ui \ + ColumnDisplayFormatDialog.ui \ + PlotDock.ui \ + RemoteDock.ui \ + RemotePushDialog.ui \ + FindReplaceDialog.ui \ + FileExtensionManager.ui \ + CondFormatManager.ui \ + ProxyDialog.ui \ + SelectItemsPopup.ui \ + TableBrowser.ui + +TRANSLATIONS += \ + translations/sqlb_ar_SA.ts \ + translations/sqlb_cs.ts \ + translations/sqlb_zh.ts \ + translations/sqlb_zh_TW.ts \ + translations/sqlb_de.ts \ + translations/sqlb_es_ES.ts \ + translations/sqlb_fr.ts \ + translations/sqlb_ru.ts \ + translations/sqlb_pl.ts \ + translations/sqlb_pt_BR.ts \ + translations/sqlb_en_GB.ts \ + translations/sqlb_ko_KR.ts \ + translations/sqlb_tr.ts \ + translations/sqlb_uk_UA.ts \ + translations/sqlb_it.ts \ + translations/sqlb_ja.ts \ + translations/sqlb_nl.ts + +# SQLite / SQLCipher switch pieces +CONFIG(sqlcipher) { + QMAKE_CXXFLAGS += -DENABLE_SQLCIPHER + LIBS += -lsqlcipher + + # Add the paths for Homebrew installed SQLCipher + macx { + INCLUDEPATH += /usr/local/opt/sqlcipher/include + LIBS += -L/usr/local/opt/sqlcipher/lib + } +} else { + LIBS += -lsqlite3 + + # Add the paths for Homebrew installed SQLite + macx { + INCLUDEPATH += /usr/local/opt/sqlite/include + LIBS += -L/usr/local/opt/sqlite/lib + } +} + +LIBPATH_QHEXEDIT=$$OUT_PWD/../libs/qhexedit +LIBPATH_QCUSTOMPLOT=$$OUT_PWD/../libs/qcustomplot-source +LIBPATH_QSCINTILLA=$$OUT_PWD/../libs/qscintilla/Qt4Qt5 +LIBPATH_JSON=$$OUT_PWD/../libs/json +unix { + LIBS += -ldl +} +os2 { + RC_FILE = os2app.rc +} +win32 { + TARGET = "DB Browser for SQLite" + RC_FILE = winapp.rc + INCLUDEPATH += $$PWD + CONFIG(debug,debug|release) { + LIBPATH_QHEXEDIT = $$LIBPATH_QHEXEDIT/debug + LIBPATH_QCUSTOMPLOT = $$LIBPATH_QCUSTOMPLOT/debug + LIBPATH_QSCINTILLA = $$LIBPATH_QSCINTILLA/debug + LIBPATH_JSON = $$LIBPATH_JSON/debug + } + CONFIG(release,debug|release) { + LIBPATH_QHEXEDIT = $$LIBPATH_QHEXEDIT/release + LIBPATH_QCUSTOMPLOT = $$LIBPATH_QCUSTOMPLOT/release + LIBPATH_QSCINTILLA = $$LIBPATH_QSCINTILLA/release + LIBPATH_JSON = $$LIBPATH_JSON/release + } + QMAKE_CXXFLAGS += -DCHECKNEWVERSION + + # Added SQLite installation path variables, matching our setup guide + LIBS += -L$$PWD/../../../dev/SQLite/ -lsqlite3 + INCLUDEPATH += $$PWD/../../../dev/SQLite + DEPENDPATH += $$PWD/../../../dev/SQLite +} +macx { + TARGET = "DB Browser for SQLite" + RC_FILE = macapp.icns + QT += macextras opengl + INCLUDEPATH += /usr/local/include + LIBS += -L/usr/local/lib -framework Carbon + QMAKE_INFO_PLIST = app.plist + QMAKE_CXXFLAGS += -DCHECKNEWVERSION +} + +CONFIG(all_warnings) { + QMAKE_CXXFLAGS += -Wall -Wextra -Wshadow -Wnon-virtual-dtor -Wold-style-cast -Wcast-align -Wunused -Woverloaded-virtual -Wpedantic -Wconversion -Wsign-conversion + QMAKE_CXXFLAGS += -Wnull-dereference -Wdouble-promotion -Wformat=2 -Wduplicated-cond -Wduplicated-branches -Wlogical-op -Wuseless-cast +} + +UI_DIR = .ui +INCLUDEPATH += $$PWD/../libs/qhexedit/src $$PWD/../libs/qcustomplot-source $$PWD/../libs/qscintilla/Qt4Qt5 $$PWD/../libs/json $$PWD/.. +LIBS += -L$$LIBPATH_QHEXEDIT -L$$LIBPATH_QCUSTOMPLOT -L$$LIBPATH_QSCINTILLA -lqhexedit -lqcustomplot -lqscintilla2 +DEPENDPATH += $$PWD/../libs/qhexedit $$PWD/../libs/qcustomplot-source $$PWD/../libs/qscintilla/Qt4Qt5 $$PWD/../libs/json + +unix { + # 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 + # DATADIR -> where data files and resources should be placed + # + # The values of each variable changes between supported platforms and are describe as follow + + # Default configuration for package sqlitebrowser. + # The default prefix is /usr/local + !defined(PREFIX, var): PREFIX = /usr/local + !defined(BINDIR, var): BINDIR = $$PREFIX/bin + !defined(DATADIR, var): DATADIR = $$PREFIX/share + + # The executable + target.path = $$BINDIR + INSTALLS += target + + # Icon + icon.path = $$DATADIR/icons/hicolor/256x256/apps/ + icon.files = icons/sqlitebrowser.png + INSTALLS += icon + + # Desktop metadata + desktop.path = $$DATADIR/applications/ + desktop.files = ../distri/sqlitebrowser.desktop + INSTALLS += desktop + appdata.path = $$DATADIR/metainfo/ + appdata.files = ../distri/sqlitebrowser.desktop.appdata.xml + INSTALLS += appdata +} + +# Rules for creating/updating {ts|qm}-files +include(i18n.pri) diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/tests/CMakeLists.txt b/src/WBCLFZSystemModule/SqliteDBProcess/src/tests/CMakeLists.txt new file mode 100644 index 0000000..ccf87c6 --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/tests/CMakeLists.txt @@ -0,0 +1,162 @@ +include_directories("${CMAKE_CURRENT_BINARY_DIR}" ..) + +if(NOT WIN32) + set(LPTHREAD pthread) +endif() + +# test-sqlobjects + +set(TESTSQLOBJECTS_SRC + ../sqlitedb.cpp + ../sqlitetablemodel.cpp + ../RowLoader.cpp + ../sql/sqlitetypes.cpp + ../sql/Query.cpp + ../sql/ObjectIdentifier.cpp + ../csvparser.cpp + ../Settings.cpp + testsqlobjects.cpp + ../Data.cpp + ../CipherSettings.cpp + ../DotenvFormat.cpp + ../CondFormat.cpp + ../sql/parser/ParserDriver.cpp + ../sql/parser/sqlite3_lexer.cpp + ../sql/parser/sqlite3_parser.cpp +) + +set(TESTSQLOBJECTS_HDR + ../sql/sqlitetypes.h + ../sql/Query.h + ../sql/ObjectIdentifier.h + ../Data.h + ../sql/parser/ParserDriver.h + ../sql/parser/sqlite3_lexer.h + ../sql/parser/sqlite3_location.h + ../sql/parser/sqlite3_parser.hpp +) + +set(TESTSQLOBJECTS_MOC_HDR + ../sqlitedb.h + ../sqlitetablemodel.h + ../Settings.h + testsqlobjects.h + ../CipherSettings.h + ../DotenvFormat.h + ../CondFormat.h +) + +if(sqlcipher) + list(APPEND TESTSQLOBJECTS_SRC ../CipherDialog.cpp) + list(APPEND TESTSQLOBJECTS_FORMS ../CipherDialog.ui) + list(APPEND TESTSQLOBJECTS_MOC_HDR ../CipherDialog.h) +endif() + +QT5_WRAP_UI(TESTSQLOBJECTS_FORM_HDR ${TESTSQLOBJECTS_FORMS}) + +add_executable(test-sqlobjects ${TESTSQLOBJECTS_MOC} ${TESTSQLOBJECTS_HDR} ${TESTSQLOBJECTS_SRC} ${TESTSQLOBJECTS_FORM_HDR}) + +find_package(Qt5 REQUIRED COMPONENTS Test Widgets Gui) +target_link_libraries(test-sqlobjects Qt5::Test Qt5::Widgets Qt5::Gui) + +set(QT_LIBRARIES "") + +target_link_libraries(test-sqlobjects ${QT_LIBRARIES} ${LIBSQLITE}) +target_link_libraries(test-sqlobjects ${LPTHREAD}) +add_test(test-sqlobjects test-sqlobjects) + +# test-import + +set(TESTIMPORT_SRC + ../csvparser.cpp + TestImport.cpp +) + +set(TESTIMPORT_MOC_HDR + TestImport.h +) + +add_executable(test-import ${TESTIMPORT_MOC} ${TESTIMPORT_SRC}) + +find_package(Qt5 REQUIRED COMPONENTS Core) +target_link_libraries(test-import Qt5::Test Qt5::Core) + +set(QT_LIBRARIES "") + +target_link_libraries(test-import ${QT_LIBRARIES}) +add_test(test-import test-import) + +# test regex + +set(TESTREGEX_SRC + ../sqlitedb.cpp + ../sqlitetablemodel.cpp + ../RowLoader.cpp + ../sql/sqlitetypes.cpp + ../sql/Query.cpp + ../sql/ObjectIdentifier.cpp + ../Settings.cpp + TestRegex.cpp + ../Data.cpp + ../CipherSettings.cpp + ../DotenvFormat.cpp + ../CondFormat.cpp + ../sql/parser/ParserDriver.cpp + ../sql/parser/sqlite3_lexer.cpp + ../sql/parser/sqlite3_parser.cpp +) + +set(TESTREGEX_HDR + ../sql/sqlitetypes.h + ../sql/Query.h + ../sql/ObjectIdentifier.h + ../Data.h + ../sql/parser/ParserDriver.h + ../sql/parser/sqlite3_lexer.h + ../sql/parser/sqlite3_location.h + ../sql/parser/sqlite3_parser.hpp +) + +set(TESTREGEX_MOC_HDR + ../sqlitedb.h + ../sqlitetablemodel.h + ../Settings.h + TestRegex.h + ../CipherSettings.h + ../DotenvFormat.h + ../CondFormat.h +) + +if(sqlcipher) + list(APPEND TESTREGEX_SRC ../CipherDialog.cpp) + list(APPEND TESTREGEX_MOC_HDR ../CipherDialog.h) +endif() + +add_executable(test-regex ${TESTREGEX_MOC} ${TESTREGEX_HDR} ${TESTREGEX_SRC}) + +target_link_libraries(test-regex Qt5::Test Qt5::Core Qt5::Gui Qt5::Widgets) + +set(QT_LIBRARIES "") + +target_link_libraries(test-regex ${QT_LIBRARIES} ${LIBSQLITE}) +target_link_libraries(test-regex ${LPTHREAD}) +add_test(test-regex test-regex) + +# test cache + +set(TESTCACHE_SRC + TestRowCache.cpp +) + +set(TESTCACHE_MOC_HDR + TestRowCache.h +) + +add_executable(test-cache ${TESTCACHE_MOC} ${TESTCACHE_SRC}) + +target_link_libraries(test-cache Qt5::Test Qt5::Core) + +set(QT_LIBRARIES "") + +target_link_libraries(test-cache ${QT_LIBRARIES}) +add_test(test-cache test-cache) diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/tests/TestImport.cpp b/src/WBCLFZSystemModule/SqliteDBProcess/src/tests/TestImport.cpp new file mode 100644 index 0000000..f43cd78 --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/tests/TestImport.cpp @@ -0,0 +1,178 @@ +// force QtCore-only main application by QTEST_MAIN +#undef QT_GUI_LIB +#include +#include +#include +#include +#include + +#include "csvparser.h" +#include "TestImport.h" + +QTEST_MAIN(TestImport) + +TestImport::TestImport() +{ +} + +TestImport::~TestImport() +{ +} + +void TestImport::csvImport() +{ + // Fetch data + QFETCH(QString, csv); + QFETCH(char, separator); + QFETCH(char, quote); + QFETCH(QString, encoding); + QFETCH(int, numfields); + QFETCH(std::vector>, result); + + // Create temporary CSV file + QTemporaryFile file; + QVERIFY(file.open()); + { + QTextStream out(&file); + out.setCodec(encoding.toUtf8()); + out << csv; + } + file.flush(); + + CSVParser csvparser(true, separator, quote); + file.seek(0); + QTextStream tstream(&file); + tstream.setCodec(encoding.toUtf8()); + + std::vector> parsedCsv; + int parsedCsvColumns = 0; + csvparser.parse([&parsedCsv, &parsedCsvColumns](size_t /*rowNum*/, const CSVRow& data) -> bool { + std::vector row; + for(size_t i=0;i parsedCsvColumns) + parsedCsvColumns = row.size(); + return true; + }, tstream); + + // Check return values + QCOMPARE(parsedCsvColumns, numfields); + QCOMPARE(parsedCsv.size(), result.size()); + for(int i=0;i("csv"); + QTest::addColumn("separator"); + QTest::addColumn("quote"); + QTest::addColumn("encoding"); + QTest::addColumn("numfields"); + QTest::addColumn>>("result"); + + std::vector> result{ + {"a", "b", "c"}, + {"d", "e", "f"}, + {"g", "h", "i"} + }; + QTest::newRow("commas_noquotes") << "a,b,c\nd,e,f\ng,h,i\n" + << ',' + << static_cast(0) + << "UTF-8" + << 3 + << result; + QTest::newRow("semicolons_noquotes") << "a;b;c\nd;e;f\ng;h;i\n" + << ';' + << static_cast(0) + << "UTF-8" + << 3 + << result; + QTest::newRow("commas_doublequotes") << "\"a\",\"b\",\"c\"\n\"d\",\"e\",\"f\"\n\"g\",\"h\",\"i\"\n" + << ',' + << '"' + << "UTF-8" + << 3 + << result; + QTest::newRow("noquotes_butquotesset") << "a,b,c\nd,e,f\ng,h,i\n" + << ',' + << '"' + << "UTF-8" + << 3 + << result; + QTest::newRow("windowslinebreaks") << "a,b,c\r\nd,e,f\r\ng,h,i\r\n" + << ',' + << static_cast(0) + << "UTF-8" + << 3 + << result; + QTest::newRow("oldmaclinebreaks") << "a,b,c\rd,e,f\rg,h,i\r" + << ',' + << static_cast(0) + << "UTF-8" + << 3 + << result; + + result.clear(); + result = { + {"a", "b", ""}, + {"c", ""}, + {"d", "", "e"}, + {""}, + {"", "", "f"} + }; + QTest::newRow("emptyvalues") << "a,b,\nc,\nd,,e\n\n,,f" + << ',' + << static_cast(0) + << "UTF-8" + << 3 + << result; + + result.clear(); + result = {{"a", "b", "c"}}; + QTest::newRow("oneline") << "a,b,c" + << ',' + << static_cast(0) + << "UTF-8" + << 3 + << result; + + result.clear(); + result = { + {"a,a\"", "b", "c"}, + {"d", "e", "\"\"f,f"} + }; + + QTest::newRow("manyquotes") << "\"a,a\"\"\",\"b\",\"c\"\n\"d\",\"e\",\"\"\"\"\"f,f\"\n" + << ',' + << '"' + << "UTF-8" + << 3 + << result; + + result.clear(); + result = {{QByteArray("\xC2\xAE"), QByteArray("\xC9\x85"), QByteArray("\xC6\x89")}}; + QString csv = QString::fromUtf8("\xC2\xAE") + "," + QString::fromUtf8("\xC9\x85") + "," + QString::fromUtf8("\xC6\x89") + "\n"; + QTest::newRow("utf8chars") << csv + << ',' + << static_cast(0) + << "UTF-8" + << 3 + << result; + + result.clear(); + result = {{QByteArray("\u4E18"), QByteArray("\u4E26"), QByteArray("\u4E4B")}}; + QString csv2 = QString::fromUtf8("\u4E18") + "," + QString::fromUtf8("\u4E26") + "," + QString::fromUtf8("\u4E4B") + "\n"; + QTest::newRow("utf16chars") << csv2 + << ',' + << static_cast(0) + << "UTF-16" + << 3 + << result; +} diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/tests/TestImport.h b/src/WBCLFZSystemModule/SqliteDBProcess/src/tests/TestImport.h new file mode 100644 index 0000000..18de561 --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/tests/TestImport.h @@ -0,0 +1,19 @@ +#ifndef TESTIMPORT_H +#define TESTIMPORT_H + +#include + +class TestImport : public QObject +{ + Q_OBJECT + +public: + TestImport(); + ~TestImport(); + +private slots: + void csvImport(); + void csvImport_data(); +}; + +#endif diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/tests/TestRegex.cpp b/src/WBCLFZSystemModule/SqliteDBProcess/src/tests/TestRegex.cpp new file mode 100644 index 0000000..c720f48 --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/tests/TestRegex.cpp @@ -0,0 +1,81 @@ +#include "TestRegex.h" +#include "../sqlitetablemodel.h" + +#include + +QTEST_APPLESS_MAIN(TestRegex) + +void TestRegex::sqlQueryComments_data() +{ + QTest::addColumn("dirtyQuery"); + QTest::addColumn("clearQuery"); + + QTest::newRow("test1") + << // dirtyQuery + "SELECT * -- asd ffdsf\n" + "-- saf ewf sf\n" + "-- dsaf fd\n" + "FROM \t-- sfsdf\n" + "qwfwqf -- asdasd" + << // clearQuery + "SELECT *\nFROM\nqwfwqf"; + + QTest::newRow("test2") + << // dirtyQuery + "SELECT *-- comment\n" + "FROM\n\n" + "-- something\n" + "qwfqwf" + << // cleanQuery + "SELECT *\nFROM\nqwfqwf"; + + QTest::newRow("test3") + << // dirtyQuery + "-- Comment before the query\n" + "SELECT * FROM test" + << // cleanQuery + "SELECT * FROM test"; + + QTest::newRow("test4") + << // dirtyQuery + "SELECT * FROM test\n" + "-- Comment after the query" + << // cleanQuery + "SELECT * FROM test"; + + QTest::newRow("test5") + << // dirtyQuery + "SELECT 40+2 -- get the answer\n" + "AS answer" + << // cleanQuery + "SELECT 40+2\n" + "AS answer"; + + QTest::newRow("test6") + << // dirtyQuery + "SELECT '-- comment inside quotes'" + << // cleanQuery + "SELECT '-- comment inside quotes'"; + + QTest::newRow("single_quote_comment") + << // dirtyQuery + "SELECT 'something--something' -- comment" + << // cleanQuery + "SELECT 'something--something'"; + + /* This still needs to be fixed in our code before activating the test + QTest::newRow("double_quote_comment") + << // dirtyQuery + "SELECT \"something--something\" -- comment" + << // cleanQuery + "SELECT \"something--something\"";*/ +} + +void TestRegex::sqlQueryComments() +{ + QFETCH(QString, dirtyQuery); + QFETCH(QString, clearQuery); + + SqliteTableModel::removeCommentsFromQuery(dirtyQuery); + QCOMPARE(dirtyQuery, clearQuery); +} diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/tests/TestRegex.h b/src/WBCLFZSystemModule/SqliteDBProcess/src/tests/TestRegex.h new file mode 100644 index 0000000..370a9be --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/tests/TestRegex.h @@ -0,0 +1,17 @@ +#ifndef TESTREGEX_H +#define TESTREGEX_H + +#define REGEX_UNIT_TEST + +#include + +class TestRegex : public QObject +{ + Q_OBJECT + +private slots: + void sqlQueryComments(); + void sqlQueryComments_data(); +}; + +#endif diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/tests/TestRowCache.cpp b/src/WBCLFZSystemModule/SqliteDBProcess/src/tests/TestRowCache.cpp new file mode 100644 index 0000000..610ba2c --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/tests/TestRowCache.cpp @@ -0,0 +1,189 @@ +#include + +#include "TestRowCache.h" +#include "../RowCache.h" + +QTEST_APPLESS_MAIN(TestRowCache) + +TestRowCache::TestRowCache() +{ +} + +TestRowCache::~TestRowCache() +{ +} + +using C = RowCache; + +void TestRowCache::construction() +{ + C c; + + QCOMPARE(c.numSet(), static_cast(0)); + + QVERIFY(c.count(0) == false); + QVERIFY(c.count(1) == false); + QVERIFY(c.count(2) == false); + + QVERIFY_EXCEPTION_THROWN(c.at(0), std::out_of_range); +} + +void TestRowCache::setGet() +{ + C c; + + c.set(1, 10); + c.set(5, 50); + c.set(0, 0); + c.set(6, 60); + c.set(100, 1000); + + QCOMPARE(c.numSet(), static_cast(5)); + QCOMPARE(c.numSegments(), static_cast(4)); // the '0' set after the '1' position does not merge currently + + int cnt = 0; + const C & cc = c; + for(size_t i = 0; i < 200; i++) { + if(c.count(i)) { + QCOMPARE(c.at(i), static_cast(10*i)); + QCOMPARE(cc.at(i), static_cast(10*i)); + cnt++; + } else { + QVERIFY_EXCEPTION_THROWN(c.at(i), std::out_of_range); + QVERIFY_EXCEPTION_THROWN(cc.at(i), std::out_of_range); + } + } + QCOMPARE(cnt, 5); +} + +void TestRowCache::insert() +{ + C c; + + c.insert(3, 30); + QCOMPARE(c.numSet(), static_cast(1)); + QCOMPARE(c.numSegments(), static_cast(1)); + QCOMPARE(c.at(3), 30); + + c.insert(3, 31); + QCOMPARE(c.numSet(), static_cast(2)); + QCOMPARE(c.numSegments(), static_cast(1)); + QCOMPARE(c.at(3), 31); + QCOMPARE(c.at(4), 30); + + c.insert(0, 0); + QCOMPARE(c.numSet(), static_cast(3)); + QCOMPARE(c.numSegments(), static_cast(2)); + QCOMPARE(c.at(0), 0); + QVERIFY_EXCEPTION_THROWN(c.at(3), std::out_of_range); + QCOMPARE(c.at(4), 31); + QCOMPARE(c.at(5), 30); + QVERIFY_EXCEPTION_THROWN(c.at(6), std::out_of_range); + + c.insert(1, 100); + QCOMPARE(c.numSet(), static_cast(4)); + QCOMPARE(c.numSegments(), static_cast(2)); + QCOMPARE(c.at(0), 0); + QCOMPARE(c.at(1), 100); + QCOMPARE(c.at(5), 31); + QCOMPARE(c.at(6), 30); + + c.insert(8, 1); + QCOMPARE(c.numSet(), static_cast(5)); + QCOMPARE(c.numSegments(), static_cast(3)); + QCOMPARE(c.at(0), 0); + QCOMPARE(c.at(1), 100); + QCOMPARE(c.at(5), 31); + QCOMPARE(c.at(6), 30); + QCOMPARE(c.at(8), 1); +} + +void TestRowCache::erase() +{ + C c; + c.insert(3, 30); + c.insert(3, 31); + c.insert(0, 0); + c.insert(8, 1); + QCOMPARE(c.numSet(), static_cast(4)); + QCOMPARE(c.numSegments(), static_cast(3)); + QCOMPARE(c.at(0), 0); + QCOMPARE(c.at(4), 31); + QCOMPARE(c.at(5), 30); + QCOMPARE(c.at(8), 1); + + // erase entire segment + c.erase(0); + QCOMPARE(c.numSet(), static_cast(3)); + QCOMPARE(c.numSegments(), static_cast(2)); + QCOMPARE(c.at(3), 31); + QCOMPARE(c.at(4), 30); + QCOMPARE(c.at(7), 1); + + // erase inside segment + c.erase(4); + QCOMPARE(c.numSet(), static_cast(2)); + QCOMPARE(c.numSegments(), static_cast(2)); + QCOMPARE(c.at(3), 31); + QCOMPARE(c.at(6), 1); + + // erase non-filled row + c.erase(5); + QCOMPARE(c.numSet(), static_cast(2)); + QCOMPARE(c.numSegments(), static_cast(2)); + QCOMPARE(c.at(3), 31); + QCOMPARE(c.at(5), 1); + + c.erase(5); + QCOMPARE(c.numSet(), static_cast(1)); + QCOMPARE(c.numSegments(), static_cast(1)); + QCOMPARE(c.at(3), 31); + + c.erase(3); + QCOMPARE(c.numSet(), static_cast(0)); + QCOMPARE(c.numSegments(), static_cast(0)); +} + +void TestRowCache::smallestNonAvailableRange() +{ + C c; + c.insert(3, 0); + c.insert(3, 0); + c.insert(0, 0); + c.insert(8, 0); + QCOMPARE(c.numSet(), static_cast(4)); + QVERIFY(c.count(0)); + QVERIFY(c.count(4)); + QVERIFY(c.count(5)); + QVERIFY(c.count(8)); + + using P = std::pair; + + auto test = [&](size_t begin, size_t end) { + P p{ begin, end }; + c.smallestNonAvailableRange(p.first, p.second); + return p; + }; + + QCOMPARE(test( 0, 0), P( 0, 0)); + QCOMPARE(test( 0, 1), P( 1, 1)); + QCOMPARE(test( 0, 2), P( 1, 2)); + QCOMPARE(test( 0, 3), P( 1, 3)); + QCOMPARE(test( 0, 4), P( 1, 4)); + QCOMPARE(test( 0, 5), P( 1, 4)); + QCOMPARE(test( 0, 6), P( 1, 4)); + QCOMPARE(test( 0, 7), P( 1, 7)); + QCOMPARE(test( 0, 8), P( 1, 8)); + QCOMPARE(test( 0, 9), P( 1, 8)); + QCOMPARE(test( 0,10), P( 1,10)); + QCOMPARE(test( 1,10), P( 1,10)); + QCOMPARE(test( 2,10), P( 2,10)); + QCOMPARE(test( 3,10), P( 3,10)); + QCOMPARE(test( 4,10), P( 6,10)); + QCOMPARE(test( 5,10), P( 6,10)); + QCOMPARE(test( 6,10), P( 6,10)); + QCOMPARE(test( 7,10), P( 7,10)); + QCOMPARE(test( 8,10), P( 9,10)); + QCOMPARE(test( 9,10), P( 9,10)); + QCOMPARE(test(10,10), P(10,10)); +} diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/tests/TestRowCache.h b/src/WBCLFZSystemModule/SqliteDBProcess/src/tests/TestRowCache.h new file mode 100644 index 0000000..beeeee9 --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/tests/TestRowCache.h @@ -0,0 +1,22 @@ +#ifndef TESTROWCACHE_H +#define TESTROWCACHE_H + +#include + +class TestRowCache : public QObject +{ + Q_OBJECT + +public: + TestRowCache(); + ~TestRowCache(); + +private slots: + void construction(); + void setGet(); + void insert(); + void erase(); + void smallestNonAvailableRange(); +}; + +#endif diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/tests/testsqlobjects.cpp b/src/WBCLFZSystemModule/SqliteDBProcess/src/tests/testsqlobjects.cpp new file mode 100644 index 0000000..bdc847b --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/tests/testsqlobjects.cpp @@ -0,0 +1,773 @@ +#include "testsqlobjects.h" +#include "../sql/ObjectIdentifier.h" +#include "../sql/sqlitetypes.h" + +#include + +QTEST_APPLESS_MAIN(TestTable) +Q_DECLARE_METATYPE(std::string) + +using namespace sqlb; + +#if QT_VERSION < QT_VERSION_CHECK(5, 10, 0) +namespace QTest +{ +template +inline bool qCompare(const T1 &t1, const T2 &t2, const char *actual, const char *expected, + const char *file, int line) +{ + return compare_helper(t1 == t2, "Compared values are not the same", + toString(t1), toString(t2), actual, expected, file, line); +} +} +#endif + +void TestTable::sqlOutput() +{ + Table tt("testtable"); + Field f("id", "integer"); + Field fkm("km", "integer", false, "", "km > 1000"); + tt.fields.push_back(f); + tt.fields.emplace_back("car", "text"); + tt.fields.push_back(fkm); + tt.addConstraint(ConstraintPtr(new PrimaryKeyConstraint({f.name(), fkm.name()}))); + + QCOMPARE(tt.sql(), "CREATE TABLE \"testtable\" (\n" + "\t\"id\"\tinteger,\n" + "\t\"car\"\ttext,\n" + "\t\"km\"\tinteger CHECK(km > 1000),\n" + "\tPRIMARY KEY(\"id\",\"km\")\n" + ");"); +} + +void TestTable::sqlGraveAccentOutput() +{ + Table tt("testtable"); + Field f("id", "integer"); + Field fkm("km", "integer", false, "", "km > 1000"); + tt.fields.push_back(f); + tt.fields.emplace_back("car", "text"); + tt.fields.push_back(fkm); + tt.addConstraint(ConstraintPtr(new PrimaryKeyConstraint({f.name(), fkm.name()}))); + sqlb::setIdentifierQuoting(sqlb::GraveAccents); + + QCOMPARE(tt.sql(), "CREATE TABLE `testtable` (\n" + "\t`id`\tinteger,\n" + "\t`car`\ttext,\n" + "\t`km`\tinteger CHECK(km > 1000),\n" + "\tPRIMARY KEY(`id`,`km`)\n" + ");"); + + sqlb::setIdentifierQuoting(sqlb::DoubleQuotes); +} + + +void TestTable::sqlSquareBracketsOutput() +{ + Table tt("testtable"); + Field f("id", "integer"); + Field fkm("km", "integer", false, "", "km > 1000"); + tt.fields.push_back(f); + tt.fields.emplace_back("car", "text"); + tt.fields.push_back(fkm); + tt.addConstraint(ConstraintPtr(new PrimaryKeyConstraint({f.name(), fkm.name()}))); + sqlb::setIdentifierQuoting(sqlb::SquareBrackets); + + QCOMPARE(tt.sql(), "CREATE TABLE [testtable] (\n" + "\t[id]\tinteger,\n" + "\t[car]\ttext,\n" + "\t[km]\tinteger CHECK(km > 1000),\n" + "\tPRIMARY KEY([id],[km])\n" + ");"); + + sqlb::setIdentifierQuoting(sqlb::DoubleQuotes); +} + +void TestTable::autoincrement() +{ + Table tt("testtable"); + Field f("id", "integer"); + Field fkm("km", "integer"); + tt.fields.push_back(f); + tt.fields.emplace_back("car", "text"); + tt.fields.push_back(fkm); + PrimaryKeyConstraint pk({f.name()}); + pk.setAutoIncrement(true); + tt.addConstraint(ConstraintPtr(new PrimaryKeyConstraint(pk))); + + QCOMPARE(tt.sql(), "CREATE TABLE \"testtable\" (\n" + "\t\"id\"\tinteger,\n" + "\t\"car\"\ttext,\n" + "\t\"km\"\tinteger,\n" + "\tPRIMARY KEY(\"id\" AUTOINCREMENT)\n" + ");"); +} + +void TestTable::notnull() +{ + Table tt("testtable"); + Field f("id", "integer"); + Field fkm("km", "integer"); + tt.fields.push_back(f); + tt.fields.emplace_back("car", "text", true); + tt.fields.push_back(fkm); + PrimaryKeyConstraint pk({f.name()}); + pk.setAutoIncrement(true); + tt.addConstraint(ConstraintPtr(new PrimaryKeyConstraint(pk))); + + QCOMPARE(tt.sql(), "CREATE TABLE \"testtable\" (\n" + "\t\"id\"\tinteger,\n" + "\t\"car\"\ttext NOT NULL,\n" + "\t\"km\"\tinteger,\n" + "\tPRIMARY KEY(\"id\" AUTOINCREMENT)\n" + ");"); +} + +void TestTable::withoutRowid() +{ + Table tt("testtable"); + Field f("a", "integer"); + tt.fields.push_back(f); + tt.fields.emplace_back("b", "integer"); + tt.setWithoutRowidTable(true); + tt.addConstraint(ConstraintPtr(new PrimaryKeyConstraint({f.name()}))); + + QCOMPARE(tt.sql(), "CREATE TABLE \"testtable\" (\n" + "\t\"a\"\tinteger,\n" + "\t\"b\"\tinteger,\n" + "\tPRIMARY KEY(\"a\")\n" + ") WITHOUT ROWID;"); +} + +void TestTable::foreignKeys() +{ + Table tt("testtable"); + Field f("a", "integer"); + tt.fields.push_back(f); + sqlb::ConstraintPtr fk = sqlb::ConstraintPtr(new sqlb::ForeignKeyClause("b", sqlb::StringVector{"c"})); + fk->setColumnList({f.name()}); + tt.addConstraint(fk); + + QCOMPARE(tt.sql(), "CREATE TABLE \"testtable\" (\n" + "\t\"a\"\tinteger,\n" + "\tFOREIGN KEY(\"a\") REFERENCES \"b\"(\"c\")\n" + ");"); +} + +void TestTable::uniqueConstraint() +{ + Table tt("testtable"); + Field f1("a", "integer"); + Field f2("b", "integer"); + Field f3("c", "integer"); + f1.setUnique(true); + tt.fields.push_back(f1); + tt.fields.push_back(f2); + tt.fields.push_back(f3); + tt.addConstraint(sqlb::ConstraintPtr(new sqlb::UniqueConstraint({f2.name(), f3.name()}))); + + QCOMPARE(tt.sql(), "CREATE TABLE \"testtable\" (\n" + "\t\"a\"\tinteger UNIQUE,\n" + "\t\"b\"\tinteger,\n" + "\t\"c\"\tinteger,\n" + "\tUNIQUE(\"b\",\"c\")\n" + ");"); +} + +void TestTable::parseSQL() +{ + std::string sSQL = "create TABLE hero (\n" + "\tid integer PRIMARY KEY AUTOINCREMENT,\n" + "\tname text NOT NULL DEFAULT 'xxxx',\n" + "\tinfo VARCHAR(255) CHECK (info == 'x')\n" + ");"; + + Table tab(*Table::parseSQL(sSQL)); + + QCOMPARE(tab.name(), "hero"); + QCOMPARE(tab.rowidColumns(), {"_rowid_"}); + QCOMPARE(tab.fields.at(0).name(), "id"); + QCOMPARE(tab.fields.at(1).name(), "name"); + QCOMPARE(tab.fields.at(2).name(), "info"); + + QCOMPARE(tab.fields.at(0).type(), "integer"); + QCOMPARE(tab.fields.at(1).type(), "text"); + QCOMPARE(tab.fields.at(2).type(), "VARCHAR(255)"); + + auto pk = tab.primaryKey(); + QVERIFY(pk->autoIncrement()); + QCOMPARE(pk->columnList().size(), 1); + QCOMPARE(pk->columnList().at(0), tab.fields.at(0).name()); + QVERIFY(tab.fields.at(1).notnull()); + QCOMPARE(tab.fields.at(1).defaultValue(), "'xxxx'"); + QCOMPARE(tab.fields.at(1).check(), ""); + QCOMPARE(tab.fields.at(2).check(), "\"info\" == 'x'"); +} + +void TestTable::parseSQLdefaultexpr() +{ + std::string sSQL = "CREATE TABLE chtest(\n" + "id integer primary key,\n" + "dumpytext text default('axa') CHECK(dumpytext == \"aa\"),\n" + "date datetime default CURRENT_TIMESTAMP," + "zoi integer)"; + + Table tab(*Table::parseSQL(sSQL)); + + QCOMPARE(tab.name(), "chtest"); + QCOMPARE(tab.fields.at(0).name(), "id"); + QCOMPARE(tab.fields.at(1).name(), "dumpytext"); + QCOMPARE(tab.fields.at(2).name(), "date"); + QCOMPARE(tab.fields.at(3).name(), "zoi"); + + QCOMPARE(tab.fields.at(0).type(), "integer"); + QCOMPARE(tab.fields.at(1).type(), "text"); + QCOMPARE(tab.fields.at(2).type(), "datetime"); + QCOMPARE(tab.fields.at(3).type(), "integer"); + + QCOMPARE(tab.fields.at(1).defaultValue(), "('axa')"); + QCOMPARE(tab.fields.at(1).check(), "\"dumpytext\" == \"aa\""); + QCOMPARE(tab.fields.at(2).defaultValue(), "CURRENT_TIMESTAMP"); + QCOMPARE(tab.fields.at(2).check(), ""); + QCOMPARE(tab.fields.at(3).defaultValue(), ""); + QCOMPARE(tab.fields.at(3).check(), ""); + + auto pk = tab.primaryKey(); + QCOMPARE(pk->columnList().size(), 1); + QCOMPARE(pk->columnList().at(0), tab.fields.at(0).name()); +} + +void TestTable::parseSQLMultiPk() +{ + std::string sSQL = "CREATE TABLE hero (\n" + "\tid1 integer,\n" + "\tid2 integer,\n" + "\tnonpkfield blob,\n" + "PRIMARY KEY(\"id1\",\"id2\")\n" + ");"; + + Table tab(*Table::parseSQL(sSQL)); + + QCOMPARE(tab.name(), "hero"); + QCOMPARE(tab.fields.at(0).name(), "id1"); + QCOMPARE(tab.fields.at(1).name(), "id2"); + + QCOMPARE(tab.fields.at(0).type(), "integer"); + QCOMPARE(tab.fields.at(1).type(), "integer"); + + auto pk = tab.primaryKey(); + QCOMPARE(pk->columnList().size(), 2); + QCOMPARE(pk->columnList().at(0), tab.fields.at(0).name()); + QCOMPARE(pk->columnList().at(1), tab.fields.at(1).name()); +} + +void TestTable::parseSQLForeignKey() +{ + std::string sSQL = "CREATE TABLE grammar_test(id, test, FOREIGN KEY(test) REFERENCES other_table);"; + + Table tab(*Table::parseSQL(sSQL)); + + QCOMPARE(tab.name(), "grammar_test"); + QCOMPARE(tab.fields.at(0).name(), "id"); + QCOMPARE(tab.fields.at(1).name(), "test"); +} + +void TestTable::parseSQLSingleQuotes() +{ + std::string sSQL = "CREATE TABLE 'test'('id','test');"; + + Table tab(*Table::parseSQL(sSQL)); + + QCOMPARE(tab.name(), "test"); + QCOMPARE(tab.fields.at(0).name(), "id"); + QCOMPARE(tab.fields.at(1).name(), "test"); +} + +void TestTable::parseSQLSquareBrackets() +{ + std::string sSQL = "CREATE TABLE [test]([id],[test]);"; + + Table tab(*Table::parseSQL(sSQL)); + + QCOMPARE(tab.name(), "test"); + QCOMPARE(tab.fields.at(0).name(), "id"); + QCOMPARE(tab.fields.at(1).name(), "test"); +} + + +void TestTable::parseSQLKeywordInIdentifier() +{ + std::string sSQL = "CREATE TABLE deffered(key integer primary key, if text);"; + + Table tab(*Table::parseSQL(sSQL)); + + QCOMPARE(tab.name(), "deffered"); + QCOMPARE(tab.fields.at(0).name(), "key"); + QCOMPARE(tab.fields.at(1).name(), "if"); +} + + +void TestTable::parseSQLSomeKeywordsInIdentifier() +{ + std::string sSQL = "CREATE TABLE \"Average Number of Volunteers by Area of Work\" (" + "`Area of Work` TEXT," + "`Average Number of Volunteers` INTEGER);"; + + Table tab(*Table::parseSQL(sSQL)); + + QCOMPARE(tab.name(), "Average Number of Volunteers by Area of Work"); + QCOMPARE(tab.fields.at(0).name(), "Area of Work"); + QCOMPARE(tab.fields.at(1).name(), "Average Number of Volunteers"); +} + +void TestTable::parseSQLWithoutRowid() +{ + std::string sSQL = "CREATE TABLE test(a integer primary key, b integer) WITHOUT ROWID;"; + + Table tab(*Table::parseSQL(sSQL)); + + QCOMPARE(tab.primaryKey()->columnList(), {"a"}); + QCOMPARE(tab.rowidColumns(), {"a"}); +} + +void TestTable::parseNonASCIIChars() +{ + std::string sSQL = "CREATE TABLE `lösung` (" + "`Fieldöäüß` INTEGER," + "PRIMARY KEY(`Fieldöäüß`)" + ");"; + + Table tab(*Table::parseSQL(sSQL)); + + QCOMPARE(tab.name(), "lösung"); + QCOMPARE(tab.fields.at(0).name(), "Fieldöäüß"); +} + +void TestTable::parseNonASCIICharsEs() +{ + std::string sSQL = "CREATE TABLE \"Cigüeñas de Alcalá\" (" + "\"Field áéíóúÃÉÃÓÚñÑçÇ\" INTEGER," + "PRIMARY KEY(\"Field áéíóúÃÉÃÓÚñÑçÇ\")" + ");"; + + Table tab(*Table::parseSQL(sSQL)); + + QCOMPARE(tab.name(), "Cigüeñas de Alcalá"); + QCOMPARE(tab.fields.at(0).name(), "Field áéíóúÃÉÃÓÚñÑçÇ"); +} + +void TestTable::parseSQLEscapedQuotes() +{ + std::string sSql = "CREATE TABLE double_quotes(a text default 'a''a');"; + + Table tab(*Table::parseSQL(sSql)); + + QCOMPARE(tab.name(), "double_quotes"); + QCOMPARE(tab.fields.at(0).name(), "a"); + QCOMPARE(tab.fields.at(0).defaultValue(), "'a''a'"); +} + +void TestTable::parseSQLForeignKeys() +{ + std::string sql = "CREATE TABLE foreign_key_test(a int, b int, foreign key (a) references x, foreign key (b) references w(y,z) on delete set null);"; + + Table tab(*Table::parseSQL(sql)); + + QCOMPARE(tab.name(), "foreign_key_test"); + QCOMPARE(tab.fields.at(0).name(), "a"); + QCOMPARE(tab.fields.at(0).type(), "int"); + QCOMPARE(std::dynamic_pointer_cast(tab.constraint({tab.fields.at(0).name()}, sqlb::Constraint::ForeignKeyConstraintType))->table(), "x"); + QCOMPARE(tab.fields.at(1).name(), "b"); + QCOMPARE(tab.fields.at(1).type(), "int"); + QCOMPARE(std::dynamic_pointer_cast(tab.constraint({tab.fields.at(1).name()}, sqlb::Constraint::ForeignKeyConstraintType))->toString(), "\"w\"(\"y\",\"z\") on delete set null"); +} + +void TestTable::parseSQLCheckConstraint() +{ + std::string sql = "CREATE TABLE a (\"b\" text CHECK(\"b\"='A' or \"b\"='B'));"; + + Table tab(*Table::parseSQL(sql)); + + QCOMPARE(tab.name(), "a"); + QCOMPARE(tab.fields.at(0).name(), "b"); + QCOMPARE(tab.fields.at(0).type(), "text"); + QCOMPARE(tab.fields.at(0).check(), "\"b\" = 'A' OR \"b\" = 'B'"); +} + +void TestTable::parseDefaultValues() +{ + std::string sql = "CREATE TABLE test(a int DEFAULT 0, b int DEFAULT -1, c text DEFAULT 'hello', d text DEFAULT '0');"; + + Table tab(*Table::parseSQL(sql)); + + QCOMPARE(tab.name(), "test"); + QCOMPARE(tab.fields.at(0).name(), "a"); + QCOMPARE(tab.fields.at(0).type(), "int"); + QCOMPARE(tab.fields.at(0).defaultValue(), "0"); + QCOMPARE(tab.fields.at(1).name(), "b"); + QCOMPARE(tab.fields.at(1).type(), "int"); + QCOMPARE(tab.fields.at(1).defaultValue(), "-1"); + QCOMPARE(tab.fields.at(2).name(), "c"); + QCOMPARE(tab.fields.at(2).type(), "text"); + QCOMPARE(tab.fields.at(2).defaultValue(), "'hello'"); + QCOMPARE(tab.fields.at(3).name(), "d"); + QCOMPARE(tab.fields.at(3).type(), "text"); + QCOMPARE(tab.fields.at(3).defaultValue(), "'0'"); +} + +void TestTable::createTableWithIn() +{ + std::string sSQL = "CREATE TABLE not_working(" + "_id PRIMARY KEY NOT NULL," + "value NVARCHAR(5) CHECK (value IN ('a', 'b', 'c'))" + ");"; + + Table tab(*Table::parseSQL(sSQL)); + QCOMPARE(tab.name(), "not_working"); + + QCOMPARE(tab.fields.at(1).check(), "\"value\" IN ('a', 'b', 'c')"); +} + +void TestTable::createTableWithNotLikeConstraint() +{ + std::string sSQL = "CREATE TABLE hopefully_working(\n" + "value TEXT CHECK(value NOT LIKE 'prefix%'),\n" + "value2 TEXT CHECK(value2 NOT MATCH 'prefix%'),\n" + "value3 TEXT CHECK(value3 NOT REGEXP 'prefix%'),\n" + "value4 TEXT CHECK(value4 NOT GLOB 'prefix%'),\n" + "value5 INTEGER CHECK(value5 BETWEEN 1+4 AND 100 OR 200),\n" + "value6 INTEGER CHECK(value6 NOT BETWEEN 1 AND 100)\n" + ");"; + + Table tab(*Table::parseSQL(sSQL)); + QCOMPARE(tab.name(), "hopefully_working"); + + QCOMPARE(tab.fields.at(0).check(), "\"value\" NOT LIKE 'prefix%'"); + QCOMPARE(tab.fields.at(1).check(), "\"value2\" NOT MATCH 'prefix%'"); + QCOMPARE(tab.fields.at(2).check(), "\"value3\" NOT REGEXP 'prefix%'"); + QCOMPARE(tab.fields.at(3).check(), "\"value4\" NOT GLOB 'prefix%'"); + QCOMPARE(tab.fields.at(4).check(), "\"value5\" BETWEEN 1 + 4 AND 100 OR 200"); + QCOMPARE(tab.fields.at(5).check(), "\"value6\" NOT BETWEEN 1 AND 100"); +} + +void TestTable::rowValues() +{ + std::string sql = "CREATE TABLE test(\n" + "a INTEGER,\n" + "b INTEGER,\n" + "CHECK((a, b) = (1, 2))\n" + ");"; + + Table tab(*Table::parseSQL(sql)); + QCOMPARE(tab.name(), "test"); + + QCOMPARE(std::dynamic_pointer_cast(tab.constraint({}, sqlb::Constraint::CheckConstraintType))->expression(), "(\"a\", \"b\") = (1, 2)"); +} + +void TestTable::complexExpressions() +{ + std::string sql = "CREATE TABLE test(\n" + "a INTEGER CHECK((a > 0)),\n" + "b INTEGER CHECK((b > 0 and b > 1)),\n" + "c INTEGER CHECK((c = -1) or (c > 0 and c > 1) or (c = 0)),\n" + "d INTEGER CHECK((((d > 0))))\n" + ");"; + + Table tab(*Table::parseSQL(sql)); + QCOMPARE(tab.name(), "test"); + + QCOMPARE(tab.fields.at(0).check(), "(\"a\" > 0)"); + QCOMPARE(tab.fields.at(1).check(), "(\"b\" > 0 AND \"b\" > 1)"); + QCOMPARE(tab.fields.at(2).check(), "(\"c\" = -1) OR (\"c\" > 0 AND \"c\" > 1) OR (\"c\" = 0)"); + QCOMPARE(tab.fields.at(3).check(), "(((\"d\" > 0)))"); +} + +void TestTable::datetimeExpression() +{ + std::string sql = "CREATE TABLE test(\n" + "entry INTEGER DEFAULT (DATETIME(CURRENT_TIMESTAMP, 'LOCALTIME'))\n" + ");"; + + Table tab(*Table::parseSQL(sql)); + QCOMPARE(tab.name(), "test"); + + QCOMPARE(tab.fields.at(0).name(), "entry"); + QCOMPARE(tab.fields.at(0).type(), "INTEGER"); + QCOMPARE(tab.fields.at(0).defaultValue(), "(DATETIME(CURRENT_TIMESTAMP, 'LOCALTIME'))"); +} + +void TestTable::extraParentheses() +{ + std::string sql = "CREATE TABLE test(\n" + "xy INTEGER DEFAULT (1 + (5) - 4)\n" + ");"; + + Table tab(*Table::parseSQL(sql)); + QCOMPARE(tab.name(), "test"); + + QCOMPARE(tab.fields.at(0).name(), "xy"); + QCOMPARE(tab.fields.at(0).type(), "INTEGER"); + QCOMPARE(tab.fields.at(0).defaultValue(), "(1 + (5) - 4)"); +} + +void TestTable::moduloOperator() +{ + std::string sql = "CREATE TABLE test(\n" + "xy INTEGER DEFAULT (7 % 2)\n" + ");"; + + Table tab(*Table::parseSQL(sql)); + QCOMPARE(tab.name(), "test"); + + QCOMPARE(tab.fields.at(0).name(), "xy"); + QCOMPARE(tab.fields.at(0).type(), "INTEGER"); + QCOMPARE(tab.fields.at(0).defaultValue(), "(7 % 2)"); +} + +void TestTable::complexExpression() +{ + std::string sql = "CREATE TABLE test(\n" + "uuid INTEGER DEFAULT (hex(randomblob(4))||'-'||hex(randomblob(2))||'-'||'4'||substr(hex(randomblob(2)),2)||'-'||substr('AB89',1+(abs(random())%4),1)||substr(hex(randomblob(2)),2)||'-'||hex(randomblob(6))),\n" + "a INTEGER,\n" + "b INTEGER,\n" + "CHECK((a = 'S' AND b IS NOT NULL) OR (a IN ('A', 'P')))" + ");"; + + Table tab(*Table::parseSQL(sql)); + QCOMPARE(tab.name(), "test"); + + QCOMPARE(tab.fields.at(0).name(), "uuid"); + QCOMPARE(tab.fields.at(0).type(), "INTEGER"); + QCOMPARE(tab.fields.at(0).defaultValue(), "(hex(randomblob(4)) || '-' || hex(randomblob(2)) || '-' || '4' || substr(hex(randomblob(2)), 2) || '-' || substr('AB89', 1 + (abs(random()) % 4), 1) || substr(hex(randomblob(2)), 2) || '-' || hex(randomblob(6)))"); + + auto c = tab.constraints({}, sqlb::Constraint::CheckConstraintType); + QCOMPARE(c.size(), 1); + QCOMPARE(std::dynamic_pointer_cast(c.at(0))->expression(), "(\"a\" = 'S' AND \"b\" IS NOT NULL) OR (\"a\" IN ('A', 'P'))"); +} + +void TestTable::parseTest() +{ + QFETCH(std::string, sql); + + Table tab(*Table::parseSQL(sql)); + QVERIFY(tab.fullyParsed()); +} + +void TestTable::parseTest_data() +{ + // These are some rather unspecific queries but we include them here to test some basic parser features. They are + // extracted from this file: https://www.sqlite.org/cgi/src/artifact/1c602347e73ab80b + + QTest::addColumn("sql"); + + QTest::newRow("1") << std::string("CREATE TABLE t1(c1 one)"); + QTest::newRow("2") << std::string("CREATE TABLE t1(c1 one two)"); + QTest::newRow("3") << std::string("CREATE TABLE t1(c1 one two three)"); + QTest::newRow("4") << std::string("CREATE TABLE t1(c1 one two three four)"); + QTest::newRow("5") << std::string("CREATE TABLE t1(c1 one two three four(14))"); + QTest::newRow("6") << std::string("CREATE TABLE t1(c1 one two three four(14, 22))"); + QTest::newRow("7") << std::string("CREATE TABLE t1(c1 var(+14, -22.3))"); + QTest::newRow("8") << std::string("CREATE TABLE t1(c1 var(1.0e10))"); + QTest::newRow("9") << std::string("CREATE TABLE t1(c1 text PRIMARY KEY)"); + QTest::newRow("10") << std::string("CREATE TABLE t1(c1 text PRIMARY KEY ASC)"); + QTest::newRow("11") << std::string("CREATE TABLE t1(c1 text PRIMARY KEY DESC)"); + QTest::newRow("12") << std::string("CREATE TABLE t1(c1 text CONSTRAINT cons PRIMARY KEY DESC)"); + QTest::newRow("13") << std::string("CREATE TABLE t1(c1 text NOT NULL)"); + // TODO Requires named column constraint: QTest::newRow("14") << std::string("CREATE TABLE t1(c1 text CONSTRAINT nm NOT NULL)"); + QTest::newRow("15") << std::string("CREATE TABLE t1(c1 text NULL)"); + QTest::newRow("16") << std::string("CREATE TABLE t1(c1 text CONSTRAINT nm NULL)"); + QTest::newRow("17") << std::string("CREATE TABLE t1(c1 text UNIQUE)"); + // TODO Requires named column constraint: QTest::newRow("18") << std::string("CREATE TABLE t1(c1 text CONSTRAINT un UNIQUE)"); + QTest::newRow("19") << std::string("CREATE TABLE t1(c1 text CHECK(c1!=0))"); + // TODO Requires named column constraint: QTest::newRow("20") << std::string("CREATE TABLE t1(c1 text CONSTRAINT chk CHECK(c1!=0))"); + QTest::newRow("21") << std::string("CREATE TABLE t1(c1 text DEFAULT 1)"); + QTest::newRow("22") << std::string("CREATE TABLE t1(c1 text DEFAULT -1)"); + QTest::newRow("23") << std::string("CREATE TABLE t1(c1 text DEFAULT +1)"); + QTest::newRow("24") << std::string("CREATE TABLE t1(c1 text DEFAULT -45.8e22)"); + QTest::newRow("25") << std::string("CREATE TABLE t1(c1 text DEFAULT (1+1))"); + // TODO Requires named column constraint: QTest::newRow("26") << std::string("CREATE TABLE t1(c1 text CONSTRAINT \"1 2\" DEFAULT (1+1))"); + QTest::newRow("27") << std::string("CREATE TABLE t1(c1 text COLLATE nocase)"); + // TODO Requires named column constraint: QTest::newRow("28") << std::string("CREATE TABLE t1(c1 text CONSTRAINT 'a x' COLLATE nocase)"); + QTest::newRow("29") << std::string("CREATE TABLE t1(c1 REFERENCES t2)"); + QTest::newRow("30") << std::string("CREATE TABLE t1(c1 CONSTRAINT abc REFERENCES t2)"); + QTest::newRow("31") << std::string("CREATE TABLE t1(c1 PRIMARY KEY NOT NULL UNIQUE CHECK(c1 IS 'ten') DEFAULT 123 REFERENCES t1);"); + QTest::newRow("32") << std::string("CREATE TABLE t1(c1 REFERENCES t1 DEFAULT 123 CHECK(c1 IS 'ten') UNIQUE NOT NULL PRIMARY KEY);"); + QTest::newRow("33") << std::string("CREATE TABLE t1(c1, c2, PRIMARY KEY(c1))"); + QTest::newRow("34") << std::string("CREATE TABLE t1(c1, c2, PRIMARY KEY(c1, c2))"); + QTest::newRow("35") << std::string("CREATE TABLE t1(c1, c2, PRIMARY KEY(c1, c2) ON CONFLICT IGNORE)"); + QTest::newRow("36") << std::string("CREATE TABLE t1(c1, c2, UNIQUE(c1))"); + QTest::newRow("37") << std::string("CREATE TABLE t1(c1, c2, UNIQUE(c1, c2))"); + QTest::newRow("38") << std::string("CREATE TABLE t1(c1, c2, UNIQUE(c1, c2) ON CONFLICT IGNORE)"); + QTest::newRow("39") << std::string("CREATE TABLE t1(c1, c2, CHECK(c1 IS NOT c2))"); + QTest::newRow("40") << std::string("CREATE TABLE t1(c1, c2, FOREIGN KEY(c1) REFERENCES t2)"); + QTest::newRow("41") << std::string("CREATE TABLE t1(col1, col2 TEXT, col3 INTEGER UNIQUE, col4 VARCHAR(10, 10) PRIMARY KEY, \"name with spaces\" REFERENCES t1);"); + QTest::newRow("42") << std::string("CREATE TABLE t1(a, b, c)"); + QTest::newRow("43") << std::string("CREATE TEMP TABLE t1(a, b, c)"); + QTest::newRow("44") << std::string("CREATE TEMPORARY TABLE t1(a, b, c)"); + QTest::newRow("45") << std::string("CREATE TABLE IF NOT EXISTS t1(a, b, c)"); + QTest::newRow("46") << std::string("CREATE TEMP TABLE IF NOT EXISTS t1(a, b, c)"); + QTest::newRow("47") << std::string("CREATE TEMPORARY TABLE IF NOT EXISTS t1(a, b, c)"); + QTest::newRow("48") << std::string("CREATE TABLE main.t1(a, b, c)"); + QTest::newRow("49") << std::string("CREATE TEMP TABLE temp.t1(a, b, c)"); + QTest::newRow("50") << std::string("CREATE TEMPORARY TABLE temp.t1(a, b, c)"); + QTest::newRow("51") << std::string("CREATE TABLE IF NOT EXISTS main.t1(a, b, c)"); + QTest::newRow("52") << std::string("CREATE TEMP TABLE IF NOT EXISTS temp.t1(a, b, c)"); + QTest::newRow("53") << std::string("CREATE TEMPORARY TABLE IF NOT EXISTS temp.t1(a, b, c)"); + //QTest::newRow("54") << std::string("CREATE TABLE t1 AS SELECT * FROM t2"); + //QTest::newRow("55") << std::string("CREATE TEMP TABLE t1 AS SELECT c, b, a FROM t2"); + //QTest::newRow("56") << std::string("CREATE TABLE t1 AS SELECT count(*), max(b), min(a) FROM t2"); + QTest::newRow("57") << std::string("CREATE TABLE t1(a REFERENCES t2(x) MATCH FULL ON DELETE SET NULL ON UPDATE RESTRICT DEFERRABLE)"); + QTest::newRow("58") << std::string("CREATE TABLE t1(a REFERENCES t2(x) ON DELETE RESTRICT ON UPDATE SET NULL MATCH FULL NOT DEFERRABLE INITIALLY IMMEDIATE)"); + QTest::newRow("59") << std::string("CREATE TABLE t1(a REFERENCES t2(x) MATCH PARTIAL ON DELETE SET NULL ON UPDATE CASCADE DEFERRABLE INITIALLY IMMEDIATE)"); + QTest::newRow("60") << std::string("CREATE TABLE t1(a REFERENCES t2(x) MATCH PARTIAL ON DELETE RESTRICT ON UPDATE SET DEFAULT )"); + QTest::newRow("61") << std::string("CREATE TABLE t1(a REFERENCES t2(x) MATCH PARTIAL ON DELETE RESTRICT ON UPDATE RESTRICT DEFERRABLE)"); + QTest::newRow("62") << std::string("CREATE TABLE t1(a REFERENCES t2(x) MATCH PARTIAL ON DELETE NO ACTION ON UPDATE SET DEFAULT NOT DEFERRABLE INITIALLY IMMEDIATE)"); + QTest::newRow("63") << std::string("CREATE TABLE t1(a REFERENCES t2(x) MATCH SIMPLE ON DELETE SET NULL ON UPDATE CASCADE NOT DEFERRABLE)"); + QTest::newRow("64") << std::string("CREATE TABLE t1(a REFERENCES t2(x) MATCH SIMPLE ON DELETE SET DEFAULT ON UPDATE SET NULL DEFERRABLE)"); + QTest::newRow("65") << std::string("CREATE TABLE t1(a REFERENCES t2(x) MATCH SIMPLE ON DELETE SET DEFAULT NOT DEFERRABLE)"); + QTest::newRow("66") << std::string("CREATE TABLE t1(a REFERENCES t2(x) MATCH SIMPLE ON DELETE RESTRICT ON UPDATE SET DEFAULT NOT DEFERRABLE INITIALLY DEFERRED)"); + QTest::newRow("67") << std::string("CREATE TABLE t1(a REFERENCES t2(x) MATCH SIMPLE ON DELETE RESTRICT ON UPDATE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE)"); + QTest::newRow("68") << std::string("CREATE TABLE t1(a REFERENCES t2(x) MATCH SIMPLE ON DELETE NO ACTION ON UPDATE SET DEFAULT NOT DEFERRABLE)"); + QTest::newRow("69") << std::string("CREATE TABLE t1(a REFERENCES t2(x) MATCH STICK ON DELETE CASCADE ON UPDATE CASCADE DEFERRABLE)"); + QTest::newRow("70") << std::string("CREATE TABLE t1(a REFERENCES t2(x) MATCH STICK ON UPDATE SET NULL NOT DEFERRABLE INITIALLY DEFERRED)"); + QTest::newRow("71") << std::string("CREATE TABLE t1(a REFERENCES t2(x) ON DELETE SET NULL ON UPDATE NO ACTION DEFERRABLE INITIALLY IMMEDIATE)"); + QTest::newRow("72") << std::string("CREATE TABLE t1(a REFERENCES t2(x) ON DELETE RESTRICT ON UPDATE NO ACTION NOT DEFERRABLE)"); + QTest::newRow("73") << std::string("CREATE TABLE t1(a REFERENCES t2(x) NOT DEFERRABLE INITIALLY DEFERRED)"); + QTest::newRow("74") << std::string("CREATE TABLE t1(a REFERENCES t2 MATCH FULL ON DELETE SET NULL ON UPDATE SET NULL DEFERRABLE INITIALLY IMMEDIATE)"); + QTest::newRow("75") << std::string("CREATE TABLE t1(a REFERENCES t2 MATCH FULL ON DELETE SET NULL ON UPDATE SET DEFAULT NOT DEFERRABLE)"); + QTest::newRow("76") << std::string("CREATE TABLE t1(a REFERENCES t2 MATCH FULL ON DELETE SET DEFAULT ON UPDATE SET NULL )"); + QTest::newRow("77") << std::string("CREATE TABLE t1(a REFERENCES t2 MATCH FULL ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE)"); + QTest::newRow("78") << std::string("CREATE TABLE t1(a REFERENCES t2 MATCH PARTIAL ON DELETE SET NULL ON UPDATE RESTRICT NOT DEFERRABLE)"); + QTest::newRow("79") << std::string("CREATE TABLE t1(a REFERENCES t2 MATCH PARTIAL ON DELETE SET NULL ON UPDATE NO ACTION DEFERRABLE)"); + QTest::newRow("80") << std::string("CREATE TABLE t1(a REFERENCES t2 MATCH PARTIAL ON DELETE CASCADE ON UPDATE SET DEFAULT )"); + QTest::newRow("81") << std::string("CREATE TABLE t1(a REFERENCES t2 MATCH PARTIAL NOT DEFERRABLE)"); + QTest::newRow("82") << std::string("CREATE TABLE t1(a REFERENCES t2 MATCH SIMPLE ON DELETE SET DEFAULT ON UPDATE CASCADE DEFERRABLE)"); + QTest::newRow("83") << std::string("CREATE TABLE t1(a REFERENCES t2 MATCH STICK ON DELETE SET NULL ON UPDATE NO ACTION DEFERRABLE INITIALLY IMMEDIATE)"); + QTest::newRow("84") << std::string("CREATE TABLE t1(a REFERENCES t2 MATCH STICK ON DELETE NO ACTION ON UPDATE SET DEFAULT NOT DEFERRABLE INITIALLY IMMEDIATE)"); + QTest::newRow("85") << std::string("CREATE TABLE t1(a REFERENCES t2 MATCH STICK ON UPDATE SET DEFAULT DEFERRABLE INITIALLY IMMEDIATE)"); + QTest::newRow("86") << std::string("CREATE TABLE t1(a REFERENCES t2 ON DELETE RESTRICT ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED)"); + QTest::newRow("87") << std::string("CREATE TABLE sqlit_abc(a, b, c)"); + QTest::newRow("88") << std::string("CREATE TABLE temp.sqlitehelloworld(x)"); + QTest::newRow("89") << std::string("CREATE TABLE auxa.\"sqlite\"(x, y)"); + QTest::newRow("90") << std::string("CREATE TABLE auxb.\"sqlite-\"(z)"); + QTest::newRow("91") << std::string("CREATE TABLE \"SQLITE-TBL\"(z)"); + QTest::newRow("92") << std::string("CREATE TABLE main.abc(a, b, c)"); + QTest::newRow("93") << std::string("CREATE TABLE temp.helloworld(x)"); + QTest::newRow("94") << std::string("CREATE TABLE auxa.\"t 1\"(x, y)"); + QTest::newRow("95") << std::string("CREATE TABLE auxb.xyz(z)"); + QTest::newRow("96") << std::string("CREATE TABLE main.abc(a, b, c)"); + QTest::newRow("97") << std::string("CREATE TABLE main.t1(a, b, c)"); + QTest::newRow("98") << std::string("CREATE TABLE temp.tmp(a, b, c)"); + QTest::newRow("99") << std::string("CREATE TABLE auxb.tbl(x, y)"); + QTest::newRow("100") << std::string("CREATE TABLE auxb.t1(k, v)"); + QTest::newRow("101") << std::string("CREATE TABLE auxa.next(c, d)"); + QTest::newRow("102") << std::string("CREATE TEMP TABLE t1(a, b)"); + QTest::newRow("103") << std::string("CREATE TEMPORARY TABLE t2(a, b)"); + QTest::newRow("104") << std::string("CREATE TEMP TABLE temp.t1(a, b)"); + QTest::newRow("105") << std::string("CREATE TEMPORARY TABLE temp.t2(a, b)"); + QTest::newRow("106") << std::string("CREATE TEMP TABLE TEMP.t3(a, b)"); + QTest::newRow("107") << std::string("CREATE TEMPORARY TABLE TEMP.xxx(x)"); + QTest::newRow("108") << std::string("CREATE TABLE t1(a, b)"); + QTest::newRow("109") << std::string("CREATE TABLE t2(a, b)"); + QTest::newRow("110") << std::string("CREATE TABLE t3(a, b)"); + QTest::newRow("111") << std::string("CREATE TABLE xxx(x)"); + QTest::newRow("112") << std::string("CREATE TABLE auxa.t1(a, b)"); + QTest::newRow("113") << std::string("CREATE TABLE auxa.i1(a, b)"); + QTest::newRow("114") << std::string("CREATE TABLE auxa.v1(a, b)"); + QTest::newRow("115") << std::string("CREATE TABLE tbl1(a, b)"); + QTest::newRow("116") << std::string("CREATE TABLE idx1(a, b)"); + QTest::newRow("117") << std::string("CREATE TABLE view1(a, b)"); + QTest::newRow("118") << std::string("CREATE TABLE IF NOT EXISTS t1(a, b)"); + QTest::newRow("119") << std::string("CREATE TABLE IF NOT EXISTS auxa.tbl1(a, b)"); + QTest::newRow("120") << std::string("CREATE TABLE IF NOT EXISTS v1(a, b)"); + QTest::newRow("121") << std::string("CREATE TABLE IF NOT EXISTS auxa.view1(a, b)"); + QTest::newRow("122") << std::string("CREATE TABLE t1(a, b, c);"); + QTest::newRow("123") << std::string("CREATE TABLE t2(d, e, f);"); + QTest::newRow("124") << std::string("CREATE TABLE t3(g BIGINT, h VARCHAR(10));"); + QTest::newRow("125") << std::string("CREATE TABLE t4(i BLOB, j ANYOLDATA);"); + QTest::newRow("126") << std::string("CREATE TABLE t5(k FLOAT, l INTEGER);"); + QTest::newRow("127") << std::string("CREATE TABLE t6(m DEFAULT 10, n DEFAULT 5, PRIMARY KEY(m, n));"); + QTest::newRow("128") << std::string("CREATE TABLE t7(x INTEGER PRIMARY KEY);"); + QTest::newRow("129") << std::string("CREATE TABLE t8(o COLLATE nocase DEFAULT 'abc');"); + QTest::newRow("130") << std::string("CREATE TABLE t9(p NOT NULL, q DOUBLE CHECK (q!=0), r STRING UNIQUE);"); + QTest::newRow("131") << std::string("CREATE TABLE t1(x VARCHAR(10), y INTEGER, z DOUBLE);"); + QTest::newRow("132") << std::string("CREATE TABLE t2(a DATETIME, b STRING, c REAL);"); + QTest::newRow("133") << std::string("CREATE TABLE t3(o, t);"); + QTest::newRow("134") << std::string("CREATE TABLE t4(a DEFAULT NULL,b DEFAULT 'string constant',c DEFAULT X'424C4F42',d DEFAULT 1,e DEFAULT -1,f DEFAULT 3.14,g DEFAULT -3.14,h DEFAULT ( substr('abcd', 0, 2) || 'cd' ),i DEFAULT CURRENT_TIME,j DEFAULT CURRENT_DATE,k DEFAULT CURRENT_TIMESTAMP);"); + QTest::newRow("135") << std::string("CREATE TABLE t5(x DEFAULT ( 'abc' ))"); + QTest::newRow("136") << std::string("CREATE TABLE t5(x DEFAULT ( 1 IN (1, 2, 3) ))"); + QTest::newRow("137") << std::string("CREATE TABLE t5(a DEFAULT NULL, b DEFAULT 'text value', c DEFAULT X'424C4F42',d DEFAULT -45678.6,e DEFAULT 394507);"); + QTest::newRow("138") << std::string("CREATE TABLE t6(a DEFAULT ( nextint() ), b DEFAULT ( nextint() ));"); + QTest::newRow("139") << std::string("CREATE TABLE t7(a DEFAULT CURRENT_TIME, b DEFAULT CURRENT_DATE, c DEFAULT CURRENT_TIMESTAMP);"); + QTest::newRow("140") << std::string("CREATE TABLE t8(a COLLATE nocase, b COLLATE rtrim, c COLLATE binary, d);"); + QTest::newRow("141") << std::string("CREATE TABLE t1(a, b, c)"); + QTest::newRow("142") << std::string("CREATE TABLE t2(a PRIMARY KEY, b, c)"); + QTest::newRow("143") << std::string("CREATE TABLE t3(a, b, c, PRIMARY KEY(a))"); + QTest::newRow("144") << std::string("CREATE TABLE t4(a, b, c, PRIMARY KEY(c,b,a))"); + QTest::newRow("145") << std::string("CREATE TABLE t5(a, b INTEGER PRIMARY KEY, c)"); + QTest::newRow("146") << std::string("CREATE TABLE t5(a PRIMARY KEY, b, c)"); + QTest::newRow("147") << std::string("CREATE TABLE t5(a, b, c, PRIMARY KEY(a))"); + QTest::newRow("148") << std::string("CREATE TABLE t5(a, b, c, PRIMARY KEY(c,b,a))"); + QTest::newRow("149") << std::string("CREATE TABLE t5(a, b INTEGER PRIMARY KEY, c)"); + QTest::newRow("150") << std::string("CREATE TABLE t1(a UNIQUE, b UNIQUE)"); + QTest::newRow("151") << std::string("CREATE TABLE t2(a UNIQUE, b, c, UNIQUE(c, b))"); + QTest::newRow("152") << std::string("CREATE TABLE t3(a, b, c, UNIQUE(a), UNIQUE(b), UNIQUE(c))"); + QTest::newRow("153") << std::string("CREATE TABLE t4(a, b, c, UNIQUE(a, b, c))"); + QTest::newRow("154") << std::string("CREATE TABLE t1(a TEXT PRIMARY KEY, b)"); + QTest::newRow("155") << std::string("CREATE TABLE t1(a INTEGER PRIMARY KEY, b)"); + QTest::newRow("156") << std::string("CREATE TABLE t1(a TEXT UNIQUE, b)"); + QTest::newRow("157") << std::string("CREATE TABLE t1(a PRIMARY KEY, b TEXT UNIQUE)"); + QTest::newRow("158") << std::string("CREATE TABLE t1(a PRIMARY KEY, b, c, UNIQUE(c, b))"); + QTest::newRow("159") << std::string("CREATE TABLE t1(a, b PRIMARY KEY);"); + QTest::newRow("160") << std::string("CREATE TABLE t2(a, b, c, UNIQUE(b, c));"); + QTest::newRow("161") << std::string("CREATE TABLE x1(a TEXT, b INTEGER CHECK( b>0 ));"); + QTest::newRow("162") << std::string("CREATE TABLE t1(a TEXT, b INTEGER, CHECK( b>0 ));"); + QTest::newRow("163") << std::string("CREATE TABLE x2(a CHECK( a||b ), b);"); + QTest::newRow("164") << std::string("CREATE TABLE t2(a, b, CHECK( a||b ));"); + QTest::newRow("165") << std::string("CREATE TABLE t1(a NOT NULL, b)"); + QTest::newRow("166") << std::string("CREATE TABLE t2(a PRIMARY KEY NOT NULL, b)"); + QTest::newRow("167") << std::string("CREATE TABLE t3(a NOT NULL, b NOT NULL, c NOT NULL UNIQUE)"); + // TODO Requires NOT NULL table constraints: QTest::newRow("168") << std::string("CREATE TABLE t4(a, b, NOT NULL(a))"); + // TODO Requires NOT NULL table constraints: QTest::newRow("169") << std::string("CREATE TABLE t4(a PRIMARY KEY, b, NOT NULL(a))"); + // TODO Requires NOT NULL table constraints: QTest::newRow("170") << std::string("CREATE TABLE t4(a, b, c UNIQUE, NOT NULL(a, b, c))"); + QTest::newRow("171") << std::string("CREATE TABLE t1_ab(a PRIMARY KEY ON CONFLICT ABORT, b);"); + QTest::newRow("172") << std::string("CREATE TABLE t1_ro(a PRIMARY KEY ON CONFLICT ROLLBACK, b);"); + QTest::newRow("173") << std::string("CREATE TABLE t1_ig(a PRIMARY KEY ON CONFLICT IGNORE, b);"); + QTest::newRow("174") << std::string("CREATE TABLE t1_fa(a PRIMARY KEY ON CONFLICT FAIL, b);"); + QTest::newRow("175") << std::string("CREATE TABLE t1_re(a PRIMARY KEY ON CONFLICT REPLACE, b);"); + QTest::newRow("176") << std::string("CREATE TABLE t1_xx(a PRIMARY KEY, b);"); + // TODO Requires NOT NULL conflict actions: QTest::newRow("177") << std::string("CREATE TABLE t2_ab(a, b NOT NULL ON CONFLICT ABORT);"); + // TODO Requires NOT NULL conflict actions: QTest::newRow("178") << std::string("CREATE TABLE t2_ro(a, b NOT NULL ON CONFLICT ROLLBACK);"); + // TODO Requires NOT NULL conflict actions: QTest::newRow("179") << std::string("CREATE TABLE t2_ig(a, b NOT NULL ON CONFLICT IGNORE);"); + // TODO Requires NOT NULL conflict actions: QTest::newRow("180") << std::string("CREATE TABLE t2_fa(a, b NOT NULL ON CONFLICT FAIL);"); + // TODO Requires NOT NULL conflict actions: QTest::newRow("181") << std::string("CREATE TABLE t2_re(a, b NOT NULL ON CONFLICT REPLACE);"); + QTest::newRow("182") << std::string("CREATE TABLE t2_xx(a, b NOT NULL);"); + QTest::newRow("183") << std::string("CREATE TABLE t3_ab(a, b, UNIQUE(a, b) ON CONFLICT ABORT);"); + QTest::newRow("184") << std::string("CREATE TABLE t3_ro(a, b, UNIQUE(a, b) ON CONFLICT ROLLBACK);"); + QTest::newRow("185") << std::string("CREATE TABLE t3_ig(a, b, UNIQUE(a, b) ON CONFLICT IGNORE);"); + QTest::newRow("186") << std::string("CREATE TABLE t3_fa(a, b, UNIQUE(a, b) ON CONFLICT FAIL);"); + QTest::newRow("187") << std::string("CREATE TABLE t3_re(a, b, UNIQUE(a, b) ON CONFLICT REPLACE);"); + QTest::newRow("188") << std::string("CREATE TABLE t3_xx(a, b, UNIQUE(a, b));"); + QTest::newRow("189") << std::string("CREATE TABLE t4(a, b CHECK (b!=10));"); + QTest::newRow("190") << std::string("CREATE TABLE t2(oid, b);"); + QTest::newRow("191") << std::string("CREATE TABLE t3(a, _rowid_);"); + QTest::newRow("192") << std::string("CREATE TABLE t4(a, b, rowid);"); + QTest::newRow("193") << std::string("CREATE TABLE t5(pk integer primary key)"); + QTest::newRow("194") << std::string("CREATE TABLE t5(pk integer, primary key(pk))"); + QTest::newRow("195") << std::string("CREATE TABLE t5(pk integer, v integer, primary key(pk))"); + QTest::newRow("196") << std::string("CREATE TABLE t5(pk integer, v integer, primary key(pk, v))"); + QTest::newRow("197") << std::string("CREATE TABLE t5(pk int, v integer, primary key(pk, v))"); + QTest::newRow("198") << std::string("CREATE TABLE t5(pk int, v integer, primary key(pk))"); + QTest::newRow("199") << std::string("CREATE TABLE t5(pk int primary key, v integer)"); + QTest::newRow("200") << std::string("CREATE TABLE t5(pk inTEger primary key)"); + QTest::newRow("201") << std::string("CREATE TABLE t5(pk inteGEr, primary key(pk))"); + QTest::newRow("202") << std::string("CREATE TABLE t5(pk INTEGER, v integer, primary key(pk))"); + QTest::newRow("203") << std::string("CREATE TABLE t6(pk INT primary key);"); + QTest::newRow("204") << std::string("CREATE TABLE t7(pk BIGINT primary key);"); + QTest::newRow("205") << std::string("CREATE TABLE t8(pk SHORT INTEGER primary key);"); + QTest::newRow("206") << std::string("CREATE TABLE t9(pk UNSIGNED INTEGER primary key);"); + QTest::newRow("207") << std::string("CREATE TABLE t(x INTEGER PRIMARY KEY ASC, y, z)"); + QTest::newRow("208") << std::string("CREATE TABLE t(x INTEGER, y, z, PRIMARY KEY(x ASC))"); + QTest::newRow("209") << std::string("CREATE TABLE t(x INTEGER, y, z, PRIMARY KEY(x DESC))"); + QTest::newRow("210") << std::string("CREATE TABLE t(x INTEGER PRIMARY KEY DESC, y, z)"); +} diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/tests/testsqlobjects.h b/src/WBCLFZSystemModule/SqliteDBProcess/src/tests/testsqlobjects.h new file mode 100644 index 0000000..ed6a12f --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/tests/testsqlobjects.h @@ -0,0 +1,47 @@ +#ifndef TESTSQLOBJECTS_H +#define TESTSQLOBJECTS_H + +#include + +class TestTable: public QObject +{ + Q_OBJECT +private slots: + void sqlOutput(); + void sqlGraveAccentOutput(); + void sqlSquareBracketsOutput(); + void autoincrement(); + void notnull(); + void withoutRowid(); + void foreignKeys(); + void uniqueConstraint(); + + void parseSQL(); + void parseSQLSquareBrackets(); + void parseSQLdefaultexpr(); + void parseSQLMultiPk(); + void parseSQLForeignKey(); + void parseSQLSingleQuotes(); + void parseSQLKeywordInIdentifier(); + void parseSQLSomeKeywordsInIdentifier(); + void parseSQLWithoutRowid(); + void parseNonASCIIChars(); + void parseNonASCIICharsEs(); + void parseSQLEscapedQuotes(); + void parseSQLForeignKeys(); + void parseSQLCheckConstraint(); + void parseDefaultValues(); + void createTableWithIn(); + void createTableWithNotLikeConstraint(); + void rowValues(); + void complexExpressions(); + void datetimeExpression(); + void extraParentheses(); + void moduloOperator(); + void complexExpression(); + + void parseTest(); + void parseTest_data(); +}; + +#endif diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/tools/create_windows_icon.sh b/src/WBCLFZSystemModule/SqliteDBProcess/src/tools/create_windows_icon.sh new file mode 100644 index 0000000..4075e5d --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/tools/create_windows_icon.sh @@ -0,0 +1,19 @@ +#!/usr/bin/env sh + +# This script depends on ImageMagick being installed + +FILES=() # array accumulating names of converted images +# commands to give to convert for each iteration +MAGICK_CMDS="+antialias -units PixelsPerInch -alpha set -background transparent" +SRC_FILE="../../images/logo.svg" # conversion source +ICO_FILE="../iconwin.ico" # ouput icon file +for imgsize in 16 32 64 128 +do + RESIZE="${imgsize}x${imgsize}" + DEST_FILE="icon${imgsize}.png" + # NOTE: explicitly not using quotes - outpput raw contents to convert command + convert ${MAGICK_CMDS} ${SRC_FILE} -resize ${RESIZE} ${DEST_FILE} + FILES+=("${DEST_FILE}") +done +convert "${FILES[@]}" "${ICO_FILE}" +rm "${FILES[@]}" diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/translations/README b/src/WBCLFZSystemModule/SqliteDBProcess/src/translations/README new file mode 100644 index 0000000..9e49b82 --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/translations/README @@ -0,0 +1 @@ +TS files for the application should be all named according to a convention such as _, e.g. sqlb_de, sqlb_ru etc. diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/translations/flags/ar.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/translations/flags/ar.png new file mode 100644 index 0000000000000000000000000000000000000000..ade5ca31271fdc1ff9f7f2a63dbf9fa888457c10 GIT binary patch literal 592 zcmeAS@N?(olHy`uVBq!ia0vp^B0$W~!3-oXyUC{mDVB6cUq=Rpjs4tz5?O(Kg=CK) zUj~LMH3o);76yi2K%s^g3=E|P3=FRl7#OT(FffQ0%-I!a1C&@4;1l8sqy+*6cmjDi z0yx^JvA$Ha(ZBMz=U;usS{Ipf_W?pEt;1$=1t2fo>f>rr?hcNLriy6Vqb!N znO%5$m~Vr(ZK;hxw!T=TC|?LKe<+`Lw777%kWsFoTeX{9yqrdwhH^mS!_z|PGiA-rqC^IJfnd7dtgArhB! z`@8v?40v2`PG0$dyM4jj1&fp(-2VUHY^m}D4fV)r^VVjrfBePqh5V6)Z^Zoqxin`? z*<|-AI_l-BgBN5g|5X^x-5PYZxs~s5s>u3l7d#UG_)f|zzZd5!`Qh1f#glzj7uD>Z zKHoN1EH%_9;VSF#=#%TrlZ%qyIr3?6+KKhgTK;{L(5&9qxgVWQ{@l%dcxP_Ao(Y4% znS00C8(X+nxOjCr0bQzE;u=wsl30>zm0Xkxq!^4049#>6%ykV7Lkx_pj7+QyEwzCR k1A~<_zCJ+Fkei>9nO2Eg!;Pc9F+dFrp00i_>zopr0C9`P4gdfE literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/translations/flags/br.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/translations/flags/br.png new file mode 100644 index 0000000000000000000000000000000000000000..dd31ddd156c2de4df4b169183d49ef1e52374c5c GIT binary patch literal 560 zcmV-00?+-4P)Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2j2w~ z6)y$dYu+LN00FQ`L_t(I%gvKNNLxVw#((#GFY3@Xc_)e%6rl?3AhknXB-SMeQgQ3j zjt)f%ty7_-e+C!D!IoCR*-0J6+JZ_(vEpEtG$i!T;>$}?f|MBJU56xXNuP;Ahkn!D z@!gN_?!JS6ECIkOx~5Ts7Bx)62(uPM`rv*?aX$AMQu*rOs=%OxCs#~*E=WLdOS(+P z3T&l7od;-JFx~-oTANtV5CEZ;4PIWGV&%Z)Rl+;%U%&wy!d)8o$rr`bFrM^;o52Dh>IHei-FJ zPQgq9MnAy1tFWy!LoIJHMR7;=ShJVaTy9*$Z#itH6}NX_D)u{_=N)cm;O-ubwJYwm zy+&!lJ7)-hk=FP024)FI74u&plRsmz%O&pf!?P~9d8rA2-RyV5(E{6= y0)>Wv560Sy>kFk+rxyD(px2N2Q`La{_xcIOm!Bt)ZQ5S|0000)>{NGCGpbGC%RlcL@d`DFHjwtgT;1xKmz;{#yg!ZfO{;C{|APz%USO#3*1!| zxFaw4#Dnim1?OEw!F$>Q4~+TWR&(A{6S$`%@H~>|uCm|@ZNbM{0*|x=UTO;-S*0of zwA;8O$S;_Iff)pxgG0a|*pbQKmx(DSmx(DaABdTla`TyzlbOUj=g#YtWasAMVrQIU zU49a%eWj<1V~E7%H literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/translations/flags/cs.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/translations/flags/cs.png new file mode 100644 index 0000000000000000000000000000000000000000..f8f671a7298af0acacd542dc472b0c61dd8467c9 GIT binary patch literal 252 zcmVvz6h;q7urL$B=_3$)1D}9OaufrR2XM2P4Eg|A3??#>;@qqjo!vlTgE`bq%Wu`G z$l(9l-FJ8H*~M{IB2BMCRsc^J#z+LgP6|*3NRkV-y~MH>#POLrQD28JJYbqre19tk z2#{qrTsNp}tNtpg+Nwom6`_v$Y7iF2jh%uPKg~3?L_L~SdS<3u~Y^Px+*$zsY zA_p!?QMMY%QkD|oV!06guW!oP)3fxx^}M~JUYDcf!*~EnZLYeQWgwHUx16~vJEDQb zwm#pWVJVX_`ws+k08T&v=7AYt5pV#+V^INz9OMJq#X>IZ8qh6>urvPLNCM~{bO(9@J%C<8 zFQ7METNG8Slh9GDD*@zLC58-6U(h0Otx~JNz%l+w5X|Oaan>$|din6Ymn<|gW!U_%O?XxI14-? zi-9_>gD|6$#_S59V85q}V~EA+x0emM4mk+4KCCyB7U~d?=HA=%ptGs{i=H-<}Ato@{Z!aezteceJUSlw)kUy{L{LM>CO%R zr#HS07h6`Z^5f?{;br;n|JziY`8X@` + + ar.png + cs.png + de.png + es.png + us.png + fr.png + it.png + ru.png + cn.png + br.png + gb.png + roc.png + kr.png + tr.png + ua.png + eg.png + pl.png + jp.png + nl.png + + diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/translations/flags/fr.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/translations/flags/fr.png new file mode 100644 index 0000000000000000000000000000000000000000..7fe158cee408c8b91215f0a1ef2319121b2b8edf GIT binary patch literal 616 zcmeAS@N?(olHy`uVBq!ia0vp^B0$W~!3-oXyUC|BFfi%__=LCuxj-g^Ru6;j3y|+1#R8+@evOLLilb)(m|5415L* zTzWwvkqHS2i9i6Pf`VgM`C>SQfXaaCK`PZ68Pw_-q$+Pcc>DJs$WQ=~`k|4ie1_ovra1IWEfnZ0b0AD7iyj&)xf_x^X{CuXAWG3;>x$|IP zZl@$WHy0eRGe$C**a6L4?CIhdB5^qx=#`|j#Kcr)<}yA$KRq^q2hScpefn5jKtx1H zOi)x*n4QbhqpG5+s;ct$k6*ujva_(Uv3YtLpE$wB%J#bBtA1Gcz;OyC=>eBs6)_q)Db*B_y_#mVEv4g_ozdr^nal z?3pvVI+79+l55uF=H$G6BP$~_cTQ|f%-uVZ47D>n0$rL_|A9i+)78&qol`;+0042) A!T?ulu;OlA4kWgP-~=d#&M0n5KU=hTq6}RERduSn(`{_ zLW(3x^CBt1g2IKQ3j^z-P_T4JDTdPAmj=Nbg)!3samDQyNB!ODBKuv&5Tf_$gY%x} zyyu+nga0gt?ebjO!l$E_4YgJYAOje6RF2KOuc9w9l3>9? zZS5^graS0#zILGS@Dnr?o~2;Xh(}!|-o?duRa7$Qq#glq0vL1A3YLpm1Spo+m>pte zV1T5gAd-@Tur)O70@jpWVWGVpMNtvX!KblWr}b}PH$w_R@ z%>cN@#o?qjff!;G%g&csj1HlTfeN=`)bl}MB~=gh()hQ`0^E#a}cpeOEfFmOU85!kx zd*@JM8b@3HyLApbIw&NdxU@XlnR1`_Zz?jMwKF}v@Yl!xqp2wyIXOlG10V6uJkO+G zXgBPh zaB^>EX>4U6ba`-PAZ2)IW&i+q+MQHsuG}CD{?93T1iS#|IFNwU8}#`7Ovt>M(R-t+ zwgQg#EeYe#?-_nMWQ##lv0QVG0IgcNfv|Xi(;W}vIWLywcmu_{&IN(=!G00Mx!L^2 z-#4{4N4ld^e-+$(wl_z7UE%>i--(2}2@Nkv?kl{P z68RE5ntD5wSN=VW8^TIYAeJYk{QYD;4JLe=%qr`t(W;x`SAIGph3E9RM7J+Rwlv%*srI6$S&m@yLaC*s=nTXaTVYloZaC#{XmZSH(FGZxO8zdakuVUhHG> zV$p2z3u>4G-L0kgGq|I&^-sEnfIf#0Mk1x8wF2lvM=smEEE{>X3~$D|=60KOqO~>N z+MmH)V*Eu^QW4Crs!2mrws*epB98d*!%OA98QRXSU){%<&&iNzEB>f;`{ sQbhqWQC;ruoR|@@d*MLMHP`&(1K)KK8pNN!+yDRo07*qoM6N<$f*wLNzyJUM literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/translations/flags/jp.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/translations/flags/jp.png new file mode 100644 index 0000000000000000000000000000000000000000..325fbad3ffd3075a4a84d8d898ad26ef7d3e0d56 GIT binary patch literal 420 zcmV;V0bBlwP)9whYk?f=!Q|Ns8||JN@lTD;`{R1ZWk|EGa3dAO8ObDh3E3Cb;oH_5X#1 z|NHy@|M?558b}5Q|Cf`4hZv9q2p|@?lb|{i68>{>{ol0lx`{mi O0000lKn+&kl?%bT0$#{+f;6bJOb0+iU*B5@eKJ&00vjiZe0AqQ1+4ube zLxcMV4~Rn19Um9t6OD;Cs$*lg_s6r(3>_PLwOAy3=v{r`E*4hf->b36&2Kq-v4}bDz`%Ly9V&2~! zX>H?6m%sh^^ry|uEl>9Kn#!noo+eVvyd^rlcklDV!@1nuaHI*qqp|RzK@)hmLM)O< zcJ}o4?mqb9!D!5C_#PM{Un)fn!?G;bb#u9#y=ixMCWDb!tzHeAf;Bs?wxX8fl;`Jv z4H@R1{{EIkVkN(}T38dS#Ue8kZ9PU45ff`B&BVlLkR~P&ftd)6h6b1c20;G;qB^E3 TNGQ1#00000NkvXXu0mjf;zOz= literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/translations/flags/nl.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/translations/flags/nl.png new file mode 100644 index 0000000000000000000000000000000000000000..99814aa9c9bad8116af7462c3060e2ce323e9117 GIT binary patch literal 119 zcmeAS@N?(olHy`uVBq!ia0vp^B0$W~!3HFs%y=IPq&N#aB8wRqn7)88W5e1tAVEz} z7sn8b)5$UFi$Bh9>}u$2Je9yAb>heW|Nk#~Najpj^x~SWlxFi82L|yf_Fs$n^R0oJ O7(8A5T-G@yGywo?2qpFa literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/translations/flags/pl.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/translations/flags/pl.png new file mode 100644 index 0000000000000000000000000000000000000000..d8ca17ce955667b52e070dbe2cfaf917240f1797 GIT binary patch literal 139 zcmeAS@N?(olHy`uVBq!ia0vp^B0$W~!3HFs%y=IPq}Y|gW!U_%O?XxI14-? zi-9_>gD|6$#_S59pth%rV~EA+UD$-=Ps633$h^Mq#twJ~_Q`njxgN@xNADbXu} literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/translations/flags/roc.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/translations/flags/roc.png new file mode 100644 index 0000000000000000000000000000000000000000..23f01ce46894a133fd3a4fbd420691bbc6ad3c7f GIT binary patch literal 329 zcmeAS@N?(olHy`uVBq!ia0vp^B0$W~!2~3;e^r1e#^NA%Cx&(BWL^R}Ea{HEjtmSN z`?>!lvI6;>1s;*b3=DjSL74G){)!Z!;5|fFgw z=a{VZCR4jY`RQ4Y~n|q&)u|Wh|nGL5|KHIID@9&PEJ6C+^(ve#>!YvZ%2E}Jh zH{N^kWM^zpoh0+)k_|sDWwFKA%wm7}o(n%!6ie(pIp+EcIX$1;0^+iHOj2S0^Piug{EBz$ UHL)l1K%X*ry85}Sb4q9e04w5s-v9sr literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/translations/flags/ru.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/translations/flags/ru.png new file mode 100644 index 0000000000000000000000000000000000000000..e634822ec003073ca208d7a78e7c77ccee29565b GIT binary patch literal 503 zcmeAS@N?(olHy`uVBq!ia0vp^B0$W~!3-oXyUC{msaF9$A+A80k%8g=|Nr;y-FpZI zckkW>a(C?5v3~vfWy_W=Sg>H_%H@j|E$Hd_Z(@>TXqY}{&VOFsr)+GY%*+AY-2d6w z9x^kBFf#fvG5r=~yTi^L#LDQy&-C>kYgrJJjvu4OAEt)?EZhs2SZ6UZ|7YU(&%(Bt ziFqy~<9{Zm|17Nij7%*+HZ#a!iHwZ-jEn`0jPZ;>M=_K!GR876Brr0@fdzpgK!^GJ zFZc6X8W6C8m9>$TwSkqjiIK6Mk+F`Ev4NejhMlpRow2ro(Xo!vv4PR)HzUgrMwb7K zjQ7auM>xFKEs`s&9~N&NqBon-!g?o-AGDIcC+y2Eug zdHRPu$@vW*KJ(m=d?G2t;a*n#NT647p2fV5Vx!iQXGN-cH)TGx{%$ttR-K}KUi{;_ zYYVQgnLE@ew&z!e(I*uOqtpE1UfbOH1#voVZCq*D!dx L`njxgN@xNA(A%r4 literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/translations/flags/tr.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/translations/flags/tr.png new file mode 100644 index 0000000000000000000000000000000000000000..f95e1ca967cb96085ca8086dbce1978cbd6ea94b GIT binary patch literal 792 zcmV+z1LypSP)#~ zVB!`R+)z~9LI00j1_Z%lz>7C8o+UFq(~h%s&rC9C5-|?>Qt$OhJZQj%AN8tURlTpO zh1VGw@$aqHSMSW`bdJUHVtP!b^nu*m^wjwH6rm?O+p11YA+)i9;OZ(uYikItum6Mj z{~<^y#P5|An3Iz~3*APe7+hXP_}~Dctu2IicQrOQ5#HX`&O19A%x66KM2LKKZx2zz zl9XfrcB928QjOin@>9Yt_y3F`bjl(8`=)6-C&fz|kDXK}Z%0CQrZjVtu` z_aiVe0)KBWl!*!aJUzv|s^Zt#8N&Pf@DC0mFf@d~@UUi?AHzQ|058RENragxWDPwX z9q_id!`sz`yNe4%Bi|9Eo%s6t5THa~cQ-t(t?;z8z}wcQ<;L)k?KvH#ERqUyn;dnfe5EagjG>@vEjLj=QlDGTCc-OdB~XOO$JB zAm!%b=I982qETMpDlO$rUFGGttgYqaM#4b`le&I9K>KBSUl+7sE+KF0!}h z=eSoC_^2sU<|uno_B#~t}XhfDQJ=)__IG94p_tKOGL9hv3 z$;qOd_P}27Qez)oFqrRS#Qf)AH69{DQ*wnVI$Z%BzEJlQgHCtC?MsN&n90To!pdL5 W*mJs6q;`=20000^eP*B^` z#WBRvVBq>N(>CEjo6t&94l>r P+88`t{an^LB{Ts5N*E&m literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/translations/flags/us.png b/src/WBCLFZSystemModule/SqliteDBProcess/src/translations/flags/us.png new file mode 100644 index 0000000000000000000000000000000000000000..10db15e8f509e5c5dd9ee106091911da3380c29d GIT binary patch literal 872 zcmeAS@N?(olHy`uVBq!ia0vp^B0$W~!3-oXyUC|BFfg7A@Ck7Rav2#IrYzWH6WknA zICtshiwqLsGglm+v-%W+NXV3R7p{1OJn;&8>J{|RGw_15_rm3yRLr8?LQ7^X+`zz~ z+uFOJbJAi42JPMj8+&=grgI6+;1Zm{CD6~nr0&rts^YqN&z}GP|LX-WV-Yf5u4S@W z({PKXVWFhl|KJq8uw@MV21_??&r3tpM7!V9DbD z1$C7gx_j*1N;P!;H}o!;J$v@F>HjCqt2MK#GPV4_dPh%3M^j@X(C=>C`~doeY9*?>~J7 z+UNpwPjo|IVvA!)m62P1L`G*wYP+FJu4P!=HZ7y@^ezR{Btw_HsH|=Vaj$^H)}Z88 z22n5f@EV|I6ZgWPq*mw9YMyM8gPlU%D3yVGx9{c0gozFLKeZG17PO*PD(8Y-*L4Lsu49qCN zIXDCkf*qLxe3_VX|NZ-y%fytI&y)vb<-u7%4hVpR^MQ(h7>tsW#JlFso7XAH&dtTe z&M2Sx!VhTK3r`ov5Q)pl2?+^FX^E-H&mTN_^z7l&r%xZJGcYnbDkcgB8WwVTYG!6; zN=7c2FsCLdsK_fTs>&@b%uGT|JCiqUc9F1F@nVUd-tsiCF5 zxv{n`OSdUC_vJY!rxpem=XtN5w~tX^i=>pH#Oy8QC1s`GzbyOa7&=SKXvWO%(GgLR zw{P6KX>HMTwxlR6pyXs(>xzb;n|WP4@8pDS)Rh>|bH?4{>9U)wwz$D_Ul&i^zu;wy z8ZsFhdAb}gr=M|QyWA`)DdFUF_|QZLmlP3ZW@YCRA045NZvO;e2KtyTSbw-{5zx;J Mp00i_>zopr064)(xc~qF literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/translations/place_translations_here b/src/WBCLFZSystemModule/SqliteDBProcess/src/translations/place_translations_here new file mode 100644 index 0000000..e69de29 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/translations/sqlb_ar_SA.qm b/src/WBCLFZSystemModule/SqliteDBProcess/src/translations/sqlb_ar_SA.qm new file mode 100644 index 0000000000000000000000000000000000000000..cfe10a92cfb5f06917346b2f6eef99e64a14c643 GIT binary patch literal 223625 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 S_tSm*fBM#EMt^$p#s3FT*B+Pv literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/translations/sqlb_ar_SA.ts b/src/WBCLFZSystemModule/SqliteDBProcess/src/translations/sqlb_ar_SA.ts new file mode 100644 index 0000000..ffd84c3 --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/translations/sqlb_ar_SA.ts @@ -0,0 +1,7051 @@ + + + + + AboutDialog + + + About DB Browser for SQLite + عن «متصÙّح قواعد بيانات SQLite» + + + + Version + الإصدارة + + + + <html><head/><body><p>DB Browser for SQLite is an open source, freeware visual tool used to create, design and edit SQLite database files.</p><p>It is bi-licensed under the Mozilla Public License Version 2, as well as the GNU General Public License Version 3 or later. You can modify or redistribute it under the conditions of these licenses.</p><p>See <a href="http://www.gnu.org/licenses/gpl.html">http://www.gnu.org/licenses/gpl.html</a> and <a href="https://www.mozilla.org/MPL/2.0/index.txt">https://www.mozilla.org/MPL/2.0/index.txt</a> for details.</p><p>For more information on this program please visit our website at: <a href="http://sqlitebrowser.org">http://sqlitebrowser.org</a></p><p><span style=" font-size:small;">This software uses the GPL/LGPL Qt Toolkit from </span><a href="http://qt-project.org/"><span style=" font-size:small;">http://qt-project.org/</span></a><span style=" font-size:small;"><br/>See </span><a href="http://qt-project.org/doc/qt-5/licensing.html"><span style=" font-size:small;">http://qt-project.org/doc/qt-5/licensing.html</span></a><span style=" font-size:small;"> for licensing terms and information.</span></p><p><span style=" font-size:small;">It also uses the Silk icon set by Mark James licensed under a Creative Commons Attribution 2.5 and 3.0 license.<br/>See </span><a href="http://www.famfamfam.com/lab/icons/silk/"><span style=" font-size:small;">http://www.famfamfam.com/lab/icons/silk/</span></a><span style=" font-size:small;"> for details.</span></p></body></html> + <html dir="rtl"> +<p>«متصÙّح قواعد بيانات SQLite» أداة رسوميّة Ù…ÙØªÙˆØ­Ø© المصدر ومجانية، ØªÙØ³ØªØ®Ø¯Ù… لإنشاء ملÙّات قواعد بيانات SQLite وتصميمها وتحريرها.</p><p>الأداة مرخّصة برخصتين، الإصدارة الثانية من رخصة موزيلا العمومية، والإصدارة الثالثة وما بعدها من رخصة غنو العمومية. يمكنك تعديل الأداة أو إعادة توزيعها بشروط تلك الرخص.</p><p>طالع <a href="http://www.gnu.org/licenses/gpl.html">http://www.gnu.org/licenses/gpl.html</a> Ùˆ<a href="https://www.mozilla.org/MPL/2.0/index.txt">https://www.mozilla.org/MPL/2.0/index.txt</a> Ù„Ù„ØªÙØ§ØµÙŠÙ„.</p><p>من ÙØ¶Ù„Ùƒ Ø²ÙØ± موقع Ø§Ù„ÙˆÙØ¨ هذا لمعلومات أكثر عن البرمجية: <a href="http://sqlitebrowser.org">http://sqlitebrowser.org</a></p><p><span style=" font-size:small;">تستخدم هذه البرمجية Ø¹ÙØ¯Ù‘Ø© أدوات كيوت المرخّصة تحت GPL/LGPL وذلك من </span><a href="http://qt-project.org/"><span style=" font-size:small;">http://qt-project.org/</span></a><span style=" font-size:small;"><br/>طالع </span><a href="http://qt-project.org/doc/qt-5/licensing.html"><span style=" font-size:small;">http://qt-project.org/doc/qt-5/licensing.html</span></a><span style=" font-size:small;"> لشروط الترخيص والمعلومات.</span></p><p><span style=" font-size:small;">تستخدم البرمجية أيضًا طقم أيقونات الحرير/Silk للمؤلّ٠Mark James المرخّصة برخصة المشاع الإبداعي - النسبة ٢٫٥ و٣٫٠.<br/>طالع </span><a href="http://www.famfamfam.com/lab/icons/silk/"><span style=" font-size:small;">http://www.famfamfam.com/lab/icons/silk/</span></a><span style=" font-size:small;"> Ù„Ù„ØªÙØ§ØµÙŠÙ„.</span></p> +</html> + + + + AddRecordDialog + + + Add New Record + أضÙ٠سجلًا جديدًا + + + + Enter values for the new record considering constraints. Fields in bold are mandatory. + أدخÙÙ„ قيم السجلّ الجديد بأخذ القيود بعين الاعتبار. الحقول الثخينة ضرورية. + + + + In the Value column you can specify the value for the field identified in the Name column. The Type column indicates the type of the field. Default values are displayed in the same style as NULL values. + يمكنك تحديد قيمة الحقل المحدّد ÙÙŠ عمود â€Ø§Ù„اسم“ وذلك ÙÙŠ عمود â€Ø§Ù„قيمة“. ÙŠÙØ´ÙŠØ± عمود â€Ø§Ù„نوع“ إلى نوع الحقل. ØªÙØ¹Ø±Ø¶ القيم المبدئية Ø¨Ù†ÙØ³ نمط قيم NULL. + + + + Name + الاسم + + + + Type + النوع + + + + Value + القيمة + + + + Values to insert. Pre-filled default values are inserted automatically unless they are changed. + القيم التي Ø³ØªÙØ¯Ø±Ø¬. لو لم تتغيّر ÙØ³Ùتدرج آليًا القيم المبدئية المعبّأة مسبقًا. + + + + When you edit the values in the upper frame, the SQL query for inserting this new record is shown here. You can edit manually the query before saving. + عندما تحرّر القيم ÙÙŠ الإطار أعلاه، ستظهر هنا Ø¥ÙØ§Ø¯Ø© SQL لإدراج هذا السجلّ. يمكنك تحرير Ø§Ù„Ø¥ÙØ§Ø¯Ø© يدويًا قبل Ø§Ù„Ø­ÙØ¸. + + + + <html><head/><body><p><span style=" font-weight:600;">Save</span> will submit the shown SQL statement to the database for inserting the new record.</p><p><span style=" font-weight:600;">Restore Defaults</span> will restore the initial values in the <span style=" font-weight:600;">Value</span> column.</p><p><span style=" font-weight:600;">Cancel</span> will close this dialog without executing the query.</p></body></html> + <p>Ø³ÙŠÙØ±Ø³Ù„ زر <span style=" font-weight:600;">Ø§Ø­ÙØ¸</span> Ø¥ÙØ§Ø¯Ø© SQL الظاهرة إلى قاعدة البيانات لإدراج السجلّ الجديد.</p><p>سيستعيد زر <span style=" font-weight:600;">استعد المبدئيات</span> القيمة الأولية ÙÙŠ عمود â€<span style=" font-weight:600;">القيمة</span>“.</p><p>Ø³ÙŠÙØºÙ„Ù‚ زر <span style=" font-weight:600;">ألغÙ</span> مربّع الحوار هذا دون تنÙيذ الاستعلام.</p> + + + + Auto-increment + + زيادة آليّة + + + + + Unique constraint + + قيد â€Ùريد“ + + + + + Check constraint: %1 + + قيد Ø§Ù„ÙØ­Øµ: %L1 + + + + + Foreign key: %1 + + Ø§Ù„Ù…ÙØªØ§Ø­ الأجنبي: %L1 + + + + + Default value: %1 + + القيمة المبدئية: %L1 + + + + + Error adding record. Message from database engine: + +%1 + خطأ أثناء Ø¥Ø¶Ø§ÙØ© السجلّ. الرسالة من محرّك قواعد البيانات: + +%L1 + + + + Are you sure you want to restore all the entered values to their defaults? + أمتأكّد من استعادة كلّ القيم Ø§Ù„Ù…ÙØ¯Ø®Ù„Ø© إلى مبدئياتها؟ + + + + Application + + + Possible command line arguments: + معطيات سطر الأوامر الممكنة: + + + + The -o/--option and -O/--save-option options require an argument in the form group/setting=value + يطلب الخياران ‎-o/--option Ùˆ ‎-O/--save-option معطًى بهذا النحو: group/setting=value + + + + Usage: %1 [options] [<database>|<project>] + + ‎الاستعمال:‎ %L1 [options] [<database>|<project>] + + + + + -h, --help Show command line options + -h, --help اعرض خيارات سطر الأوامر + + + + -q, --quit Exit application after running scripts + -q, --quit أنه٠التطبيق بعد تشغيل السكربتات + + + + -s, --sql <file> Execute this SQL file after opening the DB + -s, --sql <file> ‫نÙّذ مل٠SQL المذكور بعد ÙØªØ­ قاعدة البيانات + + + + -t, --table <table> Browse this table after opening the DB + -t, --table <table> تصÙّح الجدول المذكور بعد ÙØªØ­ قاعدة البيانات + + + + -R, --read-only Open database in read-only mode + -R, --read-only Ø§ÙØªØ­ قاعدة البيانات بوضع القراءة Ùقط + + + + -o, --option <group>/<setting>=<value> + -o, --option <group>/<setting>=<value> + + + + Run application with this setting temporarily set to value + ‎ ‫شغّل التطبيق بضبط هذا الإعداد setting مؤقتًا على القيمة value + + + + -O, --save-option <group>/<setting>=<value> + -O, --save-option <group>/<setting>=<value> + + + + Run application saving this value for this setting + ‎ ‫شغّل التطبيق Ø¨Ø­ÙØ¸ هذه القيمة value لهذا الإعداد setting + + + + -v, --version Display the current version + -v, --version اعرض الإصدارة الحالية + + + + <database> Open this SQLite database + <database> â€«Ø§ÙØªØ­ قاعدة بيانات SQLite المذكورة + + + + <project> Open this project file (*.sqbpro) + <project> â€«Ø§ÙØªØ­ مل٠المشروع المذكور (‎*.sqbpro) + + + + The -s/--sql option requires an argument + يتطلّب الخيار ‎-s/--sql معطًى + + + + The file %1 does not exist + المل٠%L1 غير موجود + + + + The -t/--table option requires an argument + يتطلّب الخيار ‎-t/--table معطًى + + + + Invalid option/non-existant file: %1 + خيار غير صالح/مل٠غير موجود: %L1 + + + + SQLite Version + إصدارة SQLite: †+ + + + SQLCipher Version %1 (based on SQLite %2) + إصدارة SQLCipher:†%L1 (مبنيّة على SQLite %L2) + + + + DB Browser for SQLite Version %1. + «متصÙّح قواعد بيانات SQLite» الإصدارة %L1. + + + + Built for %1, running on %2 + مبنيّة للمعماريّة %L1ØŒ وتعمل على المعماريّة %L2 + + + + Qt Version %1 + إصدارة كيوت: %L1 + + + + CipherDialog + + + SQLCipher encryption + تعمية SQLCipher + + + + &Password + &كلمة السر + + + + &Reenter password + Ø£&Ø¹ÙØ¯ إدخال كلمة السر + + + + Encr&yption settings + إعدادات التع&مية + + + + SQLCipher &3 defaults + مبدئيّات SQLCipher &3 + + + + SQLCipher &4 defaults + مبدئيّات SQLCipher &4 + + + + Custo&m + Ù…&خصّص + + + + Page si&ze + Ù…&قاس Ø§Ù„ØµÙØ­Ø© + + + + &KDF iterations + ت&كرارات KDF + + + + HMAC algorithm + خوارزميّة HMAC + + + + KDF algorithm + خوارزميّة KDF + + + + Plaintext Header Size + حجم ترويسة النص البائن + + + + Passphrase + عبارة سر + + + + Raw key + Ù…ÙØªØ§Ø­ خام + + + + Please set a key to encrypt the database. +Note that if you change any of the other, optional, settings you'll need to re-enter them as well every time you open the database file. +Leave the password fields empty to disable the encryption. +The encryption process might take some time and you should have a backup copy of your database! Unsaved changes are applied before modifying the encryption. + من ÙØ¶Ù„Ùƒ اضبط Ù…ÙØªØ§Ø­Ù‹Ø§ لتعمية قاعدة البيانات. +لو غيّرت أيًا من الإعدادات الأخرى (الاختيارية)ØŒ ÙØ³ÙŠÙƒÙˆÙ† عليك إعادة إدخالها أيضًا ÙÙŠ كلّ مرّة ØªÙØªØ­ Ùيها مل٠قاعدة البيانات. +اترك حقول كلمة السر ÙØ§Ø±ØºØ© لتعطيل التعمية. +قد تأخذ عملية التعمية وقتًا وعليك Ø§Ù„Ø§Ø­ØªÙØ§Ø¸ بنسخة من قاعدة البيانات احتياطًا! Ø³ØªÙØ·Ø¨Ù‘Ù‚ التعديلات غير المحÙوظة قبل تعديل التعمية. + + + + Please enter the key used to encrypt the database. +If any of the other settings were altered for this database file you need to provide this information as well. + من ÙØ¶Ù„Ùƒ أدخÙÙ„ Ø§Ù„Ù…ÙØªØ§Ø­ المستعمل لتعمية قاعدة البيانات. +إن كانت هناك إعدادات أخرى قد تغيّرت ÙÙŠ مل٠قاعدة البيانات هذا، ÙØ¹Ù„يك ذكر ذلك أيضًا. + + + + ColumnDisplayFormatDialog + + + Choose display format + اختر تنسيق العرض + + + + Display format + تنسيق العرض + + + + Choose a display format for the column '%1' which is applied to each value prior to showing it. + اختر تنسيق عرض العمود â€%L1“ Ù„ÙŠÙØ·Ø¨Ù‘Ù‚ على كلّ قيمة قبل عرضها. + + + + Default + المبدئي + + + + Decimal number + عدد عشري + + + + Exponent notation + تدوين Ø£ÙØ³Ù‘ÙŠ + + + + Hex blob + â€BLOB ستّ‌عشري + + + + Hex number + عدد ستّ‌عشري + + + + Apple NSDate to date + â€ØªØ§Ø±ÙŠØ® آبل/Apple NSDate“ إلى تاريخ + + + + Java epoch (milliseconds) to date + عَصر جاڤا (ملّي‌ثانية) إلى تاريخ + + + + .NET DateTime.Ticks to date + â€DateTime.Ticks من ‎.NET إلى تاريح + + + + Julian day to date + يوم جولياني إلى تاريخ + + + + Unix epoch to local time + عَصر لينكس إلى الوقت المحلي + + + + Date as dd/mm/yyyy + التاريخ بتنسيق dd/mm/yyyy + + + + Lower case + حالة الأحر٠صغيرة + + + + Custom display format must contain a function call applied to %1 + على تنسيق العرض المخصّص أن يحتوي على نداء دالة مطبّق على %L1 + + + + Error in custom display format. Message from database engine: + +%1 + خطأ ÙÙŠ تنسيق العرض المخصّص. الرسالة من محرّك قواعد البيانات: +%L1 + + + + Custom display format must return only one column but it returned %1. + على تنسيق العرض المخصّص إعادة عمود واحد Ùقط، لكنّه أعاد %L1. + + + + Octal number + عدد ثماني + + + + Round number + عدد تقريبي + + + + Unix epoch to date + عَصر لينكس إلى تاريخ + + + + Upper case + حالة الأحر٠كبيرة + + + + Windows DATE to date + â€ØªØ§Ø±ÙŠØ® وندوز/Windows DATE“ إلى تاريخ + + + + Custom + مخصّص + + + + CondFormatManager + + + Conditional Format Manager + مدير التنسيقات الشرطيّة + + + + This dialog allows creating and editing conditional formats. Each cell style will be selected by the first accomplished condition for that cell data. Conditional formats can be moved up and down, where those at higher rows take precedence over those at lower. Syntax for conditions is the same as for filters and an empty condition applies to all values. + ÙŠÙØªÙŠØ­ لك مربّع الحوار هذا إنشاء التنسيقات الشرطيّة وتحريرها. ستختار البرمجيّة كلّ نمط خلايا حسب أوّل شرط متواÙÙ‚ مع بيانات الخليّة. يمكنك نقل التنسيقات الشرطيّة إلى أعلى وأسÙÙ„ØŒ حيث تعبّر أعلاها أكثرها أولويّة، والعكس. صياغة الشروط هي Ù†ÙØ³Ù‡Ø§ صياغة المرشّحات، والشروط Ø§Ù„ÙØ§Ø±ØºØ© تنطبق على كلّ القيم. + + + + Add new conditional format + أضÙ٠تنسيقًا شرطيًا جديدًا + + + + &Add + Ø£&ضÙÙ + + + + Remove selected conditional format + أزÙÙ„ التنسيق الشرطيّ المحدّد + + + + &Remove + Ø£&زÙÙ„ + + + + Move selected conditional format up + انقل التنسيق الشرطيّ المحدّد لأعلى + + + + Move &up + انقل لأ&على + + + + Move selected conditional format down + انقل التنسيق الشرطيّ المحدّد لأسÙÙ„ + + + + Move &down + انقل لأ&سÙÙ„ + + + + Foreground + الأمامية + + + + Text color + لون النص + + + + Background + الخلÙية + + + + Background color + لون الخلÙية + + + + Font + الخط + + + + Size + الحجم + + + + Bold + ثخين + + + + Italic + مائل + + + + Underline + مسطّر + + + + Alignment + المحاذاة + + + + Condition + الشرط + + + + + Click to select color + انقر لاختيار لون + + + + Are you sure you want to clear all the conditional formats of this field? + أمتأكّد من مسح كلّ التنسيقات الشرطيّة لهذا الحقل؟ + + + + DBBrowserDB + + + Please specify the database name under which you want to access the attached database + من ÙØ¶Ù„Ùƒ اختر اسم قاعدة البيانات الذي تريد استعماله للوصول إلى قاعدة البيانات المرÙقة + + + + Invalid file format + تنسيق المل٠غير صالح + + + + Do you want to save the changes made to the database file %1? + أتريد Ø­ÙØ¸ التعديلات Ø§Ù„Ù…ÙØ¬Ø±Ø§Ø© على مل٠قاعدة البيانات %L1ØŸ + + + + Exporting database to SQL file... + يصدّر قاعدة البيانات إلى مل٠SQL... + + + + + Cancel + ألغ٠+ + + + Executing SQL... + ينÙّذ SQL... + + + + Action cancelled. + Ø£Ùلغي الإجراء. + + + + This database has already been attached. Its schema name is '%1'. + Ø£ÙØ±Ùقت قاعدة البيانات هذه Ø¨Ø§Ù„ÙØ¹Ù„. اسم المخطّط هو â€%L1“. + + + + Do you really want to close this temporary database? All data will be lost. + أمتأكّد من إغلاق قاعدة البيانات المؤقّتة هذه؟ ستÙقد كلّ البيانات. + + + + Database didn't close correctly, probably still busy + لم ØªÙØºÙ„Ù‚ قاعدة البيانات كما ينبغي، ربّما هي مشغولة + + + + The database is currently busy: + قاعدة البيانات مشغولة حاليًا: + + + + Do you want to abort that other operation? + أتريد إجهاض العملية الأخرى؟ + + + + + No database file opened + لم ÙŠÙÙØªØ­ مل٠قاعدة بيانات + + + + + Error in statement #%1: %2. +Aborting execution%3. + خطأ ÙÙŠ Ø§Ù„Ø¥ÙØ§Ø¯Ø© رقم %L1:†%L2. +Ø³Ø£ÙØ¬Ù‡Ø¶ التنÙيذ%L3. + + + + + and rolling back + ÙˆØ£ÙØ±Ø¬Ø¹ ما كان موجودًا. + + + + didn't receive any output from %1 + لم أستلم أيّ ناتج من %L1 + + + + could not execute command: %1 + تعذّر تنÙيذ الأمر: %L1 + + + + Cannot delete this object + تعذّر حذ٠هذا الكائن + + + + Cannot set data on this object + تعذّر ضبط البيانات على هذا الكائن + + + + + A table with the name '%1' already exists in schema '%2'. + هناك جدول Ø¨Ù†ÙØ³ الاسم â€%L1“ Ø¨Ø§Ù„ÙØ¹Ù„ ÙÙŠ المخطّط â€%L2“. + + + + No table with name '%1' exists in schema '%2'. + ما من جدول له الاسم â€%L1“ ÙÙŠ المخطّط â€%L2“. + + + + + Cannot find column %1. + تعذّر العثور على العمود %L1 + + + + Creating savepoint failed. DB says: %1 + ÙØ´Ù„ إنشاء نقطة Ø§Ù„Ø­ÙØ¸. تقول قاعدة البيانات: %L1 + + + + Renaming the column failed. DB says: +%1 + ÙØ´Ù„ تغيير اسم العمود. تقول قاعدة البيانات: +%L1 + + + + + Releasing savepoint failed. DB says: %1 + ÙØ´Ù„ت استعداة نقطة Ø§Ù„Ø­ÙØ¸. تقول قاعدة البيانات: %L1 + + + + Creating new table failed. DB says: %1 + ÙØ´Ù„ إنشاء جدول جديد. تقول قاعدة البيانات: %L1 + + + + Copying data to new table failed. DB says: +%1 + ÙØ´Ù„ نسخ البيانات إلى جدول جديد. تقول قاعدة البيانات: +%L1 + + + + Deleting old table failed. DB says: %1 + ÙØ´Ù„ حذ٠الجدول القديم. تقول قاعدة البيانات: %L1 + + + + Error renaming table '%1' to '%2'. +Message from database engine: +%3 + خطأ ÙÙŠ تغيير اسم الجدول â€%L1“ إلى â€%L2“. +الرسالة من محرّك قواعد البيانات: +%L3 + + + + could not get list of db objects: %1 + تعذّر جلب قائمة كائنات قواعد البيانات: %L1 + + + + Restoring some of the objects associated with this table failed. This is most likely because some column names changed. Here's the SQL statement which you might want to fix and execute manually: + + + ÙØ´Ù„ت استعادة بعض الكائنات المرتبطة بهذا الجدول. غالبًا ما يحدث هذا بسبب تغيّر اسم الأعمدة. هذه Ø¥ÙØ§Ø¯Ø© SQL التي قد ترغب بتنÙيذها لإصلاح ذلك يدويًا: + + + + + + could not get list of databases: %1 + تعذّر جلب قائمة قواعد البيانات: %L1 + + + + Error loading extension: %1 + خطأ أثناء تحميل الامتداد: %L1 + + + + could not get column information + تعذّر جلب معلومات العمود + + + + Error setting pragma %1 to %2: %3 + تعذّر ضبط pragma %L1 إلى %L2:†%L3 + + + + File not found. + تعذّر العثور على الملÙ. + + + + DbStructureModel + + + Name + الاسم + + + + Object + الكائن + + + + Type + النوع + + + + Schema + المخطّط + + + + Database + قاعدة البيانات + + + + Browsables + ما يمكنك تصÙّحه + + + + All + الكلّ + + + + Temporary + مؤقّتة + + + + Tables (%1) + الجداول (%L1) + + + + Indices (%1) + الÙهارس (%L1) + + + + Views (%1) + المناظير (%L1) + + + + Triggers (%1) + المحÙّزات (%L1) + + + + EditDialog + + + Edit database cell + تحرير خليّة قاعدة البيانات + + + + Mode: + الوضع: + + + + This is the list of supported modes for the cell editor. Choose a mode for viewing or editing the data of the current cell. + هذه قائمة بالأوضاع المتوÙّرة ÙÙŠ محرّر الخلايا. اختر وضعًا لعرض أو تحرير البيانات ÙÙŠ الخليّة الحالية. + + + + Text + نصوص + + + + RTL Text + نصوص من اليمين إلى اليسار + + + + Binary + بيانات ثنائيّة + + + + + Image + صور + + + + JSON + JSON + + + + XML + XML + + + + + Automatically adjust the editor mode to the loaded data type + اضبط وضع المحرّر آليًا على نوع البيانات المحمّل + + + + This checkable button enables or disables the automatic switching of the editor mode. When a new cell is selected or new data is imported and the automatic switching is enabled, the mode adjusts to the detected data type. You can then change the editor mode manually. If you want to keep this manually switched mode while moving through the cells, switch the button off. + ÙŠÙÙØ¹Ù‘Ù„/ÙŠÙØ¹Ø·Ù‘Ù„ هذا الزر التبديل التلقائي لوضع المحرّر. متى حدّدت خليّة جديدة أو استوردت بيانات جديدة ويÙÙØ¹Ù‘Ù„ التبديل الآلي سترى بأنّ الوضع Ø³ÙŠÙØ¶Ø¨Ø· على نوع البيانات المكتشÙ. يمكنك بعدها تغيير وضع المحرّر يدويًا. لو أردت أن يكون التبديل يدويًا عند الانتقال بين الخلايا، ÙØ¹Ø·Ù‘Ù„ هذا الزر. + + + + Auto-switch + التبديل الآلي + + + + The text editor modes let you edit plain text, as well as JSON or XML data with syntax highlighting, automatic formatting and validation before saving. + +Errors are indicated with a red squiggle underline. + ÙŠÙØªÙŠØ­ لك وضع التحرير هذا بتعديل النصوص ØµÙØ±ÙØ© كما وبيانات JSON ÙˆXML إذ يدعم إبراز الصياغة والتنسيق التحقّق التلقائيّين قبل Ø§Ù„Ø­ÙØ¸. + +ØªÙØ¹Ø±Ø¶ الأخطاء على شكل خطّ أحمر مسطّر مموّج. + + + + This Qt editor is used for right-to-left scripts, which are not supported by the default Text editor. The presence of right-to-left characters is detected and this editor mode is automatically selected. + ÙŠÙØ³ØªØ¹Ù…Ù„ محرّر «كيوت» هذا للغات المكتوبة من اليمين إلى اليسار (مثل العربيّة) إذ لا يدعمها محرّر النصوص المبدئي. لو كتبت حرو٠لغة تÙكتب من اليمين إلى اليسار، ÙØ³ØªÙƒØªØ´Ù البرمجيّة ذلك وتحدّد وضع الخليّة هذا تلقائيًا. + + + + Open preview dialog for printing the data currently stored in the cell + Ø§ÙØªØ­ مربّع حوار معاينة طباعة البيانات المخزّنة ÙÙŠ الخليّة حاليًا + + + + Auto-format: pretty print on loading, compact on saving. + التنسيق الآلي: طباعة جميلة (pretty print) عند التحميل، رصّ عند Ø§Ù„Ø­ÙØ¸. + + + + When enabled, the auto-format feature formats the data on loading, breaking the text in lines and indenting it for maximum readability. On data saving, the auto-format feature compacts the data removing end of lines, and unnecessary whitespace. + إن ÙØ¹Ù‘لت الخيار ÙØ³ØªÙنسّق ميزة التنسيق الآلي البياناتَ متى تحمّلت، ÙØªÙƒØ³Ø± النصوص إلى أسطر ÙˆØªÙØ²ÙŠØ­Ù‡Ø§ لزيادة مقروؤيتها. وعند Ø­ÙØ¸ البيانات ترصّ ميزة التنسيق الآلي البياناتَ بإزالة نهايات الأسطر ÙˆØ§Ù„Ù…Ø³Ø§ÙØ§Øª غير اللازمة. + + + + Word Wrap + Ù„ÙÙ‘ الأسطر + + + + Wrap lines on word boundaries + Ù„ÙÙÙ‘ الأسطر عند حدود الكلمات + + + + + Open in default application or browser + Ø§ÙØªØ­ ÙÙŠ التطبيق المبدئي أو المتصÙّح + + + + Open in application + Ø§ÙØªØ­ ÙÙŠ التطبيق + + + + The value is interpreted as a file or URL and opened in the default application or web browser. + ØªÙØ­Ù„ّل البرمجيّة القيمة على أنّها مل٠أو مسار ÙˆØªÙØªØ­Ù‡ ÙÙŠ التطبيق المبدئي أو ÙÙŠ متصÙّح الوب. + + + + Save file reference... + Ø§Ø­ÙØ¸ إشارة إلى الملÙ... + + + + Save reference to file + Ø§Ø­ÙØ¸ إشارة إلى الملÙ... + + + + + Open in external application + Ø§ÙØªØ­ ÙÙŠ تطبيق خارجي + + + + Autoformat + التنسيق الآلي + + + + &Export... + &صدّر... + + + + + &Import... + ا&Ø³ØªÙˆØ±ÙØ¯... + + + + + Import from file + Ø§Ø³ØªÙˆØ±ÙØ¯ من مل٠+ + + + + Opens a file dialog used to import any kind of data to this database cell. + ÙŠÙØªØ­ مربّع حوار Ù…Ù„ÙØ§Øª ÙŠÙØ³ØªØ¹Ù…Ù„ لاستيراد أيّ نوع من البيانات ÙÙŠ خليّة قاعدة البيانات هذه. + + + + Export to file + صدّر إلى مل٠+ + + + Opens a file dialog used to export the contents of this database cell to a file. + ÙŠÙØªØ­ مربّع حوار Ù…Ù„ÙØ§Øª ÙŠÙØ³ØªØ¹Ù…Ù„ لتصدير محتويات خليّة قاعدة البيانات هذه إلى ملÙ. + + + + + Print... + اطبع... + + + + Open preview dialog for printing displayed image + ÙŠÙØªØ­ مربّع حوار المعاينة لطباعة الصورة المعروضة + + + + + Ctrl+P + Ctrl+P + + + + Open preview dialog for printing displayed text + ÙŠÙØªØ­ مربّع حوار المعاينة لطباعة النص المعروض + + + + Copy Hex and ASCII + انسخ Hex وآسكي + + + + Copy selected hexadecimal and ASCII columns to the clipboard + انسخ الأعمدة الستّ‌عشرية وآسكي المحدّدة إلى Ø§Ù„Ø­Ø§ÙØ¸Ø© + + + + Ctrl+Shift+C + Ctrl+Shift+C + + + + Erases the contents of the cell + يمسح محتويات هذه الخليّة + + + + Set as &NULL + ا&ضبط على NULL + + + + This area displays information about the data present in this database cell + تعرض هذه المنطقة معلومات عن البيانات الموجودة ÙÙŠ خليّة قاعدة البيانات هذه + + + + Type of data currently in cell + نوع البيانات ÙÙŠ الخليّة حاليًا + + + + Size of data currently in table + حجم البيانات ÙÙŠ الخليّة حاليًا + + + + Apply data to cell + طبّق البيانات على الخليّة + + + + This button saves the changes performed in the cell editor to the database cell. + ÙŠØ­ÙØ¸ هذا الزر التغييرات Ø§Ù„Ù…ÙØ¬Ø±Ø§Ø© داخل محرّر الخلايا ÙÙŠ خليّة قاعدة البيانات. + + + + Apply + طبّق + + + + Choose a filename to export data + اختر اسمًا للمل٠لتصدير البيانات + + + + Type of data currently in cell: %1 Image + نوع البيانات ÙÙŠ الخليّة حاليًا: صورة %L1 + + + + %1x%2 pixel(s) + â€%L1×â€%L2 بكسل + + + + Type of data currently in cell: NULL + نوع البيانات ÙÙŠ الخليّة حاليًا: NULL + + + + + %n byte(s) + + لا بايتات + بايت واحد + بايتان + %Ln بايتات + %Ln بايتًا + %Ln بايت + + + + + + Type of data currently in cell: Text / Numeric + نوع البيانات ÙÙŠ الخليّة حاليًا: نصوص/عدد + + + + + Image data can't be viewed in this mode. + لا يمكن عرض بيانات الصور ÙÙŠ هذا الوضع. + + + + + Try switching to Image or Binary mode. + جرّب الانتقال إلى وضع â€ØµÙˆØ±â€œ أو â€Ø¨ÙŠØ§Ù†Ø§Øª ثنائيّة“. + + + + + Binary data can't be viewed in this mode. + لا يمكن عرض البيانات الثنائيّة ÙÙŠ هذا الوضع. + + + + + Try switching to Binary mode. + جربّ الانتقال إلى وضع â€Ø¨ÙŠØ§Ù†Ø§Øª ثنائيّة“. + + + + Couldn't save file: %1. + تعذّر Ø­ÙØ¸ الملÙ: %L1. + + + + The data has been saved to a temporary file and has been opened with the default application. You can now edit the file and, when you are ready, apply the saved new data to the cell editor or cancel any changes. + Ø­ÙÙØ¸Øª البيانات ÙÙŠ مل٠مؤقّت ÙˆÙÙØªØ­ ÙÙŠ التطبيق المبدئي. يمكنك الآن تحرير المل٠وتطبيق البيانات الجديدة المحÙوظة Ùيه متى أردت ÙÙŠ محرّر الخليّة، أو حتّى إلغاء تلك التغييرات. + + + + + Image files (%1) + Ù…Ù„ÙØ§Øª الصور (%L1) + + + + Binary files (*.bin) + Ø§Ù„Ù…Ù„ÙØ§Øª الثنائيّة (*.bin) + + + + Choose a file to import + اختر ملÙًا لاستيراده + + + + %1 Image + صورة %L1 + + + + Invalid data for this mode + بيانات غير صالحة ÙÙŠ هذا الوضع + + + + The cell contains invalid %1 data. Reason: %2. Do you really want to apply it to the cell? + تحتوي الخليّة بيانات %L1 غير صالحة. السبب: %L2. أمتأكّد من تطبيقها على الخليّة؟ + + + + + + %n character(s) + + لا محار٠+ محر٠واحد + Ù…Ø­Ø±ÙØ§Ù† + %Ln محار٠+ %Ln محرÙًا + %Ln محر٠+ + + + + Type of data currently in cell: Valid JSON + نوع البيانات ÙÙŠ الخليّة حاليًا: JSON صالحة + + + + Type of data currently in cell: Binary + نوع البيانات ÙÙŠ الخليّة حاليًا: بيانات ثنائيّة + + + + EditIndexDialog + + + &Name + الا&سم + + + + Order + الترتيب + + + + &Table + الج&دول + + + + Edit Index Schema + تحرير مخطّط الÙهرس + + + + &Unique + &ÙØ±ÙŠØ¯ + + + + For restricting the index to only a part of the table you can specify a WHERE clause here that selects the part of the table that should be indexed + إن أردت حصر الÙهرس على جزء من الجدول ÙØ­Ø³Ø¨ØŒ يمكنك هنا تحديد بند WHERE Ù„ÙŠÙØ­Ø¯Ù‘د جزء الجدول الذي يجب Ùهرسته + + + + Partial inde&x clause + بند Ù&هرس جزئي + + + + Colu&mns + الأ&عمدة + + + + Table column + عمود الجدول + + + + Type + النوع + + + + Add a new expression column to the index. Expression columns contain SQL expression rather than column names. + أضÙ٠عمود تعبير جديد إلى الÙهرس. تحتوي أعمدة التعابير على تعابير SQL بدل أسماء الأعمدة. + + + + Index column + عمود الÙهرس + + + + Deleting the old index failed: +%1 + ÙØ´Ù„ حذ٠الÙهرس القديم: +%L1 + + + + Creating the index failed: +%1 + ÙØ´Ù„ إنشاء الÙهرس: +%L1 + + + + EditTableDialog + + + Edit table definition + تحرير تعري٠الجدول + + + + Table + الجدول + + + + Advanced + متقدّم + + + + Make this a 'WITHOUT rowid' table. Setting this flag requires a field of type INTEGER with the primary key flag set and the auto increment flag unset. + اجعل هذا الجدول بلا معرّ٠للصÙÙˆÙ â€WITHOUT rowid“. لضبط هذه الراية تحتاج حقلًا بنوع â€Ø£Ø¹Ø¯Ø§Ø¯ صحيحة/INTEGER“ وأيضا عليك ضبط راية Ø§Ù„Ù…ÙØªØ§Ø­ الأساسي وألّا تضبط راية الزيادة الآليّة. + + + + Without Rowid + بلا معرّ٠للصÙÙˆÙ + + + + Fields + الحقول + + + + Database sche&ma + مخ&طّط قاعدة البيانات + + + + Add + أضÙÙ + + + + Remove + أزÙÙ„ + + + + Move to top + انقل للأعلى + + + + Move up + انقل لأعلى + + + + Move down + انقل لأسÙÙ„ + + + + Move to bottom + انقل للأسÙÙ„ + + + + + Name + الاسم + + + + + Type + النوع + + + + NN + NN + + + + Not null + ليس NULL + + + + PK + PK + + + + Primary key + Ù…ÙØªØ§Ø­ أساسي Primary key + + + + AI + AI + + + + Autoincrement + زيادة آليّة Auto Increment + + + + U + U + + + + + + Unique + ÙØ±ÙŠØ¯ Unique + + + + Default + المبدئي + + + + Default value + القيمة المبدئية + + + + + + Check + Ø§Ù„ÙØ­Øµ + + + + Check constraint + قيد Ø§Ù„ÙØ­Øµ Check constraint + + + + Collation + قواعد مقارنة المحار٠+ + + + + + Foreign Key + Ù…ÙØªØ§Ø­ أجنبي + + + + Constraints + القيود + + + + Add constraint + أضÙ٠قيدًا + + + + Remove constraint + أزÙÙ„ القيد + + + + Columns + الأعمدة + + + + SQL + SQL + + + + <html><head/><body><p><span style=" font-weight:600; color:#ff0000;">Warning: </span>There is something with this table definition that our parser doesn't fully understand. Modifying and saving this table might result in problems.</p></body></html> + <span style=" font-weight:600; color:#ff0000;">تحذير: </span>ثمّة خطب بتعري٠هذا الجدول تعذّر على المحلّل Ùهمه تمامًا. يمكن أن يؤدّي تعديل ÙˆØ­ÙØ¸ هذا الجدول إلى بعض المشاكل. + + + + + Primary Key + Ù…ÙØªØ§Ø­ أساسي + + + + Add a primary key constraint + أضÙ٠قيد ÙØ±Ø¶ Ù…ÙØªØ§Ø­ أساسي + + + + Add a foreign key constraint + أضÙ٠قيد ÙØ±Ø¶ Ù…ÙØªØ§Ø­ أجنبي + + + + Add a unique constraint + أضÙ٠قيد ÙØ±Ø¶ â€Ùريد“ + + + + Add a check constraint + أضÙ٠قيد ÙØ±Ø¶ â€Ùحص“ + + + + Error creating table. Message from database engine: +%1 + خطأ أثناء إنشاء الجدول. الرسالة من محرّك قواعد البيانات: +%L1 + + + + There already is a field with that name. Please rename it first or choose a different name for this field. + هناك حقل بهذا الاسم Ø¨Ø§Ù„ÙØ¹Ù„. من ÙØ¶Ù„Ùƒ غيّر اسمه أو اختر اسمًا مختلÙًا لهذا الحقل. + + + + + There can only be one primary key for each table. Please modify the existing primary key instead. + لكلّ جدول Ù…ÙØªØ§Ø­ أساسي واحد Ùقط. من ÙØ¶Ù„Ùƒ عدّل Ø§Ù„Ù…ÙØªØ§Ø­ الموجود بدل هذا الأمر. + + + + This column is referenced in a foreign key in table %1 and thus its name cannot be changed. + هذا العمود مذكور ÙÙŠ Ù…ÙØªØ§Ø­ أجنبي ÙÙŠ الجدول %L1 ولا يمكن تغيير اسمه. + + + + There is at least one row with this field set to NULL. This makes it impossible to set this flag. Please change the table data first. + ثمّة صÙÙ‘ واحد على الأقل Ø¶ÙØ¨Ø· هذا الحقل Ùيه على NULL. لهذا السبب يستحيل ضبط هذه الراية. من ÙØ¶Ù„Ùƒ غيّر بيانات الجدول أوّلًا. + + + + There is at least one row with a non-integer value in this field. This makes it impossible to set the AI flag. Please change the table data first. + ثمّة صÙÙ‘ واحد على الأقل Ø¶ÙØ¨Ø· هذا الحقل Ùيه على قيمة ليست بنوع â€Ø¹Ø¯Ø¯ صحيح“. لهذا السبب يستحيل ضبط راية الزيادة الآليّة. من ÙØ¶Ù„Ùƒ غيّر بيانات الجدول أوّلًا. + + + + Column '%1' has duplicate data. + + ÙÙŠ العمود â€%L1“ بيانات متكرّرة. + + + + + This makes it impossible to enable the 'Unique' flag. Please remove the duplicate data, which will allow the 'Unique' flag to then be enabled. + يمنع هذا ØªÙØ¹ÙŠÙ„ راية â€Ùريد“. من ÙØ¶Ù„Ùƒ أزÙÙ„ البيانات المتكرّرة كي تقدر على ØªÙØ¹ÙŠÙ„ هذه الراية. + + + + Are you sure you want to delete the field '%1'? +All data currently stored in this field will be lost. + أمتأكّد من حذ٠الحقل â€%L1“؟ +ستÙقد كل البيانات المخزّنة Ùيه حاليًا. + + + + Please add a field which meets the following criteria before setting the without rowid flag: + - Primary key flag set + - Auto increment disabled + من ÙØ¶Ù„Ùƒ أضÙ٠حقلًا ÙŠÙØ·Ø§Ø¨Ù‚ المعايير الآتية قبل ضبط راية â€Ø¨Ù„ا معرّ٠صÙÙˆÙ/rowid“: + - راية â€Ù…ÙØªØ§Ø­ أساسي“ مضبوطة + - الزيادة الآلية معطّلة + + + + ExportDataDialog + + + Export data as CSV + تصدير البيانات بنسق CSV + + + + Tab&le(s) + الج&داول + + + + Colu&mn names in first line + أسماء الأ&عمدة ÙÙŠ أوّل سطر + + + + Fie&ld separator + ÙØ§ØµÙ„ الح&قول + + + + , + , + + + + ; + ; + + + + Tab + جدولات + + + + | + | + + + + + + Other + شيء آخر + + + + &Quote character + محر٠ال&تنصيص + + + + " + " + + + + ' + ' + + + + New line characters + محر٠الأسطر الجديدة + + + + Windows: CR+LF (\r\n) + وندوز: CR+LF â€(‎\r\n) + + + + Unix: LF (\n) + ÙŠÙنكس: LF â€(‎\n) + + + + Pretty print + طباعة جميلة + + + + + Could not open output file: %1 + تعذّر ÙØªØ­ مل٠الخرج: %L1 + + + + + Choose a filename to export data + اختر اسمًا للمل٠لتصدير البيانات + + + + Export data as JSON + تصدير البيانات بنسق JSON + + + + exporting CSV + يصدّر CSV + + + + exporting JSON + يصدّر JSON + + + + Please select at least 1 table. + من ÙØ¶Ù„Ùƒ حدّد جدولًا واحدًا على الأقل. + + + + Choose a directory + اختر دليلًا + + + + Export completed. + اكتمل التصدير. + + + + ExportSqlDialog + + + Export SQL... + تصدير SQL... + + + + Tab&le(s) + الج&دول + + + + Select All + حدّد الكلّ + + + + Deselect All + ألغ٠تحديد الكلّ + + + + &Options + &خيارات + + + + Keep column names in INSERT INTO + أبق٠أسماء الأعمدة ÙÙŠ INSERT INTO + + + + Multiple rows (VALUES) per INSERT statement + أكثر من صÙÙ‘ واحد (VALUES) لكلّ Ø¥ÙØ§Ø¯Ø© INSERT + + + + Export everything + صدّر كل شيء + + + + Export schema only + صدّر المخطّط Ùقط + + + + Export data only + صدّر البيانات Ùقط + + + + Keep old schema (CREATE TABLE IF NOT EXISTS) + أبق٠المخطّط القديم (CREATE TABLE IF NOT EXISTS) + + + + Overwrite old schema (DROP TABLE, then CREATE TABLE) + اكتب على المخطّط القديم (DROP TABLEØŒ وبعدها CREATE TABLE) + + + + Please select at least one table. + من ÙØ¶Ù„Ùƒ حدّد جدولًا واحدًا على الأقل. + + + + Choose a filename to export + اختر اسمًا للمل٠لتصديره + + + + Export completed. + اكتمل التصدير. + + + + Export cancelled or failed. + إمّا أنّ التصدير Ø£Ùلغي أو أنّه ÙØ´Ù„. + + + + ExtendedScintilla + + + + Ctrl+H + Ctrl+H + + + + Ctrl+F + Ctrl+F + + + + + Ctrl+P + Ctrl+P + + + + Find... + ابحث... + + + + Find and Replace... + ابحث واستبدل... + + + + Print... + اطبع... + + + + ExtendedTableWidget + + + Use as Exact Filter + استعملها كمرشّح كما هي + + + + Containing + تحتوي على + + + + Not containing + لا تحتوي على + + + + Not equal to + لا تساوي + + + + Greater than + أكبر من + + + + Less than + أصغر من + + + + Greater or equal + أكبر من أو تساوي + + + + Less or equal + أصغر من أو تساوي + + + + Between this and... + بين هذه Ùˆ... + + + + Regular expression + تعبير نمطي + + + + Edit Conditional Formats... + حرّر التنسيقات الشرطيّة... + + + + Set to NULL + اضبطها على NULL + + + + Copy + انسخ + + + + Copy with Headers + انسخ مع الترويسات + + + + Copy as SQL + انسخ كَ†SQL + + + + Paste + ألصÙÙ‚ + + + + Print... + اطبع... + + + + Use in Filter Expression + استعملها ÙÙŠ تعبير الترشيح + + + + Alt+Del + Alt+Del + + + + Ctrl+Shift+C + Ctrl+Shift+C + + + + Ctrl+Alt+C + Ctrl+Alt+C + + + + The content of the clipboard is bigger than the range selected. +Do you want to insert it anyway? + محتوى Ø§Ù„Ø­Ø§ÙØ¸Ø© أكبر من المدى المحدّد. +أتريد إدراجه رغم ذلك؟ + + + + <p>Not all data has been loaded. <b>Do you want to load all data before selecting all the rows?</b><p><p>Answering <b>No</b> means that no more data will be loaded and the selection will not be performed.<br/>Answering <b>Yes</b> might take some time while the data is loaded but the selection will be complete.</p>Warning: Loading all the data might require a great amount of memory for big tables. + <p>لم ØªÙØ­Ù…ّل كلّ البيانات. <b>أتريد تحميل كلّ البيانات قبل تحديد كلّ الصÙÙˆÙØŸ</b><p><p>لو اخترت <b>لا</b> Ùلن ØªÙØ­Ù…ّل أيّة بيانات أخرى ولن ÙŠÙØ¬Ø±Ù‰ هذا التحديد.<br/>لو اخترت <b>نعم</b> ÙØ¹Ù„يك الانتظار وقتًا حتّى ØªÙØ­Ù…ّل البيانات، ولكن التحديد هنا سيحدث</p>تحذير: قد يطلب تحميل كلّ البيانات ذاكرة كثيرة لو كانت الجداول ضخمة. + + + + Cannot set selection to NULL. Column %1 has a NOT NULL constraint. + تعذّر ضبط التحديد على NULL. على العمود %L1 قيد â€Ù„يس NULL“. + + + + FileExtensionManager + + + File Extension Manager + مدير امتدادات Ø§Ù„Ù…Ù„ÙØ§Øª + + + + &Up + لأ&على + + + + &Down + لأ&سÙÙ„ + + + + &Add + Ø£&ضÙÙ + + + + &Remove + Ø£&زÙÙ„ + + + + + Description + الوص٠+ + + + Extensions + الامتدادات + + + + *.extension + يمكن للمستخدم تحرير هذه، ÙØ§Ù„Ø£ÙØ¶Ù„ أن تكون إنكليزية بدون محار٠يونيكود كي لا يتركها من غير قصد + *.extension + + + + FilterLineEdit + + + Filter + رشّح + + + + These input fields allow you to perform quick filters in the currently selected table. +By default, the rows containing the input text are filtered out. +The following operators are also supported: +% Wildcard +> Greater than +< Less than +>= Equal to or greater +<= Equal to or less += Equal to: exact match +<> Unequal: exact inverse match +x~y Range: values between x and y +/regexp/ Values matching the regular expression + تتيح لك مربّعات الإدخال هذه إجراء ترشيح سريع على الجدول المحدّد حاليًا. +مبدئيًا ØªÙØ±Ø´Ù‘Ø­ الصÙو٠التي تحتوي على نص الإدخال. +كما ويدعم البحث Ø§Ù„Ù…ÙØ¹Ø§Ù…لات الآتية: +% حر٠البدل +> أكبر من +< أصغر من +>= أكبر من أو يساوي +>= أصغر من أو يساوي += يساوي (Ù…ÙØ·Ø§Ø¨Ù‚Ø© تامّة) +<> لا يساوي (Ù…ÙØ·Ø§Ø¨Ù‚Ø© عكسية تامّة) +س~ص مدى: القيم بين â€Ø³â€œ Ùˆâ€Øµâ€œ +/ريجÙكس/ القيم التي ØªÙØ·Ø§Ø¨Ù‚ التعبير النمطي + + + + Clear All Conditional Formats + امسح كلّ التنسيقات الشرطيّة + + + + Use for Conditional Format + استعمله تنسيقًا شرطيًا + + + + Edit Conditional Formats... + حرّر التنسيقات الشرطيّة... + + + + Set Filter Expression + اضبط تعبير الترشيح + + + + What's This? + ما هذا؟ + + + + Is NULL + تساوي NULL + + + + Is not NULL + لا تساوي NULL + + + + Is empty + ÙØ§Ø±ØºØ© + + + + Is not empty + ليست ÙØ§Ø±ØºØ© + + + + Not containing... + لا تحتوي على... + + + + Equal to... + تساوي... + + + + Not equal to... + لا تساوي... + + + + Greater than... + أكبر من... + + + + Less than... + أصغر من... + + + + Greater or equal... + أكبر من أو تساوي... + + + + Less or equal... + أصغر من أو تساوي... + + + + In range... + ÙÙŠ المدى... + + + + Regular expression... + تعبير نمطي... + + + + FindReplaceDialog + + + Find and Replace + البحث والاستبدال + + + + Fi&nd text: + ابح&Ø« عن النص: + + + + Re&place with: + ا&ستبدله بÙâ€: + + + + Match &exact case + طابÙÙ‚ &حالة الأحر٠+ + + + Match &only whole words + طابÙÙ‚ الكلمات الكاملة &ÙØ­Ø³Ø¨ + + + + When enabled, the search continues from the other end when it reaches one end of the page + إن ÙØ¹Ù‘لته ÙØ³ÙŠÙواصل البحث من الطر٠التالي عندما يصل إلى نهاية Ø§Ù„ØµÙØ­Ø© + + + + &Wrap around + البحث يلت&ÙÙ‘ + + + + When set, the search goes backwards from cursor position, otherwise it goes forward + إن ÙØ¹Ù‘لته ÙØ³ÙŠØ¬Ø±ÙŠ Ø§Ù„Ø¨Ø­Ø« إلى خل٠مكان المؤشّر، وإلّا ÙØ¥Ù„Ù‰ أمامه + + + + Search &backwards + ابحث لل&خل٠+ + + + <html><head/><body><p>When checked, the pattern to find is searched only in the current selection.</p></body></html> + إن ÙØ¹Ù‘لته Ùلن يجري البحث على النمط Ø§Ù„Ù…ÙØ±Ø§Ø¯ إلّا ÙÙŠ التحديد الحالي. + + + + &Selection only + الت&حديد Ùقط + + + + <html><head/><body><p>When checked, the pattern to find is interpreted as a UNIX regular expression. See <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>.</p></body></html> + إن ÙØ¹Ù‘لته ÙØ³ÙŠÙتعامل مع نمط البحث على أنّه تعبير يونكس نمطي. طالع <a href="https://en.wikibooks.org/wiki/Regular_Expressions">التعابير النمطية ÙÙŠ ويكي‌كتب (بالإنجليزية)</a>. + + + + Use regular e&xpressions + استعمل الت&عابير النمطية + + + + Find the next occurrence from the cursor position and in the direction set by "Search backwards" + ابحث عن الحدوث التالي من موقع المؤشّر حسب الاتجاه الذي حدّده â€Ø§Ù„بحث للخلÙ“ + + + + &Find Next + ابحث عن ال&تالي + + + + F3 + + + + + &Replace + ا&ستبدل + + + + Highlight all the occurrences of the text in the page + Ø£Ø¨Ø±ÙØ² كلّ الحدوثات ÙÙŠ نص Ø§Ù„ØµÙØ­Ø© + + + + F&ind All + ابحث عن ال&كلّ + + + + Replace all the occurrences of the text in the page + استبدل كلّ الحدوثات ÙÙŠ نص Ø§Ù„ØµÙØ­Ø© + + + + Replace &All + اس&تبدل الكلّ + + + + The searched text was not found + لم ÙŠÙØ¹Ø«Ø± على نص البحث + + + + The searched text was not found. + لم ÙŠÙØ¹Ø«Ø± على نص البحث. + + + + The searched text was found one time. + Ø¹ÙØ«Ø± على نص البحث مرّة واحدة. + + + + The searched text was found %1 times. + Ø¹ÙØ«Ø± على نص البحث %L1 من المرّات. + + + + The searched text was replaced one time. + Ø§Ø³ØªÙØ¨Ø¯Ù„ نص البحث مرّة واحدة. + + + + The searched text was replaced %1 times. + Ø§Ø³ØªÙØ¨Ø¯Ù„ نص البحث %L1 من المرّات. + + + + ForeignKeyEditor + + + &Reset + &صÙّر + + + + Foreign key clauses (ON UPDATE, ON DELETE etc.) + بنود Ø§Ù„Ù…ÙØ§ØªÙŠØ­ الأجنبية (ON UPDATEØŒ أو ON DELETEØŒ إلخ.) + + + + ImportCsvDialog + + + Import CSV file + استيراد مل٠CSV + + + + Table na&me + ا&سم الجدول + + + + &Column names in first line + أسماء الأ&عمدة ÙÙŠ أوّل سطر + + + + Field &separator + &ÙØ§ØµÙ„ الحقول + + + + , + , + + + + ; + ; + + + + + Tab + جدولات + + + + | + | + + + + Other + شيء آخر + + + + &Quote character + محر٠الت&نصيص + + + + + Other (printable) + شيء آخر (مطبوع) + + + + + Other (code) + شيء آخر (كود) + + + + " + " + + + + ' + ' + + + + &Encoding + ال&ترميز + + + + UTF-8 + UTF-8 + + + + UTF-16 + UTF-16 + + + + ISO-8859-1 + ISO-8859-1 + + + + Trim fields? + أأقلّم الحقول؟ + + + + Separate tables + Ø§ÙØµÙ„ الجداول + + + + Advanced + متقدّم + + + + When importing an empty value from the CSV file into an existing table with a default value for this column, that default value is inserted. Activate this option to insert an empty value instead. + عند استيراد قيمة ÙØ§Ø±ØºØ© من مل٠CSV إلى جدول موجود يحمل قيمة مبدئية لهذا العمود، ØªÙØ¶Ø§Ù تلك القيمة المبدئية. ÙØ¹Ù‘Ù„ هذا الخيار لإدراج قيمة ÙØ§Ø±ØºØ© عوضًا عن ذلك. + + + + Ignore default &values + تجاهَل ال&قيم المبدئية + + + + Activate this option to stop the import when trying to import an empty value into a NOT NULL column without a default value. + ÙØ¹Ù‘Ù„ هذا الخيار لإيقا٠الاستيراد عند محاولة استيراد قيمة ÙØ§Ø±ØºØ© ÙÙŠ عمود â€Ù„يس NULL“ ليس له قيمة مبدئية. + + + + Fail on missing values + ÙŠÙØ´Ù„ الاستيراد إن كانت القيم ناقصة + + + + Disable data type detection + عطّل اكتشا٠نوع البيانات + + + + Disable the automatic data type detection when creating a new table. + عطّل الاكتشا٠الآلي لنوع البيانات عند إنشاء جدول جديد. + + + + When importing into an existing table with a primary key, unique constraints or a unique index there is a chance for a conflict. This option allows you to select a strategy for that case: By default the import is aborted and rolled back but you can also choose to ignore and not import conflicting rows or to replace the existing row in the table. + حين تستورد القيم إلى جدول موجود وله Ù…ÙØªØ§Ø­ أساسي أو قيود â€Ùريد“ أو Ùهرس â€Ùريد“، Ùهناك احتمال بحدوث تعارض. يتيح لك هذا الخيار تحديد الطريقة التي ستتّبعها البرمجيّة ÙÙŠ تلك الحالة. مبدئيًا تجهض البرمجيّة الاستيراد وترجع إلى ما كانت عليه قاعدة البيانات، ولكن يمكنك أيضًا تجاهل الصÙو٠المتعارضة وعدم استيرادها، أو حتّى استبدال الصÙÙ‘ الموجود ÙÙŠ الجدول كلّه. + + + + Abort import + Ø£Ø¬Ù‡ÙØ¶ الاستيراد + + + + Ignore row + تجاهَل الصÙÙ‘ + + + + Replace existing row + استبدل الصÙÙ‘ الموجود + + + + Conflict strategy + استراتيجيّة التعارضات + + + + + Deselect All + ألغ٠تحديد الكلّ + + + + Match Similar + طابÙÙ‚ المتشابهات + + + + Select All + حدّد الكلّ + + + + There is already a table named '%1' and an import into an existing table is only possible if the number of columns match. + هناك جدول Ø¨Ù†ÙØ³ الاسم â€%L1“ Ø¨Ø§Ù„ÙØ¹Ù„ ولا يمكن الاستيراد داخل أحد الجداول الموجودة إلّا إن تطابق عدد الأعمدة. + + + + There is already a table named '%1'. Do you want to import the data into it? + هناك جدول Ø¨Ù†ÙØ³ الاسم â€%L1“ Ø¨Ø§Ù„ÙØ¹Ù„. أتريد استيراد البيانات داخله؟ + + + + Creating restore point failed: %1 + ÙØ´Ù„ إنشاء نقطة استعادة: %L1 + + + + Creating the table failed: %1 + ÙØ´Ù„ إنشاء الجدول: %L1 + + + + importing CSV + يستورد CSV + + + + Importing the file '%1' took %2ms. Of this %3ms were spent in the row function. + أخذ استيراد المل٠â€%L1“ â€%L2 م‌ث. منها %L3 م‌ث على دالة الصÙÙ‘. + + + + Inserting row failed: %1 + ÙØ´Ù„ إدراج الصÙÙ‘: %L1 + + + + MainWindow + + + DB Browser for SQLite + متصÙّح قواعد بيانات SQLite + + + + + Database Structure + This has to be equal to the tab title in all the main tabs + بنية قاعدة البيانات + + + + This is the structure of the opened database. +You can drag SQL statements from an object row and drop them into other applications or into another instance of 'DB Browser for SQLite'. + + هذه بنية قاعدة البيانات Ø§Ù„Ù…ÙØªÙˆØ­Ø©. +يمكنك سحب Ø¥ÙØ§Ø¯Ø§Øª SQL من صÙÙ‘ ÙÙŠ الكائن وإسقاطها ÙÙŠ التطبيقات الأخرى أو إلى سيرورة أخرى من â€Ù…تصÙّح قواعد بيانات SQLite“. + + + + Un/comment block of SQL code + اجعل/لا تجعل كتلة كود SQL تعليقًا + + + + Un/comment block + اجعل/لا تجعل الكتلة تعليقًا + + + + Comment or uncomment current line or selected block of code + حوّل السطر الحالي (أو كتلة الكود المحدّدة) إلى تعليق، أو ألغ٠التحويل + + + + Comment or uncomment the selected lines or the current line, when there is no selection. All the block is toggled according to the first line. + اجعل الأسطر المحدّدة (أو الحالي Ùقط لو لم يكن هناك تحديد) تعليقًا، أو ألغ٠ذلك. يتغيّر تحويل كتلة الكود كاملةً حسب أوّل سطر Ùيها. + + + + Ctrl+/ + Ctrl+/ + + + + Stop SQL execution + أوقÙ٠تنÙيذ SQL + + + + Stop execution + أوقÙ٠التنÙيذ + + + + Stop the currently running SQL script + أوقÙ٠تنÙيذ سكربت SQL الذي يعمل حاليًا + + + + Warning: this pragma is not readable and this value has been inferred. Writing the pragma might overwrite a redefined LIKE provided by an SQLite extension. + تحذير: لا يمكن قراءة pragma هذه، ولهذا استÙنتجت هذه القيمة. قد تؤدّي كتابة pragma على تعويض Ø¥ÙØ§Ø¯Ø© LIKE Ù…ÙØ¹Ø§Ø¯ تعريÙها ÙˆÙّرها امتداد SQLite. + + + + toolBar1 + شريط الأدوات1 + + + + + Browse Data + This has to be equal to the tab title in all the main tabs + تصÙّح البيانات + + + + Export one or more table(s) to a JSON file + صدّر جدولًا أو أكثر إلى مل٠JSON + + + + + Edit Pragmas + This has to be equal to the tab title in all the main tabs + حرّر Pragmas + + + + Edit Database &Cell + تحرير &خليّة قاعدة البيانات + + + + DB Sche&ma + Ù…&خطّط قاعدة البيانات + + + + This is the structure of the opened database. +You can drag multiple object names from the Name column and drop them into the SQL editor and you can adjust the properties of the dropped names using the context menu. This would help you in composing SQL statements. +You can drag SQL statements from the Schema column and drop them into the SQL editor or into other applications. + + هذه بنية قاعدة البيانات Ø§Ù„Ù…ÙØªÙˆØ­Ø©. +يمكنك سحب عدد من أسماء الكائنات من عمود â€Ø§Ù„اسم“ وإسقاطها ÙÙŠ محرّر SQL ويمكنك ضبط خصائص تلك الأسماء Ø§Ù„Ù…ÙØ³Ù‚طة مستعملًا قائمة السياق. سيساعد هذا ÙÙŠ كتابة Ø¥ÙØ§Ø¯Ø§Øª SQL. +يمكنك سحب Ø¥ÙØ§Ø¯Ø§Øª SQL من عمود â€Ø§Ù„مخطّط“ وإسقاطها ÙÙŠ محرّر SQL أو ÙÙŠ أيّ تطبيق آخر. + + + + &Remote + الب&عيد + + + + + Execute SQL + This has to be equal to the tab title in all the main tabs + Ù†Ùّذ SQL + + + + + Execute current line + Ù†Ùّذ السطر الحالي + + + + This button executes the SQL statement present in the current editor line + ÙŠÙÙ†Ùّذ هذا الزر Ø¥ÙØ§Ø¯Ø© SQL الظاهرة ÙÙŠ سطر المحرّر الحالي + + + + Shift+F5 + Shift+F5 + + + + Open an existing database file in read only mode + Ø§ÙØªØ­ مل٠قاعدة بيانات موجود ÙÙŠ وضع القراءة Ùقط + + + + Opens the SQLCipher FAQ in a browser window + ÙŠÙØªØ­ الأسئلة الشائعة عن SQLCipher ÙÙŠ Ù†Ø§ÙØ°Ø© المتصÙّح + + + + &File + مل&Ù + + + + &Import + ا&Ø³ØªÙˆØ±ÙØ¯ + + + + &Export + &صدّر + + + + &Edit + ت&حرير + + + + &View + من&ظور + + + + &Help + Ù…&ساعدة + + + + &Tools + Ø£&دوات + + + + DB Toolbar + شريط قاعدة البيانات + + + + SQL &Log + س&جلّ SQL + + + + Show S&QL submitted by + اعرض SQL الذي Ù†&Ùّذه + + + + User + المستخدم + + + + Application + التطبيق + + + + Error Log + سجلّ الأخطاء + + + + This button clears the contents of the SQL logs + يمسح هذا الزر محتويات سجلّات SQL + + + + &Clear + ا&مسح + + + + This panel lets you examine a log of all SQL commands issued by the application or by yourself + تتيح لك هذه اللوحة ÙØ­Øµ كلّ أوامر SQL التي Ù†Ùّذها التطبيق أو المستخدم + + + + &Plot + الر&سم البياني + + + + &New Database... + قاعدة بيانات &جديدة... + + + + + Create a new database file + Ø£Ù†Ø´ÙØ¦ مل٠قاعدة بيانات جديد + + + + This option is used to create a new database file. + ÙŠÙØ³ØªØ®Ø¯Ù… هذا الخيار لإنشاء مل٠قاعدة بيانات جديد. + + + + Ctrl+N + Ctrl+N + + + + + &Open Database... + ا&ÙØªØ­ قاعدة بيانات... + + + + + + + + Open an existing database file + Ø§ÙØªØ­ مل٠قاعدة بيانات موجود + + + + + + This option is used to open an existing database file. + ÙŠÙØ³ØªØ®Ø¯Ù… هذا الخيار Ù„ÙØªØ­ مل٠قاعدة بيانات موجود. + + + + Ctrl+O + Ctrl+O + + + + &Close Database + Ø£&غلÙÙ‚ قاعدة البيانات + + + + This button closes the connection to the currently open database file + ÙŠÙØºÙ„Ù‚ هذا الزر الاتصال بمل٠قاعدة البيانات Ø§Ù„Ù…ÙØªÙˆØ­ حاليًا + + + + + Ctrl+W + Ctrl+W + + + + &Revert Changes + أرجÙ&ع التعديلات + + + + + Revert database to last saved state + Ø£Ø±Ø¬ÙØ¹ قاعدة البيانات إلى آخر حالة محÙوظة + + + + This option is used to revert the current database file to its last saved state. All changes made since the last save operation are lost. + ÙŠÙØ³ØªØ¹Ù…Ù„ هذا الخيار لإرجاع مل٠قاعدة البيانات إلى آخر حالة محÙوظة له. ستÙقد كلّ التعديلات عليه منذ آخر عملية Ø­ÙØ¸ أجريتها. + + + + &Write Changes + ا&كتب التعديلات + + + + + Write changes to the database file + اكتب التعديلات ÙÙŠ مل٠قاعدة البيانات + + + + This option is used to save changes to the database file. + ÙŠÙØ³ØªØ¹Ù…Ù„ هذا الخيار لكتابة التعديلات ÙÙŠ مل٠قاعدة البيانات. + + + + Ctrl+S + Ctrl+S + + + + Compact &Database... + Ø±ÙØµÙ‘ &قاعدة البيانات + + + + Compact the database file, removing space wasted by deleted records + Ø±ÙØµÙ‘ مل٠قاعدة البيانات، Ù…ÙØ²ÙŠÙ„ًا المساحة الضائعة بسبب حذ٠السجلّات + + + + + Compact the database file, removing space wasted by deleted records. + Ø±ÙØµÙ‘ مل٠قاعدة البيانات، Ù…ÙØ²ÙŠÙ„ًا المساحة الضائعة بسبب حذ٠السجلّات. + + + + E&xit + ا&خرج + + + + Ctrl+Q + Ctrl+Q + + + + &Database from SQL file... + &قاعدة بيانات من مل٠SQL... + + + + Import data from an .sql dump text file into a new or existing database. + Ø§Ø³ØªÙˆØ±ÙØ¯ بيانات من مل٠‎.sql نصي Ù…ÙØ±Ù‘غ إلى قاعدة بيانات جديدة أو موجودة. + + + + This option lets you import data from an .sql dump text file into a new or existing database. SQL dump files can be created on most database engines, including MySQL and PostgreSQL. + يتيح لك هذا الخيار استيراد البيانات من مل٠‎.sql نصي Ù…ÙØ±Ù‘غ إلى قاعدة بيانات جديدة أو موجودة. يمكن إنشاء Ù…Ù„ÙØ§Øª SQL Ø§Ù„Ù…ÙØ±Ù‘غة ÙÙŠ أغلب محرّكات قواعد البيانات، بما Ùيها MySQL ÙˆPostgreSQL. + + + + &Table from CSV file... + ج&دولًا من مل٠CSV... + + + + Open a wizard that lets you import data from a comma separated text file into a database table. + Ø§ÙØªØ­ مرشدًا يساعدك ÙÙŠ استيراد البيانات من مل٠نصي مقسوم بÙواصل إلى جدول قاعدة البيانات. + + + + Open a wizard that lets you import data from a comma separated text file into a database table. CSV files can be created on most database and spreadsheet applications. + Ø§ÙØªØ­ مرشدًا يساعدك ÙÙŠ استيراد البيانات من مل٠نصي مقسوم بÙواصل إلى جدول قاعدة البيانات. يمكن إنشاء Ù…Ù„ÙØ§Øª CSV ÙÙŠ أغلب تطبيقات قواعد البيانات والجداول الممتدّة. + + + + &Database to SQL file... + &قاعدة بيانات إلى مل٠SQL... + + + + Export a database to a .sql dump text file. + صدّر قاعدة بيانات إلى مل٠‎.sql نصي Ù…ÙØ±Ù‘غ. + + + + This option lets you export a database to a .sql dump text file. SQL dump files contain all data necessary to recreate the database on most database engines, including MySQL and PostgreSQL. + يتيح لك هذا الخيار تصدير قاعدة بيانات إلى مل٠‎.sql نصي Ù…ÙØ±Ù‘غ. يمكن Ù„Ù…Ù„ÙØ§Øª SQL Ø§Ù„Ù…ÙØ±Ù‘غة احتواء كلّ البيانات الضرورية لإعادة إنشاء قاعدة البيانات ÙÙŠ أغلب محرّكات قواعد البيانات، Ùما Ùيها MySQL ÙˆPostgreSQL. + + + + &Table(s) as CSV file... + الج&داول كمل٠CSV... + + + + Export a database table as a comma separated text file. + صدّر جدول قاعدة بيانات كمل٠نصي مقسوم بÙواصل. + + + + Export a database table as a comma separated text file, ready to be imported into other database or spreadsheet applications. + صدّر جدول قاعدة بيانات كمل٠نصي مقسوم بÙواصل، جاهز Ù„ÙŠÙØ³ØªÙˆØ±Ø¯ إلى تطبيقات قواعد البيانات أو الجداول الممتدّة الأخرى. + + + + &Create Table... + Ø£&Ù†Ø´ÙØ¦ جدولًا... + + + + Open the Create Table wizard, where it is possible to define the name and fields for a new table in the database + Ø§ÙØªØ­ مرشد إنشاء الجدول، حيث تستطيع تحديد اسم وحقول للجدول الجديد ÙÙŠ قاعدة البيانات + + + + &Delete Table... + ا&حذ٠الجدول... + + + + + Delete Table + احذ٠الجدول + + + + Open the Delete Table wizard, where you can select a database table to be dropped. + Ø§ÙØªØ­ مرشد حذ٠الجدول، حيث يمكنك تحديد جدول قاعدة البيانات الذي Ø³ÙŠÙØ­Ø°Ù. + + + + &Modify Table... + &عدّل الجدول... + + + + Open the Modify Table wizard, where it is possible to rename an existing table. It is also possible to add or delete fields form a table, as well as modify field names and types. + Ø§ÙØªØ­ مرشد تعديل الجدول، حيث يمكنك تغيير اسم أحد الجداول الموجودة. يمكنك أيضًا Ø¥Ø¶Ø§ÙØ© حقول أو حذÙها إلى ومن الجدول، كما وتعديل أسماء الحقول وأنواعها. + + + + Create &Index... + Ø£Ù†Ø´ÙØ¦ &Ùهرسًا... + + + + Open the Create Index wizard, where it is possible to define a new index on an existing database table. + Ø§ÙØªØ­ جدول إنشاء الÙهارس، حيث يمكنك تحديد Ùهرس جديد ÙÙŠ جدول قاعدة بيانات موجود. + + + + &Preferences... + التÙ&ضيلات... + + + + + Open the preferences window. + Ø§ÙØªØ­ Ù†Ø§ÙØ°Ø© Ø§Ù„ØªÙØ¶ÙŠÙ„ات. + + + + &DB Toolbar + شريط &قاعدة البيانات + + + + Shows or hides the Database toolbar. + يعرض أو ÙŠÙØ®ÙÙŠ شريط قاعدة البيانات.. + + + + Ctrl+T + Ctrl+T + + + + Open SQL file(s) + Ø§ÙØªØ­ Ù…Ù„ÙØ§Øª SQL + + + + This button opens files containing SQL statements and loads them in new editor tabs + ÙŠÙØªØ­ هذا الزر Ù…Ù„ÙØ§Øª تحتوي Ø¥ÙØ§Ø¯Ø§Øª SQL ويحمّلها ÙÙŠ ألسنة محرّر جديدة + + + + This button lets you save all the settings associated to the open DB to a DB Browser for SQLite project file + يتيح لك هذا الزر Ø­ÙØ¸ كلّ الإعدادات المرتبطة بقاعدة البيانات Ø§Ù„Ù…ÙØªÙˆØ­Ø© ÙÙŠ مل٠مشروع «متصÙّح قواعد بيانات SQLite» + + + + This button lets you open a DB Browser for SQLite project file + يتيح لك هذا الزر ÙØªØ­ مل٠مشروع «متصÙّح قواعد بيانات SQLite» + + + + Browse Table + تصÙّح الجدول + + + + W&hat's This? + ما Ù‡&ذا؟ + + + + Ctrl+F4 + Ctrl+F4 + + + + Shift+F1 + Shift+F1 + + + + Execute all/selected SQL + Ù†Ùّذ كلّ Ø¥ÙØ§Ø¯Ø§Øª SQL أو المحدّدة Ùقط + + + + This button executes the currently selected SQL statements. If no text is selected, all SQL statements are executed. + ÙŠÙÙ†Ùّذ هذا الزر Ø¥ÙØ§Ø¯Ø§Øª SQL المحدّدة حاليًا. إن لم تحدّد شيئًا ÙØ³ØªÙÙ†Ùّذ كلّ Ø¥ÙØ§Ø¯Ø§Øª SQL. + + + + &Load Extension... + &حمّل امتدادًا... + + + + Execute line + Ù†Ùّذ السطر + + + + &Wiki + الوي&كي + + + + F1 + + + + + Bug &Report... + Ø£Ø¨Ù„ÙØº عن علّ&Ø©... + + + + Feature Re&quest... + ا&طلب ميزة... + + + + Web&site + موقع الو&ب + + + + &Donate on Patreon... + تبرّع &عبر باتريون... + + + + Open &Project... + Ø§ÙØªØ­ Ù…&شروعًا... + + + + &Attach Database... + أر&ÙÙÙ‚ قاعدة بيانات... + + + + + Add another database file to the current database connection + أضÙ٠مل٠قاعدة بيانات آخر إلى اتصال قاعدة البيانات الحالي + + + + This button lets you add another database file to the current database connection + يتيح لك هذا الزر Ø¥Ø¶Ø§ÙØ© مل٠قاعدة بيانات آخر إلى اتصال قاعدة البيانات الحالي + + + + &Set Encryption... + ا&ضبط التعمية... + + + + SQLCipher &FAQ + Ø£&سئلة شائعة عن SQLCipher + + + + Table(&s) to JSON... + الج&دول/الجداول إلى JSON... + + + + Open Data&base Read Only... + Ø§ÙØªØ­ قاع&دة بيانات للقراءة Ùقط... + + + + Ctrl+Shift+O + Ctrl+Shift+O + + + + Save results + Ø§Ø­ÙØ¸ النتائج + + + + Save the results view + Ø§Ø­ÙØ¸ منظور النتائج + + + + This button lets you save the results of the last executed query + يتيح لك هذا الزر Ø­ÙØ¸ نتائج آخر استعلام Ù†ÙÙّذ + + + + + Find text in SQL editor + ابحث عن النصوص ÙÙŠ محرّر SQL + + + + Find + ابحث + + + + This button opens the search bar of the editor + ÙŠÙØªØ­ هذا الزر شريط البحث للمحرّر + + + + Ctrl+F + Ctrl+F + + + + + Find or replace text in SQL editor + ابحث أو استبدل النصوص ÙÙŠ محرّر SQL + + + + Find or replace + ابحث أو استبدل + + + + This button opens the find/replace dialog for the current editor tab + ÙŠÙØªØ­ هذا الزر مربّع حوار البحث والاستبدال للسان المحرّر الحالي + + + + Ctrl+H + Ctrl+H + + + + Export to &CSV + &صدّر بنسق CSV + + + + Save as &view + Ø§Ø­ÙØ¸ كمن&ظور + + + + Save as view + Ø§Ø­ÙØ¸ كمنظور + + + + Shows or hides the Project toolbar. + اعرض أو أخÙ٠شريط أدوات المشروع. + + + + Extra DB Toolbar + شريط أدوات قواعد البيانات الإضاÙÙŠ + + + + New In-&Memory Database + قاعدة بيانات جديدة ÙÙŠ ال&ذاكرة + + + + Drag && Drop Qualified Names + اسحب ÙˆØ£Ø³Ù‚ÙØ· الأسماء المؤهّلة + + + + + Use qualified names (e.g. "Table"."Field") when dragging the objects and dropping them into the editor + استخدم الأسماء المؤهّلة (مثل ‎"Table"."Field"‎) عند سحب الكائنات وإسقاطها ÙÙŠ المحرّر. + + + + Drag && Drop Enquoted Names + اسحب ÙˆØ£Ø³Ù‚ÙØ· الأسماء مقتبسةً + + + + + Use escaped identifiers (e.g. "Table1") when dragging the objects and dropping them into the editor + استخدم Ø§Ù„Ù…ÙØ¹Ø±Ù‘ÙØ§Øª مهرّبة (مثلًا "Table1") عند سحب الكائنات وإسقاطها ÙÙŠ المحرّر + + + + &Integrity Check + ÙØ­Øµ ال&سلامة + + + + Runs the integrity_check pragma over the opened database and returns the results in the Execute SQL tab. This pragma does an integrity check of the entire database. + ÙŠÙØ´ØºÙ‘Ù„ integrity_check pragma على قاعدة البيانات Ø§Ù„Ù…ÙØªÙˆØ­Ø© ÙˆÙŠÙØ¹ÙŠØ¯ النتائج ÙÙŠ لسان â€Ù†Ùّذ SQL“. ÙŠÙØ¬Ø±ÙŠ pragma ÙØ­Øµ سلامة على قاعدة البيانات كاملةً. + + + + &Foreign-Key Check + ÙØ­Øµ الم&ÙØªØ§Ø­ الأجنبي + + + + Runs the foreign_key_check pragma over the opened database and returns the results in the Execute SQL tab + ÙŠÙØ´ØºÙ‘Ù„ foreign_key_check pragma على قاعدة البيانات Ø§Ù„Ù…ÙØªÙˆØ­Ø© ÙˆÙŠÙØ¹ÙŠØ¯ النتائج ÙÙŠ لسان â€Ù†Ùّذ SQL“ + + + + &Quick Integrity Check + ÙØ­Øµ سلام&Ø© سريع + + + + Run a quick integrity check over the open DB + ÙŠÙØ´ØºÙ‘Ù„ ÙØ­Øµ سلامة سريع على قاعدة البيانات Ø§Ù„Ù…ÙØªÙˆØ­Ø© + + + + Runs the quick_check pragma over the opened database and returns the results in the Execute SQL tab. This command does most of the checking of PRAGMA integrity_check but runs much faster. + ÙŠÙØ´ØºÙ‘Ù„ quick_check pragma على قاعدة البيانات Ø§Ù„Ù…ÙØªÙˆØ­Ø© ÙˆÙŠÙØ¹ÙŠØ¯ النتائج ÙÙŠ لسان â€Ù†Ùّذ SQL“. ÙŠÙØ¬Ø±ÙŠ Ù‡Ø°Ø§ الأمر أغلب ما ØªÙØ¬Ø±ÙŠÙ‡ PRAGMA integrity_check إلّا أنّه أسرع. + + + + &Optimize + Ø­&سّن + + + + Attempt to optimize the database + حاوÙÙ„ تحسين قاعدة البيانات + + + + Runs the optimize pragma over the opened database. This pragma might perform optimizations that will improve the performance of future queries. + ÙŠÙØ´ØºÙ‘Ù„ optimize pragma على قاعدة البيانات Ø§Ù„Ù…ÙØªÙˆØ­Ø©. قد تؤدّي pragma إلى إجراء بعض التحسينات لها أن ØªÙØ­Ø³Ù‘Ù† من أداء الاستعلامات مستقبلًا. + + + + + Print + اطبع + + + + Print text from current SQL editor tab + اطبع النص من لسان محرّر SQL الحالي + + + + Open a dialog for printing the text in the current SQL editor tab + Ø§ÙØªØ­ مربّع حوار طباعة النص ÙÙŠ لسان محرّر SQL الحالي + + + + Print the structure of the opened database + اطبع بنية قاعدة البيانات Ø§Ù„Ù…ÙØªÙˆØ­Ø© + + + + Open a dialog for printing the structure of the opened database + Ø§ÙØªØ­ مربّع حوار طباعة بنية قاعدة البيانات Ø§Ù„Ù…ÙØªÙˆØ­Ø© + + + + &Save Project As... + احÙ&ظ المشروع ÙƒÙŽâ€... + + + + + + Save the project in a file selected in a dialog + Ø§Ø­ÙØ¸ المشروع ÙÙŠ مل٠تحدّده من مربّع حوار + + + + Save A&ll + Ø§Ø­ÙØ¸ ال&كلّ + + + + + + Save DB file, project file and opened SQL files + Ø§Ø­ÙØ¸ مل٠قاعدة البيانات ومل٠المشروع ÙˆÙ…Ù„ÙØ§Øª SQL Ø§Ù„Ù…ÙØªÙˆØ­Ø© + + + + Ctrl+Shift+S + Ctrl+Shift+S + + + + &Recently opened + Ø§Ù„Ù…ÙØªÙˆØ­Ø© حدي&ثًا + + + + Open &tab + Ø§ÙØªØ­ Ù„&سانًا + + + + + Project Toolbar + شريط أدوات المشروع + + + + Extra DB toolbar + شريط أدوات قواعد البيانات الإضاÙÙŠ + + + + + + Close the current database file + أغلÙÙ‚ مل٠قاعدة البيانات الحالي + + + + &About + &عن + + + + This button opens a new tab for the SQL editor + ÙŠÙØªØ­ هذا الزر لسانًا جديدًا لمحرّر SQL + + + + &Execute SQL + Ù†&Ùّذ SQL + + + + + + Save SQL file + Ø§Ø­ÙØ¸ مل٠SQL + + + + Ctrl+E + Ctrl+E + + + + Export as CSV file + صدّر كمل٠بنسق CSV + + + + Export table as comma separated values file + صدّر الجدول كمل٠نصي مقسوم بÙواصل + + + + Sa&ve Project + احÙ&ظ المشروع + + + + + Save the current session to a file + Ø§Ø­ÙØ¸ الجلسة الحالية ÙÙŠ مل٠+ + + + + Load a working session from a file + حمّل جلسة عمل من مل٠+ + + + + Save SQL file as + Ø§Ø­ÙØ¸ مل٠SQL كَ†+ + + + This button saves the content of the current SQL editor tab to a file + ÙŠØ­ÙØ¸ هذا الزر محتويات لسان محرّر SQL الحالي ÙÙŠ مل٠+ + + + &Browse Table + ت&صÙّح الجدول + + + + Copy Create statement + انسخ Ø¥ÙØ§Ø¯Ø© الإنشاء + + + + Copy the CREATE statement of the item to the clipboard + انسخ Ø¥ÙØ§Ø¯Ø© CREATE للعنصر إلى Ø§Ù„Ø­Ø§ÙØ¸Ø© + + + + Ctrl+Return + Ctrl+Return + + + + Ctrl+L + Ctrl+L + + + + + Ctrl+P + Ctrl+P + + + + Ctrl+D + Ctrl+D + + + + Ctrl+I + Ctrl+I + + + + Encrypted + معمّاة + + + + Database is encrypted using SQLCipher + قاعدة البيانات معمّاة بامتداد SQLCipher + + + + Read only + للقراءة Ùقط + + + + Database file is read only. Editing the database is disabled. + مل٠قاعدة البيانات للقراءة Ùقط. تحرير قاعدة البيانات معطّل. + + + + Database encoding + ترميز قاعدة البيانات + + + + + Choose a database file + اختر مل٠قاعدة بيانات + + + + + + Choose a filename to save under + اختر اسمًا Ù„Ù„Ù…Ù„Ù Ù„Ø­ÙØ¸Ù‡ به + + + + Error while saving the database file. This means that not all changes to the database were saved. You need to resolve the following error first. + +%1 + خطأ أثناء Ø­ÙØ¸ مل٠قاعدة البيانات. هذا يعني أنّه تعذّر Ø­ÙØ¸ كلّ التغييرات ÙÙŠ قاعدة البيانات. عليك حلّ الخطأ الآتي أوّلًا: + +%L1 + + + + Are you sure you want to undo all changes made to the database file '%1' since the last save? + أمتأكّد من التراجع عن كلّ التعديلات التي أجريتها على مل٠قاعدة البيانات â€%L1“ منذ آخر Ø­ÙØ¸ØŸ + + + + Choose a file to import + اختر ملÙًا لاستيراده + + + + Text files(*.sql *.txt);;All files(*) + Ø§Ù„Ù…Ù„ÙØ§Øª النصية(*.sql *.txt);;كلّ Ø§Ù„Ù…Ù„ÙØ§Øª(*) + + + + Do you want to create a new database file to hold the imported data? +If you answer no we will attempt to import the data in the SQL file to the current database. + أتريد إنشاء مل٠قاعدة بيانات جديد Ù„ÙŠØ­ØªÙØ¸ بالبيانات المستوردة؟ +إن كانت إجابتك â€Ù„ا“ ÙØ³Ù†Ø­Ø§ÙˆÙ„ استيراد البيانات من مل٠SQL إلى قاعدة البيانات الحالية. + + + + You are still executing SQL statements. Closing the database now will stop their execution, possibly leaving the database in an inconsistent state. Are you sure you want to close the database? + ما زلت تنÙّذ Ø¥ÙØ§Ø¯Ø§Øª SQL. بإغلاق قاعدة البيانات الآن تكون Ø£ÙˆÙ‚ÙØª التنÙيذ وقد يترك ذلك قاعدة البيانات ÙÙŠ حال غير مستقرّة. أمتأكّد من إغلاق قاعدة البيانات؟ + + + + Do you want to save the changes made to the project file '%1'? + أتريد Ø­ÙØ¸ التعديلات التي أجريتها ÙÙŠ مل٠المشروع â€%L1“؟ + + + + File %1 already exists. Please choose a different name. + المل٠%L1 موجود Ø¨Ø§Ù„ÙØ¹Ù„. من ÙØ¶Ù„Ùƒ اختر اسمًا آخر. + + + + Error importing data: %1 + خطأ أثناء استيراد البيانات: %L1 + + + + Import completed. + اكتمل الاستيراد. + + + + Delete View + احذ٠المنظور + + + + Modify View + عدّل المنظور + + + + Delete Trigger + احذ٠المحÙّز + + + + Modify Trigger + عدّل المحÙّز + + + + Delete Index + احذ٠الÙهرس + + + + Modify Index + عدّل الÙهرس + + + + Modify Table + عدّل الجدول + + + + Do you want to save the changes made to SQL tabs in a new project file? + أتريد Ø­ÙØ¸ التعديلات التي أجريتها على ألسنة SQL ÙÙŠ مل٠مشروع جديد؟ + + + + Do you want to save the changes made to the SQL file %1? + أتريد Ø­ÙØ¸ التعديلات التي أجريتها على مل٠SQL بالاسم â€%L1“؟ + + + + The statements in this tab are still executing. Closing the tab will stop the execution. This might leave the database in an inconsistent state. Are you sure you want to close the tab? + ما زلت تنÙّذ Ø¥ÙØ§Ø¯Ø§Øª SQL ÙÙŠ هذا اللسان. بإغلاق قاعدة البيانات الآن تكون Ø£ÙˆÙ‚ÙØª التنÙيذ وقد يترك ذلك قاعدة البيانات ÙÙŠ حال غير مستقرّة. أمتأكّد من إغلاق هذا اللسان؟ + + + + Could not find resource file: %1 + تعذّر العثور على مل٠الموارد: %L1 + + + + Choose a project file to open + اختر مل٠مشروع Ù„ÙØªØ­Ù‡ + + + + This project file is using an old file format because it was created using DB Browser for SQLite version 3.10 or lower. Loading this file format is still fully supported but we advice you to convert all your project files to the new file format because support for older formats might be dropped at some point in the future. You can convert your files by simply opening and re-saving them. + يستعمل مل٠المشروع هذا نسق Ù…Ù„ÙØ§Øª قديم إذ Ø£Ùنشأ باستعمال «متصÙّح قواعد بيانات SQLite» بإصدارة ٣٫١٠ أو أقل. تحميل نسق Ø§Ù„Ù…Ù„ÙØ§Øª هذا مدعوم بشكل كلي حتّى الآن، ولكنّنا ننصح بتحويل كلّ Ù…Ù„ÙØ§Øª المشاريع لديك لتستعمل النسق الجديد لأن دعم النسق القديمة قد ينتهي ÙÙŠ المستقبل. يمكنك تحويل Ù…Ù„ÙØ§ØªÙƒ Ø¨ÙØªØ­Ù‡Ø§ وإعادة Ø­ÙØ¸Ù‡Ø§ ÙØ­Ø³Ø¨. + + + + Could not open project file for writing. +Reason: %1 + تعذّر ÙØªØ­ مل٠المشروع للكتابة. +السبب: %L1 + + + + Setting PRAGMA values will commit your current transaction. +Are you sure? + سيؤّدي ضبط قيم PRAGMA إلى إيداع المعاملة الحالية. +أمتأكّد؟ + + + + Window Layout + تخطيط Ø§Ù„Ù†Ø§ÙØ°Ø© + + + + Reset Window Layout + صÙّر تخطيط Ø§Ù„Ù†Ø§ÙØ°Ø© + + + + Alt+0 + Alt+0 + + + + Simplify Window Layout + بسّط تخطيط Ø§Ù„Ù†Ø§ÙØ°Ø© + + + + Shift+Alt+0 + Shift+Alt+0 + + + + Dock Windows at Bottom + Ø§Ø±ØµÙ Ø§Ù„Ù†ÙˆØ§ÙØ° بالأسÙÙ„ + + + + Dock Windows at Left Side + Ø§Ø±ØµÙ Ø§Ù„Ù†ÙˆØ§ÙØ° على اليسار + + + + Dock Windows at Top + Ø§Ø±ØµÙ Ø§Ù„Ù†ÙˆØ§ÙØ° بالأعلى + + + + The database is currenctly busy. + قاعدة البيانات مشغولة حاليًا. + + + + Click here to interrupt the currently running query. + انقر هنا لمقاطعة الاستعلام الذي يعمل حاليًا. + + + + Could not open database file. +Reason: %1 + تعذّر ÙØªØ­ مل٠قاعدة البيانات. +السبب: %L1 + + + + In-Memory database + قاعدة بيانات ÙÙŠ الذاكرة + + + + Are you sure you want to delete the table '%1'? +All data associated with the table will be lost. + أمتأكّد من حذ٠الجدول â€%L1“؟ +ستÙقد كلّ البيانات المرتبطة بالجدول. + + + + Are you sure you want to delete the view '%1'? + أمتأكّد من حذ٠المنظور â€%L1“؟ + + + + Are you sure you want to delete the trigger '%1'? + أمتأكّد من حذ٠المحÙّز â€%L1“؟ + + + + Are you sure you want to delete the index '%1'? + أمتأكّد من حذ٠الÙهرس â€%L1“؟ + + + + Error: could not delete the table. + خطأ: تعذّر حذ٠الجدول. + + + + Error: could not delete the view. + خطأ: تعذّر حذ٠المنظور. + + + + Error: could not delete the trigger. + خطأ: تعذّر حذ٠المحÙّز. + + + + Error: could not delete the index. + خطأ: تعذّر حذ٠الÙهرس. + + + + Message from database engine: +%1 + الرسالة من محرّك قواعد البيانات: +%L1 + + + + Editing the table requires to save all pending changes now. +Are you sure you want to save the database? + تحرير الجدول يطلب Ø­ÙØ¸ كلّ التغييرات المرجأة الآن. +أمتأكّد من Ø­ÙØ¸ قاعدة البيانات؟ + + + + Error checking foreign keys after table modification. The changes will be reverted. + خطأ أثناء ÙØ­Øµ Ø§Ù„Ù…ÙØ§ØªÙŠØ­ الأجنبية بعد تعديل الجدول. Ø³ØªÙØ±Ø¬ÙŽØ¹ التغييرات. + + + + This table did not pass a foreign-key check.<br/>You should run 'Tools | Foreign-Key Check' and fix the reported issues. + لم يمرّ الجدول ÙØ­Øµ Ø§Ù„Ù…ÙØªØ§Ø­ الأجنبي.<br/>عليك تشغيل â€Ø£Ø¯ÙˆØ§Øª -> ÙØ­Øµ Ø§Ù„Ù…ÙØªØ§Ø­ الأجنبي“ وإصلاح المشاكل المذكورة. + + + + Edit View %1 + حرّر المنظور %L1 + + + + Edit Trigger %1 + حرّر المحÙّز %L1 + + + + You are already executing SQL statements. Do you want to stop them in order to execute the current statements instead? Note that this might leave the database in an inconsistent state. + أنت تنÙّذ حقًا Ø¥ÙØ§Ø¯Ø§Øª SQL. أتريد إيقاÙها لتنÙيذ Ø§Ù„Ø¥ÙØ§Ø¯Ø§Øª الحالية بدلها؟ وقد يترك ذلك قاعدة البيانات ÙÙŠ حال غير مستقرّة. + + + + -- EXECUTING SELECTION IN '%1' +-- + -- ينÙّذ التحديد ÙÙŠ â€%L1“ +-- + + + + -- EXECUTING LINE IN '%1' +-- + -- ينÙّذ السطر ÙÙŠ â€%L1“ +-- + + + + -- EXECUTING ALL IN '%1' +-- + -- ينÙّذ الكلّ ÙÙŠ â€%L1“ +-- + + + + + At line %1: + عند السطر %L1: + + + + Result: %1 + النتيجة: %L1 + + + + Result: %2 + النتيجة: %L2 + + + + Setting PRAGMA values or vacuuming will commit your current transaction. +Are you sure? + سيؤّدي ضبط قيم PRAGMA أو التنظي٠إلى إيداع المعاملة الحالية. +أمتأكّد؟ + + + + Opened '%1' in read-only mode from recent file list + ÙÙØªØ­ â€%L1“ بوضع القراءة Ùقط من قائمة Ø§Ù„Ù…Ù„ÙØ§Øª Ø§Ù„Ù…ÙØªÙˆØ­Ø© حديثًا + + + + Opened '%1' from recent file list + ÙÙØªØ­ â€%L1“ من قائمة Ø§Ù„Ù…Ù„ÙØ§Øª Ø§Ù„Ù…ÙØªÙˆØ­Ø© حديثًا + + + + &%1 %2%3 + â€&%L1 â€â€Ž%L2‎â€%L3 + + + + (read only) + (للقراءة Ùقط) + + + + Open Database or Project + Ø§ÙØªØ­ قاعدة بيانات أو مشروع + + + + Attach Database... + أرÙÙÙ‚ قاعدة بيانات... + + + + Import CSV file(s)... + Ø§Ø³ØªÙˆØ±ÙØ¯ Ù…Ù„ÙØ§Øª CSV... + + + + Select the action to apply to the dropped file(s). <br/>Note: only 'Import' will process more than one file. + + اختر الإجراء الذي تريد تطبيقه على Ø§Ù„Ù…Ù„ÙØ§Øª التي Ø£Ùلتّها. <br/>لاحظ أنّ خيار â€Ø§Ø³ØªÙˆØ±Ùد“ هو الوحيد الذي Ø³ÙŠÙØ¹Ø§Ù„ج Ø§Ù„Ù…Ù„ÙØ§Øª المتعدّدة. + اختر الإجراء الذي تريد تطبيقه على المل٠الذي Ø£Ùلتّه. <br/>لاحظ أنّ خيار â€Ø§Ø³ØªÙˆØ±Ùد“ هو الوحيد الذي Ø³ÙŠÙØ¹Ø§Ù„ج Ø§Ù„Ù…Ù„ÙØ§Øª المتعدّدة. + اختر الإجراء الذي تريد تطبيقه على الملÙين الذين Ø£Ùلتّهما. <br/>لاحظ أنّ خيار â€Ø§Ø³ØªÙˆØ±Ùد“ هو الوحيد الذي Ø³ÙŠÙØ¹Ø§Ù„ج Ø§Ù„Ù…Ù„ÙØ§Øª المتعدّدة. + اختر الإجراء الذي تريد تطبيقه على Ø§Ù„Ù…Ù„ÙØ§Øª التي Ø£Ùلتّها. <br/>لاحظ أنّ خيار â€Ø§Ø³ØªÙˆØ±Ùد“ هو الوحيد الذي Ø³ÙŠÙØ¹Ø§Ù„ج Ø§Ù„Ù…Ù„ÙØ§Øª المتعدّدة. + اختر الإجراء الذي تريد تطبيقه على Ø§Ù„Ù…Ù„ÙØ§Øª التي Ø£Ùلتّها. <br/>لاحظ أنّ خيار â€Ø§Ø³ØªÙˆØ±Ùد“ هو الوحيد الذي Ø³ÙŠÙØ¹Ø§Ù„ج Ø§Ù„Ù…Ù„ÙØ§Øª المتعدّدة. + اختر الإجراء الذي تريد تطبيقه على Ø§Ù„Ù…Ù„ÙØ§Øª التي Ø£Ùلتّها. <br/>لاحظ أنّ خيار â€Ø§Ø³ØªÙˆØ±Ùد“ هو الوحيد الذي Ø³ÙŠÙØ¹Ø§Ù„ج Ø§Ù„Ù…Ù„ÙØ§Øª المتعدّدة. + + + + + Do you want to save the changes made to SQL tabs in the project file '%1'? + أتريد Ø­ÙØ¸ التعديلات التي أجريتها على ألسنة SQL ÙÙŠ مل٠المشروع â€%L1“؟ + + + + Project saved to file '%1' + Ø­ÙÙØ¸ المشروع ÙÙŠ المل٠â€%L1“ + + + + This action will open a new SQL tab with the following statements for you to edit and run: + ÙŠÙØªØ­ هذا الإجراء لسان SQL جديد يحتوي Ø§Ù„Ø¥ÙØ§Ø¯Ø§Øª الآتية لتحرّرها وتنÙّذها: + + + + Busy (%1) + مشغولة (%L1) + + + + Rename Tab + غيّر اسم اللسان + + + + Duplicate Tab + كرّر اللسان + + + + Close Tab + أغلÙÙ‚ اللسان + + + + Opening '%1'... + ÙŠÙØªØ­ â€%L1“... + + + + There was an error opening '%1'... + خطأ أثناء ÙØªØ­ â€%L1“... + + + + Value is not a valid URL or filename: %1 + القيمة ليست عنوانًا ولا اسم مل٠صالح: %L1 + + + + %1 rows returned in %2ms + Ø£ÙØ¹ÙŠØ¯ من الصÙÙˆÙ %L1 خلال %L2 م‌ث + + + + Choose text files + اختر Ù…Ù„ÙØ§Øª نصية + + + + Import completed. Some foreign key constraints are violated. Please fix them before saving. + اكتمل الاستيراد. انتÙهكت بعض قيود Ø§Ù„Ù…ÙØªØ§Ø­ الأجنبي. من ÙØ¶Ù„Ùƒ Ø£ØµÙ„ÙØ­Ù‡Ø§ قبل Ø§Ù„Ø­ÙØ¸. + + + + Select SQL file to open + اختر مل٠SQL Ù„ÙØªØ­Ù‡ + + + + Select file name + اختر اسم المل٠+ + + + Select extension file + اختر مل٠الامتداد + + + + Extension successfully loaded. + نجح تحميل الامتداد. + + + + Error loading extension: %1 + خطأ أثناء تحميل الامتداد: %L1 + + + + + Don't show again + لا تعرض ثانيةً + + + + New version available. + تتوÙّر إصدارة جديدة. + + + + A new DB Browser for SQLite version is available (%1.%2.%3).<br/><br/>Please download at <a href='%4'>%4</a>. + تتوÙّر إصدارة جديدة من «متصÙّح قواعد بيانات SQLite» â€(%L1Ù«â€%L2Ù«â€%L3).<br/><br/>من ÙØ¶Ù„Ùƒ نزّلها من <a href='%4'>%L4</a>. + + + + Collation needed! Proceed? + قواعد مقارنة المحار٠مطلوبة! أنتابع؟ + + + + A table in this database requires a special collation function '%1' that this application can't provide without further knowledge. +If you choose to proceed, be aware bad things can happen to your database. +Create a backup! + يحتاج أحد الجداول ÙÙŠ قاعدة البيانات هذه دالة قواعد مقارنة المحار٠Collation الخاصّة â€%L1“ والتي لا يستطيع البرنامج توÙيرها دون معلومات أخرى. +احذر إن اخترت المتابعة، Ùقد تحدث أمور غير حسنة لقاعدة البيانات. +Ø®ÙØ° نسخة احتياطيّة! + + + + creating collation + ÙŠÙنشئ قواعد مقارنة المحار٠+ + + + Set a new name for the SQL tab. Use the '&&' character to allow using the following character as a keyboard shortcut. + ضع اسمًا جديدًا للسان SQL. استخدم محر٠â€&&“ Ù„ÙŠÙØªØ§Ø­ استخدام المحر٠الذي يليه كاختصار لوحة Ù…ÙØ§ØªÙŠØ­. + + + + Please specify the view name + من ÙØ¶Ù„Ùƒ اختر اسم المنظور + + + + There is already an object with that name. Please choose a different name. + هناك كائن Ø¨Ù†ÙØ³ الاسم. من ÙØ¶Ù„Ùƒ اختر اسمًا آخر. + + + + View successfully created. + نجح إنشاء المنظور. + + + + Error creating view: %1 + خطأ أثناء إنشاء المنظور: %L1 + + + + This action will open a new SQL tab for running: + Ø³ÙŠÙØªØ­ هذا الإجراء لسان SQL جديد لتشغيل: + + + + Press Help for opening the corresponding SQLite reference page. + انقر â€Ù…ساعدة“ Ù„ÙØªØ­ ØµÙØ­Ø© SQLite المرجعية المناسبة. + + + + DB Browser for SQLite project file (*.sqbpro) + مل٠مشروع «متصÙّح قواعد بيانات SQLite» â€(*.sqbpro) + + + + Execution finished with errors. + اكتمل التنÙيذ وحدثت أخطاء. + + + + Execution finished without errors. + اكتمل التنÙيذ دون أخطاء. + + + + NullLineEdit + + + Set to NULL + اضبطه على NULL + + + + Alt+Del + Alt+Del + + + + PlotDock + + + Plot + رسم بياني + + + + <html><head/><body><p>This pane shows the list of columns of the currently browsed table or the just executed query. You can select the columns that you want to be used as X or Y axis for the plot pane below. The table shows detected axis type that will affect the resulting plot. For the Y axis you can only select numeric columns, but for the X axis you will be able to select:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Date/Time</span>: strings with format &quot;yyyy-MM-dd hh:mm:ss&quot; or &quot;yyyy-MM-ddThh:mm:ss&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Date</span>: strings with format &quot;yyyy-MM-dd&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Time</span>: strings with format &quot;hh:mm:ss&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Label</span>: other string formats. Selecting this column as X axis will produce a Bars plot with the column values as labels for the bars</li><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Numeric</span>: integer or real values</li></ul><p>Double-clicking the Y cells you can change the used color for that graph.</p></body></html> + تعرض هذه اللوحة قائمة الأعمدة للمجدول الذي تتصÙّحه حاليًا أو للاستعلام الذي Ù†ÙÙّذ حديثًا. يمكنك تحديد الأعمدة التي تريد استخدامها كمحاور س أو ص للوحة الرسم البياني أدناه. يعرض الجدول نوع المحور المكتش٠والذي سيؤثّر على الرسم البياني الناتج. يمكنك تحديد الأعمدة العددية Ùقط لمحور ص، عكس محور س حيث يمكنك تحديد:<ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">تاريخ/وقت</span>: السلاسل النصية التي لها التنسيق â€yyyy-MM-dd hh:mm:ss“ أو â€yyyy-MM-ddThh:mm:ss“</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">تاريخ</span>: السلاسل النصية التي لها التنسيق â€yyyy-MM-dd“</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">وقت</span>: السلاسل النصّية التي لها التنسيق â€hh:mm:ss“</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">لصيقة</span>: السلاسل النصية التي لها تنسيقات أخرى. تحديد هذا العمود كمحور x سيÙنتج رسم بياني بأشرطة حيث قيم الأعمدة ستكون لصيقات للأشرطة</li><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">عدد</span>: قيم عددية صحيحة أو حقيقية</li></ul>بنقر خلايا ص مزدوجًا يمكنك تغيير اللون المستخدم لذلك الرسم. + + + + Columns + الأعمدة + + + + X + س + + + + Y1 + ص1 + + + + Y2 + ص2 + + + + Axis Type + نوع المحور + + + + Here is a plot drawn when you select the x and y values above. + +Click on points to select them in the plot and in the table. Ctrl+Click for selecting a range of points. + +Use mouse-wheel for zooming and mouse drag for changing the axis range. + +Select the axes or axes labels to drag and zoom only in that orientation. + هنا تجد الرسم البياني المرسوم عند تحديد قيم x Ùˆ y أعلاه. + +انقر النقاط لتحديدها ÙÙŠ الرسم البياني والجدول. انقر مع Ctrl لتحديد مدًى من النقاط. + +استخدم عجلة Ø§Ù„ÙØ£Ø±Ø© للتقريب والإبعاد، وحرّك Ø§Ù„ÙØ£Ø±Ø© لتغيير مدى المحور. + +اختر المحاور أو لصيقات المحاور لتحريكها أو قرّب/بعّد بذاك الاتجاه ÙØ­Ø³Ø¨. + + + + Line type: + نوع الخطوط: + + + + + None + بلا + + + + Line + خط + + + + StepLeft + عتبة يسرى + + + + StepRight + عتبة يمنى + + + + StepCenter + عتبة وسطى + + + + Impulse + نبض + + + + Point shape: + شكل النقط: + + + + Cross + علامة ضرب + + + + Plus + علامة جمع + + + + Circle + دائرة + + + + Disc + قرص + + + + Square + مربّع + + + + Diamond + معيّن + + + + Star + نجمة + + + + Triangle + مثلّث + + + + TriangleInverted + مثلّث مقلوب + + + + CrossSquare + علامة ضرب ÙÙŠ مربّع + + + + PlusSquare + علامة جمع ÙÙŠ مربّع + + + + CrossCircle + علامة ضرب ÙÙŠ دائرة + + + + PlusCircle + علامة جمع ÙÙŠ دائرة + + + + Peace + رمز السلام + + + + <html><head/><body><p>Save current plot...</p><p>File format chosen by extension (png, jpg, pdf, bmp)</p></body></html> + <p>Ø§Ø­ÙØ¸ الرسم البياني الحالي...</p><p>نسق المل٠يحدّده الامتداد (png Ùˆjpg Ùˆpdf Ùˆbmp)</p> + + + + Save current plot... + Ø§Ø­ÙØ¸ الرسم البياني الحالي... + + + + + Load all data and redraw plot + حمّل كلّ البيانات ÙˆØ£Ø¹ÙØ¯ رسم الرسم البياني + + + + + + Row # + رقم الص٠+ + + + Copy + انسخ + + + + Print... + اطبع... + + + + Show legend + اعرض Ù…ÙØªØ§Ø­ الرسم + + + + Stacked bars + أشرطة مرصوصة + + + + Date/Time + تاريخ/وقت + + + + Date + تاريخ + + + + Time + وقت + + + + + Numeric + عدد + + + + Label + لصيقة + + + + Invalid + غير صالح + + + + Load all data and redraw plot. +Warning: not all data has been fetched from the table yet due to the partial fetch mechanism. + حمّل كلّ البيانات ÙˆØ£Ø¹ÙØ¯ رسم الرسم البياني. +تحذير: لم ØªÙØ¬Ù„ب كلّ البيانات من الجدول بسبب استعمال آليّة جلب جزئية. + + + + Choose an axis color + اختر لونًا للمحور + + + + Choose a filename to save under + اختر اسمًا Ù„Ù„Ù…Ù„Ù Ù„Ø­ÙØ¸Ù‡ + + + + PNG(*.png);;JPG(*.jpg);;PDF(*.pdf);;BMP(*.bmp);;All Files(*) + PNG(*.png);;JPG(*.jpg);;PDF(*.pdf);;BMP(*.bmp);;كلّ Ø§Ù„Ù…Ù„ÙØ§Øª(*) + + + + There are curves in this plot and the selected line style can only be applied to graphs sorted by X. Either sort the table or query by X to remove curves or select one of the styles supported by curves: None or Line. + توجد منحنيات ÙÙŠ هذا الرسم البياني ولا يمكن تطبيق نمط الخطوط المحدّد إلّا على الرسوم البيانية Ø§Ù„Ù…ÙØ±ÙˆØ²Ø© حسب س. إمّا أن ØªÙØ±Ø² الجدول أو الاستعلام حسب س لإزالة المنحنيات أو تحديد أحد الأنماط التي تدعمها المنحنيات: â€Ø¨Ù„ا“ أو â€Ø®Ø·â€œ. + + + + Loading all remaining data for this table took %1ms. + أخذ تحميل كلّ البيانات الباقية لهذا الجدول %L1 م‎ث. + + + + PreferencesDialog + + + Preferences + Ø§Ù„ØªÙØ¶ÙŠÙ„ات + + + + &General + &عام + + + + Remember last location + تذكّر آخر مكان + + + + Always use this location + استخدم هذا المكان دائمًا + + + + Remember last location for session only + تذكّر آخر مكان لهذه الجلسة Ùقط + + + + + + ... + ... + + + + Default &location + الم&كان المبدئي + + + + Lan&guage + الل&غة + + + + Automatic &updates + الت&حديثات الآلية + + + + + + + + + + + + enabled + Ù…ÙØ¹Ù‘لة + + + + Show remote options + اعرض خيارات البعيد + + + + &Database + &قاعدة البيانات + + + + Database &encoding + &ترميز قاعدة البيانات + + + + Open databases with foreign keys enabled. + Ø§ÙØªØ­ قواعد البيانات ÙˆØ§Ù„Ù…ÙØ§ØªÙŠØ­ الأجنبية Ù…ÙØ¹Ù‘لة. + + + + &Foreign keys + الم&ÙØ§ØªÙŠØ­ الأجنبية + + + + Remove line breaks in schema &view + أزÙÙ„ كاسرات الأسطر ÙÙŠ من&ظور المخطّط + + + + Prefetch block si&ze + &حجم الكتلة لجلبها مسبقًا + + + + SQ&L to execute after opening database + Ø¥&ÙØ§Ø¯Ø© SQL لتÙÙ†Ùّذ بعد ÙØªØ­ قاعدة البيانات + + + + Default field type + نوع الحقول المبدئي + + + + Data &Browser + مت&صÙّح البيانات + + + + Font + الخط + + + + &Font + ال&خط + + + + Content + المحتوى + + + + Symbol limit in cell + أقصى عدد من الرموز ÙÙŠ كلّ خليّة + + + + NULL + NULL + + + + Regular + العادية + + + + Binary + البيانات الثنائيّة + + + + Background + الخلÙية + + + + Filters + المرشّحات + + + + Threshold for completion and calculation on selection + عتبة إكمال النصوص والحساب + + + + Show images in cell + اعرض الصور ÙÙŠ الخلايا + + + + Enable this option to show a preview of BLOBs containing image data in the cells. This can affect the performance of the data browser, however. + ÙØ¹Ù‘Ù„ هذا الخيار لعرض معاينة كائنات BLOB التي Ùيها بيانات صور داخل الخلايا. ولكن يمكن أن يؤثّر هذا على أداء متصÙّح البيانات. + + + + Escape character + محر٠الهروب + + + + Delay time (&ms) + وقت التأخير (&م‌ث) + + + + Set the waiting time before a new filter value is applied. Can be set to 0 for disabling waiting. + اضبط وقت انتظار قبل تطبيق قيمة المرشّح الجديدة. يمكن ضبطه إلى القيمة صÙÙØ± لتعطيل الانتظار. + + + + &SQL + Ù…&حرّر SQL + + + + Settings name + الاسم ÙÙŠ الإعدادات + + + + Context + السياق + + + + Colour + اللون + + + + Bold + ثخين + + + + Italic + مائل + + + + Underline + مسطّر + + + + Keyword + الكلمات Ø§Ù„Ù…ÙØªØ§Ø­ÙŠØ© + + + + Function + الدوال + + + + Table + الجداول + + + + Comment + التعليقات + + + + Identifier + Ø§Ù„Ù…Ø¹Ø±Ù‘ÙØ§Øª + + + + String + السلاسل النصية + + + + Current line + السطر الحالي + + + + SQL &editor font size + حجم الخط ÙÙŠ Ù…&حرّر SQL + + + + Tab size + حجم التبويبات + + + + SQL editor &font + &خط محرّر SQL + + + + Error indicators + مؤشّرات الأخطاء + + + + Hori&zontal tiling + التراتب Ø£Ù&قيًا + + + + If enabled the SQL code editor and the result table view are shown side by side instead of one over the other. + إن ÙØ¹Ù‘لته ÙØ³ØªØ±Ù‰ محرّر أكواد SQL ومنظور جدول النتائج جنبًا إلى جنب بدلًا من أن يكونان Ùوق بعض. + + + + Code co&mpletion + Ø¥&كمال الكود + + + + Toolbar style + نمط شريط الأدوات + + + + + + + + Only display the icon + اعرض الأيقونة ÙØ­Ø³Ø¨ + + + + + + + + Only display the text + اعرض النص ÙØ­Ø³Ø¨ + + + + + + + + The text appears beside the icon + يظهر النص بجانب الأيقونة + + + + + + + + The text appears under the icon + يظهر النص أسÙÙ„ الأيقونة + + + + + + + + Follow the style + اتبع النمط + + + + DB file extensions + امتدادات Ù…Ù„ÙØ§Øª قواعد البيانات + + + + Manage + Ø£Ø¯ÙØ± + + + + Main Window + Ø§Ù„Ù†Ø§ÙØ°Ø© الرئيسية + + + + Database Structure + بنية قاعدة البيانات + + + + Browse Data + تصÙّح البيانات + + + + Execute SQL + Ù†Ùّذ SQL + + + + Edit Database Cell + حرّر خليّة قاعدة البيانات + + + + When this value is changed, all the other color preferences are also set to matching colors. + ØªÙØ¶Ø¨Ø· كلّ ØªÙØ¶ÙŠÙ„ات الألوان الأخرى (متى تغيّر هذا الخيار) إلى الألوان Ø§Ù„Ù…ÙØ·Ø§Ø¨Ù‚Ø© للنمط. + + + + Follow the desktop style + اتبع نمط سطح المكتب + + + + Dark style + النمط الداكن + + + + Application style + نمط البرمجيّة + + + + This sets the font size for all UI elements which do not have their own font size option. + يضبط هذا حجم خط كلّ عناصر الواجهة التي لا تحدّد Ù„Ù†ÙØ³Ù‡Ø§ حجم خط. + + + + Font size + حجم الخط + + + + When enabled, the line breaks in the Schema column of the DB Structure tab, dock and printed output are removed. + إن ÙØ¹Ù‘لته ÙØ³ØªÙزال ÙƒØ§Ø³ÙØ±Ø§Øª الأسطر ÙÙŠ عمود â€Ø§Ù„مخطّط“ ÙÙŠ لسان â€Ø¨Ù†ÙŠØ© قاعدة البيانات“ كما والرصي٠والخرج المطبوع. + + + + Database structure font size + حجم خط بنية قاعدة البيانات + + + + Font si&ze + &حجم الخط + + + + This is the maximum number of items allowed for some computationally expensive functionalities to be enabled: +Maximum number of rows in a table for enabling the value completion based on current values in the column. +Maximum number of indexes in a selection for calculating sum and average. +Can be set to 0 for disabling the functionalities. + هذا أقصى عدد من العناصر المسموحة لإجراء مزايا الحساب الثقيلة من عدم ذلك. +أي أقصى عدد من الصÙÙˆÙ ÙÙŠ الجدول Ù„ØªÙØ¹ÙŠÙ„ إكمال القيم حسب القيم الموجودة ÙÙŠ العمود. +وأقصى عدد من الÙهارس ÙÙŠ التحديد لحساب المجموع والمتوسّط. +يمكنك ضبطه على صÙÙØ± لتعطيل الميزة. + + + + This is the maximum number of rows in a table for enabling the value completion based on current values in the column. +Can be set to 0 for disabling completion. + هذا أقصى عدد من الصÙÙˆÙ ÙÙŠ كلّ جدول Ù„ØªÙØ¹ÙŠÙ„ إكمال القيمة حسب البيانات الحالية ÙÙŠ العمود. +يمكن ضبطه على ØµÙØ± لتعطيل الإكمال. + + + + Field display + عرض الحقول + + + + Displayed &text + ال&نص المعروض + + + + + + + + + Click to set this color + انقر لضبط هذا اللون + + + + Text color + لون النص + + + + Background color + لون الخلÙية + + + + Preview only (N/A) + معاينة Ùقط (غير متوÙّر) + + + + Foreground + الأمامية + + + + SQL &results font size + حجم خط Ù†&تائج SQL + + + + &Wrap lines + Ù„Ù&ÙÙ‘ الأسطر + + + + Never + أبدًا + + + + At word boundaries + عند حدود الكلمات + + + + At character boundaries + عند حدود المحار٠+ + + + At whitespace boundaries + عند حدود Ø§Ù„Ù…Ø³Ø§ÙØ§Øª + + + + &Quotes for identifiers + &علامات التنصيص Ù„Ù„Ù…ÙØ¹Ø±Ù‘ÙØ§Øª + + + + Choose the quoting mechanism used by the application for identifiers in SQL code. + اختر آليّة التنصيص التي سيستخدمها التطبيق Ù„Ù„Ù…ÙØ¹Ø±Ù‘ÙØ§Øª ÙÙŠ كود SQL. + + + + "Double quotes" - Standard SQL (recommended) + "علامات تنصيص مزدوجة" - SQL القياسية (مستحسن) + + + + `Grave accents` - Traditional MySQL quotes + `نبر الإطالة` - علامات اقتباس MySQL التقليدية + + + + [Square brackets] - Traditional MS SQL Server quotes + [أقواس مربّعة] - علامات تنصيص خادوم SQL Ù„ÙÙ…Ø§ÙŠÙƒØ±ÙˆØ³ÙˆÙØª التقليدي + + + + Keywords in &UPPER CASE + الكلمات Ø§Ù„Ù…ÙØªØ§Ø­ÙŠØ© &كبيرة الحالة + + + + When set, the SQL keywords are completed in UPPER CASE letters. + إن ÙØ¹Ù‘لته ÙØ³ÙŠØ¬Ø±ÙŠ Ø¥ÙƒÙ…Ø§Ù„ كلمات SQL Ø§Ù„Ù…ÙØªØ§Ø­ÙŠÙ‘Ø© بالأحر٠وحالتها كبيرة. + + + + When set, the SQL code lines that caused errors during the last execution are highlighted and the results frame indicates the error in the background + إن ÙØ¹Ù‘لته ÙØ³ØªÙبرز الأسطر ÙÙŠ كود SQL التي تسبّبت بأخطاء أثناء آخر تنÙيذ ÙˆØ³ÙŠÙØ´ÙŠØ± إطار النتائج إلى الخطأ ÙÙŠ الخلÙية + + + + Close button on tabs + أزرار إغلاق على الألسنة + + + + If enabled, SQL editor tabs will have a close button. In any case, you can use the contextual menu or the keyboard shortcut to close them. + إن ÙØ¹Ù‘لته ÙØ³ØªØ¹Ø±Ø¶ ألسنة محرّر SQL زرّ إغلاق. وبغضّ النظر عن هذا الخيار، يمكنك استعمال قائمة السياق أو اختصار لوحة Ø§Ù„Ù…ÙØ§ØªÙŠØ­ لإغلاق تلك الألسنة. + + + + &Extensions + الامت&دادات + + + + Select extensions to load for every database: + حدّد الامتدادات Ù„ØªÙØ­Ù…ّل لكلّ قاعدة بيانات: + + + + Add extension + أضÙ٠امتدادًا + + + + Remove extension + أزÙÙ„ الامتداد + + + + <html><head/><body><p>While supporting the REGEXP operator SQLite doesn't implement any regular expression<br/>algorithm but calls back the running application. DB Browser for SQLite implements this<br/>algorithm for you to let you use REGEXP out of the box. However, as there are multiple possible<br/>implementations of this and you might want to use another one, you're free to disable the<br/>application's implementation and load your own by using an extension. Requires restart of the application.</p></body></html> + مع أنّ معامل REGEX مدعوم، إلّا أنّ SQLITE ليس Ùيها أية خوارزمية تعابير نمطية Ù…Ùنجزة،<br/>بل تنادي التطبيق الجاري. ينÙّذ «متصÙّح قواعد بيانات SQLite» هذه الخوارزمية لك<br/>لتستعمل REGEXP دون عناء. مع ذلك، يختل٠تنÙيذ هذه الميزة ولربّما تحتاج استعمال<br/>واحدة أخرى، لذا ÙØ£Ù†Øª حرّ ÙÙŠ تعطيل طريقة التطبيق ÙÙŠ التنÙيذ وتحميل أيّ من تلك باستعمال<br/>إحدى الامتدادات. إعادة تشغيل التطبيق مطلوبة. + + + + Disable Regular Expression extension + عطّل ملحقة العبارات النمطية + + + + <html><head/><body><p>SQLite provides an SQL function for loading extensions from a shared library file. Activate this if you want to use the <span style=" font-style:italic;">load_extension()</span> function from SQL code.</p><p>For security reasons, extension loading is turned off by default and must be enabled through this setting. You can always load extensions through the GUI, even though this option is disabled.</p></body></html> + توÙّر SQLite دالة SQL لتحميل الامتدادات من مل٠مكتبة مشتركة. ÙØ¹Ù‘Ù„ هذا إن أردت استعمال دالة <span style=" font-style:italic;">load_extension()‎</span> من كود SQL.</p><p>لأسباب أمنية، تحميل الامتداد معطّل مبدئيًا ويجب ØªÙØ¹ÙŠÙ„Ù‡ بهذا الإعداد. يمكنك دائمًا تحميل الامتدادات عبر الواجهة الرسومية، حتى لو كان هذا الخيار معطّلًا. + + + + Allow loading extensions from SQL code + اسمح بتحميل الامتدادات من كود SQL + + + + Remote + البعيد + + + + CA certificates + شهادات سلطة الشهادات + + + + Proxy + الوسيط + + + + Configure + اضبط + + + + + Subject CN + اش موضوع التعمية + + + + Common Name + الاسم الشائع + + + + Subject O + المنظّمة موضوع التعمية + + + + Organization + المنظّمة + + + + + Valid from + صالحة من + + + + + Valid to + صالحة حتى + + + + + Serial number + الرقم التسلسلي + + + + Your certificates + شهاداتك + + + + File + المل٠+ + + + Subject Common Name + الاسم الشائع لموضوع التعمية + + + + Issuer CN + اش Ø§Ù„Ù…ÙØµØ¯Ùر + + + + Issuer Common Name + الاسم الشائع Ù„Ù„Ù…ÙØµØ¯Ùر + + + + Clone databases into + استنسخ قواعد البيانات إلى + + + + + Choose a directory + اختر دليلًا + + + + The language will change after you restart the application. + ستتغيّر اللغة بعد إعادة تشغيل التطبيق. + + + + Select extension file + اختر مل٠الامتداد + + + + Extensions(*.so *.dylib *.dll);;All files(*) + الامتدادات(*.so *.dylib *.dll);;كلّ Ø§Ù„Ù…Ù„ÙØ§Øª(*) + + + + Import certificate file + Ø§Ø³ØªÙˆØ±ÙØ¯ مل٠شهادة + + + + No certificates found in this file. + لم ØªÙØ¹Ø«Ø± على شهادات ÙÙŠ هذا الملÙ. + + + + Are you sure you want do remove this certificate? All certificate data will be deleted from the application settings! + أمتأكّد من إزالة هذه الشهادة؟ Ø³ØªÙØ­Ø°Ù كلّ بيانات الشهادة من إعدادات التطبيق! + + + + Are you sure you want to clear all the saved settings? +All your preferences will be lost and default values will be used. + أمتأكّد من مسح كلّ الإعدادات المحÙوظة؟ +ستÙقد كلّ Ø§Ù„ØªÙØ¶ÙŠÙ„ات لديك ÙˆØ³ØªÙØ³ØªØ¹Ù…Ù„ القيم المبدئية. + + + + ProxyDialog + + + Proxy Configuration + ضبط الوسيط + + + + Pro&xy Type + &نوع الوسيط + + + + Host Na&me + ا&سم Ø§Ù„Ù…ÙØ¶ÙŠÙ + + + + Port + Ø§Ù„Ù…Ù†ÙØ° + + + + Authentication Re&quired + الاستيثاق Ù…&طلوب + + + + &User Name + اسم المست&خدم + + + + Password + كلمة السر + + + + None + بلا وسيط + + + + System settings + إعدادات النظام + + + + HTTP + HTTP + + + + Socks v5 + Socks v5 + + + + QObject + + + Error importing data + خطأ ÙÙŠ استيراد البيانات + + + + from record number %1 + من السجلّ رقم %L1 + + + + . +%1 + . +%L1 + + + + Importing CSV file... + يستورد مل٠CSV... + + + + Cancel + ألغ٠+ + + + All files (*) + كلّ Ø§Ù„Ù…Ù„ÙØ§Øª (*) + + + + SQLite database files (*.db *.sqlite *.sqlite3 *.db3) + Ù…Ù„ÙØ§Øª قواعد بيانات SQLite â€(*.db *.sqlite *.sqlite3 *.db3) + + + + Left + يسار + + + + Right + يمين + + + + Center + وسط + + + + Justify + ضبط + + + + SQLite Database Files (*.db *.sqlite *.sqlite3 *.db3) + Ù…Ù„ÙØ§Øª قواعد بيانات SQLite â€(*.db *.sqlite *.sqlite3 *.db3) + + + + DB Browser for SQLite Project Files (*.sqbpro) + Ù…Ù„ÙØ§Øª مشاريع «متصÙّح قواعد بيانات SQLite» â€(*.sqbpro) + + + + SQL Files (*.sql) + Ù…Ù„ÙØ§Øª SQL â€(*.sql) + + + + All Files (*) + كلّ Ø§Ù„Ù…Ù„ÙØ§Øª (*) + + + + Text Files (*.txt) + Ù…Ù„ÙØ§Øª النصوص (*.txt) + + + + Comma-Separated Values Files (*.csv) + Ù…Ù„ÙØ§Øª القيم المقسومة بÙواصل (*.csv) + + + + Tab-Separated Values Files (*.tsv) + Ù…Ù„ÙØ§Øª القيم المقسومة بجدولات (*.tsv) + + + + Delimiter-Separated Values Files (*.dsv) + Ù…Ù„ÙØ§Øª القيم المقسومة Ø¨Ø­Ø±ÙˆÙ ÙØµÙ„ (*.dsv) + + + + Concordance DAT files (*.dat) + â€Concordance DAT files â€(*.dat) + + + + JSON Files (*.json *.js) + Ù…Ù„ÙØ§Øª JSON â€(*.json *.js) + + + + XML Files (*.xml) + Ù…Ù„ÙØ§Øª XML â€(*.xml) + + + + Binary Files (*.bin *.dat) + Ø§Ù„Ù…Ù„ÙØ§Øª الثنائيّة (*.bin *.dat) + + + + SVG Files (*.svg) + Ù…Ù„ÙØ§Øª SVG â€(*.svg) + + + + Hex Dump Files (*.dat *.bin) + Ù…Ù„ÙØ§Øª ستّ‌عشرية Ù…ÙØ±Ù‘غة (*.dat *.bin) + + + + Extensions (*.so *.dylib *.dll) + الامتدادات (*.so *.dylib *.dll) + + + + RemoteCommitsModel + + + Commit ID + معرّ٠الإيداع + + + + Message + الرسالة + + + + Date + التاريخ + + + + Author + المؤلّ٠+ + + + Size + الحجم + + + + Authored and committed by %1 + ألّÙÙ‡ وأودعه: %L1 + + + + Authored by %1, committed by %2 + ألّÙÙ‡ %L1ØŒ وأودعه %L2 + + + + RemoteDatabase + + + Error opening local databases list. +%1 + خطأ أثناء ÙØªØ­ قائمة قواعد البيانات المحليّة. +%L1 + + + + Error creating local databases list. +%1 + خطأ أثناء إنشاء قائمة قواعد البيانات المحليّة. +%L1 + + + + RemoteDock + + + Remote + البعيد + + + + Identity + الهويّة + + + + Push currently opened database to server + Ø§Ø¯ÙØ¹ قاعدة البيانات Ø§Ù„Ù…ÙØªÙˆØ­Ø© حاليًا إلى الخادوم + + + + DBHub.io + DBHub.io + + + + <html><head/><body><p>In this pane, remote databases from dbhub.io website can be added to DB Browser for SQLite. First you need an identity:</p><ol style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Login to the dbhub.io website (use your GitHub credentials or whatever you want)</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Click the button to &quot;Generate client certificate&quot; (that's your identity). That'll give you a certificate file (save it to your local disk).</li><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Go to the Remote tab in DB Browser for SQLite Preferences. Click the button to add a new certificate to DB Browser for SQLite and choose the just downloaded certificate file.</li></ol><p>Now the Remote panel shows your identity and you can add remote databases.</p></body></html> + <html dir="rtl"> +<p>يمكنك ÙÙŠ هذه اللوحة Ø¥Ø¶Ø§ÙØ© قواعد البيانات البعيدة من موقع dbhub.io إلى «متصÙّح قواعد بيانات SQLite». تحتاج أولًا إلى هويّة:</p> +<ol> +<li>Ù„ÙØ¬ إلى موقع dbhub.io (استعمل معلومات ولوج ØºÙØªâ€ŒÙ‡ÙŽØ¨ أو غيرها، كما ترغب)</li> +<li>انقر الزر â€Ù„توليد شهادة العميل“ (وهذه هي الهويّة). هكذا تحصل على مل٠شهادة ØªØ­ÙØ¸Ù‡ على القرص المحلي لديك.</li> +<li>انتقل إلى لسان â€Ø§Ù„بعيد“ ÙÙŠ ØªÙØ¶ÙŠÙ„ات «متصÙّح قواعد بيانات SQLite». انقر الزر Ù„Ø¥Ø¶Ø§ÙØ© شهادة جديدة إلى التطبيق واختر مل٠الشهادة الذي نزّلته للتو.</li> +</ol> +<p>سترى الآن ÙÙŠ لوحة â€Ø§Ù„بعيد“ هويّتك ويمكنك Ø¥Ø¶Ø§ÙØ© قواعد البيانات لتصير بعيدة.</p> +</html> + + + + Local + المحلي + + + + Current Database + قاعدة البيانات الحالية + + + + Clone + استنسخ + + + + User + المستخدم + + + + Database + قاعدة البيانات + + + + Branch + Ø§Ù„ÙØ±Ø¹ + + + + Commits + الإيداعات + + + + Commits for + إيداعات Ø§Ù„ÙØ±Ø¹ + + + + Delete Database + احذ٠قاعدة البيانات + + + + Delete the local clone of this database + احذ٠النسخة المحلية من قاعدة البيانات هذه + + + + Open in Web Browser + Ø§ÙØªØ­ ÙÙŠ متصÙّح Ø§Ù„ÙˆÙØ¨ + + + + Open the web page for the current database in your browser + Ø§ÙØªØ­ ØµÙØ­Ø© Ø§Ù„ÙˆÙØ¨ لقاعدة البيانات الحالية ÙÙŠ المتصÙّح لديك + + + + Clone from Link + استنسخ من رابط + + + + Use this to download a remote database for local editing using a URL as provided on the web page of the database. + استعمل هذا لتنزيل قاعدة بيانات بعيدة للتعديل عليها محليًا باستعمال المسار الموجود ÙÙŠ ØµÙØ­Ø© Ø§Ù„ÙˆÙØ¨ لقاعدة البيانات تلك. + + + + Refresh + Ø£Ù†Ø¹ÙØ´ + + + + Reload all data and update the views + Ø£Ø¹ÙØ¯ تحميل كلّ البيانات وحدّث المناظير + + + + F5 + F5 + + + + Clone Database + استنسخ قاعدة بيانات + + + + Open Database + Ø§ÙØªØ­ قاعدة بيانات + + + + Open the local copy of this database + Ø§ÙØªØ­ النسخة المحلية من قاعدة البيانات هذه + + + + Check out Commit + اسحب الإيداع (Check out) + + + + Download and open this specific commit + نزّل هذا الإيداع بعينه ÙˆØ§ÙØªØ­Ù‡ + + + + Check out Latest Commit + اسحب الإيداع الأخير (Check out) + + + + Check out the latest commit of the current branch + اسحب الإيداع الأخير (Check out) ÙÙŠ Ø§Ù„ÙØ±Ø¹ الحالي + + + + Save Revision to File + Ø§Ø­ÙØ¸ المراجعة ÙÙŠ مل٠+ + + + Saves the selected revision of the database to another file + ÙŠØ­ÙØ¸ المراجعة المحدّدة لقاعدة البيانات ÙÙŠ مل٠آخر + + + + Upload Database + Ø§Ø±ÙØ¹ قاعدة البيانات + + + + Upload this database as a new commit + ÙŠØ±ÙØ¹ قاعدة البيانات هذه كإيداع جديد + + + + <html><head/><body><p>You are currently using a built-in, read-only identity. For uploading your database, you need to configure and use your DBHub.io account.</p><p>No DBHub.io account yet? <a href="https://dbhub.io/"><span style=" text-decoration: underline; color:#007af4;">Create one now</span></a> and import your certificate <a href="#preferences"><span style=" text-decoration: underline; color:#007af4;">here</span></a> to share your databases.</p><p>For online help visit <a href="https://dbhub.io/about"><span style=" text-decoration: underline; color:#007af4;">here</span></a>.</p></body></html> + تستعمل حاليًا هويّة مضمّنة ÙÙŠ البرمجيّة وللقراءة Ùقط. لو أردت Ø±ÙØ¹ قاعدة البيانات ÙØ¹Ù„يك ضبط حسابك على DBHub.io واستعماله.<br/>أليس لديك واحد بعد؟ <a href="https://dbhub.io/"><span style=" text-decoration: underline; color:#007af4;">Ø£Ù†Ø´ÙØ¦Ù‡ الآن</span></a> ÙˆØ§Ø³ØªÙˆØ±ÙØ¯ الشهادة <a href="#preferences"><span style=" text-decoration: underline; color:#007af4;">هنا</span></a> Ù„ØªÙØ´Ø§Ø±Ùƒ قواعد بياناتك.<br/>Ø²ÙØ± <a href="https://dbhub.io/about"><span style=" text-decoration: underline; color:#007af4;">الموقع</span></a> للمساعدة ÙˆØ§Ù„ØªÙØ§ØµÙŠÙ„. + + + + Back + Ø¹ÙØ¯ + + + + Select an identity to connect + اختر هويّة للاتصال + + + + Public + عامّة + + + + This downloads a database from a remote server for local editing. +Please enter the URL to clone from. You can generate this URL by +clicking the 'Clone Database in DB4S' button on the web page +of the database. + بهذا تÙنزّل قاعدة بيانات من خادوم بعيد للتعديل عليها محليًا. +من ÙØ¶Ù„Ùƒ أدخÙÙ„ المسار الذي ستستنسخ القاعدة منه. +يمكنك توليده بنقر â€Ø§Ø³ØªÙ†Ø³Ø® قاعدة البيانات ÙÙŠ DB4S“ +ÙÙŠ ØµÙØ­Ø© Ø§Ù„ÙˆÙØ¨ لقاعدة البيانات التي تريد. + + + + Invalid URL: The host name does not match the host name of the current identity. + مسار غير صالح: لا يتطابق اسم المضي٠مع اسم مضي٠الهويّة الحالية. + + + + Invalid URL: No branch name specified. + مسار غير صالح: لم تحدّد اسم Ø§Ù„ÙØ±Ø¹. + + + + Invalid URL: No commit ID specified. + مسار غير صالح: لم تحدّد معرّ٠الإيداع. + + + + You have modified the local clone of the database. Fetching this commit overrides these local changes. +Are you sure you want to proceed? + عدّلت النسخة المحلية من قاعدة البيانات. بجلب الإيداع ÙØ£Ù†Øª تÙلغي هذه التعديلات المحلية. +أمتأكّد من المواصلة؟ + + + + The database has unsaved changes. Are you sure you want to push it before saving? + ÙÙŠ قاعدة البيانات تعديلات غير محÙوظة. أمتأكّد من Ø¯ÙØ¹ القاعدة قبل Ø­ÙØ¸ التعديلات؟ + + + + The database you are trying to delete is currently opened. Please close it before deleting. + قاعدة البيانات التي تحاول حذÙها Ù…ÙØªÙˆØ­Ø© حاليًا. من ÙØ¶Ù„Ùƒ أغلÙقها قبل حذÙها. + + + + This deletes the local version of this database with all the changes you have not committed yet. Are you sure you want to delete this database? + بهذا تحذ٠النسخة المحلية من قاعدة البيانات هذه مع كلّ التعديلات التي لم تودعها بعد. أمتأكّد من حذ٠قاعدة البيانات هذه؟ + + + + RemoteLocalFilesModel + + + Name + الاسم + + + + Branch + Ø§Ù„ÙØ±Ø¹ + + + + Last modified + آخر تعديل + + + + Size + الحجم + + + + Commit + الإيداع + + + + File + المل٠+ + + + RemoteModel + + + Name + الاسم + + + + Commit + الإيداع + + + + Last modified + آخر تعديل + + + + Size + الحجم + + + + Size: + الحجم: + + + + Last Modified: + آخر تعديل: + + + + Licence: + الرخصة: + + + + Default Branch: + Ø§Ù„ÙØ±Ø¹ المبدئي: + + + + RemoteNetwork + + + Choose a location to save the file + اختر مكانًا Ù„Ø­ÙØ¸ المل٠Ùيه + + + + Error opening remote file at %1. +%2 + خطأ أثناء ÙØªØ­ المل٠البعيد ÙÙŠ %L1. +%L2 + + + + Error: Invalid client certificate specified. + خطأ: Ø­ÙØ¯Ù‘دت شهادة عميل غير صالحة. + + + + Please enter the passphrase for this client certificate in order to authenticate. + من ÙØ¶Ù„Ùƒ أدخÙÙ„ عبارة السر لشهادة العميل لإجراء الاستيثاق. + + + + Cancel + ألغ٠+ + + + Uploading remote database to +%1 + ÙŠØ±ÙØ¹ قاعدة البيانات البعيدة إلى +%L1 + + + + Downloading remote database from +%1 + ينزّل قاعدة البيانات البعيدة من +%L1 + + + + + Error: The network is not accessible. + خطأ: تعذّر الوصول إلى الشبكة. + + + + Error: Cannot open the file for sending. + خطأ: تعذّر ÙØªØ­ المل٠لإرساله. + + + + RemotePushDialog + + + Push database + Ø¯ÙØ¹ قاعدة البيانات + + + + Database na&me to push to + ا&سم قاعدة البيانات الذي Ø³ÙŠÙØ¯Ùع إليها + + + + Commit message + رسالة الإيداع + + + + Database licence + رخصة قاعدة البيانات + + + + Public + عامّة + + + + Branch + Ø§Ù„ÙØ±Ø¹ + + + + Force push + Ø£Ø¬Ø¨ÙØ± Ø§Ù„Ø¯ÙØ¹ + + + + Username + اسم المستخدم + + + + Database will be public. Everyone has read access to it. + ستكون قاعدة البيانات عامّة. يملك الجميع تصريح القراءة منها. + + + + Database will be private. Only you have access to it. + ستكون قاعدة البيانات خاصّة. أنت من لديك حقّ الوصول إليها لا غير. + + + + Use with care. This can cause remote commits to be deleted. + استعمله بحذر. يمكن أن يتسبّب هذا بحذ٠الإيداعات البعيدة. + + + + RunSql + + + Execution aborted by user + أجهض المستخدم التنÙيذ + + + + , %1 rows affected + ØŒ عدد الصÙو٠المتأثّرة هو %L1 + + + + query executed successfully. Took %1ms%2 + Ù†ÙÙّذ الاستعلام بنجاح: أخذ %L1 م‌ث%L2 + + + + executing query + ينÙّذ الاستعلام + + + + SelectItemsPopup + + + A&vailable + ال&Ù…ÙØªØ§Ø­ + + + + Sele&cted + الم&حدّد + + + + SqlExecutionArea + + + Form + استمارة + + + + Find previous match [Shift+F3] + ابحث عن المطابقة السابقة [Shift+F3] + + + + Find previous match with wrapping + ابحث عن المطابقة السابقة مع Ø§Ù„Ø§Ù„ØªÙØ§Ù + + + + Shift+F3 + Shift+F3 + + + + The found pattern must be a whole word + يجب أن يكون النمط محور البحث كلمة كاملة + + + + Whole Words + الكلمات الكاملة + + + + Text pattern to find considering the checks in this frame + النمط محور البحث بأخذ Ø§Ù„ÙØ­ÙˆØµ ÙÙŠ هذا الإطار بعين الاعتبار + + + + Find in editor + ابحث ÙÙŠ المحرّر + + + + The found pattern must match in letter case + يجب أن يطابق النمط محور البحث حالة الأحر٠+ + + + Case Sensitive + حسّاس لحالة الأحر٠+ + + + Find next match [Enter, F3] + ابحث عن المطابقة التالية [Enter, F3] + + + + Find next match with wrapping + ابحث عن المطابقة التالية مع Ø§Ù„Ø§Ù„ØªÙØ§Ù + + + + F3 + + + + + Interpret search pattern as a regular expression + تعامَل مع نمط البحث كتعبير نمطي + + + + <html><head/><body><p>When checked, the pattern to find is interpreted as a UNIX regular expression. See <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>.</p></body></html> + إن ÙØ¹Ù‘لته ÙØ³ØªØªØ¹Ø§Ù…Ù„ البرمجيّة مع نمط البحث على أنّه تعبير يونكس نمطي. Ø·Ø§Ù„ÙØ¹ <a href="https://en.wikibooks.org/wiki/Regular_Expressions">التعابير النمطية ÙÙŠ ويكي‌كتب (بالإنجليزية)</a>. + + + + Regular Expression + تعبير نمطي + + + + + Close Find Bar + أغلÙÙ‚ شريط البحث + + + + <html><head/><body><p>Results of the last executed statements.</p><p>You may want to collapse this panel and use the <span style=" font-style:italic;">SQL Log</span> dock with <span style=" font-style:italic;">User</span> selection instead.</p></body></html> + نتائج آخر Ø§Ù„Ø¥ÙØ§Ø¯Ø§Øª المنÙّذة.<br/>يمكنك طيّ هذه اللوحة واستعمال لوحة <span style=" font-style:italic;">سجلّ SQL</span> باختيار <span style=" font-style:italic;">المستخدم</span> بدل هذا. + + + + Results of the last executed statements + نتائج آخر Ø§Ù„Ø¥ÙØ§Ø¯Ø§Øª المنÙّذة + + + + This field shows the results and status codes of the last executed statements. + يعرض هذا الحقل نتائج ورموز حالة آخر Ø§Ù„Ø¥ÙØ§Ø¯Ø§Øª المنÙّذة. + + + + Couldn't read file: %1. + تعذّرت قراءة الملÙ: %L1. + + + + + Couldn't save file: %1. + تعذّر Ø­ÙØ¸ الملÙ: %L1. + + + + Your changes will be lost when reloading it! + ستÙقد تغييراتك لو ÙØ¹Ù„ت! + + + + The file "%1" was modified by another program. Do you want to reload it?%2 + عدّل برنامج آخر الملÙÙ‘ â€%L1“. أتريد إعادة تحميله؟%L2 + + + + SqlTextEdit + + + Ctrl+/ + Ctrl+/ + + + + SqlUiLexer + + + (X) The abs(X) function returns the absolute value of the numeric argument X. + (X) â€«ØªÙØ¹ÙŠØ¯ الدالة abs(X) القيمة Ø§Ù„Ù…ÙØ·Ù„قة للمعطى العددي X. + + + + () The changes() function returns the number of database rows that were changed or inserted or deleted by the most recently completed INSERT, DELETE, or UPDATE statement. + ‎() â€«ØªÙØ¹ÙŠØ¯ الدالة changes()‎ عدد الصÙÙˆÙ ÙÙŠ قاعدة البيانات التي تغيّرت أو Ø£ÙØ¯Ø±Ø¬Øª أو Ø­ÙØ°Ùت باستخدام أحدث Ø¥ÙØ§Ø¯Ø© INSERT أو DELETE أو UPDATE Ø£ÙØ¬Ø±ÙŠØª بنجاح. + + + + (X1,X2,...) The char(X1,X2,...,XN) function returns a string composed of characters having the unicode code point values of integers X1 through XN, respectively. + (X1,X2,...) â€«ØªÙØ¹ÙŠØ¯ الدالة char(X1,X2,...,XN) سلسلة نصية Ù…Ø¤Ù„Ù‘ÙØ© من محارÙÙŽ قيم٠نقاط رموزها اليونيكودية هي الأعداد الصحيحة بدءًا من X1 وحتّى XN بالترتيب. + + + + (X,Y,...) The coalesce() function returns a copy of its first non-NULL argument, or NULL if all arguments are NULL + (X,Y,...) â€«ØªÙØ¹ÙŠØ¯ الدالة coalesce()‎ نسخة من أوّل معطًى ليس NULØŒ أو NULL إن كانت كلّ المعطيات تساوي NULL. + + + + (X,Y) The glob(X,Y) function is equivalent to the expression "Y GLOB X". + (X,Y) ‫الدالة glob(X,Y) تعادل التعبير â€Y GLOB X“. + + + + (X,Y) The ifnull() function returns a copy of its first non-NULL argument, or NULL if both arguments are NULL. + (X,Y) ØªÙØ¹ÙŠØ¯ الدالة‫ ifnull()‎ نسخة من أوّل معطًى ليس NULØŒ أو NULL إن كان ÙƒÙلا المعطيين يساويان NULL. + + + + (X,Y) The instr(X,Y) function finds the first occurrence of string Y within string X and returns the number of prior characters plus 1, or 0 if Y is nowhere found within X. + (X,Y) ‫تبحث الدالة instr(X,Y) عن أوّل حدوث للسلسلة النصية Y داخل السلسلة النصية X ÙˆØªÙØ¹ÙŠØ¯ عدد المحار٠قبلها زائدًا Ù¡ØŒ أو ØªÙØ¹ÙŠØ¯ القيمة صÙÙØ± إن لم توجد Y ÙÙŠ أيّ مكان ÙÙŠ X. + + + + (X) The hex() function interprets its argument as a BLOB and returns a string which is the upper-case hexadecimal rendering of the content of that blob. + (X) â€«ØªÙØ³Ù‘ر الدالة hex()‎ المطى على أنّه BLOB ÙˆØªÙØ¹ÙŠØ¯ سلسلة نصية تمثّل عرضًا ستّ‌عشري بحالة أحر٠كبيرة لمحتوى كائن BLOB ذاك. + + + + () The last_insert_rowid() function returns the ROWID of the last row insert from the database connection which invoked the function. + ‎() â€«ØªÙØ¹ÙŠØ¯ الدالة last_insert_rowid()‎ معرّ٠الصÙ/ROWID لآخر عملية إدراج صÙÙ‘ من اتصال قاعدة البيانات والتي Ù†Ùّذت الدالة. + + + + (X) For a string value X, the length(X) function returns the number of characters (not bytes) in X prior to the first NUL character. + (X) ‫باعتبار X سلسلة نصية، ØªÙØ¹ÙŠØ¯ الدالة length(X) عدد المحار٠(وليس البايتات) داخل X والموجودة قبل أوّل محر٠NUL Ùيها. + + + + (X,Y) The like() function is used to implement the "Y LIKE X" expression. + (X,Y) ØªÙØ³ØªØ¹Ù…Ù„ الدالة‫ like()‎ لتنÙيذ التعبير â€Y LIKE X“. + + + + (X,Y,Z) The like() function is used to implement the "Y LIKE X ESCAPE Z" expression. + (X,Y,Z) ØªÙØ³ØªØ¹Ù…Ù„ الدالة‫ like()‎ لتنÙيذ التعبير â€Y LIKE X ESCAPE Z“. + + + + (X) The load_extension(X) function loads SQLite extensions out of the shared library file named X. +Use of this function must be authorized from Preferences. + (X) â€«ØªÙØ­Ù…ّل الدالة load_extension(X) امتدادات SQLite من مل٠مكتبة مشتركة اسمه X. +عليك السماح باستعمال هذه الدالة من Ø§Ù„ØªÙØ¶ÙŠÙ„ات. + + + + (X,Y) The load_extension(X) function loads SQLite extensions out of the shared library file named X using the entry point Y. +Use of this function must be authorized from Preferences. + (X,Y) â€«ØªÙØ­Ù…ّل الدالة load_extension(X) امتدادات SQLite من مل٠مكتبة مشتركة اسمه X باستخدام نقطة الإدخال Y. +عليك السماح باستعمال هذه الدالة من Ø§Ù„ØªÙØ¶ÙŠÙ„ات. + + + + (X) The lower(X) function returns a copy of string X with all ASCII characters converted to lower case. + (X) â€«ØªÙØ¹ÙŠØ¯ الدالة lower(X) نسخة من السلسلة النصية X حيث محار٠آسكي كلّها محوّلة إلى حالة الأحر٠الصغيرة. + + + + (X) ltrim(X) removes spaces from the left side of X. + (X) â€«ØªÙØ²ÙŠÙ„ ltrim(X) Ø§Ù„Ù…Ø³Ø§ÙØ§Øª من الجانب الأيسر للسلسلة النصية X. + + + + (X,Y) The ltrim(X,Y) function returns a string formed by removing any and all characters that appear in Y from the left side of X. + (X,Y) â€«ØªÙØ¹ÙŠØ¯ الدالة ltrim(X,Y) سلسلة نصية بإزالة كلّ المحار٠التي قد تظهر ÙÙŠ Y من الجانب الأيسر للسلسلة X. + + + + (X,Y,...) The multi-argument max() function returns the argument with the maximum value, or return NULL if any argument is NULL. + (X,Y,...) â€«ØªÙØ¹ÙŠØ¯ الدالة متعدّدة المعطيات max()‎ المعطى الذي له أكبر قيمة، أو NULL إن كان أحد المعطيات هو NULL. + + + + (X,Y,...) The multi-argument min() function returns the argument with the minimum value. + (X,Y,...) â€«ØªÙØ¹ÙŠØ¯ الدالة متعدّدة المعطيات min()‎ المعطى الذي له أصغر قيمة. + + + + (X,Y) The nullif(X,Y) function returns its first argument if the arguments are different and NULL if the arguments are the same. + (X,Y) â€«ØªÙØ¹ÙŠØ¯ الدالة nullif(X,Y) أوّل معطًى إن كانت المعطيات Ù…Ø®ØªÙ„ÙØ©ØŒ ÙˆØªÙØ¹ÙŠØ¯ NULL إن كانت المعطيات متطابقة. + + + + (FORMAT,...) The printf(FORMAT,...) SQL function works like the sqlite3_mprintf() C-language function and the printf() function from the standard C library. + (FORMAT,...) ‫تعمل دالة SQL هذه printf(FORMAT,...) تمامًا مثل دالة لغة سي sqlite3_mprintf()‎ ودالة printf()‎ من مكتبة سي القياسية. + + + + (X) The quote(X) function returns the text of an SQL literal which is the value of its argument suitable for inclusion into an SQL statement. + (X) â€«ØªÙØ¹ÙŠØ¯ الدالة quote(X) نص SQL حرÙيّ تكون قيمة معامله مناسبة لتوضع ÙÙŠ عبارة SQL. + + + + () The random() function returns a pseudo-random integer between -9223372036854775808 and +9223372036854775807. + ‎() â€«ØªÙØ¹ÙŠØ¯ الدالة random()‎ عددًا صحيحًا عشوائيًا زائÙًا بين -٩٢٢٣٣٧٢٠٣٦٨٥٤٧٧٥٨٠٨ Ùˆ +٩٢٢٣٣٧٢٠٣٦٨٥٤٧٧٥٨٠٧. + + + + (N) The randomblob(N) function return an N-byte blob containing pseudo-random bytes. + (N) â€«ØªÙØ¹ÙŠØ¯ الدالة randomblob(N) كائن BLOB بحجم N بايت يحتوي على بايتات عشوائية Ø²Ø§Ø¦ÙØ©. + + + + (X,Y,Z) The replace(X,Y,Z) function returns a string formed by substituting string Z for every occurrence of string Y in string X. + (X,Y,Z) â€«ØªÙØ¹ÙŠØ¯ الدالة replace(X,Y,Z) سلسلة نصية باستبدال كلّ ظهور للسلسة النصية Y ÙÙŠ السلسلة النصية X بالسلسلة النصية Z. + + + + (X) The round(X) function returns a floating-point value X rounded to zero digits to the right of the decimal point. + (X) ØªÙØ¹ÙŠØ¯ الدالة‫ round(X) قيمة X عشرية عائمة Ù…Ùقرّبة إلى خانات الصÙÙØ± يمين Ø§Ù„ÙØ§ØµÙ„Ø© العشرية. + + + + (X,Y) The round(X,Y) function returns a floating-point value X rounded to Y digits to the right of the decimal point. + (X,Y) ØªÙØ¹ÙŠØ¯ الدالة‫ round(X,Y) قيمة X عشرية عائمة Ù…Ùقرّبة إلى خانات Y يمين Ø§Ù„ÙØ§ØµÙ„Ø© العشرية. + + + + (X) rtrim(X) removes spaces from the right side of X. + (X) â€«ØªÙØ²ÙŠÙ„ rtrim(X) Ø§Ù„Ù…Ø³Ø§ÙØ§Øª من الجانب الأيمن للسلسلة النصية X. + + + + (X,Y) The rtrim(X,Y) function returns a string formed by removing any and all characters that appear in Y from the right side of X. + (X,Y) â€«ØªÙØ¹ÙŠØ¯ الدالة rtrim(X,Y) سلسلة نصية بإزالة كلّ المحار٠التي قد تظهر ÙÙŠ Y من الجانب الأيمن للسلسلة X. + + + + (X) The soundex(X) function returns a string that is the soundex encoding of the string X. + (X) â€«ØªÙØ¹ÙŠØ¯ الدالة soundex(X) سلسلة نصية بترميز Soundex من السلسلة النصية X. + + + + (X,Y) substr(X,Y) returns all characters through the end of the string X beginning with the Y-th. + (X,Y) â€«ØªÙØ¹ÙŠØ¯ substr(X,Y) كلّ المحار٠حتّى نهاية السلسلة النصية X بدايةً من المحر٠رقم Y. + + + + (X,Y,Z) The substr(X,Y,Z) function returns a substring of input string X that begins with the Y-th character and which is Z characters long. + (X,Y,Z) â€«ØªÙØ¹ÙŠØ¯ الدالة substr(X,Y,Z) سلسلة نصية جزئية من السلسلة الدخل X والتي تبدأ بالمحر٠رقم Y وبطول Z من المحارÙ. + + + + () The total_changes() function returns the number of row changes caused by INSERT, UPDATE or DELETE statements since the current database connection was opened. + ‎() â€«ØªÙØ¹ÙŠØ¯ الدالة total_changes()‎ عدد الصÙو٠المتأثّرة Ø¨Ø¥ÙØ§Ø¯Ø© INSERT أو UPDATE أو DELETE مذ ÙÙØªØ­ اتصال قاعدة البيانات الحالية. + + + + (X) trim(X) removes spaces from both ends of X. + (X) â€«ØªÙØ²ÙŠÙ„ trim(X) Ø§Ù„Ù…Ø³Ø§ÙØ§Øª من جانبي للسلسلة النصية X. + + + + (X,Y) The trim(X,Y) function returns a string formed by removing any and all characters that appear in Y from both ends of X. + (X,Y) â€«ØªÙØ¹ÙŠØ¯ الدالة trim(X,Y) سلسلة نصية بإزالة كلّ المحار٠التي قد تظهر ÙÙŠ Y من ÙƒÙلا جانبي X. + + + + (X) The typeof(X) function returns a string that indicates the datatype of the expression X. + (X) â€«ØªÙØ¹ÙŠØ¯ الدالة typeof(X) سلسلة نصية توضّح نوع بيانات التعبير X. + + + + (X) The unicode(X) function returns the numeric unicode code point corresponding to the first character of the string X. + (X) â€«ØªÙØ¹ÙŠØ¯ دالة unicode(X) النقطة الرمزية اليونيكودية العددية لأوّل محر٠من السلسلة النصية X. + + + + (X) The upper(X) function returns a copy of input string X in which all lower-case ASCII characters are converted to their upper-case equivalent. + (X) â€«ØªÙØ¹ÙŠØ¯ الدالة upper(X) نسخة من السلسلة النصية الدخل X حيث محار٠آسكي بحالة الأحر٠الكبيرة محوّلة كلّها إلى حالة الأحر٠الكبيرة. + + + + (N) The zeroblob(N) function returns a BLOB consisting of N bytes of 0x00. + (N) â€«ØªÙØ¹ÙŠØ¯ الدالة zeroblob(N) كائن BLOB يحتوي N بايت بالمحتوى 0x00. + + + + + + + (timestring,modifier,modifier,...) + (timestring,modifier,modifier,...) + + + + (format,timestring,modifier,modifier,...) + (format,timestring,modifier,modifier,...) + + + + (X) The avg() function returns the average value of all non-NULL X within a group. + (X) ØªÙØ¹ÙŠØ¯ الدالة‫ avg()‎ القيمة المتوسّطة لكلّ X لا تساوي NULL داخل مجموعة ما. + + + + (X) The count(X) function returns a count of the number of times that X is not NULL in a group. + (X) â€«ØªÙØ¹ÙŠØ¯ الدالة count(X) عدد المرات التي لا يكون Ùيها X يساوي NULL ÙÙŠ مجموعة ما. + + + + (X) The group_concat() function returns a string which is the concatenation of all non-NULL values of X. + (X) â€«ØªÙØ¹ÙŠØ¯ الدالة group_concat()‎ سلسلة نصية تجمع كلّ قيم X التي لا تساوي NULL. + + + + (X,Y) The group_concat() function returns a string which is the concatenation of all non-NULL values of X. If parameter Y is present then it is used as the separator between instances of X. + (X,Y) â€«ØªÙØ¹ÙŠØ¯ الدالة group_concat()‎ سلسلة نصية تجمع كلّ قيم X التي لا تساوي NULL. إن كان المعطى Y موجودًا، ÙØ³ÙŠÙستخدم ÙƒÙØ§ØµÙ„ بين سيرورات X. + + + + (X) The max() aggregate function returns the maximum value of all values in the group. + (X) â€«ØªÙØ¹ÙŠØ¯ الدالة الجامعة max()‎ أكبر قيمة لكلّ القيم ÙÙŠ المجموعة. + + + + (X) The min() aggregate function returns the minimum non-NULL value of all values in the group. + (X) â€«ØªÙØ¹ÙŠØ¯ الدالة الجامعة min()‎ أدنى قيمة لا تساوي NULL لكلّ القيم ÙÙŠ المجموعة. + + + + + (X) The sum() and total() aggregate functions return sum of all non-NULL values in the group. + (X) â€«ØªÙØ¹ÙŠØ¯ الدالتان الجامعتان sum()‎ Ùˆ total()‎ مجموع كل القيم التي لا تساوي NULL ÙÙŠ المجموعة. + + + + () The number of the row within the current partition. Rows are numbered starting from 1 in the order defined by the ORDER BY clause in the window definition, or in arbitrary order otherwise. + ‎() ‫رقم الصÙÙ‘ داخل القسم الحالي. ØªÙØ±Ù‚ّم الصÙو٠بدءًا من Ù¡ بالترتيب الذي حدّده بند ORDER BY ÙÙŠ ØªØ¹Ø±ÙŠÙ Ø§Ù„Ù†Ø§ÙØ°Ø©ØŒ أو بترتيب اعتباطي إن لم يكن كذلك.†+ + + + () The row_number() of the first peer in each group - the rank of the current row with gaps. If there is no ORDER BY clause, then all rows are considered peers and this function always returns 1. + ‎() ‫ناتج row_number()‎ لأوّل ÙØ±Ø¯ ÙÙŠ كلّ مجموعة - رتبة الصÙÙ‘ الحالي مع Ø§Ù„ÙØ±Ø§ØºØ§Øª. إن لم يكن هناك بند ORDER BYØŒ ÙØ³ØªÙعتبر كلّ الصÙÙˆÙ Ø£ÙØ±Ø§Ø¯ ÙˆØ³ØªÙØ¹ÙŠØ¯ هذه الدالة Ù¡ دومًا. + + + + () The number of the current row's peer group within its partition - the rank of the current row without gaps. Partitions are numbered starting from 1 in the order defined by the ORDER BY clause in the window definition. If there is no ORDER BY clause, then all rows are considered peers and this function always returns 1. + ‎() ‫رقم مجموعة Ø§Ù„Ø£ÙØ±Ø§Ø¯ للصÙÙ‘ الحالي داخل القسم - رتبة الصÙÙ‘ الحالي مع Ø§Ù„ÙØ±Ø§ØºØ§Øª. ØªÙØ±Ù‚ّم الأقسام بدءًا من 1 الترتيب الذي حدّده بند ORDER BY ÙÙŠ ØªØ¹Ø±ÙŠÙ Ø§Ù„Ù†Ø§ÙØ°Ø©. إن لم يوجد بند ORDER BYØŒ ÙØ³ØªÙعتبر كلّ الصÙÙˆÙ Ø£ÙØ±Ø§Ø¯ ÙˆØ³ØªÙØ¹ÙŠØ¯ هذه الدالة Ù¡ دومًا. + + + + () Despite the name, this function always returns a value between 0.0 and 1.0 equal to (rank - 1)/(partition-rows - 1), where rank is the value returned by built-in window function rank() and partition-rows is the total number of rows in the partition. If the partition contains only one row, this function returns 0.0. + ‎() ب‫غضّ النظر عن الاسم، ØªÙØ¹ÙŠØ¯ هذه الدالة دومًا قيمة بين ٠٫٠ و١٫٠ مساويةً لن(الرتبة - Ù¡)/(صÙو٠القسم - Ù¡)ØŒ حيث â€Ø§Ù„رتبة“ هي القيمة التي ØªÙØ¹ÙŠØ¯Ù‡Ø§ دالة Ø§Ù„Ù†Ø§ÙØ°Ø© المضمّنة rank()‎ Ùˆâ€ØµÙو٠القسم“ هو إجمال عدد الصÙÙˆÙ ÙÙŠ القسم. إن احتوى القسم صÙًا واحدًا ÙØ­Ø³Ø¨ØŒ ÙØ³ØªÙعيد هذه الدالة ٠٫٠. + + + + () The cumulative distribution. Calculated as row-number/partition-rows, where row-number is the value returned by row_number() for the last peer in the group and partition-rows the number of rows in the partition. + ‎() التوزيع التصاعدي. ÙŠÙØ­Ø³Ø¨ بالمعادلة رقم الصÙ/صÙو٠القسم، حيث â€Ø±Ù‚Ù… الصÙ“ هي القيمة التي أرجعتها‫ row_number()‎ لآخر ÙØ±Ø¯ ÙÙŠ المجموعة، Ùˆâ€ØµÙو٠القسم“ هي عدد الصÙÙˆÙ ÙÙŠ القسم. + + + + (N) Argument N is handled as an integer. This function divides the partition into N groups as evenly as possible and assigns an integer between 1 and N to each group, in the order defined by the ORDER BY clause, or in arbitrary order otherwise. If necessary, larger groups occur first. This function returns the integer value assigned to the group that the current row is a part of. + (N) â€«ÙŠÙØªØ¹Ø§Ù…Ù„ مع المعطى N على أنّه عدد صحيح. تقسم هذه الدالة القسم إلى N مجموعة إلى حد الإمكان من المساواة، ÙˆØªÙØ³Ù†Ø¯ عددًا صحيحًا بين 1 ÙˆN لكل مجموعة، بالترتيب الذي حدّده بند ORDER BYØŒ أو بترتيب اعتباطي إن كان عكس ذلك. إن كان ضروريا، ÙØ³ØªØ­Ø¯Ø« المجموعات الأكبر أولا. ØªÙØ¹ÙŠØ¯ هذه الدالة قيمة العدد الصحيح Ø§Ù„Ù…ÙØ³Ù†Ø­Ø¯Ø© إلى المجموعة التي هي جزء من الص٠الحالي. + + + + (expr) Returns the result of evaluating expression expr against the previous row in the partition. Or, if there is no previous row (because the current row is the first), NULL. + (expr) â€«ØªÙØ¹ÙŠØ¯ ناتج تقدير التعبير expr على الصÙÙ‘ السابق ÙÙŠ القسم. أو NULL إن لم يكن هناك صÙÙ‘ سابق (لأنّ الص٠الحالي هو الأوّل). + + + + (expr,offset) If the offset argument is provided, then it must be a non-negative integer. In this case the value returned is the result of evaluating expr against the row offset rows before the current row within the partition. If offset is 0, then expr is evaluated against the current row. If there is no row offset rows before the current row, NULL is returned. + (expr,offset) ‫لو ÙˆÙØ¬Ø¯ وسيط الإزاحة offset Ùيجب أن يكون عددًا صحيحًا غير سالب. ÙÙŠ هذه الحالة تكون القيمة Ø§Ù„Ù…ÙØ¹Ø§Ø¯Ø© هي ناتج تقدير العبارة expr للصÙÙˆÙ Ø§Ù„Ù…ÙØ²Ø§Ø­Ø© حسب الإزاحة قبل الصÙÙ‘ الحالي ÙÙŠ القسم. لو كانت الإزاحة صÙÙØ±Ù‹Ø§ ÙØ³ÙŠÙقدّر التعبير حسب الص٠الحالي. لو لم تكن هناك صÙو٠بالإزاحة تلك قبل الصÙÙ‘ الحالي، ÙØ³ÙŠÙعاد NULL. + + + + + (expr,offset,default) If default is also provided, then it is returned instead of NULL if the row identified by offset does not exist. + (expr,offset,default) ‫وإن ÙˆÙØ¬Ø¯Øª قيمة default ÙØ³ØªÙعاد بدل NULL لو لم يوجد الصÙÙ‘ الذي حدّدته الإزاحة تلك. + + + + (expr) Returns the result of evaluating expression expr against the next row in the partition. Or, if there is no next row (because the current row is the last), NULL. + (expr) â€«ØªÙØ¹ÙŠØ¯ ناتج تقدير التعبير حسب الصÙÙ‘ التالي ÙÙŠ القسم. أو NLL لو لم يكن هناك واحد (إذ الصÙÙ‘ الحالي هو آخر صÙÙ‘). + + + + (expr,offset) If the offset argument is provided, then it must be a non-negative integer. In this case the value returned is the result of evaluating expr against the row offset rows after the current row within the partition. If offset is 0, then expr is evaluated against the current row. If there is no row offset rows after the current row, NULL is returned. + (expr,offset) ‫لو ÙˆÙØ¬Ø¯ وسيط الإزاحة offset Ùيجب أن يكون عددًا صحيحًا غير سالب. ÙÙŠ هذه الحالة تكون القيمة Ø§Ù„Ù…ÙØ¹Ø§Ø¯Ø© هي ناتج تقدير العبارة expr للصÙÙˆÙ Ø§Ù„Ù…ÙØ²Ø§Ø­Ø© حسب الإزاحة بعد الصÙÙ‘ الحالي ÙÙŠ القسم. لو كانت الإزاحة صÙÙØ±Ù‹Ø§ ÙØ³ÙŠÙقدّر التعبير حسب الص٠الحالي. لو لم تكن هناك صÙو٠بالإزاحة تلك بعد الصÙÙ‘ الحالي، ÙØ³ÙŠÙعاد NULL. + + + + (expr) This built-in window function calculates the window frame for each row in the same way as an aggregate window function. It returns the value of expr evaluated against the first row in the window frame for each row. + (expr) ‫تحسب دالة Ø§Ù„Ù†ÙˆØ§ÙØ° (window) المضمّنة هذه إطار Ø§Ù„Ù†Ø§ÙØ°Ø© لكلّ ص٠كما تحسبها دوال الجامعة. ØªÙØ¹ÙŠØ¯ الدالة قيمة التعبير expr محسوبًا حسب الص٠الأوّل ÙÙŠ إطار Ø§Ù„Ù†Ø§ÙØ°Ø© لكلّ صÙ. + + + + (expr) This built-in window function calculates the window frame for each row in the same way as an aggregate window function. It returns the value of expr evaluated against the last row in the window frame for each row. + (expr) ‫تحسب دالة Ø§Ù„Ù†ÙˆØ§ÙØ° (window) المضمّنة هذه إطار Ø§Ù„Ù†Ø§ÙØ°Ø© لكلّ ص٠كما تحسبها دوال الجامعة. ØªÙØ¹ÙŠØ¯ الدالة قيمة التعبير expr محسوبًا حسب الص٠الأخير ÙÙŠ إطار Ø§Ù„Ù†Ø§ÙØ°Ø© لكلّ صÙ. + + + + (expr,N) This built-in window function calculates the window frame for each row in the same way as an aggregate window function. It returns the value of expr evaluated against the row N of the window frame. Rows are numbered within the window frame starting from 1 in the order defined by the ORDER BY clause if one is present, or in arbitrary order otherwise. If there is no Nth row in the partition, then NULL is returned. + (expr, N) ‫تحسب دالة Ø§Ù„Ù†ÙˆØ§ÙØ° (window) المضمّنة هذه إطار Ø§Ù„Ù†Ø§ÙØ°Ø© لكلّ ص٠كما تحسبها دوال الجامعة. ØªÙØ¹ÙŠØ¯ الدالة قيمة التعبير expr محسوبًا حسب الص٠رقم N ÙÙŠ إطار Ø§Ù„Ù†Ø§ÙØ°Ø©. ØªÙØ±Ù‚ّم الصÙÙˆÙ ÙÙŠ إطارات Ø§Ù„Ù†ÙˆØ§ÙØ° بدءًا بالعدد Ù¡ حسب الترتيب الذي حدّده بند ORDER BY لو ÙˆÙØ¬Ø¯ØŒ أو بترتيب اعتباطي لو لم يوجد. ولو لم يكن هناك ص٠برقم N ÙÙŠ القسم ÙØ³ÙŠÙعاد NULL. + + + + SqliteTableModel + + + reading rows + يقرأ الصÙÙˆÙ + + + + loading... + يحمّل... + + + + References %1(%2) +Hold %3Shift and click to jump there + Ø§Ù„ØªÙØ¶ÙŠÙ„ات %L1â€(%L2) +اضغط %L3Shift وانقر للانتقال إلى هناك + + + + Error changing data: +%1 + خطأ أثناء تغيير البيانات: +%L1 + + + + retrieving list of columns + يجلب قائمة الأعمدة + + + + Fetching data... + يجلب البيانات... + + + + + Cancel + ألغ٠+ + + + TableBrowser + + + Browse Data + تصÙّح البيانات + + + + &Table: + الج&دول: + + + + Select a table to browse data + اختر جدولًا لتصÙّح بياناته + + + + Use this list to select a table to be displayed in the database view + استعمل هذه القائمة لاختيار الجدول الذي Ø³ÙŠÙØ¹Ø±Ø¶ ÙÙŠ منظور قاعدة البيانات + + + + This is the database table view. You can do the following actions: + - Start writing for editing inline the value. + - Double-click any record to edit its contents in the cell editor window. + - Alt+Del for deleting the cell content to NULL. + - Ctrl+" for duplicating the current record. + - Ctrl+' for copying the value from the cell above. + - Standard selection and copy/paste operations. + هذا هو منظور جدول قاعدة البيانات. يمكنك إجراء الآتي Ùيه: + - البدء بالكتابة لتحرير القيمة داخل الخط. + - النقر مزدوجًا على أيّ سجلّ لتحرير محتوياته ÙÙŠ Ù†Ø§ÙØ°Ø© محرّر الخلايا. + - ضغط Alt+Del لحذ٠محتوى الخليّة وضبطه على NULL. + - ضغط Ctrl+"‎ لتكرار السجلّ الحالي. + - ضغط Ctrl+'‎ لنسخ القيمة من الخلية أعلاه. + - التحديد العادي وعمليات النسخ واللصق. + + + + Text pattern to find considering the checks in this frame + النمط محور البحث بأخذ Ø§Ù„ÙØ­ÙˆØµ ÙÙŠ هذا الإطار بعين الاعتبار + + + + Find in table + ابحث ÙÙŠ الجدول + + + + Find previous match [Shift+F3] + ابحث عن المطابقة السابقة [Shift+F3] + + + + Find previous match with wrapping + ابحث عن المطابقة السابقة مع Ø§Ù„Ø§Ù„ØªÙØ§Ù + + + + Shift+F3 + Shift+F3 + + + + Find next match [Enter, F3] + ابحث عن المطابقة التالية [Enter, F3] + + + + Find next match with wrapping + ابحث عن المطابقة التالية مع Ø§Ù„Ø§Ù„ØªÙØ§Ù + + + + F3 + + + + + The found pattern must match in letter case + يجب أن يطابق النمط محور البحث حالة الأحر٠+ + + + Case Sensitive + حسّاس لحالة الأحر٠+ + + + The found pattern must be a whole word + يجب أن يكون النمط محور البحث كلمة كاملة + + + + Whole Cell + الخلية كاملة + + + + Interpret search pattern as a regular expression + تعامَل مع نمط البحث كتعبير نمطي + + + + <html><head/><body><p>When checked, the pattern to find is interpreted as a UNIX regular expression. See <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>.</p></body></html> + إن ÙØ¹Ù‘لته ÙØ³ÙŠÙتعامل مع نمط البحث على أنّه تعبير يونكس نمطي. طالع <a href="https://en.wikibooks.org/wiki/Regular_Expressions">التعابير النمطية ÙÙŠ ويكي‌كتب (بالإنجليزية)</a>. + + + + Regular Expression + تعبير نمطي + + + + + Close Find Bar + أغلÙÙ‚ شريط البحث + + + + Text to replace with + نص الاستبدال + + + + Replace with + استبدله بÙ†+ + + + Replace next match + استبدÙÙ„ المطابقة التالية + + + + + Replace + استبدل + + + + Replace all matches + استبدل كلّ المطابقات + + + + Replace all + استبدل الكلّ + + + + <html><head/><body><p>Scroll to the beginning</p></body></html> + مرّر إلى البداية + + + + <html><head/><body><p>Clicking this button navigates to the beginning in the table view above.</p></body></html> + ينقلك هذا الزر إلى بداية منظور الجدول أعلاه. + + + + |< + |< + + + + Scroll one page upwards + مرّر ØµÙØ­Ø© واحدة للأمام + + + + <html><head/><body><p>Clicking this button navigates one page of records upwards in the table view above.</p></body></html> + ينقلك هذا الزر ØµÙØ­Ø© واحدة من السجلّات لأعلى ÙÙŠ منظور الجدول أعلاه. + + + + < + < + + + + 0 - 0 of 0 + Ù  - Ù  من أصل Ù  + + + + Scroll one page downwards + مرّر ØµÙØ­Ø© واحدة للأسÙÙ„ + + + + <html><head/><body><p>Clicking this button navigates one page of records downwards in the table view above.</p></body></html> + ينقلك هذا الزر ØµÙØ­Ø© واحدة من السجلّات لأسÙÙ„ ÙÙŠ منظور الجدول أعلاه. + + + + > + > + + + + Scroll to the end + مرّر إلى النهاية + + + + <html><head/><body><p>Clicking this button navigates up to the end in the table view above.</p></body></html> + ينقلك هذا الزر إلى نهاية منظور الجدول أعلاه. + + + + >| + >| + + + + <html><head/><body><p>Click here to jump to the specified record</p></body></html> + انقر هنا للانتقال إلى السجلّ المحدّد + + + + <html><head/><body><p>This button is used to navigate to the record number specified in the Go to area.</p></body></html> + ÙŠÙØ³ØªØ¹Ù…Ù„ هذا الزر ÙÙŠ التنقّل إلى رقم السطر المحدّد ÙÙŠ منطقة â€Ø§Ù†ØªÙ‚Ù„ إلى“. + + + + Go to: + انتقل إلى: + + + + Enter record number to browse + أدخÙÙ„ رقم السجلّ لتصÙّحه + + + + Type a record number in this area and click the Go to: button to display the record in the database view + اكتب رقم السجلّ ÙÙŠ هذا المربّع وانقر زر â€Ø§Ù†ØªÙ‚Ù„ إلى:“ لعرض السجلّ ÙÙŠ منظور قاعدة البيانات + + + + 1 + Ù¡ + + + + Show rowid column + اعرض عمود معرّ٠الصÙÙˆÙ + + + + Toggle the visibility of the rowid column + بدّل ظهور عمود معرّ٠الصÙÙˆÙ/rowid + + + + Unlock view editing + اسمح بتحرير المنظور + + + + This unlocks the current view for editing. However, you will need appropriate triggers for editing. + يتيح هذا تحرير المنظور الحالي. مع ذلك ستحتاج إلى المحÙّزات المناسبة لإجراء التحرير. + + + + Edit display format + حرّر تنسيق العرض + + + + Edit the display format of the data in this column + حرّر تنسيق عرض البيانات ÙÙŠ هذا العمود + + + + + New Record + سجلّ جديد + + + + + Insert a new record in the current table + Ø£Ø¯Ø±ÙØ¬ سجلًا جديدًا ÙÙŠ الجدول الحالي + + + + <html><head/><body><p>This button creates a new record in the database. Hold the mouse button to open a pop-up menu of different options:</p><ul><li><span style=" font-weight:600;">New Record</span>: insert a new record with default values in the database.</li><li><span style=" font-weight:600;">Insert Values...</span>: open a dialog for entering values before they are inserted in the database. This allows to enter values acomplishing the different constraints. This dialog is also open if the <span style=" font-weight:600;">New Record</span> option fails due to these constraints.</li></ul></body></html> + ÙŠÙنشئ هذا الزر سجلًا جديدًا ÙÙŠ قاعدة البيانات. أبق٠زر Ø§Ù„ÙØ£Ø±Ø© مضغوطًا Ù„ÙØªØ­ قائمة منبثقة Ùيها عدّة خيارات:<ul><li><span style=" font-weight:600;">سجلّ جديد</span>: لإدراج سجلّ جديد يحمل القيم المبدئية ÙÙŠ قاعدة البيانات.</li><li><span style=" font-weight:600;">Ø£Ø¯Ø±ÙØ¬ قيم...</span>: Ù„ÙØªØ­ مربّع حوار لإدخال القيم قبل إدراجها ÙÙŠ جدول البيانات. يتيح هذا إدخال القيم حسب القيود Ø§Ù„Ù…Ø®ØªÙ„ÙØ©. ÙŠÙÙØªØ­ مربّع الحوار هذا أيضًا إن ÙØ´Ù„ الخيار <span style=" font-weight:600;">سجلّ جديد</span> بسبب هذه القيود.</li></ul> + + + + + Delete Record + احذ٠السجلّ + + + + Delete the current record + احذ٠السجلّ الحالي + + + + + This button deletes the record or records currently selected in the table + يحذ٠هذا الزر السجلّ أو السجلّات المحدّدة حاليًا ÙÙŠ الجدول + + + + + Insert new record using default values in browsed table + Ø£Ø¯Ø±ÙØ¬ سجلًا جديدًا مستخدمًا القيم المبدئية ÙÙŠ الجدول الذي تتصÙّحه + + + + Insert Values... + Ø£Ø¯Ø±ÙØ¬ قيم... + + + + + Open a dialog for inserting values in a new record + Ø§ÙØªØ­ مربّع حوار لإدراج القيم ÙÙŠ سجلّ جديد + + + + Export to &CSV + &صدّر بنسق CSV + + + + + Export the filtered data to CSV + صدّر البيانات المرشّحة إلى CSV + + + + This button exports the data of the browsed table as currently displayed (after filters, display formats and order column) as a CSV file. + ÙŠÙØµØ¯Ù‘ر هذا الزر بيانات الجدول الذي تتصÙّحه كما هي معروضة حاليًا (بعد المرشّحات وتنسيقات العرض وعمود Ø§Ù„ÙØ±Ø²) كمل٠CSV. + + + + Save as &view + Ø§Ø­ÙØ¸ كمن&ظور + + + + + Save the current filter, sort column and display formats as a view + Ø§Ø­ÙØ¸ المرشّح الحالي وعمود Ø§Ù„ÙØ±Ø² وتنسيقات العرض كمنظور + + + + This button saves the current setting of the browsed table (filters, display formats and order column) as an SQL view that you can later browse or use in SQL statements. + ÙŠØ­ÙØ¸ هذا الزر الإعداد الحالي للجدول الذي تتصÙّحه (المرشّحات وتنسيقات العرض وعمود Ø§Ù„ÙØ±Ø²) ÙÙŠ منظور SQL يمكنك تصÙّحه لاحقًا أو استخدامه ÙÙŠ Ø¥ÙØ§Ø¯Ø§Øª SQL. + + + + Save Table As... + Ø§Ø­ÙØ¸ الجدول ÙƒÙŽâ€... + + + + + Save the table as currently displayed + Ø§Ø­ÙØ¸ الجدول كما هو معروض حاليًا + + + + <html><head/><body><p>This popup menu provides the following options applying to the currently browsed and filtered table:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Export to CSV: this option exports the data of the browsed table as currently displayed (after filters, display formats and order column) to a CSV file.</li><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Save as view: this option saves the current setting of the browsed table (filters, display formats and order column) as an SQL view that you can later browse or use in SQL statements.</li></ul></body></html> + توÙّر القائمة المنبثقة هذه الخيارات الآتية والتي تنطبق على الجدول الذي تتصÙّحه والمرشّح حاليًا:<ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">صدّر بنسق CSV: ÙŠÙØµØ¯Ù‘ر هذا الخيار البيانات ÙÙŠ الجدول الذي تتصÙّحه كما هي معروضة حاليًا (بعد المرشّحات وتنسيقات العرض وعمود Ø§Ù„ÙØ±Ø²) إلى مل٠بنسق CSV.</li><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Ø§Ø­ÙØ¸ كمنظور: ÙŠØ­ÙØ¸ هذا الخيار الإعداد الحالي للجدول الذي تتصÙّحه (المرشّحات وتنسيقات العرض وعمود Ø§Ù„ÙØ±Ø²) ÙÙŠ منظور SQL يمكنك تصÙّحه لاحقًا أو استعماله ÙÙŠ Ø¥ÙØ§Ø¯Ø§Øª SQL.</li></ul> + + + + Hide column(s) + أخÙ٠العمود/الأعمدة + + + + Hide selected column(s) + أخÙ٠العمود/الأعمدة المحدّدة + + + + Show all columns + اعرض كلّ الأعمدة + + + + Show all columns that were hidden + اعرض كلّ الأعمدة التي Ø£ÙØ®Ùيت + + + + + Set encoding + اضبط الترميز + + + + Change the encoding of the text in the table cells + غيّر ترميز النصوص ÙÙŠ خلايا الجدول + + + + Set encoding for all tables + اضبط ترميز كلّ الجداول + + + + Change the default encoding assumed for all tables in the database + غيّر الترميز المبدئي Ø§Ù„Ù…ÙØªØ±Ø¶ ÙÙŠ كلّ جداول قاعدة البيانات + + + + Clear Filters + امسح المرشّحات + + + + Clear all filters + امسح كلّ المرشّحات + + + + + This button clears all the filters set in the header input fields for the currently browsed table. + يمسح هذا الزر كلّ المرشّحات المضبوطة ÙÙŠ حقول الدخل ÙÙŠ الترويسة للجدول الذي تتصÙّحه حاليًا. + + + + Clear Sorting + امسح Ø§Ù„ÙØ±Ø² + + + + Reset the order of rows to the default + صÙّر ترتيب الصÙو٠إلى المبدئيات + + + + + This button clears the sorting columns specified for the currently browsed table and returns to the default order. + يمسح هذا الزر تريتب الأعمدة المحدّد للجدول الذي تتصÙّحه حاليًا ÙˆÙŠÙØ¹ÙŠØ¯Ù‡ إلى التريب المبدئي. + + + + Print + اطبع + + + + Print currently browsed table data + اطبع بيانات الجدول الذي تتصÙّحه حاليًا + + + + Print currently browsed table data. Print selection if more than one cell is selected. + اطبع بيانات الجدول الذي تتصÙّحه حاليًا. اطبع التحديد إن كانت هناك أكثر من خليّة واحدة محدّدة. + + + + Ctrl+P + Ctrl+P + + + + Refresh + Ø£Ù†Ø¹ÙØ´ + + + + Refresh the data in the selected table + Ø£Ù†Ø¹ÙØ´ البيانات ÙÙŠ الجدول المحدّد + + + + This button refreshes the data in the currently selected table. + ÙŠÙنعش هذا الزر البيانات ÙÙŠ الجدول المحدّد حاليًا. + + + + F5 + + + + + Find in cells + ابحث ÙÙŠ الخلايا + + + + Open the find tool bar which allows you to search for values in the table view below. + Ø§ÙØªØ­ شريط أدوات البحث لتبحث عن القيم التي تريد ÙÙŠ منظور الجدول أسÙله. + + + + + Bold + ثخين + + + + Ctrl+B + Ctrl+B + + + + + Italic + مائل + + + + + Underline + مسطّر + + + + Ctrl+U + Ctrl+U + + + + + Align Right + حاذ٠يمينًا + + + + + Align Left + حاذ٠يسارًا + + + + + Center Horizontally + الوسط الأÙقي + + + + + Justify + ضبط + + + + + Edit Conditional Formats... + حرّر التنسيقات الشرطيّة... + + + + Edit conditional formats for the current column + حرّر تنسيقات العمود الحالي الشرطيّة + + + + Clear Format + امسح التنسيق + + + + Clear All Formats + امسح كلّ التنسيقات + + + + + Clear all cell formatting from selected cells and all conditional formats from selected columns + امسح كلّ تنسيق الخلايا ÙÙŠ الخلايا المحدّدة وكلّ التنسيقات الشرطيّة ÙÙŠ الأعمدة المحدّدة + + + + + Font Color + لون النص + + + + + Background Color + لون الخلÙية + + + + Toggle Format Toolbar + اعرض/أخÙ٠شريط أدوات التنسيق + + + + Show/hide format toolbar + اعرض/أخÙ٠شريط التنسيق + + + + + This button shows or hides the formatting toolbar of the Data Browser + يعرض هذا الزر (أو ÙŠÙØ®ÙÙŠ) شريط التنسيق لمتصÙّح البيانات + + + + Select column + اختر عمودًا + + + + Ctrl+Space + Ctrl+Space + + + + Replace text in cells + استبدل النصوص ÙÙŠ الخلايا + + + + Filter in any column + رشّح أيّ عمود + + + + Ctrl+R + Ctrl+R + + + + %n row(s) + + لا صÙÙˆÙ + صÙÙ‘ واحد + صÙّان اثنان + %Ln صÙÙˆÙ + %Ln صÙًا + %Ln صÙÙ‘ + + + + + , %n column(s) + + ولا أعمدة + وعمود واحد + وعمودين اثنين + Ùˆ%Ln أعمدة + Ùˆ%Ln عمودًا + Ùˆ%Ln عمود + + + + + . Sum: %1; Average: %2; Min: %3; Max: %4 + . المجموع: %L1ØŒ المتوسّط: %L2ØŒ الأدنى: %L3ØŒ الأقصى: %L4 + + + + Conditional formats for "%1" + تنسيقات â€%L1“ الشرطيّة + + + + determining row count... + يحدّد عدد الصÙÙˆÙ... + + + + %1 - %2 of >= %3 + â€%L1 - â€%L2 من أصل >= â€%L3 + + + + %1 - %2 of %3 + â€%L1 - â€%L2 من أصل %L3 + + + + Please enter a pseudo-primary key in order to enable editing on this view. This should be the name of a unique column in the view. + من ÙØ¶Ù„Ùƒ أدخÙÙ„ Ù…ÙØªØ§Ø­Ù‹Ø§ أساسيًا زائÙًا (pseudo) Ù„ØªÙØ¹ÙŠÙ„ التحرير ÙÙŠ هذا المنظور. يجب أن يكون Ø§Ù„Ù…ÙØªØ§Ø­ اسمًا لأحد الأعمدة Ø§Ù„ÙØ±ÙŠØ¯Ø© ÙÙŠ المنظور. + + + + Delete Records + احذ٠السجلّات + + + + Duplicate records + كرّر السجلّات + + + + Duplicate record + كرّر السجلّ + + + + Ctrl+" + Ctrl+" + + + + Adjust rows to contents + اضبط الصÙو٠إلى محتواها + + + + Error deleting record: +%1 + خطأ أثناء حذ٠السجلّ: +%L1 + + + + Please select a record first + من ÙØ¶Ù„Ùƒ اختر سجلًا أوّلًا + + + + There is no filter set for this table. View will not be created. + لا مرشّح مضبوط لهذا الجدول. لن ÙŠÙنشأ المنظور. + + + + Please choose a new encoding for all tables. + من ÙØ¶Ù„Ùƒ اختر ترميزًا جديدًا لكلّ الجداول. + + + + Please choose a new encoding for this table. + من ÙØ¶Ù„Ùƒ اختر ترميزًا جديدًا لهذا الجدول. + + + + %1 +Leave the field empty for using the database encoding. + %L1 +اترك الحقل ÙØ§Ø±ØºÙ‹Ø§ لاستعمال ترميز قاعدة البيانات. + + + + This encoding is either not valid or not supported. + إمّا أنّ هذا الترميز غير صالح أو أنّه غير مدعوم. + + + + %1 replacement(s) made. + عدد الاستبدالات Ø§Ù„Ù…ÙØ¬Ø±Ø§Ø©: %L1 + + + + VacuumDialog + + + Compact Database + رصّ قاعدة البيانات + + + + Warning: Compacting the database will commit all of your changes. + تحذير: برصّ قاعدة البيانات ستÙودع كلّ التعديلات التي أجريتها. + + + + Please select the databases to co&mpact: + من ÙØ¶Ù„Ùƒ اختر قواعد البيانات لر&صّها: + + + diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/translations/sqlb_cs.qm b/src/WBCLFZSystemModule/SqliteDBProcess/src/translations/sqlb_cs.qm new file mode 100644 index 0000000000000000000000000000000000000000..0828541bf38830b889e2f517dacf16c054c1d698 GIT binary patch literal 72122 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 + + + + AboutDialog + + + About DB Browser for SQLite + O DB Browser pro SQLite + + + + Version + Verze + + + + <html><head/><body><p>DB Browser for SQLite is an open source, freeware visual tool used to create, design and edit SQLite database files.</p><p>It is bi-licensed under the Mozilla Public License Version 2, as well as the GNU General Public License Version 3 or later. You can modify or redistribute it under the conditions of these licenses.</p><p>See <a href="http://www.gnu.org/licenses/gpl.html">http://www.gnu.org/licenses/gpl.html</a> and <a href="https://www.mozilla.org/MPL/2.0/index.txt">https://www.mozilla.org/MPL/2.0/index.txt</a> for details.</p><p>For more information on this program please visit our website at: <a href="http://sqlitebrowser.org">http://sqlitebrowser.org</a></p><p><span style=" font-size:small;">This software uses the GPL/LGPL Qt Toolkit from </span><a href="http://qt-project.org/"><span style=" font-size:small;">http://qt-project.org/</span></a><span style=" font-size:small;"><br/>See </span><a href="http://qt-project.org/doc/qt-5/licensing.html"><span style=" font-size:small;">http://qt-project.org/doc/qt-5/licensing.html</span></a><span style=" font-size:small;"> for licensing terms and information.</span></p><p><span style=" font-size:small;">It also uses the Silk icon set by Mark James licensed under a Creative Commons Attribution 2.5 and 3.0 license.<br/>See </span><a href="http://www.famfamfam.com/lab/icons/silk/"><span style=" font-size:small;">http://www.famfamfam.com/lab/icons/silk/</span></a><span style=" font-size:small;"> for details.</span></p></body></html> + + + + + AddRecordDialog + + + Add New Record + + + + + Enter values for the new record considering constraints. Fields in bold are mandatory. + + + + + In the Value column you can specify the value for the field identified in the Name column. The Type column indicates the type of the field. Default values are displayed in the same style as NULL values. + + + + + Name + Název + + + + Type + Typ + + + + Value + + + + + Values to insert. Pre-filled default values are inserted automatically unless they are changed. + + + + + When you edit the values in the upper frame, the SQL query for inserting this new record is shown here. You can edit manually the query before saving. + + + + + <html><head/><body><p><span style=" font-weight:600;">Save</span> will submit the shown SQL statement to the database for inserting the new record.</p><p><span style=" font-weight:600;">Restore Defaults</span> will restore the initial values in the <span style=" font-weight:600;">Value</span> column.</p><p><span style=" font-weight:600;">Cancel</span> will close this dialog without executing the query.</p></body></html> + + + + + Auto-increment + + + + + + Unique constraint + + + + + + Check constraint: %1 + + + + + + Foreign key: %1 + + + + + + Default value: %1 + + + + + + Error adding record. Message from database engine: + +%1 + + + + + Are you sure you want to restore all the entered values to their defaults? + + + + + Application + + + Possible command line arguments: + Možné parametry pro příkazový řádek: + + + + Usage: %1 [options] [<database>|<project>] + + + + + + -h, --help Show command line options + + + + + -q, --quit Exit application after running scripts + + + + + -s, --sql <file> Execute this SQL file after opening the DB + + + + + -t, --table <table> Browse this table after opening the DB + + + + + -R, --read-only Open database in read-only mode + + + + + -o, --option <group>/<setting>=<value> + + + + + Run application with this setting temporarily set to value + + + + + -O, --save-option <group>/<setting>=<value> + + + + + Run application saving this value for this setting + + + + + -v, --version Display the current version + + + + + <database> Open this SQLite database + + + + + <project> Open this project file (*.sqbpro) + + + + + The -s/--sql option requires an argument + Volba -s/--sql vyžaduje parametry + + + + The file %1 does not exist + Soubor %1 neexistuje + + + + The -t/--table option requires an argument + Volba -t/--table vyžaduje parametry + + + + The -o/--option and -O/--save-option options require an argument in the form group/setting=value + + + + + Invalid option/non-existant file: %1 + Neplatná volba/neexistující soubor: %1 + + + + SQLite Version + verze SQLite + + + + SQLCipher Version %1 (based on SQLite %2) + + + + + DB Browser for SQLite Version %1. + + + + + Built for %1, running on %2 + + + + + Qt Version %1 + + + + + CipherDialog + + + SQLCipher encryption + Å¡ifrování SQLCipher + + + + &Password + &Heslo + + + + &Reenter password + &Zadejte heslo znovu + + + + Encr&yption settings + + + + + SQLCipher &3 defaults + + + + + SQLCipher &4 defaults + + + + + Custo&m + + + + + Page si&ze + Velikost strany + + + + &KDF iterations + + + + + HMAC algorithm + + + + + KDF algorithm + + + + + Plaintext Header Size + + + + + Passphrase + + + + + Raw key + + + + + Please set a key to encrypt the database. +Note that if you change any of the other, optional, settings you'll need to re-enter them as well every time you open the database file. +Leave the password fields empty to disable the encryption. +The encryption process might take some time and you should have a backup copy of your database! Unsaved changes are applied before modifying the encryption. + + + + + Please enter the key used to encrypt the database. +If any of the other settings were altered for this database file you need to provide this information as well. + + + + + ColumnDisplayFormatDialog + + + Choose display format + Vyberte formát zobrazení + + + + Display format + Formát zobrazení + + + + Choose a display format for the column '%1' which is applied to each value prior to showing it. + Vyberte formát zobrazení pro sloupec '%1' který je použit na každou hodnotu pÅ™ed zobrazením. + + + + Default + Výchozí + + + + Decimal number + Desetinné Äíslo + + + + Exponent notation + Notace exponentu + + + + Hex blob + Å estnáctkový blob + + + + Hex number + Å estnáctkové Äíslo + + + + Apple NSDate to date + Apple NSDate na datum + + + + Java epoch (milliseconds) to date + + + + + .NET DateTime.Ticks to date + + + + + Julian day to date + Juliánský den na datum + + + + Unix epoch to local time + + + + + Date as dd/mm/yyyy + Datum jako dd/mm/yyyy + + + + Lower case + Malá písmena + + + + Custom display format must contain a function call applied to %1 + + + + + Error in custom display format. Message from database engine: + +%1 + + + + + Custom display format must return only one column but it returned %1. + + + + + Octal number + OsmiÄkové Äíslo + + + + Round number + Zaokrouhlit Äíslo + + + + Unix epoch to date + Unix epoch na datum + + + + Upper case + Velká písmena + + + + Windows DATE to date + Windows DATE na datum + + + + Custom + Vlastní + + + + CondFormatManager + + + Conditional Format Manager + + + + + This dialog allows creating and editing conditional formats. Each cell style will be selected by the first accomplished condition for that cell data. Conditional formats can be moved up and down, where those at higher rows take precedence over those at lower. Syntax for conditions is the same as for filters and an empty condition applies to all values. + + + + + Add new conditional format + + + + + &Add + PÅ™idat + + + + Remove selected conditional format + + + + + &Remove + Odstranit + + + + Move selected conditional format up + + + + + Move &up + + + + + Move selected conditional format down + + + + + Move &down + + + + + Foreground + PopÅ™edí + + + + Text color + Barva textu + + + + Background + Pozadí + + + + Background color + Barva pozadí + + + + Font + Font + + + + Size + Velikost + + + + Bold + TuÄný + + + + Italic + Kurzíva + + + + Underline + Podtržený + + + + Alignment + + + + + Condition + + + + + + Click to select color + + + + + Are you sure you want to clear all the conditional formats of this field? + + + + + DBBrowserDB + + + Please specify the database name under which you want to access the attached database + Prosím specifikujte jméno databáze, pod kterým chcete pÅ™istupovat k pÅ™ipojené databázi + + + + Invalid file format + Neplatný formát souboru + + + + Do you want to save the changes made to the database file %1? + Chcete uložit zmÄ›ny provedené do databázového souboru %1? + + + + Exporting database to SQL file... + Exportuji databázi do souboru SQL... + + + + + Cancel + ZruÅ¡it + + + + Executing SQL... + Provádím SQL... + + + + Action cancelled. + Akce zruÅ¡ena. + + + + This database has already been attached. Its schema name is '%1'. + + + + + Do you really want to close this temporary database? All data will be lost. + + + + + Database didn't close correctly, probably still busy + + + + + The database is currently busy: + Databáze je právÄ› zaneprázdnÄ›ná: + + + + Do you want to abort that other operation? + + + + + + No database file opened + + + + + + Error in statement #%1: %2. +Aborting execution%3. + + + + + + and rolling back + + + + + didn't receive any output from %1 + + + + + could not execute command: %1 + + + + + Cannot delete this object + Nemohu smazat tento objekt + + + + Cannot set data on this object + + + + + + A table with the name '%1' already exists in schema '%2'. + + + + + No table with name '%1' exists in schema '%2'. + + + + + + Cannot find column %1. + + + + + Creating savepoint failed. DB says: %1 + + + + + Renaming the column failed. DB says: +%1 + + + + + + Releasing savepoint failed. DB says: %1 + + + + + Creating new table failed. DB says: %1 + + + + + Copying data to new table failed. DB says: +%1 + + + + + Deleting old table failed. DB says: %1 + + + + + Error renaming table '%1' to '%2'. +Message from database engine: +%3 + + + + + could not get list of db objects: %1 + + + + + Restoring some of the objects associated with this table failed. This is most likely because some column names changed. Here's the SQL statement which you might want to fix and execute manually: + + + + + + + could not get list of databases: %1 + + + + + Error loading extension: %1 + Chyba pÅ™i naÄítání přípony: %1 + + + + could not get column information + + + + + Error setting pragma %1 to %2: %3 + Chyba pÅ™i nastavování pragma %1 na %2: %3 + + + + File not found. + Soubor nebyl nalezen. + + + + DbStructureModel + + + Name + Název + + + + Object + Objekt + + + + Type + Typ + + + + Schema + Schéma + + + + Database + Databáze + + + + Browsables + + + + + All + VÅ¡echny + + + + Temporary + DoÄasný + + + + Tables (%1) + Tabulky (%1) + + + + Indices (%1) + Indexy (%1) + + + + Views (%1) + Pohledy (%1) + + + + Triggers (%1) + Triggery (%1) + + + + EditDialog + + + Edit database cell + Upravit buňku databáze + + + + Mode: + Mód: + + + + + Image + Obrázek + + + + Set as &NULL + Nastavit na &NULL + + + + Apply data to cell + + + + + This button saves the changes performed in the cell editor to the database cell. + + + + + Apply + Provést + + + + Text + Text + + + + This is the list of supported modes for the cell editor. Choose a mode for viewing or editing the data of the current cell. + + + + + RTL Text + + + + + Binary + Binární + + + + JSON + + + + + XML + XML + + + + + Automatically adjust the editor mode to the loaded data type + + + + + This checkable button enables or disables the automatic switching of the editor mode. When a new cell is selected or new data is imported and the automatic switching is enabled, the mode adjusts to the detected data type. You can then change the editor mode manually. If you want to keep this manually switched mode while moving through the cells, switch the button off. + + + + + Auto-switch + + + + + The text editor modes let you edit plain text, as well as JSON or XML data with syntax highlighting, automatic formatting and validation before saving. + +Errors are indicated with a red squiggle underline. + + + + + This Qt editor is used for right-to-left scripts, which are not supported by the default Text editor. The presence of right-to-left characters is detected and this editor mode is automatically selected. + + + + + Open preview dialog for printing the data currently stored in the cell + + + + + Auto-format: pretty print on loading, compact on saving. + + + + + When enabled, the auto-format feature formats the data on loading, breaking the text in lines and indenting it for maximum readability. On data saving, the auto-format feature compacts the data removing end of lines, and unnecessary whitespace. + + + + + Word Wrap + + + + + Wrap lines on word boundaries + + + + + + Open in default application or browser + + + + + Open in application + + + + + The value is interpreted as a file or URL and opened in the default application or web browser. + + + + + Save file reference... + + + + + Save reference to file + + + + + + Open in external application + + + + + Autoformat + + + + + &Export... + + + + + + &Import... + + + + + + Import from file + Importovat ze souboru + + + + + Opens a file dialog used to import any kind of data to this database cell. + + + + + Export to file + Exportovat do souboru + + + + Opens a file dialog used to export the contents of this database cell to a file. + + + + + Erases the contents of the cell + Vymazat obsah buňky + + + + This area displays information about the data present in this database cell + Tato oblast zobrazuje informace o aktuálních datech v této databázové buňce + + + + Type of data currently in cell + SouÄasný typ dat v buňce + + + + Size of data currently in table + SouÄasná velikost dat v tabulce + + + + + Print... + Tisk... + + + + Open preview dialog for printing displayed image + + + + + + Ctrl+P + + + + + Open preview dialog for printing displayed text + + + + + Copy Hex and ASCII + + + + + Copy selected hexadecimal and ASCII columns to the clipboard + + + + + Ctrl+Shift+C + + + + + Choose a filename to export data + Vyberte název souboru pro export dat + + + + Type of data currently in cell: %1 Image + Aktuální typ dat v buňce: %1 Obrázek + + + + %1x%2 pixel(s) + %1x%2 pixel/ů + + + + Type of data currently in cell: NULL + Aktuální typ dat v buňce: NULL + + + + + Type of data currently in cell: Text / Numeric + Aktuální typ dat v buňce: Text / Číselný + + + + + Image data can't be viewed in this mode. + + + + + + Try switching to Image or Binary mode. + + + + + + Binary data can't be viewed in this mode. + + + + + + Try switching to Binary mode. + Zkuste pÅ™epnout do binárního režimu. + + + + Couldn't save file: %1. + + + + + The data has been saved to a temporary file and has been opened with the default application. You can now edit the file and, when you are ready, apply the saved new data to the cell editor or cancel any changes. + + + + + + Image files (%1) + Soubory obrázků (%1) + + + + Binary files (*.bin) + Binární soubory (*.bin) + + + + Choose a file to import + Vyberte soubor pro import + + + + %1 Image + %1 Obrázek + + + + Invalid data for this mode + Neplatná data pro tento režim + + + + The cell contains invalid %1 data. Reason: %2. Do you really want to apply it to the cell? + + + + + + + %n character(s) + + %n znak + %n znaků + + + + + + Type of data currently in cell: Valid JSON + + + + + Type of data currently in cell: Binary + Aktuální typ dat v buňce: Binární + + + + + %n byte(s) + + %n byte + %n bytů + + + + + + EditIndexDialog + + + &Name + Název + + + + Order + Řadit + + + + &Table + Tabulka + + + + Edit Index Schema + Upravit schéma indexů + + + + &Unique + Unikátní + + + + For restricting the index to only a part of the table you can specify a WHERE clause here that selects the part of the table that should be indexed + + + + + Partial inde&x clause + + + + + Colu&mns + Sloupce + + + + Table column + Sloupec tabulky + + + + Type + Typ + + + + Add a new expression column to the index. Expression columns contain SQL expression rather than column names. + + + + + Index column + Index sloupce + + + + Deleting the old index failed: +%1 + + + + + Creating the index failed: +%1 + Vytváření indexu se nezdaÅ™ilo: +%1 + + + + EditTableDialog + + + Edit table definition + Upravit definici tabulky + + + + Table + Tabulka + + + + Advanced + PokroÄilé + + + + Make this a 'WITHOUT rowid' table. Setting this flag requires a field of type INTEGER with the primary key flag set and the auto increment flag unset. + + + + + Without Rowid + Bez id řádku + + + + Database sche&ma + + + + + Fields + Pole + + + + Add + + + + + Remove + + + + + Move to top + + + + + Move up + + + + + Move down + + + + + Move to bottom + + + + + + Name + Název + + + + + Type + Typ + + + + NN + NN + + + + Not null + Není null + + + + PK + PK + + + + Primary key + Primární klÃ­Ä + + + + AI + AI + + + + Autoincrement + Autoincrement + + + + U + U + + + + + + Unique + Unikátní + + + + Default + Výchozí + + + + Default value + Výchozí hodnota + + + + + + Check + Zkontrolovat + + + + Check constraint + Zkontrolovat omezení + + + + Collation + + + + + + + Foreign Key + Cizí klÃ­Ä + + + + Constraints + + + + + Add constraint + + + + + Remove constraint + + + + + Columns + Sloupce + + + + SQL + + + + + <html><head/><body><p><span style=" font-weight:600; color:#ff0000;">Warning: </span>There is something with this table definition that our parser doesn't fully understand. Modifying and saving this table might result in problems.</p></body></html> + + + + + + Primary Key + + + + + Add a primary key constraint + + + + + Add a foreign key constraint + + + + + Add a unique constraint + + + + + Add a check constraint + + + + + + There can only be one primary key for each table. Please modify the existing primary key instead. + + + + + Error creating table. Message from database engine: +%1 + Chyba pÅ™i vytváření tabulky. Zpráva z databáze: +%1 + + + + There already is a field with that name. Please rename it first or choose a different name for this field. + Pole s tímto názvem již existuje. Nejdříve jej pÅ™ejmenujte, nebo vyberte pro toto pole jiný název, prosím. + + + + This column is referenced in a foreign key in table %1 and thus its name cannot be changed. + Tento sloupec je použit jako cizí klÃ­Ä v tabulce %1 a jeho název nemůže být zmÄ›nÄ›n. + + + + There is at least one row with this field set to NULL. This makes it impossible to set this flag. Please change the table data first. + Existuje alespoň jeden řádek, který je nastaven na NULL. Z tohoto důvodu je nemožné nastavit tento flag. Nejprve změňte data v tabulce, prosím. + + + + There is at least one row with a non-integer value in this field. This makes it impossible to set the AI flag. Please change the table data first. + Existuje alespoň jeden řádek, který neobsahuje hodnotu typu integer. Z tohoto důvodu je nemožné nastavit AI flag. Nejprve změňte data v tabulce, prosím. + + + + Column '%1' has duplicate data. + + + + + + This makes it impossible to enable the 'Unique' flag. Please remove the duplicate data, which will allow the 'Unique' flag to then be enabled. + + + + + Are you sure you want to delete the field '%1'? +All data currently stored in this field will be lost. + + + + + Please add a field which meets the following criteria before setting the without rowid flag: + - Primary key flag set + - Auto increment disabled + + + + + ExportDataDialog + + + Export data as CSV + Exportovat data do CSV + + + + Tab&le(s) + Tabulka/ky + + + + Colu&mn names in first line + Názvy sloupců v prvním řádku + + + + Fie&ld separator + OddÄ›lovaÄ pole + + + + , + , + + + + ; + ; + + + + Tab + Karta + + + + | + | + + + + + + Other + Ostatní + + + + &Quote character + &Uvozovka + + + + " + " + + + + ' + ' + + + + New line characters + Znaky nového řádku + + + + Windows: CR+LF (\r\n) + Windows: CR+LF (\r\n) + + + + Unix: LF (\n) + Unix: LF (\n) + + + + Pretty print + Pretty print + + + + + Could not open output file: %1 + Nemohu otevřít výstupní soubor: %1 + + + + + Choose a filename to export data + Vyberte název souboru pro export dat + + + + Export data as JSON + Exportovat data jako JSON + + + + exporting CSV + exportování CSV + + + + exporting JSON + exportování JSONu + + + + Please select at least 1 table. + Vyberte alespoň jednu tabulku, prosím. + + + + Choose a directory + Vybrat složku + + + + Export completed. + Export byl dokonÄen. + + + + ExportSqlDialog + + + Export SQL... + Exportovat SQL... + + + + Tab&le(s) + Tabulka/ky + + + + Select All + Vybrat vÅ¡e + + + + Deselect All + ZruÅ¡it výbÄ›r + + + + &Options + Volby + + + + Keep column names in INSERT INTO + Zachovat názvy sloupců v INSERT INTO + + + + Multiple rows (VALUES) per INSERT statement + Více řádků (VALUES) pro příkaz INSERT + + + + Export everything + Exportovat vÅ¡e + + + + Export data only + Exportovat pouze data + + + + Keep old schema (CREATE TABLE IF NOT EXISTS) + + + + + Overwrite old schema (DROP TABLE, then CREATE TABLE) + PÅ™epsat staré schéma (DROP TABLE, then CREATE TABLE) + + + + Export schema only + Exportovat pouze schéma + + + + Please select at least one table. + Vyberte prosím aspoň jednu tabulku. + + + + Choose a filename to export + Vyberte název souboru pro export + + + + Export completed. + Export dokonÄen. + + + + Export cancelled or failed. + Export byl zruÅ¡en nebo selhal. + + + + ExtendedScintilla + + + + Ctrl+H + + + + + Ctrl+F + + + + + + Ctrl+P + + + + + Find... + + + + + Find and Replace... + Najít a nahradit... + + + + Print... + Tisk... + + + + ExtendedTableWidget + + + Use as Exact Filter + + + + + Containing + + + + + Not containing + + + + + Not equal to + + + + + Greater than + VÄ›tší než + + + + Less than + Menší než + + + + Greater or equal + VÄ›tší nebo rovno + + + + Less or equal + Menší nebo rovno + + + + Between this and... + Mezi tímto a... + + + + Regular expression + + + + + Edit Conditional Formats... + + + + + Set to NULL + Nastavit na NULL + + + + Copy + Kopírovat + + + + Copy with Headers + Kopírovat s hlaviÄkami + + + + Copy as SQL + Kopírovat jako SQL + + + + Paste + Vložit + + + + Print... + Tisk... + + + + Use in Filter Expression + + + + + Alt+Del + + + + + Ctrl+Shift+C + + + + + Ctrl+Alt+C + + + + + The content of the clipboard is bigger than the range selected. +Do you want to insert it anyway? + + + + + <p>Not all data has been loaded. <b>Do you want to load all data before selecting all the rows?</b><p><p>Answering <b>No</b> means that no more data will be loaded and the selection will not be performed.<br/>Answering <b>Yes</b> might take some time while the data is loaded but the selection will be complete.</p>Warning: Loading all the data might require a great amount of memory for big tables. + + + + + Cannot set selection to NULL. Column %1 has a NOT NULL constraint. + + + + + FileExtensionManager + + + File Extension Manager + + + + + &Up + Nahoru + + + + &Down + Dolů + + + + &Add + PÅ™idat + + + + &Remove + Odstranit + + + + + Description + Popis + + + + Extensions + Rozšíření + + + + *.extension + *.extension + + + + FilterLineEdit + + + Filter + Filtr + + + + These input fields allow you to perform quick filters in the currently selected table. +By default, the rows containing the input text are filtered out. +The following operators are also supported: +% Wildcard +> Greater than +< Less than +>= Equal to or greater +<= Equal to or less += Equal to: exact match +<> Unequal: exact inverse match +x~y Range: values between x and y +/regexp/ Values matching the regular expression + + + + + Clear All Conditional Formats + + + + + Use for Conditional Format + + + + + Edit Conditional Formats... + + + + + Set Filter Expression + + + + + What's This? + Co je toto? + + + + Is NULL + je NULL + + + + Is not NULL + Není NULL + + + + Is empty + Je prázdný + + + + Is not empty + Není prázdný + + + + Not containing... + + + + + Equal to... + Rovný k... + + + + Not equal to... + Není rovný k... + + + + Greater than... + VÄ›tší než... + + + + Less than... + Menší než... + + + + Greater or equal... + VÄ›tší nebo rovno... + + + + Less or equal... + Menší nebo rovno... + + + + In range... + V rozmezí... + + + + Regular expression... + + + + + FindReplaceDialog + + + Find and Replace + Najít a nahradit + + + + Fi&nd text: + Najít text + + + + Re&place with: + Nahradit s: + + + + Match &exact case + + + + + Match &only whole words + + + + + When enabled, the search continues from the other end when it reaches one end of the page + + + + + &Wrap around + + + + + When set, the search goes backwards from cursor position, otherwise it goes forward + + + + + Search &backwards + + + + + <html><head/><body><p>When checked, the pattern to find is searched only in the current selection.</p></body></html> + + + + + &Selection only + + + + + <html><head/><body><p>When checked, the pattern to find is interpreted as a UNIX regular expression. See <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>.</p></body></html> + + + + + Use regular e&xpressions + + + + + Find the next occurrence from the cursor position and in the direction set by "Search backwards" + + + + + &Find Next + Najít další + + + + F3 + + + + + &Replace + Nahradit + + + + Highlight all the occurrences of the text in the page + + + + + F&ind All + Najít vÅ¡e + + + + Replace all the occurrences of the text in the page + + + + + Replace &All + Nahradit vÅ¡e + + + + The searched text was not found + Hledaný text nebyl nalezen + + + + The searched text was not found. + Hledaný text nebyl nalezen. + + + + The searched text was found one time. + Hledaný text byl nalezen jednou. + + + + The searched text was found %1 times. + Hledaný text byl nalezen %1 krát. + + + + The searched text was replaced one time. + Hledaný text byl nahrazen jednou. + + + + The searched text was replaced %1 times. + Hledaný text byl nahrazen %1 krát. + + + + ForeignKeyEditor + + + &Reset + + + + + Foreign key clauses (ON UPDATE, ON DELETE etc.) + + + + + ImportCsvDialog + + + Import CSV file + Importovat soubor CSV + + + + Table na&me + Název tabulky + + + + &Column names in first line + &Názvy sloupců v prvním řádku + + + + Field &separator + OddÄ›lovaÄ pole + + + + , + , + + + + ; + ; + + + + + Tab + Karta + + + + | + | + + + + Other + Ostatní + + + + &Quote character + &Uvozovka + + + + + Other (printable) + + + + + + Other (code) + + + + + " + " + + + + ' + ' + + + + &Encoding + Kódování + + + + UTF-8 + UTF-8 + + + + UTF-16 + UTF-16 + + + + ISO-8859-1 + ISO-8859-1 + + + + Trim fields? + OÅ™ezat pole? + + + + Separate tables + OddÄ›lit tabulky + + + + Advanced + PokroÄilé + + + + When importing an empty value from the CSV file into an existing table with a default value for this column, that default value is inserted. Activate this option to insert an empty value instead. + + + + + Ignore default &values + Ignorovat výchozí hodnoty + + + + Activate this option to stop the import when trying to import an empty value into a NOT NULL column without a default value. + + + + + Fail on missing values + + + + + Disable data type detection + + + + + Disable the automatic data type detection when creating a new table. + + + + + When importing into an existing table with a primary key, unique constraints or a unique index there is a chance for a conflict. This option allows you to select a strategy for that case: By default the import is aborted and rolled back but you can also choose to ignore and not import conflicting rows or to replace the existing row in the table. + + + + + Abort import + + + + + Ignore row + + + + + Replace existing row + + + + + Conflict strategy + + + + + + Deselect All + ZruÅ¡it celý výbÄ›r + + + + Match Similar + + + + + Select All + Vybrat vÅ¡e + + + + There is already a table named '%1' and an import into an existing table is only possible if the number of columns match. + + + + + There is already a table named '%1'. Do you want to import the data into it? + + + + + Creating restore point failed: %1 + Vytváření bodu obnovy selhalo: %1 + + + + Creating the table failed: %1 + Vytváření tabulky selhalo: %1 + + + + importing CSV + importování CSV + + + + Importing the file '%1' took %2ms. Of this %3ms were spent in the row function. + + + + + Inserting row failed: %1 + Vkládání řádku selhalo: %1 + + + + MainWindow + + + DB Browser for SQLite + DB Browser pro SQLite + + + + toolBar1 + toolBar1 + + + + Opens the SQLCipher FAQ in a browser window + OtevÅ™e SQLCipher FAQ v oknÄ› prohlížeÄe + + + + Export one or more table(s) to a JSON file + Export jedné nebo více tabulek do souboru JSON + + + + &File + &Soubor + + + + &Import + &Import + + + + &Export + &Export + + + + Open an existing database file in read only mode + + + + + &Edit + Upravit + + + + &View + Pohled + + + + &Help + Pomoc + + + + DB Toolbar + Panel nástrojů DB + + + + Edit Database &Cell + Upravit databázovou buňku + + + + DB Sche&ma + DB Schéma + + + + + Execute SQL + This has to be equal to the tab title in all the main tabs + ProveÄte SQL + + + + + Execute current line + Provést aktuální řádek + + + + This button executes the SQL statement present in the current editor line + + + + + Shift+F5 + + + + + Sa&ve Project + Ulo&žit Projekt + + + + User + Uživatel + + + + + Database Structure + This has to be equal to the tab title in all the main tabs + Databázová Struktura + + + + + Browse Data + This has to be equal to the tab title in all the main tabs + Prohlížet data + + + + + Edit Pragmas + This has to be equal to the tab title in all the main tabs + Editovat Pragma + + + + Application + Aplikace + + + + &Clear + &VyÄistit + + + + &New Database... + Nová databáze... + + + + + Create a new database file + VytvoÅ™it nový databázový soubor + + + + This option is used to create a new database file. + Tato volba slouží k vytvoÅ™ení nového souboru databáze. + + + + Ctrl+N + + + + + + &Open Database... + Otevřít databázi... + + + + + + + + Open an existing database file + Otevřít existující soubor databáze + + + + + + This option is used to open an existing database file. + Tato volba slouží k otevÅ™ení existujícího souboru databáze. + + + + Ctrl+O + + + + + &Close Database + &Zavřít databázi + + + + This button closes the connection to the currently open database file + + + + + + Ctrl+W + + + + + + Revert database to last saved state + Vrátit databázi do posledního uloženého stavu + + + + This option is used to revert the current database file to its last saved state. All changes made since the last save operation are lost. + + + + + + Write changes to the database file + Zapsat zmÄ›ny do souboru databáze + + + + This option is used to save changes to the database file. + Tato volba slouží k uložení provedených zmÄ›n do souboru databáze. + + + + Ctrl+S + + + + + Compact &Database... + + + + + Compact the database file, removing space wasted by deleted records + + + + + + Compact the database file, removing space wasted by deleted records. + + + + + E&xit + Exit + + + + Ctrl+Q + + + + + Import data from an .sql dump text file into a new or existing database. + Importovat data z textového souboru .sql do nové nebo již existující databáze. + + + + This option lets you import data from an .sql dump text file into a new or existing database. SQL dump files can be created on most database engines, including MySQL and PostgreSQL. + + + + + Open a wizard that lets you import data from a comma separated text file into a database table. + OtevÅ™e průzkumníka, kde můžete importovat data z textového souboru, kde jsou data oddÄ›lena Äárkami, do databázové tabulky. + + + + Open a wizard that lets you import data from a comma separated text file into a database table. CSV files can be created on most database and spreadsheet applications. + + + + + Export a database to a .sql dump text file. + Exportovat databázi do textového souboru .sql + + + + This option lets you export a database to a .sql dump text file. SQL dump files contain all data necessary to recreate the database on most database engines, including MySQL and PostgreSQL. + + + + + Export a database table as a comma separated text file. + Exportovat databázovou tabulku jako textový soubor oddÄ›lený Äárkami. + + + + Export a database table as a comma separated text file, ready to be imported into other database or spreadsheet applications. + + + + + Open the Create Table wizard, where it is possible to define the name and fields for a new table in the database + + + + + + Delete Table + Smazat Tabulku + + + + Open the Delete Table wizard, where you can select a database table to be dropped. + + + + + Open the Modify Table wizard, where it is possible to rename an existing table. It is also possible to add or delete fields form a table, as well as modify field names and types. + + + + + Open the Create Index wizard, where it is possible to define a new index on an existing database table. + + + + + &Preferences... + &Možnosti... + + + + + Open the preferences window. + Otevřít okno s možnostmi. + + + + &DB Toolbar + Panel nástrojů DB + + + + Shows or hides the Database toolbar. + Zobrazí nebo skryje liÅ¡tu Databáze. + + + + Shift+F1 + + + + + Open SQL file(s) + + + + + This button opens files containing SQL statements and loads them in new editor tabs + + + + + Execute line + + + + + &Wiki + Wiki + + + + F1 + + + + + Bug &Report... + Nahlásit chybu... + + + + Feature Re&quest... + Požadavek na funkci... + + + + Web&site + Webová stránka + + + + &Donate on Patreon... + PÅ™ispÄ›t na Patreon... + + + + This button lets you save all the settings associated to the open DB to a DB Browser for SQLite project file + + + + + This button lets you open a DB Browser for SQLite project file + + + + + Browse Table + + + + + &Attach Database... + PÅ™iložit databázi... + + + + + Add another database file to the current database connection + + + + + This button lets you add another database file to the current database connection + + + + + &Set Encryption... + Nastavit Å¡ifrování... + + + + SQLCipher &FAQ + SQLCipher FAQ + + + + Table(&s) to JSON... + Tabulka(ky) do JSONu... + + + + Open Data&base Read Only... + + + + + Ctrl+Shift+O + + + + + Save results + Uložit výsledky + + + + Save the results view + + + + + This button lets you save the results of the last executed query + + + + + + Find text in SQL editor + Najít text v SQL editoru + + + + Find + + + + + This button opens the search bar of the editor + + + + + Ctrl+F + + + + + + Find or replace text in SQL editor + Najít a nahradit text v SQL editoru + + + + Find or replace + + + + + This button opens the find/replace dialog for the current editor tab + + + + + Ctrl+H + + + + + Export to &CSV + Export do CSV + + + + Save as &view + Uložit jako pohled + + + + Save as view + Uložit jako pohled + + + + Shows or hides the Project toolbar. + Zobrazit nebo skrýt liÅ¡tu projektu + + + + Extra DB Toolbar + Extra DB Toolbar + + + + New In-&Memory Database + + + + + Drag && Drop Qualified Names + + + + + + Use qualified names (e.g. "Table"."Field") when dragging the objects and dropping them into the editor + + + + + Drag && Drop Enquoted Names + + + + + + Use escaped identifiers (e.g. "Table1") when dragging the objects and dropping them into the editor + + + + + &Integrity Check + + + + + Runs the integrity_check pragma over the opened database and returns the results in the Execute SQL tab. This pragma does an integrity check of the entire database. + + + + + &Foreign-Key Check + + + + + Runs the foreign_key_check pragma over the opened database and returns the results in the Execute SQL tab + + + + + &Quick Integrity Check + + + + + Run a quick integrity check over the open DB + + + + + Runs the quick_check pragma over the opened database and returns the results in the Execute SQL tab. This command does most of the checking of PRAGMA integrity_check but runs much faster. + + + + + &Optimize + + + + + Attempt to optimize the database + + + + + Runs the optimize pragma over the opened database. This pragma might perform optimizations that will improve the performance of future queries. + + + + + + Print + Tisk + + + + Print text from current SQL editor tab + + + + + Open a dialog for printing the text in the current SQL editor tab + + + + + Print the structure of the opened database + + + + + Open a dialog for printing the structure of the opened database + + + + + &Save Project As... + + + + + + + Save the project in a file selected in a dialog + + + + + Save A&ll + + + + + + + Save DB file, project file and opened SQL files + + + + + Ctrl+Shift+S + + + + + &Recently opened + &Nedávno otevÅ™ené + + + + Open &tab + Otevřít kartu + + + + Ctrl+T + + + + + This is the structure of the opened database. +You can drag SQL statements from an object row and drop them into other applications or into another instance of 'DB Browser for SQLite'. + + + + + + Un/comment block of SQL code + + + + + Un/comment block + + + + + Comment or uncomment current line or selected block of code + + + + + Comment or uncomment the selected lines or the current line, when there is no selection. All the block is toggled according to the first line. + + + + + Ctrl+/ + + + + + Stop SQL execution + + + + + Stop execution + + + + + Stop the currently running SQL script + + + + + Warning: this pragma is not readable and this value has been inferred. Writing the pragma might overwrite a redefined LIKE provided by an SQLite extension. + + + + + &Tools + Nástroje + + + + SQL &Log + SQL &Log + + + + Show S&QL submitted by + + + + + Error Log + + + + + This button clears the contents of the SQL logs + + + + + This panel lets you examine a log of all SQL commands issued by the application or by yourself + + + + + &Plot + + + + + This is the structure of the opened database. +You can drag multiple object names from the Name column and drop them into the SQL editor and you can adjust the properties of the dropped names using the context menu. This would help you in composing SQL statements. +You can drag SQL statements from the Schema column and drop them into the SQL editor or into other applications. + + + + + + &Remote + Vzdálené + + + + + Project Toolbar + + + + + Extra DB toolbar + Extra DB toolbar + + + + + + Close the current database file + + + + + Ctrl+F4 + + + + + &Revert Changes + Vrátit ZmÄ›ny + + + + &Write Changes + Zapsat ZmÄ›ny + + + + &Database from SQL file... + Databáze z SQL souboru... + + + + &Table from CSV file... + Tabulka ze souboru CSV... + + + + &Database to SQL file... + Databáze do souboru SQL... + + + + &Table(s) as CSV file... + Tabulka/ky jako soubor CSV... + + + + &Create Table... + VytvoÅ™it Tabulku... + + + + &Delete Table... + Smazat Tabulku... + + + + &Modify Table... + Upravit Tabulku... + + + + Create &Index... + VytvoÅ™it Index... + + + + W&hat's This? + Co je toto? + + + + &About + O + + + + This button opens a new tab for the SQL editor + + + + + &Execute SQL + &Provést příkaz SQL + + + + Execute all/selected SQL + Provést vÅ¡echny/vybrané SQL + + + + This button executes the currently selected SQL statements. If no text is selected, all SQL statements are executed. + + + + + + + Save SQL file + Uložit SQL soubor + + + + &Load Extension... + NaÄíst rozšíření... + + + + Ctrl+E + + + + + Export as CSV file + Exportovat jako soubor CSV + + + + Export table as comma separated values file + Exportovat tabulku do souboru jako hodnoty oddÄ›lené Äárkami + + + + + Save the current session to a file + Uložit aktuální session do souboru + + + + Open &Project... + Otevřít projekt... + + + + + Load a working session from a file + + + + + + Save SQL file as + Uložit soubor SQL jako + + + + This button saves the content of the current SQL editor tab to a file + + + + + &Browse Table + &Prohlížet Tabulku + + + + Copy Create statement + Kopírovat příkaz Create + + + + Copy the CREATE statement of the item to the clipboard + Zkopírovat do schránky příkaz CREATE + + + + Ctrl+Return + + + + + Ctrl+L + + + + + + Ctrl+P + + + + + Ctrl+D + + + + + Ctrl+I + + + + + Encrypted + Å ifrováno + + + + Read only + Pouze pro Ätení + + + + Database file is read only. Editing the database is disabled. + Soubor databáze je urÄen pouze pro Ätení. Úprava databáze je zakázána. + + + + Database encoding + Kódování databáze + + + + Database is encrypted using SQLCipher + Databáze je Å¡ifrována pÅ™es SQLCipher + + + + + Choose a database file + Vyberte soubor databáze + + + + + + Choose a filename to save under + Vyberte název souboru pro uložení + + + + Error while saving the database file. This means that not all changes to the database were saved. You need to resolve the following error first. + +%1 + + + + + Are you sure you want to undo all changes made to the database file '%1' since the last save? + Jste si jisti, že chcete vrátit zpÄ›t vÅ¡echny provedené zmÄ›ny v databázi '%1' od posledního uložení? + + + + Choose a file to import + Vyberte soubor pro import + + + + &%1 %2%3 + &%1 %2%3 + + + + (read only) + + + + + Open Database or Project + + + + + Attach Database... + + + + + Import CSV file(s)... + + + + + Select the action to apply to the dropped file(s). <br/>Note: only 'Import' will process more than one file. + + + + + + + + + Do you want to save the changes made to SQL tabs in the project file '%1'? + + + + + Text files(*.sql *.txt);;All files(*) + Textové soubory(*.sql *.txt);;VÅ¡echny soubory(*) + + + + Do you want to create a new database file to hold the imported data? +If you answer no we will attempt to import the data in the SQL file to the current database. + + + + + You are still executing SQL statements. Closing the database now will stop their execution, possibly leaving the database in an inconsistent state. Are you sure you want to close the database? + + + + + Do you want to save the changes made to the project file '%1'? + + + + + File %1 already exists. Please choose a different name. + Soubor %1 již existuje. Vyberte jiný název, prosím. + + + + Error importing data: %1 + Chyba pÅ™i importu dat: %1 + + + + Import completed. + Import dokonÄen. + + + + Delete View + Smazat Pohled + + + + Modify View + + + + + Delete Trigger + Smazat Spoušť + + + + Modify Trigger + + + + + Delete Index + Smazat Index + + + + Modify Index + ZmÄ›nit Index + + + + Modify Table + ZmÄ›nit tabulku + + + + Do you want to save the changes made to SQL tabs in a new project file? + + + + + Do you want to save the changes made to the SQL file %1? + + + + + The statements in this tab are still executing. Closing the tab will stop the execution. This might leave the database in an inconsistent state. Are you sure you want to close the tab? + + + + + Could not find resource file: %1 + + + + + Choose a project file to open + Vybrat soubor projektu k otevÅ™ení + + + + This project file is using an old file format because it was created using DB Browser for SQLite version 3.10 or lower. Loading this file format is still fully supported but we advice you to convert all your project files to the new file format because support for older formats might be dropped at some point in the future. You can convert your files by simply opening and re-saving them. + + + + + Could not open project file for writing. +Reason: %1 + + + + + Busy (%1) + + + + + Setting PRAGMA values will commit your current transaction. +Are you sure? + + + + + Window Layout + + + + + Reset Window Layout + + + + + Alt+0 + + + + + Simplify Window Layout + + + + + Shift+Alt+0 + + + + + Dock Windows at Bottom + + + + + Dock Windows at Left Side + + + + + Dock Windows at Top + + + + + The database is currenctly busy. + + + + + Click here to interrupt the currently running query. + + + + + Could not open database file. +Reason: %1 + + + + + In-Memory database + + + + + Are you sure you want to delete the table '%1'? +All data associated with the table will be lost. + + + + + Are you sure you want to delete the view '%1'? + + + + + Are you sure you want to delete the trigger '%1'? + + + + + Are you sure you want to delete the index '%1'? + + + + + Error: could not delete the table. + + + + + Error: could not delete the view. + + + + + Error: could not delete the trigger. + + + + + Error: could not delete the index. + + + + + Message from database engine: +%1 + + + + + Editing the table requires to save all pending changes now. +Are you sure you want to save the database? + + + + + Edit View %1 + + + + + Edit Trigger %1 + + + + + You are already executing SQL statements. Do you want to stop them in order to execute the current statements instead? Note that this might leave the database in an inconsistent state. + + + + + -- EXECUTING SELECTION IN '%1' +-- + + + + + -- EXECUTING LINE IN '%1' +-- + + + + + -- EXECUTING ALL IN '%1' +-- + + + + + + At line %1: + + + + + Result: %1 + + + + + Result: %2 + + + + + Setting PRAGMA values or vacuuming will commit your current transaction. +Are you sure? + + + + + Opened '%1' in read-only mode from recent file list + + + + + Opened '%1' from recent file list + + + + + This action will open a new SQL tab with the following statements for you to edit and run: + + + + + Rename Tab + + + + + Duplicate Tab + + + + + Close Tab + + + + + Opening '%1'... + + + + + There was an error opening '%1'... + + + + + Value is not a valid URL or filename: %1 + + + + + %1 rows returned in %2ms + + + + + Choose text files + Vybrat textové soubory + + + + Import completed. Some foreign key constraints are violated. Please fix them before saving. + + + + + Select SQL file to open + Vyberte soubor SQL k otevÅ™ení + + + + Select file name + Vyberte název souboru + + + + Select extension file + Vyberte soubor s rozšířením + + + + Extension successfully loaded. + Rozšíření bylo úspěšnÄ› naÄteno. + + + + Error loading extension: %1 + Chyba pÅ™i naÄítání přípony: %1 + + + + + Don't show again + Znovu nezobrazovat + + + + New version available. + Dostupná nová verze. + + + + A new DB Browser for SQLite version is available (%1.%2.%3).<br/><br/>Please download at <a href='%4'>%4</a>. + Nová verze DB Browseru pro SQLite je nyní dostupná (%1.%2.%3).<br/><br/>StáhnÄ›te ji prosím na <a href='%4'>%4</a>. + + + + Project saved to file '%1' + + + + + Collation needed! Proceed? + Je potÅ™eba provést collation! Potvrdit? + + + + A table in this database requires a special collation function '%1' that this application can't provide without further knowledge. +If you choose to proceed, be aware bad things can happen to your database. +Create a backup! + + + + + creating collation + + + + + Set a new name for the SQL tab. Use the '&&' character to allow using the following character as a keyboard shortcut. + + + + + Please specify the view name + Specifikujte název pohledu, prosím + + + + There is already an object with that name. Please choose a different name. + Objekt s tímto názvem již existuje. Vyberte jiný název, prosím. + + + + View successfully created. + Pohled byl úspěšnÄ› vytvoÅ™en. + + + + Error creating view: %1 + Chyba pÅ™i vytváření pohledu: %1 + + + + This action will open a new SQL tab for running: + + + + + Press Help for opening the corresponding SQLite reference page. + + + + + DB Browser for SQLite project file (*.sqbpro) + DB Browser pro SQLite project file (*.sqbpro) + + + + Error checking foreign keys after table modification. The changes will be reverted. + + + + + This table did not pass a foreign-key check.<br/>You should run 'Tools | Foreign-Key Check' and fix the reported issues. + + + + + Execution finished with errors. + + + + + Execution finished without errors. + + + + + NullLineEdit + + + Set to NULL + Nastavit na NULL + + + + Alt+Del + + + + + PlotDock + + + Plot + + + + + <html><head/><body><p>This pane shows the list of columns of the currently browsed table or the just executed query. You can select the columns that you want to be used as X or Y axis for the plot pane below. The table shows detected axis type that will affect the resulting plot. For the Y axis you can only select numeric columns, but for the X axis you will be able to select:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Date/Time</span>: strings with format &quot;yyyy-MM-dd hh:mm:ss&quot; or &quot;yyyy-MM-ddThh:mm:ss&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Date</span>: strings with format &quot;yyyy-MM-dd&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Time</span>: strings with format &quot;hh:mm:ss&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Label</span>: other string formats. Selecting this column as X axis will produce a Bars plot with the column values as labels for the bars</li><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Numeric</span>: integer or real values</li></ul><p>Double-clicking the Y cells you can change the used color for that graph.</p></body></html> + + + + + Columns + Sloupce + + + + X + X + + + + Y1 + + + + + Y2 + + + + + Axis Type + + + + + Here is a plot drawn when you select the x and y values above. + +Click on points to select them in the plot and in the table. Ctrl+Click for selecting a range of points. + +Use mouse-wheel for zooming and mouse drag for changing the axis range. + +Select the axes or axes labels to drag and zoom only in that orientation. + + + + + Line type: + Typ řádku: + + + + + None + Žádná + + + + Line + Řádek + + + + StepLeft + KrokVlevo + + + + StepRight + KrokVpravo + + + + StepCenter + KrokDoprostÅ™ed + + + + Impulse + Impuls + + + + Point shape: + + + + + Cross + Kříž + + + + Plus + Plus + + + + Circle + Kruh + + + + Disc + Disk + + + + Square + ÄŒtverec + + + + Diamond + Diamand + + + + Star + HvÄ›zda + + + + Triangle + Trojúhelník + + + + TriangleInverted + ObrácenýTrojúhelník + + + + CrossSquare + + + + + PlusSquare + PlusÄŒtverec + + + + CrossCircle + + + + + PlusCircle + + + + + Peace + + + + + <html><head/><body><p>Save current plot...</p><p>File format chosen by extension (png, jpg, pdf, bmp)</p></body></html> + + + + + Save current plot... + + + + + + Load all data and redraw plot + + + + + + + Row # + Řádek # + + + + Copy + Kopírovat + + + + Print... + Tisk... + + + + Show legend + Zobrazit legendu + + + + Stacked bars + + + + + Date/Time + Datum/Äas + + + + Date + Datum + + + + Time + ÄŒas + + + + + Numeric + + + + + Label + Å títek + + + + Invalid + + + + + Load all data and redraw plot. +Warning: not all data has been fetched from the table yet due to the partial fetch mechanism. + + + + + Choose an axis color + Vyberte barvu osy + + + + Choose a filename to save under + Vyberte název souboru pro uložení + + + + PNG(*.png);;JPG(*.jpg);;PDF(*.pdf);;BMP(*.bmp);;All Files(*) + PNG(*.png);;JPG(*.jpg);;PDF(*.pdf);;BMP(*.bmp);;VÅ¡echny Soubory(*) + + + + There are curves in this plot and the selected line style can only be applied to graphs sorted by X. Either sort the table or query by X to remove curves or select one of the styles supported by curves: None or Line. + + + + + Loading all remaining data for this table took %1ms. + + + + + PreferencesDialog + + + Preferences + Možnosti + + + + &General + &Obecné + + + + Remember last location + Zapamatovat poslední umístÄ›ní + + + + Always use this location + Vždy použít toto umístÄ›ní + + + + Remember last location for session only + Pamatovat poslední umístÄ›ní pouze po dobu trvání session + + + + + + ... + ... + + + + Default &location + Výchozí &umístÄ›ní + + + + Lan&guage + Jazyk + + + + Automatic &updates + Automatické &aktualizace + + + + + + + + + + + + enabled + povoleno + + + + Show remote options + Zobrazit vzdálené možnosti + + + + &Database + &Databáze + + + + Database &encoding + Kódování &databáze + + + + Open databases with foreign keys enabled. + OtevÅ™e databázi s povolenými cizími klíÄi. + + + + &Foreign keys + &Cizí klíÄe + + + + SQ&L to execute after opening database + SQ&L k vykonání po otevÅ™ení databáze + + + + Data &Browser + ProhlížeÄ Dat + + + + Remove line breaks in schema &view + + + + + Prefetch block si&ze + + + + + Default field type + Výchozí typ pole + + + + Font + Font + + + + &Font + &Font + + + + Content + Obsah + + + + Symbol limit in cell + Maximální poÄet znaků v buňce + + + + NULL + NULL + + + + Regular + Regulární + + + + Binary + Binární + + + + Background + Pozadí + + + + Filters + Filtry + + + + Threshold for completion and calculation on selection + + + + + Show images in cell + + + + + Enable this option to show a preview of BLOBs containing image data in the cells. This can affect the performance of the data browser, however. + + + + + Escape character + + + + + Delay time (&ms) + ZpoždÄ›ní (&ms) + + + + Set the waiting time before a new filter value is applied. Can be set to 0 for disabling waiting. + + + + + &SQL + &SQL + + + + Settings name + Název možností + + + + Context + Kontext + + + + Colour + Barva + + + + Bold + TuÄný + + + + Italic + Kurzíva + + + + Underline + Podtržený + + + + Keyword + KlíÄové slovo + + + + Function + Funkce + + + + Table + Tabulka + + + + Comment + Komentář + + + + Identifier + Identifikátor + + + + String + String + + + + Current line + Aktuální řádek + + + + SQL &editor font size + velikost fontu SQL &editoru + + + + Tab size + + + + + SQL editor &font + &font SQL editoru + + + + Error indicators + + + + + Hori&zontal tiling + + + + + If enabled the SQL code editor and the result table view are shown side by side instead of one over the other. + + + + + Code co&mpletion + + + + + Toolbar style + + + + + + + + + Only display the icon + + + + + + + + + Only display the text + + + + + + + + + The text appears beside the icon + + + + + + + + + The text appears under the icon + + + + + + + + + Follow the style + + + + + DB file extensions + + + + + Manage + + + + + Main Window + + + + + Database Structure + Databázová Struktura + + + + Browse Data + Prohlížet data + + + + Execute SQL + ProveÄte SQL + + + + Edit Database Cell + + + + + When this value is changed, all the other color preferences are also set to matching colors. + + + + + Follow the desktop style + + + + + Dark style + + + + + Application style + + + + + This sets the font size for all UI elements which do not have their own font size option. + + + + + Font size + + + + + When enabled, the line breaks in the Schema column of the DB Structure tab, dock and printed output are removed. + + + + + Database structure font size + + + + + Font si&ze + Velikost písma + + + + This is the maximum number of items allowed for some computationally expensive functionalities to be enabled: +Maximum number of rows in a table for enabling the value completion based on current values in the column. +Maximum number of indexes in a selection for calculating sum and average. +Can be set to 0 for disabling the functionalities. + + + + + This is the maximum number of rows in a table for enabling the value completion based on current values in the column. +Can be set to 0 for disabling completion. + + + + + Field display + + + + + Displayed &text + + + + + + + + + + Click to set this color + + + + + Text color + Barva textu + + + + Background color + Barva pozadí + + + + Preview only (N/A) + + + + + Foreground + PopÅ™edí + + + + SQL &results font size + + + + + &Wrap lines + + + + + Never + Nikdy + + + + At word boundaries + + + + + At character boundaries + + + + + At whitespace boundaries + + + + + &Quotes for identifiers + + + + + Choose the quoting mechanism used by the application for identifiers in SQL code. + + + + + "Double quotes" - Standard SQL (recommended) + + + + + `Grave accents` - Traditional MySQL quotes + + + + + [Square brackets] - Traditional MS SQL Server quotes + + + + + Keywords in &UPPER CASE + + + + + When set, the SQL keywords are completed in UPPER CASE letters. + + + + + When set, the SQL code lines that caused errors during the last execution are highlighted and the results frame indicates the error in the background + + + + + Close button on tabs + + + + + If enabled, SQL editor tabs will have a close button. In any case, you can use the contextual menu or the keyboard shortcut to close them. + + + + + &Extensions + &Rozšíření + + + + Select extensions to load for every database: + Vyberte rozšíření k naÄtení pro každou databázi: + + + + Add extension + PÅ™idat rozšíření + + + + Remove extension + Odebrat rozšíření + + + + <html><head/><body><p>While supporting the REGEXP operator SQLite doesn't implement any regular expression<br/>algorithm but calls back the running application. DB Browser for SQLite implements this<br/>algorithm for you to let you use REGEXP out of the box. However, as there are multiple possible<br/>implementations of this and you might want to use another one, you're free to disable the<br/>application's implementation and load your own by using an extension. Requires restart of the application.</p></body></html> + + + + + Disable Regular Expression extension + Zakázat rozšíření pro regulární výrazy + + + + <html><head/><body><p>SQLite provides an SQL function for loading extensions from a shared library file. Activate this if you want to use the <span style=" font-style:italic;">load_extension()</span> function from SQL code.</p><p>For security reasons, extension loading is turned off by default and must be enabled through this setting. You can always load extensions through the GUI, even though this option is disabled.</p></body></html> + + + + + Allow loading extensions from SQL code + + + + + Remote + Vzdálený + + + + CA certificates + certifikáty CA + + + + Proxy + + + + + Configure + + + + + + Subject CN + pÅ™edmÄ›t CN + + + + Common Name + + + + + Subject O + pÅ™edmÄ›t O + + + + Organization + Organizace + + + + + Valid from + Platné od + + + + + Valid to + Platné do + + + + + Serial number + Sériové Äíslo + + + + Your certificates + VaÅ¡e certifikáty + + + + File + Soubor + + + + Subject Common Name + + + + + Issuer CN + + + + + Issuer Common Name + + + + + Clone databases into + + + + + + Choose a directory + Vyberte složku + + + + The language will change after you restart the application. + Jazyk bude zmÄ›nÄ›n po restartu aplikace. + + + + Select extension file + Vybrat soubor rozšíření + + + + Extensions(*.so *.dylib *.dll);;All files(*) + + + + + Import certificate file + Importovat soubor certifikátu + + + + No certificates found in this file. + V tomto souboru nebyly nalezeny žádné certifikáty. + + + + Are you sure you want do remove this certificate? All certificate data will be deleted from the application settings! + Opravdu chcete smazat tento certifikát? VÅ¡echny data certifikátu budou smazány z nastavení aplikace! + + + + Are you sure you want to clear all the saved settings? +All your preferences will be lost and default values will be used. + + + + + ProxyDialog + + + Proxy Configuration + + + + + Pro&xy Type + + + + + Host Na&me + + + + + Port + + + + + Authentication Re&quired + + + + + &User Name + + + + + Password + + + + + None + Žádná + + + + System settings + + + + + HTTP + + + + + Socks v5 + + + + + QObject + + + Error importing data + Chyba pÅ™i importu dat + + + + from record number %1 + ze záznamu Äíslo %1 + + + + . +%1 + . +%1 + + + + Importing CSV file... + + + + + Cancel + ZruÅ¡it + + + + All files (*) + VÅ¡echny soubory (*) + + + + SQLite database files (*.db *.sqlite *.sqlite3 *.db3) + + + + + Left + + + + + Right + + + + + Center + + + + + Justify + + + + + SQLite Database Files (*.db *.sqlite *.sqlite3 *.db3) + + + + + DB Browser for SQLite Project Files (*.sqbpro) + + + + + SQL Files (*.sql) + + + + + All Files (*) + + + + + Text Files (*.txt) + + + + + Comma-Separated Values Files (*.csv) + + + + + Tab-Separated Values Files (*.tsv) + + + + + Delimiter-Separated Values Files (*.dsv) + + + + + Concordance DAT files (*.dat) + + + + + JSON Files (*.json *.js) + + + + + XML Files (*.xml) + + + + + Binary Files (*.bin *.dat) + + + + + SVG Files (*.svg) + + + + + Hex Dump Files (*.dat *.bin) + + + + + Extensions (*.so *.dylib *.dll) + + + + + RemoteCommitsModel + + + Commit ID + + + + + Message + + + + + Date + Datum + + + + Author + + + + + Size + Velikost + + + + Authored and committed by %1 + + + + + Authored by %1, committed by %2 + + + + + RemoteDatabase + + + Error opening local databases list. +%1 + + + + + Error creating local databases list. +%1 + + + + + RemoteDock + + + Remote + Vzdálený + + + + Identity + + + + + Push currently opened database to server + + + + + DBHub.io + + + + + <html><head/><body><p>In this pane, remote databases from dbhub.io website can be added to DB Browser for SQLite. First you need an identity:</p><ol style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Login to the dbhub.io website (use your GitHub credentials or whatever you want)</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Click the button to &quot;Generate client certificate&quot; (that's your identity). That'll give you a certificate file (save it to your local disk).</li><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Go to the Remote tab in DB Browser for SQLite Preferences. Click the button to add a new certificate to DB Browser for SQLite and choose the just downloaded certificate file.</li></ol><p>Now the Remote panel shows your identity and you can add remote databases.</p></body></html> + + + + + Local + + + + + Current Database + + + + + Clone + + + + + User + Uživatel + + + + Database + Databáze + + + + Branch + VÄ›tev + + + + Commits + + + + + Commits for + + + + + <html><head/><body><p>You are currently using a built-in, read-only identity. For uploading your database, you need to configure and use your DBHub.io account.</p><p>No DBHub.io account yet? <a href="https://dbhub.io/"><span style=" text-decoration: underline; color:#007af4;">Create one now</span></a> and import your certificate <a href="#preferences"><span style=" text-decoration: underline; color:#007af4;">here</span></a> to share your databases.</p><p>For online help visit <a href="https://dbhub.io/about"><span style=" text-decoration: underline; color:#007af4;">here</span></a>.</p></body></html> + + + + + Back + + + + + Delete Database + + + + + Delete the local clone of this database + + + + + Open in Web Browser + + + + + Open the web page for the current database in your browser + + + + + Clone from Link + + + + + Use this to download a remote database for local editing using a URL as provided on the web page of the database. + + + + + Refresh + Obnovit + + + + Reload all data and update the views + + + + + F5 + + + + + Clone Database + + + + + Open Database + + + + + Open the local copy of this database + + + + + Check out Commit + + + + + Download and open this specific commit + + + + + Check out Latest Commit + + + + + Check out the latest commit of the current branch + + + + + Save Revision to File + + + + + Saves the selected revision of the database to another file + + + + + Upload Database + + + + + Upload this database as a new commit + + + + + Select an identity to connect + + + + + Public + VeÅ™ejný + + + + This downloads a database from a remote server for local editing. +Please enter the URL to clone from. You can generate this URL by +clicking the 'Clone Database in DB4S' button on the web page +of the database. + + + + + Invalid URL: The host name does not match the host name of the current identity. + + + + + Invalid URL: No branch name specified. + + + + + Invalid URL: No commit ID specified. + + + + + You have modified the local clone of the database. Fetching this commit overrides these local changes. +Are you sure you want to proceed? + + + + + The database has unsaved changes. Are you sure you want to push it before saving? + + + + + The database you are trying to delete is currently opened. Please close it before deleting. + + + + + This deletes the local version of this database with all the changes you have not committed yet. Are you sure you want to delete this database? + + + + + RemoteLocalFilesModel + + + Name + Název + + + + Branch + VÄ›tev + + + + Last modified + Poslední zmÄ›nÄ›né + + + + Size + Velikost + + + + Commit + + + + + File + Soubor + + + + RemoteModel + + + Name + Název + + + + Last modified + Poslední zmÄ›nÄ›né + + + + Size + Velikost + + + + Commit + + + + + Size: + + + + + Last Modified: + + + + + Licence: + + + + + Default Branch: + + + + + RemoteNetwork + + + Choose a location to save the file + + + + + Error opening remote file at %1. +%2 + + + + + Error: Invalid client certificate specified. + + + + + Please enter the passphrase for this client certificate in order to authenticate. + + + + + Cancel + ZruÅ¡it + + + + Uploading remote database to +%1 + Nahrávám vzdálenou databázi do +%1. {1?} + + + + Downloading remote database from +%1 + Stahuji vzdálenou databázi z +%1. {1?} + + + + + Error: The network is not accessible. + Chyba: síť není dostupná. + + + + Error: Cannot open the file for sending. + Chyba: Nemohu otevřít soubor k odeslání. + + + + RemotePushDialog + + + Push database + + + + + Database na&me to push to + + + + + Commit message + + + + + Database licence + + + + + Public + VeÅ™ejný + + + + Branch + VÄ›tev + + + + Force push + + + + + Username + + + + + Database will be public. Everyone has read access to it. + + + + + Database will be private. Only you have access to it. + + + + + Use with care. This can cause remote commits to be deleted. + + + + + RunSql + + + Execution aborted by user + + + + + , %1 rows affected + , %1 řádků bylo ovlivnÄ›no + + + + query executed successfully. Took %1ms%2 + + + + + executing query + + + + + SelectItemsPopup + + + A&vailable + + + + + Sele&cted + + + + + SqlExecutionArea + + + Form + Formulář + + + + Find previous match [Shift+F3] + + + + + Find previous match with wrapping + + + + + Shift+F3 + + + + + The found pattern must be a whole word + + + + + Whole Words + Celá slova + + + + Text pattern to find considering the checks in this frame + + + + + Find in editor + Najít v editoru + + + + The found pattern must match in letter case + + + + + Case Sensitive + + + + + Find next match [Enter, F3] + + + + + Find next match with wrapping + + + + + F3 + + + + + Interpret search pattern as a regular expression + + + + + <html><head/><body><p>When checked, the pattern to find is interpreted as a UNIX regular expression. See <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>.</p></body></html> + + + + + Regular Expression + Regulární výraz + + + + + Close Find Bar + Zavřít liÅ¡tu pro hledání + + + + <html><head/><body><p>Results of the last executed statements.</p><p>You may want to collapse this panel and use the <span style=" font-style:italic;">SQL Log</span> dock with <span style=" font-style:italic;">User</span> selection instead.</p></body></html> + + + + + Results of the last executed statements + Výsledky naposledy provedených příkazů + + + + This field shows the results and status codes of the last executed statements. + + + + + Couldn't read file: %1. + + + + + + Couldn't save file: %1. + + + + + Your changes will be lost when reloading it! + + + + + The file "%1" was modified by another program. Do you want to reload it?%2 + + + + + SqlTextEdit + + + Ctrl+/ + + + + + SqlUiLexer + + + (X) The abs(X) function returns the absolute value of the numeric argument X. + + + + + () The changes() function returns the number of database rows that were changed or inserted or deleted by the most recently completed INSERT, DELETE, or UPDATE statement. + + + + + (X1,X2,...) The char(X1,X2,...,XN) function returns a string composed of characters having the unicode code point values of integers X1 through XN, respectively. + + + + + (X,Y,...) The coalesce() function returns a copy of its first non-NULL argument, or NULL if all arguments are NULL + + + + + (X,Y) The glob(X,Y) function is equivalent to the expression "Y GLOB X". + + + + + (X,Y) The ifnull() function returns a copy of its first non-NULL argument, or NULL if both arguments are NULL. + + + + + (X,Y) The instr(X,Y) function finds the first occurrence of string Y within string X and returns the number of prior characters plus 1, or 0 if Y is nowhere found within X. + + + + + (X) The hex() function interprets its argument as a BLOB and returns a string which is the upper-case hexadecimal rendering of the content of that blob. + + + + + () The last_insert_rowid() function returns the ROWID of the last row insert from the database connection which invoked the function. + + + + + (X) For a string value X, the length(X) function returns the number of characters (not bytes) in X prior to the first NUL character. + + + + + (X,Y) The like() function is used to implement the "Y LIKE X" expression. + + + + + (X,Y,Z) The like() function is used to implement the "Y LIKE X ESCAPE Z" expression. + + + + + (X) The load_extension(X) function loads SQLite extensions out of the shared library file named X. +Use of this function must be authorized from Preferences. + + + + + (X,Y) The load_extension(X) function loads SQLite extensions out of the shared library file named X using the entry point Y. +Use of this function must be authorized from Preferences. + + + + + (X) The lower(X) function returns a copy of string X with all ASCII characters converted to lower case. + + + + + (X) ltrim(X) removes spaces from the left side of X. + (X) ltrim(X) odstraní mezery z levé strany X. + + + + (X,Y) The ltrim(X,Y) function returns a string formed by removing any and all characters that appear in Y from the left side of X. + + + + + (X,Y,...) The multi-argument max() function returns the argument with the maximum value, or return NULL if any argument is NULL. + + + + + (X,Y,...) The multi-argument min() function returns the argument with the minimum value. + (X,Y,...) Funkce s více parametry min() vrací parametr s minimální hodnotou. + + + + (X,Y) The nullif(X,Y) function returns its first argument if the arguments are different and NULL if the arguments are the same. + (X,Y) Funkce nullif(X,Y) vrací první parametr, pokud jsou parametry odliÅ¡né. NULL vrací, pokud jsou parametry stejné. + + + + (FORMAT,...) The printf(FORMAT,...) SQL function works like the sqlite3_mprintf() C-language function and the printf() function from the standard C library. + + + + + (X) The quote(X) function returns the text of an SQL literal which is the value of its argument suitable for inclusion into an SQL statement. + + + + + () The random() function returns a pseudo-random integer between -9223372036854775808 and +9223372036854775807. + () Funkce random() vrací pseudo-náhodný integer v rozmezí -9223372036854775808 a +9223372036854775807. + + + + (N) The randomblob(N) function return an N-byte blob containing pseudo-random bytes. + + + + + (X,Y,Z) The replace(X,Y,Z) function returns a string formed by substituting string Z for every occurrence of string Y in string X. + + + + + (X) The round(X) function returns a floating-point value X rounded to zero digits to the right of the decimal point. + + + + + (X,Y) The round(X,Y) function returns a floating-point value X rounded to Y digits to the right of the decimal point. + + + + + (X) rtrim(X) removes spaces from the right side of X. + + + + + (X,Y) The rtrim(X,Y) function returns a string formed by removing any and all characters that appear in Y from the right side of X. + + + + + (X) The soundex(X) function returns a string that is the soundex encoding of the string X. + + + + + (X,Y) substr(X,Y) returns all characters through the end of the string X beginning with the Y-th. + + + + + (X,Y,Z) The substr(X,Y,Z) function returns a substring of input string X that begins with the Y-th character and which is Z characters long. + + + + + () The total_changes() function returns the number of row changes caused by INSERT, UPDATE or DELETE statements since the current database connection was opened. + + + + + (X) trim(X) removes spaces from both ends of X. + (X) trim(X) odstraní mezery z obou stran X. + + + + (X,Y) The trim(X,Y) function returns a string formed by removing any and all characters that appear in Y from both ends of X. + + + + + (X) The typeof(X) function returns a string that indicates the datatype of the expression X. + + + + + (X) The unicode(X) function returns the numeric unicode code point corresponding to the first character of the string X. + + + + + (X) The upper(X) function returns a copy of input string X in which all lower-case ASCII characters are converted to their upper-case equivalent. + + + + + (N) The zeroblob(N) function returns a BLOB consisting of N bytes of 0x00. + + + + + + + + (timestring,modifier,modifier,...) + + + + + (format,timestring,modifier,modifier,...) + + + + + (X) The avg() function returns the average value of all non-NULL X within a group. + + + + + (X) The count(X) function returns a count of the number of times that X is not NULL in a group. + + + + + (X) The group_concat() function returns a string which is the concatenation of all non-NULL values of X. + + + + + (X,Y) The group_concat() function returns a string which is the concatenation of all non-NULL values of X. If parameter Y is present then it is used as the separator between instances of X. + + + + + (X) The max() aggregate function returns the maximum value of all values in the group. + (X) AgregaÄní funkce max() vrací maximální hodnotu ze vÅ¡ech hodnot ve skupinÄ›. + + + + (X) The min() aggregate function returns the minimum non-NULL value of all values in the group. + (X) AgregaÄní funkce min() vrací minimální hodnotu ze vÅ¡ech hodnot ve skupinÄ›, která není NULL. + + + + + (X) The sum() and total() aggregate functions return sum of all non-NULL values in the group. + (X) AgregaÄní funkce sum() a total() vrací souÄet vÅ¡ech hodnot ve skupinÄ›, které nejsou NULL. + + + + () The number of the row within the current partition. Rows are numbered starting from 1 in the order defined by the ORDER BY clause in the window definition, or in arbitrary order otherwise. + + + + + () The row_number() of the first peer in each group - the rank of the current row with gaps. If there is no ORDER BY clause, then all rows are considered peers and this function always returns 1. + + + + + () The number of the current row's peer group within its partition - the rank of the current row without gaps. Partitions are numbered starting from 1 in the order defined by the ORDER BY clause in the window definition. If there is no ORDER BY clause, then all rows are considered peers and this function always returns 1. + + + + + () Despite the name, this function always returns a value between 0.0 and 1.0 equal to (rank - 1)/(partition-rows - 1), where rank is the value returned by built-in window function rank() and partition-rows is the total number of rows in the partition. If the partition contains only one row, this function returns 0.0. + + + + + () The cumulative distribution. Calculated as row-number/partition-rows, where row-number is the value returned by row_number() for the last peer in the group and partition-rows the number of rows in the partition. + + + + + (N) Argument N is handled as an integer. This function divides the partition into N groups as evenly as possible and assigns an integer between 1 and N to each group, in the order defined by the ORDER BY clause, or in arbitrary order otherwise. If necessary, larger groups occur first. This function returns the integer value assigned to the group that the current row is a part of. + + + + + (expr) Returns the result of evaluating expression expr against the previous row in the partition. Or, if there is no previous row (because the current row is the first), NULL. + + + + + (expr,offset) If the offset argument is provided, then it must be a non-negative integer. In this case the value returned is the result of evaluating expr against the row offset rows before the current row within the partition. If offset is 0, then expr is evaluated against the current row. If there is no row offset rows before the current row, NULL is returned. + + + + + + (expr,offset,default) If default is also provided, then it is returned instead of NULL if the row identified by offset does not exist. + + + + + (expr) Returns the result of evaluating expression expr against the next row in the partition. Or, if there is no next row (because the current row is the last), NULL. + + + + + (expr,offset) If the offset argument is provided, then it must be a non-negative integer. In this case the value returned is the result of evaluating expr against the row offset rows after the current row within the partition. If offset is 0, then expr is evaluated against the current row. If there is no row offset rows after the current row, NULL is returned. + + + + + (expr) This built-in window function calculates the window frame for each row in the same way as an aggregate window function. It returns the value of expr evaluated against the first row in the window frame for each row. + + + + + (expr) This built-in window function calculates the window frame for each row in the same way as an aggregate window function. It returns the value of expr evaluated against the last row in the window frame for each row. + + + + + (expr,N) This built-in window function calculates the window frame for each row in the same way as an aggregate window function. It returns the value of expr evaluated against the row N of the window frame. Rows are numbered within the window frame starting from 1 in the order defined by the ORDER BY clause if one is present, or in arbitrary order otherwise. If there is no Nth row in the partition, then NULL is returned. + + + + + SqliteTableModel + + + reading rows + Ätení sloupců + + + + loading... + naÄítání... + + + + References %1(%2) +Hold %3Shift and click to jump there + + + + + Error changing data: +%1 + Chyba pÅ™i zmÄ›nÄ› dat: +%1 + + + + retrieving list of columns + + + + + Fetching data... + NaÄítám data... + + + + + Cancel + ZruÅ¡it + + + + TableBrowser + + + Browse Data + Prohlížet data + + + + &Table: + &Tabulka: + + + + Select a table to browse data + Vyberte tabulku pro prohlížení dat + + + + Use this list to select a table to be displayed in the database view + Pro zobrazení v databázovém pohledu použijte pro výbÄ›r tabulky tento seznam + + + + This is the database table view. You can do the following actions: + - Start writing for editing inline the value. + - Double-click any record to edit its contents in the cell editor window. + - Alt+Del for deleting the cell content to NULL. + - Ctrl+" for duplicating the current record. + - Ctrl+' for copying the value from the cell above. + - Standard selection and copy/paste operations. + + + + + Text pattern to find considering the checks in this frame + + + + + Find in table + + + + + Find previous match [Shift+F3] + + + + + Find previous match with wrapping + + + + + Shift+F3 + + + + + Find next match [Enter, F3] + + + + + Find next match with wrapping + + + + + F3 + + + + + The found pattern must match in letter case + + + + + Case Sensitive + + + + + The found pattern must be a whole word + + + + + Whole Cell + + + + + Interpret search pattern as a regular expression + + + + + <html><head/><body><p>When checked, the pattern to find is interpreted as a UNIX regular expression. See <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>.</p></body></html> + + + + + Regular Expression + Regulární výraz + + + + + Close Find Bar + Zavřít liÅ¡tu pro hledání + + + + Text to replace with + + + + + Replace with + + + + + Replace next match + + + + + + Replace + + + + + Replace all matches + + + + + Replace all + + + + + <html><head/><body><p>Scroll to the beginning</p></body></html> + <html><head/><body><p>Posune na úplný zaÄátek</p></body></html> + + + + <html><head/><body><p>Clicking this button navigates to the beginning in the table view above.</p></body></html> + <html><head/><body><p>Kliknutím na toto tlaÄítko se pÅ™esunete na zaÄátek pohledu tabulky výše.</p></body></html> + + + + |< + |< + + + + Scroll one page upwards + + + + + <html><head/><body><p>Clicking this button navigates one page of records upwards in the table view above.</p></body></html> + + + + + < + < + + + + 0 - 0 of 0 + 0 - 0 z 0 + + + + Scroll one page downwards + + + + + <html><head/><body><p>Clicking this button navigates one page of records downwards in the table view above.</p></body></html> + + + + + > + > + + + + Scroll to the end + Posunout na konec + + + + <html><head/><body><p>Clicking this button navigates up to the end in the table view above.</p></body></html> + + + + + >| + >| + + + + <html><head/><body><p>Click here to jump to the specified record</p></body></html> + <html><head/><body><p>Kliknutím zde pÅ™eskoÄíte na urÄený záznam</p></body></html> + + + + <html><head/><body><p>This button is used to navigate to the record number specified in the Go to area.</p></body></html> + <html><head/><body><p>Toto tlaÄítko je urÄeno k navigaci k záznamu, jehož Äíslo je nastaveno v poli Jít na.</p></body></html> + + + + Go to: + Jít na: + + + + Enter record number to browse + Vložte Äíslo záznamu pro jeho procházení + + + + Type a record number in this area and click the Go to: button to display the record in the database view + NapiÅ¡tÄ› Äíslo záznamu do tohoto pole a kliknÄ›te na Jít na: tlaÄítko k zobrazení záznamu v pohledu databáze + + + + 1 + 1 + + + + Show rowid column + Zobrazit rowid sloupce + + + + Toggle the visibility of the rowid column + PÅ™epnout viditelnost rowid sloupců + + + + Unlock view editing + + + + + This unlocks the current view for editing. However, you will need appropriate triggers for editing. + + + + + Edit display format + Upravit formát zobrazení + + + + Edit the display format of the data in this column + Upravit formát zobrazení dat v tomto sloupci + + + + + New Record + Nový záznam + + + + + Insert a new record in the current table + Vložit nový záznam do souÄasné tabulky + + + + <html><head/><body><p>This button creates a new record in the database. Hold the mouse button to open a pop-up menu of different options:</p><ul><li><span style=" font-weight:600;">New Record</span>: insert a new record with default values in the database.</li><li><span style=" font-weight:600;">Insert Values...</span>: open a dialog for entering values before they are inserted in the database. This allows to enter values acomplishing the different constraints. This dialog is also open if the <span style=" font-weight:600;">New Record</span> option fails due to these constraints.</li></ul></body></html> + + + + + + Delete Record + Smazat záznam + + + + Delete the current record + Smazat aktuální záznam + + + + + This button deletes the record or records currently selected in the table + + + + + + Insert new record using default values in browsed table + + + + + Insert Values... + Vložit hodnoty... + + + + + Open a dialog for inserting values in a new record + + + + + Export to &CSV + Export do CSV + + + + + Export the filtered data to CSV + + + + + This button exports the data of the browsed table as currently displayed (after filters, display formats and order column) as a CSV file. + + + + + Save as &view + Uložit jako pohled + + + + + Save the current filter, sort column and display formats as a view + + + + + This button saves the current setting of the browsed table (filters, display formats and order column) as an SQL view that you can later browse or use in SQL statements. + + + + + Save Table As... + + + + + + Save the table as currently displayed + + + + + <html><head/><body><p>This popup menu provides the following options applying to the currently browsed and filtered table:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Export to CSV: this option exports the data of the browsed table as currently displayed (after filters, display formats and order column) to a CSV file.</li><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Save as view: this option saves the current setting of the browsed table (filters, display formats and order column) as an SQL view that you can later browse or use in SQL statements.</li></ul></body></html> + + + + + Hide column(s) + Skrýt sloupec(ce) + + + + Hide selected column(s) + Skrýt vybraný sloupec(ce) + + + + Show all columns + Zobrazit vÅ¡echny sloupce + + + + Show all columns that were hidden + + + + + + Set encoding + Nastavit kódování + + + + Change the encoding of the text in the table cells + ZmÄ›nit kódování textu v buňkách tabulky + + + + Set encoding for all tables + Nastavit kódování pro vÅ¡echny tabulky + + + + Change the default encoding assumed for all tables in the database + + + + + Clear Filters + + + + + Clear all filters + Vymazat vÅ¡echny filtry + + + + + This button clears all the filters set in the header input fields for the currently browsed table. + + + + + Clear Sorting + + + + + Reset the order of rows to the default + + + + + + This button clears the sorting columns specified for the currently browsed table and returns to the default order. + + + + + Print + Tisk + + + + Print currently browsed table data + Tisk právÄ› prohlížených dat tabulky + + + + Print currently browsed table data. Print selection if more than one cell is selected. + + + + + Ctrl+P + + + + + Refresh + Obnovit + + + + Refresh the data in the selected table + + + + + This button refreshes the data in the currently selected table. + Toto tlaÄítko obnoví data v aktuálnÄ› vybrané tabulce. + + + + F5 + + + + + Find in cells + + + + + Open the find tool bar which allows you to search for values in the table view below. + + + + + + Bold + TuÄný + + + + Ctrl+B + + + + + + Italic + Kurzíva + + + + + Underline + Podtržený + + + + Ctrl+U + + + + + + Align Right + + + + + + Align Left + + + + + + Center Horizontally + + + + + + Justify + + + + + + Edit Conditional Formats... + + + + + Edit conditional formats for the current column + + + + + Clear Format + + + + + Clear All Formats + + + + + + Clear all cell formatting from selected cells and all conditional formats from selected columns + + + + + + Font Color + + + + + + Background Color + + + + + Toggle Format Toolbar + + + + + Show/hide format toolbar + + + + + + This button shows or hides the formatting toolbar of the Data Browser + + + + + Select column + + + + + Ctrl+Space + + + + + Replace text in cells + + + + + Filter in any column + + + + + Ctrl+R + + + + + %n row(s) + + + + + + + + + , %n column(s) + + + + + + + + + . Sum: %1; Average: %2; Min: %3; Max: %4 + + + + + Conditional formats for "%1" + + + + + determining row count... + + + + + %1 - %2 of >= %3 + + + + + %1 - %2 of %3 + %1 - %2 z %3 + + + + Please enter a pseudo-primary key in order to enable editing on this view. This should be the name of a unique column in the view. + + + + + Delete Records + + + + + Duplicate records + + + + + Duplicate record + + + + + Ctrl+" + + + + + Adjust rows to contents + + + + + Error deleting record: +%1 + Chyba pÅ™i mazání záznamu: +%1 + + + + Please select a record first + Prosím vyberte záznam jako první + + + + There is no filter set for this table. View will not be created. + + + + + Please choose a new encoding for all tables. + Vyberte nové kódování pro vÅ¡echny tabulky, prosím. + + + + Please choose a new encoding for this table. + Vyberte nové kódování pro tuto tabulku, prosím. + + + + %1 +Leave the field empty for using the database encoding. + %1 +Pro použití kódování databáze ponechte pole prázdné. + + + + This encoding is either not valid or not supported. + Toto kódování není buÄ platné, nebo podporováno. + + + + %1 replacement(s) made. + + + + + VacuumDialog + + + Compact Database + Compact Database + + + + Warning: Compacting the database will commit all of your changes. + Varování: Procesem 'compact the database' budou aplikovány vÅ¡echny vaÅ¡e provedené zmÄ›ny. + + + + Please select the databases to co&mpact: + Prosím vyberte databázi pro proces 'compact': + + + diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/translations/sqlb_de.qm b/src/WBCLFZSystemModule/SqliteDBProcess/src/translations/sqlb_de.qm new file mode 100644 index 0000000000000000000000000000000000000000..a5dd69ad7e62f55064b6bcc4450750ffdd883cf0 GIT binary patch literal 242646 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 CCuxBI literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/translations/sqlb_de.ts b/src/WBCLFZSystemModule/SqliteDBProcess/src/translations/sqlb_de.ts new file mode 100644 index 0000000..c359697 --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/translations/sqlb_de.ts @@ -0,0 +1,7015 @@ + + + + + AboutDialog + + + About DB Browser for SQLite + Über DB-Browser für SQLite + + + + Version + Version + + + + <html><head/><body><p>DB Browser for SQLite is an open source, freeware visual tool used to create, design and edit SQLite database files.</p><p>It is bi-licensed under the Mozilla Public License Version 2, as well as the GNU General Public License Version 3 or later. You can modify or redistribute it under the conditions of these licenses.</p><p>See <a href="http://www.gnu.org/licenses/gpl.html">http://www.gnu.org/licenses/gpl.html</a> and <a href="https://www.mozilla.org/MPL/2.0/index.txt">https://www.mozilla.org/MPL/2.0/index.txt</a> for details.</p><p>For more information on this program please visit our website at: <a href="http://sqlitebrowser.org">http://sqlitebrowser.org</a></p><p><span style=" font-size:small;">This software uses the GPL/LGPL Qt Toolkit from </span><a href="http://qt-project.org/"><span style=" font-size:small;">http://qt-project.org/</span></a><span style=" font-size:small;"><br/>See </span><a href="http://qt-project.org/doc/qt-5/licensing.html"><span style=" font-size:small;">http://qt-project.org/doc/qt-5/licensing.html</span></a><span style=" font-size:small;"> for licensing terms and information.</span></p><p><span style=" font-size:small;">It also uses the Silk icon set by Mark James licensed under a Creative Commons Attribution 2.5 and 3.0 license.<br/>See </span><a href="http://www.famfamfam.com/lab/icons/silk/"><span style=" font-size:small;">http://www.famfamfam.com/lab/icons/silk/</span></a><span style=" font-size:small;"> for details.</span></p></body></html> + <html><head/><body><p>DB-Browser für SQLite ist ein grafisches, freies Open-Source-Tool zum Erstellen, Entwerfen und Bearbeiten von SQLite-Datenbankdateien.</p><p>Es steht unter zwei Lizenzen zur Verfügung: der Mozilla Public License Version 2 und der GNU General Public License Version 3 oder aktueller. Sie können das Programm unter den Bedingungen dieser Lizenzen verändern und weiterverteilen.</p><p>Siehe <a href="http://www.gnu.org/licenses/gpl.html">http://www.gnu.org/licenses/gpl.html</a> und <a href="https://www.mozilla.org/MPL/2.0/index.txt">https://www.mozilla.org/MPL/2.0/index.txt</a> für Details.</p><p>Für mehr Informationen über dieses Programm besuchen Sie bitte unsere Website: <a href="http://sqlitebrowser.org">http://sqlitebrowser.org</a></p><p><span style=" font-size:small;">Diese Software verwendet das GPL/LGPL QT Toolkit von </span><a href="http://qt-project.org/"><span style=" font-size:small;">http://qt-project.org/</span></a><span style=" font-size:small;"><br/>Siehe </span><a href="http://qt-project.org/doc/qt-5/licensing.html"><span style=" font-size:small;">http://qt-project.org/doc/qt-5/licensing.html</span></a><span style=" font-size:small;"> für Lizenzbedingungen und -informationen.</span></p><p><span style=" font-size:small;">Sie verwendet ebenso das Silk-Iconset von Mark James, welches unter einer Creative Commons Attribution 2.5 und 3.0 Lizenz verfügbar ist.<br/>Siehe </span><a href="http://www.famfamfam.com/lab/icons/silk/"><span style=" font-size:small;">http://www.famfamfam.com/lab/icons/silk/</span></a><span style=" font-size:small;"> für Details.</span></p></body></html> + + + + AddRecordDialog + + + Add New Record + Neue Zeile hinzufügen + + + + Enter values for the new record considering constraints. Fields in bold are mandatory. + Geben Sie Werte für die neue Zeile unter Beachtung der Constraints ein. Fette Felder sind Pflichtfelder. + + + + In the Value column you can specify the value for the field identified in the Name column. The Type column indicates the type of the field. Default values are displayed in the same style as NULL values. + In der Wertspalte können Sie den Wert für das durch die Namensspalte identifizierte Feld angeben. Die Typspalte zeigt den Feldtyp an. Standardwerte werden im Stil von NULL-Werten angezeigt. + + + + Name + Name + + + + Type + Typ + + + + Value + Wert + + + + Values to insert. Pre-filled default values are inserted automatically unless they are changed. + Einzufügende Werte. Vorausgefüllte Standardwerte werden automatisch eingefügt, insofern sie nicht geändert wurden. + + + + When you edit the values in the upper frame, the SQL query for inserting this new record is shown here. You can edit manually the query before saving. + Wenn Sie die Werte im oberen Teil ändern, wird hier das SQL-Query für das Einfügen der neuen Zeile angezeigt. Sie können das Query vor dem Speichern manuell bearbeiten. + + + + <html><head/><body><p><span style=" font-weight:600;">Save</span> will submit the shown SQL statement to the database for inserting the new record.</p><p><span style=" font-weight:600;">Restore Defaults</span> will restore the initial values in the <span style=" font-weight:600;">Value</span> column.</p><p><span style=" font-weight:600;">Cancel</span> will close this dialog without executing the query.</p></body></html> + <html><head/><body><p><span style=" font-weight:600;">Speichern</span> wird das dargestellte SQL-Statement zum Einfügen des neuen Eintrags an die Datenbank übermitteln.</p><p><span style=" font-weight:600;">Voreinstellungen</span> wird die ursprünglichen Werte der <span style=" font-weight:600;">Wert</span>-Spalte wiederherstellen.</p><p><span style=" font-weight:600;">Abbrechen</span> schließt diesen Dialog, ohne die Query auszuführen.</p></body></html> + + + + Auto-increment + + Auto-Inkrement + + + + + Unique constraint + + Unique-Constraint + + + + + Check constraint: %1 + + Prüfungsconstraint: %1 + + + + + Foreign key: %1 + + Fremdschlüssel: %1 + + + + + Default value: %1 + + Standardwert: %1 + + + + + Error adding record. Message from database engine: + +%1 + Fehler beim Hinzufügen der Zeile. Mitteilung der Datenbank-Engine: + +%1 + + + + Are you sure you want to restore all the entered values to their defaults? + Sind Sie sicher, dass Sie alle eingegebenen Werte auf ihre Standardwerte zurücksetzen möchten? + + + + Application + + + Possible command line arguments: + Mögliche Kommandozeilen-Argumente: + + + + The -o/--option and -O/--save-option options require an argument in the form group/setting=value + Die Optionen -o/--option und -O/--save-option benötigen ein Argument der Form Gruppe/Einstellung=Wert + + + + Usage: %1 [options] [<database>|<project>] + + + + + + -h, --help Show command line options + + + + + -q, --quit Exit application after running scripts + + + + + -s, --sql <file> Execute this SQL file after opening the DB + + + + + -t, --table <table> Browse this table after opening the DB + + + + + -R, --read-only Open database in read-only mode + + + + + -o, --option <group>/<setting>=<value> + + + + + Run application with this setting temporarily set to value + + + + + -O, --save-option <group>/<setting>=<value> + + + + + Run application saving this value for this setting + + + + + -v, --version Display the current version + + + + + <database> Open this SQLite database + + + + + <project> Open this project file (*.sqbpro) + + + + + The -s/--sql option requires an argument + Die -s/--sql Option benötigt ein Argument + + + + The file %1 does not exist + Die Datei %1 existiert nicht + + + + The -t/--table option requires an argument + Die -t/--table Option benötigt ein Argument + + + + SQLite Version + SQLite-Version + + + + SQLCipher Version %1 (based on SQLite %2) + SQLCipher Version %1 (basierend auf SQLite %2) + + + + DB Browser for SQLite Version %1. + + + + + Built for %1, running on %2 + Erstellt für %1, laufend unter %2 + + + + Qt Version %1 + + + + + Invalid option/non-existant file: %1 + Ungültige Option/nicht existente Datei: %1 + + + + CipherDialog + + + SQLCipher encryption + SQLCipher-Verschlüsselung + + + + &Password + &Passwort + + + + &Reenter password + Wiede&rhole Passwort + + + + Encr&yption settings + &Verschlüsselungs-Einstellungen + + + + SQLCipher &3 defaults + SQLCipher &3 Standardwerte + + + + SQLCipher &4 defaults + SQLCipher &4 Standardwerte + + + + Custo&m + &Benutzerdefiniert + + + + Page si&ze + Seiten&größe + + + + &KDF iterations + &KDF-Iterationen + + + + HMAC algorithm + HMAC-Algorithmus + + + + KDF algorithm + KDF-Algorithmus + + + + Plaintext Header Size + Plaintext-Headergröße + + + + Passphrase + Passphrase + + + + Raw key + Originalschlüssel + + + + Please set a key to encrypt the database. +Note that if you change any of the other, optional, settings you'll need to re-enter them as well every time you open the database file. +Leave the password fields empty to disable the encryption. +The encryption process might take some time and you should have a backup copy of your database! Unsaved changes are applied before modifying the encryption. + Setzen Sie bitte einen Schlüssel zum Verschlüsseln der Datenbank. +Beachten Sie, dass bei Änderung der optionalen Einstellungen diese bei jedem Öffnen der Datenbank-Datei eingegeben werden müssen. +Lassen Sie die Passwortfelder leer, um die Verschlüsselung zu deaktivieren. +Der Verschlüsselungsprozess benötigt unter Umständen ein bisschen Zeit und Sie sollten ein Backup-Kopie Ihrer Datenbank haben! Ungespeicherte Änderungen werden vor der Änderung der Verschlüsselung übernommen. + + + + Please enter the key used to encrypt the database. +If any of the other settings were altered for this database file you need to provide this information as well. + Geben Sie bitte den zur Verschlüsselung der Datenbank genutzten Schlüssel ein. +Falls weitere Einstellungen für diese Datenbank-Datei vorgenommen worden sind, müssen Sie diese Informationen zusätzlich angeben. + + + + ColumnDisplayFormatDialog + + + Choose display format + Anzeigeformat auswählen + + + + Display format + Anzeigeformat + + + + Choose a display format for the column '%1' which is applied to each value prior to showing it. + Wählen Sie ein Anzeigeformat für die Spalte '%1', welches bei der Anzeige eines jeden Wertes angewendet wird. + + + + Default + Voreinstellung + + + + Decimal number + Dezimalzahl + + + + Exponent notation + Exponentnotation + + + + Hex blob + Hex-Blob + + + + Hex number + Hexwert + + + + Apple NSDate to date + Apple NSDate zu Datum + + + + Java epoch (milliseconds) to date + Java-Epoche (Millisekunden) zu Datum + + + + .NET DateTime.Ticks to date + + + + + Julian day to date + Julianischer Tag zu Datum + + + + Unix epoch to local time + Unix-Epoche zu lokaler Zeit + + + + Date as dd/mm/yyyy + Datum als dd/mm/yyyy + + + + Lower case + Kleinschreibung + + + + Custom display format must contain a function call applied to %1 + Benutzerdefinierte Darstellungsformate benötigen einen Funktionsaufruf, der auf %1 angewendet wird + + + + Error in custom display format. Message from database engine: + +%1 + Fehler im benutzerdefinierten Anzeigeformat. Meldung von Datenbank: + +%1 + + + + Custom display format must return only one column but it returned %1. + Das benutzerdefinierte Anzeigeformat darf nur eine Spalte zurückgeben, es wurde aber %1 zurückgegeben. + + + + Octal number + Oktalwert + + + + Round number + Gerundeter Wert + + + + Unix epoch to date + Unix-Epoche zu Datum + + + + Upper case + Großschreibung + + + + Windows DATE to date + Windows DATUM zu Datum + + + + Custom + Benutzerdefiniert + + + + CondFormatManager + + + Conditional Format Manager + Verwaltung für bedingte Formatierung + + + + This dialog allows creating and editing conditional formats. Each cell style will be selected by the first accomplished condition for that cell data. Conditional formats can be moved up and down, where those at higher rows take precedence over those at lower. Syntax for conditions is the same as for filters and an empty condition applies to all values. + Dieser Dialog erlaubt das Erstellen und Bearbeiten bedingter Formatierungen. Jeder Zellenstil wird anhand der ersten erfüllten Bedingung für diese Zelldaten ausgewählt. Bedingte Formatierungen können nach oben und unten bewegt werden, wobei jene weiter oben Vorrang vor jenen weiter unten haben. Der Syntax für Bedingungen ist der gleiche wie bei Filtern und eine leere Bedingung trifft auf alle Werte zu. + + + + Add new conditional format + Neue bedingte Formatierung hinzufügen + + + + &Add + &Hinzufügen + + + + Remove selected conditional format + Ausgewählte bedingte Formatierung entfernen + + + + &Remove + &Entfernen + + + + Move selected conditional format up + Ausgewählte bedingte Formatierung nach oben bewegen + + + + Move &up + Nach &oben + + + + Move selected conditional format down + Ausgewählte bedingte Formatierung nach unten bewegen + + + + Move &down + Nach &unten + + + + Foreground + Vordergrund + + + + Text color + Textfarbe + + + + Background + Hintergrund + + + + Background color + Hintergrundfarbe + + + + Font + Schrift + + + + Size + Größe + + + + Bold + Fett + + + + Italic + Kursiv + + + + Underline + Unterstreichung + + + + Alignment + Ausrichtung + + + + Condition + Bedingung + + + + + Click to select color + Zur Auswahl der Farbe klicken + + + + Are you sure you want to clear all the conditional formats of this field? + Sollen wirklich alle bedingten Formatierungen dieses Felds gelöscht werden? + + + + DBBrowserDB + + + Please specify the database name under which you want to access the attached database + Geben Sie bitte einen Datenbanknamen an, mit dem Sie auf die anhängte Datenbank zugreifen möchten + + + + Invalid file format + Ungültiges Dateiformat + + + + Do you want to save the changes made to the database file %1? + Sollen die getätigten Änderungen an der Datenbank-Datei %1 gespeichert werden? + + + + Exporting database to SQL file... + Datenbank in SQL-Datei exportieren... + + + + + Cancel + Abbrechen + + + + Executing SQL... + SQL ausführen... + + + + Action cancelled. + Vorgang abgebrochen. + + + + This database has already been attached. Its schema name is '%1'. + Diese Datenbank wurde bereits angehängt. Ihr Schemaname ist '%1'. + + + + Do you really want to close this temporary database? All data will be lost. + Möchten Sie diese temporäre Datenbank wirklich schließen? Alle Daten gehen damit verloren. + + + + Database didn't close correctly, probably still busy + Datenbank wurde nicht richtig geschlossen, vermutlich noch in Bearbeitung + + + + The database is currently busy: + Die Datenbank ist zur Zeit beschäfigt: + + + + Do you want to abort that other operation? + Möchten Sie die andere Operation abbrechen? + + + + + No database file opened + Keine Datenbankdatei geöffnet + + + + + Error in statement #%1: %2. +Aborting execution%3. + Fehler im Statement #%1: %2. +Ausführung wird abgebrochen %3. + + + + + and rolling back + und der Zustand zurückgesetzt + + + + didn't receive any output from %1 + keine Ausgabe von %1 erhalten + + + + could not execute command: %1 + Befehl konnte nicht ausgeführt werden: %1 + + + + Cannot delete this object + Dieses Objekt kann nicht gelöscht werden + + + + Cannot set data on this object + Daten können für dieses Objekt nicht gesetzt werden + + + + + A table with the name '%1' already exists in schema '%2'. + Es existiert eine Tabelle mit dem Namen '%1' im Schema '%2'. + + + + No table with name '%1' exists in schema '%2'. + Im Schema '%2' existiert keine Tabelle mit dem Namen '%1'. + + + + + Cannot find column %1. + Spalte %1 kann nicht gefunden werden. + + + + Creating savepoint failed. DB says: %1 + Erstellung des Sicherungspunktes fehlgeschlagen. DB meldet: %1 + + + + Renaming the column failed. DB says: +%1 + Umbenennung der Spalte fehlgeschlagen. DB meldet: +%1 + + + + + Releasing savepoint failed. DB says: %1 + Entsperren des Sicherungspunktes fehlgeschlagen. DB meldet: %1 + + + + Creating new table failed. DB says: %1 + Erstellen der neuen Tabelle ist fehlgeschlagen. DB meldet: %1 + + + + Copying data to new table failed. DB says: +%1 + Kopieren der Daten zur neuen Tabelle ist fehlgeschlagen. DB meldet: +%1 + + + + Deleting old table failed. DB says: %1 + Löschen der alten Tabelle ist fehlgeschlagen. DB meldet: %1 + + + + Error renaming table '%1' to '%2'. +Message from database engine: +%3 + Fehler beim Umbenennen der Tabelle '%1' zu '%2'. +Meldung von Datenbank: +%3 + + + + could not get list of db objects: %1 + Liste der DB-Objekte konnte nicht abgefragt werden: %1 + + + + Restoring some of the objects associated with this table failed. This is most likely because some column names changed. Here's the SQL statement which you might want to fix and execute manually: + + + Wiederherstellung einiger mit dieser Tabelle verbundener Objekte fehlgeschagen. Dies passiert häufig durch geänderte Spaltennamen. SQL-Statement zum manuellen Reparieren und Ausführen: + + + + + + could not get list of databases: %1 + konnte keine Datenbankliste abrufen: %1 + + + + Error loading extension: %1 + Fehler beim Laden der Erweiterung: %1 + + + + could not get column information + Spalteninformationen konnten nicht errmittelt werden + + + + Error setting pragma %1 to %2: %3 + Fehler beim Setzen des Pragmas %1 auf %2: %3 + + + + File not found. + Datei nicht gefunden. + + + + DbStructureModel + + + Name + Name + + + + Object + Objekt + + + + Type + Typ + + + + Schema + Schema + + + + Database + Datenbank + + + + Browsables + Durchsuchbar + + + + All + Alle + + + + Temporary + Temporär + + + + Tables (%1) + Tabellen (%1) + + + + Indices (%1) + Indizes (%1) + + + + Views (%1) + Ansichten (%1) + + + + Triggers (%1) + Trigger (%1) + + + + EditDialog + + + Edit database cell + Datenbank-Zelle bearbeiten + + + + Mode: + Modus: + + + + This is the list of supported modes for the cell editor. Choose a mode for viewing or editing the data of the current cell. + Dies ist die Liste der unterstützten Modi des Zelleneditors. Wählen Sie einen Modus für die Anzeige oder Bearbeitung der Daten der aktuellen Zelle aus. + + + + RTL Text + RTL-Text + + + + + Image + Bild + + + + JSON + JSON + + + + XML + XML + + + + + Automatically adjust the editor mode to the loaded data type + Den Editormodus automatisch dem geladenen Datentyp anpassen + + + + This checkable button enables or disables the automatic switching of the editor mode. When a new cell is selected or new data is imported and the automatic switching is enabled, the mode adjusts to the detected data type. You can then change the editor mode manually. If you want to keep this manually switched mode while moving through the cells, switch the button off. + Dieser Button aktiviert oder deaktiviert den automatischen Wechsel des Editormodus. Wenn eine neue Zelle ausgewählt wird oder neue Daten importiert werden und der automatische Wechsel aktiviert ist, passt sich der Modus dem erkannten Datentyp an. Sie können den Editormodus danach manuell ändern. Falls Sie dies bei der Bewegung durch die Zellen im manuell eingestellten Modus behalten möchten, deaktivieren Sie den Button. + + + + Auto-switch + Auto-Wechsel + + + + The text editor modes let you edit plain text, as well as JSON or XML data with syntax highlighting, automatic formatting and validation before saving. + +Errors are indicated with a red squiggle underline. + Der Text-Editor-Modus erlaubt das Bearbeiten von Reintext sowie JSON- oder XML-Daten mit Syntaxhervorhebung, automatischer Formatierung und Validierung vor dem Speichern. + +Fehler werden mittels eine roten Wellenlinie angezeigt. + + + + This Qt editor is used for right-to-left scripts, which are not supported by the default Text editor. The presence of right-to-left characters is detected and this editor mode is automatically selected. + Dieser Qt-Editor wird für rechts-nach-links-Eingaben verwendet, welche vom Standard-Texteditor nicht unterstützt werden. Das Vorhandensein von rechts-nach-links-Zeichen wird erkannt und dieser Editormodus wird automatisch ausgewählt. + + + + Open preview dialog for printing the data currently stored in the cell + Vorschau-Dialog öffnen, um die aktuell in der Zelle gespeicherten Daten auszugeben + + + + Auto-format: pretty print on loading, compact on saving. + Auto-Format: Druckoptimierung (Pretty Print) beim Laden, kompakt beim Speichern. + + + + When enabled, the auto-format feature formats the data on loading, breaking the text in lines and indenting it for maximum readability. On data saving, the auto-format feature compacts the data removing end of lines, and unnecessary whitespace. + Falls aktiviert, formatiert die Auto-Format-Funktion die Daten beim Laden, bricht den Text in Zeilen und rückt ihn ein für maximale Lesbarkeit. Beim Speichern der Daten verdichtet die Auto-Format-Funktion die Daten durch das Entfernen der Zeilenumbrüche und unnötigen Leerzeichen. + + + + Word Wrap + Wortumbrüche + + + + Wrap lines on word boundaries + Zeilen an Wortgrenzen umbrechen + + + + + Open in default application or browser + Mit der Standardanwendung oder dem Browser öffnen + + + + Open in application + Mit Anwendung öffnen + + + + The value is interpreted as a file or URL and opened in the default application or web browser. + Der Wert wird als Datei oder URL interpretiert und mit der Standardanwendung oder dem Web-Browser geöffnet. + + + + Save file reference... + Dateireferenz speichern... + + + + Save reference to file + Referenz in Datei speichern + + + + + Open in external application + Mit externer Anwendung öffnen + + + + Autoformat + Auto-Format + + + + &Export... + &Exportieren... + + + + + &Import... + &Importieren... + + + + + Import from file + Aus Datei importieren + + + + + Opens a file dialog used to import any kind of data to this database cell. + Öffnet einen Dateidialog, um jegliche Art von Daten in diese Datenbankzelle zu importieren. + + + + Export to file + In Datei exportieren + + + + Opens a file dialog used to export the contents of this database cell to a file. + Öffnet einen Dateidialog, um den Inhalt dieser Datenbankzelle in eine Datei zu exportieren. + + + + + Print... + Drucken... + + + + Open preview dialog for printing displayed image + Vorschaudialog zum Drucken des angezeigten Bildes öffnen + + + + + Ctrl+P + + + + + Open preview dialog for printing displayed text + Vorschaudialog zum Drucken des angezeigten Textes öffnen + + + + Copy Hex and ASCII + Hex und ASCII kopieren + + + + Copy selected hexadecimal and ASCII columns to the clipboard + Ausgewählte hexadezimale und ASCII-Spalten in die Zwischenablage kopieren + + + + Ctrl+Shift+C + + + + + Set as &NULL + Auf &NULL setzen + + + + Apply data to cell + Daten auf Zelle anwenden + + + + This button saves the changes performed in the cell editor to the database cell. + Dieser Button speichert die im Zelleneditor für die Datenbankzelle durchgeführten Änderungen. + + + + Apply + Übernehmen + + + + Text + Text + + + + Binary + Binär + + + + Erases the contents of the cell + Löscht den Inhalt der Zelle + + + + This area displays information about the data present in this database cell + Dieser Bereich stellt Informationen über die Daten in dieser Datenbank-Zelle dar + + + + Type of data currently in cell + Art der Daten in dieser Zelle + + + + Size of data currently in table + Größe der Daten in dieser Tabelle + + + + Choose a filename to export data + Dateinamen für den Datenexport wählen + + + + Type of data currently in cell: %1 Image + Art der Daten in der aktuellen Zelle: %1 Bild + + + + %1x%2 pixel(s) + %1x%2 Pixel + + + + Type of data currently in cell: NULL + Art der Daten in dieser Zelle: NULL + + + + + Type of data currently in cell: Text / Numeric + Art der Daten in dieser Zelle: Text / Numerisch + + + + + Image data can't be viewed in this mode. + In diesem Modus können keine Bilddaten angezeigt werden. + + + + + Try switching to Image or Binary mode. + Versuchen Sie, in den Bild- oder Binär-Modus zu wechseln. + + + + + Binary data can't be viewed in this mode. + Binärdaten können in diesem Modus nicht angezeigt werden. + + + + + Try switching to Binary mode. + Versuchen Sie, in den Binär-Modus zu wechseln. + + + + Couldn't save file: %1. + Datei konnte nicht gespeichert werden: %1. + + + + The data has been saved to a temporary file and has been opened with the default application. You can now edit the file and, when you are ready, apply the saved new data to the cell editor or cancel any changes. + Die Daten wurden in einer temporären Datei gespeichert und jene wurde mit der Standardanwendung geöffnet. Die Datei kann nun bearbeitet werden. Am Ende der Bearbeitungen können die gespeicherten neuen Daten auf den Zelleneditor angewandt oder die Änderungen verworfen werden. + + + + + Image files (%1) + Bilddateien (%1) + + + + Binary files (*.bin) + Binärdateien (*.bin) + + + + Choose a file to import + Datei für Import auswählen + + + + %1 Image + %1 Bild + + + + Invalid data for this mode + Ungültige Daten für diesen Modus + + + + The cell contains invalid %1 data. Reason: %2. Do you really want to apply it to the cell? + Die Zelle enthält ungültige %1-Daten. Grund: %2. Möchten Sie diese wirklich auf die Zelle anwenden? + + + + + + %n character(s) + + %n Zeichen + %n Zeichen + + + + + Type of data currently in cell: Valid JSON + Aktueller Datentyp in dieser Zelle: Gültiges JSON + + + + Type of data currently in cell: Binary + Art der Daten in dieser Zelle: Binär + + + + + %n byte(s) + + %n Byte + %n Bytes + + + + + EditIndexDialog + + + &Name + &Name + + + + Order + Sortierung + + + + &Table + &Tabelle + + + + Edit Index Schema + Index-Schema bearbeiten + + + + &Unique + Einde&utig + + + + For restricting the index to only a part of the table you can specify a WHERE clause here that selects the part of the table that should be indexed + Zum Einschränken des Index auf einen Teil der Tabelle kann hier eine WHERE-Klausel angegeben werden, die den Teil der Tabelle auswählt, der indexiert werden soll + + + + Partial inde&x clause + Teilinde&x-Klausel + + + + Colu&mns + &Spalten + + + + Table column + Tabellenspalte + + + + Type + Typ + + + + Add a new expression column to the index. Expression columns contain SQL expression rather than column names. + Fügt eine neue Ausdrucksspalte zum Index hinzu. Ausdrucksspalten enthalten SQL-Ausdrücke statt Spaltennamen. + + + + Index column + Indexspalte + + + + Deleting the old index failed: +%1 + Löschen des alten Index fehlgeschlagen: %1 + + + + Creating the index failed: +%1 + Erstellen des Index fehlgeschlagen: +%1 + + + + EditTableDialog + + + Edit table definition + Tabellen-Definition bearbeiten + + + + Table + Tabelle + + + + Advanced + Erweitert + + + + Make this a 'WITHOUT rowid' table. Setting this flag requires a field of type INTEGER with the primary key flag set and the auto increment flag unset. + Als 'WITHOUT rowid'-Tabelle markieren. Das Setzen dieses Flags erfordert ein Feld vom Typ INTEGER mit gesetzten Primärkey-Flag und nicht gesetztem Autoinkrement-Flag. + + + + Without Rowid + Ohne Rowid + + + + Fields + Felder + + + + Database sche&ma + Datenbank-Sche&ma + + + + Add + Hinzufügen + + + + Remove + Entfernen + + + + Move to top + Zum Beginn + + + + Move up + Nach oben + + + + Move down + Nach unten + + + + Move to bottom + Zum Ende + + + + + Name + Name + + + + + Type + Typ + + + + NN + NN + + + + Not null + Nicht Null + + + + PK + PK + + + + Primary key + Primärschlüssel + + + + AI + AI + + + + Autoincrement + Autoinkrement + + + + U + + + + + + + Unique + Eindeutig + + + + Default + Voreinstellung + + + + Default value + Voreingestellter Wert + + + + + + Check + Prüfen + + + + Check constraint + Beschränkung prüfen + + + + Collation + Kollation + + + + + + Foreign Key + Fremdschlüssel + + + + Constraints + Constraints + + + + Add constraint + Constraint hinzufügen + + + + Remove constraint + Constraint entfernen + + + + Columns + Spalten + + + + SQL + SQL + + + + <html><head/><body><p><span style=" font-weight:600; color:#ff0000;">Warning: </span>There is something with this table definition that our parser doesn't fully understand. Modifying and saving this table might result in problems.</p></body></html> + <html><head/><body><p><span style="font-weight:600; color:#ff0000;">Warnung: </span>Diese Tabellendefinitionenthält Elemente, die unser Parser nicht vollständig versteht. Das Ändern und Speichern der Tabelle kann zu Problemen führen.</p></body></html> + + + + + Primary Key + Primärschlüssel + + + + Add a primary key constraint + Ein Constraint für den Primärschlüssel hinzufügen + + + + Add a foreign key constraint + Ein Constraint für den Fremdschlüssel hinzufügen + + + + Add a unique constraint + Ein Unique-Constraint hinzufügen + + + + Add a check constraint + Ein Prüfungs-Constraint hinzufügen + + + + Error creating table. Message from database engine: +%1 + Fehler beim Erstellen der Tabelle. Meldung der Datenbank: +%1 + + + + There already is a field with that name. Please rename it first or choose a different name for this field. + Es existiert bereits ein Feld mit diesem Namen. Bitte benennen Sie es zunächst um oder wählen Sie einen anderen Namen für dieses Feld. + + + + + There can only be one primary key for each table. Please modify the existing primary key instead. + Es kann nur einen Primärschlüssel für jede Tabelle geben. Bitte stattdessen den existierenden Primärschlüssel bearbeiten. + + + + This column is referenced in a foreign key in table %1 and thus its name cannot be changed. + Diese Spalte wird in einem Fremdschlüssel in Tabelle %1 referenziert und kann aus diesem Grund nicht geändert werden. + + + + There is at least one row with this field set to NULL. This makes it impossible to set this flag. Please change the table data first. + Mindestens eine Reihe enthält ein Feld mit dem Wert NULL. Dies verhindert das Setzen dieser Markierung. Bitte zunächst die Tabellendaten ändern. + + + + There is at least one row with a non-integer value in this field. This makes it impossible to set the AI flag. Please change the table data first. + Mindestens eine Reihe enthält ein Feld mit einem nicht ganzzahligen Wert. Dies verhindert das Setzen der AI-Markierung. Bitte zunächst die Tabellendaten ändern. + + + + Column '%1' has duplicate data. + + Spalte '%1' hat doppelte Daten. + + + + + This makes it impossible to enable the 'Unique' flag. Please remove the duplicate data, which will allow the 'Unique' flag to then be enabled. + Dies macht das Aktivieren des 'Unique'-Flags unmöglich. Bitte die doppelten Daten entfernen, damit das 'Unique'-Flag dann aktiviert werden kann. + + + + Are you sure you want to delete the field '%1'? +All data currently stored in this field will be lost. + Soll das Feld '%1' wirklich gelöscht werden? +Alle aktuell in diesem Feld gespeicherten Daten gehen verloren. + + + + Please add a field which meets the following criteria before setting the without rowid flag: + - Primary key flag set + - Auto increment disabled + Bitte fügen Sie vor dem Setzen des "Without rowid"-Flags ein Feld hinzu, welches folgenden Kriterien entspricht: + - Primärschlüssel-Flag gesetzt + - Autoinkrement deaktiviert + + + + ExportDataDialog + + + Export data as CSV + Daten als CSV exportieren + + + + Tab&le(s) + Tabe&lle(n) + + + + Colu&mn names in first line + &Spaltennamen in der ersten Zeile + + + + Fie&ld separator + Fe&ld-Separator + + + + , + , + + + + ; + ; + + + + Tab + Tab + + + + | + | + + + + + + Other + Anderer + + + + &Quote character + &String-Zeichen + + + + " + " + + + + ' + ' + + + + New line characters + Zeilenumbruchs-Zeichen + + + + Windows: CR+LF (\r\n) + Windows: CR+LF (\r\n) + + + + Unix: LF (\n) + Unix: LF (\n) + + + + Pretty print + Pretty Print + + + + + Could not open output file: %1 + Ausgabedatei konnte nicht geöffnet werden: %1 + + + + + Choose a filename to export data + Dateinamen für den Datenexport wählen + + + + Export data as JSON + Daten als JSON exportieren + + + + exporting CSV + exportiere CSV + + + + exporting JSON + exportiere JSON + + + + Please select at least 1 table. + Bitte mindestens eine Tabelle auswählen. + + + + Choose a directory + Verzeichnis wählen + + + + Export completed. + Export abgeschlossen. + + + + ExportSqlDialog + + + Export SQL... + SQL exportieren... + + + + Tab&le(s) + Tabe&lle(n) + + + + Select All + Alle auswählen + + + + Deselect All + Alle abwählen + + + + &Options + &Optionen + + + + Keep column names in INSERT INTO + Spaltennamen in INSERT INTO belassen + + + + Multiple rows (VALUES) per INSERT statement + Mehrere Reihen (VALUES) je INSERT-Statement + + + + Export everything + Alles exportieren + + + + Export schema only + Nur Schema exportieren + + + + Export data only + Nur Daten exportieren + + + + Keep old schema (CREATE TABLE IF NOT EXISTS) + Altes Schema behalten (CREATE TABLE IF NOT EXISTS) + + + + Overwrite old schema (DROP TABLE, then CREATE TABLE) + Altes Schema überschreiben (DROP TABLE, dann CREATE TABLE) + + + + Please select at least one table. + Bitte wählen Sie mindestens eine Tabelle aus. + + + + Choose a filename to export + Dateinamen zum Export auswählen + + + + Export completed. + Export abgeschlossen. + + + + Export cancelled or failed. + Export abgebrochen oder fehlgeschlagen. + + + + ExtendedScintilla + + + + Ctrl+H + + + + + Ctrl+F + + + + + + Ctrl+P + + + + + Find... + Suchen... + + + + Find and Replace... + Suchen und ersetzen... + + + + Print... + Drucken... + + + + ExtendedTableWidget + + + Use as Exact Filter + Als exakten Filter verwenden + + + + Containing + Enthält + + + + Not containing + Enthält nicht + + + + Not equal to + Ungleich zu + + + + Greater than + Größer als + + + + Less than + Kleiner als + + + + Greater or equal + Größer oder gleich + + + + Less or equal + Kleiner oder gleich + + + + Between this and... + Zwischen diesem und... + + + + Regular expression + Regulärer Ausdruck + + + + Edit Conditional Formats... + Bedingte Formatierungen bearbeiten... + + + + Set to NULL + Auf NULL setzen + + + + Copy + Kopieren + + + + Copy with Headers + Mit Headern kopieren + + + + Copy as SQL + Als SQL kopieren + + + + Paste + Einfügen + + + + Print... + Drucken... + + + + Use in Filter Expression + In Filterausdruck verwenden + + + + Alt+Del + + + + + Ctrl+Shift+C + + + + + Ctrl+Alt+C + + + + + The content of the clipboard is bigger than the range selected. +Do you want to insert it anyway? + Der Inhalt der Zwischenablage ist größer als der ausgewählte Bereich. Soll er dennoch eingefügt werden? + + + + <p>Not all data has been loaded. <b>Do you want to load all data before selecting all the rows?</b><p><p>Answering <b>No</b> means that no more data will be loaded and the selection will not be performed.<br/>Answering <b>Yes</b> might take some time while the data is loaded but the selection will be complete.</p>Warning: Loading all the data might require a great amount of memory for big tables. + <p>Es wurden nicht alle Daten geladen. <b>Sollen vor dem Auswählen aller Zeilen alle Daten geladen werden?</b><p><p>Das Antworten von <b>Nein</b> wird keine weiteren Daten laden und die Auswahl nicht durchführen.</br>Das Antworten von <b>Ja</b> benötigt möglicherweise einige Zeit, während die Daten geladen werden, aber die Auswahl wird vollständig sein.</p>Warnung: Das Laden aller Daten benötigt bei großen Tabellen möglicherweise eine große Menge an Speicher. + + + + Cannot set selection to NULL. Column %1 has a NOT NULL constraint. + Auswahl kann nicht auf NULL gesetzt. Die Spalte %1 hat ein NOT NULL Constraint. + + + + FileExtensionManager + + + File Extension Manager + Dateierweiterungs-Manager + + + + &Up + H&och + + + + &Down + &Runter + + + + &Add + &Hinzufügen + + + + &Remove + &Entfernen + + + + + Description + Beschreibung + + + + Extensions + Erweiterungen + + + + *.extension + *.erweiterung + + + + FilterLineEdit + + + Filter + Filtern + + + + These input fields allow you to perform quick filters in the currently selected table. +By default, the rows containing the input text are filtered out. +The following operators are also supported: +% Wildcard +> Greater than +< Less than +>= Equal to or greater +<= Equal to or less += Equal to: exact match +<> Unequal: exact inverse match +x~y Range: values between x and y +/regexp/ Values matching the regular expression + Diese Eingabefelder erlauben Ihnen das Anwenden von schnellen Filtern in der aktuell ausgewählten Tabelle. +Standardmäßig werden Zeilen, die den Eingabetext beinhalten, herausgefiltert. +Zudem werden die folgenden Operatoren unterstützt: +% Wildcard +> Größer als +< Kleiner als +>= Größer oder gleich +<= Kleiner oder gleich += Gleich: exakte Übereinstimmung +<> Ungleich:exakte inverse Übereinstimmung +x~y Bereich: Werte zwischen x und y +/regexp/ Werte, die dem regulären Ausdruck genügen + + + + Clear All Conditional Formats + Alle bedingten Formatierungen löschen + + + + Use for Conditional Format + Als bedingte Formatierung verwenden + + + + Edit Conditional Formats... + Bedingte Formatierungen bearbeiten... + + + + Set Filter Expression + Filterausdruck setzen + + + + What's This? + Was ist das? + + + + Is NULL + Ist NULL + + + + Is not NULL + Ist nicht NULL + + + + Is empty + Ist leer + + + + Is not empty + Ist nicht leer + + + + Not containing... + Enthält nicht... + + + + Equal to... + Gleich zu... + + + + Not equal to... + Ungleich zu... + + + + Greater than... + Größer als... + + + + Less than... + Kleiner als... + + + + Greater or equal... + Größer oder gleich... + + + + Less or equal... + Kleiner oder gleich... + + + + In range... + Im Bereich... + + + + Regular expression... + Regulärer Ausdruck... + + + + FindReplaceDialog + + + Find and Replace + Suchen und Ersetzen + + + + Fi&nd text: + Text fi&nden: + + + + Re&place with: + Er&setzen mit: + + + + Match &exact case + &Exakte Schreibung + + + + Match &only whole words + Nur &ganze Wörter + + + + When enabled, the search continues from the other end when it reaches one end of the page + Falls aktiviert, fährt die Suche am anderen Ende fort, wenn sie das Ende der Seite erreicht hat + + + + &Wrap around + &Umbrechen + + + + When set, the search goes backwards from cursor position, otherwise it goes forward + Falls gesetzt, erfolgt die Suche rückwärts von der Cursorposition, andernfalls erfolgt sie vorwärts + + + + Search &backwards + Rück&wärts suchen + + + + <html><head/><body><p>When checked, the pattern to find is searched only in the current selection.</p></body></html> + <html><head/><body><p>Wenn ausgewählt, wird das gesuchte Muster nur in der aktuellen Auswahl gesucht.</p></body></html> + + + + &Selection only + Nur Au&swahl + + + + <html><head/><body><p>When checked, the pattern to find is interpreted as a UNIX regular expression. See <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>.</p></body></html> + <html><head/><body><p>Falls aktiviert, wird das Suchmuster als regulärer Ausdruck (UNIX-Stil) interpretiert. Siehe <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks (englisch)</a>.</p></body></html> + + + + Use regular e&xpressions + Reguläre A&usdrücke verwenden + + + + Find the next occurrence from the cursor position and in the direction set by "Search backwards" + Das nächste Auftreten ausgehend von der Cursorpositoin und in der durch "Rückwärts suchen" gesetzten Richtung finden + + + + &Find Next + Nächste &finden + + + + F3 + + + + + &Replace + &Ersetzen + + + + Highlight all the occurrences of the text in the page + Alle Auftreten des Textes auf der Seite hervorheben + + + + F&ind All + Alle f&inden + + + + Replace all the occurrences of the text in the page + Alle Auftreten des Textes auf der Seite ersetzen + + + + Replace &All + &Alle ersetzen + + + + The searched text was not found + Der gesuchte Text wurde nicht gefunden + + + + The searched text was not found. + Der gesuchte Text wurde nicht gefunden. + + + + The searched text was found one time. + Der gesuchte Text wurde einmal gefunden. + + + + The searched text was found %1 times. + Der gesuchte Text wurde %1-mal gefunden. + + + + The searched text was replaced one time. + Der gesuchte Text wurde einmal ersetzt. + + + + The searched text was replaced %1 times. + Der gesuchte Text wurde %1-mal ersetzt. + + + + ForeignKeyEditor + + + &Reset + Zu&rücksetzen + + + + Foreign key clauses (ON UPDATE, ON DELETE etc.) + Fremdschlüssel-Klauseln (ON UPDATE, ON DELETE etc.) + + + + ImportCsvDialog + + + Import CSV file + CSV-Datei importieren + + + + Table na&me + Tabellenna&me + + + + &Column names in first line + &Spaltennamen in erster Zeile + + + + Field &separator + Feld-&Separator + + + + , + , + + + + ; + ; + + + + + Tab + Tab + + + + | + | + + + + Other + Anderer + + + + &Quote character + &String-Zeichen + + + + + Other (printable) + Anderer (darstellbar) + + + + + Other (code) + Anderer (Code) + + + + " + " + + + + ' + ' + + + + &Encoding + &Codierung + + + + UTF-8 + UTF-8 + + + + UTF-16 + UTF-16 + + + + ISO-8859-1 + ISO-8859-1 + + + + Trim fields? + Felder trimmen? + + + + Separate tables + Tabellen trennen + + + + Advanced + Erweitert + + + + When importing an empty value from the CSV file into an existing table with a default value for this column, that default value is inserted. Activate this option to insert an empty value instead. + Beim Import eines leeren Wertes aus einer CSV-Datei in eine existierende Tabelle mit einem Standardwert für diese Spalte wird dieser Standardwert eingefügt. Aktivieren Sie diese Option, um stattdessen einen leeren Wert einzufügen. + + + + Ignore default &values + Standard&werte ignorieren + + + + Activate this option to stop the import when trying to import an empty value into a NOT NULL column without a default value. + Aktivieren Sie diese Option, um den Import zu stoppen, falls ein leerer Wert in eine NOT-NULL-Spalte ohne Standardwert importiert werden soll. + + + + Fail on missing values + Fehler bei fehlenden Werten + + + + Disable data type detection + Datentyp-Erkennung deaktivieren + + + + Disable the automatic data type detection when creating a new table. + Die automatische Datentyperkennung bei der Erstellung einer neuen Tabelle deaktivieren. + + + + When importing into an existing table with a primary key, unique constraints or a unique index there is a chance for a conflict. This option allows you to select a strategy for that case: By default the import is aborted and rolled back but you can also choose to ignore and not import conflicting rows or to replace the existing row in the table. + Beim Import von Daten in eine existierende Tabelle mit einem Primärschlüssel, Unique-Constraints oder einem eindeutigen Index besteht die Möglichkeit von Konflikten. Diese Option erlaubt die Auswahl einer Strategie für diesen Fall: Standardmäßig wird der Import abgebrochen und zurückgerollt, aber es besteht auch die Option des Ignorierens und somit Nicht-Importierens in Konflikt stehender Zeilen oder des Ersetzens existierender Zeilen der Tabelle. + + + + Abort import + Import abbrechen + + + + Ignore row + Zeile ignorieren + + + + Replace existing row + Existierende Zeile ersetzen + + + + Conflict strategy + Konflikt-Strategie + + + + + Deselect All + Alle abwählen + + + + Match Similar + Ähnliche suchen + + + + Select All + Alle auswählen + + + + There is already a table named '%1' and an import into an existing table is only possible if the number of columns match. + Es gibt bereits eine Tabelle namens '%1' und ein Import in eine existierende Tabelle ist nur bei übereinstimmender Spaltenanzahl möglich. + + + + There is already a table named '%1'. Do you want to import the data into it? + Es gibt bereits eine Tabelle namens '%1'. Möchten Sie die Daten in diese importieren? + + + + Creating restore point failed: %1 + Erstellung des Wiederherstellungspunktes fehlgeschlagen: %1 + + + + Creating the table failed: %1 + Erstellung der Tabelle fehlgeschlagen: %1 + + + + importing CSV + importierte CSV + + + + Importing the file '%1' took %2ms. Of this %3ms were spent in the row function. + Import der Datei '%1' benötigte %2ms. Davon wurden %3ms in der Zeilenfunktion verbracht. + + + + Inserting row failed: %1 + Einfügen der Zeile fehlgeschlagen: %1 + + + + MainWindow + + + toolBar1 + Toolbar1 + + + + Opens the SQLCipher FAQ in a browser window + Öffnt die SQLCiper FAQ in einem Browserfenster + + + + Export one or more table(s) to a JSON file + Exportiert eine oder mehrere Tabelle(n) in eine JSON-Datei + + + + DB Browser for SQLite + DB Browser für SQLite + + + + This is the structure of the opened database. +You can drag SQL statements from an object row and drop them into other applications or into another instance of 'DB Browser for SQLite'. + + Dies ist die Struktur der geöffneten Datenbank. +Sie können SQL-Statements aus einer Objektzeile fassen und in anderen Anwendungen oder einer anderen 'DB-Browser für SQLite'-Instanz ablegen. + + + + + Un/comment block of SQL code + Kommentieren/Unkommentieren eines Block von SQL-Code + + + + Un/comment block + Block kommentieren/unkommentieren + + + + Comment or uncomment current line or selected block of code + Aktuelle Zeilen oder ausgewählten Codeblock kommentieren oder unkommentieren + + + + Comment or uncomment the selected lines or the current line, when there is no selection. All the block is toggled according to the first line. + Aktuelle Zeilen oder aktuelle Zeile kommentieren oder unkommentieren, wenn es keine Auswahl gibt. Der gesamte Block wird entsprechend der ersten Zeile invertiert. + + + + Ctrl+/ + + + + + Stop SQL execution + SQL-Ausführung abbrechen + + + + Stop execution + Ausführung abbrechen + + + + Stop the currently running SQL script + Das aktuelle laufende SQL-Skript stoppen + + + + Error Log + Fehlerlog + + + + Ctrl+F4 + + + + + Compact &Database... + &Datenbank komprimieren... + + + + Execute all/selected SQL + Komplettes/ausgewähltes SQL ausführen + + + + This button executes the currently selected SQL statements. If no text is selected, all SQL statements are executed. + Dieser Button führt das aktuell ausgewählte SQL-Statement aus. Falls kein Text ausgewählt ist, werden alle SQL-Statements ausgeführt. + + + + &Load Extension... + Erweiterung &laden... + + + + Execute line + Zeile ausführen + + + + &Wiki + &Wiki + + + + F1 + + + + + Bug &Report... + Fehle&rmeldung... + + + + Feature Re&quest... + Funktions&anfrage... + + + + Web&site + Web&seite + + + + &Donate on Patreon... + Über &Patreon spenden... + + + + Open &Project... + &Projekt öffnen... + + + + &Attach Database... + Datenbank &anhängen... + + + + + Add another database file to the current database connection + Eine andere Datenbankdatei zur aktuellen Datenbankverbindung hinzufügen + + + + This button lets you add another database file to the current database connection + Dieser Button erlaubt Ihnen das Hinzufügen einer anderen Datenbankdatei zur aktuellen Datenbankverbindung + + + + &Set Encryption... + Verschlüsselung &setzen... + + + + SQLCipher &FAQ + SQLCiper &FAQ + + + + Table(&s) to JSON... + Tabelle(&n) zu JSON... + + + + Open Data&base Read Only... + Daten&bank im Lesemodus öffnen... + + + + Ctrl+Shift+O + + + + + Save results + Ergebnisse speichern + + + + Save the results view + Ergebnisansicht speichern + + + + This button lets you save the results of the last executed query + Dieser Button erlaubt Ihnen das Speichern der Ergebnisse der zuletzt ausgeführten Query + + + + + Find text in SQL editor + Text im SQL-Editor finden + + + + Find + Suchen + + + + This button opens the search bar of the editor + Dieser Button öffnet die Suchleiste des Editors + + + + Ctrl+F + + + + + + Find or replace text in SQL editor + Text im SQL-Editor suchen oder ersetzen + + + + Find or replace + Suchen oder ersetzen + + + + This button opens the find/replace dialog for the current editor tab + Dieser Button öffnet den Suchen-/Ersetzen-Dialog für den aktuellen Editortab + + + + Ctrl+H + + + + + Export to &CSV + Nach &CSV exportieren + + + + Save as &view + Als &View speichern + + + + Save as view + Als View speichern + + + + Browse Table + Tabelle durchsuchen + + + + Shows or hides the Project toolbar. + Zeigt oder versteckt die Projekt-Werkzeugleiste. + + + + Extra DB Toolbar + Extra-DB-Werkzeugleiste + + + + This button lets you save all the settings associated to the open DB to a DB Browser for SQLite project file + Dieser Button erlaubt Ihnen das Speichern aller mit der geöffneten DB verbundenen Einstellungen in einer DB-Browser für SQLite-Projektdatei + + + + This button lets you open a DB Browser for SQLite project file + Dieser Button erlaubt Ihnen das Öffnen einer DB-Browser für SQLite-Projektdatei + + + + New In-&Memory Database + Neue In-&Memory-Datenbank + + + + Drag && Drop Qualified Names + Drag && Drop qualifizierter Namen + + + + + Use qualified names (e.g. "Table"."Field") when dragging the objects and dropping them into the editor + Qualifizierte Namen (z.B. "Tabelle."Feld") verwenden, wenn die Objekte gefasst und im Editor abgelegt werden + + + + Drag && Drop Enquoted Names + Drag && Drop zitierter Namen + + + + + Use escaped identifiers (e.g. "Table1") when dragging the objects and dropping them into the editor + Geschützte Identifier (z.B. "Tabelle1") verwenden, wenn die Objekte gefasst und im Editor abgelegt werden + + + + &Integrity Check + &Integritätsprüfung + + + + Runs the integrity_check pragma over the opened database and returns the results in the Execute SQL tab. This pragma does an integrity check of the entire database. + Führt das integrity_check-Pragma auf der geöffneten Datenbank aus und gibt die Ergebnisse im SQL-Tab zurück. Dieses Pragma führt eine Integritätsprüfung der gesamten Datenbank durch. + + + + &Foreign-Key Check + &Fremdschlüssel-Prüfung + + + + Runs the foreign_key_check pragma over the opened database and returns the results in the Execute SQL tab + Führt das foreign_key_check-Pragma auf der geöffneten Datenbank aus und gibt die Ergebnisse im SQL-Tab zurück + + + + &Quick Integrity Check + &Schnelle Integritätsprüfung + + + + Run a quick integrity check over the open DB + Führt eine schnelle Integritätsprüfung der geöffneten DB aus + + + + Runs the quick_check pragma over the opened database and returns the results in the Execute SQL tab. This command does most of the checking of PRAGMA integrity_check but runs much faster. + Führt das quick_check-Pragma auf der geöffneten Datenbank aus und gibt die Ergebnisse im SQL-Tab zurück. Dieser Befehl führt einen Großteil der Prüfung des integrity_check-Pragmas aus, ist aber deutlich schneller. + + + + &Optimize + &Optimieren + + + + Attempt to optimize the database + Versuchen, die Datenbank zu optimieren + + + + Runs the optimize pragma over the opened database. This pragma might perform optimizations that will improve the performance of future queries. + Führt das optimize-Pragma auf der geöffneten Datenbank aus. Dieses Pragma führt möglicherweise Optimierungen durch, die die Performanz zukünftiger Queries verbessern. + + + + + Print + Drucken + + + + Print text from current SQL editor tab + Den Text aus dem aktuellen SQL-Editortab drucken + + + + Open a dialog for printing the text in the current SQL editor tab + Einen Dialog zum Drucken des Textes im aktuellen SQL-Editortab öffnen + + + + Print the structure of the opened database + Die Struktur der geöffneten Datenbank drucken + + + + Open a dialog for printing the structure of the opened database + Einen Dialog zum Drucken der Struktur der geöffneten Datenbank öffnen + + + + &Save Project As... + Projekt &speichern als... + + + + + + Save the project in a file selected in a dialog + Das Projekt in einer in einem Dialog ausgewählten Datei speichern + + + + Save A&ll + &Alle speichern + + + + + + Save DB file, project file and opened SQL files + DB-Datei, Projektdatei und geöffnete SQL-Dateien speichern + + + + Ctrl+Shift+S + + + + + Open an existing database file in read only mode + Eine existierende Datenbank schreibgeschützt öffnen + + + + &File + &Datei + + + + &Import + &Import + + + + &Export + &Export + + + + &Edit + &Bearbeiten + + + + &View + &Ansicht + + + + &Help + &Hilfe + + + + Edit Database &Cell + Datenbank&zelle bearbeiten + + + + This button clears the contents of the SQL logs + Dieser Button löscht den Inhalt der SQL-Logs + + + + This panel lets you examine a log of all SQL commands issued by the application or by yourself + Dieses Panel erlaubt Ihnen das Betrachten eines Logs aller SQL-Kommandos, die von der Anwendung oder von Ihnen selbst ausgegangen sind + + + + DB Sche&ma + DB-Sche&ma + + + + This is the structure of the opened database. +You can drag multiple object names from the Name column and drop them into the SQL editor and you can adjust the properties of the dropped names using the context menu. This would help you in composing SQL statements. +You can drag SQL statements from the Schema column and drop them into the SQL editor or into other applications. + + Dies ist die Struktur der geöffneten Datenbank. +Sie können mehrere Objektnamen aus der Namensspalte nehmen und in den SQL-Editor ziehen und Sie können die Eigenschaften der abgelegten Namen über das Kontextmenü anpassen. Dies kann Sie bei der Erstellung von SQL-Statements unterstützen. +Sie können SQL-Statements aus der Schemaspalte nehmen und in den SQL-Editor oder in anderen Anwendungen ablegen. + + + + + &Remote + Entfe&rnt + + + + + Execute SQL + This has to be equal to the tab title in all the main tabs + SQL ausführen + + + + Open SQL file(s) + SQL-Datei(en) öffnen + + + + This button opens files containing SQL statements and loads them in new editor tabs + Dieser Button öffnet Dateien mit SQL-Anweisungen und lädt diese in neue Editortabs + + + + + Execute current line + Aktuelle Zeile ausführen + + + + This button executes the SQL statement present in the current editor line + Dieser Button führt das SQL-Statement in der aktuellen Editorzeile aus + + + + Shift+F5 + + + + + Sa&ve Project + &Projekt speichern + + + + + Save SQL file as + SQL-Datei speichern als + + + + This button saves the content of the current SQL editor tab to a file + Dieser Button speichert den Inhalt des aktuellen SQL-Editortabs in einer Datei + + + + &Browse Table + Tabelle &durchsuchen + + + + Copy Create statement + Create-Statement kopieren + + + + Copy the CREATE statement of the item to the clipboard + CREATE-Statement des Elements in die Zwischenablage kopieren + + + + User + Benutzer + + + + Application + Anwendung + + + + &Clear + &Leeren + + + + &New Database... + &Neue Datenbank... + + + + + Create a new database file + Neue Datenbank-Datei erstellen + + + + This option is used to create a new database file. + Diese Option wird zum Erstellen einer neuen Datenbank-Datei verwendet. + + + + Ctrl+N + + + + + + &Open Database... + Datenbank &öffnen... + + + + + + + + Open an existing database file + Existierende Datenbank-Datei öffnen + + + + + + This option is used to open an existing database file. + Diese Option wird zum Öffnen einer existierenden Datenbank-Datei verwendet. + + + + Ctrl+O + + + + + &Close Database + Datenbank &schließen + + + + This button closes the connection to the currently open database file + Dieser Button schließt die Verbindung zu der aktuell geöffneten Datenbankdatei + + + + + Ctrl+W + + + + + + Revert database to last saved state + Datenbank auf zuletzt gespeicherten Zustand zurücksetzen + + + + This option is used to revert the current database file to its last saved state. All changes made since the last save operation are lost. + Diese Option wird zum Zurücksetzen der aktuellen Datenbank-Datei auf den zuletzt gespeicherten Zustand verwendet. Alle getätigten Änderungen gehen verloren. + + + + + Write changes to the database file + Änderungen in Datenbank-Datei schreiben + + + + This option is used to save changes to the database file. + Diese Option wird zum Speichern von Änderungen in der Datenbank-Datei verwendet. + + + + Ctrl+S + + + + + Compact the database file, removing space wasted by deleted records + Datenbank-Datei komprimieren, löscht Speicherplatz von gelöschten Zeilen + + + + + Compact the database file, removing space wasted by deleted records. + Datenbank-Datei komprimieren, löscht Speicherplatz von gelöschten Zeilen. + + + + E&xit + &Beenden + + + + Ctrl+Q + + + + + Import data from an .sql dump text file into a new or existing database. + Daten von einer .sql-Dump-Textdatei in eine neue oder existierende Datenbank importieren. + + + + This option lets you import data from an .sql dump text file into a new or existing database. SQL dump files can be created on most database engines, including MySQL and PostgreSQL. + Diese Option wird zum Importieren von Daten von einer .sql-Dump-Textdatei in eine neue oder existierende Datenbank verwendet. SQL-Dumpdateien können von den meisten Datenbankanwendungen erstellt werden, inklusive MySQL und PostgreSQL. + + + + Open a wizard that lets you import data from a comma separated text file into a database table. + Öffnet einen Assistenten zum Importieren von Daten aus einer kommaseparierten Textdatei in eine Datenbanktabelle. + + + + Open a wizard that lets you import data from a comma separated text file into a database table. CSV files can be created on most database and spreadsheet applications. + Öffnet einen Assistenten zum Importieren von Daten aus einer kommaseparierten Textdatei in eine Datenbanktabelle. CSV-Dateien können von den meisten Datenbank- und Tabellenkalkulations-Anwendungen erstellt werden. + + + + Export a database to a .sql dump text file. + Daten in eine .sql-Dump-Textdatei exportieren. + + + + This option lets you export a database to a .sql dump text file. SQL dump files contain all data necessary to recreate the database on most database engines, including MySQL and PostgreSQL. + Diese Option ermöglicht den Export einer Datenbank in eine .sql-Dump-Textdatei. SQL-Dumpdateien enthalten alle notwendigen Daten, um die Datenbank mit den meisten Datenbankanwendungen neu erstellen zu können, inklusive MySQL und PostgreSQL. + + + + Export a database table as a comma separated text file. + Datenbank als kommaseparierte Textdatei exportieren. + + + + Export a database table as a comma separated text file, ready to be imported into other database or spreadsheet applications. + Exportiert die Datenbank als kommaseparierte Textdatei, fertig zum Import in andere Datenbank- oder Tabellenkalkulations-Anwendungen. + + + + Open the Create Table wizard, where it is possible to define the name and fields for a new table in the database + Den Assistenten zum Erstellen einer Tabelle öffnen, wo der Name und die Felder für eine neue Tabelle in der Datenbank festgelegt werden können + + + + Open the Delete Table wizard, where you can select a database table to be dropped. + Den Assistenten zum Löschen einer Tabelle öffnen, wo eine zu entfernende Datenbanktabelle ausgewählt werden kann. + + + + Open the Modify Table wizard, where it is possible to rename an existing table. It is also possible to add or delete fields form a table, as well as modify field names and types. + Den Assistenten zum Ändern einer Tabelle öffnen, wo eine existierende Tabelle umbenannt werden kann. Ebenso können Felder hinzugefügt und gelöscht sowie Feldnamen und -typen geändert werden. + + + + Open the Create Index wizard, where it is possible to define a new index on an existing database table. + Den Assistenten zum Erstellen des Index öffnen, wo ein neuer Index für eine existierende Datenbanktabelle gewählt werden kann. + + + + &Preferences... + &Einstellungen... + + + + + Open the preferences window. + Das Einstellungsfenster öffnen. + + + + &DB Toolbar + &DB Toolbar + + + + Shows or hides the Database toolbar. + Zeigt oder versteckt die Datenbank-Toolbar. + + + + Shift+F1 + + + + + &Recently opened + &Kürzlich geöffnet + + + + Open &tab + &Tab öffnen + + + + Ctrl+T + + + + + + Database Structure + This has to be equal to the tab title in all the main tabs + Datenbankstruktur + + + + + Browse Data + This has to be equal to the tab title in all the main tabs + Daten durchsuchen + + + + + Edit Pragmas + This has to be equal to the tab title in all the main tabs + Pragmas bearbeiten + + + + Warning: this pragma is not readable and this value has been inferred. Writing the pragma might overwrite a redefined LIKE provided by an SQLite extension. + Warnung: dieses Pragma ist nicht lesbar und dieser Wert wurde abgeleitet. Das Schreiben des Pragmas überschreibt möglicherweise ein geändertes LIKE, welches von einer SQLite-Erweiterung zur Verfügung gestellt wird. + + + + &Tools + &Werkzeuge + + + + DB Toolbar + DB Toolbar + + + + SQL &Log + SQL-&Log + + + + Show S&QL submitted by + Anzeige des übergebenen S&QL von + + + + &Plot + &Diagramm + + + + + Project Toolbar + Projekt-Werkzeugleiste + + + + Extra DB toolbar + Extra-DB-Werkzeugleiste + + + + + + Close the current database file + Die aktuelle Datenbankdatei schließen + + + + &Revert Changes + Änderungen &rückgängig machen + + + + &Write Changes + Änderungen &schreiben + + + + &Database from SQL file... + &Datenbank aus SQL-Datei... + + + + &Table from CSV file... + &Tabelle aus CSV-Datei... + + + + &Database to SQL file... + &Datenbank als SQL-Datei... + + + + &Table(s) as CSV file... + &Tabelle(n) als CSV-Datei... + + + + &Create Table... + Tabelle &erstellen... + + + + &Delete Table... + Tabelle &löschen... + + + + &Modify Table... + Tabelle &ändern... + + + + Create &Index... + &Index erstellen... + + + + W&hat's This? + &Was ist das? + + + + &About + &Über + + + + This button opens a new tab for the SQL editor + Dieser Button öffnet einen neuen Tab im SQL-Editor + + + + &Execute SQL + SQL &ausführen + + + + + Save the current session to a file + Aktuelle Sitzung in einer Datei speichern + + + + + Load a working session from a file + Sitzung aus einer Datei laden + + + + + + Save SQL file + SQL-Datei speichern + + + + Ctrl+E + + + + + Export as CSV file + Als CSV-Datei exportieren + + + + Export table as comma separated values file + Tabelle als kommaseparierte Wertedatei exportieren + + + + Ctrl+L + + + + + + Ctrl+P + + + + + Database encoding + Datenbank-Kodierung + + + + + Choose a database file + Eine Datenbankdatei auswählen + + + + Ctrl+Return + Strg+Return + + + + Ctrl+D + Strg+D + + + + Ctrl+I + Strg+I + + + + Window Layout + + + + + Reset Window Layout + Fensteranordnung zurücksetzen + + + + Alt+0 + + + + + The database is currenctly busy. + Die Datenbank ist aktuell beschäftigt. + + + + Click here to interrupt the currently running query. + Hier klicken, um die aktuell laufende Anfrage zu unterbrechen. + + + + Encrypted + Verschlüsselt + + + + Database is encrypted using SQLCipher + Datenbank ist mittels SQLCipher verschlüsselt + + + + Read only + Nur lesen + + + + Database file is read only. Editing the database is disabled. + Zugriff auf Datenbank nur lesend. Bearbeiten der Datenbank ist deaktiviert. + + + + Could not open database file. +Reason: %1 + Datenbankdatei konnte nicht geöffnet werden. Grund: %1 + + + + + + Choose a filename to save under + Dateinamen zum Speichern auswählen + + + + Error while saving the database file. This means that not all changes to the database were saved. You need to resolve the following error first. + +%1 + Fehler beim Speichern der Datenbankdatei. Dies bedeutet, dass nicht alle Änderungen an der Datenbank gespeichert wurden. Der folgende Fehler muss zuvor gelöst werden: + +%1 + + + + Do you want to save the changes made to SQL tabs in the project file '%1'? + Sollen die in den SQL-Tabs getätigten Änderungen in der Projektdatei '%1' gespeichert werden? + + + + A new DB Browser for SQLite version is available (%1.%2.%3).<br/><br/>Please download at <a href='%4'>%4</a>. + Eine neue Version des DB Browsers für SQLite ist verfügbar (%1.%2.%3).<br/><br/>Bitte laden Sie diese von <a href='%4'>%4</a> herunter. + + + + DB Browser for SQLite project file (*.sqbpro) + DB Browser für SQLite Projektdatei (*.sqbpro) + + + + Error checking foreign keys after table modification. The changes will be reverted. + Fehler beim Prüfen von Fremdschlüsseln nach der Änderung an der Tabelle. Die Änderungen werden rückgängig gemacht. + + + + This table did not pass a foreign-key check.<br/>You should run 'Tools | Foreign-Key Check' and fix the reported issues. + Diese Tabelle hat die Fremdschlüsselprüfung nicht bestanden.<br/>Sie sollten 'Werkzeuge | Fremdschlüssel-Prüfng' ausführen und die gemeldeten Probleme beheben. + + + + Execution finished with errors. + Ausführung wurde mit Fehlern beendet. + + + + Execution finished without errors. + Ausführung wurde ohne Fehler beendet. + + + + Are you sure you want to undo all changes made to the database file '%1' since the last save? + Sollen wirklich alle Änderungen an der Datenbankdatei '%1' seit dem letzten Speichern rückgängig gemacht werden? + + + + Choose a file to import + Datei für Import auswählen + + + + Text files(*.sql *.txt);;All files(*) + Textdateien(*.sql *.txt);;Alle Dateien(*) + + + + Do you want to create a new database file to hold the imported data? +If you answer no we will attempt to import the data in the SQL file to the current database. + Soll für die importierten Daten eine neue Datenbank erstellt werden? +Bei der Antwort NEIN werden die Daten in die SQL-Datei der aktuellen Datenbank importiert. + + + + You are still executing SQL statements. Closing the database now will stop their execution, possibly leaving the database in an inconsistent state. Are you sure you want to close the database? + Es werden aktuell SQL-Statements ausgeführt. Das Schließen der Datenbank wird deren Ausführung stoppen, was die Datenbank möglicherweise in einem inkonsistenten Zustand belässt. Soll die Datenbank wirklich geschlossen werden? + + + + Do you want to save the changes made to the project file '%1'? + Sollen die an der Projektdatei '%1' getätigten Änderungen gespeichert werden? + + + + File %1 already exists. Please choose a different name. + Datei %1 existiert bereits. Bitte einen anderen Namen auswählen. + + + + Error importing data: %1 + Fehler beim Datenimport: %1 + + + + Import completed. + Import abgeschlossen. + + + + Delete View + Ansicht löschen + + + + Delete Trigger + Trigger löschen + + + + Delete Index + Index löschen + + + + + Delete Table + Tabelle löschen + + + + Setting PRAGMA values will commit your current transaction. +Are you sure? + Das Setzen von PRAGMA-Werten übermittelt den aktuellen Vorgang. +Sind Sie sicher? + + + + In-Memory database + In-Memory-Datenbank + + + + Simplify Window Layout + + + + + Shift+Alt+0 + + + + + Dock Windows at Bottom + + + + + Dock Windows at Left Side + + + + + Dock Windows at Top + + + + + Are you sure you want to delete the table '%1'? +All data associated with the table will be lost. + Möchten Sie die Tabelle '%1' wirklich löschen? +Alle mit dieser Tabelle verbundenen Daten gehen verloren. + + + + Are you sure you want to delete the view '%1'? + Möchten Sie die Ansicht '%1' wirklich löschen? + + + + Are you sure you want to delete the trigger '%1'? + Möchten Sie den Trigger '%1' wirklich löschen? + + + + Are you sure you want to delete the index '%1'? + Möchten Sie den Index '%1' wirklich löschen? + + + + Error: could not delete the table. + Fehler: Tabelle konnte nicht gelöscht werden. + + + + Error: could not delete the view. + Fehler: Ansicht konnte nicht gelöscht werden. + + + + Error: could not delete the trigger. + Fehler: Trigger konnte nicht gelöscht werden. + + + + Error: could not delete the index. + Fehler: Index konnte nicht gelöscht werden. + + + + Message from database engine: +%1 + Nachricht von Datenbank-Engine: +%1 + + + + Editing the table requires to save all pending changes now. +Are you sure you want to save the database? + Das Bearbeiten der Tabelle setzt das Speichern aller ausstehenden Änderungen voraus. +Möchten Sie die Datenbank wirklich speichern? + + + + Edit View %1 + Ansicht %1 bearbeiten + + + + Edit Trigger %1 + Trigger %1 bearbeiten + + + + You are already executing SQL statements. Do you want to stop them in order to execute the current statements instead? Note that this might leave the database in an inconsistent state. + Es werden bereits SQL-Statements ausgeführt. Sollen diese gestoppt werden, um stattdessen die aktuellen Statements auszuführen? Dies führt möglicherweise zu einem inkonsistenten Zustand der Datenbank. + + + + -- EXECUTING SELECTION IN '%1' +-- + -- FÜHRE AUSWAHL IN '%1' AUS +-- + + + + -- EXECUTING LINE IN '%1' +-- + -- FÜHRE ZEILE IN '%1' AUS +-- + + + + -- EXECUTING ALL IN '%1' +-- + -- FÜHRE ALLES IN '%1' AUS +-- + + + + + At line %1: + In Zeile %1: + + + + Result: %1 + Ergebnis: %1 + + + + Result: %2 + Ergebnis: %2 + + + + Setting PRAGMA values or vacuuming will commit your current transaction. +Are you sure? + Das Setzen von PRAGMA-Werten oder des Vakuumings wird Ihre aktuelle Transaktion committen. +Sind Sie sich sicher? + + + + Project saved to file '%1' + Projekt in Datei '%1' gespeichert + + + + This action will open a new SQL tab with the following statements for you to edit and run: + Diese Aktion öffnet einen neuen SQL-Tab mit den folgenden Anweisungen zum Bearbeiten und Ausführen: + + + + Rename Tab + Tab umbenennen + + + + Duplicate Tab + Tab duplizieren + + + + Close Tab + Tab schließen + + + + Opening '%1'... + Öffne '%1'... + + + + There was an error opening '%1'... + Fehler beim Öffnen von '%1'... + + + + Value is not a valid URL or filename: %1 + Wert ist keine gültige URL bzw. kein gültiger Dateiname: %1 + + + + %1 rows returned in %2ms + %1 Zeilen in %2ms zurückgegeben + + + + Choose text files + Textdateien auswählen + + + + Import completed. Some foreign key constraints are violated. Please fix them before saving. + Import vollständig. Ein paar Fremdschlüssel wurden verletzt. Bitten beheben Sie diese vor dem Speichern. + + + + Modify View + Ansicht verändern + + + + Modify Trigger + Trigger verändern + + + + Modify Index + Index verändern + + + + Modify Table + Tabelle verändern + + + + Opened '%1' in read-only mode from recent file list + + + + + Opened '%1' from recent file list + + + + + &%1 %2%3 + &%1 %2%3 + + + + (read only) + (nur lesend) + + + + Open Database or Project + Datenbank oder Projekt öffnen + + + + Attach Database... + Datenbank anhängen... + + + + Import CSV file(s)... + CSV-Datei(en) importieren... + + + + Select the action to apply to the dropped file(s). <br/>Note: only 'Import' will process more than one file. + + Auf die Datei anzuwendende Aktion auswählen. <br/>Hinweis: Nur 'Import' kann mehr als eine Datei verarbeiten. + Auf die Dateien anzuwendende Aktion auswählen. <br/>Hinweis: Nur 'Import' kann mehr als eine Datei verarbeiten. + + + + + Do you want to save the changes made to SQL tabs in a new project file? + Sollen die an den SQL-Tabs getätigten Änderungen in einer neuen Projektdatei gespeichert werden? + + + + Do you want to save the changes made to the SQL file %1? + Sollen die getätigten Änderungen in der SQL-Datei %1 gespeichert werden? + + + + The statements in this tab are still executing. Closing the tab will stop the execution. This might leave the database in an inconsistent state. Are you sure you want to close the tab? + Es werden aktuell SQL-Statements ausgeführt. Das Schließen des Tabs wird deren Ausführung stoppen, was die Datenbank möglicherweise in einem inkonsistenten Zustand belässt. Soll der Tab wirklich geschlossen werden? + + + + Select SQL file to open + SQL-Datei zum Öffnen auswählen + + + + Select file name + Dateinamen auswählen + + + + Select extension file + Erweiterungsdatei auswählen + + + + Extension successfully loaded. + Erweiterung erfolgreich geladen. + + + + Error loading extension: %1 + Fehler beim Laden der Erweiterung: %1 + + + + Could not find resource file: %1 + Ressourcen-Datei konnte nicht gefunden werden: %1 + + + + + Don't show again + Nicht wieder anzeigen + + + + New version available. + Neue Version verfügbar. + + + + Choose a project file to open + Wählen Sie die zu öffnende Projektdatei + + + + This project file is using an old file format because it was created using DB Browser for SQLite version 3.10 or lower. Loading this file format is still fully supported but we advice you to convert all your project files to the new file format because support for older formats might be dropped at some point in the future. You can convert your files by simply opening and re-saving them. + Diese Projektdatei verwendet ein altes Dateiformat, da es mit DB-Browser für SQLite Version 3.10 oder niedriger erstellt wurde. Das Laden dieses Dateiformats wird noch vollständig unterstützt, wird empfehlen Ihnen allerdings, alle Ihre Projektdateien in das neue Dateiformat zu überführen, da die Unterstützung für ältere Formate in Zukunft möglicherweise entfernt wird. Sie können Ihre Dateien einfach durch Öffnen und Neuspeichern umwandeln. + + + + Could not open project file for writing. +Reason: %1 + Projekt-Datei konnte nicht schreibend geöffnet werden. +Grund: %1 + + + + Collation needed! Proceed? + Kollation notwendig! Fortführen? + + + + A table in this database requires a special collation function '%1' that this application can't provide without further knowledge. +If you choose to proceed, be aware bad things can happen to your database. +Create a backup! + Eine Tabelle in dieser Datenbank benötigt eine spezielle Kollationsfunktion '%1', welche diese Anwendung ohne weiterem Wissen nicht zur Verfügung stellen kann. +Wenn Sie fortfahren, sollten Sie im Hinterkopf behalten, dass mit Ihrer Datenbank unerwartete Dinge geschehen können. +Erstellen Sie ein Backup! + + + + creating collation + erstelle Kollation + + + + Set a new name for the SQL tab. Use the '&&' character to allow using the following character as a keyboard shortcut. + Vergeben Sie einen Namen für den SQL-Tab. Verwenden Sie das '&&'-Zeichen, um das folgende Zeichen als Tastaturkürzel zu verwenden. + + + + Please specify the view name + Geben Sie bitte einen Namen für Ansicht an + + + + There is already an object with that name. Please choose a different name. + Es gibt bereits ein Objekt mit diesem Namen. Bitte wählen Sie einen anderen aus. + + + + View successfully created. + Ansicht erfolgreich erstellt. + + + + Error creating view: %1 + Fehler beim Erstellen der Ansicht: %1 + + + + This action will open a new SQL tab for running: + Diese Aktion öffnet einen neuen SQL-Tab zur Ausführung: + + + + Press Help for opening the corresponding SQLite reference page. + Drücken Sie auf 'Hilfe', um die entsprechende SQLite-Referenzseite zu öffnen. + + + + Busy (%1) + Beschäftigt (%1) + + + + NullLineEdit + + + Set to NULL + Auf NULL setzen + + + + Alt+Del + + + + + PlotDock + + + Plot + Diagramm + + + + <html><head/><body><p>This pane shows the list of columns of the currently browsed table or the just executed query. You can select the columns that you want to be used as X or Y axis for the plot pane below. The table shows detected axis type that will affect the resulting plot. For the Y axis you can only select numeric columns, but for the X axis you will be able to select:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Date/Time</span>: strings with format &quot;yyyy-MM-dd hh:mm:ss&quot; or &quot;yyyy-MM-ddThh:mm:ss&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Date</span>: strings with format &quot;yyyy-MM-dd&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Time</span>: strings with format &quot;hh:mm:ss&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Label</span>: other string formats. Selecting this column as X axis will produce a Bars plot with the column values as labels for the bars</li><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Numeric</span>: integer or real values</li></ul><p>Double-clicking the Y cells you can change the used color for that graph.</p></body></html> + <html><head/><body><p>Dieses Pane zeigt die Liste der Spalten der aktuell ausgewählten Tabelle oder des soeben ausgeführtne Queries. Sie können die für die X- und Y-Achse gewünschten Spalten für das Plot-Pane unten auswählen. Die Tabelle zeigt den erkannten Axentyp, der den entstehenden Plot beeinflusst. Für die Y-Achse sind nur numerische Spalten zulässig, während Sie für die X-Achse aus folgenden Optionen auswählen können:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Datum/Zeit</span>: Strings im Format &quot;yyyy-MM-dd hh:mm:ss&quot; or &quot;yyyy-MM-ddThh:mm:ss&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Datum</span>: Strings im Format &quot;yyyy-MM-dd&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Zeit</span>: Strings im Format &quot;hh:mm:ss&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Beschriftung</span>: andere Stringformate. Die Auswahl dieser Spalte als X-Achse erzeugt einen Barplot mit den Spaltenwerten als Beschriftungen der Bars.</li><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Numerisch</span>: Integer- oder Real-Werte</li></ul><p>Ein Doppelklick auf die Y-Zellen ermöglicht Ihnen das Ändern der für den Graph verwendeten Farbe.</p></body></html> + + + + Columns + Spalten + + + + X + X + + + + Y1 + Y1 + + + + Y2 + Y2 + + + + Axis Type + Achsentyp + + + + Here is a plot drawn when you select the x and y values above. + +Click on points to select them in the plot and in the table. Ctrl+Click for selecting a range of points. + +Use mouse-wheel for zooming and mouse drag for changing the axis range. + +Select the axes or axes labels to drag and zoom only in that orientation. + Hier wird ein Plot angezeigt, wenn Sie oben die x- und y-Werte auswählen. + +Klicken Sie auf Punkte, um diese im Plot und in der Tabelle auszuwählen. Strg+Klick zur Auswahl eines Punktebereichs. + +Verwenden Sie das Mausrad zum Zoomen und Ziehen Sie mit der Maus, um den Achsenbereich zu ändern. + +Wählen Sie die Achsen oder Achsenbeschriftungen aus, um nur in diese Richtung zu zoomen oder zu verschieben. + + + + Line type: + Linientyp: + + + + + None + Keine + + + + Line + Linie + + + + StepLeft + Linksschritt + + + + StepRight + Rechtsschritt + + + + StepCenter + Mittelschritt + + + + Impulse + Impuls + + + + Point shape: + Punktform: + + + + Cross + Kreuz + + + + Plus + Plus + + + + Circle + Kreis + + + + Disc + Scheibe + + + + Square + Quadrat + + + + Diamond + Diamant + + + + Star + Stern + + + + Triangle + Dreieck + + + + TriangleInverted + Invertiertes Dreieck + + + + CrossSquare + Quadrat mit Kreuz + + + + PlusSquare + Quadrat mit Plus + + + + CrossCircle + Kreis mit Kreuz + + + + PlusCircle + Kreis mit Plus + + + + Peace + Peace + + + + <html><head/><body><p>Save current plot...</p><p>File format chosen by extension (png, jpg, pdf, bmp)</p></body></html> + <html><head/><body><p>Aktuelles Diagramm speichern...</p><p>Dateiformat durch Endung auswählen (png, jpg, pdf, bmp)</p></body></html> + + + + Save current plot... + Aktuelles Diagramm speichern... + + + + + Load all data and redraw plot + Alle Daten laden und Plot neu zeichnen + + + + + + Row # + Zeile # + + + + Copy + Kopieren + + + + Print... + Drucken... + + + + Show legend + Legende anzeigen + + + + Stacked bars + Gestapelte Bars + + + + Date/Time + Datum/Zeit + + + + Date + Datum + + + + Time + Zeit + + + + + Numeric + Numerisch + + + + Label + Beschriftung + + + + Invalid + Ungültig + + + + Load all data and redraw plot. +Warning: not all data has been fetched from the table yet due to the partial fetch mechanism. + Alle Daten laden und Plot neu zeichnen. +Warnung: es wurden aufgrund der partiellen Abrufmechanismus noch nicht alle Daten aus der Tabelle abgerufen. + + + + Choose an axis color + Eine Achsenfarbe wählen + + + + Choose a filename to save under + Dateinamen zum Speichern auswählen + + + + PNG(*.png);;JPG(*.jpg);;PDF(*.pdf);;BMP(*.bmp);;All Files(*) + PNG(*.png);;JPG(*.jpg);;PDF(*.pdf);;BMP(*.bmp);;Alle Dateien(*) + + + + There are curves in this plot and the selected line style can only be applied to graphs sorted by X. Either sort the table or query by X to remove curves or select one of the styles supported by curves: None or Line. + Dieser Plot enthält Kurven und der ausgewählte Linienstil kann nur auf nach X sortierte Graphen angewendet werden. Sortieren Sie entweder die Tabelle oder Query nach X oder entfernen Sie die Kurven oder wählen Sie eine der Stile, die von Kurven unterstützt werden: Keiner oder Linie. + + + + Loading all remaining data for this table took %1ms. + Das Laden aller verbleibender Daten dieser Tabelle benötigte %1ms. + + + + PreferencesDialog + + + Preferences + Einstellungen + + + + &General + All&gemeines + + + + Remember last location + Letztes Verzeichnis merken + + + + Always use this location + Immer dieses Verzeichnis verwenden + + + + Remember last location for session only + Letztes Verzeichnis nur innerhalb der Sitzung merken + + + + Lan&guage + &Sprache + + + + Show remote options + Fernzugriffs-Optionen anzeigen + + + + Automatic &updates + Automatische &Updates + + + + &Database + &Datenbank + + + + Database &encoding + Datenbank-&Kodierung + + + + Open databases with foreign keys enabled. + Öffnen von Datenbanken mit Fremdschlüsseln aktiviert. + + + + &Foreign keys + &Fremdschlüssel + + + + + + + + + + + + enabled + aktiviert + + + + Default &location + Voreingestellter &Speicherort + + + + + + ... + ... + + + + Remove line breaks in schema &view + Zeilenumbrüche in der Schema&ansicht entfernen + + + + Prefetch block si&ze + Block&größe für Prefetch + + + + SQ&L to execute after opening database + Nach dem Öffnen einer Datenbank auszuführendes SQ&L + + + + Default field type + Voreingestellter Feldtyp + + + + Data &Browser + Daten&auswahl + + + + Font + Schrift + + + + &Font + Schri&ft + + + + Content + Inhalt + + + + Symbol limit in cell + Symbolbegrenzung in Zelle + + + + NULL + NULL + + + + Regular + Normal + + + + Binary + Binär + + + + Background + Hintergrund + + + + Filters + Filter + + + + Threshold for completion and calculation on selection + Schwellwert für die Vervollständigung und Berechnung bei Auswahl + + + + Show images in cell + Bilder in Zelle anzeigen + + + + Enable this option to show a preview of BLOBs containing image data in the cells. This can affect the performance of the data browser, however. + Diese Option aktivieren, um eine Vorschau von BLOBs mit Bilddaten in den Zellen anzuzeigen. Dies kann allerdings die Performanz der Anwendung beeinflussen. + + + + Escape character + Escape-Zeichen + + + + Delay time (&ms) + Verzögerung (&ms) + + + + Set the waiting time before a new filter value is applied. Can be set to 0 for disabling waiting. + Verzögerung vor der Anwendung eines neuen Filters setzen. Kann auf 0 gesetzt werden, um dies zu deaktivieren. + + + + &SQL + &SQL + + + + Settings name + Einstellungsname + + + + Context + Kontext + + + + Colour + Farbe + + + + Bold + Fett + + + + Italic + Kursiv + + + + Underline + Unterstreichung + + + + Keyword + Schlüsselwort + + + + Function + Funktion + + + + Table + Tabelle + + + + Comment + Kommentar + + + + Identifier + Bezeichner + + + + String + String + + + + Current line + Aktuelle Zeile + + + + SQL &editor font size + SQL-&Editor Schriftgröße + + + + Tab size + Tab-Größe + + + + SQL editor &font + SQL Editor &Schrift + + + + Error indicators + Fehleranzeige + + + + Hori&zontal tiling + Hori&zontale Anordnung + + + + If enabled the SQL code editor and the result table view are shown side by side instead of one over the other. + Im aktivierten Zustand werden der SQL-Codeeditor und die Ergebnistabelle neben- statt untereinander angezeigt. + + + + Code co&mpletion + &Codevervollständung + + + + Toolbar style + Werkzeugleisten-Stil + + + + + + + + Only display the icon + Nur das Symbol anzeigen + + + + + + + + Only display the text + Nur den Text anzeigen + + + + + + + + The text appears beside the icon + Der Text erscheint neben dem Symbol + + + + + + + + The text appears under the icon + Der Text erscheint unter dem Symbol + + + + + + + + Follow the style + Dem Stil folgen + + + + DB file extensions + DB-Datei-Erweiterungen + + + + Manage + Verwalten + + + + Main Window + Hauptfenster + + + + Database Structure + Datenbankstruktur + + + + Browse Data + Daten durchsuchen + + + + Execute SQL + SQL ausführen + + + + Edit Database Cell + Datenbankzelle bearbeiten + + + + When this value is changed, all the other color preferences are also set to matching colors. + Wenn dieser Wert geändert wird, werden alle anderen Farbeinstellungen auch auf die entsprechenden Farben gesetzt. + + + + Follow the desktop style + Dem Desktop-Stil folgen + + + + Dark style + Dunkler Stil + + + + Application style + Anwendungs-Stil + + + + This sets the font size for all UI elements which do not have their own font size option. + + + + + Font size + + + + + When enabled, the line breaks in the Schema column of the DB Structure tab, dock and printed output are removed. + Falls aktiviert, werden die Zeilenumbrüche in der Schemaspalte des DB-Strukturtabs, Docks und der gedruckten Ausgabe entfernt. + + + + Database structure font size + + + + + Font si&ze + Schrift&größe + + + + This is the maximum number of items allowed for some computationally expensive functionalities to be enabled: +Maximum number of rows in a table for enabling the value completion based on current values in the column. +Maximum number of indexes in a selection for calculating sum and average. +Can be set to 0 for disabling the functionalities. + Dies ist die maximale Elementanzahl, die für die Aktivierung von ein paar berechnungsintensiven Funktionalitäten erlaubt ist: +Maximale Zeilenanzahl in einer Tabelle für die Wertvervollständig basierend auf den aktuellen Werten in dieser Spalte. +Maximale Indexanzahl einer Auswahl für die Berechnung von Summe und Durchschnitt. +Kann auf 0 gesetzt werden, um diese Funktionalitäten zu deaktivieren. + + + + This is the maximum number of rows in a table for enabling the value completion based on current values in the column. +Can be set to 0 for disabling completion. + Dies ist die maximale Anzahl an Zeilen in einer Tabelle, die zur Wertvervollständigung basierend auf aktuellen Werten in dieser Spalte erlaubt ist. +Kann auf 0 gesetzt werden, um die Vervollständigung zu deaktivieren. + + + + Field display + Feldanzeige + + + + Displayed &text + Angezeigter &Text + + + + + + + + + Click to set this color + Zur Auswahl der Farbe klicken + + + + Text color + Textfarbe + + + + Background color + Hintergrundfarbe + + + + Preview only (N/A) + Nur Vorschau (N/A) + + + + Foreground + Vordergrund + + + + SQL &results font size + Schriftgröße SQL-&Ergebnisse + + + + &Wrap lines + Zeilen &umbrechen + + + + Never + Nie + + + + At word boundaries + An Wortgrenzen + + + + At character boundaries + An Zeichengrenzen + + + + At whitespace boundaries + An Leerzeichengrenzen + + + + &Quotes for identifiers + &Anführungszeichen für Identifiers + + + + Choose the quoting mechanism used by the application for identifiers in SQL code. + Wählen Sie den Zitiermechanismus aus, der von der Anwendung für Identifier im SQL-Code verwendet wird. + + + + "Double quotes" - Standard SQL (recommended) + "Doppelt Anführungszeichen" - Standard-SQL (empfohlen) + + + + `Grave accents` - Traditional MySQL quotes + `Akzente` - Traditionelle MySQL-Anführungszeichen + + + + [Square brackets] - Traditional MS SQL Server quotes + [Eckige Klammern] - Traditionelle MS-SQL-Server-Anführungszeichen + + + + Keywords in &UPPER CASE + Schlüsselwörter in &GROSSSCHREIBUNG + + + + When set, the SQL keywords are completed in UPPER CASE letters. + Falls gesetzt, werden die SQL-Schlüsselwörter in GROßSCHREIBUNG vervollständigt. + + + + When set, the SQL code lines that caused errors during the last execution are highlighted and the results frame indicates the error in the background + Falls gesetzt, werden die SQL-Codezeilen, die während der letzten Ausführung Fehler verursacht haben, hervorgehoben und das Ergebnisfenster zeigt den Fehler im Hintergrund an + + + + Close button on tabs + Schließen-Button für Tabs + + + + If enabled, SQL editor tabs will have a close button. In any case, you can use the contextual menu or the keyboard shortcut to close them. + Wenn aktiviert, werden die SQL-Editor-Tabs einen Schließen-Button haben. In allen Fällen können Sie zum Schließen auch das Kontextmenü oder die Tastenkombination verwenden. + + + + &Extensions + &Erweiterungen + + + + Select extensions to load for every database: + Bei jeder Datenbank zu ladende Erweiterungen auswählen: + + + + Add extension + Erweiterung hinzufügen + + + + Remove extension + Erweiterung entfernen + + + + <html><head/><body><p>While supporting the REGEXP operator SQLite doesn't implement any regular expression<br/>algorithm but calls back the running application. DB Browser for SQLite implements this<br/>algorithm for you to let you use REGEXP out of the box. However, as there are multiple possible<br/>implementations of this and you might want to use another one, you're free to disable the<br/>application's implementation and load your own by using an extension. Requires restart of the application.</p></body></html> + <html><head/><body><p>Auch wenn der REGEXP-Operator unterstützt wird, implementiert SQLite keinerlei Algorithmus für reguläre<br/>Ausdrücke, sondern leitet diese an die laufende Anwendung weiter. DB Browser für SQLite implementierte diesen<br/>Algorithmus für Sie, um REGEXP ohne Zusätze verwenden zu können. Allerdings gibt es viele mögliche<br/>Implementierungen und Sie möchten unter Umständen eine andere wählen, dann können Sie die<br/>Implementierung der Anwendung deaktivieren und Ihre eigene durch Laden einer Erweiterung verwenden. Ein Neustart der Anwendung ist notwendig.</p></body></html> + + + + Disable Regular Expression extension + Erweiterung für reguläre Ausdrücke deaktivieren + + + + <html><head/><body><p>SQLite provides an SQL function for loading extensions from a shared library file. Activate this if you want to use the <span style=" font-style:italic;">load_extension()</span> function from SQL code.</p><p>For security reasons, extension loading is turned off by default and must be enabled through this setting. You can always load extensions through the GUI, even though this option is disabled.</p></body></html> + <html><head/><body><p>SQLite bietet eine SQL-Funktion an, um Erweiterungen aus einer Shared-Library-Datei zu laden. Aktivieren Sie dies, falls Sie die <span style=" font-style:italic;">load_extension()</span>-Funktion aus SQL-Code heraus benutzen möchten.</p><p>Aus Sicherheitsgründen ist das Laden von Erweiterungen standardmäßig deaktiviert und muss durch diese Einstellung aktiviert werden. Sie können alternativ immer die gewünschten Erweiterungen über die GUI laden, auch wenn diese Option deaktiviert ist.</p></body></html> + + + + Allow loading extensions from SQL code + Erlaube das Laden von Erweiterungen aus SQL-Code + + + + Remote + Entfernt + + + + CA certificates + CA-Zertifikate + + + + Proxy + Proxy + + + + Configure + Konfigurieren + + + + + Subject CN + Subject CN + + + + Common Name + Common Name + + + + Subject O + Subject O + + + + Organization + Organisation + + + + + Valid from + Gültig ab + + + + + Valid to + Gültig bis + + + + + Serial number + Seriennummer + + + + Your certificates + Ihre Zertifikate + + + + File + Datei + + + + Subject Common Name + Subject Common Name + + + + Issuer CN + CN des Ausstellers + + + + Issuer Common Name + Common Name des Ausstellers + + + + Clone databases into + Datenbank klonen nach + + + + + Choose a directory + Verzeichnis wählen + + + + The language will change after you restart the application. + Die Sprache wird nach einem Neustart der Anwendung geändert. + + + + Select extension file + Erweiterungsdatei wählen + + + + Extensions(*.so *.dylib *.dll);;All files(*) + Erweiterungen(*.so *.dylib *.dll);;Alle Dateien(*) + + + + Import certificate file + Zertifikatsdatei importieren + + + + No certificates found in this file. + In dieser Datei wurden keine Zertifikate gefunden. + + + + Are you sure you want do remove this certificate? All certificate data will be deleted from the application settings! + Soll dieses Zertifikat wirklich entfernt werden? Jegliche Zertifikatdaten werden aus den Anwendungseinstellungen gelöscht! + + + + Are you sure you want to clear all the saved settings? +All your preferences will be lost and default values will be used. + Möchten Sie wirklich alle gespeicherten Einstellungen löschen? +Alle Ihre Einstellungen gehen dadurch verloren und die Standardwerte werden verwendet. + + + + ProxyDialog + + + Proxy Configuration + Proxy-Konfiguration + + + + Pro&xy Type + Pro&xy-Typ + + + + Host Na&me + Hostna&me + + + + Port + Port + + + + Authentication Re&quired + Anmeldung not&wendig + + + + &User Name + &Benutzername + + + + Password + Passwort + + + + None + Keiner + + + + System settings + Systemeinstellungen + + + + HTTP + HTTP + + + + Socks v5 + Socks v5 + + + + QObject + + + Error importing data + Fehler beim Datenimport + + + + from record number %1 + von Zeilennummer %1 + + + + . +%1 + . +%1 + + + + Importing CSV file... + Importiere CSV-Datei... + + + + Cancel + Abbrechen + + + + All files (*) + Alle Dateien (*) + + + + SQLite database files (*.db *.sqlite *.sqlite3 *.db3) + SQLite Datenbankdateien (*.db *.sqlite *.sqlite3 *.db3) + + + + Left + Links + + + + Right + Rechts + + + + Center + Zentriert + + + + Justify + Blocksatz + + + + SQLite Database Files (*.db *.sqlite *.sqlite3 *.db3) + SQLite-Datenbankdateien (*.db *.sqlite *.sqlite3 *.db3) + + + + DB Browser for SQLite Project Files (*.sqbpro) + DB Browser für SQLite Projektdateien (*.sqbpro) + + + + SQL Files (*.sql) + SQL-Dateien (*.sql) + + + + All Files (*) + Alle Dateien (*) + + + + Text Files (*.txt) + Text-Dateien (*.txt) + + + + Comma-Separated Values Files (*.csv) + Kommaseparierte Datendateien (*.csv) + + + + Tab-Separated Values Files (*.tsv) + Tabulator-separierte Datendateien (*.tsv) + + + + Delimiter-Separated Values Files (*.dsv) + Trenner-separierte Datendateien (*.dsv) + + + + Concordance DAT files (*.dat) + Konkordanz DAT-Dateien (*.dat) + + + + JSON Files (*.json *.js) + JSON-Dateien (*.json *.js) + + + + XML Files (*.xml) + XML-Dateien (*.xml) + + + + Binary Files (*.bin *.dat) + Binärdateien (*.bin *.dat) + + + + SVG Files (*.svg) + SVG-Dateien (*.svg) + + + + Hex Dump Files (*.dat *.bin) + Hex-Dump-Dateien (*.dat *.bin) + + + + Extensions (*.so *.dylib *.dll) + Erweiterungen (*.so *.dylib *.dll) + + + + RemoteCommitsModel + + + Commit ID + + + + + Message + + + + + Date + Datum + + + + Author + + + + + Size + Größe + + + + Authored and committed by %1 + + + + + Authored by %1, committed by %2 + + + + + RemoteDatabase + + + Error opening local databases list. +%1 + Fehler beim Öffnen der lokalen Datenbankliste. +%1 + + + + Error creating local databases list. +%1 + Fehler beim Erstellen der lokalen Datenbankliste. +%1 + + + + RemoteDock + + + Remote + Entfernt + + + + Local + Lokal + + + + Identity + Identität + + + + Push currently opened database to server + Aktuell geöffnete Datenbank an den Server übertragen + + + + DBHub.io + + + + + <html><head/><body><p>In this pane, remote databases from dbhub.io website can be added to DB Browser for SQLite. First you need an identity:</p><ol style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Login to the dbhub.io website (use your GitHub credentials or whatever you want)</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Click the button to &quot;Generate client certificate&quot; (that's your identity). That'll give you a certificate file (save it to your local disk).</li><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Go to the Remote tab in DB Browser for SQLite Preferences. Click the button to add a new certificate to DB Browser for SQLite and choose the just downloaded certificate file.</li></ol><p>Now the Remote panel shows your identity and you can add remote databases.</p></body></html> + <html><head/><body><p>In diesem Fensterbereich können entfernte Datenbanken von der dbhub.io-Webseite zu DB-Browser für SQLite hinzugefügt werden. Zunächst benötigen Sie eine Identität:</p><ol style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Melden Sie sich auf der dbhub.io-Webseite an (unter Verwendung Ihrer GitHub-Daten oder wie gewünscht)</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Klicken Sie auf den Button &quot;Generate client certificate&quot;, um ein Zertifikat zu erstellen (das ist Ihre Identität). Speichern Sie die erzeugte Zertifikatdatei auf ihrer lokalen Festplatte.</li><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Öffnen Sie den Entfernt-Tab in den DB-Browser für SQLite-Einstellungen. Klicken Sie auf den Button, um ein neues Zertifikat hinzuzufügen und wählen Sie die soeben heruntergeladene Zertifikatdatei aus.</li></ol><p>Jetzt zeigt der Entfernt-Fensterbereich Ihre Identität und Sie können entfernte Datenbanken hinzufügen.</p></body></html> + + + + Current Database + + + + + Clone + + + + + User + Benutzer + + + + Database + Datenbank + + + + Branch + Branch + + + + Commits + + + + + Commits for + + + + + Delete Database + + + + + Delete the local clone of this database + + + + + Open in Web Browser + + + + + Open the web page for the current database in your browser + + + + + Clone from Link + + + + + Use this to download a remote database for local editing using a URL as provided on the web page of the database. + + + + + Refresh + Aktualisieren + + + + Reload all data and update the views + + + + + F5 + + + + + Clone Database + + + + + Open Database + + + + + Open the local copy of this database + + + + + Check out Commit + + + + + Download and open this specific commit + + + + + Check out Latest Commit + + + + + Check out the latest commit of the current branch + + + + + Save Revision to File + + + + + Saves the selected revision of the database to another file + + + + + Upload Database + + + + + Upload this database as a new commit + + + + + <html><head/><body><p>You are currently using a built-in, read-only identity. For uploading your database, you need to configure and use your DBHub.io account.</p><p>No DBHub.io account yet? <a href="https://dbhub.io/"><span style=" text-decoration: underline; color:#007af4;">Create one now</span></a> and import your certificate <a href="#preferences"><span style=" text-decoration: underline; color:#007af4;">here</span></a> to share your databases.</p><p>For online help visit <a href="https://dbhub.io/about"><span style=" text-decoration: underline; color:#007af4;">here</span></a>.</p></body></html> + <html><head/><body><p>Aktuell wird eine eingebaute, nur lesend verwendbare Identität verwendet. Zum Hochladen einer Datenbank muss ein DBHub.io-Konto konfiguriert und verwendet werden.</p><p>Noch kein DBHub.io-Konto vorhanden? <a href="https://dbhub.io/"><span style=" text-decoration: underline; color:#007af4;">Jetzt ein Konto erstellen</span></a> und das Zertifikat <a href="#preferences"><span style=" text-decoration: underline; color:#007af4;">hier</span></a> hochladen, um Datenbanken zu teilen.</p><p>Eine englische Online-Hilfe ist <a href="https://dbhub.io/about"><span style=" text-decoration: underline; color:#007af4;">hier</span></a> verfügbar.</p></body></html> + + + + Back + Zurück + + + + Select an identity to connect + + + + + Public + Öffentlich + + + + This downloads a database from a remote server for local editing. +Please enter the URL to clone from. You can generate this URL by +clicking the 'Clone Database in DB4S' button on the web page +of the database. + + + + + Invalid URL: The host name does not match the host name of the current identity. + + + + + Invalid URL: No branch name specified. + + + + + Invalid URL: No commit ID specified. + + + + + You have modified the local clone of the database. Fetching this commit overrides these local changes. +Are you sure you want to proceed? + + + + + The database has unsaved changes. Are you sure you want to push it before saving? + + + + + The database you are trying to delete is currently opened. Please close it before deleting. + + + + + This deletes the local version of this database with all the changes you have not committed yet. Are you sure you want to delete this database? + + + + + RemoteLocalFilesModel + + + Name + Name + + + + Branch + Branch + + + + Last modified + Letzte Änderung + + + + Size + Größe + + + + Commit + Commit + + + + File + Datei + + + + RemoteModel + + + Name + Name + + + + Last modified + Letzte Änderung + + + + Size + Größe + + + + Commit + Commit + + + + Size: + + + + + Last Modified: + + + + + Licence: + + + + + Default Branch: + + + + + RemoteNetwork + + + Choose a location to save the file + + + + + Error opening remote file at %1. +%2 + Fehler beim Öffnen der entfernten Datei unter %1. +%2 + + + + Error: Invalid client certificate specified. + Fehler: Ungültiges Benutzerzertifikat angegeben. + + + + Please enter the passphrase for this client certificate in order to authenticate. + Bitte die Passphrase für diese Benutzerzertifikat eingeben, um die Authentifizierung durchzuführen. + + + + Cancel + Abbrechen + + + + Uploading remote database to +%1 + Entfernte Datenbank wird hochgeladen zu +%1 + + + + Downloading remote database from +%1 + Entfernte Datenbank wird heruntergeladen von +%1 + + + + + Error: The network is not accessible. + Fehler: Netzwerkzugriff nicht möglich. + + + + Error: Cannot open the file for sending. + Fehler: Öffnen der Datei zum Senden nicht möglich. + + + + RemotePushDialog + + + Push database + Datenbank übertragen + + + + Database na&me to push to + Datenbankna&me am Zielort + + + + Commit message + Commit-Nachricht + + + + Database licence + Datenbanklizenz + + + + Public + Öffentlich + + + + Branch + Branch + + + + Force push + Push erzwingen + + + + Username + + + + + Database will be public. Everyone has read access to it. + Datenbank wird öffentlich sein. Jeder hat Lesezugriff darauf. + + + + Database will be private. Only you have access to it. + Datenbank wird privat sein. Nur Sie haben Zugriff darauf. + + + + Use with care. This can cause remote commits to be deleted. + Verwenden Sie dies mit Vorsicht. Dadurch können entfernte Commits gelöscht werden. + + + + RunSql + + + Execution aborted by user + Ausführung durch Benutzer abgebrochen + + + + , %1 rows affected + , %1 Zeilen betroffen + + + + query executed successfully. Took %1ms%2 + Query erfolgreich ausgeführt. Benötigte %1ms%2 + + + + executing query + führe Query aus + + + + SelectItemsPopup + + + A&vailable + &Verfügbar + + + + Sele&cted + &Ausgewählt + + + + SqlExecutionArea + + + Form + Formular + + + + Find previous match [Shift+F3] + Vorherige Übereinstimmung finden [Umschalt+F3] + + + + Find previous match with wrapping + Vorherige Übereinstimmung mit Mapping finden + + + + Shift+F3 + + + + + The found pattern must be a whole word + Das Pattern muss ein ganzes Wort sein + + + + Whole Words + Ganze Wörter + + + + Text pattern to find considering the checks in this frame + Zu findendes Textpattern unter Einbeziehung der Prüfungen in diesem Fenster + + + + Find in editor + Im Editor finden + + + + The found pattern must match in letter case + Das Fundpattern muss in Groß-/Kleinschreibung übereinstimmen + + + + Case Sensitive + Schreibungsabhängig + + + + Find next match [Enter, F3] + Nächste Übereinstimmung finden [Enter, F3] + + + + Find next match with wrapping + Nächste Übereinstimmung mit Umbruch finden + + + + F3 + + + + + Interpret search pattern as a regular expression + Suchpattern als regulären Ausdruck interpretieren + + + + <html><head/><body><p>When checked, the pattern to find is interpreted as a UNIX regular expression. See <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>.</p></body></html> + <html><head/><body><p>Falls aktiviert, wird das Suchmuster als regulärer Ausdruck (UNIX-Stil) interpretiert. Siehe <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks (englisch)</a>.</p></body></html> + + + + Regular Expression + Regulärer Ausdruck + + + + + Close Find Bar + Suchbar schließen + + + + <html><head/><body><p>Results of the last executed statements.</p><p>You may want to collapse this panel and use the <span style=" font-style:italic;">SQL Log</span> dock with <span style=" font-style:italic;">User</span> selection instead.</p></body></html> + <html><head/><body><p>Ergebnisse der zuletzt ausgeführten Statements.</p><p>Dieses Panel kann zusammengeklappt und stattdessen der <span style=" font-style:italic;">SQL-Log</span>-Dock mit der Auswahl <span style=" font-style:italic;">Benutzer</span> verwendet werden.</p></body></html> + + + + Results of the last executed statements + Ergebnisse des zuletzt ausgeführten Statements + + + + This field shows the results and status codes of the last executed statements. + Dieses Feld zeigt die Ergebnisse und Statuscodes der zuletzt ausgeführten Statements. + + + + Couldn't read file: %1. + Datei konnte nicht gelesen werden: %1. + + + + + Couldn't save file: %1. + Datei konnte nicht gespeichert werden: %1. + + + + Your changes will be lost when reloading it! + Beim Neuladen gehen die Änderungen verloren! + + + + The file "%1" was modified by another program. Do you want to reload it?%2 + Die Datei "%1" wurde durch ein anderes Programm geändert. Soll es neu geladen werden?%2 + + + + SqlTextEdit + + + Ctrl+/ + + + + + SqlUiLexer + + + (X) The abs(X) function returns the absolute value of the numeric argument X. + (X) Die abs(X)-Funktion gibt einen absoluten Wert des numerischen Arguments X zurück. + + + + () The changes() function returns the number of database rows that were changed or inserted or deleted by the most recently completed INSERT, DELETE, or UPDATE statement. + () Die changes()-Funktion gibt die Anzahl der Datenbankzeilen zurück, die mit dem zuletzt abgeschlossenen INSERT-, DELETE- oder UPDATE-Statement geändert, einfügt oder gelöscht worden sind. + + + + (X1,X2,...) The char(X1,X2,...,XN) function returns a string composed of characters having the unicode code point values of integers X1 through XN, respectively. + (X1,X2,...) Die char(X1,X2,...,XN)-Funktion gibt eine Zeichenkette zurück, die aus den Zeichen der Unicode-Werte der Ganzzahlen X1 bis XN zusammengesetzt ist. + + + + (X,Y,...) The coalesce() function returns a copy of its first non-NULL argument, or NULL if all arguments are NULL + (X,Y,...) Die coalesce()-Funktion gibt eine Kopie des ersten nicht-NULL-Arguments zurück, oder NULL wenn alle Argumente NULL sind + + + + (X,Y) The glob(X,Y) function is equivalent to the expression "Y GLOB X". + (X,Y) Die glob(X,Y)-Funktion ist äquivalent zum Ausdruck "Y GLOB X". + + + + (X,Y) The ifnull() function returns a copy of its first non-NULL argument, or NULL if both arguments are NULL. + (X,Y) Die ifnull()-Funktion gibt eine Kopie des ersten nicht-NULL-Arguments zurück, oder NULL, wenn beide Argumente NULL sind. + + + + (X,Y) The instr(X,Y) function finds the first occurrence of string Y within string X and returns the number of prior characters plus 1, or 0 if Y is nowhere found within X. + (X,Y) Die instr(X,Y)-Funktion sucht das erste Auftreten von Zeichenkette Y innerhalb der Zeichenkette X und gibt die Anzahl vorhergehender Charakter plus 1 zurück, oder 0, wenn Y in X nicht gefunden werden konnte. + + + + (X) The hex() function interprets its argument as a BLOB and returns a string which is the upper-case hexadecimal rendering of the content of that blob. + (X) Die hex()-Funktion interpretiert ihr Argument als BLOB und gibt eine Zeichenkette zurück, die die Hexadezimaldarstellung des Blob-Inhaltes in Großbuchstaben enthält. + + + + () The last_insert_rowid() function returns the ROWID of the last row insert from the database connection which invoked the function. + () Die last_insert_rowid()-Funktion gibt die ROWID der letzte Zeile zurück, die von der diese Funktion aufrufenden Datenbankverbindung eingefügt wurde. + + + + (X) For a string value X, the length(X) function returns the number of characters (not bytes) in X prior to the first NUL character. + (X) Für eine Zeichenkette X gibt die length(X)-Funktion die Anzahl der Zeichen (keine Bytes) von X zurück, die sich for dem ersten NUL-Zeichen befinden. + + + + (X,Y) The like() function is used to implement the "Y LIKE X" expression. + (X,Y) Die like()-Funktion wird als Implementierung des "Y LIKE X"-Ausdrucks verwendet. + + + + (X,Y,Z) The like() function is used to implement the "Y LIKE X ESCAPE Z" expression. + (X,Y,Z) Die like()-Funktion wird als Implementierung des "Y LIKE X ESCAPE Z"-Ausdrucks verwendet. + + + + (X) The load_extension(X) function loads SQLite extensions out of the shared library file named X. +Use of this function must be authorized from Preferences. + (X) Die load_extension(X)-Funktion lädt SQLite-Erweiterungen aus der Shared-Library-Datei namens X. +Die Verwendung dieser Funktion muss in den Einstellungen authorisiert werden. + + + + (X,Y) The load_extension(X) function loads SQLite extensions out of the shared library file named X using the entry point Y. +Use of this function must be authorized from Preferences. + (X,Y) Die load_extension(X,Y)-Funktion lädt SQLite-Erweiterungen aus der Shared-Library-Datei namens X unter Verwendung des Eintrittspunktes Y. +Die Verwendung dieser Funktion muss in den Einstellungen authorisiert werden. + + + + (X) The lower(X) function returns a copy of string X with all ASCII characters converted to lower case. + (X) Die lower(X)-Funktion gibt eine Kopie der Zeichenkette X mit allen ASCII-Zeichen in Kleinschreibung zurück. + + + + (X) ltrim(X) removes spaces from the left side of X. + (X) ltrim(X) entfernt Leerzeichen aus der linken Seite von X. + + + + (X,Y) The ltrim(X,Y) function returns a string formed by removing any and all characters that appear in Y from the left side of X. + (X,Y) Die ltrim(X,Y)-Funktion gibt eine Zeichenkette zurück, die durch Entfernen aller Zeichen innerhalb von Y aus der linken Seite von X gebildet wird. + + + + (X,Y,...) The multi-argument max() function returns the argument with the maximum value, or return NULL if any argument is NULL. + (X,Y,...) Die max()-Funktion mit mehreren Argumenten gibt das Argument mit dem größten Wert zurück, oder NULL, wenn ein Argument NULL ist. + + + + (X,Y,...) The multi-argument min() function returns the argument with the minimum value. + (X,Y,...) Die max()-Funktion mit mehreren Argumenten gibt das Argument mit dem kleinsten Wert zurück. + + + + (X,Y) The nullif(X,Y) function returns its first argument if the arguments are different and NULL if the arguments are the same. + (X,Y) Die nullif(X,Y)-FUnktion gibt ihr erstes Argument zurück, wenn die Argumente verschieden sind und NULL, wenn die Argumente gleich sind. + + + + (FORMAT,...) The printf(FORMAT,...) SQL function works like the sqlite3_mprintf() C-language function and the printf() function from the standard C library. + (FORMAT,...) Die printf(FORMAT,...) SQL-Funktion arbeitet wie die sqlite3_mprintf() C-Funktion und die printf()-Funktion aus der C-Standardbibliothek. + + + + (X) The quote(X) function returns the text of an SQL literal which is the value of its argument suitable for inclusion into an SQL statement. + (X) Die quote(X)-Funktion gibt den Text eines SQL-Literals zurück, wobei der Wert des Arguments zum Einfügen in ein SQL-Statement geeignet ist. + + + + () The random() function returns a pseudo-random integer between -9223372036854775808 and +9223372036854775807. + () Die random()-Funktion gibt eine pseudo-zufällige Ganzzahl zwischen -9223372036854775808 und +9223372036854775807 zurück. + + + + (N) The randomblob(N) function return an N-byte blob containing pseudo-random bytes. + (N) Die randomblob(N)-Funktion gibt einen N-Byte Blob aus pseudo-zufälligen Bytes zurück. + + + + (X,Y,Z) The replace(X,Y,Z) function returns a string formed by substituting string Z for every occurrence of string Y in string X. + (X,Y,Z) Die replace(X,Y,Z)-Funktion gibt einen String zurück, der durch Ersetzen der Zeichenkette Z bei jedem Auftreten von Zeichenkette Y in Zeichenkette X gebildet wird. + + + + (X) The round(X) function returns a floating-point value X rounded to zero digits to the right of the decimal point. + (X) Die round(X)-Funktion gibt einen Gleitkommawert X auf nulll Nachkommastellen gerundet zurück. + + + + (X,Y) The round(X,Y) function returns a floating-point value X rounded to Y digits to the right of the decimal point. + (X,Y) Die round(X,Y)-Funktion gibt eine Gleitkommazahl X auf Y Nachkommastellen gerundet zurück. + + + + (X) rtrim(X) removes spaces from the right side of X. + (X) rtrim(X) entfernt Leerzeichen aus der rechten Seite von X. + + + + (X,Y) The rtrim(X,Y) function returns a string formed by removing any and all characters that appear in Y from the right side of X. + (X,Y) Die rtrim(X,Y)-Funktion gibt eine Zeichenkette zurück, die durch Entfernen aller Zeichen innerhalb von Y aus der rechten Seite von X gebildet wird. + + + + (X) The soundex(X) function returns a string that is the soundex encoding of the string X. + (X) Die soundex(X)-Funktion gibt eine Zeichenkette zurück, die aus der Soundex-Kodierung von Zeichenkette X besteht. + + + + (X,Y) substr(X,Y) returns all characters through the end of the string X beginning with the Y-th. + (X,Y) substr(X,Y) gibt alle Zeichen bis zum Ende der Zeichenkette X zurück, beginnend mit dem Y-ten. + + + + (X,Y,Z) The substr(X,Y,Z) function returns a substring of input string X that begins with the Y-th character and which is Z characters long. + (X,Y,Z) Die substr(X,Y)-Funktion gibt einen Teil der Zeichenkette X zurück, die mit dem Y-ten Zeichen beginnt und Z Zeichen lang ist. + + + + () The total_changes() function returns the number of row changes caused by INSERT, UPDATE or DELETE statements since the current database connection was opened. + () Die changes()-Funktion gibt die Anzahl dergeänderten Datenbankzeilen zurück, die seit dem Öffnen der aktuellen Datenbankverbindung mit INSERT-, DELETE- oder UPDATE-Statement geändert, einfügt oder gelöscht worden sind. + + + + (X) trim(X) removes spaces from both ends of X. + (X) trim(X) entfernt Leerzeichen an beiden Enden von X. + + + + (X,Y) The trim(X,Y) function returns a string formed by removing any and all characters that appear in Y from both ends of X. + (X,Y) Die ltrim(X,Y)-Funktion gibt eine Zeichenkette zurück, die durch Entfernen aller Zeichen innerhalb von Y aus der von beiden Seiten von X gebildet wird. + + + + (X) The typeof(X) function returns a string that indicates the datatype of the expression X. + (X) Die typeof(X)-Funktion gibt einen String zurück, der den Datentyp des Ausdruckes X angibt. + + + + (X) The unicode(X) function returns the numeric unicode code point corresponding to the first character of the string X. + (X) Die unicode(X)-Funktion gibt einen numerischen Unicode-Wert zurück, der dem ersten Zeichen der Zeichenkette X entspricht. + + + + (X) The upper(X) function returns a copy of input string X in which all lower-case ASCII characters are converted to their upper-case equivalent. + (X) Die lower(X)-Funktion gibt eine Kopie der Zeichenkette X mit allen ASCII-Zeichen in Großschreibung zurück. + + + + (N) The zeroblob(N) function returns a BLOB consisting of N bytes of 0x00. + (N) Die zeroblob(N)-Funktion gibt einen BLOB aus N Bytes mit 0x00 zurück. + + + + + + + (timestring,modifier,modifier,...) + (Zeitstring,Modifikation,Modifikation,...) + + + + (format,timestring,modifier,modifier,...) + (Format,Zeitstring,Modifikation,Modifikation,...) + + + + (X) The avg() function returns the average value of all non-NULL X within a group. + (X) Die avg()-Funktion gibt den Durchschnittswert alle nicht-NULL X in einer Gruppe zurück. + + + + (X) The count(X) function returns a count of the number of times that X is not NULL in a group. + (X) Die count(X)-Funktion gibt die Anzahl der nicht-NULL-Elemente von X in einer Gruppe zurück. + + + + (X) The group_concat() function returns a string which is the concatenation of all non-NULL values of X. + (X) Die group_conact()-Funktion gibt eine Zeichenkette zurück, die eine Verkettung aller nicht-NULL-Werte von X ist. + + + + (X,Y) The group_concat() function returns a string which is the concatenation of all non-NULL values of X. If parameter Y is present then it is used as the separator between instances of X. + (X,Y) Die group_conact()-Funktion gibt eine Zeichenkette zurück, die eine Verkettung aller nicht-NULL-Werte von X ist. Wenn der Parameter Y aktiv ist, wird dieser als Trennzeichen zwischen Instanzen von X behandelt. + + + + (X) The max() aggregate function returns the maximum value of all values in the group. + (X) Die max()-Sammelfunktion gibt den Maximalwert aller Werte in der Gruppe zurück. + + + + (X) The min() aggregate function returns the minimum non-NULL value of all values in the group. + (X) Die min()-Sammelfunktion gibt den Minimalwert aller nicht-NULL-Werte in der Gruppe zurück. + + + + + (X) The sum() and total() aggregate functions return sum of all non-NULL values in the group. + (X) Die sum()- und total()-Sammelfunktionen geben die Summe aller nicht-NULL-Werte in der Gruppe zurück. + + + + () The number of the row within the current partition. Rows are numbered starting from 1 in the order defined by the ORDER BY clause in the window definition, or in arbitrary order otherwise. + () Die Anzahl der Zeilen in der aktuellen Partition. Zeilen werden beginnend bei 1 in der durch den ORDER-BY-Befehl in der Fensterdefinition nummeriert, ansonsten in willkürlicher Reihenfolge. + + + + () The row_number() of the first peer in each group - the rank of the current row with gaps. If there is no ORDER BY clause, then all rows are considered peers and this function always returns 1. + () Die row_number() des ersten Peer in jeder Gruppe - der Rang der aktuellen Zeile mit Lücken. Falls es keinen ORDER-BY-Befehl gibt, dann werden alle Zeilen als Peers angesehen und diese Funktion gibt immer 1 zurück. + + + + () The number of the current row's peer group within its partition - the rank of the current row without gaps. Partitions are numbered starting from 1 in the order defined by the ORDER BY clause in the window definition. If there is no ORDER BY clause, then all rows are considered peers and this function always returns 1. + () Die Nummer der Peer-Gruppe der aktuellen Zeile in der Partition - der Rang der aktuellen Reihe ohne Lücken. Partitionen werden mit 1 startend nummeriert in der Reihenfolge, wie sie durch den ORDER-BY-Befehl in der Fensterdefinition festgelegt ist. Falls es keinen ORDER-BY-Befehl gibt, werden alle Zeilen als Peers angesehen und diese Funktion gibt immer 1 zurück. + + + + () Despite the name, this function always returns a value between 0.0 and 1.0 equal to (rank - 1)/(partition-rows - 1), where rank is the value returned by built-in window function rank() and partition-rows is the total number of rows in the partition. If the partition contains only one row, this function returns 0.0. + () Ungeachtet des Namens gibt diese Funktion immer einen Wert zwischen 0.0 und 1.0 identisch zu (Rang - 1)/(Partitionszeilen - 1) zurück, wobei Rang der Wert der eingebauten Fensterfunktion rank() und Partitionszeilen die Gesamtanzahl der Zeilen in der Partition ist. Falls die Partition nur eine Zeile enthält, gibt diese Funktion 0.0 zurück. + + + + () The cumulative distribution. Calculated as row-number/partition-rows, where row-number is the value returned by row_number() for the last peer in the group and partition-rows the number of rows in the partition. + () Die kumulative Verteilung. Berechnet als Zeilenanzahl/Partitionszeilen, wobei Zeilenanzahl der durch row_number() zurückgegebene Wert für den letzten Peer in der Gruppe ist und Partitionszeilen die Anzahl der Zeilen in der Partition. + + + + (N) Argument N is handled as an integer. This function divides the partition into N groups as evenly as possible and assigns an integer between 1 and N to each group, in the order defined by the ORDER BY clause, or in arbitrary order otherwise. If necessary, larger groups occur first. This function returns the integer value assigned to the group that the current row is a part of. + (N) Das Argument N wird als Integer behandelt. Diese Funktion teilt die Partition in N Gruppen so gleichmäßig wie möglich auf und weist jeder Gruppe einen Integer zwischen 1 und N zu, in der Reihenfolge, die durch den ORDER-BY-Befehl definiert ist, ansonsten in beliebiger Reihenfolge. Falls notwendig tauchen größere Gruppen als erstes auf. Diese Funktion gibt einen Integerwert zurück, der der Gruppe zugewiesen ist, zu der die aktuelle Zeile gehört. + + + + (expr) Returns the result of evaluating expression expr against the previous row in the partition. Or, if there is no previous row (because the current row is the first), NULL. + (expr) Gibt das Ergebnis der Evaluation des Ausdrucks expr gegen die vorherige Zeile in der Partition zurück. Falls es keine vorhergehende Zeile gibt (weil die aktuelle Zeile die erste ist), wird NULL zurückgegeben. + + + + (expr,offset) If the offset argument is provided, then it must be a non-negative integer. In this case the value returned is the result of evaluating expr against the row offset rows before the current row within the partition. If offset is 0, then expr is evaluated against the current row. If there is no row offset rows before the current row, NULL is returned. + (expr,offset) Falls das Offset-Argument angegeben ist, dann muss dieses ein nicht-negativer Integerwert sein. In diesem Fall ist der Rückgabewert das Ergebnis der Evaluation von expr gegen die Zeile, die innerhalb der Partition offset Zeilen weiter oben liegt. Falls offset 0 ist, wird expr gegen die aktuelle Zeile evaluiert. Falls vor der aktuellen Zeile nicht genügend Zeilen vorhanden sind, wird NULL zurückgegeben. + + + + + (expr,offset,default) If default is also provided, then it is returned instead of NULL if the row identified by offset does not exist. + (expr,offset,default) Falls auch default angegeben ist, dann wird dieser Wert anstatt NULL zurückgegeben, falls die durch offset angegebene Zeile nicht existiert. + + + + (expr) Returns the result of evaluating expression expr against the next row in the partition. Or, if there is no next row (because the current row is the last), NULL. + (expr) Gibt das Ergebnis der Evaluation des Ausdrucks expr gegen die nächste Zeile in der Partition zurück. Falls es keine nächste Zeile gibt (weil die aktuelle Zeile die letzte ist), wird NULL zurückgegeben. + + + + (expr,offset) If the offset argument is provided, then it must be a non-negative integer. In this case the value returned is the result of evaluating expr against the row offset rows after the current row within the partition. If offset is 0, then expr is evaluated against the current row. If there is no row offset rows after the current row, NULL is returned. + (expr,offset) Falls das Offset-Argument angegeben ist, dann muss dieses ein nicht-negativer Integerwert sein. In diesem Fall ist der Rückgabewert das Ergebnis der Evaluation von expr gegen die Zeile, die innerhalb der Partition offset Zeilen weiter unten liegt. Falls offset 0 ist, wird expr gegen die aktuelle Zeile evaluiert. Falls nach der aktuellen Zeile nicht genügend Zeilen vorhanden sind, wird NULL zurückgegeben. + + + + (expr) This built-in window function calculates the window frame for each row in the same way as an aggregate window function. It returns the value of expr evaluated against the first row in the window frame for each row. + (expr) Diese eingebaute Fensterfunktion berechnet das Windowframe für jede Zeile auf die gleiche Art wie ein aggregierte Fensterfunktion. Sie gibt den Wert von expr evaluiert gegen die erste Zeile des Windowframes für jede Zeile zurück. + + + + (expr) This built-in window function calculates the window frame for each row in the same way as an aggregate window function. It returns the value of expr evaluated against the last row in the window frame for each row. + (expr) Diese eingebaute Fensterfunktion berechnet das Windowframe für jede Zeile auf die gleiche Art wie ein aggregierte Fensterfunktion. Sie gibt den Wert von expr evaluiert gegen die letzte Zeile des Windowframes für jede Zeile zurück. + + + + (expr,N) This built-in window function calculates the window frame for each row in the same way as an aggregate window function. It returns the value of expr evaluated against the row N of the window frame. Rows are numbered within the window frame starting from 1 in the order defined by the ORDER BY clause if one is present, or in arbitrary order otherwise. If there is no Nth row in the partition, then NULL is returned. + (expr,N) Diese eingebaute Fensterfunktion berechnet das Windowframe für jede Zeile auf die gleiche Art wie ein aggregierte Fensterfunktion. Sie gibt den Wert von expr evaluiert gegen die N-te Zeile des Windowframes für zurück. Die Zeilen werden beginnend bei 1 in der durch den ORDER-BY-Befehl definierten Reihenfolge nummeriert, falls dieser vorhanden ist, ansonsten in beliebiger Reihenfolge. Falls es keine N-te Zeile in der Partition gibt, dann wird NULL zurückgegeben. + + + + SqliteTableModel + + + reading rows + lese Zeilen + + + + loading... + lade... + + + + References %1(%2) +Hold %3Shift and click to jump there + Referenzen %1(%2) +Halten Sie %3Umschalt und klicken Sie, um hierher zu springen + + + + Error changing data: +%1 + Fehler beim Ändern der Daten: +%1 + + + + retrieving list of columns + ermittle Liste der Spalten + + + + Fetching data... + Rufe Daten ab... + + + + + Cancel + Abbrechen + + + + TableBrowser + + + Browse Data + Daten durchsuchen + + + + &Table: + &Tabelle: + + + + Select a table to browse data + Anzuzeigende Tabelle auswählen + + + + Use this list to select a table to be displayed in the database view + Diese Liste zur Auswahl der in der Datenbankansicht anzuzeigenden Tabelle verwenden + + + + This is the database table view. You can do the following actions: + - Start writing for editing inline the value. + - Double-click any record to edit its contents in the cell editor window. + - Alt+Del for deleting the cell content to NULL. + - Ctrl+" for duplicating the current record. + - Ctrl+' for copying the value from the cell above. + - Standard selection and copy/paste operations. + Dies ist die Datenbanktabellen-Ansicht. Sie können die folgenden Aktionen durchführen: + - Mit dem Schreiben beginnen, um die Werte Inline zu bearbeiten. + - Doppelt auf einen Eintrag klicken, um dessen Inhalte im Zelleneditor-Fenster zu bearbeiten. + - Alt+Entf zum Löschen des Zellinhaltes zu NULL. + - Strg+" zur Duplizierung des aktuellen Eintrags. + - Strg+' zum Kopieren des Wertes der darüberliegenden Zelle. + - Standardmäßige Auswahl- und Kopieren/Einfügen-Operationen. + + + + Text pattern to find considering the checks in this frame + Zu findendes Textpattern unter Einbeziehung der Prüfungen in diesem Fenster + + + + Find in table + In Tabelle suchen + + + + Find previous match [Shift+F3] + Vorherige Übereinstimmung finden [Umschalt+F3] + + + + Find previous match with wrapping + Vorherige Übereinstimmung mit Umbruch finden + + + + Shift+F3 + + + + + Find next match [Enter, F3] + Nächste Übereinstimmung finden [Enter, F3] + + + + Find next match with wrapping + Nächste Übereinstimmung mit Umbruch finden + + + + F3 + + + + + The found pattern must match in letter case + Das Suchpattern muss in Groß-/Kleinschreibung übereinstimmen + + + + Case Sensitive + Schreibungsabhängig + + + + The found pattern must be a whole word + Das Pattern muss ein ganzes Wort sein + + + + Whole Cell + Gesamte Zelle + + + + Interpret search pattern as a regular expression + Suchpattern als regulären Ausdruck interpretieren + + + + <html><head/><body><p>When checked, the pattern to find is interpreted as a UNIX regular expression. See <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>.</p></body></html> + <html><head/><body><p>Falls aktiviert, wird das Suchmuster als regulärer Ausdruck (UNIX-Stil) interpretiert. Siehe <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks (englisch)</a>.</p></body></html> + + + + Regular Expression + Regulärer Ausdruck + + + + + Close Find Bar + Suchbar schließen + + + + Text to replace with + Ersetzungstext + + + + Replace with + Ersetzen mit + + + + Replace next match + Nächste Übereinstimmung ersetzen + + + + + Replace + Ersetzen + + + + Replace all matches + Alle Übereinstimmungen ersetzen + + + + Replace all + Alle ersetzen + + + + <html><head/><body><p>Scroll to the beginning</p></body></html> + <html><head/><body><p>Zum Anfang scrollen</p></body></html> + + + + <html><head/><body><p>Clicking this button navigates to the beginning in the table view above.</p></body></html> + <html><head/><body><p>Ein Klick auf diesen Button navigiert zum Anfang der oben angezeigten Tabelle.</p></body></html> + + + + |< + |< + + + + Scroll one page upwards + Eine Seite nach oben scrollen + + + + <html><head/><body><p>Clicking this button navigates one page of records upwards in the table view above.</p></body></html> + <html><head/><body><p>Ein Klick auf diesen Button navigiert in den Einträgen der Tabellenansicht oben eine Seite nach oben.</p></body></html> + + + + < + < + + + + 0 - 0 of 0 + 0 - 0 von 0 + + + + Scroll one page downwards + Eine Seite nach unten scrollen + + + + <html><head/><body><p>Clicking this button navigates one page of records downwards in the table view above.</p></body></html> + <html><head/><body><p>Ein Klick auf diesen Button navigiert in den Einträgen der Tabellenansicht oben eine Seite nach unten.</p></body></html> + + + + > + > + + + + Scroll to the end + Zum Ende scrollen + + + + <html><head/><body><p>Clicking this button navigates up to the end in the table view above.</p></body></html> + <html><head/><body><p>Ein Klick auf diesen Button navigiert zum Ende der oben angezeigten Tabelle.</p></body></html> + + + + >| + >| + + + + <html><head/><body><p>Click here to jump to the specified record</p></body></html> + <html></head><body><p>Klicken Sie hier, um zu einer bestimmten Zeile zu springen</p></body></html> + + + + <html><head/><body><p>This button is used to navigate to the record number specified in the Go to area.</p></body></html> + <html></head><body><p>Dieser Button kann zum Navigieren zu einer im "Springe zu"-Bereich festgelegten Zeile verwendet werden.</p></body></html> + + + + Go to: + Springe zu: + + + + Enter record number to browse + Zeilennummer zum Suchen auswählen + + + + Type a record number in this area and click the Go to: button to display the record in the database view + Geben Sie eine Zeilennummer in diesem Bereich ein und klicken Sie auf den "Springe zu:"-Button, um die Zeile in der Datenbankansicht anzuzeigen + + + + 1 + 1 + + + + Show rowid column + Rowid-Spalte anzeigen + + + + Toggle the visibility of the rowid column + Sichtbarkeit der Rowid-Spalte umschalten + + + + Unlock view editing + Ansicht zur Bearbeitung entsperren + + + + This unlocks the current view for editing. However, you will need appropriate triggers for editing. + Dies entsperrt die aktuelle Ansicht zur Bearbeitung. Allerdings werden zur Bearbeitung passende Trigger benötigt. + + + + Edit display format + Anzeigeformat bearbeiten + + + + Edit the display format of the data in this column + Anzeigeformat der Daten in dieser Spalte bearbeiten + + + + + New Record + Neue Zeile + + + + + Insert a new record in the current table + Fügt eine neue Zeile zur aktuellen Tabelle hinzu + + + + <html><head/><body><p>This button creates a new record in the database. Hold the mouse button to open a pop-up menu of different options:</p><ul><li><span style=" font-weight:600;">New Record</span>: insert a new record with default values in the database.</li><li><span style=" font-weight:600;">Insert Values...</span>: open a dialog for entering values before they are inserted in the database. This allows to enter values acomplishing the different constraints. This dialog is also open if the <span style=" font-weight:600;">New Record</span> option fails due to these constraints.</li></ul></body></html> + <html><head/><body><p>Dieser Button erstellt eine neue Zeile in der Datenbank. Halten sie die Maustaste gedrückt, um ein Popup-Menü mit verschiedenen Optionen zu öffnen:</p><ul><li><span style=" font-weight:600;">Neuer Eintrag</span>: eine neue Zeile mit Standardwerten in die Datenbank einfügen.</li><li><span style=" font-weight:600;">Werte einfügen...</span>: einen Dialog zur Eingabe von Werten öffnen, bevor diese in die Datenbank eingefügt werden. Dies erlaubt die Eingabe von Werten, die den Constraints Genüge tun. Dieser Dialog wird auch geöffnet, falls die <span style=" font-weight:600;">Neuer Eintrag</span>-Option aufgrund dieser Constraints fehlschlägt.</li></ul></body></html> + + + + + Delete Record + Zeile löschen + + + + Delete the current record + Aktuelle Zeile löschen + + + + + This button deletes the record or records currently selected in the table + Dieser Button löscht die Zeile oder Zeilen, die aktuell in der Tabelle ausgewählt sind + + + + + Insert new record using default values in browsed table + Eine neue Zeile mit den Standardwerten in den ausgewählte Tabelle einfügen + + + + Insert Values... + Werte einfügen... + + + + + Open a dialog for inserting values in a new record + Einen Dialog zum Einfügen von Werten in eine neue Zeile öffnen + + + + Export to &CSV + Nach &CSV exportieren + + + + + Export the filtered data to CSV + Die gefilterten Daten als CSV exportieren + + + + This button exports the data of the browsed table as currently displayed (after filters, display formats and order column) as a CSV file. + Dieser Button exportiert die Daten der ausgewählten Tabelle wie aktuell angezeigt (gefiltert, Anzeigeformate und Spaltenreihenfolge) als CSV-Datei. + + + + Save as &view + Als &View speichern + + + + + Save the current filter, sort column and display formats as a view + Den aktuellen Filter, die Spaltenreihenfolge und Anzeigeformate als View speichern + + + + This button saves the current setting of the browsed table (filters, display formats and order column) as an SQL view that you can later browse or use in SQL statements. + Dieser Button speichert die aktuellen Einstellungen der ausgewählten Tabelle (Filter, Anzeigeformate und Spaltenreihenfolge) als SQL-View, welche Sie später durchsuchen oder in SQL-Statements verwenden können. + + + + Save Table As... + Tabelle speichern als... + + + + + Save the table as currently displayed + Tabelle wie aktuell angezeigt speichern + + + + <html><head/><body><p>This popup menu provides the following options applying to the currently browsed and filtered table:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Export to CSV: this option exports the data of the browsed table as currently displayed (after filters, display formats and order column) to a CSV file.</li><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Save as view: this option saves the current setting of the browsed table (filters, display formats and order column) as an SQL view that you can later browse or use in SQL statements.</li></ul></body></html> + <html><head/><body><p>Dieses Popup-Menü bietet die folgenden Optionen zur Anwendung auf die aktuell ausgewählte und gefilterte Tabelle:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">CSV exportieren: diese Option exportiert die Daten der ausgewählten Tabelle wie aktuell angezeigt (gefiltert, Anzeigeformat und Spaltenreihenfolge) in eine CSV-Datei.</li><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Als Ansicht speichern: diese Option speichert die aktuelle Einstellung der ausgewählten Tabelle (Filter, Anzeigeformat und Spaltenreihenfolge) als eine SQL-View, die Sie später durchsuchen oder in SQL-Statements verwenden können.</li></ul></body></html> + + + + Hide column(s) + Spalte(n) verbergen + + + + Hide selected column(s) + Ausgewählte Spalte(n) verbergen + + + + Show all columns + Alle Spalten anzeigen + + + + Show all columns that were hidden + Alle versteckten Spalten anzeigen + + + + + Set encoding + Kodierung setzen + + + + Change the encoding of the text in the table cells + Kodierung des Textes in den Tabellenzellen ändern + + + + Set encoding for all tables + Kodierung für alle Tabellen setzen + + + + Change the default encoding assumed for all tables in the database + Voreingestellte Kodierung für alle Tabellen in der Datenbank ändern + + + + Clear Filters + Filter löschen + + + + Clear all filters + Alle Filter löschen + + + + + This button clears all the filters set in the header input fields for the currently browsed table. + Dieser Button löscht alle gesetzten Filter in den Header-Eingabefeldern der aktuell angezeigten Tabelle. + + + + Clear Sorting + Sortierung löschen + + + + Reset the order of rows to the default + Die Zeilenreihenfolge auf den Standardzustand zurücksetzen + + + + + This button clears the sorting columns specified for the currently browsed table and returns to the default order. + Dieser Button setzt die angegebene Spaltensortierung für die aktuell angezeigte Tabelle zurück und verwendet die Standardreihenfolge. + + + + Print + Drucken + + + + Print currently browsed table data + Aktuell angezeigte Tabellendaten drucken + + + + Print currently browsed table data. Print selection if more than one cell is selected. + Die aktuell angezeigten Tabellendaten drucken. Druckauswahl, falls mehr als eine Zelle ausgewählt ist. + + + + Ctrl+P + + + + + Refresh + Aktualisieren + + + + Refresh the data in the selected table + Die Daten in der ausgewählten Tabelle aktualisieren + + + + This button refreshes the data in the currently selected table. + Dieser Button aktualisiert die Daten der aktuellen Tabellenansicht. + + + + F5 + + + + + Find in cells + In Zellen suchen + + + + Open the find tool bar which allows you to search for values in the table view below. + Die Such-Toolbar öffnen, welche das Suchen nach Werten in der Tabellenansicht unten erlaubt. + + + + + Bold + Fett + + + + Ctrl+B + + + + + + Italic + Kursiv + + + + + Underline + Unterstreichung + + + + Ctrl+U + + + + + + Align Right + Rechts ausrichten + + + + + Align Left + Links ausrichten + + + + + Center Horizontally + Horizontal zentrieren + + + + + Justify + Blocksatz + + + + + Edit Conditional Formats... + Bedingte Formatierungen bearbeiten... + + + + Edit conditional formats for the current column + Bedingte Formatierungen der aktuellen Spalte bearbeiten + + + + Clear Format + Formatierung löschen + + + + Clear All Formats + Alle Formatierungen löschen + + + + + Clear all cell formatting from selected cells and all conditional formats from selected columns + Jegliche Zellenformatierung für die ausgewählten Zellen und alle bedingten Formatierungen für die ausgewählten Spalten löschen + + + + + Font Color + Schriftfarbe + + + + + Background Color + Hintergrundfarbe + + + + Toggle Format Toolbar + Formatierungs-Toolbar umschalten + + + + Show/hide format toolbar + Formatierungs-Toolbar anzeigen/verstecken + + + + + This button shows or hides the formatting toolbar of the Data Browser + Dieser Button zeigt oder versteckt die Formatierungs-Toolbar im Datenbrowser + + + + Select column + Spalte auswählen + + + + Ctrl+Space + + + + + Replace text in cells + Text in Zellen ersetzen + + + + Filter in any column + In allen Spalten filtern + + + + Ctrl+R + + + + + %n row(s) + + %n row + %n rows + + + + + , %n column(s) + + , %n Spalte + , %n Spalten + + + + + . Sum: %1; Average: %2; Min: %3; Max: %4 + . Summe: %1; Durchschnitt: %2; Minimum: %3; Maximum: %4 + + + + Conditional formats for "%1" + Bedingte Formatierung for "%1" + + + + determining row count... + bestimme Zeilenanzahl... + + + + %1 - %2 of >= %3 + %1 - %2 von >= %3 + + + + %1 - %2 of %3 + %1 - %2 von %3 + + + + Please enter a pseudo-primary key in order to enable editing on this view. This should be the name of a unique column in the view. + Bitte einen Pseudo-Primärschlüssel eingeben, um die Bearbeitung dieser Ansicht zu ermöglichen. Dies sollte der Name der eindeutigen Spalte dieser Ansicht sein. + + + + Delete Records + Einträge löschen + + + + Duplicate records + Einträge duplizieren + + + + Duplicate record + Eintrag duplizieren + + + + Ctrl+" + + + + + Adjust rows to contents + Zeilen an Inhalte anpassen + + + + Error deleting record: +%1 + Fehler beim Löschen des Eintrags: +%1 + + + + Please select a record first + Bitte zuerst einen Eintrag auswählen + + + + There is no filter set for this table. View will not be created. + Es gibt keinen Filtersatz für diese Tabelle. Die Ansicht wird nicht erstellt. + + + + Please choose a new encoding for all tables. + Bitte wählen Sie eine neue Kodierung für alle Tabellen. + + + + Please choose a new encoding for this table. + Bitte wählen Sie eine neue Kodierung für diese Tabelle. + + + + %1 +Leave the field empty for using the database encoding. + %1 +Lassen Sie das Feld leer, um die Datenbank-Kodierung zu verwenden. + + + + This encoding is either not valid or not supported. + Diese Kodierung ist entweder nicht gültig oder nicht unterstützt. + + + + %1 replacement(s) made. + %1 Ersetzung(en) durchgeführt. + + + + VacuumDialog + + + Compact Database + Datenbank komprimieren + + + + Warning: Compacting the database will commit all of your changes. + Warnung: Das Verdichten der Datenbank wird alle Ihre Änderungen übermitteln. + + + + Please select the databases to co&mpact: + Bitte wählen Sie die zu ver&dichtenden Datenbanken aus: + + + diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/translations/sqlb_en_GB.qm b/src/WBCLFZSystemModule/SqliteDBProcess/src/translations/sqlb_en_GB.qm new file mode 100644 index 0000000000000000000000000000000000000000..e1bf23dbe474d6f5f63ae7b4d3dc71a87457a613 GIT binary patch literal 33039 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 literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/translations/sqlb_en_GB.ts b/src/WBCLFZSystemModule/SqliteDBProcess/src/translations/sqlb_en_GB.ts new file mode 100644 index 0000000..40ddcbe --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/translations/sqlb_en_GB.ts @@ -0,0 +1,6927 @@ + + + + + AboutDialog + + + About DB Browser for SQLite + + + + + Version + + + + + <html><head/><body><p>DB Browser for SQLite is an open source, freeware visual tool used to create, design and edit SQLite database files.</p><p>It is bi-licensed under the Mozilla Public License Version 2, as well as the GNU General Public License Version 3 or later. You can modify or redistribute it under the conditions of these licenses.</p><p>See <a href="http://www.gnu.org/licenses/gpl.html">http://www.gnu.org/licenses/gpl.html</a> and <a href="https://www.mozilla.org/MPL/2.0/index.txt">https://www.mozilla.org/MPL/2.0/index.txt</a> for details.</p><p>For more information on this program please visit our website at: <a href="http://sqlitebrowser.org">http://sqlitebrowser.org</a></p><p><span style=" font-size:small;">This software uses the GPL/LGPL Qt Toolkit from </span><a href="http://qt-project.org/"><span style=" font-size:small;">http://qt-project.org/</span></a><span style=" font-size:small;"><br/>See </span><a href="http://qt-project.org/doc/qt-5/licensing.html"><span style=" font-size:small;">http://qt-project.org/doc/qt-5/licensing.html</span></a><span style=" font-size:small;"> for licensing terms and information.</span></p><p><span style=" font-size:small;">It also uses the Silk icon set by Mark James licensed under a Creative Commons Attribution 2.5 and 3.0 license.<br/>See </span><a href="http://www.famfamfam.com/lab/icons/silk/"><span style=" font-size:small;">http://www.famfamfam.com/lab/icons/silk/</span></a><span style=" font-size:small;"> for details.</span></p></body></html> + + + + + AddRecordDialog + + + Add New Record + + + + + Enter values for the new record considering constraints. Fields in bold are mandatory. + + + + + In the Value column you can specify the value for the field identified in the Name column. The Type column indicates the type of the field. Default values are displayed in the same style as NULL values. + + + + + Name + + + + + Type + + + + + Value + + + + + Values to insert. Pre-filled default values are inserted automatically unless they are changed. + + + + + When you edit the values in the upper frame, the SQL query for inserting this new record is shown here. You can edit manually the query before saving. + + + + + <html><head/><body><p><span style=" font-weight:600;">Save</span> will submit the shown SQL statement to the database for inserting the new record.</p><p><span style=" font-weight:600;">Restore Defaults</span> will restore the initial values in the <span style=" font-weight:600;">Value</span> column.</p><p><span style=" font-weight:600;">Cancel</span> will close this dialog without executing the query.</p></body></html> + + + + + Auto-increment + + + + + + Unique constraint + + + + + + Check constraint: %1 + + + + + + Foreign key: %1 + + + + + + Default value: %1 + + + + + + Error adding record. Message from database engine: + +%1 + + + + + Are you sure you want to restore all the entered values to their defaults? + + + + + Application + + + Possible command line arguments: + + + + + Usage: %1 [options] [<database>|<project>] + + + + + + -h, --help Show command line options + + + + + -q, --quit Exit application after running scripts + + + + + -s, --sql <file> Execute this SQL file after opening the DB + + + + + -t, --table <table> Browse this table after opening the DB + + + + + -R, --read-only Open database in read-only mode + + + + + -o, --option <group>/<setting>=<value> + + + + + Run application with this setting temporarily set to value + + + + + -O, --save-option <group>/<setting>=<value> + + + + + Run application saving this value for this setting + + + + + -v, --version Display the current version + + + + + <database> Open this SQLite database + + + + + <project> Open this project file (*.sqbpro) + + + + + The -s/--sql option requires an argument + + + + + The file %1 does not exist + + + + + The -t/--table option requires an argument + + + + + The -o/--option and -O/--save-option options require an argument in the form group/setting=value + + + + + Invalid option/non-existant file: %1 + + + + + SQLite Version + + + + + SQLCipher Version %1 (based on SQLite %2) + + + + + DB Browser for SQLite Version %1. + + + + + Built for %1, running on %2 + + + + + Qt Version %1 + + + + + CipherDialog + + + SQLCipher encryption + + + + + &Password + + + + + &Reenter password + + + + + Encr&yption settings + + + + + SQLCipher &3 defaults + + + + + SQLCipher &4 defaults + + + + + Custo&m + + + + + Page si&ze + + + + + &KDF iterations + + + + + HMAC algorithm + + + + + KDF algorithm + + + + + Plaintext Header Size + + + + + Passphrase + + + + + Raw key + + + + + Please set a key to encrypt the database. +Note that if you change any of the other, optional, settings you'll need to re-enter them as well every time you open the database file. +Leave the password fields empty to disable the encryption. +The encryption process might take some time and you should have a backup copy of your database! Unsaved changes are applied before modifying the encryption. + + + + + Please enter the key used to encrypt the database. +If any of the other settings were altered for this database file you need to provide this information as well. + + + + + ColumnDisplayFormatDialog + + + Choose display format + + + + + Display format + + + + + Choose a display format for the column '%1' which is applied to each value prior to showing it. + + + + + Default + + + + + Decimal number + + + + + Exponent notation + + + + + Hex blob + + + + + Hex number + + + + + Apple NSDate to date + + + + + Java epoch (milliseconds) to date + + + + + .NET DateTime.Ticks to date + + + + + Julian day to date + + + + + Unix epoch to local time + + + + + Date as dd/mm/yyyy + + + + + Lower case + + + + + Custom display format must contain a function call applied to %1 + + + + + Error in custom display format. Message from database engine: + +%1 + + + + + Custom display format must return only one column but it returned %1. + + + + + Octal number + + + + + Round number + + + + + Unix epoch to date + + + + + Upper case + + + + + Windows DATE to date + + + + + Custom + + + + + CondFormatManager + + + Conditional Format Manager + + + + + This dialog allows creating and editing conditional formats. Each cell style will be selected by the first accomplished condition for that cell data. Conditional formats can be moved up and down, where those at higher rows take precedence over those at lower. Syntax for conditions is the same as for filters and an empty condition applies to all values. + + + + + Add new conditional format + + + + + &Add + + + + + Remove selected conditional format + + + + + &Remove + + + + + Move selected conditional format up + + + + + Move &up + + + + + Move selected conditional format down + + + + + Move &down + + + + + Foreground + + + + + Text color + Text colour + + + + Background + + + + + Background color + Background colour + + + + Font + + + + + Size + + + + + Bold + + + + + Italic + + + + + Underline + + + + + Alignment + + + + + Condition + + + + + + Click to select color + + + + + Are you sure you want to clear all the conditional formats of this field? + + + + + DBBrowserDB + + + Please specify the database name under which you want to access the attached database + + + + + Invalid file format + + + + + Do you really want to close this temporary database? All data will be lost. + + + + + Do you want to save the changes made to the database file %1? + + + + + Database didn't close correctly, probably still busy + + + + + The database is currently busy: + + + + + Do you want to abort that other operation? + + + + + Exporting database to SQL file... + + + + + + Cancel + + + + + + No database file opened + + + + + Executing SQL... + + + + + Action cancelled. + + + + + + Error in statement #%1: %2. +Aborting execution%3. + + + + + + and rolling back + + + + + didn't receive any output from %1 + + + + + could not execute command: %1 + + + + + Cannot delete this object + + + + + Cannot set data on this object + + + + + + A table with the name '%1' already exists in schema '%2'. + + + + + No table with name '%1' exists in schema '%2'. + + + + + + Cannot find column %1. + + + + + Creating savepoint failed. DB says: %1 + + + + + Renaming the column failed. DB says: +%1 + + + + + + Releasing savepoint failed. DB says: %1 + + + + + Creating new table failed. DB says: %1 + + + + + Copying data to new table failed. DB says: +%1 + + + + + Deleting old table failed. DB says: %1 + + + + + Restoring some of the objects associated with this table failed. This is most likely because some column names changed. Here's the SQL statement which you might want to fix and execute manually: + + + + + + + could not get list of databases: %1 + + + + + Error loading extension: %1 + + + + + could not get column information + + + + + This database has already been attached. Its schema name is '%1'. + + + + + Error renaming table '%1' to '%2'. +Message from database engine: +%3 + + + + + could not get list of db objects: %1 + + + + + Error setting pragma %1 to %2: %3 + + + + + File not found. + + + + + DbStructureModel + + + Name + + + + + Object + + + + + Type + + + + + Schema + + + + + Database + + + + + Browsables + + + + + All + + + + + Temporary + + + + + Tables (%1) + + + + + Indices (%1) + + + + + Views (%1) + + + + + Triggers (%1) + + + + + EditDialog + + + Edit database cell + + + + + Mode: + + + + + + Image + + + + + Set as &NULL + + + + + Apply data to cell + + + + + This button saves the changes performed in the cell editor to the database cell. + + + + + Apply + + + + + Text + + + + + This is the list of supported modes for the cell editor. Choose a mode for viewing or editing the data of the current cell. + + + + + RTL Text + + + + + Binary + + + + + JSON + + + + + XML + + + + + + Automatically adjust the editor mode to the loaded data type + + + + + This checkable button enables or disables the automatic switching of the editor mode. When a new cell is selected or new data is imported and the automatic switching is enabled, the mode adjusts to the detected data type. You can then change the editor mode manually. If you want to keep this manually switched mode while moving through the cells, switch the button off. + + + + + Auto-switch + + + + + The text editor modes let you edit plain text, as well as JSON or XML data with syntax highlighting, automatic formatting and validation before saving. + +Errors are indicated with a red squiggle underline. + + + + + This Qt editor is used for right-to-left scripts, which are not supported by the default Text editor. The presence of right-to-left characters is detected and this editor mode is automatically selected. + + + + + Open preview dialog for printing the data currently stored in the cell + + + + + Auto-format: pretty print on loading, compact on saving. + + + + + When enabled, the auto-format feature formats the data on loading, breaking the text in lines and indenting it for maximum readability. On data saving, the auto-format feature compacts the data removing end of lines, and unnecessary whitespace. + + + + + Word Wrap + + + + + Wrap lines on word boundaries + + + + + + Open in default application or browser + + + + + Open in application + + + + + The value is interpreted as a file or URL and opened in the default application or web browser. + + + + + Save file reference... + + + + + Save reference to file + + + + + + Open in external application + + + + + Autoformat + + + + + &Export... + + + + + + &Import... + + + + + + Import from file + + + + + + Opens a file dialog used to import any kind of data to this database cell. + + + + + Export to file + + + + + Opens a file dialog used to export the contents of this database cell to a file. + + + + + Erases the contents of the cell + + + + + This area displays information about the data present in this database cell + + + + + Type of data currently in cell + + + + + Size of data currently in table + + + + + + Print... + + + + + Open preview dialog for printing displayed image + + + + + + Ctrl+P + + + + + Open preview dialog for printing displayed text + + + + + Copy Hex and ASCII + + + + + Copy selected hexadecimal and ASCII columns to the clipboard + + + + + Ctrl+Shift+C + + + + + Choose a filename to export data + + + + + Type of data currently in cell: %1 Image + + + + + %1x%2 pixel(s) + + + + + Type of data currently in cell: NULL + + + + + + Type of data currently in cell: Text / Numeric + + + + + + Image data can't be viewed in this mode. + + + + + + Try switching to Image or Binary mode. + + + + + + Binary data can't be viewed in this mode. + + + + + + Try switching to Binary mode. + + + + + + Image files (%1) + + + + + Binary files (*.bin) + + + + + Choose a file to import + + + + + %1 Image + + + + + Invalid data for this mode + + + + + The cell contains invalid %1 data. Reason: %2. Do you really want to apply it to the cell? + + + + + + + %n character(s) + + %n character + %n characters + + + + + Type of data currently in cell: Valid JSON + + + + + Type of data currently in cell: Binary + + + + + Couldn't save file: %1. + + + + + The data has been saved to a temporary file and has been opened with the default application. You can now edit the file and, when you are ready, apply the saved new data to the cell editor or cancel any changes. + + + + + + %n byte(s) + + %n byte + %n bytes + + + + + EditIndexDialog + + + &Name + + + + + Order + + + + + &Table + + + + + Edit Index Schema + + + + + &Unique + + + + + For restricting the index to only a part of the table you can specify a WHERE clause here that selects the part of the table that should be indexed + + + + + Partial inde&x clause + + + + + Colu&mns + + + + + Table column + + + + + Type + + + + + Add a new expression column to the index. Expression columns contain SQL expression rather than column names. + + + + + Index column + + + + + Deleting the old index failed: +%1 + + + + + Creating the index failed: +%1 + + + + + EditTableDialog + + + Edit table definition + + + + + Table + + + + + Advanced + + + + + Make this a 'WITHOUT rowid' table. Setting this flag requires a field of type INTEGER with the primary key flag set and the auto increment flag unset. + + + + + Without Rowid + + + + + Database sche&ma + + + + + Fields + + + + + Add + + + + + Remove + + + + + Move to top + + + + + Move up + + + + + Move down + + + + + Move to bottom + + + + + + Name + + + + + + Type + + + + + NN + + + + + Not null + + + + + PK + + + + + Primary key + + + + + AI + + + + + Autoincrement + + + + + U + + + + + + + Unique + + + + + Default + + + + + Default value + + + + + + + Check + + + + + Check constraint + + + + + Collation + + + + + + + Foreign Key + + + + + Constraints + + + + + Add constraint + + + + + Remove constraint + + + + + Columns + + + + + SQL + + + + + <html><head/><body><p><span style=" font-weight:600; color:#ff0000;">Warning: </span>There is something with this table definition that our parser doesn't fully understand. Modifying and saving this table might result in problems.</p></body></html> + + + + + + Primary Key + + + + + Add a primary key constraint + + + + + Add a foreign key constraint + + + + + Add a unique constraint + + + + + Add a check constraint + + + + + + There can only be one primary key for each table. Please modify the existing primary key instead. + + + + + Error creating table. Message from database engine: +%1 + + + + + There already is a field with that name. Please rename it first or choose a different name for this field. + + + + + This column is referenced in a foreign key in table %1 and thus its name cannot be changed. + + + + + There is at least one row with this field set to NULL. This makes it impossible to set this flag. Please change the table data first. + + + + + There is at least one row with a non-integer value in this field. This makes it impossible to set the AI flag. Please change the table data first. + + + + + Column '%1' has duplicate data. + + + + + + This makes it impossible to enable the 'Unique' flag. Please remove the duplicate data, which will allow the 'Unique' flag to then be enabled. + + + + + Are you sure you want to delete the field '%1'? +All data currently stored in this field will be lost. + + + + + Please add a field which meets the following criteria before setting the without rowid flag: + - Primary key flag set + - Auto increment disabled + + + + + ExportDataDialog + + + Export data as CSV + + + + + Tab&le(s) + + + + + Colu&mn names in first line + + + + + Fie&ld separator + + + + + , + + + + + ; + + + + + Tab + + + + + | + + + + + + + Other + + + + + &Quote character + + + + + " + + + + + ' + + + + + New line characters + + + + + Windows: CR+LF (\r\n) + + + + + Unix: LF (\n) + + + + + Pretty print + + + + + + Could not open output file: %1 + + + + + + Choose a filename to export data + + + + + Export data as JSON + + + + + exporting CSV + + + + + exporting JSON + + + + + Please select at least 1 table. + + + + + Choose a directory + + + + + Export completed. + + + + + ExportSqlDialog + + + Export SQL... + + + + + Tab&le(s) + + + + + Select All + + + + + Deselect All + + + + + &Options + + + + + Keep column names in INSERT INTO + + + + + Multiple rows (VALUES) per INSERT statement + + + + + Export everything + + + + + Export data only + + + + + Keep old schema (CREATE TABLE IF NOT EXISTS) + + + + + Overwrite old schema (DROP TABLE, then CREATE TABLE) + + + + + Export schema only + + + + + Please select at least one table. + + + + + Choose a filename to export + + + + + Export completed. + + + + + Export cancelled or failed. + + + + + ExtendedScintilla + + + + Ctrl+H + + + + + Ctrl+F + + + + + + Ctrl+P + + + + + Find... + + + + + Find and Replace... + + + + + Print... + + + + + ExtendedTableWidget + + + Use as Exact Filter + + + + + Containing + + + + + Not containing + + + + + Not equal to + + + + + Greater than + + + + + Less than + + + + + Greater or equal + + + + + Less or equal + + + + + Between this and... + + + + + Regular expression + + + + + Edit Conditional Formats... + + + + + Set to NULL + + + + + Copy + + + + + Copy with Headers + + + + + Copy as SQL + + + + + Paste + + + + + Print... + + + + + Use in Filter Expression + + + + + Alt+Del + + + + + Ctrl+Shift+C + + + + + Ctrl+Alt+C + + + + + The content of the clipboard is bigger than the range selected. +Do you want to insert it anyway? + + + + + <p>Not all data has been loaded. <b>Do you want to load all data before selecting all the rows?</b><p><p>Answering <b>No</b> means that no more data will be loaded and the selection will not be performed.<br/>Answering <b>Yes</b> might take some time while the data is loaded but the selection will be complete.</p>Warning: Loading all the data might require a great amount of memory for big tables. + + + + + Cannot set selection to NULL. Column %1 has a NOT NULL constraint. + + + + + FileExtensionManager + + + File Extension Manager + + + + + &Up + + + + + &Down + + + + + &Add + + + + + &Remove + + + + + + Description + + + + + Extensions + + + + + *.extension + + + + + FilterLineEdit + + + Filter + + + + + These input fields allow you to perform quick filters in the currently selected table. +By default, the rows containing the input text are filtered out. +The following operators are also supported: +% Wildcard +> Greater than +< Less than +>= Equal to or greater +<= Equal to or less += Equal to: exact match +<> Unequal: exact inverse match +x~y Range: values between x and y +/regexp/ Values matching the regular expression + + + + + Clear All Conditional Formats + + + + + Use for Conditional Format + + + + + Edit Conditional Formats... + + + + + Set Filter Expression + + + + + What's This? + + + + + Is NULL + + + + + Is not NULL + + + + + Is empty + + + + + Is not empty + + + + + Not containing... + + + + + Equal to... + + + + + Not equal to... + + + + + Greater than... + + + + + Less than... + + + + + Greater or equal... + + + + + Less or equal... + + + + + In range... + + + + + Regular expression... + + + + + FindReplaceDialog + + + Find and Replace + + + + + Fi&nd text: + + + + + Re&place with: + + + + + Match &exact case + + + + + Match &only whole words + + + + + When enabled, the search continues from the other end when it reaches one end of the page + + + + + &Wrap around + + + + + When set, the search goes backwards from cursor position, otherwise it goes forward + + + + + Search &backwards + + + + + <html><head/><body><p>When checked, the pattern to find is searched only in the current selection.</p></body></html> + + + + + &Selection only + + + + + <html><head/><body><p>When checked, the pattern to find is interpreted as a UNIX regular expression. See <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>.</p></body></html> + + + + + Use regular e&xpressions + + + + + Find the next occurrence from the cursor position and in the direction set by "Search backwards" + + + + + &Find Next + + + + + F3 + + + + + &Replace + + + + + Highlight all the occurrences of the text in the page + + + + + F&ind All + + + + + Replace all the occurrences of the text in the page + + + + + Replace &All + + + + + The searched text was not found + + + + + The searched text was not found. + + + + + The searched text was found one time. + + + + + The searched text was found %1 times. + + + + + The searched text was replaced one time. + + + + + The searched text was replaced %1 times. + + + + + ForeignKeyEditor + + + &Reset + + + + + Foreign key clauses (ON UPDATE, ON DELETE etc.) + + + + + ImportCsvDialog + + + Import CSV file + + + + + Table na&me + + + + + &Column names in first line + + + + + Field &separator + + + + + , + + + + + ; + + + + + + Tab + + + + + | + + + + + Other + + + + + &Quote character + + + + + + Other (printable) + + + + + + Other (code) + + + + + " + + + + + ' + + + + + &Encoding + + + + + UTF-8 + + + + + UTF-16 + + + + + ISO-8859-1 + + + + + Trim fields? + + + + + Separate tables + + + + + Advanced + + + + + When importing an empty value from the CSV file into an existing table with a default value for this column, that default value is inserted. Activate this option to insert an empty value instead. + + + + + Ignore default &values + + + + + Activate this option to stop the import when trying to import an empty value into a NOT NULL column without a default value. + + + + + Fail on missing values + + + + + Disable data type detection + + + + + Disable the automatic data type detection when creating a new table. + + + + + When importing into an existing table with a primary key, unique constraints or a unique index there is a chance for a conflict. This option allows you to select a strategy for that case: By default the import is aborted and rolled back but you can also choose to ignore and not import conflicting rows or to replace the existing row in the table. + + + + + Abort import + + + + + Ignore row + + + + + Replace existing row + + + + + Conflict strategy + + + + + + Deselect All + + + + + Match Similar + + + + + Select All + + + + + There is already a table named '%1' and an import into an existing table is only possible if the number of columns match. + + + + + There is already a table named '%1'. Do you want to import the data into it? + + + + + Creating restore point failed: %1 + + + + + Creating the table failed: %1 + + + + + importing CSV + + + + + Importing the file '%1' took %2ms. Of this %3ms were spent in the row function. + + + + + Inserting row failed: %1 + + + + + MainWindow + + + DB Browser for SQLite + + + + + toolBar1 + + + + + Opens the SQLCipher FAQ in a browser window + + + + + Export one or more table(s) to a JSON file + + + + + &File + + + + + &Import + + + + + &Export + + + + + &Edit + + + + + &View + + + + + &Help + + + + + DB Toolbar + + + + + Edit Database &Cell + + + + + DB Sche&ma + + + + + &Remote + + + + + + Execute current line + + + + + This button executes the SQL statement present in the current editor line + + + + + Shift+F5 + + + + + Sa&ve Project + + + + + Open an existing database file in read only mode + + + + + User + + + + + + Database Structure + This has to be equal to the tab title in all the main tabs + + + + + This is the structure of the opened database. +You can drag SQL statements from an object row and drop them into other applications or into another instance of 'DB Browser for SQLite'. + + + + + + + Browse Data + This has to be equal to the tab title in all the main tabs + + + + + Un/comment block of SQL code + + + + + Un/comment block + + + + + Comment or uncomment current line or selected block of code + + + + + Comment or uncomment the selected lines or the current line, when there is no selection. All the block is toggled according to the first line. + + + + + Ctrl+/ + + + + + Stop SQL execution + + + + + Stop execution + + + + + Stop the currently running SQL script + + + + + + Edit Pragmas + This has to be equal to the tab title in all the main tabs + + + + + Warning: this pragma is not readable and this value has been inferred. Writing the pragma might overwrite a redefined LIKE provided by an SQLite extension. + + + + + + Execute SQL + This has to be equal to the tab title in all the main tabs + + + + + &Tools + + + + + Application + + + + + Error Log + + + + + This button clears the contents of the SQL logs + + + + + &Clear + + + + + This panel lets you examine a log of all SQL commands issued by the application or by yourself + + + + + This is the structure of the opened database. +You can drag multiple object names from the Name column and drop them into the SQL editor and you can adjust the properties of the dropped names using the context menu. This would help you in composing SQL statements. +You can drag SQL statements from the Schema column and drop them into the SQL editor or into other applications. + + + + + + + Project Toolbar + + + + + Extra DB toolbar + + + + + + + Close the current database file + + + + + &New Database... + + + + + + Create a new database file + + + + + This option is used to create a new database file. + + + + + Ctrl+N + + + + + + &Open Database... + + + + + + + + + Open an existing database file + + + + + + + This option is used to open an existing database file. + + + + + Ctrl+O + + + + + &Close Database + + + + + This button closes the connection to the currently open database file + + + + + + Ctrl+W + + + + + + Revert database to last saved state + + + + + This option is used to revert the current database file to its last saved state. All changes made since the last save operation are lost. + + + + + + Write changes to the database file + + + + + This option is used to save changes to the database file. + + + + + Ctrl+S + + + + + Compact &Database... + + + + + Compact the database file, removing space wasted by deleted records + + + + + + Compact the database file, removing space wasted by deleted records. + + + + + E&xit + + + + + Ctrl+Q + + + + + Import data from an .sql dump text file into a new or existing database. + + + + + This option lets you import data from an .sql dump text file into a new or existing database. SQL dump files can be created on most database engines, including MySQL and PostgreSQL. + + + + + Open a wizard that lets you import data from a comma separated text file into a database table. + + + + + Open a wizard that lets you import data from a comma separated text file into a database table. CSV files can be created on most database and spreadsheet applications. + + + + + Export a database to a .sql dump text file. + + + + + This option lets you export a database to a .sql dump text file. SQL dump files contain all data necessary to recreate the database on most database engines, including MySQL and PostgreSQL. + + + + + Export a database table as a comma separated text file. + + + + + Export a database table as a comma separated text file, ready to be imported into other database or spreadsheet applications. + + + + + Open the Create Table wizard, where it is possible to define the name and fields for a new table in the database + + + + + + Delete Table + + + + + Open the Delete Table wizard, where you can select a database table to be dropped. + + + + + Open the Modify Table wizard, where it is possible to rename an existing table. It is also possible to add or delete fields form a table, as well as modify field names and types. + + + + + Open the Create Index wizard, where it is possible to define a new index on an existing database table. + + + + + &Preferences... + + + + + + Open the preferences window. + + + + + &DB Toolbar + + + + + Shows or hides the Database toolbar. + + + + + Shift+F1 + + + + + Open SQL file(s) + + + + + This button opens files containing SQL statements and loads them in new editor tabs + + + + + Execute line + + + + + &Wiki + + + + + F1 + + + + + Bug &Report... + + + + + Feature Re&quest... + + + + + Web&site + + + + + &Donate on Patreon... + + + + + This button lets you save all the settings associated to the open DB to a DB Browser for SQLite project file + + + + + This button lets you open a DB Browser for SQLite project file + + + + + Ctrl+Shift+O + + + + + &Save Project As... + + + + + + + Save the project in a file selected in a dialog + + + + + Save A&ll + + + + + + + Save DB file, project file and opened SQL files + + + + + Ctrl+Shift+S + + + + + Browse Table + + + + + &Attach Database... + + + + + + Add another database file to the current database connection + + + + + This button lets you add another database file to the current database connection + + + + + &Set Encryption... + + + + + SQLCipher &FAQ + + + + + Table(&s) to JSON... + + + + + Open Data&base Read Only... + + + + + Save results + + + + + Save the results view + + + + + This button lets you save the results of the last executed query + + + + + + Find text in SQL editor + + + + + Find + + + + + This button opens the search bar of the editor + + + + + Ctrl+F + + + + + + Find or replace text in SQL editor + + + + + Find or replace + + + + + This button opens the find/replace dialog for the current editor tab + + + + + Ctrl+H + + + + + Export to &CSV + + + + + Save as &view + + + + + Save as view + + + + + Shows or hides the Project toolbar. + + + + + Extra DB Toolbar + + + + + New In-&Memory Database + + + + + Drag && Drop Qualified Names + + + + + + Use qualified names (e.g. "Table"."Field") when dragging the objects and dropping them into the editor + + + + + Drag && Drop Enquoted Names + + + + + + Use escaped identifiers (e.g. "Table1") when dragging the objects and dropping them into the editor + + + + + &Integrity Check + + + + + Runs the integrity_check pragma over the opened database and returns the results in the Execute SQL tab. This pragma does an integrity check of the entire database. + + + + + &Foreign-Key Check + + + + + Runs the foreign_key_check pragma over the opened database and returns the results in the Execute SQL tab + + + + + &Quick Integrity Check + + + + + Run a quick integrity check over the open DB + + + + + Runs the quick_check pragma over the opened database and returns the results in the Execute SQL tab. This command does most of the checking of PRAGMA integrity_check but runs much faster. + + + + + &Optimize + + + + + Attempt to optimize the database + + + + + Runs the optimize pragma over the opened database. This pragma might perform optimizations that will improve the performance of future queries. + + + + + + Print + + + + + Print text from current SQL editor tab + + + + + Open a dialog for printing the text in the current SQL editor tab + + + + + Print the structure of the opened database + + + + + Open a dialog for printing the structure of the opened database + + + + + &Recently opened + + + + + Open &tab + + + + + Ctrl+T + + + + + SQL &Log + + + + + Show S&QL submitted by + + + + + &Plot + + + + + Ctrl+F4 + + + + + &Revert Changes + + + + + &Write Changes + + + + + &Database from SQL file... + + + + + &Table from CSV file... + + + + + &Database to SQL file... + + + + + &Table(s) as CSV file... + + + + + &Create Table... + + + + + &Delete Table... + + + + + &Modify Table... + + + + + Create &Index... + + + + + W&hat's This? + + + + + &About + + + + + This button opens a new tab for the SQL editor + + + + + &Execute SQL + + + + + Execute all/selected SQL + + + + + This button executes the currently selected SQL statements. If no text is selected, all SQL statements are executed. + + + + + + + Save SQL file + + + + + &Load Extension... + + + + + Ctrl+E + + + + + Export as CSV file + + + + + Export table as comma separated values file + + + + + + Save the current session to a file + + + + + Open &Project... + + + + + + Load a working session from a file + + + + + + Save SQL file as + + + + + This button saves the content of the current SQL editor tab to a file + + + + + &Browse Table + + + + + Copy Create statement + + + + + Copy the CREATE statement of the item to the clipboard + + + + + Ctrl+Return + + + + + Ctrl+L + + + + + + Ctrl+P + + + + + Ctrl+D + + + + + Ctrl+I + + + + + Encrypted + + + + + Read only + + + + + Database file is read only. Editing the database is disabled. + + + + + Database encoding + + + + + Database is encrypted using SQLCipher + + + + + + Choose a database file + + + + + + + Choose a filename to save under + + + + + Error checking foreign keys after table modification. The changes will be reverted. + + + + + This table did not pass a foreign-key check.<br/>You should run 'Tools | Foreign-Key Check' and fix the reported issues. + + + + + + At line %1: + + + + + Result: %2 + + + + + Setting PRAGMA values or vacuuming will commit your current transaction. +Are you sure? + + + + + Error while saving the database file. This means that not all changes to the database were saved. You need to resolve the following error first. + +%1 + + + + + Are you sure you want to undo all changes made to the database file '%1' since the last save? + + + + + Choose a file to import + + + + + Text files(*.sql *.txt);;All files(*) + + + + + Do you want to create a new database file to hold the imported data? +If you answer no we will attempt to import the data in the SQL file to the current database. + + + + + Window Layout + + + + + Simplify Window Layout + + + + + Shift+Alt+0 + + + + + Dock Windows at Bottom + + + + + Dock Windows at Left Side + + + + + Dock Windows at Top + + + + + You are still executing SQL statements. Closing the database now will stop their execution, possibly leaving the database in an inconsistent state. Are you sure you want to close the database? + + + + + Do you want to save the changes made to the project file '%1'? + + + + + File %1 already exists. Please choose a different name. + + + + + Error importing data: %1 + + + + + Import completed. + + + + + Delete View + + + + + Modify View + + + + + Delete Trigger + + + + + Modify Trigger + + + + + Delete Index + + + + + Modify Index + + + + + Modify Table + + + + + Do you want to save the changes made to SQL tabs in a new project file? + + + + + Do you want to save the changes made to the SQL file %1? + + + + + The statements in this tab are still executing. Closing the tab will stop the execution. This might leave the database in an inconsistent state. Are you sure you want to close the tab? + + + + + Could not find resource file: %1 + + + + + Choose a project file to open + + + + + This project file is using an old file format because it was created using DB Browser for SQLite version 3.10 or lower. Loading this file format is still fully supported but we advice you to convert all your project files to the new file format because support for older formats might be dropped at some point in the future. You can convert your files by simply opening and re-saving them. + + + + + Could not open project file for writing. +Reason: %1 + + + + + Busy (%1) + + + + + Setting PRAGMA values will commit your current transaction. +Are you sure? + + + + + Reset Window Layout + + + + + Alt+0 + + + + + The database is currenctly busy. + + + + + Click here to interrupt the currently running query. + + + + + Could not open database file. +Reason: %1 + + + + + In-Memory database + + + + + Are you sure you want to delete the table '%1'? +All data associated with the table will be lost. + + + + + Are you sure you want to delete the view '%1'? + + + + + Are you sure you want to delete the trigger '%1'? + + + + + Are you sure you want to delete the index '%1'? + + + + + Error: could not delete the table. + + + + + Error: could not delete the view. + + + + + Error: could not delete the trigger. + + + + + Error: could not delete the index. + + + + + Message from database engine: +%1 + + + + + Editing the table requires to save all pending changes now. +Are you sure you want to save the database? + + + + + Edit View %1 + + + + + Edit Trigger %1 + + + + + You are already executing SQL statements. Do you want to stop them in order to execute the current statements instead? Note that this might leave the database in an inconsistent state. + + + + + -- EXECUTING SELECTION IN '%1' +-- + + + + + -- EXECUTING LINE IN '%1' +-- + + + + + -- EXECUTING ALL IN '%1' +-- + + + + + Result: %1 + + + + + %1 rows returned in %2ms + + + + + Choose text files + + + + + Import completed. Some foreign key constraints are violated. Please fix them before saving. + + + + + Opened '%1' in read-only mode from recent file list + + + + + Opened '%1' from recent file list + + + + + &%1 %2%3 + + + + + (read only) + + + + + Open Database or Project + + + + + Attach Database... + + + + + Import CSV file(s)... + + + + + Select the action to apply to the dropped file(s). <br/>Note: only 'Import' will process more than one file. + + + + + + + + Do you want to save the changes made to SQL tabs in the project file '%1'? + + + + + Select SQL file to open + + + + + This action will open a new SQL tab with the following statements for you to edit and run: + + + + + Rename Tab + + + + + Duplicate Tab + + + + + Close Tab + + + + + Opening '%1'... + + + + + There was an error opening '%1'... + + + + + Value is not a valid URL or filename: %1 + + + + + Select file name + + + + + Select extension file + + + + + Extension successfully loaded. + + + + + Error loading extension: %1 + + + + + + Don't show again + + + + + New version available. + + + + + A new DB Browser for SQLite version is available (%1.%2.%3).<br/><br/>Please download at <a href='%4'>%4</a>. + + + + + Project saved to file '%1' + + + + + Collation needed! Proceed? + + + + + A table in this database requires a special collation function '%1' that this application can't provide without further knowledge. +If you choose to proceed, be aware bad things can happen to your database. +Create a backup! + + + + + creating collation + + + + + Set a new name for the SQL tab. Use the '&&' character to allow using the following character as a keyboard shortcut. + + + + + Please specify the view name + + + + + There is already an object with that name. Please choose a different name. + + + + + View successfully created. + + + + + Error creating view: %1 + + + + + This action will open a new SQL tab for running: + + + + + Press Help for opening the corresponding SQLite reference page. + + + + + DB Browser for SQLite project file (*.sqbpro) + + + + + Execution finished with errors. + + + + + Execution finished without errors. + + + + + NullLineEdit + + + Set to NULL + + + + + Alt+Del + + + + + PlotDock + + + Plot + + + + + <html><head/><body><p>This pane shows the list of columns of the currently browsed table or the just executed query. You can select the columns that you want to be used as X or Y axis for the plot pane below. The table shows detected axis type that will affect the resulting plot. For the Y axis you can only select numeric columns, but for the X axis you will be able to select:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Date/Time</span>: strings with format &quot;yyyy-MM-dd hh:mm:ss&quot; or &quot;yyyy-MM-ddThh:mm:ss&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Date</span>: strings with format &quot;yyyy-MM-dd&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Time</span>: strings with format &quot;hh:mm:ss&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Label</span>: other string formats. Selecting this column as X axis will produce a Bars plot with the column values as labels for the bars</li><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Numeric</span>: integer or real values</li></ul><p>Double-clicking the Y cells you can change the used color for that graph.</p></body></html> + <html><head/><body><p>This pane shows the list of columns of the currently browsed table or the just executed query. You can select the columns that you want to be used as X or Y axis for the plot pane below. The table shows detected axis type that will affect the resulting plot. For the Y axis you can only select numeric columns, but for the X axis you will be able to select:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Date/Time</span>: strings with format &quot;yyyy-MM-dd hh:mm:ss&quot; or &quot;yyyy-MM-ddThh:mm:ss&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Date</span>: strings with format &quot;yyyy-MM-dd&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Time</span>: strings with format &quot;hh:mm:ss&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Label</span>: other string formats. Selecting this column as X axis will produce a Bars plot with the column values as labels for the bars</li><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Numeric</span>: integer or real values</li></ul><p>Double-clicking the Y cells you can change the used colour for that graph.</p></body></html> + + + + Columns + + + + + X + + + + + Y1 + + + + + Y2 + + + + + Axis Type + + + + + Here is a plot drawn when you select the x and y values above. + +Click on points to select them in the plot and in the table. Ctrl+Click for selecting a range of points. + +Use mouse-wheel for zooming and mouse drag for changing the axis range. + +Select the axes or axes labels to drag and zoom only in that orientation. + + + + + Line type: + + + + + + None + + + + + Line + + + + + StepLeft + + + + + StepRight + + + + + StepCenter + + + + + Impulse + + + + + Point shape: + + + + + Cross + + + + + Plus + + + + + Circle + + + + + Disc + + + + + Square + + + + + Diamond + + + + + Star + + + + + Triangle + + + + + TriangleInverted + + + + + CrossSquare + + + + + PlusSquare + + + + + CrossCircle + + + + + PlusCircle + + + + + Peace + + + + + <html><head/><body><p>Save current plot...</p><p>File format chosen by extension (png, jpg, pdf, bmp)</p></body></html> + + + + + Save current plot... + + + + + + Load all data and redraw plot + + + + + + + Row # + + + + + Copy + + + + + Print... + + + + + Show legend + + + + + Stacked bars + + + + + Date/Time + + + + + Date + + + + + Time + + + + + + Numeric + + + + + Label + + + + + Invalid + + + + + Load all data and redraw plot. +Warning: not all data has been fetched from the table yet due to the partial fetch mechanism. + + + + + Choose an axis color + Choose an axis colour + + + + Choose a filename to save under + + + + + PNG(*.png);;JPG(*.jpg);;PDF(*.pdf);;BMP(*.bmp);;All Files(*) + + + + + There are curves in this plot and the selected line style can only be applied to graphs sorted by X. Either sort the table or query by X to remove curves or select one of the styles supported by curves: None or Line. + + + + + Loading all remaining data for this table took %1ms. + + + + + PreferencesDialog + + + Preferences + + + + + &General + + + + + Remember last location + + + + + Always use this location + + + + + Remember last location for session only + + + + + + + ... + + + + + Default &location + + + + + Lan&guage + + + + + Automatic &updates + + + + + + + + + + + + + enabled + + + + + Show remote options + + + + + &Database + + + + + Database &encoding + + + + + Open databases with foreign keys enabled. + + + + + &Foreign keys + + + + + SQ&L to execute after opening database + + + + + Data &Browser + + + + + Remove line breaks in schema &view + + + + + Prefetch block si&ze + + + + + Default field type + + + + + Font + + + + + &Font + + + + + Content + + + + + Symbol limit in cell + + + + + NULL + + + + + Regular + + + + + Binary + + + + + Background + + + + + Filters + + + + + Threshold for completion and calculation on selection + + + + + Escape character + + + + + Delay time (&ms) + + + + + Set the waiting time before a new filter value is applied. Can be set to 0 for disabling waiting. + + + + + &SQL + + + + + Settings name + + + + + Context + + + + + Colour + + + + + Bold + + + + + Italic + + + + + Underline + + + + + Keyword + + + + + Function + + + + + Table + + + + + Comment + + + + + Identifier + + + + + String + + + + + Current line + + + + + SQL &editor font size + + + + + Tab size + + + + + SQL editor &font + + + + + Error indicators + + + + + Hori&zontal tiling + + + + + If enabled the SQL code editor and the result table view are shown side by side instead of one over the other. + + + + + Code co&mpletion + + + + + Toolbar style + + + + + + + + + Only display the icon + + + + + + + + + Only display the text + + + + + + + + + The text appears beside the icon + + + + + + + + + The text appears under the icon + + + + + + + + + Follow the style + + + + + DB file extensions + + + + + Manage + + + + + Main Window + + + + + Database Structure + + + + + Browse Data + + + + + Execute SQL + + + + + Edit Database Cell + + + + + When this value is changed, all the other color preferences are also set to matching colors. + + + + + Follow the desktop style + + + + + Dark style + + + + + Application style + + + + + This sets the font size for all UI elements which do not have their own font size option. + + + + + Font size + + + + + When enabled, the line breaks in the Schema column of the DB Structure tab, dock and printed output are removed. + + + + + Database structure font size + + + + + Font si&ze + + + + + This is the maximum number of items allowed for some computationally expensive functionalities to be enabled: +Maximum number of rows in a table for enabling the value completion based on current values in the column. +Maximum number of indexes in a selection for calculating sum and average. +Can be set to 0 for disabling the functionalities. + + + + + This is the maximum number of rows in a table for enabling the value completion based on current values in the column. +Can be set to 0 for disabling completion. + + + + + Show images in cell + + + + + Enable this option to show a preview of BLOBs containing image data in the cells. This can affect the performance of the data browser, however. + + + + + Field display + + + + + Displayed &text + + + + + + + + + + Click to set this color + + + + + Text color + Text colour + + + + Background color + Background colour + + + + Preview only (N/A) + + + + + Foreground + + + + + SQL &results font size + + + + + &Wrap lines + + + + + Never + + + + + At word boundaries + + + + + At character boundaries + + + + + At whitespace boundaries + + + + + &Quotes for identifiers + + + + + Choose the quoting mechanism used by the application for identifiers in SQL code. + + + + + "Double quotes" - Standard SQL (recommended) + + + + + `Grave accents` - Traditional MySQL quotes + + + + + [Square brackets] - Traditional MS SQL Server quotes + + + + + Keywords in &UPPER CASE + + + + + When set, the SQL keywords are completed in UPPER CASE letters. + + + + + When set, the SQL code lines that caused errors during the last execution are highlighted and the results frame indicates the error in the background + + + + + Close button on tabs + + + + + If enabled, SQL editor tabs will have a close button. In any case, you can use the contextual menu or the keyboard shortcut to close them. + + + + + &Extensions + + + + + Select extensions to load for every database: + + + + + Add extension + + + + + Remove extension + + + + + <html><head/><body><p>While supporting the REGEXP operator SQLite doesn't implement any regular expression<br/>algorithm but calls back the running application. DB Browser for SQLite implements this<br/>algorithm for you to let you use REGEXP out of the box. However, as there are multiple possible<br/>implementations of this and you might want to use another one, you're free to disable the<br/>application's implementation and load your own by using an extension. Requires restart of the application.</p></body></html> + + + + + Disable Regular Expression extension + + + + + <html><head/><body><p>SQLite provides an SQL function for loading extensions from a shared library file. Activate this if you want to use the <span style=" font-style:italic;">load_extension()</span> function from SQL code.</p><p>For security reasons, extension loading is turned off by default and must be enabled through this setting. You can always load extensions through the GUI, even though this option is disabled.</p></body></html> + + + + + Allow loading extensions from SQL code + + + + + Remote + + + + + CA certificates + + + + + Proxy + + + + + Configure + + + + + + Subject CN + + + + + Common Name + + + + + Subject O + + + + + Organization + + + + + + Valid from + + + + + + Valid to + + + + + + Serial number + + + + + Your certificates + + + + + File + + + + + Subject Common Name + + + + + Issuer CN + + + + + Issuer Common Name + + + + + Clone databases into + + + + + + Choose a directory + + + + + The language will change after you restart the application. + + + + + Select extension file + + + + + Extensions(*.so *.dylib *.dll);;All files(*) + + + + + Import certificate file + + + + + No certificates found in this file. + + + + + Are you sure you want do remove this certificate? All certificate data will be deleted from the application settings! + + + + + Are you sure you want to clear all the saved settings? +All your preferences will be lost and default values will be used. + + + + + ProxyDialog + + + Proxy Configuration + + + + + Pro&xy Type + + + + + Host Na&me + + + + + Port + + + + + Authentication Re&quired + + + + + &User Name + + + + + Password + + + + + None + + + + + System settings + + + + + HTTP + + + + + Socks v5 + + + + + QObject + + + Error importing data + + + + + from record number %1 + + + + + . +%1 + + + + + Importing CSV file... + + + + + Cancel + + + + + All files (*) + + + + + SQLite database files (*.db *.sqlite *.sqlite3 *.db3) + + + + + Left + + + + + Right + + + + + Center + + + + + Justify + + + + + SQLite Database Files (*.db *.sqlite *.sqlite3 *.db3) + + + + + DB Browser for SQLite Project Files (*.sqbpro) + + + + + SQL Files (*.sql) + + + + + All Files (*) + + + + + Text Files (*.txt) + + + + + Comma-Separated Values Files (*.csv) + + + + + Tab-Separated Values Files (*.tsv) + + + + + Delimiter-Separated Values Files (*.dsv) + + + + + Concordance DAT files (*.dat) + + + + + JSON Files (*.json *.js) + + + + + XML Files (*.xml) + + + + + Binary Files (*.bin *.dat) + + + + + SVG Files (*.svg) + + + + + Hex Dump Files (*.dat *.bin) + + + + + Extensions (*.so *.dylib *.dll) + + + + + RemoteCommitsModel + + + Commit ID + + + + + Message + + + + + Date + + + + + Author + + + + + Size + + + + + Authored and committed by %1 + + + + + Authored by %1, committed by %2 + + + + + RemoteDatabase + + + Error opening local databases list. +%1 + + + + + Error creating local databases list. +%1 + + + + + RemoteDock + + + Remote + + + + + Identity + + + + + Push currently opened database to server + + + + + DBHub.io + + + + + <html><head/><body><p>In this pane, remote databases from dbhub.io website can be added to DB Browser for SQLite. First you need an identity:</p><ol style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Login to the dbhub.io website (use your GitHub credentials or whatever you want)</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Click the button to &quot;Generate client certificate&quot; (that's your identity). That'll give you a certificate file (save it to your local disk).</li><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Go to the Remote tab in DB Browser for SQLite Preferences. Click the button to add a new certificate to DB Browser for SQLite and choose the just downloaded certificate file.</li></ol><p>Now the Remote panel shows your identity and you can add remote databases.</p></body></html> + + + + + Local + + + + + Current Database + + + + + Clone + + + + + User + + + + + Database + + + + + Branch + + + + + Commits + + + + + Commits for + + + + + <html><head/><body><p>You are currently using a built-in, read-only identity. For uploading your database, you need to configure and use your DBHub.io account.</p><p>No DBHub.io account yet? <a href="https://dbhub.io/"><span style=" text-decoration: underline; color:#007af4;">Create one now</span></a> and import your certificate <a href="#preferences"><span style=" text-decoration: underline; color:#007af4;">here</span></a> to share your databases.</p><p>For online help visit <a href="https://dbhub.io/about"><span style=" text-decoration: underline; color:#007af4;">here</span></a>.</p></body></html> + + + + + Back + + + + + Delete Database + + + + + Delete the local clone of this database + + + + + Open in Web Browser + + + + + Open the web page for the current database in your browser + + + + + Clone from Link + + + + + Use this to download a remote database for local editing using a URL as provided on the web page of the database. + + + + + Refresh + + + + + Reload all data and update the views + + + + + F5 + + + + + Clone Database + + + + + Open Database + + + + + Open the local copy of this database + + + + + Check out Commit + + + + + Download and open this specific commit + + + + + Check out Latest Commit + + + + + Check out the latest commit of the current branch + + + + + Save Revision to File + + + + + Saves the selected revision of the database to another file + + + + + Upload Database + + + + + Upload this database as a new commit + + + + + Select an identity to connect + + + + + Public + + + + + This downloads a database from a remote server for local editing. +Please enter the URL to clone from. You can generate this URL by +clicking the 'Clone Database in DB4S' button on the web page +of the database. + + + + + Invalid URL: The host name does not match the host name of the current identity. + + + + + Invalid URL: No branch name specified. + + + + + Invalid URL: No commit ID specified. + + + + + You have modified the local clone of the database. Fetching this commit overrides these local changes. +Are you sure you want to proceed? + + + + + The database has unsaved changes. Are you sure you want to push it before saving? + + + + + The database you are trying to delete is currently opened. Please close it before deleting. + + + + + This deletes the local version of this database with all the changes you have not committed yet. Are you sure you want to delete this database? + + + + + RemoteLocalFilesModel + + + Name + + + + + Branch + + + + + Last modified + + + + + Size + + + + + Commit + + + + + File + + + + + RemoteModel + + + Name + + + + + Commit + + + + + Last modified + + + + + Size + + + + + Size: + + + + + Last Modified: + + + + + Licence: + + + + + Default Branch: + + + + + RemoteNetwork + + + Choose a location to save the file + + + + + Error opening remote file at %1. +%2 + + + + + Error: Invalid client certificate specified. + + + + + Please enter the passphrase for this client certificate in order to authenticate. + + + + + Cancel + + + + + Uploading remote database to +%1 + + + + + Downloading remote database from +%1 + + + + + + Error: The network is not accessible. + + + + + Error: Cannot open the file for sending. + + + + + RemotePushDialog + + + Push database + + + + + Database na&me to push to + + + + + Commit message + + + + + Database licence + + + + + Public + + + + + Branch + + + + + Force push + + + + + Username + + + + + Database will be public. Everyone has read access to it. + + + + + Database will be private. Only you have access to it. + + + + + Use with care. This can cause remote commits to be deleted. + + + + + RunSql + + + Execution aborted by user + + + + + , %1 rows affected + + + + + query executed successfully. Took %1ms%2 + + + + + executing query + + + + + SelectItemsPopup + + + A&vailable + + + + + Sele&cted + + + + + SqlExecutionArea + + + Form + + + + + Find previous match [Shift+F3] + + + + + Find previous match with wrapping + + + + + Shift+F3 + + + + + The found pattern must be a whole word + + + + + Whole Words + + + + + Text pattern to find considering the checks in this frame + + + + + Find in editor + + + + + The found pattern must match in letter case + + + + + Case Sensitive + + + + + Find next match [Enter, F3] + + + + + Find next match with wrapping + + + + + F3 + + + + + Interpret search pattern as a regular expression + + + + + <html><head/><body><p>When checked, the pattern to find is interpreted as a UNIX regular expression. See <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>.</p></body></html> + + + + + Regular Expression + + + + + + Close Find Bar + + + + + <html><head/><body><p>Results of the last executed statements.</p><p>You may want to collapse this panel and use the <span style=" font-style:italic;">SQL Log</span> dock with <span style=" font-style:italic;">User</span> selection instead.</p></body></html> + + + + + Results of the last executed statements + + + + + This field shows the results and status codes of the last executed statements. + + + + + Couldn't read file: %1. + + + + + + Couldn't save file: %1. + + + + + Your changes will be lost when reloading it! + + + + + The file "%1" was modified by another program. Do you want to reload it?%2 + + + + + SqlTextEdit + + + Ctrl+/ + + + + + SqlUiLexer + + + (X) The abs(X) function returns the absolute value of the numeric argument X. + + + + + () The changes() function returns the number of database rows that were changed or inserted or deleted by the most recently completed INSERT, DELETE, or UPDATE statement. + + + + + (X1,X2,...) The char(X1,X2,...,XN) function returns a string composed of characters having the unicode code point values of integers X1 through XN, respectively. + + + + + (X,Y,...) The coalesce() function returns a copy of its first non-NULL argument, or NULL if all arguments are NULL + + + + + (X,Y) The glob(X,Y) function is equivalent to the expression "Y GLOB X". + + + + + (X,Y) The ifnull() function returns a copy of its first non-NULL argument, or NULL if both arguments are NULL. + + + + + (X,Y) The instr(X,Y) function finds the first occurrence of string Y within string X and returns the number of prior characters plus 1, or 0 if Y is nowhere found within X. + + + + + (X) The hex() function interprets its argument as a BLOB and returns a string which is the upper-case hexadecimal rendering of the content of that blob. + + + + + () The last_insert_rowid() function returns the ROWID of the last row insert from the database connection which invoked the function. + + + + + (X) For a string value X, the length(X) function returns the number of characters (not bytes) in X prior to the first NUL character. + + + + + (X,Y) The like() function is used to implement the "Y LIKE X" expression. + + + + + (X,Y,Z) The like() function is used to implement the "Y LIKE X ESCAPE Z" expression. + + + + + (X) The load_extension(X) function loads SQLite extensions out of the shared library file named X. +Use of this function must be authorized from Preferences. + + + + + (X,Y) The load_extension(X) function loads SQLite extensions out of the shared library file named X using the entry point Y. +Use of this function must be authorized from Preferences. + + + + + (X) The lower(X) function returns a copy of string X with all ASCII characters converted to lower case. + + + + + (X) ltrim(X) removes spaces from the left side of X. + + + + + (X,Y) The ltrim(X,Y) function returns a string formed by removing any and all characters that appear in Y from the left side of X. + + + + + (X,Y,...) The multi-argument max() function returns the argument with the maximum value, or return NULL if any argument is NULL. + + + + + (X,Y,...) The multi-argument min() function returns the argument with the minimum value. + + + + + (X,Y) The nullif(X,Y) function returns its first argument if the arguments are different and NULL if the arguments are the same. + + + + + (FORMAT,...) The printf(FORMAT,...) SQL function works like the sqlite3_mprintf() C-language function and the printf() function from the standard C library. + + + + + (X) The quote(X) function returns the text of an SQL literal which is the value of its argument suitable for inclusion into an SQL statement. + + + + + () The random() function returns a pseudo-random integer between -9223372036854775808 and +9223372036854775807. + + + + + (N) The randomblob(N) function return an N-byte blob containing pseudo-random bytes. + + + + + (X,Y,Z) The replace(X,Y,Z) function returns a string formed by substituting string Z for every occurrence of string Y in string X. + + + + + (X) The round(X) function returns a floating-point value X rounded to zero digits to the right of the decimal point. + + + + + (X,Y) The round(X,Y) function returns a floating-point value X rounded to Y digits to the right of the decimal point. + + + + + (X) rtrim(X) removes spaces from the right side of X. + + + + + (X,Y) The rtrim(X,Y) function returns a string formed by removing any and all characters that appear in Y from the right side of X. + + + + + (X) The soundex(X) function returns a string that is the soundex encoding of the string X. + + + + + (X,Y) substr(X,Y) returns all characters through the end of the string X beginning with the Y-th. + + + + + (X,Y,Z) The substr(X,Y,Z) function returns a substring of input string X that begins with the Y-th character and which is Z characters long. + + + + + () The total_changes() function returns the number of row changes caused by INSERT, UPDATE or DELETE statements since the current database connection was opened. + + + + + (X) trim(X) removes spaces from both ends of X. + + + + + (X,Y) The trim(X,Y) function returns a string formed by removing any and all characters that appear in Y from both ends of X. + + + + + (X) The typeof(X) function returns a string that indicates the datatype of the expression X. + + + + + (X) The unicode(X) function returns the numeric unicode code point corresponding to the first character of the string X. + + + + + (X) The upper(X) function returns a copy of input string X in which all lower-case ASCII characters are converted to their upper-case equivalent. + + + + + (N) The zeroblob(N) function returns a BLOB consisting of N bytes of 0x00. + + + + + + + + (timestring,modifier,modifier,...) + + + + + (format,timestring,modifier,modifier,...) + + + + + (X) The avg() function returns the average value of all non-NULL X within a group. + + + + + (X) The count(X) function returns a count of the number of times that X is not NULL in a group. + + + + + (X) The group_concat() function returns a string which is the concatenation of all non-NULL values of X. + + + + + (X,Y) The group_concat() function returns a string which is the concatenation of all non-NULL values of X. If parameter Y is present then it is used as the separator between instances of X. + + + + + (X) The max() aggregate function returns the maximum value of all values in the group. + + + + + (X) The min() aggregate function returns the minimum non-NULL value of all values in the group. + + + + + + (X) The sum() and total() aggregate functions return sum of all non-NULL values in the group. + + + + + () The number of the row within the current partition. Rows are numbered starting from 1 in the order defined by the ORDER BY clause in the window definition, or in arbitrary order otherwise. + + + + + () The row_number() of the first peer in each group - the rank of the current row with gaps. If there is no ORDER BY clause, then all rows are considered peers and this function always returns 1. + + + + + () The number of the current row's peer group within its partition - the rank of the current row without gaps. Partitions are numbered starting from 1 in the order defined by the ORDER BY clause in the window definition. If there is no ORDER BY clause, then all rows are considered peers and this function always returns 1. + + + + + () Despite the name, this function always returns a value between 0.0 and 1.0 equal to (rank - 1)/(partition-rows - 1), where rank is the value returned by built-in window function rank() and partition-rows is the total number of rows in the partition. If the partition contains only one row, this function returns 0.0. + + + + + () The cumulative distribution. Calculated as row-number/partition-rows, where row-number is the value returned by row_number() for the last peer in the group and partition-rows the number of rows in the partition. + + + + + (N) Argument N is handled as an integer. This function divides the partition into N groups as evenly as possible and assigns an integer between 1 and N to each group, in the order defined by the ORDER BY clause, or in arbitrary order otherwise. If necessary, larger groups occur first. This function returns the integer value assigned to the group that the current row is a part of. + + + + + (expr) Returns the result of evaluating expression expr against the previous row in the partition. Or, if there is no previous row (because the current row is the first), NULL. + + + + + (expr,offset) If the offset argument is provided, then it must be a non-negative integer. In this case the value returned is the result of evaluating expr against the row offset rows before the current row within the partition. If offset is 0, then expr is evaluated against the current row. If there is no row offset rows before the current row, NULL is returned. + + + + + + (expr,offset,default) If default is also provided, then it is returned instead of NULL if the row identified by offset does not exist. + + + + + (expr) Returns the result of evaluating expression expr against the next row in the partition. Or, if there is no next row (because the current row is the last), NULL. + + + + + (expr,offset) If the offset argument is provided, then it must be a non-negative integer. In this case the value returned is the result of evaluating expr against the row offset rows after the current row within the partition. If offset is 0, then expr is evaluated against the current row. If there is no row offset rows after the current row, NULL is returned. + + + + + (expr) This built-in window function calculates the window frame for each row in the same way as an aggregate window function. It returns the value of expr evaluated against the first row in the window frame for each row. + + + + + (expr) This built-in window function calculates the window frame for each row in the same way as an aggregate window function. It returns the value of expr evaluated against the last row in the window frame for each row. + + + + + (expr,N) This built-in window function calculates the window frame for each row in the same way as an aggregate window function. It returns the value of expr evaluated against the row N of the window frame. Rows are numbered within the window frame starting from 1 in the order defined by the ORDER BY clause if one is present, or in arbitrary order otherwise. If there is no Nth row in the partition, then NULL is returned. + + + + + SqliteTableModel + + + reading rows + + + + + loading... + + + + + References %1(%2) +Hold %3Shift and click to jump there + + + + + Error changing data: +%1 + + + + + retrieving list of columns + + + + + Fetching data... + + + + + + Cancel + + + + + TableBrowser + + + Browse Data + + + + + &Table: + + + + + Select a table to browse data + + + + + Use this list to select a table to be displayed in the database view + + + + + This is the database table view. You can do the following actions: + - Start writing for editing inline the value. + - Double-click any record to edit its contents in the cell editor window. + - Alt+Del for deleting the cell content to NULL. + - Ctrl+" for duplicating the current record. + - Ctrl+' for copying the value from the cell above. + - Standard selection and copy/paste operations. + + + + + Text pattern to find considering the checks in this frame + + + + + Find in table + + + + + Find previous match [Shift+F3] + + + + + Find previous match with wrapping + + + + + Shift+F3 + + + + + Find next match [Enter, F3] + + + + + Find next match with wrapping + + + + + F3 + + + + + The found pattern must match in letter case + + + + + Case Sensitive + + + + + The found pattern must be a whole word + + + + + Whole Cell + + + + + Interpret search pattern as a regular expression + + + + + <html><head/><body><p>When checked, the pattern to find is interpreted as a UNIX regular expression. See <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>.</p></body></html> + + + + + Regular Expression + + + + + + Close Find Bar + + + + + Text to replace with + + + + + Replace with + + + + + Replace next match + + + + + + Replace + + + + + Replace all matches + + + + + Replace all + + + + + <html><head/><body><p>Scroll to the beginning</p></body></html> + + + + + <html><head/><body><p>Clicking this button navigates to the beginning in the table view above.</p></body></html> + + + + + |< + + + + + Scroll one page upwards + + + + + <html><head/><body><p>Clicking this button navigates one page of records upwards in the table view above.</p></body></html> + + + + + < + + + + + 0 - 0 of 0 + + + + + Scroll one page downwards + + + + + <html><head/><body><p>Clicking this button navigates one page of records downwards in the table view above.</p></body></html> + + + + + > + + + + + Scroll to the end + + + + + <html><head/><body><p>Clicking this button navigates up to the end in the table view above.</p></body></html> + + + + + >| + + + + + <html><head/><body><p>Click here to jump to the specified record</p></body></html> + + + + + <html><head/><body><p>This button is used to navigate to the record number specified in the Go to area.</p></body></html> + + + + + Go to: + + + + + Enter record number to browse + + + + + Type a record number in this area and click the Go to: button to display the record in the database view + + + + + 1 + + + + + Show rowid column + + + + + Toggle the visibility of the rowid column + + + + + Unlock view editing + + + + + This unlocks the current view for editing. However, you will need appropriate triggers for editing. + + + + + Edit display format + + + + + Edit the display format of the data in this column + + + + + + New Record + + + + + + Insert a new record in the current table + + + + + <html><head/><body><p>This button creates a new record in the database. Hold the mouse button to open a pop-up menu of different options:</p><ul><li><span style=" font-weight:600;">New Record</span>: insert a new record with default values in the database.</li><li><span style=" font-weight:600;">Insert Values...</span>: open a dialog for entering values before they are inserted in the database. This allows to enter values acomplishing the different constraints. This dialog is also open if the <span style=" font-weight:600;">New Record</span> option fails due to these constraints.</li></ul></body></html> + + + + + + Delete Record + + + + + Delete the current record + + + + + + This button deletes the record or records currently selected in the table + + + + + + Insert new record using default values in browsed table + + + + + Insert Values... + + + + + + Open a dialog for inserting values in a new record + + + + + Export to &CSV + + + + + + Export the filtered data to CSV + + + + + This button exports the data of the browsed table as currently displayed (after filters, display formats and order column) as a CSV file. + + + + + Save as &view + + + + + + Save the current filter, sort column and display formats as a view + + + + + This button saves the current setting of the browsed table (filters, display formats and order column) as an SQL view that you can later browse or use in SQL statements. + + + + + Save Table As... + + + + + + Save the table as currently displayed + + + + + <html><head/><body><p>This popup menu provides the following options applying to the currently browsed and filtered table:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Export to CSV: this option exports the data of the browsed table as currently displayed (after filters, display formats and order column) to a CSV file.</li><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Save as view: this option saves the current setting of the browsed table (filters, display formats and order column) as an SQL view that you can later browse or use in SQL statements.</li></ul></body></html> + + + + + Hide column(s) + + + + + Hide selected column(s) + + + + + Show all columns + + + + + Show all columns that were hidden + + + + + + Set encoding + + + + + Change the encoding of the text in the table cells + + + + + Set encoding for all tables + + + + + Change the default encoding assumed for all tables in the database + + + + + Clear Filters + + + + + Clear all filters + + + + + + This button clears all the filters set in the header input fields for the currently browsed table. + + + + + Clear Sorting + + + + + Reset the order of rows to the default + + + + + + This button clears the sorting columns specified for the currently browsed table and returns to the default order. + + + + + Print + + + + + Print currently browsed table data + + + + + Print currently browsed table data. Print selection if more than one cell is selected. + + + + + Ctrl+P + + + + + Refresh + + + + + Refresh the data in the selected table + + + + + This button refreshes the data in the currently selected table. + + + + + F5 + + + + + Find in cells + + + + + Open the find tool bar which allows you to search for values in the table view below. + + + + + + Bold + + + + + Ctrl+B + + + + + + Italic + + + + + + Underline + + + + + Ctrl+U + + + + + + Align Right + + + + + + Align Left + + + + + + Center Horizontally + + + + + + Justify + + + + + + Edit Conditional Formats... + + + + + Edit conditional formats for the current column + + + + + Clear Format + + + + + Clear All Formats + + + + + + Clear all cell formatting from selected cells and all conditional formats from selected columns + + + + + + Font Color + + + + + + Background Color + + + + + Toggle Format Toolbar + + + + + Show/hide format toolbar + + + + + + This button shows or hides the formatting toolbar of the Data Browser + + + + + Select column + + + + + Ctrl+Space + + + + + Replace text in cells + + + + + Filter in any column + + + + + Ctrl+R + + + + + %n row(s) + + %n row + %n rows + + + + + , %n column(s) + + , %n column + , %n columns + + + + + . Sum: %1; Average: %2; Min: %3; Max: %4 + + + + + Conditional formats for "%1" + + + + + determining row count... + + + + + %1 - %2 of >= %3 + + + + + %1 - %2 of %3 + + + + + Please enter a pseudo-primary key in order to enable editing on this view. This should be the name of a unique column in the view. + + + + + Delete Records + + + + + Duplicate records + + + + + Duplicate record + + + + + Ctrl+" + + + + + Adjust rows to contents + + + + + Error deleting record: +%1 + + + + + Please select a record first + + + + + There is no filter set for this table. View will not be created. + + + + + Please choose a new encoding for all tables. + + + + + Please choose a new encoding for this table. + + + + + %1 +Leave the field empty for using the database encoding. + + + + + This encoding is either not valid or not supported. + + + + + %1 replacement(s) made. + + + + + VacuumDialog + + + Compact Database + + + + + Warning: Compacting the database will commit all of your changes. + + + + + Please select the databases to co&mpact: + + + + diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/translations/sqlb_es_ES.qm b/src/WBCLFZSystemModule/SqliteDBProcess/src/translations/sqlb_es_ES.qm new file mode 100644 index 0000000000000000000000000000000000000000..cf849f0b8d23685df3964d62cab301bde618cb74 GIT binary patch literal 252959 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 + + + + AboutDialog + + + About DB Browser for SQLite + Acerca de «DB Browser for SQLite» + + + + Version + Versión + + + + <html><head/><body><p>DB Browser for SQLite is an open source, freeware visual tool used to create, design and edit SQLite database files.</p><p>It is bi-licensed under the Mozilla Public License Version 2, as well as the GNU General Public License Version 3 or later. You can modify or redistribute it under the conditions of these licenses.</p><p>See <a href="http://www.gnu.org/licenses/gpl.html">http://www.gnu.org/licenses/gpl.html</a> and <a href="https://www.mozilla.org/MPL/2.0/index.txt">https://www.mozilla.org/MPL/2.0/index.txt</a> for details.</p><p>For more information on this program please visit our website at: <a href="http://sqlitebrowser.org">http://sqlitebrowser.org</a></p><p><span style=" font-size:small;">This software uses the GPL/LGPL Qt Toolkit from </span><a href="http://qt-project.org/"><span style=" font-size:small;">http://qt-project.org/</span></a><span style=" font-size:small;"><br/>See </span><a href="http://qt-project.org/doc/qt-5/licensing.html"><span style=" font-size:small;">http://qt-project.org/doc/qt-5/licensing.html</span></a><span style=" font-size:small;"> for licensing terms and information.</span></p><p><span style=" font-size:small;">It also uses the Silk icon set by Mark James licensed under a Creative Commons Attribution 2.5 and 3.0 license.<br/>See </span><a href="http://www.famfamfam.com/lab/icons/silk/"><span style=" font-size:small;">http://www.famfamfam.com/lab/icons/silk/</span></a><span style=" font-size:small;"> for details.</span></p></body></html> + <html><head/><body><p>«DB Browser for SQLite» es una herramienta visual, libre y de fuente abierta usada para crear, diseñar y editar archivos de bases de datos SQLite.</p><p>Está licenciada dualmente con la Mozilla Public License Versión 2, y con la GNU General Public License Versión 3 o posterior. Puede modificarla o redistribuirla bajo las condiciones de estas licencias.</p><p>Vea <a href="http://www.gnu.org/licenses/gpl.html">http://www.gnu.org/licenses/gpl.html</a> y <a href="https://www.mozilla.org/MPL/2.0/index.txt">https://www.mozilla.org/MPL/2.0/index.txt</a> para más detalles.</p><p>Para más información sobre este programa visite nuestra página web: <a href="http://sqlitebrowser.org">http://sqlitebrowser.org</a></p><p><span style=" font-size:small;">Esta aplicación utiliza GPL/LGPL Qt Toolkit de </span><a href="http://qt-project.org/"><span style=" font-size:small;">http://qt-project.org/</span></a><span style=" font-size:small;"><br/>Vea </span><a href="http://qt-project.org/doc/qt-5/licensing.html"><span style=" font-size:small;">http://qt-project.org/doc/qt-5/licensing.html</span></a><span style=" font-size:small;"> para los términos de licencia e información.</span></p><p><span style=" font-size:small;">Además utiliza el conjunto de iconos Silk de Mark James licenciado bajo la licencia Creative Commons Attribution 2.5 y 3.0.<br/>Vea </span><a href="http://www.famfamfam.com/lab/icons/silk/"><span style=" font-size:small;">http://www.famfamfam.com/lab/icons/silk/</span></a><span style=" font-size:small;"> para los detalles.</span></p></body></html> + + + + AddRecordDialog + + + Add New Record + Añadir nuevo registro + + + + Enter values for the new record considering constraints. Fields in bold are mandatory. + Introduzca valores para el nuevo registro teniendo en cuenta las restricciones. Los campos en negrita son obligatorios. + + + + In the Value column you can specify the value for the field identified in the Name column. The Type column indicates the type of the field. Default values are displayed in the same style as NULL values. + En la columna Valor puede especificar el valor del campo identificado en la columna Nombre. La columna Tipo indica el tipo de campo. Los valores por defecto se muestran en la misma tipografía que los valores NULL. + + + + Name + Nombre + + + + Type + Tipo + + + + Value + Valor + + + + Values to insert. Pre-filled default values are inserted automatically unless they are changed. + Valores a insertar. Los valores mostrados por defecto son insertados automáticamente a menos que se cambien. + + + + When you edit the values in the upper frame, the SQL query for inserting this new record is shown here. You can edit manually the query before saving. + Cuando se editan los valores en el cuadro superior, aquí se muestra la consulta SQL para insertar este nuevo registro. Puede editarla antes de guardar. + + + + <html><head/><body><p><span style=" font-weight:600;">Save</span> will submit the shown SQL statement to the database for inserting the new record.</p><p><span style=" font-weight:600;">Restore Defaults</span> will restore the initial values in the <span style=" font-weight:600;">Value</span> column.</p><p><span style=" font-weight:600;">Cancel</span> will close this dialog without executing the query.</p></body></html> + <html><head/><body><p><span style=" font-weight:600;">Guardar</span> enviará a la base de datos la sentencia SQL mostrada para insertar el nuevo registro.</p><p><span style=" font-weight:600;">Restituir valores por Defecto</span> restituirá los valores iniciales en la columna <span style=" font-weight:600;">Valor</span></p><p><span style=" font-weight:600;">Cancelar</span> cierra este diálogo sin ejecutar la consulta.</p></body></html> + + + + Auto-increment + + Auto-incremento + + + + + Unique constraint + + Restricción UNIQUE + + + + + Check constraint: %1 + + Restricción CHECK: %1 + + + + + Foreign key: %1 + + Clave foránea: %1 + + + + + Default value: %1 + + Valor por defecto: %1 + + + + + Error adding record. Message from database engine: + +%1 + Error añadiendo registro. Mensaje de la base de datos: + +%1 + + + + Are you sure you want to restore all the entered values to their defaults? + ¿Está seguro de que quiere restaurar todos los valores introducidos a sus valores por defecto? + + + + Application + + + Possible command line arguments: + Argumentos de línea de comandos disponibles: + + + + The -o/--option and -O/--save-option options require an argument in the form group/setting=value + Las opciones -o/--option y -O/--save-option requieren un argumento de la forma grupo/ajuste=valor + + + + Usage: %1 [options] [<database>|<project>] + + Uso: %1 [opciones] [<base de datos>|<proyecto>] + + + + + -h, --help Show command line options + -h, --help Mostrar opciones de línea de comandos + + + + -q, --quit Exit application after running scripts + -q, --quit Salir de la aplicación tras ejecutar los scripts + + + + -s, --sql <file> Execute this SQL file after opening the DB + -s, --sql <archivo> Ejecuta este archivo de SQL tras abrir la base de datos + + + + -t, --table <table> Browse this table after opening the DB + -t, --table <tabla> Mostrar esta tabla en la hoja de datos tras abrir la base de datos + + + + -R, --read-only Open database in read-only mode + -R, --read-only Abrir base de datos en modo de solo-lectura + + + + -o, --option <group>/<setting>=<value> + -o, --option <grupo>/<ajuste>=<valor> + + + + Run application with this setting temporarily set to value + Ejecutar la aplicación con este ajuste establecido temporalmente a este valor + + + + -O, --save-option <group>/<setting>=<value> + -O, --save-option <grupo>/<ajuste>=<valor> + + + + Run application saving this value for this setting + Ejecutar la aplicación guardando este valor para este ajuste + + + + -v, --version Display the current version + -v, --version Mostrar la versión actual + + + + <database> Open this SQLite database + <base de datos> Abrir esta base de datos SQLite + + + + <project> Open this project file (*.sqbpro) + <proyecto> Abrir este archivo de proyecto (*.sqbpro) + + + + The -s/--sql option requires an argument + La opción -s/--sql necesita un argumento + + + + The file %1 does not exist + El archivo %1 no existe + + + + The -t/--table option requires an argument + La opción -t/--table necesita un argumento + + + + SQLite Version + Versión de SQLite + + + + SQLCipher Version %1 (based on SQLite %2) + Versión de SQLCipher %1 (basado en SQLite %2) + + + + DB Browser for SQLite Version %1. + «DB Browser for SQLite» Versión %1. + + + + Built for %1, running on %2 + Compilado para %1, ejecutándose en %2 + + + + Qt Version %1 + Versión de Qt %1 + + + + Invalid option/non-existant file: %1 + Opción inválida o archivo inexistente: %1 + + + + CipherDialog + + + SQLCipher encryption + Cifrado con SQLCipher + + + + &Password + &Clave + + + + &Reenter password + &Reintroducir clave + + + + Encr&yption settings + Ajustes de &cifrado + + + + SQLCipher &3 defaults + Predeterminados de SQLCipher &3 + + + + SQLCipher &4 defaults + Predeterminados de SQLCipher &4 + + + + Custo&m + &Personalizado + + + + Page si&ze + &Tamaño de página + + + + &KDF iterations + Iteraciones &KDF + + + + HMAC algorithm + Algoritmo HMAC + + + + KDF algorithm + Algoritmo KDF + + + + Plaintext Header Size + Tamaño de la cabecera del texto en claro + + + + Passphrase + Frase de contraseña + + + + Raw key + Clave en bruto + + + + Please set a key to encrypt the database. +Note that if you change any of the other, optional, settings you'll need to re-enter them as well every time you open the database file. +Leave the password fields empty to disable the encryption. +The encryption process might take some time and you should have a backup copy of your database! Unsaved changes are applied before modifying the encryption. + Por favor, elija una clave para cifrar la base de datos. +Tenga en cuenta que: +- Si modifica cualquiera de los otros ajustes opcionales necesitará + reintroducirlos también cada vez que abra la base de datos. +- Puede dejar los campos de clave en blanco para no usar cifrado. +- El proceso de cifrado puede llevar algún tiempo. +- ¡Debería hacer una copia de respaldo de la base de datos! +- Los cambios no guardados son aplicados antes de modificar el cifrado. + + + + Please enter the key used to encrypt the database. +If any of the other settings were altered for this database file you need to provide this information as well. + Por favor, introduzca la clave a usar en el cifrado de la base de datos. +Si se modificaron cualquiera de los otros ajustes para este archivo de base de datos, también tendrá que proporcionar esta información. + + + + ColumnDisplayFormatDialog + + + Choose display format + Elija el formato de presentación + + + + Display format + Formato de presentación + + + + Choose a display format for the column '%1' which is applied to each value prior to showing it. + Elija el formato para la columna «%1» el cual se aplicará a cada valor antes de mostrarlo. + + + + Default + Por defecto + + + + Decimal number + Número decimal + + + + Exponent notation + Notación exponencial + + + + Hex blob + Secuencia hexadecimal + + + + Hex number + Número hexadecimal + + + + Apple NSDate to date + Fecha de Apple NSDate a fecha + + + + Java epoch (milliseconds) to date + Tiempo Java (milisegundos) a fecha + + + + .NET DateTime.Ticks to date + DateTime.Ticks de .NET a fecha + + + + Julian day to date + Fecha juliana a fecha + + + + Unix epoch to local time + Tiempo Unix a hora local + + + + Date as dd/mm/yyyy + Fecha dd/mm/aaaa + + + + Lower case + Minúsculas + + + + Custom display format must contain a function call applied to %1 + El formato de presentación a medida tiene que contener una llamada de función aplicada a %1 + + + + Error in custom display format. Message from database engine: + +%1 + Error en el formato de presentación a medida. Mensaje del motor de la base de datos: + +%1 + + + + Custom display format must return only one column but it returned %1. + El formato de presentación a medida debe devolver sólo una columna pero ha devuelto %1. + + + + Octal number + Número octal + + + + Round number + Número redondeado + + + + Unix epoch to date + Tiempo Unix a fecha + + + + Upper case + Mayúsculas + + + + Windows DATE to date + Fecha Windows a fecha + + + + Custom + A medida + + + + CondFormatManager + + + Conditional Format Manager + Gestor de Formato Condicional + + + + This dialog allows creating and editing conditional formats. Each cell style will be selected by the first accomplished condition for that cell data. Conditional formats can be moved up and down, where those at higher rows take precedence over those at lower. Syntax for conditions is the same as for filters and an empty condition applies to all values. + Este diálogo permite crear y editar formatos condicionales. Cada estilo de celda será seleccionado por la primera condición que se cumpla para los datos de esa celda. Los formatos condicionales se pueden mover arriba y abajo, teniendo precedencia aquellos en líneas superiores sobre los inferiores. La sintaxis es la misma que para los filtros y se aplica una condición vacía a todos los valores. + + + + Add new conditional format + Añadir un nuevo formato condicional + + + + &Add + &Añadir + + + + Remove selected conditional format + Elimina el formato condicional seleccionado + + + + &Remove + &Eliminar + + + + Move selected conditional format up + Mueve arriba el formato condicional seleccionado + + + + Move &up + Mueve a&rriba + + + + Move selected conditional format down + Mueve abajo el formato condicional seleccionado + + + + Move &down + Mueve a&bajo + + + + Foreground + Texto + + + + Text color + Color del texto + + + + Background + Fondo + + + + Background color + Color del fondo + + + + Font + Tipo de letra + + + + Size + Tamaño + + + + Bold + Negrita + + + + Italic + Cursiva + + + + Underline + Subrayado + + + + Alignment + Justificado + + + + Condition + Condición + + + + + Click to select color + Haga clic para seleccionar el color + + + + Are you sure you want to clear all the conditional formats of this field? + ¿Está seguro de que quiere borrar todos los formatos condicionales de este campo? + + + + DBBrowserDB + + + Please specify the database name under which you want to access the attached database + Por favor, especifique el nombre con el que acceder a la base de datos anexada + + + + Invalid file format + Formato de archivo inválido + + + + Do you want to save the changes made to the database file %1? + ¿Guardar los cambios hechos al archivo de base de datos «%1»? + + + + Exporting database to SQL file... + Exportando base de datos a un archivo SQL... + + + + + Cancel + Cancelar + + + + Executing SQL... + Ejecutando SQL... + + + + Action cancelled. + Acción cancelada. + + + + This database has already been attached. Its schema name is '%1'. + Esta base de datos ya ha sido anexada. Su nombre de esquema es «%1». + + + + Do you really want to close this temporary database? All data will be lost. + ¿Está seguro de que quiere cerrar esta base de datos temporal? Todos los datos se perderán. + + + + Database didn't close correctly, probably still busy + La base de datos no se ha cerrado correctamente, probablemente todavía está ocupada + + + + The database is currently busy: + La base de datos está actualmente ocupada: + + + + Do you want to abort that other operation? + ¿Desea abortar la otra operación? + + + + + No database file opened + No hay una base de datos abierta + + + + + Error in statement #%1: %2. +Aborting execution%3. + Error en la sentencia #%1: %2. +Abortando ejecución%3. + + + + + and rolling back + y deshaciendo cambios + + + + didn't receive any output from %1 + no se recibió ninguna salida de «%1» + + + + could not execute command: %1 + no se pudo ejecutar el comando: «%1» + + + + Cannot delete this object + No se puede borrar este objeto + + + + Cannot set data on this object + No se pueden poner datos en este objeto + + + + + A table with the name '%1' already exists in schema '%2'. + Una tabla con el nombre «%1» ya existe en el esquema «%2». + + + + No table with name '%1' exists in schema '%2'. + No existe una tabla con el nombre «%1» en el esquema «%2». + + + + + Cannot find column %1. + No se puede encontrar la columna %1. + + + + Creating savepoint failed. DB says: %1 + Creación del punto de guardado fallido. La base de datos dice: %1 + + + + Renaming the column failed. DB says: +%1 + Renombrado de la columna fallido. La base de datos dice: +%1 + + + + + Releasing savepoint failed. DB says: %1 + Liberación del punto de guardado fallido. La base de datos dice: %1 + + + + Creating new table failed. DB says: %1 + Creación de la nueva tabla fallida. La base de datos dice: %1 + + + + Copying data to new table failed. DB says: +%1 + Copia de datos a la nueva table fallida. La base de datos dice: +%1 + + + + Deleting old table failed. DB says: %1 + Borrado de tabla fallido. La base de datos dice: %1 + + + + Error renaming table '%1' to '%2'. +Message from database engine: +%3 + Error renombrando la tabla «%1» a «%2». +Mensaje de la base de datos: +%3 + + + + could not get list of db objects: %1 + No se pudo obtener la lista de objetos de la base de datos: %1 + + + + Restoring some of the objects associated with this table failed. This is most likely because some column names changed. Here's the SQL statement which you might want to fix and execute manually: + + + La restitución de algunos de los objetos asociados con esta tabla ha fallado. Lo más probable es que esto suceda porque los nombres de algunas columnas han cambiado. Esta es la sentencia SQL que puede que quiera corregir y ejecutar manualmente: + + + + + + could not get list of databases: %1 + no se pudo obtener lista de bases de datos: %1 + + + + Error loading extension: %1 + Error cargando la extensión: %1 + + + + could not get column information + No se pudo obtener información de la columna + + + + Error setting pragma %1 to %2: %3 + Error definiendo pragma %1 como %2: %3 + + + + File not found. + Archivo no encontrado. + + + + DbStructureModel + + + Name + Nombre + + + + Object + Objeto + + + + Type + Tipo + + + + Schema + Esquema + + + + Database + Base de datos + + + + Browsables + Navegables + + + + All + Todos + + + + Temporary + Temporal + + + + Tables (%1) + Tablas (%1) + + + + Indices (%1) + Ãndices (%1) + + + + Views (%1) + Vistas (%1) + + + + Triggers (%1) + Disparadores (%1) + + + + EditDialog + + + Edit database cell + Editar celda de la base de datos + + + + Mode: + Modo: + + + + This is the list of supported modes for the cell editor. Choose a mode for viewing or editing the data of the current cell. + Esta es la lista de modos admitidos en el editor de celdas. Elija un modo para visualizar o editar los datos de la celda actual. + + + + RTL Text + Texto RTL + + + + + Image + Imagen + + + + JSON + JSON + + + + XML + XML + + + + + Automatically adjust the editor mode to the loaded data type + Ajustar automáticamente el modo de edición al tipo de datos cargados + + + + This checkable button enables or disables the automatic switching of the editor mode. When a new cell is selected or new data is imported and the automatic switching is enabled, the mode adjusts to the detected data type. You can then change the editor mode manually. If you want to keep this manually switched mode while moving through the cells, switch the button off. + Esta casilla activa o desactiva el cambio automático del modo de edición. Cuando se selecciona una nueva celda o se importan nuevos datos y la selección automática está activada, el modo de edición se ajusta al tipo de datos detectados. El modo de edición para la celda se puede cambiar manualmente. Si prefiere mantener el modo de edición seleccionado manualmente mientras se mueve por las celdas, desmarque la casilla. + + + + Auto-switch + Auto-selección + + + + The text editor modes let you edit plain text, as well as JSON or XML data with syntax highlighting, automatic formatting and validation before saving. + +Errors are indicated with a red squiggle underline. + Los modos de edición de texto permiten editar texto plano, y también JSON o XML con resaltado de sintaxis, formato automático y validación previa a guardar. + +Los errores se indican con un subrayado ondulado en rojo. + + + + This Qt editor is used for right-to-left scripts, which are not supported by the default Text editor. The presence of right-to-left characters is detected and this editor mode is automatically selected. + Este editor Qt se usa para scripts de derecha-a-izquierda, que no están soportados por el editor de Texto por defecto. Al detectar la presencia de caracteres de derecha-a-izquierda este modo de edición se activa automáticamente. + + + + Open preview dialog for printing the data currently stored in the cell + Abrir diálogo de previsualización para imprimir los datos actualmente almacenados en la celda + + + + Auto-format: pretty print on loading, compact on saving. + Auto-formato: dar formato al cargar, compactar al guardar. + + + + When enabled, the auto-format feature formats the data on loading, breaking the text in lines and indenting it for maximum readability. On data saving, the auto-format feature compacts the data removing end of lines, and unnecessary whitespace. + Si se habilita, la opción de auto-formato da formato a los datos al cargarlos, rompiendo y sangrando las líneas de texto para una legibilidad máxima. Al guardar los datos, esta opción los compacta, eliminando fines de línea y espacio en blanco innecesario. + + + + Word Wrap + Ajuste del Texto + + + + Wrap lines on word boundaries + Ajustar las líneas en palabras completas + + + + + Open in default application or browser + Abrir en la aplicacion por defecto o navegador + + + + Open in application + Abrir en una aplicacion + + + + The value is interpreted as a file or URL and opened in the default application or web browser. + El valor es interpretado como un nombre de archivo o URL y abierto en la aplicación por defecto del sistema o el navegador de internet. + + + + Save file reference... + Guardar referencia de archivo... + + + + Save reference to file + Guardar referencia a archivo + + + + + Open in external application + Abrir en una aplicación externa + + + + Autoformat + Auto-formato + + + + &Export... + &Exportar... + + + + + &Import... + &Importar... + + + + + Import from file + Importar desde archivo + + + + + Opens a file dialog used to import any kind of data to this database cell. + Abre un diálogo para elegir el archivo para importar cualquier tipo de datos a esta celda. + + + + Export to file + Exportar a archivo + + + + Opens a file dialog used to export the contents of this database cell to a file. + Abre un diálogo para elegir el archivo al que exportar el contenido de esta celda de la base de datos. + + + + + Print... + Imprimir... + + + + Open preview dialog for printing displayed image + Abre un diálogo de previsualización para imprimir la imagen mostrada + + + + + Ctrl+P + + + + + Open preview dialog for printing displayed text + Abre un diálogo de previsualización para imprimir el texto mostrado + + + + Copy Hex and ASCII + Copiar hex. y ASCII + + + + Copy selected hexadecimal and ASCII columns to the clipboard + Copia las columnas seleccionadas en hexadecimal y ASCII al portapapeles + + + + Ctrl+Shift+C + + + + + Set as &NULL + Borrar a &NULL + + + + Apply data to cell + Aplicar los datos a la celda + + + + This button saves the changes performed in the cell editor to the database cell. + Este botón guarda los cambios realizados en el editor a la celda de la base de datos. + + + + Apply + Aplicar + + + + Text + Texto + + + + Binary + Binario + + + + Erases the contents of the cell + Borra el contenido de la celda + + + + This area displays information about the data present in this database cell + Esta zona muestra información acerca de los datos presentes en esta celda de la base de datos + + + + Type of data currently in cell + Tipo de datos actualmente en la celda + + + + Size of data currently in table + Tamaño de los datos actualmente en la tabla + + + + Choose a filename to export data + Seleccione un nombre de archivo para exportar los datos + + + + + Image data can't be viewed in this mode. + Datos de imagen no se puede visualizar en este modo. + + + + + Try switching to Image or Binary mode. + Intente cambiando al modo «Imagen» o «Binario». + + + + + Binary data can't be viewed in this mode. + Datos binarios no se puede visualizar en este modo. + + + + + Try switching to Binary mode. + Intente cambiando al modo «Binario». + + + + + Image files (%1) + Archivos de imagen (%1) + + + + Binary files (*.bin) + Archivos binarios (*.bin) + + + + Choose a file to import + Seleccione el archivo a importar + + + + %1 Image + %1 Imagen + + + + Invalid data for this mode + Datos inválidos para este modo + + + + The cell contains invalid %1 data. Reason: %2. Do you really want to apply it to the cell? + La celda contiene datos de tipo %1 inválidos. Razón: «%2». ¿Realmente desea aplicarlos a la celda? + + + + Type of data currently in cell: %1 Image + El tipo de datos en la celda es: Imagen %1 + + + + %1x%2 pixel(s) + %1×%2 píxel(s) + + + + Type of data currently in cell: NULL + El tipo de datos en la celda es: NULL + + + + Type of data currently in cell: Valid JSON + Tipo de datos actualmente en la celda: JSON válido + + + + Couldn't save file: %1. + No se pudo guardar el archivo: %1. + + + + The data has been saved to a temporary file and has been opened with the default application. You can now edit the file and, when you are ready, apply the saved new data to the cell editor or cancel any changes. + Los datos se han guardado en un archivo temporal y se ha abierto con la aplicación por defecto. Ahora puede editar ese archivo y cuado termine puede aplicar los nuevos datos guardados a la celda o cancelar los cambios. + + + + + Type of data currently in cell: Text / Numeric + Tipo de datos actualmente en la celda: Texto / Numérico + + + + + + %n character(s) + + %n carácter + %n caracteres + + + + + Type of data currently in cell: Binary + Tipo de datos actualmente en la celda: Binario + + + + + %n byte(s) + + %n byte + %n bytes + + + + + EditIndexDialog + + + &Name + &Nombre + + + + Order + Orden + + + + &Table + &Tabla + + + + Edit Index Schema + Editar índice del esquema + + + + &Unique + &Único + + + + For restricting the index to only a part of the table you can specify a WHERE clause here that selects the part of the table that should be indexed + Para restringir el índice exclusivamente a una parte de la tabla hay que especificar aquí una cláusula WHERE que seleccione la parte de la tabla que será indexada + + + + Partial inde&x clause + Cláusula para inde&xado parcial + + + + Colu&mns + Colu&mnas + + + + Table column + Columna de la tabla + + + + Type + Tipo + + + + Add a new expression column to the index. Expression columns contain SQL expression rather than column names. + Añade una nueva columna computada al índice. Las columnas computadas contienen una expresión SQL en lugar de nombres de columna. + + + + Index column + Columna de índice + + + + Deleting the old index failed: +%1 + Borrado del índice previo fallido: +%1 + + + + Creating the index failed: +%1 + Creación de índice fallida: +%1 + + + + EditTableDialog + + + Edit table definition + Editar la definición de la tabla + + + + Table + Tabla + + + + Advanced + Avanzado + + + + Make this a 'WITHOUT rowid' table. Setting this flag requires a field of type INTEGER with the primary key flag set and the auto increment flag unset. + Hacer de esta una tabla «SIN rowid». Para activar este flag es necesario un campo de tipo ENTERO con la clave primaria activada y el indicador de autoincremento desactivado. + + + + Without Rowid + Sin Rowid + + + + Fields + Campos + + + + Database sche&ma + Esque&ma de la base de datos + + + + Add + Añadir + + + + Remove + Eliminar + + + + Move to top + Mover al principio + + + + Move up + Mover hacia arriba + + + + Move down + Mover hacia abajo + + + + Move to bottom + Mover al final + + + + + Name + Nombre + + + + + Type + Tipo + + + + NN + NN + + + + Not null + No nulo + + + + PK + PK + + + + Primary key + Clave primaria + + + + AI + AI + + + + Autoincrement + Autoincremento + + + + U + U + + + + + + Unique + Único + + + + Default + Por defecto + + + + Default value + Valor por defecto + + + + + + Check + Check + + + + Check constraint + Restricción de «check» + + + + Collation + Comparación + + + + + + Foreign Key + Clave foránea + + + + Constraints + Restricciones + + + + Add constraint + Añadir restricción + + + + Remove constraint + Eliminar restricción + + + + Columns + Columnas + + + + SQL + SQL + + + + <html><head/><body><p><span style=" font-weight:600; color:#ff0000;">Warning: </span>There is something with this table definition that our parser doesn't fully understand. Modifying and saving this table might result in problems.</p></body></html> + <html><head/><body><p><span style=" font-weight:600; color:#ff0000;">Aviso: </span>algo ocurre con la definición de esta tabla que nuestro intérprete no entiende completamente. Modificar y guardar esta tabla podría traer problemas.</p></body></html> + + + + + Primary Key + Clave Primaria + + + + Add a primary key constraint + Añadir una restricción de clave primaria + + + + Add a foreign key constraint + Añadir una restricción de clave foránea + + + + Add a unique constraint + Añadir una restricción de único" + + + + Add a check constraint + Añadir una restricción de «check» + + + + Error creating table. Message from database engine: +%1 + Error creando la tabla. Mensaje de la base de datos: +%1 + + + + There already is a field with that name. Please rename it first or choose a different name for this field. + Ya hay un campo con este nombre. Por favor, renómbrelo antes o elija un nombre diferente para este campo. + + + + + There can only be one primary key for each table. Please modify the existing primary key instead. + Sólo puede existir una clave primaria en cada tabla. Por favor, modifique la clave primaria existente. + + + + This column is referenced in a foreign key in table %1 and thus its name cannot be changed. + Esta columna está referenciada en una clave foránea en la tabla %1 y por tanto no se le puede cambiar el nombre. + + + + There is at least one row with this field set to NULL. This makes it impossible to set this flag. Please change the table data first. + Hay al menos una línea con este campo NULO. Esto hace imposible activar este flag. Por favor, modifique antes los datos de la tabla. + + + + There is at least one row with a non-integer value in this field. This makes it impossible to set the AI flag. Please change the table data first. + Hay al menos una línea con un valor no entero en este campo. Esto hace imposible activar el flag AI. Por favor, modifique antes los datos de la tabla. + + + + Column '%1' has duplicate data. + + La columna «%1» tiene datos duplicados. + + + + + This makes it impossible to enable the 'Unique' flag. Please remove the duplicate data, which will allow the 'Unique' flag to then be enabled. + Como en otros textos, pasamos los términos estándar de SQL a mayúsculas para evitar traducirlos, lo que podría ser más confuso para el usuario experto y no tener beneficio para el inexperto. + Esto imposibilita la habilitación de la restricción UNIQUE. Por favor, elimine primero los datos duplicados, lo cual permitirá habilitar la restricción UNIQUE. + + + + Are you sure you want to delete the field '%1'? +All data currently stored in this field will be lost. + ¿Está seguro de que quiere borrar este campo «%1»? +Todos los datos actualmente almacenados en este campo se perderán. + + + + Please add a field which meets the following criteria before setting the without rowid flag: + - Primary key flag set + - Auto increment disabled + Por favor añada un campo que cumpla las siguientes condiciones antes de activar el indicador «sin rowid»: + - Indicador de clave primaria activado + - Indicador de autoincremento desactivado + + + + ExportDataDialog + + + Export data as CSV + Exportar datos como CSV + + + + Tab&le(s) + Tab&la(s) + + + + Colu&mn names in first line + Nombres de las &columnas en la primera línea + + + + Fie&ld separator + &Separador de campos + + + + , + , + + + + ; + ; + + + + Tab + Tab + + + + | + | + + + + + + Other + Otro + + + + &Quote character + &Entrecomillado + + + + " + " + + + + ' + ' + + + + New line characters + Caracteres de nueva línea + + + + Windows: CR+LF (\r\n) + Windows: CR+LF (\r\n) + + + + Unix: LF (\n) + Unix: LF (\n) + + + + Pretty print + Impresión formateada + + + + + Could not open output file: %1 + No se puede abrir el archivo de salida: %1 + + + + + Choose a filename to export data + Seleccione un nombre de archivo para exportar los datos + + + + Export data as JSON + Exportar datos como JSON + + + + exporting CSV + exportando CSV + + + + exporting JSON + exportando JSON + + + + Please select at least 1 table. + Por favor, seleccione al menos 1 tabla. + + + + Choose a directory + Seleccione una carpeta + + + + Export completed. + Exportación completada. + + + + ExportSqlDialog + + + Export SQL... + Exportar SQL... + + + + Tab&le(s) + Tab&la(s) + + + + Select All + Seleccionar Todo + + + + Deselect All + Deseleccionar Todo + + + + &Options + &Opciones + + + + Keep column names in INSERT INTO + Mantener el nombre de la columna en INSERT INTO + + + + Multiple rows (VALUES) per INSERT statement + Múltiples líneas (VALUES) en cada sentencia INSERT + + + + Export everything + Exportar todo + + + + Export data only + Exportar solo los datos + + + + Keep old schema (CREATE TABLE IF NOT EXISTS) + Mantener esquema previo (CREATE TABLE IF NOT EXISTS) + + + + Overwrite old schema (DROP TABLE, then CREATE TABLE) + Sobrescribir esquema previo (DROP TABLE, después CREATE TABLE) + + + + Export schema only + Exportar solo el esquema + + + + Please select at least one table. + Por favor, seleccione al menos una tabla. + + + + Choose a filename to export + Seleccione un nombre de archivo al que exportar + + + + Export completed. + Exportación completada. + + + + Export cancelled or failed. + Exportación cancelada o fallida. + + + + ExtendedScintilla + + + + Ctrl+H + + + + + Ctrl+F + + + + + + Ctrl+P + + + + + Find... + Buscar... + + + + Find and Replace... + Buscar y reemplazar... + + + + Print... + Imprimir... + + + + ExtendedTableWidget + + + Use as Exact Filter + Usar como filtro exacto + + + + Containing + Conteniendo + + + + Not containing + Que no contenga + + + + Not equal to + No igual a + + + + Greater than + Mayor que + + + + Less than + Menor que + + + + Greater or equal + Mayor o igual + + + + Less or equal + Menor o igual + + + + Between this and... + Entre esto y... + + + + Regular expression + Expresión regular + + + + Edit Conditional Formats... + Editar formatos condicionales... + + + + Set to NULL + Poner a NULL + + + + Copy + Copiar + + + + Copy with Headers + Copiar con cabeceras + + + + Copy as SQL + Copiar como SQL + + + + Paste + Pegar + + + + Print... + Imprimir... + + + + Use in Filter Expression + Usar en expresión de filtro + + + + Alt+Del + + + + + Ctrl+Shift+C + + + + + Ctrl+Alt+C + + + + + <p>Not all data has been loaded. <b>Do you want to load all data before selecting all the rows?</b><p><p>Answering <b>No</b> means that no more data will be loaded and the selection will not be performed.<br/>Answering <b>Yes</b> might take some time while the data is loaded but the selection will be complete.</p>Warning: Loading all the data might require a great amount of memory for big tables. + <p>No se han cargado todos los datos. <b>¿Quiere cargar todos los datos antes de seleccionar todas las filas?</b><p><p>Responder <b>No</b> significa que no se cargarán mas datos y la selección no se se realizará.<br/>Responder <b>Sí</b> puede tardar un tiempo mientras los datos se cargan pero la selección se realizará en su totalidad.</p>Precaución: Cargar todos los datos puede necesitar una gran cantidad de memoria para tablas grandes. + + + + Cannot set selection to NULL. Column %1 has a NOT NULL constraint. + No se puede ajustar la selección a NULL. La columna %1 tiene una restricción NOT NULL. + + + + The content of the clipboard is bigger than the range selected. +Do you want to insert it anyway? + El contenido del portapapeles es mayor que el rango seleccionado. +¿Quiere insertarlo de todos modos? + + + + FileExtensionManager + + + File Extension Manager + Gestor de extensiones de archivos + + + + &Up + &Subir + + + + &Down + &Bajar + + + + &Add + &Añadir + + + + &Remove + &Eliminar + + + + + Description + Descripción + + + + Extensions + Extensiones + + + + *.extension + *.extensión + + + + FilterLineEdit + + + Filter + Filtro + + + + These input fields allow you to perform quick filters in the currently selected table. +By default, the rows containing the input text are filtered out. +The following operators are also supported: +% Wildcard +> Greater than +< Less than +>= Equal to or greater +<= Equal to or less += Equal to: exact match +<> Unequal: exact inverse match +x~y Range: values between x and y +/regexp/ Values matching the regular expression + Estos campos de texto permiten realizar filtros rápidos sobre la tabla actualmente seleccionada. +Por defecto, las filas que contengan el texto introducido se muestran. +Los siguientes operadores también se admiten: +% Comodín +> Mayor que +< Menor que +>= Igual o mayor que +<= Igual o menor que += Igual a: correspondencia exacta +<> Distinto: correspondencia inversa exacta +x~y Rango: valores entre x e y + + + + Clear All Conditional Formats + Eliminar todos los formatos condicionales + + + + Use for Conditional Format + Usar para formato condicional + + + + Edit Conditional Formats... + Editar formatos condicionales... + + + + Set Filter Expression + Establecer expresión de filtro + + + + What's This? + ¿Qué es esto? + + + + Is NULL + Es nulo + + + + Is not NULL + No es nulo + + + + Is empty + Es vacío + + + + Is not empty + No es vacío + + + + Not containing... + No contiene... + + + + Equal to... + Igual a... + + + + Not equal to... + No igual a... + + + + Greater than... + Mayor que... + + + + Less than... + Menor que... + + + + Greater or equal... + Mayor o igual... + + + + Less or equal... + Menor o igual... + + + + In range... + En el rango... + + + + Regular expression... + Expresión regular... + + + + FindReplaceDialog + + + Find and Replace + Buscar y reemplazar + + + + Fi&nd text: + &Buscar texto: + + + + Re&place with: + &Reemplazar con: + + + + Match &exact case + Distinguir &mayús. y minús. + + + + Match &only whole words + &Solo palabras completas + + + + When enabled, the search continues from the other end when it reaches one end of the page + Si se habilita, la búsqueda continua desde el otro extremo cuando llega a un extremo de la página + + + + &Wrap around + &Dar la vuelta + + + + When set, the search goes backwards from cursor position, otherwise it goes forward + Si se marca, la búsqueda va hacia atrás desde la posición del cursor. De lo contrario va hacia adelante + + + + Search &backwards + Buscar hacia &atrás + + + + <html><head/><body><p>When checked, the pattern to find is searched only in the current selection.</p></body></html> + <html><head/><body><p>Si se marca, el patrón de búsqueda se limita a buscar sólo en la selección.</p></body></html> + + + + &Selection only + En la &selección + + + + <html><head/><body><p>When checked, the pattern to find is interpreted as a UNIX regular expression. See <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>.</p></body></html> + <html><head/><body><p>Si se marca, el patrón de búsqueda se interpreta como una expresión regular UNIX. Véase <a href="https://es.wikipedia.org/wiki/Expresi%C3%B3n_regular">«Expresión regular» en Wikipedia</a>.</p></body></html> + + + + Use regular e&xpressions + Usar e&xpresiones regulares + + + + Find the next occurrence from the cursor position and in the direction set by "Search backwards" + Encontrar la siguiente ocurrencia desde la posición del cursor y en la dirección definida por «Buscar hacia atrás» + + + + &Find Next + Buscar &siguiente + + + + F3 + + + + + &Replace + R&eemplazar + + + + Highlight all the occurrences of the text in the page + Resaltar todas las ocurrencias del texto en la página + + + + F&ind All + Encontrar &todo + + + + Replace all the occurrences of the text in the page + Reemplazar todas las ocurrencias del texto en la página + + + + Replace &All + Reem&plazar todo + + + + The searched text was not found + El texto buscado no fue encontrado + + + + The searched text was not found. + El texto buscado no fue encontrado. + + + + The searched text was found one time. + El texto buscado fue encontrado una vez. + + + + The searched text was found %1 times. + El texto buscado fue encontrado %1 veces. + + + + The searched text was replaced one time. + El texto buscado fue reemplazado una vez. + + + + The searched text was replaced %1 times. + El texto buscado fue reemplazado %1 veces. + + + + ForeignKeyEditor + + + &Reset + &Reiniciar + + + + Foreign key clauses (ON UPDATE, ON DELETE etc.) + Cláusulas de clave foránea (ON UPDATE, ON DELETE etc.) + + + + ImportCsvDialog + + + Import CSV file + Importar archivo CSV + + + + Table na&me + &Nombre de la tabla + + + + &Column names in first line + Nombres de &columna en la primera línea + + + + Field &separator + &Separador de campos + + + + , + , + + + + ; + ; + + + + + Tab + Tab + + + + | + | + + + + Other + Otro + + + + &Quote character + &Entrecomillado + + + + + Other (printable) + Otro (imprimible) + + + + + Other (code) + Otro (código) + + + + " + " + + + + ' + ' + + + + &Encoding + &Codificación + + + + UTF-8 + UTF-8 + + + + UTF-16 + UTF-16 + + + + ISO-8859-1 + ISO-8859-1 + + + + Trim fields? + ¿Recortar campos? + + + + Separate tables + Tablas separadas + + + + Advanced + Avanzado + + + + When importing an empty value from the CSV file into an existing table with a default value for this column, that default value is inserted. Activate this option to insert an empty value instead. + Cuando se importe un valor vacío desde el archivo CSV a una tabla existente con un valor por defecto para la columna, ese valor por defecto es insertado. Active esta opción si, por el contrario, desea insertar un valor vacío para esta columna. + + + + Ignore default &values + Ignorar &valores por defecto + + + + Activate this option to stop the import when trying to import an empty value into a NOT NULL column without a default value. + Active esta opción para para la importación cuando se intente importar un valor vacío a una columna NOT NULL sin un valor por defecto. + + + + Fail on missing values + Fallar cuando falten valores + + + + Disable data type detection + Deshabilitar detección de tipo + + + + Disable the automatic data type detection when creating a new table. + Deshabilitar la detección automática de tipo cuando se esté creando una nueva tabla. + + + + When importing into an existing table with a primary key, unique constraints or a unique index there is a chance for a conflict. This option allows you to select a strategy for that case: By default the import is aborted and rolled back but you can also choose to ignore and not import conflicting rows or to replace the existing row in the table. + Cuando se importa a una tabla existente con una clave primaria, restricciones de único o un índice de único, existe la posibilidad de que se genere un conflicto. Esta opción le permite elegir la estrategia en esos casos: Por defecto la importación se aborta y se deshacen los cambios pero también puede elegir ignorar y no importar las filas conflictivas o reemplazar las filas existentes en la tabla. + + + + Abort import + Abortar importación + + + + Ignore row + Ignorar fila + + + + Replace existing row + Reemplazar la fila existente + + + + Conflict strategy + Estrategia para conflictos + + + + + Deselect All + Deseleccionar Todo + + + + Match Similar + Emparejar Similares + + + + Select All + Seleccionar Todo + + + + There is already a table named '%1' and an import into an existing table is only possible if the number of columns match. + Ya existe una tabla con nombre «%1» y una importación a una tabla existente solo es posible si el número de columnas coincide. + + + + There is already a table named '%1'. Do you want to import the data into it? + Ya existe una tabla con nombre «%1». ¿Desea importar los datos cargándolos en ella? + + + + Creating restore point failed: %1 + Creación del punto de restauración fallido: %1 + + + + Creating the table failed: %1 + Creación de la tabla fallido: %1 + + + + importing CSV + importando CSV + + + + Importing the file '%1' took %2ms. Of this %3ms were spent in the row function. + Importar el archivo «%1» tardó %2ms. De ellos, %3ms se gastaron en la función fila. + + + + Inserting row failed: %1 + Inserción de línea fallido: %1 + + + + MainWindow + + + DB Browser for SQLite + DB Browser for SQLite + + + + toolBar1 + toolBar1 + + + + This button clears the contents of the SQL logs + Este botón limpia el contenido del historial SQL + + + + This panel lets you examine a log of all SQL commands issued by the application or by yourself + Este panel le permite examinar el histórico de todos los comandos SQL ordenados por la aplicación o por usted mismo + + + + + Project Toolbar + Barra de herramientas de proyectos + + + + Extra DB toolbar + Barra de herramientas extra + + + + + + Close the current database file + Cierra el archivo de base de datos actual + + + + This button closes the connection to the currently open database file + Este botón cierra la conexión con el archivo de base de datos actualmente abierto + + + + Ctrl+F4 + + + + + Compact &Database... + Compactar base de &datos... + + + + &About + &Acerca de + + + + This button opens a new tab for the SQL editor + Este botón abre una nueva pestaña para el editor SQL + + + + Execute all/selected SQL + Ejecuta todo el SQL (o la selección) + + + + This button executes the currently selected SQL statements. If no text is selected, all SQL statements are executed. + Este botón ejecuta las sentencias SQL actualmente seleccionadas. Si no hay ningún texto seleccionado, se ejecutan todas las sentencias. + + + + &Load Extension... + &Cargar extensión... + + + + Execute line + Ejecutar línea + + + + This button executes the SQL statement present in the current editor line + Este botón ejecuta la sentencia SQL presente en la línea actual del editor + + + + &Wiki + &Wiki + + + + F1 + + + + + Bug &Report... + &Informar de fallos... + + + + Feature Re&quest... + Solicitud de &mejoras... + + + + Web&site + &Sitio web + + + + &Donate on Patreon... + &Donar en Patreon... + + + + Open &Project... + Abrir &proyecto... + + + + &Attach Database... + Ane&xar base de datos... + + + + + Add another database file to the current database connection + Añade un archivo de base de datos adicional a la conexión actual + + + + This button lets you add another database file to the current database connection + Este botón le permite añadir otro archivo de base de datos a la conexión de base de datos actual + + + + &Set Encryption... + &Establecer cifrado... + + + + This button saves the content of the current SQL editor tab to a file + Este botón guarda el contenido de la pestaña actual del editor SQL a un archivo + + + + SQLCipher &FAQ + SQLCipher &FAQ + + + + Find + Buscar + + + + Find or replace + Buscar o reemplazar + + + + Ctrl+H + + + + + Open SQL file(s) + Abrir archivo(s) SQL + + + + This button opens files containing SQL statements and loads them in new editor tabs + Este botón abre archivos que contengan sentencias SQL y los carga en pestañas nuevas del editor + + + + This button lets you save all the settings associated to the open DB to a DB Browser for SQLite project file + Este botón le permite guardar todos los ajustes asociados a la base de datos abierta a un archivo de proyecto de «DB Browser for SQLite» + + + + This button lets you open a DB Browser for SQLite project file + Este botón le permite abrir un archivo de proyecto «DB Browser for SQLite» + + + + New In-&Memory Database + Nueva base de datos en &memoria + + + + Drag && Drop Qualified Names + Arrastrar y soltar nombres calificados + + + + + Use qualified names (e.g. "Table"."Field") when dragging the objects and dropping them into the editor + Usa nombres calificados (p.ej. "Tabla"."Campo") al arrastrar los objetos y soltarlos en el editor + + + + Drag && Drop Enquoted Names + Arrastrar y soltar nombres entrecomillados + + + + + Use escaped identifiers (e.g. "Table1") when dragging the objects and dropping them into the editor + Usa identificadores escapados (p.ej. "Tabla1") al arrastrar los objetos y soltarlos en el editor + + + + &Integrity Check + Comprobar &integridad + + + + Runs the integrity_check pragma over the opened database and returns the results in the Execute SQL tab. This pragma does an integrity check of the entire database. + Ejecuta el pragma integrity_check en la base de datos abierta y devuelve los resultados en la pestaña Ejecutar SQL. Este pragma realiza una comprobación de integridad de toda la base de datos. + + + + &Foreign-Key Check + Comprobar clave &foránea + + + + Runs the foreign_key_check pragma over the opened database and returns the results in the Execute SQL tab + Ejecuta el pragma foreign_key_check con la base de datos abierta y devuelve los resultados en la pestaña Ejecutar SQL. + + + + &Quick Integrity Check + Comprobar integridad &rápido + + + + Run a quick integrity check over the open DB + Ejecuta una comprobación de integridad rápida en la base de datos abierta + + + + Runs the quick_check pragma over the opened database and returns the results in the Execute SQL tab. This command does most of the checking of PRAGMA integrity_check but runs much faster. + Ejecuta el pragma quick_check en la base de datos abierta y devuelve los resultados en la pestaña Executar SQL. Este comando hace la mayoría de comprobaciones de PRAGMA integrity_check pero se ejecuta mucho más rápido. + + + + &Optimize + &Optimizar + + + + Attempt to optimize the database + Intenta optimizar la base de datos + + + + Runs the optimize pragma over the opened database. This pragma might perform optimizations that will improve the performance of future queries. + Ejecuta el pragma optimize en la base de datos abierta. Este pragma realiza optimizaciones que pueden mejorar el rendimiento de consultas futuras. + + + + + Print + Imprimir + + + + Print text from current SQL editor tab + Imprime el texto de la pestaña actual del editor SQL + + + + Open a dialog for printing the text in the current SQL editor tab + Abre un diálogo para imprimir el texto de la pestaña actual del editor SQL + + + + Print the structure of the opened database + Imprime la estructura de la base de datos abierta + + + + Open a dialog for printing the structure of the opened database + Abre un diálogo para imprimir la estructura de la base de datos abierta + + + + Un/comment block of SQL code + Des/comentar bloque de código SQL + + + + Un/comment block + Des/comentar bloque de código + + + + Comment or uncomment current line or selected block of code + Comenta o descomenta la línea actual o el bloque de código seleccionado + + + + Comment or uncomment the selected lines or the current line, when there is no selection. All the block is toggled according to the first line. + Comenta o descomenta las líneas seleccionadas o la línea actual cuando no hay selección. El estado de todo el bloque es intercambiado en función de la primera línea. + + + + Ctrl+/ + + + + + Stop SQL execution + Detener ejecución de SQL + + + + Stop execution + Detener ejecución + + + + Stop the currently running SQL script + Detener el script SQL que está ejecutándose + + + + &Save Project As... + &Guardar proyecto como... + + + + + + Save the project in a file selected in a dialog + Guarda el proyecto en un archivo seleccionado en una ventana de diálogo + + + + Save A&ll + Guardar &todo + + + + + + Save DB file, project file and opened SQL files + Guarda los archivos de la base de datos, el proyecto y los archivos SQL abiertos + + + + Ctrl+Shift+S + + + + + Browse Table + Navegar Tabla + + + + Shows or hides the Project toolbar. + Muestra u oculta la barra de herramientas de proyecto. + + + + Extra DB Toolbar + Barra de herramientas extra + + + + Export one or more table(s) to a JSON file + Exportar una o más tablas a un archivo JSON + + + + This is the structure of the opened database. +You can drag SQL statements from an object row and drop them into other applications or into another instance of 'DB Browser for SQLite'. + + Esta es la estructura de la base de datos abierta. +Puede arrastrar sentencias SQL desde una fila de objeto y soltarlas en otras aplicaciones o en otra instancia de «DB Browser for SQLite». + + + + + Table(&s) to JSON... + Tabla(&s) a JSON... + + + + Open Data&base Read Only... + Abrir &base de datos como solo lectura... + + + + Ctrl+Shift+O + + + + + Save results + Guardar resultados + + + + Save the results view + Guarda la vista de resultados + + + + This button lets you save the results of the last executed query + Este botón le permite guardar los resultados de la última consulta ejecutada + + + + + Find text in SQL editor + Buscar texto en el editor SQL + + + + This button opens the search bar of the editor + Este botón abre la barra de búsqueda del editor + + + + Ctrl+F + + + + + + Find or replace text in SQL editor + Buscar o reemplazar texto en el editor SQL + + + + This button opens the find/replace dialog for the current editor tab + Este botón abre el diálogo de buscar/reemplazar para la pestaña actual del editor + + + + Export to &CSV + Exportar a &CSV + + + + Save as &view + Guardar como &vista + + + + Save as view + Guardar como vista + + + + Open an existing database file in read only mode + Abre una base de datos existente en modo de solo lectura + + + + &File + &Archivo + + + + &Import + &Importar + + + + &Export + E&xportar + + + + &Edit + &Editar + + + + &View + &Ver + + + + &Help + Ay&uda + + + + &Tools + &Herramientas + + + + DB Toolbar + DB Toolbar + + + + Edit Database &Cell + Editar &celda + + + + Error Log + Registro de errores + + + + DB Sche&ma + Esque&ma + + + + This is the structure of the opened database. +You can drag multiple object names from the Name column and drop them into the SQL editor and you can adjust the properties of the dropped names using the context menu. This would help you in composing SQL statements. +You can drag SQL statements from the Schema column and drop them into the SQL editor or into other applications. + + Esta es la estructura de la base de datos abierta. +Puede arrastrar múltiples objetos de la columna Nombre, soltarlos en el editor SQL y ajustar sus propiedades usando el menú contextual. Esto le ayudará a componer sentencias SQL. +Puede arrastrar sentencias SQL desde la columna Esquema y soltarlas en el editor SQL o en otras aplicaciones. + + + + + &Remote + &Remoto + + + + + Execute SQL + This has to be equal to the tab title in all the main tabs + Ejecutar SQL + + + + + Execute current line + Ejecuta la línea actual + + + + Shift+F5 + + + + + Sa&ve Project + &Guardar proyecto + + + + User + Usuario + + + + Application + Aplicación + + + + &Clear + &Limpiar + + + + &New Database... + &Nueva base de datos... + + + + + Create a new database file + Crea un nuevo archivo de base de datos + + + + This option is used to create a new database file. + Esta opción se usa para crear un nuevo archivo de base de datos. + + + + Ctrl+N + + + + + + &Open Database... + &Abrir base de datos... + + + + + + + + Open an existing database file + Abre un archivo de base de datos + + + + + + This option is used to open an existing database file. + Esta opción se usa para abrir un archivo de base de datos. + + + + Ctrl+O + + + + + &Close Database + &Cerrar base de datos + + + + + Ctrl+W + + + + + Opens the SQLCipher FAQ in a browser window + Abre la FAQ de SQLCipher en una ventana del navegador + + + + + Revert database to last saved state + Deshace los cambios al último estado guardado + + + + This option is used to revert the current database file to its last saved state. All changes made since the last save operation are lost. + Esta opción se usa para deshacer los cambios en la base de datos actual al último estado guardado. Todos los cambios hechos desde la última vez que se guardó se perderán. + + + + + Write changes to the database file + Escribe los cambios al archivo de la base de datos + + + + This option is used to save changes to the database file. + Esta opción se usa para guardar los cambios en el archivo de la base de datos. + + + + Ctrl+S + + + + + Compact the database file, removing space wasted by deleted records + Compacta el archivo de la base de datos eliminando el espacio malgastado por los registros borrados + + + + + Compact the database file, removing space wasted by deleted records. + Compacta el archivo de la base de datos, eliminando el espacio malgastado por los registros borrados. + + + + E&xit + &Salir + + + + Ctrl+Q + + + + + Import data from an .sql dump text file into a new or existing database. + Importa datos de un archivo de texto con un volcado .sql en una base de datos nueva o existente. + + + + This option lets you import data from an .sql dump text file into a new or existing database. SQL dump files can be created on most database engines, including MySQL and PostgreSQL. + Esta opción se usa para importar datos de un archivo de texto con un volcado .sql en una base de datos nueva o existente. Los archivos de volcado SQL se pueden crear en la mayoría de los motores de base de datos, incluyendo MySQL y PostgreSQL. + + + + Open a wizard that lets you import data from a comma separated text file into a database table. + Abre un asistente que le permite importar datos desde un archivo de texto con valores separado por comas a una tabla de una base de datos. + + + + Open a wizard that lets you import data from a comma separated text file into a database table. CSV files can be created on most database and spreadsheet applications. + Abre un asistente que le permite importar datos desde un archivo de texto con valores separado por comas a una tabla de una base de datos. Los archivos CSV se pueden crear en la mayoría de las aplicaciones de bases de datos y hojas de cálculo. + + + + Export a database to a .sql dump text file. + Exporta la base de datos como un volcado .sql a un archivo de texto. + + + + This option lets you export a database to a .sql dump text file. SQL dump files contain all data necessary to recreate the database on most database engines, including MySQL and PostgreSQL. + Esta opción le permite exportar la base de datos como un volcado .sql a un archivo de texto. Los archivos de volcado SQL contienen todos los datos necesarios para recrear la base de datos en la mayoría de los motores de base de datos, incluyendo MySQL y PostgreSQL. + + + + Export a database table as a comma separated text file. + Exporta la base de datos como un archivo de texto con valores separados por comas. + + + + Export a database table as a comma separated text file, ready to be imported into other database or spreadsheet applications. + Exporta la base de datos como un archivo de texto con valores separados por comas, listo para ser importado en otra base de datos o aplicaciones de hoja de cálculo. + + + + Open the Create Table wizard, where it is possible to define the name and fields for a new table in the database + Abre el asistente para Crear una Tabla, donde se puede definir el nombre y los campos de una nueva tabla en la base de datos + + + + + Delete Table + Borrar tabla + + + + Open the Delete Table wizard, where you can select a database table to be dropped. + Abre el asistente para «Borrar tabla», donde se puede seleccionar una tabla de la base de datos para borrar. + + + + Open the Modify Table wizard, where it is possible to rename an existing table. It is also possible to add or delete fields form a table, as well as modify field names and types. + Abre el asistente «Modificar tabla», donde se puede renombrar una tabla existente de la base de datos. También se pueden añadir o borrar campos de la tabla, así como modificar los nombres de los campos y sus tipos. + + + + Open the Create Index wizard, where it is possible to define a new index on an existing database table. + Abre el asistente «Crear índice», donde se puede definir un nuevo índice de una tabla existente de la base de datos. + + + + &Preferences... + &Preferencias... + + + + + Open the preferences window. + Abrir la ventana de preferencias. + + + + &DB Toolbar + &Barra de herramientas + + + + Shows or hides the Database toolbar. + Muestra u oculta la barra de herramientas de la base de datos. + + + + Shift+F1 + + + + + &Recently opened + Archivos &recientes + + + + Open &tab + Abrir &pestaña + + + + Ctrl+T + + + + + + Database Structure + This has to be equal to the tab title in all the main tabs + Estructura + + + + + Browse Data + This has to be equal to the tab title in all the main tabs + Hoja de datos + + + + + Edit Pragmas + This has to be equal to the tab title in all the main tabs + Editar pragmas + + + + Warning: this pragma is not readable and this value has been inferred. Writing the pragma might overwrite a redefined LIKE provided by an SQLite extension. + Aviso: este pragma no es legible y este valor se ha supuesto. Escribir el pragma puede sobreescribir un LIKE redefinido que proporcione una extensión de SQLite. + + + + SQL &Log + Historial de &SQL + + + + Show S&QL submitted by + Mostrar S&QL ejecutado por + + + + &Plot + &Gráfica + + + + &Revert Changes + &Deshacer cambios + + + + &Write Changes + &Guardar cambios + + + + &Database from SQL file... + Base de datos de &archivo SQL... + + + + &Table from CSV file... + &Tabla de archivo CSV... + + + + &Database to SQL file... + &Base de datos a archivo SQL... + + + + &Table(s) as CSV file... + &Tabla(s) a archivo CSV... + + + + &Create Table... + &Crear tabla... + + + + &Delete Table... + &Borrar tabla... + + + + &Modify Table... + &Modificar tabla... + + + + Create &Index... + Crear &índice... + + + + W&hat's This? + ¿&Qué es esto? + + + + &Execute SQL + &Ejecutar SQL + + + + + + Save SQL file + Guardar archivo SQL + + + + Ctrl+E + + + + + Export as CSV file + Exportar como archivo CSV + + + + Export table as comma separated values file + Exportar tabla como archivo de valores separados por comas + + + + + Save the current session to a file + Guarda la sesión actual en un archivo + + + + + Load a working session from a file + Carga una sesión de trabajo de un archivo + + + + + Save SQL file as + Guardar archivo SQL como + + + + &Browse Table + &Mostrar datos + + + + Copy Create statement + Copiar sentencia CREATE + + + + Copy the CREATE statement of the item to the clipboard + Copia la sentencia CREATE del ítem al portapapeles + + + + Ctrl+Return + + + + + Ctrl+L + + + + + + Ctrl+P + + + + + Ctrl+D + + + + + Ctrl+I + + + + + Encrypted + Cifrado + + + + Read only + Solo lectura + + + + Database file is read only. Editing the database is disabled. + El archivo de la base de datos es de solo lectura. La edición de la base de datos está desactivada. + + + + Database encoding + Codificación de la base de datos + + + + Database is encrypted using SQLCipher + La base de datos está cifrada usando SQLCipher + + + + + Choose a database file + Seleccione un archivo de base de datos + + + + + + Choose a filename to save under + Seleccione un nombre de archivo en el que guardar + + + + Error while saving the database file. This means that not all changes to the database were saved. You need to resolve the following error first. + +%1 + Error mientras se guardaba el archivo de la base de datos. Esto significa que no todos lo cambios hechos a la base de datos se han guardado. Antes tiene que solucionar el siguiente error. +%1 + + + + Are you sure you want to undo all changes made to the database file '%1' since the last save? + ¿Está seguro de que quiere deshacer todos los cambios hechos al archivo de la base de datos «%1» desde la última vez que se guardó? + + + + Choose a file to import + Seleccione el archivo a importar + + + + &%1 %2%3 + &%1 %2%3 + + + + (read only) + (sólo lectura) + + + + Open Database or Project + Abrir base de datos o proyecto + + + + Attach Database... + Ane&xar base de datos... + + + + Import CSV file(s)... + Importar archivo(s) CSV... + + + + Select the action to apply to the dropped file(s). <br/>Note: only 'Import' will process more than one file. + + Seleccione la acción a aplicar al archivo. + Seleccione la acción a aplicar a los archivos <br/>Nota: sólo 'Importar' procesará más de un archivo. + + + + + Do you want to save the changes made to SQL tabs in the project file '%1'? + ¿Quiere guardar los cambios hechos a las pestañas SQL en el archivo de proyecto «%1»? + + + + Text files(*.sql *.txt);;All files(*) + Archivos de texto(*.sql *.txt);;Todos los archivos(*) + + + + Do you want to create a new database file to hold the imported data? +If you answer no we will attempt to import the data in the SQL file to the current database. + ¿Quiere crear un nuevo archivo de base de datos donde poner los datos importados? +Si responde no se intentarán importar los datos del archivo SQL en la base de datos actual. + + + + Do you want to save the changes made to the project file '%1'? + ¿Quiere guardar los cambios hechos al archivo de proyecto «%1»? + + + + Edit View %1 + Editar vista %1 + + + + Edit Trigger %1 + Editar disparador %1 + + + + Result: %1 + Resultado: %1 + + + + File %1 already exists. Please choose a different name. + El archivo %1 ya existe. Por favor elija un nombre diferente. + + + + Error importing data: %1 + Error importando datos: %1 + + + + Import completed. + Importación completada. + + + + Delete View + Borrar vista + + + + Modify View + Modificar vista + + + + Delete Trigger + Borrar disparador + + + + Modify Trigger + Modificar disparador + + + + Delete Index + Borrar índice + + + + Modify Index + Modificar índice + + + + Modify Table + Modificar tabla + + + + Opened '%1' in read-only mode from recent file list + Se ha abierto «%1» en modo de sólo lectura desde la lista de archivos recientes + + + + Opened '%1' from recent file list + Se ha abierto «%1» desde la lista de archivos recientes + + + + This action will open a new SQL tab with the following statements for you to edit and run: + Esta acción abrirá una nueva pestaña SQL con las siguientes sentencias para que usted las pueda modificar y ejecutar: + + + + Rename Tab + Renombrar Pestaña + + + + Duplicate Tab + Duplicar Pestaña + + + + Close Tab + Cerrar Pestaña + + + + Opening '%1'... + Abriendo «%1»... + + + + There was an error opening '%1'... + Hubo un error abriendo «%1»... + + + + Value is not a valid URL or filename: %1 + Valor no es un nombre de archivo o URL válido: %1 + + + + Do you want to save the changes made to SQL tabs in a new project file? + ¿Quiere guardar los cambios hechos a las pestañas SQL en un nuevo archivo de proyecto? + + + + Do you want to save the changes made to the SQL file %1? + ¿Quiere guardar los cambios hechos al archivo SQL %1? + + + + The statements in this tab are still executing. Closing the tab will stop the execution. This might leave the database in an inconsistent state. Are you sure you want to close the tab? + Las sentencias en esta pestaña todavía se están ejecutando. Al cerrar la pestaña detendrá la ejecución. Esto puede dejar la base de datos en un estado inconsistente. ¿Está seguro de que quiere cerrar la pestaña? + + + + Could not find resource file: %1 + No se pudo encontrar el archivo de recursos: %1 + + + + Choose a project file to open + Seleccione un archivo de proyecto para abrir + + + + This project file is using an old file format because it was created using DB Browser for SQLite version 3.10 or lower. Loading this file format is still fully supported but we advice you to convert all your project files to the new file format because support for older formats might be dropped at some point in the future. You can convert your files by simply opening and re-saving them. + Este archivo de proyecto está usando un formato antiguo porque fue creado usando una versión 3.10 o inferior de «DB Browser for SQLite». La carga de este archivo aún está completamente soportada pero le recomendamos convertir todos sus archivos de proyecto al nuevo formato porque el soporte de formatos antiguos podría ser descartado en algún momento futuro. Puede convertir sus archivos simplemente abriéndolos y guardándolos de nuevo. + + + + Could not open project file for writing. +Reason: %1 + No se pudo abrir el archivo de proyecto para escritura. +Motivo: %1 + + + + Collation needed! Proceed? + ¡Es necesaria una función de comparación! ¿Proceder? + + + + A table in this database requires a special collation function '%1' that this application can't provide without further knowledge. +If you choose to proceed, be aware bad things can happen to your database. +Create a backup! + Una tabla en esta base de datos necesita una función de comparación especial «%1» que esta aplicación no puede proporcionar sin más información. +Si decide continuar, está avisado de que la base de datos se puede dañar. +¡Cree una copia de respaldo! + + + + Setting PRAGMA values will commit your current transaction. +Are you sure? + Al definir los valores de PRAGMA se consolidará la transacción actual. +¿Está seguro? + + + + Window Layout + Disposición de la ventana + + + + Reset Window Layout + Reiniciar disposición + + + + Alt+0 + + + + + Simplify Window Layout + Simplificar disposición + + + + Shift+Alt+0 + + + + + Dock Windows at Bottom + Acoplar ventanas en la parte inferior + + + + Dock Windows at Left Side + Acoplar ventanas en la parte izquierda + + + + Dock Windows at Top + Acoplar ventanas en la parte superior + + + + The database is currenctly busy. + La base de datos está ocupada + + + + Click here to interrupt the currently running query. + Haga clic aquí para interrumpir la consulta que se está ejecutando + + + + Could not open database file. +Reason: %1 + No se pudo abrir el archivo de base de datos. +Razón: %1 + + + + In-Memory database + Base de datos en memoria + + + + You are still executing SQL statements. Closing the database now will stop their execution, possibly leaving the database in an inconsistent state. Are you sure you want to close the database? + Todavía se están ejecutando sentencias SQL. Al cerrar la base de datos se detendrá la ejecución. Esto puede dejar la base de datos en un estado inconsistente. ¿Está seguro de que quiere cerrar la base de datos? + + + + Are you sure you want to delete the table '%1'? +All data associated with the table will be lost. + ¿Está seguro de que quiere borrar la tabla «%1»? +Se perderán todos los datos asociados con la tabla. + + + + Are you sure you want to delete the view '%1'? + ¿Está seguro de que quiere borrar la vista «%1»? + + + + Are you sure you want to delete the trigger '%1'? + ¿Está seguro de que quiere borrar el disparador «%1»? + + + + Are you sure you want to delete the index '%1'? + ¿Está seguro de que quiere borrar el índice «%1»? + + + + Error: could not delete the table. + Error: no se pudo borrar la tabla. + + + + Error: could not delete the view. + Error: no se pudo borrar la vista. + + + + Error: could not delete the trigger. + Error: no se pudo borrar el disparador. + + + + Error: could not delete the index. + Error: no se pudo borrar el índice. + + + + Message from database engine: +%1 + Mensaje de la base de datos: +%1 + + + + Editing the table requires to save all pending changes now. +Are you sure you want to save the database? + Para editar la tabla es necesario guardar antes todos los cambios pendientes. +¿Está seguro de que quiere guardar la base de datos? + + + + You are already executing SQL statements. Do you want to stop them in order to execute the current statements instead? Note that this might leave the database in an inconsistent state. + Ya se están ejecutando sentencias SQL. ¿Quiere detenerlas para en su lugar ejecutar las sentencias actuales?. Esto puede dejar la base de datos en un estado inconsistente. + + + + -- EXECUTING SELECTION IN '%1' +-- + -- EJECUTANDO SELECCIÓN DE «%1» +-- + + + + -- EXECUTING LINE IN '%1' +-- + -- EJECUTANDO LÃNEA DE «%1» +-- + + + + -- EXECUTING ALL IN '%1' +-- + -- EJECUTANDO TODO «%1» +-- + + + + Setting PRAGMA values or vacuuming will commit your current transaction. +Are you sure? + Establecer valores PRAGMA o realizar una limpieza consolidará la transacción actual. +¿Está seguro? + + + + Busy (%1) + Ocupado (%1) + + + + %1 rows returned in %2ms + %1 filas devueltas en %2ms + + + + Choose text files + Elija archivos de texto + + + + Import completed. Some foreign key constraints are violated. Please fix them before saving. + Importación completada. Algunas restricciones de las claves foráneas se han infringido. Por favor arréglelas antes de guardar. + + + + Select SQL file to open + Seleccione el archivo SQL a abrir + + + + Select file name + Seleccione el nombre del archivo + + + + Select extension file + Seleccione el archivo de extensión + + + + Extension successfully loaded. + Extensiones cargadas con éxito. + + + + Error loading extension: %1 + Error cargando la extensión: %1 + + + + + Don't show again + No volver a mostrar + + + + New version available. + Hay una nueva versión disponible. + + + + A new DB Browser for SQLite version is available (%1.%2.%3).<br/><br/>Please download at <a href='%4'>%4</a>. + Hay disponible una nueva versión de «DB Browser for SQLite» (%1.%2.%3).<br/><br/>Por favor, descárguela de <a href='%4'>%4</a>. + + + + Project saved to file '%1' + Proyecto guardado en el archivo «%1» + + + + creating collation + creando comparación + + + + Set a new name for the SQL tab. Use the '&&' character to allow using the following character as a keyboard shortcut. + Establezca el nuevo nombre para la pestaña SQL. Use el carácter «&&» para permitir usar el carácter siguiente como un atajo de teclado. + + + + Please specify the view name + Por favor, especifique el nombre de la vista + + + + There is already an object with that name. Please choose a different name. + Ya hay un objeto con ese nombre. Por favor, elija un nombre diferente. + + + + View successfully created. + Vista creada con éxito. + + + + Error creating view: %1 + Error creando la vista: %1 + + + + This action will open a new SQL tab for running: + Esta acción abrirá una nueva pestaña SQL para ejecutar: + + + + Press Help for opening the corresponding SQLite reference page. + Pulse Ayuda para abrir la página correspondiente de la referencia de SQLite. + + + + DB Browser for SQLite project file (*.sqbpro) + Archivo de proyecto de «DB Browser for SQLite» (*.sqbpro) + + + + Error checking foreign keys after table modification. The changes will be reverted. + Error comprobando las claves foráneas tras la modificación de la tabla. Los cambios se desharán. + + + + This table did not pass a foreign-key check.<br/>You should run 'Tools | Foreign-Key Check' and fix the reported issues. + Esta tabla no ha pasado la comprobación de claves foráneas.<br/>Debería ejecutar 'Herramientas | Comprobar Claves foráneas' y arreglar los problemas mostrados. + + + + + At line %1: + En la línea %1: + + + + Result: %2 + Resultado: %2 + + + + Execution finished with errors. + Ejecución terminada con errores. + + + + Execution finished without errors. + Ejecución terminada sin errores. + + + + NullLineEdit + + + Set to NULL + Poner a NULL + + + + Alt+Del + + + + + PlotDock + + + Plot + Gráfica + + + + <html><head/><body><p>This pane shows the list of columns of the currently browsed table or the just executed query. You can select the columns that you want to be used as X or Y axis for the plot pane below. The table shows detected axis type that will affect the resulting plot. For the Y axis you can only select numeric columns, but for the X axis you will be able to select:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Date/Time</span>: strings with format &quot;yyyy-MM-dd hh:mm:ss&quot; or &quot;yyyy-MM-ddThh:mm:ss&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Date</span>: strings with format &quot;yyyy-MM-dd&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Time</span>: strings with format &quot;hh:mm:ss&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Label</span>: other string formats. Selecting this column as X axis will produce a Bars plot with the column values as labels for the bars</li><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Numeric</span>: integer or real values</li></ul><p>Double-clicking the Y cells you can change the used color for that graph.</p></body></html> + <html><head/><body><p>Esta tabla muestra la lista de columnas de la tabla actualmente visualizada o de la consulta recién ejecutada. Puede seleccionar las columnas que desea usar como ejes X o Y en el gráfico del panel inferior. La tabla muestra el tipo de eje detectado, el cual afectará al gráfico resultante. Para los ejes Y solo se pueden seleccionar columnas numéricas, pero para el eje X se pueden seleccionar :</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Fecha/Hora</span>: texto con formato &quot;aaaa-MM-dd hh:mm:ss&quot; o &quot;aaaa-MM-ddThh:mm:ss&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Fecha</span>: texto con formato &quot;aaaa-MM-dd&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Time</span>: texto con formato &quot;hh:mm:ss&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Etiqueta</span>: texto con otros formatos. Seleccionado esta columna como eje X se dibuja un gráfico de barras con los valores de la columna usados como etiquetas de las barras.</li><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Numérico</span>: valores reales o enteros</li></ul><p>Haciendo doble clic sobre las celdas Y se puede cambiar el color usado para la gráfica correspondiente.</p></body></html> + + + + Columns + Columnas + + + + X + X + + + + Y1 + + + + + Y2 + + + + + Axis Type + Tipo de eje + + + + Here is a plot drawn when you select the x and y values above. + +Click on points to select them in the plot and in the table. Ctrl+Click for selecting a range of points. + +Use mouse-wheel for zooming and mouse drag for changing the axis range. + +Select the axes or axes labels to drag and zoom only in that orientation. + Aquí se dibuja un gráfico cuando se seleccionan los valores de X e Y en la parte superior. + +Con un clic sobre los puntos se seleccionan en el gráfico y en la tabla. Con Ctrl+Clic se pueden seleccionar rangos de puntos. + +Use la rueda del ratón para aumentar y disminuir el gráfico y arrastre con el ratón para cambiar el rango del eje. + +Seleccione los ejes o sus etiquetas para arrastrar y aumentar/disminuir solo en esa orientación. + + + + Line type: + Tipo de línea: + + + + + None + Ninguno + + + + Line + Línea + + + + StepLeft + EscalónIzquierda + + + + StepRight + EscalónDerecha + + + + StepCenter + EscalónCentrado + + + + Impulse + Impulso + + + + Point shape: + Forma de punto: + + + + Cross + Aspa es más específico que cruz. El signo más también es una cruz (una cruz griega). + Aspa + + + + Plus + Más + + + + Circle + Circunferencia + + + + Disc + Círculo + + + + Square + Cuadrado + + + + Diamond + Diamante + + + + Star + Estrella + + + + Triangle + Triángulo + + + + TriangleInverted + TriánguloInvertido + + + + CrossSquare + AspaCuadrado + + + + PlusSquare + MásCuadrado + + + + CrossCircle + AspaCircunferencia + + + + PlusCircle + MásCircunferencia + + + + Peace + Paz + + + + <html><head/><body><p>Save current plot...</p><p>File format chosen by extension (png, jpg, pdf, bmp)</p></body></html> + <html><head/><body><p>Guarda la gráfica actual...</p><p>El formato del archivo es elegido por la extensión (png, jpg, pdf, bmp)</p></body></html> + + + + Save current plot... + Guarda la gráfica actual... + + + + + Load all data and redraw plot + Cargar todos los datos y redibujar el gráfico + + + + + + Row # + Nº de línea + + + + Copy + Copiar + + + + Print... + Imprimir... + + + + Show legend + Mostrar leyenda + + + + Stacked bars + Barras apiladas + + + + Date/Time + Fecha/hora + + + + Date + Fecha + + + + Time + Tiempo + + + + + Numeric + Numérico + + + + Label + Etiqueta + + + + Invalid + Inválido + + + + Load all data and redraw plot. +Warning: not all data has been fetched from the table yet due to the partial fetch mechanism. + Cargar todos los datos y redibujar el gráfico. +Aviso: aún no se han cargado todos los datos desde la tabla debido al mecanismo de lectura parcial. + + + + Choose an axis color + Elija un color para el eje + + + + Choose a filename to save under + Seleccione un nombre de archivo en el que guardar + + + + PNG(*.png);;JPG(*.jpg);;PDF(*.pdf);;BMP(*.bmp);;All Files(*) + PNG(*.png);;JPG(*.jpg);;PDF(*.pdf);;BMP(*.bmp);;Todos los archivos(*) + + + + There are curves in this plot and the selected line style can only be applied to graphs sorted by X. Either sort the table or query by X to remove curves or select one of the styles supported by curves: None or Line. + Existen lazos en este gráfico y el estilo de línea seleccionado solo se puede aplicar a gráficos ordenados por X. Debe ordenar la tabla o consulta por X para eliminar los lazos o seleccionar uno de los estilos soportados por los lazos: Ninguno o Línea. + + + + Loading all remaining data for this table took %1ms. + Cargar todos los datos restantes para esta tabla tardó %1ms. + + + + PreferencesDialog + + + Preferences + Preferencias + + + + &General + &General + + + + Remember last location + Recordar la última posición + + + + Always use this location + Usar siempre esta posición + + + + Remember last location for session only + Recordar la última posición solamente para esta sesión + + + + + + ... + ... + + + + Default &location + &Posición por defecto + + + + Lan&guage + &Idioma + + + + Automatic &updates + &Actualizaciones automáticas + + + + + + + + + + + + enabled + activado + + + + Show remote options + Mostrar opciones del remoto + + + + &Database + &Base de datos + + + + Database &encoding + Co&dificación de la base de datos + + + + Open databases with foreign keys enabled. + Abrir base de datos con claves foráneas activadas. + + + + &Foreign keys + Claves &foráneas + + + + Data &Browser + &Hoja de datos + + + + Remove line breaks in schema &view + Elimina los saltos de línea en la &vista del esquema + + + + Prefetch block si&ze + &Tamaño del bloque de precarga + + + + SQ&L to execute after opening database + SQ&L a ejecutar tras abrir la base de datos + + + + Default field type + Tipo de campo por defecto + + + + Font + Tipo de letra + + + + &Font + &Tipo de letra + + + + Content + Contenido + + + + Symbol limit in cell + Límite de símbolos en la celda + + + + NULL + NULL + + + + Regular + Normal + + + + Binary + Binario + + + + Background + Fondo + + + + Filters + Filtros + + + + Toolbar style + Estilo de barra de herramientas + + + + + + + + Only display the icon + Solo mostrar el icono + + + + + + + + Only display the text + Solo mostrar el texto + + + + + + + + The text appears beside the icon + El texto aparece junto al icono + + + + + + + + The text appears under the icon + El texto aparece bajo el icono + + + + + + + + Follow the style + Seguir el estilo predefinido + + + + DB file extensions + Extensiones de archivos de BB.DD. + + + + Manage + Gestionar + + + + Main Window + Ventana principal + + + + Database Structure + Estructura + + + + Browse Data + Hoja de datos + + + + Execute SQL + Ejecutar SQL + + + + Edit Database Cell + Editar celda + + + + When this value is changed, all the other color preferences are also set to matching colors. + Cuando se cambia este valor, también se ajustan con colores a juego todas las otras prefencias de color. + + + + Follow the desktop style + Usa el estilo del escritorio + + + + Dark style + Estilo oscuro + + + + Application style + Estilo de la aplicación + + + + This sets the font size for all UI elements which do not have their own font size option. + Esto establece el tamaño de tipografía para todos los elementos de la interfaz de usuario que no tienen su propia opción. + + + + Font size + Tamaño de fuente + + + + When enabled, the line breaks in the Schema column of the DB Structure tab, dock and printed output are removed. + Cuando está activado, se omiten los saltos de línea en la columna Esquema, tanto en la pestaña Estructura en pantalla, como al imprimir. + + + + Database structure font size + Tamaño de fuente de la estructura de base de datos + + + + Font si&ze + &Tamaño de fuente + + + + This is the maximum number of items allowed for some computationally expensive functionalities to be enabled: +Maximum number of rows in a table for enabling the value completion based on current values in the column. +Maximum number of indexes in a selection for calculating sum and average. +Can be set to 0 for disabling the functionalities. + Este es el máximo número ocurrencias permitidos para que algunas funcionalidades computacionalmente costosas sean activadas: +Máximo número de filas en una tabla para activar el autocompletado basado en los valores actuales en la columna. +Máximo número de índices en una selección para calcular la suma y la media. +Pueden ajustarse a 0 parar desactivar las funcionalidades. + + + + This is the maximum number of rows in a table for enabling the value completion based on current values in the column. +Can be set to 0 for disabling completion. + Este el el número máximo de filas en una tabla para activar el autocompletado basado en los valores actuales en la columna. +Se puede poner a 0 para desactivar el autocompletado. + + + + Close button on tabs + Botón de cerrar en pestañas + + + + If enabled, SQL editor tabs will have a close button. In any case, you can use the contextual menu or the keyboard shortcut to close them. + Si se habilita, las pestañas del editor SQL tendrán un botón para cerrarlas. En cualquier caso, usted siempre podrá usar el menú contextual o el atajo de teclado para cerrarlas. + + + + Proxy + Proxy + + + + Configure + Configurar + + + + Field display + Estilo de las celdas + + + + Displayed &text + &Texto presentado + + + + + + + + + Click to set this color + Haga clic para ajustar este color + + + + Text color + Color del texto + + + + Background color + Color del fondo + + + + Preview only (N/A) + Solo vista previa (N/A) + + + + Escape character + Carácter de escape + + + + Delay time (&ms) + Tiempo de retardo (&ms) + + + + Set the waiting time before a new filter value is applied. Can be set to 0 for disabling waiting. + Define el tiempo de espera antes de que se aplique un nuevo valor de filtro. Se puede poner a 0 para desactivar la espera. + + + + &SQL + &SQL + + + + Settings name + Nombre de los ajustes + + + + Context + Contexto + + + + Colour + Color + + + + Bold + Negrita + + + + Italic + Cursiva + + + + Underline + Subrayado + + + + Keyword + Palabra clave + + + + Function + Función + + + + Table + Tabla + + + + Comment + Comentario + + + + Identifier + Identificador + + + + String + Cadena + + + + Current line + Línea actual + + + + SQL &editor font size + Tamaño de letra del &editor SQL + + + + Tab size + Tamaño del tabulador + + + + &Wrap lines + Ajuste de líneas + + + + Never + Nunca + + + + At word boundaries + En los límites de palabra + + + + At character boundaries + En los límites de caracteres + + + + At whitespace boundaries + En los límites de espacios en blanco + + + + &Quotes for identifiers + &Comillas para identificadores + + + + Choose the quoting mechanism used by the application for identifiers in SQL code. + Elija el mecanismo de entrecomillado usado por la aplicación para los identificadores en el código SQL. + + + + "Double quotes" - Standard SQL (recommended) + "Dobles comillas" - SQL estándar (recomendado) + + + + `Grave accents` - Traditional MySQL quotes + `Acentos graves` - Entrecomillado tradicional de MySQL + + + + [Square brackets] - Traditional MS SQL Server quotes + [Corchetes] - Entrecomillado tradicional de MS SQL Server + + + + Keywords in &UPPER CASE + Palabras claves en &MAYÚSCULAS + + + + When set, the SQL keywords are completed in UPPER CASE letters. + Si se activa, las palabras claves de SQL se completan en letras MAYÚSCULAS. + + + + When set, the SQL code lines that caused errors during the last execution are highlighted and the results frame indicates the error in the background + Si se activa, las líneas de código SQL que causaron errores durante la última ejecución se destacan y el marco de resultados indica el error mediante el color del fondo + + + + <html><head/><body><p>SQLite provides an SQL function for loading extensions from a shared library file. Activate this if you want to use the <span style=" font-style:italic;">load_extension()</span> function from SQL code.</p><p>For security reasons, extension loading is turned off by default and must be enabled through this setting. You can always load extensions through the GUI, even though this option is disabled.</p></body></html> + <html><head/><body><p>SQLite proporciona una función SQL para cargar extensiones desde un archivo de biblioteca compartida. Active esta opción si desea usar la función <span style=" font-style:italic;">load_extension()</span> desde código SQL.</p><p>Por razónes de seguridad, la carga de extensiones está desactivada por defecto y debe ser habilitada usando esta configuración. Siempre puede cargar extensiones a través de la interfaz de usuario, incluso aunque esta opción esté deshabilitada.</p></body></html> + + + + Allow loading extensions from SQL code + Permitir cargar extensiones desde código SQL + + + + Remote + Remoto + + + + CA certificates + Certificados CA + + + + + Subject CN + Sujeto CN + + + + Common Name + Nombre común + + + + Subject O + Sujeto O + + + + Organization + Organización + + + + + Valid from + Válido desde + + + + + Valid to + Válido hasta + + + + + Serial number + Número de serie + + + + Your certificates + Sus certificados + + + + File + Archivo + + + + Subject Common Name + Nombre común del sujeto + + + + Issuer CN + Emisor CN + + + + Issuer Common Name + Nombre común del emisor + + + + Clone databases into + Clonar las bases de datos en + + + + SQL editor &font + &Tipo de letra del editor SQL + + + + Error indicators + Indicadores de error + + + + Hori&zontal tiling + Mosaico hori&zontal + + + + If enabled the SQL code editor and the result table view are shown side by side instead of one over the other. + Si se activa, el editor de código SQL y la vista de la tabla de resultados se muestran de lado a lado en lugar de una sobre la otra. + + + + Code co&mpletion + Co&mpletar código + + + + Threshold for completion and calculation on selection + Umbral para cálculos al seleccionar y completación + + + + Show images in cell + Mostrar imágenes en la celda + + + + Enable this option to show a preview of BLOBs containing image data in the cells. This can affect the performance of the data browser, however. + Active esta opción para mostrar una previsualización de los BLOBs que contengan datos de imagen en las celdas. Tenga en cuenta que esto puede afectar el desempeño del navegador de la hoja de datos. + + + + Foreground + Texto + + + + SQL &results font size + Tamaño de letra de resultados + + + + &Extensions + E&xtensiones + + + + Select extensions to load for every database: + Seleccione extensiones a cargar para cada base de datos: + + + + Add extension + Añadir extensión + + + + Remove extension + Eliminar extensión + + + + <html><head/><body><p>While supporting the REGEXP operator SQLite doesn't implement any regular expression<br/>algorithm but calls back the running application. DB Browser for SQLite implements this<br/>algorithm for you to let you use REGEXP out of the box. However, as there are multiple possible<br/>implementations of this and you might want to use another one, you're free to disable the<br/>application's implementation and load your own by using an extension. Requires restart of the application.</p></body></html> + +<html><head/><body><p> +Aunque SQLite admite el operador REGEXP, no implementa en sí ningún algoritmo de expresiones<br/> +regulares sino que llama a los de la aplicación en ejecución. «DB Browser for SQLite» implementa este<br/> +método para permitirle usar REGEXP de fábrica. Sin embargo, como hay múltiples posibles<br/> +implementaciones y puede querer usar otra, puede desactivar este método y cargar el suyo propio<br/> +usando una extensión. Necesitará reiniciar la aplicación.</p> +</body></html> + + + + Disable Regular Expression extension + Desactivar extensión de expresiones regulares + + + + + Choose a directory + Seleccione una carpeta + + + + The language will change after you restart the application. + El idioma cambiará al reiniciar la aplicación. + + + + Select extension file + Seleccione archivo de extensión + + + + Extensions(*.so *.dylib *.dll);;All files(*) + Extensiones (*.so *.dll);;Todos los archivos (*) + + + + Import certificate file + Importar archivo de certificado + + + + No certificates found in this file. + No hay certificados en este archivo. + + + + Are you sure you want do remove this certificate? All certificate data will be deleted from the application settings! + ¿Está seguro de que quiere eliminar este certificado? ¡Todos los datos del certificado se borrarán de los ajustes de la aplicación! + + + + Are you sure you want to clear all the saved settings? +All your preferences will be lost and default values will be used. + ¿Está seguro de que desea borrar todos los ajustes guardadas? +Todas sus preferencias se perderán y se usarán valores predeterminados. + + + + ProxyDialog + + + Proxy Configuration + Configuración del proxy + + + + Pro&xy Type + Tipo de pro&xy + + + + Host Na&me + No&mbre del host + + + + Port + Puerto + + + + Authentication Re&quired + Autentificación re&querida + + + + &User Name + Nombre de &usuario + + + + Password + Contraseña + + + + None + Ninguno + + + + System settings + Ajustes del sistema + + + + HTTP + HTTP + + + + Socks v5 + Socks v5 + + + + QObject + + + Error importing data + Error importando datos + + + + from record number %1 + del registro número %1 + + + + . +%1 + . +%1 + + + + Importing CSV file... + Importando archivo CSV... + + + + Cancel + Cancelar + + + + All files (*) + Todos los archivos (*) + + + + SQLite database files (*.db *.sqlite *.sqlite3 *.db3) + Archivos de BB.DD. SQLite (*.db *.sqlite *.sqlite3 *.db3) + + + + Left + Izquierda + + + + Right + Derecha + + + + Center + Centrado + + + + Justify + Justificado + + + + SQLite Database Files (*.db *.sqlite *.sqlite3 *.db3) + Archivos de BB.DD. SQLite (*.db *.sqlite *.sqlite3 *.db3) + + + + DB Browser for SQLite Project Files (*.sqbpro) + Archivos de proyecto de DB Browser for SQLite (*.sqbpro) + + + + SQL Files (*.sql) + Archivos SQL (*.sql) + + + + All Files (*) + Todos los archivos (*) + + + + Text Files (*.txt) + Archivos de texto (*.txt) + + + + Comma-Separated Values Files (*.csv) + Archivos de valores separados por comas (*.csv) + + + + Tab-Separated Values Files (*.tsv) + Archivos de valores separados por tabuladores (*.tsv) + + + + Delimiter-Separated Values Files (*.dsv) + Archivos de Valores Separados por Delimitador (*.dsv) + + + + Concordance DAT files (*.dat) + Archivos DAT de Concordance (*.dat) + + + + JSON Files (*.json *.js) + Archivos JSON (*.json *.js) + + + + XML Files (*.xml) + Archivos XML (*.xml) + + + + Binary Files (*.bin *.dat) + Archivos binarios (*.bin *.dat) + + + + SVG Files (*.svg) + Archivos SVG (*.svg) + + + + Hex Dump Files (*.dat *.bin) + Archivos de volcado Hex (*.dat *.bin) + + + + Extensions (*.so *.dylib *.dll) + Extensiones (*.so *.dylib *.dll) + + + + RemoteCommitsModel + + + Commit ID + ID versión + + + + Message + Mensaje + + + + Date + Fecha + + + + Author + Autor + + + + Size + Tamaño + + + + Authored and committed by %1 + Escrito y registrado por %1 + + + + Authored by %1, committed by %2 + Escrito por %1, registrado por %2 + + + + RemoteDatabase + + + Error opening local databases list. +%1 + Error abriendo la lista de bases de datos locales. +%1 + + + + Error creating local databases list. +%1 + Error creando la lista de bases de datos locales. +%1 + + + + RemoteDock + + + Remote + Remoto + + + + Local + Local + + + + Identity + Identidad + + + + Push currently opened database to server + Volcar la base de datos actualmente abierta al servidor + + + + DBHub.io + + + + + <html><head/><body><p>In this pane, remote databases from dbhub.io website can be added to DB Browser for SQLite. First you need an identity:</p><ol style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Login to the dbhub.io website (use your GitHub credentials or whatever you want)</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Click the button to &quot;Generate client certificate&quot; (that's your identity). That'll give you a certificate file (save it to your local disk).</li><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Go to the Remote tab in DB Browser for SQLite Preferences. Click the button to add a new certificate to DB Browser for SQLite and choose the just downloaded certificate file.</li></ol><p>Now the Remote panel shows your identity and you can add remote databases.</p></body></html> + <html><head/><body><p>En este panel, las BB.DD. remotas del sitio web dbhub.io se pueden añadir a «DB Browser for SQLite». En primer lugar necesita una identidad:</p><ol style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Ingrese en el sitio web dbhub.io (use sus credenciales de GitHub o las que desee)</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Haga clic en el botón de crear un certificado de cliente (esa es su identidad). Eso le proporcionará un archivo de certificado (guárdelo en su disco local).</li><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Vaya a la pestaña «Remoto» de las preferencias de «DB Browser for SQLite». Haga clic en el botón para añadir el nuevo certificado a la aplicación y elija el archivo de certificado recién descargado.</li></ol><p>Ahora el panel «Remoto» le mostrará su identidad y podrá añadir BB.DD. remotas.</p></body></html> + + + + Current Database + Base de datos actual + + + + Clone + Clonar + + + + User + Usuario + + + + Database + Base de datos + + + + Branch + Rama + + + + Commits + Versiones + + + + Commits for + Versiones para + + + + Delete Database + Borrar base de datos + + + + Delete the local clone of this database + Borrar el clon local de la base de datos + + + + Open in Web Browser + Abrir en el navegador web + + + + Open the web page for the current database in your browser + Abrir la página web de la base de datos actual en su navegador + + + + Clone from Link + Clonar desde enlace + + + + Use this to download a remote database for local editing using a URL as provided on the web page of the database. + Use esto para descargar una base de datos remota y editarla localmente usando una URL provista por la página web de la base de datos. + + + + Refresh + Refrescar + + + + Reload all data and update the views + Recargar todos los datos y actualizar las vistas + + + + F5 + + + + + Clone Database + Clonar base de datos + + + + Open Database + Abrir base de datos + + + + Open the local copy of this database + Abrir la copia local de esta base de datos + + + + Check out Commit + Obtener versión + + + + Download and open this specific commit + Descargar y abrir esta versión específica + + + + Check out Latest Commit + Obtener la última versión + + + + Check out the latest commit of the current branch + Obtener la última versión de la rama actual + + + + Save Revision to File + Guardar versión en un archivo + + + + Saves the selected revision of the database to another file + Guarda la versión seleccionada de la base de datos a otro archivo + + + + Upload Database + Cargar base de datos + + + + Upload this database as a new commit + Cargar en el servidor esta base de datos como una nueva versión + + + + <html><head/><body><p>You are currently using a built-in, read-only identity. For uploading your database, you need to configure and use your DBHub.io account.</p><p>No DBHub.io account yet? <a href="https://dbhub.io/"><span style=" text-decoration: underline; color:#007af4;">Create one now</span></a> and import your certificate <a href="#preferences"><span style=" text-decoration: underline; color:#007af4;">here</span></a> to share your databases.</p><p>For online help visit <a href="https://dbhub.io/about"><span style=" text-decoration: underline; color:#007af4;">here</span></a>.</p></body></html> + <html><head/><body><p>Está usando una identidad integrada de sólo lectura. Para subir su base de datos necesita configurar y usar su cuenta DBHub.io.</p><p>¿Todavía no tiene una cuenta en DBHub.io? <a href="https://dbhub.io/"><span style=" text-decoration: underline; color:#007af4;">Cree una ahora</span></a> e importe su certificado <a href="#preferences"><span style=" text-decoration: underline; color:#007af4;">aquí</span></a> para compartir sus bases de datos.</p><p>Tiene ayuda en línea <a href="https://dbhub.io/about"><span style=" text-decoration: underline; color:#007af4;">aquí</span></a>.</p></body></html> + + + + Back + Retroceder + + + + Select an identity to connect + Seleccione una identidad para conectar + + + + Public + Pública + + + + This downloads a database from a remote server for local editing. +Please enter the URL to clone from. You can generate this URL by +clicking the 'Clone Database in DB4S' button on the web page +of the database. + Esto descarga una base de datos desde un servidor remoto para edición local. +Por favor, introduzca la URL desde la que clonar. Puede obtener esta URL +haciendo clic en el botón «Clonar base de datos en DB4S» de la página web +de la base de datos. + + + + Invalid URL: The host name does not match the host name of the current identity. + URL inválida: El nombre de 'host' no encaja con el de la identidad actual. + + + + Invalid URL: No branch name specified. + URL inválida: No se ha especificado el nombre de rama. + + + + Invalid URL: No commit ID specified. + URL inválida: No se ha especificado el ID de versión. + + + + You have modified the local clone of the database. Fetching this commit overrides these local changes. +Are you sure you want to proceed? + Ha realizado cambios en el clon local de la base de datos. Al obtener esta versión sobreescribiría los cambios locales. +¿Está seguro de querer proceder? + + + + The database has unsaved changes. Are you sure you want to push it before saving? + La base de datos tiene cambios sin guardar. ¿Está seguro de enviarlos sin guardar? + + + + The database you are trying to delete is currently opened. Please close it before deleting. + La base de datos que pretende borrar está actualmente abierta. Por favor, ciérrela antes de borrarla. + + + + This deletes the local version of this database with all the changes you have not committed yet. Are you sure you want to delete this database? + Esto borra la versión local de esta base de datos con todos los cambios que aún no ha registrado. ¿Está seguro de querer borrarla? + + + + RemoteLocalFilesModel + + + Name + Nombre + + + + Branch + Rama + + + + Last modified + Última modificación + + + + Size + Tamaño + + + + Commit + Versión + + + + File + Archivo + + + + RemoteModel + + + Name + Nombre + + + + Last modified + Última modificación + + + + Size + Tamaño + + + + Commit + Versión + + + + Size: + Tamaño: + + + + Last Modified: + Última modificación: + + + + Licence: + Licencia: + + + + Default Branch: + Rama por defecto: + + + + RemoteNetwork + + + Choose a location to save the file + Seleccione una localización para guardar el archivo + + + + Error opening remote file at %1. +%2 + Error abriendo el archivo remoto en %1. +%2 + + + + Error: Invalid client certificate specified. + Error: El certificado del cliente es inválido. + + + + Please enter the passphrase for this client certificate in order to authenticate. + Por favor, introduzca la frase de contraseña de este certificado de cliente para autenticarse. + + + + Cancel + Cancelar + + + + Uploading remote database to +%1 + Subiendo base de datos remota a +%1 + + + + Downloading remote database from +%1 + Descargando base de datos remota desde +%1 + + + + + Error: The network is not accessible. + Error: La red no está accesible. + + + + Error: Cannot open the file for sending. + Error: No se puede abrir el archivo para enviar. + + + + RemotePushDialog + + + Push database + Remitir base de datos + + + + Database na&me to push to + No&mbre de la base de datos de destino + + + + Commit message + Mensaje de versión + + + + Database licence + Licencia de la base de datos + + + + Public + Pública + + + + Branch + Rama + + + + Force push + Forzar remisión + + + + Username + Nombre de usuario + + + + Database will be public. Everyone has read access to it. + La base de datos será pública. Todo el mundo podrá leerla. + + + + Database will be private. Only you have access to it. + La base de datos será privada. Sólo usted tendrá acceso. + + + + Use with care. This can cause remote commits to be deleted. + Usar con cuidado. Esto puede provocar borrados de versiones remotas. + + + + RunSql + + + Execution aborted by user + Ejecución abortada por el usuario + + + + , %1 rows affected + , %1 filas afectadas + + + + query executed successfully. Took %1ms%2 + consulta ejecutada con éxito. Tardó %1ms%2 + + + + executing query + ejecutando consulta + + + + SelectItemsPopup + + + A&vailable + &Disponible + + + + Sele&cted + &Seleccionado + + + + SqlExecutionArea + + + Form + Formulario + + + + Find previous match [Shift+F3] + Buscar la siguiente ocurrencia [Shift+F3] + + + + Find previous match with wrapping + Buscar la siguiente ocurrencia + + + + Shift+F3 + + + + + The found pattern must be a whole word + El patrón de búsqueda debe ser una palabra completa + + + + Whole Words + Palabras completas + + + + Text pattern to find considering the checks in this frame + El patrón de texto buscado considerando las opciones de este marco + + + + Find in editor + Buscar en el editor + + + + The found pattern must match in letter case + El patrón de búsqueda debe coincidir en mayúsculas y minúsculas + + + + Case Sensitive + Distinguir mayús./minús. + + + + Find next match [Enter, F3] + Buscar la siguiente ocurrencia [Enter, F3] + + + + Find next match with wrapping + Encontrar la siguiente ocurrencia volviendo al principio si es necesario + + + + F3 + + + + + Interpret search pattern as a regular expression + Interpretar el patrón de búsqueda como una expresión regular + + + + <html><head/><body><p>When checked, the pattern to find is interpreted as a UNIX regular expression. See <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>.</p></body></html> + <html><head/><body><p>Si se activa, el patrón de búsqueda se interpreta como una expresión regular UNIX. Véase <a href="https://es.wikipedia.org/wiki/Expresi%C3%B3n_regular">«Expresión regular» en Wikipedia</a>.</p></body></html> + + + + Regular Expression + Expresión regular + + + + + Close Find Bar + Cerrar la barra de búsqueda + + + + <html><head/><body><p>Results of the last executed statements.</p><p>You may want to collapse this panel and use the <span style=" font-style:italic;">SQL Log</span> dock with <span style=" font-style:italic;">User</span> selection instead.</p></body></html> + <html><head/><body><p>Resultados de las útimas sentencias ejecutadas.</p><p>Puede que prefiera colapsar este panel y en su lugar usar el <span style=" font-style:italic;">Registro SQL</span> con selección de <span style=" font-style:italic;">Usuario</span>.</p></body></html> + + + + Results of the last executed statements + Resultados de las últimas sentencias ejecutadas + + + + This field shows the results and status codes of the last executed statements. + Este campo muestra los resultados y códigos de estado de las últimas sentencias ejecutadas. + + + + Couldn't read file: %1. + No se pudo leer el archivo: %1. + + + + + Couldn't save file: %1. + No se pudo guardar el archivo: %1. + + + + Your changes will be lost when reloading it! + ¡Los cambios se perderán al recargarlo! + + + + The file "%1" was modified by another program. Do you want to reload it?%2 + El archivo "%1" ha sido modificado por otro programa. ¿Quiere recargarlo?%2 + + + + SqlTextEdit + + + Ctrl+/ + + + + + SqlUiLexer + + + (X) The abs(X) function returns the absolute value of the numeric argument X. + (X) La función abs(X) devuelve el valor absoluto del argumento numérico X. + + + + () The changes() function returns the number of database rows that were changed or inserted or deleted by the most recently completed INSERT, DELETE, or UPDATE statement. + () La función changes() devuelve el número de líneas de la base de datos que se modificaron, insertaron o borraron por la consulta INSERT, DELETE, o UPDATE más reciente. + + + + (X1,X2,...) The char(X1,X2,...,XN) function returns a string composed of characters having the unicode code point values of integers X1 through XN, respectively. + (X1,X2,...) La función char(X1,X2,...,XN) devuelve una cadena compuesta por caracteres que tienen el valor numérico del código de punto unicode los enteros X1 hasta XN, respectivamente. + + + + (X,Y,...) The coalesce() function returns a copy of its first non-NULL argument, or NULL if all arguments are NULL + (X,Y,...) La función coalesce() devuelve una copia de su primer argumento no nulo, o NULL si todos los argumentos son NULL + + + + (X,Y) The glob(X,Y) function is equivalent to the expression "Y GLOB X". + (X,Y) La función glob(X,Y) es equivalente a la expresión "Y GLOB X". + + + + (X,Y) The ifnull() function returns a copy of its first non-NULL argument, or NULL if both arguments are NULL. + (X,Y) La función ifnull() devuelve una copia de su primer argumento no nulo, o NULL si ambos argumentos son NULL. + + + + (X,Y) The instr(X,Y) function finds the first occurrence of string Y within string X and returns the number of prior characters plus 1, or 0 if Y is nowhere found within X. + (X,Y) La función instr(X,Y) busca la primera coincidencia de la cadena Y en la cadena X y devuelve el número de caracteres precedentes más 1, ó 0 si Y no se encuentra en X. + + + + (X) The hex() function interprets its argument as a BLOB and returns a string which is the upper-case hexadecimal rendering of the content of that blob. + (X) La función hex() interpreta su argumento como un BLOB y devuelve una cadena que es el equivalente codificado en hexadecimal en mayúsculas del contenido del BLOB. + + + + () The last_insert_rowid() function returns the ROWID of the last row insert from the database connection which invoked the function. + () La función last_insert_rowid() devuelve el ROWID del la última línea insertada desde la conexión de la base de datos que invocó la función. + + + + (X) For a string value X, the length(X) function returns the number of characters (not bytes) in X prior to the first NUL character. + (X) La función length(X) devuelve el número de caracteres (no bytes) en X anteriores al primer carácter NUL. + + + + (X,Y) The like() function is used to implement the "Y LIKE X" expression. + X,Y) La función like() se usa para implementar la expresión "Y LIKE X". + + + + (X,Y,Z) The like() function is used to implement the "Y LIKE X ESCAPE Z" expression. + (X,Y,Z) La función like() se usa para implementar la expresión "Y LIKE X ESCAPE Z". + + + + (X) The load_extension(X) function loads SQLite extensions out of the shared library file named X. +Use of this function must be authorized from Preferences. + (X) La función load_extension(X) carga extensiones SQLite del archivo de la biblioteca compartida llamada X usando el punto de entrada Y. +El uso de esta función tiene que ser autorizado desde las Preferencias. + + + + (X,Y) The load_extension(X) function loads SQLite extensions out of the shared library file named X using the entry point Y. +Use of this function must be authorized from Preferences. + (X,Y) La función load_extension(X,Y) carga extensiones SQLite del archivo de la biblioteca compartida llamado X usando el punto de entrada Y. +El uso de esta función tiene que ser autorizado desde las Preferencias. + + + + (X) The lower(X) function returns a copy of string X with all ASCII characters converted to lower case. + (X) La función lower(X) devuelve una copia de la cadena X con todos los caracteres ASCII convertidos a minúsculas. + + + + (X) ltrim(X) removes spaces from the left side of X. + (X) La función ltrim(X) quita los espacios a la izquierda de X. + + + + (X,Y) The ltrim(X,Y) function returns a string formed by removing any and all characters that appear in Y from the left side of X. + (X,Y) La función ltrim(X,Y) devuelve una cadena formada quitando todos los caracteres que aparecen en Y de la izquierda de X. + + + + (X,Y,...) The multi-argument max() function returns the argument with the maximum value, or return NULL if any argument is NULL. + (X,Y,...) La función multi-argumento max() devuelve el argumento con el valor máximo, o NULL si cualquier argumento es NULL. + + + + (X,Y,...) The multi-argument min() function returns the argument with the minimum value. + (X,Y,...) La función multi-argumento max() devuelve el argumento con el valor mínimo. + + + + (X,Y) The nullif(X,Y) function returns its first argument if the arguments are different and NULL if the arguments are the same. + (X,Y) La función nullif(X,Y) devuelve su primer argumento si los argumentos son diferentes y NULL si los argumentos son el mismo. + + + + (FORMAT,...) The printf(FORMAT,...) SQL function works like the sqlite3_mprintf() C-language function and the printf() function from the standard C library. + (FORMAT,...) La función SQL printf(FORMAT,...) funciona como la función de lenguaje C sqlite3_mprintf() y la función printf() de la biblioteca C estándar. + + + + (X) The quote(X) function returns the text of an SQL literal which is the value of its argument suitable for inclusion into an SQL statement. + (X) La función quote(X) devuelve el texto de un literal SQL, que es el valor de su argumento, apropiado para la inclusión en una sentencia SQL. + + + + () The random() function returns a pseudo-random integer between -9223372036854775808 and +9223372036854775807. + () La función random() devuelve un entero pseudo-aleatorio entre -9223372036854775808 y +9223372036854775807. + + + + (N) The randomblob(N) function return an N-byte blob containing pseudo-random bytes. + (N) La función randomblob(N) devuelve un BLOB de N bytes que contiene bytes pseudo-aleatorios. + + + + (X,Y,Z) The replace(X,Y,Z) function returns a string formed by substituting string Z for every occurrence of string Y in string X. + (X,Y,Z) La función replace(X,Y,Z) devuelve una cadena formada substituyendo en la cadena Z cada coincidencia con la subcadena Y por la subcadena X. + + + + (X) The round(X) function returns a floating-point value X rounded to zero digits to the right of the decimal point. + (X) La función round(X) devuelve un valor en coma flotante X redondeado a cero dígitos a la derecha de la coma decimal. + + + + (X,Y) The round(X,Y) function returns a floating-point value X rounded to Y digits to the right of the decimal point. + (X,Y) La función round(X,Y) devuelve un valor en coma flotante X redondeado a Y dígitos a la derecha de la coma decimal. + + + + (X) rtrim(X) removes spaces from the right side of X. + (X) La función rtrim(X) quita los espacios a la derecha de X. + + + + (X,Y) The rtrim(X,Y) function returns a string formed by removing any and all characters that appear in Y from the right side of X. + (X,Y) La función rtrim(X,Y) devuelve una cadena formada quitando todos los caracteres que aparecen en Y de la derecha de X. + + + + (X) The soundex(X) function returns a string that is the soundex encoding of the string X. + (X) La función soundex(X) devuelve una cadena que es la codificación soundex de la cadena X. + + + + (X,Y) substr(X,Y) returns all characters through the end of the string X beginning with the Y-th. + (X,Y) La función substr(X,Y) devuelve una subcadena con todos los caracteres de la cadena X desde el Y-ésimo hasta el último. + + + + (X,Y,Z) The substr(X,Y,Z) function returns a substring of input string X that begins with the Y-th character and which is Z characters long. + (X,Y) La función substr(X,Y) devuelve una subcadena de la cadena X desde el Y-ésimo y que es Z caracteres de largo. + + + + () The total_changes() function returns the number of row changes caused by INSERT, UPDATE or DELETE statements since the current database connection was opened. + () La función total_changes() devuelve el número de cambios en las líneas causadas por sentencias INSERT, UPDATE o DELETE desde que la conexión con la base de datos actual se abrió. + + + + (X) trim(X) removes spaces from both ends of X. + (X) La función trim(X) quita los espacios de ambos lados de X. + + + + (X,Y) The trim(X,Y) function returns a string formed by removing any and all characters that appear in Y from both ends of X. + (X,Y) La función trim(X,Y) devuelve una cadena formada quitando todos los caracteres que aparecen en Y de ambos lados de X. + + + + (X) The typeof(X) function returns a string that indicates the datatype of the expression X. + (X) La función typeof(X) devuelve una cadena que indica el tipo de datos de la expresión X. + + + + (X) The unicode(X) function returns the numeric unicode code point corresponding to the first character of the string X. + (X) La función unicode(X) devuelve el valor numérico del código de punto unicode correspondiente al primer carácter de la cadena X. + + + + (X) The upper(X) function returns a copy of input string X in which all lower-case ASCII characters are converted to their upper-case equivalent. + (X) La función upper(X) devuelve una copia de la cadena X con todos los caracteres ASCII convertidos a mayúsculas. + + + + (N) The zeroblob(N) function returns a BLOB consisting of N bytes of 0x00. + (N) La función zeroblob(N) devuelve un BLOB consistente en N bytes de 0x00. + + + + + + + (timestring,modifier,modifier,...) + (timestring,modificador,modificador,...) + + + + (format,timestring,modifier,modifier,...) + (formato,timestring,modificador,modificador,...) + + + + (X) The avg() function returns the average value of all non-NULL X within a group. + (X) La función avg() devuelve el valor medio de todos los valores no nulos del grupo X. + + + + (X) The count(X) function returns a count of the number of times that X is not NULL in a group. + (X) La función count(X) devuelve el conteo del número de veces que X no es nulo en un grupo. + + + + (X) The group_concat() function returns a string which is the concatenation of all non-NULL values of X. + (X) La función group_concat() devuelve una cadena que es la concatenación de todos los valores no nulos X. + + + + (X,Y) The group_concat() function returns a string which is the concatenation of all non-NULL values of X. If parameter Y is present then it is used as the separator between instances of X. + (X,Y) La función group_concat() devuelve una cadena que es la concatenación de todos los valores no nulos X, usando el parámetro Y como separador entre las instancias de X. + + + + (X) The max() aggregate function returns the maximum value of all values in the group. + (X) La función agregada max() devuelve el máximo valor de entre todos los valores en el grupo. + + + + (X) The min() aggregate function returns the minimum non-NULL value of all values in the group. + (X) La función agregada min() devuelve el mínimo valor no NULO de entre todos los valores en el grupo. + + + + + (X) The sum() and total() aggregate functions return sum of all non-NULL values in the group. + (X) Las funciones agregadas sum() y total() devuelven la suma de todos los valores no NULOS en el grupo. + + + + () The number of the row within the current partition. Rows are numbered starting from 1 in the order defined by the ORDER BY clause in the window definition, or in arbitrary order otherwise. + () El número de fila dentro de la partición actual. Las filas se numeran empezando por 1 en el orden definido por la cláusula ORDER BY en la ventana de definición, o sino en un orden arbitrario. + + + + () The row_number() of the first peer in each group - the rank of the current row with gaps. If there is no ORDER BY clause, then all rows are considered peers and this function always returns 1. + () El row_number() del primer par (igual) en cada grupo - el rango de la fila actual con huecos. Si no hay una cláusula ORDER BY, entonces todas las filas son consideradas pares y esta función siempre devuelve 1. + + + + () The number of the current row's peer group within its partition - the rank of the current row without gaps. Partitions are numbered starting from 1 in the order defined by the ORDER BY clause in the window definition. If there is no ORDER BY clause, then all rows are considered peers and this function always returns 1. + () El número del grupo de pares de la fila actual dentro de su partición - el rango de la fila actual sin huecos. Las particiones se numeran empezando por 1 en el orden definido por la cláusula ORDER BY en la ventana de definición. Si no hay una cláusula ORDER BY, entonces todas las filas son consideradas pares y esta función siempre devuelve 1. + + + + () Despite the name, this function always returns a value between 0.0 and 1.0 equal to (rank - 1)/(partition-rows - 1), where rank is the value returned by built-in window function rank() and partition-rows is the total number of rows in the partition. If the partition contains only one row, this function returns 0.0. + () A pesar del nombre, esta función siempre devuelve un valor entre 0.0 y 1.0 igual a (rank - 1)/(partition-rows - 1), donde rank es el valor devuelto por la función de ventana incorporada rank() y partition-rows es el número total de filas en la partición. Si la partición contiene sólo una fila, esta función devuelve 0.0. + + + + () The cumulative distribution. Calculated as row-number/partition-rows, where row-number is the value returned by row_number() for the last peer in the group and partition-rows the number of rows in the partition. + () La distribución acumulada. Calculada como row-number/partition-rows, donde row-number es el valor devuelto por row_number() para el último par (igual) en el grupo y partition-rows el número de filas en la partición. + + + + (N) Argument N is handled as an integer. This function divides the partition into N groups as evenly as possible and assigns an integer between 1 and N to each group, in the order defined by the ORDER BY clause, or in arbitrary order otherwise. If necessary, larger groups occur first. This function returns the integer value assigned to the group that the current row is a part of. + (N) El argumento N es tratado como un entero. Esta función divide la partición en N grupos tan equitativamente como sea posible y asigna un entero entre 1 y N a cada grupo, en el orden definido por la cláusula ORDER BY, o sino en un orden arbitrario. Si es necesario, los grupos mayores aparecen primero. Esta función devuelve un valor entero asignado al grupo del que la fila actual es parte. + + + + (expr) Returns the result of evaluating expression expr against the previous row in the partition. Or, if there is no previous row (because the current row is the first), NULL. + (expr) Devuelve el resultado de evaluar la expresión expr con la fila anterior en la partición. Si no hay fila anterior (porque la fila actual es la primera) devuelve NULL. + + + + (expr,offset) If the offset argument is provided, then it must be a non-negative integer. In this case the value returned is the result of evaluating expr against the row offset rows before the current row within the partition. If offset is 0, then expr is evaluated against the current row. If there is no row offset rows before the current row, NULL is returned. + (expr,offset) Si se proporciona un offset, éste debe ser un entero no negativo. En este caso el valor devuelto es el resultado de evaluar expr con la fila offset veces anterior a la fila actual dentro de la partición. Si offset es 0, entonces expr se evalua con la fila actual. Si no hay fila offset veces anterior devuelve NULL. + + + + + (expr,offset,default) If default is also provided, then it is returned instead of NULL if the row identified by offset does not exist. + (expr,offset,default) Si también se proporciona un default, entonces éste es devuelto en lugar de NULL si no existe la fila identificada por offet. + + + + (expr) Returns the result of evaluating expression expr against the next row in the partition. Or, if there is no next row (because the current row is the last), NULL. + (expr) Devuelve el resultado de evaluar la expresión expr con la siguiente fila en la partición. Si no hay fila siguiente (porque la fila actual es la última) devuelve NULL. + + + + (expr,offset) If the offset argument is provided, then it must be a non-negative integer. In this case the value returned is the result of evaluating expr against the row offset rows after the current row within the partition. If offset is 0, then expr is evaluated against the current row. If there is no row offset rows after the current row, NULL is returned. + (expr,offset) Si se proporciona un offset, éste debe ser un entero no negativo. En este caso el valor devuelto es el resultado de evaluar expr con la fila offset veces posterior a la fila actual dentro de la partición. Si offset es 0, entonces expr se evalua con la fila actual. Si no hay fila offset veces siguiente devuelve NULL. + + + + (expr) This built-in window function calculates the window frame for each row in the same way as an aggregate window function. It returns the value of expr evaluated against the first row in the window frame for each row. + (expr) Esta función de ventana incorporada calcula el marco de la ventana para cada fila de la misma forma que una función agregada de ventana. Devuelve el valor de expr evaluada con la primera fila en el marco de la ventana para cada fila. + + + + (expr) This built-in window function calculates the window frame for each row in the same way as an aggregate window function. It returns the value of expr evaluated against the last row in the window frame for each row. + (expr) Esta función de ventana incorporada calcula el marco de la ventana para cada fila de la misma forma que una función agregada de ventana. Devuelve el valor de expr evaluada con la última fila en el marco de la ventana para cada fila. + + + + (expr,N) This built-in window function calculates the window frame for each row in the same way as an aggregate window function. It returns the value of expr evaluated against the row N of the window frame. Rows are numbered within the window frame starting from 1 in the order defined by the ORDER BY clause if one is present, or in arbitrary order otherwise. If there is no Nth row in the partition, then NULL is returned. + (expr,N) Esta función de ventana incorporada calcula el marco de la ventana para cada fila de la misma forma que una función agregada de ventana. Devuelve el valor de expr evaluada con la fila N del marco de la ventana. Las columnas se numeran dentro del marco de la ventana empezando por 1 en el orden definico por la cláusula ORDER BY, o sino en orden arbitrario. Si no hay fila N-ava en la partición, entonces devuelve NULL. + + + + SqliteTableModel + + + reading rows + leyendo filas + + + + loading... + cargando... + + + + References %1(%2) +Hold %3Shift and click to jump there + Referencia %1(%2) +Mantenga pulsado %3Mayús. y haga clic para ir ahí + + + + Error changing data: +%1 + Error modificando datos: +%1 + + + + retrieving list of columns + obteniendo lista de columnas + + + + Fetching data... + Obteniendo datos... + + + + + Cancel + Cancelar + + + + TableBrowser + + + Browse Data + Hoja de datos + + + + &Table: + &Tabla: + + + + Select a table to browse data + Seleccione una tabla para ver sus datos + + + + Use this list to select a table to be displayed in the database view + Use esta lista para seleccionar la tabla a mostrar en la vista de la base de datos + + + + This is the database table view. You can do the following actions: + - Start writing for editing inline the value. + - Double-click any record to edit its contents in the cell editor window. + - Alt+Del for deleting the cell content to NULL. + - Ctrl+" for duplicating the current record. + - Ctrl+' for copying the value from the cell above. + - Standard selection and copy/paste operations. + Este es el visor de la tabla de la base de datos. Puede realizar lo siguiente: + - Escribir y editar valores. + - Doble-clic en cualquier registro para editar su contenido en la ventana del editor de celdas. + - Alt+Supr para borrar el contenido de la celda a NULL. + - Ctrl+" para duplicar el registro actual. + - Ctrl+' para copiar el valor de la celda de arriba. + - Las operaciones de copiar y pegar usuales. + + + + Text pattern to find considering the checks in this frame + El patrón de texto a buscar según las opciones seleccionadas en este marco + + + + Find in table + Buscar en la tabla + + + + Find previous match [Shift+F3] + Buscar la anterior ocurrencia [Mayús.+F3] + + + + Find previous match with wrapping + Buscar la anterior ocurrencia volviendo al final si es necesario + + + + Shift+F3 + + + + + Find next match [Enter, F3] + Buscar la siguiente ocurrencia [Intro, F3] + + + + Find next match with wrapping + Buscar la siguiente ocurrencia volviendo al principio si es necesario + + + + F3 + + + + + The found pattern must match in letter case + El patrón de búsqueda tiene que coincidir en mayúsculas y minúsculas + + + + Case Sensitive + Distinguir mayús./minús. + + + + The found pattern must be a whole word + El patrón de búsqueda tiene que ser una palabra completa + + + + Whole Cell + Toda la celda + + + + Interpret search pattern as a regular expression + Interpretar el patrón de búsqueda como una expresión regular + + + + <html><head/><body><p>When checked, the pattern to find is interpreted as a UNIX regular expression. See <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>.</p></body></html> + <html><head/><body><p>Si se marca, el patrón de búsqueda se interpreta como una expresión regular UNIX. Véase <a href="https://es.wikipedia.org/wiki/Expresi%C3%B3n_regular">«Expresión regular» en Wikipedia</a>.</p></body></html> + + + + Regular Expression + Expresión regular + + + + + Close Find Bar + Cerrar la barra de búsqueda + + + + Text to replace with + Texto con el que reemplazar + + + + Replace with + Reemplazar con + + + + Replace next match + Reemplazar la siguiente coincidencia + + + + + Replace + Reemplazar + + + + Replace all matches + Reemplazar todas las coincidencias + + + + Replace all + Reemplazar todo + + + + <html><head/><body><p>Scroll to the beginning</p></body></html> + <html><head/><body><p>Desplazarse hasta el principio</p></body></html> + + + + <html><head/><body><p>Clicking this button navigates to the beginning in the table view above.</p></body></html> + <html><head/><body><p>Pulsando este botón se mueve hasta el principio en la vista de tabla de arriba.</p></body></html> + + + + |< + |< + + + + Scroll one page upwards + Retroceder una página + + + + <html><head/><body><p>Clicking this button navigates one page of records upwards in the table view above.</p></body></html> + <html><head/><body><p>Pulsando este botón se retrocede una página de registros en la vista de tabla de arriba.</p></body></html> + + + + < + < + + + + 0 - 0 of 0 + 0 - 0 de 0 + + + + Scroll one page downwards + Avanzar una página + + + + <html><head/><body><p>Clicking this button navigates one page of records downwards in the table view above.</p></body></html> + <html><head/><body><p>Pulsando este botón se avanza una página de registros en la vista de tabla de arriba.</p></body></html> + + + + > + > + + + + Scroll to the end + Desplazarse hasta el final + + + + <html><head/><body><p>Clicking this button navigates up to the end in the table view above.</p></body></html> + <html><head/><body><p>Pulsando este botón se mueve al final de la vista de tabla de arriba.</p></body></html> + + + + >| + >| + + + + <html><head/><body><p>Click here to jump to the specified record</p></body></html> + <html><head/><body><p>Pulse aquí para saltar al registro especificado</p></body></html> + + + + <html><head/><body><p>This button is used to navigate to the record number specified in the Go to area.</p></body></html> + <html><head/><body><p>Este botón se usa para moverse al número de registro especificado en la casilla Ir a.</p></body></html> + + + + Go to: + Ir a: + + + + Enter record number to browse + Introduzca el número de registro al que navegar + + + + Type a record number in this area and click the Go to: button to display the record in the database view + Escriba un número de registro en esta casilla y haga clic en el botón «Ir a:» para mostrar el registro en la vista de la base de datos + + + + 1 + 1 + + + + Show rowid column + Mostrar la columna rowid + + + + Toggle the visibility of the rowid column + Cambia la visibilidad de la columna rowid + + + + Unlock view editing + Desbloquear edición de vistas + + + + This unlocks the current view for editing. However, you will need appropriate triggers for editing. + Esto desbloquea la vista actual para edición. Aunque para la edición se necesitarán los disparadores adecuados. + + + + Edit display format + Editar el formato de presentación + + + + Edit the display format of the data in this column + Editar el formato de presentación de los datos en esta columna + + + + + New Record + Nuevo registro + + + + + Insert a new record in the current table + Inserta un nuevo registro en la tabla actual + + + + <html><head/><body><p>This button creates a new record in the database. Hold the mouse button to open a pop-up menu of different options:</p><ul><li><span style=" font-weight:600;">New Record</span>: insert a new record with default values in the database.</li><li><span style=" font-weight:600;">Insert Values...</span>: open a dialog for entering values before they are inserted in the database. This allows to enter values acomplishing the different constraints. This dialog is also open if the <span style=" font-weight:600;">New Record</span> option fails due to these constraints.</li></ul></body></html> + <html><head/><body><p>Este botón crea un nuevo registro en la base de datos. Mantenga pulsado el botón del ratón para abrir un menú emergente con varias opciones:</p><ul><li><span style=" font-weight:600;">Nuevo Registro</span>: inserta en la base de datos un nuevo registro con valores por defecto.</li><li><span style=" font-weight:600;">Introduce Valores...</span>: abre un diálogo para introducir valores antes de insertarlos en la base de datos. Esto permite introducir valores que cumplan con las restricciones. Este diálogo también se abre si la opción de <span style=" font-weight:600;">Nuevo Registro</span> falla debido a esas restricciones.</li></ul></body></html> + + + + + Delete Record + Borrar registro + + + + Delete the current record + Borra el registro actual + + + + + This button deletes the record or records currently selected in the table + Este botón borra el registro seleccionado (o los registros seleccionados) actualmente en la base de datos + + + + + Insert new record using default values in browsed table + Inserta un nuevo registro usando valores por defecto en la tabla visualizada + + + + Insert Values... + Introducir valores... + + + + + Open a dialog for inserting values in a new record + Abre un diálogo para introducir valores en un nuevo registro + + + + Export to &CSV + Exportar a &CSV + + + + + Export the filtered data to CSV + Exportar los datos filtrados a CSV + + + + This button exports the data of the browsed table as currently displayed (after filters, display formats and order column) as a CSV file. + Este botón exporta los datos de la tabla mostrada tal como se presentan (después de filtros, formatos de presentación y columna de orden) como un archivo CSV. + + + + Save as &view + Guardar como &vista + + + + + Save the current filter, sort column and display formats as a view + Guardar el filtro actual, la columna de orden y los formatos de presentación como una vista + + + + This button saves the current setting of the browsed table (filters, display formats and order column) as an SQL view that you can later browse or use in SQL statements. + Este botón guarda los ajustes actuales de la tabla visualizada (filtros, formatos de presentación y la columna de orden) como una vista SQL que más tarde puede visualizar o usar en sentencias SQL. + + + + Save Table As... + Guardar Tabla Como... + + + + + Save the table as currently displayed + Guarda la tabla tal como se presenta + + + + <html><head/><body><p>This popup menu provides the following options applying to the currently browsed and filtered table:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Export to CSV: this option exports the data of the browsed table as currently displayed (after filters, display formats and order column) to a CSV file.</li><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Save as view: this option saves the current setting of the browsed table (filters, display formats and order column) as an SQL view that you can later browse or use in SQL statements.</li></ul></body></html> + <html><head/><body><p>Este menú contextual provee las siguientes opciones que se aplican a la tabla actualmente visualizada y filtrada:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Exportar a CSV: esta opción exporta los datas de la tabla tal cual se presentan actualmente (después de filtros, formatos de presentación y columna de orden) a un archivo CSV.</li><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Guardar como vista: esta opción guarda la configuración actual de la tabla visualizada (filtros, formatos de presentación y columna de orden) como una vista SQL que luego puede visualizar o usar en sentencias SQL.</li></ul></body></html> + + + + Hide column(s) + Ocultar columna(s) + + + + Hide selected column(s) + Ocultar columna(s) seleccionada(s) + + + + Show all columns + Mostrar todas las columnas + + + + Show all columns that were hidden + Mostrar todas las columnas que están ocultas + + + + + Set encoding + Definir codificación + + + + Change the encoding of the text in the table cells + Cambia la codificación del texto de las celdas de la tabla + + + + Set encoding for all tables + Definir la codificación para todas las tablas + + + + Change the default encoding assumed for all tables in the database + Cambia la codificación por defecto para todas las tablas en la base de datos + + + + Clear Filters + Borrar Filtros + + + + Clear all filters + Borra todos los filtros + + + + + This button clears all the filters set in the header input fields for the currently browsed table. + Este botón elimina todos los filtros establecidos en la cabecera para la tabla mostrada actualmente. + + + + Clear Sorting + Eliminar ordenación + + + + Reset the order of rows to the default + Reinicia el orden de las filas al orden por defecto + + + + + This button clears the sorting columns specified for the currently browsed table and returns to the default order. + Este botón elimina la ordenación de las columnas especificadas para la tabla mostrada actualmente y vuelve al orden por defecto. + + + + Print + Imprimir + + + + Print currently browsed table data + Imprime los datos de la tabla mostrada actualmente + + + + Print currently browsed table data. Print selection if more than one cell is selected. + Imprime los datos de la tabla mostrada actualmente. Imprime la selección si se ha seleccionado más de una celda. + + + + Ctrl+P + + + + + Refresh + Refrescar + + + + Refresh the data in the selected table + Refresca los datos en la tabla seleccionada + + + + This button refreshes the data in the currently selected table. + Este botón refresca los datos de la tabla seleccionada actualmente. + + + + F5 + + + + + Find in cells + Buscar en celdas + + + + Open the find tool bar which allows you to search for values in the table view below. + Abre la barra de búsqueda que permite buscar valores en la vista de la tabla de abajo. + + + + + Bold + Negrita + + + + Ctrl+B + + + + + + Italic + Cursiva + + + + + Underline + Subrayado + + + + Ctrl+U + + + + + + Align Right + Alineado derecha + + + + + Align Left + Alineado izquierda + + + + + Center Horizontally + Centrado horizontal + + + + + Justify + Justificar + + + + + Edit Conditional Formats... + Editar formatos condicionales... + + + + Edit conditional formats for the current column + Edita formatos condicionales para la columna actual + + + + Clear Format + Eliminar formato + + + + Clear All Formats + Eliminar todos los formatos + + + + + Clear all cell formatting from selected cells and all conditional formats from selected columns + Elimina todo el formato de las celdas seleccionadas y los formatos condicionales de las columnas seleccionadas + + + + + Font Color + Color del texto + + + + + Background Color + Color del fondo + + + + Toggle Format Toolbar + Conmutar barra de formato + + + + Show/hide format toolbar + Mostrar/ocultar la barra de formato + + + + + This button shows or hides the formatting toolbar of the Data Browser + Este botón muestra u oculta la barra de formato de la Hoja de Datos + + + + Select column + Seleccionar columna + + + + Ctrl+Space + + + + + Replace text in cells + Reemplazar texto en las celdas + + + + Filter in any column + Filtrar en cualquier columna + + + + Ctrl+R + + + + + %n row(s) + + %n fila + %n filas + + + + + , %n column(s) + + , %n columna + , %n columnas + + + + + . Sum: %1; Average: %2; Min: %3; Max: %4 + . Suma: %1; Media: %2; Mín: %3; Máx: %4 + + + + Conditional formats for "%1" + Formatos condicionales para "%1" + + + + determining row count... + determinando nº de filas... + + + + %1 - %2 of >= %3 + %1 - %2 de >= %3 + + + + %1 - %2 of %3 + %1 - %2 de %3 + + + + Please enter a pseudo-primary key in order to enable editing on this view. This should be the name of a unique column in the view. + Introduzca una clave pseudo-primaria para activar la edición en esta vista. Esta debería ser el nombre de una columna única en la vista. + + + + Delete Records + Borrar registros + + + + Duplicate records + Duplicar registros + + + + Duplicate record + Duplicar registro + + + + Ctrl+" + + + + + Adjust rows to contents + Ajustar las filas al contenido + + + + Error deleting record: +%1 + Error borrando registro: +%1 + + + + Please select a record first + Por favor, antes seleccione un registro + + + + There is no filter set for this table. View will not be created. + No existe un filtro para esta tabla. La vista no será creada. + + + + Please choose a new encoding for all tables. + Por favor, elija una nueva codificación para todas las tablas. + + + + Please choose a new encoding for this table. + Por favor, elija una nueva codificación para esta tabla. + + + + %1 +Leave the field empty for using the database encoding. + %1 +Deje este campo vacío para usar la codificación de la base de datos. + + + + This encoding is either not valid or not supported. + Esta codificación no es válida o no está soportada. + + + + %1 replacement(s) made. + Se realizaron %1 sustitucion(es). + + + + VacuumDialog + + + Compact Database + Compactar base de datos + + + + Warning: Compacting the database will commit all of your changes. + Aviso: compactar la base de datos provocará la consolidación de todos sus cambios. + + + + Please select the databases to co&mpact: + Seleccione las bases de datos que desea co&mpactar: + + + diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/translations/sqlb_fa.ts b/src/WBCLFZSystemModule/SqliteDBProcess/src/translations/sqlb_fa.ts new file mode 100644 index 0000000..0bda49c --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/translations/sqlb_fa.ts @@ -0,0 +1,6922 @@ + + + + + AboutDialog + + + About DB Browser for SQLite + + + + + Version + + + + + <html><head/><body><p>DB Browser for SQLite is an open source, freeware visual tool used to create, design and edit SQLite database files.</p><p>It is bi-licensed under the Mozilla Public License Version 2, as well as the GNU General Public License Version 3 or later. You can modify or redistribute it under the conditions of these licenses.</p><p>See <a href="http://www.gnu.org/licenses/gpl.html">http://www.gnu.org/licenses/gpl.html</a> and <a href="https://www.mozilla.org/MPL/2.0/index.txt">https://www.mozilla.org/MPL/2.0/index.txt</a> for details.</p><p>For more information on this program please visit our website at: <a href="http://sqlitebrowser.org">http://sqlitebrowser.org</a></p><p><span style=" font-size:small;">This software uses the GPL/LGPL Qt Toolkit from </span><a href="http://qt-project.org/"><span style=" font-size:small;">http://qt-project.org/</span></a><span style=" font-size:small;"><br/>See </span><a href="http://qt-project.org/doc/qt-5/licensing.html"><span style=" font-size:small;">http://qt-project.org/doc/qt-5/licensing.html</span></a><span style=" font-size:small;"> for licensing terms and information.</span></p><p><span style=" font-size:small;">It also uses the Silk icon set by Mark James licensed under a Creative Commons Attribution 2.5 and 3.0 license.<br/>See </span><a href="http://www.famfamfam.com/lab/icons/silk/"><span style=" font-size:small;">http://www.famfamfam.com/lab/icons/silk/</span></a><span style=" font-size:small;"> for details.</span></p></body></html> + + + + + AddRecordDialog + + + Add New Record + + + + + Enter values for the new record considering constraints. Fields in bold are mandatory. + + + + + In the Value column you can specify the value for the field identified in the Name column. The Type column indicates the type of the field. Default values are displayed in the same style as NULL values. + + + + + Name + + + + + Type + + + + + Value + + + + + Values to insert. Pre-filled default values are inserted automatically unless they are changed. + + + + + When you edit the values in the upper frame, the SQL query for inserting this new record is shown here. You can edit manually the query before saving. + + + + + <html><head/><body><p><span style=" font-weight:600;">Save</span> will submit the shown SQL statement to the database for inserting the new record.</p><p><span style=" font-weight:600;">Restore Defaults</span> will restore the initial values in the <span style=" font-weight:600;">Value</span> column.</p><p><span style=" font-weight:600;">Cancel</span> will close this dialog without executing the query.</p></body></html> + + + + + Auto-increment + + + + + + Unique constraint + + + + + + Check constraint: %1 + + + + + + Foreign key: %1 + + + + + + Default value: %1 + + + + + + Error adding record. Message from database engine: + +%1 + + + + + Are you sure you want to restore all the entered values to their defaults? + + + + + Application + + + Possible command line arguments: + + + + + Usage: %1 [options] [<database>|<project>] + + + + + + -h, --help Show command line options + + + + + -q, --quit Exit application after running scripts + + + + + -s, --sql <file> Execute this SQL file after opening the DB + + + + + -t, --table <table> Browse this table after opening the DB + + + + + -R, --read-only Open database in read-only mode + + + + + -o, --option <group>/<setting>=<value> + + + + + Run application with this setting temporarily set to value + + + + + -O, --save-option <group>/<setting>=<value> + + + + + Run application saving this value for this setting + + + + + -v, --version Display the current version + + + + + <database> Open this SQLite database + + + + + <project> Open this project file (*.sqbpro) + + + + + The -s/--sql option requires an argument + + + + + The file %1 does not exist + + + + + The -t/--table option requires an argument + + + + + The -o/--option and -O/--save-option options require an argument in the form group/setting=value + + + + + SQLite Version + + + + + SQLCipher Version %1 (based on SQLite %2) + + + + + DB Browser for SQLite Version %1. + + + + + Built for %1, running on %2 + + + + + Qt Version %1 + + + + + Invalid option/non-existant file: %1 + + + + + CipherDialog + + + SQLCipher encryption + + + + + &Password + + + + + &Reenter password + + + + + Passphrase + + + + + Raw key + + + + + Encr&yption settings + + + + + SQLCipher &3 defaults + + + + + SQLCipher &4 defaults + + + + + Custo&m + + + + + Page si&ze + + + + + &KDF iterations + + + + + HMAC algorithm + + + + + KDF algorithm + + + + + Plaintext Header Size + + + + + Please set a key to encrypt the database. +Note that if you change any of the other, optional, settings you'll need to re-enter them as well every time you open the database file. +Leave the password fields empty to disable the encryption. +The encryption process might take some time and you should have a backup copy of your database! Unsaved changes are applied before modifying the encryption. + + + + + Please enter the key used to encrypt the database. +If any of the other settings were altered for this database file you need to provide this information as well. + + + + + ColumnDisplayFormatDialog + + + Choose display format + + + + + Display format + + + + + Choose a display format for the column '%1' which is applied to each value prior to showing it. + + + + + Default + + + + + Decimal number + + + + + Exponent notation + + + + + Hex blob + + + + + Hex number + + + + + Octal number + + + + + Round number + + + + + Apple NSDate to date + + + + + Java epoch (milliseconds) to date + + + + + .NET DateTime.Ticks to date + + + + + Julian day to date + + + + + Unix epoch to date + + + + + Unix epoch to local time + + + + + Windows DATE to date + + + + + Date as dd/mm/yyyy + + + + + Lower case + + + + + Upper case + + + + + Custom + + + + + Custom display format must contain a function call applied to %1 + + + + + Error in custom display format. Message from database engine: + +%1 + + + + + Custom display format must return only one column but it returned %1. + + + + + CondFormatManager + + + Conditional Format Manager + + + + + This dialog allows creating and editing conditional formats. Each cell style will be selected by the first accomplished condition for that cell data. Conditional formats can be moved up and down, where those at higher rows take precedence over those at lower. Syntax for conditions is the same as for filters and an empty condition applies to all values. + + + + + Add new conditional format + + + + + &Add + + + + + Remove selected conditional format + + + + + &Remove + + + + + Move selected conditional format up + + + + + Move &up + + + + + Move selected conditional format down + + + + + Move &down + + + + + Foreground + + + + + Text color + + + + + Background + + + + + Background color + + + + + Font + + + + + Size + + + + + Bold + + + + + Italic + + + + + Underline + + + + + Alignment + + + + + Condition + + + + + + Click to select color + + + + + Are you sure you want to clear all the conditional formats of this field? + + + + + DBBrowserDB + + + This database has already been attached. Its schema name is '%1'. + + + + + Please specify the database name under which you want to access the attached database + + + + + Invalid file format + + + + + Do you really want to close this temporary database? All data will be lost. + + + + + Do you want to save the changes made to the database file %1? + + + + + Database didn't close correctly, probably still busy + + + + + The database is currently busy: + + + + + Do you want to abort that other operation? + + + + + Exporting database to SQL file... + + + + + + Cancel + + + + + + No database file opened + + + + + Executing SQL... + + + + + Action cancelled. + + + + + + Error in statement #%1: %2. +Aborting execution%3. + + + + + + and rolling back + + + + + didn't receive any output from %1 + + + + + could not execute command: %1 + + + + + Cannot delete this object + + + + + Cannot set data on this object + + + + + + A table with the name '%1' already exists in schema '%2'. + + + + + No table with name '%1' exists in schema '%2'. + + + + + + Cannot find column %1. + + + + + Creating savepoint failed. DB says: %1 + + + + + Renaming the column failed. DB says: +%1 + + + + + + Releasing savepoint failed. DB says: %1 + + + + + Creating new table failed. DB says: %1 + + + + + Copying data to new table failed. DB says: +%1 + + + + + Deleting old table failed. DB says: %1 + + + + + Restoring some of the objects associated with this table failed. This is most likely because some column names changed. Here's the SQL statement which you might want to fix and execute manually: + + + + + + + Error renaming table '%1' to '%2'. +Message from database engine: +%3 + + + + + could not get list of db objects: %1 + + + + + could not get list of databases: %1 + + + + + Error setting pragma %1 to %2: %3 + + + + + File not found. + + + + + Error loading extension: %1 + + + + + could not get column information + + + + + DbStructureModel + + + Name + + + + + Object + + + + + Type + + + + + Schema + + + + + Database + + + + + Browsables + + + + + All + + + + + Temporary + + + + + Tables (%1) + + + + + Indices (%1) + + + + + Views (%1) + + + + + Triggers (%1) + + + + + EditDialog + + + Edit database cell + + + + + Mode: + + + + + This is the list of supported modes for the cell editor. Choose a mode for viewing or editing the data of the current cell. + + + + + Text + + + + + RTL Text + + + + + Binary + + + + + + Image + + + + + JSON + + + + + XML + + + + + + Automatically adjust the editor mode to the loaded data type + + + + + This checkable button enables or disables the automatic switching of the editor mode. When a new cell is selected or new data is imported and the automatic switching is enabled, the mode adjusts to the detected data type. You can then change the editor mode manually. If you want to keep this manually switched mode while moving through the cells, switch the button off. + + + + + Auto-switch + + + + + The text editor modes let you edit plain text, as well as JSON or XML data with syntax highlighting, automatic formatting and validation before saving. + +Errors are indicated with a red squiggle underline. + + + + + This Qt editor is used for right-to-left scripts, which are not supported by the default Text editor. The presence of right-to-left characters is detected and this editor mode is automatically selected. + + + + + Open preview dialog for printing the data currently stored in the cell + + + + + Auto-format: pretty print on loading, compact on saving. + + + + + When enabled, the auto-format feature formats the data on loading, breaking the text in lines and indenting it for maximum readability. On data saving, the auto-format feature compacts the data removing end of lines, and unnecessary whitespace. + + + + + Word Wrap + + + + + Wrap lines on word boundaries + + + + + + Open in default application or browser + + + + + Open in application + + + + + The value is interpreted as a file or URL and opened in the default application or web browser. + + + + + Save file reference... + + + + + Save reference to file + + + + + + Open in external application + + + + + Autoformat + + + + + &Export... + + + + + + &Import... + + + + + + Import from file + + + + + + Opens a file dialog used to import any kind of data to this database cell. + + + + + Export to file + + + + + Opens a file dialog used to export the contents of this database cell to a file. + + + + + Erases the contents of the cell + + + + + Set as &NULL + + + + + This area displays information about the data present in this database cell + + + + + Type of data currently in cell + + + + + Size of data currently in table + + + + + Apply data to cell + + + + + This button saves the changes performed in the cell editor to the database cell. + + + + + Apply + + + + + + Print... + + + + + Open preview dialog for printing displayed image + + + + + + Ctrl+P + + + + + Open preview dialog for printing displayed text + + + + + Copy Hex and ASCII + + + + + Copy selected hexadecimal and ASCII columns to the clipboard + + + + + Ctrl+Shift+C + + + + + + Image data can't be viewed in this mode. + + + + + + Try switching to Image or Binary mode. + + + + + + Binary data can't be viewed in this mode. + + + + + + Try switching to Binary mode. + + + + + + Image files (%1) + + + + + Binary files (*.bin) + + + + + Choose a file to import + + + + + %1 Image + + + + + Choose a filename to export data + + + + + Invalid data for this mode + + + + + The cell contains invalid %1 data. Reason: %2. Do you really want to apply it to the cell? + + + + + + Type of data currently in cell: Text / Numeric + + + + + + + %n character(s) + + + + + + + Type of data currently in cell: %1 Image + + + + + %1x%2 pixel(s) + + + + + Type of data currently in cell: NULL + + + + + + %n byte(s) + + + + + + + Type of data currently in cell: Valid JSON + + + + + Type of data currently in cell: Binary + + + + + Couldn't save file: %1. + + + + + The data has been saved to a temporary file and has been opened with the default application. You can now edit the file and, when you are ready, apply the saved new data to the cell editor or cancel any changes. + + + + + EditIndexDialog + + + Edit Index Schema + + + + + &Name + + + + + &Table + + + + + &Unique + + + + + For restricting the index to only a part of the table you can specify a WHERE clause here that selects the part of the table that should be indexed + + + + + Partial inde&x clause + + + + + Colu&mns + + + + + Table column + + + + + Type + + + + + Add a new expression column to the index. Expression columns contain SQL expression rather than column names. + + + + + Index column + + + + + Order + + + + + Deleting the old index failed: +%1 + + + + + Creating the index failed: +%1 + + + + + EditTableDialog + + + Edit table definition + + + + + Table + + + + + Advanced + + + + + Without Rowid + + + + + Make this a 'WITHOUT rowid' table. Setting this flag requires a field of type INTEGER with the primary key flag set and the auto increment flag unset. + + + + + Fields + + + + + Database sche&ma + + + + + Add + + + + + Remove + + + + + Move to top + + + + + Move up + + + + + Move down + + + + + Move to bottom + + + + + + Name + + + + + + Type + + + + + NN + + + + + Not null + + + + + PK + + + + + Primary key + + + + + AI + + + + + Autoincrement + + + + + U + + + + + + + Unique + + + + + Default + + + + + Default value + + + + + + + Check + + + + + Check constraint + + + + + Collation + + + + + + + Foreign Key + + + + + Constraints + + + + + Add constraint + + + + + Remove constraint + + + + + Columns + + + + + SQL + + + + + <html><head/><body><p><span style=" font-weight:600; color:#ff0000;">Warning: </span>There is something with this table definition that our parser doesn't fully understand. Modifying and saving this table might result in problems.</p></body></html> + + + + + + Primary Key + + + + + Add a primary key constraint + + + + + Add a foreign key constraint + + + + + Add a unique constraint + + + + + Add a check constraint + + + + + + There can only be one primary key for each table. Please modify the existing primary key instead. + + + + + Error creating table. Message from database engine: +%1 + + + + + There already is a field with that name. Please rename it first or choose a different name for this field. + + + + + This column is referenced in a foreign key in table %1 and thus its name cannot be changed. + + + + + There is at least one row with this field set to NULL. This makes it impossible to set this flag. Please change the table data first. + + + + + There is at least one row with a non-integer value in this field. This makes it impossible to set the AI flag. Please change the table data first. + + + + + Column '%1' has duplicate data. + + + + + + This makes it impossible to enable the 'Unique' flag. Please remove the duplicate data, which will allow the 'Unique' flag to then be enabled. + + + + + Are you sure you want to delete the field '%1'? +All data currently stored in this field will be lost. + + + + + Please add a field which meets the following criteria before setting the without rowid flag: + - Primary key flag set + - Auto increment disabled + + + + + ExportDataDialog + + + Export data as CSV + + + + + Tab&le(s) + + + + + Colu&mn names in first line + + + + + Fie&ld separator + + + + + , + + + + + ; + + + + + Tab + + + + + | + + + + + + + Other + + + + + &Quote character + + + + + " + + + + + ' + + + + + New line characters + + + + + Windows: CR+LF (\r\n) + + + + + Unix: LF (\n) + + + + + Pretty print + + + + + Export data as JSON + + + + + exporting CSV + + + + + + Could not open output file: %1 + + + + + exporting JSON + + + + + + Choose a filename to export data + + + + + Please select at least 1 table. + + + + + Choose a directory + + + + + Export completed. + + + + + ExportSqlDialog + + + Export SQL... + + + + + Tab&le(s) + + + + + Select All + + + + + Deselect All + + + + + &Options + + + + + Keep column names in INSERT INTO + + + + + Multiple rows (VALUES) per INSERT statement + + + + + Export everything + + + + + Export schema only + + + + + Export data only + + + + + Keep old schema (CREATE TABLE IF NOT EXISTS) + + + + + Overwrite old schema (DROP TABLE, then CREATE TABLE) + + + + + Please select at least one table. + + + + + Choose a filename to export + + + + + Export completed. + + + + + Export cancelled or failed. + + + + + ExtendedScintilla + + + + Ctrl+H + + + + + Ctrl+F + + + + + + Ctrl+P + + + + + Find... + + + + + Find and Replace... + + + + + Print... + + + + + ExtendedTableWidget + + + Use as Exact Filter + + + + + Containing + + + + + Not containing + + + + + Not equal to + + + + + Greater than + + + + + Less than + + + + + Greater or equal + + + + + Less or equal + + + + + Between this and... + + + + + Regular expression + + + + + Edit Conditional Formats... + + + + + Set to NULL + + + + + Copy + + + + + Copy with Headers + + + + + Copy as SQL + + + + + Paste + + + + + Print... + + + + + Use in Filter Expression + + + + + Alt+Del + + + + + Ctrl+Shift+C + + + + + Ctrl+Alt+C + + + + + The content of the clipboard is bigger than the range selected. +Do you want to insert it anyway? + + + + + <p>Not all data has been loaded. <b>Do you want to load all data before selecting all the rows?</b><p><p>Answering <b>No</b> means that no more data will be loaded and the selection will not be performed.<br/>Answering <b>Yes</b> might take some time while the data is loaded but the selection will be complete.</p>Warning: Loading all the data might require a great amount of memory for big tables. + + + + + Cannot set selection to NULL. Column %1 has a NOT NULL constraint. + + + + + FileExtensionManager + + + File Extension Manager + + + + + &Up + + + + + &Down + + + + + &Add + + + + + &Remove + + + + + + Description + + + + + Extensions + + + + + *.extension + + + + + FilterLineEdit + + + Filter + + + + + These input fields allow you to perform quick filters in the currently selected table. +By default, the rows containing the input text are filtered out. +The following operators are also supported: +% Wildcard +> Greater than +< Less than +>= Equal to or greater +<= Equal to or less += Equal to: exact match +<> Unequal: exact inverse match +x~y Range: values between x and y +/regexp/ Values matching the regular expression + + + + + Clear All Conditional Formats + + + + + Use for Conditional Format + + + + + Set Filter Expression + + + + + What's This? + + + + + Is NULL + + + + + Is not NULL + + + + + Is empty + + + + + Is not empty + + + + + Not containing... + + + + + Equal to... + + + + + Not equal to... + + + + + Greater than... + + + + + Less than... + + + + + Greater or equal... + + + + + Less or equal... + + + + + In range... + + + + + Regular expression... + + + + + Edit Conditional Formats... + + + + + FindReplaceDialog + + + Find and Replace + + + + + Fi&nd text: + + + + + Re&place with: + + + + + Match &exact case + + + + + Match &only whole words + + + + + When enabled, the search continues from the other end when it reaches one end of the page + + + + + &Wrap around + + + + + When set, the search goes backwards from cursor position, otherwise it goes forward + + + + + Search &backwards + + + + + <html><head/><body><p>When checked, the pattern to find is searched only in the current selection.</p></body></html> + + + + + &Selection only + + + + + <html><head/><body><p>When checked, the pattern to find is interpreted as a UNIX regular expression. See <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>.</p></body></html> + + + + + Use regular e&xpressions + + + + + Find the next occurrence from the cursor position and in the direction set by "Search backwards" + + + + + &Find Next + + + + + F3 + + + + + &Replace + + + + + Highlight all the occurrences of the text in the page + + + + + F&ind All + + + + + Replace all the occurrences of the text in the page + + + + + Replace &All + + + + + The searched text was not found + + + + + The searched text was not found. + + + + + The searched text was replaced one time. + + + + + The searched text was found one time. + + + + + The searched text was replaced %1 times. + + + + + The searched text was found %1 times. + + + + + ForeignKeyEditor + + + &Reset + + + + + Foreign key clauses (ON UPDATE, ON DELETE etc.) + + + + + ImportCsvDialog + + + Import CSV file + + + + + Table na&me + + + + + &Column names in first line + + + + + Field &separator + + + + + , + + + + + ; + + + + + + Tab + + + + + | + + + + + Other + + + + + &Quote character + + + + + + Other (printable) + + + + + + Other (code) + + + + + " + + + + + ' + + + + + &Encoding + + + + + UTF-8 + + + + + UTF-16 + + + + + ISO-8859-1 + + + + + Trim fields? + + + + + Separate tables + + + + + Advanced + + + + + When importing an empty value from the CSV file into an existing table with a default value for this column, that default value is inserted. Activate this option to insert an empty value instead. + + + + + Ignore default &values + + + + + Activate this option to stop the import when trying to import an empty value into a NOT NULL column without a default value. + + + + + Fail on missing values + + + + + Disable data type detection + + + + + Disable the automatic data type detection when creating a new table. + + + + + When importing into an existing table with a primary key, unique constraints or a unique index there is a chance for a conflict. This option allows you to select a strategy for that case: By default the import is aborted and rolled back but you can also choose to ignore and not import conflicting rows or to replace the existing row in the table. + + + + + Abort import + + + + + Ignore row + + + + + Replace existing row + + + + + Conflict strategy + + + + + + Deselect All + + + + + Match Similar + + + + + Select All + + + + + There is already a table named '%1' and an import into an existing table is only possible if the number of columns match. + + + + + There is already a table named '%1'. Do you want to import the data into it? + + + + + Creating restore point failed: %1 + + + + + Creating the table failed: %1 + + + + + importing CSV + + + + + Inserting row failed: %1 + + + + + Importing the file '%1' took %2ms. Of this %3ms were spent in the row function. + + + + + MainWindow + + + DB Browser for SQLite + + + + + + Database Structure + This has to be equal to the tab title in all the main tabs + + + + + This is the structure of the opened database. +You can drag SQL statements from an object row and drop them into other applications or into another instance of 'DB Browser for SQLite'. + + + + + + + Browse Data + This has to be equal to the tab title in all the main tabs + + + + + + Edit Pragmas + This has to be equal to the tab title in all the main tabs + + + + + Warning: this pragma is not readable and this value has been inferred. Writing the pragma might overwrite a redefined LIKE provided by an SQLite extension. + + + + + + Execute SQL + This has to be equal to the tab title in all the main tabs + + + + + toolBar1 + + + + + &File + + + + + &Import + + + + + &Export + + + + + &Edit + + + + + &View + + + + + &Help + + + + + &Tools + + + + + DB Toolbar + + + + + Edit Database &Cell + + + + + SQL &Log + + + + + Show S&QL submitted by + + + + + User + + + + + Application + + + + + Error Log + + + + + This button clears the contents of the SQL logs + + + + + &Clear + + + + + This panel lets you examine a log of all SQL commands issued by the application or by yourself + + + + + &Plot + + + + + DB Sche&ma + + + + + This is the structure of the opened database. +You can drag multiple object names from the Name column and drop them into the SQL editor and you can adjust the properties of the dropped names using the context menu. This would help you in composing SQL statements. +You can drag SQL statements from the Schema column and drop them into the SQL editor or into other applications. + + + + + + &Remote + + + + + + Project Toolbar + + + + + Extra DB toolbar + + + + + + + Close the current database file + + + + + &New Database... + + + + + + Create a new database file + + + + + This option is used to create a new database file. + + + + + Ctrl+N + + + + + + &Open Database... + + + + + + + + + Open an existing database file + + + + + + + This option is used to open an existing database file. + + + + + Ctrl+O + + + + + &Close Database + + + + + This button closes the connection to the currently open database file + + + + + + Ctrl+W + + + + + &Revert Changes + + + + + + Revert database to last saved state + + + + + This option is used to revert the current database file to its last saved state. All changes made since the last save operation are lost. + + + + + &Write Changes + + + + + + Write changes to the database file + + + + + This option is used to save changes to the database file. + + + + + Ctrl+S + + + + + Compact &Database... + + + + + Compact the database file, removing space wasted by deleted records + + + + + + Compact the database file, removing space wasted by deleted records. + + + + + E&xit + + + + + Ctrl+Q + + + + + &Database from SQL file... + + + + + Import data from an .sql dump text file into a new or existing database. + + + + + This option lets you import data from an .sql dump text file into a new or existing database. SQL dump files can be created on most database engines, including MySQL and PostgreSQL. + + + + + &Table from CSV file... + + + + + Open a wizard that lets you import data from a comma separated text file into a database table. + + + + + Open a wizard that lets you import data from a comma separated text file into a database table. CSV files can be created on most database and spreadsheet applications. + + + + + &Database to SQL file... + + + + + Export a database to a .sql dump text file. + + + + + This option lets you export a database to a .sql dump text file. SQL dump files contain all data necessary to recreate the database on most database engines, including MySQL and PostgreSQL. + + + + + &Table(s) as CSV file... + + + + + Export a database table as a comma separated text file. + + + + + Export a database table as a comma separated text file, ready to be imported into other database or spreadsheet applications. + + + + + &Create Table... + + + + + Open the Create Table wizard, where it is possible to define the name and fields for a new table in the database + + + + + &Delete Table... + + + + + + Delete Table + + + + + Open the Delete Table wizard, where you can select a database table to be dropped. + + + + + &Modify Table... + + + + + Open the Modify Table wizard, where it is possible to rename an existing table. It is also possible to add or delete fields form a table, as well as modify field names and types. + + + + + Create &Index... + + + + + Open the Create Index wizard, where it is possible to define a new index on an existing database table. + + + + + &Preferences... + + + + + + Open the preferences window. + + + + + &DB Toolbar + + + + + Shows or hides the Database toolbar. + + + + + Ctrl+T + + + + + Open SQL file(s) + + + + + This button opens files containing SQL statements and loads them in new editor tabs + + + + + Sa&ve Project + + + + + This button lets you save all the settings associated to the open DB to a DB Browser for SQLite project file + + + + + This button lets you open a DB Browser for SQLite project file + + + + + Ctrl+Shift+O + + + + + &Save Project As... + + + + + + + Save the project in a file selected in a dialog + + + + + Save A&ll + + + + + + + Save DB file, project file and opened SQL files + + + + + Ctrl+Shift+S + + + + + Browse Table + + + + + W&hat's This? + + + + + Ctrl+F4 + + + + + Shift+F1 + + + + + &About + + + + + &Recently opened + + + + + Open &tab + + + + + This button opens a new tab for the SQL editor + + + + + &Execute SQL + + + + + Execute all/selected SQL + + + + + This button executes the currently selected SQL statements. If no text is selected, all SQL statements are executed. + + + + + Ctrl+Return + + + + + + + Save SQL file + + + + + &Load Extension... + + + + + + Execute current line + + + + + Execute line + + + + + This button executes the SQL statement present in the current editor line + + + + + Shift+F5 + + + + + Export as CSV file + + + + + Export table as comma separated values file + + + + + &Wiki + + + + + F1 + + + + + Bug &Report... + + + + + Feature Re&quest... + + + + + Web&site + + + + + &Donate on Patreon... + + + + + + Save the current session to a file + + + + + Open &Project... + + + + + + Load a working session from a file + + + + + &Attach Database... + + + + + + Add another database file to the current database connection + + + + + This button lets you add another database file to the current database connection + + + + + &Set Encryption... + + + + + + Save SQL file as + + + + + This button saves the content of the current SQL editor tab to a file + + + + + &Browse Table + + + + + Copy Create statement + + + + + Copy the CREATE statement of the item to the clipboard + + + + + SQLCipher &FAQ + + + + + Opens the SQLCipher FAQ in a browser window + + + + + Table(&s) to JSON... + + + + + Export one or more table(s) to a JSON file + + + + + Open Data&base Read Only... + + + + + Open an existing database file in read only mode + + + + + Save results + + + + + Save the results view + + + + + This button lets you save the results of the last executed query + + + + + + Find text in SQL editor + + + + + Find + + + + + This button opens the search bar of the editor + + + + + Ctrl+F + + + + + + Find or replace text in SQL editor + + + + + Find or replace + + + + + This button opens the find/replace dialog for the current editor tab + + + + + Ctrl+H + + + + + Export to &CSV + + + + + Save as &view + + + + + Save as view + + + + + Shows or hides the Project toolbar. + + + + + Extra DB Toolbar + + + + + New In-&Memory Database + + + + + Drag && Drop Qualified Names + + + + + + Use qualified names (e.g. "Table"."Field") when dragging the objects and dropping them into the editor + + + + + Drag && Drop Enquoted Names + + + + + + Use escaped identifiers (e.g. "Table1") when dragging the objects and dropping them into the editor + + + + + &Integrity Check + + + + + Runs the integrity_check pragma over the opened database and returns the results in the Execute SQL tab. This pragma does an integrity check of the entire database. + + + + + &Foreign-Key Check + + + + + Runs the foreign_key_check pragma over the opened database and returns the results in the Execute SQL tab + + + + + &Quick Integrity Check + + + + + Run a quick integrity check over the open DB + + + + + Runs the quick_check pragma over the opened database and returns the results in the Execute SQL tab. This command does most of the checking of PRAGMA integrity_check but runs much faster. + + + + + &Optimize + + + + + Attempt to optimize the database + + + + + Runs the optimize pragma over the opened database. This pragma might perform optimizations that will improve the performance of future queries. + + + + + + Print + + + + + Print text from current SQL editor tab + + + + + Open a dialog for printing the text in the current SQL editor tab + + + + + + Ctrl+P + + + + + Print the structure of the opened database + + + + + Open a dialog for printing the structure of the opened database + + + + + Un/comment block of SQL code + + + + + Un/comment block + + + + + Comment or uncomment current line or selected block of code + + + + + Comment or uncomment the selected lines or the current line, when there is no selection. All the block is toggled according to the first line. + + + + + Ctrl+/ + + + + + Stop SQL execution + + + + + Stop execution + + + + + Stop the currently running SQL script + + + + + Ctrl+L + + + + + Ctrl+D + + + + + Ctrl+I + + + + + Ctrl+E + + + + + Window Layout + + + + + Reset Window Layout + + + + + Alt+0 + + + + + Simplify Window Layout + + + + + Shift+Alt+0 + + + + + Dock Windows at Bottom + + + + + Dock Windows at Left Side + + + + + Dock Windows at Top + + + + + The database is currenctly busy. + + + + + Click here to interrupt the currently running query. + + + + + Encrypted + + + + + Database is encrypted using SQLCipher + + + + + Read only + + + + + Database file is read only. Editing the database is disabled. + + + + + Database encoding + + + + + + Choose a database file + + + + + Could not open database file. +Reason: %1 + + + + + + + Choose a filename to save under + + + + + In-Memory database + + + + + Could not open project file for writing. +Reason: %1 + + + + + Project saved to file '%1' + + + + + Rename Tab + + + + + Duplicate Tab + + + + + Close Tab + + + + + Opening '%1'... + + + + + There was an error opening '%1'... + + + + + Value is not a valid URL or filename: %1 + + + + + Are you sure you want to delete the table '%1'? +All data associated with the table will be lost. + + + + + Are you sure you want to delete the view '%1'? + + + + + Are you sure you want to delete the trigger '%1'? + + + + + Are you sure you want to delete the index '%1'? + + + + + Error: could not delete the table. + + + + + Error: could not delete the view. + + + + + Error: could not delete the trigger. + + + + + Error: could not delete the index. + + + + + Message from database engine: +%1 + + + + + Editing the table requires to save all pending changes now. +Are you sure you want to save the database? + + + + + Error checking foreign keys after table modification. The changes will be reverted. + + + + + This table did not pass a foreign-key check.<br/>You should run 'Tools | Foreign-Key Check' and fix the reported issues. + + + + + Edit View %1 + + + + + Edit Trigger %1 + + + + + You are already executing SQL statements. Do you want to stop them in order to execute the current statements instead? Note that this might leave the database in an inconsistent state. + + + + + -- EXECUTING SELECTION IN '%1' +-- + + + + + -- EXECUTING LINE IN '%1' +-- + + + + + -- EXECUTING ALL IN '%1' +-- + + + + + %1 rows returned in %2ms + + + + + Setting PRAGMA values or vacuuming will commit your current transaction. +Are you sure? + + + + + Execution finished with errors. + + + + + Execution finished without errors. + + + + + Choose text files + + + + + Error while saving the database file. This means that not all changes to the database were saved. You need to resolve the following error first. + +%1 + + + + + Are you sure you want to undo all changes made to the database file '%1' since the last save? + + + + + Choose a file to import + + + + + Opened '%1' in read-only mode from recent file list + + + + + Opened '%1' from recent file list + + + + + &%1 %2%3 + + + + + (read only) + + + + + Open Database or Project + + + + + Attach Database... + + + + + Import CSV file(s)... + + + + + Select the action to apply to the dropped file(s). <br/>Note: only 'Import' will process more than one file. + + + + + + + Do you want to save the changes made to SQL tabs in a new project file? + + + + + Do you want to save the changes made to SQL tabs in the project file '%1'? + + + + + Do you want to save the changes made to the SQL file %1? + + + + + Text files(*.sql *.txt);;All files(*) + + + + + Do you want to create a new database file to hold the imported data? +If you answer no we will attempt to import the data in the SQL file to the current database. + + + + + You are still executing SQL statements. Closing the database now will stop their execution, possibly leaving the database in an inconsistent state. Are you sure you want to close the database? + + + + + Do you want to save the changes made to the project file '%1'? + + + + + + At line %1: + + + + + Result: %1 + + + + + Result: %2 + + + + + File %1 already exists. Please choose a different name. + + + + + Error importing data: %1 + + + + + Import completed. Some foreign key constraints are violated. Please fix them before saving. + + + + + Import completed. + + + + + Delete View + + + + + Modify View + + + + + Delete Trigger + + + + + Modify Trigger + + + + + Delete Index + + + + + Modify Index + + + + + Modify Table + + + + + Setting PRAGMA values will commit your current transaction. +Are you sure? + + + + + The statements in this tab are still executing. Closing the tab will stop the execution. This might leave the database in an inconsistent state. Are you sure you want to close the tab? + + + + + Select SQL file to open + + + + + Select file name + + + + + Select extension file + + + + + Extension successfully loaded. + + + + + Error loading extension: %1 + + + + + Could not find resource file: %1 + + + + + + Don't show again + + + + + New version available. + + + + + A new DB Browser for SQLite version is available (%1.%2.%3).<br/><br/>Please download at <a href='%4'>%4</a>. + + + + + Choose a project file to open + + + + + DB Browser for SQLite project file (*.sqbpro) + + + + + This project file is using an old file format because it was created using DB Browser for SQLite version 3.10 or lower. Loading this file format is still fully supported but we advice you to convert all your project files to the new file format because support for older formats might be dropped at some point in the future. You can convert your files by simply opening and re-saving them. + + + + + Collation needed! Proceed? + + + + + A table in this database requires a special collation function '%1' that this application can't provide without further knowledge. +If you choose to proceed, be aware bad things can happen to your database. +Create a backup! + + + + + creating collation + + + + + Set a new name for the SQL tab. Use the '&&' character to allow using the following character as a keyboard shortcut. + + + + + Please specify the view name + + + + + There is already an object with that name. Please choose a different name. + + + + + View successfully created. + + + + + Error creating view: %1 + + + + + This action will open a new SQL tab for running: + + + + + This action will open a new SQL tab with the following statements for you to edit and run: + + + + + Press Help for opening the corresponding SQLite reference page. + + + + + Busy (%1) + + + + + NullLineEdit + + + Set to NULL + + + + + Alt+Del + + + + + PlotDock + + + Plot + + + + + <html><head/><body><p>This pane shows the list of columns of the currently browsed table or the just executed query. You can select the columns that you want to be used as X or Y axis for the plot pane below. The table shows detected axis type that will affect the resulting plot. For the Y axis you can only select numeric columns, but for the X axis you will be able to select:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Date/Time</span>: strings with format &quot;yyyy-MM-dd hh:mm:ss&quot; or &quot;yyyy-MM-ddThh:mm:ss&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Date</span>: strings with format &quot;yyyy-MM-dd&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Time</span>: strings with format &quot;hh:mm:ss&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Label</span>: other string formats. Selecting this column as X axis will produce a Bars plot with the column values as labels for the bars</li><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Numeric</span>: integer or real values</li></ul><p>Double-clicking the Y cells you can change the used color for that graph.</p></body></html> + + + + + Columns + + + + + X + + + + + Y1 + + + + + Y2 + + + + + Axis Type + + + + + Here is a plot drawn when you select the x and y values above. + +Click on points to select them in the plot and in the table. Ctrl+Click for selecting a range of points. + +Use mouse-wheel for zooming and mouse drag for changing the axis range. + +Select the axes or axes labels to drag and zoom only in that orientation. + + + + + Line type: + + + + + + None + + + + + Line + + + + + StepLeft + + + + + StepRight + + + + + StepCenter + + + + + Impulse + + + + + Point shape: + + + + + Cross + + + + + Plus + + + + + Circle + + + + + Disc + + + + + Square + + + + + Diamond + + + + + Star + + + + + Triangle + + + + + TriangleInverted + + + + + CrossSquare + + + + + PlusSquare + + + + + CrossCircle + + + + + PlusCircle + + + + + Peace + + + + + <html><head/><body><p>Save current plot...</p><p>File format chosen by extension (png, jpg, pdf, bmp)</p></body></html> + + + + + Save current plot... + + + + + + Load all data and redraw plot + + + + + Copy + + + + + Print... + + + + + Show legend + + + + + Stacked bars + + + + + Date/Time + + + + + Date + + + + + Time + + + + + + Numeric + + + + + Label + + + + + Invalid + + + + + + + Row # + + + + + Load all data and redraw plot. +Warning: not all data has been fetched from the table yet due to the partial fetch mechanism. + + + + + Choose an axis color + + + + + Choose a filename to save under + + + + + PNG(*.png);;JPG(*.jpg);;PDF(*.pdf);;BMP(*.bmp);;All Files(*) + + + + + There are curves in this plot and the selected line style can only be applied to graphs sorted by X. Either sort the table or query by X to remove curves or select one of the styles supported by curves: None or Line. + + + + + Loading all remaining data for this table took %1ms. + + + + + PreferencesDialog + + + Preferences + + + + + &General + + + + + Default &location + + + + + Remember last location + + + + + Always use this location + + + + + Remember last location for session only + + + + + + + ... + + + + + Lan&guage + + + + + Toolbar style + + + + + + + + + Only display the icon + + + + + + + + + Only display the text + + + + + + + + + The text appears beside the icon + + + + + + + + + The text appears under the icon + + + + + + + + + Follow the style + + + + + + + + + + + + + enabled + + + + + Automatic &updates + + + + + DB file extensions + + + + + Manage + + + + + Show remote options + + + + + &Database + + + + + Database &encoding + + + + + Open databases with foreign keys enabled. + + + + + &Foreign keys + + + + + Remove line breaks in schema &view + + + + + When enabled, the line breaks in the Schema column of the DB Structure tab, dock and printed output are removed. + + + + + Prefetch block si&ze + + + + + SQ&L to execute after opening database + + + + + Default field type + + + + + Main Window + + + + + Database Structure + + + + + Browse Data + + + + + Execute SQL + + + + + Edit Database Cell + + + + + When this value is changed, all the other color preferences are also set to matching colors. + + + + + Follow the desktop style + + + + + Dark style + + + + + Application style + + + + + This sets the font size for all UI elements which do not have their own font size option. + + + + + Font size + + + + + Database structure font size + + + + + Data &Browser + + + + + Font + + + + + &Font + + + + + Font si&ze + + + + + Content + + + + + Symbol limit in cell + + + + + This is the maximum number of items allowed for some computationally expensive functionalities to be enabled: +Maximum number of rows in a table for enabling the value completion based on current values in the column. +Maximum number of indexes in a selection for calculating sum and average. +Can be set to 0 for disabling the functionalities. + + + + + This is the maximum number of rows in a table for enabling the value completion based on current values in the column. +Can be set to 0 for disabling completion. + + + + + Threshold for completion and calculation on selection + + + + + Show images in cell + + + + + Enable this option to show a preview of BLOBs containing image data in the cells. This can affect the performance of the data browser, however. + + + + + Field display + + + + + Displayed &text + + + + + Binary + + + + + NULL + + + + + Regular + + + + + + + + + + Click to set this color + + + + + Text color + + + + + Background color + + + + + Preview only (N/A) + + + + + Filters + + + + + Escape character + + + + + Delay time (&ms) + + + + + Set the waiting time before a new filter value is applied. Can be set to 0 for disabling waiting. + + + + + &SQL + + + + + Settings name + + + + + Context + + + + + Colour + + + + + Bold + + + + + Italic + + + + + Underline + + + + + Keyword + + + + + Function + + + + + Table + + + + + Comment + + + + + Identifier + + + + + String + + + + + Current line + + + + + Background + + + + + Foreground + + + + + SQL editor &font + + + + + SQL &editor font size + + + + + SQL &results font size + + + + + Tab size + + + + + &Wrap lines + + + + + Never + + + + + At word boundaries + + + + + At character boundaries + + + + + At whitespace boundaries + + + + + &Quotes for identifiers + + + + + Choose the quoting mechanism used by the application for identifiers in SQL code. + + + + + "Double quotes" - Standard SQL (recommended) + + + + + `Grave accents` - Traditional MySQL quotes + + + + + [Square brackets] - Traditional MS SQL Server quotes + + + + + Code co&mpletion + + + + + Keywords in &UPPER CASE + + + + + When set, the SQL keywords are completed in UPPER CASE letters. + + + + + Error indicators + + + + + When set, the SQL code lines that caused errors during the last execution are highlighted and the results frame indicates the error in the background + + + + + Hori&zontal tiling + + + + + If enabled the SQL code editor and the result table view are shown side by side instead of one over the other. + + + + + Close button on tabs + + + + + If enabled, SQL editor tabs will have a close button. In any case, you can use the contextual menu or the keyboard shortcut to close them. + + + + + &Extensions + + + + + Select extensions to load for every database: + + + + + Add extension + + + + + Remove extension + + + + + <html><head/><body><p>While supporting the REGEXP operator SQLite doesn't implement any regular expression<br/>algorithm but calls back the running application. DB Browser for SQLite implements this<br/>algorithm for you to let you use REGEXP out of the box. However, as there are multiple possible<br/>implementations of this and you might want to use another one, you're free to disable the<br/>application's implementation and load your own by using an extension. Requires restart of the application.</p></body></html> + + + + + Disable Regular Expression extension + + + + + <html><head/><body><p>SQLite provides an SQL function for loading extensions from a shared library file. Activate this if you want to use the <span style=" font-style:italic;">load_extension()</span> function from SQL code.</p><p>For security reasons, extension loading is turned off by default and must be enabled through this setting. You can always load extensions through the GUI, even though this option is disabled.</p></body></html> + + + + + Allow loading extensions from SQL code + + + + + Remote + + + + + Your certificates + + + + + File + + + + + + Subject CN + + + + + Subject Common Name + + + + + Issuer CN + + + + + Issuer Common Name + + + + + + Valid from + + + + + + Valid to + + + + + + Serial number + + + + + CA certificates + + + + + Common Name + + + + + Subject O + + + + + Organization + + + + + Clone databases into + + + + + Proxy + + + + + Configure + + + + + + Choose a directory + + + + + The language will change after you restart the application. + + + + + Select extension file + + + + + Extensions(*.so *.dylib *.dll);;All files(*) + + + + + Import certificate file + + + + + No certificates found in this file. + + + + + Are you sure you want do remove this certificate? All certificate data will be deleted from the application settings! + + + + + Are you sure you want to clear all the saved settings? +All your preferences will be lost and default values will be used. + + + + + ProxyDialog + + + Proxy Configuration + + + + + Pro&xy Type + + + + + Host Na&me + + + + + Port + + + + + Authentication Re&quired + + + + + &User Name + + + + + Password + + + + + None + + + + + System settings + + + + + HTTP + + + + + Socks v5 + + + + + QObject + + + All files (*) + + + + + Error importing data + + + + + from record number %1 + + + + + . +%1 + + + + + Importing CSV file... + + + + + Cancel + + + + + SQLite database files (*.db *.sqlite *.sqlite3 *.db3) + + + + + Left + + + + + Right + + + + + Center + + + + + Justify + + + + + SQLite Database Files (*.db *.sqlite *.sqlite3 *.db3) + + + + + DB Browser for SQLite Project Files (*.sqbpro) + + + + + SQL Files (*.sql) + + + + + All Files (*) + + + + + Text Files (*.txt) + + + + + Comma-Separated Values Files (*.csv) + + + + + Tab-Separated Values Files (*.tsv) + + + + + Delimiter-Separated Values Files (*.dsv) + + + + + Concordance DAT files (*.dat) + + + + + JSON Files (*.json *.js) + + + + + XML Files (*.xml) + + + + + Binary Files (*.bin *.dat) + + + + + SVG Files (*.svg) + + + + + Hex Dump Files (*.dat *.bin) + + + + + Extensions (*.so *.dylib *.dll) + + + + + RemoteCommitsModel + + + Commit ID + + + + + Message + + + + + Date + + + + + Author + + + + + Size + + + + + Authored and committed by %1 + + + + + Authored by %1, committed by %2 + + + + + RemoteDatabase + + + Error opening local databases list. +%1 + + + + + Error creating local databases list. +%1 + + + + + RemoteDock + + + Remote + + + + + Identity + + + + + DBHub.io + + + + + <html><head/><body><p>In this pane, remote databases from dbhub.io website can be added to DB Browser for SQLite. First you need an identity:</p><ol style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Login to the dbhub.io website (use your GitHub credentials or whatever you want)</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Click the button to &quot;Generate client certificate&quot; (that's your identity). That'll give you a certificate file (save it to your local disk).</li><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Go to the Remote tab in DB Browser for SQLite Preferences. Click the button to add a new certificate to DB Browser for SQLite and choose the just downloaded certificate file.</li></ol><p>Now the Remote panel shows your identity and you can add remote databases.</p></body></html> + + + + + Local + + + + + Current Database + + + + + Clone + + + + + User + + + + + Database + + + + + Branch + + + + + Commits + + + + + Commits for + + + + + <html><head/><body><p>You are currently using a built-in, read-only identity. For uploading your database, you need to configure and use your DBHub.io account.</p><p>No DBHub.io account yet? <a href="https://dbhub.io/"><span style=" text-decoration: underline; color:#007af4;">Create one now</span></a> and import your certificate <a href="#preferences"><span style=" text-decoration: underline; color:#007af4;">here</span></a> to share your databases.</p><p>For online help visit <a href="https://dbhub.io/about"><span style=" text-decoration: underline; color:#007af4;">here</span></a>.</p></body></html> + + + + + Back + + + + + Delete Database + + + + + Delete the local clone of this database + + + + + Open in Web Browser + + + + + Open the web page for the current database in your browser + + + + + Clone from Link + + + + + Use this to download a remote database for local editing using a URL as provided on the web page of the database. + + + + + Refresh + + + + + Reload all data and update the views + + + + + F5 + + + + + Clone Database + + + + + Open Database + + + + + Open the local copy of this database + + + + + Check out Commit + + + + + Download and open this specific commit + + + + + Check out Latest Commit + + + + + Check out the latest commit of the current branch + + + + + Save Revision to File + + + + + Saves the selected revision of the database to another file + + + + + Upload Database + + + + + Upload this database as a new commit + + + + + Push currently opened database to server + + + + + Select an identity to connect + + + + + Public + + + + + This downloads a database from a remote server for local editing. +Please enter the URL to clone from. You can generate this URL by +clicking the 'Clone Database in DB4S' button on the web page +of the database. + + + + + Invalid URL: The host name does not match the host name of the current identity. + + + + + Invalid URL: No branch name specified. + + + + + Invalid URL: No commit ID specified. + + + + + You have modified the local clone of the database. Fetching this commit overrides these local changes. +Are you sure you want to proceed? + + + + + The database has unsaved changes. Are you sure you want to push it before saving? + + + + + The database you are trying to delete is currently opened. Please close it before deleting. + + + + + This deletes the local version of this database with all the changes you have not committed yet. Are you sure you want to delete this database? + + + + + RemoteLocalFilesModel + + + Name + + + + + Branch + + + + + Last modified + + + + + Size + + + + + Commit + + + + + File + + + + + RemoteModel + + + Name + + + + + Commit + + + + + Last modified + + + + + Size + + + + + Size: + + + + + Last Modified: + + + + + Licence: + + + + + Default Branch: + + + + + RemoteNetwork + + + Choose a location to save the file + + + + + Error opening remote file at %1. +%2 + + + + + Error: Invalid client certificate specified. + + + + + Please enter the passphrase for this client certificate in order to authenticate. + + + + + Cancel + + + + + Uploading remote database to +%1 + + + + + Downloading remote database from +%1 + + + + + + Error: The network is not accessible. + + + + + Error: Cannot open the file for sending. + + + + + RemotePushDialog + + + Push database + + + + + Database na&me to push to + + + + + Commit message + + + + + Database licence + + + + + Public + + + + + Branch + + + + + Force push + + + + + Username + + + + + Database will be public. Everyone has read access to it. + + + + + Database will be private. Only you have access to it. + + + + + Use with care. This can cause remote commits to be deleted. + + + + + RunSql + + + Execution aborted by user + + + + + , %1 rows affected + + + + + query executed successfully. Took %1ms%2 + + + + + executing query + + + + + SelectItemsPopup + + + A&vailable + + + + + Sele&cted + + + + + SqlExecutionArea + + + Form + + + + + Find previous match [Shift+F3] + + + + + Find previous match with wrapping + + + + + Shift+F3 + + + + + The found pattern must be a whole word + + + + + Whole Words + + + + + Text pattern to find considering the checks in this frame + + + + + Find in editor + + + + + The found pattern must match in letter case + + + + + Case Sensitive + + + + + Find next match [Enter, F3] + + + + + Find next match with wrapping + + + + + F3 + + + + + Interpret search pattern as a regular expression + + + + + <html><head/><body><p>When checked, the pattern to find is interpreted as a UNIX regular expression. See <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>.</p></body></html> + + + + + Regular Expression + + + + + + Close Find Bar + + + + + <html><head/><body><p>Results of the last executed statements.</p><p>You may want to collapse this panel and use the <span style=" font-style:italic;">SQL Log</span> dock with <span style=" font-style:italic;">User</span> selection instead.</p></body></html> + + + + + Results of the last executed statements + + + + + This field shows the results and status codes of the last executed statements. + + + + + Couldn't read file: %1. + + + + + + Couldn't save file: %1. + + + + + Your changes will be lost when reloading it! + + + + + The file "%1" was modified by another program. Do you want to reload it?%2 + + + + + SqlTextEdit + + + Ctrl+/ + + + + + SqlUiLexer + + + (X) The abs(X) function returns the absolute value of the numeric argument X. + + + + + () The changes() function returns the number of database rows that were changed or inserted or deleted by the most recently completed INSERT, DELETE, or UPDATE statement. + + + + + (X1,X2,...) The char(X1,X2,...,XN) function returns a string composed of characters having the unicode code point values of integers X1 through XN, respectively. + + + + + (X,Y,...) The coalesce() function returns a copy of its first non-NULL argument, or NULL if all arguments are NULL + + + + + (X,Y) The glob(X,Y) function is equivalent to the expression "Y GLOB X". + + + + + (X,Y) The ifnull() function returns a copy of its first non-NULL argument, or NULL if both arguments are NULL. + + + + + (X,Y) The instr(X,Y) function finds the first occurrence of string Y within string X and returns the number of prior characters plus 1, or 0 if Y is nowhere found within X. + + + + + (X) The hex() function interprets its argument as a BLOB and returns a string which is the upper-case hexadecimal rendering of the content of that blob. + + + + + () The last_insert_rowid() function returns the ROWID of the last row insert from the database connection which invoked the function. + + + + + (X) For a string value X, the length(X) function returns the number of characters (not bytes) in X prior to the first NUL character. + + + + + (X,Y) The like() function is used to implement the "Y LIKE X" expression. + + + + + (X,Y,Z) The like() function is used to implement the "Y LIKE X ESCAPE Z" expression. + + + + + (X) The load_extension(X) function loads SQLite extensions out of the shared library file named X. +Use of this function must be authorized from Preferences. + + + + + (X,Y) The load_extension(X) function loads SQLite extensions out of the shared library file named X using the entry point Y. +Use of this function must be authorized from Preferences. + + + + + (X) The lower(X) function returns a copy of string X with all ASCII characters converted to lower case. + + + + + (X) ltrim(X) removes spaces from the left side of X. + + + + + (X,Y) The ltrim(X,Y) function returns a string formed by removing any and all characters that appear in Y from the left side of X. + + + + + (X,Y,...) The multi-argument max() function returns the argument with the maximum value, or return NULL if any argument is NULL. + + + + + (X,Y,...) The multi-argument min() function returns the argument with the minimum value. + + + + + (X,Y) The nullif(X,Y) function returns its first argument if the arguments are different and NULL if the arguments are the same. + + + + + (FORMAT,...) The printf(FORMAT,...) SQL function works like the sqlite3_mprintf() C-language function and the printf() function from the standard C library. + + + + + (X) The quote(X) function returns the text of an SQL literal which is the value of its argument suitable for inclusion into an SQL statement. + + + + + () The random() function returns a pseudo-random integer between -9223372036854775808 and +9223372036854775807. + + + + + (N) The randomblob(N) function return an N-byte blob containing pseudo-random bytes. + + + + + (X,Y,Z) The replace(X,Y,Z) function returns a string formed by substituting string Z for every occurrence of string Y in string X. + + + + + (X) The round(X) function returns a floating-point value X rounded to zero digits to the right of the decimal point. + + + + + (X,Y) The round(X,Y) function returns a floating-point value X rounded to Y digits to the right of the decimal point. + + + + + (X) rtrim(X) removes spaces from the right side of X. + + + + + (X,Y) The rtrim(X,Y) function returns a string formed by removing any and all characters that appear in Y from the right side of X. + + + + + (X) The soundex(X) function returns a string that is the soundex encoding of the string X. + + + + + (X,Y) substr(X,Y) returns all characters through the end of the string X beginning with the Y-th. + + + + + (X,Y,Z) The substr(X,Y,Z) function returns a substring of input string X that begins with the Y-th character and which is Z characters long. + + + + + () The total_changes() function returns the number of row changes caused by INSERT, UPDATE or DELETE statements since the current database connection was opened. + + + + + (X) trim(X) removes spaces from both ends of X. + + + + + (X,Y) The trim(X,Y) function returns a string formed by removing any and all characters that appear in Y from both ends of X. + + + + + (X) The typeof(X) function returns a string that indicates the datatype of the expression X. + + + + + (X) The unicode(X) function returns the numeric unicode code point corresponding to the first character of the string X. + + + + + (X) The upper(X) function returns a copy of input string X in which all lower-case ASCII characters are converted to their upper-case equivalent. + + + + + (N) The zeroblob(N) function returns a BLOB consisting of N bytes of 0x00. + + + + + + + + (timestring,modifier,modifier,...) + + + + + (format,timestring,modifier,modifier,...) + + + + + (X) The avg() function returns the average value of all non-NULL X within a group. + + + + + (X) The count(X) function returns a count of the number of times that X is not NULL in a group. + + + + + (X) The group_concat() function returns a string which is the concatenation of all non-NULL values of X. + + + + + (X,Y) The group_concat() function returns a string which is the concatenation of all non-NULL values of X. If parameter Y is present then it is used as the separator between instances of X. + + + + + (X) The max() aggregate function returns the maximum value of all values in the group. + + + + + (X) The min() aggregate function returns the minimum non-NULL value of all values in the group. + + + + + + (X) The sum() and total() aggregate functions return sum of all non-NULL values in the group. + + + + + () The number of the row within the current partition. Rows are numbered starting from 1 in the order defined by the ORDER BY clause in the window definition, or in arbitrary order otherwise. + + + + + () The row_number() of the first peer in each group - the rank of the current row with gaps. If there is no ORDER BY clause, then all rows are considered peers and this function always returns 1. + + + + + () The number of the current row's peer group within its partition - the rank of the current row without gaps. Partitions are numbered starting from 1 in the order defined by the ORDER BY clause in the window definition. If there is no ORDER BY clause, then all rows are considered peers and this function always returns 1. + + + + + () Despite the name, this function always returns a value between 0.0 and 1.0 equal to (rank - 1)/(partition-rows - 1), where rank is the value returned by built-in window function rank() and partition-rows is the total number of rows in the partition. If the partition contains only one row, this function returns 0.0. + + + + + () The cumulative distribution. Calculated as row-number/partition-rows, where row-number is the value returned by row_number() for the last peer in the group and partition-rows the number of rows in the partition. + + + + + (N) Argument N is handled as an integer. This function divides the partition into N groups as evenly as possible and assigns an integer between 1 and N to each group, in the order defined by the ORDER BY clause, or in arbitrary order otherwise. If necessary, larger groups occur first. This function returns the integer value assigned to the group that the current row is a part of. + + + + + (expr) Returns the result of evaluating expression expr against the previous row in the partition. Or, if there is no previous row (because the current row is the first), NULL. + + + + + (expr,offset) If the offset argument is provided, then it must be a non-negative integer. In this case the value returned is the result of evaluating expr against the row offset rows before the current row within the partition. If offset is 0, then expr is evaluated against the current row. If there is no row offset rows before the current row, NULL is returned. + + + + + + (expr,offset,default) If default is also provided, then it is returned instead of NULL if the row identified by offset does not exist. + + + + + (expr) Returns the result of evaluating expression expr against the next row in the partition. Or, if there is no next row (because the current row is the last), NULL. + + + + + (expr,offset) If the offset argument is provided, then it must be a non-negative integer. In this case the value returned is the result of evaluating expr against the row offset rows after the current row within the partition. If offset is 0, then expr is evaluated against the current row. If there is no row offset rows after the current row, NULL is returned. + + + + + (expr) This built-in window function calculates the window frame for each row in the same way as an aggregate window function. It returns the value of expr evaluated against the first row in the window frame for each row. + + + + + (expr) This built-in window function calculates the window frame for each row in the same way as an aggregate window function. It returns the value of expr evaluated against the last row in the window frame for each row. + + + + + (expr,N) This built-in window function calculates the window frame for each row in the same way as an aggregate window function. It returns the value of expr evaluated against the row N of the window frame. Rows are numbered within the window frame starting from 1 in the order defined by the ORDER BY clause if one is present, or in arbitrary order otherwise. If there is no Nth row in the partition, then NULL is returned. + + + + + SqliteTableModel + + + reading rows + + + + + loading... + + + + + References %1(%2) +Hold %3Shift and click to jump there + + + + + Error changing data: +%1 + + + + + retrieving list of columns + + + + + Fetching data... + + + + + + Cancel + + + + + TableBrowser + + + Browse Data + + + + + &Table: + + + + + Select a table to browse data + + + + + Use this list to select a table to be displayed in the database view + + + + + This is the database table view. You can do the following actions: + - Start writing for editing inline the value. + - Double-click any record to edit its contents in the cell editor window. + - Alt+Del for deleting the cell content to NULL. + - Ctrl+" for duplicating the current record. + - Ctrl+' for copying the value from the cell above. + - Standard selection and copy/paste operations. + + + + + Text pattern to find considering the checks in this frame + + + + + Find in table + + + + + Find previous match [Shift+F3] + + + + + Find previous match with wrapping + + + + + Shift+F3 + + + + + Find next match [Enter, F3] + + + + + Find next match with wrapping + + + + + F3 + + + + + The found pattern must match in letter case + + + + + Case Sensitive + + + + + The found pattern must be a whole word + + + + + Whole Cell + + + + + Interpret search pattern as a regular expression + + + + + <html><head/><body><p>When checked, the pattern to find is interpreted as a UNIX regular expression. See <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>.</p></body></html> + + + + + Regular Expression + + + + + + Close Find Bar + + + + + Text to replace with + + + + + Replace with + + + + + Replace next match + + + + + + Replace + + + + + Replace all matches + + + + + Replace all + + + + + <html><head/><body><p>Scroll to the beginning</p></body></html> + + + + + <html><head/><body><p>Clicking this button navigates to the beginning in the table view above.</p></body></html> + + + + + |< + + + + + Scroll one page upwards + + + + + <html><head/><body><p>Clicking this button navigates one page of records upwards in the table view above.</p></body></html> + + + + + < + + + + + 0 - 0 of 0 + + + + + Scroll one page downwards + + + + + <html><head/><body><p>Clicking this button navigates one page of records downwards in the table view above.</p></body></html> + + + + + > + + + + + Scroll to the end + + + + + <html><head/><body><p>Clicking this button navigates up to the end in the table view above.</p></body></html> + + + + + >| + + + + + <html><head/><body><p>Click here to jump to the specified record</p></body></html> + + + + + <html><head/><body><p>This button is used to navigate to the record number specified in the Go to area.</p></body></html> + + + + + Go to: + + + + + Enter record number to browse + + + + + Type a record number in this area and click the Go to: button to display the record in the database view + + + + + 1 + + + + + Show rowid column + + + + + Toggle the visibility of the rowid column + + + + + Unlock view editing + + + + + This unlocks the current view for editing. However, you will need appropriate triggers for editing. + + + + + Edit display format + + + + + Edit the display format of the data in this column + + + + + + New Record + + + + + + Insert a new record in the current table + + + + + <html><head/><body><p>This button creates a new record in the database. Hold the mouse button to open a pop-up menu of different options:</p><ul><li><span style=" font-weight:600;">New Record</span>: insert a new record with default values in the database.</li><li><span style=" font-weight:600;">Insert Values...</span>: open a dialog for entering values before they are inserted in the database. This allows to enter values acomplishing the different constraints. This dialog is also open if the <span style=" font-weight:600;">New Record</span> option fails due to these constraints.</li></ul></body></html> + + + + + + Delete Record + + + + + Delete the current record + + + + + + This button deletes the record or records currently selected in the table + + + + + + Insert new record using default values in browsed table + + + + + Insert Values... + + + + + + Open a dialog for inserting values in a new record + + + + + Export to &CSV + + + + + + Export the filtered data to CSV + + + + + This button exports the data of the browsed table as currently displayed (after filters, display formats and order column) as a CSV file. + + + + + Save as &view + + + + + + Save the current filter, sort column and display formats as a view + + + + + This button saves the current setting of the browsed table (filters, display formats and order column) as an SQL view that you can later browse or use in SQL statements. + + + + + Save Table As... + + + + + + Save the table as currently displayed + + + + + <html><head/><body><p>This popup menu provides the following options applying to the currently browsed and filtered table:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Export to CSV: this option exports the data of the browsed table as currently displayed (after filters, display formats and order column) to a CSV file.</li><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Save as view: this option saves the current setting of the browsed table (filters, display formats and order column) as an SQL view that you can later browse or use in SQL statements.</li></ul></body></html> + + + + + Hide column(s) + + + + + Hide selected column(s) + + + + + Show all columns + + + + + Show all columns that were hidden + + + + + + Set encoding + + + + + Change the encoding of the text in the table cells + + + + + Set encoding for all tables + + + + + Change the default encoding assumed for all tables in the database + + + + + Clear Filters + + + + + Clear all filters + + + + + + This button clears all the filters set in the header input fields for the currently browsed table. + + + + + Clear Sorting + + + + + Reset the order of rows to the default + + + + + + This button clears the sorting columns specified for the currently browsed table and returns to the default order. + + + + + Print + + + + + Print currently browsed table data + + + + + Print currently browsed table data. Print selection if more than one cell is selected. + + + + + Ctrl+P + + + + + Refresh + + + + + Refresh the data in the selected table + + + + + This button refreshes the data in the currently selected table. + + + + + F5 + + + + + Find in cells + + + + + Open the find tool bar which allows you to search for values in the table view below. + + + + + + Bold + + + + + Ctrl+B + + + + + + Italic + + + + + + Underline + + + + + Ctrl+U + + + + + + Align Right + + + + + + Align Left + + + + + + Center Horizontally + + + + + + Justify + + + + + + Edit Conditional Formats... + + + + + Edit conditional formats for the current column + + + + + Clear Format + + + + + Clear All Formats + + + + + + Clear all cell formatting from selected cells and all conditional formats from selected columns + + + + + + Font Color + + + + + + Background Color + + + + + Toggle Format Toolbar + + + + + Show/hide format toolbar + + + + + + This button shows or hides the formatting toolbar of the Data Browser + + + + + Select column + + + + + Ctrl+Space + + + + + Replace text in cells + + + + + Filter in any column + + + + + Ctrl+R + + + + + %n row(s) + + + + + + + , %n column(s) + + + + + + + . Sum: %1; Average: %2; Min: %3; Max: %4 + + + + + Conditional formats for "%1" + + + + + determining row count... + + + + + %1 - %2 of >= %3 + + + + + %1 - %2 of %3 + + + + + Please enter a pseudo-primary key in order to enable editing on this view. This should be the name of a unique column in the view. + + + + + Delete Records + + + + + Duplicate records + + + + + Duplicate record + + + + + Ctrl+" + + + + + Adjust rows to contents + + + + + Error deleting record: +%1 + + + + + Please select a record first + + + + + There is no filter set for this table. View will not be created. + + + + + Please choose a new encoding for all tables. + + + + + Please choose a new encoding for this table. + + + + + %1 +Leave the field empty for using the database encoding. + + + + + This encoding is either not valid or not supported. + + + + + %1 replacement(s) made. + + + + + VacuumDialog + + + Compact Database + + + + + Warning: Compacting the database will commit all of your changes. + + + + + Please select the databases to co&mpact: + + + + diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/translations/sqlb_fr.qm b/src/WBCLFZSystemModule/SqliteDBProcess/src/translations/sqlb_fr.qm new file mode 100644 index 0000000000000000000000000000000000000000..589b9f6eb70052b506a3266217e86d22a4489fcb GIT binary patch literal 264290 zcmcG12Vhgx_y2kCB^_znD55wqpbQx;;6_BDWeNqMfS@30o3?>AElJ97peSwx7w(0M z2;xR@q9P7NL2)mfs5tPeg8Kc*7yqBny?J>_no|6J{flsuH|{<6+_TTQH+>$j-1pU= zZeI9$y91w{yy%%vmWYU173nY1`Eh(~FY-SAqBZuv4s9oVzf-lw0k5L%hVScCYaH-1 z+MZ%XmZCil*MC*5ap1ma`{4TPX#0wF^;)!JMBY0W?I~jR;`g&eK69zoIN}5m*Labq z=A%6g&;N+_N--|ji1unRykDx;{HCjFt-FS!T`1npAgt`PIm>%{d3;JD}`aTlB~M*YR&?)tWv zS1%WLj{#zKEE0Ebub7oH#Xa~)k#>jZcGghczH+&0&Gnz@_KnxYJr?hEX`|cAa>X63 z6tim-?F(q{7WedP#Jp^VxEBG(h_DC;(f3HYq>)5 zzXlB)-9ZZ4Rf%!<7vdXnh8U&GWsi-m#k%HAY5hW5F|O<^ZD#Zp;X7yIFp4cw? zecUL9@87cj;7MX!GD8mDwzn8>?Uasp0nY>8lf$0bAhO?l>GE(X=<-+T^4KQOQAD~t z`l*x?o+*Bcjq}%M&7Bjh8Mz^uYDcr7Q9L-~#Ciycx%br0a&4#pu^V zx_-7F+S8z&&<={;!ciFT5ybhZ|(jrx>r{0~vhO zXJQPQD}!eo3s(A0hJ+6hbI8jwGp%OWG>z@vKGk2{!)mt&t%>q>%sdc$Te4>-zzSXYc`lzuYG0FSjd(4-;+fT+$Bce z8d>}U`U!j?cW0N1weN>=Z|7xV?D4!TzbaddC;lV%KLq+aGg}^77ZPjA4tb>2tzwnj zAuA`(6S-oPJX_gLj6?R3XE$sWGjfx>PzL_qaIU=Mnk~lUw`KjynBR+M%KFV?#H?5@ zZx0EJ@z*-}#F#Hun+IjnrkKbxJLD_R!(yKDgM9zzLNP9P%l4BXAKLFBf919Zp01F; z?!8~EUc=E0{@oUdIbeUo?+=O;Utsv(`9|c6-;8#_kjRBM8y#B}iZ!sp=oFbG zmgjDx(+22*ib+Q2L5r|1*+%D+cZ%tM#VBgERg9vZMo|Fcc0SH1dhZDE?JDDh$}g!Q8RNZropIS->&1F*y>Z!n<3u_p?=27Q}G38CuHDiv*hqstni(VG<+mlsm z-Cb+uR)Nnh?QZ7voelZ=yP4msMy%Bf&HM*}pV=GDf*%`2j@@GJ@y_02-O=7W$TbM- zUt)GRFe1jiMP`TY7l}FLSF^AS*7u=f%))y>hedCjh0opq{V~%#vNz^eiFQsztoLp+ z`<(_ldv?3oe;>?egwGs$JoszJp62*NfZxa0o8!9`L%(h{Cp_O*j5E(LC*C{`eAC7Z zUJJRhwBD>M1;6Znf*JnibFm&-WlkF~OstO&GSB)oCg!HC=7sG>iup@h^Wxh#iPgTh zIq#-+BGdbs^GkP%@xp)1E0=)}N+RY}_r4~^S!2yx4&EllfhU-^yFm9>Jzy?=yRFE= zkIW_4t`XzN3UgW4^Tar6lKJ>reBbXH^GV992cI*asyZC&@E`M;S><2pWnJ=Ff0lcR9@`JO*GOjgW zerCQHtxqvueE@LRoMXN{^H?!IS!TXl5fFLdQS<#yFNhp-s`Tr1|r4Lty88 zZvN^8y*+b@xqS%a!K&kCnx`69hCp2SasX2gC@GgeDYVTeNWhj6PH?t+}u~p z3r@2-p79*)!zothuL1vaKUzm+wH2##j&<}Y25hrD>$nM+_nB{5eKx-(##dTZZK0n&w@QB8F2?z1StE}Gou7HQHR0y_VUK)gO?>W9 zF;1Oio!;esu?}BnO>Vpc`tuU2;*LpTe1EwWyc_Fx;m=mpOW^z3q1Kej6@cdwtG?F< z(03nN(Y$lSd||jXy`n$#{`qLj(H>!)dF%aR?A6UW=b^>mqfXXUU)(N6_)Y7EOUH=u z_)P2ey`g8??yzpZq>IS@4_b@*hDA<_T8oyh63gYc?zsL|=*=apHH4}xBPzKiwLyj(G_ea3oj82F|t zX1&nnQ87mLwO)xlDaNL6tXJ+EA?9;)tXHpt+_@p!dh-ppNO*s1+T zvCsOdsz!{eL#?mEUqQcltzWJx665)NYx^rfv0f>(ej9TE?oYG+I(xpDAI)@`H%$`x zdald7tv&Sa2QGK^a52AmM77r9jV|Ad17OE|>}u0`yO^h5=Q{B5keCbicC~$ch?v(* zaQO>P7Nf&zmw!b^$d_we?K)vSJ~+?S@m0w0h90i2mq4E1@wBUG4diF&4%g9NRf>_l z)^+^M(?AFLt`qkR!Y^6nIb$$qPu=Y{cC68_u z>&QP`^Bw>^*VVcf)LSB5{?B#A;2T8F`B=5)&`(^~t}7Pnmd&o~hdeEEdVkfL^Doxz zo2RSRnmWgI{oL!}KfI;e*VpRyy`iq_7u^rnYJuy<1*Kvg`;hDA39H4N|G4YcBW8=$ zxXE?fzf9QIXS!~`w1b#!pK~p~@FFn|INWvjQFv~|RM*|dkbf?6-Cg1mbA7gMH5x0Kmb#XfZxZ97H(mG6-ze72=b-&mjMLkw*8KSow7=l`-DrWg)BB(W z|D7H{`n?PyYBx~i(*dqk??Qgh>FIiY z*fP+A&-MJX1+a(qbiI0Uff#T6=vu$y4&bq;Ys1}}q1TUgZCL$?$eNX|H+n-4|M{_N z~I+5>lodBGu8FZW#Es|C%E2w@OQC3^142*fLwU(A=l?;b`k5I8(m+w z2ORfZ>iYV5_@uKVuJ2|;Z_aP+`aTH!zP-iu{kr)gv97MIw?GcHf712SgjOOwEZ6Vh zy+EfuTz_OAD&}Jkx&AK~;}3k<_2=ttp|^|O?q>?b{C<>bt;Zg6XXCqU_qjdi!DkcrGl)G55Pq+X+4P)Q|4TJ?DzCZyR^@ z)}WZDMcuXipMZQG@2(%VSd5eX?uK&6r!jlDW4HGg>Gr<6@g~6g-uv$956%_q*4NxK zj9bOHtf%|Tt9}*p>8Nf$e9L|I7RZykzH?vD4|1U57S)=g*19ja>m4y}c*cFH;@zI*<6@H6k*$Gu<@=;5$w?rZ*9 zFV>-^`-UHSVqW*74T=n#@4o#d(0lEV?nODziTP$H_Z_2vmw7|ncl?F_{-aiaUh9Ps~pOWbQ0fId#Y(Y+z^f*7Z~>3;Kd z$dBjtb#FZQ2+-Zb?u}2+5$l;-+;80udc5;}_vhWwe)*;Qi^ty+W5qe{Z_jxhe(SI9 z?Z*{}wfE)joi}0J?LD>chYCbF$jL3;lWShOEvj4;Kjy%_{6LTFk+hW))7^B-R_( zW*xD41m z8XU$rrQ5QGyac`f$F*6d3wwcYhG&g9v=Q>{+pLl67Q%jgA#3~{c<#l0vnEek2!A)0 zHF+lJzxw#B$qPOg(_NTV+50Fl=8jaYb?3jbszD#pW7MMuN0dn4=Or@<$&r?M^`41IT9o2<*% z?!dZ^&RWn1->-3JEqD%g;=+wtS6qS^*VuEi7Ct;cjP={Iu5DWh`uid4x;^@fQFc_; z-5(DV`L!hLfe#RGSUn(X#i_l-c<-{Tl_zc$tJ`B)PySUZ)?HU;t-f>??ADL6UhaG@ z`2Mb}m&?CLd}4amh7*23JnGG?4QG!LS@1#Dd)Hqr#-mHK-uwJI@JC_Rho^o3|Fk^o z^RwR(>)I7rpRapV%vHZ$`V(_Q+k+T(VkiVsfHi=&8TeSR?zRie$IC71Yg!4o1N8rlbDTnX1972{_)3?vRj`z zMvU{;W_P$}4fNDGx_#r=?8E-m7I06_?s~+pkn3%-yM1xKm>2KNF3#Tozk5*jfUkcL zbF4di&^fRVK3wr zb~*U6S9S&Lc=P**vMa9wpLBdSyQ=Ib#96-0u13tmxaW)P>Zzco!gI2xVx6tqdS*}k zWGCV;HQ7@?2c4d^G<({T14Wknk{v08ece5lJ@Z?vcfU)s&-&;c*jwYX&pGN<#1|%H z&wUL3UdPw6FL>iT_<8G9YYsg#`;u^9vBI0PFYgXIefQDqE4Cu;^yQ=33lBa)%+hw* z*FG{H^WKzw!&mbm9}mmE^^Xpq7gzS3v$5V)&t>2FPN^6_t;$}EeyxQEWiS2{@}ld8 z?0bH?1p0kd_JiFZ?~d=D{m>TJH_-*zkGv0kcuN25M+?S_@zM*~Puz8=7!$T-zcdc^ z>*aT6zk2R$u`cvvZ@2;S{g6|#H!SjswQ^wg8`l+x+L|<7nVvqnZ8T zNw5>jc4mJ%Z>Lx})3d+K!umcrEqil+_=hL|sao@(7qY+eUx2vOS=m1>+#hz|Puahf zEfsUZ#O%LLb%U-NbKGtAKz!=coUDO>f78;Oyw<==#}zsGRXfGF@!Xs}Znz8ly*_7; zO>QwJ-I&wnQ_#g<-E;Pz2)@7gubhJ}o-eXvZBE;jhlzQ`O*x%@1|RJ8Mov+Ay_n~I zlhf-$%;(5%IlbNm-j*JkbNJy~MOIyvbJYLs5ZU^SYE5@Er_T>_#oRhawbtrwIsLOu z#Ivr>DPFb|e#VrXL5L|Dk#0GI!|T!CjX6UuIs|dJ>YULxfj{5-BxiiA403ctPI(>l z(@~L};A5YOJa9u!^&V}->K@Fg*#x-H_2o?OzaIXRm2+m>O=1gb!I}&m1Csk`c zT9dQnjw2EO{v>DFmtTo_+0i-o=6{9wXf)@(bpzlBw#s>6pG_jaY|DAzt7@^{e>P{u z!=uD{zE{p;w}FnAzL@i5hioxNjm~*y-Ya50bFyl!N8iXQne*D`|AxG3pYyuGHk9+`^=~0gx;*Ej zQBlzQX*pjMb^txB&e^;-^zCP!=KqXKQ2XoH=U64+sIpCf4!9R`_xtNGk?zcqh!6vT|egh z0sq$QH7HkR;(ZyH>z+PaWd0Yr{dSXXx2;vJ+3n`soTCBHIVHKdC)_H=En9N)cKii- za#ZeKN4+WX$i2C(mtx*e{-j#7?y=nceg&Pzy5t`CL!lVAb;~^{P$BYjm)v&Cf!CXJ za=Y9!0rAT@xrMjQ7Q=sDZjb%&{*no~$9N}+`QohHWA3>De&d4NV~0T=pY6{*zHdJ< zMtrAQ^Q0lFwH7YPEqU7~M%Q(@!>f0S{QIojQrNk2_r1Aevq6`$+_~cx1)z6c%bjo> z`01zpRcpO)Np9uAFGJtd){Y+o@y zoSQqdAM{3t%W`M+{{(TO?W(nwcys5x0XWM8x#!&pIv(9K_lkF6rygFEd*i<`ZpB`? zH-8FzUwl;V-S;C-bH}jUr=EO3jNyH9pWX_+7+9bC{9xF-pDfH>ePM5rqt41*^J)(< z-?$=oZSi)@}MxiEL@qUXi@`PkfT)E9&Q z%>C^t^f#iy<9h6VG0vUsai0|x^P(Uq9l>A9=r+pB~|9bv5AV6Yv~x=T?!2 ziahPM9tpiv=IQt|)^F~;o^HP^hMm~k)7@PlR+pDNh4X>0R%<^Y_k_!)njr?3B3v0m%%IUyhZN%cXV0l$aEczLR4@KX3SD^__%^nl(te{avY9jl;->+jcU!dKY1$qKn{#p?5RBQSHuTS^909PVxDxDC%7EfN1lOp1=>eFRrhT| zek0(S@)_j8v3Gdt9s^z7&mA`wh;eO=XYrGuZ~s=$l7oPUva>w*tk_qq$332V z-o77n*vqr@YQ%3IY43TsYLm!~Vb8Amp2vTB8-Cxto~OPA-p; zo}L$j9rb{2S3m4|u`mYz^?uKbD~2GySLaz9L)>EG6xEvNR;kwdu-x(ih`;!wr+rR21=8sc6zZGqUef^Q=_X*oT zuLYhz2D*T^kmry0@xAu-JYyU9>6+Gg7T16L;5_TG*@%BF&vOyJ<9vDEUvU41b$M;h z1HHa@RNlV#_7(ZIFzoyYp?anoMMROqULhbX4u0sEXd*}5S+*V|2ZC;OgTgBM8Jg=v52XdTW=k?qSz4h?; zyyGBWe`2Y<_ZWjO4=RTETe zv>lhX)^v&W@Rxb7e!oeq!5`$kHam#8uq*HN+sS`_<*k2rA>zJQ=e-%24LjrPyp02a z{~6chy|oa0SbAOFd%=hp%X9MHUvsiZbIF@A63-OGANq_Wbx->6lBV5N8e=L#{u?cV)=8U(qs)$3n_ zbv}NP_fT(0q^PgALjd`bd*1RMHf=ldOMY*cDIb8}hIqSP2fAK4-`o9I;P0s|-tKcD zk1p=*?N!u*Fv5qVE_Pz#qKJjqx@sEuVsruP_!cySr z);Zqd)3=L^ILBLj{{X}n7kCF<^|qLo+~pm#V=>w@470#CtjEV8d4LHPd1D?l{i7aNvt#ESTrLt~2=X_debmmLpEK{w43CC)$Xy za*}GTCntIDDA>$Y1tBSqP`(6}Ty~X={_n;ViR(sbRx*Yc0HQu$i7a*@$ z>wOJzAUWhB@0;sEcL%@V-FObxVbenI`^Q3#EPdJg(M7=1feXE#tj4-kU*!GtGsy3u zBfZ~0g81B71*$d2kM#cV=~npBe|dj;xCDIoy7%{P&%Dd4_=SF$h`dA-#~xI=H+|a7b2dvHGkiH=%dZmsXSe;*d+LdBnw>ZCKJm_NXVBP-w0$Rjf0>|c;Oo06#n3+HL zI@pt|e#jsEHst3ukL8b=`+^vcACNz8Bk1noto&1o)%?*5X$A z^&j+y+|JIQcE%Xs>6`pn!!e)7_ROEXFX;5-W%;uY-i+sF=AXNyo5*Dy^5=A`fS$Z4 z|GcY!$J@ThzW{MAv)5VqmmLCn{@|AU%g@^hJ@Hrmbu(@i^QOb{7e(ib^d6u8!29h) z%5Tnpw0m1I-yW3z#6!;`4!%Br)qtI14PBo9LYsx)TW|iFo5CVH+vTr$^<&WWU-_?i zkthC7hx`pW&@U@j<-c(>_^WPI{^xV*MYfgXf4&fY`GWrWpMSCj{Qp+|w=2I8BY1B9 zx8GwOuJGjltMw`|#)k6$e0e?W$9MDpeD8GlIWzMAbHT%ipWRgep9%Wz!UC&rSgg{9 zf;`g8vCkIdZQfUm`6m_l27Cqm`EEh0lFvb(B?WsQfcIZ93l4rC{5Svl0>1@4F#nr^ zc58NudEu!A?a%xI^+Q8dYa9?M=yoRTg}v4m9NoPD`fEtR(aQn6ZC=4~Z=E2>sWcbxG{ z!RZ}ch|km%1h#BK9<5J7O~pFMxgQIrd@)I^m#!KzY`ba=e>Y#jq8RLv z>Ar&3kVm=Y0H4o`d0g_M&sW`7jJ@aiTActqOufmsPbJp3@lIcxovTEC8t2=$E9BWe z3w-nqwH ze6#dnU$1osi)nWA_51P>_|s#3{eETpq;E*=3czu`Z|KBpL?%!54V`m%ddyKM*pL(^W77gF2>f0zGc;rPbDjT%Lg|?-mmxFw{Hmc{sX@Ij-7@4 z#gD#+ceWO}be8X_k}~*hfB2qy{6pZeyYHp0C1R|(&i69nisqB&_+Ep3D?88gZ8!-0 zJnwej8(nS{Bd3FE%`Xy_)ALajoyj?5bMYWhcyzDI;lnFAwLHtAeB<2zLiToKF?C08}M(5 z^cO$=MsR(GMDc6{-y86)QGFUMC(AGip}!!m2k}G>nRN=3NxDss?ef7s&ISYQ~H9uy^Uc#zhUQM1+A@Ea#@rft?Tddw_z(|}~1bx-v z4|^d5jjC502l^?(u4kd=$PtJgzEi2*DaTCtjq~MP^o;z{8`p;8i8FA$7JmZxJ`(Tp zc|Pe^c-L=mMt&KKeK^B(*K0b)Is@PI?3%8K?n&PzMR2`HJrT6!=wGiJ@!`icVwKcVfhY8+ zx@V53>45K(Za8;d)vHVV@LMW&qmsU|gkDn+@!khx_`w+*w@Qvjr7t-q1_*kC9*V#T z{8I=T2m{hWyc@yiqNGtYjTPZ)1FjY(IIcaY=%4C~v>8Bu_9{0Ibu51P-z3JRdSv4Jfk+Uf0NY!EVN?PR`_I1Au!F4{t zUNz_K4mCw(nxY)ON$KcFT6<-Zv92kw<#%kHrb@6rfVM%+m~h7+>B)hla6c%Wyc1LM zID}aSK{ZjxH_D1yRId|?Vq7IRrAzi?nXRATzk}lRG%Wtf4{bsHP=@#G(aThYQ9Ux( zFO2V8fdD>}3yTuaQUdRqC#NaM_3BLll#~=U{)!ar|LfdS`F7XirNgc{^?!w+kD?E1 z>U4Sa&tZyMsREeS^E(os9N9@q4@0J<%CrAlnnyc{kjH&N?XN=Lw{Et=y% z30m*!*^kC|@-t;CZ8UASX+9pV_?h>H;uGy9t)D4T*&Dguwt}cPDP6SvNRCg(T`~Hn z#Y$;T8^aHoRIltXTl4qBJ;#o4q&~IUk$9f+z7p->_}&A5GjUZqG&x{ z3G1qF4nvMv*wgfLpPE=*ZQnjM!9ZnE-#+E_m9zTxY3N(h-`_t{KO-89_^aw8{?R87 z3&n!|P}Cm?`|BHmVSlu~F;Wri=C6tbgEIn=pnrNO+8C(y$Li~A{f*IJB|iBpBEdim z4^;-Eq3ST+t@H;gLovI%%0Mho9*740RiWBow6IT61BV_G<2dD^?zN$cV3<8MhARO_ ztS0CmUVlcYwl?4&*;tOd{$ctF|JYz88mbTbdv)^%qW&4d+FG`JVNmH9|Da$v7y)R_ zymYu96RZWCkwX9Y`bK{RrdU^B8LFDa8xa5;jYUG`jhufh36_fbFy?|`qyG9T4u*-u zK~BtNbTH`e6Y$qWf>p=2uZhJPdKVSVm@%WUI^0-TAE_>~pD(Izs4e6|wC}q+PxUDZ z^i|kQ={p+lyiOxY4KRG(&sduZ{%j{0+51t}LhmNCT~4Rm$-(=nuqtH$h2sS}kssYl0)( z2{bghL!jb>(kI%0rHaO8)dr7m4>AqMx<^B21bav80=2crweMR-c%t=HF-4!C$v8;> zCBp`d9Ogec<}U-aP6dEfk@`A+pCWeHHwC9a>9kmPOlnH7BBn6fzHdw8##b=yJ-c_p z-vZ!$$|FU673u62M3waw1oFr@HHE^}aZ+k&oXmhW)7{^IUx^G&+5pB6&Z?u}s7xjp zaJ$B~X8M*ug-{68M(ZhA^eT=H)lT(?z=Qs1Fy=3xp>VKG>LaFK(~8_-wYT^AsFuL zx3?Sxv!_Sgp&I~Whz1n{bvpb)_cc}Z(^aIYO4Ci7R@yMr4z_-)5oV2JYUv;vO|2^Y zp~+LD0&ITy4C|qTS#~JSSrHm=P9V++1vp_pzDtvj?suay|7f-{NR&PY!b)ehP#JiC z-&AfMW24YB=S-8GqtcMEodAZ!_?dTT2$Rl+rbyBRO~S3f zFF)HMqmY7>!3qWxNyj#x7}VN=_q7A2*N{DOHKyU}cdDo4*|lhN8cQ-8of(wCj9{p` zCf56?9zCGYM+c?{Miy)h)-&gy9l` zMHz`HwS>3A!5OgdD(WMZw)NQ(45Nb47;T@DU{#>8HWp2RClbF&fI?vyhp;-Q2WlIk zlR~tQU<@`@{V7u%%ct!=E9z?->%zMWS#cm-5v;Y}Rrsl>t%nV!?6OKF>w&gd4J5xm zI5Sw$m_Wm{#$aTY9;b<_@b#;#9Hmf{q%KaBelkUg79GX2Ga0)rZW0o{0Nwjbu?%_) z3i^yAu8>z1p+%vLoE$<_{sbY~WUQ}~9d(4dslf1~4?C8ig+ONELGsseOnqMqV@F)= zp0GI~G0UO-Kr*x7Ttpk=A7%tJf!ZVklT{H2=r#zS!zLR|!Xet=n%+)m7DL@sR8^}0 zTd3Rd68il*5iYEb?uU})VzI!MPSB*U5X|{WY(zXEE$;l#Hnrla$p#-9h+C-zR zx8!1RI^bXrXTW`mYl0P1{WO(gkw7RM>z(WG(6jk*dth8gS7g={Oae6>X|FhsYFxH3 z%#+Ax*=rt!_;YeHq?7dZ*4Y+LGdU_wEH|jhYl`HXnNh<$(6Bg?sPY-@X;5lO_pEbf ze4hpd5z35`&S+KRX;Lw1oMst-07Tua!e&WgxeNddghJ;O$az|wYqe5~6JG)eIYFFs!jp_xah7~9 z*_g6vmbe+NW=1Zo#wWhXxEixD#JL_#kI|BG)LT6G0}@PN>8Jsb2v8HKtRx!Z(%(Nk z7>x$15sIKEn9vx(aCImgL{Vsmp3P#RGvaEsU=2V1Y8GJR_ggi;%!IioJZR{(uzzZB z)~?CYco3Gkt%Lsg2Us)I#IGS~J;vYo`l#w@_YrKP;6#J^fF*>)=vF8aP+dIz3l)=7q3 z&sYaildZ^P7D~6W`A+go2u~d>8j>R4v(rBQ6zKR?`p8Th55pga8DAZuHNMj5;5Mpq zr2-gViZ%o*7+@lQDg!~eZv0k7PV|FG!?6%P(`QysmBO=)_fqID!-HkB8te;rrZQ9k zt4F)WG2YQ3DcxP6ZLQd%f&7iIRzq!ImNP<>BdBN!gJ-2a_m)ip64W*eg04tuqNFl>lJNk*!1G)l~!ZIA=oiVa;oZvIt6q#Hc?Q(B{O~d!80~p2E?>my;8G|()BtPvSrE7It zf@bUI6^nTnb~xH?$bER7ir;3}L6jbf$a*1R`NljVD1ZF0APUY&%pGGiEJbHxoGCSlDQ1VJIvZIJiHr+4fODJ)c>}nwrn`DPDF01^t8rZr{)Ljh& zy90RyPzpQLos|b+%Rn{-rbA;lODS?UaIpJ-sF&;#B5kNN#MzJZ;Y4VNCDI95j=GfQ zS0t`AxOSRWlJx;8g!;oSli>3-@V-@&ESSLWV1LH{Ml~W+($Ih)rjD%ZX#*X=TC%Pn z5`!`Na1>d2{hU`+L~qsKz=hV*yN?aV0+^7ai$p9E59C4$F!Cx5X)Vxf(emG8X=Fwu z`O~pP$5!JgjueEQ>l*4Kfk+6n#27IomqK4gY?Ui)b(ayUV6M9=?I70#@rmVk4n6b% z1+eslawCWWgCazIv}jLSV_ZKT*ORFtk#dvnet-87-Td9VV`YQg>l;-5q)&CEzOkWi zQJ*;YeUI;>pzWIx+;ijLj!J+_bW^Mm+%T4AR?_m1P^8NzY;tYMYSu(gUBO`GEWEGZ zreCB&P6;AD5|bIl$sojD*}XmtWb?lf%n>HcXxK2$ZRFOJ&Tm4oH^wJblb94sE^C3^ zOkCYBDPpQ8rWITAYEc`c(yC6M^SUhu1NclzW{Dd6v3ZxuRZCP{Nldp0)2-ojYl5{6 zYNqO+(U4}aJnHB)A&C%%{iT*QnsN0`!7zTcQdBl1wq&3gl>A>wtTVu@Cz$^gbzKpM zZ(3p@s0LZnm1!YPj^CpIAS&teWfrBp9)TDn`uSXPXwgxkdKsgjJSt_fUNnLJKA6`u z&TCpD;(m$$2F%2_WSJSLq9Yt>42S9CMJpnqhFIpcxGFx^XkxCqVvMU`2jpoQM8MMa z><1tuO3ol@an4%Mr#|hN3(2#lNU@_+6d@Ea5rtPRAp3*-N)od@5wneQw#b6|`!Gq~ zms1{~Vt4Vl9#t;y`1O>To9C3NJWKj#q`r&eGma%@%n-d@SJDU2*xxwgk@yzD3<<4< zG&z*)JWC_SS>3-kPp)c=^F%oSX3|GBed7fPTBz$gyFEvmL*%UKi8*RaJI0#5mTa4f zk^ruzzhMiEX6QSyYCSQV>732FW`WSBgKWD%ddKrIRSq$2Lb1R&%3*rHnzoSuLZ>B0Dm-qkEiRCVAuLc0Uy7qnWl4>!sxVe zTskb{BnHPzrWzoKbcn~vwK1wm@vVzNot&N%5TtKGLhK;D65t)szcEycdIJQYI`r(8 zkWfftcj%Q7gp$9xvtX=}C=Q(yOvj{emoX)qsGsT3Q(4zdH1kL-QL+t0w^G|SIyPjN zyQhml4z68fih7+lRrX>6ABPSJ!^{a)#`R@UxIWxHI1?2&43AT;^#-0YBIXpZEsM!@ zwv{&MuC%>v(6pfE0d4ODZ2pn;(P)SgDMhmfBGruyl}CGLgsbWH0xdXnL2q&(G9Lvf zcI8qtlN=S_Wl^j&AvcNx%FG*wHUUG=GiAsGE`4#CVb3=s>b`@kpV^4hT~iAs8D*FeEvKRk78H}6 zygMR(mu?E>dAg;=BswJyBmTN(T{|;6N=?m|Okl(-^`N$20vN%rKBX0qY_k=CUDDh> zI0Q-VKmsw7%b=;d*B2#BHCm9}N8o$1cM!KGVMW96fh!z z;!q{q8h;lh|IC}aJn#%XM#|5Qi&pOw(16IC>|iDqbvq+?8lKb@Ef*`uSJ1jRKl zK^VS{CzT9D{Ui!8Rmmi0?bXsJDXqLe5lI#*>O}5avk!pVV5K952)C06eDS5GXuk=-;#hb zySNc`0v+oz!`LfsRtL~SA}*AewI(mt1JNXkNAVIpw;q68ZO2(UY7pmi<=QkwXIrSq zTF?+fGL&vLsx!X~2AcaxaiYtD!NdC%qrR@XK7uGpGcX_6OlPUz*MME9WQ1ODM^E(h|cqy^q{V0WmC)Jf{nv1-n5 zcR6KPd_;yrZ7$>(dThItBUP6r^bMZ-41XDL(HV$je&&jDKH8tuAqZQ4rLLi!-QgP1 zY-TTvOWWqGHd8gPXMU4!Fq}&+=DUSB* zI$$S zEdVorYOfE4q%91U6T7DVnsNlDvQ!VOhJgse*p9n`bHK!x-8c6>G{w=eXRrF^G2 ztYAjCj)k87SYRqtemzE4AkZ07WpgN6L|H@)2Mzek0~J#n8{m~UD4C20P#+hUx9$96 z!t|Uf{W`M@uY=;5$uV4uXA<@H9y?B&1YAaiEi6RPs#ud~F+>a%U1kFY__0pB|04g!|~QT9&YE`o3Z$-F~$)sjL{1?$$*8V5p*CR zDRPmROKWE?4(>Cf>nKeX|=@Blg%2ANi)saG+2rot$1=Q_qs*fL(q>g9*hU zal0u|(A23z&rbdsHKB?cwdXL-y%dW9TvBlj2#yeqt$I~TKwb{TlVF5slaGt*9Txbs9kv-Fj(gQLu%Eo?DFP|IJ{ z7_LwWah3}ui|Xo%X5qixV1Wa5%^>VwB9%zi zRjEW$ZKCgj5)?>cAE!UuSXUm5>_)#{K-yGoX2)y5ccX(tWgu3g1x`u=FrLrT0&F+> zUy)WVO|4;XMY4ISh0%d79nxyb$27=?1EJI!wl4T5tET(us%h|O1tVLikxrR^p?|ju zs9T`ME^%+u@!ZK;tc0UTqOf6fL3yExh1hez%m%Ol(nScVs^H>otOcD4@@P4*HW;1H z1kN%OV$R^;On-T8efe(mdT1JH@49CXd){sG?yt^-pthx{LoH9e%&boxP{KeGB@E+V zl;M^5e3*KY4o|v$(r##AdcYrSsE01?T!#wIP!t<{!j;j({)VyABS~^hQNoWPaGkX9 z)V?b%vl0LeyDhO|t%f$%hLFLi3}`=L_e`-?Aa8o1^lMpqffzudN6)Z&L}9RVUx)Zw zpt81U%cL#G5$Khkt|NoIBPwElM*^iwHX8HVn?zhJ0jqaZJ^I@dr$f!TduY z)>IPE@HfFS>Y-=G7kT#$-V((QcDYyP@tl=qLehSg>_m?{d0qBRg`u_{N?kd2yTMFc zZ*CsRxZYz_<>_v&cjqJwj#D&5lZS`&*NQ#QsW zR^8PR``kF|J&VC;+Rqps2qVB9QPrBQ@#bjEmCgnuQuJ>kiMO+nnW(Fut~{1zIvAEZ zFs8=9OY#QbOzPd17PS9#1s0jtVS)X*JCB9C6c6gK3oM|c@tT39HDIAI&?R;8KviNg zx&3Of_k|hsUEt%!|6;ozkD#O5tfN-;RzI$?9WP9Fp?JNS=_|_6hA#Wk5gffm%P-ER zz9G$S>Z?GAIf9t5-qP0;cTpWmMg^}5ny5W}&ERrh;F4k_l-Njt-n0Z*brm!)VAa@T$D;q*;AvtAiu%|M!iv&&R2CIOkNKQ@!?Vv&aeCen!x zE7PiWyjSk2Agqp$LCUn{HaIl3E6T5)G3$K#ftC*Q~l%i`OoT^>C zMJ{!`_mOx%g{m-mutlocL#2Ny^wZ6vdFSs4 zDIDHK9|aJb471ZXOct0q`t8PsUA$X{(YJu&IB(77q_@;nYhFYo$A9#DDhr>0zk`Ax zs%VhGNSlxn@)KnMyPVqCe;7OlaS-cI0C-4?0PYfdW1FZeJ57;H^}E7fCJuKJ=yof;BN^mz|SsMuO=R(o$t4DT1`662OU`JY~%EwjdF$+aX$< zV;6WNLs%u1ZO4~=Q|yp`oTC@Chexf+n2fE4?DKqSvN+e1Qx94?^7+3ddk_iaypv;m zlx6z7OJ{sWe|QF&rgfbtp)Zng6>;5;W$P%UPA}0@vG>I`RlPbU;_QJ-)&?Avv$CsO z>|~6M9S6(gWCv2tZP?$&i1xB|YDy=$SqfmUnjQC+-w&&M$dz!|BmUwo;Qk#r+l?S6qcKsi*vFj1&QdMC*S{Sx5&vF30C5S!E zQqna5I5oX$2%4@Ralw0}PQB{RR$8s$DGl`MB=<*Hxvn+j7O-B6ohefHk5$aMO8^c=CYk8RDA_E_kDU=wD=J5np$HdtWR6-AEo)I3Vs#-U=Z0cA|$+{RttWnL0qk}Eh!s_Bq9 zL~IN28|ARFUE2cK&}&prbyO5Hn~V@_5#(3FK$(0&*sC zND4%tV=2;lp>C!VKr6!`vj2VwoEfmB!1HZ5P`F)BPu8=V3`TYC&?GT6+cQyky) z2qeDr!L^m4%5W#BY<12SjuC@~jn&TT#-f&T$YpFij`5tb^2Vr2jWt=vGvZiqR=45Xmz5SlFZ*k+OC=-H;oQC@q3 z97%|&?CZoMyTm78LmnuvkFb&zwxBLqMKPByzgGdrCh*7f)eYQixL{fPZ8%OJ{rcO=f9R&ZqL(^##OyNM3!s_pPG&5n#bGmAlPI#&lV< zNg!$CW4u=)6AjSgv#G`b^pYDTFlKa1Mj6SL+Xrdi#9n1 zqyyq(F&oN%?tP-2q~}lBPs!>y)LP|a+Hqt@XozDLc56qIp?BJ1Om6E?7DI%Lig0g^ zzD}K<`D{0Jz-dAutkLIFD+=Z=3VX|%ih4z{%OhG}5kkRLr5!P3cvnRbZ8}kra9pi} zAA_TerUu~)l?N*V_~iw?F(Xb_W>I-zoV_xEkt*1=8rVI{BArs4JgT!$WYMP7aA-3VDUV0+ zo1e+hCTOR){YIfab5@XQger|bgM;d1m$zL!(8mlKe@8~`25yWspypm37#%;pCEfAm ziMKS-9DCV9yokiIM@jkUSfsH6rToF+I1sN^C71S%*CLT7nG&_blg>dB9+i!vz*c*| zGI!H<*Flv8S?83*Wkd52wT8*ga0OYL#l|$g4@-359fJHMEIohc4n5T=F`40M_L$(z zk9%YUC_goolQkldx5@mH7v86~U!f`!0A`I=Qmy&h1I`S7dzAs=zHQnvoQO`wXM!oeEE1|l;b==}-^F>$nSp2p zzeYzznfsV}MFDM@1%Mr)ORF)8Wm=@7NDU}3-eH+M6se;@jXi4+N-gelVOAUdX^&^w`b4jEZp6hb?LP7Eo_1+;m0d zc%wA86BRm%)orE5QHqKYD5jM&k;;V_ltxEAk`2lFTq}^|E81>O_61TSp4^zF%@Ud~ znqFvuYe1Q9Y8vylZAd4^bBy}=3>|psjUXBhPmjx(3hyufef| zb*@aSbd2tkG`T1W)ERMxC`jNaPYo7D;G&`?6LQjbFxjXgGg7;$I6|T~4|{V$M(Mzu z2Vivdy{0JbR}u3m-QgQC<#=bhB#kPap$Hu`*9FIVEs{_6*S1coMWfwku9Z^;(ubfr zXNU(Xr*P9CeGS&-pdy85%Gxo1B0U~%@bf7AOqeQwhNMZDE~>Nohr)qKMsnBgy*3Y0 zAx`N^84$^4kK>&>#!vFbT?V#vuXbL93}T;TkX&_fmwDDP0` zjt~B71vcd? z0luILC#!YI1Z1JI>U8A2>nmMC@%J`3c>40{0C6%8QaU-@*EDK~ zx|0Of+Z5B+BXg^m1xTUFU(%D;H z_2TH7P*tpJai-V%%G!h+)zrf|b8#tkDSPQtCKn1cqhM)tB^<$K73_(~#H4Pc(JS0^ zK!RaA&6za%!2@{Y7M4=QB5^hrj?A>U+;c&?^VbY_l zq*S}q-KvFVT9$IU3eYpIx2* zn%;FUbn6@|l}rc}^3EvUwqljT}GX4CSjy7!ePrW3;$luA1|9EpIa0fOEu3aOT5iJ0O>PlOm;JpNz z4zxjGr z&?>X*$yqY3TmnYr zrO4kyqo%NAG%{MBdezS1v1p+szcp3k?;7R1Mz&*%4&4WcX z8PT{;T;V%xmKt};8OcCKvq7V>B-v9UpUI$v7|a<}Hq6g0a+yTNFxYraLo1ranFyhf zsKQ@LScXEm#JT_=#qdark?k{@b%3-xa0E^jl9AY%&422qi zaV#h2sqME+Qq!SUEeR93hQ#0pbF*ZEs2oAZKm%jqnc(rLIC$z-Nmp}p@Gj=c^-h;c zwj5(NMq7l`%$X*k9lfUZVj+4Rg}!ODQd!v9B~}JH$5zs>X{ly8)n?OmIHc5OqM5kk z6sk@rqvJzihOJRN-HOFU*bIdqJK!PUFjNcuqfl+43MYGEw?fA9W12Rzc(9Z05u-y@ z#hPY#n!TGft!=~F&NLIPWUgw3AiAba^f_@rFfuqp8)uhvOgRFLEQ+OF~Q%N!+ zY}d-#yH1>9D_umc>o#b~FrL6S9NX0)501f^GHq>;PDkIoMUqv94T}X-kpP1rN_PhmKd3fKi&+M35|7oZsz1A^ z1fA%gt4_Aeo!|Kj|h6h zVP+#L3XW4cF$AwR}@RNNMa(`3mced`Zj9Z^=%+(<#DYckO z;CClrK+N%|8G019B(tT5o&{wbrGv9Ze49CT{iZV}%@5w;OdY;>jeJ2D$R;&L*`t1J zn^8MP6fNV&bg3Hg5U7@?f7>T|wRp10V+=Gjel8ik*vf-T z%0;G4z-Jw$LB?_%x8_xb9zhHE%n^ViCT!DWfN=zlxR1E1K4zkyRtVe^7%+0bf z$1k*%4$H%6(W_t1Q~l}h`UjG44thGwM$GX# zDM1GXwRmyTcI?r{FIl{0v1&h^vKr_`+lQLwNE@kwt4UH`!L>W{qcG8w%@HY4qG{p{+xN(TVm`!GK)heEt)xx;s}>lRhb@s3yNX{lme1d{xZWxDD0}~oc_U8PM6(|TH|;}yN{*THyRGpkY?AZ% zPNg2nl*GVuGW3S@vyKSKq&1$YO$m5p@}_=Km}3elwA#bw)-6lgvm!S{4$K+N};LjbxkIlpG9RQgYaLwC2&0Fnu>$ zW+_3mF^ua-np9~?Njwa&(Bz?M= z3nYihY?Dh%PTPRhjAUB~B;QmsP!n`r{Hpzy4YPw+_D*wDr#atf-?%=~yOqlOfQ;gXNsOPFusqy90^yiI{RuM`iBETR33h+=e9X;w^C+YsU`kBuy>ai!&ijEVkCNt#eR zeq9E|lnMf$yp^P)3jOM*>jV1eN?PL3S+h`j;aI<;}@;cfc4uuA5e#{f7HX?A~7`>Y{1hP+kPZIYXGYN zfE@tS9!CKY4Y3-W0a;z6x~DkAF9&NJsVi~3)>lQgE9ADGvTu z6EK~4$QZ@yBoG>w{7d2|0cnTA9-D+nC!pz%AJ_uT(OI^!Mn=gb(li6v!YZkZ0i#lQ z>BBN~R4GBUa;73$tP7XYuCaH_Fzp@Ee&hWl)r1qB?B737>&Hi!DO6M(Q539KG9HDA zQ?~tc!R#s1>cN#7ps*EC$J1+8rN}A=mgo-XO@b6!T96PE=>j#i7R;IJL1p+o7>C)Q zT;s)HoIyrtV*da%LsZN`#~bvj?k>C?o4~7UAAstX053)O+SVS)p>(ZFGLz3PjGly{ z*tQI^Aaf|4OPa~{oAh6R!WGX%$>ghKd?s&f=)7ytSozd^-S$5Tq>j<25Mcs;9a{oY zFKi|}p7IakQG=MCq&c)D;F?R`ME-Hm${^(IP-PJoy%dbkozwKxm8MT%w6GFqEiFXrKJgsRf(2n zs(Q?2X;!rs{A8eAS)c@!t|{XXPSJv%e6q{hQlONGp!G!yQ}@Uat7hNKYRXPaP!iF~ z)wXEUf_5F~q}6D{WA~a`Dxybr!k?6F8Yb2!Qs8Qv*H)VhygETtKJCPv?1-K=7r1>} z$EWO{h2+VR^cNVO)v+bpqtSBJ7FtcqG6}m4K`L=+kKmtL5ACHe3dMD`F_uZ*YrN4b za1Ls>ZE4Pq@96xlep_G3glGF{KA}g}&ocZ$>=TE);wa*6%BD@RLTL?m*8vBARWQKK zWbxRsHcgZvn!FF89Ki|{3(#1M2ejcoGb)Ub4y<2Q8%nlhDJgV*COpwGkJtTn=;VJg)K8V3!+^CVesi7OgVeGAoMp1pw z@K!7s#fFK@_Jw^+FY6LXm=2N9LPVG|A?9+&;b(&V<01id4s^N%p*6txMSdf-|Z|Y8H2)LrV39F zQ}1T($zGrIzIdIz)0z+AeLaG9gl#dC2{OKC@9EcP55!~}`f%K5`)$s&EG7Y-;!gXd*KxQPPkhCRUx}{NE`4RC zXQYucBZyFuMWwqy2! zhZiK9qX#9pko>V;7{Ou@1cn3bADcyD20{J^ zj37uBNWPzY-nsX_SNByHDao-Hwmj_as`u_a_uO;O?{hA|(JXIj08bW^_%Y2=hgXc+ zh^=^DpWLYNYZFP6n3u zhOrJk0ghZuTvEz2M%H}QKimkxPh&w%i@*w zURmnaN`p=~%0%dls=hhB&d2X9U0G6_$k0WjYSXN?eCCoe0XaTQ=-fB5n@?5f6^P9` zE0wl?=B36-X4{U)@T<;Wq$rBERa0b53|i#?Mc6})AhL;XKK$WO?S5Kcq0TAa*_@!e zL5fR-m`FpknUQ*0(D=M(LM*qVnT^Sr&v!lg zevKd7VQd;^_<%iMv1#$(zVkHKhHZ2t!9)*AF&)I9DT9|XAbaF<&+d!?N?J+-Y5bbBdHauTm2DbacjG@M-BNT>hhz$cAXEl zRtIaL7c)kLnFV@14r+~m#7B46L->>Kxa<9m(fsKXTGI(z-HEW`crz(cpdgpF}{%=3>)PZ~2a_@1CqG0X;bo-WCr20Pzvg~qWT*In&f(|CE#u&^5} zm}#cu-sgk>PWA+Hh{%3|X{JE$0gY~@IxAU``(q2MpOd~AdM6gicjf&9ckoOMb_p4!t_DOGLs5)r)aQ~9sGDa$pY?KpTkrw+cJwp zqF>mX$uR0K$cGWGe8-uQ_Y{m>{7LiIRr8@m)jM;s0dq=G&uekSgzV|D{>()bzZMiG zGiZ{iDF*N3wm-fgH_TvD_l5YScEzC&D#T{KSR|@;A`bBIIl`Z&{}qC2EnMc{M?+WLCDSGBk@N@bl9<$9Ur=ktxr#q_gIOVAKcL3d_c zDETvjpnFil^$DTJE-A;WyH+1*VY2zqFs=yM!G=zpQ1hsbnT*?}7I zGxkKSkDP~PwiD_L!FIzXGp1|Az27fuIA{?+=!Xs|rRisXtTrP_EojrB59?ekC_c5U z39o32Zi(%#O8#K_U)JA*|J~j&b01lf>0cyt8o+XWt$3l>mZeKxs=4_ctoM;?~5A-t^(B%1Ld5enQ z{h;?5X(WL!@Y+=_dK#=AF+EAd%*aoC z76hg*T)MjS?$Q;v1^N^#NBu0k%55=uc8o0bO4@b8_q&^VB6%5`tn`rT-q;=X2yaC0 zQ`i@-A@sWtOC&Y(^7!jQP|`Sqff}jwi7=qtGuOA2Jh;)yDP9VN{ie^O6d~gc?br2N z>e#p6$J^NoQG_Ch)+L}CEQ0cAc-5{^EWY-TNbpj8{DDiCTA^)ip;sLDpvFbO9@kHD zKa#KIu}exA-joH`I@3eq1eX&`mw(XquB(CMs5C=nc`CQ5 zNVrPeDS+~6iFl?o<9W~PNbF$ae=M;L4q=^LEQk3SHL)J!%g6QEq7I(BJf>v>Z%b+B zU7T&x9`>;V9&!HLRom@e2oY4;YsmQC==aq_1t;X1lro)n9dPA@t3F}SQ@Ivao_vaa z@av!h)l-nH8!w5u#~#<-OIKGg(~F>?>Y$YN|G zNA>wz7BQx{Y_4HHlJ3tg9+;Ek?`k`zvH6~=?kSzZ?0ZC${4gu;eNf?>*41EzHFcqf z17mG{<&Q*v>jIk?7A`UORCuT1agms+#$e3|Qk-oF;qjBr3AZac?I|}V^OK1BZl`^` zC70Py<}I)ha=~fyCvlw&!cWa><(-Rz%yWxw=cW#Wyi`QF<~!A~2^Vw7T`o^mxNlJ| z{1wl-lb%s^2X>Y3@MhNvs=b@-uB-p017YYgu^U zr+8>u@NQX;=FW8U9YvvSlzjh<&jNRnmMNt-;kaiwCT0S(Fv_{%Vi5R#Z2qvssCOtR|)IRrM;<;5S#9rx-MhwKhuCltewW`(7T?%1vkXin9mhHjDT@ zFmo-garRoP)_Wk|*7(9Bjcm2%;LqrU_?e4VV0`=Wj|aLOTZYpWd@8L|KQMDRzA}55 z$8_5nrMP%(vz5FoUA`-`*Afj)cHRiOi1G127jdM6-5>65>AK=rlG{G;12aeBYqLit zJ$EcUcWlygZ>Q(pZh!7I@j8;Yurf^FHT4Yc#v+Fza?^xUO!QDJeOZ+kYDJaK!IUdw z>@Q?r-!iCg1z(Fd8-`7IN*#RISj6iwY8$glBc8ubAVO(&fm@1iZdPUsxv}j#@KXtV zn znmW~4{y97lpmI_3l${wxsW!H`r`rTX8QI5bW13!W`k3dtvs^NSmS;YSOE^@`5VDpP zK03GjQ9Ic4Q%=$BAo_G;5-&X{FXX7GgovBPT5?t2*h930<01~qgWr|ccGOosMo-75 zeF-lF=0*e;DFZ=_likyo)JX>#OME6o2g=~i$y?8OQd=TG4}U0mFae4y1t&tO7CGO= zro{*B$-YPi>o+R%(-P=(lTl?#==Mr9ksyT1D>+oVZxIVC#bFOz&iePaqnF!0FlCNuC-$hXd|Ak80-Buil((v>8_vp;8=}4t+?T<_L z-9FX1c)oM=*Q`x@d92rzdub{@0hm!3@tl03-_FJzHpc$i$4b)Mx~1E9&RzL-m|-|^ zj{7^XkN4vRonOgWeIkuN`ItU1^NYB#v%hHH)`QyC4|SM5CY1tjkEwC)j&i%J&|6s7 z^3T>Y?ch?2Fm=`4PH>aaTe_`lyq30(1(_K4*Q3Ct#a6vnJu7+A7*-t^Yf*@|3i?cC zP9B6quIJH_1B>b?vMzDXMcA#QzA+_FEnU|7c*R%cEUo%E76D%r(c;y~B~BhsL)kOS zndq81D(!n%Eq~`S>Fd>`GG3_ARK2y_U)2qHt*iWE0?#&ym!<{M&*S-K;R&2*zsR_LZyo>MZhPsL1 z|5S$w%h!^POqW6Y8FK7M8Jg^qx}9#{xLrVicv5?jn zE(r3g`d^X?#{#@mEmU|sdhW{7!quhD)rGScmpT{DcP@Q+wX^ieh2^Wu;cky2LH=0b zdAofRjT84GI77?Dqfv6p^8Hb%0tRwQpK1BFnWU7+WDax#J!h2Rghz#O?)^r-=U+ZH4=zxkmK#VulT zp+dxQy?Eur%ZBMtFSjZ2nULR(?ypjZ`eus`g*!HBQAH{sedF$w5@K$7Z~1UYw2DU6 z4P#EyipIeyT*Gl5st}XXl@q!NXn956&vs!MT(O1|l2I_7siin0#(`{R%zCfh z^oHTOl2LoWkOwPGuWGkQ$|FWgDy;RL04MqUsosMe|0`Mt8d{a@5?6C6d`2YzZy@fh zPmYK8ta<`L;Fq;y0r6L`z4UvIRouILZ^F)kf;k>x%wXFqGR!MEzT)w5e1FEsXz zr9}^D#7kRz(b?$t)Ii&!{ab2zq)eCK&Pi$A;np|LQZu83n%eL{6@iFt8xNI*8!DSuxrAaao$CXo^o4dpS08B`b2T^>vg;&YMvT=hLn|ho96%&C_T5JGZz^ zI)vYZ{z~k$4*fgQ1KSQ^yJwR81rKy09Bhob_HNOyRMTpQ(L@dh1?FNoF|H}c5hHfa zp0jWjapbh83M^YJ(UQh#iUaZYg38P{S&IGSeK}O={=k86RuILx=af-SpZLn2YQ-QK zzGSoopKpBoA+A@OxT)rs_KVqIqA)sG7_5TKoqB$fGTe3loYq<8DYXLByx=aS6}c{8 z)I`ux94CVORG1)y{ohlPh;FoPhrgz}&4o+TAmnrHZ-~C{@#?kK1)d*EXE(-~JDp*i zU=(%?15UNdG}5gfny-hXc5Sz6yTzka`l{4wb$lM}b$E_O^DF26?$5X@i9ptcjzGlm z!FORMvYg1@`Ppu7^0|MpW&EH)#4!)}m}1A96E`4-7pVqXkm5)na-GNFef*+&A>2E# z`QUY6_k{uXgcSCYGmLmV1!vHP;_9D32rAugnxp!>(n-P*En+VubpdY)^Q`RyY= zy((n|Dpf-t?@kbJ(a6W+(L3kbz$v`(Dn z!S1zC0MY*Dvoo(r(6O7Q-eBEIAjbLkzc#Oqz<5>XCoe1MU1PYkrZ|a&CvH8 z>6yT`YVc$l$Xwiqpn9|~?Yzo_j2*aKPeo27@{BE7RAuH@EpQVT@GL|iqN=dbsmNe5 zR&e$rOWcp-CqK6(&kN&3*$GVYIjUk&C5fQ?(mADJ4vF8W&T>p60iq}D3|v&S7{w*f z>h}eUDLUqVF-tz5y?yR`Q-(^jAJXhmcW5YA`yR0O)B~ms|y#0NCM{In0GqN8FP>EP{H> zr8Y&kaTcD;)!hl>c@|DnUXN*;jq$%Wu5(V9<@A`wiNXahPimp@d$*7?#U(P(uc3(= z>u9J61>$?~&%~0EB<{p?N2f^(N$ss`nZc4)>A{0^YZQJGvaM5w6?kza+h(*+d^9&obH_5&z^-^cU+#YPitc^t zSi7aWW^D(KN(2+!0E6JeFloJ8UKN(k%c~rX%Qcj-LQ?>DmF)ro2V)oyaSr+VyZ8?rZJ&W9kA-S4XCo*R%7j;Lz;FZtx z1PaLrI|S!**5V`tRh5@wk=nVlcl^pd>&F@*=gCPC-X3f+X}HFWtAlK8Qd@R+=I1aM zQ&FihJwuM6fYXz`^^q!T{FWhgV%+!fV10F^H(Z@NvoBXd=1wPX%iNjo?Q=~Gf6fi_ zL(QG8f4nYt&s_TGl$-^ad~$}Z+?+doX5Y2V;2iPKb%Unxp*s)4_qYGXoqboZTTfY~ z5O)@uH~Mx6sNR`7F;pGV?d=o$)DL=B1w-LI9Ppr1-xd551*R>6%k5cgZnxJxA~luf z>trzV0>&l&{Be!DO>25hwWCxNniX=qI(?=JAWQt4+zD{tV^v2U8HI|eV6d0ghRKS} zh}R)7#0ceFH-x4y$!G(rr}(RiQD^yU&nONEv+N2dL>OTU$!dJ8TfH%1gx3ND&4dDr zb2T!ZB5Y4~m%|Z|0T^l)Ck_vQ@N9Uq{j@A?yi9gGLS@ax;SY2}Bj28`)YuGGdwKD* ze=LqSeKWv|fs^`GJ}y<^N~TG}aexmw<}%Y7+Tl!DtN0H54F2cYP5w5#6RDYB(^q%9 zc;K+C;f!%D&38>2;|1jt5p%(H1;z-?6T!Ku-_bs3W(W>;L;z%wp3r}2DD%oH9Y`Wl z_PC}0KGV1J`bn7oMEveVARqG}A}N0&6@Og+8fgv!&TwqYy9JKYlUBAyU(x2=gxz}@ zB?WXX5T6=0mRj-skL6Z;p&55*@Yb)cgxS`Ojs2k*^_EyG&9q_L`b6D*U)Q8?(A%jPMtW>-<-cS_-t@}YwNSo{MPWs3H~}!X}CX8iel9_ zcy#!TtG($%WX8w-_URM7GcDcr%7i`hFYcSL5!>(p7t1I>F3j7=9CCt~nupW^g7!Ab zq(u*$>E-HcTS&2~!rt5F?|gyHAIYmC0+D=GzGXv#r`Y1X?Fua`npol>kW>y!NWsK? z=erQ0ygF^1u@+H#;QV*mo)hPPK@*fGJ{39U{_}&bCPckBHDM?#9ZHNC=uIhO|7&?t zacGr3)H9?ejQ@WM6Lt1z4M0``qc=6yRoA*10NtY2VF**eWUS82GRvGn=Ht^$et5r) z!Bj@C*0%LDsS|IR(RluT3V1NT%}qbPGP+$gcCCXf80~sihxXHeE3}(U?L=p5#dO9M zsT;$s4c8(^Qaw~QZH+$3nWz*@E6qZt5&+kAl82WA6?d-pRzABWg>Mwf+*)|Xde9?= z(gFrz)0|y)*P|0=lDZj)phNWLJA#2_7_A$BXeE5-yAWD&Me6wF_mr^_ZqbeTBx%(O zCED#^LG7(pxh;?T1QL2#)Lxb>$W3D?DS-FX2dJW*uIa5Sz0sthPs+326&0Cp*39@2 z#t-X5Jh$mP&sEa|W^(K1mb}MYE)d+-E!$y4MB}+kF%ue7cs`xpC$99nA^9*=;ZHii zF9p(UjtTqe))>%%O7H7*C-5NgmQTmV`|3&NI}V#nuW%&37{Q#J^0aoPCWZ4FY4@q> zcy;6Xnn0JAt3YOcIE`OE76*0fi6Gg3L#D_DO~UWKD_tEZxP zlwXov$blM##FiFP<1T0T*ZqU$s_8uf7m}3)-6Y`NpAxuc>*)dxYS4P`RwhlAK9NNyLkK!LDY{ADpFmyzOqjyNG9we5nbaKDC(zQz z3}8L)=A;QayaLG_1;0&}!yNXRr<1vUWlm(e+=P~Tdak(xFe|eY+<0|(aq1G^sq0^L z$^WDA8n;&o(0rc522+MGz~3-!=eS4bOe&?E~4eI z1yUBx?O37zhFZlZmC^Pq=N<4Ijtj;b{1lAgJy2nXHb zslo!2_UWSjB0O)kSr`B-@-w8epc54w*7H1EaG}bk4=;7DU0zfX*0GL$U0k}jq^ql2Lq&JRt60<;-w~-5j!%F7#*E zbTZfvEL_(nR<{vDx}{NP4{Oxa@P>|?xvQn#=Q6pdF=&S~mVS##)__4!CX>`VCcBd* z#UK$3#Nh6T6EL&g?-Ey{PZ`@;d>)A*E@M$g-g0x!pM+ZSUP)wUbJ9FJ8*b(A)JJu5 z*&3;tDV((0Uo5D~;BzIvO2wBmZY$JbP~7kfOYTcsVGnWp)F>2Q2EoGkVmYFZ0yk4RLq=1kDzVzYQB ziiM2J$QG4uy}7oon~a12MR)o)tO~d^*{YZsvcA+P+p;DxAv_4}8URzX2{ye4&P^x7 zvxkQYO_4yIOpyrKH_s6pA}S+?rg*euu=?pslkO==YLz=^+s=amGwpyTX>*+wldb5Iy!*D$?gOb|>|?Htoq75PDq7zW@57 zU94^;Euj;%-C$nj)D@}s_X{Ao%2oo%&LoPV@fhbSQvj-kI4@#hX*Wwmc_i{3v>J=GfveSiXU6oH@aAE{662 zb~Zzq9zWSseHxF)bLVvqq@{K?25NMuQxbabk2-(PbXRfczK&1H%N@JuKz|4{9Y zzpMX#dFEI2TRO>e7nVOf{@w5X@~<3kKeF6Mg?A9~XClL`q;7~n@)u|WF$D%6(emtt z8=LS7U0KxQVxg{~r4=hD3-h9Ux0bHQndYjQ6jW~=eO{xNMB#Xgrh0Fp3d!^&A|fB0 zhegEyfjAxQLDM9;)VA}4(FA8Rm*SD&?>Qng!Y)z{%PTW)XcS^`u;K57-zmv3cJ5ve zPBTeoxL)su%}A2lBn_?_biJfIOh9Jls`$`&ok!tWb-2q#qIv7H&MR-|VyMoCcx@%L zU-{0)sH0*)`8L#iO6pOStgdc!YrC70?^~PgqV~rX%2)!FmH>5jGI9Sa#N7=jZIfNk zUkHiuL3jbw-Xe?AJi1hS0&$9!KW;wW<-x{4WfQHWHn|y7k$9fhoWuz@akOJF1-+jc zCW^3Yz#*5R&Q-r)&%2fPEI%vs_OlDCLSB+gi-DOQIvBDlWNF+U zjO@OSfPc&tqQ3o4Xs=spVUfhYRzgN@!|lfxmknTSbm2oS!b`pvEr;LteC% zFLAkKzI}DUUQ3~6`A)MI$#942X64u*aj+9IoQm{+G&qfrkrslrO}7mt zB!f)luLReDtGXjW0+~y5+Q+5$=vCPuQh{dPifel0+ST*NUw>-?|Ms`O8{c`DcfQ;9 z%Ixn;lGVMs$twrO>nG)y0TF9Ow{K|%=1rK{aC_DG#I!U7#Ntaic+#8k{Y6=%>63{0O@!te@shxdP zhK7$JI;&k9l)h8s4^^vlSAB!#8}bQ*(qy~=k8E!zs>k+BNJ^rTPbGexHvdRf>(>CT z*2=#i79M;f5^1v6CTXnq%G8~a->pa#?}u-Pdu~n3MH#V^4gtZ;oq40<;+`<)g?-K# z9(LzBR6QHnTc9Ii>=S>EaVcR;*Xl9~K6@m+3z#HElE(%vdQK2|dQ{zKmyR_Ym_ja3 zCV>-|vhM3-Ip+P*TlIs+fwC(PaKl{I?`T>G?|Qa=`_APD3|$6+i14IM7El_*?5;Q5 zvusA&6)>Ey(yetE7al9i!A^};%u@qa*-;<`vbq787& ztT>IB3+XPWIw|=)_o^}(E^TGNkzq8{jYayEM28MtQ~Z+jkX&9}(1I8@qnKx;( zLyM1fH2%?`gJKxq_ppPG4+PCLSyKl(N9889bi!ar&3&L|A=ZyIlw>Xjwc2QzVQvIo zWJaH#Cukl1XMf)fXT)f~@(M(avwRN(+G0ss^np2ZQZpkGKBd0$1Ab3a|hl2$E9$$Q9EAm}&MZbi_jec1cCK!1tzS1UNOLzn5|9&@tP#<}Oz&hC z6C5S2x72d>g|4H>Lf7hl6MS^@37@x>0J&3cc{$f(>3}=tKKzbAKeMwIH2CV;l&4)DPd+)X-p)@SI%R zmwP+IzI=J}!IW)o_(4^rbwwf;^4Ca_R37dU)-O>qd}T>`8}2(u&Cd($wch9GKzHeO ze`QyIRE>_B(_2`Z{2io17%Bqrs9q-eUIGEGcwRt9mu!6NVO7?cueUkZDVf-JH4Eh) zgA8bh$dp`uV`-+yrYqr7Wam(~$~HKzw1-Z(1G)s>oQ7G@B+_p(z~1Yxhc*vQz(7Jn zT*kK^?V3GMn&q|Pf{ujI(8kgESgwAH;~nf?-~uRhQJnxjU8hnPKx2js%ciqOSbr9S ztdrfLE=|}{?}ZkcJEoy%g8|j0t#F!e=Z7EIjc9@Kw+#JV4UI#t9;TYi(duhB*rk2H zbE%eTPHUPE!z3=Q9Qu2i>M1oaSH9F9bJ4owLmd#9Emu4QhkM-5eW3~Z#^C26ywRkr zXVhB*odi9A*hR3O;=2!bFRyPEkJn3j_qt4)GIp=~l9Op9uWN^OhCIH=5~ z6~#g18ssvLe#n(-;uHSHV8|Tf!p1wtz2w#q#@a_UM?u$E(E7}VOWYIovyq*P99M}2 zJt;s{sktNWLw#mZX*{i?O7N{KICEXqjxv1O^ukZ|J&2*=n~bgcQFyw$-21$*J59Gf z4Q=S#c9>g6p{}l|WlgiPqWVaOR8qLpQI^v1PDmALA(b;4;;P8iy~&t|sY5hJtj)Jp zpYFM?`Pzfi#~nT`bDnC$%V;BgMJ8^Hi-+-Qx)jNp&#y2u2vEuPAFwEF?qN*Nj{;HPTF!$pvY75(8cbo{(tX=B`6Cg5Emy}NZ&Y;afvnVwjO9E4p>r9MgCFhr^ z*eDu|>P{@gyT@`;gy?9nX6NP-ojGvQ|}SdGNBu@KTvWFDD)sY@y3#*x|zVN)4T=@yQc&lQIbk))%q zygvWR8}qMx=T+-@8yeqMo!_~2-8%H{#NyKi(F zd(&0|_4xXj2^NeHhMsXdrvyxkHCUt*Q3-9QzJ!bcUD^!bh`%^ZNGKDg=+8m*uD-?T zY-f#mc?ujr(~gJa%w!E_+U?QrKf%SzI~+o*Gi6l@JCAfsx+!w(=kCnU&t=ksaMty!H8D zHQkiHwmZaC+WBmA>z3S=H~RB)7uL*IX?IA=64yH`eX73I<+-PX^}d{%t4y$YVp=GKkk!9ZVulsMOe` z8@P1@tmz500_BJ4_It8~uxEuZ0@jT)9cgI)LfZAx`#+ueM?$R8WjdFmng2&i^OIXn$`s+R}L^t`NeYAk7|3z2HYXML*K!Jt1%MRwFKmnjwVD^28Bs_EvM_ zU!Q8RL+i-ey7j;QB|^{Ue;zhvoJ{AZf%bE0_O>&nGxcW?)Z>|~Ydcd$r72)&nw!;) zLwQbtNHU&6i*o78_w@oQ3u+`eH62T{ErX_$EoX1?ndt%6zRPrhajBKg`Co5Epz3Lr z?juUJyO2rWk?^T_W1V3_1|6mQDpUuBuX9uSNS1DqE4&l}DF!cOYt{F@wW-W||H6)4 z`uNK0p~kz(UCxM?dSvB`#8nPW7gl*stcJ5=>K~C^kA_DdQrLc|b)rm)%)XX-7&>+Xdo&hFmm(0obG=@zfTvobTS3j_K!aY#-9*?Gct4@;K7P8eWM1GU(v`ZSM*-@A(UWyzXi4?G$x+w9yIV{#&qxqM>u{d z!Xe!@xX~O(co|Djyg3F1^TCYkaPSGIJGkWId{0&Lg-!!ZRdgs_*Bmf2GvhFeFxoJm z5~e+mC*`1kcQ?QJowu#>%_8HO-kPZ+Z=RE3@L4BhNr-hQ{h~h{?!rfs(kiFxaCejI zInpHjF-Lmb>d{eWZ6KU10)jXl{1(lOl*4d_vr~c|UaoJ)=6$RSg3ByGPxR%EG zfp%T%;v~8fVBe05KP#L<_4HaG8^N3iIB;o0!-&ufR+0Ty%Ckz*skhHO4 z-SZRvaLXp#sVt|Achc`%U*8gCg_PaZ5~^q4yRWs{X-mSMlU9UVYvVg#IfRtn8Y7yj z?_5eYCCWjb8!6Rf`SQMJSG8elUeCA@Vd`5axXTUOz=Lz)y2j#;OA=iWKSsXe?jM`Q zb{Bqz^5@MG^0g%6;`*i8Xc?3K|Nt=(-WX5H3?nP8OJtN4vC$u z8#l;n>aDD(9S^*r(&kdRbdgVdzuI(AX(a&=xGl0NKRv*1w@5StAkS#A+w{zg=>jd{ z{_jti()Pk^8vB>SY!l*ivXB%e@7=Hi2CTcDEX_4H_KZgCDWkuVO!V_>w3{2$QsSeu zIOhul@ikrHnA|`ca^MK-BcVWU94-m;dxH7d|p+wfH4qq)3(M zbg1Ad^T2|fmR8E0gm@#(VU*p48n^0e;YO#*%~iXkwW-qG&Srw{rUg7J$Hk={IWU;gp^?qqFIHMq4p0hBqwOkrW5DjNMhKW@zj~TRfFa%gIPW zrzE-8N;d&q6M!)8CTD4;DNO~67Jw(4% z7cJPV>$1~<>QV(ijXB8K16u(06vm5@b8`vbX)K|p854Ekl3#J2y;k$G2)&+9M~MG| zh!s-4EmZ2ih`58**--+F(so-I`Qq4+5Z`#5Y~pUmDPM?Q=}ozGYW#IfF|4^{9|^ax zotWmK#c3W|n&zQ!w{MNSYcM?;U^@TiG(&}}f7^$$Ix$bZMH0!mZ(Z!4&Qx z-s_&#>X32-@N323Y-#+pdUBwS zunD(1pSuSbG{Vtv1rrr0*Cq4_g(r8;@gih|vy#bw^tJiX&#vpEqRZ!*3M0$nrnm>G zDDB0S&uRQ+b=2x^w0OkeN7Lp2GuVU_;4=!OLcFGu7*BWnm6hn4sEaTk!hd&NRSccw zo#F0^GTloinj-(47Bdh-TcfyH_cGa2ak75a3aNIGMRxzml(O2*s7y)Fmbkz}3o2I> zV4PhL2QZV)M{$!5*9yu?%7w_yuRO~JqdN(%@5QwR*O4rvSgbJLAxAfuM!5n{G}k(i ztQK|ApH7Jf^qRXO224oE5{-leFH)~DS5cr=^qb{>oYVKD84CJH1g}Kc1(UXh{4ZG% zyP?^Jk}J*)wq*^LjxdGex!K~5h$BhB$5{?kiPk}~mj-*eWiS>P6VAqllLx8n!8zG7 z99UTtcE$o%ap)&JCEOxXC0IdcY2m;;DK2Nt7E%0qJdZtnDVPNn|-oh)Jj_<$UD6w9lBa_k_Lb}na z^T=?tWe}_;M5kU*hVR-tvp|=~X3uO* zp~H6@`w(IQV7eJF1YeR|Bk*Utl*{p=Pxbz>m9zakZ3>FbV^V%*SThL_&~oMY4%9u4 zE$F^vH$(Mx9Hq3bgsu1Q2U}n>$5ne2`*;4_$*Y76M_Mzf;JecrLfrm*0WwapMp;u~Y|q(KEMJIc;y7xDI6Ri={D zb~rD z^mKE!t6RlNA-c`5o1|osuMdwvB{L3~D_#dx0H!3o(M^@?_HL+}wFLHAEuDac`SM`m z6e*exW7=w6sKa_`Z-q8!xsAz{{Po3QPf_u1XK|<&kV~6C+ucIbyVO&E^U~b!-}l^v z9j!Ml3(wuzFVxO_J4QQKX5-7k4emF_iR`7DZXw4>cml zK?_KV@WV^p+vRGy@2dijRO#@%P-}b}eZn*e5>z?QsSh7@q!xDzx?P0tX^eqbPSok1 z>)RD2O*81_!i;R{<)FXZ!1Byu1P8*Xm$kbaz2Z)ulm$1wfC&j)5#T4o(CP;h?#s4b zluckM8K{pAd&?56;%Eja%5c@zvN6=`smknWleu7-(`ANdo_LpsW^JczN7{5DOR!=` z!K-VaZS(Ss@dYY6dCPX*x)*vJp0sE_$3g6AmAPIvIR&f@(kYB=L6`J`8@a(LElC}% zV!p7{*Pv99g(cT?2-&%ErKI2axz^;ZsEfHyT9l+ui0(5ZG;aL9s<5bBv(*i^N1~g9 zL5y>D*>IjRd=ewuw=^8e2YqqtM(KqAiO4a%Ycdy^T(MwkCbzcDPursqJ0Ht*4JdO{t4Wo67?8hda>>)^ zn+DsGyKBndsIo#gwpPVpE$f>$7fF})e9>VjRZ~Zt5-zVaa5;TX(sW9l5j0~A&sA%{ z*kTPNRklS%F7F8kA+%&yCJJg=xlJgZHz>?70}SZ94UCT_fPn}w!^$dMJiMDof`D4p4n;8QerFPue%2Bp+%4JJ=*#BUx6*eB zOy(J`Rs1x*Wz9U5;-&^vKT<9{*+3Zm#4*>E_{J3JBGP_fb0L>ver~QTe48W*eX~Gv zB~4Ywor$KB6Cx4|gkq=qxyc=$$v1L1AmWrt6+G~2$prz_kgi{39F!2|IG+YA=ph&B zUjVQm_KJZ0`aJ<=dR@U?xF_CTo`km@)2E66QgnGgm~%Ee8EfC11Qr~)2-8b~X_{sd z`}gQ2@#DfcDOC#h9K_2xMIlRE$`o$*1r!s#;>ms9VbD1|5i_3T0w~G1^96uRcIR1Q zP0t~brVqqEK2;#`yxKsgDAO}Od7cngn)vYE6UP-D@In3hiH6p!dfkhG$)zpw6K^-H zSjL%IFJzCIhcyomxDJ#v%3R<0hJg^u%Lbc+5jQ)A`jfz->~^dsRG01(s#I*4Lz8o) z(6D3-7A_)a2WR$Rz&JK@)x|`#)>PB5T9_1hW75kFcXMNB>AZnbafB1qLxS0FN%5d7 zBAS5FG9w<9{9Kl+>DAyWhdq<*V%>UD+KZoGpk&N1d3B9=+#H~#|dRl?I>yFWY?IqKhQUEy9kx)+6Vl%Zo<+jz8= zkT_=5(adGP8`R}j^{MGj^{#I)3)5B8`oCRRzY2Of3Yx1rZFfW0ia2c)*Gxfwt&foA zcEh`=rk7v}rzdj7Lk>-9=TKs_pB5(dgJg%pJ#`#$4hBax9TooC3+3+%t?F42L3^zN zjk~o(`WrOr4=0ND6FM%v&il*i0l*3u`Lv zF^)6w$T;s46)J_bZq;zGDQ7Nf-lH6ZAkIkpX zjo!yRG}qL%3{~TZ6|04pv>dF3#!5S(!+DYAJ)^oc5-_Zsu=*KidWh?aOB~>S?umXf z+`61ztmR-h>T840Ja|J2E*{p(5mdtU>|-@t8^t)RP34A_ zq(W<>t2!lN2Aj%;ae;(d4?DvSfC-BgGInF6gl_c-+6!a|1V{Z{ z{SWaV?iTsdp$nVGKTz?^P^B_edQXWD{Zyx!qWjdk$T7(3&0m&#)=cz6u~s#<=RQY( z4u`IcJ#IA*{``^jjbPw%ZN0G9qA9M)4Pk(|reB|u5TpewIJm~4{TQJf?S(`9qPbVJ z^MT;f4Y9VJjyh!x-cUi=sTL3A;ZQ7L64%XWqxlQkBEY#F@o=DOAUPpT@B{7U_+Sv@ zRUtm~r5hXWYFnD%d@F2wBnf(>%SlOs?T|K-1gpVXk_45Ca4AS=%#djhtWiHrJWKTd z91S#e2D;TDSe$SOxY^nK4&!XY4I_6qL5s$qP~I#_&~s@MV|bR?yS;_+&fDZ z5UzgI5u+RHeCZivby<5bH0)H<%aGUIB4)koWPMnUa@SL~A`R`c0cH4hQaT^%j+~bDafxUXZJdz3;7V-1mVg#<@qC0M zfFW*O;kksG*9t(4>-%+u(RR=CwWKGN2L8KoVAkX;`Fh~;@Htl%;1YzBw}Kar&!I@; zg63so|M4C0 zo0W_PyeS2o%)S|MlCz72N>sDArlz1cu~R^tUp11xFDELqI$I@p$P<;_CURa(-VQ=Am2(QYfS6HeTn^W>7>KHW>c^z}wE;nEo~w`-!r z|M)AW#Ml7XS{5pNVJZLIFCurXnoUL01Gs?Szw5lu-;FFU9#`!`h$nN-4ep1N?KHF6MkUbckBs1iE-003| zI(Kj+6B)M!Pm$`7>Y*^rt+fsol9_85bvQaW7v(xI9Fd$k?+0r9D%Xn{E6q1MA@`@KL%I?-JYO>ub^E>2o za0YrMatpry5*MF6)*!h1-7SbT$56uGm$P4t0!L%VEK9o1k#Nwa3lW`$fGXc(Mrnt0 z&pnF=WxKg!!AzZY$Jpu6Gz$)8cQuB7$mU21d&N=9la>l9)674)r>$$xEK0f0`3ANf zxLo}*l^o|Y-uzN>N3NjfqoXV(h+LIVN8(CEu-Ej3Y}opd@T<7uMPHG<8V+?vBp+6l zGQVAp`^^61dqQDb`X{IU-jFyg*8;Uh@owvswA67vgtPX7q&`9bo@+q&VSbjBCQ2oxq&FX>5JVPYx8#;j*cLduH~DN5<^ zn?=O6)ZMe3J+@v=&(5S<-b`|*!Z!X+PI23Nt9(f|J$pE=^CCq75=}QHiGLF?WkZKn zqT!kebwi@460J$iu13XcReozKSWPKH4wSt&hRiQ>HQ&isQ)y7g!!5~ZP-c-$vp(0W zChbMtq4p#*d(VBZZ+F(j}xR@z66}HiEij8 z)S&YkrRcYTZxrO590XRa-Z{VULxi7tjfb1))UPIxXX$Wo`AsvVoOhZ^EA*)Yf)*&K-a z`89TFX{GL%HRUQDF0bdcaBe#9@8|-d(Wt}KSV6(qs_21*slAxK+}^TE65*e#7$R5b zY%5k!`*^t?Rt*CUkjFAK^l z--#HF=X>tyqtb?6knRbSHHF2g2nqY;dmdk_0M%aIkCX9eFkFpppe`JM?hLSMw8{$~ zG4o{Q5uVh)v>j-;+%K_|FcbX+RLb46#?RUNb1?QG-3wiAo# zTX(paI7Aq^dnbv%r?2!!O0~3F+|I?G)ZF5!dLhi5BFw0HBaA9e@p3Y8tf#=ku`9bsLERRz@)=&)>RQ22H`duw3@(T#IJ%P2N(=kHL*5?x702GBJO9GJ z5IQ7_p_7qS-Pab;d;KRfpXv8I`iZ^`Nw zr*Gpv;xkDp`VS*b#8dT^Py{ubcKEWlty}CGE^Gxk$1xx0sB9z0xqeeZf{pKR>kjl2N8a6_SsQbr=ZpnI zTx*6~rnGmv$jWqRVdFRzijx; z4dJ3Dn1;#p5e;F1jKq z-U8~|ddh1P?B06UB5>nD$%z90t4M)C)PI$%C?x*N-4u9Hh?R)|gDvRA==%Hem4$ad zSV(-T0_eI*w1x=Nja^+kzed06VTnu4Jg-EY_qBVRHOn?{3gyQTnYzrl*aF~1z0RF$ zKNAYaJP%RXdqP80{(`O?1_j}(Laimu&v_>?$gLC8?o4|_3^#3{$CrEEbSrCVT+08- zw`6d=YOt{)nERHw5@VrT?iBKG7e{iso~$+EP%Yb5*{bx6DO@~hTyPK+J9CWiiJ`cz zgCSDoc2Q)^a)D)@%{T5 zU-LSLNgDUT+FWwimZoc8P8?8!yO+KzhmWpthy-EF>5V#F{7R+q-)LPBXN(nAOPI-3uV3^QuCf*vWL}@VnH`nw{N34-X1mtj7Wnf!XuRTw> z4Y|l|k@fOvOLSO2H_7NIfT9g9#k%UA4<~^=liT9L?6k2kX$zsXZSaEzr+2J|4j)-E zT4@s|od(RkKrs60+F1L3e=VZf4WBludQV&gZOtrbODn;w1Gi=DIoH8cVAd}#wd5Fn zZdtb==w=8%_jrWhHKi3(!8d7kcnkqDOf1ZYdfH2w#J*O|uYwcn;t|+eY4+25%}B&E;8@}WQ_j$tIb3-{Q$_Y+eQHVc=7i>4CnX4hgF;XeLh}!*dGJ5|(iTUuNDa$j z(tLr`z5O{aF`n`DYNt8ny8DDe0l1cK`c$}KD=1@CygHB^`MY_*i1S3z z3V8PORX1zcH?YXRhr_e@11T|r0&eItAHf1vc5X@X;54%XcB)~Wwu8=LV5f#(n|ZI+ zX{pWGN5XALpss97s^QdlJIs&R@wXum%BR8quuKwGdg5kFGh=QYN~u9Q(DMfA+OPL5g`Uh;=2AV z2i*W+vQd|~&&vQeBC+JAnxdNjd9kYW5sL|x;wAR3elm4Xp><;cIk0vDCWBjx5oV0> zTLsWOd^ZWQi<0n!P4SCR!JUHhz;VB^vS*j&TT>&_J9~%A-Vkco83JzbHS;K^_<{2^ zV*zzD^w9E-`mVzJ``*E(M3ddx6o%!xuP96sY4C|K?8G5)QPrUacCMd8WyZ~$jQA!; zHtC7->#nN$^sj{J5m8kPJi959wT@PXgY9DI@mQ+ZQ)iN{;GtaAgL@r0fI?dhDO!0g z)H4d9uJ@02N1>GljWk-4QdS!`jBs?WYSX-ABHb2(GWwb(*$LmhI`g*vGcOG9IDd8? z;eHR^Po1A$xk_O<8q+9TBeLFkZGPwW&Z}>~y`ZeE>hoeb6WyDj-pR)r`-9jx%C`lr zy%^BFft=BFp>3YV7WzJVRDc9v+o_cuZPj(%a$8~ov%ep!43P0m?b!)NoXhgOefT|8Z+Q(G#th!-eg?Y z^;5JL3qkO?>$i#B?X^)&v;VGOCPZQGVTAQfoh8-~oVfb@AL(1Rclu_r2_McN>NrSx z(m%MWqZw~^t0Ir00qLI|irz;%0}*J&K6Im3hx<~!FpYvlw&5PrGUBbR2Yv!a=86wO=I#QwHSMoufI zn2j+ej9vEW492P%AX^fke!D=*K!!}+lE%;&Px~TVJ>E$KBgWNOGi8#9eP77cB7{zF z7J}(?J@{Qhe>Cd~DPuhL6u6i6A#2rg{pwLDIr#-S5l|850XBslold1?qNHlX`l<1} z%Q|m8Y|GI_k|B9Dw4d~JuL8kH|wP9dY2zZ1Qkz| z4zO}nq8vOKBBhl*9EdjLHJJHTSzIB3O%VtZ8jE+p|Ff@TDTxSOn6&fMy6tH$ch?Tv z)8_N6a#LcBC+Bk8K2Hey@iYjls5m!3GiHK8%L&%urJakVJM3;2QF}F@7UdRQ5~0AJ zvRvy`n$qDor?5$L>827?lg5^ZGIuRD50Mm}VAuHlXLsNLge&9V)gDpx0A*cqo z=$8M@B7}+6x_WM~;hlsF**a3b(q7_WlKf7`HM#qj>MIkAj4Ruef3x!bzjpAnHySUTov^;XL8SJz&-k(wt_E6U>>(>JDinR1ad*-6lvbIi^j?U|F> ze>cpRWZzEfo+LUP1s8l3-AjC9zH?!X8?in>u4t?P+}3LEt{^n*GLTwIUa-`=17ml+0>8p)O%XW zNK(K!^)TlAAViiRwpcNb!hx9it>S^0gi%(t349h0$ozphEm=ZjziwXq?DfiajzFxngV{gWv{Zj!5U zO-P%hAJjkF8IDa^1<3`iX}s(*>SJo$#TfNtk|I>&=7&>4n<}zAj-KG%p_|-}ZgIkN zZb~p^xzIN>=xrM)C-gcq^kIh=mC^rlPaK*gL7o2JBRgR2xIycEZ>|U@mW$05?ADC( z#0;OBD-{*Rtb=59nf-WQ-Cp8(SRBU{=Rg(bt0$^9m3dE`Tv8?MlmyhxsgaXA(m@VK z*->CWbMhEF9dRjzQ(?TXH&iOy_1@48jP_IU9~FTvi4#-R%0`eW?XSw8f#%bu8OLuEy1y4NVX;$JVvU+}KV#iv zF`eF27mx(PKGON{PCx!F*$!(uBNW;|6kxLM=QB~gH_x%ivY9oxiDL=W$qkiw6C5ig z64ffG^O&)lmrt^qoOlrftR}smxMnhC;BQB&?!;%c{;io?QcIer-zdeh zFpkI^nTu2*f1=!7I1my2do-?^pZk%#11oZht#bEVgD-}v+~hEm@)jHjf`CT&_{}D#*z8C0v~yB^)EOfdj2ml2aW>-VLnJBBT8AE$m|mc zz>W&S6sI7Ks`&Jhey13IT2dV2g?iT+h>ekJ$@$U3yyD0q$jvqB`Y_~%8Gz<%-J^|N zHP@9AiTK8hp*(@Zl>-y@76IWfBn1LHSxJ+^0JbzbzG1}$9Nq_W@~2hsi79`klQS9u zl4dY|P^V)Ie;$mdeW&e)`n!T1kL#DQ-%VCCJ)6o{$LyUiz&bWmHZ@SMWB0C;PcyQ* zcNozn8ZNACt?zCSc2IVDormy9CZKo%w^l+Y#t*F9^9hFeHF!wYnn=NJI z1h1mveR4YOR)LUP;ew=_R7o?mlsuXE?~87v)TGoL?4s-wbu< z(1ux(UQq+TfM(3Il%F~LKY5~+HC?iE(X>DiLCp+0S4<|`xXHitMxYidYUI(CyxASe zk0g1}emi$5jydzMf5BxMV}oVE%3Q`yUIYmA0F|+-JRJL0%fif$QR=*e9#vZ0?3D?N z%M;-o_ozGUEc?Un#+|2$J|`8$X%J{jO zdFaV{#ST7ZnQBGpB{UX(yfNUunT;@FqE8DvxFKRJPIn15c<_VEj6nz2V7IOpI^U%%6(B zcnWR66D7SL`+Z%ZqcP#N;~cR(nrks=eMX^WKR)J3s$cZ9ZPTSlbbt<^e=~FV+_fLK zgK>o=4i1ESF*fsQx{hi3seP6^YoH$FitDV#B_@weyn;ZtYhAEhVE#a#*7eTIK_lA{ zuYiZycZtgW>zvA>i@bk(Tj{a#WJSUXKFLBq`uU(Kg!_zYj-BA|W4Zs1Pdzqae861Q;SnY-UigWqdp(?9+F>!N8mcu~yi z)ACsZKj<@^*ewHE;{;H1^B144|MMbUkN4%hze^Uzh+eAkq`s(MfSzamd9_2}+^kd6 z7bnp&3KfwQcwXXI9a);tMye7u8ZPro<1AQ3Ru2q!an6FZ1iyi2=G1^YrsROJ%$D?| z!+u=j{IB|73JUys*thN8W`Dhtv7??c)cfK`Gz6C`jbIAwpenD$!!p_p$;5%NWbO~V zAJ^|-WDFHvT`RdY{=3#AfYRfsQMq!@VKQL|a`4QV(VdGIS0bC@(vA+|#_#_f$k@gY zmG1XV2QB5o+(QIVBY9q^CtQ3-isb7vC-sdn2NQqT3`i1unk$DVjKobzFsvZ@ zVebZ)kHXLTUhzpi3hP)!ptFC8HM{gs}qX1e~8(&s&{&5coXlg4W~zBB*&Nf?cakW`}I;d&Y-*}?Z4=B=jC zpO!#sx8sd=w^6g;TPpRxCH}Vh`9LNP9uZ9UtxfeDk`^Xr2mh)?=jBn}3cQZsSU!g@ zqZ&NKAhlHGIv5ZtTMG>|Qk&L}7C+*)r|m8IiSfmtoLQF)yLcPVk3$n6F;!1|bwn+| zolq%iXkC?xcU&flt-rrfRM9TiR5Un&cmF3*2Tll=G)l7s0F;iz3!!JfgwQ#$Q6Utc zT17$URGaZOE>xql8&yTzd{uLKV&+Un+t8F#b{@GlF^W0=p=P)0xX#QkH1au7G1Ob1 z8R%_pejA^imKIL$z)p55NnbvXi&kV1*!k0NMj4A$AY^%`x>PX68*T@hSCmx5zB*V9 zSFCR<(?FtA+s|EI$5jF+ySl&f*?g#S{E>)F#c|&uKy0wt!&#xn>-y_eeU_&y<14I(;ErpV9s@A!vRFu^8Sj8`@_8Xz5s|V= znPq>p(o+ZLj!L1_CP_VZl^}YwKd*%M!&f1$*AKtixph;G(1=v&J}a1=dz(dUl}~xw zxqtqs5X7q)08 zCOOEeBim&EIC4#LC6|FqxO{7DMbm7;4L0FtyFJxe4YUpBQO`Hv@Vu^z?60qW`TH>Q zY;7OVWdadL0(nTV4GSA6`n{+}QOZoUL#;$fO1YQL*4;L}rnHKS@eMmcuA&-;u#NYF zTvyP>doLdSsJFfw#JuwR#Pd|?;|uwh&yXK`gI6t#|- z7e1nWZS5A^N|h*yLXl=yjemC|j*g34GK~}EO8llXlgd;c|G2A8S4T#n-&v{lLznw3 zXye#A<46{%IHi$od=%T%lCZQ#95H$~xM(&4=WX{N*Y`O`7etSTn3$pYu$MG10?rgt zQ=jWF_|X9_i#6hv<1h0+yP&_QGLIj~n`vG-Q5&14YJ}sjv!!Rb3w-o)zqDv(i*S##S;gcYVp50=pKJ{Q}iG8Q#e;)us$UyLFZ(ZY!gXjVrX zdiESifc3u`DD{h5`47-hiSKyXSggMb%37W&zql2wC$Ew7LOhaVBm%I4 zL{x9N~J;cs0#3UtM7DZ0HTLv9)(kGC-+{8_euozM>=PwSC~Cwht`#22*yb% z)r5|3Tay41QJvT5R{LqnDQtPKjWN#(Oau0uvPtU%$Vjk%U@XH9Q75u7zlIAkG&%Em zeC33rdA@j!=rnjs0{IV|L>mR7V+5Mli$-R&sa&pF;pkvk5vd}Z$NUDOJ93Cd!#V{| zMA;G(_gOmXAe3|n$&_;<2;4=GlIdgCyv0s_MYQpp9tw&MI=|8|))1DAH!*DuO-yrg=& z*$4H>%fWa=k3?f&UCBBn>+717z>9IL{j{VJ$GCLu;>F^4vp5lM3iu5{b0+*wSIX5H zoC>sb;wG>=;rDI*yQEn;V)eczW>R2ipzUmHyg}6e@?_OeeyUMV=ov=mUyPc(3Ktn* zdeCG?q-#g`@zb#$*N`~um{;T);Jo})zuRxyTG?9o?7CLZ?b!*k6Sb9}NEnKky>KLwPne{i+^^NUU!>cE3@DpJ|cJZ;x8hBCO1t{W)KN8&2?;z~W+|FPc zmnBl!?Gk5k>?mx`^f5PLp|q4^Xu3gqBX@)4yUsi=9(>mr3H^ecJ-3$h zpk=B~yEncA?bJx^FkPS#-1hV+%$Nc%ImQ!QpETg|r{Hw#Z9Bc3%6Nvgx#P^-33&RR zd|%8=7z%EET;Gs)hYfpDKX0q=hy{hx6YyKCQ=CPUo?{=@^xULp%pD77s6TaFxY-dj ze!`Cj=)fww$Fr{svcrKx^9<|H*VKgBSM~bL8&j>SZS84IZBOJYO3(OuDqpOwA84-V zWWY2uj{Q9Tt?h-a7y}Xq*Z8Wj&B4%drO?~u2Zr0Xw42Pp`-^&)c~0n#4-ZQsReaPl z8W#)`QtGLYhZ6vQDuv&=frg=nxAndKcU<`~9|(d^^w_oG|>dU1~|5{0aWljeyXNkgskTQrnq=?U-|v>tOlz>CeEN*?069$2@v zT&qE+vos6y7@MYK*5<0l#!Jm-7D4m`0qq{lvV9%W1IVr;=C5{_gk-thlfbvt z&cte-)R)Arg;cB~L_HKqB!8z$+E}2_!az&#UhFNip$d{n}90%+Zn=mYeW^h_ZfJ$y6 zd;L`KI_$11*XPc9|9giwdP7CXkEj`|z35>jR(3M`o(m-x!}NA2-aDe_#`ZPnaj9U-(2P-wxep z;-4B?6OXh#aq2Y{^dG;a3=={7*2$Cleo=YeC$0`Q`lnCuSBwY@8a6>yzPHY_iRGy;!ss41zIMvLdTPF8j4@&=T&<>{nhvR=;_KvF z?DnfQoY<9ncl*rZ)~@n}j<2liQbj{vU#xybw{wp|s4nCdh9GU=%0VOuQ5w-0t~mOQ zVQ>4Uxq&D9a%Y}V?v!0ip84pa&w1YhlH#f)#h4d(=GVtO>C@z&B)t%gq~zJJJdF{C zZ=AciMc+>4<5lS>#1}$M*RGg)$g8ROr{xuD`uIJc0X;U?DhLV&tvb&3jL)VR5o-^K z9bfzbO@RuA5|mQ$A2~M|syE>H;|KM4&66GHd-Pl=Dh@4L>Z@Q1ymvuoi_brFZfiTV z@u@#Nr-#XV9L(H~k3M{ExHT#a{8A3P6en}akH5b^yx+E@7d46*6u5A043bakFxVK& z%F7xS(DInOuOiG3Ap*zo_l!T7`?=yv`=Z<&fAa~wiA980NWQfA&ZCQi-iGd#9)IIN zc%y2W9-n_`aWGmLd-%cIA^8C{7`LUVyW@&za&eoh9>=!3)p68zw>g8& zRm_|v^NlM;Y*(!4EqCRcBY#faOU`LtHzR(oH(ZtXQ8}(aXvMPW@cQ>{uuY?$JA6$= zz8+Y>bUvr~hl2Fm6}&6@EWy$agCBcK)F4yX@NRGWx@e{_r!ZzRFdVb&6JZTj>nU99 z8@t7K#;P#H>L%~c^^R2tV9?ku?3E!oX}mnw$6N+Be{)?xVNL>CJhH0gqSJw$_8s)+ z-F@qym(BXfFvE&Tg|T(P$j9?OZRI>w#|Zo4RF?vEi4HIz9pB_^!vdi}T-{aPh9At? z)9-nQWYZm#UVCfPGHo$9GP~+_$g;gtiCmc=N-3M4n>&Y`l`&(<{2}ity|h6Z3^q~F zOGsa<{tkAPnpy7**S~EeAbjmbgtn5@NTb3^3`GJX%|wRk#+KyuaU}w)T8lS+zO|)7 zEj_QH!*|xnhOa^*mMZ{37=QMMSm!)vtafBnAa5$Tsdqv?|P@Olkc+)GmD7_l0 zuZ%S+3`jAn1dmhY_1XHY^UCWRRsmCACe%iuk_1FN7Y|+1U14M7KXXW_M~&cneC5%~ z>KcFRwh{#{={jAzoWqiI>_U$B^^JdSDLeN0WvPSbz7QI}3?&&;S>_L*% zy6|&e*fKUzzsTeCr?O1$Tx%QCyivBluHanoh1dT_U3QeX^3b4ZIf zKG=MDj+fi)i5E0P)1D{}&}K}4a(IfLdiX(7U-M4>2QG)Qz0pk->=c;)vy}*h-Wg0c zuJK=_uE#FRCr6sqIKrNo`IcrKmsJm6QNH50#-BgEM}C|0Ecj!d;Zz6cnNkke_+(uC zlP6x8vz@a|y&u|fC|i%~)D>ESdcA+6Uow-h9jg6`Z#>erH*Zx|SUoOSRaU0r3L|PIElQYZv8$9tX-^TGT86CW#j3+Q&;*@cWLvrLHpD09VgOz9bi8p0e zIWHx6fEt{8S8A^{`6T3TT@BylhF6mM$ut2Y2r%aIOuaNtF32!sw=1D#hd60%<^@W) z#3uxX?m|A=VAl{>J*E=oO4^B(o5YHeSTwC97tnmm5ow>9%$z9k^t(Y4`A5cd{`hLR z35J}0g_-D;8uWQd)o7WZQJ4XugR+ix8^S3mRzuuHmv~YhCj}(<2vuHP)l=W;d@|oz z8fXxiF|@K_IFr~iFGBZdvPVDRRS9_6P7a8^t_&tF^_0OA03nj2(Nn>;YG?!Cr&J}t zbHffAc!7z|rBtSPWFEqUK6YAW4ocaFqEKc+yW04|V^@a*8DJ%69PPnsFA4D%Gyq{v z3Q!VLIOv012zBNCf)(??%qMZq*-yqHd`QvH*W(ip{3xVm*F`vwypcWf#`q||rd+SZ zKpkFNc0*JNyMtn(?;SnSQJxlg2BzG>A%@};sXXGS{)WD-wiuj|iJ9&gJ9gMy&)RL( zaf}Xkj(5aDH&=T@yFUG>dJ%fsnJ+TRr$2C+a8Ryp2Nw6H$knd_JEJp@gkI+2UeOK4j z4}0qq06H7qZtlNvBRELTahf&OruHY0pX>fGY<6%)WVOo^rhiP+*Q>%G>Z;~$!W%E^ zjVpmj9lTUT6~$0Q!T#>Y3SR^cHVKE1G}N*OD~+tYiw_-AGQjjn>v@r*rTBnW%u2+d z`xPxgGYO1z)RK2H7YJ;O3-of~0C+K>fe^Cixmy?kx{B%qsDavUqCH6GBgiX=Ws zS2o!wgk1<7``=L>*T!pZ* zUDPYaGXo3vlTl=@m>E6R-!{A6#>y`Ynb%k!g*7Mk;nZRNguDw;zBZ>o-W%T$KBaWR ztP5Jjfd}Xof3ZO`9wz~dReLM_W;EDNqwQFu7~>vNe`f!Sa_Uc2NL-Z{kE+^Y^?BK} zYq4-_tXG|DVpWZT)A)RPN*9u{h9Y)-NGm^rm%5u!Z+>pw{G_@K)@rqv@(c&vsgNcT zG`UlQ9l26hlqkZiKZ#QwRn<<&7s)^a2Jg!e>w$u%CM|5RbBE~jNLMEw%j$uAEx2lS zhnoU^Yi$jsPu12v^+z@*HQkJ*Nvbh`qSVqPZw|M1Z`{;Ry;fb-lG2)b>$iG$F(rO`ihN>JI$qaSzxg) zZoR+c@yrSzU#AHO!vyS_x%-W3BeR@=4GdY1s0+5H2r}&DOnB0I83k@YrU|(6#e0-Bi&B|8xh~Jf^cb7i7T=i=f=dPsD>Q;ZWd1R+U8!@|-u(t^}zp=aC z8;ZwrMd3)Xz0j(vw|+z6zMY#JAs=%^&UrQ5kS9&7R%xDgPpSC?RxBXca*0-)4Awmu zHO58`5^I%bKn*CvuZS{VfHFZVr@-~C+w-0G)bdTeJdTmhg||UY3H>kj-&aff(LjFo*6jPQUwAOaY;f%6uzH_Djv)zG^u02po1UXKs#bzxv?@4s&+V2GwTfyv1 zW12wT(PnylL3yANs0pUnF!-BL?T|vw9q(UtMIBB`wvR&%H~g}0CUzIrm6zPAGP$}k z0s6CY-GG=}Db4vo&aIG=CLK-TtR!Sa+4Bpgo0!%mqEh#?Sb<;GD#S)rQjd`!58p1+pNO5?Jf@FuiW#F>5mYus z>m%l;(Y8MY&hC`APhulns2p-1g74TaHK?wAd}oe53|v^U&E1Vww4goY27|z?-AJjD zg?*28yzN@omLpBuFAG_qrqJBMQ3+jw29#r{7Q4FX@q2DzhdiC3t_7Fh{Q8zMQhUm; zndG;c-*ZBy1=nHEBJn@3sczj=hbEbN%9oyMuA_U-MQWLn`{FEzm_>bmrW^lF1;I^< zfGC_-&Y6j8bb|=P+ibd@>ACq_yDH}p&t2(scej-*FcELhYeZ}LX`5i$xHP~B``lTn zHaBFBTD-Dl!?}$a83L8Ns|W3F^4JH{*eNHtWriozt_6n&&N7|82;U=T2b*#QwDXgh z$7DM~Y6(XVomDH^32(e6I}_MFre#h;KfyJ29^u$;*Q9pvy-yh0gZg#p!A75(S%`x@ zd2S(Ru#+hNHN9Bxy<&DToXR*6ys(b5L!OVV=Bx@o>}*ZM9~XnB8PM`QqKGgYNpfS! zSz}liJmZlRmRRRweB#`%T~L{=XEfzI(Dc8XrJbzD++H$)UDKVi2;dJZOu!)t&|oLT zlp!k&lZMK-xfDY;&)oV%4PDO)p|=(iUKAqXhjwHMf+kbVJdqH%5gTmEvo(zjtD_ZZ zPz7%G4RN-}Y+DRbewu{EV7MDb`3D5c%zfOIEgf$ubDhJrZ&uF6vvxe>PbbX!xwL*xqs9My+igA=wRzl-Cy8y_ zx5&RQ4(*E(N9l%E%30Oj{^yg(c3wLKkLw29AUND_o#bm4=!$#t)M6EZ=uTmzpA>RZ zNt+2(T&YYvd748$jao>nyE_%q6E@*lovOQGA;e0L2KGJ5(kTwArCv`GS(z)Hquq_s zq?Cythq3b5pNlF9M1oEu;7Xyss{@WMm~v*G)GXUtx6JD9jyzHm2E3xQJ^EF!I4oh*24jtpJ?n4t=UXNk z6a&qhG^^A7Sv|QJ7kh~Qg+ap&NBNwpC)**Jy(rtl!=|P&=1L85o`m{zqH+Y-3OvqZ z+U)-#I1NTv@L36f5A`p|-SvM&;GElm%CjZ82C z&Sasvri1d}Qn*qe`4`#=SRF#q2P`L{ew^wq*!@el`zyO@(kmli!f@+hI0niRu0$o4 zHjfg}k(+v6JC84v7?S_Z>9hoSb1*_%ZVQd8CH2(!V@olQOWE(EtM@SW~VE*!gi`kgV*-!_5FPF$3$GfS4yjUO&4=2r$vZLuBah`5x_8 zp`NuHp6QP-7EU6ydiMmIp zs56zu+gFV@akythWH?A+?;u6>hrY9HFq4yLI?EV~1yDrT{R>madmP!c36606|A*?q-Id>sm zcG3>#>xjR3lG*=EzjGvTa;Cp*R9GPL!MJ+L#bPz4 z5-^*oI6#Yl=71$pxp`qN%c!x-#ASQPMw1#NK|{ckgKVvNs=VwVJ_(*8QPo#Qejb99 z;b+y79qAgfttJ1$0HIUI1W7piH>=%hSAZt%o>_7=r%1qxF_ZDV^}R$PLO+LkO@8@q z82)JE2-f)2cX8Y;gDSKr{8|EnDL}aZLbh9j)|6^t>YV4iF$XM%GnEu1veKXib~veS z=)nX|NU#AqXO|W$;5qi(Is?!r!W1YQ)n;|27Z}rORBsed*l#4dI2Igt6+PfjvJl8k z`aky+K}im$`OXD8oGam8R&0oZhZ+D2bmBIWqvQ6DuF47b%ae%@X(?s-`WC6)qNd@F zlmz1WHmtt3qQn+~dscj+zIzt4Zp&GPwi;2%xZ>w7=vI40(et1kGQXX{==z;M3>#!l zNIPh`b7|iN?z$Xy&RuF73VH*D&hPIg--~- zpuj7ME57-tt`H*#GvU?w>Q!S-WPrgCIUHSmvoQ1i%rzb4bNct9bh+g?^#9l1+s4Rs zoq2vuS(as5l4)6f9eG@)EsC`Ig`^}~L(%k5O;VzkqBv}lqU7<&)!o(IC3bhUyQ)Rf znH>bq3nq)nW)mPmuox_o{g6zO`LGCr`LIb4U=l2lMG(w~AXs2G!6F|PqeUVszW4EJB81xB+ zNsJ2xxfeJ0$Q#}5$;)|EJ}5wv8rDDTo$6a~`!Rvi+J}fI#F;*Q6^mlR5`UsIz$awv ztAOx2DZje!1EB!thfsiNSn6)F{CK-bN{K~$`>Mz^MYw5>qyU)NP0DJ3b|&z9C8Ooa zvT-LC?Y{rypg|b~-LR41!}=8A@ufGnb*W*cKL>Ww7n_*?pO+3aEwHH^4-=-`$KCKV zncsGIro}DTC4imi7S!)XRwlJQZ6@eJ`psbie>Y8m!!*BctPjcf`H44oxB@Q5BfPI0 z_Y8)j5!V7H9obj45lX;W1cEAN)z}(|k7tT-e&m9gk4rF8BkE{OlwcWwJNzvRR;=qUo%Q00gR($m{l?!eHOfTqV zuoJx$tOW}VZ_OctE^HMkMzfQXoxXfsxq@5E5`vpu=Cx2%51_ z&748F%QN~y;s%Z|s`RgEGVgw(m3mDo;B(etxjkltaH#x3h{Tvvk^<)6JEoo59TtWL zLkLN%M?S;2s-xAaLJjD$68-N4X+Km)iY;PIcGFtr>`M67qK5IbjDE3hc<>$|^uxAZ${V z3f$y{HVmq}%)Ugt{8*)TPZQ*Lslf~D6CM*_kQ8<6vp(gQ!<1(0A@ten)Auhll@ zfN!z6BC;G|u4;G3m}&xGF9{Whcr=ToomiSmirK^M#(vB*rA6ibd zXq&{#y{idMRy#$i%}|&CIqH`X3fR?UdT*tI23^w*ld<6}{ zyuIe+z*Kb=hZGQVV*p)l7d3I@vBx}1&=<^n?(F15;K#Uoyc)pLO6<;@Yx*6tJMS(4 z?||FdtrtWV>ZWkm zPsl3dHuR8O!%dZoib5#=Fl4k0Iw!+HO957d4K`H`I7y9rx^^^a@!%e%fYiFDf+8Hqmbeb{O_l@qd zEP#p5ce0)<$8H3|r}f@MH<9HaF=C)qnhIQ*P5JT-F|bWFyTBD=PQlPR zP#i31P9)5GZ3>RQEIn`%d%CLa)xe`oz>#e`x#{KH+1%oM0+ZNc$yH!&=>f17(xd0| zaxb{7S=&BdgVztVCNrHJ)NSkeCg8($5Z4ph3Qyt0_|&|7e|Ud~L40 zjls-6*C!}~!(~R+VnUreMW*xPy7dO-7Z)r(Lx_Qt<`4cdAf7bNG$18FsnJ zL*lDjMbd(jPO=KB8;de^j~Ok$R#lVSydi&t%IDSaX5?LDH3-iuoq2C-d%iFg7f;Ze zHOyvxl5lG{Fk;9_ znBPsF8=@w}eGme6BFl-`SyB_d4obql>NYYi5e5Z8>=_HPZhbTf!tIYX1{KkN=HHu) z{vR81PDZJO?2|C*v6|5WvoUCz*m0XMXHVcm^0y@H7!S{m3q&8M+(0A`*20cltwYu7 zYh|V0v*4(S0~9gL6B8`Cp<;MtSl!p!4X5(b@^q_ck=C&xd@E|!{nf9g8!sVhGB|#XNpP*IcU;IfX96D+1D)f>B|Cfl zH?HCEExKBV%FziUJlz=KJuSv=7I=2%AIGsCwXr5urW`^WC-_v|OArp!6eA#4$KK>` zab=N8%vn7LCd1A4^Es!}s4F`d@X_C_aT0xE-+CPkPoc0qU`~8ksRua*n(vNgG9>o- z;IXJZsJo=zco&XceWC|6-|)L7^wj-Cs42n2^(=-@*;*Il4 zhZSrB9L=pbBpX~3z6th}nFr%qK+5YgQFlF3;0bE!R7|qk>dfRYMV)>m#&wa`=B2mO zH$Kb?SHpS?|5#DUrEV&>hp|~Tsq|?lu2mSf@!mRfk_a%v?MR*fcEAwvcEb+bm~?<1 z=N<;VA6wBZRy)i>5=usPKO6_D@{h=Qk>W2XRmzB9q@AZM75a;iE;~Ui9(r^l6*cur z0|VP7=@2u>d1W~&U?w`$0N$ZJl&b8F#sF^aZc3n|NCU}|*S|0l9F+NuN4wc-pX;OX z1m74wQ!fq$n`wzAl=HaX48RV(5uzL0JVdLrvFP5e@Cs#_q~^yudrqUfsbuWR(XD#z zl@0JaJUZzll$3r;tFo0sdGKl=Y;LTSJo1INX|a;$uuKrC@6G&3E?-nP@D|1}ocXbU zK}F%K0=Fw{<~Lw+!&A#CH8zB^n_ujh-jKMmAm^3vFG~#};K%}A_>ncX?x>ZU+E9;% zKkm$RZtQlIn<=tZ80L+okesKW40)E;K6Sz#Zq1M$w4(n(D`;m{_RXw6(WmykfUZW_ zu&vdwi#KH7*W-uZ{mHAlAuVua1&#A3&DGwAiS4_}C$&aYY>*5iNN|Y|`Aj7-Cv37) zxkboGyQyI~7>0?OdK~QVv71AI&1*lEbfUb9te@=ZY9Smq;L5Sc}bWCl3Y;&WHVCz=4ixazjCH z%wrlG-c)>aLvkAOJV=a=pe<&=U4hFDy2 z$Y0k2l6hqtYpW#!{qj8|7?FzaW2OO-qDI-!hNv2(|4BsE$ZwbaG1s8=OsN1jyQzK0Ew%Pe6hw(Q=nILB7po0xEz|6}otE$C=uR^j;4&{y*N{HP$O3x2} zy1cVH7zfci4{&Js0+DXsKFBR4KRg6=et5@K8cYbaw>#kgS4#(YNm**S4Kr?w;VVnY z_zAIU*(;INJXIAkhNOGcIeR1h`I1#L0NBN)Tb7J%7su2X#rF!^d|ku6DILSN^PX@B615HSDQ)Mg zuP?oMHErcRb@tU>-m{YP+Du23&W<2(Eh@RhKJ&Ud`}WsDLTl}n$E2NN_5^)99_7P+ z>q+C;(uF6Vj+dR(9zI^!wVRoaSwGc*rhR?^#Wkbg&GEB(uQ8~rN})Vlz_SU6fMN$b zrYu)rg{45q_A4c>`8Us3PpyjWJfAJ=#fryVs4~3L5?3i+9sX2tsb2i!dHuDz{QUUR zH}_3N|2P*9;fGpzm(W^dTyy-Rb@AoHyd~UmD8mBRGpK!G>DH?WQp5Mx$02h20eG>+ zq7a`+(M)0#b1~<{N0l`)fd`LDJb1Q&VvK%6=;VzN45>!pbHd#xLsCgZ-qF2+I#L4S zZRz|NrZ(z5F}WH=+ItpMn+=>Gu%~qd`a=e3E?OQ4fWpKN`NFvct`w zUed1%uLQn8^T3(+q#qbA$}SpoU3GohhOL}ia^q-7v=h}Onqt~E*$dfZ*}%aW+&1m$ zxSMarX~RUbIFPcLPa{~`X8x+U`vq+y=|M!(#RKB#YAnQPoy!*{jWgjk< zRjgE@IN@jBQ1*LO$<+4lW5T&uauMHrc&W;qYJ2Uk@2fyq0F#4H1mw`MIFT9h#v_3m z1mJlU{B4k|DIEG1RmGxE!9Ar+gxqp@))bKyrK^X4I3)^pt0GKE-C6s?ksCKp7{WTc z4amCxzDfz|zSfU#U&m};p1yv-Z5@6}X_eDoTXI21X2~_Cyi?|i!8ZzIRb9V$u>rRH|cO&vCEghL0;~pSmN~al?O!)GHg@xexcWhK|9L%s zS$jhLGG8n!AoNLzFs2J$05^8wRJqRx*B*&W>2e6*!>&9Q$)zNgibp!vwp?*Iz;^Tw z@&6t1^q2Kl{Rw8q#ZDT|r00PDnx32V46e5IaN_l+=A@W#Ns5!+Tv(m&j%QC*7p0sH z&ouYcT(j@$)XeFrcGb4`w5PTw@*SmTd_P_yc1L^jBq^}wjGzsq!8PRS_^);rM|E$2 znXaTa5$~jb&s>HBDgDc$f{wrAczaw}oBWj42MAmO`P*2_N})+A~W~oP>vMPkk~@jQtvXeirtfVjYMQ=obvd+A*&# z6!x-|NvIhrMl=Ci3NQQNTT61_H@9sp&ftDw8v#9PB}4+Dc{>|VF3iuE1j!TPXnAj? zbdF>qv0^L9Ltt7mW78xwK?pW9SH(Km3w~=j4XfdAaF-JT7YruM>MJz9?0A&~Dl3Jj zeSFx|&L=(z_;g-7H>yG!xD3Pv3l8OZ37iCy$zXe-g1k|)DFaYDp6*gy?;w(@Q(@2a zn4X-+Nlvm}$F5X+gXFW&?l@i@RHC|Wk9lu>!oWttJy53M;z97*u`^MNX#zH$Q3TXQ zq?0+ZAuLV4j>8LD&1T?@T+H=`o26T1RJ&9h>M;Lw9;SvZf9Zn6+KAw9N`5DP&o!1_Dq+Wy0L%J+#}-d47N z(rb6R+=5Zn(ztz3nt?8dT3z1QTb}O^I(K`^L);T9R?pO3)$NXC&=%dO^D@|X70{xl zV7nKrysEwM=>D0r3p?k|syZZeg!;kJt?ur6e|t`Sr_OXv?%aD>nZDtR<$=25Zq>ir z)D^n*Z+6L%sJ@!}>1Yo9e~x6@ZGC%6cVL~}?E6eUGE<#8Jw8=FdzdNz!X^seFwe3y z^gBM$$(KWAK>VnokDj|S(6)dO85v_>JWiXH(5?Q}{^+&6<&G?x&?QMhbXu+4Rl*4M zfB}TuT%yanHv4V6$roC|E&uAnZ>H+ZOm2xaE7ragAsvifwtFZ+4BZ&3gy$?iZx3{i zll-EaQ^Ibo$@J*{37YijYekRN$;}2+y7|k&3EDY6BtR{jTJweXE5oQiymLa=r5p$% zwIl!VAbC|MYlmxQCb?atp%e*1afO&Gp_)M5Cu5iEBxs7D1OQ42GYGa4SjY)l*%;8x z2mE@E>(*A48p>TXqPKhu9Ca0}76zN=&hDJMTJ?LY77qQ3996~FIHWKOCj-&5z$TAq zxv}Q34SYc)g3$>V(Qnb zqLXtLhJ{Y8_&hjgqbBrEv(nM8#-X}D7MeE*D*NO@I)~A|n%+adRo3+0M!J$OX;n$8 zimI+ClQ>srQ7JCyf8Eu&0bOofMoWv6CbFlS@Js^aV_7@5*}!(4;&Iqv^+53>uk0#IWTW)TcO<&3 zvjqmG2}m8LBP7CUptv z8T@DQI6ob3NGU@ydtU2uJ#3;r6vurcj2j!UmnI;*7#CE5CS4_Hg1d6=#bG~h!v+iX zN`Jcr5woMsz!YY}=b#$HSaN+aHcG5k26OrMa z;v8sxcz6wKnbkvxbxN9U9nV(l2t*XZi)wEwCajX<;4X0qSc1VVMO#ZgE7upHS-NJE zyvLeZd5(r2Ek|dx0{Xy*;sG4HP}z7vauF@GH4S%qD_mw+k^9)vYMo0Tx)hRKo1B>z zrSKiBCG@J4^YiHC;F=hPq@U(%x0JShJ)|C7)~hK7&(=`Wt?JzmqRGr~R>ICuF>&-+ z()I^g4al*}+bTy;5#7z}SI%^#IT-H>eQr9{zN><%=F+b0v$Q(oExf<~g1*ySP{m>| zU)X0k|5;oPM#ea#t^{;o0mWo-LCK69ctf+G!w?6KWUkFgqquM(1+aGD;cYXBy$g3L zfxA}Q_6~kw`xVx{11H(k{o46m20?<%IBm#Q9HOfe1@a zzo5*woSxcbPc6kDj{A6MvN?&Hz7od=nN!5Tgbx1Y@w+Y{0<2e}KCP2GMe*#+%*t^2XE<4!Qx-L}@kXDu z;9WXUb5WLHbXBQO;}KWnwb9~r399;a3Qf*Xi-W}}zqEue`?}i6hK{8=C$juXEBIT* z6|~PkR*&S|_WOwX@ zd{OP!Z(YYDUE238X?JK(mZ4!aTfq*g*2Ip+MON}eng11DX;D7Q^GNvpjjI1*cRNZU zJnV8_Y^xJNX+{4`@@QYqs#V#X=uM_S8RUUwUNdT$2DUGLOS%TIhR~_^Bs+=Ivpbvq zennsPT$O*Wr~Gtblz6S}PE^MdgNj9Hc{cCW=n4Qkvl{<=ZnJxT81eQukoA$hY;=cm zwGft3lwm{d#CpT|&UyKk#8?{_ZVR+K@G5yNs$PkDO^&1=mLUD7Q$l(?ZVaT@1?`LQ z1lsOkr8~i|ijUUz#FOx#_9%ks=R6Hp!-sxL|E6+L#y4upFJhPk-R3HiLiM8>Tmc_0 zy3y`^d~JfA@@p}N6rfFRJ7f0qookytt{#+OqW>oNhFA1@D12^c!-sxHmIi7ar;hSz zxg$*&`R~9WT^Li+IS_VUGQOXn2m7FEmlcOe1gii;7K%%FABXohW(>3O4K}|(_6XVpWN0JNO z-;sntr!krf&d%a&t2#3%6l~z^atz2D6q_t|8$V$UZOg{#)i^S8%-(x8nqj52x$^4R2JYpt zJF08;0>-A;gV9X#Klx(nK0RLbY0vX`RpsovB*tn)_hnqV;VEAWx+XI>S|&= z5ALW=4r+C|X=~e$K9dGR9PtIo;iH;4%>%b+s`>}$+MSv6e`45QxiN-{c}F}C?z*lA znN5iey1dZ`-KXJghb!i%Yy;&-Kojx|1UVkuG>kIedAo{QuS+?m@KMi+qY42)V)*i_0uX%u|NC(Do8Ris6;n$meh*hh2;f}U~8}{ zU$D-P!!zEQd9af%ulR1S>e3R3*F!~8M0R!lK{pXfRU=fo{^53Ae|NB=T)&b&F-_F( zOJaZY%bs}lh;(LnE3)pE#jRgYhxnUfy@ zh(2M0N6b4OUw+t|n@o6TpMtK5Z|(!e&)E?qz<*cD05nkrYlY*c%0X!)KAVdm`1#`= zbf5KFcW-kfCnqt+GaXQ|n=mO|#Dtk3IinUgOsQ*CSN=wXA50wib^YN?h%Y)Ga1t^T~U+ zDE)Ul2i&|y#S4Z4;-E?(UjZJvZ(h$}au-Hh_B0(`v|Pt-ypsrp4=+Sua_&$ntai1i zAbmLf0m0xQ=z4kLw>>_GcDZY}6S%kx3Ds5KmBKC43#jZ9MD>A4=bM5@}EjAV>j>V3L2FP0&%j*BI^HSxX ztDE>=lBeW&Sm+t<(!koq2@;Pzs58T!n&DM$kHTuV3#+}NwV3E;uDn+i%+2a1&`eo7 zYitH6*_C;dn!&uZ?%8VH9yuFNk#0l`3v0htSi31fYk}qcSBmjw$V4vCLpYIE$-FQMF~O2D=g~|vh>*Gj4^poZ@|ToTf$z`k!GNE zGuV{f9kCW9j=6IA?}|SEsg8i-N{YK{WsKfDJ~NnY^t9dI7&9Ap)B|g0V;4u7MT~H@ zjb*W85UPa@rlvgDsZCfbXy^Z9jz4kn;i`A7>i6=}W(|xhAEWJGFnK3zPy7m+XPt*gBT<}g5vgQ%H z=o#hduB$rmYS19-(BIE2HvbSjDf!Xy;^bLZUyIAwrh6Mm5}e-FrnkJF%_)7|iJr+A z;l5AzN!yytgNE>E-^hF?T+4|E+O7!> z)Xz@(qd@=VUHrAyUA!rt=@BSM7=ng)J+5k2F+Q>zIu&ecmmX->metK}QX~pKX4j!W z*7kJD+)sOaX?%|%a68|*D68f^X*>il$aSrl+`ilFsEr5t7I2)TrW_618H!sSjTos5 z=66>FRS{4-E*{C^%K;AY^(@9*2KY-A&rQhat_Ncy#xsqQYC+gI#p4inbhx!I@;{h4 zAAp~`XV`mkHr)GQzVOuv2+l2QmWxw&`yh*Qm&T*G zG{}Q#2k4m~0@cW(0!LH-b?LyS?amyFfl9*1!+Ua8I$0;Q{qL@=DPU>cDIdAMx4raJ zYsEs_ukmKe$y)&fNj4lw_LFz^wTt(9y5c)DC0*!K$5NMns>`=ShFLzYr5(ig0{GGnZ9fSs!6#=GVBipyqym_n2O6InPrgV>#0I0vm(d?v50UZ_6@;cAQ_`V12Tig zjuVngR&m|xL=f#t5rK#xyd*FoC07n0POC37JJ3Wd?^yfLZ4c8p$HymtS} zDg^wz5&-+^uM6iJ=znzDo!7tQiY>(77G|z%%{DKYF7F1h(OjKXzSWC$0dZis;jm4(UDH@M4TSEWKo$q@d! zdG+#b=^pF4ylIzfsFYeqfPcQT)a#Ac@$|Om@AmKXmnCF|^Ml>>1wJiQH-Nu;F}^-L zdanAilfJ}AeaqjbvgsgrEpdb3A@|F@1UV}~$qOoHlx9yXVlyvst=34z+d=Iq5zNd> z(w*V!o`7S#32oK#mz`7cjHeccf3vAVipwQn{7N?jj*7G?%DkdM8va9lHc{X1aoQA} zB>Ukji-Wz*)$M0TW+LDVJA)^zeT!EfaNhB}t32sFtt0q2_ghCJz5n_4<<1A^Eo{T# z%^4tVk>hBD$YTqJ<~r^Z;RJ+bb_aC(1ivMluFkRS(BXE?q;(4{aB8R^Sh##+uAU!> z-uW9oW&H7ynrZ$xBF3+T1#NR7qa~gH=pytt+qv}okK0$b{1L4#sho*xugXHzr?|pz zG*=kp)!kj)XDRPZ`x@VQpf#ElSP92x1{ZMsQRs;B-pq3%#2k9R8rCL`^nQP^H*^Rt zZS>bh&rJm2+DEv!X@K~x(n6;Ms+EQz99yYfNpuYErj?D7a7Gx|5|7f>nPwFh_aZu zA2(hq6x0>866q__PQs-@?YsPg7BO}-2vDpQENE9V4f(xRD|r+w1ZX}Xh=E@a2DIMb z3I+54?DAWpMU+~YXT1%du~R3c)bz<(P2|z5*NIz%VAauQP92r0AvWfT4{}m?uDOy~ z)^%UfeCI;wAQMfJT`Mr?kA7&@d|9jT+l_OrJRLO}H)bQ^GLK>z80;N)fAzK1lm&Av zEM6t?tC5tqXyGEKY*)R11`5IX?HuKW;X($!`NAA(F5Tyv{GAbma<#aOb~z!Icf`L(~5+)jpm za|>HHDIV}9^8$YEt$-bGaR*lWINKqaicxY><)GcI#BVr^Ax~pZpa!)Eq!#fjDNER| z4njvSCrbBOc4od65oA`DzwT(Na+E#JAQgTjtX9<4sE*)OfAp=E<=2$iM;1rBo6jxq z=;vf&!1*pJ4-|9!q5nb65l?7&G=19)JO+$64npSQRxqpafq0s_d4rN~4gBI)coCur z%(G8kqQv&ykhY4=;QQ6L&dtrI$eVUxj7SsMdHo;XfrF>2Png`Sl_!uI$2BX`VO@W7 zo6{-nXCeC*)z=PyH!Syt1I!Q6-@}D4nE5~T-!vv~Gry_e_4U_x&P+aoKR*sFqc2Jy zwzHr;COGZ~Z?NPmxKo{v!N6BF&7RV_S(Tk7mBW1Ee9U`iDuvHRTD3z9m>LS3-xrk4 z;f4%a5*&S}CmqqKhe3+ z8}86_4{k$%0pA0%d~Z8koT?kw?so4J&Km9QZVx3o?Bcd%Me}>2wv+QGL*d*h{oDKL zURMq_bxxgFIIc@!M&WX@xe!+1%UK9jbtvH}&BfF8xM0W0g&Dnv8B&$UkR?mWV`BCKz#*xwpBOyQ{ zS|h#vBF!Kb=;*w-tZ0GWkU0d0+u3Ym=7NFc;WTQVoE!|fK~EzOdmGVCuq0IyIF)(#XoP#)s z*_?m`Ub7guzBP2rB z{Ev>9ds}ka;@j-3s-fs^Uws;b=XSBXxxz2z;uSW|*|lp6kx>Os8kuN(00%L+IL=Bn z$h$TObWl~UhXBh?PuL&qw_bH-W9a_t8Lut`kQa5BS;=F)8iGJvfjEJUF2+45i+4E zyZODp{r*7VhJZEB9!n?rsVCw|LOeOsaLv6=UewdV;pM?=Q_j z+P52{06APohYyK4~X>Z_b}K%rX<{Xs$5D8S4 zyMs`(v2CqVO8P{5;#66Q{=wz%!l<~70CgaRAD~&=hP7?V7_ymw$R|u$BNKF`xg0i zcbEI4-R`bTypVGp?i;_`A6m9`Lld9*Un3@#gtvPJaM5nHC@TiVx`)C1IDIiY7(Z={ zvGEyYE-**C@d~%Ev3+~q{+^rpHC>f+TEVvG)pq!_d_d37d{1%k7gbdKef{r6{e4pZ z=UVP_`fHjuzMq}spgKvhrPaY!N&o0}lx(xNI+(LZ#70KFbt#kX7?}ID)2E+*{`;p- zKL5R!UVP#E-+%F?lP?8!@Z9(h-!Ca0hyGcFJmRd~I+&zrl!SqcI5WiEDyl0mc)Z%w zhW$8CovYNdxlFiORx8S`DH2QKW*>)8%?0WtDAhUKCqTqTYw5psJj^YaN=&YW`ybqb z>2(#eG%>rsM6JZBd4N7{0atPo?L^!zbCu+Qe7A~WJcz?+GNy9sC}OCj76Zu@O2bs- z0w&tHBPVy%vfQ|{iWd^)nM&C!#*JHyVfufma_>>hrQvc#xef*z8^X7Q-(ohR|FISefsDk#dt9eZ-pS;kDmT6y13`BZIw| zaA-A{Q3(@%|M;ahufK8r#_at3yg3V1tg<~?t9?yUsGG*bOYd<1;~hKCVYp5A`FFRf z_fB*c=Qh=@YA-Yhj1Kgm0*6W%2G1OkL0Ly7lKQ^A+TC64ENXD|9^JiP5{RF=qT{<- z9XTC|>~eOuscD0noNun6m2)=jD6siZKu~)Z^;dfci*zmPN0*2**{;cUv;$@xxj1z( z#6gk^$7hrxg8L|!I3Uw5aQ0aisZ|rY8be%>U2)jv;xomHIejP1keTn(Sc_FgfM~3c z;8?o~082}XFy=0n|m*J#V|@IZqEMMQ58JGxAshM>< zeHxp7e@lnpml_gMM7eu^R*l?u(cP<64^||pl=q_RwVIpGV<)cho4?sMB%o>8@HA7! zLL4Qx`jDf7a5p$W|x|u)D7+qPm?N(@vbb?I`^j~L=pk5wKGdAH*x$J-ikQ|TW z$!bze+op=ouo^>miZ>4kwFwZxH`9dUx8Sj@K7W! zow}LDBf}!l{#FD)n?mq2Z3Z*SK`|L%uSl_YQ=Y@bQ{l@W=(7pmaRA!)bqYTzKRWm0 zB!Il`0Qp&OchCY35ag9BZ@yv?)((O9g@SEyvGM&A7^N$Q6}vh0nrsH` zTuT7K%n3LbQHG}-0asDY|jwYZ$iAGU=tbWt-oB~j^acC8)b6Rzp$^kS9IPW@e z!W~6L)ai=Z>HZ=Q=Oro|_0{Y^GF1&zZksD!Y6|eempK7a|8v}b8$U}2iI>6bI@Ihk zaV|0L>W|$cNK$J>5fVm z7`a^){WNxF&-b>&9Zx{NhLZtPgTyJ)>!ITj$ZhCItCD+KvH{f$apW+p+nbJ9tPlp@ zwCMn(8{mduNiL(fjK{{OJtn|tgkkBcwoVeku_nmw!8zpmKcC*yQ4jT-C8L?hvMx5J zkHcd;5f(II2G=zbpZIs36gGPI@>4>c47F{;5Fm?u5+&S}0fI@+P0DAvx3kmRog+0^ z_gUT3HI*yLY&`s#G!5fyUNm~ zIB>9CW2XEx?8s?DN@ILP^s5kRb@t&tv{iSsSb9H+kE@;A^M_T)YtP9>iONq*n^$L^ z!LE9pty-M*T6W=T!D%=1zeEIR;|(AWms*hMRMuz`HK*G-?695DlHi`y*F4;iWIUEV z$ThAW^6hyc-Jw2}ir9H&5vA zaRs5INAbM#MTpbR!JxdKATu7D1a9Vmn7QS!+v>s*yX)&Jx1ynN#6Sljmb4z~Z|!Z> zb*M^ANh9EqAP9?~`tKhARL%tq0j3Aoxa_tOJ`NB@{c5YfJp~B++W~}8^Q`HkQ^NAl z)BC~_-3Xs_FFrYrXdn_#c%@fTvvF%#Y{mq!`}4~hSFSn11gz;kOaty~ytiT;ff$;K zM#`~tWdw4^nF+}|4kUBH8528VMWN@4_F}6{jNxB*~H&mnsyKn%>FVnmyP3OW8qOWY|wf=0KGng^Z2r?O-TNZ zgK!w&ajyl4mD~%aoD>Z3zIvgf?sBRul)KNh6!XgzjgFar5VwA%!UgQsJSvCS#-CId zdQQbuyLq;X84(CEt9U8#clS6U6akPMBnJ_I>Py4~`0TgNjhNaReXNkgckb1AWr- zpbA{GL`trlS`v0iB>g90-p4HPN;ygd;CwNY zMMvN6yh?cR_R%6Y{Qbse+C)<_$A1a^-vX$mf4Jzh$lq3QDq|yX^vN%e-~-`|8*I z4m%F@g?4=&7yypVtObK?)A8r_c~g}c4<0miZcZHoD#e76t$lrVIh~kQb2M0$%?w-c z_*Y_D^20ho_t&=7%~Yy-q-XbEWs*}?qD6(H6UHt2kiB97uC-2Jb^Z%he=o$oieyg; zNY2CB$llQtcY6H|&=~;X{{$!)0tw8Xr9_aPD2QpA=BRe@Y46mv#!~H7{Rv4i&2%v! z1T#00!ARVk_Vs%3vPaj5J@3@T@ufU4GT{snXdq!Iz$!}}{*#iI%i2H8j$4Ewk1wYm z4_p;Tl1>nk9dbx1QW!>=u%ezyVS3x+y-|V6BRssEf}oa85S3!lulzinQvp{_cKT~Z z)Y}8=EU<?QTcS@9dPr&mloFX&F8`H_5}A3Q$bw0C=A_9T>Whf0qt(uI)6_l77QVGkAq^$`l9A%#z4JaqzHr>@&f)@bm{ z;a&IWvwIA3ZKpXReA)b`98uDaT$|cbR0L^|=Y#%>>5$Np`ts2gPYE}=$xhdPka7^0 ze>QDMca*KEPl+^H&dt@P@#pwvCIF zrV4}<&t;lW$lD(-4)T9beHstW;c#zTRU$i?7C&&?psw%}E+WByCoiTtAY z*%aQPLo-vJ&nM}0OzDJz>W%>Hf(Q3h{nd0rzlZ~x!teFpG|mQ`CS#bhm?TuD#d7f0 zld1BAtZfx;)8!s^Z;ltsmP5ur8?fChLlU>hrm2j8U}4sEkDLO!2H)Y{ax}4`6mLps zF|GBDARy!!#L5aBU&kV`ep_CQ_5SuYe}~S-{Py&&F zPli)t{7fgS0F_fCmTm;2HdP0%4CId=uGGw}cp51r5asq{#|9c!U6LcaOZM2&h`7^K zeS)B+ZCbZ5Qo3*ha8UcDKoLD|W{Gqa19idR?h!BP!<)))hT3)EZ_b9MCg)xx*Q*}z zz%sXT(5}*vsm0c)Kj&a3bt<=&{qS;SDUnAl&noyC?D?o;1zp**`DJ%=enoovIK>9w6aC5X6#6@&in6zT0r5b^wR$tLO#V2f$SpR*29S0q33w7%GhDor$50 zPl~7JVo0YvuSSO#!k{xCfz7`0fWm`#TXl4wY%`uFxVq z7k_h?02Bpu;lyARR`dS#go*PW|q2vnkYkEDH?ZGJ8Jsq#P+R!qt)%blX3Rn zbNJuDkc|ovhg3R|@Bq-4BGib|2WLjmhlYvUqYNdFN3f-1?%_M>2UY(Ms!M7O9lc}YEd#Bymk0;6vJYfmO)$X7xr z>rK6rqJ-#o`*%2+Jg3#ka;Fe;yI>e!Eoce%Ff`*?puq0zS)iD=4nC3bnE&uNIR+;> z*Q;jNpn-MZ2Tgh$e@KGOA}HZcrR>u;Is}tdR{?12% zU-3qzsd23K#(sDfe9jXP?IGeX&Prfli~2OFa}0-?_Yw6>Yb+OXpsXr~r;t;d`fqA> z@86R7)kKbbOnyrN*t+g$tiW3LCniZ`-`(?O2$QAi5q|U9xRyJf3T&)6UxDu`C0r9A zgca7K`b}2PI&!J&D|85xf#uBJLXNIEw=?f13c~uVr;5Q4)(osa3{=yI$u|6-D)bIF znY6a=U-ACdmLK5V{YlO-4Vgx68EzA_(3Lu&g^KDqQgxKSSv6Wxzf$qtjB^KR9T>Nm zx^r(bd@^Qj5teK=A9QRvC58MiX+fCu$)<&-xc^1b!aw@uqXjgKobV1r3ZME%nOK;u z441zY4TK#&NunXKZM1WUcY0xfFuNk5hAEc|RX(TKcPh)Eq6m@2?`BzG1DMb!W8L#e z53+`)ufZzf5o;e`+jPq!pyxDx^JGt$9_h&%c7dq*xs#&_6@pZ|)W98|db5Kv@B=c~ zaX@*Rey~^dhKHN-Q%!TX*=HEpC|azFvq@ffx0Fz}lA@Ab8hhvu0$ZC6Ev@A8{^bzz zi1(`~0@zVGS1Wa%&N@}+kIHZGAzG}jh1-M#uqx{~gcIcLYi~te-A)wk#H(^oWok+^ zDyuH+miOU>aJ|)%w(=?ZN4j1)tK%o#1@s*SN5qm43h7vi8syI=0zfau)JAh|B9$eV zQ_6)N>~e|a6zB!{slAq(Od0?B17-G?%YJ&oLr4~AJnbl zaBFv-wCUwmcV^|cke!PIG!w`#5ig%`$j}$Ye!)6Oznjkuh$rX9{^V{9#m}~Uk_Pon z%?6`BId+<9_s$}6tE3$!WrtGJMKdkSOOOCMrgxU%T8G-fUNW0xV)EvadBB2M?HccP652$LaD1!zMlDNhS4Q*gvX406EBTGg< z@olS%s%GlIJ*rjd&ta##MlA&I=ia7_{Y4%VZi1*@)s!bIo`bK9B~*T~hGmrvI(C!9 zR7){m7Zdn?i%ji>zhr7+2vqiXy6W`4;zZUT74w1}qv1h-f62VOuOnjU!I{@VV0uvI zwfRfRyq0?kw${6;qtFE+x)*XlajxYy7L7 z8N)(B7GFc7>Pg314;q)5F6dY8$E|BsJd4g@@8*U9h;8}}=#4?=aydy*Oq&ur;07nx z0?CT2dpGNPiq$32eTh&Gv$Eejt@>Zh5qVa(7xSl#GGEEV)qx5E>3!O}r(66=5=s%i<2n*cw?(y`)&Ehi zZHI#;Ow@Z;-w;qm@dcE-#c!%qych&Mah#-s?r1hNi44hpv(**lyXg-a+!tbzx*qKK zN4S=w#~)}BPpJPGy-CgMpYAVzWRYsiP1eo*mwKZW-4AAS>CD=v`u#9fDpr7Y8D1OEk?IP2S#*a5 zSK0vVh3>CE)2~pXrvU;O>d=h>`OSd%j4l&;ZsrXw{yn_`N5JZUx-I0&I4RPCGXn&+ zesPo(t8--B(D$zQLTLguv(KD5{>8USputdaMg&)1GozeXe3sNhuDjOr-nc|I-0(CqVSi&oug5AD6^YyS(yY~?~ zaCs!Wjv##enNyv)&NHV0-80W~eBzFwQ5N zUuNj_*=M#vY7JY4%aNI5V!ZU!HrzQAq57F);V{mW-}|b>8E|7UHPmK7UvK*{Ti6q` z9WBi;y>)drD)*_kE;tkBJT>#O{(VEll=@)XFQ=dbDp|h&wz!-&xw* zIwM~8a_7AA_|(Z-A5OpAd85CrKc3eg-Fy1ug)#`9l4HdXihqsBPR79xpA=4>1SL=XiiwVdc$+il!rwie=c=xM=F_sEv?@69_m2L% z7*NM}KSDNec>SBW12^2FU9u(GL^xvev`ZD|7j2x??#lJnSRZKag)lq+<||rAE06oU zes*KDwR!IBhFJ2#xwFfI)%)kp?wnf;f+gHDAEnD6Fc~tmOpVip-MUWW?845uvkUg# zLKv$ExIHL8X;;&9P2xH??v~|n%NZlE?m1jqbQ#I4rRx>Pm z!VB~5Jcgas!QJhbYXdXps{t)5=_+qz9vwod<$>)gUg_a(!6x z`0WD$`j`MQl6-XOaZId;&*^)YB+Xx(hd009(YrQAQ_ej2A*Pr^sn)K^@S2C{dqMvA z+R}Gz`$%%h-#Lf`+j<~m*psMN-*3YeGA|dnzyb%#KS&0_}AJEqVr?k-q-g%*-uCH*;YGJp$Yx(@kGK^&gddz zZi{+Z&zw^fE{FO>t+Y*lWCcFgxv-{=n&)r|p3!;mbL6rm%rMT;cAk4h*?HOLdeHM{ z?G7*h*Z1;ZaI>A`f-(x_JXvpj{pLz6LC$f;@!v7gD+3dLSQ?3y?BrNy_YmT50_)22 zBW_udhl@NN2ud)IGw+*%d{CHLRvEoE_k?NHB13W*ZE1idoRR#&h;yz7xEd*d<#7^$c{IM&gPaeD&_mU}sL^S^k+l%$n4qWw0|+Z~EbxAj$S* zv~Kp#omD?o>i+I;_I_|wUa#%Z+}&P(ePeXydnZr6eDvH^E#!J-sPgE!GXyDgH%5Jt zp{(Cy9aW)Hr4+=4pIu#a_F&#sbEasR zGPX%y3PX{sV5VGLjP6kjAsO|_RT{&9o>9t2s7C2hpC$KZaEAlw1Vh~nq9RGv+l+?Q z?UdDOJirsySoO*|FmQE*98qVj+uxKSx+mLnfC;K&&L=iVE^vfXcn%&DQMl5KSj48E z++gM7b-rF6d#!u96|TVg7cPpnDio7UpCH26mNPF?EH8mF4c@ToL@o2lN-* z-=7?Hq@gLN&cHnet`(ZEz&ivcpH78lujfd|8ZCZZ<;YL6iXY8csSnZmgoAe9{ ztgDFmjB|nvN+d8sOwxqKI#6%|jEM6WWzv+==ANwdXM9(u6grq@SMATGUA4g{-&1CTw(Uv1s&`J&DR#f9q5+*r$_(I_NKGq*G%&_eWj5J@=nw5 zSNv%*E;dzq3r04LL&kQFYuMM-Jbx`_9hh{Sa&jTAQb~>H_xV z5F}RhpPXfD{Y~kb(n&*H!L@PM!MD^esJ}fo8tk0uoZPwhvf``Z3w0kG4HW*%zvJ$M z`ZuA0T=mu5Pe*ga=;zc8S?cYX&ME2h(!YHsADO96ogSa6_Fb4NpW9{%-!PHxuw1$0 zGo5@n+^7{lYV4!uF5cT2$ZU{aw77KZjI>&*SCzV}TweWTP(?$>Y(edIs96A}t5oFB zw`3%MuJ(uOi*jF3JZ`DP2G!xL|AKj-)Fd4W{m6E817{V!JrPth7Qsmn%rUd%F93a&O;F`3^6uqX_<%Tbk9_ z+*vXFj@AilTnm0kjIxnf=1|Jdg8m1yoR>$Emf!v0eI4j8{5A;ubv@y~EhqzvEFtDa zEq=FBwoJ76>V`q}tUpObxV8VN?*lk=X5Jc`8;07IGIy|G>_05C)3>#_L-cx`v)#^yE<*jm z(T&k)XLx2|p|?GMw|}RRpj8f;UeWUBmu1A1mB+YVk9xrq^ z709y}2mi|X)%W(SpjIqofcJnaheMLqc;W_^u%@xmT(I(9)xlTy^TcrvpWp1SZ+EUp z@RS#yh5{FTs0;ebYO#88sL$C@*KszL$C{OK0L`*}%MUbF*|Pqe+AQZ|JC1wgmF~(N z?jRL9EefU&IJjy z@~Fq8wwQthwHx0`=CyG;c_!nCPb^Z2v&6;2RO*xmoewQBU}}B_fTVc4RbUf4auvhYwa2Pd+V6I}<7Sk9wVz(kN z+;yKk4NX0HVt6a=?UhCHXf4Ulos^!*Cmy4V`^0OcFNDV9LD_%}1r@{{hGkH!O$7=| z2!@#BHLLoYtzhtCf*OuDHy5`ZH*z}LNZdfBEQLEvt5uuAr2OU07K%S9F@VKsS%8o! zo)XjH9jz|~yuquYZsc(ZUs&9v5BqsVNH3X&RR+zmu^D{an&lG5ecZ;q6qMtZRkx2> zUh8Akm|>meWjU8Q{oZFOyTu%#P~Hr1I- zWEPMzDCOZvAC&LZ=Fl1H?MSCq|q5ogOX>|W(uhJ!RyDAEbNYyI}+}X z#)+O@ECEwo?dUV7juv+J|LFh4mmgUi?QT9d>0ENxnEIg)pUXT>dJJ0($m)$y*V>_^SWD&QsYFA0zTa!i=N^D5W~;cj z>0R|eg2_pAHfqBR1Cm2D4^-5k8`pn2tRI-w_u#Ir;N}Y2noQnF;QY;i@TSe1U3hQ|@R12h;;u3jHT>ew0)?-xBw|)}7zZ6_sHC0L&lrO^Vh`QpO z*x2Ji)zVZG>>peUnX)!E1FpJp^DB-V?5i^PeoF;Pbys6z!liUBc7cLjkHL3leiZ56 z9h;X_9Qor2(q9R?3=Lf6=2p|f9|aPg?Ob~P$K{nRe?%**rzV=Kbydz!ol9KZH=3&p z2|{;w6(MOgpx$|)^_8m{eiYJL-;?TChuW`(b;XvX734xe=yR=rTl)wXHVyE;Ra)c} z06Z$BM(=?@++PNAT?_J`a-MWRhcC&;Gs!>pWbg?x6x4_GNX2%Kg#4D4TDy}0^zOaq zW%Hmfh>w^Ytx3$xweZAiT;pxbp|!~FwJ?0HUv}l9PCOx3b*3|2zY?ZR25K-kTj!q* z-dVux-dW#PA;C4$!;xlATbV?+tGr>7c?|F-C_hXFcw}Qb2?Vb3Xz(Mk%;VMaN{NTA z`cL3_fAkS7+m@C`fj#5M&$bR<*Jh9mxrdR{a5FvMdR_MknMm<;zF%!W%eu7MUw0O! zjK*3>vV4d?5702|@Sswz23x0vz%R8@TQA35mw9$fo|$mKAXMDh$;%#1kq4%`D>2~_ zmk?SRkE)cnbVOSMn9;P06FhQRp5p#W+iS0jP6*SPG4Mfr?K7_{I?-Qi@i2dP`sDjK z;^CC3T3*cGoq1D>c|TB=^CWB%5bvLAiLOe6K3Fg8b`WB0e3K`A00|uIpc(p5DPx>> znh2Zpr~^`U+~nyuEyXv>fVB))k`5A*=44z3#-G%HQF3aL#O>5*1`=B;;VHbBY@$?( zn**yI!%eF*k|9ypb5w)nxa4GCFsMsSMF8s`1tC#Q~1VM;(y_b9S z%!Ld00P4>B(*E86#`>d4&rW z#p`x4UCFQ(jtIb;s3;4O`y zc)9|GsdQR$<<;>zt{zb4468I90=nWfDw!s!GUan$U1T4k0Xjq>6AR`%|n1vxSy&0qpfwSXk9;#jqc7~ggx_Pv?JC@=DO<-mdlbEn=| z9#ov}$?-Is^3YEP&rjZ+rUtoi4O;olr^nwEd@4yA7xKC5c9j}Ju{_Relg0@fP7)bz z-R93pl={VNPUTz5Pt$7&JG@?;+c*Y%$&%cxoX@32%lvW20)2p*-3k<@FK_(P*yIQt z(sEHmQr1EeL2k+CRGGH@C7;-n5+=CfzCJcL;yajYaU+lUcz8j|TUgaFA85HIFih$q zwNtLVNo>=qnt42-p6G?viNM~bZF$Ueia5#Ro|<|L>0X}U@3qcg zaxi(;JvkHIrK#zd4UDdZ0I*aB-sh}xAH3Nig|LyH%Oxq#Ip7?qJ`S{#3zncq#XY|g z_RI;o+rxbOvz;Ny%azhYN^w1`GqhC2c0m1P0-$QnW-Tv2oMwSZeWRJm5V!D5+=6KX z-D28w`8ba&gbUcw;7LC))i?(iL?M$U&i1vcTS9E46T9b>XE;_-yQQL;&NpfNuQbQ6 zy1bM}e|pSmX%qz-rVPO^)H^(=fkk<=WrbkIGj43n?vQbY16rkYwz{*)#JH6c+38}a z0O6Fd`HiKJAR}efPECBIO2KZ|=1xwrz8a~;Q+vFcZBiiSJHiDRAN~zjL@dn6n3d@o zM|^Ba?9ffmGB~eKGhhvj``W^B`d`VXZ=~{-SMyjNA&BEV>Y;%0OD_q(QlXY%LV1xj zxM!Z$BTE}<=89Qvuy4@@MsnISJoW(gBP5cuf&)ygx7|ZyL`N~drMYAOnxj6%JtGvp z)m)@xT6fgBtE!dGMt@b+BxUfNE`Y}funrFHog65c{qoFeobwA|PRY=|a>RlQzC6ck zV{-97 z3f1vJppkb!G+keY%o=x$m3R1E#k-Q$$8L}VHN{-t)it!I!WuO9Zl!XzYid_R`_p=f zMgkY!8La1~-^9#+E9{OA|RC|QC;*y_hS+d0?<*!ky1JyWO!BAfJUlS40HK(md zwc!#0_5@yd~#LO!WHtarDx*N z4c=|42ysY^+0!#v&r^CfF3z=YngLtYFWIK{2wR6D1MSAPnqAml!hZA>nub4e=R@P z-Y>RHSB7ghmFX7oV&-ob@uEZ#h%NKWei+|sI|C}yPR`ALn8Q*vi+F-7DoNR((eWTo z9qA(wMwurZ`nyv>piKFuvY4O6XyKQwM?v!PIK3n({E6>Y5V_}nlw-#5lU(*)roum- z5(mdEShO{lS;-o8c?D0a+i~Tr1V4LtrSnB|UvKL(!hc==!rAk*xSEuRXK}H17P1V7 z6v1O1S}ndryR`El_sK0FwV*1%yFljxEBb6P9d86Up@iW4fm>H@l<+$qrw~ici|&^I_%ggCSVeleb(7A=+38!7ByE>Yb&QZ<(Un2`T%07I5q9`yuKYN zvvx^)BELU}pkpV{O?oF#cDF`wdxq8Vt>H?2CRg0;H}`;XZhoy(T1zSsJF4FkgrNQd zRwC(rJ8@PT(j&9eP4hfkn}=t2v{%PcI947k&hrlaJa7&%476}`k!7-q%n=wtbXTmWRaPvc0)h~j_p<5BT(saq!olahcv*# zj&3{e(Xew@mu|{YS61$3{;x4Nu&FoPf69S_sGfY5{7=rL9g#s9b5A4!sgpg7%u<(7 zoejZw2ZJP~^^uzcdxA+X>t7fT;>wX6OCQF^2$pxb3~hn`RSCk>>c9n2-8l2zZ;IjVqp&!^&3x&`V0~Tw$V)+)=-eRd1R8H;_ML>?tpVq&?Zj7wPv64qY4l>i^JPf7YySnsJrpn1#eoPv2mxbi7HM! z>x~=tcX}xaZF_HPIXLOWGQ@G|5o&C~t|AjxvEmAM`-y3JsF_o$cx2@)IGi%7?6L4F;T)3i8F9fo`qQR7Ixc`TlU`W{_X3 z)Ev#Ag1OC2SFkRd{GC`w$?ndjanexD^*4?HAMSWB+(cAzl;J)!9haHywMcHP0u?Ko z{^(`{bpeWcOO&G86!GowTOri3sD!mLoNtG7MIaDggn=i$0dmD6gOMDhzOpBrqbbR$5L8%3IHT2U_eUzAD%mLA^IIP7P)*(;Kk*VVn?aG>UceW z6|#3im-rh9n#aO6tN?3l`Tw05pmkA&y?PV-Gu6b+X^o{VYbhX_Zzi{mO)rMYchxSQ zKoEa{g!?mgMjVgH7=y3hjfv%Eu^hMjP!gh!I&=Q5?k@OrMn!93_pYuvXe^SX&fQzm d9f^|2ELWa?b%~}LiH{%l@2cGOp-&z9e*p~{&Q$;a literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/translations/sqlb_fr.ts b/src/WBCLFZSystemModule/SqliteDBProcess/src/translations/sqlb_fr.ts new file mode 100644 index 0000000..031adce --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/translations/sqlb_fr.ts @@ -0,0 +1,7039 @@ + + + + + AboutDialog + + + About DB Browser for SQLite + À propos de DB-Browser pour SQLite + + + + Version + Version + + + + <html><head/><body><p>DB Browser for SQLite is an open source, freeware visual tool used to create, design and edit SQLite database files.</p><p>It is bi-licensed under the Mozilla Public License Version 2, as well as the GNU General Public License Version 3 or later. You can modify or redistribute it under the conditions of these licenses.</p><p>See <a href="http://www.gnu.org/licenses/gpl.html">http://www.gnu.org/licenses/gpl.html</a> and <a href="https://www.mozilla.org/MPL/2.0/index.txt">https://www.mozilla.org/MPL/2.0/index.txt</a> for details.</p><p>For more information on this program please visit our website at: <a href="http://sqlitebrowser.org">http://sqlitebrowser.org</a></p><p><span style=" font-size:small;">This software uses the GPL/LGPL Qt Toolkit from </span><a href="http://qt-project.org/"><span style=" font-size:small;">http://qt-project.org/</span></a><span style=" font-size:small;"><br/>See </span><a href="http://qt-project.org/doc/qt-5/licensing.html"><span style=" font-size:small;">http://qt-project.org/doc/qt-5/licensing.html</span></a><span style=" font-size:small;"> for licensing terms and information.</span></p><p><span style=" font-size:small;">It also uses the Silk icon set by Mark James licensed under a Creative Commons Attribution 2.5 and 3.0 license.<br/>See </span><a href="http://www.famfamfam.com/lab/icons/silk/"><span style=" font-size:small;">http://www.famfamfam.com/lab/icons/silk/</span></a><span style=" font-size:small;"> for details.</span></p></body></html> + <html><head/><body><p>DB Browser pour SQLite est un logiciel libre, open-source utilisé pour créer, concevoir et modifier des Bases de Données SQLite.</p><p>Ce programme vous est proposé sous une double licence : Mozilla Public License Version 2 et GNU General Public License Version 3 ou suivante. Vous pouvez le modifier ou le redistribuer en respectant les conditions de ces licences.</p><p>Voir : <a href="http://www.gnu.org/licenses/gpl.html">http://www.gnu.org/licenses/gpl.html</a> et <a href="https://www.mozilla.org/MPL/2.0/index.txt">https://www.mozilla.org/MPL/2.0/index.txt</a> pour plus de détails</p><p>Pour plus d'information concernant ce programme, visitez notre site Internet : <a href="http://sqlitebrowser.org">http://sqlitebrowser.org</a></p><p><span style=" font-size:small;">Ce logiciel utilise le GPL/LGPL Qt Toolkit fourni par </span><a href="http://qt-project.org/"><span style=" font-size:small;">http://qt-project.org/</span></a><span style=" font-size:small;"><br/>Voir : </span><a href="http://qt-project.org/doc/qt-5/licensing.html"><span style=" font-size:small;">http://qt-project.org/doc/qt-5/licensing.html</span></a><span style=" font-size:small;"> pour les conditions de licence et toute autre information.</span></p><p><span style=" font-size:small;">Il utilise le jeu d&apos;icones Silk créé par Mark James disponible selon la licence Creative Commons Attribution 2.5 and 3.0.<br/>Voir </span><a href="http://www.famfamfam.com/lab/icons/silk/"><span style=" font-size:small;">http://www.famfamfam.com/lab/icons/silk/</span></a><span style=" font-size:small;"> pour plus de details.</span></p></body></html> + + + + AddRecordDialog + + + Add New Record + Ajouter un nouvel enregistrement + + + + Enter values for the new record considering constraints. Fields in bold are mandatory. + Saisissez les valeurs en tenant compte des contraintes. Les champs en gras sont obligatoires. + + + + In the Value column you can specify the value for the field identified in the Name column. The Type column indicates the type of the field. Default values are displayed in the same style as NULL values. + Dans la colonne Valeur, vous pouvez spécifier la valeur du champ identifié dans la colonne Nom. La colonne Type indique le type du champ. Les valeurs par défaut sont affichées dans le même style que les valeurs NULL. + + + + Name + Nom + + + + Type + Type + + + + Value + Valeur + + + + Values to insert. Pre-filled default values are inserted automatically unless they are changed. + Valeurs à insérer. Les valeurs par défaut pré-remplies sont insérées automatiquement à moins qu'elles ne soient modifiées. + + + + When you edit the values in the upper frame, the SQL query for inserting this new record is shown here. You can edit manually the query before saving. + Lorsque vous éditez les valeurs dans le cadre supérieur, la requête SQL d'insersion du nouvel enregistrement est affichée ici. Vous pouvez l'éditer manuellement avant de l'enregistrer. + + + + <html><head/><body><p><span style=" font-weight:600;">Save</span> will submit the shown SQL statement to the database for inserting the new record.</p><p><span style=" font-weight:600;">Restore Defaults</span> will restore the initial values in the <span style=" font-weight:600;">Value</span> column.</p><p><span style=" font-weight:600;">Cancel</span> will close this dialog without executing the query.</p></body></html> + <html><head/><body><p><span style=" font-weight:600;">Enregistrer</span> soumettra l'instruction SQL affichée à la Base de Données pour créer le nouvel enregistrement..</p><p><span style=" font-weight:600;">Restaurer les valeurs par défaut</span> restaurera les valeurs par défaut dans la <span style=" font-weight:600;">colonne</span> Valeur.</p><p><span style=" font-weight:600;">Annuler</span> fermera cette boîte de dialogue sans exécuter la requête.</p></body></html> + + + + Auto-increment + + Incrément automatique + + + + + Unique constraint + + Contrainte unique + + + + + Check constraint: %1 + + Vérifier les contraintes : %1 + + + + + Foreign key: %1 + + Clé étrangère : %1 + + + + + Default value: %1 + + Valeur par défaut : %1 + + + + + Error adding record. Message from database engine: + +%1 + Erreur lors de l'ajout d'un enregistrement. Message du moteur de Base de Données : + +%1 + + + + Are you sure you want to restore all the entered values to their defaults? + Êtes-vous sûr de vouloir restaurer toutes les valeurs saisies à leurs valeurs par défaut ? + + + + Application + + + Possible command line arguments: + Arguments utilisables en ligne de commande : + + + + The -o/--option and -O/--save-option options require an argument in the form group/setting=value + Les options de commande -o/--option et -O/--save-option nécessitent un argument sous la forme groupe/paramètre=valeur + + + + Usage: %1 [options] [<database>|<project>] + + Usage: %1 [options] [<basededonnees>|<projet>] + + + + + -h, --help Show command line options + -h, --help Affiche les options utilisables de la ligne de commande + + + + -q, --quit Exit application after running scripts + -q, --quit Quitte l'application après l'exécution des scripts + + + + -s, --sql <file> Execute this SQL file after opening the DB + -s, --sql <fichier> Execute ce fichier SQL après avoir ouvert la BdD + + + + -t, --table <table> Browse this table after opening the DB + -t, --table <table> Parcourt cette table après avoir ouvert la BdD + + + + -R, --read-only Open database in read-only mode + -R, --read-only Ouvre la Base de Données en lectyure seule + + + + -o, --option <group>/<setting>=<value> + -o, --option <groupe>/<paramètre>=<valeur> + + + + Run application with this setting temporarily set to value + Lance l'application en utilisant temporairement la valeur de ce paramètre + + + + -O, --save-option <group>/<setting>=<value> + -O, --save-option <groupe>/<paramètre>=<valeur> + + + + Run application saving this value for this setting + Lance l'application en sauvegardant la valeur de ce paramètre + + + + -v, --version Display the current version + -v, --version Affiche la version de l'application + + + + <database> Open this SQLite database + <database> Ouvre cette Base de Données SQLite + + + + <project> Open this project file (*.sqbpro) + <projet> Ouvre ce fichier projet (*.sqbpro) + + + + The -s/--sql option requires an argument + L'option -s/--sql nécessite un argument + + + + The file %1 does not exist + Le fichier %1 n'existe pas + + + + The -t/--table option requires an argument + L'option -t/--table nécessite un argument + + + + Invalid option/non-existant file: %1 + Option invalide ou fichier %1 inexistant + + + + SQLite Version + Version de SQLite + + + + SQLCipher Version %1 (based on SQLite %2) + SQLCipher Version %1 (basé sur SQLite %2) + + + + DB Browser for SQLite Version %1. + DB Browser pour SQLite Version %1. + + + + Built for %1, running on %2 + Compilé pour %1, fonctionnant sur %2 + + + + Qt Version %1 + Version de Qt %1 + + + + CipherDialog + + + SQLCipher encryption + Chiffrement par SQLCipher + + + + &Password + Mot de &Passe + + + + &Reenter password + &Retaper le mot de passe + + + + Encr&yption settings + Para&mètre de chiffrement + + + + SQLCipher &3 defaults + SQLCipher &3 par défaut + + + + SQLCipher &4 defaults + SQLCipher &4 par défaut + + + + Custo&m + Pers&onnalisé + + + + Page si&ze + &Taille de page + + + + &KDF iterations + Itérations &KDF + + + + HMAC algorithm + Algorithme HMAC + + + + KDF algorithm + Algorithme KDF + + + + Plaintext Header Size + Taille En-tête texte en clair + + + + Passphrase + The button size is not large enought to handle the whole "french text", if #Passphrase must be translate + Phrase Secrète + + + + Raw key + Same comment as for Passphrase + Clé de Chiffrement + + + + Please set a key to encrypt the database. +Note that if you change any of the other, optional, settings you'll need to re-enter them as well every time you open the database file. +Leave the password fields empty to disable the encryption. +The encryption process might take some time and you should have a backup copy of your database! Unsaved changes are applied before modifying the encryption. + Veuillez définir une clé pour chiffrer la Base de Données. +Notez que si vous modifiez les autres paramètres, optionnels, vous devrez les ressaisir chaque fois que vous ouvrirez la Base de Données. +Laisser les champs Mot de passe à blanc pour désactiver le chiffrement. +Le processus de chiffrement peut prendre un certain temps. Vous devriez avoir une copie de sauvegarde de votre Base de Données ! +Les modifications non enregistrées seront appliquées avant la modification du chiffrement. + + + + Please enter the key used to encrypt the database. +If any of the other settings were altered for this database file you need to provide this information as well. + Veuillez entrer la clé utilisée pour le chiffrement de la Base de Données. +Si d'autres paramètres ont été modifiés pour cette Base de Données, vous devrez aussi fournir ces informations. + + + + ColumnDisplayFormatDialog + + + Choose display format + Choisir un format d'affichage + + + + Display format + Format d'affichage + + + + Choose a display format for the column '%1' which is applied to each value prior to showing it. + Choisissez le format d'affichage pour la colonne '%1'. +Il sera appliqué à chaque valeur avant son affichage. + + + + Default + Défaut + + + + Decimal number + Nombre décimal + + + + Exponent notation + Notation scientifique + + + + Hex blob + Blob Hexadécimal + + + + Hex number + Nombre Hexadécimal + + + + Apple NSDate to date + Apple NSDate vers date + + + + Java epoch (milliseconds) to date + Java epoch (milliseconds) en date + + + + .NET DateTime.Ticks to date + .NET DateTime.Ticks en date + + + + Julian day to date + Date jullienne vers Date + + + + Unix epoch to local time + Heure Unix epoch vers heure locale + + + + Date as dd/mm/yyyy + Date au format DD/MM/AAAA + + + + Lower case + Minuscule + + + + Custom display format must contain a function call applied to %1 + Le format d'affichage personnalisé doit contenir un appel de fonction appliqué à %1 + + + + Error in custom display format. Message from database engine: + +%1 + Erreur dans le format d'affichage personnalisé. Message du moteur de Base de Données : + +%1 + + + + Custom display format must return only one column but it returned %1. + Le format d'affichage personnalisé ne doit renvoyer qu'une seule colonne, mais il a renvoyé %1. + + + + Octal number + Nombre en Octal + + + + Round number + Nombre arrondi + + + + Unix epoch to date + Date Unix epoch en Date + + + + Upper case + Majuscule + + + + Windows DATE to date + Date Windows en Date + + + + Custom + Personnalisé + + + + CondFormatManager + + + Conditional Format Manager + Gestion des formats conditionnels + + + + This dialog allows creating and editing conditional formats. Each cell style will be selected by the first accomplished condition for that cell data. Conditional formats can be moved up and down, where those at higher rows take precedence over those at lower. Syntax for conditions is the same as for filters and an empty condition applies to all values. + Cette fenêtre de dialogue permet de créer et de modifier des formats conditionnels. Chaque style de cellule sera sélectionné par la première condition remplie pour les données de cette cellule. Les formats conditionnels peuvent être déplacés vers le haut et vers le bas. Ceux des rangées supérieures ont la priorité sur ceux des rangées inférieures. La syntaxe des conditions est la même que celle des filtres et une condition vide s'applique à toutes les valeurs. + + + + Add new conditional format + Ajouter un nouveau format conditionnel + + + + &Add + &Ajouter + + + + Remove selected conditional format + Supprime le format conditionnel sélectionné + + + + &Remove + &Supprimer + + + + Move selected conditional format up + Déplace le format conditionnel vers le haut + + + + Move &up + &Monter + + + + Move selected conditional format down + Déplace le format conditionnel vers le bas + + + + Move &down + &Descendre + + + + Foreground + Avant Plan + + + + Text color + Couleur de texte + + + + Background + Arrière plan + + + + Background color + Couleur d'arrière plan + + + + Font + Police + + + + Size + Taille + + + + Bold + Gras + + + + Italic + Italique + + + + Underline + Souligné + + + + Alignment + Alignement + + + + Condition + Condition + + + + + Click to select color + Cliquer pour sélectionner une couleur + + + + Are you sure you want to clear all the conditional formats of this field? + Êtes-vous sûr de vouloir effacer tous les formats conditionnels de ce champ ? + + + + DBBrowserDB + + + Please specify the database name under which you want to access the attached database + Veuillez spécifier le nom de la Base de Données sous laquelle vous voulez accéder à la Base de Données attachée + + + + Invalid file format + Format de fichier invalide + + + + Do you want to save the changes made to the database file %1? + Voulez-vous enregistrer les changements effectués dans la Base de Données %1 ? + + + + Exporting database to SQL file... + Exporter la Base de Données dans un fichier SQL... + + + + + Cancel + Annuler + + + + Executing SQL... + Exécution du SQL... + + + + Action cancelled. + Action annulée. + + + + This database has already been attached. Its schema name is '%1'. + Cette Base de Données a déjà été attachée. Son nom de schéma est '%1'. + + + + Do you really want to close this temporary database? All data will be lost. + Voulez-vous vraiment fermer cette Base de Données temporaire ? Toutes les données seront perdues. + + + + Database didn't close correctly, probably still busy + La Base de Données ne s'est pas fermée correctement; Elle est probablement encore occupée + + + + The database is currently busy: + La Base de Données est actuellement occupée : + + + + Do you want to abort that other operation? + Voulez-vous annuler cette autre opération ? + + + + + No database file opened + Aucun fichier de Base de Données ouvert + + + + + Error in statement #%1: %2. +Aborting execution%3. + Erreur dans le traitement #%1 : %2. +Exécution de %3 abandonnée. + + + + + and rolling back + et annulation des changements + + + + didn't receive any output from %1 + n'a pas reçu toutes les sorties de %1 + + + + could not execute command: %1 + ne peut pas exécuter les commandes : %1 + + + + Cannot delete this object + Impossible de supprimer cet objet + + + + Cannot set data on this object + 170726 MVT Has to be checked in real context + Définition des données impossible pour cet objet + + + + + A table with the name '%1' already exists in schema '%2'. + Une table portant le nom " %1 " existe déjà dans le schéma " %2 ". + + + + No table with name '%1' exists in schema '%2'. + Il n'existe pas de table nommée " %1 " dans le schéma " %2 ". + + + + + Cannot find column %1. + La colonne %1 n'a pas été trouvée. + + + + Creating savepoint failed. DB says: %1 + La création du point de restauration a échoué. DB indique : %1 + + + + Renaming the column failed. DB says: +%1 + Le changement de nom de la colonne a échoué. DB indique : +%1 + + + + + Releasing savepoint failed. DB says: %1 + La libération du point de sauvegarde a échoué. DB indique : %1 + + + + Creating new table failed. DB says: %1 + La création d'une nouvelle table a échoué. DB indique : %1 + + + + Copying data to new table failed. DB says: +%1 + La copie des données dans une nouvelle table a échoué. DB indique : %1 + + + + Deleting old table failed. DB says: %1 + La suppression d'une ancienne table a échoué. DB indique : %1 + + + + Error renaming table '%1' to '%2'. +Message from database engine: +%3 + Erreur lors du changement de nom de la table %1 vers %2. +Message du moteur de Base de Données : +%3 + + + + could not get list of db objects: %1 + La liste des objets de la Base de Données ne peut être obtenue : %1 + + + + Restoring some of the objects associated with this table failed. This is most likely because some column names changed. Here's the SQL statement which you might want to fix and execute manually: + + + La restauration de certains des objets associés à cette table a échoué. Cela est le plus souvent dû au changement du nom de certaines colonnes. Voici l'instruction SQL que vous pourrez corriger et exécuter manuellement : + + + + + + could not get list of databases: %1 + n'a pas pu obtenir la liste des bases de données : %1 + + + + Error loading extension: %1 + Erreur lors du chargement de l'extension %1 + + + + could not get column information + 170726 MVT Has to be checked in real context + ne peut obtenir les informations sur la colonne + + + + Error setting pragma %1 to %2: %3 + Erreur dans les paramètres des pragma %1 à %2 : %3 + + + + File not found. + Fichier non trouvé. + + + + DbStructureModel + + + Name + Nom + + + + Object + Objet + + + + Type + Type + + + + Schema + Schéma + + + + Database + Base de Données + + + + Browsables + Consultables + + + + All + Tout + + + + Temporary + Temporaire + + + + Tables (%1) + Tables (%1) + + + + Indices (%1) + Index (%1) + + + + Views (%1) + Vues (%1) + + + + Triggers (%1) + Déclencheurs (%1) + + + + EditDialog + + + Edit database cell + Éditer le contenu d'une cellule + + + + Mode: + Mode : + + + + This is the list of supported modes for the cell editor. Choose a mode for viewing or editing the data of the current cell. + Voici la liste des modes pris en charge par l'éditeur de cellules. Choisissez un mode d'affichage ou d'édition des données de la cellule courante. + + + + RTL Text + Remark : there is not acronym in french for Right to Left Text (DàG : Droite à Gauche ?). If DçG is not correct, we should use the HTML dir parameter RTL + Texte DàG + + + + + Image + Image + + + + JSON + JSON + + + + XML + XML + + + + + Automatically adjust the editor mode to the loaded data type + Ajuster automatiquement le mode éditeur au type de données chargé + + + + This checkable button enables or disables the automatic switching of the editor mode. When a new cell is selected or new data is imported and the automatic switching is enabled, the mode adjusts to the detected data type. You can then change the editor mode manually. If you want to keep this manually switched mode while moving through the cells, switch the button off. + Ce bouton à cocher active ou désactive le changement automatique du mode éditeur. Lorsqu'une nouvelle cellule est sélectionnée ou de nouvelles données sont importées et que la commutation automatique est activée, le mode s'adapte au type de données détecté. Vous pouvez ensuite changer le mode éditeur manuellement. Si vous souhaitez conserver ce mode de commutation manuelle pendant que vous vous déplacez dans les cellules, éteignez le bouton. + + + + Auto-switch + Auto-switch + + + + The text editor modes let you edit plain text, as well as JSON or XML data with syntax highlighting, automatic formatting and validation before saving. + +Errors are indicated with a red squiggle underline. + Les modes éditeur de texte vous permettent de modifier du texte brut, ainsi que des données JSON ou XML avec une mise en évidence de la syntaxe, un formatage automatique et une validation avant l'enregistrement. + +Les erreurs sont signalées par un trait de soulignement rouge. + + + + This Qt editor is used for right-to-left scripts, which are not supported by the default Text editor. The presence of right-to-left characters is detected and this editor mode is automatically selected. + Cet éditeur Qt est utilisé pour les scripts écrits de droite à gauche. Ils ne sont pas pris en charge par l'éditeur de texte par défaut. La présence de caractères de droite à gauche est détectée et ce mode d'édition est automatiquement sélectionné. + + + + Open preview dialog for printing the data currently stored in the cell + Ouvrir la fenêtre de prévisualisation pour imprimer les données actuellement stockées dans la cellule + + + + Auto-format: pretty print on loading, compact on saving. + Auto-format : formater au chargement, compacter à l'enregistrement. + + + + When enabled, the auto-format feature formats the data on loading, breaking the text in lines and indenting it for maximum readability. On data saving, the auto-format feature compacts the data removing end of lines, and unnecessary whitespace. + Lorsqu'elle est activée, la fonction de formatage automatique met en forme les données lors du chargement, transforme le texte en lignes et ajoute des retraits pour une lisibilité maximale. Lors de la sauvegarde des données, la fonction de formatage automatique compacte les données en supprimant les fins des lignes et les espaces inutiles. + + + + Word Wrap + Coupure des mots + + + + Wrap lines on word boundaries + Coupe les lignes aux limites des mots + + + + + Open in default application or browser + Ouvrir dans l'application ou le navigateur par défaut + + + + Open in application + Ouvrir dans l'application + + + + The value is interpreted as a file or URL and opened in the default application or web browser. + La valeur est interprétée comme étant un fichier ou une URL. Elle sera ouverte dans l'application ou le navigateur web par défaut. + + + + Save file reference... + Enregistrer la référence du fichier... + + + + Save reference to file + Enregistre la référence au fichier + + + + + Open in external application + Ouvrir dans une application externe + + + + Autoformat + Format Automatique + + + + &Export... + &Exporter... + + + + + &Import... + &Importer... + + + + + Import from file + Importer depuis un fichier + + + + + Opens a file dialog used to import any kind of data to this database cell. + Ouvre une boîte de dialogue pour importer n'importe quel type de données dans cette cellule de Base de Données. + + + + Export to file + Exporter vers un fichier + + + + Opens a file dialog used to export the contents of this database cell to a file. + Ouvrir la boîte de dialogue pour exporter le contenu de cette cellule de la Base de Données vers un fichier. + + + + + Print... + Imprimer... + + + + Open preview dialog for printing displayed image + Ouvrir un apperçu de l'image pour son impression + + + + + Ctrl+P + + + + + Open preview dialog for printing displayed text + Ouvrir un apperçu du texte avant son impression + + + + Copy Hex and ASCII + Copier l'Hex et l'ASCII + + + + Copy selected hexadecimal and ASCII columns to the clipboard + Copier les colonnes hexadécimales et ASCII sélectionnées dans le presse-papiers + + + + Ctrl+Shift+C + Ctrl+Maj+C + + + + Set as &NULL + Définir comme &NULL + + + + Apply data to cell + Appliquer les données à la cellule + + + + This button saves the changes performed in the cell editor to the database cell. + Ce bouton permet d'enregistrer les modifications effectuées dans l'éditeur de cellule dans la cellule de Base de Données. + + + + Apply + Appliquer + + + + Text + Texte + + + + Binary + Binaire + + + + Erases the contents of the cell + Effacer le contenu de la cellule + + + + This area displays information about the data present in this database cell + Cette zone affiche des informations à propos des données contenues dans la cellule de la Base de Données + + + + Type of data currently in cell + Type actuel des données dans la cellule + + + + Size of data currently in table + Taille actuelle des données dans la table + + + + Choose a filename to export data + Choisir un nom de fichier pour exporter les données + + + + Type of data currently in cell: %1 Image + Type actuel des données de la cellule. Image %1 + + + + %1x%2 pixel(s) + %1x%2 pixel(s) + + + + Type of data currently in cell: NULL + Type actuel des données de la cellule : NULL + + + + + Type of data currently in cell: Text / Numeric + Type actuel des données de la cellule : Texte / Numérique + + + + + Image data can't be viewed in this mode. + L'image ne peut être affichée dans ce mode. + + + + + Try switching to Image or Binary mode. + Essayez de basculer vers le mode Image ou le mode Binaire. + + + + + Binary data can't be viewed in this mode. + Les données Binaires ne peuvent être affichées dans ce mode. + + + + + Try switching to Binary mode. + Essayez de basculer vers le mode Binaire. + + + + Couldn't save file: %1. + Le fichier %1 ne peut être sauvegardé. + + + + The data has been saved to a temporary file and has been opened with the default application. You can now edit the file and, when you are ready, apply the saved new data to the cell editor or cancel any changes. + Les données ont été enregistrées dans un fichier temporaire. Elles ont été ouvertes avec l'application par défaut. Vous pouvez maintenant modifier le fichier et, lorsque vous serez prêt, appliquer les nouvelles données enregistrées à l'éditeur de cellules ou annuler les modifications. + + + + + Image files (%1) + Fichiers image (%1) + + + + Binary files (*.bin) + Fichiers Binaires (*.bin) + + + + Choose a file to import + Choisir un fichier à importer + + + + %1 Image + %1 Image + + + + Invalid data for this mode + Les données sont invalides pour ce mode + + + + The cell contains invalid %1 data. Reason: %2. Do you really want to apply it to the cell? + La cellule contient des données %1 invalides. Raison : %2. Vouslez-vous vraiment l'appliquer à la cellule ? + + + + + + %n character(s) + + %n caractère + %n caractères + + + + + Type of data currently in cell: Valid JSON + Type de données actuellement dans la cellule : JSON valide + + + + Type of data currently in cell: Binary + Type actuel des données de la cellule : Binaire + + + + + %n byte(s) + + %n octet + %n octets + + + + + EditIndexDialog + + + &Name + &Nom + + + + Order + Ordre + + + + &Table + &Table + + + + Edit Index Schema + Éditer le schéma d'index + + + + &Unique + &Unique + + + + For restricting the index to only a part of the table you can specify a WHERE clause here that selects the part of the table that should be indexed + Pour restreindre l'index à un sous-ensemble de la table, vous pouvez spécifier une clause WHERE ici. Elle sélectionnera le sous-ensemble de la table qui sera indexé + + + + Partial inde&x clause + Clause d'inde&x partiel + + + + Colu&mns + &Colonnes + + + + Table column + Colonne de table + + + + Type + Type + + + + Add a new expression column to the index. Expression columns contain SQL expression rather than column names. + 170726 MVT Has to be checked in real context + Ajouter une nouvelle expression de colonne à l'index. Les expressions de colonnes contiennent des expressions SQL plutôt que des noms de colonnes. + + + + Index column + Colonne d'Index + + + + Deleting the old index failed: +%1 + La suppression de l'ancien index a échoué : +%1 + + + + Creating the index failed: +%1 + La création de l'index a échoué : +%1 + + + + EditTableDialog + + + Edit table definition + Éditer la définition de la table + + + + Table + Table + + + + Advanced + Avancé + + + + Make this a 'WITHOUT rowid' table. Setting this flag requires a field of type INTEGER with the primary key flag set and the auto increment flag unset. + Faire cette table "SANS RowId". Positionner cette option nécessite un champ de type INTEGER défini comme clé primaire ET pour lequel l'incrément automatique a été désactivé. + + + + Without Rowid + Sans RowId + + + + Fields + Champs + + + + Database sche&ma + Sché&ma de la Base de Données + + + + Add + Ajouter + + + + Remove + Supprimer + + + + Move to top + Monter au début + + + + Move up + Monter + + + + Move down + Descendre + + + + Move to bottom + Descendre à la fin + + + + + Name + Nom + + + + + Type + Type + + + + NN + NN + + + + Not null + Non-Null + + + + PK + CP + + + + Primary key + Clé primaire + + + + AI + IA + + + + Autoincrement + Incrément automatique + + + + U + U + + + + + + Unique + Unique + + + + Default + Défaut + + + + Default value + Valeur par défaut + + + + + + Check + Vérifier + + + + Check constraint + Vérifier les contraintes + + + + Collation + Séquence + + + + + + Foreign Key + Clé étrangère + + + + Constraints + Contraintes + + + + Add constraint + Ajouter une contrainte + + + + Remove constraint + Supprimer une contrainte + + + + Columns + Colonnes + + + + SQL + SQL + + + + <html><head/><body><p><span style=" font-weight:600; color:#ff0000;">Warning: </span>There is something with this table definition that our parser doesn't fully understand. Modifying and saving this table might result in problems.</p></body></html> + <html><head/><body><p><span style=" font-weight:600; color:#ff0000;">Attention : </span>Il y a quelque chose dans la définition de cette table que notre analyseur syntaxique n'a pas complètement compris. La modification et l'enregistrement de cette table peuvent créer des problèmes.</p></body></html> + + + + + Primary Key + Clé primaire + + + + Add a primary key constraint + Ajoute une clé primaire à la contrainte + + + + Add a foreign key constraint + Ajoute une clé étrangère à la contrainte + + + + Add a unique constraint + Ajoute une contrainte unique + + + + Add a check constraint + Ajouter une contrainte de contrôle + + + + Error creating table. Message from database engine: +%1 + Erreur lors de la création de la table. Message du moteur de la Base de Données : +%1 + + + + There already is a field with that name. Please rename it first or choose a different name for this field. + Il existe déjà un champ avec ce nom. Veuillez le renommer avant ou choisir un autre nom pour ce champ. + + + + + There can only be one primary key for each table. Please modify the existing primary key instead. + Une table ne peut avoir qau'une seule clé primaire. Veuillez modifier la clé primaire existante à la place. + + + + This column is referenced in a foreign key in table %1 and thus its name cannot be changed. + Cette colonne est référencée dans une clé étrangère dans la table %1. Son nom ne peut être changé. + + + + There is at least one row with this field set to NULL. This makes it impossible to set this flag. Please change the table data first. + Il existe au moins un enregistrement avec ce champ autorisant des valeurs nulles (NULL). Il est donc impossible de définir cet indicateur. Veuillez modifier les données de la table au préalable. + + + + There is at least one row with a non-integer value in this field. This makes it impossible to set the AI flag. Please change the table data first. + Il existe au moins un enregistrement avec une valeur qui n'est pas un nombre entier dans ce champ. Il est donc impossible de définir l'indicateur AI (Incrément automatique) sur ce champ. Veuillez modifier les données de la table au préalable. + + + + Column '%1' has duplicate data. + + La colonne %1 a des des données en double. + + + + + This makes it impossible to enable the 'Unique' flag. Please remove the duplicate data, which will allow the 'Unique' flag to then be enabled. + Il est donc impossible d'activer l'indicateur "Unique". Veuillez supprimer les données en double, cela vous permettra d'activer l'indicateur "Unique". + + + + Are you sure you want to delete the field '%1'? +All data currently stored in this field will be lost. + Êtes-vous sûr de vouloir supprimer le champ "%1" ? +Toutes les données contenues dans ce champ seront perdues. + + + + Please add a field which meets the following criteria before setting the without rowid flag: + - Primary key flag set + - Auto increment disabled + Veuillez ajouter un champ ayant les caractéristiques suivant avant de positionner l'option Sans RowId : +- Défini comme clé primaire ; +- Incrément automatique désactivé + + + + ExportDataDialog + + + Export data as CSV + Exporter au format CSV + + + + Tab&le(s) + &Table(s) + + + + Colu&mn names in first line + Nom des &Col. en 1ère ligne + + + + Fie&ld separator + &Séparateur de champ + + + + , + , + + + + ; + ; + + + + Tab + Tabulation + + + + | + | + + + + + + Other + Autre + + + + &Quote character + T&ype de guillemet + + + + " + " + + + + ' + ' + + + + New line characters + Saut de ligne + + + + Windows: CR+LF (\r\n) + Windows: CR+LF (\r\n) + + + + Unix: LF (\n) + Unix: LF (\n) + + + + Pretty print + Formatter + + + + + Could not open output file: %1 + Le fichier de destination %1 ne peut être ouvert + + + + + Choose a filename to export data + Choisir un nom de fichier pour exporter les données + + + + Export data as JSON + Exporter au format JSON + + + + exporting CSV + Exporter au format CSV + + + + exporting JSON + Exporter au format JSON + + + + Please select at least 1 table. + Veuillez sélectionner au moins une table. + + + + Choose a directory + Choisir un répertoire + + + + Export completed. + Export terminé. + + + + ExportSqlDialog + + + Export SQL... + Same as defined in English... But converted to uniformize with other dialog boxes. + Exporter au format SQL... + + + + Tab&le(s) + Tab&le(s) + + + + Select All + Sélectionner tout + + + + Deselect All + Déselectionner tout + + + + &Options + &Options + + + + Keep column names in INSERT INTO + Conserver les noms des colonnes dans INSERT INTO + + + + Multiple rows (VALUES) per INSERT statement + Plusieurs enregistrements (VALUES) par INSERT + + + + Export everything + Exporter tout + + + + Export schema only + Exporter uniquement le schéma + + + + Export data only + Exporter uniquement les données + + + + Keep old schema (CREATE TABLE IF NOT EXISTS) + Conserver l'ancien schéma (CREATE TABLE IF NOT EXISTS) + + + + Overwrite old schema (DROP TABLE, then CREATE TABLE) + Écraser l'ancien schéma (DROP TABLE, puis CREATE TABLE) + + + + Please select at least one table. + Veuillez sélectionner au moins une table. + + + + Choose a filename to export + Choisir un nom de fichier pour l'export + + + + Export completed. + Export terminé. + + + + Export cancelled or failed. + L'export a été annulé ou a échoué. + + + + ExtendedScintilla + + + + Ctrl+H + + + + + Ctrl+F + + + + + + Ctrl+P + + + + + Find... + Rechercher... + + + + Find and Replace... + Chercher et remplacer... + + + + Print... + Imprimer... + + + + ExtendedTableWidget + + + Use as Exact Filter + Utiliser comme filtre exact + + + + Containing + Contenant + + + + Not containing + Ne contenant pas + + + + Not equal to + Différent de + + + + Greater than + Plus grand que + + + + Less than + Plus petit que + + + + Greater or equal + Plus grand ou égal à + + + + Less or equal + Plus petit ou égal à + + + + Between this and... + Entre ceci et... + + + + Regular expression + Expression régulière + + + + Edit Conditional Formats... + Éditer les formats conditionnels... + + + + Set to NULL + Définir comme NULL + + + + Copy + Copier + + + + Copy with Headers + Copier avec les Entêtes + + + + Copy as SQL + Copier comme du SQL + + + + Paste + Coller + + + + Print... + Imprimer... + + + + Use in Filter Expression + Utiliser dans l'expression du Filtre + + + + Alt+Del + Alt+Supp + + + + Ctrl+Shift+C + Ctrl+Maj+C + + + + Ctrl+Alt+C + + + + + The content of the clipboard is bigger than the range selected. +Do you want to insert it anyway? + Le contenu du presse-papier est plus grand que la plage sélectionnée. +Voulez-vous poursuivre l'insertion malgré tout ? + + + + <p>Not all data has been loaded. <b>Do you want to load all data before selecting all the rows?</b><p><p>Answering <b>No</b> means that no more data will be loaded and the selection will not be performed.<br/>Answering <b>Yes</b> might take some time while the data is loaded but the selection will be complete.</p>Warning: Loading all the data might require a great amount of memory for big tables. + <p>Toutes les données n'ont pas été chargées. <b>Voulez-vous charger toutes les données avant de sélectionner toutes les lignes ? </b><p><p>Répondre <b>Non</b> signifie qu'aucune autre donnée ne sera chargée et que la sélection ne sera pas effectuée.<br/>Répondre <b>Oui</b> peut prendre un certain temps pendant le chargement des données mais la sélection sera complète.</p>Avertissement : Le chargement de toutes les données peut nécessiter une grande quantité de mémoire pour les grandes tables. + + + + Cannot set selection to NULL. Column %1 has a NOT NULL constraint. + La sélection ne peut être à NULL. La colonne %1 à une contrainte NOT NULL. + + + + FileExtensionManager + + + File Extension Manager + Gestionnaire d'extension de fichier + + + + &Up + &Monter + + + + &Down + &Descendre + + + + &Add + &Ajouter + + + + &Remove + &Supprimer + + + + + Description + Description + + + + Extensions + Extensions + + + + *.extension + *.extension + + + + FilterLineEdit + + + Filter + Filtre + + + + These input fields allow you to perform quick filters in the currently selected table. +By default, the rows containing the input text are filtered out. +The following operators are also supported: +% Wildcard +> Greater than +< Less than +>= Equal to or greater +<= Equal to or less += Equal to: exact match +<> Unequal: exact inverse match +x~y Range: values between x and y +/regexp/ Values matching the regular expression + Ces champs de saisie vous permettent d'effectuer des filtres rapides dans le tableau actuellement sélectionné. +Par défaut, les lignes contenant le texte de saisie sont filtrées. +Les opérateurs suivants sont également pris en charge : +% Joker (métacaractère) +> Supérieur à +< Inférieur à +>= Supérieur ou Égal à +<= Inférieur oiu Égal à += Égal à : correspondance exacte +<> Différent de: correspondance inverse exacte +x~y Fourchette : valeurs entre x et y +/regexp/ Valeurs correspondant à l'expression régulière + + + + Clear All Conditional Formats + Effacer tous les Formats Conditionnels + + + + Use for Conditional Format + Utilisé pour le Format Conditionnel + + + + Edit Conditional Formats... + Editer un Format Conditionnel... + + + + Set Filter Expression + Définir l'expression du filtre + + + + What's This? + Qu'est-ce que c'est ? + + + + Is NULL + Est NULL + + + + Is not NULL + Est non NULL + + + + Is empty + Est Vide + + + + Is not empty + Est non Vide + + + + Not containing... + Ne contenant pas... + + + + Equal to... + Egal à... + + + + Not equal to... + Différent de... + + + + Greater than... + Plus grand que... + + + + Less than... + Plus petit que... + + + + Greater or equal... + Plus grand ou égal à... + + + + Less or equal... + Plus petit ou égal à... + + + + In range... + Peut être aussi traduit par "dans la plage..." ou "Entre..." + Entre les valeurs... + + + + Regular expression... + Expression régulière... + + + + FindReplaceDialog + + + Find and Replace + Chercher et remplacer + + + + Fi&nd text: + &Rechercher : + + + + Re&place with: + Re&mplacer avec : + + + + Match &exact case + &Expression exacte + + + + Match &only whole words + M&ots entiers uniquement + + + + When enabled, the search continues from the other end when it reaches one end of the page + Lorsque la Recherche circulaire est activée, la recherche recommence au début une fois atteinte la fin de la page + + + + &Wrap around + Recherche &Circulaire + + + + When set, the search goes backwards from cursor position, otherwise it goes forward + Lorsqu'elle est activée, la recherche s'effectue en remontant à partir de la position du curseur, sinon elle se fait en descendant + + + + Search &backwards + Rechercher vers le &haut + + + + <html><head/><body><p>When checked, the pattern to find is searched only in the current selection.</p></body></html> + <html><head/><body><p>Lorsque cette case est cochée, la recherche ne se fait que dans la sélection actuelle.</p></body></html> + + + + &Selection only + &Sélection uniquement + + + + <html><head/><body><p>When checked, the pattern to find is interpreted as a UNIX regular expression. See <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>.</p></body></html> + La version française de https://en.wikibooks.org/wiki/Regular_Expressions n'existe pas + <html><head/><body><p>Lorsqu'elle est cochée, le motif à trouver est interprété comme une expression régulière UNIX. Voir <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>.</p></body></html> + + + + Use regular e&xpressions + Utiliser les e&xpressions régulières + + + + Find the next occurrence from the cursor position and in the direction set by "Search backwards" + Trouver l'occurrence suivante à partir de la position du curseur et dans la direction définie par "Rechercher vers le haut" + + + + &Find Next + &Suivant + + + + F3 + + + + + &Replace + Rem&placer + + + + Highlight all the occurrences of the text in the page + Surligner toutes les occurrences du texte dans la page + + + + F&ind All + Rechercher &Tout + + + + Replace all the occurrences of the text in the page + Remplace toutes les occurrences du texte dans la page + + + + Replace &All + Remplacer To&ut + + + + The searched text was not found + Le texte recherché n'a pas été trouvé + + + + The searched text was not found. + Le texte recherché n'a pas été trouvé. + + + + The searched text was found one time. + Le texte recherché a été trouvé une fois. + + + + The searched text was found %1 times. + Le texte recherché a été trouvé %1 fois. + + + + The searched text was replaced one time. + Le texte recherché a été remplacé une fois. + + + + The searched text was replaced %1 times. + Le texte recherché a été remplacé %1 fois. + + + + ForeignKeyEditor + + + &Reset + &Réinitialiser + + + + Foreign key clauses (ON UPDATE, ON DELETE etc.) + Clauses de clé étrangère (ON UPDATE, ON DELETE etc.) + + + + ImportCsvDialog + + + Import CSV file + Importer un fichier CSV + + + + Table na&me + No&m de la Table + + + + &Column names in first line + Nom des &Col. en 1ère ligne + + + + Field &separator + &Séparateur de champ + + + + , + , + + + + ; + ; + + + + + Tab + Tabulation + + + + | + | + + + + Other + Autre + + + + &Quote character + T&ype de guillemet + + + + + Other (printable) + Autre (imprimable) + + + + + Other (code) + Autre (code) + + + + " + " + + + + ' + ' + + + + &Encoding + &Encodage + + + + UTF-8 + UTF-8 + + + + UTF-16 + UTF-16 + + + + ISO-8859-1 + ISO-8859-1 + + + + Trim fields? + Réduire les champs ? + + + + Separate tables + Tables distinctes + + + + Advanced + Avancé + + + + When importing an empty value from the CSV file into an existing table with a default value for this column, that default value is inserted. Activate this option to insert an empty value instead. + Lorsque vous importez une valeur vide du fichier CSV dans une table existante avec une valeur par défaut pour cette colonne, cette valeur par défaut est insérée. Activez cette option pour insérer une valeur vide à la place. + + + + Ignore default &values + Ignorer les &valeurs par défaut + + + + Activate this option to stop the import when trying to import an empty value into a NOT NULL column without a default value. + Activez cette option pour arrêter l'importation lorsque vous essayez d'importer une valeur vide dans une colonne NON NULL sans valeur par défaut. + + + + Fail on missing values + Erreur sur les valeurs manquantes + + + + Disable data type detection + Désactiver la détection du type de données + + + + Disable the automatic data type detection when creating a new table. + Désactive la détection automatique du type de données lors de la création d'une nouvelle table. + + + + When importing into an existing table with a primary key, unique constraints or a unique index there is a chance for a conflict. This option allows you to select a strategy for that case: By default the import is aborted and rolled back but you can also choose to ignore and not import conflicting rows or to replace the existing row in the table. + Lors de l'importation dans une table existante possédant une clé primaire, des contraintes uniques ou un index unique, il y a un risque de conflit. Cette option vous permet de sélectionner une stratégie pour ce cas : Par défaut, l'importation est interrompue et annulée, mais vous pouvez également choisir d'ignorer et de ne pas importer les lignes en conflit ou de remplacer la ligne existante dans la table. + + + + Abort import + Abandonner l'import + + + + Ignore row + Ignorer l'enregistrement + + + + Replace existing row + Remplacer l'enregistrement existant + + + + Conflict strategy + En conflit avec la stratégie + + + + + Deselect All + Déselectionner tout + + + + Match Similar + 170726 MVT Has to be checked in real context or after explanation of this function. I suppose this function permits, with data names on the first line to "prefill a corresponding names" in an existing object ? + Appairer + + + + Select All + Sélectionner tout + + + + There is already a table named '%1' and an import into an existing table is only possible if the number of columns match. + Il existe déjà une table nommée'%1' et une importation dans une table existante n'est possible que si le nombre de colonnes correspond. + + + + There is already a table named '%1'. Do you want to import the data into it? + Il existe déjà une table appelée "%1". Voulez-vous y importer les données ? + + + + Creating restore point failed: %1 + La création du point de restauration a échoué : %1 + + + + Creating the table failed: %1 + La création de la table a échoué %1 + + + + importing CSV + Importer au format CSV + + + + Importing the file '%1' took %2ms. Of this %3ms were spent in the row function. + L'importation du fichier'%1' a pris %2ms. %3ms ont été dépensés dans la fonction enregistrement. + + + + Inserting row failed: %1 + L'insertion de l'enregistrement a échoué : %1 + + + + MainWindow + + + toolBar1 + Barre d'outils1 + + + + Warning: this pragma is not readable and this value has been inferred. Writing the pragma might overwrite a redefined LIKE provided by an SQLite extension. + Attention : ce pragma n'est pas lisible et cette valeur a été déduite. Ecrire le pragma pourrait écraser un LIKE redéfini fourni par une extension SQLite. + + + + &Tools + &Outils + + + + Edit Database &Cell + Éditer le contenu d'une &Cellule + + + + Opens the SQLCipher FAQ in a browser window + Ouvre la FAQ de SQLCipher dans la fenêtre d'un navigateur + + + + Export one or more table(s) to a JSON file + Exporter une ou plusieurs tables vers un fichier JSON + + + + DB Browser for SQLite + DB Browser pour SQLite + + + + &File + &Fichier + + + + &Import + &Importer + + + + &Export + &Exporter + + + + &Edit + É&dition + + + + &View + &Vue + + + + &Help + &Aide + + + + User + Utilisateur + + + + Application + Application + + + + This button clears the contents of the SQL logs + Ce bouton supprime le contenu des logs SQL + + + + &Clear + &Effacer + + + + &New Database... + &Nouvelle Base de Données... + + + + + Create a new database file + Créer une nouvelle Base de Données + + + + This option is used to create a new database file. + Cette option est utilisée pour créer un nouveau fichier de Base de Données. + + + + Ctrl+N + + + + + + &Open Database... + &Ouvrir une Base de Données... + + + + + + + + Open an existing database file + Ouvre une Base de Données existante + + + + + + This option is used to open an existing database file. + Cette option est utilisée pour ouvrir une Base de Données existante. + + + + Ctrl+O + + + + + &Close Database + &Fermer la Base de Données + + + + This button closes the connection to the currently open database file + Ce bouton ferme la connexion à la Base de Données actuellement ouverte + + + + + Ctrl+W + + + + + &Revert Changes + &Annuler les modifications + + + + + Revert database to last saved state + Revenir à la dernière version sauvegardée de la Base de Données + + + + This option is used to revert the current database file to its last saved state. All changes made since the last save operation are lost. + Cette option permet de restaurer la Base de Données dans l'état de sa dernière sauvegarde. Tous les changements effectués depuis cette dernière sauvegarde seront perdus. + + + + &Write Changes + Enregistrer les &modifications + + + + + Write changes to the database file + Enregistrer les modifications dans la Base de Données + + + + This option is used to save changes to the database file. + Cette option est utilisée pour enregistrer les modifications dans la Base de Données. + + + + Ctrl+S + + + + + Execute all/selected SQL + Exécuter Tout ou seulement le SQL sélectionné + + + + This button executes the currently selected SQL statements. If no text is selected, all SQL statements are executed. + Ce bouton lance l'exécution des commandes SQL actuellement sélectionnées. Si aucun texte n'est sélectionné, toutes les commandes SQL seront éxécutées. + + + + Execute line + Exécuter la ligne + + + + &Wiki + &Wiki + + + + F1 + + + + + Bug &Report... + &Rapport d'erreur... + + + + Feature Re&quest... + &Demande de fonctionnalités... + + + + Web&site + &Site Internet + + + + &Donate on Patreon... + Effectuer une &Donation sur Patreon... + + + + Open &Project... + Ouvrir un &Projet... + + + + &Attach Database... + Attac&her une Base de Données... + + + + + Add another database file to the current database connection + Ajouter un autre fichier de Base de Données à la connexion de la Base de Données en cours + + + + This button lets you add another database file to the current database connection + Ce bouton vous permet d'ajouter un autre fichier de Base de Données à la connexion de la Base de Données en cours + + + + &Set Encryption... + Chi&ffrer... + + + + SQLCipher &FAQ + &Faq SQLCipher + + + + Table(&s) to JSON... + Table(&s) vers JSON... + + + + Open Data&base Read Only... + Ouvrir la Base de Données en &Lecture seule... + + + + Ctrl+Shift+O + Ctrl+Maj+O + + + + Save results + Enregistrer les résultats + + + + Save the results view + Enregistrer la vue des résultats + + + + This button lets you save the results of the last executed query + Ce bouton vous permet d'enregistrer les résultats de la dernière requête exécutée + + + + + Find text in SQL editor + Rechercher du texte dans l'éditeur SQL + + + + Find + Rechercher + + + + This button opens the search bar of the editor + Ce bouton ouvre la barre de recherche dans l'éditeur + + + + Ctrl+F + + + + + + Find or replace text in SQL editor + Rechercher ou remplacer du texte dans l'éditeur SQL + + + + Find or replace + Chercher et remplacer + + + + This button opens the find/replace dialog for the current editor tab + Ce bouton ouvre la boîte de dialogue Rechercher/Remplacer pour l'onglet en cours de l'éditeur + + + + Ctrl+H + + + + + Export to &CSV + Exporter au format &CSV + + + + Save as &view + Enregistrer comme une &vue + + + + Save as view + Enregistrer comme une vue + + + + Browse Table + Parcourir la table + + + + Shows or hides the Project toolbar. + Afficher ou masquer la barre d'outil Projet. + + + + Extra DB Toolbar + Extra DB Toolbar + + + + This button lets you save all the settings associated to the open DB to a DB Browser for SQLite project file + Ce bouton vous permet d'enregistrer tous les paramètres associés à la Base de Données ouverte dans un fichier projet DB Browser pour SQLite + + + + This button lets you open a DB Browser for SQLite project file + Ce bouton vous permet d'ouvrir un fichier projet DB Browser pour SQLite + + + + New In-&Memory Database + Nouvelle Base de Données en &Mémoire + + + + Drag && Drop Qualified Names + Glisser && Déposer les noms qualifiés + + + + + Use qualified names (e.g. "Table"."Field") when dragging the objects and dropping them into the editor + Utilisez des noms qualifiés (par ex. "Table", "Champ") lorsque vous faites glisser les objets et pour les déposez dans l'éditeur + + + + Drag && Drop Enquoted Names + Glisser && Déposer les noms cités + + + + + Use escaped identifiers (e.g. "Table1") when dragging the objects and dropping them into the editor + Utiliser les identificateurs par défaut (par ex. "Table1") lors du glisser-déposer des objets dans l'éditeur + + + + &Integrity Check + Vérifier l'&Intégrité + + + + Runs the integrity_check pragma over the opened database and returns the results in the Execute SQL tab. This pragma does an integrity check of the entire database. + Exécute le pragma integrity_check sur la Base de Données ouverte et retourne les résultats dans l'onglet Exécuter SQL. Ce pragma effectue un contrôle d'intégrité de l'ensemble de la Base de Données. + + + + &Foreign-Key Check + Vérifier les clés &Etrangères + + + + Runs the foreign_key_check pragma over the opened database and returns the results in the Execute SQL tab + Exécute le pragma foreign_key_check_check sur la Base de Données ouverte et retourne les résultats dans l'onglet Exécuter SQL + + + + &Quick Integrity Check + Vérification &rapide de l'intégrité + + + + Run a quick integrity check over the open DB + Effectuer un rapide contrôle d'intégrité sur la Base de Données ouverte + + + + Runs the quick_check pragma over the opened database and returns the results in the Execute SQL tab. This command does most of the checking of PRAGMA integrity_check but runs much faster. + Exécute le pragma quick_check sur la Base de Données ouverte et retourne les résultats dans l'onglet Exécuter SQL. Cette commande effectue la plupart des vérifications de PRAGMA integrity_check mais s'exécute beaucoup plus rapidement. + + + + &Optimize + &Optimiser + + + + Attempt to optimize the database + Tente d'optimiser la Base de Données + + + + Runs the optimize pragma over the opened database. This pragma might perform optimizations that will improve the performance of future queries. + Exécute le pragma d'optimisation sur la Base de Données ouverte. Ce pragma pourrait effectuer des optimisations qui amélioreront la performance des requêtes futures. + + + + + Print + Imprimer + + + + Print text from current SQL editor tab + Imprime le contenu de l'onglet en cours de l'éditeur SQL [Ctrp+P] + + + + Open a dialog for printing the text in the current SQL editor tab + Ouvre une boite de dialogue pour imprimer le contenu de l'onglet en cours de l'éditeur SQL + + + + Print the structure of the opened database + Imprime la structure de la Base de Données ouverte + + + + Open a dialog for printing the structure of the opened database + Ouvre une boite de dialogue pour imprimer la structure de la Base de Données ouverte + + + + &Save Project As... + Enr&egistrer le projet sous... + + + + + + Save the project in a file selected in a dialog + Enregistrer le projet dans un fichier sélectionné dans une boite de dialogue + + + + Save A&ll + Enregistrer &Tout + + + + + + Save DB file, project file and opened SQL files + Enregistre la Base de Données, le fichier projet et les fichiers SQL ouverts + + + + Ctrl+Shift+S + Ctrl+Maj+S + + + + Compact the database file, removing space wasted by deleted records + Compacter la base de donnée, récupérer l'espace perdu par les enregistrements supprimés + + + + + Compact the database file, removing space wasted by deleted records. + Compacter la base de donnée, récupérer l'espace perdu par les enregistrements supprimés. + + + + E&xit + &Quitter + + + + Ctrl+Q + + + + + Import data from an .sql dump text file into a new or existing database. + Importer les données depuis un fichier sql résultant d'un vidage (sql dump) dans une nouvelle Base de Données ou une base existante. + + + + This option lets you import data from an .sql dump text file into a new or existing database. SQL dump files can be created on most database engines, including MySQL and PostgreSQL. + Cette option vous permet d'importer un fichier sql de vidage d'une Base de Données (SQL dump) dans une nouvelle Base de Données ou une base existante. Ce fichier peut être créé par la plupart des moteurs de Base de Données, y compris MySQL et PostgreSQL. + + + + Open a wizard that lets you import data from a comma separated text file into a database table. + Ouvrir un Assistant vous permettant d'importer des données dans une table de la Base de Données à partir d'un fichier texte séparé par des virgules (csv). + + + + Open a wizard that lets you import data from a comma separated text file into a database table. CSV files can be created on most database and spreadsheet applications. + Ouvre un Assistant vous permettant d'importer des données dans une table de la Base de Données à partir d'un fichier texte séparé par des virgules (csv). Les fichiers CSV peuvent être créés par la plupart des outils de gestion de Base de Données et les tableurs. + + + + Export a database to a .sql dump text file. + Exporter la Base de Données vers un fichier de vidage sql (SQL dump) au format texte. + + + + This option lets you export a database to a .sql dump text file. SQL dump files contain all data necessary to recreate the database on most database engines, including MySQL and PostgreSQL. + Exporter la Base de Données vers un fichier de vidage sql (SQL dump) au format texte. Ce fichier (SQL dump) contient toutes les informations nécessaires pour recréer une Base de Données par la plupart des moteurs de Base de Données, y compris MySQL et PostgreSQL. + + + + Export a database table as a comma separated text file. + Exporter la table vers un fichier texte séparé par des virgules (CSV). + + + + Export a database table as a comma separated text file, ready to be imported into other database or spreadsheet applications. + Exporter la table vers un fichier texte séparé par des virgules (CSV), prêt à être importé dans une autre Base de Données ou un tableur. + + + + &Create Table... + &Créer une table... + + + + Open the Create Table wizard, where it is possible to define the name and fields for a new table in the database + Ouvrir l'assistant de création d'une table dans lequel il sera possible de définir les noms et les champs d'une nouvelle table dans la Base de Données + + + + &Delete Table... + &Supprimer une table... + + + + Open the Delete Table wizard, where you can select a database table to be dropped. + Ouvrir l'assistant de suppression d'une table avec lequel vous pourrez sélectionner la table à supprimer. + + + + &Modify Table... + &Modifier une table... + + + + Open the Modify Table wizard, where it is possible to rename an existing table. It is also possible to add or delete fields form a table, as well as modify field names and types. + Ouvrir l'assistant de modification d'une table avec lequel il sera possible de renommer une table existante. Il est aussi possible d'ajouter ou de supprimer des champs de la table, tout comme modifier le nom des champs et leur type. + + + + Open the Create Index wizard, where it is possible to define a new index on an existing database table. + Ouvrir l'assistant de création d'un index avec lequel il sera possible de définir un nouvel index dans une table préexistante de la Base de Données. + + + + &Preferences... + &Préférences... + + + + + Open the preferences window. + Ouvrir la fenêtre des préférences. + + + + &DB Toolbar + &Barre d'outils BdD + + + + Shows or hides the Database toolbar. + Affiche ou masque la barre d'outils Base de Données. + + + + Shift+F1 + Maj+F1 + + + + &Recently opened + Ouvert &récemment + + + + Open &tab + vérifier le contexte + Ouvrir un on&glet + + + + Ctrl+T + + + + + This is the structure of the opened database. +You can drag multiple object names from the Name column and drop them into the SQL editor and you can adjust the properties of the dropped names using the context menu. This would help you in composing SQL statements. +You can drag SQL statements from the Schema column and drop them into the SQL editor or into other applications. + + Ceci est la structure de la Base de Données ouverte. +Vous pouvez faire glisser plusieurs noms d'objets de la colonne Nom et les déposer dans l'éditeur SQL et vous pouvez ajuster les propriétés des noms déposés en utilisant le menu contextuel. Cela pourrait vous aider à composer des instructions SQL. +Vous pouvez faire glisser les instructions SQL de la colonne Schéma et les déposer dans l'éditeur SQL ou dans d'autres applications. + + + + + + Project Toolbar + Barre d'outil Projet + + + + Extra DB toolbar + Extra DB Toolbar + + + + + + Close the current database file + Fermer la Base de Données en cours + + + + Ctrl+F4 + + + + + Compact &Database... + Compacter la Base de &Données... + + + + &About + À &propos + + + + This button opens a new tab for the SQL editor + Ce bouton ouvre un nouvel onglet dans l'éditeur SQL + + + + &Execute SQL + &Exécuter le SQL + + + + + Execute SQL + This has to be equal to the tab title in all the main tabs + Exécuter le SQL + + + + + Save the current session to a file + Enregistrer la session courante dans un fichier + + + + + Load a working session from a file + Charger une session de travail depuis un fichier + + + + + Database Structure + This has to be equal to the tab title in all the main tabs + Structure de la Base de Données + + + + This is the structure of the opened database. +You can drag SQL statements from an object row and drop them into other applications or into another instance of 'DB Browser for SQLite'. + + Ceci est la structure de la Base de Données ouverte. +Vous pouvez faire glisser les instructions SQL d'une ligne d'objet et les déposer dans d'autres applications ou dans une autre instance de'DB Browser pour SQLite'. + + + + + + Browse Data + This has to be equal to the tab title in all the main tabs + Parcourir les données + + + + Error Log + Journal des erreurs + + + + Un/comment block of SQL code + Dé/commenter un bloc de code SQL + + + + Un/comment block + Dé/commenter un bloc + + + + Comment or uncomment current line or selected block of code + Commenter ou décommenter la ligne actuelle ou le bloc de code sélectionné + + + + Comment or uncomment the selected lines or the current line, when there is no selection. All the block is toggled according to the first line. + Commenter ou décommenter les lignes sélectionnées ou la ligne en cours, lorsqu'il n'y a pas de sélection. Tout le bloc est basculé en fonction de la première ligne. + + + + Ctrl+/ + + + + + Stop SQL execution + Arrête l'exécution du SQL + + + + Stop execution + Arrêter l'exécution + + + + Stop the currently running SQL script + Arrête le script SQL en cours d'exécution + + + + + Edit Pragmas + This has to be equal to the tab title in all the main tabs + Éditer les Pragmas + + + + DB Toolbar + Barre d'outils BdD + + + + SQL &Log + &Journal SQL + + + + Show S&QL submitted by + A&fficher le SQL soumis par + + + + This panel lets you examine a log of all SQL commands issued by the application or by yourself + Ce panneau vous permet d'examiner un journal de toutes les commandes SQL émises par l'application ou par vous-même + + + + &Plot + Gra&phique + + + + DB Sche&ma + DB Sche&ma + + + + &Remote + Serveur &distant + + + + &Database from SQL file... + &Base de Données à partir du fichier SQL... + + + + &Table from CSV file... + &Table depuis un fichier CSV... + + + + &Database to SQL file... + Base de &Données vers un fichier SQL... + + + + &Table(s) as CSV file... + &Table vers un fichier CSV... + + + + Create &Index... + Créer un &Index... + + + + W&hat's This? + &Qu'est-ce que c'est ? + + + + Open SQL file(s) + Ouvrir un fichier SQL + + + + This button opens files containing SQL statements and loads them in new editor tabs + Ce bouton ouvre un fichier contenant des instructions SQL et le charge dans un nouvel onglet de l'éditeur + + + + + + Save SQL file + Enregistrer le fichier SQL + + + + &Load Extension... + Charger l'&Extension... + + + + + Execute current line + Exécuter la ligne courante (Maj+F5) + + + + This button executes the SQL statement present in the current editor line + Ce bouton exécute l'instruction SQL présente dans la ligne courante de l'éditeur + + + + Shift+F5 + Maj+F5 + + + + Sa&ve Project + Enre&gistrer le projet + + + + + Save SQL file as + Enregistrer le fichier SQL comme + + + + This button saves the content of the current SQL editor tab to a file + Ce bouton enregistre le contenu de l'onglet actuel de l'éditeur SQL dans un fichier + + + + &Browse Table + &Parcourir la table + + + + Copy Create statement + Copier l'instruction CREATE + + + + Copy the CREATE statement of the item to the clipboard + Copie l'instruction CREATE de cet item dans le presse-papier + + + + Open an existing database file in read only mode + Ouvrir une Base de Données existante en mode Lecture seule + + + + Ctrl+E + + + + + Export as CSV file + Exporter les données au format CSV + + + + Export table as comma separated values file + Exporter la table vers un fichier texte séparé par des virgules (CSV) + + + + Ctrl+L + + + + + + Ctrl+P + + + + + Database encoding + Encodage de la Base de Données + + + + + Choose a database file + Choisir une Base de Données + + + + Ctrl+Return + Ctrl+Entrée + + + + Ctrl+D + + + + + Ctrl+I + + + + + Reset Window Layout + Rétablir la disposition des fenêtres + + + + Alt+0 + + + + + The database is currenctly busy. + La Base de Données est actuellement occupée. + + + + Click here to interrupt the currently running query. + Cliquez ici pour interrompre la requête en cours. + + + + Encrypted + Chiffré + + + + Database is encrypted using SQLCipher + La Base de Données a été chiffrée avec SQLCipher + + + + Read only + Lecture seule + + + + Database file is read only. Editing the database is disabled. + La Base de Données est ouverte en lecture seule. Il n'est pas possible de la modifier. + + + + Could not open database file. +Reason: %1 + La Base de Données ne peut être ouverte. +Motif : %1 + + + + + + Choose a filename to save under + Choisir un nom de fichier pour enregistrer sous + + + + Error while saving the database file. This means that not all changes to the database were saved. You need to resolve the following error first. + +%1 + Erreur lors de l'enregistrement de la Base de Données. Cela sous-entend qu'aucun changement n'a été sauvegardé. Vous devez corriger au préalable l'erreur suivante : + +%1 + + + + Do you want to save the changes made to SQL tabs in the project file '%1'? + Voulez-vous enregistrer les modifications apportées aux onglets SQL dans le fichier du projet '%1' ? + + + + A new DB Browser for SQLite version is available (%1.%2.%3).<br/><br/>Please download at <a href='%4'>%4</a>. + Une nouvelle version de DB Browser pour SQLite est disponible (%1.%2.%3).<br/><br/>Vous pouvez la télécharger sur <a href='%4'>%4</a>. + + + + DB Browser for SQLite project file (*.sqbpro) + Fichier de projet DB Browser pour SQLite (*.sqbpro) + + + + Error checking foreign keys after table modification. The changes will be reverted. + Erreur de vérification des clés étrangères après modification de la table. Les modifications seront annulées. + + + + This table did not pass a foreign-key check.<br/>You should run 'Tools | Foreign-Key Check' and fix the reported issues. + Cette table n'a pas passé avec succès un contrôle de clé étrangère.<br/>Vous devez exécuter l'Outil | Contrôle des clés étrangères' et corriger les problèmes rapportés. + + + + Execution finished with errors. + L'exécution s'est terminée avec des erreurs. + + + + Execution finished without errors. + L'exécution s'est terminée sans erreur. + + + + Are you sure you want to undo all changes made to the database file '%1' since the last save? + Êtes-vous sûr de vouloir annuler tous les changements effectués dans la Base de Données %1 depuis la dernière sauvegarde ? + + + + Choose a file to import + Choisir un fichier à importer + + + + Text files(*.sql *.txt);;All files(*) + Fichiers Texte (*.sql *.txt);;Tous les fichiers(*) + + + + Do you want to create a new database file to hold the imported data? +If you answer no we will attempt to import the data in the SQL file to the current database. + Voulez vous créer une nouvelle base de donnée pour gérer les données importées ? +Si vous répondez non, nous essaierons d'importer les données du fichier SQL dans la Base de Données courante. + + + + Window Layout + Disposition des fenêtres + + + + Simplify Window Layout + Simplifier la disposition des fenêtres + + + + Shift+Alt+0 + Maj+Alt+0 + + + + Dock Windows at Bottom + Ancrer les fenêtres en Bas + + + + Dock Windows at Left Side + Ancrer les fenêtres à Gauche + + + + Dock Windows at Top + Ancrer les fenêtres en Haut + + + + You are still executing SQL statements. Closing the database now will stop their execution, possibly leaving the database in an inconsistent state. Are you sure you want to close the database? + Des traitements SQL sont en cours d'exécution. Fermer la Base de Données maintrenant arrêtera ces traitements. Cela risque de laisser la Base de Données dans un état incohérent. Êtes-vous sûr de vouloir fermer la Base de Données ? + + + + Do you want to save the changes made to the project file '%1'? + Voulez-vous enregistrer les changements effectués dans la dans le fichier projet '%1' ? + + + + File %1 already exists. Please choose a different name. + Le fichier %1 existe déjà. Veuillez choisir un nom de fichier différent. + + + + Error importing data: %1 + Erreur lors de l'import des données : %1 + + + + Import completed. + Import terminé. + + + + Delete View + Supprimer la Vue + + + + Delete Trigger + Supprimer le Déclencheur + + + + Delete Index + Supprimer l'Index + + + + + Delete Table + Supprimer la Table + + + + Setting PRAGMA values will commit your current transaction. +Are you sure? + Paramétrer les valeurs du PRAGMA enregistrera les actions de votre transaction courante. +Êtes-vous sûr ? + + + + In-Memory database + Base de Données en mémoire + + + + Are you sure you want to delete the table '%1'? +All data associated with the table will be lost. + Êtes vous sûr de vouloir supprimer la table %1 ? +Toutes les données de la table seront perdues. + + + + Are you sure you want to delete the view '%1'? + Êtes vous sûr de voulolir supprimer la vue %1 ? + + + + Are you sure you want to delete the trigger '%1'? + Êtes vous sûr de voulolir supprimer le déclencheur %1 ? + + + + Are you sure you want to delete the index '%1'? + Êtes vous sûr de voulolir supprimer l'index %1 ? + + + + Error: could not delete the table. + Erreur : suppression de la table impossible. + + + + Error: could not delete the view. + Erreur : suppression de la vue impossible. + + + + Error: could not delete the trigger. + Erreur : suppression du déclencheur impossible. + + + + Error: could not delete the index. + Erreur : suppression de l'index impossible. + + + + Message from database engine: +%1 + Message depuis el moteur de la Base de Données : +%1 + + + + Editing the table requires to save all pending changes now. +Are you sure you want to save the database? + La modification de la table nécessite d'enregistrer toutes les modifications en attente maintenant. +Êtes-vous sûr de vouloir enregistrer la Base de Données ? + + + + Edit View %1 + Editer la vue %1 + + + + Edit Trigger %1 + Editer le déclencheur %1 + + + + You are already executing SQL statements. Do you want to stop them in order to execute the current statements instead? Note that this might leave the database in an inconsistent state. + Vous avez des instructions SQL en cours d'exécution. Voulez-vous les arrêter afin d'exécuter les instructions en cours à la place ? Cela pourrait laisser la Base de Données dans un état incohérent. + + + + -- EXECUTING SELECTION IN '%1' +-- + -- EXECUTION DE LA SELECTION DANS '%1' +-- + + + + -- EXECUTING LINE IN '%1' +-- + -- EXECUTION DE LA LIGNE DANS '%1' +-- + + + + -- EXECUTING ALL IN '%1' +-- + -- EXECUTER TOUT DANS '%1' +-- + + + + + At line %1: + À la ligne %1 : + + + + Result: %1 + Résultat : %1 + + + + Result: %2 + Résultat : %2 + + + + Setting PRAGMA values or vacuuming will commit your current transaction. +Are you sure? + Le réglage des valeurs PRAGMA ou du "vacuuming" validera votre transaction en cours. +Êtes-vous sûr ? + + + + Opened '%1' in read-only mode from recent file list + Ouverture de '%1' en lecture seule depuis la liste des fichiers récents + + + + Opened '%1' from recent file list + Ouverture de '%1' depuis la liste des fichiers récents + + + + Project saved to file '%1' + Projet enregistré dans le fichier '%1' + + + + This action will open a new SQL tab with the following statements for you to edit and run: + Need to verify if following statements ore shown bellow ou above or on the open action + Cette action ouvrira un nouvel onglet SQL avec les instructions suivantes que vous pourrez modifier et exécuter : + + + + Rename Tab + Renommer l'onglet + + + + Duplicate Tab + Dupliquer l'onglet + + + + Close Tab + Fermer l'onglet + + + + Opening '%1'... + Ouverture de '%1'... + + + + There was an error opening '%1'... + Il y a eu une erreur lors de l'ouverture de '%1'... + + + + Value is not a valid URL or filename: %1 + Le valeur n'est pas une URL valide ou un nom de fichier : %1 + + + + %1 rows returned in %2ms + %1 enregistrements ramenés en %2ms + + + + Choose text files + Choisir des fichiers texte + + + + Import completed. Some foreign key constraints are violated. Please fix them before saving. + Importation terminée. Certaines contraintes clés étrangères sont violées. Veuillez les corriger avant de les enregistrer. + + + + Modify View + Modifier une Vue + + + + Modify Trigger + Modifier un Déclencheur + + + + Modify Index + Modifier un Index + + + + Modify Table + Modifier une Table + + + + &%1 %2%3 + &%1 %2%3 + + + + (read only) + (lecture seule) + + + + Open Database or Project + Ouvrir une Base de Données ou un projet + + + + Attach Database... + Attacher une Base de Données... + + + + Import CSV file(s)... + Importer un ou des fichiers CSV... + + + + Select the action to apply to the dropped file(s). <br/>Note: only 'Import' will process more than one file. + + Sélectionnez l'action à appliquer au fichier déposé. <br>Note : seul "Importer" traitera plusieurs fichiers. + Sélectionnez l'action à appliquer aux fichiers déposés. <br>Note : seul "Importer" traitera plusieurs fichiers. + + + + + Do you want to save the changes made to SQL tabs in a new project file? + Voulez-vous enregistrer les changements effectués dans l'onglet SQL dans un nouveau fichier projet ? + + + + Do you want to save the changes made to the SQL file %1? + Voulez-vous enregistrer les changements effectués dans le fichier SQL %1 ? + + + + The statements in this tab are still executing. Closing the tab will stop the execution. This might leave the database in an inconsistent state. Are you sure you want to close the tab? + Les instructions de cet onglet sont toujours en cours d'exécution. La fermeture de l'onglet arrête leur exécution. Cela pourrait laisser la Base de Données dans un état incohérent. Êtes-vous sûr de vouloir fermer l'onglet ? + + + + Select SQL file to open + Sélectionner un fichier SQL à ouvrir + + + + Select file name + Sélectionner un nom de fichier + + + + Select extension file + Sélectionner une extension de fichier + + + + Extension successfully loaded. + l'extension a été chargée avec succès. + + + + Error loading extension: %1 + Erreur lors du chargement de l'extension %1 + + + + Could not find resource file: %1 + Le fichier de ressources : %1 ne peut être ouvert + + + + + Don't show again + Ne plus afficher + + + + New version available. + Une nouvelle version est disponible. + + + + Choose a project file to open + Choisir un fichier de projet à ouvrir + + + + This project file is using an old file format because it was created using DB Browser for SQLite version 3.10 or lower. Loading this file format is still fully supported but we advice you to convert all your project files to the new file format because support for older formats might be dropped at some point in the future. You can convert your files by simply opening and re-saving them. + Ce fichier projet utilise un ancien format de fichier parce qu'il a été créé avec DB Browser pour SQLite version 3.10 ou inférieure. Le chargement de ce format de fichier est toujours totalement pris en charge, mais nous vous conseillons de convertir tous vos fichiers projet vers le nouveau format de fichier, car la prise en charge des anciens formats pourrait être supprimée à un moment ou un autre. Vous pouvez convertir vos fichiers en les ouvrant et en les sauvegardant de nouveau. + + + + Could not open project file for writing. +Reason: %1 + Le fichier projet ne peut être ouvert en écriture. +Raison : %1 + + + + Collation needed! Proceed? + Classement nécessaire ! Continuer ? + + + + A table in this database requires a special collation function '%1' that this application can't provide without further knowledge. +If you choose to proceed, be aware bad things can happen to your database. +Create a backup! + Une table de cette Base de Données nécessite la fonction spéciale de classement '%1' que cette application ne peut fournir sans connaissances complémentaires. +Si vous choisissez de continuer, ayez à l'esprit que des choses non souhaitées peuvent survenir dans votre Base de Données. +Faites une sauvegarde ! + + + + creating collation + Créer un classement + + + + Set a new name for the SQL tab. Use the '&&' character to allow using the following character as a keyboard shortcut. + Définissez un nouveau nom pour l'onglet SQL. Utilisez le caractère '&&' pour permettre d'utiliser le caractère suivant comme raccourci clavier. + + + + Please specify the view name + Veuillez spécifier le nom de la vue + + + + There is already an object with that name. Please choose a different name. + Il existe déjà un objet avec ce nom. Veuillez choisir un autre nom. + + + + View successfully created. + La vue a été crée avec succès. + + + + Error creating view: %1 + Erreur lors de la création de la vue : %1 + + + + This action will open a new SQL tab for running: + Cette action ouvrira un nouvel onglet SQL pour son exécution : + + + + Press Help for opening the corresponding SQLite reference page. + Cliquez sur Aide pour ouvrir la page de référence correspondante de SQLite. + + + + Busy (%1) + Occupé (%1) + + + + NullLineEdit + + + Set to NULL + Définir comme NULL + + + + Alt+Del + Alt+Supp + + + + PlotDock + + + Plot + Graphique + + + + <html><head/><body><p>This pane shows the list of columns of the currently browsed table or the just executed query. You can select the columns that you want to be used as X or Y axis for the plot pane below. The table shows detected axis type that will affect the resulting plot. For the Y axis you can only select numeric columns, but for the X axis you will be able to select:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Date/Time</span>: strings with format &quot;yyyy-MM-dd hh:mm:ss&quot; or &quot;yyyy-MM-ddThh:mm:ss&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Date</span>: strings with format &quot;yyyy-MM-dd&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Time</span>: strings with format &quot;hh:mm:ss&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Label</span>: other string formats. Selecting this column as X axis will produce a Bars plot with the column values as labels for the bars</li><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Numeric</span>: integer or real values</li></ul><p>Double-clicking the Y cells you can change the used color for that graph.</p></body></html> + <html><head/><body><p>Ce volet affiche la liste des colonnes de la table actuellement parcourue ou de la requête qui vient d'être exécutée. Vous pouvez sélectionner les colonnes que vous voulez utiliser comme axe X ou Y pour le volet de tracé ci-dessous. Le tableau montre le type d'axe détecté qui affectera le tracé résultant. Pour l'axe Y, vous ne pouvez sélectionner que des colonnes numériques, mais pour l'axe X, vous pourrez sélectionner :</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Date/Heure</span> : chaînes au format &quot;aaaa-MM-jj hh:mm:ss&quot; ou &quot;aaaa-MM-jjThh:mm:ss&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Date</span> : chaînes au format &quot;aaaa-MM-jj&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Heures</span> : chaînes au format &quot;hh:mm:ss&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Label</span> : autres formats de chaînes. Sélectionner cette colonne comme axe X produira un diagramme en barres avec les valeurs de la colonne comme étiquettes pour les barres</li><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Numerique</span> : Nombres entiers ou Réels</li></ul><p>Avec Double-clic sur une cellule Y, vous pouvez changer le couleur utilisée dans le graphique.</p></body></html> + + + + Columns + Colonnes + + + + X + X + + + + Y1 + Y1 + + + + Y2 + Y2 + + + + Axis Type + Type d'axe + + + + Here is a plot drawn when you select the x and y values above. + +Click on points to select them in the plot and in the table. Ctrl+Click for selecting a range of points. + +Use mouse-wheel for zooming and mouse drag for changing the axis range. + +Select the axes or axes labels to drag and zoom only in that orientation. + Voici le graphique qui sera dessiné lorsque vous sélectionnerez les valeurs x et y ci-dessus. + +Cliquez sur les points pour les sélectionner dans le graphique et dans le tableau. Ctrl+Clic pour sélectionner une plage de points. + +Utilisez la molette de la souris pour zoomer et faites glisser la souris pour modifier la plage des axes. + +Sélectionnez les axes ou les étiquettes d'axes à faire glisser et à zoomer uniquement dans cette orientation. + + + + Line type: + Type de ligne : + + + + + None + Aucun + + + + Line + Ligne + + + + StepLeft + A Gauche + + + + StepRight + A Droite + + + + StepCenter + Centré + + + + Impulse + Impulsion + + + + Point shape: + Forme du point : + + + + Cross + Croix + + + + Plus + Plus + + + + Circle + Cercle + + + + Disc + Disque + + + + Square + Carré + + + + Diamond + Diamant + + + + Star + Étoile + + + + Triangle + Triangle + + + + TriangleInverted + Triangle Inversé + + + + CrossSquare + Carré et croix + + + + PlusSquare + Carré et Plus + + + + CrossCircle + Cercle et Croix + + + + PlusCircle + Cercle et Plus + + + + Peace + Paix + + + + <html><head/><body><p>Save current plot...</p><p>File format chosen by extension (png, jpg, pdf, bmp)</p></body></html> + <html><head/><body><p>Enregistrer le graphique actuel...</p><p>Choisir le format de fichier parmi ces extensions (png, jpg, pdf, bmp)</p></body></html> + + + + Save current plot... + Enregistrer le tracé actuel... + + + + + Load all data and redraw plot + Charger toutes les données et redessiner le graphique + + + + + + Row # + # Ligne + + + + Copy + Copier + + + + Print... + Imprimer... + + + + Show legend + Afficher la légende + + + + Stacked bars + Diagramme à barres empilées + + + + Date/Time + Date/Heure + + + + Date + Date + + + + Time + Heure + + + + + Numeric + Numérique + + + + Label + Label + + + + Invalid + Invalide + + + + Load all data and redraw plot. +Warning: not all data has been fetched from the table yet due to the partial fetch mechanism. + Charger toutes les données et redessiner le tracé. +Attention : toutes les données n'ont pas encore été extraites du tableau en raison du mécanisme d'extraction partielle. + + + + Choose an axis color + Choisir une couleur d'axe + + + + Choose a filename to save under + Choisir un nom de fichier pour enregistrer sous + + + + PNG(*.png);;JPG(*.jpg);;PDF(*.pdf);;BMP(*.bmp);;All Files(*) + PNG(*.png);;JPG(*.jpg);;PDF(*.pdf);;BMP(*.bmp);;All Files(*) + + + + There are curves in this plot and the selected line style can only be applied to graphs sorted by X. Either sort the table or query by X to remove curves or select one of the styles supported by curves: None or Line. + Il y a des courbes dans ce graphique et le style de ligne sélectionné ne peut être appliqué qu'aux graphiques triés par X. Triez la table ou la requête par X pour supprimer les courbes ou sélectionnez un des styles pris en charge par les courbes : Aucun ou Ligne. + + + + Loading all remaining data for this table took %1ms. + Le chargement de toutes les données restantes pour ce tableau a pris %1 ms. + + + + PreferencesDialog + + + Preferences + Préférences + + + + &General + &Général + + + + Remember last location + Se souvenir du dernier emplacement + + + + Always use this location + Toujours utiliser cet emplacement + + + + Remember last location for session only + Dernier emplac. pour cette session uniquement + + + + Lan&guage + Lan&gue + + + + Show remote options + Afficher options Serv. Distant + + + + Automatic &updates + Mises à jour A&utomatiques + + + + &Database + Base de &Données + + + + Database &encoding + &Encodage de la Base de Données + + + + Open databases with foreign keys enabled. + Ouvrir une Base de Données en autorisant les clés étrangères. + + + + &Foreign keys + &Clés étrangères + + + + + + + + + + + + enabled + Autoriser + + + + Default &location + Emp&lacement par défaut + + + + + + ... + ... + + + + Remove line breaks in schema &view + Suppr. les sauts de ligne dans la &vue du schéma + + + + Prefetch block si&ze + &Taille du bloc de préfetch + + + + SQ&L to execute after opening database + Fichier SQ&L à exécuter à l'ouverture +de la Base de Données + + + + Default field type + Type de champ par défaut + + + + Data &Browser + &Navigateur des données + + + + Font + Police + + + + &Font + &Police + + + + Content + Contenu + + + + Symbol limit in cell + Texte : Nb max. de caractères + + + + NULL + NULL + + + + Regular + Standard + + + + Binary + Binaire + + + + Background + Arrière plan + + + + Filters + Filtres + + + + Threshold for completion and calculation on selection + Seuil d'achèvement et calcul lors de la sélection + + + + Show images in cell + Afficher les images dans la cellule + + + + Enable this option to show a preview of BLOBs containing image data in the cells. This can affect the performance of the data browser, however. + Activez cette option pour afficher un aperçu des BLOBs contenant des images dans les cellules. Cela peut toutefois affecter les performances du navigateur de données. + + + + Escape character + Caractère d'échappement + + + + Delay time (&ms) + Délai (&ms) + + + + Set the waiting time before a new filter value is applied. Can be set to 0 for disabling waiting. + Défini le temps d'attente avant qu'une nouvelle valeur de filtre est appliquee. Peut être renseigné à 0 pour supprimer le temps d'attente. + + + + &SQL + &SQL + + + + Settings name + Définir le nom + + + + Context + Contexte + + + + Colour + Couleur + + + + Bold + Gras + + + + Italic + Italique + + + + Underline + Souligné + + + + Keyword + Mot Clé + + + + Function + Fonction + + + + Table + Table + + + + Comment + Commentaire + + + + Identifier + Identifiant + + + + String + Chaîne de caractère + + + + Current line + Ligne courante + + + + SQL &editor font size + &Taille de la police : Éditeur SQL + + + + Tab size + Largeur de tabulation + + + + SQL editor &font + &Police de l'éditeur SQL + + + + Error indicators + Indicateur d'erreur + + + + Hori&zontal tiling + Division hori&zontale + + + + If enabled the SQL code editor and the result table view are shown side by side instead of one over the other. + Si elle est activée, l'éditeur de code SQL et l'affichage du tableau de résultats sont présentés côte à côte au lieu d'être l'un sur l'autre. + + + + Code co&mpletion + Co&mplétion de code + + + + Toolbar style + Style de la barre d'outil + + + + + + + + Only display the icon + Afficher uniquement les icones + + + + + + + + Only display the text + Afficher uniquement le texte + + + + + + + + The text appears beside the icon + Le texte sera affiché à côté des icones + + + + + + + + The text appears under the icon + Le texte sera affiché sous les icones + + + + + + + + Follow the style + Suivre le style + + + + DB file extensions + Extensions de fichiers DB + + + + Manage + Gestion + + + + Main Window + Fenêtre principale + + + + Database Structure + Structure de la Base de Données + + + + Browse Data + Parcourir les données + + + + Execute SQL + Exécuter le SQL + + + + Edit Database Cell + Éditer le contenu d'une cellule de la BdD + + + + When this value is changed, all the other color preferences are also set to matching colors. + Lorsque cette valeur est modifiée, toutes les autres préférences de couleur sont également réglées sur les couleurs correspondantes. + + + + Follow the desktop style + Suit le style du bureau + + + + Dark style + Style sombre + + + + Application style + Style de l'application + + + + This sets the font size for all UI elements which do not have their own font size option. + Définit la taille de la police pour tous les éléments de l'interface utilisateur qui n'ont pas leur propre option de taille de police. + + + + Font size + Taille de police + + + + When enabled, the line breaks in the Schema column of the DB Structure tab, dock and printed output are removed. + Lorsque cette option est activée, les sauts de ligne de la colonne Schéma de l'onglet Structure de la Base de Données, du dock et de la sortie imprimée sont supprimés. + + + + Database structure font size + Taille de la police pour la structure de la Base de Données + + + + Font si&ze + T&aille de police + + + + This is the maximum number of items allowed for some computationally expensive functionalities to be enabled: +Maximum number of rows in a table for enabling the value completion based on current values in the column. +Maximum number of indexes in a selection for calculating sum and average. +Can be set to 0 for disabling the functionalities. + Il s'agit du nombre maximum d'éléments autorisés pour l'activation de certaines fonctionnalités coûteuses en termes de calcul : +Nombre maximal de lignes dans un tableau pour permettre la complétion des valeurs sur la base des valeurs actuelles de la colonne. +Nombre maximum d'index dans une sélection pour le calcul de la somme et de la moyenne. +Peut être fixé à 0 pour la désactivation des fonctionnalités. + + + + This is the maximum number of rows in a table for enabling the value completion based on current values in the column. +Can be set to 0 for disabling completion. + Il s'agit du nombre maximum de lignes dans une table pour permettre la complétion de la valeur en fonction des valeurs actuelles dans la colonne. +Peut être mis à 0 pour désactiver la complétion. + + + + Field display + Affichage des champs + + + + Displayed &text + &Texte affiché + + + + + + + + + Click to set this color + Cliquez pour définir cette couleur + + + + Text color + Couleur de texte + + + + Background color + Couleur d'arrière plan + + + + Preview only (N/A) + Préaffichage uniquement (N/A) + + + + Foreground + Avant Plan + + + + SQL &results font size + Taille police &résultats SQL + + + + &Wrap lines + &Retour à la ligne + + + + Never + Jamais + + + + At word boundaries + Aux limites des mots + + + + At character boundaries + Aux limites des caractères + + + + At whitespace boundaries + Aux limites des espaces + + + + &Quotes for identifiers + &Guillemets pour les identifiants + + + + Choose the quoting mechanism used by the application for identifiers in SQL code. + Choisissez le système de guillemets utilisés par l'application pour les identificateurs dans le code SQL. + + + + "Double quotes" - Standard SQL (recommended) + "Double guillemet" - Standard SQL (recommandé) + + + + `Grave accents` - Traditional MySQL quotes + `Accent Grave` - Guillemets standards MySQL + + + + [Square brackets] - Traditional MS SQL Server quotes + [Crochets] - Guillemets traditionels de MS SQL Server + + + + Keywords in &UPPER CASE + Mots clé en &MAJUSCULES + + + + When set, the SQL keywords are completed in UPPER CASE letters. + Quand cette case est cochée, les mots clé SQL sont transformés en MAJUSCULES. + + + + When set, the SQL code lines that caused errors during the last execution are highlighted and the results frame indicates the error in the background + Lorsque cette option est activée, les lignes de code SQL qui ont causé des erreurs lors de la dernière exécution sont mises en surbrillance et le cadre des résultats indique l'erreur en arrière-plan + + + + Close button on tabs + Bouton de fermeture des onglets + + + + If enabled, SQL editor tabs will have a close button. In any case, you can use the contextual menu or the keyboard shortcut to close them. + Si cette option est activée, les onglets de l'éditeur SQL comporteront un bouton de fermeture. Dans tous les cas, vous pouvez utiliser le menu contextuel ou le raccourci clavier pour les fermer. + + + + &Extensions + E&xtensions + + + + Select extensions to load for every database: + Sélectionner une extension à charger pour toutes les bases de données : + + + + Add extension + Ajouter une extension + + + + Remove extension + Enlever une extension + + + + <html><head/><body><p>While supporting the REGEXP operator SQLite doesn't implement any regular expression<br/>algorithm but calls back the running application. DB Browser for SQLite implements this<br/>algorithm for you to let you use REGEXP out of the box. However, as there are multiple possible<br/>implementations of this and you might want to use another one, you're free to disable the<br/>application's implementation and load your own by using an extension. Requires restart of the application.</p></body></html> + <html><head/><body><p>Bien que SQLite supporte l'opérateur REGEXP, aucun algorithme<br>d'expression régulière est implémenté, mais il rappelle l'application en cours d'exécution. DB Browser pour SQLite implémente<br/>cet algorithme pour vous permettre d'utiliser REGEXP. Cependant, comme il existe plusieurs implémentations possibles<br/>et que vous souhaitez peut-être utiliser autre chose, vous êtes libre de désactiver cette implémentation dans l'application<br/>pour utiliser la votre en utilisant une extension. Cela nécessite le redémarrage de l'application.</p></body></html> + + + + Disable Regular Expression extension + Désactiver l'extention "Expression Régulière" + + + + <html><head/><body><p>SQLite provides an SQL function for loading extensions from a shared library file. Activate this if you want to use the <span style=" font-style:italic;">load_extension()</span> function from SQL code.</p><p>For security reasons, extension loading is turned off by default and must be enabled through this setting. You can always load extensions through the GUI, even though this option is disabled.</p></body></html> + <html><head/><body><p>SQLite fournit une fonction SQL pour charger des extensions à partir d'un fichier de bibliothèque partagé. Activez cette option si vous souhaitez utiliser la fonction <span style=" font-style:italic;">load_extension()</span> depuis el code SQL.</p><p>Pour des raisons de sécurité, le chargement des extensions est désactivé par défaut et doit être activé par ce paramètre. Vous pouvez toujours charger des extensions via l'interface graphique, même si cette option est désactivée.</p></body></html> + + + + Allow loading extensions from SQL code + Autoriser le chargement des extensions depuis le code SQL + + + + Remote + Serveur distant + + + + CA certificates + Certificats CA + + + + Proxy + Proxy + + + + Configure + Configurer + + + + + Subject CN + Sujet CN + + + + Common Name + Nom Commun - CN + + + + Subject O + Sujet O + + + + Organization + Organisation + + + + + Valid from + Valide de + + + + + Valid to + Valide jusqu'à + + + + + Serial number + Numéro de série + + + + Your certificates + Vos certificats + + + + File + Fichier + + + + Subject Common Name + Sujet Common Name + + + + Issuer CN + Émetteur CN + + + + Issuer Common Name + + + + + Clone databases into + Cloner la Base de Données dans + + + + + Choose a directory + Choisir un répertoire + + + + The language will change after you restart the application. + La langue ne changera qu'après le redémarrage de l'application. + + + + Select extension file + Sélectionner un fichier d'extension + + + + Extensions(*.so *.dylib *.dll);;All files(*) + Extensions (*.so *.dylib *.dll);;Tous les fichiers (*) + + + + Import certificate file + Importer un fichier de certificat + + + + No certificates found in this file. + Aucun certificat n'a été trouvé dans ce fichier. + + + + Are you sure you want do remove this certificate? All certificate data will be deleted from the application settings! + Êtes-vous sûr de vouloir supprimer ce certificat ? Toutes les données de ce certificat seront supprimées des paramètres de l'application! + + + + Are you sure you want to clear all the saved settings? +All your preferences will be lost and default values will be used. + Êtes-vous sûr de vouloir effacer tous les réglages sauvegardés ? +Toutes vos préférences seront perdues et les valeurs par défaut seront utilisées. + + + + ProxyDialog + + + Proxy Configuration + Configuration du proxy + + + + Pro&xy Type + Type de Pro&xy + + + + Host Na&me + No&m de l'hôte + + + + Port + Port + + + + Authentication Re&quired + Authentification re&quise + + + + &User Name + Nom &Utilisateur + + + + Password + Mot de Passe + + + + None + Aucun + + + + System settings + Paramètres système + + + + HTTP + HTTP + + + + Socks v5 + Socks v5 + + + + QObject + + + Error importing data + Erreur lors de l'import des données + + + + from record number %1 + pour l'enregistrement numéro %1 + + + + . +%1 + . +%1 + + + + Importing CSV file... + Import du fichier CSV... + + + + Cancel + Annuler + + + + All files (*) + Tous les fichiers (*) + + + + SQLite database files (*.db *.sqlite *.sqlite3 *.db3) + Base de Données SQLite (*.db *.sqlite *.sqlite3 *.db3) + + + + Left + Gauche + + + + Right + Droite + + + + Center + Centré + + + + Justify + Justifié + + + + SQLite Database Files (*.db *.sqlite *.sqlite3 *.db3) + Fichier de BdD SQLite (*.db *.sqlite *.sqlite3 *.db3) + + + + DB Browser for SQLite Project Files (*.sqbpro) + Fichiers projet DB Browser pour SQLite (*.sqbpro) + + + + SQL Files (*.sql) + Fichiers SQL (*.sql) + + + + All Files (*) + Tous les fichiers (*) + + + + Text Files (*.txt) + Fichiers Texte (*.txt) + + + + Comma-Separated Values Files (*.csv) + Valeurs séparées par des virgules (*.csv) + + + + Tab-Separated Values Files (*.tsv) + Valeurs séparées par des tabulations (*.tsv) + + + + Delimiter-Separated Values Files (*.dsv) + Valeurs séparées par des délimiteurs (*.dsv) + + + + Concordance DAT files (*.dat) + Fichiers de Concordance (*.dat) + + + + JSON Files (*.json *.js) + Fichiers JSON (*.json *.js) + + + + XML Files (*.xml) + Fichiers XML (*.xml) + + + + Binary Files (*.bin *.dat) + Fichiers Binaires (*.bin *.dat) + + + + SVG Files (*.svg) + Fichiers SVG (*.svg) + + + + Hex Dump Files (*.dat *.bin) + Fichiers Dump Hexadécimal (*.dat *.bin) + + + + Extensions (*.so *.dylib *.dll) + Extensions (*.so *.dylib *.dll) + + + + RemoteCommitsModel + + + Commit ID + ID de Commit + + + + Message + Message + + + + Date + Date + + + + Author + Auteur + + + + Size + Taille + + + + Authored and committed by %1 + Need to see the context Authored can be translated by "Publié" (published) too as the main author + Créé et validé par %1 + + + + Authored by %1, committed by %2 + Créé par %1, validé par %2 + + + + RemoteDatabase + + + Error opening local databases list. +%1 + Erreur lors de l'ouverture de la liste des bases de données locales. +%1 + + + + Error creating local databases list. +%1 + Erreur lors de la création de la liste des bases de données locales. +%1 + + + + RemoteDock + + + Remote + Serveur Distant + + + + Local + Local + + + + Identity + Identité + + + + Push currently opened database to server + Déplacer la Base de Données en cours sur le serveur + + + + DBHub.io + DBHub.io + + + + <html><head/><body><p>In this pane, remote databases from dbhub.io website can be added to DB Browser for SQLite. First you need an identity:</p><ol style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Login to the dbhub.io website (use your GitHub credentials or whatever you want)</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Click the button to &quot;Generate client certificate&quot; (that's your identity). That'll give you a certificate file (save it to your local disk).</li><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Go to the Remote tab in DB Browser for SQLite Preferences. Click the button to add a new certificate to DB Browser for SQLite and choose the just downloaded certificate file.</li></ol><p>Now the Remote panel shows your identity and you can add remote databases.</p></body></html> + <html><head/><body><p>Dans ce volet, les bases de données distantes du site Web dbhub.io peuvent être ajoutées à DB Browser pour SQLite. Il faut d'abord vous identifier :</p><ol style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Connectez-vous sur le site dbhub.io (utilisez vos identifiants GitHub ou ce que vous voulez)</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Cliquez sur le bouton &quot;Generate client certificate&quot; (c'est votre identité). Cela vous fournira un fichier de certificat (enregistrez-le sur votre disque local).</li><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Allez dans l'onglet Serveur Distant des Préférences DB Browser pour SQLite . Cliquez sur le bouton pour ajouter un nouveau certificat à DB Browser pour SQLite et choisissez le fichier de certificat que vous venez de télécharger.</li></ol><p>Maintenant, le panneau Serveur distant affiche votre identité et vous pouvez ajouter des bases de données distantes..</p></body></html> + + + + Current Database + Base de Données en cours + + + + Clone + Cloner + + + + User + Utilisateur + + + + Database + Base de Données + + + + Branch + Branche + + + + Commits + Commits + + + + Commits for + Commits pour + + + + Delete Database + Supprime la Base de Données + + + + Delete the local clone of this database + Supprime le clone local de la Base de Données + + + + Open in Web Browser + Ouvre dans un navigateur Internet + + + + Open the web page for the current database in your browser + Ouvre la page web de la Base de Données en cours dans votre navigateur + + + + Clone from Link + Cloner depuis un lien + + + + Use this to download a remote database for local editing using a URL as provided on the web page of the database. + Utilisez ceci pour télécharger une Base de Données distante pour l'édiiter localement en utilisant une URL telle que fournie sur la page web de la Base de Données. + + + + Refresh + Rafraichir + + + + Reload all data and update the views + Recherge toutes les données et met à jour les vues + + + + F5 + + + + + Clone Database + Cloner une Base de Données + + + + Open Database + Ouvrir une Base de données + + + + Open the local copy of this database + Ouvrir la copie locale de la Base de Données + + + + Check out Commit + Vérifier le Commit + + + + Download and open this specific commit + Télécharger et ouvrir ce Commit particulier + + + + Check out Latest Commit + Vérifier le dernier Commit + + + + Check out the latest commit of the current branch + Vérifie le dernier Commit de la branche en cours + + + + Save Revision to File + Enregistrer la Révision dans un fichier + + + + Saves the selected revision of the database to another file + Enregistre la Révision sélectionnée de la Base de Données dans un autre fichier + + + + Upload Database + Télécharger la Base de Données + + + + Upload this database as a new commit + Téléchargez cette Base de Données en tant que nouveau Commit + + + + <html><head/><body><p>You are currently using a built-in, read-only identity. For uploading your database, you need to configure and use your DBHub.io account.</p><p>No DBHub.io account yet? <a href="https://dbhub.io/"><span style=" text-decoration: underline; color:#007af4;">Create one now</span></a> and import your certificate <a href="#preferences"><span style=" text-decoration: underline; color:#007af4;">here</span></a> to share your databases.</p><p>For online help visit <a href="https://dbhub.io/about"><span style=" text-decoration: underline; color:#007af4;">here</span></a>.</p></body></html> + <html><head/><body><p>Vous utilisez actuellement une identité intégrée, en lecture seule. Pour télécharger votre Base de Données, vous devez configurer et utiliser votre compte DBHub.io. </p><p>Vous n'avez pas encore de compte DBHub.io ? <a href="https://dbhub.io/"><span style=" text-decoration : underline ; color:#007af4 ;">Créez-en un maintenant</span></a> et importez votre certificat <a href="#preferences"><span style=" text-decoration : underline ; color:#007af4 ;">ici</span></a> pour partager vos bases de données.</p><p>Pour l'aide en ligne, visitez <a href="https://dbhub.io/about"><span style=" text-decoration : underline ; color:#007af4 ;">ici</span></a>.</p></body></html> + + + + Back + Retour + + + + Select an identity to connect + Sélectionner une identité pour se connecter + + + + Public + Public + + + + This downloads a database from a remote server for local editing. +Please enter the URL to clone from. You can generate this URL by +clicking the 'Clone Database in DB4S' button on the web page +of the database. + Cela télécharge une Base de Données à partir d'un serveur distant pour l'éditer localement. +Veuillez entrer l'URL à partir de laquelle vous souhaitez la cloner. Vous pouvez générer cette URL en +en cliquant sur le bouton "Cloner la Base de Données dans DB4S" sur la page web +de la Base de Données. + + + + Invalid URL: The host name does not match the host name of the current identity. + URL invalide : Le nom de l'hôte ne correspond pas au nom de l'hôte de l'identité actuelle. + + + + Invalid URL: No branch name specified. + URL Invalide : Nom de branche non spécifié. + + + + Invalid URL: No commit ID specified. + URL Invalide : Commit ID non spécifié. + + + + You have modified the local clone of the database. Fetching this commit overrides these local changes. +Are you sure you want to proceed? + Vous avez modifié le clone local de la Base de Données. La récupération de ce commit annule ces modifications locales. +Êtes-vous sûr de vouloir continuer ? + + + + The database has unsaved changes. Are you sure you want to push it before saving? + La Base de Données contient des modifications non sauvegardées. Êtes-vous sûr de vouloir la pousser avant de la sauvegarder ? + + + + The database you are trying to delete is currently opened. Please close it before deleting. + La Base de Données que vous essayez de supprimer est actuellement ouverte. Veuillez la fermer avant de la supprimer. + + + + This deletes the local version of this database with all the changes you have not committed yet. Are you sure you want to delete this database? + Cela va supprimer la version locale de cette Base de Données avec tous les changements pour lesquels vous n'avez pas fait de Commit. Êtes-vous sûr de vouloir supprimer cette Base de Données ? + + + + RemoteLocalFilesModel + + + Name + Nom + + + + Branch + Branche + + + + Last modified + Dernière modification + + + + Size + Taille + + + + Commit + Commit + + + + File + Fichier + + + + RemoteModel + + + Name + Nom + + + + Last modified + Dernière modification + + + + Size + Taille + + + + Commit + Commit + + + + Size: + Taille : + + + + Last Modified: + Dernière modification : + + + + Licence: + Licence : + + + + Default Branch: + Branche par défaut : + + + + RemoteNetwork + + + Choose a location to save the file + Choisissez un emplacement pour enregistrer le fichier + + + + Error opening remote file at %1. +%2 + Erreur lors de l'ouverture du fichier distant %1. +%2 + + + + Error: Invalid client certificate specified. + Erreur : Le certificat du client spécifié est invalide. + + + + Please enter the passphrase for this client certificate in order to authenticate. + Pour vous authentifier, veuillez entrer la phrase secrète pour ce certificat client. + + + + Cancel + Annuler + + + + Uploading remote database to +%1 + Téléchargement de la base distante dans +%1 + + + + Downloading remote database from +%1 + Télécharger une Base de Données distante depuis +%1 + + + + + Error: The network is not accessible. + Erreur : le réseau n'est pas accessible. + + + + Error: Cannot open the file for sending. + Erreur : le fichier à envoyer ne peut être ouvert. + + + + RemotePushDialog + + + Push database + Je ne pense pas que Push soir le bon terme. Est-ce que cela fonctionne comme un serveur de version ? + Pousser une basse de données + + + + Database na&me to push to + &Nom de la Base de Données à pousser vers + + + + Commit message + Message de Commit + + + + Database licence + Licence de la Base de Données + + + + Public + Publique + + + + Branch + Branche + + + + Force push + Forcer le "push" + + + + Username + Nom utilisateur + + + + Database will be public. Everyone has read access to it. + La Base de DOnnée sera publique. Tout le monde a un accès en lecture. + + + + Database will be private. Only you have access to it. + La Base de Données est privée. Vous seul y avez accès. + + + + Use with care. This can cause remote commits to be deleted. + A utiliser avec précaution. Cela peut entraîner la suppression des commit distants. + + + + RunSql + + + Execution aborted by user + Exécution annulée par l'utilisateur + + + + , %1 rows affected + , %1 enregistrements affectés + + + + query executed successfully. Took %1ms%2 + Requête exécutée avec succès. Elle a pris %1 ms %2 + + + + executing query + Exécution de la requête + + + + SelectItemsPopup + + + A&vailable + &Disponible + + + + Sele&cted + Sele&ctionné + + + + SqlExecutionArea + + + Form + Formulaire + + + + Find previous match [Shift+F3] + Trouver la correspondance précédente [Maj+F3] + + + + Find previous match with wrapping + Trouver la correspondance précédente avec le modèle + + + + Shift+F3 + Maj+F3 + + + + The found pattern must be a whole word + Le motif trouvé doit être un mot entier + + + + Whole Words + Mots entiers + + + + Text pattern to find considering the checks in this frame + Modèle de texte à trouver en tenant compte des contrôles de ce cadre + + + + Find in editor + Chercher dans l'éditeur + + + + The found pattern must match in letter case + Le motif recherché doit respecter la casse des lettres + + + + Case Sensitive + Sensible à la casse + + + + Find next match [Enter, F3] + Trouver la correspondance suivante [Entrée, F3] + + + + Find next match with wrapping + Trouver la correspondance suivante avec le modèle + + + + F3 + + + + + Interpret search pattern as a regular expression + Interpréter le modèle de recherche comme une expression régulière + + + + <html><head/><body><p>When checked, the pattern to find is interpreted as a UNIX regular expression. See <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>.</p></body></html> + <html><head/><body><p>Lorsqu'elle est cochée, le motif à trouver est interprété comme une expression régulière UNIX. Voir <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>.</p></body></html> + + + + Regular Expression + Expression régulière + + + + + Close Find Bar + Fremer la barre de recherche + + + + <html><head/><body><p>Results of the last executed statements.</p><p>You may want to collapse this panel and use the <span style=" font-style:italic;">SQL Log</span> dock with <span style=" font-style:italic;">User</span> selection instead.</p></body></html> + <html><head/><body><p>Résultats des derniers traitements exécutées.</p><p>Vous pouvez réduire ce panneau et utiliser le <span style=" font-style:italic ;">dock SQL Log</span> avec la sélection de l'<span style=" font-style:italic ;">utilisateur</span> à la place.</p></body></html> + + + + Results of the last executed statements + Résultats du dernier traitement exécuté + + + + This field shows the results and status codes of the last executed statements. + Ce champ affiche les résultats et les codes de statut du dernier traitement exécuté. + + + + Couldn't read file: %1. + Le fichier %1 ne peut être lu. + + + + + Couldn't save file: %1. + Le fichier %1 ne peut être sauvegardé. + + + + Your changes will be lost when reloading it! + Vos modifications seront perdues lors du rechargement ! + + + + The file "%1" was modified by another program. Do you want to reload it?%2 + Le fichier "%1" a été modifié par un autre programme. Vioulez-vous le recharger ? %2 + + + + SqlTextEdit + + + Ctrl+/ + + + + + SqlUiLexer + + + (X) The abs(X) function returns the absolute value of the numeric argument X. + (X) La fonction abs(X) renvoie la valeur absolue de l'argument numérique X. + + + + () The changes() function returns the number of database rows that were changed or inserted or deleted by the most recently completed INSERT, DELETE, or UPDATE statement. + () La fonction changes() renvoie le nombre de lignes de la Base de Données qui ont été modifiées, insérées ou supprimées par les instructions UPDATE, INSERT ou DELETE terminées dernièrement. + + + + (X1,X2,...) The char(X1,X2,...,XN) function returns a string composed of characters having the unicode code point values of integers X1 through XN, respectively. + (X1, X2,...) La fonction char(X1,X2,...,XN) renvoie une chaîne composée des caractères ayant les valeurs des points de code unicode des entiers allant de X1 à XN, respectivement. + + + + (X,Y,...) The coalesce() function returns a copy of its first non-NULL argument, or NULL if all arguments are NULL + (X, Y, ...) La fonction coalesce () renvoie une copie de son premier argument non-NULL, ou NULL si tous les arguments sont NULL + + + + (X,Y) The glob(X,Y) function is equivalent to the expression "Y GLOB X". + (X, Y) La fonction glob (X, Y) est équivalente à l'expression « Y GLOB X ». + + + + (X,Y) The ifnull() function returns a copy of its first non-NULL argument, or NULL if both arguments are NULL. + (X, Y) La fonction ifnull () renvoie une copie de son premier argument non-NULL, ou NULL si les deux arguments sont NULL. + + + + (X,Y) The instr(X,Y) function finds the first occurrence of string Y within string X and returns the number of prior characters plus 1, or 0 if Y is nowhere found within X. + (X, Y) La fonction instr (X, Y) trouve la première occurrence de la chaîne Y dans la chaîne X. Elle renvoie le nombre de caractères précédents plus 1 ou 0 si Y n'est pas dans X. + + + + (X) The hex() function interprets its argument as a BLOB and returns a string which is the upper-case hexadecimal rendering of the content of that blob. + (X) La fonction hex () interprète son argument comme un BLOB et renvoie une chaîne qui est le rendu hexadécimal en majuscules du contenu de ce blob. + + + + () The last_insert_rowid() function returns the ROWID of the last row insert from the database connection which invoked the function. + () La fonction last_insert_rowid () renvoie le ROWID de la dernière ligne insérée par la connexion de la Base de Données qui a invoqué la fonction. + + + + (X) For a string value X, the length(X) function returns the number of characters (not bytes) in X prior to the first NUL character. + (X) Pour une valeur de chaîne X, la fonction length(X) renvoie le nombre de caractères (pas d'octets) dans X avant le premier caractère NULL. + + + + (X,Y) The like() function is used to implement the "Y LIKE X" expression. + (X, Y) La fonction like() est utilisée pour mettre en Å“uvre de l’expression « Y LIKE X ». + + + + (X,Y,Z) The like() function is used to implement the "Y LIKE X ESCAPE Z" expression. + (X, Y, Z) La fonction like() est utilisée pour mettre en Å“uvre de l’expression « Y LIKE X ESCAPE Z ». + + + + (X) The load_extension(X) function loads SQLite extensions out of the shared library file named X. +Use of this function must be authorized from Preferences. + (X) La fonction load_extension(X) charge les extensions SQLite à partir du fichier de bibliothèque partagé nommé X. +L'utilisation de cette fonction doit être autorisée à partir des Préférences. + + + + (X,Y) The load_extension(X) function loads SQLite extensions out of the shared library file named X using the entry point Y. +Use of this function must be authorized from Preferences. + (X,Y) La fonction load_extension(X) charge les extensions SQLite à partir du fichier de bibliothèque partagée nommé X en utilisant le point d'entrée Y. +L'utilisation de cette fonction doit être autorisée à partir des Préférences. + + + + (X) The lower(X) function returns a copy of string X with all ASCII characters converted to lower case. + (X) La fonction lower(X) renvoie une copie de la chaîne X avec tous ses caractères ASCII convertis en minuscules. + + + + (X) ltrim(X) removes spaces from the left side of X. + (X) ltrim(X) supprime les espaces gauche de X. + + + + (X,Y) The ltrim(X,Y) function returns a string formed by removing any and all characters that appear in Y from the left side of X. + (X, Y) La fonction ltrim(X,Y) renvoie une chaîne résultant de la suppression de tous les caractères qui apparaissent en Y à gauche de X. + + + + (X,Y,...) The multi-argument max() function returns the argument with the maximum value, or return NULL if any argument is NULL. + (X,Y,...) La fonction à arguments multiples max() renvoie l'argument ayant la plus grande valeur ou renvoie NULL si tous les arguments sont NULL. + + + + (X,Y,...) The multi-argument min() function returns the argument with the minimum value. + (X,Y,...) La fonction à arguments multiples min() renvoie l'argument ayant la plus petite valeur. + + + + (X,Y) The nullif(X,Y) function returns its first argument if the arguments are different and NULL if the arguments are the same. + (X, Y) La fonction nullif(X,Y) renvoie le premier argument, si les arguments sont différents et NULL si les X et Y sont les mêmes. + + + + (FORMAT,...) The printf(FORMAT,...) SQL function works like the sqlite3_mprintf() C-language function and the printf() function from the standard C library. + (FORMAT,...) La fonction SQL printf(FORMAT,...) fonctionne comme la fonction de sqlite3_mprintf() en langage C et la fonction printf() de la bibliothèque C standard. + + + + (X) The quote(X) function returns the text of an SQL literal which is the value of its argument suitable for inclusion into an SQL statement. + (X) La fonction quote(X) renvoie le texte d’un litéral SQL qui est la valeur appropriée de l’argument pour son inclusion dans une requête SQL. + + + + () The random() function returns a pseudo-random integer between -9223372036854775808 and +9223372036854775807. + () La fonction random() renvoie un nombre entier pseudo-aléatoire entre -9223372036854775808 et + 9223372036854775807. + + + + (N) The randomblob(N) function return an N-byte blob containing pseudo-random bytes. + (N) La fonction randomblob(N) renvoie un blob de N octets contenant des octets pseudo-aléatoires. + + + + (X,Y,Z) The replace(X,Y,Z) function returns a string formed by substituting string Z for every occurrence of string Y in string X. + (X, Y, Z) La fonction replace(X,Y,Z) renvoie une chaîne formée en substituant par la chaîne Z chaque occurrence de la chaîne Y présente dans la chaîne X. + + + + (X) The round(X) function returns a floating-point value X rounded to zero digits to the right of the decimal point. + (X) La fonction round(X) renvoie une valeur à virgule flottante X arrondie à zéro chiffres à droite de la virgule décimale. + + + + (X,Y) The round(X,Y) function returns a floating-point value X rounded to Y digits to the right of the decimal point. + (X, Y) La fonction round(X,Y) renvoie une valeur à virgule flottante X arrondie à Y chiffres à droite de la virgule décimale. + + + + (X) rtrim(X) removes spaces from the right side of X. + X) rtrim(X) supprime les espaces droite de X. + + + + (X,Y) The rtrim(X,Y) function returns a string formed by removing any and all characters that appear in Y from the right side of X. + (X, Y) La fonction rtrim(X,Y) renvoie une chaîne formée en supprimant tous les caractères qui apparaissent en Y, à droite de X. + + + + (X) The soundex(X) function returns a string that is the soundex encoding of the string X. + (X) La fonction soundex(X) renvoie une chaîne qui est l'encodage soundex de la chaîne X. + + + + (X,Y) substr(X,Y) returns all characters through the end of the string X beginning with the Y-th. + (X, Y) substr(X,Y) renvoie tous les caractères à partir du n-ième Y jusqu'à la fin de la chaîne X. + + + + (X,Y,Z) The substr(X,Y,Z) function returns a substring of input string X that begins with the Y-th character and which is Z characters long. + (X, Y, Z) La fonction substr(X,Y,Z) renvoie une sous-chaîne de la chaîne X à partie du n-ième caractère Y, de longueur Z. + + + + () The total_changes() function returns the number of row changes caused by INSERT, UPDATE or DELETE statements since the current database connection was opened. + () La fonction total_changes() renvoie le nombre d'enregistrements altérés par les instructions INSERT, UPDATE ou DELETE depuis l’ouverture de la connexion de Base de Données courante. + + + + (X) trim(X) removes spaces from both ends of X. + (X) trim(X) supprime les espaces aux deux extrémités de X. + + + + (X,Y) The trim(X,Y) function returns a string formed by removing any and all characters that appear in Y from both ends of X. + (X, Y) La fonction trim(X,Y) renvoie une chaîne formée en supprimant tous les caractères de Y présents aux deux extrémités de X. + + + + (X) The typeof(X) function returns a string that indicates the datatype of the expression X. + (X) La fonction typeof(X) renvoie une chaîne qui indique le type de données de l’expression X. + + + + (X) The unicode(X) function returns the numeric unicode code point corresponding to the first character of the string X. + (X) La fonction unicode(X) renvoie le point de code unicode numérique correspondant au premier caractère de la chaîne X. + + + + (X) The upper(X) function returns a copy of input string X in which all lower-case ASCII characters are converted to their upper-case equivalent. + (X) La fonction upper(X) renvoie une copie de la chaîne X dans laquel tous les caractères ASCII en minuscules sont convertis en leurs équivalents en majuscules. + + + + (N) The zeroblob(N) function returns a BLOB consisting of N bytes of 0x00. + (N) La fonction zeroblob(N) renvoie un BLOB composé de N octets de valeur 0x00. + + + + + + + (timestring,modifier,modifier,...) + (timestring,modifier,modifier,...) + + + + (format,timestring,modifier,modifier,...) + (format,timestring,modifier,modifier,...) + + + + (X) The avg() function returns the average value of all non-NULL X within a group. + (X) La fonction avg() renvoie la valeur moyenne de tous les X non-NULL dans d’un groupe. + + + + (X) The count(X) function returns a count of the number of times that X is not NULL in a group. + (X) La fonction count(X) renvoie le nombre de fois où X n’est pas NULL dans un groupe. + + + + (X) The group_concat() function returns a string which is the concatenation of all non-NULL values of X. + (X) la fonction group_concat() renvoie une chaîne qui est la concaténation de toutes les valeurs non-NULL de X. + + + + (X,Y) The group_concat() function returns a string which is the concatenation of all non-NULL values of X. If parameter Y is present then it is used as the separator between instances of X. + (X, Y) La fonction group_concat() renvoie une chaîne qui est la concaténation de toutes les valeurs non-NULL de X. Si le paramètre Y est présent, il est utilisé comme séparateur entre chaque instances de X. + + + + (X) The max() aggregate function returns the maximum value of all values in the group. + (X) La fonction d’agrégat max() renvoie la valeur maximale de toutes les valeurs du groupe. + + + + (X) The min() aggregate function returns the minimum non-NULL value of all values in the group. + (X) La fonction d’agrégation min() renvoie la valeur non-NULL minimale de toutes les valeurs du groupe. + + + + + (X) The sum() and total() aggregate functions return sum of all non-NULL values in the group. + (X) Les fonctions d'agrégation sum() et total() renvoient la somme de toutes les valeurs non-NULL du groupe. + + + + () The number of the row within the current partition. Rows are numbered starting from 1 in the order defined by the ORDER BY clause in the window definition, or in arbitrary order otherwise. + () Le numéro del'enregistrement dans la partition courante. Les lignes sont numérotées à partir de 1 dans l'ordre défini par la clause ORDER BY dans la définition de la fenêtre, ou, sinon, dans un ordre arbitraire. + + + + () The row_number() of the first peer in each group - the rank of the current row with gaps. If there is no ORDER BY clause, then all rows are considered peers and this function always returns 1. + () Le row_number() enregistrement homologue de chaque groupe - le rang de l'enregistrement courant avec les écarts. S'il n'y a pas de clause ORDER BY, alors tous les enregistrements sont considérées comme homologues et cette fonction renvoie toujours 1. + + + + () The number of the current row's peer group within its partition - the rank of the current row without gaps. Partitions are numbered starting from 1 in the order defined by the ORDER BY clause in the window definition. If there is no ORDER BY clause, then all rows are considered peers and this function always returns 1. + () Le numéro du groupe d'enregistrements homologues de la rangée courante dans sa partition - le rang de la rangée courante sans espaces. Les partitions sont numérotées à partir de 1 dans l'ordre défini par la clause ORDER BY dans la définition de la fenêtre. S'il n'y a pas de clause ORDER BY, alors toutes les lignes sont considérées comme homologues et cette fonction renvoie toujours 1. + + + + () Despite the name, this function always returns a value between 0.0 and 1.0 equal to (rank - 1)/(partition-rows - 1), where rank is the value returned by built-in window function rank() and partition-rows is the total number of rows in the partition. If the partition contains only one row, this function returns 0.0. + () Malgré le nom, cette fonction retourne toujours une valeur comprise entre 0.0 et 1.0 égale à (rang - 1)/(rangées de partitions - 1), où rang est la valeur retournée par la fonction de fenêtre intégrée rank() et rangées de partitions est le nombre total de rangées dans la partition. Si la partition ne contient qu'une seule ligne, cette fonction renvoie 0.0. + + + + () The cumulative distribution. Calculated as row-number/partition-rows, where row-number is the value returned by row_number() for the last peer in the group and partition-rows the number of rows in the partition. + () Répartition cumulée. Calculée en tant que ligne-numéro/rangées-partition, où ligne-numéro est la valeur retournée par row_number() pour le dernier homologue dans le groupe et ligne-partition le nombre de lignes dans la partition. + + + + (N) Argument N is handled as an integer. This function divides the partition into N groups as evenly as possible and assigns an integer between 1 and N to each group, in the order defined by the ORDER BY clause, or in arbitrary order otherwise. If necessary, larger groups occur first. This function returns the integer value assigned to the group that the current row is a part of. + (N) L'argument N est traité comme un entier. Cette fonction divise la partition en N groupes le plus uniformément possible et attribue un entier compris entre 1 et N à chaque groupe, dans l'ordre défini par la clause ORDER BY, ou, sinon, dans un ordre arbitraire. Si nécessaire, les plus grands groupes se forment en premier. Cette fonction retourne la valeur entière assignée au groupe dont la ligne courante fait partie. + + + + (expr) Returns the result of evaluating expression expr against the previous row in the partition. Or, if there is no previous row (because the current row is the first), NULL. + (expr) Retourne le résultat de l'évaluation de l'expression expr par rapport à la ligne précédente de la partition. Ou NULL s'il n'y a pas de ligne précédente (parce que la ligne courante est la première). + + + + (expr,offset) If the offset argument is provided, then it must be a non-negative integer. In this case the value returned is the result of evaluating expr against the row offset rows before the current row within the partition. If offset is 0, then expr is evaluated against the current row. If there is no row offset rows before the current row, NULL is returned. + (expr,offset) Si l'argument offset est fourni, alors il doit être un entier non négatif. Dans ce cas, la valeur retournée est le résultat de l'évaluation de expr par rapport au décalage des lignes avant la ligne courante dans la partition. Si l'offset est égal à 0, alors expr est évalué par rapport à la ligne courante. S'il n'y a pas de lignes de décalage de ligne avant la ligne courante, NULL est retourné. + + + + + (expr,offset,default) If default is also provided, then it is returned instead of NULL if the row identified by offset does not exist. + (expr,offset,default) Si la valeur par défaut est aussi renseignée, cette valeur sera retournée au lieu de NULL si la ligne identifiée par offset n'existe pas. + + + + (expr) Returns the result of evaluating expression expr against the next row in the partition. Or, if there is no next row (because the current row is the last), NULL. + (expr) Retourne le résultat de l'évaluation de l'expression expr par rapport à la ligne suivante de la partition. Ou NULL s'il n'y a pas de ligne suivante (parce que la ligne courante est la dernière). + + + + (expr,offset) If the offset argument is provided, then it must be a non-negative integer. In this case the value returned is the result of evaluating expr against the row offset rows after the current row within the partition. If offset is 0, then expr is evaluated against the current row. If there is no row offset rows after the current row, NULL is returned. + (expr,offset) Si l'argument offset est fourni, alors il doit être un entier non négatif. Dans ce cas, la valeur retournée est le résultat de l'évaluation de expr par rapport par rapport au décalage des lignes après la ligne courante dans la partition. Si l'offset est égal à 0, alors expr est évalué par rapport à la ligne courante. S'il n'y a pas de lignes de décalage de ligne après la ligne courante, NULL est retourné. + + + + (expr) This built-in window function calculates the window frame for each row in the same way as an aggregate window function. It returns the value of expr evaluated against the first row in the window frame for each row. + (expr) Cette fonction de fenêtrage intégrée calcule le cadre de la fenêtre pour chaque rangée de la même manière qu'une fonction de fenêtrage agrégée. Elle retourne la valeur de expr évaluée par rapport à la première ligne du cadre de la fenêtre pour chaque ligne. + + + + (expr) This built-in window function calculates the window frame for each row in the same way as an aggregate window function. It returns the value of expr evaluated against the last row in the window frame for each row. + (expr) Cette fonction de fenêtrage intégrée calcule le cadre de la fenêtre pour chaque rangée de la même manière qu'une fonction de fenêtrage agrégée. Elle retourne la valeur de expr évaluée par rapport à la dernière ligne du cadre de la fenêtre pour chaque ligne. + + + + (expr,N) This built-in window function calculates the window frame for each row in the same way as an aggregate window function. It returns the value of expr evaluated against the row N of the window frame. Rows are numbered within the window frame starting from 1 in the order defined by the ORDER BY clause if one is present, or in arbitrary order otherwise. If there is no Nth row in the partition, then NULL is returned. + (expr,N) Cette fonction de fenêtrage intégrée calcule le cadre de la fenêtre pour chaque rangée de la même manière qu'une fonction de fenêtrage agrégée. Elle retourne la valeur de expr évaluée par rapport à la ligne N du cadre de la fenêtre. Les rangées sont numérotées à l'intérieur du cadre de la fenêtre à partir de 1 dans l'ordre défini par la clause ORDER BY si elle est présente, ou dans un ordre arbitraire sinon. S'il n'y a pas de Nième ligne dans la partition, alors NULL est retourné. + + + + SqliteTableModel + + + reading rows + Lecture des enregistrements + + + + loading... + chargement... + + + + References %1(%2) +Hold %3Shift and click to jump there + Références %1(%2) +Appuyez simultanément sur %3+Maj et cliquez pour arriver ici + + + + Error changing data: +%1 + Erreur lors du changement des données : +%1 + + + + retrieving list of columns + récupération de la liste des colonnes + + + + Fetching data... + Récupération des données... + + + + + Cancel + Annuler + + + + TableBrowser + + + Browse Data + Parcourir les données + + + + &Table: + &Table : + + + + Select a table to browse data + Sélectionner une table pour parcourir son contenu + + + + Use this list to select a table to be displayed in the database view + Utiliser cette liste pour sélectionner la table à afficher dans la vue Base de Données + + + + This is the database table view. You can do the following actions: + - Start writing for editing inline the value. + - Double-click any record to edit its contents in the cell editor window. + - Alt+Del for deleting the cell content to NULL. + - Ctrl+" for duplicating the current record. + - Ctrl+' for copying the value from the cell above. + - Standard selection and copy/paste operations. + Ceci est la vue des tables de la Base de Données. Vous pouvez effectuer les actions suivantes : + - Commencez à écrire pour éditer en ligne la valeur. + - Double-cliquez sur n'importe quel enregistrement pour éditer son contenu dans la fenêtre de l'éditeur de cellule. + - Alt+Supp pour supprimer le contenu de la cellule et la met à NULL. + - Ctrl+" pour dupliquer l'enregistrement en cours. + - Ctrl+' pour copier la valeur de la cellule ci-dessus. + - Sélection standard et opérations de copier/coller. + + + + Text pattern to find considering the checks in this frame + Modèle de texte à trouver en tenant compte des contrôles de ce cadre + + + + Find in table + Chercher dans la table + + + + Find previous match [Shift+F3] + Trouver la correspondance précédente [Maj+F3] + + + + Find previous match with wrapping + Trouver la correspondance précédente avec le modèle + + + + Shift+F3 + Maj+F3 + + + + Find next match [Enter, F3] + Trouver la correspondance suivante [Entrée, F3] + + + + Find next match with wrapping + Trouver la correspondance suivante avec le modèle + + + + F3 + + + + + The found pattern must match in letter case + Le motif recherché doit respecter la casse des lettres + + + + Case Sensitive + Sensible à la casse + + + + The found pattern must be a whole word + Le motif trouvé doit être un mot entier + + + + Whole Cell + Ensemble de la cellule + + + + Interpret search pattern as a regular expression + Interpréter le modèle de recherche comme une expression régulière + + + + <html><head/><body><p>When checked, the pattern to find is interpreted as a UNIX regular expression. See <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>.</p></body></html> + <html><head/><body><p>Lorsque cette case est cochée, le motif à trouver est interprété comme une expression régulière UNIX. Voir <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>.</p></body></html> + + + + Regular Expression + Expression régulière + + + + + Close Find Bar + Fremer la barre de recherche + + + + Text to replace with + Texte à remplacer par + + + + Replace with + Remplacer par + + + + Replace next match + Remplacer la prochaine correspondance + + + + + Replace + Remplacer + + + + Replace all matches + Remplacer toutes les correspondances + + + + Replace all + Remplacer tout + + + + <html><head/><body><p>Scroll to the beginning</p></body></html> + <html><head/><body><p>Aller au début</p></body></html> + + + + <html><head/><body><p>Clicking this button navigates to the beginning in the table view above.</p></body></html> + <html><head/><body><p>Cliquer sur ce bouton permet d'aller au début de la table ci-dessus.</p></body></html> + + + + |< + |< + + + + Scroll one page upwards + Remonter d'une page + + + + <html><head/><body><p>Clicking this button navigates one page of records upwards in the table view above.</p></body></html> + <html><head/><body><p>Cliquer sur ce bouton permet d'afficher la page précédente des enregistrements de la table ci dessus.</p></body></html> + + + + < + < + + + + 0 - 0 of 0 + 0 - 0 de 0 + + + + Scroll one page downwards + Descendre d'une page + + + + <html><head/><body><p>Clicking this button navigates one page of records downwards in the table view above.</p></body></html> + <html><head/><body><p>Cliquer sur ce bouton permet d'afficher la page suivante des enregistrements de la table ci dessus.</p></body></html> + + + + > + > + + + + Scroll to the end + Aller à la fin + + + + <html><head/><body><p>Clicking this button navigates up to the end in the table view above.</p></body></html> + <html><head/><body><p>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Cliquer sur ce bouton permet d'aller à la fin de la table ci-dessus.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</p></body></html> + + + + >| + >| + + + + <html><head/><body><p>Click here to jump to the specified record</p></body></html> + <html><head/><body><p>Cliquer ici pour vous déplacer sur l'enregistrement indiqué</p></body></html> + + + + <html><head/><body><p>This button is used to navigate to the record number specified in the Go to area.</p></body></html> + <html><head/><body><p>Ce bouton est utilisé pour aller directement à l'enregistrement indiqué dans le champ Aller à.</p></body></html> + + + + Go to: + Aller à : + + + + Enter record number to browse + Entrez le nombre d'enregistrements à parcourir + + + + Type a record number in this area and click the Go to: button to display the record in the database view + Entrez un numéro d'enregistrement dans ce champ et cliquez sur le bouton "Aller à" pour afficher l'enregistrement dans la vue Base de Données + + + + 1 + 1 + + + + Show rowid column + Afficher la colonne RowId + + + + Toggle the visibility of the rowid column + Permet d'afficher ou non la colonne RowId + + + + Unlock view editing + Dévérouiller l'éditeur de vues + + + + This unlocks the current view for editing. However, you will need appropriate triggers for editing. + Permet de dévérouiller la vue courante pour l'éditer. Cependant, vous aurez besoin de déclencheurs appropriés pour faire cela. + + + + Edit display format + Modifier le format d'affichage + + + + Edit the display format of the data in this column + Modifie le format d'affichage des données contenues dans cette colonne + + + + + New Record + Nouvel Enregistrement + + + + + Insert a new record in the current table + Insérer un nouvel enregistrement dans la table en cours + + + + <html><head/><body><p>This button creates a new record in the database. Hold the mouse button to open a pop-up menu of different options:</p><ul><li><span style=" font-weight:600;">New Record</span>: insert a new record with default values in the database.</li><li><span style=" font-weight:600;">Insert Values...</span>: open a dialog for entering values before they are inserted in the database. This allows to enter values acomplishing the different constraints. This dialog is also open if the <span style=" font-weight:600;">New Record</span> option fails due to these constraints.</li></ul></body></html> + <html><head/><body><p>Ce bouton crée un nouvel enregistrement dans la Base de Données. Maintenez le bouton de la souris enfoncé pour ouvrir un menu contextuel de différentes options :</p><ul><li><span style=" font-weight:600;">Nouvel Enregistrement</span> : Insère un nouvel enregistrement avec les valeurs par défaut dans la Base de Données.</li><li><span style=" font-weight:600;">Insérer des valeurs...</span> : ouvre une boite de dialogue pour saisir des valeurs avant leur insersion dans la Base de Données. Ceci permet de saisir des valeurs correspondant aux différentes contraintes. Cette boîte de dialogue est également ouverte si l'option <span style=" font-weight:600;">Nouvel Enregistrement </span> est en erreur à cause de ces contraintes.</li></ul></body></html> + + + + + Delete Record + Supprimer l'enregistrement + + + + Delete the current record + Supprimer l'enregistrement courant + + + + + This button deletes the record or records currently selected in the table + Ce bouton permet de supprimer l'enregistrement sélectionné dans la table + + + + + Insert new record using default values in browsed table + Insérer un nouvel enregistrement en utilisant les valeurs par défaut de la table parcourrue + + + + Insert Values... + Ajouter des valeurs... + + + + + Open a dialog for inserting values in a new record + Ouvre une fenêtre de dialogue permettant l'insersion de valeurs dans un nouvel enregistrement + + + + Export to &CSV + Exporter au format &CSV + + + + + Export the filtered data to CSV + Exporte les données filtrées au format CSV + + + + This button exports the data of the browsed table as currently displayed (after filters, display formats and order column) as a CSV file. + Ce bouton exporte les données de la table parcourue telles qu'elles sont actuellement affichées (après les filtres, les formats d'affichage et la colonne d'ordre) dans un fichier CSV. + + + + Save as &view + Enregistrer comme une &vue + + + + + Save the current filter, sort column and display formats as a view + Enregistrer le filtre, la colonne de tri et les formats d'affichage actuels sous la forme d'une vue + + + + This button saves the current setting of the browsed table (filters, display formats and order column) as an SQL view that you can later browse or use in SQL statements. + Ce bouton permet d'enregistrer les paramètres actuels de la table parcourue (filtres, formats d'affichage et colonne d'ordre) sous forme de vue SQL que vous pourrez ensuite parcourir ou utiliser dans les instructions SQL. + + + + Save Table As... + Enregistrer la table sous... + + + + + Save the table as currently displayed + Enregistrer la table comme affichée actuellement + + + + <html><head/><body><p>This popup menu provides the following options applying to the currently browsed and filtered table:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Export to CSV: this option exports the data of the browsed table as currently displayed (after filters, display formats and order column) to a CSV file.</li><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Save as view: this option saves the current setting of the browsed table (filters, display formats and order column) as an SQL view that you can later browse or use in SQL statements.</li></ul></body></html> + <html><head/><body><p>Ce menu déroulant fournit les options suivantes s'appliquant à la table actuellement parcourue et filtrée:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Exporter au format CSV : cette option exporte les données de la table parcourue telles qu'elles sont actuellement affichées (après filtres, formats d'affichage et colonne d'ordre) vers un fichier CSV.</li><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Enregistrer comme vue : cette option permet d'enregistrer les paramètres actuels de la table parcourue (filtres, formats d'affichage et colonne d'ordre) dans une vue SQL que vous pourrez ensuite parcourir ou utiliser dans les instructions SQL.</li></ul></body></html> + + + + Hide column(s) + Masquer une/des colonnes + + + + Hide selected column(s) + Maquer la/les colonnes sélectionnées + + + + Show all columns + Afficher toutes les colonnes + + + + Show all columns that were hidden + Permet d'afficher toutes les colonnes qui ont été masquées + + + + + Set encoding + Définir l'encodage + + + + Change the encoding of the text in the table cells + Change l'encodage du texte des cellules de la table + + + + Set encoding for all tables + Définir l'encodage pour toutes les tables + + + + Change the default encoding assumed for all tables in the database + Change l'encodage par défaut choisi pour l'ensemble des tables de la Base de Données + + + + Clear Filters + Effacer les filtres + + + + Clear all filters + Effacer tous les filtres + + + + + This button clears all the filters set in the header input fields for the currently browsed table. + Ce bouton efface tous les filtres définis dans les champs de saisie de l'en-tête de la table actuellement parcourue. + + + + Clear Sorting + Effacer le tri + + + + Reset the order of rows to the default + Rétablit l'ordre des lignes aux valeurs par défaut + + + + + This button clears the sorting columns specified for the currently browsed table and returns to the default order. + Ce bouton efface les critères de tri définis pour les colonnes de la table actuellement parcourue et revient à l'ordre par défaut. + + + + Print + Imprimer + + + + Print currently browsed table data + Imprimer le données de la table actuellement parcourues + + + + Print currently browsed table data. Print selection if more than one cell is selected. + Imprimer le données de la table actuellement parcourues. Imprime la sélection si plus d'une cellule est sélectionnée. + + + + Ctrl+P + + + + + Refresh + Rafraichir + + + + Refresh the data in the selected table + Rafraîchir les données de la table sélectionnée + + + + This button refreshes the data in the currently selected table. + Ce bouton permet de rafraîchir les données de la table actuellement sélectionnée. + + + + F5 + + + + + Find in cells + Rechercher dans les cellules + + + + Open the find tool bar which allows you to search for values in the table view below. + Ouvre la barre d'outils de recherche qui vous permet de rechercher des valeurs dans la table ci-dessous. + + + + + Bold + Gras + + + + Ctrl+B + + + + + + Italic + Italique + + + + + Underline + Souligné + + + + Ctrl+U + + + + + + Align Right + Aligrer à Droite + + + + + Align Left + Aligner à Gauche + + + + + Center Horizontally + Centrer Horizontalement + + + + + Justify + Justifié + + + + + Edit Conditional Formats... + Éditer les formats conditionnels... + + + + Edit conditional formats for the current column + Éditer les formats conditionnels de la colonne en cours + + + + Clear Format + Effacer les Formats + + + + Clear All Formats + Effacer tous les Formats + + + + + Clear all cell formatting from selected cells and all conditional formats from selected columns + Effacr tous les formats de cellule des cellules sélectionnées et tous les formats conditionnels des colonnes sélectionnées + + + + + Font Color + Couleur de Police + + + + + Background Color + Couleur d'arrière plan + + + + Toggle Format Toolbar + Changer le format de lma barre d'outils + + + + Show/hide format toolbar + Afficher/Cacher la barre des formats + + + + + This button shows or hides the formatting toolbar of the Data Browser + Ce bouton permet d'afficher ou de masquer la barre d'outils de formatage du navigateur de données + + + + Select column + Sélectionner une colonne + + + + Ctrl+Space + Ctrl+Espace + + + + Replace text in cells + Remplace du texte dans les cellules + + + + Filter in any column + Filtrer dans n'importe quelle colonne + + + + Ctrl+R + + + + + %n row(s) + + %n ligne + %n lignes + + + + + , %n column(s) + + , %n colonne + , %n colonnes + + + + + . Sum: %1; Average: %2; Min: %3; Max: %4 + . Somme: %1; Moyenne: %2; Min: %3; Max: %4 + + + + Conditional formats for "%1" + Format conditionnel pour "%1" + + + + determining row count... + Détermination du nombre d'enregistrements... + + + + %1 - %2 of >= %3 + %1 - %2 de >= %3 + + + + %1 - %2 of %3 + %1 - %2 de %3 + + + + Please enter a pseudo-primary key in order to enable editing on this view. This should be the name of a unique column in the view. + Veuillez entrer une pseudo clé primaire pour permettre l'édition de la vue. Ce devrait être le nom d'une colonne unique dans la vue. + + + + Delete Records + Supprimer les enregistrements + + + + Duplicate records + Enregistrement en double + + + + Duplicate record + Dupliquer l'enregistrement + + + + Ctrl+" + + + + + Adjust rows to contents + Ajuster les lignes au contenu + + + + Error deleting record: +%1 + Erreur dans la suppression d'un enregistrement : +%1 + + + + Please select a record first + Veuillez sélectionner au préalable un enregistrement + + + + There is no filter set for this table. View will not be created. + Il n'existe pas de filtre pour cette table. La vue ne sera pas créée. + + + + Please choose a new encoding for all tables. + Veuillez choisir un nouvel encodage pour toutes les tables. + + + + Please choose a new encoding for this table. + Veuillez choisir un nouvel encodage pour cette table. + + + + %1 +Leave the field empty for using the database encoding. + %1 +Laissez le champ vide pour utiliser l'encodage de la Base de Données. + + + + This encoding is either not valid or not supported. + Cet encodage est invalide ou non supporté. + + + + %1 replacement(s) made. + %1 remplacement(s) effectué(s). + + + + VacuumDialog + + + Compact Database + Compacter la Base de Données + + + + Warning: Compacting the database will commit all of your changes. + Attention : compacter la base de donnée entraînera l'enregistrement de tous les changements effectués. + + + + Please select the databases to co&mpact: + Veuillez saisir le nom de la Base de Données à co&mpacter : + + + diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/translations/sqlb_it.qm b/src/WBCLFZSystemModule/SqliteDBProcess/src/translations/sqlb_it.qm new file mode 100644 index 0000000000000000000000000000000000000000..49ab89b73f7b5b40299a76086ec4d0bbfe78ce6d GIT binary patch literal 249391 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 z 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 DGcA9% literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/translations/sqlb_it.ts b/src/WBCLFZSystemModule/SqliteDBProcess/src/translations/sqlb_it.ts new file mode 100644 index 0000000..ea0b7e3 --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/translations/sqlb_it.ts @@ -0,0 +1,7020 @@ + + + + + AboutDialog + + + About DB Browser for SQLite + Informazioni su DB Browser for SQLite + + + + Version + Versione + + + + <html><head/><body><p>DB Browser for SQLite is an open source, freeware visual tool used to create, design and edit SQLite database files.</p><p>It is bi-licensed under the Mozilla Public License Version 2, as well as the GNU General Public License Version 3 or later. You can modify or redistribute it under the conditions of these licenses.</p><p>See <a href="http://www.gnu.org/licenses/gpl.html">http://www.gnu.org/licenses/gpl.html</a> and <a href="https://www.mozilla.org/MPL/2.0/index.txt">https://www.mozilla.org/MPL/2.0/index.txt</a> for details.</p><p>For more information on this program please visit our website at: <a href="http://sqlitebrowser.org">http://sqlitebrowser.org</a></p><p><span style=" font-size:small;">This software uses the GPL/LGPL Qt Toolkit from </span><a href="http://qt-project.org/"><span style=" font-size:small;">http://qt-project.org/</span></a><span style=" font-size:small;"><br/>See </span><a href="http://qt-project.org/doc/qt-5/licensing.html"><span style=" font-size:small;">http://qt-project.org/doc/qt-5/licensing.html</span></a><span style=" font-size:small;"> for licensing terms and information.</span></p><p><span style=" font-size:small;">It also uses the Silk icon set by Mark James licensed under a Creative Commons Attribution 2.5 and 3.0 license.<br/>See </span><a href="http://www.famfamfam.com/lab/icons/silk/"><span style=" font-size:small;">http://www.famfamfam.com/lab/icons/silk/</span></a><span style=" font-size:small;"> for details.</span></p></body></html> + <html><head/><body><p>DB-Browser for SQLite è uno strumento grafico opensource e freeware usato per creare, struttutturare e modificare file database di SQLite</p><p>È rilasciato sotto la licenza Mozilla Public License Version 2, così come sotto la licenza GNU General Public License Version 3 o successive. È possibile modificarlo e redistribuirlo sotto le condizioni specificate da queste licenze.</p><p>Si veda <a href="http://www.gnu.org/licenses/gpl.html">http://www.gnu.org/licenses/gpl.html</a> e <a href="https://www.mozilla.org/MPL/2.0/index.txt">https://www.mozilla.org/MPL/2.0/index.txt</a> per ulteriori dettagli.</p><p>Per ulteriori dettagli riguardo questo programma visitate il nostro sito web a: <a href="http://sqlitebrowser.org">http://sqlitebrowser.org</a></p><p><span style=" font-size:small;">Questo software usa GPL/LGPL QT Toolkit da </span><a href="http://qt-project.org/"><span style=" font-size:small;">http://qt-project.org/</span></a><span style=" font-size:small;"><br/>Si veda </span><a href="http://qt-project.org/doc/qt-5/licensing.html"><span style=" font-size:small;">http://qt-project.org/doc/qt-5/licensing.html</span></a><span style=" font-size:small;"> per termini di licenza e informazioni.</span></p><p><span style=" font-size:small;">Utilizza inoltre Silk-Iconset di Mark James, rilasciato sotto licenza Creative Commons Attribution 2.5 e 3.0.<br/>Si veda </span><a href="http://www.famfamfam.com/lab/icons/silk/"><span style=" font-size:small;">http://www.famfamfam.com/lab/icons/silk/</span></a><span style=" font-size:small;"> per ulteriori dettagli.</span></p></body></html> + + + + AddRecordDialog + + + Add New Record + Aggiungi un nuovo record + + + + Enter values for the new record considering constraints. Fields in bold are mandatory. + Inserisci i valori per il nuovo record considerando i vincoli. I campi in grassetto sono obbligatori. + + + + In the Value column you can specify the value for the field identified in the Name column. The Type column indicates the type of the field. Default values are displayed in the same style as NULL values. + Nella colonna Valore puoi specificare il valore per il campo identificato dalla colonna Nome. La colonna Tipo indica il tipo del campo. I valori di default sono mostrati nello stesso stile come valori NULL. + + + + Name + Nome + + + + Type + Tipo + + + + Value + Valore + + + + Values to insert. Pre-filled default values are inserted automatically unless they are changed. + Valori da inserire. Sono preinseriti dei valori di default automaticamente a meno che essi non vengano cambiati. + + + + When you edit the values in the upper frame, the SQL query for inserting this new record is shown here. You can edit manually the query before saving. + Quando modifichi i valori nel riquadro superiore, la query SQL per inserire questo nuovo record è mostrata qui. Puoi modificare manualmente la query prima di salvare. + + + + <html><head/><body><p><span style=" font-weight:600;">Save</span> will submit the shown SQL statement to the database for inserting the new record.</p><p><span style=" font-weight:600;">Restore Defaults</span> will restore the initial values in the <span style=" font-weight:600;">Value</span> column.</p><p><span style=" font-weight:600;">Cancel</span> will close this dialog without executing the query.</p></body></html> + <html><head/><body><p><span style=" font-weight:600;">Salva</span> invia la richiesta SQL mostrata al database per inserire un nuovo record.</p><p><span style=" font-weight:600;">Ripristina Defaults</span> ripristinerà i valori iniziali della colonna <span style=" font-weight:600;">Valore</span>.</p><p><span style=" font-weight:600;">Annulla</span> chiuderà questa finestra di dialogo senza eseguire la query.</p></body></html> + + + + Auto-increment + + Auto-incrementale + + + + + Unique constraint + + Restrizione univoco + + + + + Check constraint: %1 + + Controlla restrizioni: %1 + + + + + Foreign key: %1 + + Chiave esterna: %1 + + + + + Default value: %1 + + Valore di default: %1 + + + + + Error adding record. Message from database engine: + +%1 + Errore nell'aggiungere il record. Messaggio dal database engine: + +%1 + + + + Are you sure you want to restore all the entered values to their defaults? + Sei sicuro di voler ripristinare tutti i valori inseriti ai loro valori di default? + + + + Application + + + Possible command line arguments: + Possibili argomenti da linea di comando: + + + + Usage: %1 [options] [<database>|<project>] + + Utilizzo: %1 [opzioni] [<database>|<progetto>] + + + + + -h, --help Show command line options + -h, --help Mostra le opzioni da riga di comando + + + + -q, --quit Exit application after running scripts + -q, --quit Chiude l'applicazione dopo aver eseguito gli scripts + + + + -s, --sql <file> Execute this SQL file after opening the DB + -s, --sql <file> Esegue questo file SQL dopo aver aperto il DB + + + + -t, --table <table> Browse this table after opening the DB + -t, --table <table> Mostra questa tabella dopo aver aperto il DB + + + + -R, --read-only Open database in read-only mode + -R, --read-only Apre il database in sola lettura + + + + -o, --option <group>/<setting>=<value> + -o, --option <gruppo>/<impostazione>=<valore> + + + + Run application with this setting temporarily set to value + Esegue l'applicazione con queste impostazioni applicate temporaneamente + + + + -O, --save-option <group>/<setting>=<value> + -O, --save-option <gruppo>/<impostazione>=<valore> + + + + Run application saving this value for this setting + Esegue l'applicazione salvando questo valore come impostazione + + + + -v, --version Display the current version + -v, --version Mostra la versione corrente + + + + <database> Open this SQLite database + <database> Apre questo database SQLite + + + + <project> Open this project file (*.sqbpro) + <project> Apre questo file di progetto (*.sqbpro) + + + + The -s/--sql option requires an argument + L'opzione -s/--sql richiede un argomento + + + + The file %1 does not exist + Il file %1 non esiste + + + + The -t/--table option requires an argument + L'opzione -t/--table richiede un argomento + + + + The -o/--option and -O/--save-option options require an argument in the form group/setting=value + L'opzioni -o/--option e -O/--save-option richiedono un parametro nel formato gruppo/impostaizione=valore + + + + SQLite Version + Versione SQLite + + + + SQLCipher Version %1 (based on SQLite %2) + Versione SQLCipher %1 (basata su SQLite %2) + + + + DB Browser for SQLite Version %1. + DB Browser for SQLite Versione %1. + + + + Built for %1, running on %2 + Compilato per %1, in esecuzione su %2 + + + + Qt Version %1 + Versione Qt %1 + + + + Invalid option/non-existant file: %1 + Opzione non valida/file inesistente: %1 + + + + CipherDialog + + + SQLCipher encryption + Criptatura SQLCipher + + + + &Password + &Password + + + + &Reenter password + &Reinserire password + + + + Encr&yption settings + I&mpostazioni cifratura + + + + SQLCipher &3 defaults + Predefiniti SQLCipher &3 + + + + SQLCipher &4 defaults + Predefiniti SQLCipher &4 + + + + Custo&m + Personalizzat&i + + + + Page si&ze + Di&mensioni pagina + + + + &KDF iterations + Integrazione &KDF + + + + HMAC algorithm + Algoritmo HMAC + + + + KDF algorithm + Algoritmo KDF + + + + Plaintext Header Size + Dimensione header testuale + + + + Passphrase + Chiave testuale + + + + Raw key + Chiave grezza + + + + Please set a key to encrypt the database. +Note that if you change any of the other, optional, settings you'll need to re-enter them as well every time you open the database file. +Leave the password fields empty to disable the encryption. +The encryption process might take some time and you should have a backup copy of your database! Unsaved changes are applied before modifying the encryption. + Perfavore inserisci una chiave per criptare il database. +Nota che se cambi una qualsiasi delle altre impostazioni opzionali, dovrai reinserirle ogni volta che apri il file del database. +Lascia i campi password vuoti per disabilitare la crittografia. +Il processo di crittazione può richiedere del tempo e dovresti avere una copia di backup del database! Modifiche non salvate sono applicate prima di modificare la crittografia. + + + + Please enter the key used to encrypt the database. +If any of the other settings were altered for this database file you need to provide this information as well. + Si prega d'inserire la chiave utilizzata per criptare il database. +Se una qualunque altra impostazione è stata modificata per l'inserimento della criptazione si prega d'impostarla in modo adeguato. + + + + ColumnDisplayFormatDialog + + + Choose display format + Seleziona il formato di visualizzazione + + + + Display format + Formato di visualizzazione + + + + Choose a display format for the column '%1' which is applied to each value prior to showing it. + Seleziona un formato di visualizzazione per la colonna '%1' che è applicato a ciascun valore prima di mostrarlo. + + + + Default + Default + + + + Decimal number + Numero decimale + + + + Exponent notation + Notazione esponenziale + + + + Hex blob + Blob esadecimale + + + + Hex number + Numero esadecimale + + + + Octal number + Numero ottale + + + + Round number + Numero arrotondato + + + + Apple NSDate to date + Apple NSDate ad oggi + + + + Java epoch (milliseconds) to date + Java epoch (millisecondi) ad oggi + + + + .NET DateTime.Ticks to date + .NET DateTime.Ticks ad oggi + + + + Julian day to date + Giorno giuliano ad oggi + + + + Unix epoch to date + Unix epoch ad oggi + + + + Unix epoch to local time + Unix epoch a ora locale + + + + Windows DATE to date + Windows DATE ad oggi + + + + Date as dd/mm/yyyy + Data come gg/mm/aaaa + + + + Lower case + Minuscolo + + + + Upper case + Maiuscolo + + + + Custom + Personalizzato + + + + Custom display format must contain a function call applied to %1 + I formati di visualizzazione personalizzati devono contenere una chiamata a funzione applicata a %1 + + + + Error in custom display format. Message from database engine: + +%1 + Errore nel formato personalizzato di visualizzazione. Messaggio dal motore DB: + +%1 + + + + Custom display format must return only one column but it returned %1. + Il formato di visualizzazione personalizzato deve restituire solo una colonna ma ha restituito %1. + + + + CondFormatManager + + + Conditional Format Manager + Gestore della formattazione condizionale + + + + This dialog allows creating and editing conditional formats. Each cell style will be selected by the first accomplished condition for that cell data. Conditional formats can be moved up and down, where those at higher rows take precedence over those at lower. Syntax for conditions is the same as for filters and an empty condition applies to all values. + Questa finestra permette la creazione e modifica della formattazione condizionale. Lo stile di ogni cella corrisponde alla prima condizione corrispondente. Le formattazioni condizionali possono essere spostate su e giù, quelle in posizione superiore avranno precedenza su quelle inferiori. La sintassi per le condizioni è la stessa utilizzata per i filtri e una condizione vuota corrisponde a tutti i valori. + + + + Add new conditional format + Aggiunti nuova condizione + + + + &Add + &Aggiungi + + + + Remove selected conditional format + Rimuovi la condizione selezionata + + + + &Remove + &Rimuovi + + + + Move selected conditional format up + Sposta la condizione selezionata in su + + + + Move &up + Sposta &su + + + + Move selected conditional format down + Sposta la condizione selezionata giù + + + + Move &down + Sposta &giù + + + + Foreground + Primo piano + + + + Text color + Colore del testo + + + + Background + Sfondo + + + + Background color + Colore dello sfondo + + + + Font + Testo + + + + Size + Dimensione + + + + Bold + Grassetto + + + + Italic + Corsivo + + + + Underline + Sottolinea + + + + Alignment + Allineamento + + + + Condition + Condizione + + + + + Click to select color + Clicca per scegliere il colore + + + + Are you sure you want to clear all the conditional formats of this field? + Sei sicuro di voler eliminare tutte le formattazioni condizionali di questo campo? + + + + DBBrowserDB + + + This database has already been attached. Its schema name is '%1'. + Questo database è già stato collegato. Il nome del suo schema è '%1'. + + + + Please specify the database name under which you want to access the attached database + Si prega di specificare il nome del database con cui si vuol accedere al database collegato + + + + Invalid file format + Formato file non valido + + + + Do you really want to close this temporary database? All data will be lost. + Vuoi davvero chiudere questo database temporaneo? Tutti i dati andranno persi. + + + + Do you want to save the changes made to the database file %1? + Vuoi salvare le modifiche effettuate al database %1? + + + + Database didn't close correctly, probably still busy + Il database non è stato chiuso correttamente; probabilmente è ancora occupato + + + + The database is currently busy: + Il database è attualmente in uso: + + + + Do you want to abort that other operation? + Vuoi annullare l'altra operazione? + + + + Exporting database to SQL file... + Esportando il database in file SQL... + + + + + Cancel + Annulla + + + + + No database file opened + Nessun database aperto + + + + Executing SQL... + Eseguendo SQL... + + + + Action cancelled. + Azione annullata. + + + + + Error in statement #%1: %2. +Aborting execution%3. + Errore nello statement #%1: %2. +Annullo l'esecuzione %3. + + + + + and rolling back + e ripristino il db + + + + didn't receive any output from %1 + non ho ricevuto alcun ouput da %1 + + + + could not execute command: %1 + impossibile eseguire il comando: %1 + + + + Cannot delete this object + Non posso cancellare questo oggetto + + + + Cannot set data on this object + Non posso impostare i dati in questo oggetto + + + + + A table with the name '%1' already exists in schema '%2'. + Una tabella con il nome '%1' esiste già nello schema '%2'. + + + + No table with name '%1' exists in schema '%2'. + Nessuna tabella col nome '%1' esiste nello schema '%2'. + + + + + Cannot find column %1. + Impossibile trovare la colonna %1. + + + + Creating savepoint failed. DB says: %1 + Creazione del punto di salvataggio fallita. DB log: %1 + + + + Renaming the column failed. DB says: +%1 + Fallimento dell'operazione di rinomina. DB log: %1 + + + + + Releasing savepoint failed. DB says: %1 + Rilascio del salvataggio falitto. DB log: %1 + + + + Creating new table failed. DB says: %1 + Creazione della nuova tabella fallita. DB log: %1 + + + + Copying data to new table failed. DB says: +%1 + Copia dei dati nella nuova tabella fallita. DB log: %1 + + + + Deleting old table failed. DB says: %1 + Eliminazione della vecchia tabella fallita. DB log: %1 + + + + Error renaming table '%1' to '%2'. +Message from database engine: +%3 + Errore durante il rinomino della tabella '%1' in '%2. +Messaggio dal DB: +%3 + + + + could not get list of db objects: %1 + non posso ottenere la listra degli oggetti db: %1 + + + + Restoring some of the objects associated with this table failed. This is most likely because some column names changed. Here's the SQL statement which you might want to fix and execute manually: + + + Ripristino di alcuni oggetti associati a questa tabella fallito. Questo è probabilmente dovuto al fatto che i nomi di alcune colonne sono cambiati . Qui c'è la richiesta SQL che potresti voler sistemare ed eseguire manualmente: + + + + + + could not get list of databases: %1 + non è possibile ricavare la lista dei database: %1 + + + + Error setting pragma %1 to %2: %3 + Errore nell'impostare pragma %1 in %2: %3 + + + + File not found. + File non trovato. + + + + Error loading extension: %1 + Errore nel caricamento dell'estensione: %1 + + + + could not get column information + non è possibile ricavare informazioni sulla colonna + + + + DbStructureModel + + + Name + Nome + + + + Object + Oggetto + + + + Type + Tipo + + + + Schema + Schema + + + + Database + Database + + + + Browsables + Navigabili + + + + All + Tutti + + + + Temporary + Temporaneo + + + + Tables (%1) + Tabelle (%1) + + + + Indices (%1) + Indici (%1) + + + + Views (%1) + Viste (%1) + + + + Triggers (%1) + Triggers (%1) + + + + EditDialog + + + Edit database cell + Modifica la cella del database + + + + Mode: + Modalità: + + + + This is the list of supported modes for the cell editor. Choose a mode for viewing or editing the data of the current cell. + Questa è la lista delle modalità supportate dall'editor della cella. Scegli una modalità per vedere o modificare i dati della cella corrente. + + + + Text + Testo + + + + RTL Text + Testo RTL + + + + Binary + Binario + + + + + Image + Immagine + + + + JSON + JSON + + + + XML + XML + + + + + Automatically adjust the editor mode to the loaded data type + Seleziona automaticamente la modalità dell'editor in base al tipo di dato caricato + + + + This checkable button enables or disables the automatic switching of the editor mode. When a new cell is selected or new data is imported and the automatic switching is enabled, the mode adjusts to the detected data type. You can then change the editor mode manually. If you want to keep this manually switched mode while moving through the cells, switch the button off. + Questo bottone spuntabile permette di abilitare o disabilitare l'adattamento automatico della modalità dell'editor. Quando una nuova cella è selezionata o sono importati nuovi dati e la modalità di adattamento automaitco è abilitata, la modalità si aggiusta al tipo di dato rilevato. Puoi cambiare in seguito la modalità dell'editor in modo manuale. Se vuoi mantenere la modalità selezionata manualmente mentre ti muovi tre le celle, togli la spunta a questo bottone. + + + + Auto-switch + Auto-switch + + + + The text editor modes let you edit plain text, as well as JSON or XML data with syntax highlighting, automatic formatting and validation before saving. + +Errors are indicated with a red squiggle underline. + La modalità editor di testo ti pemrette di editare del testo semplice, così come dei dati JSON o XML con evidenziazione della sintassi, formattazione automatica e validazione prima del salvataggio. + +Gli errori sono indicati da una sottolineatura rossa ondulata. + + + + This Qt editor is used for right-to-left scripts, which are not supported by the default Text editor. The presence of right-to-left characters is detected and this editor mode is automatically selected. + Questo editor Qt è utilizzato per le scritture da destra a sinistra, che non sono supportate dall'editor testuale standard. La presenza di caratteri da destra a sinistra è rilevata e la modalità dell'editor viene selezionata automaticamente. + + + + Open preview dialog for printing the data currently stored in the cell + Apre una finestra d'anteprima per la stampa dei dati attualmente memorizzati nella cella + + + + Auto-format: pretty print on loading, compact on saving. + Auto-formato: migliore stampa al caricamento, compatta in salvataggio. + + + + When enabled, the auto-format feature formats the data on loading, breaking the text in lines and indenting it for maximum readability. On data saving, the auto-format feature compacts the data removing end of lines, and unnecessary whitespace. + Quando abilitato, la feature dell'auto-formato formatta i dati al caricamento, rompe il testo in righe e lo indenta per una maggiore leggibilità. Al salvataggio dei dati, la feature dell'auto-formato compatta i dati rimuovendo i fine riga, e spazi bianchi non necessari. + + + + Word Wrap + A capo automatico + + + + Wrap lines on word boundaries + Porta a capo le line di testo al raggiungimento del bordo + + + + + Open in default application or browser + Apri nell'applicazione predefinita o nel browser + + + + Open in application + Apri nell'applicazione + + + + The value is interpreted as a file or URL and opened in the default application or web browser. + Il valore è interpretato come file o URL e aperto nell'applicazione predefinita o nel web browser. + + + + Save file reference... + Salva riferimento file... + + + + Save reference to file + Salva riferimento su file + + + + + Open in external application + Apri in un'applicazione esterna + + + + Autoformat + Autoformato + + + + &Export... + &Esporta... + + + + + &Import... + &Importa... + + + + + Import from file + Importa da file + + + + + Opens a file dialog used to import any kind of data to this database cell. + Apri una finestra di dialogo per importare qualsiasi tipo di dato in questa cella del database. + + + + Export to file + Esporta in un file + + + + Opens a file dialog used to export the contents of this database cell to a file. + Apri una finestra di dialogo utilizzata per esportare i contenuti di questa cella del database in un file. + + + + Apply data to cell + Applica i dati alla cella + + + + Erases the contents of the cell + Cancella i contenuti di questa cella + + + + Set as &NULL + Imposta come &NULL + + + + This area displays information about the data present in this database cell + Quest'area mostra informazioni riguardo i dati presenti in questa cella del database + + + + Type of data currently in cell + Tipo di dato attualmente nella cella + + + + Size of data currently in table + Dimensione dei dati attualmente in tabella + + + + This button saves the changes performed in the cell editor to the database cell. + Questo bottone salva le modifiche fatte alla cella dell'editor alla cella del database. + + + + Apply + Applica + + + + + Print... + Stampa... + + + + Open preview dialog for printing displayed image + Apri la finestra di anteprima per stampare l'immagine mostrata + + + + + Ctrl+P + + + + + Open preview dialog for printing displayed text + Apri la finestra di anteprima per stampare il testo mostrato + + + + Copy Hex and ASCII + Copia HEX e ASCII + + + + Copy selected hexadecimal and ASCII columns to the clipboard + Copia le colonne esadecimali e ASCII selezionate negli appunti + + + + Ctrl+Shift+C + + + + + + Image data can't be viewed in this mode. + I dati immagine non possono essere visualizzati in questa modalità. + + + + + Try switching to Image or Binary mode. + Prova a passare alla modalità Immagine o Binario. + + + + + Binary data can't be viewed in this mode. + I dati binari non possono essere visualizzati in questa modalità. + + + + + Try switching to Binary mode. + Prova a passare alla modalità Binario. + + + + + Image files (%1) + File immagine (%1) + + + + Binary files (*.bin) + File binario (*.bin) + + + + Choose a file to import + Scegli un file da importare + + + + %1 Image + %1 Immagine + + + + Choose a filename to export data + Scegli un nome del file per esportare i dati + + + + Invalid data for this mode + Dati non validi per questa modalità + + + + The cell contains invalid %1 data. Reason: %2. Do you really want to apply it to the cell? + La cella continete dati %1 non validi. Ragione: %2. Sei davvero sicuro di applicare quello alla cella? + + + + + Type of data currently in cell: Text / Numeric + Tipo di dato attualmente nella cella: Testo / Numerico + + + + + + %n character(s) + + %n carattere + %n caratteri + + + + + Type of data currently in cell: %1 Image + Tipo di dato attualmente nella cella: %1 Immagine + + + + %1x%2 pixel(s) + %1x%2 pixel(s) + + + + Type of data currently in cell: NULL + Tipo di dato attualmente nella cella: NULL + + + + + %n byte(s) + + %n byte + %n bytes + + + + + Type of data currently in cell: Valid JSON + Tipo di dato attualmente nella cella: Valid JSON + + + + Type of data currently in cell: Binary + Tipo di dato attualmente nella cella: Binario + + + + Couldn't save file: %1. + Impossibile salvare il file: %1. + + + + The data has been saved to a temporary file and has been opened with the default application. You can now edit the file and, when you are ready, apply the saved new data to the cell editor or cancel any changes. + I dati sono stati salvati in un file temporane e sono stati aperti con l'applicazione predefinita. Ora puoi modificare il file e, quando sei pronto, applicare i nuovi dati salvati all'editor di cella o annullare ogni modifica. + + + + EditIndexDialog + + + Edit Index Schema + Modifica Indice Schema + + + + &Name + &Nome + + + + &Table + &Tabella + + + + &Unique + &Univoco + + + + For restricting the index to only a part of the table you can specify a WHERE clause here that selects the part of the table that should be indexed + Per restringere l'indice a solo una parte della tabella puoi specificare una clausula WHERE qui che selezioni la parte della tabella che dovrà essere indicizzata + + + + Partial inde&x clause + Clausola di &indice parziale + + + + Colu&mns + &Colonne + + + + Table column + Colonna della tabella + + + + Type + Tipo + + + + Add a new expression column to the index. Expression columns contain SQL expression rather than column names. + Aggiungi una nuova espressione colonna all'indice. Le espressioni colonna contengono espressioni SQL piuttosto che i nomi delle colonne. + + + + Index column + Indice di colonna + + + + Order + Ordine + + + + Deleting the old index failed: +%1 + Cancellazione del vecchio indice fallita: +%1 + + + + Creating the index failed: +%1 + Creazione del vecchio indice fallita: +%1 + + + + EditTableDialog + + + Edit table definition + Modifica la definizione della tabella + + + + Table + Tabella + + + + Advanced + Avanzate + + + + Database sche&ma + Sche&ma database + + + + Without Rowid + Senza id riga + + + + Make this a 'WITHOUT rowid' table. Setting this flag requires a field of type INTEGER with the primary key flag set and the auto increment flag unset. + Fai una tabella 'WITHOUT rowid'. Impostare questa spunta richiede un campo di tipo INTEGER con la chiave primaria impostata e l'auto incremento non impostato. + + + + Fields + Campi + + + + Add + Aggiungi + + + + Remove + Rimuovi + + + + Move to top + Muovi in cima + + + + Move up + Muovi su + + + + Move down + Muovi giù + + + + Move to bottom + Muovi al fondo + + + + + Name + Nome + + + + + Type + Tipo + + + + NN + NN + + + + Not null + Non null + + + + PK + CP + + + + Primary key + Chiave Primaria + + + + AI + AI + + + + Autoincrement + Autoincremento + + + + U + U + + + + + + Unique + Univoco + + + + Default + Default + + + + Default value + Valore di default + + + + + + Check + Controlla + + + + Check constraint + Controlla le restrizioni + + + + Collation + Fascicola + + + + + + Foreign Key + Chiave esterna + + + + Constraints + Vincoli + + + + Add constraint + Aggiungi vincolo + + + + Remove constraint + Rimuovi vincolo + + + + Columns + Colonne + + + + SQL + SQL + + + + <html><head/><body><p><span style=" font-weight:600; color:#ff0000;">Warning: </span>There is something with this table definition that our parser doesn't fully understand. Modifying and saving this table might result in problems.</p></body></html> + <html><head/><body><p><span style=" font-weight:600; color:#ff0000;">Attenzione: </span>C'è qualcosa in questa definizione di tabella che il nostro parser non comprende. Modificare e salvare questa tabella potrebbe creare dei problemi.</p></body></html> + + + + + Primary Key + Chiave primaria + + + + Add a primary key constraint + Aggiungi un vincolo di chiave primaria + + + + Add a foreign key constraint + Aggiungi un vincolo di chiave esterna + + + + Add a unique constraint + Aggiungi un vincolo di unicità + + + + Add a check constraint + Aggiungi un vincolo di controllo + + + + + There can only be one primary key for each table. Please modify the existing primary key instead. + Puoi avere solo una chiave primaria per ogni tabella. Si prega di modificare la chiave primaria attuale. + + + + Error creating table. Message from database engine: +%1 + Error nella creazione della tabella. Messaggio dal database engine: +%1 + + + + There already is a field with that name. Please rename it first or choose a different name for this field. + Esiste già un campo con quel nome. Si prega di rinominarlo prima o scegliere un nome differente per questo campo. + + + + This column is referenced in a foreign key in table %1 and thus its name cannot be changed. + Questa colonna è referenziata in una chiave esterna nella tabella %1 e quindi il nome non può essere modificato. + + + + There is at least one row with this field set to NULL. This makes it impossible to set this flag. Please change the table data first. + Esiste almeno una riga con questo campo impostato a NULL. Questo rende impossibile impostare questa opzione. Si prega prima di modificare quel dato. + + + + There is at least one row with a non-integer value in this field. This makes it impossible to set the AI flag. Please change the table data first. + Esiste almeno un riga con un valore non intero in questo campo. Questo rende impossibile impostare l'AI. Si prega prima di cambiare il dato. + + + + Column '%1' has duplicate data. + + La colonna '%1' ha dei dati duplicati. + + + + + This makes it impossible to enable the 'Unique' flag. Please remove the duplicate data, which will allow the 'Unique' flag to then be enabled. + Questo rende impossibile abilitare l'opzionie 'Univoco'. Perfavore rimuovi i dati duplicati, il che permetterà l'abilitazione dell'opzione 'Univoco'. + + + + Are you sure you want to delete the field '%1'? +All data currently stored in this field will be lost. + Sei sicuro di voler eliminare il campo '%1'? +Tutti i dati che sono attualmente memorizzati in questo campo andranno persi. + + + + Please add a field which meets the following criteria before setting the without rowid flag: + - Primary key flag set + - Auto increment disabled + Perfavore agginugi un campo che rispetti i seguenti criteri prima di impostare l'opzione senza id di riga: + - Opzione Chiave Primaria impostata + - Autoincremento disabilitato + + + + ExportDataDialog + + + Export data as CSV + Esporta i dati come CSV + + + + Tab&le(s) + Tabe&lla(e) + + + + Colu&mn names in first line + Nomi delle &Colonne sulla prima riga + + + + Fie&ld separator + Separatore di ca&mpo + + + + , + , + + + + ; + ; + + + + Tab + Tab + + + + | + | + + + + + + Other + Altro + + + + &Quote character + &Carattere citazione + + + + " + " + + + + ' + ' + + + + New line characters + Carattere di nuova riga + + + + Windows: CR+LF (\r\n) + Windows: CR+LF (\r\n) + + + + Unix: LF (\n) + Unix: LF (\n) + + + + Pretty print + Visualizzazione piacevole + + + + Export data as JSON + Esporta i dati come JSON + + + + exporting CSV + esportando in CSV + + + + + Could not open output file: %1 + Impossibile aprire il file di output: %1 + + + + exporting JSON + esportando in JSON + + + + + Choose a filename to export data + Scegliere un nome file per esportare i dati + + + + Please select at least 1 table. + Perfavore seleziona almeno una tabella. + + + + Choose a directory + Scegliere una cartella + + + + Export completed. + Esportazione completata. + + + + ExportSqlDialog + + + Export SQL... + Esporta SQL... + + + + Tab&le(s) + Tabe&lla(e) + + + + Select All + Seleziona tutto + + + + Deselect All + Deseleziona tutto + + + + &Options + &Opzioni + + + + Keep column names in INSERT INTO + Tieni i nomi delle colonne in INSERT INTO + + + + Multiple rows (VALUES) per INSERT statement + Righe multiple (VALUES) per lo statement INSERT + + + + Export everything + Esporta tutto + + + + Export schema only + Esporta solo lo schema + + + + Export data only + Esporta solo i dati + + + + Keep old schema (CREATE TABLE IF NOT EXISTS) + Mantieni lo schema esistente (CREATE TABLE IF NOT EXISTS) + + + + Overwrite old schema (DROP TABLE, then CREATE TABLE) + Sovrascrivi schema precedente (DROP TABLE, poi CREATE TABLE) + + + + Please select at least one table. + Perfavore seleziona almeno una tabella. + + + + Choose a filename to export + Scegli un nome del file per esportare + + + + Export completed. + Esportazione completata. + + + + Export cancelled or failed. + Esportazione annullata o fallita. + + + + ExtendedScintilla + + + + Ctrl+H + + + + + Ctrl+F + + + + + + Ctrl+P + + + + + Find... + Trova... + + + + Find and Replace... + Trova e Sostituisci... + + + + Print... + Stampa... + + + + ExtendedTableWidget + + + Use as Exact Filter + Usa come filtro esatto + + + + Containing + Che contiene + + + + Not containing + Non contenuto + + + + Not equal to + Non uguale a + + + + Greater than + Maggiore di + + + + Less than + Minore di + + + + Greater or equal + Maggiore o uguale + + + + Less or equal + Minore o uguale + + + + Between this and... + Tra questo e... + + + + Regular expression + Espressione regolare + + + + Edit Conditional Formats... + Modifica Formattazione Condizionale... + + + + Set to NULL + Imposta a NULL + + + + Copy + Copia + + + + Copy with Headers + Copia con gli Headers + + + + Copy as SQL + Copia come SQL + + + + Paste + Incolla + + + + Print... + Stampa... + + + + Use in Filter Expression + Usa nell'espressione del filtro + + + + Alt+Del + + + + + Ctrl+Shift+C + + + + + Ctrl+Alt+C + + + + + The content of the clipboard is bigger than the range selected. +Do you want to insert it anyway? + Il contenuto degli appunti è più grande del range selezionato. +Vuoi inserirlo comunque? + + + + <p>Not all data has been loaded. <b>Do you want to load all data before selecting all the rows?</b><p><p>Answering <b>No</b> means that no more data will be loaded and the selection will not be performed.<br/>Answering <b>Yes</b> might take some time while the data is loaded but the selection will be complete.</p>Warning: Loading all the data might require a great amount of memory for big tables. + <p>Non tutti i dati sono stati caricati. <b>Vuoi caricare tutti i dati prima di selezionare tutte le righe?</b><p><p>Rispondere <b>No</b> significa che non verranno caricati i restanti dati e la selezione non verrà effettuata.<br/>Rispondere <b>Si</b> potrebbe richiedere del tempo per caricare i dati, ma la selezione sarà completa.</p>Attenzione: Caricare tutti i dati potrebbe richiedere un grosso quantitativo di memoria in caso di grandi tabelle. + + + + Cannot set selection to NULL. Column %1 has a NOT NULL constraint. + Impossibile modificare la selezione in NULL. La colonna %1 ho un vincolo NOT NULL. + + + + FileExtensionManager + + + File Extension Manager + Gestore delle estensioni dei files + + + + &Up + Porta &su + + + + &Down + Porta &giù + + + + &Add + &Aggiungi + + + + &Remove + &Rimuovi + + + + + Description + Descrizione + + + + Extensions + Estensioni + + + + *.extension + *.estensione + + + + FilterLineEdit + + + Filter + Filtro + + + + These input fields allow you to perform quick filters in the currently selected table. +By default, the rows containing the input text are filtered out. +The following operators are also supported: +% Wildcard +> Greater than +< Less than +>= Equal to or greater +<= Equal to or less += Equal to: exact match +<> Unequal: exact inverse match +x~y Range: values between x and y +/regexp/ Values matching the regular expression + Questi campi di input permettono di effettuare filtri rapidi nella tabella correntemente selezionata. +er impostazione predefinita, le righe che contengono il testo immesso sono escluse. +Sono inoltre supportati i seguenti operatori: +% Wildcard +> Maggiore di +< Minore di +>= Maggiore o uguale +<= Minore o uguale += Uguale a: corrispondenza esatta +<> Diverso: corrispondenza esatta invertita +x~y Intervallo: valori tra x e y +/regexp/ Valori che corrispondono all'espressione regolare + + + + Use for Conditional Format + Usa per formattazioni condizionali + + + + Clear All Conditional Formats + Elimina tutte le formattazioni condizionali + + + + Edit Conditional Formats... + Modifica Formattazione Condizionale... + + + + Set Filter Expression + Imposta l'espressione del filtro + + + + What's This? + Cos'è questo? + + + + Is NULL + È NULL + + + + Is not NULL + Non è NULL + + + + Is empty + È vuoto + + + + Is not empty + Non è vuoto + + + + Not containing... + Non contenente... + + + + Equal to... + Uguale a... + + + + Not equal to... + Non uguale a... + + + + Greater than... + Maggiore di... + + + + Less than... + Minore di... + + + + Greater or equal... + Maggiore o uguale... + + + + Less or equal... + Minore o uguale... + + + + In range... + Nell'intervallo... + + + + Regular expression... + Espressione regolare... + + + + FindReplaceDialog + + + Find and Replace + Trova e sostituisci + + + + Fi&nd text: + Tr&ova testo: + + + + Re&place with: + So&stituisci con: + + + + Match &exact case + Corrispondenza &esatta + + + + Match &only whole words + Trova solo &parole complete + + + + When enabled, the search continues from the other end when it reaches one end of the page + Quando abilitato, la ricerca contninua dall'altro capo del documento quando si raggiunge una fine del documento + + + + &Wrap around + Senza &limiti + + + + When set, the search goes backwards from cursor position, otherwise it goes forward + Quando abilitato, la ricerca va all'indietro dalla corrente posizione del cursore, altrimenti va in avanti + + + + Search &backwards + Cerca &indietro + + + + <html><head/><body><p>When checked, the pattern to find is searched only in the current selection.</p></body></html> + <html><head/><body><p>Quando abilitato, la ricerca viene effettuata solo all'interno della selezione corrente.</p></body></html> + + + + &Selection only + &Solo selezionati + + + + <html><head/><body><p>When checked, the pattern to find is interpreted as a UNIX regular expression. See <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>.</p></body></html> + <html><head/><body><p>Quando selezionato, la stringa del testo viene interpretata come una espressione regolare Unix. Vedi <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Espressioni regolari su Wikibooks (in inglese)</a>.</p></body></html> + + + + Use regular e&xpressions + Usa &espressioni regolari + + + + Find the next occurrence from the cursor position and in the direction set by "Search backwards" + Trova la prossima occorrenza dalla corrente posizione del cursore nella direzione impostata da "Cerca indietro" + + + + &Find Next + &Trova successivo + + + + F3 + + + + + &Replace + &Sostituisci + + + + Highlight all the occurrences of the text in the page + Evidenzia tutte le occorrenze del testo nella pagina + + + + F&ind All + T&rova tutti + + + + Replace all the occurrences of the text in the page + Sostituisce tutte le occorrenze del testo nella pagina + + + + Replace &All + Sostituisci &Tutti + + + + The searched text was not found + Il testo cercato non è stato trovato + + + + The searched text was not found. + Il testo cercato non è stato trovato. + + + + The searched text was found one time. + Il testo cercato è stato trovato una volta. + + + + The searched text was found %1 times. + Il testo cercato è stato trovato %1 volte. + + + + The searched text was replaced one time. + Il testo cercato è stato sostituito una volta. + + + + The searched text was replaced %1 times. + Il testo cercato è stato sostituito %1 volte. + + + + ForeignKeyEditor + + + &Reset + &Reimposta + + + + Foreign key clauses (ON UPDATE, ON DELETE etc.) + Clausule per chiave esterna (ON UPDATE, ON DELETE etc.) + + + + ImportCsvDialog + + + Import CSV file + Imoprta file CSV + + + + Table na&me + No&me tabella + + + + &Column names in first line + Nomi &colonna nella prima riga + + + + Field &separator + &Separatore di campo + + + + , + , + + + + ; + ; + + + + + Tab + Tab + + + + | + | + + + + Other + Altro + + + + &Quote character + &Carattere citazione + + + + + Other (printable) + Altro (stampabile) + + + + + Other (code) + Altro (codice) + + + + " + " + + + + ' + ' + + + + &Encoding + Codific&a + + + + UTF-8 + UTF-8 + + + + UTF-16 + UTF-16 + + + + ISO-8859-1 + ISO-8859-1 + + + + Trim fields? + Pulizia campi? + + + + Separate tables + Separa tabelle + + + + Advanced + Avanzate + + + + When importing an empty value from the CSV file into an existing table with a default value for this column, that default value is inserted. Activate this option to insert an empty value instead. + Quando importo un campo vuoto dal file CSV dentro una tabella con un valore predefinito per quella colonna, quel valore viene inserito. Attivare quest'opzione per inserire invece un valore vuoto. + + + + Ignore default &values + Ignora valori &predefiniti + + + + Activate this option to stop the import when trying to import an empty value into a NOT NULL column without a default value. + Attivare quest'opzione per fermare l'importazione quando si prova ad importare un valore vuoto in una colonna "NOT NULL" senza valore predefinito. + + + + Fail on missing values + Fallisci su valori mancanti + + + + Disable data type detection + Disabilita rilevamento tipo dati + + + + Disable the automatic data type detection when creating a new table. + Disabilita il riconoscimento automatico della tipologia di dato quando crea una nuova tabella. + + + + When importing into an existing table with a primary key, unique constraints or a unique index there is a chance for a conflict. This option allows you to select a strategy for that case: By default the import is aborted and rolled back but you can also choose to ignore and not import conflicting rows or to replace the existing row in the table. + Quando si importano dati all'interno di una tabella esistente con una chiave primaria, potrebbero esserci conflitti. Questa opzione ti permette di selezionare una strategia per quei casi: Di base l'importazione è annullata e viene fatto un rollback, ma puoi anche scegliere d'ignorare e non importare le righe in conflitto o di rimpiazzare quelle presenti nella tabella. + + + + Abort import + Annulla l'importazione + + + + Ignore row + Ignora la riga + + + + Replace existing row + Rimpiazza la riga esistente + + + + Conflict strategy + Strategia di conflitto + + + + + Deselect All + Deseleziona tutte + + + + Match Similar + Seleziona simili + + + + Select All + Seleziona tutte + + + + There is already a table named '%1' and an import into an existing table is only possible if the number of columns match. + Esiste già una tabella col nome '%1' e l'importazione in una tabella esistente non è possibile se il numero di colonne non corrisponde. + + + + There is already a table named '%1'. Do you want to import the data into it? + Esiste già una tabella col nome '%1'. Vuoi importare i dati al suo interno? + + + + Creating restore point failed: %1 + Creazione del punto di ripristino fallita: %1 + + + + Creating the table failed: %1 + Creazione della tabella fallita: %1 + + + + importing CSV + importo il CSV + + + + Inserting row failed: %1 + Inserimento della riga fallito: %1 + + + + Importing the file '%1' took %2ms. Of this %3ms were spent in the row function. + Importare il file '%1' ha richiesto %2ms. Di questi %3ms sono stati spesi in funzioni di riga. + + + + MainWindow + + + DB Browser for SQLite + DB Browser for SQLite + + + + + Database Structure + This has to be equal to the tab title in all the main tabs + Struttura database + + + + This is the structure of the opened database. +You can drag SQL statements from an object row and drop them into other applications or into another instance of 'DB Browser for SQLite'. + + Questa è la struttura del database aperto. +Puoi trascinare SQL da una riga oggetto e rilasciarli dentro altri applicativi o in altre istanze di àDB Browser for SQLite'. + + + + + + Browse Data + This has to be equal to the tab title in all the main tabs + Naviga nei dati + + + + + Edit Pragmas + This has to be equal to the tab title in all the main tabs + Modifica Pragmas + + + + Warning: this pragma is not readable and this value has been inferred. Writing the pragma might overwrite a redefined LIKE provided by an SQLite extension. + Attenzione: questo pragma non è leggibile e questo valore è stato dedotto. Scrivere i pragma può sovrascrivere un LIKE ridefinito provvisto da un'estensione di SQLite. + + + + + Execute SQL + This has to be equal to the tab title in all the main tabs + Esegui SQL + + + + toolBar1 + + + + + &File + &File + + + + &Import + &Importa + + + + &Export + &Esporta + + + + &Edit + &Modifica + + + + &View + &Visualizza + + + + &Help + &Aiuto + + + + &Tools + &Strumenti + + + + DB Toolbar + Barra degli strumenti del DB + + + + Edit Database &Cell + Modifica &cella + + + + SQL &Log + &Log SQL + + + + Show S&QL submitted by + Mostra l'S&QL inviato da + + + + User + Utente + + + + Application + Applicazione + + + + Error Log + Registro errori + + + + This button clears the contents of the SQL logs + Questo pulsante cancella il contenuto del log SQL + + + + &Clear + &Pulisci + + + + This panel lets you examine a log of all SQL commands issued by the application or by yourself + Questo pannello ti permette di esaminare il log di tutti i comandi SQL inviati dall'applicazione o da te stesso + + + + &Plot + &Grafica + + + + DB Sche&ma + Sche&ma DB + + + + This is the structure of the opened database. +You can drag multiple object names from the Name column and drop them into the SQL editor and you can adjust the properties of the dropped names using the context menu. This would help you in composing SQL statements. +You can drag SQL statements from the Schema column and drop them into the SQL editor or into other applications. + + Questa è la struttura del database aperto. +Puoi trascinare nomi d'oggetto multipli dalla colonna "Nome" e rilasciarli all'interno dell'editor SQL e puoi modificare le proprietà dei nomi rilasciati utilizzando il menù contestuale. Questo può aiutarti nel comporre statement SQL. +Puoi trascinare statement SQL dalla colonna Schema e rilasciarli dentro l'editor SQL o all'interno di altre applicazioni. + + + + + &Remote + &Remoto + + + + + Project Toolbar + Barra degli strumenti di progetto + + + + Extra DB toolbar + Barra degli strumenti extra DB + + + + + + Close the current database file + Chiudi il file di database corrente + + + + &New Database... + &Nuovo Database... + + + + + Create a new database file + Crea un nuovo file di database + + + + This option is used to create a new database file. + Questa opzione è utilizzata per creare un nuovo file di database. + + + + Ctrl+N + + + + + + &Open Database... + &Apri Database... + + + + + + + + Open an existing database file + Apre un file di database esistente + + + + + + This option is used to open an existing database file. + Questa opzione è utilizzata per aprire un file esistente di database. + + + + Ctrl+O + + + + + &Close Database + &Chiudi Database + + + + This button closes the connection to the currently open database file + Questo pulsnate chiude la connessione al file di database attualmente aperto + + + + + Ctrl+W + + + + + &Revert Changes + &Ripristina le modifiche + + + + + Revert database to last saved state + Ripristina il database all'ultimo stato salvato + + + + This option is used to revert the current database file to its last saved state. All changes made since the last save operation are lost. + Questa opzione è utilizzata per ripristinare il file di database al suo ultimo stato salvato. Tutte le modifiche fatte dall'ultima opzione di salvataggio sono perse. + + + + &Write Changes + &Salva le modifiche + + + + + Write changes to the database file + Scrive le modifiche sul file di database + + + + This option is used to save changes to the database file. + Questa opzione è utilizzata per salvare le modifiche sul file di database. + + + + Ctrl+S + + + + + Compact &Database... + &Compatta Database... + + + + Compact the database file, removing space wasted by deleted records + Compatta il file di database, rimuovendo lo spazio sprecato dalle righe eliminate + + + + + Compact the database file, removing space wasted by deleted records. + Compatta il file di database rimuovendo lo spazio sprecato dalle righe eliminate. + + + + E&xit + &Esci + + + + Ctrl+Q + + + + + &Database from SQL file... + &Database dal file SQL... + + + + Import data from an .sql dump text file into a new or existing database. + Importa i dati da un file di testo di dump .sql all'interno di un database nuovo o esistente. + + + + This option lets you import data from an .sql dump text file into a new or existing database. SQL dump files can be created on most database engines, including MySQL and PostgreSQL. + Questa opzione ti permette d'importare i dati da un file di testo di dump .sql all'interno di un database nuovo o esistente. I file di dump SQL possono essere creati dalla maggiorparte dei motori SQL, inclusi MySQL e PostgreSQL. + + + + &Table from CSV file... + &Tabella da file CSV... + + + + Open a wizard that lets you import data from a comma separated text file into a database table. + Apre un wizard che ti permette d'importare dati da un file CSV all'interno di una tabella del database. + + + + Open a wizard that lets you import data from a comma separated text file into a database table. CSV files can be created on most database and spreadsheet applications. + Apre un wizard che ti permette d'importare dati da un file CSV all'interno di una tabella del database. I file CSV possono essere creati dalla maggiorparte delle applicazioni database o foglio di calcolo. + + + + &Database to SQL file... + &Database in file SQL... + + + + Export a database to a .sql dump text file. + Esporta un database in un file di testo di dump .sql. + + + + This option lets you export a database to a .sql dump text file. SQL dump files contain all data necessary to recreate the database on most database engines, including MySQL and PostgreSQL. + Questa opzione ti permette di esportare un database in un file di testo di dump .sql. Il file di dump SQL contiene tutti i dati necessari per ricreare il database sulla maggiorparte di motori di database, inclusi MySQL e PostgreSQL. + + + + &Table(s) as CSV file... + &Tabella(e) come file CSV... + + + + Export a database table as a comma separated text file. + Esporta la tabella del database come un file di testo CSV. + + + + Export a database table as a comma separated text file, ready to be imported into other database or spreadsheet applications. + Esporta la tabella del database come un file di testo CSV, pronto per essere importato in un altro database o foglio di calcolo. + + + + &Create Table... + &Crea tabella... + + + + Open the Create Table wizard, where it is possible to define the name and fields for a new table in the database + Apre un wizard per la creazione di una tabella, dov'è possibile definire il nome e i campi di una nuova tabella del database + + + + &Delete Table... + &Elimina tabella... + + + + + Delete Table + Elimina Tabella + + + + Open the Delete Table wizard, where you can select a database table to be dropped. + Apre un wizard per la cancellazione della tabella, da qui puoi selezionare la tabella del database da eliminare. + + + + &Modify Table... + &Modifica Tabella... + + + + Open the Modify Table wizard, where it is possible to rename an existing table. It is also possible to add or delete fields form a table, as well as modify field names and types. + Apre un wizard per la modifica di una tabella, da qui è possibile rinominare una tabella esistente. Si può anche aggiungere o rimuovere campi da una tabella così come modificarne il nome o il tipo. + + + + Create &Index... + Crea &Indice... + + + + Open the Create Index wizard, where it is possible to define a new index on an existing database table. + Apre un wizard per la crazione di un indice, da qui è possibile definire un nuovo indice s'una tabella di database pre-esistente. + + + + &Preferences... + &Preferenze... + + + + + Open the preferences window. + Apre la finestra delle preferenze. + + + + &DB Toolbar + &Barra degli strumenti + + + + Shows or hides the Database toolbar. + Mostra o nasconde la barra degli strumenti del database. + + + + Ctrl+T + + + + + Open SQL file(s) + Apri file(s) SQL + + + + This button opens files containing SQL statements and loads them in new editor tabs + Questo pulsante apre files contenenti stringhe SQL e li carica in una nuova scheda dell'editor + + + + Execute line + Esegui riga + + + + F1 + + + + + Sa&ve Project + Sal&va Progetto + + + + This button lets you save all the settings associated to the open DB to a DB Browser for SQLite project file + Questo pulsante ti permette di salvare tutte le impostazioni associate al DB aperto nel file di progetto di DB BRowser for SQLite + + + + This button lets you open a DB Browser for SQLite project file + Questo pulsante ti permette di aprire un file di progetto di DB Browser for SQLite + + + + Ctrl+Shift+O + + + + + Find + Trova + + + + Find or replace + Trova o sostituisci + + + + Print text from current SQL editor tab + Stampa testo dalla scheda corrente dell'editor SQL + + + + Print the structure of the opened database + Stampa la struttura del database aperto + + + + Un/comment block of SQL code + De/Commenta il blocco di codice SQL + + + + Un/comment block + De/Commenta il blocco + + + + Comment or uncomment current line or selected block of code + Commenta o decommenta la riga corrente o il blocco selezionato di codice + + + + Comment or uncomment the selected lines or the current line, when there is no selection. All the block is toggled according to the first line. + Commenta o decommenta le righe selezionate o la riga corrente, quando non c'è nessuna selezione. Tutti i blocchi sono modificati in accordo alla prima riga. + + + + Ctrl+/ + + + + + Stop SQL execution + Ferma esecuzione SQL + + + + Stop execution + Ferma esecuzione + + + + Stop the currently running SQL script + Ferma lo script SQL attualmente in esecuzione + + + + &Save Project As... + &Salva Progetto Come... + + + + + + Save the project in a file selected in a dialog + Salva il progetto in un file selezionato tramite una finestra di dialogo + + + + Save A&ll + Salva T&utto + + + + + + Save DB file, project file and opened SQL files + Salva il file DB, file di progetto e tutti i file SQL aperti + + + + Ctrl+Shift+S + + + + + Browse Table + Naviga nei dati + + + + W&hat's This? + Cos'è &questo? + + + + Shift+F1 + + + + + &About + &Informazioni + + + + &Recently opened + &Aperti di recente + + + + Open &tab + Apri &scheda + + + + This button opens a new tab for the SQL editor + Questo pulsante apre una nuova schede dell'editor SQL + + + + &Execute SQL + &Esegui SQL + + + + This button executes the currently selected SQL statements. If no text is selected, all SQL statements are executed. + Questo pulsante esegue gli statement SQL evidenziati. Se nessun testo è selezionato, tutti gli statement SQL vengono eseguiti. + + + + + + Save SQL file + Salva file SQL + + + + &Load Extension... + &Carica Estensioni... + + + + + Execute current line + Esegue la riga corrente + + + + This button executes the SQL statement present in the current editor line + Questo pulsante esegue lo statement SQL presente nella riga corrente dell'editor + + + + Shift+F5 + + + + + Export as CSV file + Esporta come file CSV + + + + Export table as comma separated values file + Esporta la tabella come file CSV + + + + &Wiki + &Wiki + + + + Bug &Report... + Bug &Report... + + + + Feature Re&quest... + Richiesta &Funzionalità... + + + + Web&site + Sito &Web + + + + &Donate on Patreon... + &Dona su Patreon... + + + + + Save the current session to a file + Salva la sessione correte in un file + + + + Open &Project... + Apri &Progetto... + + + + + Load a working session from a file + Carica una sessione di lavoro da file + + + + &Attach Database... + &Collega Database... + + + + + Add another database file to the current database connection + Aggiunge un altro file di database alla connessione corrente + + + + This button lets you add another database file to the current database connection + Questo pulsante ti permette di aggiungere un altro file alla connessione corrente + + + + &Set Encryption... + &Imposta cifratura... + + + + + Save SQL file as + Salva file SQL come + + + + This button saves the content of the current SQL editor tab to a file + Questo pulsante salva il contenuto della scheda di editor SQL in un file + + + + &Browse Table + &Naviga Tabella + + + + Copy Create statement + Copia statement CREATE + + + + Copy the CREATE statement of the item to the clipboard + Copia lo statement CREATE negli appunti + + + + SQLCipher &FAQ + SLQCipher &FAQ + + + + Opens the SQLCipher FAQ in a browser window + Apre le SQLCipher FAQ in una finestra del browser + + + + Table(&s) to JSON... + Tabella(&e) in JSON... + + + + Export one or more table(s) to a JSON file + Esporta una o più tabelle in un file JSON + + + + Open Data&base Read Only... + Apri un Data&base in Sola Lettura... + + + + Open an existing database file in read only mode + Apre un file databse esistente in modalità sola lettura + + + + Save results + Salva risultati + + + + Save the results view + Salva i risultati della vista + + + + This button lets you save the results of the last executed query + Questo pulsante ti permette di salvare i risultati dell'ultima query eseguita + + + + + Find text in SQL editor + Trova testo nell'editor SQL + + + + This button opens the search bar of the editor + Questo pulsante apre la barra di ricerca dell'editor + + + + Ctrl+F + + + + + + Find or replace text in SQL editor + Trova e/o sostituisci testo nell'editor SQL + + + + This button opens the find/replace dialog for the current editor tab + Questo pulsante apre la finestra di ricerca/sostituzione testo per la scheda corrente dell'editor + + + + Ctrl+H + + + + + Export to &CSV + Esporta in &CSV + + + + Save as &view + Salva come &vista + + + + Save as view + Salva come vista + + + + Shows or hides the Project toolbar. + Mostra o nasconde la barra degli strumenti di progetto. + + + + Extra DB Toolbar + Barra degli strumenti DB estesa + + + + New In-&Memory Database + Nuovo Database In &Memoria + + + + Drag && Drop Qualified Names + Trascina && Rilascia Nomi Qualificati + + + + + Use qualified names (e.g. "Table"."Field") when dragging the objects and dropping them into the editor + Usa nomi qualificati (es. "Table"."Campo") quando trascini gli oggetti e li rilasci all'interno dell'editor + + + + Drag && Drop Enquoted Names + Trascina && Rilascia Nomi Quotati + + + + + Use escaped identifiers (e.g. "Table1") when dragging the objects and dropping them into the editor + Usa gl'identificatori di citazione (es. "Tabella1") quando trascini e rilasci gli oggetti nell'editor + + + + &Integrity Check + Controllo &Integrità + + + + Runs the integrity_check pragma over the opened database and returns the results in the Execute SQL tab. This pragma does an integrity check of the entire database. + Avvia il controllo integrità (integrity check pragma) sul database aperto e riporta il risultato nella scheda "Esegui SQL". Questa operazione esegue un controllo d'integrità sull'intero database. + + + + &Foreign-Key Check + Controlla Chiave &Esterna + + + + Runs the foreign_key_check pragma over the opened database and returns the results in the Execute SQL tab + Avvia il controllo chiavi esterne (foreign_key_check pragma) nel database aperto e riporta il risultato nella scheda "Esegui SQL" + + + + &Quick Integrity Check + Controllo Integrità &Veloce + + + + Run a quick integrity check over the open DB + Avvia un controllo veloce d'integrità sul DB aperto + + + + Runs the quick_check pragma over the opened database and returns the results in the Execute SQL tab. This command does most of the checking of PRAGMA integrity_check but runs much faster. + Avvia un controllo veloce d'integrità (quick_check pragma) sul database e riporta il risultato nella scheda "Esegui SQL". Quest comando esegue la maggiorparte dei controlli d'integrità del controllo completo, ma in modo molto più veloce. + + + + &Optimize + &Ottimizza + + + + Attempt to optimize the database + Prova ad ottimizzare il database + + + + Runs the optimize pragma over the opened database. This pragma might perform optimizations that will improve the performance of future queries. + Avvia l'ottimizzazione del database aperto. Questa operazione potrebbe eseguire delle ottimizzazione che miglioreranno le performance delle query future. + + + + + Print + Stampa + + + + Open a dialog for printing the text in the current SQL editor tab + Apre una finetra per la stampa del testo nella scheda dell'editor SQL + + + + Open a dialog for printing the structure of the opened database + Apre una finestra per la stampa della struttura del database aperto + + + + + Ctrl+P + + + + + Ctrl+F4 + + + + + Execute all/selected SQL + Esegui tutti gli SQL o quelli selezionati + + + + Ctrl+Return + + + + + Ctrl+L + + + + + Ctrl+D + + + + + Ctrl+I + + + + + Ctrl+E + + + + + Reset Window Layout + Ripristina disposizione finestra + + + + Alt+0 + + + + + The database is currenctly busy. + Il database è occupato. + + + + Click here to interrupt the currently running query. + Clicca qui per interrompere la query in esecuzione. + + + + Encrypted + Criptato + + + + Database is encrypted using SQLCipher + Il database è stato criptato utilizzando SQLCipher + + + + Read only + Sola lettura + + + + Database file is read only. Editing the database is disabled. + Il file di database è in sola lettura. Le modifiche al database sono disabilitate. + + + + Database encoding + Codifica Database + + + + + Choose a database file + Seleziona un file di database + + + + Could not open database file. +Reason: %1 + Impossibile aprire il file di database. +Motivo: %1 + + + + + + Choose a filename to save under + Seleziona un nome file per il salvataggio + + + + In-Memory database + Database In-Memoria + + + + Are you sure you want to delete the table '%1'? +All data associated with the table will be lost. + Sei sicuro di voler eliminare la tabella '%1'? +Tutti i dati associati alla tabella andranno perduti. + + + + Are you sure you want to delete the view '%1'? + Sei sicuro di voler eliminare la vista '%1'? + + + + Are you sure you want to delete the trigger '%1'? + Sei sicuro di voler eliminare il trigger '%1'? + + + + Are you sure you want to delete the index '%1'? + Sei sicuro di voler eliminare l'indice '%1'? + + + + Error: could not delete the table. + Errore: impssibile eliminare la tabella. + + + + Error: could not delete the view. + Errore: impossibile eliminare la vista. + + + + Error: could not delete the trigger. + Errore: impossibile eliminare il trigger. + + + + Error: could not delete the index. + Errore: impossibile eliminare l'indice. + + + + Message from database engine: +%1 + Messaggio dal database: +%1 + + + + Editing the table requires to save all pending changes now. +Are you sure you want to save the database? + Per modificare la tabella bisogna salvare tutte le modifiche pendenti. +Sei sicuro di voler salvare il database? + + + + Error checking foreign keys after table modification. The changes will be reverted. + Errore nel controllo delle chiavi esterne dopo le modifiche alla tabella. Le modifiche saranno eliminate. + + + + This table did not pass a foreign-key check.<br/>You should run 'Tools | Foreign-Key Check' and fix the reported issues. + Questa tabella non ha passato il controllo sulle chiavi esterne.<br/>Dovresti avviare 'Strumenti | Controllo Chiavi Esterne' e correggere i problemi riportati. + + + + Edit View %1 + Modifica vista %1 + + + + Edit Trigger %1 + Modifica Trigger %1 + + + + You are already executing SQL statements. Do you want to stop them in order to execute the current statements instead? Note that this might leave the database in an inconsistent state. + Sto eseguendo degli SQL. Vuoi fermarli per poter eseguire invece l'SQL corrente? Nota che questo potrebbe lasciare il database in uno stato inconsistente. + + + + -- EXECUTING SELECTION IN '%1' +-- + -- ESEGUO LA SELEZIONE IN '%1' +-- + + + + -- EXECUTING LINE IN '%1' +-- + -- ESEGUO LINEA IN '%1' +-- + + + + -- EXECUTING ALL IN '%1' +-- + -- ESEGUO TUTTO IN '%1' +-- + + + + + At line %1: + Alla riga %1: + + + + Result: %1 + Risultato: %1 + + + + Result: %2 + Risultato: %2 + + + + Opened '%1' in read-only mode from recent file list + Aperto '%1' in modalità solo lettura dalla lista dei file recenti + + + + Opened '%1' from recent file list + Aperto '%1' dalla lista di file recenti + + + + Project saved to file '%1' + Progetto salvato sul file '%1' + + + + This action will open a new SQL tab with the following statements for you to edit and run: + Questa azione aprirà una nuova scheda SQL con la seguente stringa SQL per permetterti di modificarla ed eseguirla + + + + Rename Tab + Rinomina il Tab + + + + Duplicate Tab + Duplica il Tab + + + + Close Tab + Chiudi il Tab + + + + Opening '%1'... + Apro '%1'... + + + + There was an error opening '%1'... + Errore durante l'apertura di '%1'... + + + + Value is not a valid URL or filename: %1 + Il valore non è un URL valida o nome file: %1 + + + + Setting PRAGMA values or vacuuming will commit your current transaction. +Are you sure? + Impostare i valori PRAGMA o pulizia chiuderanno la transazione corrente. +Sei sicuro? + + + + Execution finished with errors. + Esecuzione completata con errori. + + + + Execution finished without errors. + Esecuzione completata senza errori. + + + + %1 rows returned in %2ms + %1 righe ritornate in %2ms + + + + Choose text files + Seleziona i file di testo + + + + Error while saving the database file. This means that not all changes to the database were saved. You need to resolve the following error first. + +%1 + Errore nel salvataggio del database. Questo significa che non tutte le modifiche del database sono state salvate. Avrai bisogno di risolvere prima il seguente errore. + +%1 + + + + Are you sure you want to undo all changes made to the database file '%1' since the last save? + Sei sicuro di voler annullare tutte le modifiche effettuate al database '%1' dall'ultimo salvataggio? + + + + Choose a file to import + Seleziona un file da importare + + + + &%1 %2%3 + &%1 %2%3 + + + + (read only) + (sola lettura) + + + + Open Database or Project + Apri Database o Progetto + + + + Attach Database... + Collega Database... + + + + Import CSV file(s)... + Importa file(s) CSV... + + + + Select the action to apply to the dropped file(s). <br/>Note: only 'Import' will process more than one file. + + Seleziona l'azione da applicare al(ai) file(s) scartato(i). <br/>Nota: solo 'Importa' processa più di un file. + + + + + + Do you want to save the changes made to SQL tabs in the project file '%1'? + Vuoi salvare le modifiche effettuate ai tabs SQL nel file di progetto '%1'? + + + + Text files(*.sql *.txt);;All files(*) + File di testo(*.sql *.txt);;Tutti i files(*) + + + + Do you want to create a new database file to hold the imported data? +If you answer no we will attempt to import the data in the SQL file to the current database. + Vuoi creare un nuovo file di database per mantenere i dati importati? +Se rispondi di no proveremo ad importare i dati del file SQL all'interno del database corrente. + + + + Window Layout + Disposizione finestra + + + + Simplify Window Layout + Semplifica disposizione finestra + + + + Shift+Alt+0 + + + + + Dock Windows at Bottom + Blocca finestre in basso + + + + Dock Windows at Left Side + Blocca finestre al lato sinistro + + + + Dock Windows at Top + Blocca finestre in cima + + + + You are still executing SQL statements. Closing the database now will stop their execution, possibly leaving the database in an inconsistent state. Are you sure you want to close the database? + Sto ancora eseguendo comandi SQL. Se chiudi il database ora non verrano eseguiti, il database potrebbe rimanere in uno stato inconsistente. Sei sicuro di voler chiudere il database? + + + + Do you want to save the changes made to the project file '%1'? + Vuoi salvare le modifiche fatte al file di progetto '%1'? + + + + File %1 already exists. Please choose a different name. + Il file %1 esiste già. Si prega di scegliere un nome differente. + + + + Error importing data: %1 + Errore nell'importazione: %1 + + + + Import completed. Some foreign key constraints are violated. Please fix them before saving. + Importaizone completata. Alcuni vincoli per le chiavi esterne non sono rispettati. Si prega di correggerli prima di salvare. + + + + Import completed. + Import completato. + + + + Delete View + Elimina Vista + + + + Modify View + Modifica Vista + + + + Delete Trigger + Elimina Trigger + + + + Modify Trigger + Modifica Trigger + + + + Delete Index + Elimina Indice + + + + Modify Index + Modifica Indice + + + + Modify Table + Modifica Tabella + + + + Setting PRAGMA values will commit your current transaction. +Are you sure? + Impostare i valori di PRAGMA chiuderà la transaione corrente. +Sei sicuro? + + + + Do you want to save the changes made to SQL tabs in a new project file? + Vuoi salvare le modifiche effettuate alle schede SQL in un nuovo file di progetto? + + + + Do you want to save the changes made to the SQL file %1? + Vuoi salvare le modifiche fatte al file SQL %1? + + + + The statements in this tab are still executing. Closing the tab will stop the execution. This might leave the database in an inconsistent state. Are you sure you want to close the tab? + Gli SQL in questa scheda sono ancora in esecuzione. Chiudere la scheda bloccherà l'esecuzione. Questo potrebbe lasciare il database in uno stato inconsistente. Sei sicuro di voler chiudere la scheda? + + + + Select SQL file to open + Selezionare il file SQL da aprire + + + + Select file name + Seleziona il nome del file + + + + Select extension file + Seleziona l'estensione del file + + + + Extension successfully loaded. + Estensione caricata con successo. + + + + Error loading extension: %1 + Errore nel caricamento dell'estensione: %1 + + + + Could not find resource file: %1 + Non posso aprire il file di risorse: %1 + + + + + Don't show again + Non mostrare di nuovo + + + + New version available. + Nuova versione disponibile. + + + + A new DB Browser for SQLite version is available (%1.%2.%3).<br/><br/>Please download at <a href='%4'>%4</a>. + Una nuova versione di DB Browser for SQLite è disponibile (%1.%2.%3).<br/><br/>Si prega di scaricarla da <a href='%4'>%4</a>. + + + + Choose a project file to open + Seleziona un file di progetto da aprire + + + + DB Browser for SQLite project file (*.sqbpro) + File di progetto DB Browser for SQLite (*.sqbpro) + + + + This project file is using an old file format because it was created using DB Browser for SQLite version 3.10 or lower. Loading this file format is still fully supported but we advice you to convert all your project files to the new file format because support for older formats might be dropped at some point in the future. You can convert your files by simply opening and re-saving them. + Questo file di progetto utilizza un vecchio formato poiché è stato creato con la versione 3.10 o antecedente. Il caricamento di questo formato è ancora supportato, ma ti suggeriamo di convertire tutti i tuoi files di progetto al nuovo formato poiché il supporto ai formati precedenti potrebbe essere eliminato in futuro. Puoi convertire i tuoi file semplicemente aprendoli e salvandoli nuovamente. + + + + Could not open project file for writing. +Reason: %1 + Non posso scrivere nel file di progetto. +Motivo: %1 + + + + Collation needed! Proceed? + Necessario confronto! Procedo? + + + + A table in this database requires a special collation function '%1' that this application can't provide without further knowledge. +If you choose to proceed, be aware bad things can happen to your database. +Create a backup! + Una tabella di questo database richiede una funzione di confronto speciale '%1' che questa applicazione non può fornire senza ulteriori informazioni. +Se scegli di proseguire, sappi che potrebbero generarsi problemi nel tuo database. +Crea un backup! + + + + creating collation + creo confronto + + + + Set a new name for the SQL tab. Use the '&&' character to allow using the following character as a keyboard shortcut. + Imposta un nuovo nome per la scheda SQL. Usa il carattere '&&' per utilizzare il carattere succesivo come scorciatoia da tastiera. + + + + Please specify the view name + Si prega di specificare il nome della vista + + + + There is already an object with that name. Please choose a different name. + Esiste già un oggetto con quel nome. Si prega di scegliere un nome diverso. + + + + View successfully created. + Vista creata con successo. + + + + Error creating view: %1 + Errore nella creazione della vista: %1 + + + + This action will open a new SQL tab for running: + Questa azione aprirà una nuova scheda SQL per eseguire: + + + + Press Help for opening the corresponding SQLite reference page. + Premi Aiuto per aprire la pagina di riferimento SQLite corrispondente. + + + + Busy (%1) + Occupato (%1) + + + + NullLineEdit + + + Set to NULL + Imposta a NULL + + + + Alt+Del + + + + + PlotDock + + + Plot + Grafico + + + + <html><head/><body><p>This pane shows the list of columns of the currently browsed table or the just executed query. You can select the columns that you want to be used as X or Y axis for the plot pane below. The table shows detected axis type that will affect the resulting plot. For the Y axis you can only select numeric columns, but for the X axis you will be able to select:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Date/Time</span>: strings with format &quot;yyyy-MM-dd hh:mm:ss&quot; or &quot;yyyy-MM-ddThh:mm:ss&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Date</span>: strings with format &quot;yyyy-MM-dd&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Time</span>: strings with format &quot;hh:mm:ss&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Label</span>: other string formats. Selecting this column as X axis will produce a Bars plot with the column values as labels for the bars</li><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Numeric</span>: integer or real values</li></ul><p>Double-clicking the Y cells you can change the used color for that graph.</p></body></html> + <html><head/><body><p>Questo pannello mostra la lista delle colonne della tabella corrente o della query eseguita. Puoi selezionare la colonna che vuoi utilizzare come asse X o Y per il grafico sottostante. La tabella mostra i tipi d'asse rilevati. Per l'asse Y puoi selezionare solo colonne numeriche, ma per l'asse X potrai selezionare:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Data/Ora</span>: stringhe col formato &quot;aaaa-MM-gg hh:mm:ss&quot; o &quot;aaaa-MM-ggThh:mm:ss&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Data</span>: stringhe col formato &quot;aaaa-MM-dd&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Orario</span>: stringhe col formato &quot;hh:mm:ss&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Etichette</span>: altri formati di stringa. Selezionando queste colonne come X verrà visualizzato un grafico a barre</li><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Numeri</span>: interi or valori reali</li></ul><p>Cliccando due volte sulle celle Y potrai cambiare il colore utilizzato per il grafico.</p></body></html> + + + + Columns + Colonne + + + + X + + + + + Y1 + Y1 + + + + Y2 + Y2 + + + + Axis Type + Tipo asse + + + + Here is a plot drawn when you select the x and y values above. + +Click on points to select them in the plot and in the table. Ctrl+Click for selecting a range of points. + +Use mouse-wheel for zooming and mouse drag for changing the axis range. + +Select the axes or axes labels to drag and zoom only in that orientation. + Qui compare il grafico quando vengono selezionati i valori x e y. + +Clicca s'un punto per selezionarl sul grafico e nella tabella. Ctrl+Click per selezionare un intervallo di punti. + +Usa la rotella del mouse per ingrandire e trascina col mouse per cambiare l'intervallo degli assi. + +Seleziona le etichette dell'asse o degli assi per trascinare o ingrandire solo in quella direzione. + + + + Line type: + Tipo linea: + + + + + None + Nessuna + + + + Line + Linea + + + + StepLeft + Salto sinistro + + + + StepRight + Salto destro + + + + StepCenter + Salto centrato + + + + Impulse + Impulso + + + + Point shape: + Tipo punta: + + + + Cross + Croce + + + + Plus + Più + + + + Circle + Cerchio + + + + Disc + Disco + + + + Square + Quadrato + + + + Diamond + Rombo + + + + Star + Stella + + + + Triangle + Triangolo + + + + TriangleInverted + Triangolo inverso + + + + CrossSquare + Croce quadrato + + + + PlusSquare + Più quadrato + + + + CrossCircle + Croce cerchio + + + + PlusCircle + Più cerchio + + + + Peace + Pace + + + + <html><head/><body><p>Save current plot...</p><p>File format chosen by extension (png, jpg, pdf, bmp)</p></body></html> + <html><head/><body><p>Salva il grafico corrente...</p><p>Formato file selezionato dall'estensione (png, jpg, pdf, bmp)</p></body></html> + + + + Save current plot... + Salva il grafico corrente... + + + + + Load all data and redraw plot + Carica tutti i dati e ridisegna grafico + + + + Copy + Copia + + + + Print... + Stampa... + + + + Show legend + Mostra legenda + + + + Stacked bars + Barre impilate + + + + Date/Time + Data/Ora + + + + Date + Data + + + + Time + Ora + + + + + Numeric + Numerico + + + + Label + Etichetta + + + + Invalid + Invalido + + + + + + Row # + Riga # + + + + Load all data and redraw plot. +Warning: not all data has been fetched from the table yet due to the partial fetch mechanism. + Carica tutti i dati e ridisegna grafico. +Attenzione: non sono ancora stati recuperati tutti i dati dalla tabella a causa del meccanismo di recupero. + + + + Choose an axis color + Scegli il colore per l'asse + + + + Choose a filename to save under + Scegli il nome di salvataggio + + + + PNG(*.png);;JPG(*.jpg);;PDF(*.pdf);;BMP(*.bmp);;All Files(*) + + + + + There are curves in this plot and the selected line style can only be applied to graphs sorted by X. Either sort the table or query by X to remove curves or select one of the styles supported by curves: None or Line. + Ci sono delle curve in questo grafico e lo stile di line selezionato può essere applicato solo a grafici ordinati per X. Riordina la tabella o seleziona per X per rimuovere le curve o seleziona uno degli stili supportati dalle curve: Nessuno o Linea. + + + + Loading all remaining data for this table took %1ms. + Caricare tutti i dati restanti per questa tabella ha richiesto %1ms. + + + + PreferencesDialog + + + Preferences + Preferenze + + + + &General + &Generale + + + + Default &location + &Posizione di default + + + + Remember last location + Ricorda l'ultima posizione + + + + Always use this location + Usa sempre questa posizione + + + + Remember last location for session only + Ricorda l'ultima posizione solo per questa sessione + + + + + + ... + + + + + Lan&guage + Lin&gua + + + + Toolbar style + Stile barra degli strumenti + + + + + + + + Only display the icon + Mostra solo le icone + + + + + + + + Only display the text + Mostra solo il testo + + + + + + + + The text appears beside the icon + Mostra il testo a lato delle icone + + + + + + + + The text appears under the icon + Mostra il testo sotto le icone + + + + + + + + Follow the style + Segui lo stile + + + + Show remote options + Mostra opzioni remote + + + + + + + + + + + + enabled + abilitato + + + + Automatic &updates + Aggiornamenti a&utomatici + + + + DB file extensions + Estensioni file DB + + + + Manage + Gestisci + + + + Main Window + Finestra principale + + + + Database Structure + Struttura database + + + + Browse Data + Naviga nei dati + + + + Execute SQL + Esegui SQL + + + + Edit Database Cell + Modifica Cella Database + + + + When this value is changed, all the other color preferences are also set to matching colors. + Quando questo valore viene modificato, tutte le altre preferenze di colore vengono impostate al colore corrispondente. + + + + Follow the desktop style + Segui lo stile del desktop + + + + Dark style + Stile scuro + + + + Application style + Stile Applicazione + + + + This sets the font size for all UI elements which do not have their own font size option. + Questo imposta la dimensione del testo per tutti gli elementi dell'interfaccia che non hanno una loro opzione specifica. + + + + Font size + Dimensione testo + + + + &Database + + + + + Database &encoding + &Codifica Database + + + + Open databases with foreign keys enabled. + Apri database contenenti chiavi esterne. + + + + &Foreign keys + Chiavi &Esterne + + + + Remove line breaks in schema &view + Rimuovi a-capo nella &vista dello schema + + + + When enabled, the line breaks in the Schema column of the DB Structure tab, dock and printed output are removed. + Quando abilitato, vengono rimossi gli a-capo nella colonna dello Schema del tab "Struttura DB", dock e stampa. + + + + Prefetch block si&ze + &Dimensione blocco di prefetch + + + + SQ&L to execute after opening database + SQ&L da eseguire dopo aver aperto il database + + + + Default field type + Tipo di campo di default + + + + Database structure font size + Dimensione testo per la struttura del database + + + + Data &Browser + + + + + Font + + + + + &Font + + + + + Font si&ze + Dimensione te&sto + + + + Content + Contenuto + + + + Symbol limit in cell + Limite simboli nella cella + + + + This is the maximum number of items allowed for some computationally expensive functionalities to be enabled: +Maximum number of rows in a table for enabling the value completion based on current values in the column. +Maximum number of indexes in a selection for calculating sum and average. +Can be set to 0 for disabling the functionalities. + Questo è il numero massimo di oggetti permessi per l'esecuzione di alcune funzioni computazionalmente intense: +Massimo numero di righe in una tabella per abilitare l'autocompletamento basato sui valori correnti di una colonna. +Massimo numero di indici in una selezione per calcolare somma e media. +Può essere impostato a 0 per disabilitare le funzionalità. + + + + This is the maximum number of rows in a table for enabling the value completion based on current values in the column. +Can be set to 0 for disabling completion. + Questo è il numero massimo di righe in una tabella per abilitare il completamento dei valori basandosi su quelli attualmente nella colonna. +Può essere impostato a 0 per disabilitare il completamento. + + + + Field display + Visualizzazione campi + + + + Displayed &text + &Testo visualizzato + + + + Binary + Binario + + + + NULL + + + + + Regular + Normale + + + + + + + + + Click to set this color + Clicca per impostare questo colore + + + + Text color + Colore del testo + + + + Background color + Colore dello sfondo + + + + Preview only (N/A) + Solo anteprima (N/A) + + + + Filters + Filtri + + + + Escape character + Carattere di escape + + + + Delay time (&ms) + Ritardo (&ms) + + + + Set the waiting time before a new filter value is applied. Can be set to 0 for disabling waiting. + Imposta il tempo d'attesa prima che un nuovo filtro venga applicato. Può essere impostato a 0 per disabilitare l'attesa. + + + + &SQL + &SQL + + + + Settings name + Nome impostazioni + + + + Context + Contesto + + + + Colour + Colore + + + + Bold + Grassetto + + + + Italic + Corsivo + + + + Underline + Sottolinea + + + + Keyword + Parola chiave + + + + Function + Funzione + + + + Table + Tabella + + + + Comment + Commento + + + + Identifier + Identificatore + + + + String + Stringa + + + + Current line + Linea corrente + + + + Background + Sfondo + + + + Foreground + Primo piano + + + + SQL editor &font + &Font editor SQL + + + + SQL &editor font size + Dimensione font &editor SQL + + + + SQL &results font size + Dimensione font &risultati SQL + + + + Tab size + Dimensione tabulazione + + + + &Wrap lines + &A-capo automatico + + + + Never + Mai + + + + At word boundaries + Al limite della parola + + + + At character boundaries + Al limite del carattere + + + + At whitespace boundaries + Al limite del carattere vuoto + + + + &Quotes for identifiers + Identificatori per &citazioni + + + + Choose the quoting mechanism used by the application for identifiers in SQL code. + Scegli il tipo meccanismo di citazione utilizzato per il codice SQL. + + + + "Double quotes" - Standard SQL (recommended) + "Doppie virgolette" - Standard SQL (raccomandato) + + + + `Grave accents` - Traditional MySQL quotes + `Apice inverso` - Citazione tradizionale MySQL + + + + [Square brackets] - Traditional MS SQL Server quotes + [Parentesi quadre] - Citazione tradizionale MS SQL Server + + + + Code co&mpletion + Auto co&mpletamento + + + + Keywords in &UPPER CASE + Parole chiave &MAIUSCOLE + + + + When set, the SQL keywords are completed in UPPER CASE letters. + Quando impostato, le parole chiave vengono completate in MAIUSCOLO. + + + + Error indicators + Indicatori d'errore + + + + When set, the SQL code lines that caused errors during the last execution are highlighted and the results frame indicates the error in the background + Quando impostato, le righe di codice SQL che causano errori durante l'ultima esecuzione sono evidenziate e il campo del risultato indica l'errore sullo sfondo + + + + Hori&zontal tiling + Affianca &orizzontalmente + + + + If enabled the SQL code editor and the result table view are shown side by side instead of one over the other. + Se abilitato l'editor di codice SQL e la tabella del risultato sono mostrate una accanto all'altra anzichè una sopra l'altra. + + + + Close button on tabs + Pulsante di chiusura sulle schede + + + + If enabled, SQL editor tabs will have a close button. In any case, you can use the contextual menu or the keyboard shortcut to close them. + Se abilitato, le schede dell'editor SQL avranno un pulsante di chiusura. In ogni caso, puoi utilizzare il menù contestuale o le scorciatoie da tastiera per chiuderle. + + + + &Extensions + &Estensioni + + + + Select extensions to load for every database: + Seleziona le estensioni da caricare per ogni database: + + + + Add extension + Aggiungi estensione + + + + Remove extension + Rimuovi estensione + + + + <html><head/><body><p>While supporting the REGEXP operator SQLite doesn't implement any regular expression<br/>algorithm but calls back the running application. DB Browser for SQLite implements this<br/>algorithm for you to let you use REGEXP out of the box. However, as there are multiple possible<br/>implementations of this and you might want to use another one, you're free to disable the<br/>application's implementation and load your own by using an extension. Requires restart of the application.</p></body></html> + <html><head/><body><p>Anche se SQLite supporta l'operatore REGEXP non implementa alcun algoritmo<br/>di espressione regolare, ma richiama l'applicativo in esecuzione. DB Browser for SQLite implementa questo<br/>algoritmo per te per permetterti di usare le REGEXP immediatamente. Ci sono però multiple implementazioni<br/>possibili e potresti voler utilizzare una o l'altra, sei libero di disabilitare l'implementazione<br/>dell'applicativo e caricare la tua utilizzando un'estensione. Richiede il riavvio dell'applicativo.</p></body></html> + + + + Disable Regular Expression extension + Disabilita l'estensione per l'Espressione regolare + + + + <html><head/><body><p>SQLite provides an SQL function for loading extensions from a shared library file. Activate this if you want to use the <span style=" font-style:italic;">load_extension()</span> function from SQL code.</p><p>For security reasons, extension loading is turned off by default and must be enabled through this setting. You can always load extensions through the GUI, even though this option is disabled.</p></body></html> + <html><head/><body><p>SQLite fornisce una funzione SQL per il cariamento di estensioni da una libreria dinamica condivisa. Attiva questa opzione se vuoi utilizzare la funzione<span style=" font-style:italic;">load_extension()</span> dal codice SQL.</p><p>Per motivi di sicurezza, il caricamento delle estensioni è disabilitato di default e dev'essere abilitato tramite questa impostazione. Puoi sempre caricare le estensioni attraverso l'interfaccia grafica, anche se quest'opzione è disabilitata.</p></body></html> + + + + Allow loading extensions from SQL code + Permetti il caricamento di estensioni dal codice SQL + + + + Remote + Remoto + + + + CA certificates + Certificati CA + + + + Proxy + Proxy + + + + Configure + Configura + + + + + Subject CN + Soggetto CN + + + + Common Name + Nome comune + + + + Subject O + Soggetto O + + + + Organization + Organizzazione + + + + + Valid from + Valido dal + + + + + Valid to + Valido al + + + + + Serial number + Numero di serie + + + + Your certificates + Tuo certificato + + + + Threshold for completion and calculation on selection + Soglia per l'autocompletamento e il calcolo sulla selezione + + + + Show images in cell + Mostra immagini nella cella + + + + Enable this option to show a preview of BLOBs containing image data in the cells. This can affect the performance of the data browser, however. + Abilita questa opzione per mostrare un'anteprima dei BLOBs contenti dati immagine nella cella. Questo potrebbe impattare sulle performance. + + + + File + File + + + + Subject Common Name + Nome comune del soggetto + + + + Issuer CN + CN emittente + + + + Issuer Common Name + Nome comune emittente + + + + Clone databases into + Clona il database in + + + + + Choose a directory + Seleziona una cartella + + + + The language will change after you restart the application. + La lingua verrà modificata dopo il riavvio dell'applicativo. + + + + Select extension file + Seleziona il file d'estensione + + + + Extensions(*.so *.dylib *.dll);;All files(*) + Estensioni(*.so *.dylib *.dll);;Tutti i files(*) + + + + Import certificate file + Importa il file di certificato + + + + No certificates found in this file. + Nessun certificato trovato in questo file. + + + + Are you sure you want do remove this certificate? All certificate data will be deleted from the application settings! + Sei sicuro di voler rimuovere questo certificato? Tutti i dati del certificato saranno eliminati dalle impostazioni dell'applicativo! + + + + Are you sure you want to clear all the saved settings? +All your preferences will be lost and default values will be used. + Sei sicuro di voler pulire tutte le impostazioni salvate? +Tutte le tue preferenze andranno perse e verranno utilizzati i valori predefiniti. + + + + ProxyDialog + + + Proxy Configuration + Configurazione proxy + + + + Pro&xy Type + Tipo Pro&xy + + + + Host Na&me + No&me host + + + + Port + Porta + + + + Authentication Re&quired + Autenticazione ri&chiesta + + + + &User Name + Nome &Utente + + + + Password + Password + + + + None + Nessuna + + + + System settings + Impostazioni di sistema + + + + HTTP + HTTP + + + + Socks v5 + Socks v5 + + + + QObject + + + All files (*) + Tutti i files (*) + + + + Error importing data + Errore nell'import dei dati + + + + from record number %1 + dalla riga numero %1 + + + + . +%1 + . +%1 + + + + Importing CSV file... + Importa file CSV... + + + + Cancel + Annulla + + + + SQLite database files (*.db *.sqlite *.sqlite3 *.db3) + File database SQLite (*.db *.sqlite *.sqlite3 *.db3) + + + + SQLite Database Files (*.db *.sqlite *.sqlite3 *.db3) + SQLite Database Files (*.db *.sqlite *.sqlite3 *.db3) + + + + DB Browser for SQLite Project Files (*.sqbpro) + File di progetto DB Browser for SQLite (*.sqbpro) + + + + SQL Files (*.sql) + SQL Files (*.sql) + + + + All Files (*) + Tutti i files (*) + + + + Text Files (*.txt) + File testuali (*.txt) + + + + Comma-Separated Values Files (*.csv) + File con valori separati da virgola (*.csv) + + + + Tab-Separated Values Files (*.tsv) + Files con valori separati da tabulazione (*.tsv) + + + + Delimiter-Separated Values Files (*.dsv) + Files con valori separati da delimitatore (*.dsv) + + + + Concordance DAT files (*.dat) + File DAT Concordance (*.dat) + + + + JSON Files (*.json *.js) + JSON Files (*.json *.js) + + + + XML Files (*.xml) + XML Files (*.xml) + + + + Binary Files (*.bin *.dat) + Files binari (*.bin *.dat) + + + + SVG Files (*.svg) + SVG Files (*.svg) + + + + Hex Dump Files (*.dat *.bin) + Hex Dump Files (*.dat *.bin) + + + + Extensions (*.so *.dylib *.dll) + Estensioni (*.so *.dylib *.dll) + + + + Left + Sinistra + + + + Right + Destra + + + + Center + Centrato + + + + Justify + Giustificato + + + + RemoteCommitsModel + + + Commit ID + ID Invio + + + + Message + Messaggio + + + + Date + Data + + + + Author + Autore + + + + Size + Dimensione + + + + Authored and committed by %1 + Creato e inviato da %1 + + + + Authored by %1, committed by %2 + Creato da %1, inviato da %2 + + + + RemoteDatabase + + + Error opening local databases list. +%1 + Errore nell'apertura della lista di database locale. +%1 + + + + Error creating local databases list. +%1 + Errore nella creazione della lista di database locale. +%1 + + + + RemoteDock + + + Remote + Remoto + + + + Identity + Identità + + + + Push currently opened database to server + Invia il database corrente al server + + + + DBHub.io + DBHub.io + + + + <html><head/><body><p>In this pane, remote databases from dbhub.io website can be added to DB Browser for SQLite. First you need an identity:</p><ol style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Login to the dbhub.io website (use your GitHub credentials or whatever you want)</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Click the button to &quot;Generate client certificate&quot; (that's your identity). That'll give you a certificate file (save it to your local disk).</li><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Go to the Remote tab in DB Browser for SQLite Preferences. Click the button to add a new certificate to DB Browser for SQLite and choose the just downloaded certificate file.</li></ol><p>Now the Remote panel shows your identity and you can add remote databases.</p></body></html> + <html><head/><body><p>In questo pannello, possono essere aggiunti a DB Browser for SQLite i database dal sito web dbhub.io. Prima hai bisogno di un'identità:</p><ol style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Accedi al sito web dbhub.io (usa le tue credenziali GitHub o qualsiasi cosa tu voglia)</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Clicca il pulsante per &quot;Generare un certificato cliente&quot; (la tua identità). Questo di darà un file certificato (da salvare sul to disco locale).</li><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Vai alla scheda Remoto nelle preferenze di DB Browser for SQLite. Clicca il pulsante per aggiungere un nuovo certificato a DB Browser for SQLite e scegli il file di certificato appena scaricato.</li></ol><p>Ora il pannello Remoto ti mostrerà la tua identità e potrai aggiungere database remoti.</p></body></html> + + + + Local + Locale + + + + Current Database + Database Corrente + + + + Clone + Clona + + + + User + Utente + + + + Database + Database + + + + Branch + Ramo + + + + Commits + Invii + + + + Commits for + Invii per + + + + Delete Database + Elimina Database + + + + Delete the local clone of this database + Elimina il clone locale di questo database + + + + Open in Web Browser + Apri in nel Web Browser + + + + Open the web page for the current database in your browser + Apre la pagina web per il database corrente nel tuo browser + + + + Clone from Link + Clona dal collegamento + + + + Use this to download a remote database for local editing using a URL as provided on the web page of the database. + Usa questo per scaricare un database remoto per modificarlo in locale usando un URL come fornito sulla pagina web del database. + + + + Refresh + Aggiorna + + + + Reload all data and update the views + Ricarica tutti i dati e aggiorna le viste + + + + F5 + + + + + Clone Database + Clona Database + + + + Open Database + Apri Database + + + + Open the local copy of this database + Apre una copia locale di questo database + + + + Check out Commit + Scarica invio + + + + Download and open this specific commit + Scarica e apre questo specifico invio + + + + Check out Latest Commit + Scarica l'ultimo invio + + + + Check out the latest commit of the current branch + Scarica l'invio più recente per il ramo corrente + + + + Save Revision to File + Salva la revisione su file + + + + Saves the selected revision of the database to another file + Salva la revisione selezionata del database s'un altro file + + + + Upload Database + Carica Database + + + + Upload this database as a new commit + Carica questo database come nuovo invio + + + + <html><head/><body><p>You are currently using a built-in, read-only identity. For uploading your database, you need to configure and use your DBHub.io account.</p><p>No DBHub.io account yet? <a href="https://dbhub.io/"><span style=" text-decoration: underline; color:#007af4;">Create one now</span></a> and import your certificate <a href="#preferences"><span style=" text-decoration: underline; color:#007af4;">here</span></a> to share your databases.</p><p>For online help visit <a href="https://dbhub.io/about"><span style=" text-decoration: underline; color:#007af4;">here</span></a>.</p></body></html> + <html><head/><body><p>Stai attulamente utilizzando un profilo interno in sola lettura. Per caricare i tuoi database, devi configurare e usare un account DBHub.io.</p><p>Non hai ancora un account DBHub.io? <a href="https://dbhub.io/"><span style=" text-decoration: underline; color:#007af4;">Creane uno adesso</span></a> e importa il tuo certificato <a href="#preferences"><span style=" text-decoration: underline; color:#007af4;">qui</span></a> per condividere i tuoi databases.</p><p>Per aiuto online clicca <a href="https://dbhub.io/about"><span style=" text-decoration: underline; color:#007af4;">qui</span></a>.</p></body></html> + + + + Back + Indietro + + + + Select an identity to connect + Seleziona un'identità per connetterti + + + + Public + Pubblico + + + + This downloads a database from a remote server for local editing. +Please enter the URL to clone from. You can generate this URL by +clicking the 'Clone Database in DB4S' button on the web page +of the database. + Questo scarica un database ad un server remoto per modificarlo localmente. +Si prega d'inserire l'URL da clonare. Puoi generare questa URL cliccando +il pulsante 'Clona Database in DB4S' sulla pagina web del database. + + + + Invalid URL: The host name does not match the host name of the current identity. + URL non valida: Il nome dell'host non corrisponde al nome dell'host dell'identità corrente. + + + + Invalid URL: No branch name specified. + URL non valida: Nessun ramo specificato. + + + + Invalid URL: No commit ID specified. + URL non valida: Nessun ID Invio specificato. + + + + You have modified the local clone of the database. Fetching this commit overrides these local changes. +Are you sure you want to proceed? + Hai modificato il clone locale del database. Recuperare questo commit sovrascriverà le modifiche locali. +Sei sicuro di voler proseguire? + + + + The database has unsaved changes. Are you sure you want to push it before saving? + Il database ha delle modifiche non salvate. Sei sicuro di volerlo inviare prima di salvare? + + + + The database you are trying to delete is currently opened. Please close it before deleting. + Il database che stai provando a cancellare è attualmente aperto. Si prega di chiuderlo prima d'eliminarlo. + + + + This deletes the local version of this database with all the changes you have not committed yet. Are you sure you want to delete this database? + Questo elimina la versione locale di questo database con tutte le modifiche che non hai ancora inviato. Sei sicuro di voler eliminare questo database? + + + + RemoteLocalFilesModel + + + Name + Nome + + + + Branch + Ramo + + + + Last modified + Ultima modifca + + + + Size + Dimensione + + + + Commit + Invio + + + + File + File + + + + RemoteModel + + + Name + Nome + + + + Commit + Commit + + + + Last modified + Ultima modifca + + + + Size + Dimensione + + + + Size: + Dimensione: + + + + Last Modified: + Ultima modifica: + + + + Licence: + Licenza: + + + + Default Branch: + Ramo di default: + + + + RemoteNetwork + + + Choose a location to save the file + Scegli una posizione per salvare il file + + + + Error opening remote file at %1. +%2 + Errore aprendo il file remoto a %1. +%2 + + + + Error: Invalid client certificate specified. + Errore: specificato certificato invalido per il client. + + + + Please enter the passphrase for this client certificate in order to authenticate. + Si prega d'inserire la passphrase per questo certificato di client in modo da permetterne l'autenticazione. + + + + Cancel + Annulla + + + + Uploading remote database to +%1 + Carico il database remoto in +%1 + + + + Downloading remote database from +%1 + Scarico il database remoto da +%1 + + + + + Error: The network is not accessible. + Errore: Rete non disponibile. + + + + Error: Cannot open the file for sending. + Errore:Impossibile aprire il file per l'invio. + + + + RemotePushDialog + + + Push database + Invia database + + + + Database na&me to push to + No&me del database a cui inviare + + + + Commit message + Messaggio di commit + + + + Database licence + Licenza database + + + + Public + Pubblico + + + + Branch + Branch + + + + Force push + Forza invio + + + + Username + Nome utente + + + + Database will be public. Everyone has read access to it. + Il database sarà pubblico. Chiunque potrà accedere in lettura. + + + + Database will be private. Only you have access to it. + Il database sarà privato. Solo tu potrai accedervi. + + + + Use with care. This can cause remote commits to be deleted. + Usa con cautela. Questo può eliminare dei commit remoti. + + + + RunSql + + + Execution aborted by user + Esecuzione terminata dall'utente + + + + , %1 rows affected + , %1 righe modificate + + + + query executed successfully. Took %1ms%2 + query eseguita con successo. Impiegati %1ms%2 + + + + executing query + query in esecuzione + + + + SelectItemsPopup + + + A&vailable + &Disponibile + + + + Sele&cted + Se&lezionato + + + + SqlExecutionArea + + + Form + + + + + Find previous match [Shift+F3] + Trova corrispondenza precedente [Shift+F3] + + + + Find previous match with wrapping + Trova la corrispondenza precedente con reinizio + + + + Shift+F3 + + + + + The found pattern must be a whole word + Il pattern trovato deve essere una parola intera + + + + Whole Words + Parole intere + + + + Text pattern to find considering the checks in this frame + Il pattern da cercare considerando le spunte in quest'area + + + + Find in editor + Trova nell'editor + + + + The found pattern must match in letter case + Il patter trovato deve corrispondere esattamente (maiuscole/minuscole) incluse + + + + Case Sensitive + Case Sensitive + + + + Find next match [Enter, F3] + Trova la prossima corrispondenza [Invio, F3] + + + + Find next match with wrapping + Trova la prossima corrispondenza con reinizio + + + + F3 + + + + + Interpret search pattern as a regular expression + Interpreta il pattern di ricerca come un'espressione regolare + + + + <html><head/><body><p>When checked, the pattern to find is interpreted as a UNIX regular expression. See <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>.</p></body></html> + <html><head/><body><p>Quando selezionato, la stringa del testo viene interpretata come una RegExp Unix. Vedi <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Espressioni regolari su Wikibooks (in inglese)</a>.</p></body></html> + + + + Regular Expression + Espressione regolare + + + + + Close Find Bar + Chiudi la barra di ricerca + + + + <html><head/><body><p>Results of the last executed statements.</p><p>You may want to collapse this panel and use the <span style=" font-style:italic;">SQL Log</span> dock with <span style=" font-style:italic;">User</span> selection instead.</p></body></html> + <html><head/><body><p>Risultati degli ultimi statements eseguiti.</p><p>Potresti voler rimpicciolire questo pannello e usare la casella <span style=" font-style:italic;">SQL Log</span> con la selezione dell'<span style=" font-style:italic;">Utente</span>.</p></body></html> + + + + Results of the last executed statements + Risultato degli 'ultimi statement eseguiti + + + + This field shows the results and status codes of the last executed statements. + Questo campo mostra i risultati e i codici di stato degli ultimi statements eseguiti. + + + + Couldn't read file: %1. + Impossibile leggere il file: %1. + + + + + Couldn't save file: %1. + Impossibile salvare il file: %1. + + + + Your changes will be lost when reloading it! + Le tue modifiche andranno perse quando ricaricherai! + + + + The file "%1" was modified by another program. Do you want to reload it?%2 + Il file "%1" è stato modificato da un altro programma. Vuoi ricaricarlo?%2 + + + + SqlTextEdit + + + Ctrl+/ + + + + + SqlUiLexer + + + (X) The abs(X) function returns the absolute value of the numeric argument X. + (X) La funzione abs(X) ritorna il valore assoluto dell'argomento numerico X. + + + + () The changes() function returns the number of database rows that were changed or inserted or deleted by the most recently completed INSERT, DELETE, or UPDATE statement. + () La funzione changes() ritorna il numero delle righe di database che sono state modificate o inserite o eliminate dallo statement INSERT, DELETE o UPDATE più recente. + + + + (X1,X2,...) The char(X1,X2,...,XN) function returns a string composed of characters having the unicode code point values of integers X1 through XN, respectively. + (X1, X2,...) La funzione char(X1,X2,...,XN) ritorna una stringa composta dai caratteri unicode rappresentati dai valori interi da X1 a XN. + + + + (X,Y,...) The coalesce() function returns a copy of its first non-NULL argument, or NULL if all arguments are NULL + (X,Y,...) La funzione coalesce(X,Y,...) ritorna una copia del suo primo argomento non NULL oppure NULL se tutti gli argomenti sono NULL + + + + (X,Y) The glob(X,Y) function is equivalent to the expression "Y GLOB X". + (X,Y) La funzione glob(X,Y) è equivalente all'espressione "Y GLOB X". + + + + (X,Y) The ifnull() function returns a copy of its first non-NULL argument, or NULL if both arguments are NULL. + (X,Y) La funzione ifnull(X,Y) ritorno una copia del suo primo argomento non NULL o NULL se entrambi gli argomenti sono NULL. + + + + (X,Y) The instr(X,Y) function finds the first occurrence of string Y within string X and returns the number of prior characters plus 1, or 0 if Y is nowhere found within X. + (X,Y) La funzione intstr(X,Y) trova la prima occorrenza della stringa Y all'interno della stringa X e ritorna il numero dei caratteri precedenti più 1 o 0 se Y non si trova all'interno di X. + + + + (X) The hex() function interprets its argument as a BLOB and returns a string which is the upper-case hexadecimal rendering of the content of that blob. + (X) La funzione hex() interpreta i suoi argomenti come un BLOB e ritorna una stringa corrispondente al rendering esadecimale maiuscolo del contenuto di quel blob. + + + + () The last_insert_rowid() function returns the ROWID of the last row insert from the database connection which invoked the function. + () La funzione last_insert_rowid() ritorna il ROWID dell'ultima riga inserita nella connessione database che ha invocato la funzione. + + + + (X) For a string value X, the length(X) function returns the number of characters (not bytes) in X prior to the first NUL character. + (X) La funzione lenght(X) ritorna per una stringa X, il numero di caratteri (non bytes) di X prima del primo carattere NUL. + + + + (X,Y) The like() function is used to implement the "Y LIKE X" expression. + (X,Y) La funzione like(X,Y) è utilizzata per implementare l'espressione "Y LIKE X". + + + + (X,Y,Z) The like() function is used to implement the "Y LIKE X ESCAPE Z" expression. + (X,Y,Z) La funzione like(X,Y,Z) è utilizzata per implementare l'espressione "Y LIKE X ESCAPE Z". + + + + (X) The load_extension(X) function loads SQLite extensions out of the shared library file named X. +Use of this function must be authorized from Preferences. + (X) La funzione load_extension(X) carica l'estensione SQLite da un file di libreria condivisa di nome X. +L'utilizzo di questa funzione dev'essere permesso tramite le Preferenze. + + + + (X,Y) The load_extension(X) function loads SQLite extensions out of the shared library file named X using the entry point Y. +Use of this function must be authorized from Preferences. + (X,Y) La funzione load_extension(X,Y) carica un'estensione SQLite da un file di libreria condivisa di nome X utilizzando il punto d'ingresso Y. +L'utilizzo di questa funzione dev'essere permesso tramite le Preferenze. + + + + (X) The lower(X) function returns a copy of string X with all ASCII characters converted to lower case. + (X) La funzione lower(X) ritorna una copia della stringa X con tutti i caratteri ASCII convertiti in minuscolo. + + + + (X) ltrim(X) removes spaces from the left side of X. + (X) La funzione ltrim(X) rimuove gli spazi dal lato sinistro di X. + + + + (X,Y) The ltrim(X,Y) function returns a string formed by removing any and all characters that appear in Y from the left side of X. + (X,Y) La funzione ltrim(X,Y) ritorna una stringa formata rimuovendo tutti i caratteri che compaiono in Y dal lato sinistro di X. + + + + (X,Y,...) The multi-argument max() function returns the argument with the maximum value, or return NULL if any argument is NULL. + (X,Y,...) La funzione multi-argomento max(X,Y,...) ritorna l'argomento con valore massimo o ritorna NULL se tutti gli argomenti sono NULL. + + + + (X,Y,...) The multi-argument min() function returns the argument with the minimum value. + (X,Y,...) La funzione multi-argomento min(X,Y,...) ritorna l'argomento con valore minore o NULL se tutti gli argomenti sono NULL. + + + + (X,Y) The nullif(X,Y) function returns its first argument if the arguments are different and NULL if the arguments are the same. + (X,Y) La funzione nullif(X,Y) ritorna il primo argomento se gli argomenti sono diversi e NULL se gli argomenti sono uguali. + + + + (FORMAT,...) The printf(FORMAT,...) SQL function works like the sqlite3_mprintf() C-language function and the printf() function from the standard C library. + (FORMAT,...) La funzione SQL printf(FORMAT,...) si comporta come la funzione del linguaggio C sqlite3_mprintf() e la funzione printf() della libreria standard C. + + + + (X) The quote(X) function returns the text of an SQL literal which is the value of its argument suitable for inclusion into an SQL statement. + (X) La funzione quote(X) ritorna il testo di un literale SQL il cui valore può essere incluso in uno statement SQL. + + + + () The random() function returns a pseudo-random integer between -9223372036854775808 and +9223372036854775807. + () La funzione random() ritorna un numero intero pseudo-casuale tra -9223372036854775808 e +9223372036854775807. + + + + (N) The randomblob(N) function return an N-byte blob containing pseudo-random bytes. + (N) La funzione randomblob(N) ritorna un blob di N-bytes contenenti dati pseudo-casuali. + + + + (X,Y,Z) The replace(X,Y,Z) function returns a string formed by substituting string Z for every occurrence of string Y in string X. + (X,Y,Z) La funzione replace(X,Y,Z) ritorna una striga formata sostituendo la stringa Z in ogni occorrenza della stringa Y nella stringa X. + + + + (X) The round(X) function returns a floating-point value X rounded to zero digits to the right of the decimal point. + (X) La funzione round(X) ritorna un valore in virgola mobile X arrotondato a 0 cifre decimali. + + + + (X,Y) The round(X,Y) function returns a floating-point value X rounded to Y digits to the right of the decimal point. + (X,Y) La funzione round(X,Y) ritorna un numero in virgola mobile X arrotondato a Y cifre decimali. + + + + (X) rtrim(X) removes spaces from the right side of X. + (X) La funzione rtrim(X) rimuove gli spazi dalla destra di X. + + + + (X,Y) The rtrim(X,Y) function returns a string formed by removing any and all characters that appear in Y from the right side of X. + (X,Y) La funzione rtrim(X,Y) ritorna una stringa formata rimuovendo tutti i caratteri che compaiono in Y dal lato destro di X. + + + + (X) The soundex(X) function returns a string that is the soundex encoding of the string X. + (X) La funzione soundex(X) ritorna una stringa che rappresenta la codifica soundex della stringa X. + + + + (X,Y) substr(X,Y) returns all characters through the end of the string X beginning with the Y-th. + (X,Y) La funzione substr(X,Y) ritorna tutti i caratteri dalla fine della stringa X iniziando dall'Y-esimo. + + + + (X,Y,Z) The substr(X,Y,Z) function returns a substring of input string X that begins with the Y-th character and which is Z characters long. + (X,Y,Z) La funzione substr(X,Y,Z) ritorna una sotto-stringa di X che inizia dal carattere Y-esimo e lunga Z caratteri. + + + + () The total_changes() function returns the number of row changes caused by INSERT, UPDATE or DELETE statements since the current database connection was opened. + () La funzione total_changes() ritorna il numero di righe modificate da INSERT, UPDATE o DELETE dall'apertura della connessione al database. + + + + (X) trim(X) removes spaces from both ends of X. + (X) La funzione trim(X) rimuove gli spazi da entrambi i lati di X. + + + + (X,Y) The trim(X,Y) function returns a string formed by removing any and all characters that appear in Y from both ends of X. + (X,Y) La funzione trim(X,Y) ritorna una stringa formata rimuovendo tutti i caratteri che compaiono in Y da entrambi i termini di X. + + + + (X) The typeof(X) function returns a string that indicates the datatype of the expression X. + (X) La funzione typeof(X) ritorna una stringa che indica il tipo di dato dell'espressione X. + + + + (X) The unicode(X) function returns the numeric unicode code point corresponding to the first character of the string X. + (X) La funzione unicode(X) ritorna il valore numerico in unicode corrispondente al primo carattere della stringa X. + + + + (X) The upper(X) function returns a copy of input string X in which all lower-case ASCII characters are converted to their upper-case equivalent. + (X) La funzione upper(X) ritorna una copia della stringa X in cui tutti i caratteri minuscoli ASCII sono stati converiti in maiuscolo. + + + + (N) The zeroblob(N) function returns a BLOB consisting of N bytes of 0x00. + (N) La funizione zeroblob(N) ritorna un BLOB di N byte di 0x00. + + + + + + + (timestring,modifier,modifier,...) + (stringa data,modificatore,modificatore,...) + + + + (format,timestring,modifier,modifier,...) + (formato,stringa data-ora,modificatore,modificatore,...) + + + + (X) The avg() function returns the average value of all non-NULL X within a group. + (X) La funzione avg(X) ritorna il valore medio di tutti gli X non-NULL in un gruppo. + + + + (X) The count(X) function returns a count of the number of times that X is not NULL in a group. + (X) La funzione count(X) ritorna il numero di volte che X non è NULL in un gruppo. + + + + (X) The group_concat() function returns a string which is the concatenation of all non-NULL values of X. + (X) La funzione group_concat(X) ritorna una stringa rappresentante la concatenazione di tutti i valori di X non-NULL. + + + + (X,Y) The group_concat() function returns a string which is the concatenation of all non-NULL values of X. If parameter Y is present then it is used as the separator between instances of X. + (X,Y) La funzione group_concat(X,Y) ritorna una stringa rappresentate la concatenazione di tutti i valori di X non-NULL. Se il parametro Y è presente allora è utilizzato come separatore tra le istanze di X. + + + + (X) The max() aggregate function returns the maximum value of all values in the group. + (X) La funzione aggregata max(X) ritorna il valore massimo di tutti i valori nel gruppo. + + + + (X) The min() aggregate function returns the minimum non-NULL value of all values in the group. + (X) La funzione aggregata min(X) ritorna il minore non-NULL tra tutti i valori del gruppo. + + + + + (X) The sum() and total() aggregate functions return sum of all non-NULL values in the group. + (X) Le funzioni aggregate sum(X) e total(X) ritornano la somma di tutti i valori non-NULL nel gruppo. + + + + () The number of the row within the current partition. Rows are numbered starting from 1 in the order defined by the ORDER BY clause in the window definition, or in arbitrary order otherwise. + () Il numero di righe all'interno della partizione corrente. Le righe sono numerate partendo da 1 nell'ordine definito dalla clausula ORDER BY nella finestra definizione, o altrimenti in ordine arbitrario. + + + + () The row_number() of the first peer in each group - the rank of the current row with gaps. If there is no ORDER BY clause, then all rows are considered peers and this function always returns 1. + () Il row_number() del primo peer in ogni gruppo - il rango della riga corrente con intervalli. Se non ci sono clausule ORDER BY, allora tutte le righe sono considerate peer e questa funzione ritorna 1. + + + + () The number of the current row's peer group within its partition - the rank of the current row without gaps. Partitions are numbered starting from 1 in the order defined by the ORDER BY clause in the window definition. If there is no ORDER BY clause, then all rows are considered peers and this function always returns 1. + () Il numero di peer nel gruppo della riga corrente all'interno della sua partizione - il rango della riga corrente senza intervalli. Le partizioni sono numerate a partire da 1 nell'ordine definito dalla clausula ORDER BY nella finestra definizione. Se non ci sono clausule ORDER BY allora tutte le righe sono considerate peer e questa funzione ritorna 1. + + + + () Despite the name, this function always returns a value between 0.0 and 1.0 equal to (rank - 1)/(partition-rows - 1), where rank is the value returned by built-in window function rank() and partition-rows is the total number of rows in the partition. If the partition contains only one row, this function returns 0.0. + () A dispetto del nome, questa funzione ritorna sempre un valore tra 0.0 e 1.0 uguale a (rango - 1)/(righe della partizione - 1), dove rango è il valore ritornato dalla funzione interna rank() e le "righe della partizione" sono il numero di righe nella partizione. Se la partizione contiene solo una riga, questa funzione ritorna 0.0. + + + + () The cumulative distribution. Calculated as row-number/partition-rows, where row-number is the value returned by row_number() for the last peer in the group and partition-rows the number of rows in the partition. + () La distribuzione cumulativa. Calcolata come "numero di righe"/"righe della partizione", dove "numero di righe" è il valore ritornato dalla funzione row_number() per l'utimo peer nel gruppo. + + + + (N) Argument N is handled as an integer. This function divides the partition into N groups as evenly as possible and assigns an integer between 1 and N to each group, in the order defined by the ORDER BY clause, or in arbitrary order otherwise. If necessary, larger groups occur first. This function returns the integer value assigned to the group that the current row is a part of. + (N) L'argomento N è gestito come valore intero. Questa funzione divide la partizione in N gruppi il più uniformemente possibile e assegna un'intero tra 1 e N ad ogni gruppo, nell'ordine definito dalla clausula ORDER BY o altrimenti in ordine arbitrario. Se necessario i gruppi più grandi compariranno per primi. Questa funzione ritorna il valore intero assegnato al gruppo di cui fa parte la riga corrente. + + + + (expr) Returns the result of evaluating expression expr against the previous row in the partition. Or, if there is no previous row (because the current row is the first), NULL. + (expr) Ritorna il risultato della valutazione dell'espressione expr sulla riga precedente della partizione o, se non esiste una riga precedente (perché la riga è la prima), NULL. + + + + (expr,offset) If the offset argument is provided, then it must be a non-negative integer. In this case the value returned is the result of evaluating expr against the row offset rows before the current row within the partition. If offset is 0, then expr is evaluated against the current row. If there is no row offset rows before the current row, NULL is returned. + (expr, offset) Se l'argomento offset viene fornito, allora dev'essere un intero non negativo. In questo caso il valore ritornato è il risultato della valutazione dell'espressione expr sulla riga "offset" posizioni antecedente nella partizione. Se offset è 0 allora expr viene valutata sulla riga corrente. Se non ci sono offset righe antecedenti viene ritornato NULL. + + + + + (expr,offset,default) If default is also provided, then it is returned instead of NULL if the row identified by offset does not exist. + (expr,offset,default) Se viene fornito anche default, allora viene ritornato al posto di NULL se la riga identificata da offset non esiste. + + + + (expr) Returns the result of evaluating expression expr against the next row in the partition. Or, if there is no next row (because the current row is the last), NULL. + (expr) Ritorna il risultato della valutazione dell'espressione expr con la riga successiva nella partizione o, se non c'è una riga successiva (perché la riga corrente è l'utlima) NULL. + + + + (expr,offset) If the offset argument is provided, then it must be a non-negative integer. In this case the value returned is the result of evaluating expr against the row offset rows after the current row within the partition. If offset is 0, then expr is evaluated against the current row. If there is no row offset rows after the current row, NULL is returned. + (expr,offset) Se viene fornito l'argomento offset, dev'essere un intero non negativo. In questo caso il valore ritornato è il risultato della valutazione dell'espressione expr sulla riga "offset" posizioni successiva a quella corrente nella partizione. Se offset è 0, allora expr viene valutata sulla riga corrente. Se non c'è una riga "offset" posizioni successive, NULL viene restituito. + + + + (expr) This built-in window function calculates the window frame for each row in the same way as an aggregate window function. It returns the value of expr evaluated against the first row in the window frame for each row. + (expr) Questa funzione interna calcola la cornice della finestra di ciascuna riga allo stesso modo di una funzione finestra aggregata. Ritorna il valore della valutazione di expr sulla prima riga nella cornice della finestra per ciascuna riga. + + + + (expr) This built-in window function calculates the window frame for each row in the same way as an aggregate window function. It returns the value of expr evaluated against the last row in the window frame for each row. + (expr) Questa funzione interna calcola la cornice della finestra per ciascuna riga allo stesso modo della funzione finestra aggregata. Ritorna il valore dell'espressione expr valutata sull'ultima riga della cornice della finestra per ciascuna riga. + + + + (expr,N) This built-in window function calculates the window frame for each row in the same way as an aggregate window function. It returns the value of expr evaluated against the row N of the window frame. Rows are numbered within the window frame starting from 1 in the order defined by the ORDER BY clause if one is present, or in arbitrary order otherwise. If there is no Nth row in the partition, then NULL is returned. + (expr,N) Questa funzione interna calcola la cornice della finestra per ciascuna riga allo stesso modo della funzione aggregata finestra. Ritorna il valore della valutazione dell'espressione expr sulla riga N della cornice della finestra. Le righe sono numerate dalla cornice della finestra partendo da 1 nell'ordine definito dalla clausula ORDER BY se presente o in modo arbitrario. Se non esiste la riga Nesima nella partizione, viene ritornato NULL. + + + + SqliteTableModel + + + reading rows + leggo le righe + + + + loading... + caricamento... + + + + References %1(%2) +Hold %3Shift and click to jump there + Riferimenti %1(%2) +Tieni premuto %3Shift e clicca per saltare lì + + + + Error changing data: +%1 + Errore nella modifica dei dati: +%1 + + + + retrieving list of columns + recupero la lista delle colonne + + + + Fetching data... + Recupero dati... + + + + + Cancel + Annulla + + + + TableBrowser + + + Browse Data + Naviga nei dati + + + + &Table: + &Tabella: + + + + Select a table to browse data + Seleziona una tabella per navigare tra i dati + + + + Use this list to select a table to be displayed in the database view + Usa questa lista per selezionare una tabella da visualizzare nella vista del database + + + + This is the database table view. You can do the following actions: + - Start writing for editing inline the value. + - Double-click any record to edit its contents in the cell editor window. + - Alt+Del for deleting the cell content to NULL. + - Ctrl+" for duplicating the current record. + - Ctrl+' for copying the value from the cell above. + - Standard selection and copy/paste operations. + Questa è la vista della tabella del database. Puoi eseguire le seguenti operazioni: + - Inizia a scrivere per modificare i valori. + - Doppio-click su qualsiasi valore per modificarne il contenuto nella finestra di editor della cella. + - Alt+Del per eliminare il contenuto della cella e portarlo a NULL. + - Ctrl+" per duplicare il valore corrente. + - Ctrl+' per copiare il valore dalla cella soprastante. + - Operazioni di selezione e copia/incolla. + + + + Text pattern to find considering the checks in this frame + Il pattern da cercare considerando le spunte in quest'area + + + + Find in table + Trova nella tabella + + + + Find previous match [Shift+F3] + Trova corrispondenza precedente [Shift+F3] + + + + Find previous match with wrapping + Trova la corrispondenza precedente con reinizio + + + + Shift+F3 + + + + + Find next match [Enter, F3] + Trova la prossima corrispondenza [Invio, F3] + + + + Find next match with wrapping + Trova la prossima corrispondenza con reinizio + + + + F3 + + + + + The found pattern must match in letter case + Il pattern trovato deve corrispondere esattamente (maiuscole/minuscole) incluse + + + + Case Sensitive + Case Sensitive + + + + The found pattern must be a whole word + Il pattern trovato deve essere una parola intera + + + + Whole Cell + Cella completa + + + + Interpret search pattern as a regular expression + Interpreta il pattern di ricerca come un'espressione regolare + + + + <html><head/><body><p>When checked, the pattern to find is interpreted as a UNIX regular expression. See <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>.</p></body></html> + <html><head/><body><p>Quando selezionata, il pattern da trovare viene interpretato come un'espressione regolare UNIX. Vedi: <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>.</p></body></html> + + + + Regular Expression + Espressione regolare + + + + + Close Find Bar + Chiudi la barra di ricerca + + + + Text to replace with + Testo da usare per la sostituzione + + + + Replace with + Sostituisci con + + + + Replace next match + Sostituisci la prossima corrispondenza + + + + + Replace + Sostituisci + + + + Replace all matches + Sostituisci tutte le corrispondenze + + + + Replace all + Sostituisci tutto + + + + <html><head/><body><p>Scroll to the beginning</p></body></html> + <html><head/><body><p>Scorri all'ìinizio</p></body></html> + + + + <html><head/><body><p>Clicking this button navigates to the beginning in the table view above.</p></body></html> + <html><head/><body><p>Cliccare questo pulsante scorre la vista all'inizio della tabella.</p></body></html> + + + + |< + |< + + + + Scroll one page upwards + Scorri di una pagina in su + + + + <html><head/><body><p>Clicking this button navigates one page of records upwards in the table view above.</p></body></html> + <html><head/><body><p>Cliccando questo pulsante la vista scorre le righe di una pagina verso l'inizio della tabella.</p></body></html> + + + + < + < + + + + 0 - 0 of 0 + 0 - 0 di 0 + + + + Scroll one page downwards + Scorri di una pagina in giù + + + + <html><head/><body><p>Clicking this button navigates one page of records downwards in the table view above.</p></body></html> + <html><head/><body><p>Cliccando questo pulsante la vista scorre le righe di una pagina verso il fondo della tabella.</p></body></html> + + + + > + > + + + + Scroll to the end + Scorri alla fine + + + + <html><head/><body><p>Clicking this button navigates up to the end in the table view above.</p></body></html> + <html><head/><body><p>Cliccando questo pulsante la vista scorre al fondo della tabella.</p></body></html> + + + + >| + >| + + + + <html><head/><body><p>Click here to jump to the specified record</p></body></html> + <html><head/><body><p>Clicca qui per saltare alla riga specificata</p></body></html> + + + + <html><head/><body><p>This button is used to navigate to the record number specified in the Go to area.</p></body></html> + <html><head/><body><p>Questo pulsante è utilizzato per navigare alla riga impostata nell'area "Vai a".</p></body></html> + + + + Go to: + Vai a: + + + + Enter record number to browse + Inserisci il numero di riga a cui scorrere + + + + Type a record number in this area and click the Go to: button to display the record in the database view + Inserisci un numero in quest'area e clicca sul pul pulsante "Vai a" per visualizzare la riga selezionata + + + + 1 + 1 + + + + Show rowid column + Mostra colonna rowid + + + + Toggle the visibility of the rowid column + Mostra/nasconde la colonna rowid + + + + Unlock view editing + Sblocca la modifica della vista + + + + This unlocks the current view for editing. However, you will need appropriate triggers for editing. + Sblocca la vista corrente per modificarla. Per poterla modificare avrai comunque bisogno degli appropriati trigger. + + + + Edit display format + Modifica formato di visualizzazione + + + + Edit the display format of the data in this column + Modifica il formato di visualizzazione dei dati in questa colonna + + + + + New Record + Nuova Riga + + + + + Insert a new record in the current table + Inserisci un nuovo valore nella tabella corrente + + + + <html><head/><body><p>This button creates a new record in the database. Hold the mouse button to open a pop-up menu of different options:</p><ul><li><span style=" font-weight:600;">New Record</span>: insert a new record with default values in the database.</li><li><span style=" font-weight:600;">Insert Values...</span>: open a dialog for entering values before they are inserted in the database. This allows to enter values acomplishing the different constraints. This dialog is also open if the <span style=" font-weight:600;">New Record</span> option fails due to these constraints.</li></ul></body></html> + <html><head/><body><p>Questo pulsante crea una nuova riga nel database. Mantieni premuto il tasto del mouse per ottenere più opzioni:</p><ul><li><span style=" font-weight:600;">Nuova Riga</span>: inserisce una nuova riga con i valori predefiniti.</li><li><span style=" font-weight:600;">Inserisci Valori...</span>: apre una finestra per inserire i valori prima che vengano immessi nel database. Questo permette che l'immissione dei valori rispetti diversi limiti (constraints). Questa finestra si apre anche se l'opzione <span style=" font-weight:600;">Nuova Riga</span> fallisce a causa di questi limiti (constraints).</li></ul></body></html> + + + + + Delete Record + Elimina Riga + + + + Delete the current record + Elimina il valore corrente + + + + + This button deletes the record or records currently selected in the table + Questo pulsante elimina la/e righe selezionate nella tabella + + + + + Insert new record using default values in browsed table + Inserisce un nuovo record utilizzando i valori di default della tabella + + + + Insert Values... + Inserisci Valori... + + + + + Open a dialog for inserting values in a new record + Apre una finestra per l'inermento di valori all'interno di un nuovo record + + + + Export to &CSV + Esporta in &CSV + + + + + Export the filtered data to CSV + Esporta i dati filtrati in CSV + + + + This button exports the data of the browsed table as currently displayed (after filters, display formats and order column) as a CSV file. + Questo pulsante esporta i dati della tabella così come visualizzati (applicando filtri, formati e ordine delle colonne) in un file CSV. + + + + Save as &view + Salva come &vista + + + + + Save the current filter, sort column and display formats as a view + Salva il filtro corrente, ordine colonne e formati dati come vista + + + + This button saves the current setting of the browsed table (filters, display formats and order column) as an SQL view that you can later browse or use in SQL statements. + Questo pulsante salva le impostazioni della tabella visualizzata (filtri, formati e ordine colonne) in una vista SQL che puoi successivamente navigare o utilizzare in statement SQL. + + + + Save Table As... + Salva Tabella Come... + + + + + Save the table as currently displayed + Salva la tabella così come visualizzata + + + + <html><head/><body><p>This popup menu provides the following options applying to the currently browsed and filtered table:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Export to CSV: this option exports the data of the browsed table as currently displayed (after filters, display formats and order column) to a CSV file.</li><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Save as view: this option saves the current setting of the browsed table (filters, display formats and order column) as an SQL view that you can later browse or use in SQL statements.</li></ul></body></html> + <html><head/><body><p>Questo menù fornisce le seguenti opzioni applicabili alla tabella filtrata e visualizzata correntemente:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Esporta in CSV: questa opzione esporta i dati della tabella così come visualizzati (con filtri, riordine delle colonne e formati) in un file CSV.</li><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Salva come vista: questa opzione salva le impostazioni correnti della tabella visualizzata (filtri, riordine delle colonne e formati) come vista SQL che puoi successivamente visualizzare o utilizzare come statement.</li></ul></body></html> + + + + Hide column(s) + Nascondi colonna(e) + + + + Hide selected column(s) + Nasconde la(e) colonna(e) selezionata(e) + + + + Show all columns + Mostra tutte le colonne + + + + Show all columns that were hidden + Mostra tutte le colonne nascoste + + + + + Set encoding + Imposta codifica + + + + Change the encoding of the text in the table cells + Modifica la codifica del testo nelle celle della tabella + + + + Set encoding for all tables + Imposta la codifica per tutte le tabelle + + + + Change the default encoding assumed for all tables in the database + Modifica il valore predefinito di codifica per tutte le tabelle del database + + + + Clear Filters + Pulisci Filtri + + + + Clear all filters + Cancella tutti i filtri + + + + + This button clears all the filters set in the header input fields for the currently browsed table. + Questo pulsante pulisce tutti i filtri impostati nella riga d'intestazione per la tabella corrente. + + + + Clear Sorting + Ripristina Ordinamento + + + + Reset the order of rows to the default + Ripristina l'ordine delle righe predefinito + + + + + This button clears the sorting columns specified for the currently browsed table and returns to the default order. + Questo pulsante ripristina l'ordinamento delle colonne predefinito per la tabella corrente. + + + + Print + Stampa + + + + Print currently browsed table data + Stampa i dati della tabella attualmente in esplorazione + + + + Print currently browsed table data. Print selection if more than one cell is selected. + Stampa i dati visualizzati. Stampa la selezione se più di una cella è selezionata. + + + + Ctrl+P + + + + + Refresh + Aggiorna + + + + Refresh the data in the selected table + Aggiorna i dati della tabella selezionata + + + + This button refreshes the data in the currently selected table. + Questo pulsante aggiorna i dati della tabella selezionata. + + + + F5 + + + + + Find in cells + Trova nelle celle + + + + Open the find tool bar which allows you to search for values in the table view below. + Apre la barra di ricerca che ti permette di cercare valori nella tabella visualizzata qui sotto. + + + + + Bold + Grassetto + + + + Ctrl+B + + + + + + Italic + Corsivo + + + + + Underline + Sottolinea + + + + Ctrl+U + + + + + + Align Right + Allinea a Destra + + + + + Align Left + Allinea a Sinistra + + + + + Center Horizontally + Centra Orizzontalmente + + + + + Justify + Giustifica + + + + + Edit Conditional Formats... + Modifica Formattazione Condizionale... + + + + Edit conditional formats for the current column + Modifica formattazione condizionale per la colonna corrente + + + + Clear Format + Ripristina formattazione + + + + Clear All Formats + Ripristina Tutte le Formattazioni + + + + + Clear all cell formatting from selected cells and all conditional formats from selected columns + Ripristina la formattazione di tutte le celle selezionate e tutte le formattazioni condizionali delle colonne selezionate + + + + + Font Color + Colore Testo + + + + + Background Color + Colore Sfondo + + + + Toggle Format Toolbar + Mostra/Nascondi barra dei formati + + + + Show/hide format toolbar + Mostra/nascondi barra dei formati + + + + + This button shows or hides the formatting toolbar of the Data Browser + Questo pulsante mostra o nasconde la barra dei formati per il Browser dei dati + + + + Select column + Seleziona colonna + + + + Ctrl+Space + + + + + Replace text in cells + Sostituisci testo nelle celle + + + + Filter in any column + Filtra in qualsiasi colonna + + + + Ctrl+R + + + + + %n row(s) + + %n riga + %n righe + + + + + , %n column(s) + + , %n colonna + , %n colonne + + + + + . Sum: %1; Average: %2; Min: %3; Max: %4 + . Somma: %1; Media: %2; Min: %3; Max: %4 + + + + Conditional formats for "%1" + Formattazione condizionale per '%1' + + + + determining row count... + determino il numero di righe... + + + + %1 - %2 of >= %3 + %1 - %2 di >= %3 + + + + %1 - %2 of %3 + %1 - %2 di %3 + + + + Please enter a pseudo-primary key in order to enable editing on this view. This should be the name of a unique column in the view. + Si prega d'inserire una pseudo-chiave primaria in modo da abilitare le modifiche su questa vista. Deve corrispondere al nome di una colonna univoca nella vista. + + + + Delete Records + Elimina i Records + + + + Duplicate records + Duplica i records + + + + Duplicate record + Duplica il record + + + + Ctrl+" + + + + + Adjust rows to contents + Adatta le righe al contenuto + + + + Error deleting record: +%1 + Errore eliminando le righe: +%1 + + + + Please select a record first + Si prega di selezionare prima un record + + + + There is no filter set for this table. View will not be created. + Non c'è filtro impostato per questa tabella. La vista non sarà creata. + + + + Please choose a new encoding for all tables. + Si prega di scegliere una nuova codifica per tutte le tabelle. + + + + Please choose a new encoding for this table. + Si prega di scegliere una nuova codifica per questa tabella. + + + + %1 +Leave the field empty for using the database encoding. + %1 +Lasciare il campo vuoto per utilizzare la codifica del database. + + + + This encoding is either not valid or not supported. + Questa codifica non è valida o non è supportata. + + + + %1 replacement(s) made. + %1 sostituzione(i) effettuata(e). + + + + VacuumDialog + + + Compact Database + Compatta Database + + + + Warning: Compacting the database will commit all of your changes. + Attenzione: Compattare il database salverà tutte le tue modifiche. + + + + Please select the databases to co&mpact: + Si prega di selezionare il database da co&mpattare: + + + diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/translations/sqlb_ja.qm b/src/WBCLFZSystemModule/SqliteDBProcess/src/translations/sqlb_ja.qm new file mode 100644 index 0000000000000000000000000000000000000000..536ea32ffe0e209c40d264eb06d1eb04332162da GIT binary patch literal 182656 zcmc$H31Cyj_V>BB*_xyYyNG~cDIn1HvMXQ_D0?ZTEtI{aZQ6#mNl8*@SrtK60jq#3 z0?LlKp@Iu2i+~F%vbcgEptAWC1m6?k`_0^&o1{$u|L^~OA1Ko%cV^CrxDTKmM#A*EXr~Z8(?V_!cO=pb zCz@eHI||P~kM=PVEHlw!%(q|Tt#IAUTXD)Fv`a|%z7=o9DfnI+Pc-jSv;&CdV=V0l znCD)!JJF6L(qAL-`A$Tw-Y4308em&Un1S*7yoh=G6ZOTqGD`v8D56IJ?+6dkQ`6=4 z)3=C5*C(1Zi^R2fzUu(F-PDo9t)obIXc39$A0pwMhe=Z>k*L=@q?!E;316Ki&C;eo zK{juNMGx>+^lT!{nsTBwr+6!P>XK&NY7#s<1*WniE5Qbx8zn!mmc-`{P->^cMD~0d+$9G5(uUH?-UU6h zr1araNH~u6i`Af;d6Y3?9#M{gGCl#`SH3_)I)g7>zCuF{;JfieL+9bS^`D{LNi^*Y z4c(0P$qjP*NqZXl7M?3VNtug*kH)KcE6#eKGME0Fgcplx*x#2ykGp7i;xQ8LE~nv6 zz(2VfjVK2mA6>^=VN)87m}?;Vyo^T8coA@lH0t3ui0;zUnC}uv_;o3bjR73@9jEMp z>q*#=McJQ#-VZ-bc@L~6;oE%5Ti%f9tL8Lr>}C>7GsuH}zM%oY-7+(}dK23=2BM-PwqfN0Eexm~KGnG+y$-q=ZVY$-$!cxXYB1CT%ep(hq& z+}gA0iO)n5*8M^&hgwLuluRpMhMf3*KCM2FarzvjHTo11?|zmxw%9=Q-Z0u!p(i0B ziZ;Ir`pbHWUj5ifVup=gud$rOuAk6bV;2w=6w!{{MnwC!(T>k9lCaTCyE4Gv=hxDQ znrTE=V(7qL&~rzT4xAoB!iqg~sGp035%KiBu#m)tAJVa7KB9*=&?)0Go%;*> zQu8kQV*u#?uC{a|x-sySKsPpSCQ8dYJ%=lrU|A!3yC(K5@O!-lF)s< zU>)Ql$~w(k;qT3YHD@6S&z=zO{Af0b3-$~3TCXHw{$qm8<{)bOZ^3r>C!*&(LL-M0 zbVWk58u29F|8JqWXAFt8Jwo%(pga1$Ewt!^ewt{Z#o+6ZdznH)jf+GFI|~VRFVUwy zA>n9y@NJpUZS4Cb4Ea)cpk_LWk3K5&>Lmbg?+Zi!{EcX8XTkN%b zkhPuY+pEGyFV6*iPvWik&?~~nTW68*_;}&-Gl#HG9fTu)_9WV#BOLt-`e?sRIF<`O z{$#yys(lIx{Wc31E}SB||99RB3!fG)|Ji|rc@u;`HbOUj+fcYVdOHc5-Vv_O-3&Q) zRrsqK_^(?v;o6WLL_e(%u3cyf`c0PGb2{P1rXirGmqf86blSBGqGsYlL`(OJx|MrL zxc(Jy#it1oh2Zkt?T&~Q8$Thz&{}-%?#o1blEoF8h0srbi>nVcBr1GW zT)T8P(UI2ThE_9(jy4jv?#J)DqQtkEyqa`Ud?&9R0j#UnX(qS+saUp3zaTjpc&>(hXL`VsM);x9=!@vQiL>3X8! z4)Ob=hhWcL7LO+%gFVtvJQ3}JeB3Mk{P0=m>&@c%Jka6V{o-$3`Vl?dLA+!Jy*->I z{?Ts<(S^^&Yjr@6&0B~!hGQS5d=eEk$wlIz4N^wXiJqziwLVE!R0wZjnDYYTgjgXWgh3wIPr8CPb~6 z+mfhGa@5L1;OpM!qE@coPGYrTQLCO@4!!we)cT#kYm>X8HpTYBeo@rR4X#5jY>L_v zJski=Mmm5+0 zJa3cG>$RwTFAXB$M_<%O%OH35^pE=Db1l)JEl~&mT2A7mjZr7EAB8DDB2z);+yISH+q;YGFT~5jFLCrk9`n*sxzzMvz-JlsZ^ADm4cWOp-zfNM}bpXzUS9uH_BriHVy06X5$d{?d$V{tfo)sHSM*V%SH^HKkv~5`8dP zGvVNH@Krla+4e86uTN;EzO@T-sk7!`C*%o)YSdq| zxbIW&9a4EKEHY}Ae%zD9vL%`)`@KulTgO}B-N)qiVjbR!8S^zy&U})Dug!9ME?#bb zkJUW65_A{;s^;lMDI|7qXr3LhlZ1EQ(=2a4jl@xHHP8P`1i!Y|te6)IJ8i#a^&_*1 zcBg69bi{KNZ8dA|1)X%hpjndyJMvtf+@3GjtT~uL^n7*A+6mZaT|dqG>|-R{vtF}t z;Xx874o7>O=yED=Ma>$tzvJ@<(E@LmOVI+~m!C#^g=l3RxxKst?VtF)hur>QMEh@| zKN8TwuKgneE$ID^aY({(j)jE#M`;dRTLt{RtodxsY2foa z&1XAbCz>-_^Lc0J-!U6<=!(&j(*DsiQgi%2m)|EzNg1 zkOz-`tvNBdC5h9UYR)tU9L;-Z&U~@?`hcjGkY9N?pF8#L!WUPzR&Lv!)D zY}gCMnqNoMAd2mzx$3G3`fRTGQ{R+?@7~w^CmQoFSg85y(}vL3!?oJ?EF{vyay$D~ ztscMAhD5D##wFMbAM#ds{swQwho)=qsNR8uo)fiq?ZzOb| z+wyC`ablac^_}rVO@?V({|op(X4JNSG7Wy|Deb)-w-bGIP?b@Oq+aQ-)Xx+)HiO#;IEy-R;!qSOa--;dxUA(3(eFpIU{+xEg zD>F$fw`nH|%Sosaqn%uFiG&{x$nE7V+Nr-_yhdxZv$}&H{USU3CNV#6GNDw-|Kz zc@OP6W-m^DL%ZSqA7Jla&~Dg!8uat2cEgd!N!Tz;yRifK{Mn7#jf?x>_iwa2tQUdL zN42|36G=?^M7wL>3-H&^X?GU@zq+m3JqE1viG1z;MWB!8KGS~Y*+um0dF>aULT)^I zPHl=(kv1 zzYiOdX!u!|vZO7E(|*+rYFY|DT%t?;cnR#*IlAGi08fVKt zc^~A_LES@M;Nv~L?%~;pL47nxH|O2$Bt(tY&Fc$2x9bVrqx-L6A3N(7b;a-RpV2LP z|KB9+d`h=?ZVCL&6S^g@^&+8bUER`#xuCzUx@FZs@8^%})_j*twC=R-<*y~^?e}$C zMz)2Y)>8M@0~bkbovnNOMhb~j4(oQ#D~H}p)a`BYAjZ2_w>SG7;u3D%XWh;dt*xW` zZ0ZpB2TgQGp9Foi?xs6>Vj1|Oh3=b?Uz3==Tz6vXVG_NM=uUk61_>u0(f!=waT0x3 zbZ3wJ3Ol)@?!r$gBupgTrAFZ2kw57!Td~ehe%Jk#3j68Xb-KUvUxS^{PA@D+zo@_T zn(M&(jTiK~&c`4xQ}s38*g!&31AVQLz@IrwAG>Zh^wS}^z0g8`&%YW%UR~3-YJZ8u z%s2F{Pd-e-);sk*W8lyI{ME4r|)y-6X=si^(nn; z!;d_vPn*6Qe&T%nm{yQK@Ac7-Jp_4rUkiN>?01oN>T@f=Ck<=s^D?lm(_iTG8(=@0 zj@9QEf}WcErZ2=ki{)AR!tbxc&iqqfcmi}fvWtHF+WJJLJN2G;*wvFC)|dT^{r+K~ ze#*CpVP`GTPw)5<2@@vjXTEtK@RFmS_4y3wqh`Dn79P;gbtS@H{zCs~9O(47E&9b5 zKSTT|TEFD(Zt#ox>zBSh9Qtgi{;5+7As-j&m;V_HdJ*(5OoQL~AD{k(!@&QbkM*lD zuIMS%um0;a?EDP-udk zHiey>ssAt&@sXNy^dCJqjl{h3`p=$%eBb|<{466e&_f4{s4)gNDQoy3~e^grsBBfim3f4YZ<=-e>g3gg@A&)Q}o9+jiNu%sT* z;7t9MjP=kjq`xsz3%crP(B4svXr9xc>kas?<{C`3fR`4F4KaDwA(s~zsyzk&wBvn- zYR9xhmwq$caU68<>KsG8(ct@PFBlrk0e)V7*U<2-dq~*c-_ZOw@In2qhJl-@$2mCjBnxX4?=nb)4ZWnDa^w2}jHvZJmbHjS< zcYi~lC%%9kdeG3p805uT!^@}gNqlyrVasc2hbL*nf7hJEMa z!8fN3`$we^Z5wX*oMMh z$%ZSbptsE?!_~s=B#x+V_%jLn<2_;c6aK6)ZD%x}!bcK?(wqHC=O+zHF%cHQ04cU}VgBd$f) zKac%uSTDMPJqPl1WOO6MF2#wO=$7k7Ag;Y9I{tagyDu(Ux)c4I^oYLKJcfibjic{f zhyDHVeDr|gOKxm|3H&b@mt^h~Sh{QH3?-)qs%vG+iZ_mB2Gjs1G| zo@noK;N{e@Xzzx)BwQ|!F6$0`(fsA;@*dwKpAgSmaav;ZL!SfAs{^8EywH%u-p!*I zA9)ISm1)sW{~PmOy%7EEao{_ree{~m86@0&Ao`uRUq;-$cJ#X!Ar&Y z_h}b>ndyl~_eEcM2Xgoqmr?WPW)h4)7`0Piue{aSXxMQd_f!w+dyVjLtvUu=2B zn0XERu)d)&XLn7aM^bnzjK65i?Fubqhk|3f82_83)%;a zc`qG<9iCzw_XFfX>qExkH-XphY8a>VSWdKPopH+9JCJYMY@B)K4e;G5anpO61- zTv}p>oZMu5=Ij^}@11X4(eW|~;@`$qPg_X1v$b*c+o12JKN#0Gz_=G`8rN;93q7#h zxbDzq&|w4P`o{(EMTzmXJk0O18DC?3e|EZY>#wkjE}t^K^E2>f_|5oktz)1AkMZ3F zKG;t=aywfz?uqxoUv(PyZ0U!1da`l94{|-}McxXp-^E+;xfRBbUPZj3)#Jv`CTxM- zA{dV%H%3`0#%~Hik29V%p6QA4%UT)F^^QjT`n>U6W&-%7qw!oG`+cMF{FPV|g{E@5 z@LS_=z_;kwV7#P-UDA_`m)m2%pZv!7$0^vA!kfk`38%sLNye)qF2lY%Y5cRd261VN z@z1aDd&M|`u1spSTY_l(xmIu-K`pJhsT2>bBj z7p8;?j32keB=v0w|7o{LT5yqsM7ybtu!^N@O>IukM7-cZQy0h=%I$6HG1En~@C#GY zi0z0oEHd?eCmQ+LcX%r-I&13F)J5W$`KEr(!H5sNZW_3{6!Y~r4PtrO4G;2G7`?@m zIvaQ$W-w)MItV|hrOBC(dB2}!n)*!^31_vY1-)k>&v6LtY2-y8lG{z|O^e6WhCi|2 zw3zif`jctdag6KUV|s4wYNBczP0#-hxca?sS~adQ33qHTz3`oxXvIpo{j{rTZN&!I zJ9A9yTW=>JE5o$mevI>E1Jg^~K2I~f{4V5VYN=_8QhlWJa#(tKEZ<+IE?aRR>+n zc+YgQ2+u!#-1Os@7fI~&u<2A|w2wbxIyE61{%0@KnJv(xS4NtC@@*sGfn}x(+W}X% z3f>CO{AK#rE0AA5n@qnA*nxfc!1TvY^N?36GSfBCNB{54;({8;Hytr+4jv#{m1fqB zYfs|bBD3L(JD~@DGaE-&AnvokY;89N_R%VHwTs9@XS6iejCvLLPBGt^wjK8CC3C&^ ztoBLdYoZWiF+<((T__+z@ zVQVuWC!RKs7zKHyHJe8dxCHt0xH+pJ3I6|=X2+84@MoVg=VdGdovt$Hmo$N&P;4Ie z4&ZNn*zCpg!h^lczPwHNU2C2w;`w=Go_K8;iSu0MSxrD+IaAED4Orj&@#fhNg3ec; zG|!n_4nJXodHxjOo5=hqql0Cs<|if`hhO@Uc}ed*B-HxGysQQIaN`p5Q=5J#ap^1O zmD}zBJ?8ROoY%s<$^v;}-DF-P?nfS~nR(5!*ANdrW!}K_u z2b$j)QX6@qBJ;baenA}QNAr$8(06q{Gk;*+gZO_Z^9OOD*Y{4DcQ@Sxd#=#De}x5k z%zEZe5dWe2TJskNKzB{=G#{LfeR%2@^H=v-NH~~c{&qIT-?PB{{Z8!L3ro$%e}Me% zbjEz{b=bf9KjrqRIP>}A7vVoIGXMHo65{lN`D$y7|F0G1zh3(a^w!0E{m3ZHzal1T z)0eQ{y)l~cDUfeJ#%TKb6v-O((jZVdL}+5z5*UQc`Z-2>$8NBc{n^;CtSEG0i^*oz$xl6W6jS^?flTnf|CrpiN@ED znT7b4FzuI^`ArrgKYTLg(HYl~$J-RMY$Evj!woSjy$g|7%ZhpVt47F&_KtZYt|9yb zL(H~UKY+inFlKwN>m)w#ub5qTKrS6Q9<%!y7vd+M$L#*-I}#qEn0@BOB$|t3J~KeS z#I1|@ywfzq`GxYCs|CO7y5dq#dI2W zW6etzYp+wFv;LMENhcsbU$fM{3;jF&WV!n*;Hj2mu|+}d)pA-Ip=L;UbAqMuWX%7> zHM!mWn5FgPLqt2KSUSa7z=ywDI&A{{n?JSO+Z6a})7;Xf4EXwdqovE2-H_jGX1Tv7 z@KyHi{X3H{<1Lx_utSD_W65f!L0o2`#s14N@Qu$>kn=I* z+yjV@9<)D9LYGyR z$6Mj~%oi+6I&3Gg&pFF8LjmW20?W#`Ku@o@EHAt|3vtuCEgK6UZysN7d8^(B$o~(p zy!BQh==*2OwxzQ`Kie()KLI_o+F|*)WFd)*$6G#L;6R>isO6L2G0)_0EMFX*34Qvu z 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 + + + + AboutDialog + + + About DB Browser for SQLite + DB Browser for SQLite ã«ã¤ã„㦠+ + + + Version + ãƒãƒ¼ã‚¸ãƒ§ãƒ³ + + + + <html><head/><body><p>DB Browser for SQLite is an open source, freeware visual tool used to create, design and edit SQLite database files.</p><p>It is bi-licensed under the Mozilla Public License Version 2, as well as the GNU General Public License Version 3 or later. You can modify or redistribute it under the conditions of these licenses.</p><p>See <a href="http://www.gnu.org/licenses/gpl.html">http://www.gnu.org/licenses/gpl.html</a> and <a href="https://www.mozilla.org/MPL/2.0/index.txt">https://www.mozilla.org/MPL/2.0/index.txt</a> for details.</p><p>For more information on this program please visit our website at: <a href="http://sqlitebrowser.org">http://sqlitebrowser.org</a></p><p><span style=" font-size:small;">This software uses the GPL/LGPL Qt Toolkit from </span><a href="http://qt-project.org/"><span style=" font-size:small;">http://qt-project.org/</span></a><span style=" font-size:small;"><br/>See </span><a href="http://qt-project.org/doc/qt-5/licensing.html"><span style=" font-size:small;">http://qt-project.org/doc/qt-5/licensing.html</span></a><span style=" font-size:small;"> for licensing terms and information.</span></p><p><span style=" font-size:small;">It also uses the Silk icon set by Mark James licensed under a Creative Commons Attribution 2.5 and 3.0 license.<br/>See </span><a href="http://www.famfamfam.com/lab/icons/silk/"><span style=" font-size:small;">http://www.famfamfam.com/lab/icons/silk/</span></a><span style=" font-size:small;"> for details.</span></p></body></html> + <html><head/><body><p>DB Browser for SQLite 㯠SQLite データベースを作æˆã€ãƒ‡ã‚¶ã‚¤ãƒ³ã€ç·¨é›†ã§ãã‚‹ã€ã‚ªãƒ¼ãƒ—ンソースã§ç„¡æ–™ã®ãƒ´ã‚£ã‚¸ãƒ¥ã‚¢ãƒ«ãƒ„ールã§ã™ã€‚</p><p>ã“ã®ã‚½ãƒ•トウェア㯠Mozilla Public License Version 2 㨠the GNU General Public License Version 3 (ã‚‚ã—ãã¯ãれ以é™ã®ã‚‚ã®) ã®2ã¤ã§ãƒ©ã‚¤ã‚»ãƒ³ã‚¹ã•れã¦ã„ã¾ã™ã€‚ã‚ãªãŸã¯ã“れらã®ãƒ©ã‚¤ã‚»ãƒ³ã‚¹ã®æ¡ä»¶ã®ä¸‹ã§ã“ã®ã‚½ãƒ•トウェアを変更ã€ã‚‚ã—ãã¯ã€å†é…布ã§ãã¾ã™ã€‚</p><p>詳細㯠<a href="http://www.gnu.org/licenses/gpl.html">http://www.gnu.org/licenses/gpl.html</a> 㨠<a href="https://www.mozilla.org/MPL/2.0/index.txt">https://www.mozilla.org/MPL/2.0/index.txt</a> ã‚’ã”覧ãã ã•ã„。</p><p>ã“ã®ãƒ—ログラムã®ã•らãªã‚‹æƒ…å ±ã¯ã€ç§ãŸã¡ã®ã‚¦ã‚§ãƒ–サイトをã”覧ãã ã•ã„。: <a href="http://sqlitebrowser.org">http://sqlitebrowser.org</a></p><p><span style=" font-size:small;">ã“ã®ã‚½ãƒ•トウェア㯠GPL/LGPL Qt Toolkit を使用ã—ã¦ã„ã¾ã™ã€‚ </span><a href="http://qt-project.org/"><span style=" font-size:small;">http://qt-project.org/</span></a><span style=" font-size:small;"><br/>ライセンスæ¡é …や情報㯠</span><a href="http://qt-project.org/doc/qt-5/licensing.html"><span style=" font-size:small;">http://qt-project.org/doc/qt-5/licensing.html</span></a><span style=" font-size:small;"> ã‚’ã”覧ãã ã•ã„。</span></p><p><span style=" font-size:small;">ã¾ãŸã€ Mark James ã® Silk icon set ã‚’ Creative Commons Attribution 2.5 and 3.0 license ã®å…ƒã§ä½¿ç”¨ã—ã¦ã„ã¾ã™ã€‚<br/>詳細㯠</span><a href="http://www.famfamfam.com/lab/icons/silk/"><span style=" font-size:small;">http://www.famfamfam.com/lab/icons/silk/</span></a><span style=" font-size:small;"> ã‚’ã”覧ãã ã•ã„。</span></p></body></html> + + + + AddRecordDialog + + + Add New Record + æ–°ã—ã„レコードを追加 + + + + Enter values for the new record considering constraints. Fields in bold are mandatory. + 制約を考慮ã—ã¦æ–°ã—ã„レコードã«å€¤ã‚’入力ã—ã¾ã™ã€‚太字ã®ãƒ•ィールドã¯å¿…é ˆã§ã™ã€‚ + + + + In the Value column you can specify the value for the field identified in the Name column. The Type column indicates the type of the field. Default values are displayed in the same style as NULL values. + 「値ã€åˆ—ã§ã¯ã€ã€Œåå‰ã€åˆ—ã§è­˜åˆ¥ã•れãŸãƒ•ィールドã®å€¤ã‚’指定ã§ãã¾ã™ã€‚「データ型ã€åˆ—ã¯ãƒ•ィールドã®ãƒ‡ãƒ¼ã‚¿åž‹ã‚’示ã—ã¾ã™ã€‚ デフォルト値ã¯NULL値ã¨åŒã˜ã‚¹ã‚¿ã‚¤ãƒ«ã§è¡¨ç¤ºã•れã¾ã™ã€‚ + + + + Name + åå‰ + + + + Type + データ型 + + + + Value + 値 + + + + Values to insert. Pre-filled default values are inserted automatically unless they are changed. + 挿入ã™ã‚‹å€¤ã€‚変更ã•れãªã„é™ã‚Šã€äº‹å‰å…¥åŠ›ã•れãŸãƒ‡ãƒ•ォルト値ãŒè‡ªå‹•çš„ã«æŒ¿å…¥ã•れã¾ã™ã€‚ + + + + When you edit the values in the upper frame, the SQL query for inserting this new record is shown here. You can edit manually the query before saving. + 上ã®ãƒ•レームã§å€¤ã‚’編集ã™ã‚‹ã¨ã€ã“ã®æ–°ã—ã„レコードを挿入ã™ã‚‹ SQL クエリーãŒã“ã“ã«è¡¨ç¤ºã•れã¾ã™ã€‚ä¿å­˜ã™ã‚‹å‰ã«ã“ã®ã‚¯ã‚¨ãƒªãƒ¼ã‚’手動ã§ç·¨é›†ã§ãã¾ã™ã€‚ + + + + <html><head/><body><p><span style=" font-weight:600;">Save</span> will submit the shown SQL statement to the database for inserting the new record.</p><p><span style=" font-weight:600;">Restore Defaults</span> will restore the initial values in the <span style=" font-weight:600;">Value</span> column.</p><p><span style=" font-weight:600;">Cancel</span> will close this dialog without executing the query.</p></body></html> + <html><head/><body><p><span style=" font-weight:600;">ä¿å­˜</span>ã¯è¡¨ç¤ºã•れã¦ã„ã‚‹æ–°ã—ã„レコードを挿入ã™ã‚‹SQL文をデータベースã«é©ç”¨ã—ã¾ã™ã€‚</p><p><span style=" font-weight:600;">ãƒ‡ãƒ•ã‚©ãƒ«ãƒˆã«æˆ»ã™</span>ã¯<span style=" font-weight:600;">「値ã€</span>åˆ—ã‚’åˆæœŸå€¤ã«æˆ»ã—ã¾ã™ã€‚</p><p><span style=" font-weight:600;">キャンセル</span>ã¯ã‚¯ã‚¨ãƒªãƒ¼ã‚’実行ã›ãšã«ãƒ€ã‚¤ã‚¢ãƒ­ã‚°ã‚’é–‰ã˜ã¾ã™ã€‚</p></body></html> + + + + Auto-increment + + 自動増加 + + + + + Unique constraint + + ä¸€æ„æ€§åˆ¶ç´„ + + + + + Check constraint: %1 + + 検査誓約: %1 + + + + + Foreign key: %1 + + 外部キー: %1 + + + + + Default value: %1 + + デフォルト値: %1 + + + + + Error adding record. Message from database engine: + +%1 + レコード追加ã§ã‚¨ãƒ©ãƒ¼ã€‚データベースエンジンã‹ã‚‰ã®ãƒ¡ãƒƒã‚»ãƒ¼ã‚¸: + +%1 + + + + Are you sure you want to restore all the entered values to their defaults? + 入力ã—ãŸå€¤ã‚’ã™ã¹ã¦ãƒ‡ãƒ•ã‚©ãƒ«ãƒˆã«æˆ»ã—ã¾ã™ã‹? + + + + Application + + + Possible command line arguments: + 使用å¯èƒ½ãªã‚³ãƒžãƒ³ãƒ‰ãƒ©ã‚¤ãƒ³å¼•æ•°: + + + + Usage: %1 [options] [<database>|<project>] + + ä½¿ã„æ–¹: %1 [オプション] [<DB>|<プロジェクト>] + + + + + -h, --help Show command line options + -h, --help コマンドラインã®ã‚ªãƒ—ションを表示 + + + + -q, --quit Exit application after running scripts + -q, --quit スクリプト実行後ã«ã‚¢ãƒ—リケーションを終了 + + + + -s, --sql <file> Execute this SQL file after opening the DB + -s, --sql <ファイル> DBã‚’é–‹ã„ãŸå¾Œã€ã“ã®SQLファイルを実行 + + + + -t, --table <table> Browse this table after opening the DB + -t, --table <テーブル> DBã‚’é–‹ã„ãŸå¾Œã“ã®ãƒ†ãƒ¼ãƒ–ルを閲覧 + + + + -R, --read-only Open database in read-only mode + -R, --read-only 読ã¿å–り専用モードã§ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã‚’é–‹ã + + + + -o, --option <group>/<setting>=<value> + -o, --option <グループ>/<設定>=<値> + + + + Run application with this setting temporarily set to value + 一時的ã«ã“ã®å€¤ã‚’設定ã—ã¦ã‚¢ãƒ—リケーションを実行 + + + + -O, --save-option <group>/<setting>=<value> + -O, --save-option <グループ>/<設定>=<値> + + + + Run application saving this value for this setting + ã“ã®å€¤ã®è¨­å®šã‚’ä¿å­˜ã—ã¦ã‚¢ãƒ—リケーションを実行 + + + + -v, --version Display the current version + -v, --version ç¾åœ¨ã®ãƒãƒ¼ã‚¸ãƒ§ãƒ³ã‚’表示 + + + + <database> Open this SQLite database + <データベース> ã“ã®SQLiteデータベースを開ã + + + + <project> Open this project file (*.sqbpro) + <プロジェクト> ã“ã®ãƒ—ロジェクトファイル(*.sqbpro)ã‚’é–‹ã + + + + The -s/--sql option requires an argument + -s/--sql オプションã¯å¼•æ•°ãŒå¿…è¦ã§ã™ + + + + The file %1 does not exist + ファイル %1 ãŒå­˜åœ¨ã—ã¾ã›ã‚“ + + + + The -t/--table option requires an argument + -t/--table オプションã¯å¼•æ•°ãŒå¿…è¦ã§ã™ + + + + The -o/--option and -O/--save-option options require an argument in the form group/setting=value + -o/--option 㨠-O/--save-optionオプション㯠グループ/設定=値 ã®å½¢å¼ã§å¼•æ•°ãŒå¿…è¦ã§ã™ + + + + SQLite Version + SQLite ãƒãƒ¼ã‚¸ãƒ§ãƒ³ + + + + SQLCipher Version %1 (based on SQLite %2) + SQLCipher ãƒãƒ¼ã‚¸ãƒ§ãƒ³ %1 (SQLite %2 ãŒãƒ™ãƒ¼ã‚¹) + + + + DB Browser for SQLite Version %1. + DB Browser for SQLite ãƒãƒ¼ã‚¸ãƒ§ãƒ³ %1. + + + + Built for %1, running on %2 + %1 å‘ã‘ビルド, %2 ã§å‹•作中 + + + + Qt Version %1 + Qt ãƒãƒ¼ã‚¸ãƒ§ãƒ³ %1 + + + + Invalid option/non-existant file: %1 + 䏿­£ãªã‚ªãƒ—ション/存在ã—ãªã„ファイルã§ã™: %1 + + + + CipherDialog + + + SQLCipher encryption + SQLCipher æš—å·åŒ– + + + + &Password + パスワード(&P) + + + + &Reenter password + パスワードã®å†å…¥åŠ›(&R) + + + + Passphrase + パスフレーズ + + + + Raw key + 生ã®ã‚­ãƒ¼ + + + + Encr&yption settings + æš—å·åŒ–設定(&Y) + + + + SQLCipher &3 defaults + SQLCipher 3 デフォルト(&3) + + + + SQLCipher &4 defaults + SQLCipher 4 デフォルト(&4) + + + + Custo&m + カスタム(&M) + + + + Page si&ze + ページサイズ(&Z) + + + + &KDF iterations + KDFå復回数(&K) + + + + HMAC algorithm + HMACアルゴリズム + + + + KDF algorithm + KDFアルゴリズム + + + + Plaintext Header Size + プレーンテキストヘッダーサイズ + + + + Please set a key to encrypt the database. +Note that if you change any of the other, optional, settings you'll need to re-enter them as well every time you open the database file. +Leave the password fields empty to disable the encryption. +The encryption process might take some time and you should have a backup copy of your database! Unsaved changes are applied before modifying the encryption. + データベースを暗å·åŒ–ã™ã‚‹ã‚­ãƒ¼ã‚’設定ã—ã¦ãã ã•ã„。 +ãã®ã»ã‹ã®ä»»æ„ã®è¨­å®šã‚’変更ã™ã‚‹ã¨ã€ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ãƒ•ァイルを開ãã¨ãã¯æ¯Žå›žå†å…¥åŠ›ãŒå¿…è¦ã«ãªã‚‹ã“ã¨ã«æ³¨æ„ã—ã¦ãã ã•ã„。 +æš—å·åŒ–を無効ã«ã™ã‚‹ã«ã¯ãƒ‘スワード欄を空白ã«ã—ã¾ã™ã€‚ +æš—å·åŒ–工程ã«ã¯å°‘ã—æ™‚é–“ãŒã‹ã‹ã‚‹ã§ã—ょã†ã€‚データベースã®ãƒãƒƒã‚¯ã‚¢ãƒƒãƒ—を作æˆã™ã‚‹ã¹ãã§ã™! ä¿å­˜ã—ã¦ã„ãªã„å¤‰æ›´ã¯æš—å·åŒ–ã®å‰ã«å映ã•れã¾ã™ã€‚ + + + + Please enter the key used to encrypt the database. +If any of the other settings were altered for this database file you need to provide this information as well. + ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã®æš—å·åŒ–ã«ä½¿ç”¨ã™ã‚‹ã‚­ãƒ¼ã‚’入力ã—ã¦ãã ã•ã„。 +ã“ã®ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ãƒ•ァイルã®ä»–ã®è¨­å®šãŒå¤‰æ›´ã•れãŸå ´åˆã¯ã€ã“ã®æƒ…報も指定ã™ã‚‹å¿…è¦ãŒã‚りã¾ã™ã€‚ + + + + ColumnDisplayFormatDialog + + + Choose display format + 表示書å¼ã‚’é¸æŠž + + + + Display format + è¡¨ç¤ºæ›¸å¼ + + + + Choose a display format for the column '%1' which is applied to each value prior to showing it. + カラム '%1' ã®è¡¨ç¤ºå½¢å¼ã‚’é¸æŠžã—ã¦ãã ã•ã„。ã“れã¯è¡¨ç¤ºå‰ã«å„値ã«é©ç”¨ã•れã¾ã™ã€‚ + + + + Default + デフォルト + + + + Decimal number + å進数 + + + + Exponent notation + 指数表記 + + + + Hex blob + å六進Blob + + + + Hex number + å六進数 + + + + Octal number + 八進数 + + + + Round number + 概数 + + + + Apple NSDate to date + Apple NSDate を日付㫠+ + + + Java epoch (milliseconds) to date + Java エãƒãƒƒã‚¯ (ミリ秒) を日付㫠+ + + + .NET DateTime.Ticks to date + .NET DateTime.Ticks を日付㫠+ + + + Julian day to date + ユリウス日を日付㫠+ + + + Unix epoch to date + Unix エãƒãƒƒã‚¯ã‚’日付㫠+ + + + Unix epoch to local time + Unix エãƒãƒƒã‚¯ã‚’地方時㫠+ + + + Windows DATE to date + Windows DATE を日付㫠+ + + + Date as dd/mm/yyyy + 日付(dd/mm/yyyy) + + + + Lower case + å°æ–‡å­— + + + + Upper case + 大文字 + + + + Custom + カスタム + + + + Custom display format must contain a function call applied to %1 + カスタム表示形å¼ã«ã¯ã€%1 ã«é©ç”¨ã•れる関数呼ã³å‡ºã—ãŒå«ã¾ã‚Œã¦ã„ã‚‹å¿…è¦ãŒã‚りã¾ã™ + + + + Error in custom display format. Message from database engine: + +%1 + カスタム表示形å¼ã§ã‚¨ãƒ©ãƒ¼ã€‚データベースエンジンã‹ã‚‰ã®ãƒ¡ãƒƒã‚»ãƒ¼ã‚¸: + +%1 + + + + Custom display format must return only one column but it returned %1. + カスタム表示形å¼ã¯ãŸã 1ã¤ã®ã‚«ãƒ©ãƒ ã‚’è¿”ã™å¿…è¦ãŒã‚りã¾ã™ãŒã€%1 ãŒè¿”ã£ã¦ãã¾ã—ãŸã€‚ + + + + CondFormatManager + + + Conditional Format Manager + æ¡ä»¶ä»˜ã書å¼ç®¡ç† + + + + This dialog allows creating and editing conditional formats. Each cell style will be selected by the first accomplished condition for that cell data. Conditional formats can be moved up and down, where those at higher rows take precedence over those at lower. Syntax for conditions is the same as for filters and an empty condition applies to all values. + ã“ã®ãƒ€ã‚¤ã‚¢ãƒ­ã‚°ã§æ¡ä»¶ä»˜ã書å¼ã®ä½œæˆã¨ç·¨é›†ãŒã§ãã¾ã™ã€‚ãれãžã‚Œã®ã‚»ãƒ«ã‚¹ã‚¿ã‚¤ãƒ«ã¯ã‚»ãƒ«ã®ãƒ‡ãƒ¼ã‚¿ãŒæœ€åˆã«ä¸€è‡´ã—ãŸæ¡ä»¶ã®ã‚‚ã®ãŒé¸æŠžã•れã¾ã™ã€‚æ¡ä»¶ä»˜ã書å¼ã¯ä¸Šä¸‹ã«ç§»å‹•ã§ãã€ä¸Šã®è¡Œã¯ä¸‹ã®è¡Œã«å„ªå…ˆã—ã¾ã™ã€‚æ¡ä»¶ã®æ§‹æ–‡ã¯ãƒ•ィルターã¨åŒã˜ã§ã€ç©ºç™½ã®æ¡ä»¶ã¯å…¨ã¦ã®å€¤ã«é©ç”¨ã•れã¾ã™ã€‚ + + + + Add new conditional format + æ–°ã—ã„æ¡ä»¶ä»˜ã書å¼ã‚’追加ã—ã¾ã™ + + + + &Add + 追加(&A) + + + + Remove selected conditional format + é¸æŠžã—ãŸæ¡ä»¶ä»˜ã書å¼ã‚’削除ã—ã¾ã™ + + + + &Remove + 削除(&R) + + + + Move selected conditional format up + é¸æŠžã—ãŸæ¡ä»¶ä»˜ã書å¼ã‚’上ã¸ç§»å‹•ã—ã¾ã™ + + + + Move &up + 上ã¸(&U) + + + + Move selected conditional format down + é¸æŠžã—ãŸæ¡ä»¶ä»˜ã書å¼ã‚’下ã¸ç§»å‹•ã—ã¾ã™ + + + + Move &down + 下ã¸(&D) + + + + Foreground + 剿™¯ + + + + Text color + 文字色 + + + + Background + 背景 + + + + Background color + 背景色 + + + + Font + フォント + + + + Size + サイズ + + + + Bold + 太字 + + + + Italic + イタリック + + + + Underline + 下線 + + + + Alignment + é…ç½® + + + + Condition + æ¡ä»¶ + + + + + Click to select color + クリックã§è‰²ã‚’é¸æŠž + + + + Are you sure you want to clear all the conditional formats of this field? + 本当ã«ã“ã®ãƒ•ã‚£ãƒ¼ãƒ«ãƒ‰ã®æ¡ä»¶ä»˜ã書å¼ã‚’ã™ã¹ã¦å‰Šé™¤ã—ã¾ã™ã‹? + + + + DBBrowserDB + + + This database has already been attached. Its schema name is '%1'. + ã“ã®ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã«ã¯æ—¢ã«æŽ¥ç¶šã—ã¦ã„ã¾ã™ã€‚ã“ã®ã‚¹ã‚­ãƒ¼ãƒžã®åå‰ã¯ '%1' ã§ã™ã€‚ + + + + Please specify the database name under which you want to access the attached database + 接続ã—ãŸãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã¸ã®ã‚¢ã‚¯ã‚»ã‚¹æ™‚ã«ä½¿ç”¨ã™ã‚‹ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹åを指定ã—ã¦ãã ã•ã„ + + + + Invalid file format + 䏿­£ãªãƒ•ァイルフォーマット + + + + Do you really want to close this temporary database? All data will be lost. + 本当ã«ã“ã®ä¸€æ™‚データベースを閉ã˜ã¾ã™ã‹? ã™ã¹ã¦ã®ãƒ‡ãƒ¼ã‚¿ã¯å–ªå¤±ã—ã¾ã™ã€‚ + + + + Do you want to save the changes made to the database file %1? + データベースファイル '%1' ã¸ã®å¤‰æ›´ã‚’ä¿å­˜ã—ã¾ã™ã‹? + + + + Database didn't close correctly, probably still busy + ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ãŒæ­£å¸¸ã«é–‰ã˜ã‚‰ã‚Œã¾ã›ã‚“ã§ã—ãŸã€‚多分ã¾ã ãƒ“ジー状態ã§ã™ + + + + The database is currently busy: + データベースã¯ç¾åœ¨ãƒ“ジー状態ã§ã™: + + + + Do you want to abort that other operation? + ä»–ã®æ“作を中断ã—ã¾ã™ã‹? + + + + Exporting database to SQL file... + データベースをSQLファイルã«ã‚¨ã‚¯ã‚¹ãƒãƒ¼ãƒˆ... + + + + + Cancel + キャンセル + + + + + No database file opened + データベースファイルを開ã„ã¦ã„ã¾ã›ã‚“ + + + + Executing SQL... + SQLを実行... + + + + Action cancelled. + æ“作をキャンセルã—ã¾ã—ãŸã€‚ + + + + + Error in statement #%1: %2. +Aborting execution%3. + ã“ã®æ–‡ã§ã‚¨ãƒ©ãƒ¼ #%1: %2。 +実行を中断%3。 + + + + + and rolling back + ロールãƒãƒƒã‚¯ã—ã¾ã—㟠+ + + + didn't receive any output from %1 + %1 ã‹ã‚‰å‡ºåŠ›ã‚’å¾—ã‚‰ã‚Œã¾ã›ã‚“ã§ã—㟠+ + + + could not execute command: %1 + コマンド: %1 を実行ã§ãã¾ã›ã‚“ã§ã—㟠+ + + + Cannot delete this object + ã“ã®ã‚ªãƒ–ジェクトã¯å‰Šé™¤ã§ãã¾ã›ã‚“ + + + + Cannot set data on this object + ã“ã®ã‚ªãƒ–ジェクトã«ãƒ‡ãƒ¼ã‚¿è¨­å®šã¯ã§ãã¾ã›ã‚“ + + + + + A table with the name '%1' already exists in schema '%2'. + åå‰ãŒ '%1' ã®ãƒ†ãƒ¼ãƒ–ルã¯ã‚¹ã‚­ãƒ¼ãƒž '%2' ã«æ—¢ã«å­˜åœ¨ã—ã¾ã™ã€‚ + + + + No table with name '%1' exists in schema '%2'. + スキーマ '%2' ã«åå‰ãŒ '%1' ã®ãƒ†ãƒ¼ãƒ–ルãŒã‚りã¾ã›ã‚“。 + + + + + Cannot find column %1. + カラム %1 ãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“。 + + + + Creating savepoint failed. DB says: %1 + セーブãƒã‚¤ãƒ³ãƒˆã®ä½œæˆã«å¤±æ•—。DBã®å応: %1 + + + + Renaming the column failed. DB says: +%1 + カラムå変更ã«å¤±æ•—。DBã®å応: +%1 + + + + + Releasing savepoint failed. DB says: %1 + セーブãƒã‚¤ãƒ³ãƒˆã®è§£æ”¾ã«å¤±æ•—。DBã®å応: %1 + + + + Creating new table failed. DB says: %1 + æ–°ã—ã„テーブルã®ä½œæˆã«å¤±æ•—。DBã®å応: %1 + + + + Copying data to new table failed. DB says: +%1 + æ–°ã—ã„テーブルã¸ã®ãƒ‡ãƒ¼ã‚¿ã®ã‚³ãƒ”ーã«å¤±æ•—。DBã®å応: +%1 + + + + Deleting old table failed. DB says: %1 + å¤ã„テーブルã®å‰Šé™¤ã«å¤±æ•—。DBã®å応: %1 + + + + Error renaming table '%1' to '%2'. +Message from database engine: +%3 + テーブルåã® '%1' ã‹ã‚‰ '%2' ã¸ã®å¤‰æ›´ã§ã‚¨ãƒ©ãƒ¼ã€‚ +データベースエンジンã‹ã‚‰ã®ãƒ¡ãƒƒã‚»ãƒ¼ã‚¸: +%3 + + + + could not get list of db objects: %1 + DBオブジェクトã®ä¸€è¦§ã‚’å–å¾—ã§ãã¾ã›ã‚“: %1 + + + + Restoring some of the objects associated with this table failed. This is most likely because some column names changed. Here's the SQL statement which you might want to fix and execute manually: + + + ã“ã®ãƒ†ãƒ¼ãƒ–ルã«é–¢é€£ã™ã‚‹ã‚ªãƒ–ジェクトã®å¾©å…ƒã«å¤±æ•—ã—ã¾ã—ãŸã€‚ã“れã¯ãŠãらã一部ã®ã‚«ãƒ©ãƒ åãŒå¤‰æ›´ã•れãŸãŸã‚ã§ã™ã€‚ã“ã®SQL文を手動ã§ä¿®æ­£ã—実行ã—ã¦ãã ã•ã„。 +Restoring some of the objects associated with this table failed. This is most likely because some column names changed. Here's the SQL statement which you might want to fix and execute manually: + + + + + + could not get list of databases: %1 + データベースã®ä¸€è¦§ã‚’å–å¾—ã§ãã¾ã›ã‚“: %1 + + + + Error setting pragma %1 to %2: %3 + プラグマ %1 ã‚’ %2 ã«è¨­å®šæ™‚ã«ã‚¨ãƒ©ãƒ¼: %3 + + + + File not found. + ファイルãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“。 + + + + Error loading extension: %1 + æ‹¡å¼µã®èª­ã¿è¾¼ã¿ã§ã‚¨ãƒ©ãƒ¼: %1 + + + + could not get column information + カラム情報ãŒå–å¾—ã§ãã¾ã›ã‚“ã§ã—㟠+ + + + DbStructureModel + + + Name + åå‰ + + + + Object + オブジェクト + + + + Type + データ型 + + + + Schema + スキーマ + + + + Database + データベース + + + + Browsables + 表示å¯èƒ½ + + + + All + ã™ã¹ã¦ + + + + Temporary + 一時 + + + + Tables (%1) + テーブル (%1) + + + + Indices (%1) + インデックス (%1) + + + + Views (%1) + ビュー (%1) + + + + Triggers (%1) + トリガー (%1) + + + + EditDialog + + + Edit database cell + データベースã®ã‚»ãƒ«ã‚’編集 + + + + Mode: + モード: + + + + This is the list of supported modes for the cell editor. Choose a mode for viewing or editing the data of the current cell. + ã“れã¯ã‚µãƒãƒ¼ãƒˆã—ã¦ã„るセル編集モードã®ä¸€è¦§ã§ã™ã€‚ç¾åœ¨ã®ã‚»ãƒ«ãƒ‡ãƒ¼ã‚¿ã®è¡¨ç¤ºä¿®æ­£ã«ä½¿ç”¨ã™ã‚‹ãƒ¢ãƒ¼ãƒ‰ã‚’é¸ã‚“ã§ãã ã•ã„。 + + + + Text + テキスト + + + + RTL Text + RTL テキスト + + + + Binary + ãƒã‚¤ãƒŠãƒªãƒ¼ + + + + + Image + ç”»åƒ + + + + JSON + JSON + + + + XML + XML + + + + + Automatically adjust the editor mode to the loaded data type + 編集モードを読ã¿è¾¼ã‚“ã ãƒ‡ãƒ¼ã‚¿åž‹ã«è‡ªå‹•çš„ã«èª¿æ•´ + + + + This checkable button enables or disables the automatic switching of the editor mode. When a new cell is selected or new data is imported and the automatic switching is enabled, the mode adjusts to the detected data type. You can then change the editor mode manually. If you want to keep this manually switched mode while moving through the cells, switch the button off. + ã“ã®ãƒã‚§ãƒƒã‚¯ãƒœã‚¿ãƒ³ã¯ç·¨é›†ãƒ¢ãƒ¼ãƒ‰ã®è‡ªå‹•切り替ãˆã‚’有効/無効ã«ã—ã¾ã™ã€‚æ–°ã—ã„セルãŒé¸æŠžã•ã‚Œã‚‹ã‹æ–°ã—ã„データãŒã‚¤ãƒ³ãƒãƒ¼ãƒˆã•ã‚ŒãŸæ™‚ã«è‡ªå‹•切り替ãˆãŒæœ‰åйã ã¨ã€æ¤œå‡ºã—ãŸãƒ‡ãƒ¼ã‚¿åž‹ã«ãƒ¢ãƒ¼ãƒ‰ã‚’調整ã—ã¾ã™ã€‚ãã®å¾Œã€ç·¨é›†ãƒ¢ãƒ¼ãƒ‰ã¯æ‰‹å‹•ã§å¤‰æ›´ã§ãã¾ã™ã€‚セル間ã®ç§»å‹•æ™‚ã«æ‰‹å‹•ã§å¤‰æ›´ã—ãŸãƒ¢ãƒ¼ãƒ‰ã‚’ç¶­æŒã—ãŸã„ãªã‚‰ã°ã€ã“ã®ãƒœã‚¿ãƒ³ã‚’オフã«ã—ã¾ã™ã€‚ + + + + Auto-switch + 自動切替 + + + + The text editor modes let you edit plain text, as well as JSON or XML data with syntax highlighting, automatic formatting and validation before saving. + +Errors are indicated with a red squiggle underline. + ã“ã®ç·¨é›†ãƒ¢ãƒ¼ãƒ‰ã¯æ§‹æ–‡å¼·èª¿ã—ã¦ã€ãƒ—レーンテキストã ã‘ã§ãªãã€JSONã‚„XMLデータを編集ã—ã‚„ã™ãã—ã¾ã™ã€‚ä¿å­˜å‰ã«è‡ªå‹•çš„ã«æ•´å½¢ã¨æ¤œè¨¼ã‚’ã—ã¾ã™ã€‚ + +エラーã¯èµ¤ã„ç ´ç·šã§ç¤ºã•れã¾ã™ã€‚ + + + + This Qt editor is used for right-to-left scripts, which are not supported by the default Text editor. The presence of right-to-left characters is detected and this editor mode is automatically selected. + ã“ã®Qtエディターã¯å³æ›¸ãã®æ–‡ç« ã«ä½¿ã‚れã¾ã™ã€‚ã“れã¯ãƒ‡ãƒ•ォルトã®ãƒ†ã‚­ã‚¹ãƒˆã‚¨ãƒ‡ã‚£ã‚¿ãƒ¼ã§ã¯ã‚µãƒãƒ¼ãƒˆã•れã¦ã„ã¾ã›ã‚“ã€‚å³æ›¸ãã®æ–‡å­—ã®å­˜åœ¨ãŒæ¤œçŸ¥ã•れるã¨ã€ã“ã®ã‚¨ãƒ‡ã‚£ã‚¿ãƒ¼ãƒ¢ãƒ¼ãƒ‰ãŒè‡ªå‹•çš„ã«é¸æŠžã•れã¾ã™ã€‚ + + + + Apply data to cell + セルã«ãƒ‡ãƒ¼ã‚¿ã‚’é©ç”¨ + + + + Open preview dialog for printing the data currently stored in the cell + ç¾åœ¨ã‚»ãƒ«ã«ã‚るデータをå°åˆ·ã™ã‚‹ãƒ—レビューダイアログを開ã + + + + Auto-format: pretty print on loading, compact on saving. + 自動整形: ãれã„ã«è¡¨ç¤ºã€åœ§ç¸®ã—ã¦ä¿å­˜ã€‚ + + + + When enabled, the auto-format feature formats the data on loading, breaking the text in lines and indenting it for maximum readability. On data saving, the auto-format feature compacts the data removing end of lines, and unnecessary whitespace. + 有効ã«ã™ã‚‹ã¨ã€è‡ªå‹•整形機能ã¯èª­ã¿è¾¼ã¿æ™‚ã«ãƒ‡ãƒ¼ã‚¿ã®å¯èª­æ€§ã‚’高ã‚る改行ã¨ã‚¤ãƒ³ãƒ‡ãƒ³ãƒˆã‚’加ãˆã¾ã™ã€‚データã®ä¿å­˜æ™‚ã«ã¯ã€æ”¹è¡Œã¨ä¸è¦ãªç©ºç™½ã‚’å–り除ãデータを圧縮ã—ã¾ã™ã€‚ + + + + Word Wrap + ワードラップ + + + + Wrap lines on word boundaries + å˜èªžå˜ä½ã§ãƒ¯ãƒ¼ãƒ‰ãƒ©ãƒƒãƒ— + + + + + Open in default application or browser + デフォルトã®ã‚¢ãƒ—リケーションã‹ãƒ–ラウザーã§é–‹ã + + + + Open in application + アプリケーションã§é–‹ã + + + + The value is interpreted as a file or URL and opened in the default application or web browser. + 値ã¯ãƒ•ァイルã‹URLã¨è§£é‡ˆã•れã€ãƒ‡ãƒ•ォルトã®ã‚¢ãƒ—リケーションã‹ã‚¦ã‚§ãƒ–ブラウザã§é–‹ã‹ã‚Œã¾ã™ã€‚ + + + + Save file reference... + ファイルå‚ç…§ã‚’ä¿å­˜... + + + + Save reference to file + å‚照をファイルã«ä¿å­˜ + + + + + Open in external application + 外部ã®ã‚¢ãƒ—リケーションã§é–‹ã + + + + Autoformat + 自動整形 + + + + &Export... + エクスãƒãƒ¼ãƒˆ(&E)... + + + + + &Import... + インãƒãƒ¼ãƒˆ(&I)... + + + + + Import from file + ファイルã‹ã‚‰ã‚¤ãƒ³ãƒãƒ¼ãƒˆ + + + + + Opens a file dialog used to import any kind of data to this database cell. + ã“ã®ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã®ã‚»ãƒ«ã«ä»»æ„ã®ç¨®é¡žã®ãƒ‡ãƒ¼ã‚¿ã‚’インãƒãƒ¼ãƒˆã™ã‚‹ãƒ•ァイルダイアログを開ãã¾ã™ã€‚ + + + + Export to file + ファイルã¸ã‚¨ã‚¯ã‚¹ãƒãƒ¼ãƒˆ + + + + Opens a file dialog used to export the contents of this database cell to a file. + ã“ã®ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã®ã‚»ãƒ«ã®å†…容をファイルã«ã‚¨ã‚¯ã‚¹ãƒãƒ¼ãƒˆã™ã‚‹ãƒ•ァイルダイアログを開ãã¾ã™ã€‚ + + + + Erases the contents of the cell + セルã®å†…容を削除 + + + + Set as &NULL + NULLã«è¨­å®š(&N) + + + + This area displays information about the data present in this database cell + ã“ã®ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã®ã‚»ãƒ«ã«å­˜åœ¨ã™ã‚‹ãƒ‡ãƒ¼ã‚¿ã®æƒ…報をã“ã“ã«è¡¨ç¤º + + + + Type of data currently in cell + ç¾åœ¨ã‚»ãƒ«ã«ã‚るデータã®ç¨®é¡ž + + + + Size of data currently in table + ç¾åœ¨ãƒ†ãƒ¼ãƒ–ルã«ã‚るデータã®ã‚µã‚¤ã‚º + + + + This button saves the changes performed in the cell editor to the database cell. + ã“ã®ãƒœã‚¿ãƒ³ã¯ã‚¨ãƒ‡ã‚£ã‚¿ãƒ¼ã§è¡Œã‚れãŸå¤‰æ›´ã‚’データベースã®ã‚»ãƒ«ã«ä¿å­˜ã—ã¾ã™ã€‚ + + + + Apply + é©ç”¨ + + + + + Print... + å°åˆ·... + + + + Open preview dialog for printing displayed image + 表示ã•れãŸç”»åƒã‚’å°åˆ·ã™ã‚‹ãƒ—レビューダイアログを開ã + + + + + Ctrl+P + + + + + Open preview dialog for printing displayed text + 表示ã•れãŸãƒ†ã‚­ã‚¹ãƒˆã‚’å°åˆ·ã™ã‚‹ãƒ—レビューダイアログを開ã + + + + Copy Hex and ASCII + å六進数ã¨ASCIIをコピー + + + + Copy selected hexadecimal and ASCII columns to the clipboard + é¸æŠžã—ãŸå六進数ã¨ASCIIã®ã‚«ãƒ©ãƒ ã‚’クリップボードã«ã‚³ãƒ”ー + + + + Ctrl+Shift+C + + + + + + Image data can't be viewed in this mode. + ç”»åƒãƒ‡ãƒ¼ã‚¿ã¯ã“ã®ãƒ¢ãƒ¼ãƒ‰ã§ã¯è¡¨ç¤ºã§ãã¾ã›ã‚“。 + + + + + Try switching to Image or Binary mode. + ç”»åƒ/ãƒã‚¤ãƒŠãƒªãƒ¼ãƒ¢ãƒ¼ãƒ‰ã«åˆ‡ã‚Šæ›¿ãˆã¦ã¿ã¦ãã ã•ã„。 + + + + + Binary data can't be viewed in this mode. + ãƒã‚¤ãƒŠãƒªãƒ¼ãƒ‡ãƒ¼ã‚¿ã¯ã“ã®ãƒ¢ãƒ¼ãƒ‰ã§ã¯è¡¨ç¤ºã§ãã¾ã›ã‚“。 + + + + + Try switching to Binary mode. + ãƒã‚¤ãƒŠãƒªãƒ¼ãƒ¢ãƒ¼ãƒ‰ã«åˆ‡ã‚Šæ›¿ãˆã¦ã¿ã¦ãã ã•ã„。 + + + + + Image files (%1) + ç”»åƒãƒ•ァイル (%1) + + + + Binary files (*.bin) + ãƒã‚¤ãƒŠãƒªãƒ¼ãƒ•ァイル (*.bin) + + + + Choose a file to import + インãƒãƒ¼ãƒˆã™ã‚‹ãƒ•ã‚¡ã‚¤ãƒ«ã‚’é¸æŠž + + + + %1 Image + %1 ç”»åƒ + + + + Choose a filename to export data + エクスãƒãƒ¼ãƒˆãƒ‡ãƒ¼ã‚¿ã®ãƒ•ァイルåã‚’é¸æŠž + + + + Invalid data for this mode + ã“ã®ãƒ¢ãƒ¼ãƒ‰ã§ã¯ä¸æ­£ãªãƒ‡ãƒ¼ã‚¿ + + + + The cell contains invalid %1 data. Reason: %2. Do you really want to apply it to the cell? + セルã«ä¸æ­£ãªãƒ‡ãƒ¼ã‚¿ %1 ãŒã‚りã¾ã™ã€‚ç†ç”±: %2。本当ã«ã‚»ãƒ«ã«é©ç”¨ã—ã¾ã™ã‹? + + + + + Type of data currently in cell: Text / Numeric + ç¾åœ¨ã‚»ãƒ«ã«ã‚るデータã®ç¨®é¡ž: テキスト / 数値 + + + + + + %n character(s) + + %n 文字 + + + + + Type of data currently in cell: %1 Image + ç¾åœ¨ã‚»ãƒ«ã«ã‚るデータã®ç¨®é¡ž: %1 ç”»åƒ + + + + %1x%2 pixel(s) + %1x%2 ピクセル + + + + Type of data currently in cell: NULL + ç¾åœ¨ã‚»ãƒ«ã«ã‚るデータã®ç¨®é¡ž: NULL + + + + + %n byte(s) + + %n ãƒã‚¤ãƒˆ + + + + + Type of data currently in cell: Valid JSON + ç¾åœ¨ã‚»ãƒ«ã«ã‚るデータã®ç¨®é¡ž: æ­£è¦ãªJSON + + + + Type of data currently in cell: Binary + ç¾åœ¨ã‚»ãƒ«ã«ã‚るデータã®ç¨®é¡ž: ãƒã‚¤ãƒŠãƒªãƒ¼ + + + + Couldn't save file: %1. + ファイルをä¿å­˜ã§ãã¾ã›ã‚“: %1. + + + + The data has been saved to a temporary file and has been opened with the default application. You can now edit the file and, when you are ready, apply the saved new data to the cell editor or cancel any changes. + データã¯ä¸€æ™‚ファイルã«ä¿å­˜ã•れã€ãƒ‡ãƒ•ォルトã®ã‚¢ãƒ—リケーションã§é–‹ã‹ã‚Œã¾ã—ãŸã€‚ã™ãã«ãƒ•ァイルを編集ã§ãã€æº–å‚™ãŒã§ããŸã‚‰ã€ä¿å­˜ã—ãŸæ–°ã—ã„データをセルエディターã«é©ç”¨ã™ã‚‹ã‹ã€å¤‰æ›´ã‚’キャンセルã§ãã¾ã™ã€‚ + + + + EditIndexDialog + + + Edit Index Schema + インデックスã®ã‚¹ã‚­ãƒ¼ãƒžã‚’編集 + + + + &Name + åå‰(&N) + + + + &Table + テーブル(&T) + + + + &Unique + 一æ„(&U) + + + + For restricting the index to only a part of the table you can specify a WHERE clause here that selects the part of the table that should be indexed + インデックスをテーブルã®ä¸€éƒ¨ã®ã¿ã«åˆ¶é™ã™ã‚‹å ´åˆã¯ã€ãã®éƒ¨åˆ†ã‚’é¸æŠžã™ã‚‹WHERE節をã“ã“ã«æŒ‡å®šã—ã¾ã™ + + + + Partial inde&x clause + インデックス指定節(&X) + + + + Colu&mns + カラム(&M) + + + + Table column + テーブルã®ã‚«ãƒ©ãƒ  + + + + Type + データ型 + + + + Add a new expression column to the index. Expression columns contain SQL expression rather than column names. + æ–°ã—ã„å¼ã‚«ãƒ©ãƒ ã‚’インデックスã«åŠ ãˆã‚‹ã€‚å¼ã‚«ãƒ©ãƒ ã¯ã‚«ãƒ©ãƒ åã§ãªãSQLå¼ã‚’æŒã¡ã¾ã™ã€‚ + + + + Index column + インデックスカラム + + + + Order + 順番 + + + + Deleting the old index failed: +%1 + å¤ã„インデックスã®å‰Šé™¤ã«å¤±æ•—: +%1 + + + + Creating the index failed: +%1 + インデックスã®ä½œæˆã«å¤±æ•—: +%1 + + + + EditTableDialog + + + Edit table definition + テーブルã®å®šç¾©ã‚’編集 + + + + Table + テーブル + + + + Advanced + 高度ãªè¨­å®š + + + + Without Rowid + Rowidãªã— + + + + Make this a 'WITHOUT rowid' table. Setting this flag requires a field of type INTEGER with the primary key flag set and the auto increment flag unset. + テーブルをrowidãªã—ã§ä½œæˆã—ã¾ã™ã€‚ã“れを設定ã™ã‚‹ã«ã¯ã€ä¸»ã‚­ãƒ¼ã«è¨­å®šã•れãŸè‡ªå‹•増加ãªã—ã®INTEGERフィールドãŒå¿…è¦ã§ã™ã€‚ + + + + Fields + フィールド + + + + Database sche&ma + データベーススキーマ(&M) + + + + Add + 追加 + + + + Remove + 削除 + + + + Move to top + 先頭㸠+ + + + Move up + 上㸠+ + + + Move down + 下㸠+ + + + Move to bottom + 末尾㸠+ + + + + Name + åå‰ + + + + + Type + データ型 + + + + NN + NN + + + + Not null + éžnull + + + + PK + PK + + + + Primary key + 主キー + + + + AI + AI + + + + Autoincrement + 自動増加 + + + + U + U + + + + + + Unique + ä¸€æ„ + + + + Default + デフォルト + + + + Default value + デフォルト値 + + + + + + Check + 検査 + + + + Check constraint + 検査制約 + + + + Collation + ç…§åˆé †åº + + + + + + Foreign Key + 外部キー + + + + Constraints + 制約 + + + + Add constraint + 制約を追加 + + + + Remove constraint + 制約を削除 + + + + Columns + カラム + + + + SQL + SQL + + + + <html><head/><body><p><span style=" font-weight:600; color:#ff0000;">Warning: </span>There is something with this table definition that our parser doesn't fully understand. Modifying and saving this table might result in problems.</p></body></html> + <html><head/><body><p><span style=" font-weight:600; color:#ff0000;">警告: </span>ãƒ†ãƒ¼ãƒ–ãƒ«å®šç¾©ã«æ§‹æ–‡è§£æžã§ããªã„ã‚‚ã®ãŒã‚りã¾ã™ã€‚ã“ã®ãƒ†ãƒ¼ãƒ–ルを変更ã—ä¿å­˜ã™ã‚‹ã¨å•題ãŒèµ·ãã‚‹ã‹ã‚‚ã—れã¾ã›ã‚“。.</p></body></html> + + + + + Primary Key + 主キー + + + + Add a primary key constraint + 主キー制約を追加 + + + + Add a foreign key constraint + 外部キー制約を追加 + + + + Add a unique constraint + ä¸€æ„æ€§åˆ¶ç´„を追加 + + + + Add a check constraint + 検査誓約を追加 + + + + + There can only be one primary key for each table. Please modify the existing primary key instead. + 主キーã¯å„テーブルã«ä¸€ã¤ã ã‘存在ã§ãã¾ã™ã€‚替ã‚ã‚Šã«æ—¢å­˜ã®ä¸»ã‚­ãƒ¼ã‚’変更ã—ã¦ãã ã•ã„。 + + + + Error creating table. Message from database engine: +%1 + テーブル作æˆã§ã‚¨ãƒ©ãƒ¼ã€‚データベースエンジンã‹ã‚‰ã®ãƒ¡ãƒƒã‚»ãƒ¼ã‚¸: +%1 + + + + There already is a field with that name. Please rename it first or choose a different name for this field. + ã“ã®åå‰ã¯æ—¢ã«åˆ¥ã®ãƒ•ィールドã«ä½¿ç”¨ã•れã¦ã„ã¾ã™ã€‚既存ã®ãƒ•ィールドåを変更ã™ã‚‹ã‹ã€åˆ¥ã®åå‰ã‚’付ã‘ã¦ãã ã•ã„。 + + + + This column is referenced in a foreign key in table %1 and thus its name cannot be changed. + ã“ã®ã‚«ãƒ©ãƒ ã¯ãƒ†ãƒ¼ãƒ–ル %1 ã®å¤–部キーã«å‚ç…§ã•れã¦ã„ã‚‹ã®ã§ã€åå‰ã‚’変更ã§ãã¾ã›ã‚“。 + + + + There is at least one row with this field set to NULL. This makes it impossible to set this flag. Please change the table data first. + å°‘ãªãã¨ã‚‚1ã¤ã®è¡Œã§ã“ã®ãƒ•ィールドã«NULLãŒè¨­å®šã•れã¦ã„ã¾ã™ã€‚ãã®ãŸã‚ã€éžNULLを設定ã™ã‚‹ã®ã¯ä¸å¯èƒ½ã§ã™ã€‚å…ˆã«ãƒ†ãƒ¼ãƒ–ルã®ãƒ‡ãƒ¼ã‚¿ã‚’変更ã—ã¦ãã ã•ã„。 + + + + There is at least one row with a non-integer value in this field. This makes it impossible to set the AI flag. Please change the table data first. + å°‘ãªãã¨ã‚‚1ã¤ã®è¡Œã§ã“ã®ãƒ•ィールドã«INTEGERã§ãªã„値ãŒè¨­å®šã•れã¦ã„ã¾ã™ã€‚ãã®ãŸã‚ã€è‡ªå‹•増加を設定ã™ã‚‹ã®ã¯ä¸å¯èƒ½ã§ã™ã€‚å…ˆã«ãƒ†ãƒ¼ãƒ–ルã®ãƒ‡ãƒ¼ã‚¿ã‚’変更ã—ã¦ãã ã•ã„。 + + + + Column '%1' has duplicate data. + + カラム '%1' ã«é‡è¤‡ãƒ‡ãƒ¼ã‚¿ãŒã‚りã¾ã™ã€‚ + + + + + This makes it impossible to enable the 'Unique' flag. Please remove the duplicate data, which will allow the 'Unique' flag to then be enabled. + 一æ„ã«ã™ã‚‹ã®ã¯ä¸å¯èƒ½ã§ã™ã€‚é‡è¤‡ãƒ‡ãƒ¼ã‚¿ã‚’削除ã™ã‚‹ã¨ã€ä¸€æ„ã«ã§ãるよã†ã«ãªã‚Šã¾ã™ã€‚ + + + + Are you sure you want to delete the field '%1'? +All data currently stored in this field will be lost. + 本当ã«ãƒ•ィールド '%1' を削除ã—ã¾ã™ã‹? +ç¾åœ¨ã“ã®ãƒ•ィールドã«ã‚ã‚‹ã™ã¹ã¦ã®ãƒ‡ãƒ¼ã‚¿ã¯å¤±ã‚れã¾ã™ã€‚ + + + + Please add a field which meets the following criteria before setting the without rowid flag: + - Primary key flag set + - Auto increment disabled + rowidã‚’ãªã—ã«ã—ã¦ã€ä»¥ä¸‹ã®æ¡ä»¶ã«åˆã†ãƒ•ィールドを追加ã—ã¦ãã ã•ã„。 + - 主キーã«ã™ã‚‹ + - 自動増加ãªã— + + + + ExportDataDialog + + + Export data as CSV + データをCSVã«ã‚¨ã‚¯ã‚¹ãƒãƒ¼ãƒˆ + + + + Tab&le(s) + テーブル(&L) + + + + Colu&mn names in first line + 先頭行をカラムåã«(&M) + + + + Fie&ld separator + フィールド区切り(&L) + + + + , + , + + + + ; + ; + + + + Tab + タブ + + + + | + | + + + + + + Other + ãã®ä»– + + + + &Quote character + 引用符文字(&Q) + + + + " + " + + + + ' + ' + + + + New line characters + 改行文字 + + + + Windows: CR+LF (\r\n) + Windows: CR+LF (\r\n) + + + + Unix: LF (\n) + Unix: LF (\n) + + + + Pretty print + æ•´å½¢ + + + + Export data as JSON + データをJSONã«ã‚¨ã‚¯ã‚¹ãƒãƒ¼ãƒˆ + + + + exporting CSV + CSVã«ã‚¨ã‚¯ã‚¹ãƒãƒ¼ãƒˆ + + + + + Could not open output file: %1 + 出力ファイルを開ã‘ã¾ã›ã‚“: %1 + + + + exporting JSON + JSONã«ã‚¨ã‚¯ã‚¹ãƒãƒ¼ãƒˆ + + + + + Choose a filename to export data + エクスãƒãƒ¼ãƒˆãƒ‡ãƒ¼ã‚¿ã®ãƒ•ァイルåã‚’é¸æŠž + + + + Please select at least 1 table. + å°‘ãªãã¨ã‚‚1ã¤ã®ãƒ†ãƒ¼ãƒ–ãƒ«ã‚’é¸æŠžã—ã¦ãã ã•ã„。 + + + + Choose a directory + ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªãƒ¼ã‚’é¸æŠž + + + + Export completed. + エクスãƒãƒ¼ãƒˆå®Œäº†ã€‚ + + + + ExportSqlDialog + + + Export SQL... + SQLã«ã‚¨ã‚¯ã‚¹ãƒãƒ¼ãƒˆ... + + + + Tab&le(s) + テーブル(&L) + + + + Select All + ã™ã¹ã¦é¸æŠž + + + + Deselect All + ã™ã¹ã¦éžé¸æŠž + + + + &Options + オプション(&O) + + + + Keep column names in INSERT INTO + INSERT INTO ã«ã‚«ãƒ©ãƒ åã‚’ä¿æŒ + + + + Multiple rows (VALUES) per INSERT statement + INSERTæ–‡ã«è¤‡æ•°è¡Œ(VALUES) + + + + Export everything + ã™ã¹ã¦ã‚¨ã‚¯ã‚¹ãƒãƒ¼ãƒˆ + + + + Export schema only + スキーマã®ã¿ã‚’エクスãƒãƒ¼ãƒˆ + + + + Export data only + データã®ã¿ã‚’エクスãƒãƒ¼ãƒˆ + + + + Keep old schema (CREATE TABLE IF NOT EXISTS) + å¤ã„ã‚¹ã‚­ãƒ¼ãƒžã‚’ä¿æŒ (CREATE TABLE IF NOT EXISTS) + + + + Overwrite old schema (DROP TABLE, then CREATE TABLE) + å¤ã„スキーマを上書ã (DROP TABLE ã—ãŸå¾Œã« CREATE TABLE) + + + + Please select at least one table. + å°‘ãªãã¨ã‚‚1ã¤ã®ãƒ†ãƒ¼ãƒ–ãƒ«ã‚’é¸æŠžã—ã¦ãã ã•ã„。 + + + + Choose a filename to export + エクスãƒãƒ¼ãƒˆã™ã‚‹ãƒ•ァイルåã‚’é¸æŠž + + + + Export completed. + エクスãƒãƒ¼ãƒˆå®Œäº†ã€‚ + + + + Export cancelled or failed. + エクスãƒãƒ¼ãƒˆã‚’キャンセルã¾ãŸã¯å¤±æ•—ã—ã¾ã—ãŸã€‚ + + + + ExtendedScintilla + + + + Ctrl+H + + + + + Ctrl+F + + + + + + Ctrl+P + + + + + Find... + 検索... + + + + Find and Replace... + 検索ã¨ç½®æ›... + + + + Print... + å°åˆ·... + + + + ExtendedTableWidget + + + Use as Exact Filter + 抽出フィルターã«ä½¿ã† + + + + Containing + å«ã‚€ + + + + Not containing + å«ã¾ãªã„ + + + + Not equal to + ç­‰ã—ããªã„ + + + + Greater than + より大ãã„ + + + + Less than + 未満 + + + + Greater or equal + 以上 + + + + Less or equal + 以下 + + + + Between this and... + ã“れã¨ã®é–“... + + + + Regular expression + æ­£è¦è¡¨ç¾ + + + + Edit Conditional Formats... + æ¡ä»¶ä»˜ã書å¼ã‚’編集... + + + + Set to NULL + NULLã«è¨­å®š + + + + Copy + コピー + + + + Copy with Headers + ヘッダーをå«ã‚ã¦ã‚³ãƒ”ー + + + + Copy as SQL + SQLã¨ã—ã¦ã‚³ãƒ”ー + + + + Paste + 貼り付㑠+ + + + Print... + å°åˆ·... + + + + Use in Filter Expression + フィルターå¼ã‚’使用 + + + + Alt+Del + + + + + Ctrl+Shift+C + + + + + Ctrl+Alt+C + + + + + The content of the clipboard is bigger than the range selected. +Do you want to insert it anyway? + クリップボードã®å†…容ã¯é¸æŠžã•れãŸç¯„囲より大ãã„ã§ã™. +ãれã§ã‚‚挿入ã—ã¾ã™ã‹? + + + + <p>Not all data has been loaded. <b>Do you want to load all data before selecting all the rows?</b><p><p>Answering <b>No</b> means that no more data will be loaded and the selection will not be performed.<br/>Answering <b>Yes</b> might take some time while the data is loaded but the selection will be complete.</p>Warning: Loading all the data might require a great amount of memory for big tables. + <p>読ã¿è¾¼ã¾ã‚Œã¦ã„ãªã„データãŒã‚りã¾ã™ã€‚<b>ã™ã¹ã¦ã®è¡Œã‚’é¸æŠžã™ã‚‹å‰ã«ã€ã™ã¹ã¦ã®ãƒ‡ãƒ¼ã‚¿ã‚’読ã¿è¾¼ã¿ã¾ã™ã‹?</b><p><p>ç­”ãˆãŒ <b>ã„ã„ãˆ</b> ãªã‚‰ã°ã€ãƒ‡ãƒ¼ã‚¿ã¯èª­ã¿è¾¼ã¾ã‚Œãšã€é¸æŠžã¯å®Ÿè¡Œã•れã¾ã›ã‚“。<br/>ç­”ãˆãŒ <b>ã¯ã„</b> ãªã‚‰ã°ã€æ™‚é–“ãŒã‹ã‹ã‚Šã¾ã™ãŒã€ã™ã¹ã¦ã®ãƒ‡ãƒ¼ã‚¿ã‚’読ã¿è¾¼ã¿ã€é¸æŠžãŒå®Ÿè¡Œã•れã¾ã™ã€‚</p>警告: 大ãã„テーブルã«ã‚ã‚‹ã™ã¹ã¦ã®ãƒ‡ãƒ¼ã‚¿ã®èª­ã¿è¾¼ã¿ã«ã¯ã‹ãªã‚Šã®è¨˜æ†¶é ˜åŸŸã‚’å¿…è¦ã¨ã—ã¾ã™ã€‚ + + + + Cannot set selection to NULL. Column %1 has a NOT NULL constraint. + é¸æŠžç¯„å›²ã«NULLを設定ã§ãã¾ã›ã‚“。カラム %1 ã«ã¯éžNULL制約ãŒã‚りã¾ã™ã€‚ + + + + FileExtensionManager + + + File Extension Manager + ファイル拡張å­ç®¡ç† + + + + &Up + 上ã¸(&U) + + + + &Down + 下ã¸(&D) + + + + &Add + 追加(&A) + + + + &Remove + 削除(&R) + + + + + Description + 説明 + + + + Extensions + æ‹¡å¼µå­ + + + + *.extension + *.æ‹¡å¼µå­ + + + + FilterLineEdit + + + Filter + フィルター + + + + These input fields allow you to perform quick filters in the currently selected table. +By default, the rows containing the input text are filtered out. +The following operators are also supported: +% Wildcard +> Greater than +< Less than +>= Equal to or greater +<= Equal to or less += Equal to: exact match +<> Unequal: exact inverse match +x~y Range: values between x and y +/regexp/ Values matching the regular expression + ã“ã®å…¥åŠ›æ¬„ã¯ç¾åœ¨é¸æŠžã—ãŸãƒ†ãƒ¼ãƒ–ルã®å³å¸­ãƒ•ィルターã«ãªã‚Šã¾ã™ã€‚ +デフォルトã§ã¯å…¥åŠ›ãƒ†ã‚­ã‚¹ãƒˆãŒå«ã¾ã‚Œã‚‹è¡ŒãŒæŠ½å‡ºã•れã¾ã™ã€‚ +ä»¥ä¸‹ã®æ¼”ç®—å­ã«ã‚‚対応ã—ã¦ã„ã¾ã™ã€‚: +% ワイルドカード +> より大ãã„ +< 未満 +>= 以上 +<= 以下 += ç­‰ã—ã„: 完全ã«ä¸€è‡´ +<> ç­‰ã—ããªã„: ä¸ä¸€è‡´ +x~y 範囲: xã¨yã®é–“ +/regexp/ æ­£è¦è¡¨ç¾ã«ä¸€è‡´ã™ã‚‹å€¤ + + + + Set Filter Expression + フィルターå¼ã‚’設定 + + + + What's This? + ã“れã¯ä½•? + + + + Is NULL + NULL + + + + Is not NULL + NULLã§ãªã„ + + + + Is empty + 空文字 + + + + Is not empty + 空文字ã§ãªã„ + + + + Not containing... + å«ã¾ãªã„... + + + + Equal to... + ç­‰ã—ã„... + + + + Not equal to... + ç­‰ã—ããªã„... + + + + Greater than... + より大ãã„... + + + + Less than... + 未満... + + + + Greater or equal... + 以上... + + + + Less or equal... + 以下... + + + + In range... + 範囲内... + + + + Regular expression... + æ­£è¦è¡¨ç¾... + + + + Clear All Conditional Formats + ã™ã¹ã¦ã®æ¡ä»¶ä»˜ã書å¼ã‚’削除 + + + + Use for Conditional Format + æ¡ä»¶ä»˜ã書å¼ã‚’使ㆠ+ + + + Edit Conditional Formats... + æ¡ä»¶ä»˜ã書å¼ã‚’編集... + + + + FindReplaceDialog + + + Find and Replace + 検索ã¨ç½®æ› + + + + Fi&nd text: + 検索文字列(&N): + + + + Re&place with: + ç½®æ›æ–‡å­—列(&P): + + + + Match &exact case + 大/å°æ–‡å­—を区別(&E) + + + + Match &only whole words + å˜èªžä¸€è‡´ã®ã¿(&O) + + + + When enabled, the search continues from the other end when it reaches one end of the page + 有効ã«ã™ã‚‹ã¨ã€ãƒšãƒ¼ã‚¸ã®æœ€å¾Œã«åˆ°é”ã™ã‚‹ã¨å…ˆé ­ã«æˆ»ã£ã¦æ¤œç´¢ã—ã¾ã™ + + + + &Wrap around + 折り返ã—ã‚り(&W) + + + + When set, the search goes backwards from cursor position, otherwise it goes forward + 設定ã™ã‚‹ã¨ã‚«ãƒ¼ã‚½ãƒ«ä½ç½®ã‹ã‚‰æˆ»ã£ã¦æ¤œç´¢ã—ã¾ã™ã€‚設定ã—ãªã„ã¨ã‚«ãƒ¼ã‚½ãƒ«ä½ç½®ã®å…ˆã‚’検索ã—ã¾ã™ + + + + Search &backwards + 戻ã£ã¦æ¤œç´¢(&B) + + + + <html><head/><body><p>When checked, the pattern to find is searched only in the current selection.</p></body></html> + <html><head/><body><p>設定ã™ã‚‹ã¨ã€ç¾åœ¨é¸æŠžã—ãŸç¯„囲ã®ã¿ã‚’検索ã—ã¾ã™ã€‚</p></body></html> + + + + &Selection only + é¸æŠžç¯„å›²ã®ã¿(&S) + + + + <html><head/><body><p>When checked, the pattern to find is interpreted as a UNIX regular expression. See <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>.</p></body></html> + <html><head/><body><p>設定ã™ã‚‹ã¨ã€æ¤œç´¢æ–‡å­—列ã¯UNIXæ­£è¦è¡¨ç¾ã¨è§£é‡ˆã•れã¾ã™ã€‚以下をå‚ç…§ <a href="https://ja.wikibooks.org/wiki/%E6%AD%A3%E8%A6%8F%E8%A1%A8%E7%8F%BE">Wikibooksã®æ­£è¦è¡¨ç¾</a>。</p></body></html> + + + + Use regular e&xpressions + æ­£è¦è¡¨ç¾ã‚’使用(&X) + + + + Find the next occurrence from the cursor position and in the direction set by "Search backwards" + カーソルä½ç½®ã‹ã‚‰"戻ã£ã¦æ¤œç´¢"ã§è¨­å®šã—ãŸæ–¹å‘ã«ã‚ã‚‹ã€æ¬¡ã«ä¸€è‡´ã™ã‚‹æ–‡å­—列を検索ã—ã¾ã™ + + + + &Find Next + 次を検索(&F) + + + + F3 + + + + + &Replace + ç½®æ›(&R) + + + + Highlight all the occurrences of the text in the page + ページ内ã®ã™ã¹ã¦ã®ä¸€è‡´ã™ã‚‹æ–‡å­—列を強調 + + + + F&ind All + ã™ã¹ã¦æ¤œç´¢(&I) + + + + Replace all the occurrences of the text in the page + ページ内ã®ã™ã¹ã¦ã®ä¸€è‡´ã™ã‚‹æ–‡å­—åˆ—ã‚’ç½®æ› + + + + Replace &All + ã™ã¹ã¦ç½®æ›(&A) + + + + The searched text was not found + 検索文字列ã¯è¦‹ã¤ã‹ã‚Šã¾ã›ã‚“ã§ã—㟠+ + + + The searched text was not found. + 検索文字列ã¯è¦‹ã¤ã‹ã‚Šã¾ã›ã‚“ã§ã—ãŸã€‚ + + + + The searched text was found one time. + 検索文字列ãŒ1ã¤ã‚りã¾ã—ãŸã€‚ + + + + The searched text was found %1 times. + 検索文字列ãŒ%1ã¤ã‚りã¾ã—ãŸã€‚ + + + + The searched text was replaced one time. + 検索文字列を1ã¤ç½®ãæ›ãˆã¾ã—ãŸã€‚ + + + + The searched text was replaced %1 times. + 検索文字列を%1ã¤ç½®ãæ›ãˆã¾ã—ãŸã€‚ + + + + ForeignKeyEditor + + + &Reset + リセット(&R) + + + + Foreign key clauses (ON UPDATE, ON DELETE etc.) + 外部キー節 (ON UPDATE, ON DELETE ãªã©ã€‚) + + + + ImportCsvDialog + + + Import CSV file + CSVファイルをインãƒãƒ¼ãƒˆ + + + + Table na&me + テーブルå(&M) + + + + &Column names in first line + 先頭行をカラムåã«(&C) + + + + Field &separator + フィールド区切り(&S) + + + + , + , + + + + ; + ; + + + + + Tab + タブ + + + + | + | + + + + Other + ãã®ä»– + + + + &Quote character + 引用符文字(&Q) + + + + + Other (printable) + ãã®ä»– (å°åˆ·å¯èƒ½) + + + + + Other (code) + ãã®ä»– (文字コード) + + + + " + " + + + + ' + ' + + + + &Encoding + エンコード(&E) + + + + UTF-8 + UTF-8 + + + + UTF-16 + UTF-16 + + + + ISO-8859-1 + ISO-8859-1 + + + + Trim fields? + フィールドをトリムã™ã‚‹? + + + + Separate tables + テーブルを分ã‘ã‚‹ + + + + Advanced + 高度ãªè¨­å®š + + + + When importing an empty value from the CSV file into an existing table with a default value for this column, that default value is inserted. Activate this option to insert an empty value instead. + 空値をCSVファイルã‹ã‚‰æ—¢å­˜ã®ãƒ†ãƒ¼ãƒ–ルã®ãƒ‡ãƒ•ォルト値ãŒã‚るカラムã«ã‚¤ãƒ³ãƒãƒ¼ãƒˆã™ã‚‹ã¨ã€ãƒ‡ãƒ•ã‚©ãƒ«ãƒˆå€¤ãŒæŒ¿å…¥ã•れã¾ã™ã€‚ã“ã®ã‚ªãƒ—ションを有効ã«ã™ã‚‹ã¨ä»£ã‚りã«ç©ºå€¤ãŒæŒ¿å…¥ã•れã¾ã™ã€‚ + + + + Ignore default &values + デフォルト値を無視(&V) + + + + Activate this option to stop the import when trying to import an empty value into a NOT NULL column without a default value. + ã“ã®ã‚ªãƒ—ションを有効ã«ã™ã‚‹ã¨ã€ãƒ‡ãƒ•ォルト値ãŒãªã NOT NULL ãªã‚«ãƒ©ãƒ ã«ç©ºå€¤ã‚’インãƒãƒ¼ãƒˆã—よã†ã¨ã—ãŸã¨ãã«ã€ã‚¤ãƒ³ãƒãƒ¼ãƒˆã‚’中止ã—ã¾ã™ã€‚ + + + + Fail on missing values + 値ãŒãªã„å ´åˆä¸­æ­¢ + + + + Disable data type detection + データ型検出を無効 + + + + Disable the automatic data type detection when creating a new table. + æ–°ã—ã„テーブルを作るã¨ãã«è‡ªå‹•データ型検出を無効ã«ã—ã¾ã™ã€‚ + + + + When importing into an existing table with a primary key, unique constraints or a unique index there is a chance for a conflict. This option allows you to select a strategy for that case: By default the import is aborted and rolled back but you can also choose to ignore and not import conflicting rows or to replace the existing row in the table. + 主キーã€ä¸€æ„性制約ã€ä¸€æ„ãªã‚¤ãƒ³ãƒ‡ãƒƒã‚¯ã‚¹ãŒã‚る既存ã®ãƒ†ãƒ¼ãƒ–ルã«ã‚¤ãƒ³ãƒãƒ¼ãƒˆã™ã‚‹ã¨ã€ç«¶åˆãŒç™ºç”Ÿã™ã‚‹å¯èƒ½æ€§ãŒã‚りã¾ã™ã€‚ã“ã®ã‚ªãƒ—ションã§ã€ç«¶åˆã®è§£æ±ºæ–¹æ³•ã‚’é¸æŠžã§ãã¾ã™ã€‚デフォルトã§ã¯ã‚¤ãƒ³ãƒãƒ¼ãƒˆã‚’中止ã—ロールãƒãƒƒã‚¯ã—ã¾ã™ãŒã€ç„¡è¦–ã‚’é¸æŠžã—ã¦ç«¶åˆã—ãŸè¡Œã‚’インãƒãƒ¼ãƒˆã—ãªã„ã€ã‚‚ã—ãã¯ã€ãƒ†ãƒ¼ãƒ–ãƒ«å†…ã®æ—¢å­˜ã®è¡Œã‚’ç½®ãæ›ãˆã‚‹ã“ã¨ã‚‚ã§ãã¾ã™ã€‚ + + + + Abort import + インãƒãƒ¼ãƒˆã‚’中止 + + + + Ignore row + 行を無視 + + + + Replace existing row + 既存ã®è¡Œã‚’ç½®ãæ›ãˆ + + + + Conflict strategy + ç«¶åˆã®è§£æ±ºæ–¹æ³• + + + + + Deselect All + ã™ã¹ã¦éžé¸æŠž + + + + Match Similar + 類似ã«ä¸€è‡´ + + + + Select All + ã™ã¹ã¦é¸æŠž + + + + There is already a table named '%1' and an import into an existing table is only possible if the number of columns match. + åå‰ãŒ '%1' ã®ãƒ†ãƒ¼ãƒ–ãƒ«ã¯æ—¢ã«å­˜åœ¨ã—ã¦ã„ã¾ã™ã€‚既存ã®ãƒ†ãƒ¼ãƒ–ルã¸ã®ã‚¤ãƒ³ãƒãƒ¼ãƒˆã¯ã‚«ãƒ©ãƒ ã®æ•°ãŒä¸€è‡´ã™ã‚‹å ´åˆã®ã¿å¯èƒ½ã§ã™ã€‚ + + + + There is already a table named '%1'. Do you want to import the data into it? + åå‰ãŒ '%1' ã®ãƒ†ãƒ¼ãƒ–ãƒ«ã¯æ—¢ã«å­˜åœ¨ã—ã¦ã„ã¾ã™ã€‚データをã“れã«ã‚¤ãƒ³ãƒãƒ¼ãƒˆã—ã¾ã™ã‹? + + + + Creating restore point failed: %1 + 復元ãƒã‚¤ãƒ³ãƒˆã®ä½œæˆã«å¤±æ•—: %1 + + + + Creating the table failed: %1 + テーブルã®ä½œæˆã«å¤±æ•—: %1 + + + + importing CSV + CSVã®ã‚¤ãƒ³ãƒãƒ¼ãƒˆ + + + + Inserting row failed: %1 + è¡Œã®æŒ¿å…¥ã«å¤±æ•—: %1 + + + + Importing the file '%1' took %2ms. Of this %3ms were spent in the row function. + ファイル '%1' ã®ã‚¤ãƒ³ãƒãƒ¼ãƒˆã« %2msã‹ã‹ã‚Šã¾ã—ãŸã€‚内 %3ms ã¯è¡Œé–¢æ•°ã«è²»ã‚„ã•れã¾ã—ãŸã€‚ + + + + MainWindow + + + DB Browser for SQLite + DB Browser for SQLite + + + + + Database Structure + This has to be equal to the tab title in all the main tabs + データベース構造 + + + + This is the structure of the opened database. +You can drag SQL statements from an object row and drop them into other applications or into another instance of 'DB Browser for SQLite'. + + ã“れã¯é–‹ã„ã¦ã„ã‚‹ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã®æ§‹é€ ã§ã™ã€‚ +SQL文をオブジェクト行ã‹ã‚‰ãƒ‰ãƒ©ãƒƒã‚°ã—ã»ã‹ã®ã‚¢ãƒ—リケーションや'DB Browser for SQLite'ã®ä»–ã®ã‚¤ãƒ³ã‚¹ã‚¿ãƒ³ã‚¹ã«ãƒ‰ãƒ­ãƒƒãƒ—ã§ãã¾ã™ã€‚ + + + + + + Browse Data + This has to be equal to the tab title in all the main tabs + データ閲覧 + + + + + Edit Pragmas + This has to be equal to the tab title in all the main tabs + プラグマ編集 + + + + Warning: this pragma is not readable and this value has been inferred. Writing the pragma might overwrite a redefined LIKE provided by an SQLite extension. + 警告: ã“ã®ãƒ—ラグマã¯èª­ã¿å–りå¯èƒ½ã§ãªãã€ã“ã®å€¤ã¯æŽ¨å®šã§ã™ã€‚プラグマを書ã込んã§ã‚‚ã€SQLite æ‹¡å¼µãªã©ã§ä¸Šæ›¸ãã•れるã‹ã‚‚ã—れã¾ã›ã‚“。 + + + + + Execute SQL + This has to be equal to the tab title in all the main tabs + SQL実行 + + + + toolBar1 + ツールãƒãƒ¼1 + + + + &File + ファイル(&F) + + + + &Import + インãƒãƒ¼ãƒˆ(&I) + + + + &Export + エクスãƒãƒ¼ãƒˆ(&E) + + + + &Edit + 編集(&E) + + + + &View + ビュー(&V) + + + + &Help + ヘルプ(&H) + + + + &Tools + ツール(&T) + + + + DB Toolbar + DBツールãƒãƒ¼ + + + + Edit Database &Cell + データベースã®ã‚»ãƒ«ã‚’編集(&C) + + + + SQL &Log + SQLログ(&L) + + + + Show S&QL submitted by + 表示ã™ã‚‹SQLã®é€ä¿¡å…ƒã¯(&Q) + + + + User + ユーザー + + + + Application + アプリケーション + + + + Error Log + エラーログ + + + + This button clears the contents of the SQL logs + ã“ã®ãƒœã‚¿ãƒ³ã§SQLログã®å†…容を消去ã—ã¾ã™ + + + + &Clear + 消去(&C) + + + + This panel lets you examine a log of all SQL commands issued by the application or by yourself + ã“ã®ãƒ‘ãƒãƒ«ã§ã‚¢ãƒ—リケーションやã‚ãªãŸãŒç™ºè¡Œã—ãŸå…¨ã¦ã®SQLコマンドã®ãƒ­ã‚°ã‚’調査ã§ãã¾ã™ + + + + &Plot + プロット(&P) + + + + DB Sche&ma + DBスキーマ(&M) + + + + This is the structure of the opened database. +You can drag multiple object names from the Name column and drop them into the SQL editor and you can adjust the properties of the dropped names using the context menu. This would help you in composing SQL statements. +You can drag SQL statements from the Schema column and drop them into the SQL editor or into other applications. + + ã“れã¯é–‹ã„ã¦ã„ã‚‹ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã®æ§‹é€ ã§ã™ã€‚ +複数ã®ã‚ªãƒ–ジェクトåã‚’åå‰ã‚«ãƒ©ãƒ ã‹ã‚‰ãƒ‰ãƒ©ãƒƒã‚°ã—SQLエディターã«ãƒ‰ãƒ­ãƒƒãƒ—ã§ãã¾ã™ã€‚ドロップã—ãŸåå‰ã®ãƒ—ロパティã¯ã‚³ãƒ³ãƒ†ã‚­ã‚¹ãƒˆãƒ¡ãƒ‹ãƒ¥ãƒ¼ã§èª¿ç¯€ã§ãã¾ã™ã€‚ã“れã¯SQLæ–‡ã®ä½œæˆã«å½¹ç«‹ã¡ã¾ã™ã€‚ +SQL文をスキーマカラムã‹ã‚‰SQLエディターや他ã®ã‚¢ãƒ—リケーションã«ãƒ‰ãƒ­ãƒƒãƒ—ã§ãã¾ã™ã€‚ + + + + + &Remote + リモート(&R) + + + + + Project Toolbar + プロジェクトツールãƒãƒ¼ + + + + Extra DB toolbar + 追加DBツールãƒãƒ¼ + + + + + + Close the current database file + ç¾åœ¨ã®ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ãƒ•ァイルを閉ã˜ã¾ã™ + + + + &New Database... + æ–°ã—ã„データベース(&N)... + + + + + Create a new database file + æ–°ã—ã„データベースファイルを作æˆã—ã¾ã™ + + + + This option is used to create a new database file. + ã“ã®ã‚ªãƒ—ã‚·ãƒ§ãƒ³ã¯æ–°ã—ã„データベースファイルを作æˆã™ã‚‹ãŸã‚ã«ä½¿ã„ã¾ã™ã€‚ + + + + Ctrl+N + + + + + + &Open Database... + データベースを開ã(&O)... + + + + + + + + Open an existing database file + 既存ã®ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ãƒ•ァイルを開ãã¾ã™ + + + + + + This option is used to open an existing database file. + ã“ã®ã‚ªãƒ—ã‚·ãƒ§ãƒ³ã¯æ—¢å­˜ã®ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ãƒ•ァイルを開ããŸã‚ã«ä½¿ã„ã¾ã™ã€‚ + + + + Ctrl+O + + + + + &Close Database + データベースを閉ã˜ã‚‹(&C) + + + + This button closes the connection to the currently open database file + ã“ã®ãƒœã‚¿ãƒ³ã§ç¾åœ¨é–‹ã„ã¦ã„るデータベースファイルã¨ã®æŽ¥ç¶šã‚’é–‰ã˜ã¾ã™ + + + + Open SQL file(s) + SQLファイルを開ã + + + + This button opens files containing SQL statements and loads them in new editor tabs + ã“ã®ãƒœã‚¿ãƒ³ã§SQL文をå«ã‚€ãƒ•ァイルを新ã—ã„エディタータブã«é–‹ãã¾ã™ + + + + Execute line + 行を実行 + + + + Sa&ve Project + プロジェクトをä¿å­˜(&V) + + + + This button lets you save all the settings associated to the open DB to a DB Browser for SQLite project file + ã“ã®ãƒœã‚¿ãƒ³ã§é–‹ã„ã¦ã„ã‚‹DBã«é–¢é€£ä»˜ã‘られる全ã¦ã®è¨­å®šã‚’SQLiteプロジェクトファイルã«ä¿å­˜ã—ã¾ã™ + + + + This button lets you open a DB Browser for SQLite project file + ã“ã®ãƒœã‚¿ãƒ³ã§SQLiteプロジェクトファイルを開ãã¾ã™ + + + + Ctrl+Shift+O + + + + + Find + 検索 + + + + Find or replace + 検索ã¨ç½®æ› + + + + Print text from current SQL editor tab + ç¾åœ¨ã®SQLエディタータブã®ãƒ†ã‚­ã‚¹ãƒˆã‚’å°åˆ·ã—ã¾ã™ + + + + Print the structure of the opened database + é–‹ã„ã¦ã„ã‚‹ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã®æ§‹é€ ã‚’å°åˆ·ã—ã¾ã™ + + + + Un/comment block of SQL code + SQLコードã®ãƒ–ロックをコメント/éžã‚³ãƒ¡ãƒ³ãƒˆã« + + + + Un/comment block + ブロックをコメント/éžã‚³ãƒ¡ãƒ³ãƒˆ + + + + Comment or uncomment current line or selected block of code + ç¾åœ¨è¡Œã‹ã‚³ãƒ¼ãƒ‰ã®é¸æŠžã•れãŸãƒ–ロックをコメント/éžã‚³ãƒ¡ãƒ³ãƒˆã«ã—ã¾ã™ + + + + Comment or uncomment the selected lines or the current line, when there is no selection. All the block is toggled according to the first line. + é¸æŠžã•れãŸè¡Œã‹ã€é¸æŠžãŒãªã„ãªã‚‰ã°ç¾åœ¨è¡Œã‚’コメント/éžã‚³ãƒ¡ãƒ³ãƒˆã«ã—ã¾ã™ã€‚ブロック全体ã¯ãã®å…ˆé ­è¡Œã«å¾“ã„コメント/éžã‚³ãƒ¡ãƒ³ãƒˆã•れã¾ã™ã€‚ + + + + Ctrl+/ + + + + + Stop SQL execution + SQLã®å®Ÿè¡Œã‚’中止 + + + + Stop execution + 実行を中止 + + + + Stop the currently running SQL script + ç¾åœ¨å®Ÿè¡Œä¸­ã® SQL スクリプトを中止ã—ã¾ã™ + + + + &Save Project As... + プロジェクトã«åå‰ã‚’付ã‘ã¦ä¿å­˜(&S)... + + + + + + Save the project in a file selected in a dialog + ダイアログã§é¸æŠžã—ãŸãƒ•ァイルã«ãƒ—ロジェクトをä¿å­˜ã—ã¾ã™ + + + + Save A&ll + ã™ã¹ã¦ä¿å­˜(&L) + + + + + + Save DB file, project file and opened SQL files + DBファイルã€ãƒ—ロジェクトファイルã€é–‹ã„ã¦ã„ã‚‹SQLファイルをä¿å­˜ã—ã¾ã™ + + + + Ctrl+Shift+S + + + + + Browse Table + テーブルを閲覧 + + + + + Ctrl+W + + + + + &Revert Changes + 変更をå–り消ã—(&R) + + + + + Revert database to last saved state + 最後ã«ä¿å­˜ã—ãŸçŠ¶æ…‹ã¸ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã‚’戻ã—ã¾ã™ + + + + This option is used to revert the current database file to its last saved state. All changes made since the last save operation are lost. + ã“ã®ã‚ªãƒ—ションã¯ç¾åœ¨ã®ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ãƒ•ァイルを最後ã«ä¿å­˜ã—ãŸçŠ¶æ…‹ã«æˆ»ã™ãŸã‚ã«ä½¿ã„ã¾ã™ã€‚最後ã®ä¿å­˜ã®å¾Œã«è¡Œã‚れãŸã™ã¹ã¦ã®å¤‰æ›´ã¯å¤±ã‚れã¾ã™ã€‚ + + + + &Write Changes + 変更を書ãè¾¼ã¿(&W) + + + + + Write changes to the database file + データベースファイルã«å¤‰æ›´ã‚’書ãè¾¼ã¿ã¾ã™ + + + + This option is used to save changes to the database file. + ã“ã®ã‚ªãƒ—ションã¯ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ãƒ•ァイルã«å¤‰æ›´ã‚’ä¿å­˜ã™ã‚‹ãŸã‚ã«ä½¿ã„ã¾ã™ã€‚ + + + + Ctrl+S + + + + + Compact &Database... + データベースを圧縮(&D)... + + + + Compact the database file, removing space wasted by deleted records + 削除ã•れãŸãƒ¬ã‚³ãƒ¼ãƒ‰ãŒæ®‹ã£ã¦ã„るスペースをå–り除ãã€ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ãƒ•ァイルを圧縮ã—ã¾ã™ + + + + + Compact the database file, removing space wasted by deleted records. + 削除ã•れãŸãƒ¬ã‚³ãƒ¼ãƒ‰ãŒæ®‹ã£ã¦ã„るスペースをå–り除ãã€ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ãƒ•ァイルを圧縮ã—ã¾ã™ã€‚ + + + + E&xit + 終了(&X) + + + + Ctrl+Q + + + + + &Database from SQL file... + SQLファイルã‹ã‚‰ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã¸(&D)... + + + + Import data from an .sql dump text file into a new or existing database. + SQLダンプテキストファイルã‹ã‚‰ãƒ‡ãƒ¼ã‚¿ã‚’ã€æ–°ã—ã„ã‚‚ã—ãã¯æ—¢å­˜ã®ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã«ã‚¤ãƒ³ãƒãƒ¼ãƒˆã—ã¾ã™ã€‚ + + + + This option lets you import data from an .sql dump text file into a new or existing database. SQL dump files can be created on most database engines, including MySQL and PostgreSQL. + ã“ã®ã‚ªãƒ—ションã§SQLダンプテキストファイルã‹ã‚‰ãƒ‡ãƒ¼ã‚¿ã‚’ã€æ–°ã—ã„ã‚‚ã—ãã¯æ—¢å­˜ã®ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã«ã‚¤ãƒ³ãƒãƒ¼ãƒˆã§ãã¾ã™ã€‚SQLダンプファイルã¯ã€MySQLã‚„PostgreSQLãªã©ã€ã»ã¨ã‚“ã©ã®ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã‚¨ãƒ³ã‚¸ãƒ³ã§ä½œæˆã§ãã¾ã™ã€‚ + + + + &Table from CSV file... + CSVファイルã‹ã‚‰ãƒ†ãƒ¼ãƒ–ルã¸(&T)... + + + + Open a wizard that lets you import data from a comma separated text file into a database table. + カンマ区切りã®ãƒ†ã‚­ã‚¹ãƒˆãƒ•ァイルã®ãƒ‡ãƒ¼ã‚¿ã‚’データベースã®ãƒ†ãƒ¼ãƒ–ルã«ã‚¤ãƒ³ãƒãƒ¼ãƒˆã™ã‚‹ã‚¦ã‚£ã‚¶ãƒ¼ãƒ‰ã‚’é–‹ãã¾ã™ã€‚ + + + + Open a wizard that lets you import data from a comma separated text file into a database table. CSV files can be created on most database and spreadsheet applications. + カンマ区切りã®ãƒ†ã‚­ã‚¹ãƒˆãƒ•ァイルã®ãƒ‡ãƒ¼ã‚¿ã‚’データベースã®ãƒ†ãƒ¼ãƒ–ルã«ã‚¤ãƒ³ãƒãƒ¼ãƒˆã™ã‚‹ã‚¦ã‚£ã‚¶ãƒ¼ãƒ‰ã‚’é–‹ãã¾ã™ã€‚CSVファイルã¯ã»ã¨ã‚“ã©ã®ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã‚„表計算アプリケーションã§ä½œæˆã§ãã¾ã™ã€‚ + + + + &Database to SQL file... + データベースをSQLファイルã¸(&D)... + + + + Export a database to a .sql dump text file. + データベースを .sql ダンプテキストファイルã«ã‚¨ã‚¯ã‚¹ãƒãƒ¼ãƒˆã—ã¾ã™ã€‚ + + + + This option lets you export a database to a .sql dump text file. SQL dump files contain all data necessary to recreate the database on most database engines, including MySQL and PostgreSQL. + ã“ã®ã‚ªãƒ—ションã§ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã‚’ .sql ダンプテキストファイルã«ã‚¨ã‚¯ã‚¹ãƒãƒ¼ãƒˆã§ãã¾ã™ã€‚SQLダンプファイルã¯ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã®å†ä½œæˆã«å¿…è¦ãªã™ã¹ã¦ã®ãƒ‡ãƒ¼ã‚¿ã‚’å«ã¿ã€MySQLã‚„PostgreSQLãªã©ã€ã»ã¨ã‚“ã©ã®ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã‚¨ãƒ³ã‚¸ãƒ³ã§åˆ©ç”¨ã§ãã¾ã™ã€‚ + + + + &Table(s) as CSV file... + テーブルをCSVファイルã¸(&T)... + + + + Export a database table as a comma separated text file. + データベースã®ãƒ†ãƒ¼ãƒ–ルをカンマ区切りã®ãƒ†ã‚­ã‚¹ãƒˆãƒ•ァイルã«ã‚¨ã‚¯ã‚¹ãƒãƒ¼ãƒˆã—ã¾ã™ã€‚ + + + + Export a database table as a comma separated text file, ready to be imported into other database or spreadsheet applications. + データベースã®ãƒ†ãƒ¼ãƒ–ルをカンマ区切りã®ãƒ†ã‚­ã‚¹ãƒˆãƒ•ァイルã«ã‚¨ã‚¯ã‚¹ãƒãƒ¼ãƒˆã—ã¾ã™ã€‚ä»–ã®ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã‚„表計算アプリケーションã§ã‚¤ãƒ³ãƒãƒ¼ãƒˆã§ãã¾ã™ã€‚ + + + + &Create Table... + テーブルを作æˆ(&C)... + + + + Open the Create Table wizard, where it is possible to define the name and fields for a new table in the database + ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã«æ–°ã—ã„テーブルã®åå‰ã¨ãƒ•ィールドを定義ã§ãã‚‹ã€ãƒ†ãƒ¼ãƒ–ル作æˆã‚¦ã‚¤ã‚¶ãƒ¼ãƒ‰ã‚’é–‹ãã¾ã™ + + + + &Delete Table... + テーブルを削除(&D)... + + + + + Delete Table + テーブルを削除 + + + + Open the Delete Table wizard, where you can select a database table to be dropped. + 削除ã™ã‚‹ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ãƒ†ãƒ¼ãƒ–ãƒ«ã‚’é¸æŠžã§ãã‚‹ã€ãƒ†ãƒ¼ãƒ–ル削除ウィザードをã²ã‚‰ãã¾ã™ã€‚ + + + + &Modify Table... + テーブルを変更(&M)... + + + + Open the Modify Table wizard, where it is possible to rename an existing table. It is also possible to add or delete fields form a table, as well as modify field names and types. + 既存ã®ãƒ†ãƒ¼ãƒ–ルåを変更ã§ãã‚‹ã€ãƒ†ãƒ¼ãƒ–ル変更ウィザードを開ãã¾ã™ã€‚テーブルã®ãƒ•ィールドを追加削除ã—ãŸã‚Šã€ãƒ•ィールドåやデータ型ã®å¤‰æ›´ã‚‚ã§ãã¾ã™ã€‚ + + + + Create &Index... + インデックスã®ä½œæˆ(&I)... + + + + Open the Create Index wizard, where it is possible to define a new index on an existing database table. + 既存ã®ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ãƒ†ãƒ¼ãƒ–ãƒ«ã«æ–°ã—ã„インデックスを定義ã§ãã‚‹ã€ã‚¤ãƒ³ãƒ‡ãƒƒã‚¯ã‚¹ã‚¦ã‚£ã‚¶ãƒ¼ãƒ‰ã‚’é–‹ãã¾ã™ã€‚ + + + + &Preferences... + 設定(&P)... + + + + + Open the preferences window. + 設定ウィンドウを開ãã¾ã™ã€‚ + + + + &DB Toolbar + DBツールãƒãƒ¼(&D) + + + + Shows or hides the Database toolbar. + データベースツールãƒãƒ¼ã‚’表示/éžè¡¨ç¤ºã—ã¾ã™ã€‚ + + + + Ctrl+T + + + + + W&hat's This? + ã“れã¯ä½•(&H)? + + + + Ctrl+F4 + + + + + Shift+F1 + + + + + &About + DB Browser for SQLite ã«ã¤ã„ã¦(&A) + + + + &Recently opened + 最近開ã„ãŸãƒ•ァイル(&R) + + + + Open &tab + タブを開ã(&T) + + + + This button opens a new tab for the SQL editor + ã“ã®ãƒœã‚¿ãƒ³ã§SQLã‚¨ãƒ‡ã‚£ã‚¿ãƒ¼ã®æ–°ã—ã„タブを開ãã¾ã™ + + + + &Execute SQL + SQLを実行(&E) + + + + This button executes the currently selected SQL statements. If no text is selected, all SQL statements are executed. + ã“ã®ãƒœã‚¿ãƒ³ã§ç¾åœ¨é¸æŠžã—ã¦ã„ã‚‹SQL文を実行ã—ã¾ã™ã€‚テキストãŒé¸æŠžã•れã¦ã„ãªã„å ´åˆã€ã™ã¹ã¦ã®SQLæ–‡ãŒå®Ÿè¡Œã•れã¾ã™ã€‚ + + + + + + Save SQL file + SQLファイルをä¿å­˜ + + + + &Load Extension... + 拡張を読ã¿è¾¼ã¿(&L)... + + + + + Execute current line + ç¾åœ¨è¡Œã‚’実行 + + + + This button executes the SQL statement present in the current editor line + ã“ã®ãƒœã‚¿ãƒ³ã¯ç¾åœ¨ã‚¨ãƒ‡ã‚£ã‚¿ãƒ¼ã®è¡Œã«ã‚ã‚‹SQL文を実行ã—ã¾ã™ + + + + Shift+F5 + + + + + Export as CSV file + CSVファイルã«ã‚¨ã‚¯ã‚¹ãƒãƒ¼ãƒˆ + + + + Export table as comma separated values file + テーブルをカンマ区切りã®ãƒ•ァイルã«ã‚¨ã‚¯ã‚¹ãƒãƒ¼ãƒˆã—ã¾ã™ + + + + &Wiki + ウィキ(&W) + + + + F1 + + + + + Bug &Report... + ãƒã‚°ãƒ¬ãƒãƒ¼ãƒˆ(&R)... + + + + Feature Re&quest... + æ©Ÿèƒ½ã‚’è¦æ±‚(&Q)... + + + + Web&site + ウェブサイト(&S) + + + + &Donate on Patreon... + Patreonã§å¯„付(&D)... + + + + + Save the current session to a file + ç¾åœ¨ã®ã‚»ãƒƒã‚·ãƒ§ãƒ³ã‚’ファイルã«ä¿å­˜ã—ã¾ã™ + + + + Open &Project... + プロジェクトを開ã(&P)... + + + + + Load a working session from a file + 作業中ã®ã‚»ãƒƒã‚·ãƒ§ãƒ³ã‚’ファイルã‹ã‚‰èª­ã¿è¾¼ã¿ã¾ã™ + + + + &Attach Database... + ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã«æŽ¥ç¶š(&A)... + + + + + Add another database file to the current database connection + ä»–ã®ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ãƒ•ァイルをç¾åœ¨ã®ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹æŽ¥ç¶šã«åŠ ãˆã¾ã™ + + + + This button lets you add another database file to the current database connection + ã“ã®ãƒœã‚¿ãƒ³ã§ä»–ã®ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ãƒ•ァイルをç¾åœ¨ã®ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹æŽ¥ç¶šã«åŠ ãˆã¾ã™ + + + + &Set Encryption... + æš—å·åŒ–を設定(&S)... + + + + + Save SQL file as + åå‰ã‚’付ã‘ã¦SQLファイルをä¿å­˜ + + + + This button saves the content of the current SQL editor tab to a file + ã“ã®ãƒœã‚¿ãƒ³ã¯ç¾åœ¨ã®SQLエディタータブã®å†…容をファイルã«ä¿å­˜ã—ã¾ã™ + + + + &Browse Table + テーブルを閲覧(&B) + + + + Copy Create statement + CREATE文をコピー + + + + Copy the CREATE statement of the item to the clipboard + ã“ã®ã‚¢ã‚¤ãƒ†ãƒ ã®CREATE文をクリップボードã«ã‚³ãƒ”ーã—ã¾ã™ + + + + SQLCipher &FAQ + SQLCipher FAQ(&F) + + + + Opens the SQLCipher FAQ in a browser window + SQLCipher ã® FAQ をブラウザã§é–‹ãã¾ã™ + + + + Table(&s) to JSON... + テーブルをJSONã¸(&S)... + + + + Export one or more table(s) to a JSON file + 1ã¤ä»¥ä¸Šã®ãƒ†ãƒ¼ãƒ–ルをJSONファイルã«ã‚¨ã‚¯ã‚¹ãƒãƒ¼ãƒˆã—ã¾ã™ + + + + Open Data&base Read Only... + データベースを読ã¿å–り専用ã§é–‹ã(&B)... + + + + Open an existing database file in read only mode + 既存ã®ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ãƒ•ァイルを読ã¿å–り専用モードã§é–‹ãã¾ã™ + + + + Save results + çµæžœã‚’ä¿å­˜ + + + + Save the results view + çµæžœã®ãƒ“ューをä¿å­˜ + + + + This button lets you save the results of the last executed query + ã“ã®ãƒœã‚¿ãƒ³ã§æœ€å¾Œã«å®Ÿè¡Œã—ãŸã‚¯ã‚¨ãƒªãƒ¼ã®çµæžœã‚’ä¿å­˜ã—ã¾ã™ + + + + + Find text in SQL editor + SQLã‚¨ãƒ‡ã‚£ã‚¿ãƒ¼ã®æ–‡å­—列を検索 + + + + This button opens the search bar of the editor + ã“ã®ãƒœã‚¿ãƒ³ã¯ã‚¨ãƒ‡ã‚£ã‚¿ãƒ¼ã®æ¤œç´¢ãƒãƒ¼ã‚’é–‹ãã¾ã™ + + + + Ctrl+F + + + + + + Find or replace text in SQL editor + SQLã‚¨ãƒ‡ã‚£ã‚¿ãƒ¼ã®æ–‡å­—列を検索/ç½®æ›ã—ã¾ã™ + + + + This button opens the find/replace dialog for the current editor tab + ã“ã®ãƒœã‚¿ãƒ³ã¯ç¾åœ¨ã®ã‚¨ãƒ‡ã‚£ã‚¿ãƒ¼ã‚¿ãƒ–ã®æ¤œç´¢/ç½®æ›ãƒ€ã‚¤ã‚¢ãƒ­ã‚°ã‚’é–‹ãã¾ã™ + + + + Ctrl+H + + + + + Export to &CSV + CSVã«ã‚¨ã‚¯ã‚¹ãƒãƒ¼ãƒˆ(&C) + + + + Save as &view + ビューã¨ã—ã¦ä¿å­˜(&V) + + + + Save as view + ビューã¨ã—ã¦ä¿å­˜ + + + + Shows or hides the Project toolbar. + プロジェクトツールãƒãƒ¼ã‚’表示/éžè¡¨ç¤ºã—ã¾ã™ã€‚ + + + + Extra DB Toolbar + 追加DBツールãƒãƒ¼ + + + + New In-&Memory Database + æ–°ã—ã„インメモリーデータベース(&M) + + + + Drag && Drop Qualified Names + æ­£è¦åŒ–åå‰ã‚’ドラッグ&&ドロップ + + + + + Use qualified names (e.g. "Table"."Field") when dragging the objects and dropping them into the editor + オブジェクトをドラッグã—エディターã«ãƒ‰ãƒ­ãƒƒãƒ—ã—ãŸã¨ãã«ã€æ­£è¦åŒ–åç§°(例 "Table"."Field")を使ã„ã¾ã™ + + + + Drag && Drop Enquoted Names + クォートã•れãŸåå‰ã‚’ドラッグ&&ドロップ + + + + + Use escaped identifiers (e.g. "Table1") when dragging the objects and dropping them into the editor + オブジェクトをドラッグã—エディターã«ãƒ‰ãƒ­ãƒƒãƒ—ã—ãŸã¨ãã«ã€ã‚¨ã‚¹ã‚±ãƒ¼ãƒ—ã•れãŸåå‰(例 "Table1")を使ã„ã¾ã™ + + + + &Integrity Check + æ•´åˆæ€§æ¤œæŸ»(&I) + + + + Runs the integrity_check pragma over the opened database and returns the results in the Execute SQL tab. This pragma does an integrity check of the entire database. + é–‹ã„ã¦ã„ã‚‹ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã®æ•´åˆæ€§æ¤œæŸ»ãƒ—ラグマを実行ã—ã€çµæžœã‚’SQL実行タブã«å‡ºåŠ›ã—ã¾ã™ã€‚ã“ã®ãƒ—ラグマã¯ã™ã¹ã¦ã®ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã®æ•´åˆæ€§æ¤œæŸ»ã‚’行ã„ã¾ã™ã€‚ + + + + &Foreign-Key Check + 外部キー検査(&F) + + + + Runs the foreign_key_check pragma over the opened database and returns the results in the Execute SQL tab + é–‹ã„ã¦ã„るデータベースã®å¤–部キー検査プラグマを実行ã—ã€çµæžœã‚’SQL実行タブã«å‡ºåŠ›ã—ã¾ã™ + + + + &Quick Integrity Check + 峿™‚æ•´åˆæ€§æ¤œæŸ»(&Q) + + + + Run a quick integrity check over the open DB + é–‹ã„ã¦ã„ã‚‹DBã®é«˜é€Ÿæ•´åˆæ€§æ¤œæŸ»ã‚’実行ã—ã¾ã™ + + + + Runs the quick_check pragma over the opened database and returns the results in the Execute SQL tab. This command does most of the checking of PRAGMA integrity_check but runs much faster. + é–‹ã„ã¦ã„るデータベースã®é«˜é€Ÿæ•´åˆæ€§æ¤œæŸ»ãƒ—ラグマを実行ã—ã€çµæžœã‚’SQL実行タブã«å‡ºåŠ›ã—ã¾ã™ã€‚ã“ã®ã‚³ãƒžãƒ³ãƒ‰ã¯(通常ã®)æ•´åˆæ€§æ¤œæŸ»PRAGMAã®å¤§éƒ¨åˆ†ã‚’行ã„ã¾ã™ãŒã€ã‚ˆã‚Šé«˜é€Ÿã«å‹•作ã—ã¾ã™ã€‚ + + + + &Optimize + 最é©åŒ–(&O) + + + + Attempt to optimize the database + ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã®æœ€é©åŒ–を試ã¿ã¾ã™ + + + + Runs the optimize pragma over the opened database. This pragma might perform optimizations that will improve the performance of future queries. + é–‹ã„ã¦ã„ã‚‹ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã®æœ€é©åŒ–プラグマを実行ã—ã¾ã™ã€‚ã“ã®ãƒ—ラグマã¯å°†æ¥ã®ã‚¯ã‚¨ãƒªãƒ¼ã®æ€§èƒ½ã‚’改善ã•ã›ã¾ã™ã€‚ + + + + + Print + å°åˆ· + + + + Open a dialog for printing the text in the current SQL editor tab + ç¾åœ¨ã®SQLã‚¨ãƒ‡ã‚£ã‚¿ãƒ¼ã‚¿ãƒ–ã®æ–‡å­—列をå°åˆ·ã™ã‚‹ãƒ€ã‚¤ã‚¢ãƒ­ã‚°ã‚’é–‹ãã¾ã™ + + + + Open a dialog for printing the structure of the opened database + é–‹ã„ã¦ã„ã‚‹ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã®æ§‹é€ ã‚’å°åˆ·ã™ã‚‹ãƒ€ã‚¤ã‚¢ãƒ­ã‚°ã‚’é–‹ãã¾ã™ + + + + + Ctrl+P + + + + + Execute all/selected SQL + ã™ã¹ã¦/é¸æŠžã—ãŸSQLを実行 + + + + Ctrl+Return + Ctrl+Return + + + + Ctrl+L + + + + + Ctrl+D + + + + + Ctrl+I + + + + + Ctrl+E + + + + + Window Layout + ウィンドウレイアウト + + + + Reset Window Layout + ウィンドウレイアウトをリセット + + + + Alt+0 + + + + + Simplify Window Layout + ウィンドウレイアウトをシンプル㫠+ + + + Shift+Alt+0 + + + + + Dock Windows at Bottom + ウィンドウを下ã«ãƒ‰ãƒƒã‚­ãƒ³ã‚° + + + + Dock Windows at Left Side + ウィンドウを左ã«ãƒ‰ãƒƒã‚­ãƒ³ã‚° + + + + Dock Windows at Top + ウィンドウを上ã«ãƒ‰ãƒƒã‚­ãƒ³ã‚° + + + + The database is currenctly busy. + データベースã¯ç¾åœ¨ãƒ“ジー状態ã§ã™ã€‚ + + + + Click here to interrupt the currently running query. + ã“ã“をクリックã—ã¦ã€ç¾åœ¨å®Ÿè¡Œä¸­ã®ã‚¯ã‚¨ãƒªãƒ¼ã‚’中断ã—ã¾ã™ã€‚ + + + + Encrypted + æš—å·åŒ– + + + + Database is encrypted using SQLCipher + データベースã¯SQLCipherã§æš—å·åŒ–ã•れã¦ã„ã¾ã™ + + + + Read only + 読ã¿å–り専用 + + + + Database file is read only. Editing the database is disabled. + データベースã¯èª­ã¿å–り専用ã§ã™ã€‚データベースã®ç·¨é›†ã¯ã§ãã¾ã›ã‚“。 + + + + Database encoding + データベースã®ã‚¨ãƒ³ã‚³ãƒ¼ãƒ‰ + + + + + Choose a database file + ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ãƒ•ã‚¡ã‚¤ãƒ«ã‚’é¸æŠž + + + + Could not open database file. +Reason: %1 + データベースファイルを開ã‘ã¾ã›ã‚“。 +ç†ç”±: %1 + + + + + + Choose a filename to save under + セーブã™ã‚‹ãƒ•ァイルåを下ã‹ã‚‰é¸æŠž + + + + In-Memory database + インメモリーデータベース + + + + You are still executing SQL statements. Closing the database now will stop their execution, possibly leaving the database in an inconsistent state. Are you sure you want to close the database? + ã¾ã SQL文を実行中ã§ã™ã€‚今ã€ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã‚’é–‰ã˜ã‚‹ã¨ã€å®Ÿè¡ŒãŒä¸­æ­¢ã•れã€ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã«ä¸€è²«æ€§ãŒãªã„状態を残ã™ã‹ã‚‚ã—れã¾ã›ã‚“。本当ã«ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã‚’é–‰ã˜ã¾ã™ã‹? + + + + Edit View %1 + ビュー %1 を編集 + + + + Edit Trigger %1 + トリガー %1 を編集 + + + + Opened '%1' in read-only mode from recent file list + 最近使ã£ãŸãƒ•ァイルリストã‹ã‚‰èª­ã¿å–り専用モード㧠'%1' ã‚’é–‹ãã¾ã—㟠+ + + + Opened '%1' from recent file list + 最近使ã£ãŸãƒ•ァイルリストã‹ã‚‰ '%1' ã‚’é–‹ãã¾ã—㟠+ + + + Could not find resource file: %1 + リソースファイルãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“: %1 + + + + Could not open project file for writing. +Reason: %1 + 書ã込むプロジェクトファイルを開ãã“ã¨ãŒã§ãã¾ã›ã‚“。 +ç†ç”±: %1 + + + + Project saved to file '%1' + プロジェクトをファイル '%1' ã«ä¿å­˜ã—ã¾ã—㟠+ + + + This action will open a new SQL tab with the following statements for you to edit and run: + ã“ã®æ“作ã¯ã“ã®æ–‡ã®ç·¨é›†ã¨å®Ÿè¡ŒãŒã§ãã‚‹æ–°ã—ã„SQLタブを開ãã¾ã™: + + + + Busy (%1) + ビジー (%1) + + + + Rename Tab + タブåを変更 + + + + Duplicate Tab + タブを複製 + + + + Close Tab + タブを閉ã˜ã‚‹ + + + + Opening '%1'... + '%1' ã‚’é–‹ã„ã¦ã„ã¾ã™... + + + + There was an error opening '%1'... + '%1' ã‚’é–‹ãã¨ãã«ã‚¨ãƒ©ãƒ¼ãŒã‚りã¾ã—ãŸ... + + + + Value is not a valid URL or filename: %1 + å€¤ã¯æ­£è¦ã®URLã‚‚ã—ãã¯ãƒ•ァイルåã§ã‚りã¾ã›ã‚“: %1 + + + + Are you sure you want to delete the table '%1'? +All data associated with the table will be lost. + 本当ã«ãƒ†ãƒ¼ãƒ–ル '%1' を削除ã—ã¾ã™ã‹? +テーブルã«é–¢é€£ã™ã‚‹ã™ã¹ã¦ã®ãƒ‡ãƒ¼ã‚¿ã¯å¤±ã‚れã¾ã™ã€‚ + + + + Are you sure you want to delete the view '%1'? + 本当ã«ãƒ“ュー '%1' を削除ã—ã¾ã™ã‹? + + + + Are you sure you want to delete the trigger '%1'? + 本当ã«ãƒˆãƒªã‚¬ãƒ¼ '%1' を削除ã—ã¾ã™ã‹? + + + + Are you sure you want to delete the index '%1'? + 本当ã«ã‚¤ãƒ³ãƒ‡ãƒƒã‚¯ã‚¹ '%1' を削除ã—ã¾ã™ã‹? + + + + Error: could not delete the table. + エラー: テーブルを削除ã§ãã¾ã›ã‚“ã§ã—ãŸã€‚ + + + + Error: could not delete the view. + エラー: ビューを削除ã§ãã¾ã›ã‚“ã§ã—ãŸã€‚ + + + + Error: could not delete the trigger. + エラー: トリガーを削除ã§ãã¾ã›ã‚“ã§ã—ãŸã€‚ + + + + Error: could not delete the index. + エラー: インデックスを削除ã§ãã¾ã›ã‚“ã§ã—ãŸã€‚ + + + + Message from database engine: +%1 + データベースエンジンã‹ã‚‰ã®ãƒ¡ãƒƒã‚»ãƒ¼ã‚¸ã€‚ +%1 + + + + Editing the table requires to save all pending changes now. +Are you sure you want to save the database? + テーブルã®ç·¨é›†ã«ã¯ä¿ç•™ä¸­ã®ã™ã¹ã¦ã®å¤‰æ›´ã‚’今ä¿å­˜ã™ã‚‹å¿…è¦ãŒã‚りã¾ã™ã€‚ +本当ã«ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã‚’ä¿å­˜ã—ã¾ã™ã‹? + + + + Error checking foreign keys after table modification. The changes will be reverted. + デーブル変更後ã®å¤–部キー検査ã§ã‚¨ãƒ©ãƒ¼ã€‚変更ã¯å…ƒã«æˆ»ã‚Šã¾ã™ã€‚ + + + + This table did not pass a foreign-key check.<br/>You should run 'Tools | Foreign-Key Check' and fix the reported issues. + ã“ã®ãƒ†ãƒ¼ãƒ–ルã¯å¤–部キー検査ã«åˆæ ¼ã—ã¾ã›ã‚“ã§ã—ãŸã€‚<br/>'ツール | 外部キー検査' を実行ã—ã€å ±å‘Šã•れãŸå•題を解決ã—ã¾ã™ã€‚ + + + + You are already executing SQL statements. Do you want to stop them in order to execute the current statements instead? Note that this might leave the database in an inconsistent state. + SQLæ–‡ã¯æ—¢ã«å®Ÿè¡Œä¸­ã§ã™ã€‚替ã‚りã«ç¾åœ¨ã®æ–‡ã‚’実行ã™ã‚‹ãŸã‚ã€ä¸­æ­¢ã—ã¾ã™ã‹? 注æ„: ã“れã¯ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã«ä¸€è²«æ€§ãŒãªã„状態を残ã™ã‹ã‚‚ã—れã¾ã›ã‚“。 + + + + -- EXECUTING SELECTION IN '%1' +-- + -- '%1 内ã®é¸æŠžéƒ¨åˆ†ã‚’実行中' +-- + + + + -- EXECUTING LINE IN '%1' +-- + -- '%1 内ã®è¡Œã‚’実行中' +-- + + + + -- EXECUTING ALL IN '%1' +-- + -- '%1 内をã™ã¹ã¦å®Ÿè¡Œä¸­' +-- + + + + Result: %1 + çµæžœ: %1 + + + + Setting PRAGMA values or vacuuming will commit your current transaction. +Are you sure? + PRAGMA 値ã®è¨­å®šã‚„ãƒã‚­ãƒ¥ãƒ¼ãƒ ã¯ç¾åœ¨ã®ãƒˆãƒ©ãƒ³ã‚¶ã‚¯ã‚·ãƒ§ãƒ³ã‚’コミットã—ã¾ã™ã€‚ +本当ã«è¡Œã„ã¾ã™ã‹? + + + + %1 rows returned in %2ms + %1 行㌠%2ms ã§è¿”ã•れã¾ã—㟠+ + + + + At line %1: + %1 行目: + + + + Result: %2 + çµæžœ: %2 + + + + Choose text files + ãƒ†ã‚­ã‚¹ãƒˆãƒ•ã‚¡ã‚¤ãƒ«ã‚’é¸æŠž + + + + Error while saving the database file. This means that not all changes to the database were saved. You need to resolve the following error first. + +%1 + データベースã®ä¿å­˜ä¸­ã«ã‚¨ãƒ©ãƒ¼ã€‚ã“れã¯å…¨ã¦ã®å¤‰æ›´ãŒãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã«ä¿å­˜ã•れã¦ã„ãªã‹ã£ãŸãŸã‚ã§ã™ã€‚ã¾ãšã€ä»¥ä¸‹ã®ã‚¨ãƒ©ãƒ¼ã‚’解決ã—ã¦ãã ã•ã„。 + +%1 + + + + Are you sure you want to undo all changes made to the database file '%1' since the last save? + 本当ã«ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ãƒ•ァイル '%1' ã¸ã®æœ€å¾Œã®ä¿å­˜å¾Œã«è¡Œã‚れãŸã™ã¹ã¦ã®å¤‰æ›´ã‚’å…ƒã«æˆ»ã—ã¾ã™ã‹? + + + + Choose a file to import + インãƒãƒ¼ãƒˆã™ã‚‹ãƒ•ã‚¡ã‚¤ãƒ«ã‚’é¸æŠž + + + + &%1 %2%3 + &%1 %2%3 + + + + (read only) + (読ã¿å–り専用) + + + + Open Database or Project + データベース化プロジェクトを開ã + + + + Attach Database... + ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã«æŽ¥ç¶š... + + + + Import CSV file(s)... + CSVファイルをインãƒãƒ¼ãƒˆ... + + + + Select the action to apply to the dropped file(s). <br/>Note: only 'Import' will process more than one file. + + ドロップã•れãŸãƒ•ァイルã«å¯¾ã—ã¦è¡Œã†æ“ä½œã‚’é¸æŠžã—ã¦ãã ã•ã„。 <br/>注æ„: 'インãƒãƒ¼ãƒˆ' ã®ã¿ãŒè¤‡æ•°ãƒ•ァイルを処ç†ã§ãã¾ã™ã€‚ + + + + + Do you want to save the changes made to SQL tabs in a new project file? + æ–°ã—ã„プロジェクトファイルã«SQLタブã§è¡Œã‚れãŸå¤‰æ›´ã‚’ä¿å­˜ã—ã¾ã™ã‹? + + + + Do you want to save the changes made to SQL tabs in the project file '%1'? + プロジェクトファイル '%1' ã«SQLタブã§è¡Œã‚れãŸå¤‰æ›´ã‚’ä¿å­˜ã—ã¾ã™ã‹? + + + + Do you want to save the changes made to the SQL file %1? + 変更をSQLファイル %1 ã«ä¿å­˜ã—ã¾ã™ã‹? + + + + The statements in this tab are still executing. Closing the tab will stop the execution. This might leave the database in an inconsistent state. Are you sure you want to close the tab? + ã“ã®ã‚¿ãƒ–ã®æ–‡ã¯ã¾ã å®Ÿè¡Œä¸­ã§ã™ã€‚タブを閉ã˜ã‚‹ã¨å®Ÿè¡ŒãŒä¸­æ­¢ã•れã¾ã™ã€‚ã“れã¯ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã«ä¸€è²«æ€§ãŒãªã„状態を残ã™ã‹ã‚‚ã—れã¾ã›ã‚“。本当ã«ã‚¿ãƒ–ã‚’é–‰ã˜ã¾ã™ã‹? + + + + Text files(*.sql *.txt);;All files(*) + テキストファイル(*.sql *.txt);;ã™ã¹ã¦ã®ãƒ•ァイル(*) + + + + Do you want to create a new database file to hold the imported data? +If you answer no we will attempt to import the data in the SQL file to the current database. + インãƒãƒ¼ãƒˆã—ãŸãƒ‡ãƒ¼ã‚¿ã‚’ä¿æŒã™ã‚‹æ–°ã—ã„データベースを作æˆã—ã¾ã™ã‹ +ã„ã„ãˆã‚’é¸æŠžã™ã‚‹ã¨ã€SQLファイルã‹ã‚‰ã®ãƒ‡ãƒ¼ã‚¿ã‚’ç¾åœ¨ã®ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã«ã‚¤ãƒ³ãƒãƒ¼ãƒˆã—よã†ã¨ã—ã¾ã™ã€‚ + + + + Do you want to save the changes made to the project file '%1'? + プロジェクトファイル '%1' ã«å¤‰æ›´ã‚’ä¿å­˜ã—ã¾ã™ã‹? + + + + Execution finished with errors. + エラーãŒã‚りã¾ã—ãŸãŒã€å®Ÿè¡ŒãŒçµ‚了ã—ã¾ã—ãŸã€‚ + + + + Execution finished without errors. + エラーãªã—ã§å®Ÿè¡ŒãŒçµ‚了ã—ã¾ã—ãŸã€‚ + + + + File %1 already exists. Please choose a different name. + ファイル %1 ã¯æ—¢ã«å­˜åœ¨ã—ã¦ã„ã¾ã™ã€‚é•ã†åå‰ã‚’é¸ã‚“ã§ãã ã•ã„。 + + + + Error importing data: %1 + データã®ã‚¤ãƒ³ãƒãƒ¼ãƒˆã§ã‚¨ãƒ©ãƒ¼: %1 + + + + Import completed. Some foreign key constraints are violated. Please fix them before saving. + インãƒãƒ¼ãƒˆãŒçµ‚了ã—ã¾ã—ãŸã€‚ã„ãã¤ã‹ã®å¤–部キー制約ã«é•åãŒã‚りã¾ã™ã€‚ä¿å­˜å‰ã«ä¿®æ­£ã—ã¦ãã ã•ã„。 + + + + Import completed. + インãƒãƒ¼ãƒˆå®Œäº†ã€‚ + + + + Delete View + ビューを削除 + + + + Modify View + ビューを変更 + + + + Delete Trigger + トリガーを削除 + + + + Modify Trigger + トリガーを変更 + + + + Delete Index + インデックスを削除 + + + + Modify Index + インデックスを変更 + + + + Modify Table + テーブルを変更 + + + + Setting PRAGMA values will commit your current transaction. +Are you sure? + PRAGMA 値ã®è¨­å®šã¯ç¾åœ¨ã®ãƒˆãƒ©ãƒ³ã‚¶ã‚¯ã‚·ãƒ§ãƒ³ã‚’コミットã—ã¾ã™ã€‚ +本当ã«è¡Œã„ã¾ã™ã‹? + + + + Select SQL file to open + é–‹ãSQLãƒ•ã‚¡ã‚¤ãƒ«ã‚’é¸æŠž + + + + Select file name + ファイルåã‚’é¸æŠž + + + + Select extension file + æ‹¡å¼µãƒ•ã‚¡ã‚¤ãƒ«ã‚’é¸æŠž + + + + Extension successfully loaded. + æ‹¡å¼µã®èª­ã¿è¾¼ã¿ã«æˆåŠŸã—ã¾ã—ãŸã€‚ + + + + Error loading extension: %1 + æ‹¡å¼µã®èª­ã¿è¾¼ã¿ã§ã‚¨ãƒ©ãƒ¼: %1 + + + + + Don't show again + 二度ã¨è¡¨ç¤ºã—ãªã„ + + + + New version available. + æ–°ã—ã„ãƒãƒ¼ã‚¸ãƒ§ãƒ³ãŒã‚りã¾ã™ã€‚ + + + + A new DB Browser for SQLite version is available (%1.%2.%3).<br/><br/>Please download at <a href='%4'>%4</a>. + æ–°ã—ã„ãƒãƒ¼ã‚¸ãƒ§ãƒ³ã® DB Browser for SQLite (%1.%2.%3)ãŒã‚りã¾ã™ã€‚<br/><br/><a href='%4'>%4</a>ã‹ã‚‰ãƒ€ã‚¦ãƒ³ãƒ­ãƒ¼ãƒ‰ã—ã¦ãã ã•ã„。 + + + + Choose a project file to open + é–‹ããƒ—ãƒ­ã‚¸ã‚§ã‚¯ãƒˆãƒ•ã‚¡ã‚¤ãƒ«ã‚’é¸æŠž + + + + DB Browser for SQLite project file (*.sqbpro) + DB Browser for SQLite プロジェクトファイル (*.sqbpro) + + + + This project file is using an old file format because it was created using DB Browser for SQLite version 3.10 or lower. Loading this file format is still fully supported but we advice you to convert all your project files to the new file format because support for older formats might be dropped at some point in the future. You can convert your files by simply opening and re-saving them. + ã“ã®ãƒ—ロジェクトファイル㯠DB Browser for SQLite version 3.10 以下ã®ãƒãƒ¼ã‚¸ãƒ§ãƒ³ã§ä½¿ã‚れãŸã€å¤ã„ファイルフォーマットを使用ã—ã¦ã„ã¾ã™ã€‚ã“ã®ãƒ•ァイルフォーマットã®èª­ã¿è¾¼ã¿ã¯ã„ã¾ã å®Œå…¨ã«ã‚µãƒãƒ¼ãƒˆã•れã¦ã„ã¾ã™ãŒã€å°†æ¥å¤ã„フォーマットã®ã‚µãƒãƒ¼ãƒˆã¯ãªããªã‚‹ãŸã‚ã€ã™ã¹ã¦ã®ãƒ—ロジェクトファイルを新ã—ã„フォーマットã«å¤‰æ›ã™ã‚‹ã“ã¨ã‚’ãŠã™ã™ã‚ã—ã¾ã™ã€‚ファイルを変æ›ã™ã‚‹ã«ã¯å˜ç´”ã«ãƒ•ァイルを開ãå†ä¿å­˜ã—ã¾ã™ã€‚ + + + + Collation needed! Proceed? + ç…§åˆé †åºãŒå¿…è¦ã§ã™!続行ã—ã¾ã™ã‹? + + + + A table in this database requires a special collation function '%1' that this application can't provide without further knowledge. +If you choose to proceed, be aware bad things can happen to your database. +Create a backup! + ã“ã®ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã«ã‚るテーブルã¯ç‰¹åˆ¥ãªç…§åˆé †åºé–¢æ•° '%1' ãŒå¿…è¦ã§ã™ãŒã€ã“ã®ã‚¢ãƒ—ãƒªã‚±ãƒ¼ã‚·ãƒ§ãƒ³ã¯æ›´ãªã‚‹çŸ¥è­˜ãªã—ã§ã¯æä¾›ã§ãã¾ã›ã‚“。 +続行ã™ã‚‹ã¨ã€ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã«ä½•ã‹æ‚ªã„ã“ã¨ãŒã‚ã‚‹ã‹ã‚‚ã—れã¾ã›ã‚“。 +ãƒãƒƒã‚¯ã‚¢ãƒƒãƒ—を作æˆã—ã¦ãã ã•ã„! + + + + creating collation + ç…§åˆé †åºã®ä½œæˆä¸­ + + + + Set a new name for the SQL tab. Use the '&&' character to allow using the following character as a keyboard shortcut. + SQLã‚¿ãƒ–ã«æ–°ã—ã„åå‰ã‚’設定ã—ã¦ãã ã•ã„。'&&'ã®æ–‡å­—を使ã†ã¨ã€ãã®æ¬¡ã®æ–‡å­—をキーボードショートカットã«ã§ãã¾ã™ã€‚ + + + + Please specify the view name + ビューã®åå‰ã‚’指定ã—ã¦ãã ã•ã„ + + + + There is already an object with that name. Please choose a different name. + ãã®åå‰ã®ã‚ªãƒ–ã‚¸ã‚§ã‚¯ãƒˆã¯æ—¢ã«å­˜åœ¨ã—ã¾ã™ã€‚別ã®åå‰ã‚’é¸ã‚“ã§ãã ã•ã„。 + + + + View successfully created. + ビューã®ä½œæˆã«æˆåŠŸã—ã¾ã—ãŸã€‚ + + + + Error creating view: %1 + ビューã®ä½œæˆã§ã‚¨ãƒ©ãƒ¼: %1 + + + + This action will open a new SQL tab for running: + ã“ã®æ“作ã¯å®Ÿè¡Œã®ãŸã‚æ–°ã—ã„SQLタブを開ãã¾ã™: + + + + Press Help for opening the corresponding SQLite reference page. + ヘルプを押ã™ã¨ã€å¯¾å¿œã™ã‚‹ SQLite ã®ãƒªãƒ•ァレンスページを開ãã¾ã™ã€‚ + + + + NullLineEdit + + + Set to NULL + NULL ã«è¨­å®š + + + + Alt+Del + Alt+Del + + + + PlotDock + + + Plot + プロット + + + + <html><head/><body><p>This pane shows the list of columns of the currently browsed table or the just executed query. You can select the columns that you want to be used as X or Y axis for the plot pane below. The table shows detected axis type that will affect the resulting plot. For the Y axis you can only select numeric columns, but for the X axis you will be able to select:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Date/Time</span>: strings with format &quot;yyyy-MM-dd hh:mm:ss&quot; or &quot;yyyy-MM-ddThh:mm:ss&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Date</span>: strings with format &quot;yyyy-MM-dd&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Time</span>: strings with format &quot;hh:mm:ss&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Label</span>: other string formats. Selecting this column as X axis will produce a Bars plot with the column values as labels for the bars</li><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Numeric</span>: integer or real values</li></ul><p>Double-clicking the Y cells you can change the used color for that graph.</p></body></html> + <html><head/><body><p>ã“ã®ãƒšã‚¤ãƒ³ã¯ç¾åœ¨é–²è¦§ä¸­ã®ãƒ†ãƒ¼ãƒ–ルã‹ç›´å‰ã«å®Ÿè¡Œã—ãŸã‚¯ã‚¨ãƒªãƒ¼ã®ã‚«ãƒ©ãƒ ã®ä¸€è¦§ã‚’表示ã—ã¾ã™ã€‚下ã®ãƒ—ロットペインã§Xã‚‚ã—ãã¯Y軸ã¨ã—ã¦ä½¿ç”¨ã•ã‚Œã‚‹ã‚«ãƒ©ãƒ ã‚’é¸æŠžã§ãã¾ã™ã€‚表ã¯çµæžœã®ãƒ—ロットã«ä½¿ç”¨ã§ãる軸ã®ç¨®é¡žã‚’表示ã—ã¾ã™ã€‚Y軸ã«ã¯æ•°å€¤ã®ã‚«ãƒ©ãƒ ã®ã¿é¸æŠžã§ãã¾ã™ãŒã€X軸ã«ã¯ã“れらãŒé¸æŠžã§ãã¾ã™:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">日時</span>: &quot;yyyy-MM-dd hh:mm:ss&quot; ã‚‚ã—ã㯠&quot;yyyy-MM-ddThh:mm:ss&quot; å½¢å¼ã®æ–‡å­—列</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">日付</span>: &quot;yyyy-MM-dd&quot; å½¢å¼ã®æ–‡å­—列</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">時刻</span>: &quot;hh:mm:ss&quot; å½¢å¼ã®æ–‡å­—列</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">ラベル</span>: ãã®ä»–ã®å½¢å¼ã®æ–‡å­—列。ã“れをX軸ã«é¸æŠžã™ã‚‹ã¨ã€ã‚«ãƒ©ãƒ ã®å€¤ã‚’棒グラフã®ãƒ©ãƒ™ãƒ«ã¨ã—ã¦è¡¨ç¤ºã—ã¾ã™</li><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">数値</span>: INTEGER ã‹ REAL ã®å€¤</li></ul><p>Yã®ã‚»ãƒ«ã‚’ダブルクリックã™ã‚‹ã¨ã€ã‚°ãƒ©ãƒ•ã«ä½¿ç”¨ã™ã‚‹è‰²ã‚’変更ã§ãã¾ã™ã€‚</p></body></html> + + + + Columns + カラム + + + + X + X + + + + Y1 + Y1 + + + + Y2 + Y2 + + + + Axis Type + 軸ã®ãƒ‡ãƒ¼ã‚¿åž‹ + + + + Here is a plot drawn when you select the x and y values above. + +Click on points to select them in the plot and in the table. Ctrl+Click for selecting a range of points. + +Use mouse-wheel for zooming and mouse drag for changing the axis range. + +Select the axes or axes labels to drag and zoom only in that orientation. + 上ã§Xã¨Yè»¸ã‚’é¸æŠžã™ã‚‹ã¨ã€ã“ã“ã«ã‚°ãƒ©ãƒ•ãŒæç”»ã•れã¾ã™ã€‚ + +点をクリックã™ã‚‹ã¨ã€ç‚¹ã¨è©²å½“ã™ã‚‹ãƒ†ãƒ¼ãƒ–ルã®å€¤ãŒé¸æŠžã§ãã¾ã™ã€‚Ctrl+クリックã§ç‚¹ã‚’ç¯„å›²é¸æŠžã§ãã¾ã™ã€‚ + +マウスホイールã§ã‚ºãƒ¼ãƒ ã€ãƒ‰ãƒ©ãƒƒã‚°ã§è»¸ã®ç¯„囲を変更ã§ãã¾ã™ã€‚ + +軸ã‹è»¸ã®ãƒ©ãƒ™ãƒ«ã‚’é¸æŠžã™ã‚‹ã¨ã€ã‚ºãƒ¼ãƒ ã‚„ãƒ‰ãƒ©ãƒƒã‚°ã®æ–¹å‘ã‚’é™å®šã§ãã¾ã™ã€‚ + + + + Line type: + ç·šã®ç¨®é¡ž: + + + + + None + ãªã— + + + + Line + ç›´ç·š + + + + StepLeft + 階段(左値) + + + + StepRight + 階段(å³å€¤) + + + + StepCenter + 階段(最近値) + + + + Impulse + インパルス + + + + Point shape: + 点ã®å½¢çж: + + + + Cross + × + + + + Plus + + + + + + Circle + â—‹ + + + + Disc + â— + + + + Square + â–¡ + + + + Diamond + â—‡ + + + + Star + * + + + + Triangle + â–³ + + + + TriangleInverted + â–½ + + + + CrossSquare + ×+â–¡ + + + + PlusSquare + ++â–¡ + + + + CrossCircle + ×+â—‹ + + + + PlusCircle + ++â—‹ + + + + Peace + é™è¬ + + + + <html><head/><body><p>Save current plot...</p><p>File format chosen by extension (png, jpg, pdf, bmp)</p></body></html> + <html><head/><body><p>ç¾åœ¨ã®ãƒ—ロットをä¿å­˜...</p><p>ãƒ•ã‚¡ã‚¤ãƒ«ãƒ•ã‚©ãƒ¼ãƒžãƒƒãƒˆã¯æ‹¡å¼µå­ (png, jpg, pdf, bmp) ã‹ã‚‰é¸æŠžã•れã¾ã™</p></body></html> + + + + Save current plot... + ç¾åœ¨ã®ãƒ—ロットをä¿å­˜... + + + + + Load all data and redraw plot + ã™ã¹ã¦ã®ãƒ‡ãƒ¼ã‚¿ã‚’読ã¿è¾¼ã¿å†æç”» + + + + Copy + コピー + + + + Print... + å°åˆ·... + + + + Show legend + 凡例を表示 + + + + Stacked bars + 値をç©ã¿é‡ã­ã‚‹ + + + + Date/Time + 日時 + + + + Date + 日付 + + + + Time + 時刻 + + + + + Numeric + 数値 + + + + Label + ラベル + + + + Invalid + 䏿­£ + + + + + + Row # + 行 # + + + + Load all data and redraw plot. +Warning: not all data has been fetched from the table yet due to the partial fetch mechanism. + ã™ã¹ã¦ã®ãƒ‡ãƒ¼ã‚¿ã‚’読ã¿è¾¼ã¿å†æç”»ã—ã¾ã™ã€‚ +警告: 部分的ãªãƒ•ã‚§ãƒƒãƒæ©Ÿæ§‹ã«ã‚ˆã‚Šã€ã¾ã ãƒ†ãƒ¼ãƒ–ルã‹ã‚‰ã™ã¹ã¦ã®ãƒ‡ãƒ¼ã‚¿ãŒãƒ•ェッãƒã•れã¦ã„ã‚‹ã‚ã‘ã§ã¯ã‚りã¾ã›ã‚“。 + + + + Choose an axis color + 軸ã®è‰²ã‚’é¸æŠž + + + + Choose a filename to save under + 以下をä¿å­˜ã™ã‚‹ãƒ•ァイルåã‚’é¸æŠž + + + + PNG(*.png);;JPG(*.jpg);;PDF(*.pdf);;BMP(*.bmp);;All Files(*) + PNG(*.png);;JPG(*.jpg);;PDF(*.pdf);;BMP(*.bmp);;ã™ã¹ã¦ã®ãƒ•ァイル(*) + + + + There are curves in this plot and the selected line style can only be applied to graphs sorted by X. Either sort the table or query by X to remove curves or select one of the styles supported by curves: None or Line. + ã“ã®ãƒ—ロットã«ã¯æœªã‚½ãƒ¼ãƒˆãªãƒ‡ãƒ¼ã‚¿ãŒã‚りã¾ã™ã€‚é¸æŠžã—ãŸç·šã®ç¨®é¡žã¯X軸ã§ã‚½ãƒ¼ãƒˆã•れãŸãƒ‡ãƒ¼ã‚¿ã®ã¿ã«é©ç”¨ã§ãã¾ã™ã€‚テーブルやクエリーをX軸ã§ã‚½ãƒ¼ãƒˆã™ã‚‹ã‹ã€æœªã‚½ãƒ¼ãƒˆã®ãƒ‡ãƒ¼ã‚¿ã§ã‚‚使用ã§ãる〠ãªã— ã‚„ ç›´ç·š å½¢å¼ã‚’é¸æŠžã—ã¦ãã ã•ã„。 + + + + Loading all remaining data for this table took %1ms. + ã“ã®ãƒ†ãƒ¼ãƒ–ãƒ«ã®æ®‹ã£ã¦ã„るデータã™ã¹ã¦ã®èª­ã¿è¾¼ã¿ã« %1ms ã‹ã‹ã‚Šã¾ã—ãŸã€‚ + + + + PreferencesDialog + + + Preferences + 設定 + + + + &General + 全般(&G) + + + + Default &location + デフォルトã®ãƒ•ォルダー(&L) + + + + Remember last location + 最後ã«ä½¿ç”¨ã—ãŸãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªãƒ¼ã‚’記憶 + + + + Always use this location + 常ã«ã“ã®ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªãƒ¼ã‚’使用 + + + + Remember last location for session only + セッションã ã‘ã§æœ€å¾Œã«ä½¿ç”¨ã—ãŸãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªãƒ¼ã‚’記憶 + + + + + + ... + ... + + + + Lan&guage + 言語(&L) + + + + Toolbar style + ツールãƒãƒ¼å½¢å¼ + + + + + + + + Only display the icon + アイコンã®ã¿è¡¨ç¤º + + + + + + + + Only display the text + 文字ã®ã¿è¡¨ç¤º + + + + + + + + The text appears beside the icon + ã‚¢ã‚¤ã‚³ãƒ³ã®æ¨ªã«æ–‡å­—を表示 + + + + + + + + The text appears under the icon + アイコンã®ä¸‹ã«æ–‡å­—を表示 + + + + + + + + Follow the style + スタイルã«å¾“ㆠ+ + + + Show remote options + リモートオプションを表示ã™ã‚‹ + + + + + + + + + + + + enabled + 有効 + + + + Automatic &updates + 自動アップデート(&U) + + + + DB file extensions + DBãƒ•ã‚¡ã‚¤ãƒ«æ‹¡å¼µå­ + + + + Manage + ç®¡ç† + + + + Main Window + メインウィンドウ + + + + Database Structure + データベース構造 + + + + Browse Data + データ閲覧 + + + + Execute SQL + SQL実行 + + + + Edit Database Cell + データベースセル編集 + + + + When this value is changed, all the other color preferences are also set to matching colors. + ã“ã®å€¤ãŒå¤‰æ›´ã•れるã¨ã€ä»–ã®è‰²è¨­å®šã™ã¹ã¦ã‚‚一致ã™ã‚‹è‰²ã«è¨­å®šã•れã¾ã™ã€‚ + + + + Follow the desktop style + デスクトップスタイルã«å¾“ㆠ+ + + + Dark style + ダークスタイル + + + + Application style + アプリケーションスタイル + + + + This sets the font size for all UI elements which do not have their own font size option. + ã“れã¯ç‹¬è‡ªã®ãƒ•ォントサイズオプションをæŒãŸãªã„å…¨ã¦ã®UIè¦ç´ ã®ãƒ•ォントサイズを設定ã—ã¾ã™ã€‚ + + + + Font size + フォントサイズ + + + + &Database + データベース(&D) + + + + Database &encoding + データベースã®ã‚¨ãƒ³ã‚³ãƒ¼ãƒ‰(&E) + + + + Open databases with foreign keys enabled. + 外部キーを有効ã«ã—ã¦ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã‚’é–‹ã。 + + + + &Foreign keys + 外部キー(&F) + + + + Remove line breaks in schema &view + スキーマビューã‹ã‚‰æ”¹è¡Œã‚’å–り除ã(&V) + + + + When enabled, the line breaks in the Schema column of the DB Structure tab, dock and printed output are removed. + 有効ã«ã™ã‚‹ã¨ã€DB構造タブã®ã‚«ãƒ©ãƒ ã‚¹ã‚­ãƒ¼ãƒžã€ãƒ‰ãƒƒã‚¯ã‚„å°åˆ·ã•れãŸå‡ºåŠ›ã«ã‚る改行ãŒå–り除ã‹ã‚Œã¾ã™ã€‚ + + + + Prefetch block si&ze + 先読ã¿ãƒ–ロックサイズ(&Z) + + + + SQ&L to execute after opening database + データベースを開ã„ãŸå¾Œã«å®Ÿè¡Œã™ã‚‹SQL(&L) + + + + Default field type + デフォルトã®ãƒ•ã‚£ãƒ¼ãƒ«ãƒ‰ãƒ‡ãƒ¼ã‚¿å½¢å¼ + + + + Database structure font size + データベース構造ã®ãƒ•ォントサイズ + + + + Data &Browser + データ閲覧(&B) + + + + Font + フォント + + + + &Font + フォント(&F) + + + + Font si&ze + フォントサイズ(&Z) + + + + Content + 内容 + + + + Symbol limit in cell + セル内ã®ã‚·ãƒ³ãƒœãƒ«ä¸Šé™ + + + + This is the maximum number of items allowed for some computationally expensive functionalities to be enabled: +Maximum number of rows in a table for enabling the value completion based on current values in the column. +Maximum number of indexes in a selection for calculating sum and average. +Can be set to 0 for disabling the functionalities. + ã“れã¯ã„ãã¤ã‹ã®è¨ˆç®—è² è·ã®é«˜ã„機能を有効ã«ã§ãã‚‹é …ç›®ã®æœ€å¤§æ•°ã§ã™ã€‚ +カラム内ã®ç¾åœ¨å€¤ã«åŸºã¥ã„ãŸå€¤è£œå®Œã‚’有効ã«ã™ã‚‹ã€ãƒ†ãƒ¼ãƒ–ル内ã®è¡Œã®æœ€å¤§æ•°ã€‚ +é¸æŠžå†…ã®åˆè¨ˆã¨å¹³å‡ã‚’計算ã™ã‚‹ã‚¤ãƒ³ãƒ‡ãƒƒã‚¯ã‚¹ã®æœ€å¤§æ•°ã€‚ +0ã«è¨­å®šã™ã‚‹ã¨ã“ã®æ©Ÿèƒ½ã‚’無効ã«ã§ãã¾ã™ã€‚ + + + + This is the maximum number of rows in a table for enabling the value completion based on current values in the column. +Can be set to 0 for disabling completion. + ã“れã¯ç¾åœ¨ã®å€¤ã‚’基ã«ã—ãŸã‚«ãƒ©ãƒ ã®å€¤è£œå®Œã‚’有効ã«ã—ãŸã¨ãã®ãƒ†ãƒ¼ãƒ–ル内ã®è¡Œæ•°ã®æœ€å¤§å€¤ã§ã™ã€‚ + + + + Field display + フィールド表示 + + + + Displayed &text + 表示ã•れãŸãƒ†ã‚­ã‚¹ãƒˆ(&T) + + + + Binary + ãƒã‚¤ãƒŠãƒªãƒ¼ + + + + NULL + NULL + + + + Regular + 通常 + + + + + + + + + Click to set this color + クリックã§ã“ã®è‰²ã‚’設定 + + + + Text color + 文字色 + + + + Background color + 背景色 + + + + Preview only (N/A) + 閲覧ã®ã¿(設定ä¸å¯) + + + + Filters + フィルター + + + + Escape character + エスケープ文字 + + + + Delay time (&ms) + é…延時間 (ms) (&M) + + + + Set the waiting time before a new filter value is applied. Can be set to 0 for disabling waiting. + æ–°ã—ã„フィルターã®å€¤ãŒé©ç”¨ã•れるå‰ã®å¾…機時間を設定ã—ã¾ã™ã€‚0ã«ã™ã‚‹ã¨å¾…機ã—ã¾ã›ã‚“。 + + + + &SQL + SQL(&S) + + + + Settings name + 設定å + + + + Context + 内容 + + + + Colour + 色 + + + + Bold + 太字 + + + + Italic + イタリック + + + + Underline + 下線 + + + + Keyword + キーワード + + + + Function + 関数 + + + + Table + テーブル + + + + Comment + コメント + + + + Identifier + è­˜åˆ¥å­ + + + + String + 文字列 + + + + Current line + ç¾åœ¨è¡Œ + + + + Background + 背景 + + + + Foreground + 剿™¯ + + + + SQL editor &font + SQLエディターフォント(&F) + + + + SQL &editor font size + SQLエディターフォントサイズ(&E) + + + + SQL &results font size + SQLçµæžœãƒ•ォントサイズ(&R) + + + + Tab size + タブサイズ + + + + &Wrap lines + ワードラップ(&W) + + + + Never + ã—ãªã„ + + + + At word boundaries + å˜èªžã§ + + + + At character boundaries + 文字㧠+ + + + At whitespace boundaries + 空白㧠+ + + + &Quotes for identifiers + 識別å­ã®ã‚¯ã‚©ãƒ¼ãƒˆ(&Q) + + + + Choose the quoting mechanism used by the application for identifiers in SQL code. + アプリケーションãŒSQLコード内ã§è­˜åˆ¥å­ã‚’クォートã™ã‚‹ä»•組ã¿ã‚’é¸æŠžã—ã¾ã™ã€‚ + + + + "Double quotes" - Standard SQL (recommended) + "ダブルクォート" - 一般的㪠SQL (推奨) + + + + `Grave accents` - Traditional MySQL quotes + `グレイヴアクセント` - ä¼çµ±çš„㪠MySQL ã®ã‚¯ã‚©ãƒ¼ãƒˆ + + + + [Square brackets] - Traditional MS SQL Server quotes + [角括弧] - ä¼çµ±çš„㪠MS SQL Server ã®ã‚¯ã‚©ãƒ¼ãƒˆ + + + + Code co&mpletion + コード補完(&M) + + + + Keywords in &UPPER CASE + キーワードを大文字ã«(&U) + + + + When set, the SQL keywords are completed in UPPER CASE letters. + 設定ã™ã‚‹ã¨ã€SQLキーワードを大文字ã«è£œå®Œã—ã¾ã™ã€‚ + + + + Error indicators + エラー指摘 + + + + When set, the SQL code lines that caused errors during the last execution are highlighted and the results frame indicates the error in the background + 設定ã™ã‚‹ã¨ã€æœ€å¾Œã®å®Ÿè¡Œã§ã‚¨ãƒ©ãƒ¼ãŒèµ·ããŸSQLコードã®è¡ŒãŒå¼·èª¿ã•れã€çµæžœãƒ•レームãŒãƒãƒƒã‚¯ã‚°ãƒ©ã‚¦ãƒ³ãƒ‰ã§ã‚¨ãƒ©ãƒ¼ã‚’指摘ã—ã¾ã™ + + + + Hori&zontal tiling + 横ã«ä¸¦ã¹ã‚‹(&Z) + + + + If enabled the SQL code editor and the result table view are shown side by side instead of one over the other. + 有効ã«ã™ã‚‹ã¨ã€é‡ã­ã‚‹ä»£ã‚りã«ã€SQLコードエディターã¨çµæžœã‚¿ãƒ–ビューãŒä¸¦ã‚“ã§è¡¨ç¤ºã•れã¾ã™ã€‚ + + + + Close button on tabs + タブ上ã®é–‰ã˜ã‚‹ãƒœã‚¿ãƒ³ + + + + If enabled, SQL editor tabs will have a close button. In any case, you can use the contextual menu or the keyboard shortcut to close them. + å¯èƒ½ãªã‚‰ã°ã€SQLエディタータブã«é–‰ã˜ã‚‹ãƒœã‚¿ãƒ³ã‚’表示ã—ã¾ã™ã€‚ã©ã®ã‚ˆã†ãªå ´åˆã§ã‚‚ã€ã‚³ãƒ³ãƒ†ã‚­ã‚¹ãƒˆãƒ¡ãƒ‹ãƒ¥ãƒ¼ã‚„キーボートショートカットを使ã£ã¦é–‰ã˜ã‚‹ã“ã¨ã¯ã§ãã¾ã™ã€‚ + + + + &Extensions + æ‹¡å¼µ(&E) + + + + Select extensions to load for every database: + ã™ã¹ã¦ã®ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã§èª­ã¿è¾¼ã‚€æ‹¡å¼µã‚’é¸æŠž: + + + + Add extension + 拡張を追加 + + + + Remove extension + 拡張を削除 + + + + <html><head/><body><p>While supporting the REGEXP operator SQLite doesn't implement any regular expression<br/>algorithm but calls back the running application. DB Browser for SQLite implements this<br/>algorithm for you to let you use REGEXP out of the box. However, as there are multiple possible<br/>implementations of this and you might want to use another one, you're free to disable the<br/>application's implementation and load your own by using an extension. Requires restart of the application.</p></body></html> + <html><head/><body><p>REGEXP演算å­ãŒã‚µãƒãƒ¼ãƒˆã•れã¦ã„ã‚‹é–“ã€SQLite ã¯æ­£è¦è¡¨ç¾ã‚’実装ã—ã¾ã›ã‚“ãŒã€å®Ÿè¡Œä¸­ã®ã‚¢ãƒ—リケーションをコールãƒãƒƒã‚¯ã—ã¾ã™ã€‚DB Browser for SQLite ã¯ã“れを実装ã—ã¦ã„ã‚‹ã®ã§ã€REGEXP ã‚’ã™ãã«ä½¿ãˆã¾ã™ã€‚ã—ã‹ã—ã€ã“れã«ã¯è¤‡æ•°ã®å®Ÿè£…ãŒã‚りã€ã‚¢ãƒ—リケーションã®å®Ÿè£…を無効ã«ã—拡張を使ã£ã¦ä»–ã®å®Ÿè£…を読ã¿è¾¼ã‚€ã“ã¨ãŒè‡ªç”±ã«ã§ãã¾ã™ã€‚アプリケーションã®å†èµ·å‹•ãŒå¿…è¦ã§ã™ã€‚</p></body></html> + + + + Disable Regular Expression extension + æ­£è¦è¡¨ç¾æ‹¡å¼µã‚’無効 + + + + <html><head/><body><p>SQLite provides an SQL function for loading extensions from a shared library file. Activate this if you want to use the <span style=" font-style:italic;">load_extension()</span> function from SQL code.</p><p>For security reasons, extension loading is turned off by default and must be enabled through this setting. You can always load extensions through the GUI, even though this option is disabled.</p></body></html> + <html><head/><body><p>SQLite ã¯å…±æœ‰ãƒ©ã‚¤ãƒ–ラリファイルã‹ã‚‰æ‹¡å¼µã‚’読ã¿è¾¼ã‚€SQL関数をæä¾›ã—ã¾ã™ã€‚SQLコードã‹ã‚‰<span style=" font-style:italic;">load_extension()</span>関数を使ã„ãŸã„ãªã‚‰ã°ã€.ã“れを有効ã«ã—ã¾ã™ã€‚</p><p>セキュリティー上ã®ç†ç”±ã‹ã‚‰ã€æ‹¡å¼µã®èª­ã¿è¾¼ã¿ã¯ãƒ‡ãƒ•ォルトã§ç„¡åйã«ãªã£ã¦ãŠã‚Šã€ä½¿ç”¨ã™ã‚‹ã«ã¯ã“ã®è¨­å®šã‚’有効ã«ã™ã‚‹å¿…è¦ãŒã‚りã¾ã™ã€‚ã“ã®ã‚ªãƒ—ションãŒç„¡åйã§ã‚‚ã€GUIを通ã˜ã¦æ‹¡å¼µã‚’読ã¿è¾¼ã‚€ã“ã¨ã¯å¸¸ã«ã§ãã¾ã™ã€‚</p></body></html> + + + + Allow loading extensions from SQL code + SQLã‚³ãƒ¼ãƒ‰ã§æ‹¡å¼µã®èª­ã¿è¾¼ã¿ã‚’許å¯ã™ã‚‹ + + + + Remote + リモート + + + + CA certificates + èªè¨¼å±€è¨¼æ˜Žæ›¸ + + + + Proxy + プロキシ + + + + Configure + 設定 + + + + + Subject CN + 対象CN + + + + Common Name + Common Name + + + + Subject O + 対象O + + + + Organization + Organization + + + + + Valid from + 証明開始 + + + + + Valid to + 証明終了 + + + + + Serial number + ã‚·ãƒªã‚¢ãƒ«ç•ªå· + + + + Your certificates + ã‚ãªãŸã®è¨¼æ˜Žæ›¸ + + + + Threshold for completion and calculation on selection + 補完ã¨é¸æŠžç¯„囲内ã®è¨ˆç®—ã®é–¾å€¤ + + + + Show images in cell + セル内ã«ç”»åƒã‚’表示 + + + + Enable this option to show a preview of BLOBs containing image data in the cells. This can affect the performance of the data browser, however. + ã“ã®ã‚ªãƒ—ションを有効ã«ã™ã‚‹ã¨ã€ã‚»ãƒ«å†…ã®ç”»åƒãƒ‡ãƒ¼ã‚¿ã‚’å«ã‚€ BLOB ã®ãƒ—レビューãŒã§ãã¾ã™ã€‚ã—ã‹ã—ã€ã“れã¯ãƒ‡ãƒ¼ã‚¿é–²è¦§ã®æ€§èƒ½ã«å½±éŸ¿ã—ã¾ã™ã€‚ + + + + File + ファイル + + + + Subject Common Name + 対象Common Name + + + + Issuer CN + 発行者CN + + + + Issuer Common Name + 発行者Common Name + + + + Clone databases into + ã“ã“ã«ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã‚’複製 + + + + + Choose a directory + ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªãƒ¼ã‚’é¸æŠž + + + + The language will change after you restart the application. + アプリケーションをå†èµ·å‹•ã™ã‚‹ã¨ã€è¨€èªžãŒå¤‰æ›´ã•れã¾ã™ã€‚ + + + + Select extension file + æ‹¡å¼µãƒ•ã‚¡ã‚¤ãƒ«ã‚’é¸æŠž + + + + Extensions(*.so *.dylib *.dll);;All files(*) + æ‹¡å¼µ(*.so *.dylib *.dll);;ã™ã¹ã¦ã®ãƒ•ァイル(*) + + + + Import certificate file + 証明書ファイルをインãƒãƒ¼ãƒˆ + + + + No certificates found in this file. + ã“ã®ãƒ•ァイルã«è¨¼æ˜Žæ›¸ãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“。 + + + + Are you sure you want do remove this certificate? All certificate data will be deleted from the application settings! + 本当ã«ã“ã®è¨¼æ˜Žæ›¸ã‚’削除ã—ã¾ã™ã‹? ã™ã¹ã¦ã®è¨¼æ˜Žæ›¸ãƒ‡ãƒ¼ã‚¿ã¯ã“ã®ã‚¢ãƒ—リケーション設定ã‹ã‚‰å‰Šé™¤ã•れã¾ã™! + + + + Are you sure you want to clear all the saved settings? +All your preferences will be lost and default values will be used. + 本当ã«ä¿å­˜ã•れãŸè¨­å®šã‚’削除ã—ã¾ã™ã‹? +ã™ã¹ã¦ã®è¨­å®šã¯å¤±ã‚れã€ãƒ‡ãƒ•ォルト値ãŒä½¿ç”¨ã•れã¾ã™ã€‚ + + + + ProxyDialog + + + Proxy Configuration + プロキシ設定 + + + + Pro&xy Type + プロキシタイプ(&X) + + + + Host Na&me + ホストå(&M) + + + + Port + ãƒãƒ¼ãƒˆ + + + + Authentication Re&quired + èªè¨¼ãŒå¿…è¦(&Q) + + + + &User Name + ユーザーå(&U) + + + + Password + パスワード + + + + None + ãªã— + + + + System settings + システム設定 + + + + HTTP + HTTP + + + + Socks v5 + Socks v5 + + + + QObject + + + All files (*) + ã™ã¹ã¦ã®ãƒ•ァイル (*) + + + + Error importing data + データã®ã‚¤ãƒ³ãƒãƒ¼ãƒˆã§ã‚¨ãƒ©ãƒ¼ + + + + from record number %1 + ãƒ¬ã‚³ãƒ¼ãƒ‰ç•ªå· %1 ã§ + + + + . +%1 + . +%1 + + + + Importing CSV file... + CSVファイルをインãƒãƒ¼ãƒˆä¸­... + + + + Cancel + キャンセル + + + + SQLite database files (*.db *.sqlite *.sqlite3 *.db3) + SQLite データベースファイル (*.db *.sqlite *.sqlite3 *.db3) + + + + Left + å·¦ + + + + Right + å³ + + + + Center + 中央 + + + + Justify + å‡ç­‰ + + + + SQLite Database Files (*.db *.sqlite *.sqlite3 *.db3) + SQLite データベースファイル (*.db *.sqlite *.sqlite3 *.db3) + + + + DB Browser for SQLite Project Files (*.sqbpro) + DB Browser for SQLite プロジェクトファイル (*.sqbpro) + + + + SQL Files (*.sql) + SQL ファイル (*.sql) + + + + All Files (*) + ã™ã¹ã¦ã®ãƒ•ァイル (*) + + + + Text Files (*.txt) + テキストファイル (*.txt) + + + + Comma-Separated Values Files (*.csv) + カンマ区切りファイル (*.csv) + + + + Tab-Separated Values Files (*.tsv) + タブ区切りファイル (*.tsv) + + + + Delimiter-Separated Values Files (*.dsv) + 区切りファイル (*.dsv) + + + + Concordance DAT files (*.dat) + 用語索引 DAT ファイル (*.dat) + + + + JSON Files (*.json *.js) + JSONファイル (*.json *.js) + + + + XML Files (*.xml) + XMLファイル (*.xml) + + + + Binary Files (*.bin *.dat) + ãƒã‚¤ãƒŠãƒªãƒ¼ãƒ•ァイル (*.bin *.dat) + + + + SVG Files (*.svg) + SVG ファイル (*.svg) + + + + Hex Dump Files (*.dat *.bin) + å六進ダンプファイル (*.dat *.bin) + + + + Extensions (*.so *.dylib *.dll) + æ‹¡å¼µ (*.so *.dylib *.dll) + + + + RemoteCommitsModel + + + Commit ID + コミットID + + + + Message + メッセージ + + + + Date + 日付 + + + + Author + 作者 + + + + Size + サイズ + + + + Authored and committed by %1 + %1 ãŒä½œæˆãƒ»ã‚³ãƒŸãƒƒãƒˆã—ã¾ã—㟠+ + + + Authored by %1, committed by %2 + %1 ãŒä½œæˆ, %2 ãŒã‚³ãƒŸãƒƒãƒˆã—ã¾ã—㟠+ + + + RemoteDatabase + + + Error opening local databases list. +%1 + ローカルデータベースã®ä¸€è¦§ã‚’é–‹ãã¨ãã«ã‚¨ãƒ©ãƒ¼ã€‚ +%1 + + + + Error creating local databases list. +%1 + ローカルデータベースã®ä¸€è¦§ã®ä½œæˆã§ã‚¨ãƒ©ãƒ¼ã€‚ +%1 + + + + RemoteDock + + + Remote + リモート + + + + Identity + アイデンティティー + + + + Push currently opened database to server + ç¾åœ¨é–‹ã„ã¦ã„るデータベースをサーãƒãƒ¼ã«ãƒ—ッシュã—ã¾ã™ + + + + DBHub.io + DBHub.io + + + + <html><head/><body><p>In this pane, remote databases from dbhub.io website can be added to DB Browser for SQLite. First you need an identity:</p><ol style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Login to the dbhub.io website (use your GitHub credentials or whatever you want)</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Click the button to &quot;Generate client certificate&quot; (that's your identity). That'll give you a certificate file (save it to your local disk).</li><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Go to the Remote tab in DB Browser for SQLite Preferences. Click the button to add a new certificate to DB Browser for SQLite and choose the just downloaded certificate file.</li></ol><p>Now the Remote panel shows your identity and you can add remote databases.</p></body></html> + <html><head/><body><p>ã“ã®ãƒšã‚¤ãƒ³ã§ã¯ã€dbhub.io ウェブサイトã®ãƒªãƒ¢ãƒ¼ãƒˆãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã‚’ DB Browser for SQLite ã«è¿½åŠ ã—ã¾ã™ã€‚最åˆã«ã‚¢ã‚¤ãƒ‡ãƒ³ãƒ†ã‚£ãƒ†ã‚£ãƒ¼ãŒå¿…è¦ã§ã™ã€‚:</p><ol style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">dbhub.io ウェブサイトã«ãƒ­ã‚°ã‚¤ãƒ³ã—ã¾ã™ã€‚(GitHubã‹ã‚ãªãŸãŒæœ›ã‚€èªè¨¼æƒ…報を使ã„ã¾ã™)</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">ボタンをクリックã—&quotクライアント証明書を作æˆ&quotã—ã¾ã™(ã“れãŒã‚ãªãŸã®ã‚¢ã‚¤ãƒ‡ãƒ³ãƒ†ã‚£ãƒ†ã‚£ã§ã™)。 証明書ファイルãŒä¸Žãˆã‚‰ã‚Œã¾ã™(ã‚ãªãŸã®ãƒ­ãƒ¼ã‚«ãƒ«ãƒ‡ã‚£ã‚¹ã‚¯ã«ä¿å­˜ã—ã¾ã™)。</li><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> +DB Browser for SQLite 設定ã®ãƒªãƒ¢ãƒ¼ãƒˆã‚¿ãƒ–ã«è¡Œãã€æ–°ã—ã„証明書を DB Browsser for SQLite ã«è¿½åŠ ã™ã‚‹ãƒœã‚¿ãƒ³ã‚’クリックã—ã€ãƒ€ã‚¦ãƒ³ãƒ­ãƒ¼ãƒ‰ã—ãŸè¨¼æ˜Žæ›¸ãƒ•ã‚¡ã‚¤ãƒ«ã‚’é¸æŠžã—ã¾ã™ã€‚</li></ol><p>ã“れã§ã€ãƒªãƒ¢ãƒ¼ãƒˆãƒ‘ãƒãƒ«ã«ã‚ãªãŸã®ã‚¢ã‚¤ãƒ‡ãƒ³ãƒ†ã‚£ãƒ†ã‚£ãŒè¡¨ç¤ºã•れã€ãƒªãƒ¢ãƒ¼ãƒˆãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ãŒè¿½åŠ ã§ãã¾ã™ã€‚</p></body></html> + + + + Local + ローカル + + + + Current Database + ç¾åœ¨ã®ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ + + + + Clone + クローン + + + + User + ユーザー + + + + Database + データベース + + + + Branch + ブランム+ + + + Commits + コミット + + + + Commits for + ã“れã«ã‚³ãƒŸãƒƒãƒˆ + + + + Delete Database + データベースを削除 + + + + Delete the local clone of this database + ã“ã®ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã®ãƒ­ãƒ¼ã‚«ãƒ«ã‚¯ãƒ­ãƒ¼ãƒ³ã‚’削除 + + + + Open in Web Browser + ウェブブラウザーã§é–‹ã + + + + Open the web page for the current database in your browser + ブラウザã§ç¾åœ¨ã®ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã®ã‚¦ã‚§ãƒ–ページを開ã + + + + Clone from Link + リンクã‹ã‚‰ã‚¯ãƒ­ãƒ¼ãƒ³ + + + + Use this to download a remote database for local editing using a URL as provided on the web page of the database. + データベースã®ã‚¦ã‚§ãƒ–ãƒšãƒ¼ã‚¸ã§æä¾›ã•れるURLを使ã£ã¦ã€ãƒ­ãƒ¼ã‚«ãƒ«ç·¨é›†ç”¨ã®ãƒªãƒ¢ãƒ¼ãƒˆãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã‚’ダウンロードã™ã‚‹ã«ã¯ã€ã“れを使ã„ã¾ã™ã€‚ + + + + Refresh + æ›´æ–° + + + + Reload all data and update the views + å…¨ã¦ã®ãƒ‡ãƒ¼ã‚¿ã‚’å†èª­ã¿è¾¼ã¿ã—ビューを更新ã™ã‚‹ + + + + F5 + + + + + Clone Database + データベースをクローン + + + + Open Database + データベースを開ã + + + + Open the local copy of this database + ã“ã®ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã®ãƒ­ãƒ¼ã‚«ãƒ«ã‚³ãƒ”ーを開ã + + + + Check out Commit + コミットをãƒã‚§ãƒƒã‚¯ã‚¢ã‚¦ãƒˆ + + + + Download and open this specific commit + ã“ã®ç‰¹å®šã®ã‚³ãƒŸãƒƒãƒˆã‚’ダウンロードã—é–‹ã + + + + Check out Latest Commit + 最新ã®ã‚³ãƒŸãƒƒãƒˆã‚’ãƒã‚§ãƒƒã‚¯ã‚¢ã‚¦ãƒˆ + + + + Check out the latest commit of the current branch + ç¾åœ¨ã®ãƒ–ランãƒã®æœ€æ–°ã®ã‚³ãƒŸãƒƒãƒˆã‚’ãƒã‚§ãƒƒã‚¯ã‚¢ã‚¦ãƒˆ + + + + Save Revision to File + リヴィジョンをファイルã«ä¿å­˜ + + + + Saves the selected revision of the database to another file + データベースã®é¸æŠžã—ãŸãƒªãƒ´ã‚£ã‚¸ãƒ§ãƒ³ã‚’ã»ã‹ã®ãƒ•ァイルã«ä¿å­˜ + + + + Upload Database + データベースをアップロード + + + + Upload this database as a new commit + ã“ã®ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã‚’æ–°ã—ã„コミットã¨ã—ã¦ã‚¢ãƒƒãƒ—ロード + + + + <html><head/><body><p>You are currently using a built-in, read-only identity. For uploading your database, you need to configure and use your DBHub.io account.</p><p>No DBHub.io account yet? <a href="https://dbhub.io/"><span style=" text-decoration: underline; color:#007af4;">Create one now</span></a> and import your certificate <a href="#preferences"><span style=" text-decoration: underline; color:#007af4;">here</span></a> to share your databases.</p><p>For online help visit <a href="https://dbhub.io/about"><span style=" text-decoration: underline; color:#007af4;">here</span></a>.</p></body></html> + <html><head/><body><p>ã‚ãªãŸã¯ç¾åœ¨çµ„ã¿è¾¼ã¿ã®èª­ã¿è¾¼ã¿å°‚用ã®ã‚¢ã‚¤ãƒ‡ãƒ³ãƒ†ã‚£ãƒ†ã‚£ãƒ¼ã‚’使用ã—ã¦ã„ã¾ã™ã€‚ã‚ãªãŸã®ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã‚’アップロードã™ã‚‹ã«ã¯ã€ã‚ãªãŸã® DBHub.io アカウントを設定ã—使ã†å¿…è¦ãŒã‚りã¾ã™ã€‚</p><p>DBHub.io ã®ã‚¢ã‚«ã‚¦ãƒ³ãƒˆãŒã¾ã ãªã„? <a href="https://dbhub.io/"><span style=" text-decoration: underline; color:#007af4;">今ã™ãアカウントを作り</span></a>ã€ã‚ãªãŸã®è¨¼æ˜Žæ›¸ã‚’<a href="#preferences"><span style=" text-decoration: underline; color:#007af4;">ã“ã“ã‹ã‚‰</span></a>インãƒãƒ¼ãƒˆã—ã¦ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã‚’共有ã—ã¦ãã ã•ã„。</p><p>オンラインã®ãƒ˜ãƒ«ãƒ—ã¯<a href="https://dbhub.io/about"><span style=" text-decoration: underline; color:#007af4;">ã“ã“</span></a>を見ã¦ãã ã•ã„。</p></body></html> + + + + Back + 戻る + + + + Select an identity to connect + 接続ã™ã‚‹ã‚¢ã‚¤ãƒ‡ãƒ³ãƒ†ã‚£ãƒ†ã‚£ãƒ¼ã‚’é¸æŠž + + + + Public + 公開 + + + + This downloads a database from a remote server for local editing. +Please enter the URL to clone from. You can generate this URL by +clicking the 'Clone Database in DB4S' button on the web page +of the database. + ã“れã¯ãƒ­ãƒ¼ã‚«ãƒ«ç·¨é›†ç”¨ã«ãƒªãƒ¢ãƒ¼ãƒˆã‚µãƒ¼ãƒãƒ¼ã‹ã‚‰ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã‚’ダウンロードã—ã¾ã™ã€‚ +クローン元ã®URLを入力ã—ã¦ãã ã•ã„。ã“ã®URLã¯ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã® +ウェブページã«ã‚ã‚‹ 'Clone Database in DB4S' ボタンを +クリックã—ã¦ç”Ÿæˆã§ãã¾ã™ã€‚ + + + + Invalid URL: The host name does not match the host name of the current identity. + 䏿­£ãªURL: ホストåãŒç¾åœ¨ã®ã‚¢ã‚¤ãƒ‡ãƒ³ãƒ†ã‚£ãƒ†ã‚£ãƒ¼ã®ãƒ›ã‚¹ãƒˆåã¨ä¸€è‡´ã—ã¾ã›ã‚“。 + + + + Invalid URL: No branch name specified. + 䏿­£ãªURL: ブランãƒåãŒæŒ‡å®šã•れã¦ã„ã¾ã›ã‚“。 + + + + Invalid URL: No commit ID specified. + 䏿­£ãªURL: コミットIDãŒæŒ‡å®šã•れã¦ã„ã¾ã›ã‚“。 + + + + You have modified the local clone of the database. Fetching this commit overrides these local changes. +Are you sure you want to proceed? + データベースã®ãƒ­ãƒ¼ã‚«ãƒ«ã‚¯ãƒ­ãƒ¼ãƒ³ãŒç·¨é›†ã•れã¦ã„ã¾ã™ã€‚ã“ã®ã‚³ãƒŸãƒƒãƒˆã‚’フェッãƒã™ã‚‹ã¨ãƒ­ãƒ¼ã‚«ãƒ«ã®å¤‰æ›´ãŒç„¡è¦–ã•れã¾ã™ã€‚ +本当ã«å®Ÿè¡Œã—ã¾ã™ã‹? + + + + The database has unsaved changes. Are you sure you want to push it before saving? + データベースã«ä¿å­˜ã•れã¦ã„ãªã„変更ãŒã‚りã¾ã™ã€‚本当ã«ä¿å­˜å‰ã«ãƒ—ッシュã—ã¾ã™ã‹? + + + + The database you are trying to delete is currently opened. Please close it before deleting. + 削除ã—よã†ã¨ã—ãŸãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã¯ç¾åœ¨é–‹ã‹ã‚Œã¦ã„ã¾ã™ã€‚削除å‰ã«é–‰ã˜ã¦ãã ã•ã„。 + + + + This deletes the local version of this database with all the changes you have not committed yet. Are you sure you want to delete this database? + ã“れã¯ã“ã®ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã®ãƒ­ãƒ¼ã‚«ãƒ«ãƒãƒ¼ã‚¸ãƒ§ãƒ³ã‚’ã¾ã ã‚³ãƒŸãƒƒãƒˆã—ã¦ã„ãªã„変更ã¨å…±ã«å‰Šé™¤ã—ã¾ã™ã€‚本当ã«ã“ã®ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã‚’削除ã—ã¾ã™ã‹? + + + + RemoteLocalFilesModel + + + Name + åå‰ + + + + Branch + ブランム+ + + + Last modified + 最終変更 + + + + Size + サイズ + + + + Commit + コミット + + + + File + ファイル + + + + RemoteModel + + + Name + åå‰ + + + + Commit + コミット + + + + Last modified + 最終変更 + + + + Size + サイズ + + + + Size: + サイズ: + + + + Last Modified: + 最終変更: + + + + Licence: + ライセンス: + + + + Default Branch: + デフォルトブランãƒ: + + + + RemoteNetwork + + + Choose a location to save the file + ファイルをä¿å­˜ã™ã‚‹å ´æ‰€ã‚’é¸æŠž + + + + Error opening remote file at %1. +%2 + %1 ã®ãƒªãƒ¢ãƒ¼ãƒˆãƒ•ァイルを開ãã¨ãã«ã‚¨ãƒ©ãƒ¼. +%2 + + + + Error: Invalid client certificate specified. + エラー: 䏿­£ãªã‚¯ãƒ©ã‚¤ã‚¢ãƒ³ãƒˆè¨¼æ˜Žæ›¸ãŒæŒ‡å®šã•れã¾ã—ãŸã€‚ + + + + Please enter the passphrase for this client certificate in order to authenticate. + ã“ã®ã‚¯ãƒ©ã‚¤ã‚¢ãƒ³ãƒˆè¨¼æ˜Žæ›¸ã‚’確èªã™ã‚‹ãŸã‚パスフレーズを入力ã—ã¦ãã ã•ã„。 + + + + Cancel + キャンセル + + + + Uploading remote database to +%1 + リモートデータベースをã“ã“ã«ã‚¢ãƒƒãƒ—ロード中 +%1 + + + + Downloading remote database from +%1 + リモートデータベースをã“ã“ã‹ã‚‰ãƒ€ã‚¦ãƒ³ãƒ­ãƒ¼ãƒ‰ä¸­ +%1 + + + + + Error: The network is not accessible. + エラー: ãƒãƒƒãƒˆãƒ¯ãƒ¼ã‚¯ã«ã‚¢ã‚¯ã‚»ã‚¹ã§ãã¾ã›ã‚“。 + + + + Error: Cannot open the file for sending. + エラー: é€ä¿¡ã™ã‚‹ãƒ•ァイルを開ã‘ã¾ã›ã‚“。 + + + + RemotePushDialog + + + Push database + データベースをプッシュ + + + + Database na&me to push to + プッシュã™ã‚‹ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã®åå‰(&M) + + + + Commit message + コミットメッセージ + + + + Database licence + データベースライセンス + + + + Public + 公開 + + + + Branch + ブランム+ + + + Force push + 強制プッシュ + + + + Username + ユーザーå + + + + Database will be public. Everyone has read access to it. + データベースを公開ã«ã—ã¾ã™ã€‚ã™ã¹ã¦ã®äººãŒã‚¢ã‚¯ã‚»ã‚¹ã§ãã¾ã™ã€‚ + + + + Database will be private. Only you have access to it. + データベースをéžå…¬é–‹ã«ã—ã¾ã™ã€‚ã‚ãªãŸã ã‘ãŒã‚¢ã‚¯ã‚»ã‚¹ã§ãã¾ã™ã€‚ + + + + Use with care. This can cause remote commits to be deleted. + 注æ„ã—ã¦ä½¿ç”¨ã—ã¦ãã ã•ã„。ã“れã¯ãƒªãƒ¢ãƒ¼ãƒˆã‚³ãƒŸãƒƒãƒˆãŒå‰Šé™¤ã•れるå¯èƒ½æ€§ãŒã‚りã¾ã™ã€‚ + + + + RunSql + + + Execution aborted by user + 実行ã¯ãƒ¦ãƒ¼ã‚¶ãƒ¼ã«ã‚ˆã‚Šä¸­æ­¢ã•れã¾ã—㟠+ + + + , %1 rows affected + , %1 行ã«å½±éŸ¿ã‚’与ãˆã¾ã—㟠+ + + + query executed successfully. Took %1ms%2 + クエリーã®å®Ÿè¡Œã«æˆåŠŸã—ã¾ã—ãŸã€‚ %1ms%2 ã‹ã‹ã‚Šã¾ã—㟠+ + + + executing query + 実行クエリー + + + + SelectItemsPopup + + + A&vailable + 使用å¯èƒ½(&V) + + + + Sele&cted + é¸æŠžæ¸ˆ(&C) + + + + SqlExecutionArea + + + Form + フォーム + + + + Find previous match [Shift+F3] + å‰ã‚’検索 [Shift+F3] + + + + Find previous match with wrapping + ワードラップ込ã¿ã§å‰ã‚’検索 + + + + Shift+F3 + + + + + The found pattern must be a whole word + å˜èªžå˜ä½ã§æ¤œç´¢ã—ã¾ã™ + + + + Whole Words + å˜èªžå˜ä½ + + + + Text pattern to find considering the checks in this frame + ã“ã®ãƒ•レームã§ã®ãƒã‚§ãƒƒã‚¯ãƒœãƒƒã‚¯ã‚¹ã‚’考慮ã—ãŸæ¤œç´¢æ–‡å­—列 + + + + Find in editor + エディター内を検索 + + + + The found pattern must match in letter case + 大/å°æ–‡å­—を区別ã—ã¾ã™ + + + + Case Sensitive + 大/å°æ–‡å­—を区別 + + + + Find next match [Enter, F3] + 次を検索 [Enter, F3] + + + + Find next match with wrapping + ãƒžãƒƒãƒ”ãƒ³ã‚°ã§æ¬¡ã‚’検索 + + + + F3 + + + + + Interpret search pattern as a regular expression + æ­£è¦è¡¨ç¾ã§æ¤œç´¢ + + + + <html><head/><body><p>When checked, the pattern to find is interpreted as a UNIX regular expression. See <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>.</p></body></html> + <html><head/><body><p>設定ã™ã‚‹ã¨ã€æ¤œç´¢æ¡ä»¶ã¯UNIXæ­£è¦è¡¨ç¾ã¨è§£é‡ˆã•れã¾ã™ã€‚以下をå‚ç…§ <a href="https://ja.wikibooks.org/wiki/%E6%AD%A3%E8%A6%8F%E8%A1%A8%E7%8F%BE">Wikibooksã®æ­£è¦è¡¨ç¾</a>。</p></body></html> + + + + Regular Expression + æ­£è¦è¡¨ç¾ + + + + + Close Find Bar + 検索ãƒãƒ¼ã‚’é–‰ã˜ã‚‹ + + + + <html><head/><body><p>Results of the last executed statements.</p><p>You may want to collapse this panel and use the <span style=" font-style:italic;">SQL Log</span> dock with <span style=" font-style:italic;">User</span> selection instead.</p></body></html> + <html><head/><body><p>最後ã«å®Ÿè¡Œã—ãŸæ–‡ã®çµæžœã€‚</p><p>ã“ã®ãƒ‘ãƒãƒ«ã‚’折りãŸãŸã‚“ã§ã€<span style=" font-style:italic;">SQL Log</span>ドックã§<span style=" font-style:italic;">ユーザー</span>ã‚’é¸æŠžã—ã¦è¡¨ç¤ºã•ã›ã‚‹ã“ã¨ã‚‚ã§ãã¾ã™ã€‚</p></body></html> + + + + This field shows the results and status codes of the last executed statements. + ã“ã®ãƒ•ィールドã«ã¯æœ€å¾Œã«å®Ÿè¡Œã—ãŸæ–‡ã®çµæžœã¨ã‚¹ãƒ†ãƒ¼ã‚¿ã‚¹ã‚³ãƒ¼ãƒ‰ãŒè¡¨ç¤ºã•れã¾ã™ã€‚ + + + + Results of the last executed statements + 最後ã«å®Ÿè¡Œã—ãŸæ–‡ã®çµæžœ + + + + Couldn't read file: %1. + ファイルを読ã‚ã¾ã›ã‚“: %1. + + + + + Couldn't save file: %1. + ファイルをä¿å­˜ã§ãã¾ã›ã‚“: %1. + + + + Your changes will be lost when reloading it! + å†èª­ã¿è¾¼ã¿ã™ã‚‹ã¨å¤‰æ›´ãŒå¤±ã‚れã¾ã™! + + + + The file "%1" was modified by another program. Do you want to reload it?%2 + ファイル "%1" ã¯ä»–ã®ãƒ—ログラムã«ã‚ˆã£ã¦å¤‰æ›´ã•れã¾ã—ãŸã€‚å†èª­ã¿è¾¼ã¿ã—ã¾ã™ã‹?%2 + + + + SqlTextEdit + + + Ctrl+/ + + + + + SqlUiLexer + + + (X) The abs(X) function returns the absolute value of the numeric argument X. + (X) abs(X) 関数ã¯ã€æ•°å€¤ã§ã‚る引数 X ã®çµ¶å¯¾å€¤ã‚’è¿”ã—ã¾ã™ã€‚ + + + + () The changes() function returns the number of database rows that were changed or inserted or deleted by the most recently completed INSERT, DELETE, or UPDATE statement. + () changes() 関数ã¯ã€æœ€å¾Œã«æˆåŠŸã—㟠INSERT, DELETE, UPDATE æ–‡ã§ã€å¤‰æ›´ã€æŒ¿å…¥ã€å‰Šé™¤ã•れãŸãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã®è¡Œæ•°ã‚’è¿”ã—ã¾ã™ã€‚ + + + + (X1,X2,...) The char(X1,X2,...,XN) function returns a string composed of characters having the unicode code point values of integers X1 through XN, respectively. + (X1,X2,...) char(X1,X2,...,XN) 関数ã¯ã€ãれãžã‚Œã®æ–‡å­—㌠Unicode 符å·ä½ç½®ã§æ•´æ•°å€¤ X1 ã‹ã‚‰ XN ã‚’æŒã¤æ–‡å­—列を返ã—ã¾ã™ã€‚ + + + + (X,Y,...) The coalesce() function returns a copy of its first non-NULL argument, or NULL if all arguments are NULL + (X,Y,...) coalesce() 関数㯠NULL ã§ãªã„引数ã®ã†ã¡ã€æœ€ã‚‚å·¦ã®å¼•æ•°ã®ã‚³ãƒ”ーを返ã—ã¾ã™ã€‚ã™ã¹ã¦ã®å¼•数㌠NULL ãªã‚‰ã°ã€NULL ã‚’è¿”ã—ã¾ã™ + + + + (X,Y) The glob(X,Y) function is equivalent to the expression "Y GLOB X". + (X,Y) glob(X,Y) é–¢æ•°ã¯æ¬¡ã®å¼ã¨åŒå€¤ã§ã™ã€‚ "Y GLOB X". + + + + (X,Y) The ifnull() function returns a copy of its first non-NULL argument, or NULL if both arguments are NULL. + (X,Y) ifnull() 関数㯠NULL ã§ãªã„引数ã®ã†ã¡ã€æœ€ã‚‚å·¦ã®å¼•æ•°ã®ã‚³ãƒ”ーを返ã—ã¾ã™ã€‚両方ã®å¼•数㌠NULL ãªã‚‰ã°ã€NULL ã‚’è¿”ã—ã¾ã™ã€‚ + + + + (X,Y) The instr(X,Y) function finds the first occurrence of string Y within string X and returns the number of prior characters plus 1, or 0 if Y is nowhere found within X. + (X,Y) instr(X,Y) é–¢æ•°ã¯æ–‡å­—列 X 内ã«ã‚る最åˆã®æ–‡å­—列 Y を検索ã—ã€ãã®å‰ã®æ–‡å­—æ•°ã«1を加ãˆãŸå€¤ã‚’è¿”ã—ã¾ã™ã€‚X ã« Y ãŒãªã„å ´åˆã¯0ã‚’è¿”ã—ã¾ã™ã€‚ + + + + (X) The hex() function interprets its argument as a BLOB and returns a string which is the upper-case hexadecimal rendering of the content of that blob. + (X) hex() 関数ã¯å¼•æ•°ã‚’ BLOB ã¨è§£é‡ˆã—ã€ãã®ä¸­èº«ã‚’大文字ã®åå…­é€²æ•°ã®æ–‡å­—列ã¨ã—ã¦è¿”ã—ã¾ã™ã€‚ + + + + () The last_insert_rowid() function returns the ROWID of the last row insert from the database connection which invoked the function. + () last_insert_rowid() 関数ã¯ã€ã“ã®é–¢æ•°ã‚’呼ã³å‡ºã—ãŸãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹æŽ¥ç¶šãŒæœ€å¾Œã« INSERT ã—ãŸè¡Œã® ROWID ã‚’è¿”ã—ã¾ã™ã€‚of the last row insert from the database connection which invoked the function. + + + + (X) For a string value X, the length(X) function returns the number of characters (not bytes) in X prior to the first NUL character. + (X) 文字列 X ã«å¯¾ã—ã€length(X) 関数ã¯ã€æœ€åˆã® NULL 文字ã®å‰ã«ã‚る文字数(ãƒã‚¤ãƒˆæ•°ã§ãªã)ã‚’è¿”ã—ã¾ã™ã€‚ + + + + (X,Y) The like() function is used to implement the "Y LIKE X" expression. + (X,Y) like() 関数㯠"Y LIKE X" å¼ã¨åŒå€¤ã§ã™ã€‚ + + + + (X,Y,Z) The like() function is used to implement the "Y LIKE X ESCAPE Z" expression. + (X,Y,Z) like() 関数㯠"Y LIKE X ESCAPE Z" å¼ã¨åŒå€¤ã§ã™ã€‚ + + + + (X) The load_extension(X) function loads SQLite extensions out of the shared library file named X. +Use of this function must be authorized from Preferences. + (X) load_extension(X) 関数ã¯ã€åå‰ãŒ X ã®å…±æœ‰ãƒ©ã‚¤ãƒ–ラリã‹ã‚‰ã™ãã« SQLite 拡張を読ã¿è¾¼ã¿ã¾ã™ã€‚. +ã“ã®é–¢æ•°ã®ä½¿ç”¨ã«ã¯ã€è¨­å®šãƒ€ã‚¤ã‚¢ãƒ­ã‚°ã‹ã‚‰ã®èªè¨¼ãŒå¿…è¦ã§ã™ã€‚ + + + + (X,Y) The load_extension(X) function loads SQLite extensions out of the shared library file named X using the entry point Y. +Use of this function must be authorized from Preferences. + (X) load_extension(X,Y) 関数ã¯ã€åå‰ãŒ X ã®å…±æœ‰ãƒ©ã‚¤ãƒ–ラリã®ã‚¨ãƒ³ãƒˆãƒªãƒ¼ãƒã‚¤ãƒ³ãƒˆ Y ã‹ã‚‰ã™ãã« SQLite 拡張を読ã¿è¾¼ã¿ã¾ã™ã€‚. +ã“ã®é–¢æ•°ã®ä½¿ç”¨ã«ã¯ã€è¨­å®šãƒ€ã‚¤ã‚¢ãƒ­ã‚°ã‹ã‚‰ã®èªè¨¼ãŒå¿…è¦ã§ã™ã€‚ + + + + (X) The lower(X) function returns a copy of string X with all ASCII characters converted to lower case. + (X) lower(X) 関数ã¯ã€ã™ã¹ã¦ ASCII 文字ã§ã‚る文字列 X ã‚’ã€ã™ã¹ã¦å°æ–‡å­—ã«å¤‰æ›ã—ãŸæ–‡å­—列を返ã—ã¾ã™ã€‚ + + + + (X) ltrim(X) removes spaces from the left side of X. + (X) ltrim(X) 関数ã¯ã€X ã®å·¦ç«¯ã«ã‚る空白をå–り除ãã¾ã™ã€‚ + + + + (X,Y) The ltrim(X,Y) function returns a string formed by removing any and all characters that appear in Y from the left side of X. + (X,Y) ltrim(X,Y)関数ã¯ã€X ã®å·¦ç«¯ã‹ã‚‰ã€ Y ã«å«ã¾ã‚Œã‚‹æ–‡å­—ã‚’ã™ã¹ã¦å–り除ã„ãŸæ–‡å­—列を返ã—ã¾ã™ã€‚ + + + + (X,Y,...) The multi-argument max() function returns the argument with the maximum value, or return NULL if any argument is NULL. + (X,Y,...) 複数ã®å¼•æ•°ã‚’æŒã¤ max() 関数ã¯å¼•æ•°ã®æœ€å¤§å€¤ã‚’è¿”ã—ã¾ã™ã€‚引数㫠NULL ãŒå«ã¾ã‚Œã¦ã„ã‚‹å ´åˆã¯ NULL ã‚’è¿”ã—ã¾ã™ã€‚ + + + + (X,Y,...) The multi-argument min() function returns the argument with the minimum value. + (X,Y,...) 複数ã®å¼•æ•°ã‚’æŒã¤ min() 関数ã¯å¼•æ•°ã®æœ€å°å€¤ã‚’è¿”ã—ã¾ã™ã€‚引数㫠NULL ãŒå«ã¾ã‚Œã¦ã„ã‚‹å ´åˆã¯ NULL ã‚’è¿”ã—ã¾ã™ã€‚ + + + + (X,Y) The nullif(X,Y) function returns its first argument if the arguments are different and NULL if the arguments are the same. + (X,Y) nullif(X,Y) 関数ã¯ã€äºŒã¤ã®å¼•æ•°ãŒé•ã†å ´åˆç¬¬ä¸€å¼•æ•°ã‚’ã€åŒã˜å ´åˆã¯ NULL ã‚’è¿”ã—ã¾ã™ã€‚ + + + + (FORMAT,...) The printf(FORMAT,...) SQL function works like the sqlite3_mprintf() C-language function and the printf() function from the standard C library. + (FORMAT,...) printf(FORMAT,...) SQL 関数ã¯ã€C言語㮠sqlite3_mprintf() é–¢æ•°ã‚„ã€æ¨™æº–Cライブラリー㮠printf() 関数ã®ã‚ˆã†ã«å‹•作ã—ã¾ã™ã€‚ + + + + (X) The quote(X) function returns the text of an SQL literal which is the value of its argument suitable for inclusion into an SQL statement. + (X) quote(X) 関数ã¯ã€å¼•æ•°ã‚’SQLæ–‡ã«å«ã‚ã‚‹ã®ã«é©ã—ãŸSQLãƒªãƒ†ãƒ©ãƒ«ã®æ–‡å­—ã«ã—ã¦è¿”ã—ã¾ã™ã€‚ + + + + () The random() function returns a pseudo-random integer between -9223372036854775808 and +9223372036854775807. + () random() 関数ã¯ã€ç¯„囲㌠-9223372036854775808 ã‹ã‚‰ +9223372036854775807 ã®æ•´æ•°ã§ã‚る疑似乱数を返ã—ã¾ã™ã€‚ + + + + (N) The randomblob(N) function return an N-byte blob containing pseudo-random bytes. + (N) randomblob(N) 関数ã¯ã€ç–‘ä¼¼ä¹±æ•°ã§æ§‹æˆã•れ㟠N ãƒã‚¤ãƒˆã® BLOB ã‚’è¿”ã—ã¾ã™ã€‚function return an N-byte blob containing pseudo-random bytes. + + + + (X,Y,Z) The replace(X,Y,Z) function returns a string formed by substituting string Z for every occurrence of string Y in string X. + (X,Y,Z) replace(X,Y,Z) 関数ã¯ã€æ–‡å­—列 X ã«å«ã¾ã‚Œã‚‹æ–‡å­—列 Y ã‚’ã™ã¹ã¦æ–‡å­—列 Z ã«ç½®ãæ›ãˆã¦è¿”ã—ã¾ã™ã€‚ + + + + (X) The round(X) function returns a floating-point value X rounded to zero digits to the right of the decimal point. + (X) round(X) 関数ã¯ã€æµ®å‹•å°æ•°ç‚¹æ•° X ã®å°æ•°ç‚¹ä»¥ä¸‹ã‚’å››æ¨äº”å…¥ã—ã¦è¿”ã—ã¾ã™ã€‚ + + + + (X,Y) The round(X,Y) function returns a floating-point value X rounded to Y digits to the right of the decimal point. + (X,Y) round(X,Y) 関数ã¯ã€æµ®å‹•å°æ•°ç‚¹æ•° X ã‚’å°æ•°ç‚¹ç¬¬ Y ä½ã¾ã§ã«ãªã‚‹ã‚ˆã†ã«å››æ¨äº”å…¥ã—ã¦è¿”ã—ã¾ã™ã€‚ + + + + (X) rtrim(X) removes spaces from the right side of X. + (X) rtrim(X) 関数ã¯ã€X ã®å³ç«¯ã«ã‚る空白をå–り除ãã¾ã™ã€‚ + + + + (X,Y) The rtrim(X,Y) function returns a string formed by removing any and all characters that appear in Y from the right side of X. + (X,Y) rtrim(X,Y) 関数ã¯ã€X ã®å³ç«¯ã‹ã‚‰ã€ Y ã«å«ã¾ã‚Œã‚‹æ–‡å­—ã‚’ã™ã¹ã¦å–り除ã„ãŸæ–‡å­—列を返ã—ã¾ã™ã€‚ + + + + (X) The soundex(X) function returns a string that is the soundex encoding of the string X. + (X) soundex(X) 関数ã¯ã€æ–‡å­—列 X ã‚’ soundex ã«ã‚¨ãƒ³ã‚³ãƒ¼ãƒ‰ã—ãŸæ–‡å­—列を返ã—ã¾ã™ã€‚ + + + + (X,Y) substr(X,Y) returns all characters through the end of the string X beginning with the Y-th. + (X,Y) substr(X,Y) 関数ã¯ã€æ–‡å­—列 Xã®ã€å…ˆé ­ã‹ã‚‰ Y 番目ã‹ã‚‰æœ«å°¾ã¾ã§ã®æ–‡å­—列を返ã—ã¾ã™ã€‚ + + + + (X,Y,Z) The substr(X,Y,Z) function returns a substring of input string X that begins with the Y-th character and which is Z characters long. + (X,Y,Z) substr(X,Y,Z) 関数ã¯ã€æ–‡å­—列 X ã®ã€å…ˆé ­ã‹ã‚‰ Y 番目ã‹ã‚‰ Z æ–‡å­—ã®æ–‡å­—列を返ã—ã¾ã™ã€‚ + + + + () The total_changes() function returns the number of row changes caused by INSERT, UPDATE or DELETE statements since the current database connection was opened. + () total_changes() 関数ã¯ã€ç¾åœ¨é–‹ã‹ã‚ŒãŸæŽ¥ç¶šã®ã‚るデータベースã«ãŠã„ã¦ã€INSERTã€UPDATEã€DELETEã§å¤‰æ›´ã•れãŸè¡Œæ•°ã‚’è¿”ã—ã¾ã™ã€‚ returns the number of row changes caused by INSERT, UPDATE or DELETE statements since the current database connection was opened. + + + + (X) trim(X) removes spaces from both ends of X. + (X) trim(X) 関数ã¯ã€X ã®ä¸¡ç«¯ã«ã‚る空白をå–り除ãã¾ã™ã€‚ + + + + (X,Y) The trim(X,Y) function returns a string formed by removing any and all characters that appear in Y from both ends of X. + (X,Y) trim(X,Y) 関数ã¯ã€X ã®ä¸¡ç«¯ã‹ã‚‰ã€ Y ã«å«ã¾ã‚Œã‚‹æ–‡å­—ã‚’ã™ã¹ã¦å–り除ã„ãŸæ–‡å­—列を返ã—ã¾ã™ã€‚ + + + + (X) The typeof(X) function returns a string that indicates the datatype of the expression X. + (X) typeof(X) 関数ã¯ã€å¼ X ã®ãƒ‡ãƒ¼ã‚¿åž‹ã‚’ç¤ºã™æ–‡å­—列を返ã—ã¾ã™ã€‚ + + + + (X) The unicode(X) function returns the numeric unicode code point corresponding to the first character of the string X. + (X) unicode(X) 関数ã¯ã€æ–‡å­—列 X ã®æœ€åˆã®æ–‡å­—ã«å¯¾å¿œã™ã‚‹ Unicode 符å·ä½ç½®ã‚’è¿”ã—ã¾ã™ã€‚ + + + + (X) The upper(X) function returns a copy of input string X in which all lower-case ASCII characters are converted to their upper-case equivalent. + (X) upper(X) 関数ã¯ã€ã™ã¹ã¦ ASCII 文字ã§ã‚る文字列 X ã‚’ã€ã™ã¹ã¦å¤§æ–‡å­—ã«å¤‰æ›ã—ãŸæ–‡å­—列を返ã—ã¾ã™ã€‚ + + + + (N) The zeroblob(N) function returns a BLOB consisting of N bytes of 0x00. + (N) zeroblob(N) 関数ã¯ã€ã™ã¹ã¦ 0x00 ã§åŸ‹ã‚られãŸã€N ãƒã‚¤ãƒˆã® BLOB ã‚’è¿”ã—ã¾ã™ã€‚ + + + + + + + (timestring,modifier,modifier,...) + (時刻文字列, 修飾å­, 修飾å­,...) + + + + (format,timestring,modifier,modifier,...) + (フォーマット, 時刻文字列, 修飾å­, 修飾å­,...) + + + + (X) The avg() function returns the average value of all non-NULL X within a group. + (X) avg() 関数ã¯ã€ã‚°ãƒ«ãƒ¼ãƒ—内ã®éžNULLãªå€¤ã®å¹³å‡ã‚’è¿”ã—ã¾ã™ã€‚ + + + + (X) The count(X) function returns a count of the number of times that X is not NULL in a group. + (X) count(X) 関数ã¯ã‚°ãƒ«ãƒ¼ãƒ—内ã«ã‚ã‚‹ã€NULLã§ãªã„ X ã®ä»¶æ•°ã‚’è¿”ã—ã¾ã™ã€‚ + + + + (X) The group_concat() function returns a string which is the concatenation of all non-NULL values of X. + (X) group_concat() 関数ã¯ã€éžNULLãªã™ã¹ã¦ã® X を連çµã—ãŸæ–‡å­—列を返ã—ã¾ã™ã€‚ + + + + (X,Y) The group_concat() function returns a string which is the concatenation of all non-NULL values of X. If parameter Y is present then it is used as the separator between instances of X. + (X,Y) group_concat() 関数ã¯ã€éžNULLãªã™ã¹ã¦ã® X を連çµã—ãŸæ–‡å­—列を返ã—ã¾ã™ã€‚ã‚‚ã—ã€å¼•æ•° Y ãŒå­˜åœ¨ã™ã‚‹ãªã‚‰ã°ã€X を連çµã™ã‚‹ã¨ãã®åŒºåˆ‡ã‚Šæ–‡å­—ã¨ã—ã¦ä½¿ç”¨ã—ã¾ã™ã€‚ + + + + (X) The max() aggregate function returns the maximum value of all values in the group. + (X) max() 集計関数ã¯ã€ã‚°ãƒ«ãƒ¼ãƒ—内ã®(éžNULLã§ã‚ã‚‹)最大値を返ã—ã¾ã™ã€‚ + + + + (X) The min() aggregate function returns the minimum non-NULL value of all values in the group. + (X) min() 集計関数ã¯ã€ã‚°ãƒ«ãƒ¼ãƒ—内ã®(éžNULLã§ã‚ã‚‹)最å°å€¤ã‚’è¿”ã—ã¾ã™ã€‚ + + + + + (X) The sum() and total() aggregate functions return sum of all non-NULL values in the group. + (X) sum() 㨠total() 集計関数ã¯ã€ã‚°ãƒ«ãƒ¼ãƒ—内ã®éžNULLãªå€¤ã®åˆè¨ˆã‚’è¿”ã—ã¾ã™ã€‚ + + + + () The number of the row within the current partition. Rows are numbered starting from 1 in the order defined by the ORDER BY clause in the window definition, or in arbitrary order otherwise. + () ç¾åœ¨ã®åˆ†å‰²å†…ã®è¡Œç•ªå·ã€‚行ã¯ã€ã‚¦ã‚£ãƒ³ãƒ‰ã‚¦å®šç¾©ã® ORDER BY å¥ã‚„ãれ以外ã®ä»»æ„ã®é †åºã«å¾“ã„ã€1 ã‹ã‚‰é †ã«ç•ªå·ä»˜ã‘ã•れã¾ã™ã€‚ + + + + () The row_number() of the first peer in each group - the rank of the current row with gaps. If there is no ORDER BY clause, then all rows are considered peers and this function always returns 1. + () å„グループã®é †ä½ - åŒå€¤ã¯åŒé †ä½ã§ã€æ¬¡ã®å€¤ã¯é‡è¤‡åˆ†ã ã‘é †ä½ãŒãšã‚Œã¾ã™ã€‚ã‚‚ã—ã€ORDER BY å¥ãŒãªã‘れã°ã€ã™ã¹ã¦ã®è¡Œã‚’åŒé †ä½ã¨ã¿ãªã—ã€å¸¸ã« 1 ã‚’è¿”ã—ã¾ã™ã€‚ + + + + () The number of the current row's peer group within its partition - the rank of the current row without gaps. Partitions are numbered starting from 1 in the order defined by the ORDER BY clause in the window definition. If there is no ORDER BY clause, then all rows are considered peers and this function always returns 1. + () å„グループã®é †ä½ - åŒå€¤ã¯åŒé †ä½ã§ã€æ¬¡ã®å€¤ã¯é‡è¤‡ã«é–¢ã‚らãšå‰ã®é †ä½+1ã«ãªã‚Šã¾ã™ã€‚パーティションã¯ã‚¦ã‚£ãƒ³ãƒ‰ã‚¦å®šç¾©ã® ORDER BY å¥ã‚„ãれ以外ã®ä»»æ„ã®é †åºã«å¾“ã„ã€1 ã‹ã‚‰é †ã«ç•ªå·ä»˜ã‘ã•れã¾ã™ã€‚ã‚‚ã—ã€ORDER BY å¥ãŒãªã‘れã°ã€ã™ã¹ã¦ã®è¡Œã‚’åŒé †ä½ã¨ã¿ãªã—ã€å¸¸ã« 1 ã‚’è¿”ã—ã¾ã™ã€‚ + + + + () Despite the name, this function always returns a value between 0.0 and 1.0 equal to (rank - 1)/(partition-rows - 1), where rank is the value returned by built-in window function rank() and partition-rows is the total number of rows in the partition. If the partition contains only one row, this function returns 0.0. + () ãã®åå‰ã«ã‚‚é–¢ã‚らãšã€ã“ã®é–¢æ•°ã¯å¸¸ã« 0.0 ã‹ã‚‰ 1.0 ã®å€¤ã‚’è¿”ã—ã¾ã™ã€‚ã“ã®å€¤ã¯ã€(rank - 1)/(パーティション行数 - 1) ã§ã™ã€‚ã“ã“ã§ã€rank ã¯çµ„ã¿è¾¼ã¿ã‚¦ã‚£ãƒ³ãƒ‰ã‚¦é–¢æ•°ã® rank()ã€ãƒ‘ーティション行数ã¯ãƒ‘ーティション内ã®è¡Œã®æ•°ã§ã™ã€‚ã‚‚ã—ã€ãƒ‘ーティションã«1行ã—ã‹å«ã¾ã‚Œã¦ã„ãªã‘れã°ã€ã“ã®é–¢æ•°ã¯ 0.0 ã‚’è¿”ã—ã¾ã™ã€‚ + + + + () The cumulative distribution. Calculated as row-number/partition-rows, where row-number is the value returned by row_number() for the last peer in the group and partition-rows the number of rows in the partition. + () ç´¯ç©åˆ†å¸ƒã€‚(行番å·)/(パーティション行数) ã§è¨ˆç®—ã•れã¾ã™ã€‚ã“ã“ã§è¡Œç•ªå·ã¯ã‚°ãƒ«ãƒ¼ãƒ—内㧠row_number() ã§è¿”ã•れãŸå€¤ã€ãƒ‘ーティション行数ã¯ãƒ‘ーティション内ã®è¡Œã®æ•°ã§ã™ã€‚ + + + + (N) Argument N is handled as an integer. This function divides the partition into N groups as evenly as possible and assigns an integer between 1 and N to each group, in the order defined by the ORDER BY clause, or in arbitrary order otherwise. If necessary, larger groups occur first. This function returns the integer value assigned to the group that the current row is a part of. + (N) 引数 N ã¯INTEGERã¨ã—ã¦æ‰±ã‚れã¾ã™ã€‚ã“ã®é–¢æ•°ã¯ãƒ‘ーティションを ORDER BY å¥ã‚„ãれ以外ã®ä»»æ„ã®é †åºã«å¾“ã„ N 個ã®ã‚°ãƒ«ãƒ¼ãƒ—ã«å¯èƒ½ãªé™ã‚Šç­‰åˆ†ã—ã€ãれãžã‚Œã®ã‚°ãƒ«ãƒ¼ãƒ—ã« 1 ã‹ã‚‰ N ã®INTEGERã‚’ã¤ã‘ã¾ã™ã€‚å¿…è¦ãŒã‚れã°ã€å…ˆé ­ã®ã»ã†ã«ã‚るグループã®ä»¶æ•°ã‚’多ãã™ã‚‹ã‚ˆã†ã«å‰²ã‚Šå½“ã¦ã‚‰ã‚Œã¾ã™ã€‚ã“ã®é–¢æ•°ã¯ç¾åœ¨ã®è¡ŒãŒå«ã¾ã‚Œã‚‹ã‚°ãƒ«ãƒ¼ãƒ—ã«å‰²ã‚Šå½“ã¦ã‚‰ã‚ŒãŸINTEGERã‚’è¿”ã—ã¾ã™ã€‚ + + + + (expr) Returns the result of evaluating expression expr against the previous row in the partition. Or, if there is no previous row (because the current row is the first), NULL. + (expr) パーティション内ã®å‰ã®è¡Œã«å¯¾ã—ã¦å¼ expr を評価ã—ãŸçµæžœã‚’è¿”ã—ã¾ã™ã€‚(先頭行ã®ãŸã‚)å‰ã®è¡ŒãŒãªã‘れã°ã€NULLã‚’è¿”ã—ã¾ã™ã€‚ + + + + (expr,offset) If the offset argument is provided, then it must be a non-negative integer. In this case the value returned is the result of evaluating expr against the row offset rows before the current row within the partition. If offset is 0, then expr is evaluated against the current row. If there is no row offset rows before the current row, NULL is returned. + (expr,offset) 引数 offset ãŒä¸Žãˆã‚‰ã‚Œã‚‹å ´åˆã€éžè² ã®INTEGERã§ã‚ã‚‹å¿…è¦ãŒã‚りã¾ã™ã€‚ã“ã®å ´åˆã€ãƒ‘ーティション内㮠offset ã ã‘å‰ã®è¡Œã«å¯¾ã—ã¦å¼ expr を評価ã—ãŸçµæžœã‚’è¿”ã—ã¾ã™ã€‚offset ㌠0 ãªã‚‰ã°ã€ç¾åœ¨è¡Œã«å¯¾ã—ã¦è©•価ã—ã¾ã™ã€‚å‰ã®è¡ŒãŒãªã‘れã°ã€NULLã‚’è¿”ã—ã¾ã™ã€‚ + + + + + (expr,offset,default) If default is also provided, then it is returned instead of NULL if the row identified by offset does not exist. + (expr,offset,default) default ãŒä¸Žãˆã‚‰ã‚Œã‚‹å ´åˆã€è©²å½“ã®è¡ŒãŒãªã‘れã°ã€NULL ã®ä»£ã‚り㫠defaul 値を返ã—ã¾ã™ã€‚ + + + + (expr) Returns the result of evaluating expression expr against the next row in the partition. Or, if there is no next row (because the current row is the last), NULL. + (expr) ãƒ‘ãƒ¼ãƒ†ã‚£ã‚·ãƒ§ãƒ³å†…ã®æ¬¡ã®è¡Œã«å¯¾ã—ã¦å¼ expr を評価ã—ãŸçµæžœã‚’è¿”ã—ã¾ã™ã€‚(最終行ã®ãŸã‚)次ã®è¡ŒãŒãªã‘れã°ã€NULLã‚’è¿”ã—ã¾ã™ã€‚ + + + + (expr,offset) If the offset argument is provided, then it must be a non-negative integer. In this case the value returned is the result of evaluating expr against the row offset rows after the current row within the partition. If offset is 0, then expr is evaluated against the current row. If there is no row offset rows after the current row, NULL is returned. + (expr,offset) 引数 offset ãŒä¸Žãˆã‚‰ã‚Œã‚‹å ´åˆã€éžè² ã®INTEGERã§ã‚ã‚‹å¿…è¦ãŒã‚りã¾ã™ã€‚ã“ã®å ´åˆã€ãƒ‘ーティション内㮠offset ã ã‘次ã®è¡Œã«å¯¾ã—ã¦å¼ expr を評価ã—ãŸçµæžœã‚’è¿”ã—ã¾ã™ã€‚offset ㌠0 ãªã‚‰ã°ã€ç¾åœ¨è¡Œã«å¯¾ã—ã¦è©•価ã—ã¾ã™ã€‚次ã®è¡ŒãŒãªã‘れã°ã€NULLã‚’è¿”ã—ã¾ã™ã€‚ + + + + (expr) This built-in window function calculates the window frame for each row in the same way as an aggregate window function. It returns the value of expr evaluated against the first row in the window frame for each row. + (expr) ã“ã®çµ„ã¿è¾¼ã¿ã‚¦ã‚£ãƒ³ãƒ‰ã‚¦é–¢æ•°ã¯ã€åŒã˜é›†è¨ˆã‚¦ã‚£ãƒ³ãƒ‰ã‚¦é–¢æ•°ã‚’使ã£ã¦ãれãžã‚Œã®è¡Œã®ã‚¦ã‚£ãƒ³ãƒ‰ã‚¦ãƒ•レームを計算ã—ã¾ã™ã€‚å„行ã®ã‚¦ã‚£ãƒ³ãƒ‰ã‚¦ãƒ•ãƒ¬ãƒ¼ãƒ ã®æœ€åˆã®è¡Œã«å¯¾ã—ã¦è©•価ã•れる expr ã®å€¤ã‚’è¿”ã—ã¾ã™ã€‚ + + + + (expr) This built-in window function calculates the window frame for each row in the same way as an aggregate window function. It returns the value of expr evaluated against the last row in the window frame for each row. + (expr) ã“ã®çµ„ã¿è¾¼ã¿ã‚¦ã‚£ãƒ³ãƒ‰ã‚¦é–¢æ•°ã¯ã€åŒã˜é›†è¨ˆã‚¦ã‚£ãƒ³ãƒ‰ã‚¦é–¢æ•°ã‚’使ã£ã¦ãれãžã‚Œã®è¡Œã®ã‚¦ã‚£ãƒ³ãƒ‰ã‚¦ãƒ•レームを計算ã—ã¾ã™ã€‚å„行ã®ã‚¦ã‚£ãƒ³ãƒ‰ã‚¦ãƒ•ãƒ¬ãƒ¼ãƒ ã®æœ€å¾Œã®è¡Œã«å¯¾ã—ã¦è©•価ã•れる expr ã®å€¤ã‚’è¿”ã—ã¾ã™ã€‚ + + + + (expr,N) This built-in window function calculates the window frame for each row in the same way as an aggregate window function. It returns the value of expr evaluated against the row N of the window frame. Rows are numbered within the window frame starting from 1 in the order defined by the ORDER BY clause if one is present, or in arbitrary order otherwise. If there is no Nth row in the partition, then NULL is returned. + (expr,N) ã“ã®çµ„ã¿è¾¼ã¿ã‚¦ã‚£ãƒ³ãƒ‰ã‚¦é–¢æ•°ã¯ã€åŒã˜é›†è¨ˆã‚¦ã‚£ãƒ³ãƒ‰ã‚¦é–¢æ•°ã‚’使ã£ã¦ãれãžã‚Œã®è¡Œã®ã‚¦ã‚£ãƒ³ãƒ‰ã‚¦ãƒ•レームを計算ã—ã¾ã™ã€‚å„行ã®ã‚¦ã‚£ãƒ³ãƒ‰ã‚¦ãƒ•レーム㮠N 番目ã®è¡Œã«å¯¾ã—ã¦è©•価ã•れる expr ã®å€¤ã‚’è¿”ã—ã¾ã™ã€‚行ã¯ã€ã‚¦ã‚£ãƒ³ãƒ‰ã‚¦å®šç¾©ã® ORDER BY å¥ã‚„ãれ以外ã®ä»»æ„ã®é †åºã«å¾“ã„ã€1 ã‹ã‚‰é †ã«ç•ªå·ä»˜ã‘ã•れã¾ã™ã€‚ N 番目ã®è¡ŒãŒãƒ‘ーティションã«ãªã„å ´åˆã€NULL ãŒè¿”ã•れã¾ã™ã€‚ + + + + SqliteTableModel + + + reading rows + 行を読ã¿è¾¼ã¿ä¸­ + + + + loading... + 読ã¿è¾¼ã¿ä¸­... + + + + References %1(%2) +Hold %3Shift and click to jump there + ã“れをå‚ç…§ %1(%2) +%3Shift ã‚’ä¿æŒã—クリックã§ã‚¸ãƒ£ãƒ³ãƒ— + + + + Error changing data: +%1 + データã®å¤‰æ›´ã§ã‚¨ãƒ©ãƒ¼: +%1 + + + + retrieving list of columns + カラムã®ä¸€è¦§ã‚’å–得中 + + + + Fetching data... + データをå–得中... + + + + + Cancel + キャンセル + + + + TableBrowser + + + Browse Data + データ閲覧 + + + + &Table: + テーブル(&T): + + + + Select a table to browse data + 閲覧ã™ã‚‹ãƒ‡ãƒ¼ã‚¿ã®ãƒ†ãƒ¼ãƒ–ãƒ«ã‚’é¸æŠž + + + + Use this list to select a table to be displayed in the database view + ã“ã®ä¸€è¦§ã‚’使ã£ã¦ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ãƒ“ューã«è¡¨ç¤ºã™ã‚‹ãƒ†ãƒ¼ãƒ–ãƒ«ã‚’é¸æŠž + + + + This is the database table view. You can do the following actions: + - Start writing for editing inline the value. + - Double-click any record to edit its contents in the cell editor window. + - Alt+Del for deleting the cell content to NULL. + - Ctrl+" for duplicating the current record. + - Ctrl+' for copying the value from the cell above. + - Standard selection and copy/paste operations. + ã“れã¯ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ãƒ†ãƒ¼ãƒ–ルã®ãƒ“ューã§ã™ã€‚ä»¥ä¸‹ã®æ“作ãŒã§ãã¾ã™: + - 値をインライン編集ã§ãã¾ã™ã€‚ + - レコードをダブルクリックã™ã‚‹ã¨ã€ã‚»ãƒ«ç·¨é›†ã‚¦ã‚£ãƒ³ãƒ‰ã‚¦ã§å†…容を編集ã§ãã¾ã™ã€‚ + - Alt+Del ã§ã‚»ãƒ«ã®å†…容をNULLã«ã§ãã¾ã™ã€‚ + - Ctrl+" ã§ç¾åœ¨ã®ãƒ¬ã‚³ãƒ¼ãƒ‰ã‚’複製ã§ãã¾ã™ã€‚ + - Ctrl+' ã§ä¸Šã®ã‚»ãƒ«ã®å€¤ã‚’コピーã§ãã¾ã™ã€‚ + - é€šå¸¸ã®æ“作ã§ã€é¸æŠž/コピー/貼り付ã‘ãŒã§ãã¾ã™ã€‚ + + + + Text pattern to find considering the checks in this frame + ã“ã®ãƒ•レームã§ã®ãƒã‚§ãƒƒã‚¯ãƒœãƒƒã‚¯ã‚¹ã‚’考慮ã—ãŸæ¤œç´¢æ–‡å­—列 + + + + Find in table + テーブルを検索 + + + + Find previous match [Shift+F3] + å‰ã‚’検索 [Shift+F3] + + + + Find previous match with wrapping + 折り返ã—ã¦å‰ã‚’検索 + + + + Shift+F3 + + + + + Find next match [Enter, F3] + 次を検索 [Enter, F3] + + + + Find next match with wrapping + 折り返ã—ã¦æ¬¡ã‚’検索 + + + + F3 + + + + + The found pattern must match in letter case + 大/å°æ–‡å­—を区別ã—ã¾ã™ + + + + Case Sensitive + 大/å°æ–‡å­—を区別 + + + + The found pattern must be a whole word + å˜èªžå˜ä½ã§æ¤œç´¢ã—ã¾ã™ + + + + Whole Cell + セル全体ã«ä¸€è‡´ + + + + Interpret search pattern as a regular expression + æ­£è¦è¡¨ç¾ã§æ¤œç´¢ + + + + <html><head/><body><p>When checked, the pattern to find is interpreted as a UNIX regular expression. See <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>.</p></body></html> + <html><head/><body><p>設定ã™ã‚‹ã¨ã€æ¤œç´¢æ¡ä»¶ã¯UNIXæ­£è¦è¡¨ç¾ã¨è§£é‡ˆã•れã¾ã™ã€‚以下をå‚ç…§ <a href="https://ja.wikibooks.org/wiki/%E6%AD%A3%E8%A6%8F%E8%A1%A8%E7%8F%BE">Wikibooksã®æ­£è¦è¡¨ç¾</a>。</p></body></html> + + + + Regular Expression + æ­£è¦è¡¨ç¾ + + + + + Close Find Bar + 検索ãƒãƒ¼ã‚’é–‰ã˜ã‚‹ + + + + Text to replace with + ã“ã®æ–‡å­—列ã§ç½®ãæ›ãˆã‚‹ + + + + Replace with + ç½®æ› + + + + Replace next match + 次ã«ä¸€è‡´ã—ãŸã‚‚ã®ã‚’ç½®ãæ›ãˆ + + + + + Replace + ç½®æ› + + + + Replace all matches + 一致ã—ãŸã‚‚ã®ã™ã¹ã¦ã‚’ç½®ãæ›ãˆ + + + + Replace all + ã™ã¹ã¦ç½®æ› + + + + <html><head/><body><p>Scroll to the beginning</p></body></html> + 先頭㸠+ + + + <html><head/><body><p>Clicking this button navigates to the beginning in the table view above.</p></body></html> + <html><head/><body><p>ã“ã®ãƒœã‚¿ãƒ³ã‚’クリックã™ã‚‹ã¨ã€ä¸Šã®ãƒ†ãƒ¼ãƒ–ルビューを先頭ã¾ã§ç§»å‹•ã—ã¾ã™ã€‚</p></body></html> + + + + |< + |< + + + + Scroll one page upwards + 1ページå‰ã¸ + + + + <html><head/><body><p>Clicking this button navigates one page of records upwards in the table view above.</p></body></html> + <html><head/><body><p>ã“ã®ãƒœã‚¿ãƒ³ã‚’クリックã™ã‚‹ã¨ã€ä¸Šã®ãƒ†ãƒ¼ãƒ–ルビューを1ページå‰ã¸ç§»å‹•ã—ã¾ã™ã€‚</p></body></html> + + + + < + < + + + + 0 - 0 of 0 + 0 - 0 of 0 + + + + Scroll one page downwards + 1ページ後㸠+ + + + <html><head/><body><p>Clicking this button navigates one page of records downwards in the table view above.</p></body></html> + <html><head/><body><p>ã“ã®ãƒœã‚¿ãƒ³ã‚’クリックã™ã‚‹ã¨ã€ä¸Šã®ãƒ†ãƒ¼ãƒ–ルビューを1ページ後ã¸ç§»å‹•ã—ã¾ã™ã€‚</p></body></html> + + + + > + > + + + + Scroll to the end + 末尾㸠+ + + + <html><head/><body><p>Clicking this button navigates up to the end in the table view above.</p></body></html> + <html><head/><body><p>ã“ã®ãƒœã‚¿ãƒ³ã‚’クリックã™ã‚‹ã¨ã€ä¸Šã®ãƒ†ãƒ¼ãƒ–ルビューを末尾ã¾ã§ç§»å‹•ã—ã¾ã™ã€‚</p></body></html> + + + + >| + >| + + + + <html><head/><body><p>Click here to jump to the specified record</p></body></html> + <html><head/><body><p>ã“ã“をクリックã—ã¦æŒ‡å®šã®ãƒ¬ã‚³ãƒ¼ãƒ‰ã¾ã§ç§»å‹•</p></body></html> + + + + <html><head/><body><p>This button is used to navigate to the record number specified in the Go to area.</p></body></html> + <html><head/><body><p>ã“ã®ãƒœã‚¿ãƒ³ã¯ ã“ã“ã¸ç§»å‹• ã®å…¥åŠ›æ¬„ã§æŒ‡å®šã•れãŸç•ªå·ã®ãƒ¬ã‚³ãƒ¼ãƒ‰ã¸ç§»å‹•ã™ã‚‹ãŸã‚ã«ä½¿ç”¨ã—ã¾ã™ã€‚</p></body></html> + + + + Go to: + ã“ã“ã¸ç§»å‹•: + + + + Enter record number to browse + 閲覧ã™ã‚‹ãƒ¬ã‚³ãƒ¼ãƒ‰ã®ç•ªå·ã‚’入力 + + + + Type a record number in this area and click the Go to: button to display the record in the database view + ã“ã®æ¬„ã«ãƒ¬ã‚³ãƒ¼ãƒ‰ã®ç•ªå·ã‚’入力ã—ã€ã“ã“ã¸ç§»å‹•ボタンをクリックã™ã‚‹ã¨ã€ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ãƒ“ューã«ãƒ¬ã‚³ãƒ¼ãƒ‰ãŒè¡¨ç¤ºã•れã¾ã™ + + + + 1 + 1 + + + + Show rowid column + rowidカラムを表示 + + + + Toggle the visibility of the rowid column + rowidカラムã®è¡¨ç¤ºã‚’切り替ãˆã¾ã™ + + + + Unlock view editing + ビューã®ç·¨é›†ã‚’開放 + + + + This unlocks the current view for editing. However, you will need appropriate triggers for editing. + ã“れã¯ç¾åœ¨ã®ãƒ“ューã§ç·¨é›†ã§ãるよã†ã«ã—ã¾ã™ã€‚ã—ã‹ã—ã€ç·¨é›†æ™‚ã®ãƒˆãƒªã‚¬ãƒ¼ã«å¯¾å¿œã™ã‚‹å¿…è¦ãŒã‚りã¾ã™ã€‚ + + + + Edit display format + 表示書å¼ã‚’編集 + + + + Edit the display format of the data in this column + ã“ã®ã‚«ãƒ©ãƒ ã®ãƒ‡ãƒ¼ã‚¿ã®è¡¨ç¤ºæ›¸å¼ã‚’編集ã—ã¾ã™ + + + + + New Record + æ–°ã—ã„レコード + + + + + Insert a new record in the current table + æ–°ã—ã„レコードをç¾åœ¨ã®ãƒ†ãƒ¼ãƒ–ãƒ«ã«æŒ¿å…¥ + + + + <html><head/><body><p>This button creates a new record in the database. Hold the mouse button to open a pop-up menu of different options:</p><ul><li><span style=" font-weight:600;">New Record</span>: insert a new record with default values in the database.</li><li><span style=" font-weight:600;">Insert Values...</span>: open a dialog for entering values before they are inserted in the database. This allows to enter values acomplishing the different constraints. This dialog is also open if the <span style=" font-weight:600;">New Record</span> option fails due to these constraints.</li></ul></body></html> + <html><head/><body><p>ã“ã®ãƒœã‚¿ãƒ³ã¯æ–°ã—ã„レコードをデータベースã«ä½œæˆã—ã¾ã™ã€‚マウスボタンを押ã—ãŸã¾ã¾ã«ã™ã‚‹ã¨ã€é•ã†ã‚ªãƒ—ションã®ãƒãƒƒãƒ—アップメニューãŒé–‹ãã¾ã™:</p><ul><li><span style=" font-weight:600;">æ–°ã—ã„レコード</span>: データベースã«ãƒ‡ãƒ•ã‚©ãƒ«ãƒˆå€¤ã§æ–°ã—ã„レコードを挿入ã—ã¾ã™ã€‚</li><li><span style=" font-weight:600;">値を挿入...</span>: ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã«æŒ¿å…¥ã™ã‚‹å‰ã«ãƒ‡ãƒ¼ã‚¿ã‚’入力ã™ã‚‹ãƒ€ã‚¤ã‚¢ãƒ­ã‚°ã‚’é–‹ãã¾ã™ã€‚ã“れã§ä»–ã®åˆ¶ç´„を満ãŸã™å€¤ãŒå…¥åŠ›ã§ãã¾ã™ã€‚ã“ã®ãƒ€ã‚¤ã‚¢ãƒ­ã‚°ã¯<span style=" font-weight:600;">æ–°ã—ã„レコード</span>オプションãŒãれらã®åˆ¶ç´„ã®ã›ã„ã§å¤±æ•—ã—ãŸã¨ãã«ã‚‚é–‹ãã¾ã™ã€‚</li></ul></body></html> + + + + + Delete Record + レコードを削除 + + + + Delete the current record + ç¾åœ¨ã®ãƒ¬ã‚³ãƒ¼ãƒ‰ã‚’削除 + + + + + This button deletes the record or records currently selected in the table + ã“ã®ãƒœã‚¿ãƒ³ã¯ãƒ†ãƒ¼ãƒ–ルã«ã‚ã‚‹ç¾åœ¨é¸æŠžä¸­ã®ãƒ¬ã‚³ãƒ¼ãƒ‰ã‚’削除ã—ã¾ã™ + + + + + Insert new record using default values in browsed table + 閲覧中ã®ãƒ†ãƒ¼ãƒ–ルã®ãƒ‡ãƒ•ã‚©ãƒ«ãƒˆå€¤ã‚’ä½¿ã„æ–°ã—ã„レコードを挿入ã—ã¾ã™ + + + + Insert Values... + 値を挿入... + + + + + Open a dialog for inserting values in a new record + æ–°ã—ã„レコードã«å€¤ã‚’挿入ã™ã‚‹ãƒ€ã‚¤ã‚¢ãƒ­ã‚°ã‚’é–‹ãã¾ã™ + + + + Export to &CSV + CSVã«ã‚¨ã‚¯ã‚¹ãƒãƒ¼ãƒˆ(&C) + + + + + Export the filtered data to CSV + フィルターã•れãŸãƒ‡ãƒ¼ã‚¿ã‚’CSVã«ã‚¨ã‚¯ã‚¹ãƒãƒ¼ãƒˆ + + + + This button exports the data of the browsed table as currently displayed (after filters, display formats and order column) as a CSV file. + ã“ã®ãƒœã‚¿ãƒ³ã¯é–²è¦§ä¸­ã®ãƒ†ãƒ¼ãƒ–ルã®ãƒ‡ãƒ¼ã‚¿ã‚’ç¾åœ¨ã®è¡¨ç¤ºé€šã‚Š(フィルターã€è¡¨ç¤ºå½¢å¼ã€ã‚«ãƒ©ãƒ é †ç•ª)ã«CSVファイルã«ã‚¨ã‚¯ã‚¹ãƒãƒ¼ãƒˆã—ã¾ã™ã€‚ + + + + Save as &view + ビューã¨ã—ã¦ä¿å­˜(&V) + + + + + Save the current filter, sort column and display formats as a view + ç¾åœ¨ã®ãƒ•ィルターã€ã‚«ãƒ©ãƒ é †ç•ªã€è¡¨ç¤ºå½¢å¼ã‚’ビューã«ä¿å­˜ + + + + This button saves the current setting of the browsed table (filters, display formats and order column) as an SQL view that you can later browse or use in SQL statements. + ã“ã®ãƒœã‚¿ãƒ³ã¯é–²è¦§ä¸­ã®ãƒ†ãƒ¼ãƒ–ルã®ç¾åœ¨ã®è¡¨ç¤ºè¨­å®š(フィルターã€è¡¨ç¤ºå½¢å¼ã€ã‚«ãƒ©ãƒ é †ç•ª)ã‚’SQLビューã¨ã—ã¦ä¿å­˜ã—ã€ã‚ã¨ã§é–²è¦§ã‚„SQLæ–‡ã¨ã—ã¦ä½¿ç”¨ã§ãるよã†ã«ã—ã¾ã™ã€‚ + + + + Save Table As... + テーブルã«åå‰ã‚’付ã‘ã¦ä¿å­˜... + + + + + Save the table as currently displayed + ç¾åœ¨è¡¨ç¤ºã•れã¦ã„ã‚‹ã‚‚ã®ã‚’テーブルã«ä¿å­˜ + + + + <html><head/><body><p>This popup menu provides the following options applying to the currently browsed and filtered table:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Export to CSV: this option exports the data of the browsed table as currently displayed (after filters, display formats and order column) to a CSV file.</li><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Save as view: this option saves the current setting of the browsed table (filters, display formats and order column) as an SQL view that you can later browse or use in SQL statements.</li></ul></body></html> + <html><head/><body><p>ã“ã®ãƒãƒƒãƒ—アップメニューã¯ç¾åœ¨é–²è¦§ã—ã¦ã„るテーブルã«é©ç”¨ã•れる以下ã®ã‚ªãƒ—ションをæä¾›ã—ã¾ã™ã€‚:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">CSVã«ã‚¨ã‚¯ã‚¹ãƒãƒ¼ãƒˆ: ã“ã®ã‚ªãƒ—ションã¯é–²è¦§ä¸­ã®ãƒ†ãƒ¼ãƒ–ルã®ãƒ‡ãƒ¼ã‚¿ã‚’ç¾åœ¨ã®è¡¨ç¤ºé€šã‚Š(フィルターã€è¡¨ç¤ºå½¢å¼ã€ã‚«ãƒ©ãƒ é †ç•ª)ã«CSVファイルã«ã‚¨ã‚¯ã‚¹ãƒãƒ¼ãƒˆã—ã¾ã™ã€‚</li><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">ビューã¨ã—ã¦ä¿å­˜: ã“ã®ã‚ªãƒ—ションã¯é–²è¦§ä¸­ã®ãƒ†ãƒ¼ãƒ–ルã®ç¾åœ¨ã®è¡¨ç¤ºè¨­å®š(フィルターã€è¡¨ç¤ºå½¢å¼ã€ã‚«ãƒ©ãƒ é †ç•ª)ã‚’SQLビューã¨ã—ã¦ä¿å­˜ã—ã€ã‚ã¨ã§é–²è¦§ã‚„SQLæ–‡ã¨ã—ã¦ä½¿ç”¨ã§ãるよã†ã«ã—ã¾ã™ã€‚</li></ul></body></html> + + + + Hide column(s) + カラムを隠㙠+ + + + Hide selected column(s) + é¸æŠžã—ãŸã‚«ãƒ©ãƒ ã‚’éš ã™ + + + + Show all columns + ã™ã¹ã¦ã®ã‚«ãƒ©ãƒ ã‚’表示 + + + + Show all columns that were hidden + éš ã•れãŸã™ã¹ã¦ã®ã‚«ãƒ©ãƒ ã‚’表示 + + + + + Set encoding + エンコードã®è¨­å®š + + + + Change the encoding of the text in the table cells + テーブルã®ã‚»ãƒ«ã«ã‚るテキストã®ã‚¨ãƒ³ã‚³ãƒ¼ãƒ‰ã‚’変更ã—ã¾ã™ + + + + Set encoding for all tables + ã™ã¹ã¦ã®ãƒ†ãƒ¼ãƒ–ルã®ã‚¨ãƒ³ã‚³ãƒ¼ãƒ‰ã®è¨­å®š + + + + Change the default encoding assumed for all tables in the database + データベース内ã®ã™ã¹ã¦ã®ãƒ†ãƒ¼ãƒ–ルã®ãƒ‡ãƒ•ォルトエンコードを変更ã—ã¾ã™ + + + + Clear Filters + フィルターを削除 + + + + Clear all filters + ã™ã¹ã¦ã®ãƒ•ィルターを消去 + + + + + This button clears all the filters set in the header input fields for the currently browsed table. + ã“ã®ãƒœã‚¿ãƒ³ã§ç¾åœ¨é–²è¦§ã—ã¦ã„るテーブルã®ãƒ˜ãƒƒãƒ€ãƒ¼å…¥åŠ›æ¬„ã«è¨­å®šã•れãŸã™ã¹ã¦ã®ãƒ•ィルターを消去ã—ã¾ã™ã€‚ + + + + Clear Sorting + ä¸¦ã¹æ›¿ãˆã‚’解除 + + + + Reset the order of rows to the default + 行ã®é †ç•ªã‚’デフォルトã«ãƒªã‚»ãƒƒãƒˆã—ã¾ã™ + + + + + This button clears the sorting columns specified for the currently browsed table and returns to the default order. + ã“ã®ãƒœã‚¿ãƒ³ã¯ã€ç¾åœ¨é–²è¦§ä¸­ã®ãƒ†ãƒ¼ãƒ–ルã«ã‚ã‚‹ä¸¦ã³æ›¿ãˆãŸã‚«ãƒ©ãƒ ã‚’デフォルトã®é †ç•ªã«æˆ»ã—ã¾ã™ã€‚ + + + + Print + å°åˆ· + + + + Print currently browsed table data + ç¾åœ¨é–²è¦§ä¸­ã®ãƒ†ãƒ¼ãƒ–ルデータをå°åˆ· + + + + Print currently browsed table data. Print selection if more than one cell is selected. + ç¾åœ¨é–²è¦§ä¸­ã®ãƒ†ãƒ¼ãƒ–ルデータをå°åˆ·ã—ã¾ã™ã€‚複数ã®ã‚»ãƒ«ã‚’é¸æŠžã—ã¦ã„ã‚‹å ´åˆã€é¸æŠžç¯„囲をå°åˆ·ã—ã¾ã™ã€‚ + + + + Ctrl+P + + + + + Refresh + æ›´æ–° + + + + Refresh the data in the selected table + é¸æŠžã—ãŸãƒ†ãƒ¼ãƒ–ルã®ãƒ‡ãƒ¼ã‚¿ã‚’æ›´æ–° + + + + This button refreshes the data in the currently selected table. + ã“ã®ãƒœã‚¿ãƒ³ã§ç¾åœ¨é¸æŠžã—ã¦ã„るテーブルã®ãƒ‡ãƒ¼ã‚¿ã‚’æ›´æ–°ã—ã¾ã™ã€‚ + + + + F5 + + + + + Find in cells + セル内を検索 + + + + Open the find tool bar which allows you to search for values in the table view below. + テーブルビューã®ä¸‹ã«å€¤ã‚’検索ã™ã‚‹ãŸã‚ã®æ¤œç´¢ãƒ„ールãƒãƒ¼ã‚’é–‹ãã¾ã™ã€‚ + + + + + Bold + 太字 + + + + Ctrl+B + + + + + + Italic + イタリック + + + + + Underline + 下線 + + + + Ctrl+U + + + + + + Align Right + 峿ƒãˆ + + + + + Align Left + å·¦æƒãˆ + + + + + Center Horizontally + 中央æƒãˆ + + + + + Justify + å‡ç­‰å‰²ä»˜ + + + + + Edit Conditional Formats... + æ¡ä»¶ä»˜ã書å¼ã‚’編集... + + + + Edit conditional formats for the current column + ç¾åœ¨ã®ã‚«ãƒ©ãƒ ã®æ¡ä»¶ä»˜ã書å¼ã‚’編集ã—ã¾ã™ + + + + Clear Format + 書å¼ã‚’削除 + + + + Clear All Formats + ã™ã¹ã¦ã®æ›¸å¼ã‚’削除 + + + + + Clear all cell formatting from selected cells and all conditional formats from selected columns + é¸æŠžã—ãŸã‚»ãƒ«ã®ã™ã¹ã¦ã®æ›¸å¼ã‚’削除ã—ã€é¸æŠžã—ãŸã‚«ãƒ©ãƒ ã®ã™ã¹ã¦ã®æ¡ä»¶ä»˜ã書å¼ã‚’削除ã—ã¾ã™ + + + + + Font Color + フォント色 + + + + + Background Color + 背景色 + + + + Toggle Format Toolbar + フォーマットツールãƒãƒ¼ã‚’切り替㈠+ + + + Show/hide format toolbar + フォーマットツールãƒãƒ¼ã‚’表示/éžè¡¨ç¤ºã—ã¾ã™ + + + + + This button shows or hides the formatting toolbar of the Data Browser + ã“ã®ãƒœã‚¿ãƒ³ã§ãƒ‡ãƒ¼ã‚¿é–²è¦§ã®æ›¸å¼ãƒ„ールãƒãƒ¼ã‚’表示/éžè¡¨ç¤ºã—ã¾ã™ + + + + Select column + ã‚«ãƒ©ãƒ ã‚’é¸æŠž + + + + Ctrl+Space + Ctrl+スペース + + + + Replace text in cells + セル内ã®ãƒ†ã‚­ã‚¹ãƒˆã‚’ç½®ãæ›ãˆ + + + + Filter in any column + カラムをフィルター + + + + Ctrl+R + + + + + %n row(s) + + %n 行 + + + + + , %n column(s) + + , %n カラム + + + + + . Sum: %1; Average: %2; Min: %3; Max: %4 + . åˆè¨ˆ: %1; å¹³å‡: %2; 最低: %3; 最高: %4 + + + + Conditional formats for "%1" + "%1" ã®æ¡ä»¶ä»˜ãæ›¸å¼ + + + + determining row count... + 行数を計算中... + + + + %1 - %2 of >= %3 + %1 - %2 of >= %3 + + + + %1 - %2 of %3 + %1 - %2 of %3 + + + + Please enter a pseudo-primary key in order to enable editing on this view. This should be the name of a unique column in the view. + ã“ã®ãƒ“ューã§ã®ç·¨é›†ã‚’有効ã«ã™ã‚‹ãŸã‚ã€ç–‘似主キーを入力ã—ã¦ãã ã•ã„。ビューã«ä¸€æ„ãªã‚«ãƒ©ãƒ ã®åå‰ãŒå¿…è¦ã§ã™ã€‚ + + + + Delete Records + レコードを削除 + + + + Duplicate records + レコードを複製 + + + + Duplicate record + レコードを複製 + + + + Ctrl+" + + + + + Adjust rows to contents + 行を内容ã«åˆã‚ã›èª¿æ•´ + + + + Error deleting record: +%1 + レコードã®å‰Šé™¤ã§ã‚¨ãƒ©ãƒ¼: +%1 + + + + Please select a record first + 最åˆã«ãƒ¬ã‚³ãƒ¼ãƒ‰ã‚’é¸æŠžã—ã¦ãã ã•ã„ + + + + There is no filter set for this table. View will not be created. + ã“ã®ãƒ†ãƒ¼ãƒ–ルã«ãƒ•ィルターã®è¨­å®šã¯ã‚りã¾ã›ã‚“。ビューã¯ä½œæˆã•れã¾ã›ã‚“。 + + + + Please choose a new encoding for all tables. + ã™ã¹ã¦ã®ãƒ†ãƒ¼ãƒ–ãƒ«ã®æ–°ã—ã„ã‚¨ãƒ³ã‚³ãƒ¼ãƒ‰ã‚’é¸æŠžã—ã¦ãã ã•ã„。 + + + + Please choose a new encoding for this table. + ã™ã¹ã¦ã®ãƒ†ãƒ¼ãƒ–ãƒ«ã®æ–°ã—ã„ã‚¨ãƒ³ã‚³ãƒ¼ãƒ‰ã‚’é¸æŠžã—ã¦ãã ã•ã„。 + + + + %1 +Leave the field empty for using the database encoding. + %1 +データベースã®ã‚¨ãƒ³ã‚³ãƒ¼ãƒ‰ã‚’使ã†ãŸã‚ã€ãƒ•ィールドを空ã«ã—ã¾ã™ã€‚ + + + + This encoding is either not valid or not supported. + ã“ã®ã‚¨ãƒ³ã‚³ãƒ¼ãƒ‰ã¯ä¸æ­£ã‹ã‚µãƒãƒ¼ãƒˆã•れã¦ã„ã¾ã›ã‚“。 + + + + %1 replacement(s) made. + %1 ã¤ç½®ãæ›ãˆã¾ã—ãŸã€‚ + + + + VacuumDialog + + + Compact Database + データベースを圧縮 + + + + Warning: Compacting the database will commit all of your changes. + 警告: データベースã®åœ§ç¸®ã¯ã‚ãªãŸã®å¤‰æ›´ã‚’ã™ã¹ã¦ã‚³ãƒŸãƒƒãƒˆã—ã¾ã™ã€‚ + + + + Please select the databases to co&mpact: + 圧縮ã™ã‚‹ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã‚’é¸æŠžã—ã¦ãã ã•ã„(&M): + + + diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/translations/sqlb_ko_KR.qm b/src/WBCLFZSystemModule/SqliteDBProcess/src/translations/sqlb_ko_KR.qm new file mode 100644 index 0000000000000000000000000000000000000000..c4fc87686111cbaeaa3916a4068cdad072874fd3 GIT binary patch literal 186801 zcmce<31Cx2*FSvjZIY&GngFsYVnB9E3kZl<%2swL2t^PPN!xURZnP;-1r!BAMMOme z7X+0}%OVshP_RY1u`h!1h`2nUD2p2?D#G_WGr2cun*zS?`~5+gHn}r%=FHj8nYj`9 z@%8uo^yaJk8#nxT{PG=Nt|B7i#Pml84ev$NG9SM+AzE@owtG_1wjg?afNb|ZhBg$x zPm=B4Uw2`Dfc{|#X7`G|f(WE^0AGFhmmPN_-WGf=W zLqxNiqaBOqF`nTiQtCX3_7$SS??tOxFfM*qpXcXZCFO_dqE(*y@z>+5%tHqM(@Y}V~JimLo_Cn zXerjm?Wa?T9zoyfcagdZ&v$!QwjcgNYW`S^GlGN?!Z}yVy^54k1!A5lNKnnRT4txAJ z*%~JheQ}oTLqW4YEu|VqYJ;wRrP`k~BIVB3RBsCKb7nTx+jWuDCAFx*$!wxe6uQ0t zI8y5ULU&!NLrVWv)cif*xziuiYR5sMy0xhF#%R#xa%%n2DbP_Ewcc(Z`r1XUu}}1k zjap-0lzF|V^$%N#-knLU&$q+pPg5Jl^Ynhy26&_YzD;comJ)q;fZBZB0PQsjuZj6K z4W>?K14s$1PZ1L_&*lZxx5ib_|4QojNip`V7WMnefbUmO|IS|%o$pBfr`$(0b{!2! zyPK5POK8BkH;CpwM*}-!zrI^X0~ftZ%CvJdxW_6|*Dj}F_Z}mPy+9A#A42rPWg0%U z0OLMMBOaPY%DEXd;_wR4O?`?P^BmgODP|w=zV&&8vV~D(Bl$%DDo63 zE!xmS$$0mf~(iWVMJv0o3+@&|3CTwh7c*F#R6j-?gnG0uQxv@$T7)Ha{c2Q49cKKX!h zUk)VY-rltCL(pGZJNj^MGO4jcXj84Fqz+VQ%lLWV52BCb8xtLJ)5ixdlCotUeG&uy zzH*&P3^RzXuBHQ}py$Y`bl}WL?9*NJ>3}p+;ycin%6w8=U!YT`+(geDq0^R)q^wA% zbAMxBZtqE#2Z8?YI8WDungCDJ>G}ujNbS~#t{-ksN?9w#bQ|b?*r!Tx@qD5W-%vt! zWRWuH4#hq+jmSAdw5laRvB%9PWzC~XgFSOdeY3A}d+2gfUi)5gI9x;>U5euvWcNGI zDUDspL~$=G&1;2`Iw(bHkvWdk#utAB zomr5-_bTC^bp+ooRJxBZB<0Z$lpeQ@AoVS?(x;C?YMi1xc;y$OC;n2>-na%jy-%5Z z%0bGw5@p&2=$~avl$ra30LOl1)*S~)>H4fPD{cv?iQ&qe6X1uL7nHeYfZv|KD$n0` z0OP)^Jim4nQKN9>#hqC1Yx|Vt2YNyko>5k%T_d%=TiLMIM#`HXDfxF!Benl7rQnYa zM4MhxiXPob^zA-n&-!OU-_fE~7c5uy=FcYO?VprG-+f9-?n}z?E4_(!mnffo4t;d+ zOXXBN`1ok1a=K$QDI>-!7cQKJ-iQ{h@@v0RQ#KP_B;rnCRjI%GC=^LBFeI`^zTfdhSTjQy*3B`~)chAF75aGl|~# zOf@YpB{g`FZ09|%1|@*civLoBBWFOqUQk0iB$2xGlp3-D_^EL~wOz<23Tvj;I97+$ zXN%N34gE-2{h8XVVJ0bUC#ucb&LL&vcr~mw_V<KaXS zeXiPRW+tg0`)^2H__sQ#&tOv5Emo)f<|fr}pZZMWVWie- zq0U`)iqsBwsq@|dKaI*!=SPFix;>@7^nN7dd!+jE2m45|_gCM#>k`r4pVVcB`9u@9 zs4G5gM3g#FUA1U8(U;-s`)!^=`>UE?j^E2ys@qszO`oQ2Pq+ti{4I4yPAn;Z&s28~ z#riEKwP-x>JnEvlD+J^G7NG7rhxKhaq3+(saxhEXeZB$Y*3W9`Sl}ZdPA%OqgVct1 zs--(He@T+MXFcE^?^ZvZdLO=TqaKfQ5 z3VM6y3H9=TSBWk?u3oJRdTiN5z5WpPVQy?dz+-8oKJr$8sXc^JgZ=@5bJM_=rvvJo z_=o8GV*$61I6%rjlL8uk0eQ0Q!+<+O{!427(ttZ3F_LmVG@wa)*oS?W2i*N8_HozY zfaZ@Cg8!}uwEPb6KU*)Lv#AlOokIfd9jy>G|0m%7F<5un?*S2Kur70}fbOq>PaQD< zJtl63Y57(_@ArYnr=kO*1~wvPU1&hmh0CPec0OQOr;$Vtj|>>|<~rCTQvx0-1Rq@K zAMj}Fb)-gS28_>s2l{hTK-@dyNEuZ(z_k+l7x!5}LJ9ajZdAa8_&m_#mVopQCx|{8 z9*`9be)(l=z~s1I(EB~nVt?zX0go?TM^yYwz!M*?03SUb@bb6IU}yCVSOQx{={zA| zSslou{e=O`o^1`gAwOVwB=B|LKLN|v>?HNhHv-;SycBY0M!=d~z-xF?KyI@>!1s>< z>+igVaqR(lLC-@j*9piQ3V5Dr7LfNg_A&9ffc$>X0bhdyw$BS9Gz) zlX}3*&#ME7{%UqK}Y0oSL`CslddpuRDVXvG+V z`gRlO-OUDL;1I}<&a$1?)?hF013PAop_Dk#x1ZPgH9Nl?*YC>^fk137V`YLyA9#HpC#qP9K*e*c))R(ap`%Eh)xIxM(W^) z4G*u!{;%6>c=&VZo0G!~kGgYV2gMlTZJVJd5)FypfbR?H8z!`XZ&EMOkTPWf{E5d5 z*@v4Em01mwk30mv$}vpcd6?)xC&TnDpTN$$WOzCmaxiY4;n~d>N$n9}n71DA99m^~ zF+BjTRDHvO{!56)trM;C#xsURdwY{Qr@3MAfCBgldqk_0Pn7Ln6GW@V9x*JQwHW@x z%d-7rfo!imZ&bQfM^c>Tp_QhQ|@-W;=wl=7DhOFPaWb;4%D+dr$Yua6s+J=Y9& zUyfnLGjo8iUkocdJuXCbRYbj`dCH0wRXo0uCYoGH`2+k+N%?cYD41-)ObjrKa)`wSnz%p&J{*{)nD+pFV5t3ERrE#$-1r_rjI zKMO7JeDw%g1JOT2&>Hc1G1@@e)1#YVbF@Or(I7*9 zo$o+zQw&=ZqDkrXmSJb(zL1Ao3_FiQJ`^rB6b*hK^ia=G^sx>0(6fd;b8V#b?PWM{ z^&QavWy8UhXQ0=|7!K~*1iAd7;ZRrT;kD8PzY+9y zw$Zr5Mrz38vR(A8F%ZAg`k#!Jr+$My+fuYj?xUhr7r2e}YIY)J@E^uI;CE5c>&AvX z0r#pV##Y0yo~dVztxo`svu_$h8-x)xZD$Pq8T)YhD`UsS!{MKPYwXf_C(+?K#xDJi z!7hEpcwaQ+-ra6vuV{>$Yc~!tJWVuosBzdy=)Z`3_Orl;Ul|iGx?pc~Hm3C23Onx`WBT9~M8AwPX2i}X<(;EO_p)9@ zch4|pzX5o!{cW7QVHWu9L*o=>DJczF7$1N6H|WXMqE!`#arzG!uT_L`c2Drdbw#ww z^1;U0?*Z;6&l;b(7)i>{3yt&ou7Er`FWZX~(H0|4kZF8jZz9$=#yI~~BjzhG&i@g9 z=7Rmk7sr7f8V48`UOzzUJw1&}&bNpBFr$V1>blFgtmHZ=#t`FjGwj*FB8=}02VP1) zGQM*i^Mw9kT)hBv_*nzvYPK8aj5NMq_%$hib~nCXdIsx6d;Asn12v5wbOOJxX=VIi z0qn3XV~ii$FT$>=WBepLlGNd;#!t%Lh252C+?@pchWy7^Y{oj53^JC#2>N)xyYXP= zCq%!mH6Gp%`SI2OKn_9N0&vD(sHixo3?0&cQJmO{~0OwJZ(Jt z1Y#xMXB#iy54viVWW4qU=6ysl)lAC5IxdKuIG~>ppFYezgPmW}|6n(`@kJU8Z4sUq$?5vgx6B08eBm)A(_( zLe6h6jh||Ro_yal{>5)dNqor^-?cL-wMUCqeeO$BBItvf&oU)GIt}roAXD-q82{y6 zrZoG@h-Zu!t&;zzY0@Zs-u7?Pq>n+5T`roY+%b;SF@>fn<3OjapEEsf{x9NMDW>Tu zBf&41Ow$j)1pA}h^u*h+N9QY`~;qj=EYGSh1{K<~dTFs(c} zm}uQR)A|$bz)w9)c@K9WW#F5pEj=!hdS6@9w(HS|o28g`J(mN!^(#|p%O}D2%S@%Q z=ipC7nhth9k9btE>EQH{M9EuCpDhM`b$r3}**C9Y{|}h{^Y95$otsSGOg~2IQ@u^! z?A=Vt#Z#uUEfJ4pZ%}^!G5>QQu!R z{gb#6cJWVv%2M>J**DN|4SZ>OI?&Yh6#SWzz*?K%CuPWzz}gQ3f45B!Y_@tg{M}I5 z{y8JC)z6Ip_n5#o9e;yduN@fr?bGmAf&zPoz^}XBH?Yrl=Sg|@nZSNez@Jy23hcLX z1u6M22lo4JAN0!g!05hpV7D$09R9>^q9=O?j%x$?v*(V$@t?+mFP{pGgB`Di>{m%xM=tn2*zz{ESTA8k$rCQbxBH7yRDh<#S){2Dm%%WH_gvIA-eS9jPsCj%F4dI;h9b|1$`7!lj0RU(LHlsv|q_zb5SOy|V+) z^vWdqH9)k=4U#d?xVv!$#26LbI`64cK4znN5Aq z!0-9p99$cC>2#MlB;gt1b@44q9(VQrA=f7Z= zd|(uB2#r)CRpyQlD=55Ua;m=($@0eExy;&k!bx}X_&Rs{~ zzg{sH_jng^zggzeX3bzfk1?0FC+f`ArUH_qIm1m|0neUAx<>T<6pzav2=^sJC zSE0A_?LoJ7h9B_6?4a6f0QbEoWSciCsKIZ5KY2<}!}Hj`W`#j_I^&4eT7nwq0_Jm)T zDO%-?A4RLqoF5eRsh#Nf;h-Uj*ARDd1VzKnr74dDJs1eOd}w0OsO3(gKRX1CxgYj$ zjk{#~_A^28ca=ilC_#zcfTyP?1|^Sg1$+hsWxkI6THZS-Ybo$@?zNz-_v@2N-v>?Y z3BA#=OHfX)FOgp$+0OeVXyzfn`OoE`r`~Nu>WH&J3yv=Vo%INM{ZGt$?WLeMzXHDF zcL%Lp7lZijjG*n?))QUa6;yB$a{YtHgNpjY-d(>mXxB5)`)x9VcJG1S`g2QAdGE`R z+e3oNrvo2}!-MvAhyUDSX3+8cW2AIx5%izGVb81x5Bg&GQSg--baIo8D1BhisT!;& zHwK;Vei8Qd??FHObd8jqu|Yq+1UkR_YS6{yMbI~MgD$bYc)e@T@7p1df4<9N_-GyC z!ZwR>8tj(c5f<~u_kpjAEg{3!A%2u?sr3rrc-dsR#pHVhNiMe6@(Sgnc&v{IJLp?nFHGud9|WF~HA?UoDZ2rKG-B zZ0Q~XzEYAcef~&;-2Kbae+~SRdv;oewu9a%df77SD)wPru_bQzZSeQEiB_4m)Dj;7 zIk5DiCBDaR(5E9Tu2BJ`yxGFy%EjkzzkoIm?M_R=+Ea)Nwy;e28uFm+@0Qe$E|YRL z!7{DaQlf>8EYp6h2Yo-vGV8m|;JZA_vs0mmj+9vzWjG-(=ULwPaU7|AKC&$9e2J8x z!UZkJxf9DQ=o$bmV$Y1*ioBh`&_1_ILwWBlhIO~HvoRj zQcJlT^1W}GXqAtD60N#6%d+P~#4kd(TMkanL;mG+%V${~iN`yJ{Mumf4f-L6}`1d82^S?JE)iy%5OM6*<0lroDM9Xi+jqrPBSuSBci0o${>&`I5B>_iAM%A+9=*&e+fyz1rmVfXwIye4!fDap?S zzuyhxymf!@T4AU64qjgXIXS#2IPdpUkmo~!Ki&X6+-X$s$Di0qQU477$Ayyx60Qit>k-Z#UAIMS)${mYpDeh5Br9Q{r; z3qI_e0XyTx;3Iv3|B1f^AAJ>kxHL5QGgl_!-)DnA-~9mm^ZejbH9;4%_XdBPg6H4< zJNUmxFOnLyI{0)GwC@^&Pfw0TTy#nBcX>x3?+ylk@7@Y~T?xLh6L9tTRkX_L^x&U2 zKz?1y3I1ge;`$q=1z-ODImB((S?Mb1BW9shomUI_r(dmxBL|39J!v&f=t%0~wN~@t z2JkoUvsxZ`8F8QvR{K5UU?=so*0_kg^tdM0+X6lWzWZAn4BtuW+_~1<3&XI!RO{_O z^@H5`%j(z-JpT8fwW&3ks9C(VnG^Yv`OU4ZCP9wGePV4r;RN_C(c0!U(DiF`tZnZD z{$B54Z95C{X!lHOhv>$zt6o5h{S4h@?QpIY%dUYrK+A-FInAhOfM_Cgy?uK2x&pKf{;O|t& znuX_;d5YDYkPAO&gmsFF=U>=nopSXxjc1Q11BA`dUly;fMXLOLBk3_ucl>FSdU0StRV93D!;h0N0c)*3Bd9 zAa1hTT5$RY#Dlh2Kkf&8cjpCbk-eDcxp%EaZ9%WQyIXfR&BgxJx0WxnA+I^cx({(6 zYIw|g_yFjxU6S?46WE8h1FfImXCvj*73&vsF#f)_)-QKq-`0O^{pxGT@B2Dh&uxMq zYOf{R6`QT+zq*Jxc|Ge-8>0}n&$Rv#it+y#Y5jZS=b$&Y_1f{V@N54J3CKMPJN}mt z!=z}?V@Qax{{f=!I)?=PJ`QsFju2~;FvQa~hSU#%o)3CPwlhmY>UW(1{hk)m@FMu9 z^UEQ3Ujn`tJsZ;E5a^_NVo2N8O(E~IL&EAo{e=d>yW2jzDSfcEMzv~T*`AR zLY}{SKJ2WhkQbi1M)d6yA+JpVUmslj@`B6v6=C+MUx%y~oFOXjjN5^&pqN+!(U^jWonjUJTj2=OpNQTS%F80jUjgLk^muUpie3Idty~ z=&8p-zL}YhxL;(*H?Q6cI?W6D=F8pS|KCH-Zuu5*{;nZs&&_~5i4OU>Ht6DV&5*xK z55Rt$6Y}?GkniTNLjIWz{di%7O-#IqmnpVUiLgT+zTNg{a|7Zt@7bI`oB~|`u_eXrg}%DYHsRZG zq%L>cQd8m2p|NGNsu?oTG_VTUW9r8yKT#sNK#(w zZ`-=ebBZx6-!nSIjf#N!#JiW}%d-mhD)#aqv$& z+D;72hW*^z_GKyLSAJjHmtRDaGO~;9^hf28(}}hp&tsjv%53M7k^da}lZOGep#Uvvy{$Ukj=r}sg>zifYB!1zCZWxE;-d$3Ek?dm6ZZrVZH zKNA$hl_sDKfIZY)wr_rg)`-tvveO@5A|Bk?uI!A)xI1K<7b#kGZby4i{}%!OyLJof z_2mJwJ@C5Sw%m<8$R)dNUme8lU$@(>SV#SCc6(wZQE6X$t?t0X#v}H+@z~!{4ea%< z?ZooV-(p(TCv}qf3%OX93%C`iS|dnauWTp(f;U+rx1S_WOq^; zDVLku<7%RRVH3OSJJ931pW2gP|EX`<>}g>xQk9|hN$+Dl2ix0omaaoS{F*)IGUi$I zgZ<^bXJN1Ou)p%dGNP8N?2ERXBDIccU;I`Wsr`=ImmGq9{LUQv8#dtS+c5iz9oXMK zZ`xPB3qRf(C)*c>*;jYP_`f>stCJ^_GWv-9{lpcZyEpB*{j=e}H?Xg*pA38dh<)vS zImlmpW#4$MHssYP`}Qd4*A_q9x99%{c(mC|+CZ;%J8v)LxZ=6f_I7#x2gLeYo z4Su#CYQ21fDxT+J5}2`S5q%wto@wEAn>t*}sT_zUnr_{>8Ux zL?y@V-?rb3xN#Tz88_%5GQ)oHVmwiuL-wDpo6(tarn_a>QVKm6LQETb6ywjyoAYMQ(I*y!A^$+4?`Ssni7*ywfb$WdxI zhOu@=m0c|^Ajgr8rL#AdZ9Gk3SVK55tP%Wgshj7{AG`L-mer*_(92z3lN?*7mAZ=} zcD*N{83O1Z1Jo(_>jZSeD4SyOb27!@H(pO1)|n<&>!1h4nzQg}IzDqyhuo|9w;x5L zUXxpXlCk2%2>*7hd&u!o4aVHsD-7xJ-Q*~kRc7EdZ*I3$TOWSjGOef~KT&yY-j!{g zMvnb!$|fBf&Epj;EH#j0LtgPA?#FnP7%j~$Xm|8HMj6kaV#K+-Hv7fmf}$>r?ZVt+ zsf+pbh>TMv1^iHd>~SM0_r>s$nw=pCqDB3ZBqt zunBhV|7t9z1Sds`9jYGUtV%GaR-gwj>_b2qgE3+UK-&&&GS(K4^-sm`Zv5*87QC?k z-;L^71@Gv-F1cSH8@=l!(|$qyOQ&L<)0L>A>n-ej7EKbn3>g3}@|6=BCVjCaspaNS4{{z)x<-sT9o0)F@?A8a``_Z<4{^F6?p^q#W~Q3Tm$b1@lkQykmwV`7D_j z7vNvH$AdjTIUv#S6vcoh($Q}s#&Qeklv}dqSh5eVXppenxiN1{5>RCb+)Mymarj-s zO}L<;|K++W@z0ItW6b)(E;#0Yi&^yNy@w9bB(0Pk%!wM^;hBmv|8KAskKKvGcyg_s z@RP5kVNOk~BxC+x;`rY|R~aw=Cp&Tj=}~n)U3>m->ENRpEO{#HDH;L}$pkMsXdr${ z1rKDEj>c~zz+KE^4zzLDQOVaXax?VQ8-3U|apT*`_=!JBM{kzbteqXy6W_V2gd?&dPSCINa&!DUR$cS3G`l#AUjiZaft4%1Ta5L*ICZ zD?Zt+4HxfpJ7b+$E=NLgiYqHDB0Phq9^mGAVw2mZB*(eZc%iKbD-5 z;&cqlj>Wf*!SV^mgRac1ZDbh^iZ1*QPb z%rM78>Di7rEHO1bJ~<(WzsLl@S?N#!~?RvmJu$O zBf{xO%5)`kYm(%4XLJn@pE6}iSYldsSbAn+xb}Q_Vn#|BZ$y*GTX`xX+!-mbSz+uf z&)}&NNn(N_!v=?U2x}Lf3=~ccb5C{432y08F$?d0yvyxOPSF?D7aygjW6P7%@NKG- zap1sz?j-D6MrL|qrZd%%k>cW=1yulPpcU*&EPix3obIkwP?9w%1z*KVf@8RKG*tP9 zf$|VaL{4s& z20I>bJ7Pes69HgCW_qe4BAf?|tbkLXbdtL*7B#^Y=N1@k5_z+EJv&&bpEf$fe-pqX zVl%@d1?k)pMDgiy3}hz{H6^DddPwPJ^Y{m}n&JKh{6b_%(grXNa8@b{j(A^!0k=zR zOQydWs1ORyl&o}?EOHk|B&SStB!dSXSuVFDHpellBzs$uN6)+^*CaD{m*=o-!(3 zAwnn>lsCISg=OT(Hy@12JIN~8H!#C)<-O9+)j zN$l|4egH~n|GZ)_AEJyOW4fj|Mzuc ztZzK$CzNwjGf7$H-%Ro&wx+m}6O-IsJGW~G6*R&*+2vti#}rsDj;!q1ROlNvO|p{G zr=+nd1QiDBBh{6L&(p5O1WWAkf zajq1tufR`SN;<3tVM)Xb=>)X7lOU@cuBooLY#j}gvR#=ua-J%}&E7LUez-u9kASP; zWn#&)x&*S}aYr=JD*Lb?@;gG8vN~H2F;Q<@o%c0JYIc4z_TqAD$+)b4!e2L-y6ZCy z?1^p2fr*)w?fGGfQ*OGp4KQ2;(m@L@Sf1KeNU}&~OHA%z_iCXGEnTqb1Ubsz%0;*z zo}cvh+Ct=|!Fys)k^M@J0JS2E4w=1YwmZFTavBVFrbA1$!`CfqSUepXAS0KhXAoS+ zW;nR-9jI>aBv;%-2P;B%rZYLs-8IP3tbO(4)n3=G;0hzr?`XGqXjbCkCPQUy$Rea1Sb_z-VNse9`z?RO63mOdZ@`rd8Dx8o~?X|ctJ z3QK3pemn|~$C`pa7345_`xR|#$)QoE2<&qjV=xWQt;M0b+y?yFuJ_Py8ViI^$L>0r z*GdLGbwutNAmyi!kJxh-jDq>uzs$;T#j%6Q0#=AyVY=~e2}}zT-jdV%naABJ4*9erU3~p^kiZjPMLl(~ zH=f>xCs_iQDbfJSJ6)WYTeA{rJSxD!W~F22Sh?bHxg3$q!ZO%C zWieP$)W~Ee+gL1WiqEfW$2PFAbk}HU7u}L}AW7%mGL4Z^UQ`AV#r;?ai#dVtUG+CX z7q-$Y()mO;OR_UEI5ve)1L8~kH5*dGDiEyXYcwGW;3J7SCLk=Y zBxqP~#79g6$%_~kFv|nV!D3yI=HLtGWXQwnF*^pD@Rt7;H7%>7VPE2Eo4W{@))TT( zzznQcDT{QR^mq9EGdvrSwTuiny)qIbLB$fVQeWA^3wOEMf?`Gp?&<9!Jiz!{ho6(r z-W8P2+I3PRcd;5s#N*giZ8d(^GR*H%9F^C?#-Ch?2Xq7zQZv#soteqlCHDNmLt>GB z*ThMA2U1-_nYPh#(#t7=FijQ8A{d&3-lx_p5jaE+EpTwP5^T_gNcwweB1Oipo#ws<(RFmxS>p=b6jcf@p(ix2Z(H=hNnSYW#|0LMh zT-)IXDKHUIw(dBRFIk`>TQHK!X6Ns#w0{wRZW2Q`DI0#G{-@7W{N~H$&IC3%Gqcmu z*iOre%S_I2`^Q*}2jVOpVwqP)cATq9K=c~q2mvvr75@x3`E==EeC`QZ@N*2WAEDF( z@MbZ*h}1eFIFKL7K=%>en#Yr4(ahgCB+#5cV4zvZM)mT$%Nmx2QWA{o2IF$|3Fo&W zfNkwJhQ12itgjCbE_Ls$%}^gYR9Nl@%Wj4m2?)RyA(}`}%0mhq`OPgujCt_4Erg3E zYB(2{De_b@+ooX|?QuhCE?C4N$g6MoS+OaK+(D@uH}+Xo;3t!i9e01&(1^|vE0NXh@?_^#}vFXiF0wccl zloN^gQ+Z7tm^*r9C#N9S0Qag{`%s;C5yEcP!S94!{!LJpsR`I%cRWm=va#Q=te!7x z)?QdNRV06p(#6}hv+buzbD0D#q1+6PX9{tEwU@a|bB~Rd#;+%;#-%X6?qt&eX;6sC z@gA8To|c~0)-@FwH4c2ROy~++_+5NcG3R&)o%(DcvcIP3n60OC8x|De^RD_r9mCSI zvXYsXD`*mDW@0u6G_tz-ouh^LbBE7|!YpcwzttE|f=GH`eTjnmvVo0oJd64SVPJ8MNjJzvt}x1G z`F*_3t}ogBD4n{iK06V|qDmH4l7Hi4pc~qzhwDn3ZG*N$@w>0}<*^fB%RpJeNQYys zZMfz(gV|CY!bl7Em}uRqHy5MD8nv}@y_RGEtW9V>5Tma~+$Mqs2nK)^$_r6D=tj+D zo;NOBb=u(*i|ix`5u`phCy>oKbc z5yde|5#Q2bX)R!J0~V>^{w*|8!rVXv=ri5UGYPfdti2;X9l?pTbPnT!`Tedlk{Q0> zRYZzBbI`*~S@Z~gf0!yOv1t|b#v?vKf;J;LRK;?|@vw(N9&tSE)mGDVjqr$w9#oNj zwW&D`g6M_)TTs8?G6?qVUG?>4*_#iF>WfMMloW{MKd;3qIoK!MY%PvC-UX_uISS{z z>L{rBFlScQ6a?@6_o^*=IZAUm%piIX_vu};`EVCx86-u<4M(xUt3Dxm5Ao?8*gG3} zfaa+;m>E}2O3#kre#ob9?LLSMH_wqikB5(hu~~KDwWvSpn0lfH$x%Ew_v@{><%@OH z+4>LZ*&BJ>#Pm$~b=5#pL&JTQ?jel$oAj=IbTLYq3t{x7z+K{XjPY5AWf%uBvyz)X zCOn?1&>MIIba?T2R#rw*CSL zr3wB=S?Ft@30n(59FJjlPuduoCOq^Wf4lLtHyB-Z)f2q7_>SSx(6CVo3UhaObCX34 zSwyg~;9|qdV--)^x({pdWb5>mEFUH-IV9z|!PAJ=>J>gN5C-T%SfrY*7iJld09lOk z8BrGFNJpnkE%w0WIV`GEK*!KhhE@IBmn*kh9s50#JkmYjG>eS`^9 zWh<3^z8LXhm7~I&2NO!RQPzf^B~CT*tznZMF1rd91<_M{e#`kCvlwR_Bt)EJs^k$C zuL8ScMbIy_qQ&gpf#OR%-&QWccQA1=BwJ4x%*8&ia7H>o!#G(`jDMa}N;~Er%|DjJ zGaQTX?w;&_JcdWmtS$r@n{sqb$_*_CyECd}U*0gW77KsFd|modaj}S6pUg!}4ixYt zB2ZJe=4tkoo)txrJz{%blVg2bef6wnDjY{BXkT1ha7Ez2lN{N)k3*fFSsQDx%6XaQ z$_&Ma05?|0F`~Ts(rRRg7>m3g$5J^KD58$_HzMQCJ0O*p*PvCN^H3v)ew>05K_UK$ zFghJ}lRL?Ya|-Rj)B~!S_O}Fd1=k zj#P@eIA#!y5rp;&vkZ12Vk9_3liT=0WPK3Ja$|sW4#o>dlzV$tgVK~ROH75|nHAzV z;+x7TW{2B35yC7TvkMT|L=wqGq)U-PNa9JIj#y{h#Ow@M#TkMh@c^=j9$stg7@5ZQ zRJ=n*j$w;1YjR)^pLrsmvJ_79*L{HVFU%~6ZaHzr0gR=Kkig;2DZE$yduTRQ1v?so z8>c=v0`C*Xuj93qo8P0w$*a*r)s5QmhNE`8$*8ycv-u^9>8q{nh0=>H|4VNN$2FSz zpp2e_7+k{Z!q3SfMa#wYT<|)PvY6vHEGtLIPoLzDu;@N9jws}OVnBXjG0AZgMLq#r zE3{05-Xh`T2^jPhWqLm5Nh4_J4E&YxlxVCaC3*ire1V z6Kz3`1LwD}C>2REkL?e^R^&MJWo723M|&rwbNb(@C8t275_-C;MYHxT98;2# zJv#{;A%f93&^_xC14 zTUq6lE|9*0KAcIIWx^J^N&kUbf1LKJh))Pn#x@JsGNojV$XzF~+kCvs{x?}jA3c98 ziB*lJ-u2mg$k{97I~ArPC)rT;375)|kewDM!rh#9(&YniD?Q_zz#XH(%}TZc9RTiQ zqc<$()f8W1~7WqktZGLHQjR3lV?GR$#Hr3yFMYePArOFANI_L-Ui z@WEEAkG+Kv%#fd*%Xj+#V&UGmObkuLDH4vm zICjD4qm~7Teae*rc5(gnN8zL}^?1%z3L#<~9u|5&z6E6K}) z{P#h+b$B|?AKW_Ho1%81oR92Eq@(I#7ScfHj~VS;H!^l|aN+Qqw03 z+o_t4jku1C3*UA;3HzlXVwm6~Q8`jEcXK<}6LP@;GmtnS0yKMNXf>l7%If5Y>RT1m zGX-@~9J#*1N+Q^g(`uMxQDSBAw30<$Gar!6UB-T1g`&g()fOej!SP2Wn5QJM>S{da zUQkyc+!;}mSk3B81?_To6qf7jv-E;n!eQC88*NqPUNyYESeK^@l~~=3vYJny(a;O! zbvHm}t-^A|QL&?5%T(`Mr#Ff#CJJNHm4b61H=W$T`=ECZVnP&zaD(}4`)(ahxGg=1bpad4vCO@>#k#XM7h24AUr(}_xXiDqKlEI|eAHftNJb2tLsHw3$7b(6~F_?hzVn@)Md zRW_+^LLm|=O0FhS1|kZ=RPJ|uH^8T%LIBjD#XGCx&vjI~z*i!~aIEwuT&)aak++GC z$ADKCuvN(cO>O@~UP+V5`pp>r%0P1!@HxB>S;EOdsAKMpf6C9K#l{xsz7GoKmS2(M zvu}lP6lP~HMl1I8&Mou-#zBEycm?_y&&C8kpIaKSErZj)D zRuyX!mDm`r7xUEIL*}zS7RNW)cjnL%7s&C?RcRho%zfDLMlFAer+`${^2Z`NrBM{N&e9P!E!&@tPE zA|}AGWt9FLnXB-6Np@O4&c~134^%BNVFK?WNOL>{< zJ#{mnlT!C~P(OI&y{)i(#FHJUg@`h6;=gjD;J%(fGH2jDMSD1_!Wa|58fOaEo8`#t zpQz!?ic4~(I`M6X76LIybOMZGmWNz6uGMK&-o8-A4+AW#;-%xd@Ir|fFa^Z`Ytw?=RyHT_49jTTvg_eEb4;# zGAqZ{N~a#l7ZmfqgMlOQ8R@!V%~WrC%6w1;h= zd5WX9mTlV2ZFvzehG-u;7LAd2YVnS3JXadEZg9y$>aOWYiBZO7VeXb`<%cV3Ng5QDE^;i8W?Uw&9pCaf zwWif4=Lp*7GM?^^oh}gKajoXZULsO2tn->TRbd&v`C`o42DNhl-JyN)<;n^<6BL1if*sR4ZWu= z?{3x}Wg;EIEI7g}Pgr^m8K$Q-yT`vWX@V=DR;+8caRu+sj=5XTmo#NOF+f`3iazBX za>|r+r#MRm`xe((Ag!mDyj2$GQ?=?HO)IlL7J3^MgZwWFAOP#6AZIaW33dha~Wo@}}fVJ5@el=hZ;?hhf zO2JY&AjviMj6vRB863t>9efwH31+MhR=prLmLPhnP#}k#iLfJ3>;nLsbpUSt15j71 z++wqWLa|07L7X zF;&+oJ`?)vXBeiG)GN$UuPG`D&~D8H?eDwWSk}+E8+apRQI24KXjR{5m|qKaA4uh= zd`n7nM2ytR7ktkD>BJyl#OA>>*XwF0zY@S$GoD;XO$ifrPelX?2FZUcjM8#XCtA%u$S-N=@u9vK31&c=9 z3CMwn7=!232#x}Yb9gvf?3cEM-{Z@8yf5-lg>Kf$W1KJ@bbN?ovl`E^SMNDO!Ha_V z+STEAu4vx1%5zEAm<585!GZI|n&=YZs)tuxfeAdvN_A*@%7BZe36c<5(7fbWlzHl0 z9_AR}#>qYDE(;L>$XO%%m+?(C<58xle^JH~M=zRyThS!TO4P|+Zc=6jARR5mOv2m%h1sSSOo0C*+50X3pxN4PVy z<4`K$8iJ#MDIzdr;G>25vlbCGV$mR~t^9Yf`Z9^$)g0xa@apHPQ95uT~P(5nn|8bLKX>W%Sf)j7B8mVvm ztR^@{VDP4kfvc)d7Zl?;?<%}&{~*>t_#rnJnyU)_LSizL6Os75DFXeU&G$c@bq6T5 z%2bvIlU)e2-gu*|Vt++ovAj@UqZ!8gfK()C8L5^&h%@_Cs?`u(rs7}tf5*BN_0YT7 znzf(Wtb-#Xd8#X=WtJe1%AI+>G_X@`zQR}UXlaJ{agN(nO((PLJ;SJwGjQjSgC3?v~1^f~YsruWH!F;^|yACW0H6xfSs!Pm;;`)?hhOHZp z7Ks#3tl3h|;;r0JMH_Yz7tlzDqbr;`98}NY8a_nBa0trdLWe?!q-J0j z_%j%zuxx}9th`E#yaT7qaD23mlVCAH7My{&B!9~?Ys=DmSh$DR1*$wr2eI~+nr#5f z4)WU9-u6?*2)W~YStpu81T*y-a)e$_j_Z|ml`~)tzW80pyEXXhLnQSdq!i)D9 z`wqU^!!Ptq;vbr~=IYR!dL^ehGyM`lN9|z^cDA0_%8?KY+x2QCwdZw|TgibXoy0jg zIEZA-WN<%#6ql6&*STK!nX z!8uwz`<#W7LUE7n5&XN^(YQx>KHS zs?0IXwJp+Qg0I!68CE_ne7)XmKQe)dSR(Ho8*o+W>N@^-3BR{HGo{V2DwwJ8kX1Z1 zA}Kk+-KKYyN1=wA`WiDD8NiPd*G9=3Q+({BTCB8mGqYOJ*{G-oQ<5B78_Z80{;ocJ z2( zMEllLY^U?hKN>>x!EVAsv$d2NoE=Wd6Nx~8m z?|>+sTC`i<@KgY|2ccGRRiwOOK;MvdVmg>6tn0K&3D^hHOyMYtrxcm>V0GqfB)fPl zoDUD#^`1-{^5ps{FNoq>0w(-l0K=yc{h_0mjF?E1kYzH%C52P zqosX(qAucIO8thj>LgoC98E#kcaaW(D)T4pA6!07)YLoW`L2+L%k5IRnM&v zUUOy`1CG#(kd4}|YWJ6Wl(*1q7345DSq~&J+$>z>5LLAkv`K$|OJHFwvCV*K(g^!+ zkk=M!nDz_yz#D-rts4;>n8;NGo)CyMC@X{R7hs!Cloh=g^Ds8at8qeV;OJKjZpq`5 zOZ@s5Zv~`zc+6l27kK$2!`t_DDa+tRO3^G`hDzR3-4UEkWSNX(8wm(6qT-_(C_EA# zOpIaWU^)xSVe}Dhq!MozZ!W@>f4oh6xY6U9Mf+44T1W6H#4Ja1zAVq*(wayPJ1nlE z5x#&Z_|go33I%g_alxFvRo>7fo75aP@Hf7RYqEFYC8hhvm$FxSX3k&@7Y+FQjT z>EeN0AtpR*A5s*jg(|=C0W!1H;W5(qO+Uh603U+?v?616agL3b`E(tmF)?fwGK;V! zgY!h3dXZOx@U;L?j$w}B$S;VrXb04N_)W00V9()0JK!_HjTlhmj4P|WT@vFG!@@cd ziGN?x;)ty%#`E0psA(7(Wk+6XhZdnn=|V$KR*S_b;5k$;BYJlh1n1mhoYVO zMQAyaE!ZU2A4`W!!*hBemLKiwz4YfFQPAkYv(%CD95H80AT#SQ zhl`_2h%`t)n+q{z@(q@#9iKXmuf_}09Jx;xikk=Jn0zg)W^rj|42`BCEWPADetd|J zpA|=KEZYJ|_*|8yv$=#u&_b1+BMYbCnd){XPi|zy~VH>4|Sv>xjb!+ZH!h7hT;pNjMsLZWw zV`@yQ%b7OxG#p>OkjYUbfC+?ov^!8Wa`<48Y4UIgW0jdqUaRbDKQdnN$_mXw z^}Dh|ELG(dLXzEi>*YEslC-pp%M1BBcCW_(Vwt*Uhy1Q&+MXR!0PX&nM?utC+#JVB zL)bDNvJq7tetMOPOXs;Ks|2nB$*oadD1{V5DdCf>#oscs$oWLHpfXYJ5y>gsf#iut z0j0twVsjTEmWYTaC{?14?h%J8dB;-WN5i(B~JxF|+RiBf!l36p=8 zJg>cMQT_%LYDLrFT`l9~=U&4>0$EtOer}lwQ1ThSU;?#S$j=BmV_#4%7)MZ<_IP2Q z1WC1Fg9jPHf>}oj7+MWBX|=Pak?}@0h%0Irsdre?iFk{A;USMwITJZdz>ib0ZW&h9 zA`c>+i#NKsGI=f7N)NXPZSFz7NAOozgFloj!UEZs$CvtQOYseqvbgusq^uN>+$2k_ z4!tK8=!TJ+a%Pna`va&E6kK0^Us#quwj@tOli&kRQT8Y=WHlmHghZ1l;=*SK8|r0sd^<- zY%j7_aT7&y-?PyutKfVd%Q^V1@@J+|osAqaSk8{EC-&sSaA6K{L9bIDbYt@ll&tX_ zkExpm_+0uUEQ$r|`kw>ONswTBFdTxdWn^3rFX}Qt8XX9Rd(9a15m_4CfGqm^0LwS3 zi+Td&(&bekTH(P&mn%bZq4tPp)c{ri0I3EAhoc6J26qxptR?b=w9=%-y_XV4;u8;E z(-RW>F#u(HdDW{9q>H+3^`@zLr?KUn>(;NI*1U6X$dHMz;F2VCEd~jq7B76&$i*9& z_KBoEE=T|vX2`XyxK~6=i-TpmwlZBp>oIMC4Ss~9AA%+_#X}M=9y?WwQF^YXWI^E< z7d}}4hMR4pg4*jpEx07_-_e!&oiVsy#Y=_|HlDNqL*sYkmNK-%w-kCa4L6*ld6hY2 z91%;s*<_8hE%M{qAsM7Eqmj6)UGu^#xOR*pf1aJkbMzHTdW0Mrt3tH4<&B5un0fX2 zRnHnKPoyDFUqkboO(K!yZ!PtGeKMIR}C@Q^Ca96jawr#9%eODvY)|9Lh~y0wY9$4ln;vgF{_F8DrPCwg(Vj%HJC`g z!p?+dg#MB{$D+YE87pc#p%p|GqR?XNIttrR6fU!-f*yHRT7Vqg;0vE{fz$cjKd)=Y zW5F(O2m^>V6{Bno;~ZO2Sfri!@tspkx{&*kPVBk$1T+`qiI5RenM#UgMZ|{T11FC#nQ+;YaY%*Xby2bd!+f23mNE2R4`Qji|O`imX5q&KAtdPsbiNa1=pYT?FD6hy2Agnr!e@_!cD2 zPl5D#oj72*3#63eFTaztlZS`oR4hQ`;UPbDx|ItX8|w##ctSoj zbjy?0)>ft!bF!(W6M9W1Scjlkhqn~WFZ8p#a7%(_ORjX5;*kkp)j}W)w z`CnN0;#NT6uT|{F7?1*;g(U9O=#RU@hU0%nnVE&O_-=efCqoDPmA;T;{GKW3H6hx( zI{{h~cO=0#bt3->fyCd*QecijA&#fNvBv2b)xXd1KFIWoDqzonTO2!*#=jJDRfiEL zlknaRE(k@rh}aBS|L+%dR&5WMx%4G)IUuSZBw1I>%oe^$14w9C)KKqf9GZ!;`f9th z6cybqaaSw9fSF&U%$F6n!fuJm#4@vBkkLM(sLn88ieHw-D`^gx1Ujmnz~Yf;NSf&| zS%omW*=nkLZH^zgsXR#kuU?nv5N~2m!F4W~Fy-#11pMU}De5m%1aUGd(?nTMqA*=6 zyr_?bqJ|TBTU2>XmLf;3MGe_&=eVF28kaT!ZxQ$M2Fh9JYNIguOP5HxM>6EWKL7SE zusSfJI2BciIUvp%D)~~vo4y2)uKZ740>~Sjp4s*8goJkZgLeXsa%S@D5AYUT`3BS& z!9(mmqeveSAy^%rz&$%`!evMBOuU>Ax>+9a!zGU3F@8HUU#!d}G6~u8jX)rCzFZwA zXorY*81ry!S0G@|KVp1sP+5WxiGY^^f{YQDN=HB-)$^L)s&Ca}iW4O3qp1zJM{s~n z(P~dokR&*|%9E@_^(O;7cl7vuw5|*jd0*!yHL%{fuGE_%q5gaXkrf zcI7u>Rf~oi)h=GV0r3`qGUR@}E=Wh2xo7-jPVk6RTz)q)Uds$>r?%M2moYS{$bBy) zA`5dff6sD2ORT|l|621mL^My_w$8n^+c0!^Ts>j+v%0GCc18V^KBtiR^=f>4qPs;u zmh1J%eJc{cDDvqlr*{1=wxtX%R(SDZx)6VrUc0CR9MThRi~i2VYWK~+?4Wlt_U1rd zwGW5#Ci8_T&{)02O9}V}Q7Nv|a4ElAoWkV0xbOl1hdZ*ytx>TvYV?*hAYe@r-wOHAbt`Vh$_xT7<^HgWG zSTeCN@wx5R_xeV^3$5HCB+8S<5^1n%=c!du?{Z{WUw9p1-MT9&ooa{bpbf=N05+IU zLBm6;h?r{bfbhI%QomzHOnS5H8|C>Hzu2g_?WVrshUID@H_6vh>I)Bsbu1+RAbCx( z-zm;lv^OBtGR1{<$rR6YEbJ8Acq@^TKNju^-w2^+3b?m+@L8sz<>lRFa37&U*!;|d zz(^IA6Tb;;5XxwBL*+VS*#9s zgn0%3;uco%wEiXzpLolnA$-rYFdT4S%cub{{fCZ>;Y)Rr<6B7k1Q+MX7t6_~5>lM} z=1}oY4w-vpnaf@UznF4BbWERqeTHi`j*H9Zbj>Kb^1UQ%val1v@e~**pc1|e&mq3g z#yb<`^$C7=$)?@EB<~l~w>U^#q@~@@<+p3C{qV>(o|R#-O5JUuJD`b8N1{wz*jwEg zg+oH+`EoJZ-2D zjHxUiYhc`TXbT4jEE`^tR~4C~k?2i>-C6BS29We1eF^HYLDfF_tuHfyaYW^ZOqJtB zWG&ddm!ENYCLh3-SAWSfw0yQLm-uO|vS#bPvPrv69(s@cWL_Qm(|0OUMS7CDGUM3hB7>Z=)#%|aAST4_?iu

$=B6qk|naA(FJOJTiWZr*7y8<-=`zn?}J=E`26gQ z?JC?peA@(p7sdQzWDN115A^f^>CJn86igK_3=%v1>%cPfA(Oj-XSk=PnU?5Vmd7ZM zV{1)*BZ`Suz9{~j@`m@AjN30=enTmD7H9S{xi7O_XOYQ_W+n-I_ySX^bDOjz%EuY} zIwsA=THa)`*eyVyU80scH|Qr2uAF*BmndC#A1{`dlKOc+y)>-Wac)fSpnCmyi;;8( zKa)@r=k3$)Yq@T3yMu_qvYCt1)teO!ejO|)h2BuF=SX`Ur2wAP6T-~EbK=GYpG4d5H4&$I*bg8Ns956airJN%~D&lP4aE86RlrJ zh$kw0O#H)ZoCBqC-{IA&MO9V%#9E8GR$8aTd*C;f-`*77h2It-dVj zAo$MwWV?zKhw)3GC=ETEDk^0M*h!K09+u+ke1QqH*Xxd_^k3= zUV;nA#UzE)JUKxV4qUi+8M=@XI!b9A=lnOBN&rj>W@_Ey$UQ9MVpCt)HiuCJF<{AE zgm?b0b<=n;5Ymq;z+gID1AqYKhQJ<;5^cm!A#T(Hsti&^&mCd(XgvU-0G@qV4iGe9 zO0R*skav@Q?bs{i$XzqV|H-f9C={XGrc`~`nU`2-j(G%oY`rgtF$1C^o?k-t~ z?yOu!G1%Jq*qtXGvL$&Oo%qH)J03kL-Mt~Hy-je`eA|rQQy}{7Ho4nwGB2rKDR4#@ z?i*ZTF@GGF8D*cH4WYgoBb`||ThpomkYY+X5J z)l{uA!|$y3l64fadx#;TiM! z#db6lIc(A^eKVB`5DVzVo^43A-75ts(@Mv z8qVXQNxBUajha5xY8y#Ro9hzfN`%qhbqZ$ zr$v3%>p3c)h52k(`@`u|U1?D(R`X>NGcSbn=0s-}tP-APgG#9<`{A&8PCRGurMdmA z+tb%mfIM32fd`|AYnMK)YJwE_8eQX?_aowfCmg*z%}5fwwN)=}x*VmMSo|O;W5#G} zDVI@pa7+-DXUG(z$KzQ=K5a93NrvM{m_i;p@~n(gT&=(lMw!e_Y(0vDZlWAZNASQ8T`dIUd4MllI+nWhzT<>7R7Oo&i20KS5a6b#Pw6?(5)ufn|l)9|ORU=(?+I1!i9= zA($jW!S;=+UHfMN>#(16@djO$mvJ%JkrHhXB+;HsI%orfjU{Vy6a1vGT#uom2g^C63L%t;!DFdi)T?uXdUr)P zmQm0>fkc{_Q)v=2a=Vz2JMendsQjR60BThPuJbb<=g9vd5!OcD=e-k7y?1~6?t>jP z1wWWN=L3rUu^^mTpj#9zBc3gyUUrB(aQZB9oHBt{5ZDJ{hV{2;1O8SP=ingzL=qg@%xJ?lKZs=cPtgu3NGiK) ztp^`GpnE3R$3c+jXdBZv?heam$!j$Yqp@T_91~t!X|=d5h1=3}5%JsLIfZhc)wIt~ zy%xqbD~F8b8CfEEM)vUJ@LZ9|1DSlf`lx7QxA`iD+^d^uwz~vb)IpXV1`!!Stdy@|H6==w)-xIZY_7qR9Em$D*q9eQi=TGts1fBV= z{etaPDkQ>)#h=xVr}Um&%AY6E&HS1Q%~a!+Z`t`!my!t>W6BV)9gYC8_%gW@9z zYC7tl(y8WtX0b8$fBHSz7X8A$T1U~2FM5cH_LEVt#{dPtOYtteL+YcvJZ$A+?kycK znA@9_UZ=l93*;*uulx{6=&*9)xUDs%(hjod+uMe>({BV@h4MZZw5)lqn)BN_w;xF<8Jw*hd3x;ZN2w^=y zj0iS7f_O--E$e+$A%`)1@`158xq!IlZJi@6@o^sQDd|8Ak_2grRp`}VB2HBXh55_m z_Cn~8tROKSZCfmq0=2MtTgz~S9BVTv#qG+aJB#NMzbnlC$AEFiJ`VuLEtt*$fX)Fx zf`u*L*#{&T)f6pC0`*Qw6BL5}o=5t+k*+gAoUY%|U;ZpGwWLnr&+!Xn=%FQ)ROiC@ zY#HXl1l8HuQ+|qJ?2uLjXm7|zYKOhNw(Lyf<*m7u5@njvZu$cd1Ia3me_J`gn2l+| zv-mGgweouAcJ5NMBJJ4GX+TzH1PaU1n0g!%YhM&Wfxq#fGotyWuBcj*E1Zr*^BQ1H zm>0pwZ|N zaUE!(d(p?koyFK)jj%>uD@nk$fEE==yTWa75gTnuD9r}I;OE3u{GUOY>bxP}vI?ot{y5KOY%nHTs#JK#XDLaa6rgJ^mZlw$`>KRzJJlZ23wAxVoW@ zCBPRp;Hw{=d)*DVR2t4Z+H$?3Hcs6&Urw?Or|Lp3Yt8uY8Mk+oud|lzWs_i#&RlQx z`TutM{g@iD_y8PLV%AGN^92bTsjX}0R-Amt#&)k!N6so)jzFwL-T>j7{O)X()&%oXiJ$$;TH+)H;*iY1@>mBL z4$qAMnjyvZyF7jL!GIgk*T;(?Txg`o7+R%%ut(M;xG|igJuq0p^@r@kPZf_#9+uRN zMeM}YL*kJ`l`;};4NLd7<>o`I)>T4`3p0D}k;+<`+q04d&+J(RI&5Tzum@{bUhGU} zuXP&b1A&o-m|#WG2K3k?ypoYR`@Eu}7IVa=el5erg;rA!FuiRZy@sONvh_hvQN6wp zfgsY`D_)3g{g|gu6b=c*D7{?`6K}GdiDzG3c1JVvGiaF-?pAv1s*A`p9$jr1gd`D! zfq|yCTap;D#_gvtj`W5NG<74?UM9?3{;>j?D|s|HYBP7gIA(g6t5o8RGYe$tIOW~W zPwj$}d_+q41h@tFXu00AHdv*}R3v@&Z_j{2y@IMj;*QHy%XX9PfUFqC6>0})(ZtU7&agY@j-63tjcnojKONi0mRnr!c z6F+(ETzMSIIUgg{dSQf*srPaAoAR6Tr5j9olNw^6<`$_xZdUrATru?m`;l1EoPvr- zy7;qm|A8aJwD2D1zn%@+{f`yB>!#Su1=JghKgAQ(7Piot2A> z-LYmTD!nQ0UL(N8jvI-|(zGale+if> zn@b6?vP&Q7>+kMDg5{d+OMRkRvn`VDYqo!WspSgP6OO5lQnM}o<9?_SHPMf@Ldc~6 zhU8#fy*1mmqX?-8>-Oi!+K13GEc`8K0%gBnDx47~CqP;`#(J2q}Cw2NJv1}p2wNtwi|IfNC#W%&H8B!Z-| zSh{<}TTX33(gGBtGVQ?yE$YO}?uA2P0O)WUPkZq)i@@qwgXR$ad|ZA5W22}slG9J? znZ4cg7II4Ctseq&-3xyWs79oTDgBcqan@)_Q!gsWVH8qdp~vC7?gV;h2vJZa{EPvs$M6NwMEqR~1a8t2BHJ0T`c=3>NLAQ(3IFt=1>>gH zVE*wh>0PS)GLIH?syt%)kH%)8X)(8*lwWH+P5pA}otd?m)3t=4{x9JWR7r^e2VU3X zJtlq9Fmn7MDKZJ$QQG?Z=y=0VkY~Up#XGcr@8Q5xWH?7pep@l$3v}M+*YuXl!=zlPd;cfba>cGZ#ynV>`z~U}V2^k;#M9CZ`ucXy`o8c8;PP*={UzuT zI3iGeczd}Y9$$%Ujn}p>_0V7rc+?1mLmW9 zn^;ScE=m)wCmp3cO%(k8+yge>r}KwI^M|=m?LIcu4VN-(D(<9AXw{kA#b*h=GV)s< z1$24tC~f05?52Gb2J!`!9J&xska2FSmE~w68WH$xmpserRc)6b$hqoblCF$y;pJfvA{p9NL@gTVI z_72=LNB89NJq1gjlqi*wt$hH5h{Gi1Xe)*#`=mATqYo>P0gRh9Y$3T?;o22d+uf;s zI=oI=1Z1rl8{4$7p*-XvPSpmGsZHT=Miem6y`b|m z^h^B0_S8PwXbU;ERlew$gUUGbBOwKT;ubLuJN2UwNi7*?)Zyh|Ga@rB^H+}i<$2iW zzfAse=C#xBYpGA>?$lr|`&)7=3fL5L$6venFEw+4yF8Cp<}=eLBS!naK`Kv<|7dY< zrVV?F`7U9EhjIt00u&xl7?Vz{JU?~c?=LB0sIV>wE9G>fz~z%4PF!!yR@(@8nEr~& z<UVh)`((lRsU6@h4vi0X4*%ItJ6>8}!Q+<}b`N$T zUe3S^L-YE`5fj0QR0d3>e3p!tNck)oE)o1}c~pPn4FF8teXf<#@Ls*JVC$zfVv%+# zM5f?{(9{dLNdo`0W)$w2ViFw|Vfq6Ktvc?+T1kNjTO7%UoeQ}Ri`ri~tRNirOsFu0 z*Ko4m+=(5)#5@U?G_(t-d_#gDrV@zECd_n;$E8J%gnX1oj*CSGQNj9CcmTx=?E?SM zGKO*x_yfKDjJH9)Yd_VDKpF6akx2hLx=6 zn4)GwU2I}WXBar%pB>XOJCch5N!2P!Jk!wV=c>ES<*H-0G(v=ik);Kkya*Rlw=E$X zT<2OFI>5pBOcP1*;seE#;t3vSA%k2CEIYI_jfzq;iC7U8$5e->T0NiFCtEckw8E4m zYlCK9Hr~D9+FO~BI|6dbcANXGG4r8eC5b6+vrX&m-d(Gm0V&@`FfAum%5oF82rc)17WhYWB82xN*yt&;7y1JIU9AJv3TEL=y4p zW}~t_?D2+`dyftBPTQAT(8ZU#N%BiLRCZM(VOu+}P_1&S?Zjuk` zgsjb)^UO;+qB2Zi`P=V8sgZ@+thbvdxHB?O6?OrQ3Pz7(_a>iSM znl}Bk18$>8P^y*4t9%p0h#tj-hmN|=wq|@3B=@NOO{P6U^npGCL@~1yW)R?pCQM8X zRWJExJ_(s5LEh9 zWWkkyi~_l34AtJ{t;+WlerRWP$qD+@0ya20&`G@BQD|2bW{hJh{c#?SZ<4n~SeD^; zc5}>f{0$)`iZ)8NXG5YyR@(v=?FwVr$^~ZiWRD6a<~H<|#cvh7FO573>TYLWz~&>t zHVzc&xPAW@s)Y}L9Md(L-cKz&H63t!fi>msaR;~LP{*E)cixjqM`~QFEw0UCw%L-} znr8cs3pWUnziG?`PpySJc2kh zN!}cd!rxwl==~R>`s%sx9wuaIr@~vFM}JJ{=9)AdmO%@D7B8nT8ojmDu8XKR>xOB1Y3bWh&N5DgM3&P|a78dO3-NNd1pTeXU4D59YSaw(Mu zaVF$KXI`85vOlLYulcjG?_trG5*H}@et7w6HXv(!-xH&P@}y#fhM;~U(9g`z;aox9 zWY7vjTP0-%-5T-{zzU*NnUo_&XB2EiNfK(}nkwo6JzB-f+(=wPn*F!tBN&9QWs;D0 zY8@!XRE!|26&zqRIOiGjV3SJ=%)z7`A{kQwlPze~G^EZ>(+EGZLVRrOkus{|0Thmm zTV@_rpw3bmdl~F;W1%^WZ1~5Gdvjq&xeOa;zSU&XG~lk}6r4aLHGGrajvER)xd%P@4vGh%l`mK1 zr_92)rY$K51T@rSl?pyK1?cI&H?R)B`Hg5kgmLZcL;c*Uv?HepBY{SEWxau2s?z=-N?6GzTJO`vsrk@lU~ zz7tbiRj>?Xf++PicD6e?|`a>_uB(LkUA^9&Phu#dII&Ln1ESCF~^ z*&Dp_>T4|IXHKcIlNA7c57Gn&6T*RFd87xrU$Y39$?dL{$P`{x->bT~Ktpxto|uSw zS}d-7%gw-VTU*#Y*3&hL!A)3Ca>%;aw)#!4M^mQ52@PEPHo@1NsE>DA47^kLEj4Ju zD6rV4FN{~Tt1lSK`9>J!ktoI_G)_)+`I*;dE}Xk8%^&d8!Nr9Kdiu4>NrI@<#V)50 zhPb|zbT!?JAxQ)<_0Hz zqPv^4`ujZnEq~+4+#=(`@qqwKCH=(!iXw;3toBOn#E>iletyR)78efm4+Ssq%BzRR z&l414+a%_CV*y!LOkrso1D3pxtAOAgqcJRTTl~aOE0GwA@X-a_nbmI`Ir$svG1GHr zAT;uYp$Ht`nD5D|gD0yC7A2^%TC+5`8#9;3)z#@Y)$kDwo2pm~qmvj{2^p7Fh%Ghq z+uw+xf%z=sg%ar*6c;vlc`GI5A*(6Red=cu5OYvbUY5hm2l0z`b3y8P9~c?>8e(|! zJ5qOiy5s5=mTz|_SJ_uRK#%1-d{iUH#o3W^Z8uptkNd2KLCbVwL<9AP5|h0}s}3nU zv&viADB33le}B9Rc2+q`qmI&4TF+Rhd4{PKQp2l~D31ir9z3R6ClmR$;KhZ9QOqxR zp=PVZHCh0W(SKfq@P)o#6T z3-{hXxp5=%bnM=BsAKQ``|~>xhr4&bm}qM@ZVXLR`(Gyl?mE2$FP~suRp}cR<3#_f zWBs@7-H+@b3mCvGfZ}?D*ENI07jRo_fOa^GcXjNA+cnkQ6B5Z-2X;uw zPl%T)XCvJXluHO9JaQt(35=sU_#~VwVxeog{m$mw?`ppN?)4f+FTwOC&j+(~Yt(<) z0a4f8zIomD+cyh%G<3MXpbF%3IqtuCkFZ3F&B&`Rt?QY69u&BZYWyp&s-pk1bCa)0 zykakn2lgrog2l^@&T18Ba(vfBbimp08U!*iIEV$+m>g(AFjZkO7k_RvT%3CT0@}|k zx*~P_#;a+rh?@p-HIsKvPm`Lc_fq!!Hh2C1!wzE{6;&6T+if%?XnHRDI{Xn`EK~%; zQNPytwhjq-DQZX((^7F*D=hG&x{8A+Dua?RPxf_3d8Ut!j?jpZe;hUAp~xTWX|6E^ zRU_pcZMu4hLPqw2BH$Z6Q1_)^^WZTQErZ>u7vnGoz!24c6tJ;cU5(Lgkm(xsfzjdH zLWjK5FZgKnE-H`QP~}DbHe>toJ8qyvcZz-1ZQnMjpaKg6mt?0Q$_gh(%c_a`h<*th z1j_T-Viz%{8UxcVW?cKG&;n}x3g>Pr%XUP2A8OT9SxLn+vr(r>M*X%dq#BCag`^rv zXw--8sFqXO*C01iG^uz67xUV1*A?ifN5Qwl7*}g)b*p}CA#+sof1+Ybu~ZtuttOIP z%%wam{V>YpQPLU#u|tBvBe0bK2#k*pQ~Q)q+~ii?xu9vHEIOm8Q#TW`=ef%y7pI1`|!mp%mLt@2^$J2U|(z=?wKO|~=G2cK{xq`mqD8k^#qsyd9j*m-n991T}W zb1JnMS(ROK=(W{qm*C}4sa#jfjM=IcWHQ*wzRk;*FI;l1YUeX{HBLUm!sVzY{jOCx z5*x96=jgFKLy}+;NRf8y1z}0C$x0iMthjXNXz6$!JU(dBjPXL%eMnO@I4G96aHY#! zX!p(m29k%nN(A{0ncdyux)XOk&PT1hp{*4Sh7KUIbUqtRt{9l)r(?a^^oqQ_u)v$b zgUQ*hwdHyvjfrEVY{RGA2;i@xG}-x6D-6xP-o$Fi%ynzs^|;COCWvfy6jU0vPQS0k zfKS)5T(ELpD=AZI{^@TtyD)+hKq3UGmUQTD-UYbU<9YEsaI+bLG&0JU5wTaOwj(He zOS?Xt7$e7nrn2hGzXXGafz>TysoGUx&kZd4W)S@Mb-a7LaU{Y&X?XdU zydOw0|0%#Zo*?XkDa19a8SQ(M55(4|{|IQM4j`!9}SFqV{eg8!W z6Y1&2a{ns0YM!oJDVMI!qv#4sPGRO!m*iB&O@<6%+KAvC$pFEAbfX|_mxqoWqc^MA z)r9~RK^~~o7=dkrH#tH3rVqXGJt4uBhU5k;2GyU-d1vZQA;fz`yuuC9A`@iPr%wK) z^=u<=&-kyA8jdHHD83zk6r6^8TD$DPTyTu;Zh&erptY-|Fm)dB9F)Qk?xa=r;N4r5S6i-1k8^q#m#WSJT9gR#Myb2T%U!9J3MHbsL< zqV?FlYpywnS|vk+X@h@36P|*Ch?rW*Qx`mqyA#uh@mtz7mTV2T z@GKMZ zHtL}G__M#%eQ3}A$j`Pn&l>zs=jm04?#LcmKYFC%BWUk;sB;?*?h!=hKZVHr9{eef zJOGUBH{Ro1AF>hjIBvEgXp{`~&Ilm5&KJ@q@A_zog^T0Kf75Pg+gD+j>o~<7V-BHw#gyAlErCPII1qcoFP;F^G0njgQb;9myGQ z@#jGS%wQ^Z;aUz$a*Pq0eN>=T2Uj8@@OC#RjD^jiXA3gcs01Uxq`s?f7z$PB0@pdF zV{i^`ok-cwJhE_1g3AP(zSTBc{z(HEN?OxY9!&;m`DTR4SU$3o-Qp8r*#;WE=O z%|Z2Vbd$M}qV<1)Sg3iJGa&oCx|KZfiE9#LOt{qfkgt}|VQ#DB7y!pv}*1(Ru#RxBe zNQNi_%|^@wAI8R{O`L_vLft7A#K=hmLBaPRcQH=eD5To`xhxu}%av$SL0k8q z=o#?)#uID19l1ZTBVr+;l$$gUa^|q-O0fXlFP~BdwdTXtr1?9W{TDyV?72FB?&AqJd-l!Sf}Q+cvXi!+qvd=%9AqK7R>vy9 z!G3N|_S2!&fGcKl`aMRcO@5##W6$(e2Y?yebERIuT#Ltm77a~c_3YTpk7zcs@f@ex zrq7a0{`g;eU4623qzF52A>TTJ0MXrpPq408cYZ%hb%c7ol`;0nt}|c1t7H8>gdCN9 zh%CtHSPXoVzxJxk+|cSuzNZ-ZYUjQ&p=q%E5dX!y3u9sYoGGAXWtxkyGR5#!K5p}7 zGJgk#$`^L^Xd<2DDb-8a?jmwXv2eHa=dN9?^l<?d7YFFb^ z1#&|LfcTCY;E5yGl9h4^*AL|7$&5A zJqj!XV{sH#cH<9~Qn!6w;`t}QKjO94Q#v9bFH?9fxu%sOor&p6_9JPuxy8(bq7COk zmt>la=2pEak?aHu)Ma=Ul6^L6pDNU_Q=V&Dr-Hm>c&CTF40roU?Ut|-c8Uy7n&&vJ z=Slx!N9<0oH=hTOkqdCg=mnb4=zZ=oBjBP(MBl0===6Igi(sEx6$B_0q@?AuoIU*N zhwhO{<|=-9>iHRQM{!(UDy>L+r96I0>n}n9ts%2^SN6NQYArp1m%^o!quRHk;B3ix z7_W|@B|7X2#OsW;(ok18xDaaeDDr30uR$@Bmco9xz4&pI)Urn|t5*B1sR>i0CVLl> zz=ovx&@F9^ENv^0E!J46CTJO4pbbF**9{brKy~|nw1I?-We=3Z7o-lfHfu#?Aex5w zSG{UwjPvDmh+lP6YOo#o&aO}=)pW7NR#R)6(n%C*5`XZA8QW$(qKF@B@;not)~*Pq zLITFV5;Ok^Rz)6zX1z*M+eSG?lS4%NWx*b=*EK1rdRoMZ^tGp9zw=L{4E2$Bc# zqURI&DvRAX7NCbc);$3(=g9&1Y2y-gE)s?Ss^0Lwlb|UU^nsUSk}Bd%*2@k z3r8z;o#e(4PL0zq=2@syE=g#(HQsQ$K%27a>e@YW7czMrO|lSP$k14;bdTIZP}Ner zzrO0R+$;w(FPPB7B&8^@4uZ{Uaq-UaU)x;af-32-(xlt?TX$P=2kE4{x{&($=x9HH z7nFulM87%?fqUel$y{fsU5O~ue75~~Aw`n<3u(94&BH6`_lF1ZL z!9>S~+BR7(Oa<`8O-iFJXz2Cr)8Gz?Ue_dgRdN9EG3`e^l3Xn`kYo4ZfxLCzA_EAK znYY)~KC$t1ig={SioKd8!Uj};Af()a)z+d*aX!6Vx9JbBUh1-iT>!&bec^_kIRA8{ z8`9bw#nQ_SteR|$;&^eZML~dFlTkXRoT1t+Yz}F6Q@&I&zkK`9fJAy*{SXXv&_#(C z@jRaF8v;6slDxU7NBbmLd;n~edL{L8s13n;+L^^>^hzmXB1@uW*=JJ}8Z>z?m_Q9bzAkM_&@yWU^ zuHQSjai7-Gvpt4x{jH=HCdfdnDi^n0#7PT%MtGp>ZjHnP7MbN%H2D%}vj~kNLjzbu z8XrlRvZjB|TrID3OuYkRp_Xunbin*R^oeZ0x@mUO@GKpJl#8MQLHg=kN!CK84?ZJ^^kuB3{F%S^*GS5otQCy$Fu14z>4dJBUkaTf~aGPD|x zPUteMT|mT66!E^2J=>TW7cdjNwyPsgjf=!&=HoaOtb33V7YK0_Z*vL(tRuqGb>at> zE!E}_c|vR3*g+;U zBBN%St?9F*eZGE^Tko?TYwlMmpRFU7B#dSQbk|0llC$5r!~d#TjUoj2?#T{pEn$sUthXM<1r?-sHLs;&QScfnZ)6l(@s=9%32r_VnVxyN;9 zna_Vd-Cvx9kEQPO|M)xJXBSYbA!sbDON%w$4a_qGLkKl-2g9s0*JK-5Qz^nk*5btL zzE#)hWh-;zrZM`h5qTA3vfvvv6&t}NabioEgT~{;u$!`nC0>BW5Y3ndk3mp#?RMA_ zaR-EMX=o?()zNlM@h>v&&aId|oM8hxCQ~N$FknWJHef;HLlmSo1XDQZfRJ%1-XQfM zBNk*DBm9XCm?z9^S2jJI+i=m~gD=oH#|+=khgRxuyV4r2PS+~dd!h66yiz;kJ0(pE zt=Z9<;pB=%NLuKMxlL+j>Or?miwzP#VEkZhVkk8OQ)M>7mGNrfr16Hk;j$i1v0nTeyAbt`h8E%{ zB_mCWMi~{MMc!p)X8=CL4r*^XIR81G=)r&rRNF^Xl^N+>VSpe%ft? zm2CrCQF+Hlddxvbms;;~ey_X-$)@E$iefjOHmskD0E;dM^$TgafjI}Bf`gm?#{2I( ziaOzvwU#5n=!!eVG{9lwD6&qO+!_F0MAXN#jI4GGh0)b!*}%<4bYR%maF^!Bc$?Pe z{3}12K#qM$c4b2MF-Q~M(|U?(({pO$w~@~K#x)|LCBu) zh#}%@fkv6LxZ9tFp|2YyBPHpp$_opbSEC&bYki*tA700}aDO95qIk#!r%29gjqK-P z5W(H|AlueMq)X=)$7ImYvPT5CfTTcVQ?y}z&yI&kKoFfRd9;9om*Wc&kw!X=?Q6Pp zVQvM&lYSG6>RW9r4HBG=%f_MTcoGs8>T;*%{4>iCd@o==TjqwrYNdu5mw}AxYl-F4 zyg|H)r>oADD{Lh9A=L{iXfuhBkjNpkf1CtDSMbYW)&<9oV)aa4;O?x{%n7oLYAfQq zYq=bL3OTbk;2mZ_ z?8rw^IF?6B8Pkxtb=+uluq@p1hUmic`A>k;*xo4ctE;@?(XX;S6AU7rXnE~?5}_lg ziQcuF+)`0L`9wo4mQy?ComNWkS|Kh)s4}U$zd#lODOced-+Yi& zDhw_y-&O?M3*MO8@ly~Zk~j$rT^j8#r{Nd;Mt8X(qegdy=6hFK;I}XE@U7WEaIbdJ zXH2@Fh*u9qVcZa^%MiGOV^%89R5h;PB?mGt#T~XA4vvy0Y0XZ&5tFD(a54EI*ieMD z@P)%&5gPpI%E2kC>hLD4pa;n9W3Uc>6(s|EP|EPDxh}zRcj52(9HIUO{>6<^cQm2K zR^L`f?qz7(Fl^!=`4v+&CIUA5uoNY_2F&wSfO)>ED;X9DS$sjB(k~2JvpZ@JpkcTf z0-q&SvtDf~;9&TneVEDI2NpF%NCkFbM1m_m<~;yM!`q7QB`K9+2mGr?dgUkJk{xdZ z0Km9v+&zE6?WVgGzmvTrriwa<9#A*S)gqF3{Knm%D+F~C_kdr*0br2?3 zTKLjAZ&he3ul#^`G)8Q53oqVz`Um8XSAKBe;?z5rU*KkI-)=+GmGy7Ct#!E#=DDBo zO&UO@I^>q=8Nodtu=x=LpvKD!3yUDrU|m7>8ATGAZ;MP0fe_`RqvF1hv4r?ajtG}3r zvSDjTlcZFnQ+d^$i;%xCIEgA>z2o zN+2qKxNLcTGPN7piv?WQEGsjhfCsb(nMA+0nx*Yb7O|rc#u#r^C%mXbR5=roXH+`% zzS|vB#fh?#+piWG0X};QMjPTW3Dob%Bf(O*tNbDeS6*4!e++qrJ-{k#7onYG!QzKd zQA2T5mWE1(N741#Sxm0~MAKMbZ64sCL*q`H?y*LL)EN-JmiU>wAS;h!s=P_VZRo zZTmNd8zd_@98)K6X_va!?&cBm!}}bX)hc}(1h=RICeYss(;v`IiV>D45$df`d$Y=J zpsza9muwwXg-|zTgsl${cV~}93e|uG&%$-=7VQ{(&SmjqDQQs*)>+6wZXL7EkWFLs3$V;}q{fHIWs#fE5 z>YQJv%o~@67$bwkLi$jA1fvJ8Xpqu>)1EP+%P`psG!#SCl7%C0mV-7kcUA%atW$Rn zd1T}!VsT&IXqNg_kThLF{O0ltlOM45#pz$X@x9A0OdOF|!E6ZPD3gk+?Nrn|h$_P0 zNZTMmH|JS;o*T2SP*}(CwGnI_wGHfBe?P)|HWCU$*5}n&n8~}v)PjuQ5YHTMu1y-KVLt2@mal0AdU}1 zUFm`ZGzy@@ddiA#zBjqdN)st5Y#zpbh!4^*b%S!lt~^=n8XX;=wM4`=N(L}lN@_oA zr2trLu%s6&9>x(2)c8t#!A$+ii=b9nHSk0^730h1cU;Vsc!0{^z|(Me>X(VEWqZR* z`Z!h*!>=uC@9jHU{%klSVC>6k{W5@e3x4*w5G85K{Rs~rE5^Z!mm}0&aF`v=fI%w^(P;2y%z7ifM{@zOTs-X3J_WpK5w>M*_98mfcIfonA!Bse0P# ztoaH63|{=Eh&9oO#DRW(M9Oc7Wj-*}X97bRc?=IzpoYPb5=NTSznEHmwZl=zm8g-0 z#F$5q&u^!3I09AqnGwr%Q{T=CjHDkulA#?`HgtY9fu_r)X=XEHQ?!kloy#6NG6wXY zJ5NYv1sUw)9=q!{na=1>GH(vQ1T^q{Pf=|z2`}@z0|E)uWycAbK(g8e~gdcUji+s zvnNjGw8GA`WaDB=NB;b5KIxW+yk>G$YP2`U494?Kbm029)I`SIgw=yX=7}ssK`v~z zxwt?O=9z5GB3by65L*=4)Y7Exh8uf<8VdS*s8sNxMjI?HUF3=ck`ewKI(K9i$kK&T z={zhE_sc)ndRbjkgoC|c+#uiCsleay-{Uce_yJL5{8O)=6|-}B)=O08X$v@#@psRa zB{Oe?;QAsq1{1(mSS&C_piU8_O~O*xIVf2;(B-wDgEv_lIp3gj3&mqo9GHdfB1eVR z=)_osolbFy%d-BD4FAyt5@`(dU2nPu@h+(YL$mxZDrZUc5Ww!U zcuTPvn#&oRC5?&aUT29lw!+E=UilGwM1g4$_?7e7HAdH)uhI(hZl&eal}3AC5*^x@ zfTH``oJWdpq#aQ}U&-ZB1ZDuVJ+@JxDIj`gBg4q}PPZvotmm z#jT67fg6e<8-neiI?gzykFYJ<+_qr(>J?QfSJ)n=Z+$7Wa;a7>3yPDNFQhMnORxqo zL!u?=wS7OD3^zns?((N*DS%QyHJ?lznE{RQIkBSz&HjYAP1rt(l%P1~TRGC>c_95q z%)$;2B8#6|-fGQF)66d|oYoTP%i;!=5)$#9YOkD_Na+k$DI>)R#l|GHf!Ue?Y{FLt zNS+z;p%bT=7i4u0__MEMbrh5qRuthWyN4V<%^36N zt986zq;=~pGKOrPYjkY-YSYNo9Bd6zT9}ZQbU=&Kn`*{aGXR}}fk4QN|3QTUn-a$e z^bgITtP0HzCqI1ohqGk@03m5FJSX5fK0njf*whPeZJv689PG#cS_F_rvVEoJVD2^U z*q}v0QJ~ty! zUs=w`g0R-zx-LjS*EQD!?(8Cn==ONhA|j%rp_YZ`^no4?t$MUt^SG?}*B(&(5+*kl z645X$f4{KcsaHBqm-$d5n?jVSlQRiWe<(1^soNc`bZ>7NKVLN4`D-K#BArkkRU< z)JRJTPUL0WkH3QcvQBpB9`O_J>GGyg(c$GRc7JUYsCs?@`2+s@GCcK`{8(p#juu(U zMPorQKZNd4V*+?ea(na=s>iND;u(3VMuhm?U%!e7$Kst9dc;UogEdAt3slm%*zB)QI(b;q<+o=6{5ZCAC#z}+-$yiKAb#ZLky zPUx!~(b`N@pkS#AyMjdUvU^r}uej#;8bu(Lpkc(F;a>8FSxV*D&mW|$S!8WHb*zuC zC${L&xh}fSzyJOmd7_}HOpgmYZbnXu$++r6J=ju9Z6#L~uM1$B(bF_F{HMi2vL?QRZO%q?H zm&n_o)x3-WhRIt zv}3l+kvIm&RU<5n!k5|a8{Z|$Q+z^sdnmKpUcE38k+2wcO!Sg>PrehIksz@qF94tn zAy?*vp6C9B(_9>wM74X(QfgVvxz~+N-T+RdpTq@;81ABP=oRtPpo@@0ZJ&A!aw3!T z(K0ark4a}wR}m5r1OMp4utA(ELI%|o7e{}0^PQV`fdI|`-Viw)H4R{y!m~dF{;F;( zO^{O>9cBeA-bdgTk$bt={bV0tsFX%2h7An@WUjgLcrP7XN(r`Mn>0)KW7uVw&c*J6 zr2;>q>jZE{FtSmM8*|o{n8;&z2znajV6tNc!fFOSO5JugG83Hv-b;!8Yb_tF+sc9- z8^PZBH*_-)B=vvF`}7t>j-ND8WwMzpaUY&mbn06#jsNC~U{IK}(A^FPP0Fp)g4jr^ zu|3%yASEzQbs#Z^8tag0+OfIS{Ea3wtccthliLEz4sJwupB5+?hV>7`1RKW$CmR8( zQOva#6@3)P1b7V-1j4bDU&n;^rTmHf9`pGh+5+V3g#DS!C)giz=t7IaVQ(v0s0a@u zD#p~pGE9#8)g2maAx)#_K#B$h=vB@JX61j{L4?vgU9L`cN%~3F-IWrv+evMj8*24V z)i+5v)F?q2dbT|E!cTJ`b5%ToslT0kZT7ib(@eGC%GTsM02k_n%+>>PxCVeBOW0IX z$-DJ-6B5-^>M9~6GY_Z-uor=ZJWKTrO%rgQS8-Za^Gx`3V=121-VuFqCO7r2Wrq|hRa;jx4Vffq zE`_>ySq0w5i6i*`-xBWQwseBrk`@RHS}}l}3eQV(K3QGBKzPIngX(XJgf*Tl5ml_& zByud{3Ie)Q?7lBg7%@JAh$A;uZ{M}RenQ7_db;(}#fsy=1LlTmWjr5U<=+lIzaY*^ zT=)K$q;Nj23g#v#y1p_*^MyrI`7P}jL0r`Zdk_f#mGJs#2jh4uXHG!2^f<7pk4eya z05AsT5Ro54NHEq3fsi|FAHHi0$r2CxBSNceFF|^{+*Zv56@UWeZe6{QdQQZZC=Z=y z9ZWkz_@^H}^&-L$qYkQx?c7-$sZ3)QgUwz~1TJz;u=Cpe$bQ)dHFP%+Ig37lpETt5 zgGaXI+W4Zx9{{_Vo8vOV!6D4=Kh)M1Za)P~elMmtfC+AwKlfmo-MJR|TPG&o4QmyD zGo0J5@Bd2e#E{x7C7?*6`tkb~exctfpMLxObN`2E+7$r{xZX|pdJr}*iY{NnpY>0} z811P1tP?XD239iaw*}H%G@F)a)^4>=ZR;%$^l#tRi`Ut*eOu>H_wnu9hPSuV`EK9w zaQ_hVX>My7=CAg6IvRj%K+8~3cl;pVG(320L;h>S_`l)qqo@r(FuY!xwrJ-qG9Y)h z`T#m+fefC?vNf3Zf_IhN`D({2W%6g;VJUBHur{j7SP5uy{fpIx;^MrmE1$VMG~Wa% z?&Js4?_avXLMx|RnaW?!jH670dE^eGcBhf4a*w|8Jp~Ae+W#27HCbOICTgH_nM!B0fu*1=c_H+1clS z0Jt!V%p@|8*G=Gzn}-?`xB~7ML2{gfq91i1*qZwgoc~tuMvdam=f(DV9DnM`eIA1I zfIQM;66&~7p6;;d6Ps`w$AH|;C%)jFEX#KTncuPhqxg=&@M(RGVANxBZ{lBVgzdQu zb+jM9r=@tK%&r?f4w@eC#LU*n>*F`cH6`avg2YwbnY(L2t4f=1w5GH#{1rvt*!565 z8RITDOISk@J5jl67T4nrZA8I6jfLl%+?u-wC%_Tdz7=gb zP7CzKKAdfj+z;F5b~!KZIafk@Rl+z=;m>89Q{Kec^UmN+K$2&GF7Ly=pqcv5Mp*mz zVFum!CyzG0=y3r5Y(-C{Sc^PbvJ~Kay>w*uLVC$NKuUZqcOg2R_zQ^N@3gP}3EYHJ z-@o)u<=Mk?{v2J4%FE_G8~^P7`6NE#n}ldtbxkLc^{W2)6h7i9ynJHvhn1&5-f!gt z;lW~b7fvgXcICjZF5tU!m(JwK@tH>ECk>QO83#ps0e=H*=7%pof2E45h!|Mb8;Rw2 zdt&K4@1Fn-6X}Wj7vo=ZD=5LK1#Rj*{Mp~(7H}+;{3*RZ3aRM}l%39Wu%srceVGhY24sgxx4$iYQxjz-CNHr(;MsNf9~q zyA*Mxs9I{2qNUK-FB3E4aZ2=-NH#Vz@4?XlBopbfI|2;_-kzhT-C-S2mcoE0tV8w% z3ZXXND!R;QKRidr`+GjWW}r9%+xA8nMYiTQ4UgTMH$UiUMxeO3(36a5m(us#+ z3`6C6kK;cZ_wCyVIDT*M)`5YorIP-FHzWB;NBom*E&Y9IyWlU-?6?1;|93Xwn%1w2 z{YSl~1)k~uhfb-j2qNQ-Nzr|JS*;JYIo~c3F=`?M!LgV@QZJ!ELU&*a?;eFixR{3t z3TAi`F&7YKnuzV4aS8y4Vc3Y|0h3+2#)FT&^56Y!-miqw?UZD;f_WE@6h4N2`h-wg zMc2?W3Zv053cHTN)3>p!zfWrulD0pZ??QS}&6_QrYUG4KK?43tSOPW*Ju1Nki8wY= z9PU-)QnrOCS4|5HEfvmswR8u$LkGA+g+0ky+a}i1>O$*UvYdqWw=W zaibu`;%$rBs&XqilM9z#>~J=d!?7eK4Yo&ESUE#ka^)1So4M>Jv1C`@2qO9_KdPd9 z=svrCmvY>|cay)qFz&vq+BGyRasBa$FPZu!AwTZ3#k)peBChOgB@(fZK)I&E%|xOj zFgZZjbM2N%yR<3$t=mPxrxiEZx*Z->EhZnIV-?j(H&PWDP2~h@ME7i=-s3)9>UdJ+ z_e;*roqOh$AG&X^Z|y4%AoXYEm-R0-FpM77)>bUMgoQ_u=2fkIrLKx5i^gWF)YX?8 zV*nM*7_gQvF4Sy8$PktCx`a~JW8X6mElvC5C_9kI~5G*5+lKojwC!Dzg zqM!WkY!y`o`?Zd#$un?vYR=(V_UAs!o_J+lmKBVA^$-+`mN&k4@mcyQY<1Xkb2F!= zUdZMDD$nm((n6t+y!afE-!fiC$I-9(v$OBK{QSue{r(v^I=LQZPN+SSu13DF!gX?V z8b7E0*G1y9#0XcYTP|*hzz&J>B6N8Y(M=)tA)DNoyc5WbBzNe2wcQ&f`c3!?I|Pp0)Red zFec|$?eaKWYu$jE;BNAV!$ri3K(LUn5emY)-d9qLTKt$=bupxKr=EXh3olpV$iU_q zq$Abq2XZCBqdYtFUB9-LTij-g2qYeL1Ti8SawzA>Hz%%XoiY54kE71pfa1d9lUlBz z&x)H~wI3Oqf zr#n!8z7uBj1Lo(}Ihd75W!r)M_alP}9C*l`^2G!EGyHh?^MTeq{CW3L{CVfT1Nbw& zdYWH_{y>{wCB8p37@VHbE|2vuKG0L_3T+MoUK%iN zKWJ81bg5yZG|44u8j@S2X`0xw{O$K=$C!HOl^;%j$4e_wdq7~ErCxyL0t9He%_ffL z?q~0)mbBa^YfgM$mypQiKI3+4@j;*fK2y0}tI~bXu5Cle(_7h9&E$6{KzeA5bWM@$ z3gh^#VDZChOMxdTNkHfxpnwr1Gogg1?Ra0 z$hjiebOxL`Ma5Ikv+tO|xej-et<6spxpMxxLvrO1cLW0@BZWmCfl%WlEAj;upm6vs z&8#-4$cjgc9MTo`;n!dzqCEn}ZE)Mi^M{-ByZg`y#4!BK<2|73%pwefCq80R5Pl{d zHWR_Gjg%;rWi^kA*!a+U1Plk_SSG#|NG8k;ttedtM5wBmYEnh3O69#+a$z#|M5;SR z`XDfd)WGWLUnV}TvmZmS0xrEL@CdKV9d@^W(c#MRt6;s3z%|!BDzKV3vEe6CO8M&^ zl~nTaPd4P%Tn6iXY17PR+`Kio(HrqU6MX&iBbOj=caiV?>kZy_*2S^R~hU#DnguphO*_=Ez*yl zE%27YLvl2tqIf9ptQDDKPl7(H3OLe?c69{6K%bnGNj%~$W?A787>I-tWbMR~1pEAi z;hf>+Uw04OEei%4nKcQdS0FsUp3PGqg^RBC<@e8xTZAc<2FW!G@+Vm@Y&a&!v3(9# zdZ!wNAQKd90)V66GBUte61G8nnIEJ< zCH$T?0X#)=Dh9e@qsqz7OWlN7YG|Sz;R4PYVO?AM%22tx z;I84QUv)z^0g)$O8-x|vsZmoS-DP}?Fg)xGEAtyKW^Yv`Ng2oqt*h+_~4!z8lR3GB5gZV;&xVclJ3v<0EPaytb8! zY-=Je*sHFCea}7zvNXUT%TsNYva=&~*y-e%%#KgJGy5Ip8um!hH4u#JmWBz&BfUh^ z8u`*%`3~;BfA`@7CQ|@jprI-(z%aND0f8(>E}>?{LB7gkqy0sqzL~m?<)kHDcd`E% zOnl{D6!wO9y9K?fuF2H-$zG!#Mopg0!P&qP=U~eBWx%>mJA`}2c5wA1v@ebnueW%o;w=a zoIluu;v3j>oB@FPP&UkBy)fo$B0;(3_R%ot$n(nb~Oy<=^Jhz62-R7n@x&wERw>6%kw%h5RVrcAQ#+;+Pjy?C~ zaR_jqx*w=*S)9+{pjy?@v#NSG4ce=w$h$3L3yv~$n-&ILiWRr)#%Rg1MC4J8_bpCV zzd74TM-2r!IJyMSb|&}wS?ii|8*n_l0U#HWyfjMhhj0U=Q86pHuZFuIuMafMs(c#f zf?Z(F6nUgp$S^Kt*Hab7%ermv@?1)5P5! z@)W819i!zTU~+(bDvS=p)}6VsC6k-R&tJIY)>X3;%;OkjFtzoiY;CetUDPV_fv2>s zo@|&c|G4^GGxrAElC+v){Ave zqPeGGQPhfd@vI+8!c-DdY4z$BXT3AZm0Q$9W+r6aG|x~naqbyKaeycCw>|};G~k&D zXxp<~Lkwgo2X9P;6c0(6;gh;ZW);|=Thzx2@&QtT;lV;2vLdDPl`-p3e)89It79&N z2Bay69gnUb8i{C-EDvQ|g1XC+)bjM-OTtKGZ+3geo*;%m++uQO{1-iD-G+Ki12EHi z@lG*%?DO7g-7Xf6?HVdj)T56!V@6fPp}1Kr0X_s`OV;NC zp4x5Z%Z#3Gt?UUB2kor+%l#hpUhU==<_KU&- zMASO%C<>(W7HqoF0^39}XDoQ-nH-6VgmN(0vjFHt$vf9N1hf`Gb>T_KHx&j-Sw``g zDjzB1k;Tl-aV;QCf^a@)6v^FAk&Lcz#;hCO__K-IVPV@h^@0&PI=ngGh~9@WYe;tm zW);uqC_$+&LJOa2^r%NY<9CHe%VpdJjA2G^e}3@`Jfd@N~oaL4fN-C`Y6re;i853h71Hbz{nmN?&evZRd4snF*{-+xh?5AZ{UeWP)zEDR_EE^> zA2m@AZq%iwWoE-Ab5(KGiq5`yRjVp`XWT&5dyL&aYl9iOPJ;9HC8DNISAn~btN2T; ze*jj(!q-VnkZ8XT@=q3XU!qP!H;bCRF7;E!Jld?M$4ifsSK(JvR1q_)^&=JK#iE=f z)u*0+`DxZik`TD{8tUf89z>~%$fKaiiRrqq*`sJE@aYb=M+JjvYCWZ5*5WSVEO{)hL`;eR4GPBkb z?rzzO4A8Kw`X({b(v0hdILawpnzR3atd-A!itozpcbl?wFY`@~LKT_Ax5R}p6R&5e#|7UVy=Hi3*tw6V! zt^|2gICS8^?t}SVJKA?=bX_|=0rM0)@<9em+lqsQW22BgGMZMu(!ug{uYca1z_NV+ zTbk;684asW=6plYzT)6K1KE@=ZlEfgza{17)$$$T{lRB_rPsAuyr0rf#>Cd}0h8HI zUlxy=7=uWxre`WJw4d3JXAs$P843jRnS(s>9%s>&<301SU!Ttpe`ufBSC{Cvz3vCM-KWi&)~*>mG>H@yjAo&md> zv60GW1s`pY4uN^r^pEoj538NZfzwqD3VrSe0%3vSKK^>xHVTi z$6rB%eGS}DPyr$~Ky8w1?Atwn(kh_nF{;-YHL7@&m5!P7pC(|cit|9})>yS{`tnN+ zZ*B4|HZq!TSz1BsaKXqW3o+SPP=k>cBLQ5xKIpximD07!ex$qen}b%{iCf7{dgrnD z$hGj7`&h~(KaW_Opop{H&COa&1J^67Tli#P}O$mXC z5RI>Hy@yoaXd;T-oraqpj(s9=Xxb-d1m7`tK%nd?Q>>kO=iK=8BofayPDVE48`=?e z5780v_aG7(8#i)cPODl`O@&Zc&lO6QbOF@OA=r*Sju$sc76n8A$_~VehexI~{w}vk zeUzG)L0U>O<3QX?v0Xe1JxF9=Qf1QI*4cv%fU`r2PJwUpQHa-3%6=*u8DU_62f#lm zzKNmyCfPKwX;|0zcua>`?5&1OiY6t`(vDp-rO%jwHDlN6;})-&$Z)ej^~F*oWP}!? zjIQcPBo$?saFuCCBSJMn7U-JDvKuVXTtJR$E`i}UTg9xITm1@#j!Eq`?W0;wHB)S_ zoBPe&YHS`6vGFau*|lGgyk2dl@SvOaQrp3U8JmXvS8;Oc{mI`zU^p@!g(x(%A0Ox( zLT3Cv7EFf#JkJ4CUq-g+n3cP_qu2?lBHOT_>a&~nVzkLrm6p7in|;oA@^;|q&+AgV zNAv+noJbPmn{oKqe5jO1Xd+4Q-VW%D{eZbsc~DhUf*kR_gxe4>VG%V{FFhAy*5he3 zQZ9v05u9;>m&5`(G|32;h%TjeYG;qA{v2f<8QSzNlD_GkSpvQ2l23D46rf%25D z0e#V$>0ezqMaAOWoBaRrv2)|1T%0)nbOatW253`^iqIX+Z2HC#CI({kFKq!XMRCpa z2Q)&fuS-cN{1lB!2*>NOIdDAkyllVpJs=tF5gRzj)~4@o@z3Kee(zWM#$N+%xDm?G zrIYWnpYhi&oMJ!;XHMU(&ME3;cI?a(gd6(32z0>P3e-==Q~b zd1wO&h#eRmFf4_p8z3(RfD)rM5vQoDS z952GEZmro@F#^-&@Cg@|S2i{TuX-5!#WMhxf3BQL6 z8%4L814A(p3?q7FG>uLH!If13(bomspLpg=*a4cmV9!CObwo2~Ga`WFJHBQP~p+9QquboGVuZ7d?MyZyt$F2o{CWueT5SDZpn8*%jj-ZUXWJ z(-IoBRHmM_m;zt7F*Jc%%(PBGZzClj6$1@ELH(jc7&6XZwiVvz;86(!s=CA%x zGEOuR2ka>tH4ihUUE-WG+AojVpZc=bx>{RjB2K;%GcOC~n_hLAmU&C8ZfPqkxIUb)E^BEWH8h_E3kUQkMzPoV@&EBgfbcP{2j|fzRosAE z2B=}Q})+9hjpN*MB{H5Sa5e>QR@(-G9O_moJ=}rnA9ak?+aQ z;FamFSWJ_~Bw+)J1XvSwm`9p@_&yQhPAONnkfspTrb)W#d+0@sXg}jb(ID=nAk>y+ z7>yehl%KmRostLeFT`-q>nqyqZ=cm`)j&)EMoq&L@^(?(DCt?buX4Gt@YDVb#)|oy z2aMTcPLTzf2ynU)v(EK^oQq^SWCZKkM!JNw8m3Y}g1^qb$5@0}$+|py;!RVUNMK=t zG^JQjG3g^RX@P_}#Z0BjZs5&93AuTi`bi*Tbg4UJDOXkOhwIj;Za_(P_3{Me)65ku zKmDJk-sL+?zyfc2l;CmS`kO%>nsZ+|lRH_35Ih7}Nbux7oSL(C%vHVh5(l8Y`ux*Z zx44VB`AZs7jU0XqmM)jRj3CO65mY;(Vg^-vU%R+|pm@`prGb_i^SBG4yWio{Frl35 z+-ywoJ&=yHx!m#C{UhQ~>gpo5c`P{-DLXgs464Vb}q1Dt!sxAhlSPdV-3hpE^9dK@iul_7(4E=b5#se zYn#VR^Eb;G<$?PXsGzg$S2VA~6VXiA%rE_9?sIO&)$QOurTmkh3(gwGDU@pl@rw<6 zWBYMbs2CsxkV5mprYo74Rap!zTaxJ7FQT(j^PMno8K`Zwb0K*M`?~(22gQaVAxdA58bceVFVnftL>Vd6y68DQVL^ANp|%`TdC zSLw;h`EG_GiqW!N5>&^P^UpoliB@=OIuc_hcji;L#k>kqUAuKhhX6yl?cvQ~8ke2u zdI1rApjNTse&%`*$@B!UORR7-50zak)g_MC~%8spG)2B z?!;y{0jfw-SI0j$P7Y=?u$+;O)#@tiR$6fMDR+138A1`s!kJQjO6cOa2aJFt)YZFlm-n^9AQ zI5_*v`L}4gjbChkaDOz_uOSi`bN!lvP-DGUG1rLO&FjC2=-o#d4Ce0a%3}eRw>oz?w-1*p-qRSs z-Lczwc%OGW#|8qovkI`{=iGH(Lcw%M+-UXm6_Q-{ z*g%!i8}lxb*t9Wg*cbZWn`?CoKwt^m=l8Z|wM@w?nl{jqS30KNxpct|a{WG*-&VL& zTAQkv&!(!~_-oQW-!pOK&G(aZ=9M35xn(B!zjF8tR7)mXA`_(UKDqkB-+C2T<3$|T zDRXp1wivvi=?Q6qM!YSui(5f+xn7!9*kx=y@G zjIAh?UfU>MM<)Hds0u^+HzU}If3B0nN=6H>lSFAervSPb@vyk`Qo%g42@2{0-WXY)_Du1VVv%C&HZ=n$yb#wLb3 zNal(A`^pcDcIF{VNsJ5J0}OX~3eFzl;A9J#eFllN{xjAmG4b&93u)Ln)}(CcVOu;#bOdio(QmA=%}r7q0TMUHllDfu z>nlCJ9w~3GX-7WhA{Y1LWc6@Wz@c)e^X3jNQ!CfN317XnThlL<2fQyDRD?L3QwjBfJ06& zNh4CS4%KMKw&Ln1{`YHc%0hcCrq*a#H4=p4K#p zrdUCRyfywBcnqld$$qLr>`nSj%ff}^eWnm}xF^U1(=)T%rhaJ?{b2n?%(<7vDUdgf zwM>~5vYZ=+1z{_|_${ywcH(D|F41CYhT61=Nf|#cX%@8tXE%CP!!c`JYT89sDIJB4 zjlUZaGtnUa#2Tsmk_j6}F!E=l+UD)8g@`5CNHSIv1aF(l2}rT<*3V|k45suVGwygB1Y!D*pk($1x!oN0pOIEK6S z+RTM>mw9_8KQQ;}qnvgT=RbrKEC1u$8NRd0^{;LT?8CgW$8}!`%N~!C-qXjgNHrkk zOyV;z7{H!UB8(DAv3sKwRI^+Ias_zfC~`Q%^$g>)umo!>)G$I3H$a#XsiY}DgortA z+qx6Xmhw!os|!I=Wu;)l+Yv#P{8b)B1n$dkE9QYJI{NuFz2)+7X=_W1W#ui&(q)8X zZtSK@PJD@5^8(8xwB=s)?{EFgrcJ+JJh~ZKGIwEZ;F*m7L}hi8BXe6zal6bGdEyw0 zD68`+xtq&pJW#=JGY#g(^9RSiNp8^i#+K|Rar1E=SW&*Wr++yAWFJJrj2%MFlhN|W zIKPFln_TtT7bcF31Geu>YE?`RMU!2EGv$^bkHVk58Rf2CvJ*v5x_U#OE?0Zt>t`?b zPq)teh3mU+S8orvIaUf^GOdH5#&vHTnF3eQF5oj7bIoswnzu1kR#q>!QnS<4Ss5#*D7oVLt za{g(CV8j~VsEwtxM_b=u@Bpj0rEZdvWC*6|&^Qgc`E$cppOqN9_`yq_A+#i*G1R(V z#S))AxKZnDRv&BQ40TYKv=+MN)t2ytnwdmm>KpQ!cmYz$JDoTWrX6$*Z-l=T1uruX zq`+I|FO+vpZ5TWr=CXC~n}4Cz$hbl$Y4g=FO2a)}Ol@c`dBsrwH~!-~xo(dDHj?{RMca=1sCuucV`XtD zCO_Rg`}`}f(j5dK?LoL)AZ%T_0I(Q-qR$f|5@Kt(k%4gCf+HUeS!W+yp z?j~`8?7LT1uQ3eOY}>F3$?_|$q5w~0JI-C zhBqVs{^B-X)zEi|_cQHh@Vh~Ri?iPOO8Nk7b{>@}V?Ep~JwQ)sTv&d+!jX`4;pHx5Ou0N$bP_hlRcU{45G?Q6NkVz10m3LlG=W2)F?ymD93^ zW9a~uWD#vlE}+mERE__7Jfd1l4xspBpVY%kZqo*x>+}cbPASn+O34`#_BL?@JOx3B zYASS(yXnAasn?S|hd@Z6HM<#74iYG1Xl~Vv8XSN3%_x{35zR;dTndT}n-w3W^pw-m zDqpIPQqw&DE7?wyO*1jkwFgnP7-5kFmU4C~%t}&C*;@u}2f1Bp_;GRrSDqXHN$Z?M zHWE-m%Ovg7ZmU*E-JXL84`<3}8YJk24(-dZyQGSR58aaj7nWkP`%1ZFAJ z>k)sYcE`>dsw;?ZV2)`+xH7<3>{}+dx6BKPU6$z5pN~zwL$6Mh7TC?}A<{v&SXMk6 z9i%x7)*UHyT0+i#Xi#`ciL}3%{4nn~Wb;mqCq*-;OZSD=vR~5@YdDp^F50H;J8G>*%Jvm0_^ERSbn_O2|zhSQ@_k~<16hy>e_7YW{ zKn*j*&f((AY4F3&<25jyM^%m2#Z@LXDQ|9HXD#m}!WhG{*_s4Z3_cE%$I~Lr)Ew#v z&5eh|ppvN+G$o&iTz9z5L~Iv`RHE0lrq|fDV@7@rZr95jqDbF_=*+hSti4vJ2;EBm z6ajz&}BiQNrn)Z#&7>A<`` z`Tvyn^|4W2=bq!Nmr_EwBqa@PN$!LOY8o5ckPkvA4PdyTB@P9L7)nb0F*ehTJyUyJ zAeUTKZF-eT>8g>stL&;;Wv{B;X0ORo;9j6LUChSVtek8}YNTq@RsYBz{Ua-NcT=fX z%1ZnDJh9oq@%ZSSf|8PB}$`FPHAp6?Iv7|GF$AEGJcHd62q7jOr$z^r`ezck`gT-xp`xwk#p&`unO8^LkHMd_SysMrG! zWRTv~u>RbtE{t7N5+v*{igrty98d?@j6SvAq0HkioG+VLkVR#-&zbDH!27tz`6RhPD6&y?B7DgS#9H^=C_Sm z?yLI!I7p~-`}hA$fP$F>!%|*f9Dm)vS`E*tc~NQ=Eps*@r#wFAM|b6sfYg&qnJoqM zRfDHQ@>M;zP|88Y7qEa)e`&L)r9a%Hhti%aBP-`g3C3GV+$32L*%X}8iY|%#p6oZj z(pQe>{bTYM86BlkVM->32WEMQA)JuJ5IbiwMVw5L;ztzt%FVvKKsNK2c<=L>r~Qe2 z+H6215so<<;gq}>m*EmvM4K&wLODbDloc2NW{o^#E=|;<@YBi2L$?&dAd3L|Rjr7C zlnB$nLK>yCElzXn-IHfj_Kp^zvP!^k)F2aXWc?S)e-xKJ*hMfIMu$`rkOQ+KP!9i8HYDTfC@6!!hkB!%+blKJ?*0l3Qeghi+WbGc>y2}lr(sB^wt4f3_bkFOu;*27 zUaAv=inUZ4q#HCc0MUpDrALHc1}5CVa2*jorQSsKHi3{xS0nOGQamlg7QF$lH<}jiUN(ENycZ zZNv@>StSPu54BQsX3(iP{lEc&)k$t(JiqZ1e%L|gIPx$=HP%G<@c3;%Z=>}oIX+HC zOuQx=f?6RTmxbiw_#0`-eq;Cg6r`jg z+6Cd=O9nHOkv)tTQX!ztJbjDVOe1t-;l!v62%KQecyOUlnXkYPc1t5TSXPRibV*rv z%|u?XXJl~i*EQ{T-P?jRvjp*3sWtXHbqEt&zdJ0vPr} zKxL$J8!Fb`piP~1ek^==L~cXh2+I86OpC=Q0kDB#W%=zGDqeqa(U#TU z=*kzYfYwqqM($*Fq20yONJ&JrB^1TZG|0=_Vwn9=KE1jJaFinty<7Jz!dB+ofmTIi z4ZITg;4b|1JLeuic{TWSi0>vCB!gji<_v5luYL7jj>8N`)As2Mo!)pdJ&1`-BnJ`n z(u8MfbeL64lR0fHgdq_skrD5D%;VDBB;>www$l^bolpiapQJfSo}Ft?*BiniF?({u z=wyoMPpx$#wM`>zLrp0yuVcX&RICTOj-lKiqAtNTP(q^6RWd_`#`Ll32X2=LiLJlvWY4HT$ciJoer&a8kR_x=QCMVH-<9M?5`%{@z7Yuj>XV=ZvnZq0m?{ zy_tveX2aEch>EcOwZq~MludLR6*CnG{O#U!LFAk*GLJE9Ycod>SNA0TW0Y1ApN8=r zW9a%36KB6QXZ9ertse}ifKi9g4tYEB_%!})7;k7~p2ofOI!JvlG0mvPtOL>|V6S^pQ&zMU@*|dnEs4z8hq7cx`d0znOnEyUM_aqSi3OD>u6@ zv(c9nt{=Cz88tN@49hGzof&^lTl3K=?ODr`ZItQvvRoTFAuAINp=f6D=r=E3VPPmX z=Zd{9?us3R&(!@w>uxr;ZP zvTWwdxG7{9j3#YF$=vmsC;Sn7N`@R{X+#Yc`0{pQX=8TB`X|!IZ#etX%$LAgAIFGY zxUD6*bx0IeHW%)+Bt6ShBx2y0IG+yKadWG zJ2m-F%_Ueae*=a-u?)a`Dgvb~n5{gqzY|^J(9A^Z60_4joy^3f{`VcEdnYV?g zyA$u3V0xnPvkfX1`5{p{d`@gUWuCsvY7AuLVZCPzFjObAy72Uz zU8`%<_0(=i6YuH~_@zG}N#+J(h!lOKW$=TucBwBkCX7K!MT%!f3W=q!Zy&;$scx*q zTr@LcwHgG#vLZ;H`!S_+O&h0IA}Nn+sDw5XjvVBa@co*AR56Q-oR2Dj|iZS)OD}fhq1znL?=@XsMP)gJL;cgMaN3oM}7rmguk^ zsd*A6^AoX6;%C>Ki{r1qrA6;3a*Vw@@s2fO_uFq5wN@L@X)XyR2ZY6lP)kV^y{pS0 zW^A4_yOf)bQnyr}hF`>uj|-e1XAQaZ5gOu%Md>k$2_Q$F{I-jmyVH-`2x%Kt*3{di zrG%lRgWN9a%Xg+soVeNxwv~qpcQ^CV8zE%y=52>RSw!IDU`A_5t`q{h4@j+5{WVl5Gt_B-M&;t$4Q?-FJHM}`LJ+18SP-LO;VfE6ukTO?qs75}1zJ4z&gs5T(j^GOt~YhBaafD%zA-thQ=05_u9e|ai1^CNjgY90hMS2fV zm+v*hwm@2ncpl*a>i`G^KriD#sLxcS@YxyuXcyx+10*r1^M>FOfE_kM)_TU1JKOhe z-_y~UZQH(Ud&l-hzWLa0RQ}p7R8}kn8bnZW0PpDmoT{Iy16_IM&3ACq?WQ$>ij1IK zOt%Qv&DD1mRKwlLbG)ml!yPHoF?zsTn;477dgAxz{(<+`oUk*SCZHA2Ml^$4>Bc>j zSOL(YiaL~OSE{u#&J|G$Jxrr1{t&O(A&v}4ZELtM(LVt#1CZSc<0LyQXw_>~ZgFx= zdSjaXg^(NTFROpR3Wir-SqySW2O-Yjym-7~<&N#4Y4)lnB5Lul|s#L;M~=&_qJL%6*bM z#G}SteH2=ii@c1JS$`1UaR)&-9MWrW2z$%-rroPOk3NoA^|*-)kGl(`MG*-of9G5f zCk@V8l{!E8jUvn%0&BatA-L5oQFtgSk+oSgBp3|#M)Xyr1_OB(1yzNmj@FO9L?)xP zwl#WEpTD$XvYvFxp(aEsvPo7p5J)`=SdpUb!8ltp`==K2YVcRW{?dx^6{j=2a+y|5 zlVNS>=;{H=iMR3QLS4n=CQ3IN_vjcS)-9K}e(F64+t@>#DLRot%Js+3D+;x!YjYcZg(0$3)7R1%-$N zvm+6tN@0E|R4s@|R3mzDHeP>8C#kI4{GWp;z0B2qQA*xsr(}+dsXYB*6BeqIm6&ZJH_L#Pf!zf# z{Tkx8oHneKezDX3}NR57R@JdF$ z&ob%;(Uv`D&C4H+)K$+p=fSw>7JApe=P z$NITuiZP}z^VL)TV21-@i;D8hdQdaR>m^5!vC5xrn!@3qeBrXM(GlOJC%JeMA>3sp z#Ih=U!#Q|OZO*tvXb4gFR}JlJkcZSi!rm|0b_!0glJyoK58-}vLG)9;8ypZ!YrT z>=FdcBS;Qo(A&_lMrd(E{j+7)`GY+ zMVbZ(gSSKag&Gt>c~BLH@}M%b45~EKEk$3t?Kj?Yp(-kQ#N-avWq;!wB@bH9B$=i? z)1==5Dcv}gmNP?$Oa~F7L*;vjCf$W%H^1=*uP`8Hv^RAhgK>>dn0bi;eNt@UBib0F zlChO+E19Q6n=RVX?0dgO+#g-Okh~W7A!M6BRZm5{DK_1f9U5{>61p%e0u`@^$?a)cEA%1K*+R_p{zkiDjpus`pr5U>@ z*3?d(iFQsK{kA$Mai$DU=*O8Kwzq8Ckt_xR@)$OkrPG^ZoS#1VB6@G^dU@BCivkj< z#m^Fms`O8^otn;|;0p<64H@*AhR!uokfjU6So}kZ%blVp!51;uUp~xdD$ZUneWXBw zNu#X@9JQ!e&$wQJ&>G&@PBH+RO7v2w7>0h^uM5P)AWPyqeA!8RQ@4KSDP=Elyy zjb2#}umr-?!qXXTUl%;{N4OE9HQL&z?g_u4#~N^20pX-a>=f>^9%v+vN_GZU{S{j$ zR?R}y3407_vRYhJn|DVlt{ge8Y(^9~>;QYQR(Zjl?D0GKMt_{M#)%UG`q|+v+6Q&s z!Qx;Oo1NoWoTAsIbSk(VHtG;8mV#3(MMb(K-`GJ!o2uT<=nBQW@eMRm1UGWXHX@aL zf`@{Va;)-W2BQe)%ILOAJVc;=rz-nkUfdfs#~QmDvOVB{sM(BUN+M5d?*^9NN*tRW zO4^Z)-g4$`9v5%g#JdzoX7baLAQ9ZJ+$Ex*Fo#31JRk)lbb|gqI-8eXIDH;nZX|63 zxS2Rp!C0Y7VeEX?Z~QPw4yw_TK-odsT_SPubX4S;v5RmTVPm2+80)~6Po6<88z`-| zh@z~Mx$nv=By$lk~PVmxk?OSdE}> z=TH;fsHk*w6eaa~(9;%HALLiyDk~`$z6`GjWlv^(Mf>qCwIWj1f zrFur;@LC|Ene!vXbbQJDrpl1--BGSuB;O?$oxyp8lw*QFqDsdtyVs;6T zO#%X_L)74g`)qduUA%i;{rw2WVOq04JKH302_BN}sh%s6@;HJ6ddo+Iqy;xq@P|1d zI1UR|4DUU}n7XNjsOJC5xhH_!&Vq1$^lHo5cMWj`l|!!0@7bYB_p~6&@~Bwn zj&~IjJQaO55E%k(Oz;}N{{#gd9?7FfD&k=1{(_CAfSP~s%!tzGMq`Xfy7!V!DwQde z_fog1pqUrGdHR>*&mop*DG`_#T$oY|X&>sat)*Z*_#$bg@4% zQX+WwE#dwJ1frjQ!zG^6ouGR?blFJ*G7O9)-=7_C% zQ2~gv6_+)Mu~b;uD4t|&rVRU*get1GHkmy&r48}kd}s2gnkRyMSCF&=C^#~RPV2q7 z;9iNMrj@zpz+ih}Z`c4t-j^opl}q9#VO;i7?ofyDtqgn6fSevvo= zi*Z5_NrHqxB2|m}tIkU_dET%=q}(8Ys5fctu>2s~>Dn%-9x0(G3l}j&rQ|Ak#rZ}f znFTOM59pX+jff~DLc&U*>5i4=ok)o<;QrHIPKuDY9eOLKo_p<1-j31VjWNOeoiTA= zv-NP5Bzq4xTY#-%fFGE!&1zG_r7oEAqUeD_t`9qgb&_Ws#_vtG6f7*UI9iu=S(i_~ zcBd|i*D|=Adu0`~Ek~I}?e#q5*OORHB=6~(CZ7MV7iL*gGuKpWN!@Uyg04f_Ple7N zSxsYRzc@Skz2UJF5fJj77iU)D?<^X1iRF!uW1z4SJq=BCk(g0F#KR4pjr-LS(@)c) z{N<%iu%8I6?B>R()yn2`V;^~A*YCpa2=4uc-0gy<^ zCFQr7{A*vO1&^jmYnUjRX_cjGF2uma(4r5~YCxkn%+k>4AP{Ev)2c!)LG>7SpD`f( z3h@`>86XKB)*hJ<2F)qWj4?K`tbtsNlkkWHs?Y}p!-Om92{Dtz^xvu_SpN01uI zLMoh{2A`t@c?PuQ6qKWAq_fBA&hdZaWP+>+8nU5kzHbnDq7WuLrkZ{fqqL9@mC1NR zo7pbJBcbN0zN}n8`-S$6oLH`c2z|K%STr?|Lc~C5cQN9{suBCY6R2oBnucgb!6Vdx zwi~A_LeaR#h^~RrkK;6L|F?`gwqkVDD(9X0fqKwjn@s=7E}OL zK#D5{MjLo@L984T+i%uO&(z}fASW7h1BLO5nx8$>2S!6@$+pUQv}E&rismTcEit=& z6q9ZAFymkXaD=^V7W1TtMKR0;2_#Y61tY{45fYXliUiDw!nJy4cW7=$@Ye5)z(mJu z9PjK3LK8um@q*}DBC>-t?%Mgq?I4Y?-(5W6_Rjhb(d0-;TfC=eMPQ9z&ih)rDio{)w2%x)%FbdEZh?qSQ%&0YX4KjrX z`~t#e>=KHmiDWzEgi#>fKQGbk87Gz)*B}Rp-AN;dXLe)r-~d9}K~G}+sDRan=yLE}!p&Gl z^>h4Y7_2&Y!PS0h@>|l>Qh_yLbBh^ZC<7Zd&C~cY5&_1UUxIL%ivec;2eZB;?@&_S zuYg7*`P;73?vNA_nf(rZI|hY6)E%0OzM=ZPVaTjhW#ajhPsAY-Y4@ZdaDsuY%@HC` zM-cf#0Avo@jvA;97BpSa=R8L#E3=J6}e|8Az{_fe(mljEx_Ww!k>TYULFIuPLrUOo+r4!-Nn^a=(QD zBvA#zmQ=)7=9D==a7aAZ^y^Rpf)m{aN_<87<0-+PR$P)!q;SM21F(k~sS3Qx-}$t}5F5Bg>qhHn za>n=QdoKXv6Iu0DsA;LvV_`Ou(F~&v3CuHZ6WbVT$SB(|wndp&nZIf1Y;EjZ7f}>y zMA3JRoz+p6jCgU#!qice(--z1Q>9RPkOx3&9B_mne5*$ zrT5E5k{pH05;4Pk?}m7Iv(G#I?j*1mmQ$=H5+W3zEfm~~4gaBmrjRw+JubnUV8V{U z;E1w0f=8UcF^h?OL_h>{rN!`xKwJrh#;e<3#kaHJ5&+!M)4{(CkrpuKwIYok;nYqNo6QETT27FG z{*jzsM6e352+Jrh> zhaV9Y)kDD)(#vz6_s}LolRC;}jv%~MG#(gJ-@;jR?NrMfoqu*^c$#rmq zIbV&h>D4Iq^$q9BYpeo~{^{*Y>Q&b+GVbW$SNDO^lA|%mP+Uml46J0zH<&0TPhgJ( zv`1`I87sIae&V;OqHTh`5{ulb@DVCTAN~D&KQ5)lu7SrjsjuK(#gr{>1C+731Sd~d zaP!!pRrML>v=o(*If3mr#P;iUU2o)$M6}sao7CM$jGb4ex6a^=W;ESm6?h0UZqYk2*ko(ju5y>l3U|+tIMAPOFE? zZQ4}_HmX7RrTV3o(?-|GBs}U$9hKBjyO)WA9kmbw-2LcFeRDC!Gy}E-ZFtzu=?zmQ zU@*&%s3iuEG{gEfZSDzIOaEJiYUl(`FBsRj#*%7&3yHgdE4%T5Ws zNNv%-d`}0zzCGdY1KZdP6B~BNMQd&)>AHPxl?Gbvflh^w02$3FFenv|J@dv`lGFqJ<^z(aYk))v z6vQ3Ws4OFEZV;Xurd%Ra8pT+p<2rChAu}vpN{^sA4sxK?>!68u>=%v-21t8IX_-)c zd;jLcf!@SdoRRx_!tXDy8~jE}*9Ut4Vm{D|@D33hzad*w3^NutzJjdzx?o!AeL>2l zFLwKgp%02&-~S-snP@xv!iNT+f%gR<)NXY!Vx-jvg-+jmphItuk|u%4&Cb+2AM*40 z@SgYf457D>ZOkA39Letu|9d{W@W>6zUtI2^8R8<^O-H0y`g&W5gJ_r3Wyx_E{=$E) zT~t;Swqy7{2gwRqMxxfSC`l8_73c7DKcxCHc>aB?4wQKi&uorn#7ND4tj&}R;;W9^7Z z^Q#Q<0GW{nsi!m7IxdcDXxha8HTQvb=)U@QGhlkB-kx}#Y;kG@Q<$boqh-$W>Pu5! zciNB4mmJvyQ4%xl*Uq;Ub|^%FQ9rbk%U-@0h2$~ArMKT~kiY_j3TT;qerx-s*gWy> z`3tdIWT(|E_L4ctI5%{MZW(5g6b2=MM}7+S!i6Sh$DG^;hUN{-yG)LsT1r&NCoPBt%Z2vW_BCw z&36@wsP>CwF=#5esN56;B5$jMKbZ~>E2mz$811}>a7~)60XrGU3Q=@ParOML>paei z;1){H8owwd3v)UO63f}S)tFgI*68B#=M7vOp;YAQLmNN{ZX+W1;;3=V@rf0Z%{;<6 z$h<$m1@a=de9pnp*9#&>#EpyQ5ZB{GR|S41caf-Bh0dQWAA6>f)q;qiv7xteMp%rX8{ z6Y7zYeUdQJ8rmeQqY0U8l_Rz)8wGUvOy!;`*KE6Lg{f^WyGnm9+SOe46g^`*(n3`| z$jz(V69t1Tc1IUs^^R>Mhz^LT-J99RJ9F|3n|wot2Sj+&@Z(FY${4LJK?~l8 zxbe>(u0dBJA((*RyeKYH7P37$F2MZhM1?Fe>k7xj+@N+B=Yd5T)^3`B>7RvigQiFebtT8x{J+Y5%hG203W1rmkLWFvE`)^*iWCBBoX;&bav@(m|K{kEPbZKjq7rPh)E z6JxL3y!~hijf=@)w(Z@wQQhi}fy0lDpA@PTfGCJjWHYF#2?k~8B7man2;#<%0g4Uk zMpvi~H$wW5UnuavMFjDXnLE-@UQM2BgvoIcQb`T0P6e%hB(UtIWgT0ifhh?UHkDME zm?t0M4OR}d8axg2fB-A{X%Q;1Ye~#F`>FTfTLvSdu7DscyW>!5hJe6|Rldg5u!Gth zg{r!*%tuT}^rqc(?k)-n;r_H1@A*%uGcC!YcBXYr)aN4}{!{NuTWw^$A+y;F$8{-Y z?0N_l$Nf_`Y(5^gcCTP*O-h~T{|8HrGj`+k0xgJBrKyGf_1m`eevQouc|S-=plPs> zr8wiNm$yV}?1*V&>eh3Oew0O93Mj*!-30<3Ud$3^0IOb~c=1MkaSxTw@S6+9T1GEi zyyB-?y0xq4NmdC29o$wd6s5s#^-339d4(m`{cH7G;ZP0Fuvi5r6{-9SH>#5_+Xez2 zes3QAgR9rKcr=5uY$cpV9F8B`rmE<}#i9IDY_x`+^5Mzb;$|mEhEo48o}?eig)~S( z;`HuPsSzaxGr!rb+oYqRa4A#d&F=|nj`C*UOjNm<;wbFP`x8vV4=;1AnX<=E3k6F z7VK$c?XzTU~eJ+KylBEq?)34``| z2ZG2kh=3x`vTPa+8mI|r!b`>Tk>9`ig3RIIIE#}K!mwCO!Fw(Zx~r$Z17=_8S4#?t ztR!j;F(COPS+Om&P23c=p$)7m(EM|bk8PdXXuIe3*q+%QTO^H1_p&6~Y>#RW)5ijj zF$};=N6hQ@V7sX;$Nq)Rx;URVmn7ayxpyB|-7P+KqQCVg+#nP?O&V2eQg|s#ZKSc^ zO|3|bw6txc1V=T5Oy_c)?*KPf4v?~?<#F_b1bObt)r#PrPqA?`B z8G<1dqy*LD`_pQcks%sXUua-@9Ehruq`)9y&Oi-iKmNyL{G_H69^)QcF|VcbOq3?e zSEa0LG(M$HhL))!?dMr1^KiY%xlBP5WlcB>td6y|a@X``PGML<*^2oU=Z|AisN+}> z-gWzS8mb+BSj$z&TB?+UH~L8%o2?YVIzth1pU?<7=@d#eT`|~V{vhh zBliX#0sUE~9B|@Y4dGCetl#1?W#7~YSy7_OAPInJj}ABims_aZ!1jHiv|+H zm>lXh87dOuY6sFSp_^G~QZll1X{FyT1>KY}t5!f7p7fA&;0l`E;06x4MU8dWxILS6 zLR!ly!zHyM=K`liR_e}0i&4k8Kd1ZMA_n0QbzUcp6g6cj@_HtWd|@EmMYMEAAaIeX zTTi@Y#ZDDVXaMqax9lYMz>PpHTBs|?pDlHj@eL>zoyDlPkAzz|Lw&8j@T3b~Zn=DJ z@)l0e(N4@|HLB20V6I~QR%@4jP@*IaJxG#E%vPWes0^)daSmuK# zTh*8YKf$_3(QpsDk9mXD+e5dYLQEa((62ziMyjDat(lS_u0%$~CMA8>Mu$)uRa)3|nUy!Bd#hOz*Cw2ow=n<{u4J(%i2 zJqBLNikrtGneEbBphoZSAvznTZu$N~h%PCbOzvZB-mK@)G6%|C` z`Z$(-GIxyPf|~Gw2O_(oja&lI(o`$_K#CDQQH4(nvonYB`F+Q9HekaR_ za>Bo`o&d=RA<7k+kIKKm$_IY>()np#GHlz$oq71}n|-NhWliva0u)#2c)tb3*r~(51@KlTAOwBLvmOYMHLHx%u**75k`hu}#|LI%|qp&Y2s}z2E zF=*j#-rU4HH@bI7%);;8K|xW2(;PK*rpbztJ{B7ZUdD0{Vsd63Q6*vJA!z`mQlIDhJHV=`lG6VN+f~soKjcAJk*Rdnq zbm%6{5fJMr*`+UQr7r8$AD&x9>U8ba*WcpV#$o0cvC1z(sU?PXs{tW(^X5`KBZ)Kz zi?Y7-qt^@PdMl*#Pq^4%pMua^JTfSe^I^c=LHW)SC^Wo1IPPtg)dkdz;FANZ#n9!K8c@yT72L|Sf$ppvh+MXuMcXuV z^vm}mk|eye6=oKN%veNVcpfp6a^n+#zF9^GmCM8XA&PT&wB_mtdgC5CBZO`=S19z$ zIZ`uLBz2O&5k!4}_7EO$E2WbesRTv8nyM{m`iJIy6k;I&<9D@w#4}K}ww$V-9@Y6%uwh*Mt7uB4$D~>0=G0@YZ3_x*>*6_yJdUfVgV4eOrH20^`WxA_Qx+9Z$LC%TH&tr(f#u zcc%=mRw;l2J`7rRSxzGii}pxQqLPAh0o@}zAw41cw4MhOolz|Oh2Qd5W((M__M6}M zLs%IjoQF~91LwsEEXZYLxt=loDZ7t(UPtm!=cJ)7IFUq|_onbn35b{MHE2DNq@Ik6 zn|b?m2eu;pikNCk1yHsER-|&27+H^tBXL}HDZlXUM94e+uV8i5HhGZhN|lW`b>=Wq zjyjM|O3iQxGDr zJv}|qHtKR~{N{!No8wB!?y1}a5e^DwWdD$9FlT8lpSPxLz0CCx41^ zd?`5gVtj4Mt3(A_Pn2}wA1iv+pYlub{SW^!harZs;Ndu=O=JK0;_~|Spts}nnf!njhHU@rj7Be8XA=% znuv?mSs=khE;o)XJ73lsbGjN3)YnrP+j?1<$*xij3YsZc0QnaTyAZUnQvNZF7IL_+ zu0&atY*;roSyt$9y-U=!azO zyA-*jXOE-$x+tr3#(TjF%wh8Rap^rL75Ut4w716r6FyHdZTfRcm8}W3j-z?x5p6!* zftm@LTpt+A-i-?EV12SGq3JF~A630s+UM>}8*H8hTMK-$Y)=52wzO|r8Rf7xp-M@@WxWaRyPH zmbz~VK0wY9)(7P4rsZ0dD=Nrqv-@43Z?6Wa_xUjPF0rl+Z(M|W3VT^}FMDK2jjZIl zW^m097V^lO=kVe;Sj)%TiX$+}HfhZjI))w3qrH|v7VN?T0a+p?&GITnJN}Bnwcwu& zwWUzL8_^~rwRlfGXOrjMAoK`G0bfoofj2Al1s7aG;X&S!Lg1`~N~^4lFHe6)o@T2? zds6li^}~_LG~eHWW3U%h0h}$5Mo5|=I6!j=^@L$zM&EO35TE7&D4F3MGOZZfmEhx2 z;fhVZ`0_$tq?t0pWej;x1?S2|T25ncmNk`Knib>Xpr7aHXo=GAOxxuj@CxDzf2Tr( z>=Be08DxllGN7CYA&_u~%XG;jETY~hZWon(`)jV?%xe6Z$6oT#dU#KK{CdLqcJNwA#59qb!R zf2BAST+*JYlg!dn6qKqT+^D+7V;QbyB;${66end;iV?a%1PBAYe(dHe_5Qd%`WSLZ zhIsMAPcOglTSZevWrxUd6U)aQ6Z{h+ozar;SUb*-GT>EdrIXqKN;MvZK}jFv*n3<7 z=6_cCk6(M+V1E<6# zUBQ)(o@9xbs+v>Fd)Wta0G%s9#DJ@yG9zg9nr61G&m7N0wQFuTo>IK#vq=Qh$o4Ds zlV!2=?n5j~57M*QJvypSv~(M4--9biOgHgGwzRLSXJllcP11^`qSHDKMx_YD;s4_k z@!QDiCnn`b5`~N!lKwNIsv)NfuU{=o(2$R+sSivs6tAMFfW__W?zn`RPT~zs<0ePZ zOR2gyi7PnqfXIx?FV|U#Qh%gd9`73BS!_i3imb(0hAmX>1;~OP0H>pF4mty`HOw3m LB<>hOV(tGA)46V5 literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/translations/sqlb_ko_KR.ts b/src/WBCLFZSystemModule/SqliteDBProcess/src/translations/sqlb_ko_KR.ts new file mode 100644 index 0000000..e0d1881 --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/translations/sqlb_ko_KR.ts @@ -0,0 +1,7012 @@ + + + + + AboutDialog + + + About DB Browser for SQLite + ~ì— ëŒ€í•˜ì—¬.. 보다는 ~~ ì •ë³´ ë¼ëŠ” í‘œí˜„ì„ ìš”ì¦˜ì— ë§Žì´ ì‚¬ìš©í•¨. + DB Browser for SQLite ì •ë³´ + + + + Version + 버전 + + + + <html><head/><body><p>DB Browser for SQLite is an open source, freeware visual tool used to create, design and edit SQLite database files.</p><p>It is bi-licensed under the Mozilla Public License Version 2, as well as the GNU General Public License Version 3 or later. You can modify or redistribute it under the conditions of these licenses.</p><p>See <a href="http://www.gnu.org/licenses/gpl.html">http://www.gnu.org/licenses/gpl.html</a> and <a href="https://www.mozilla.org/MPL/2.0/index.txt">https://www.mozilla.org/MPL/2.0/index.txt</a> for details.</p><p>For more information on this program please visit our website at: <a href="http://sqlitebrowser.org">http://sqlitebrowser.org</a></p><p><span style=" font-size:small;">This software uses the GPL/LGPL Qt Toolkit from </span><a href="http://qt-project.org/"><span style=" font-size:small;">http://qt-project.org/</span></a><span style=" font-size:small;"><br/>See </span><a href="http://qt-project.org/doc/qt-5/licensing.html"><span style=" font-size:small;">http://qt-project.org/doc/qt-5/licensing.html</span></a><span style=" font-size:small;"> for licensing terms and information.</span></p><p><span style=" font-size:small;">It also uses the Silk icon set by Mark James licensed under a Creative Commons Attribution 2.5 and 3.0 license.<br/>See </span><a href="http://www.famfamfam.com/lab/icons/silk/"><span style=" font-size:small;">http://www.famfamfam.com/lab/icons/silk/</span></a><span style=" font-size:small;"> for details.</span></p></body></html> + <html><head/><body><p>DB Browser for SQLite는 오픈소스, 프리웨어로 SQLite ë°ì´í„°ë² ì´ìФ 파ì¼ë“¤ì„ ìƒì„±, 설계하고 ìˆ˜ì •ì„ í•˜ê¸° 위한 비주얼 툴입니다.</p><p>ì´ í”„ë¡œê·¸ëž¨ì€ ì´ì¤‘ ë¼ì´ì„¼ìŠ¤ë¡œ Mozilla Public License Version 2ê³¼ GNU General Public License Version 3 ë˜ëŠ” ê·¸ ì´í›„ ë²„ì „ì„ ë”°ë¦…ë‹ˆë‹¤. ë”°ë¼ì„œ ì´ í”„ë¡œê·¸ëž¨ì€ ì´ ë¼ì´ì„¼ìŠ¤ë¥¼ 충족하는 범위 ë‚´ì—서 수정하고 ìž¬ë°°í¬ í•  수 있습니다.</p><p>ìžì„¸í•œ ì‚¬í•­ì€ <a href="http://www.gnu.org/licenses/gpl.html">http://www.gnu.org/licenses/gpl.html</a>ê³¼ <a href="https://www.mozilla.org/MPL/2.0/index.txt">https://www.mozilla.org/MPL/2.0/index.txt</a>를 참고하시기 ë°”ëžë‹ˆë‹¤. </p><p>ì´ í”„ë¡œê·¸ëž¨ì— ëŒ€í•œ 좀 ë” ìžì„¸í•œ 정보는 우리 웹사ì´íЏì—서 확ì¸í•˜ì‹¤ 수 있습니다: <a href="http://sqlitebrowser.org">http://sqlitebrowser.org</a></p><p><span style=" font-size:small;">ì´ ì†Œí”„íŠ¸ì›¨ì–´ëŠ” GPL/LGPL Qt Toolkitì„ ì‚¬ìš©í•©ë‹ˆë‹¤.</span><a href="http://qt-project.org/"><span style=" font-size:small;">http://qt-project.org/</span></a><span style=" font-size:small;"><br/>ë¼ì´ì„¼ìФ 사항과 정보는 </span><a href="http://qt-project.org/doc/qt-5/licensing.html"><span style=" font-size:small;">http://qt-project.org/doc/qt-5/licensing.html</span></a><span style=" font-size:small;">를 참고하시기 ë°”ëžë‹ˆë‹¤.</span></p><p><span style=" font-size:small;">ë˜í•œ ì´ í”„ë¡œê·¸ëž¨ì€ Mark Jamesì˜ Silk icon set를 Creative Commons Attribution 2.5와 3.0 ë¼ì´ì„¼ìФ 아래ì—서 사용하고 있습니다.<br/> ìžì„¸í•œ 정보는 </span><a href="http://www.famfamfam.com/lab/icons/silk/"><span style=" font-size:small;">http://www.famfamfam.com/lab/icons/silk/</span></a><span style=" font-size:small;">를 참고하시기 ë°”ëžë‹ˆë‹¤.</span></p></body></html> + + + + AddRecordDialog + + + Add New Record + 새 레코드 추가 + + + + Enter values for the new record considering constraints. Fields in bold are mandatory. + 제약 ì¡°ê±´ì„ ê³ ë ¤í•˜ì—¬ 새 레코드를 위한 ê°’ì„ ìž…ë ¥í•˜ì„¸ìš”. 진하게 ì²˜ë¦¬ëœ í•„ë“œëŠ” 반드시 입력해야 합니다. + + + + In the Value column you can specify the value for the field identified in the Name column. The Type column indicates the type of the field. Default values are displayed in the same style as NULL values. + ê°’ 필드ì—는 ì´ë¦„ í•„ë“œì— ëŒ€ì‘하는 ê°’ì„ ìž…ë ¥ í•  수 있습니다. 타입 필드는 í•„ë“œì˜ íƒ€ìž…ì„ ì˜ë¯¸í•©ë‹ˆë‹¤. 기본 ê°’ì€ NULLê°’ê³¼ ê°™ì€ ìŠ¤íƒ€ì¼ë¡œ 표시ë©ë‹ˆë‹¤. + + + + Name + ì´ë¦„ + + + + Type + 타입 + + + + Value + ê°’ + + + + Values to insert. Pre-filled default values are inserted automatically unless they are changed. + 추가할 값들입니다. 기본 ê°’ë“¤ì´ ë¯¸ë¦¬ ìž…ë ¥ë˜ì–´ 있어 수정하지 않는다면 ìžë™ì ìœ¼ë¡œ 들어갑니다. + + + + When you edit the values in the upper frame, the SQL query for inserting this new record is shown here. You can edit manually the query before saving. + 위 í”„ë ˆìž„ì˜ ê°’ì„ ìˆ˜ì •í•˜ë©´, ìˆ˜ì •ì‚¬í•­ì´ ë°˜ì˜ëœ 레코드 추가 SQL쿼리가 ì—¬ê¸°ì— ë‚˜íƒ€ë‚©ë‹ˆë‹¤. 저장하기 ì „ì´ë¼ë©´ ì§ì ‘ 쿼리를 수정할 ìˆ˜ë„ ìžˆìŠµë‹ˆë‹¤. + + + + <html><head/><body><p><span style=" font-weight:600;">Save</span> will submit the shown SQL statement to the database for inserting the new record.</p><p><span style=" font-weight:600;">Restore Defaults</span> will restore the initial values in the <span style=" font-weight:600;">Value</span> column.</p><p><span style=" font-weight:600;">Cancel</span> will close this dialog without executing the query.</p></body></html> + <html><head/><body><p><span style=" font-weight:600;">저장하기</span>는 새 레코드를 ë°ì´í„°ë² ì´ìŠ¤ì— ì¶”ê°€í•˜ê¸° 위해 작성ë˜ì–´ 나타나 있는 SQL êµ¬ë¬¸ì„ ë°˜ì˜í•©ë‹ˆë‹¤.</p><p><span style=" font-weight:600;">초기값 ë³µì›í•˜ê¸°</span>는 <span style=" font-weight:600;">ê°’</span> 필드를 초기 값으로 ë³µì›í•©ë‹ˆë‹¤.</p><p><span style=" font-weight:600;">취소하기</span>는 ì¿¼ë¦¬ì˜ ì‹¤í–‰ ì—†ì´ ì´ ì°½ì„ ë‹«ìŠµë‹ˆë‹¤.</p></body></html> + + + + Auto-increment + + ìžë™ ì¦ê°€(Auti-increment) + + + + + Unique constraint + + ìœ ë‹ˆí¬ ì œì•½ + + + + + Check constraint: %1 + + 제약 ì¡°ê±´: %1 + + + + + Foreign key: %1 + + 외래키: %1 + + + + + Default value: %1 + + 기본 ê°’: %1 + + + + + Error adding record. Message from database engine: + +%1 + 레코드 추가 ë„중 ì—러가 ë°œìƒí–ˆìŠµë‹ˆë‹¤. ë°ì´í„°ë² ì´ìФ 엔진 메시지: + +%1 + + + + Are you sure you want to restore all the entered values to their defaults? + ì •ë§ë¡œ 모든 입력한 ê°’ë“¤ì„ ì´ˆê¸° 값으로 ë³µì›í•©ë‹ˆê¹Œ? + + + + Application + + + Possible command line arguments: + 사용할 수 있는 명령줄 매개변수: + + + + Usage: %1 [options] [<database>|<project>] + + 사용법: %1 [옵션] [<ë°ì´í„°ë² ì´ìФ>|<프로ì íЏ>] + + + + + -h, --help Show command line options + -h, --help 명령줄 ì˜µì…˜ì„ ë³´ì—¬ì¤ë‹ˆë‹¤ + + + + -q, --quit Exit application after running scripts + -q, --quit 스í¬ë¦½íЏ 실행 후 í”„ë¡œê·¸ëž¨ì„ ì¢…ë£Œí•©ë‹ˆë‹¤ + + + + -s, --sql <file> Execute this SQL file after opening the DB + -s, --sql <파ì¼> DB를 ì—° ë‹¤ìŒ SQL 파ì¼ì„ 실행합니다 + + + + -t, --table <table> Browse this table after opening the DB + -t, --table <table> DB를 ì—° ë‹¤ìŒ ì´ í…Œì´ë¸”ì„ íƒìƒ‰í•©ë‹ˆë‹¤ + + + + -R, --read-only Open database in read-only mode + -R, --read-only ë°ì´í„°ë² ì´ìŠ¤ë¥¼ ì½ê¸° ì „ìš© 모드로 열기합니다 + + + + -o, --option <group>/<setting>=<value> + -o, --option <그룹>/<설정>=<ê°’> + + + + Run application with this setting temporarily set to value + 설정 ê°’ì„ ìž„ì‹œì ìœ¼ë¡œ 저장한 후 프로그램 실행합니다 + + + + -O, --save-option <group>/<setting>=<value> + -O, --save-option <그룹>/<설정>=<ê°’> + + + + Run application saving this value for this setting + 설정 ê°’ì„ ì €ìž¥í•˜ë©´ì„œ í”„ë¡œê·¸ëž¨ì„ ì‹¤í–‰í•©ë‹ˆë‹¤ + + + + -v, --version Display the current version + -v, --version 현재 ë²„ì „ì„ ì¶œë ¥í•©ë‹ˆë‹¤ + + + + <database> Open this SQLite database + <ë°ì´í„°ë² ì´ìФ> ì´ SQLite ë°ì´í„°ë² ì´ìŠ¤ë¥¼ 엽니다 + + + + <project> Open this project file (*.sqbpro) + <프로ì íЏ> ì´ í”„ë¡œì íЏ 파ì¼ì„ 엽니다 (*.sqbpro) + + + + The -s/--sql option requires an argument + -s/--sql ì˜µì…˜ì€ ì‹¤í–‰í•  SQL 파ì¼ëª…ì„ ê°™ì´ ì§€ì •í•´ì£¼ì–´ì•¼ 합니다 + + + + The file %1 does not exist + %1 파ì¼ì´ 존재하지 않습니다 + + + + The -t/--table option requires an argument + -t/--table ì˜µì…˜ì˜ ëŒ€ìƒì´ ë˜ëŠ” í…Œì´ë¸” ëª…ì„ ìž…ë ¥í•˜ì„¸ìš” + + + + The -o/--option and -O/--save-option options require an argument in the form group/setting=value + -o/--option ë˜ëŠ” -O/--save-option ì˜µì…˜ì€ group/setting=value 형ì‹ì˜ ì¸ìˆ˜ê°€ 필요합니다 + + + + Invalid option/non-existant file: %1 + ìž˜ëª»ëœ ì˜µì…˜ì„ ì‚¬ìš©í•˜ì˜€ê±°ë‚˜ 파ì¼ì´ 존재하지 않습니다: %1 + + + + SQLite Version + SQLite 버전 + + + + SQLCipher Version %1 (based on SQLite %2) + SQLCipher 버전 %1 (SQLite %2 기반) + + + + DB Browser for SQLite Version %1. + DB Browser for SQLite 버전 %1. + + + + Built for %1, running on %2 + %1 í™˜ê²½ì„ ìœ„í•´ 빌드ë¨, %2 환경ì—서 실행 중 + + + + Qt Version %1 + Qt 버전 %1 + + + + CipherDialog + + + SQLCipher encryption + SQLCipher 암호화 + + + + &Password + 암호(&P) + + + + &Reenter password + 암호 재입력(&R) + + + + Encr&yption settings + 암호화 설정(&Y) + + + + SQLCipher &3 defaults + SQLCipher &3 기본값 + + + + SQLCipher &4 defaults + SQLCipher &4 기본값 + + + + Custo&m + 수ë™(&M) + + + + Page si&ze + 페ì´ì§€ í¬ê¸°(&Z) + + + + &KDF iterations + &KDF 반복 횟수 + + + + HMAC algorithm + HMAC 알고리즘 + + + + KDF algorithm + KDF 알고리즘 + + + + Plaintext Header Size + í‰ë¬¸ í—¤ë” í¬ê¸° + + + + Passphrase + 암호 + + + + Raw key + Raw 키 + + + + Please set a key to encrypt the database. +Note that if you change any of the other, optional, settings you'll need to re-enter them as well every time you open the database file. +Leave the password fields empty to disable the encryption. +The encryption process might take some time and you should have a backup copy of your database! Unsaved changes are applied before modifying the encryption. + ë°ì´í„°ë² ì´ìŠ¤ë¥¼ 암호화할 때 사용할 키를 지정해주세요. +[주ì˜] ì—¬ëŸ¬ë¶„ì´ ì¶”ê°€ì ì¸ ì„¤ì •ì„ ë³€ê²½í•œë‹¤ë©´, ë°ì´í„°ë² ì´ìФ 파ì¼ì„ ì—´ 때마다 암호를 매번 입력해야합니다. +그러한 ë¶ˆíŽ¸í•¨ì„ í”¼í•˜ê¸° 위해 암호화를 하지 않으려면 암호 필드를 비워ë‘세요 +암호화 ìž‘ì—…ì€ ì‹œê°„ì´ ì¢€ 걸릴 수 있습니다. 그리고 ê¼­ ì—¬ëŸ¬ë¶„ì˜ ë°ì´í„°ë² ì´ìФ ë°±ì—…ë³¸ì„ ë°˜ë“œì‹œ 만들어ë‘세요! 암호화 작업 ì´ì „ì— í•œ 저장ë˜ì§€ ì•Šì€ ë³€ê²½ ì‚¬í•­ë„ ë°˜ì˜ë˜ë‹ˆ 주ì˜í•˜ì„¸ìš”. + + + + Please enter the key used to encrypt the database. +If any of the other settings were altered for this database file you need to provide this information as well. + ë°ì´í„°ë² ì´ìŠ¤ë¥¼ 암호화기 위해 사용할 키를 다시 입력해주세요. +ë°ì´í„°ë² ì´ìФ 파ì¼ì„ 변경하기 위해서는 ì´ ì •ë³´ë¥¼ 다시 입력해야만 합니다. + + + + ColumnDisplayFormatDialog + + + Choose display format + 표시 형ì‹ì„ ì„ íƒí•˜ì„¸ìš” + + + + Display format + 표시 í˜•ì‹ + + + + Choose a display format for the column '%1' which is applied to each value prior to showing it. + '%1' ì»¬ëŸ¼ì˜ í‘œì‹œ 형ì‹ì„ ì„ íƒí•˜ì„¸ìš”. + + + + Default + ì¼ë°˜ + + + + Decimal number + ìˆ«ìž + + + + Exponent notation + 지수 + + + + Hex blob + ì´ì§„ ë°ì´í„° + + + + Hex number + 16진수 + + + + Apple NSDate to date + Apple NSDate ë‚ ì§œ + + + + Java epoch (milliseconds) to date + Java 시간(밀리초)ì„ ë‚ ì§œë¡œ + + + + .NET DateTime.Ticks to date + .NET DateTime Ticks를 날짜로 + + + + Julian day to date + ë‚ ì§œ + + + + Unix epoch to local time + 유닉스 시간(타임스탬프)ì„ ì§€ì—­ 시간으로 + + + + Date as dd/mm/yyyy + 날짜를 dd/mm/yyyy 형태로 + + + + Lower case + ì†Œë¬¸ìž + + + + Custom display format must contain a function call applied to %1 + ì‚¬ìš©ìž ì •ì˜ í‘œì‹œ 형ì‹ì€ %1ì— ì ìš©ëœ 함수 í˜¸ì¶œì„ í¬í•¨í•´ì•¼ 합니다 + + + + Error in custom display format. Message from database engine: + +%1 + ì‚¬ìš©ìž ì •ì˜ í‘œì‹œ 형ì‹ì—서 ì—러가 ë°œìƒí–ˆìŠµë‹ˆë‹¤. ë°ì´í„°ë² ì´ìФ ì—”ì§„ì˜ ë©”ì‹œì§€: +%1 + + + + Custom display format must return only one column but it returned %1. + ì‚¬ìš©ìž ì§€ì • 표시 형ì‹ì€ í•˜ë‚˜ì˜ ì—´ë§Œ 반환해야 하지만 %1개를 반환했습니다. + + + + Octal number + 8진수 + + + + Round number + ë¼ìš´ë“œ 수 + + + + Unix epoch to date + 유닉스 시간(타임스탬프)ì„ ë‚ ì§œë¡œ + + + + Upper case + ëŒ€ë¬¸ìž + + + + Windows DATE to date + Windows ë‚ ì§œ + + + + Custom + ì‚¬ìš©ìž ì§€ì • + + + + CondFormatManager + + + Conditional Format Manager + ì¡°ê±´ë¶€ ì„œì‹ ê´€ë¦¬ìž + + + + This dialog allows creating and editing conditional formats. Each cell style will be selected by the first accomplished condition for that cell data. Conditional formats can be moved up and down, where those at higher rows take precedence over those at lower. Syntax for conditions is the same as for filters and an empty condition applies to all values. + ì´ ëŒ€í™”ìƒìžì—서는 ì¡°ê±´ë¶€ 형ì‹ì„ 추가하고 수정할 수 있습니다. ê° ì…€ 스타ì¼ì€ 해당 ì…€ ë°ì´í„°ì˜ 첫번째 ì¡°ê±´ì— ì˜í•´ 지정ë©ë‹ˆë‹¤. ì¡°ê±´ë¶€ 서ì‹ì€ 위/아래로 ì´ë™í•  수 있으며, ìƒìœ„ í–‰ì— ìžˆëŠ” 형ì‹ì€ 하위 í–‰ì— ìžˆëŠ” 형ì‹ë³´ë‹¤ ìš°ì„ ë©ë‹ˆë‹¤. ì¡°ê±´ êµ¬ë¬¸ì€ í•„í„°ì™€ ë™ì¼í•˜ë©° 빈 ì¡°ê±´ì€ ëª¨ë“  ê°’ì— ëŒ€í•´ ì ìš©ë©ë‹ˆë‹¤. + + + + Add new conditional format + 새 ì¡°ê±´ë¶€ 서ì‹ì„ 추가합니다 + + + + &Add + 추가(&A) + + + + Remove selected conditional format + ì„ íƒí•œ ì¡°ê±´ë¶€ 서ì‹ì„ 삭제합니다 + + + + &Remove + ì‚­ì œ(&R) + + + + Move selected conditional format up + ì„ íƒí•œ ì¡°ê±´ë¶€ 서ì‹ì„ 위로 ì´ë™í•©ë‹ˆë‹¤ + + + + Move &up + 위로 올리기(&U) + + + + Move selected conditional format down + ì„ íƒí•œ ì¡°ê±´ë¶€ 서ì‹ì„ 아래로 ì´ë™í•©ë‹ˆë‹¤ + + + + Move &down + 아래로 내리기(&D) + + + + Foreground + 전경색 + + + + Text color + 글ìžìƒ‰ + + + + Background + 배경색 + + + + Background color + 배경색 + + + + Font + 글꼴 + + + + Size + í¬ê¸° + + + + Bold + 진하게 + + + + Italic + 기울임 + + + + Underline + 밑줄 + + + + Alignment + ì •ë ¬ + + + + Condition + ì¡°ê±´ + + + + + Click to select color + 색ìƒì„ ì„ íƒí•˜ì„¸ìš” + + + + Are you sure you want to clear all the conditional formats of this field? + ì´ í•„ë“œì˜ ëª¨ë“  ì¡°ê±´ë¶€ 서ì‹ì„ ì •ë§ë¡œ 삭제하시겠습니까? + + + + DBBrowserDB + + + Please specify the database name under which you want to access the attached database + ë°ì´í„°ë² ì´ìФ ì—°ê²°ì„ ìœ„í•´ 불러올 ë°ì´í„°ë² ì´ìŠ¤ì˜ ë³„ì¹­ì„ ì§€ì •í•´ì£¼ì„¸ìš” + + + + Invalid file format + ìž˜ëª»ëœ íŒŒì¼ í¬ë§·ìž…니다 + + + + Do you want to save the changes made to the database file %1? + %1 ë°ì´í„°ë² ì´ìФ 파ì¼ì„ ìƒì„±í•˜ê¸° 위해 ë³€ê²½ì‚¬í•­ì„ ì €ìž¥í•˜ê² ìŠµë‹ˆê¹Œ? + + + + Exporting database to SQL file... + ë°ì´í„°ë² ì´ìŠ¤ë¥¼ SQL 파ì¼ë¡œ 내보내는 중... + + + + + Cancel + 취소 + + + + Executing SQL... + SQL 실행 중... + + + + Action cancelled. + ì‹¤í–‰ì´ ì·¨ì†Œë˜ì—ˆìŠµë‹ˆë‹¤. + + + + Do you really want to close this temporary database? All data will be lost. + ì´ ìž„ì‹œ ë°ì´í„°ë² ì´ìŠ¤ë¥¼ ë‹«ì„까요? 모든 ë°ì´í„°ê°€ 사ë¼ì§‘니다. + + + + This database has already been attached. Its schema name is '%1'. + ì´ ë°ì´í„°ë² ì´ìŠ¤ëŠ” ì´ë¯¸ ì—°ê²°ë˜ì—ˆìŠµë‹ˆë‹¤. 스키마 ì´ë¦„ì€ '%1' 입니다. + + + + Database didn't close correctly, probably still busy + ë°ì´í„°ë² ì´ìŠ¤ê°€ 제대로 닫히지 않았습니다, ì•„ë§ˆë„ ì•„ì§ ì‚¬ìš© ì¤‘ì¼ ê²ƒìž…ë‹ˆë‹¤ + + + + The database is currently busy: + ì´ ë°ì´í„°ë² ì´ìŠ¤ëŠ” 현재 사용 중입니다: + + + + Do you want to abort that other operation? + ì´ ëª…ë ¹ì„ ì·¨ì†Œí•˜ì‹œê² ìŠµë‹ˆê¹Œ? + + + + + No database file opened + 열린 ë°ì´í„°ë² ì´ìФ 파ì¼ì´ 없습니다 + + + + + Error in statement #%1: %2. +Aborting execution%3. + #%1: %2 êµ¬ë¬¸ì— ì—러가 있어 ì‹¤í–‰ì´ ì¤‘ë‹¨ë˜ì—ˆìŠµë‹ˆë‹¤%3. + + + + + and rolling back + 그리고 롤백합니다 + + + + didn't receive any output from %1 + %1ì—서 아무런 ì¶œë ¥ì„ ë°›ì§€ 못했습니다 + + + + could not execute command: %1 + ëª…ë ¹ì„ ì‹¤í–‰í•  수 없습니다: %1 + + + + Cannot delete this object + ì´ ê°ì²´ë¥¼ 삭제할 수 없습니다 + + + + Cannot set data on this object + ì´ ê°ì²´ì—는 ë°ì´í„°ë¥¼ 저장할 수 없습니다 + + + + + A table with the name '%1' already exists in schema '%2'. + '%1' ì´ë¦„ì˜ í…Œì´ë¸”ì´ ì´ë¯¸ 스키마 '%2'ì— ì¡´ìž¬í•©ë‹ˆë‹¤. + + + + No table with name '%1' exists in schema '%2'. + 스키마 '%2'ì— ì´ë¦„ì´ '%1'ì¸ í…Œì´ë¸”ì´ ì—†ìŠµë‹ˆë‹¤. + + + + + Cannot find column %1. + %1 ì»¬ëŸ¼ì„ ì°¾ì„ ìˆ˜ 없습니다. + + + + Creating savepoint failed. DB says: %1 + 세ì´ë¸Œ í¬ì¸íŠ¸ë¥¼ ìƒì„±í•˜ì§€ 못했습니다. DB 메시지: %1 + + + + Renaming the column failed. DB says: +%1 + ì—´ ì´ë¦„ì„ ë³€ê²½í•˜ì§€ 못했습니다. DB 메시지: +%1 + + + + + Releasing savepoint failed. DB says: %1 + 세ì´ë¸Œ í¬ì¸íŠ¸ë¥¼ 해제하지 못했습니다. DB 메시지: %1 + + + + Creating new table failed. DB says: %1 + 새 í…Œì´ë¸”ì„ ìƒì„±í•˜ì§€ 못했습니다. DB 메시지: %1 + + + + Copying data to new table failed. DB says: +%1 + 새 í…Œì´ë¸”ì— ë°ì´í„°ë¥¼ 복사하지 못했습니다. DB 메시지: +%1 + + + + Deleting old table failed. DB says: %1 + ì´ì „ í…Œì´ë¸”ì„ ì‚­ì œí•˜ì§€ 못했습니다. DB 메시지: %1 + + + + Error renaming table '%1' to '%2'. +Message from database engine: +%3 + í…Œì´ë¸” '%1'ì˜ ì´ë¦„ì„ '%2'(으)로 변경하는 ë™ì•ˆ 오류가 ë°œìƒí–ˆìŠµë‹ˆë‹¤. +ë°ì´í„°ë² ì´ìФ 엔진 메시지: +%3 + + + + could not get list of db objects: %1 + DB 개체 목ë¡ì„ 가져알 수 없습니다: %1 + + + + Restoring some of the objects associated with this table failed. This is most likely because some column names changed. Here's the SQL statement which you might want to fix and execute manually: + + + ì´ í…Œì´ë¸”ì— ê´€ë ¨ëœ ëª‡ ê°œì˜ ê°ì²´ë¥¼ ë³µì›í•˜ëŠ”ë° ì‹¤íŒ¨í–ˆìŠµë‹ˆë‹¤. ì´ëŸ¬í•œ 경우는 대부분 몇 ê°œì˜ í•„ë“œëª…ì´ ë³€ê²½ë˜ì–´ì„œ ë°œìƒ í–ˆì„ ê°€ëŠ¥ì„±ì´ í½ë‹ˆë‹¤. 아래 SQL êµ¬ë¬¸ì„ ì°¸ê³ í•˜ë©´ ì§ì ‘ 수ë™ìœ¼ë¡œ ê³ ì³ì„œ 실행할 수 ìžˆì„ ê²ƒìž…ë‹ˆë‹¤: + + + + + + could not get list of databases: %1 + ë°ì´í„°ë² ì´ìФ 목ë¡ì„ 가져올 수 없습니다: %1 + + + + Error loading extension: %1 + í™•ìž¥ê¸°ëŠ¥ì„ ë¶ˆëŸ¬ì˜¤ê¸° ì—러: %1 + + + + could not get column information + ì—´ 정보를 가져올 수 없습니다 + + + + Error setting pragma %1 to %2: %3 + pragma ì„¤ì •ì„ %1ì—서 %2로 ë³€ê²½í•˜ëŠ”ë° ì—러: %3 + + + + File not found. + 파ì¼ì„ ì°¾ì„ ìˆ˜ 없습니다. + + + + DbStructureModel + + + Name + ì´ë¦„ + + + + Object + ê°ì²´ + + + + Type + 타입 + + + + Schema + 스키마 + + + + Database + ë°ì´í„°ë² ì´ìФ + + + + Browsables + 열기 + + + + All + ëª¨ë‘ ì„ íƒ + + + + Temporary + 임시 + + + + Tables (%1) + í…Œì´ë¸” (%1) + + + + Indices (%1) + ì¸ë±ìФ (%1) + + + + Views (%1) + ë·° (%1) + + + + Triggers (%1) + 트리거 (%1) + + + + EditDialog + + + Edit database cell + ë°ì´í„°ë² ì´ìФ ë°ì´í„° ê°’ì„ ìˆ˜ì •í•˜ê¸° + + + + Mode: + 모드: + + + + This is the list of supported modes for the cell editor. Choose a mode for viewing or editing the data of the current cell. + ì…€ ì—디터ì—서 ì§€ì›ë˜ëŠ” 모ë¸ë“¤ 목ë¡ìž…니다. 현재 ì…€ì˜ ë°ì´í„°ë¥¼ 보거나 수정하기 위한 모드를 ì„ íƒí•˜ì„¸ìš”. + + + + RTL Text + RTL Text + + + + + Image + ì´ë¯¸ì§€ + + + + JSON + JSON + + + + XML + XML + + + + + Automatically adjust the editor mode to the loaded data type + 불러온 ë°ì´í„° íƒ€ìž…ì„ ì—디터 ëª¨ë“œì— ìžë™ ì ìš© + + + + This checkable button enables or disables the automatic switching of the editor mode. When a new cell is selected or new data is imported and the automatic switching is enabled, the mode adjusts to the detected data type. You can then change the editor mode manually. If you want to keep this manually switched mode while moving through the cells, switch the button off. + ì´ ì²´í¬ ë²„íŠ¼ì€ ì—디터 모드를 ìžë™ìœ¼ë¡œ 변경하는 ê¸°ëŠ¥ì„ í‚¤ê±°ë‚˜ ë•니다. 새 ì…€ì´ ì„ íƒë˜ê±°ë‚˜ 새로운 ë°ì´í„°ê°€ 가져와지면 ìžë™ 변경 ê¸°ëŠ¥ì´ ì¼œì ¸ì„œ ë°ì´í„° íƒ€ìž…ì„ ì¸ì‹í•˜ì—¬ ì ì ˆí•œ 모드를 ì ìš©í•©ë‹ˆë‹¤. ê·¸ í›„ì— ì—¬ëŸ¬ë¶„ì€ ëª¨ë“œë¥¼ 수ë™ìœ¼ë¡œ 변경할 수 있습니다. 만약 ì…€ë“¤ì„ ì´ë™í•  때 모드를 ì§ì ‘ ë³€ê²½í•˜ê³ ìž í•œë‹¤ë©´, ì´ ë²„íŠ¼ì„ ë¹„í™œì„±í™”í•˜ì„¸ìš”. + + + + Auto-switch + ìžë™ 전환 + + + + The text editor modes let you edit plain text, as well as JSON or XML data with syntax highlighting, automatic formatting and validation before saving. + +Errors are indicated with a red squiggle underline. + í…스트 편집기 모드를 사용하면 저장하기 ì „ì— êµ¬ë¬¸ ê°•ì¡° 표시, ìžë™ ì„œì‹ ì§€ì • ë° ìœ íš¨ì„± 검사를 사용하여 JSON ë˜ëŠ” XML ë°ì´í„°ë¿ë§Œ ì•„ë‹ˆë¼ ì¼ë°˜ í…ìŠ¤íŠ¸ë„ íŽ¸ì§‘í•  수 있습니다. +오류는 빨간색 물결 밑줄로 표시ë©ë‹ˆë‹¤. + + + + This Qt editor is used for right-to-left scripts, which are not supported by the default Text editor. The presence of right-to-left characters is detected and this editor mode is automatically selected. + ì´ Qt 편집기는 기본 í…스트 편집기ì—서 ì§€ì›í•˜ì§€ 않는 오른쪽ì—서 왼쪽으로 쓰는 스í¬ë¦½íŠ¸ì— ì‚¬ìš©ë©ë‹ˆë‹¤. 오른쪽ì—서 왼쪽으로 작성ë˜ëŠ” 문ìžê°€ ê°ì§€ë˜ë©´ ì´ íŽ¸ì§‘ê¸° 모드가 ìžë™ìœ¼ë¡œ ì„ íƒë©ë‹ˆë‹¤. + + + + Apply data to cell + ì…€ì— ë°ì´í„° ì ìš© + + + + Open preview dialog for printing displayed image + í‘œì‹œëœ ì´ë¯¸ì§€ì— 대한 ì¸ì‡„ 미리보기 ì°½ì„ ì—½ë‹ˆë‹¤ + + + + Open preview dialog for printing the data currently stored in the cell + 현재 ì…€ì— ì €ìž¥ëœ ë°ì´í„°ì— 대한 ì¸ì‡„ 미리보기 대화ìƒìž 열기 + + + + Auto-format: pretty print on loading, compact on saving. + ìžë™í¬ë§·: 불러올 때 예ì˜ê²Œ 프린트ë˜ê³ , 저장할 때 ìš©ëŸ‰ì„ ì¤„ìž…ë‹ˆë‹¤. + + + + When enabled, the auto-format feature formats the data on loading, breaking the text in lines and indenting it for maximum readability. On data saving, the auto-format feature compacts the data removing end of lines, and unnecessary whitespace. + 활성화ë˜ë©´, ìžë™í¬ë§· ê¸°ëŠ¥ì´ ë°ì´í„°ë¥¼ 불러올 때 í¬ë§·ì„ 지정하여 긴 ë¬¸ìž¥ì„ ì—¬ëŸ¬ 행으로 만들고 들여쓰기를 해서 ê°€ë…ì„±ì„ í–¥ìƒí•©ë‹ˆë‹¤. ë°ì´í„°ë¥¼ 저장할 때는 ìžë™í¬ë§· ê¸°ëŠ¥ì€ ê°œí–‰ 문ìžë¥¼ 제거하여 ë°ì´í„°ë¥¼ 줄ì´ê³  í•„ìš” 없는 ê³µë°±ì„ ì‚­ì œí•©ë‹ˆë‹¤. + + + + Word Wrap + 개행 + + + + Wrap lines on word boundaries + 단어 경계마다 개행 + + + + + Open in default application or browser + 기본 ì‘ìš© 프로그램 ë˜ëŠ” 브ë¼ìš°ì €ì—서 열기 + + + + Open in application + ì‘ìš© 프로그램ì—서 열기 + + + + The value is interpreted as a file or URL and opened in the default application or web browser. + ê°’ì€ íŒŒì¼ ë˜ëŠ” URL로 í•´ì„ë˜ë©° 기본 애플리케ì´ì…˜ ë˜ëŠ” 웹 브ë¼ìš°ì €ì—서 열립니다. + + + + Save file reference... + 참조를 파ì¼ì— 저장... + + + + Save reference to file + 파ì¼ì— 참조 저장 + + + + + Open in external application + 외부 프로그램ì—서 열기 + + + + Autoformat + ìžë™í¬ë§· + + + + &Export... + 내보내기(&E)... + + + + + &Import... + 가져오기(&I)... + + + + + Import from file + 파ì¼ì—서 가져오기 + + + + + Opens a file dialog used to import any kind of data to this database cell. + ì´ ë°ì´í„°ë² ì´ìФ 셀로 ë°ì´í„°ë¥¼ 가져오기 위하여 대화ìƒìžë¥¼ 엽니다. + + + + Export to file + 파ì¼ë¡œ 내보내기 + + + + Opens a file dialog used to export the contents of this database cell to a file. + ì´ ë°ì´í„°ë² ì´ìФ ì…€ì˜ ë‚´ìš©ì„ íŒŒì¼ë¡œ ë‚´ë³´ë‚´ëŠ”ë° ì‚¬ìš©ë˜ëŠ” 대화 ìƒìžë¥¼ 엽니다. + + + + + Print... + ì¸ì‡„하기... + + + + + Ctrl+P + + + + + Open preview dialog for printing displayed text + ì¶œë ¥ëœ í…스트를 ì¸ì‡„하기 위한 ì¸ì‡„ 미리보기 ì°½ì„ ì—½ë‹ˆë‹¤ + + + + Copy Hex and ASCII + Hex와 ASCII를 복사합니다 + + + + Copy selected hexadecimal and ASCII columns to the clipboard + ì„ íƒëœ 16진수와 ASCII 필드를 í´ë¦½ë³´ë“œë¡œ 복사합니다 + + + + Ctrl+Shift+C + + + + + Set as &NULL + NULL로 만들기(&N) + + + + This button saves the changes performed in the cell editor to the database cell. + ì´ ë²„íŠ¼ì€ ë°ì´í„° ì…€ì— ì…€ ì—ë””í„°ì˜ ë³€ê²½ ì‚¬í•­ì„ ì ìš©í•˜ì—¬ 저장하는 버튼입니다. + + + + Apply + ì ìš© + + + + Text + 문ìžì—´ + + + + Binary + ë°”ì´ë„ˆë¦¬ + + + + Erases the contents of the cell + ì…€ì˜ ë°ì´í„° ê°’ì„ ì‚­ì œí•©ë‹ˆë‹¤ + + + + This area displays information about the data present in this database cell + ì´ ì˜ì—­ì€ ì´ ë°ì´í„°ë² ì´ìФ ë°ì´í„° ê°’ì— ëŒ€í•œ 정보를 ë³´ì—¬ì¤ë‹ˆë‹¤ + + + + Type of data currently in cell + 현재 ì…€ì— ìžˆëŠ” ë°ì´í„° 타입 + + + + Size of data currently in table + 현재 í…Œì´ë¸”ì— ìžˆëŠ” ë°ì´í„° í¬ê¸° + + + + Choose a filename to export data + 내보내기 í•  ë°ì´í„°ì˜ íŒŒì¼ ì´ë¦„ì„ ì„ íƒí•˜ì„¸ìš” + + + + + Image data can't be viewed in this mode. + ì´ë¯¸ì§€ ë°ì´í„°ëŠ” ì´ ëª¨ë“œì—서는 ë³¼ 수 없습니다. + + + + + Try switching to Image or Binary mode. + ì´ë¯¸ì§€ë‚˜ ë°”ì´ë„ˆë¦¬ 모드로 바꿔보세요. + + + + + Binary data can't be viewed in this mode. + ë°”ì´ë„ˆë¦¬ ë°ì´í„°ëŠ” ì´ ëª¨ë“œì—서 ë³¼ 수 없습니다. + + + + + Try switching to Binary mode. + ë°”ì´ë„ˆë¦¬ 모드로 바꿔보세요. + + + + + Image files (%1) + ì´ë¯¸ì§€ íŒŒì¼ (%1) + + + + Binary files (*.bin) + ë°”ì´ë„ˆë¦¬ íŒŒì¼ (*.bin) + + + + Choose a file to import + 가져올 파ì¼ì„ ì„ íƒí•˜ì„¸ìš” + + + + %1 Image + %1 ì´ë¯¸ì§€ + + + + Invalid data for this mode + ì´ ëª¨ë“œì— ë§žì§€ 않는 ë°ì´í„° + + + + The cell contains invalid %1 data. Reason: %2. Do you really want to apply it to the cell? + ì´ ì…€ì—는 올바르지 ì•Šì€ %1 ë°ì´í„°ë¥¼ í¬í•¨í•˜ê³  있습니다. ì´ìœ : %2. ì´ ì…€ì„ ì •ë§ë¡œ ì ìš©í• ê¹Œìš”? + + + + + + %n character(s) + + %n ìž + + + + + Type of data currently in cell: %1 Image + 현재 ë°ì´í„° 타입: %1 ì´ë¯¸ì§€ + + + + %1x%2 pixel(s) + %1x%2 픽셀 + + + + Type of data currently in cell: NULL + 현재 ë°ì´í„° 타입: ë„ + + + + Type of data currently in cell: Valid JSON + 현재 ë°ì´í„° 타입: 유효한 JSON + + + + Couldn't save file: %1. + 파ì¼ì„ 저장할 수 없습니다: %1. + + + + The data has been saved to a temporary file and has been opened with the default application. You can now edit the file and, when you are ready, apply the saved new data to the cell editor or cancel any changes. + 현재 ë°ì´í„°ëŠ” 임시 파ì¼ì— 저장ë˜ì—ˆìœ¼ë©° 기본 프로그램으로 열립니다. ì´ì œ 파ì¼ì„ 편집하고 준비ë˜ë©´ ì €ìž¥ëœ ìƒˆ ë°ì´í„°ë¥¼ ì…€ íŽ¸ì§‘ê¸°ì— ì ìš©í•˜ê±°ë‚˜ 변경 ì‚¬í•­ì„ ì·¨ì†Œí•  수 있습니다. + + + + + Type of data currently in cell: Text / Numeric + 현재 ë°ì´í„° 타입: 문ìžì—´ / ìˆ«ìž + + + + Type of data currently in cell: Binary + 현재 ë°ì´í„° 타입: ë°”ì´ë„ˆë¦¬ + + + + + %n byte(s) + + %n ë°”ì´íЏ + + + + + EditIndexDialog + + + &Name + ì´ë¦„(&N) + + + + Order + ì •ë ¬ 순서 + + + + &Table + í…Œì´ë¸”(&T) + + + + Edit Index Schema + ì¸ë±ìФ 스키마 수정 + + + + &Unique + 유니í¬(&U) + + + + For restricting the index to only a part of the table you can specify a WHERE clause here that selects the part of the table that should be indexed + ì¸ë±ìŠ¤ë¥¼ í…Œì´ë¸”ì˜ ì¼ë¶€ë¡œë§Œ 제한하기 위해서 ì¸ë±ì‹± 해야하는 í…Œì´ë¸”ì˜ ì¼ë¶€ë¥¼ 지정하는 WHERE ì ˆì„ ì§€ì •í•  수 있습니다 + + + + Partial inde&x clause + 부분(Partial) ì¸ë±ìŠ¤ì ˆ(&X) + + + + Colu&mns + ì—´(&M) + + + + Table column + í…Œì´ë¸” ì—´ + + + + Type + 타입 + + + + Add a new expression column to the index. Expression columns contain SQL expression rather than column names. + ì¸ë±ìŠ¤ì— ìƒˆ í‘œí˜„ì‹ ì»¬ëŸ¼ì„ ì¶”ê°€í•˜ì„¸ìš”. í‘œí˜„ì‹ ì»¬ëŸ¼ì€ ì»¬ëŸ¼ ì´ë¦„ 대신 SQL 표현ì‹ì´ 들어갑니다. + + + + Index column + ì¸ë±ìФ 컬럼 + + + + Deleting the old index failed: +%1 + ì´ì „ ì¸ë±ìŠ¤ë¥¼ ì‚­ì œí•˜ëŠ”ë° ì‹¤íŒ¨í–ˆìŠµë‹ˆë‹¤: %1 + + + + Creating the index failed: +%1 + ì¸ë±ìФ ìƒì„±ì— 실패했습니다: +%1 + + + + EditTableDialog + + + Edit table definition + í…Œì´ë¸” ì •ì˜ ë³€ê²½ + + + + Table + í…Œì´ë¸” + + + + Advanced + 고급 + + + + Make this a 'WITHOUT rowid' table. Setting this flag requires a field of type INTEGER with the primary key flag set and the auto increment flag unset. + ì´ í…Œì´ë¸”ì„ 'rowidê°€ 없는' í…Œì´ë¸”로 ìƒì„±í•©ë‹ˆë‹¤. ì´ ì„¤ì •ì„ ì‚¬ìš©í•˜ë ¤ë©´ 주 키(Primary Key)로 설정ë˜ê³  ìžë™ ì¦ê°€(Auto Increment)ê°€ í•´ì œëœ INTEGER íƒ€ìž…ì˜ í•„ë“œ 하나가 필요합니다. + + + + Without Rowid + Rowid 필드 ì—†ìŒ + + + + Fields + 필드 + + + + Database sche&ma + ë°ì´í„°ë² ì´ìФ 스키마(&M) + + + + Add + 추가 + + + + Remove + ì‚­ì œ + + + + Move to top + 최ìƒë‹¨ìœ¼ë¡œ 올리기 + + + + Move up + 위로 올리기 + + + + Move down + 아래로 내리기 + + + + Move to bottom + 최하단으로 내리기 + + + + + Name + 필드명 + + + + + Type + 타입 + + + + NN + NN + + + + Not null + Not null + + + + PK + PK + + + + Primary key + 기본 키 + + + + AI + AI + + + + Autoincrement + ìžë™ ì¦ê°€(Autoincrement) + + + + U + U + + + + + + Unique + 유니í¬(Unique) + + + + Default + 기본값 + + + + Default value + 기본값 + + + + + + Check + ì²´í¬ + + + + Check constraint + 제약조건(Check constraint) + + + + Collation + 콜레ì´ì…˜ + + + + + + Foreign Key + 외래키 + + + + Constraints + 제약 ì¡°ê±´ + + + + Add constraint + 제약 ì¡°ê±´ 추가 + + + + Remove constraint + 제약 ì¡°ê±´ ì‚­ì œ + + + + Columns + 필드 + + + + SQL + SQL + + + + <html><head/><body><p><span style=" font-weight:600; color:#ff0000;">Warning: </span>There is something with this table definition that our parser doesn't fully understand. Modifying and saving this table might result in problems.</p></body></html> + <html><head/><body><p><span style=" font-weight:600; color:#ff0000;">Warning: </span>ì´ í…Œì´ë¸” ì •ì˜ ì¤‘ì— íŒŒì„œê°€ í•´ì„í•  수 없는 ë¶€ë¶„ì´ ìžˆìŠµë‹ˆë‹¤. ì´ í…Œì´ë¸”ì„ ìˆ˜ì •í•˜ê±°ë‚˜ 저장하면 문제가 ë°œìƒí•  수 있습니다.</p></body></html> + + + + + Primary Key + 기본 키 + + + + Add a primary key constraint + 기본 키 제약 ì¡°ê±´ 추가 + + + + Add a foreign key constraint + 외래 키 제약 ì¡°ê±´ 추가 + + + + Add a unique constraint + ìœ ë‹ˆí¬ ì œì•½ ì¡°ê±´ 추가 + + + + Add a check constraint + ì²´í¬ ì œì•½ ì¡°ê±´ 추가 + + + + Error creating table. Message from database engine: +%1 + í…Œì´ë¸” ìƒì„± ì—러. ë°ì´í„°ë² ì´ìФ 메시지: +%1 + + + + There already is a field with that name. Please rename it first or choose a different name for this field. + ì´ë¯¸ 다른 필드ì—서 ì‚¬ìš©ì¤‘ì¸ ì´ë¦„입니다. 다른 ì´ë¦„ì„ ì‚¬ìš©í•˜ê±°ë‚˜ 사용 ì¤‘ì¸ í•„ë“œ ì´ë¦„ì„ ë°”ê¾¸ì„¸ìš”. + + + + + There can only be one primary key for each table. Please modify the existing primary key instead. + ê° í…Œì´ë¸”마다 í•˜ë‚˜ì˜ ê¸°ë³¸ 키만 ìžˆì„ ìˆ˜ 있습니다. 기존 기본 키를 대신 수정하세요. + + + + This column is referenced in a foreign key in table %1 and thus its name cannot be changed. + ì´ í•„ë“œëŠ” í…Œì´ë¸” %1 ì— ìžˆëŠ” ì™¸ëž˜í‚¤ì— ì°¸ì¡°ë˜ì–´ 있기 ë•Œë¬¸ì— ì´ë¦„ì„ ë³€ê²½í•  수 없습니다. + + + + There is at least one row with this field set to NULL. This makes it impossible to set this flag. Please change the table data first. + ì´ í•„ë“œ ê°’ì´ NULL로 ë˜ì–´ 있는 레코드가 최소한 하나 ì´ìƒ 존재합니다. ì´ëŸ¬í•œ ìƒíƒœì—서는 ë³€ê²½ì´ ë¶ˆê°€ëŠ¥í•˜ë‹ˆ í…Œì´ë¸”ì˜ ë°ì´í„°ë¥¼ 먼저 수정해서 NULL ê°’ì„ ì‚­ì œì£¼ì„¸ìš”. + + + + There is at least one row with a non-integer value in this field. This makes it impossible to set the AI flag. Please change the table data first. + ì´ í•„ë“œ ê°’ì´ ìˆ«ìžê°€ 아닌 값으로 ë˜ì–´ 있는 레코드가 최소 하나 ì´ìƒ 존재합니다. ì´ëŸ¬í•œ ìƒíƒœì—서는 ë³€ê²½ì´ ë¶ˆê°€ëŠ¥í•˜ë‹ˆ í…Œì´ë¸”ì˜ ë°ì´í„° ê°’ì„ ë¨¼ì € 변경해주세요. + + + + Column '%1' has duplicate data. + + %1 ì—´ì— ì¤‘ë³µëœ ë°ì´í„°ê°€ 있습니다. + + + + + This makes it impossible to enable the 'Unique' flag. Please remove the duplicate data, which will allow the 'Unique' flag to then be enabled. + ì´ë¡œ ì¸í•´ ìœ ë‹ˆí¬ í”Œëž˜ê·¸ë¥¼ 설정할 수 없습니다. 중복 ë°ì´í„°ë¥¼ 제거하여야 ìœ ë‹ˆí¬ í”Œëž˜ê·¸ë¥¼ 설정할 수 있습니다. + + + + Are you sure you want to delete the field '%1'? +All data currently stored in this field will be lost. + ì •ë§ë¡œ '%1' 필드를 삭제하시겠습니까? +ì´ í•„ë“œì— ì €ìž¥ëœ ëª¨ë“  ë°ì´í„°ê°€ ê°™ì´ ì‚­ì œë©ë‹ˆë‹¤. + + + + Please add a field which meets the following criteria before setting the without rowid flag: + - Primary key flag set + - Auto increment disabled + 'rowid 사용하지 않ìŒ'ì„ ì‚¬ìš©í•˜ê¸° 위해서는 아래 ë‘ ê°€ì§€ ì‚¬í•­ì„ ë§Œì¡±ì‹œí‚¤ëŠ” 필드를 추가해주세요: + - 기본 키(Primary Key) 사용 + - ìžë™ ì¦ê°€(Auto Increment) 사용하지 ì•ŠìŒ + + + + ExportDataDialog + + + Export data as CSV + ë°ì´í„°ë¥¼ CSV 파ì¼ë¡œ 내보내기 + + + + Tab&le(s) + í…Œì´ë¸”(&l) + + + + Colu&mn names in first line + 첫 í–‰ì´ í•„ë“œ ì´ë¦„(&M) + + + + Fie&ld separator + 필드 구분ìž(&l) + + + + , + , + + + + ; + ; + + + + Tab + 탭 + + + + | + | + + + + + + Other + 기타 + + + + &Quote character + 문ìžì—´ ë¬¶ìŒ ê¸°í˜¸(&Q) + + + + " + " + + + + ' + ' + + + + New line characters + ê°œí–‰ë¬¸ìž + + + + Windows: CR+LF (\r\n) + Windows: CR+LF (\r\n) + + + + Unix: LF (\n) + Unix: LF (\n) + + + + Pretty print + ì¸ì‡„하기 ì¢‹ì€ ìŠ¤íƒ€ì¼ + + + + + Could not open output file: %1 + 내보낸 파ì¼ì„ ì—´ 수 없습니다: %1 + + + + + Choose a filename to export data + ë°ì´í„°ë¥¼ 내보낼 íŒŒì¼ ì´ë¦„ì„ ì •í•˜ì„¸ìš” + + + + Export data as JSON + JSON으로 내보내기 + + + + exporting CSV + CSV로 내보내기 + + + + exporting JSON + JSON으로 내보내기 + + + + Please select at least 1 table. + 최소한 í…Œì´ë¸” 1개는 ì„ íƒí•˜ì„¸ìš”. + + + + Choose a directory + 디렉터리를 ì„ íƒí•˜ì„¸ìš” + + + + Export completed. + 내보내기가 완료ë˜ì—ˆìŠµë‹ˆë‹¤. + + + + ExportSqlDialog + + + Export SQL... + SQL로 내보내기... + + + + Tab&le(s) + í…Œì´ë¸”(&l) + + + + Select All + ëª¨ë‘ ì„ íƒ + + + + Deselect All + ëª¨ë‘ ì„ íƒ í•´ì œ + + + + &Options + 옵션(&O) + + + + Keep column names in INSERT INTO + INSERT INTOë¬¸ì— í•„ë“œëª… 넣기 + + + + Multiple rows (VALUES) per INSERT statement + í•˜ë‚˜ì˜ INSERTë¬¸ì— ì—¬ëŸ¬ì¤„ (VALUES) 사용하기 + + + + Export everything + ëª¨ë‘ ë‚´ë³´ë‚´ê¸° + + + + Export data only + ë°ì´í„°ë§Œ 내보내기 + + + + Keep old schema (CREATE TABLE IF NOT EXISTS) + ì´ì „ 스키마 유지하기 (CREATE TABLE IF NOT EXISTS) + + + + Overwrite old schema (DROP TABLE, then CREATE TABLE) + ì´ì „ 스키마 ë®ì–´ì“°ê¸° (DROP TABLE, then CREATE TABLE) + + + + Export schema only + 스키마만 내보내기 + + + + Please select at least one table. + 최소한 한 ê°œì˜ í…Œì´ë¸”ì„ ì„ íƒí•´ì£¼ì„¸ìš”. + + + + Choose a filename to export + 내보내기 í•  파ì¼ëª…ì„ ê³ ë¥´ì„¸ìš” + + + + Export completed. + 내보내기가 완료ë˜ì—ˆìŠµë‹ˆë‹¤. + + + + Export cancelled or failed. + 내보내기가 취소ë˜ì—ˆê±°ë‚˜ 실패했습니다. + + + + ExtendedScintilla + + + + Ctrl+H + + + + + Ctrl+F + + + + + + Ctrl+P + + + + + Find... + 찾기... + + + + Find and Replace... + 검색과 바꾸기... + + + + Print... + ì¸ì‡„하기... + + + + ExtendedTableWidget + + + Use as Exact Filter + 정확한 필터로 ì ìš©í•˜ê¸° + + + + Containing + í¬í•¨í•˜ëŠ” + + + + Not containing + í¬í•¨í•˜ì§€ 않는 + + + + Not equal to + 같지 ì•Šì€ + + + + Greater than + 초과 + + + + Less than + 미만 + + + + Greater or equal + ì´ìƒ + + + + Less or equal + ì´í•˜ + + + + Between this and... + ì´ ê°’ê³¼ 사ì´ì—... + + + + Regular expression + ì •ê·œ í‘œí˜„ì‹ + + + + Edit Conditional Formats... + ì¡°ê±´ë¶€ ì„œì‹ íŽ¸ì§‘... + + + + Set to NULL + NULL로 변경하기 + + + + Copy + 복사하기 + + + + Copy with Headers + í—¤ë” í¬í•¨ 복사하기 + + + + Copy as SQL + SQL로 복사하기 + + + + Paste + 붙여넣기 + + + + Print... + ì¸ì‡„하기... + + + + Use in Filter Expression + í•„í„° í‘œí˜„ì‹ ì ìš©í•˜ê¸° + + + + Alt+Del + + + + + Ctrl+Shift+C + + + + + Ctrl+Alt+C + + + + + The content of the clipboard is bigger than the range selected. +Do you want to insert it anyway? + í´ë¦½ë³´ë“œì˜ ë‚´ìš©ì´ ì„ íƒí•œ 범위보다 í½ë‹ˆë‹¤. 어쨌든 추가할까요? + + + + <p>Not all data has been loaded. <b>Do you want to load all data before selecting all the rows?</b><p><p>Answering <b>No</b> means that no more data will be loaded and the selection will not be performed.<br/>Answering <b>Yes</b> might take some time while the data is loaded but the selection will be complete.</p>Warning: Loading all the data might require a great amount of memory for big tables. + <p>모든 ë°ì´í„°ê°€ 로드ë˜ì§€ 않았습니다. <b>모든 í–‰ì„ ì„ íƒí•˜ê¸° ì „ì— ëª¨ë“  ë°ì´í„°ë¥¼ 로드하시겠습니까?</b><p><p><b> 아니요</b>를 ì„ íƒí•˜ë©´ ë” ì´ìƒ ë°ì´í„°ê°€ 로드ë˜ì§€ 않고 ì„ íƒì´ 수행ë˜ì§€ 않습니다.<br/><b>예</b> 를 ì„ íƒí•˜ë©´ ë°ì´í„°ê°€ 로드ë˜ëŠ” ë™ì•ˆ ì‹œê°„ì´ ë‹¤ì†Œ 걸릴 수 있지만 ì„ íƒì´ 완료ë©ë‹ˆë‹¤.</p>경고: 모든 ë°ì´í„°ë¥¼ 로드하려면 í° í…Œì´ë¸”ì„ ìœ„í•´ ë§Žì€ ì–‘ì˜ ë©”ëª¨ë¦¬ê°€ 필요할 수 있습니다. + + + + Cannot set selection to NULL. Column %1 has a NOT NULL constraint. + ì„ íƒ ì‚¬í•­ì„ NULL로 설정할 수 없습니다. ì—´ %1ì— NOT NULL 제약 ì¡°ê±´ì´ ìžˆìŠµë‹ˆë‹¤. + + + + FileExtensionManager + + + File Extension Manager + íŒŒì¼ í™•ìž¥ìž ê´€ë¦¬ìž + + + + &Up + 위로(&U) + + + + &Down + 아래로(&D) + + + + &Add + 추가하기(&A) + + + + &Remove + 삭제하기(&R) + + + + + Description + 설명 + + + + Extensions + í™•ìž¥ìž + + + + *.extension + *.í™•ìž¥ìž + + + + FilterLineEdit + + + Filter + í•„í„° + + + + These input fields allow you to perform quick filters in the currently selected table. +By default, the rows containing the input text are filtered out. +The following operators are also supported: +% Wildcard +> Greater than +< Less than +>= Equal to or greater +<= Equal to or less += Equal to: exact match +<> Unequal: exact inverse match +x~y Range: values between x and y +/regexp/ Values matching the regular expression + ì´ ìž…ë ¥ 필드는 현재 ì„ íƒëœ í…Œì´ë¸”ì— ë¹ ë¥´ê²Œ 필터를 ì ìš©í•  수 있게 í•´ì¤ë‹ˆë‹¤. +기본ì ìœ¼ë¡œ ìž…ë ¥ ë°•ìŠ¤ì— ë“¤ì–´ê°€ìžˆëŠ” ì¡°ê±´ì— ë§žëŠ” í–‰ë“¤ì´ í‘œì‹œë©ë‹ˆë‹¤. +아래와 ê°™ì€ ì—°ì‚°ìžë“¤ì„ 사용할 수 있습니다: +% 와ì¼ë“œì¹´ë“œ +> 초과 +< 미만 +>= ì´ìƒ +<= ì´í•˜ += ê°™ìŒ: 정확히 ì¼ì¹˜ +<> 같지않ìŒ: 정확히 불ì¼ì¹˜ +x~y 범위: x와 yê°’ ì‚¬ì´ ê°’ +/regexp/ ì •ê·œ 표현ì‹ì— ì¼ì¹˜í•˜ëŠ” ê°’ + + + + Clear All Conditional Formats + 모든 ì¡°ê±´ë¶€ ì„œì‹ ì§€ìš°ê¸° + + + + Use for Conditional Format + ì¡°ê±´ë¶€ ì„œì‹ ì‚¬ìš© + + + + Edit Conditional Formats... + ì¡°ê±´ë¶€ ì„œì‹ íŽ¸ì§‘... + + + + Set Filter Expression + í•„í„° í‘œí˜„ì‹ ì„¤ì •í•˜ê¸° + + + + What's This? + ì´ê±´ 무엇ì¸ê°€ìš”? + + + + Is NULL + NULLìž„ + + + + Is not NULL + NULLì´ ì•„ë‹˜ + + + + Is empty + ë¹„ì–´ìžˆìŒ + + + + Is not empty + 비어있지 ì•ŠìŒ + + + + Not containing... + í¬í•¨í•˜ì§€ 않는... + + + + Equal to... + ê°™ì€... + + + + Not equal to... + 같지 않ì€... + + + + Greater than... + 초과... + + + + Less than... + 미만... + + + + Greater or equal... + ì´ìƒ... + + + + Less or equal... + ì´í•˜... + + + + In range... + 범위... + + + + Regular expression... + ì •ê·œ 표현ì‹... + + + + FindReplaceDialog + + + Find and Replace + 찾기와 바꾸기 + + + + Fi&nd text: + ì°¾ì„ í…스트(&N): + + + + Re&place with: + 바꾸려는 í…스트(&P): + + + + Match &exact case + ëŒ€ì†Œë¬¸ìž ì¼ì¹˜ 시(&E) + + + + Match &only whole words + ì „ì²´ 단어 ì¼ì¹˜ 시(&O) + + + + When enabled, the search continues from the other end when it reaches one end of the page + 활성화ë˜ë©´ 페ì´ì§€ì˜ 한쪽 ëì— ë„ë‹¬í–ˆì„ ë•Œ 다른 쪽 ëì—서 ê²€ìƒ‰ì´ ê³„ì†ë©ë‹ˆë‹¤ + + + + &Wrap around + ì „ì²´ 페ì´ì§€ 검색(&W) + + + + When set, the search goes backwards from cursor position, otherwise it goes forward + 활성화ë˜ë©´ 커서 위치 뒤로 검색합니다. 그렇지 않으면 앞으로 검색합니다 + + + + Search &backwards + 뒤로 찾기(&B) + + + + <html><head/><body><p>When checked, the pattern to find is searched only in the current selection.</p></body></html> + <html><head/><body><p>할성화ë˜ë©´ 현재 ì„ íƒ í•­ëª©ì—서만 찾습니다.</p></body></html> + + + + &Selection only + ì„ íƒ í•­ëª©ë§Œ(&S) + + + + <html><head/><body><p>When checked, the pattern to find is interpreted as a UNIX regular expression. See <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>.</p></body></html> + <html><head/><body><p>ì„ íƒí•˜ë©´ ì°¾ì„ íŒ¨í„´ì´ UNIX ì •ê·œ 표현ì‹ìœ¼ë¡œ í•´ì„ë©ë‹ˆë‹¤. <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>를 참고하십시오.</p></body></html> + + + + Use regular e&xpressions + ì •ê·œ í‘œí˜„ì‹ ì‚¬ìš©(&X) + + + + Find the next occurrence from the cursor position and in the direction set by "Search backwards" + 커서 위치ì—서 "뒤로 찾기"ì—서 설정한 ë°©í–¥ì— ë”°ë¼ ë‹¤ìŒ í•­ëª©ì„ ì°¾ìŠµë‹ˆë‹¤ + + + + &Find Next + ë‹¤ìŒ ì°¾ê¸°(&F) + + + + F3 + + + + + &Replace + 바꾸기(&R) + + + + Highlight all the occurrences of the text in the page + 페ì´ì§€ ë‚´ 찾으려는 í…스트를 ëª¨ë‘ ê°•ì¡° 표시합니다 + + + + F&ind All + ëª¨ë‘ ì°¾ê¸°(&I) + + + + Replace all the occurrences of the text in the page + 페ì´ì§€ ë‚´ ì¼ì¹˜í•˜ëŠ” 모든 í…스트를 바꿉니다 + + + + Replace &All + ëª¨ë‘ ë°”ê¾¸ê¸°(&A) + + + + The searched text was not found + 찾으려는 í…스트를 ì°¾ì„ ìˆ˜ 없습니다 + + + + The searched text was not found. + 찾으려는 í…스트를 ì°¾ì„ ìˆ˜ 없습니다. + + + + The searched text was found one time. + 찾으려는 í…스트를 한 번 발견ë˜ì—ˆìŠµë‹ˆë‹¤. + + + + The searched text was found %1 times. + 찾으려는 í…스트가 %1번 발견ë˜ì—ˆìŠµë‹ˆë‹¤. + + + + The searched text was replaced one time. + í…스트가 한 번 바뀌었습니다. + + + + The searched text was replaced %1 times. + %1ê°œì˜ í…스트가 바뀌었습니다. + + + + ForeignKeyEditor + + + &Reset + 초기화(&R) + + + + Foreign key clauses (ON UPDATE, ON DELETE etc.) + 외부 키(ON UPDATE, ON DELETE 등.) + + + + ImportCsvDialog + + + Import CSV file + CSV íŒŒì¼ ê°€ì ¸ì˜¤ê¸° + + + + Table na&me + í…Œì´ë¸” ì´ë¦„(&M) + + + + &Column names in first line + 첫 í–‰ì— í•„ë“œëª… í¬í•¨(&C) + + + + Field &separator + 필드 구분ìž(&S) + + + + , + , + + + + ; + ; + + + + + Tab + 탭 + + + + | + | + + + + Other + 기타 + + + + &Quote character + 문ìžì—´ ë¬¶ìŒ ê¸°í˜¸(&Q) + + + + + Other (printable) + 기타 (ì¸ì‡„ìš©) + + + + + Other (code) + 기타 (코드) + + + + " + " + + + + ' + ' + + + + &Encoding + ì¸ì½”딩(&E) + + + + UTF-8 + UTF-8 + + + + UTF-16 + UTF-16 + + + + ISO-8859-1 + ISO-8859-1 + + + + Trim fields? + 필드 앞뒤 공백 제거? + + + + Separate tables + í…Œì´ë¸” 나누기 + + + + Advanced + 고급 + + + + When importing an empty value from the CSV file into an existing table with a default value for this column, that default value is inserted. Activate this option to insert an empty value instead. + CSV 파ì¼ì˜ 빈 ê°’ì„ ì´ ì—´ì˜ ê¸°ë³¸ ê°’ì´ ìžˆëŠ” 기존 í…Œì´ë¸”로 가져올 때 해당 ê¸°ë³¸ê°’ì´ ì‚½ìž…ë©ë‹ˆë‹¤. 대신 빈 ê°’ì„ ì‚½ìž…í•˜ë ¤ë©´ ì´ ì˜µì…˜ì„ í™œì„±í™”í•˜ì„¸ìš”. + + + + Ignore default &values + 기본 ê°’ì„ ë¬´ì‹œ(&V) + + + + Activate this option to stop the import when trying to import an empty value into a NOT NULL column without a default value. + 기본 ê°’ ì—†ì´ ë¹„ì–´ 있는 ê°’ì„ NOT NULL 열로 가져오려고 í•  때 가져오기를 중단하려면 ì´ ì˜µì…˜ì„ í™œì„±í™”í•˜ì„¸ìš”. + + + + Fail on missing values + ê°’ ëˆ„ë½ ì‹œ 실패 + + + + Disable data type detection + ë°ì´í„° 타입 ì¸ì‹ ë„기 + + + + Disable the automatic data type detection when creating a new table. + 새 í…Œì´ë¸”ì„ ìƒì„±í•  때 ìžë™ ë°ì´í„° 타입 ì¸ì‹ ê¸°ëŠ¥ì„ ë•니다. + + + + When importing into an existing table with a primary key, unique constraints or a unique index there is a chance for a conflict. This option allows you to select a strategy for that case: By default the import is aborted and rolled back but you can also choose to ignore and not import conflicting rows or to replace the existing row in the table. + 기본 키, 고유 제약 ì¡°ê±´ ë˜ëŠ” 고유 ì¸ë±ìŠ¤ë¥¼ 사용하여 기존 í…Œì´ë¸”로 가져올 때 ì¶©ëŒ ê°€ëŠ¥ì„±ì´ ìžˆìŠµë‹ˆë‹¤. ì´ ì˜µì…˜ì„ ì‚¬ìš©í•˜ë©´ 해당 ê²½ìš°ì— ëŒ€í•œ 대처 ë°©ì•ˆì„ ì„ íƒí•  수 있습니다. 기본ì ìœ¼ë¡œëŠ” 가져오기가 중단ë˜ê³  롤백ë˜ì§€ë§Œ ì¶©ëŒí•˜ëŠ” í–‰ì„ ë¬´ì‹œí•˜ê³  가져오지 않거나 í…Œì´ë¸”ì˜ ê¸°ì¡´ í–‰ì„ ë°”ê¾¸ë„ë¡ ì„ íƒí•  ìˆ˜ë„ ìžˆìŠµë‹ˆë‹¤. + + + + Abort import + 가져오기 취소 + + + + Ignore row + ì—´ 무시 + + + + Replace existing row + 기존 í–‰ 바꾸기 + + + + Conflict strategy + ì¶©ëŒ ë°œìƒ ì‹œ + + + + + Deselect All + ëª¨ë‘ ì„ íƒ í•´ì œ + + + + Match Similar + 비슷한거 찾기 + + + + Select All + ëª¨ë‘ ì„ íƒ + + + + There is already a table named '%1' and an import into an existing table is only possible if the number of columns match. + ì´ë¯¸ '%1'ì´ë¼ëŠ” ì´ë¦„ì„ ê°€ì§„ í…Œì´ë¸”ì´ ì¡´ìž¬í•˜ë©° 기존 í…Œì´ë¸”로 ë°ì´í„°ë¥¼ 가져오는 ê²ƒì€ í•„ë“œì˜ ìˆ˜ê°€ ê°™ì„ ë•Œë§Œ 가능합니다. + + + + There is already a table named '%1'. Do you want to import the data into it? + ì´ë¯¸ '%1'ë¼ëŠ” ì´ë¦„ì˜ í…Œì´ë¸”ì´ ì¡´ìž¬í•©ë‹ˆë‹¤. ë°ì´í„°ë¥¼ ì´ í…Œì´ë¸”로 가져올까요? + + + + Creating restore point failed: %1 + ë³µì› í¬ì¸íŠ¸ë¥¼ ìƒì„±í•˜ëŠ”ë° ì‹¤íŒ¨í–ˆìŠµë‹ˆë‹¤: %1 + + + + Creating the table failed: %1 + í…Œì´ë¸” ìƒì„±ì— 실패했습니다: %1 + + + + importing CSV + CSV 가져오기 + + + + Importing the file '%1' took %2ms. Of this %3ms were spent in the row function. + íŒŒì¼ '%1' ê°€ì ¸ì˜¤ëŠ”ë° %2msê°€ 걸렸습니다. ì´ ì¤‘ì—서 í–‰ ê¸°ëŠ¥ì„ ì ìš©í•˜ëŠ”ë° %3msê°€ 걸렸습니다. + + + + Inserting row failed: %1 + í–‰ ì¶”ê°€ì— ì‹¤íŒ¨í–ˆìŠµë‹ˆë‹¤: %1 + + + + MainWindow + + + DB Browser for SQLite + DB Browser for SQLite + + + + toolBar1 + toolBar1 + + + + Opens the SQLCipher FAQ in a browser window + SQLCipher FAQ를 봅니다 + + + + Export one or more table(s) to a JSON file + í…Œì´ë¸”ì„ JSON 파ì¼ë¡œ 내보냅니다 + + + + Find + 찾기 + + + + Find or replace + 검색과 바꾸기 + + + + Print text from current SQL editor tab + 현재 SQL 편집기 íƒ­ì˜ í…스트 ì¸ì‡„ + + + + Print the structure of the opened database + 현재 ì—´ë ¤ 있는 ë°ì´í„°ë² ì´ìŠ¤ì˜ êµ¬ì¡° ì¸ì‡„ + + + + Un/comment block of SQL code + SQL 코드 블럭 ì£¼ì„ ì²˜ë¦¬/í•´ì œ + + + + Un/comment block + 블럭 ì£¼ì„ ì²˜ë¦¬/í•´ì œ + + + + Comment or uncomment current line or selected block of code + 현재 줄 ë˜ëŠ” ì„ íƒëœ ë¸”ëŸ­ì„ ì£¼ì„ ì²˜ë¦¬ ë˜ëŠ” 해제합니다 + + + + Comment or uncomment the selected lines or the current line, when there is no selection. All the block is toggled according to the first line. + ì„ íƒëœ ì¤„ì„ ì£¼ì„ ì²˜ë¦¬ ë˜ëŠ” 해제합니다. ì„ íƒ í•­ëª©ì´ ì—†ëŠ” 경우 현재 ì¤„ì„ ì²˜ë¦¬í•©ë‹ˆë‹¤. 모든 ë¸”ëŸ­ì€ ì²«ë²ˆì§¸ ì¤„ì„ í†µí•´ 토글 í•  수 있습니다. + + + + Ctrl+/ + + + + + Stop SQL execution + SQL 실행 중단 + + + + Stop execution + 실행 중단 + + + + Stop the currently running SQL script + 현재 실행 ì¤‘ì¸ SQL 스í¬ë¦½íЏ 중단 + + + + Execute all/selected SQL + ì „ì²´ ë˜ëŠ” ì„ íƒí•œ SQL 실행 + + + + Open an existing database file in read only mode + ì½ê¸° ì „ìš© 모드로 존재하는 ë°ì´í„°ë² ì´ìФ 파ì¼ì„ 엽니다 + + + + &File + 파ì¼(&F) + + + + &Import + 가져오기(&I) + + + + &Export + 내보내기(&E) + + + + &Edit + 편집(&E) + + + + &View + 보기(&V) + + + + &Help + ë„움ë§(&H) + + + + &Tools + ë„구(&T) + + + + DB Toolbar + DB 툴바 + + + + Edit Database &Cell + ë°ì´í„°ë² ì´ìФ ì…€ 수정하기(&C) + + + + Error Log + ì—러 로그 + + + + This button clears the contents of the SQL logs + ì´ ë²„íŠ¼ì€ SQL 로그 ë‚´ìš©ì„ ì§€ì›ë‹ˆë‹¤ + + + + This panel lets you examine a log of all SQL commands issued by the application or by yourself + ì´ íŒ¨ë„ì—서 ì‘ìš© 프로그램 ë˜ëŠ” 사용ìžê°€ 실행한 모든 SQL ëª…ë ¹ì˜ ê¸°ë¡ì„ 확ì¸í•  수 있습니다 + + + + DB Sche&ma + DB 스키마(&M) + + + + This is the structure of the opened database. +You can drag multiple object names from the Name column and drop them into the SQL editor and you can adjust the properties of the dropped names using the context menu. This would help you in composing SQL statements. +You can drag SQL statements from the Schema column and drop them into the SQL editor or into other applications. + + ì´ê²ƒì€ 열린 ë°ì´í„°ë² ì´ìŠ¤ì˜ êµ¬ì¡°ìž…ë‹ˆë‹¤. +ì´ë¦„ ì—´ì—서 여러 개체 ì´ë¦„ì„ ëŒì–´ì„œ SQL íŽ¸ì§‘ê¸°ì— ë†“ì„ ìˆ˜ 있으며 컨í…스트 메뉴를 사용하여 ëŒì–´ì„œ ë†“ì€ ì´ë¦„ì˜ ì†ì„±ì„ 변경할 수 있습니다. +ì´ê²ƒì€ SQL ë¬¸ì„ ìž‘ì„±í•˜ëŠ”ë° ë„ì›€ì´ ë©ë‹ˆë‹¤. +스키마 ì—´ì—서 SQL ë¬¸ì„ ëŒì–´ì„œ SQL 편집기나 다른 ì‘ìš© í”„ë¡œê·¸ëž¨ì— ë†“ì„ ìˆ˜ë„ ìžˆìŠµë‹ˆë‹¤. + + + + + &Remote + ì›ê²©(&R) + + + + This button executes the SQL statement present in the current editor line + ì´ ë²„íŠ¼ì€ í˜„ìž¬ 편집기 í–‰ì— ìžˆëŠ” SQL ë¬¸ì„ ì‹¤í–‰í•©ë‹ˆë‹¤ + + + + Shift+F5 + + + + + Sa&ve Project + 프로ì íЏ 저장하기(&V) + + + + User + ì‚¬ìš©ìž + + + + Application + 애플리케ì´ì…˜ + + + + &Clear + 지우기(&C) + + + + &New Database... + 새 ë°ì´í„°ë² ì´ìФ(&N)... + + + + + Create a new database file + 새 ë°ì´í„°ë² ì´ìФ 파ì¼ì„ ìƒì„±í•©ë‹ˆë‹¤ + + + + This option is used to create a new database file. + ì´ ì˜µì…˜ì€ ìƒˆ ë°ì´í„°ë² ì´ìФ 파ì¼ì„ ìƒì„±í•˜ë ¤ê³  í•  때 사용합니다. + + + + Ctrl+N + + + + + + &Open Database... + ë°ì´í„°ë² ì´ìФ 열기(&O)... + + + + + + + + Open an existing database file + 기존 ë°ì´í„°ë² ì´ìФ 파ì¼ì„ 엽니다 + + + + + + This option is used to open an existing database file. + ì´ ì˜µì…˜ì€ ê¸°ì¡´ ë°ì´í„°ë² ì´ìФ 파ì¼ì„ ì—´ 때 사용합니다. + + + + Ctrl+O + + + + + &Close Database + ë°ì´í„°ë² ì´ìФ 닫기(&C) + + + + This button closes the connection to the currently open database file + ì´ ë²„íŠ¼ì€ í˜„ìž¬ ì—´ë ¤ 있는 ë°ì´í„°ë² ì´ìФ 파ì¼ì— 대한 ì—°ê²°ì„ ë‹«ìŠµë‹ˆë‹¤ + + + + + Ctrl+W + + + + + + Revert database to last saved state + 마지막 ì €ìž¥ëœ ìƒíƒœë¡œ ë°ì´í„°ë² ì´ìŠ¤ë¥¼ ë˜ëŒë¦½ë‹ˆë‹¤ + + + + This option is used to revert the current database file to its last saved state. All changes made since the last save operation are lost. + ì´ ì˜µì…˜ì€ í˜„ìž¬ ë°ì´í„°ë² ì´ìŠ¤ë¥¼ 마지막 ì €ìž¥ëœ ìƒíƒœë¡œ ë˜ëŒë¦´ 때 사용합니다. 저장 ì´í›„ì— ì´ë£¨ì–´ì§„ 모든 변경 ì‚¬í•­ì„ ë˜ëŒë¦½ë‹ˆë‹¤. + + + + + Write changes to the database file + 변경 ì‚¬í•­ì„ ë°ì´í„°ë² ì´ìФ 파ì¼ì— ë°˜ì˜í•©ë‹ˆë‹¤ + + + + This option is used to save changes to the database file. + ì´ ì˜µì…˜ì€ ë°ì´í„°ë² ì´ìФ 파ì¼ì— 변경 ì‚¬í•­ì„ ì €ìž¥í•˜ê¸° 위해 사용ë©ë‹ˆë‹¤. + + + + Ctrl+S + + + + + Compact the database file, removing space wasted by deleted records + ì‚­ì œëœ ë ˆì½”ë“œë¡œ 낭비ë˜ëŠ” ê³µê°„ì„ ì œê±°í•˜ì—¬ ë°ì´í„°ë² ì´ìФ íŒŒì¼ ì••ì¶• + + + + + Compact the database file, removing space wasted by deleted records. + ì‚­ì œëœ ë ˆì½”ë“œë¡œ 낭비ë˜ëŠ” ê³µê°„ì„ ì œê±°í•˜ì—¬ ë°ì´í„°ë² ì´ìФ íŒŒì¼ ì••ì¶•. + + + + E&xit + 종료(&X) + + + + Ctrl+Q + + + + + Import data from an .sql dump text file into a new or existing database. + .sql ë¤í”„ 문ìžì—´ 파ì¼ì—서 ë°ì´í„°ë¥¼ 새 ë°ì´í„°ë² ì´ìŠ¤ë‚˜ 기존 ë°ì´í„°ë² ì´ìŠ¤ë¡œ 가져옵니다. + + + + This option lets you import data from an .sql dump text file into a new or existing database. SQL dump files can be created on most database engines, including MySQL and PostgreSQL. + ì´ ì˜µì…˜ì€ .sql ë¤í”„ 문ìžì—´ 파ì¼ì—서 ë°ì´í„°ë¥¼ 새 ë°ì´í„°ë² ì´ìŠ¤ë‚˜ 기존 ë°ì´í„°ë² ì´ìŠ¤ë¡œ 가져옵니다. SQL ë¤í”„ 파ì¼ì€ MySQLì´ë‚˜ PostgreSQL 등 ëŒ€ë¶€ë¶„ì˜ ë°ì´í„°ë² ì´ìФ 엔진ì—서 ìƒì„±í•  수 있습니다. + + + + Open a wizard that lets you import data from a comma separated text file into a database table. + 마법사를 사용하여 CSV 파ì¼(쉼로 필드가 나누어진 문ìžì—´ 파ì¼)ì—서 ë°ì´í„°ë² ì´ìФ í…Œì´ë¸”로 ë°ì´í„°ë¥¼ 가져올 수 있습니다. + + + + Open a wizard that lets you import data from a comma separated text file into a database table. CSV files can be created on most database and spreadsheet applications. + 마법사를 사용하여 CSV 파ì¼(쉼표로 필드가 나누어진 문ìžì—´ 파ì¼)ì—서 ë°ì´í„°ë² ì´ìФ í…Œì´ë¸”로 ë°ì´í„°ë¥¼ 가져올 수 있습니다. CSV 파ì¼ì€ ëŒ€ë¶€ë¶„ì˜ ë°ì´í„°ë² ì´ìŠ¤ì™€ 스프레드시트 애플리케ì´ì…˜ì—서 ìƒì„±í•  수 있습니다. + + + + Export a database to a .sql dump text file. + ë°ì´í„°ë² ì´ìŠ¤ë¥¼ .sql ë¤í”„ 문ìžì—´ 파ì¼ë¡œ 내보내기. + + + + This option lets you export a database to a .sql dump text file. SQL dump files contain all data necessary to recreate the database on most database engines, including MySQL and PostgreSQL. + ì´ ì˜µì…˜ì€ ë°ì´í„°ë² ì´ìŠ¤ë¥¼ .sql ë¤í”„ 문ìžì—´ 파ì¼ë¡œ 내보낼 수 있습니다. SQL ë¤í”„ 파ì¼ì€ MySQLê³¼ PostgreSQL 등 ëŒ€ë¶€ë¶„ì˜ ë°ì´í„°ë² ì´ìФ 엔진ì—서 ë°ì´í„°ë² ì´ìŠ¤ë¥¼ 재ìƒì„±í•˜ê¸° 위한 모든 필요한 ë°ì´í„°ë¥¼ í¬í•¨í•˜ê³  있습니다. + + + + Export a database table as a comma separated text file. + ë°ì´í„°ë² ì´ìФ í…Œì´ë¸”ì„ CSV(쉼표로 ë¶„ë¦¬ëœ ë¬¸ìžì—´ 파ì¼)로 내보내기. + + + + Export a database table as a comma separated text file, ready to be imported into other database or spreadsheet applications. + ë°ì´í„°ë² ì´ìФ í…Œì´ë¸”ì„ CSV(쉼표로 ë¶„ë¦¬ëœ ë¬¸ìžì—´ 파ì¼)로 내보내기. 다른 ë°ì´í„°ë² ì´ìŠ¤ë‚˜ 스프레드시트 애플리케ì´ì…˜ì—서 가져와서 사용할 수 있습니다. + + + + Open the Create Table wizard, where it is possible to define the name and fields for a new table in the database + í…Œì´ë¸” ìƒì„± 마법사를 사용하여 ë°ì´í„°ë² ì´ìФì—서 새 í…Œì´ë¸”ì„ ìœ„í•œ ì´ë¦„ê³¼ 필드를 ì •ì˜í•  수 있습니다 + + + + + Delete Table + í…Œì´ë¸” 삭제하기 + + + + Open the Delete Table wizard, where you can select a database table to be dropped. + í…Œì´ë¸” ì‚­ì œ 마법사를 사용하여 ì„ íƒí•œ ë°ì´í„°ë² ì´ìФ í…Œì´ë¸”ì„ ì‚­ì œí•  수 있습니다. + + + + Open the Modify Table wizard, where it is possible to rename an existing table. It is also possible to add or delete fields form a table, as well as modify field names and types. + í…Œì´ë¸” 편집 마법사를 사용하여 기존 í…Œì´ë¸”ì˜ ì´ë¦„ì„ ë³€ê²½í•˜ê±°ë‚˜ í…Œì´ë¸”ì˜ í•„ë“œë¥¼ 추가, ì‚­ì œ, 필드명 변경 ë° íƒ€ìž… ë³€ê²½ì„ í•  수 있습니다. + + + + Open the Create Index wizard, where it is possible to define a new index on an existing database table. + ì¸ë±ìФ ìƒì„± 마법사를 사용하여 기존 ë°ì´í„°ë² ì´ìФ í…Œì´ë¸”ì— ìƒˆ ì¸ë±ìŠ¤ë¥¼ ì •ì˜í•  수 있습니다. + + + + &Preferences... + 환경설정(&P)... + + + + + Open the preferences window. + 환경설정 ì°½ì„ ì—½ë‹ˆë‹¤. + + + + &DB Toolbar + DB 툴바(&D) + + + + Shows or hides the Database toolbar. + ë°ì´í„°ë² ì´ìФ 툴바를 ë³´ì´ê±°ë‚˜ 숨ê¹ë‹ˆë‹¤. + + + + Shift+F1 + + + + + &Recently opened + 최근 ì—´ì—ˆë˜ íŒŒì¼ë“¤(&R) + + + + Open &tab + 탭 열기(&T) + + + + Ctrl+T + + + + + + Database Structure + This has to be equal to the tab title in all the main tabs + ë°ì´í„°ë² ì´ìФ 구조 + + + + This is the structure of the opened database. +You can drag SQL statements from an object row and drop them into other applications or into another instance of 'DB Browser for SQLite'. + + ì´ê²ƒì€ 열려있는 ë°ì´í„°ë² ì´ìŠ¤ì˜ êµ¬ì¡°ìž…ë‹ˆë‹¤. +개체 í–‰ì—서 SQL ë¬¸ì„ ëŒì–´ì„œ 다른 ì‘ìš© 프로그램ì´ë‚˜ 'DB Browser for SQLite'ì˜ ë‹¤ë¥¸ ì¸ìŠ¤í„´ìŠ¤ì— ë†“ì„ ìˆ˜ 있습니다. + + + + + + Browse Data + This has to be equal to the tab title in all the main tabs + ë°ì´í„° 보기 + + + + + Edit Pragmas + This has to be equal to the tab title in all the main tabs + Pragma 수정 + + + + Warning: this pragma is not readable and this value has been inferred. Writing the pragma might overwrite a redefined LIKE provided by an SQLite extension. + 경고: ì´ pragma는 ì½ê¸° ì „ìš©ì´ ì•„ë‹ˆë©° ì´ ê°’ì€ ì¶”ì¸¡ëœ ê°’ìž…ë‹ˆë‹¤. pragma를 작성하면 SQLiteì—서 제공하는 ìž¬ì •ì˜ ëœ LIKE를 ë®ì–´ 쓸 수 있습니다. + + + + + Execute SQL + This has to be equal to the tab title in all the main tabs + SQL 실행 + + + + Ctrl+F4 + + + + + Compact &Database... + ë°ì´í„°ë² ì´ìФ ì••ì¶•(&D)... + + + + This button executes the currently selected SQL statements. If no text is selected, all SQL statements are executed. + ì´ ë²„íŠ¼ì€ í˜„ìž¬ ì„ íƒë˜ì–´ 있는 SQL ëª…ë ¹ë¬¸ì„ ì‹¤í–‰í•©ë‹ˆë‹¤. 만약 ì„ íƒ í•­ëª©ì´ ì—†ìœ¼ë©´ 모든 SQL ëª…ë ¹ë¬¸ì´ ì‹¤í–‰ë©ë‹ˆë‹¤. + + + + &Load Extension... + 확장ë„구 불러오기(&L)... + + + + Execute line + 줄 실행 + + + + &Wiki + 위키(&W) + + + + F1 + + + + + Bug &Report... + 버그 ë³´ê³ (&R)... + + + + Feature Re&quest... + 기능 제안(&Q)... + + + + Web&site + 웹 사ì´íЏ(&S) + + + + &Donate on Patreon... + 후ì›í•˜ê¸°(&D)... + + + + Open &Project... + 프로ì íЏ 열기(&P)... + + + + &Attach Database... + ë°ì´í„°ë² ì´ìФ ì—°ê²°(&A)... + + + + + Add another database file to the current database connection + 현재 ë°ì´í„°ë² ì´ìФ ì—°ê²°ì— ë‹¤ë¥¸ ë°ì´í„°ë² ì´ìФ ì—°ê²°ì„ ì¶”ê°€í•©ë‹ˆë‹¤ + + + + This button lets you add another database file to the current database connection + ì´ ë²„íŠ¼ì„ ì‚¬ìš©í•˜ë©´ 현재 ë°ì´í„°ë² ì´ìФ ì—°ê²°ì— ë‹¤ë¥¸ ë°ì´í„°ë² ì´ìФ 파ì¼ì„ 추가할 수 있습니다 + + + + &Set Encryption... + 암호화 설정(&S)... + + + + SQLCipher &FAQ + SQLCipher FAQ(&F) + + + + Table(&s) to JSON... + í…Œì´ë¸”ì„ JSON으로 내보내기(&S)... + + + + Browse Table + í…Œì´ë¸” íƒìƒ‰ + + + + Open Data&base Read Only... + ì½ê¸° 전용으로 ë°ì´í„°ë² ì´ìФ 열기(&B)... + + + + Open SQL file(s) + SQL íŒŒì¼ ì—´ê¸° + + + + This button opens files containing SQL statements and loads them in new editor tabs + ì´ ë²„íŠ¼ì€ SQL ë¬¸ì´ í¬í•¨ëœ 파ì¼ì„ ì—´ê³  새 편집기 íƒ­ì— ë¡œë“œí•©ë‹ˆë‹¤ + + + + This button lets you save all the settings associated to the open DB to a DB Browser for SQLite project file + ì´ ë²„íŠ¼ì„ ì‚¬ìš©í•˜ë©´ 열린 DB와 ê´€ë ¨ëœ ëª¨ë“  ì„¤ì •ì„ DB Browser for SQLite 프로ì íЏ 파ì¼ë¡œ 저장할 수 있습니다 + + + + This button lets you open a DB Browser for SQLite project file + ì´ ë²„íŠ¼ì„ ì‚¬ìš©í•˜ë©´ DB Browser for SQLite 프로ì íЏ 파ì¼ì„ ì—´ 수 있습니다 + + + + Ctrl+Shift+O + + + + + Save results + ê²°ê³¼ 저장 + + + + Save the results view + ê²°ê³¼ ë·° 저장 + + + + This button lets you save the results of the last executed query + ì´ ë²„íŠ¼ì€ ë§ˆì§€ë§‰ìœ¼ë¡œ 실행한 ì¿¼ë¦¬ì˜ ê²°ê³¼ê°’ì„ ì €ìž¥í•©ë‹ˆë‹¤ + + + + + Find text in SQL editor + SQL 편집기ì—서 í…스트 찾기 + + + + This button opens the search bar of the editor + ì´ ë²„íŠ¼ì€ íŽ¸ì§‘ê¸°ì˜ ê²€ìƒ‰ì°½ì„ ì—½ë‹ˆë‹¤ + + + + Ctrl+F + + + + + + Find or replace text in SQL editor + SQL 편집기ì—서 í…스트 찾아 바꾸기 + + + + This button opens the find/replace dialog for the current editor tab + ì´ ë²„íŠ¼ì€ í˜„ìž¬ ì—´ë ¤ 있는 íŽ¸ì§‘ê¸°ì˜ ì°¾ê¸° 바꾸기 대화ìƒìžë¥¼ 엽니다 + + + + Ctrl+H + + + + + Export to &CSV + CSV로 내보내기(&C) + + + + Save as &view + 뷰로 저장하기(&V) + + + + Save as view + 다른 ì´ë¦„ì˜ ë·°ë¡œ 저장하기 + + + + Shows or hides the Project toolbar. + 프로ì íЏ 툴바를 표시하거나 숨ê¹ë‹ˆë‹¤. + + + + Extra DB Toolbar + 확장 DB 툴바 + + + + New In-&Memory Database + In-Memory ë°ì´í„°ë² ì´ìФ ìƒì„±(&M) + + + + Drag && Drop Qualified Names + ì •ê·œí™”ëœ ì´ë¦„ì„ ëŒì–´ì„œ 놓기 + + + + + Use qualified names (e.g. "Table"."Field") when dragging the objects and dropping them into the editor + 개체를 ëŒì–´ì„œ íŽ¸ì§‘ê¸°ì— ë†“ì„ ë•Œ ì •ê·œí™”ëœ ì´ë¦„(예: "Table", "Field")ì„ ì‚¬ìš©í•©ë‹ˆë‹¤ + + + + Drag && Drop Enquoted Names + ì¸ìš©ëœ ì´ë¦„ì„ ëŒì–´ì„œ 놓기 + + + + + Use escaped identifiers (e.g. "Table1") when dragging the objects and dropping them into the editor + 개체를 ëŒì–´ì„œ íŽ¸ì§‘ê¸°ì— ë†“ì„ ë•Œ ì´ìŠ¤ì¼€ì´í”„ëœ ì‹ë³„ìž(예: "Table1")ì„ ì‚¬ìš©í•©ë‹ˆë‹¤ + + + + &Integrity Check + 무결성 검사(&I) + + + + Runs the integrity_check pragma over the opened database and returns the results in the Execute SQL tab. This pragma does an integrity check of the entire database. + 열린 ë°ì´í„°ë² ì´ìŠ¤ì— ëŒ€í•´ integrity_check pragma를 실행하고 SQL 실행 íƒ­ì— ê²°ê³¼ë¥¼ 반환합니다. ì´ pragma는 ì „ì²´ ë°ì´í„°ë² ì´ìŠ¤ì˜ ë¬´ê²°ì„± 검사를 수행합니다. + + + + &Foreign-Key Check + 외래키 검사(&F) + + + + Runs the foreign_key_check pragma over the opened database and returns the results in the Execute SQL tab + 열린 ë°ì´í„°ë² ì´ìŠ¤ì— ëŒ€í•´ foreign_key_check pragma를 실행하고 SQL 실행 íƒ­ì— ê²°ê³¼ë¥¼ 반환합니다 + + + + &Quick Integrity Check + 빠른 무결성 검사(&Q) + + + + Run a quick integrity check over the open DB + 열린 ë°ì´í„°ë² ì´ìФ 대해 빠른 무결성 검사 실행 + + + + Runs the quick_check pragma over the opened database and returns the results in the Execute SQL tab. This command does most of the checking of PRAGMA integrity_check but runs much faster. + 열린 ë°ì´í„°ë² ì´ìŠ¤ì— ëŒ€í•´ quick_check pragma를 실행하고 SQL 실행 íƒ­ì— ê²°ê³¼ë¥¼ 반환합니다. ì´ ëª…ë ¹ì€ ëŒ€ë¶€ë¶„ì˜ PRAGMA integrity_check 검사를 수행하지만 훨씬 빠르게 실행ë©ë‹ˆë‹¤. + + + + &Optimize + 최ì í™”(&O) + + + + Attempt to optimize the database + ë°ì´í„°ë² ì´ìФ 최ì í™” + + + + Runs the optimize pragma over the opened database. This pragma might perform optimizations that will improve the performance of future queries. + 열린 ë°ì´í„°ë² ì´ìŠ¤ì— ëŒ€í•´ 최ì í™” pragma를 실행합니다. ì´ pragma는 향후 ì¿¼ë¦¬ì˜ ì„±ëŠ¥ì„ í–¥ìƒì‹œí‚¤ëŠ” 최ì í™”를 수행할 수 있습니다. + + + + + Print + ì¸ì‡„하기 + + + + &Save Project As... + 다른 ì´ë¦„으로 프로ì íЏ 저장(&S)... + + + + + + Save the project in a file selected in a dialog + 대화ìƒìžì—서 ì„ íƒí•œ 파ì¼ì— 프로ì íЏ 저장 + + + + Save A&ll + ëª¨ë‘ ì €ìž¥(&l) + + + + + + Save DB file, project file and opened SQL files + DB 파ì¼, 프로ì íЏ íŒŒì¼ ë° ì—´ë¦° SQL íŒŒì¼ ì €ìž¥ + + + + Ctrl+Shift+S + + + + + Open a dialog for printing the text in the current SQL editor tab + 현재 SQL 편집기 탭ì—서 í…스트를 ì¸ì‡„하기 위한 대화ìƒìžë¥¼ 엽니다 + + + + Open a dialog for printing the structure of the opened database + 열린 ë°ì´í„°ë² ì´ìŠ¤ì˜ êµ¬ì¡°ë¥¼ ì¸ì‡„하기 위한 대화ìƒìžë¥¼ 엽니다 + + + + SQL &Log + SQL 로그(&L) + + + + Show S&QL submitted by + ~ì— ì˜í•´ ì‹¤í–‰ëœ SQL 보기(&Q) + + + + &Plot + 플롯(&P) + + + + + Project Toolbar + 프로ì íЏ 툴바 + + + + Extra DB toolbar + 확장 DB 툴바 + + + + + + Close the current database file + 현재 ë°ì´í„°ë² ì´ìФ íŒŒì¼ ë‹«ê¸° + + + + &Revert Changes + 변경사항 취소하기(&R) + + + + &Write Changes + 변경사항 저장하기(&W) + + + + &Database from SQL file... + SQL 파ì¼ë¡œë¶€í„° ë°ì´í„°ë² ì´ìФ 가져오기(&D)... + + + + &Table from CSV file... + CSV 파ì¼ì—서 í…Œì´ë¸” 가져오기(&T)... + + + + &Database to SQL file... + ë°ì´í„°ë² ì´ìŠ¤ë¥¼ SQL로 내보내기(&D)... + + + + &Table(s) as CSV file... + í…Œì´ë¸”ì„ CSV 파ì¼ë¡œ 내보내기(&T)... + + + + &Create Table... + í…Œì´ë¸” ìƒì„±í•˜ê¸°(&C)... + + + + &Delete Table... + í…Œì´ë¸” 삭제하기(&D)... + + + + &Modify Table... + í…Œì´ë¸” 수정하기(&M)... + + + + Create &Index... + ì¸ë±ìФ ìƒì„±í•˜ê¸°(&I)... + + + + W&hat's This? + ì´ê±´ 무엇ì¸ê°€ìš”?(&H) + + + + &About + ì •ë³´(&A) + + + + This button opens a new tab for the SQL editor + ì´ ë²„íŠ¼ì€ SQL íŽ¸ì§‘ê¸°ì˜ ìƒˆë¡œìš´ íƒ­ì„ ì—½ë‹ˆë‹¤ + + + + &Execute SQL + SQL 실행하기(&E) + + + + + + Save SQL file + SQL íŒŒì¼ ì €ìž¥í•˜ê¸° + + + + + Execute current line + 현재 í–‰ 실행하기 + + + + Ctrl+E + + + + + Export as CSV file + CSV 파ì¼ë¡œ 내보내기 + + + + Export table as comma separated values file + í…Œì´ë¸”ì„ CSV 파ì¼ë¡œ 내보내기 + + + + + Save the current session to a file + 현재 ì„¸ì…˜ì„ íŒŒì¼ë¡œ 저장하기 + + + + + Load a working session from a file + 파ì¼ì—서 작업 세션 불러오기 + + + + + Save SQL file as + SQL íŒŒì¼ ë‹¤ë¦„ ì´ë¦„으로 저장하기 + + + + This button saves the content of the current SQL editor tab to a file + ì´ ë²„íŠ¼ì€ í˜„ìž¬ SQL íŽ¸ì§‘ê¸°ì˜ ë‚´ìš©ì„ íŒŒì¼ë¡œ 저장합니다 + + + + &Browse Table + í…Œì´ë¸” 보기(&B) + + + + Copy Create statement + ìƒì„± 구문 복사하기 + + + + Copy the CREATE statement of the item to the clipboard + í•­ëª©ì˜ ìƒì„± êµ¬ë¬¸ì„ í´ë¦½ë³´ë“œì— 복사합니다 + + + + Ctrl+Return + + + + + Ctrl+L + + + + + + Ctrl+P + + + + + Ctrl+D + + + + + Ctrl+I + + + + + Encrypted + ì•”í˜¸í™”ë¨ + + + + Read only + ì½ê¸° ì „ìš© + + + + Database file is read only. Editing the database is disabled. + ë°ì´í„°ë² ì´ìФ 파ì¼ì´ ì½ê¸° 전용입니다. ë°ì´í„°ë² ì´ìФ 수정 ê¸°ëŠ¥ì´ ë¹„í™œì„±í™”ë©ë‹ˆë‹¤. + + + + Database encoding + ë°ì´í„°ë² ì´ìФ ì¸ì½”딩 + + + + Database is encrypted using SQLCipher + ë°ì´í„°ë² ì´ìŠ¤ëŠ” SQLCipher를 통해 암호화ë©ë‹ˆë‹¤ + + + + + Choose a database file + ë°ì´í„°ë² ì´ìФ 파ì¼ì„ ì„ íƒí•˜ì„¸ìš” + + + + + + Choose a filename to save under + 저장하려는 파ì¼ëª…ì„ ì„ íƒí•˜ì„¸ìš” + + + + Error while saving the database file. This means that not all changes to the database were saved. You need to resolve the following error first. + +%1 + ë°ì´í„°ë² ì´ìФ 파ì¼ì„ ì €ìž¥í•˜ë˜ ì¤‘ ì—러가 ë°œìƒí–ˆìŠµë‹ˆë‹¤. ì´ ë§ì€ 모든 ë³€ê²½ì‚¬í•­ë“¤ì´ ë°ì´í„°ë² ì´ìŠ¤ì— ì €ìž¥ë˜ì§€ 못했ìŒì„ ì˜ë¯¸í•©ë‹ˆë‹¤. 다ìŒì— 나오는 ì—러를 먼저 해결하세요. +%1 + + + + Are you sure you want to undo all changes made to the database file '%1' since the last save? + ì •ë§ë¡œ ë°ì´í„°ë² ì´ìФ íŒŒì¼ '%1'ì˜ ëª¨ë“  변경 ì‚¬í•­ì„ ë§ˆì§€ë§‰ ì €ìž¥ëœ ìƒíƒœë¡œ ë˜ëŒë¦½ë‹ˆê¹Œ? + + + + Choose a file to import + 가져올 파ì¼ì„ ì„ íƒí•˜ì„¸ìš” + + + + &%1 %2%3 + &%1 %2%3 + + + + (read only) + (ì½ê¸° ì „ìš©) + + + + Open Database or Project + ë°ì´í„°ë² ì´ìФ ë˜ëŠ” 프로ì íЏ 열기 + + + + Attach Database... + ë°ì´í„°ë² ì´ìФ ì—°ê²°... + + + + Import CSV file(s)... + CSV íŒŒì¼ ê°€ì ¸ì˜¤ê¸°... + + + + Select the action to apply to the dropped file(s). <br/>Note: only 'Import' will process more than one file. + + ë“œë¡­ëœ íŒŒì¼ì— ì ìš©í•  ìž‘ì—…ì„ ì„ íƒí•©ë‹ˆë‹¤. <br/>참고: '가져오기'ë§Œ ë‘ ê°œ ì´ìƒì˜ 파ì¼ì„ 처리합니다. + + + + + Do you want to save the changes made to SQL tabs in the project file '%1'? + '%1' 프로ì íЏ 파ì¼ì— SQL íƒ­ì„ ì¶”ê°€í•˜ê¸° 위해 ë³€ê²½ì‚¬í•­ì„ ì €ìž¥í•˜ì‹œê² ìŠµë‹ˆê¹Œ? + + + + Text files(*.sql *.txt);;All files(*) + 문ìžì—´ 파ì¼(*.sql *.txt);;모든 파ì¼(*) + + + + Do you want to create a new database file to hold the imported data? +If you answer no we will attempt to import the data in the SQL file to the current database. + ë°ì´í„°ë¥¼ 가져와서 새 ë°ì´í„°ë² ì´ìФ 파ì¼ì„ ìƒì„±í•˜ê³  ì‹¶ì€ì‹ ê°€ìš”? +아니ë¼ë©´ SQL 파ì¼ì˜ ë°ì´í„°ë¥¼ 현재 ë°ì´í„°ë² ì´ìŠ¤ë¡œ 가져오기를 í•  것입니다. + + + + You are still executing SQL statements. Closing the database now will stop their execution, possibly leaving the database in an inconsistent state. Are you sure you want to close the database? + ì•„ì§ SQL ëª…ë ¹ë¬¸ì´ ì‹¤í–‰ë˜ëŠ” 중입니다. ë°ì´í„°ë² ì´ìŠ¤ë¥¼ 닫으면 ì‹¤í–‰ì´ ì¤‘ë‹¨ë˜ì–´ ë°ì´í„°ë² ì´ìŠ¤ê°€ ì¼ê´€ì„±ì´ 없어질 수 있습니다. ì •ë§ë¡œ ë°ì´í„°ë² ì´ìŠ¤ë¥¼ 닫으시겠습니까? + + + + Do you want to save the changes made to the project file '%1'? + %1 ë°ì´í„°ë² ì´ìФ 파ì¼ì„ ìƒì„±í•˜ê¸° 위해 ë³€ê²½ì‚¬í•­ì„ ì €ìž¥í•˜ì‹œê² ìŠµë‹ˆê¹Œ? + + + + File %1 already exists. Please choose a different name. + íŒŒì¼ %1ì´ ì´ë¯¸ 존재합니다. 다른 파ì¼ëª…ì„ ì„ íƒí•˜ì„¸ìš”. + + + + Error importing data: %1 + ë°ì´í„° 가져오기 ì—러: %1 + + + + Import completed. + 가져오기가 완료ë˜ì—ˆìŠµë‹ˆë‹¤. + + + + Delete View + ë·° 삭제하기 + + + + Modify View + ë·° 수정하기 + + + + Delete Trigger + 트리거 삭제하기 + + + + Modify Trigger + 트리거 수정하기 + + + + Delete Index + ì¸ë±ìФ 삭제하기 + + + + Modify Index + ì¸ë±ìФ 수정하기 + + + + Modify Table + í…Œì´ë¸” 수정하기 + + + + Do you want to save the changes made to SQL tabs in a new project file? + 새 프로ì íЏ 파ì¼ì— SQL íƒ­ì„ ì¶”ê°€í•˜ê¸° 위해 ë³€ê²½ì‚¬í•­ì„ ì €ìž¥í•˜ì‹œê² ìŠµë‹ˆê¹Œ? + + + + Do you want to save the changes made to the SQL file %1? + %1 SQL 파ì¼ì„ ìƒì„±í•˜ê¸° 위해 ë³€ê²½ì‚¬í•­ì„ ì €ìž¥í•˜ì‹œê² ìŠµë‹ˆê¹Œ? + + + + Could not find resource file: %1 + 리소스 파ì¼ì„ ì°¾ì„ ìˆ˜ 없습니다: %1 + + + + Choose a project file to open + 불러올 프로ì íЏ 파ì¼ì„ ì„ íƒí•˜ì„¸ìš” + + + + Could not open project file for writing. +Reason: %1 + 쓰기 모드로 프로ì íЏ 파ì¼ì„ ì—´ 수 없습니다. +ì›ì¸: %1 + + + + Busy (%1) + 사용 중 (%1) + + + + Setting PRAGMA values will commit your current transaction. +Are you sure? + PRAGMA ì„¤ì •ì„ ë³€ê²½í•˜ë ¤ë©´ ì—¬ëŸ¬ë¶„ì˜ í˜„ìž¬ íŠ¸ëžœìž­ì…˜ì„ ì»¤ë°‹í•´ì•¼í•©ë‹ˆë‹¤. +ë™ì˜í•˜ì‹­ë‹ˆê¹Œ? + + + + Window Layout + ì°½ ë ˆì´ì•„웃 + + + + Reset Window Layout + ì°½ ë ˆì´ì•„웃 초기화 + + + + Alt+0 + + + + + Simplify Window Layout + ì°½ ë ˆì´ì•„웃 단순화 + + + + Shift+Alt+0 + + + + + Dock Windows at Bottom + í•˜ë‹¨ì— ì°½ ê³ ì • + + + + Dock Windows at Left Side + ì¢Œì¸¡ì— ì°½ ê³ ì • + + + + Dock Windows at Top + ìƒë‹¨ì— ì°½ ê³ ì • + + + + The database is currenctly busy. + ì´ ë°ì´í„°ë² ì´ìŠ¤ëŠ” 현재 사용 중입니다. + + + + Click here to interrupt the currently running query. + 여기를 눌러 현재 실행 ì¤‘ì¸ ì¿¼ë¦¬ë¥¼ ê°•ì œ 중단합니다. + + + + Could not open database file. +Reason: %1 + ë°ì´í„°ë² ì´ìФ 파ì¼ì„ ì—´ 수 없습니다. +ì›ì¸: %1 + + + + In-Memory database + In-Memory ë°ì´í„°ë² ì´ìФ + + + + Are you sure you want to delete the table '%1'? +All data associated with the table will be lost. + ì •ë§ë¡œ í…Œì´ë¸” '%1'ì„ ì‚­ì œí•˜ì‹œê² ìŠµë‹ˆê¹Œ? +í…Œì´ë¸”ì˜ ëª¨ë“  ë°ì´í„°ê°€ ì‚­ì œë©ë‹ˆë‹¤. + + + + Are you sure you want to delete the view '%1'? + ì •ë§ë¡œ '%1' 뷰를 삭제할까요? + + + + Are you sure you want to delete the trigger '%1'? + ì •ë§ë¡œ '%1' 트리거를 삭제할까요? + + + + Are you sure you want to delete the index '%1'? + ì •ë§ë¡œ '%1' ì¸ë±ìŠ¤ë¥¼ 삭제할까요? + + + + Error: could not delete the table. + ì—러: í…Œì´ë¸”ì„ ì‚­ì œí•  수 없습니다. + + + + Error: could not delete the view. + ì—러: 뷰를 삭제할 수 없습니다. + + + + Error: could not delete the trigger. + ì—러: 트리거를 삭제할 수 없습니다. + + + + Error: could not delete the index. + ì—러: ì¸ë±ìŠ¤ë¥¼ 삭제할 수 없습니다. + + + + Message from database engine: +%1 + ë°ì´í„°ë² ì´ìФ 엔진 메시지: +%1 + + + + Editing the table requires to save all pending changes now. +Are you sure you want to save the database? + 'pending'ì˜ ëœ»ì´ ë³´ë¥˜ìž…ë‹ˆë‹¤ë§Œ, 여기서는 작업 중ì´ë˜ì´ ë” ë§žë‹¤ê³  íŒë‹¨í–ˆìŠµë‹ˆë‹¤. + í…Œì´ë¸”ì„ íŽ¸ì§‘í•˜ë ¤ë©´ 작업 중ì´ë˜ 모든 변경 ì‚¬í•­ì„ ì €ìž¥í•´ì•¼í•©ë‹ˆë‹¤. +ë°ì´í„°ë² ì´ìŠ¤ë¥¼ 저장하시겠습니까? + + + + Edit View %1 + ë·° 편집 %1 + + + + Edit Trigger %1 + 트리거 편집 %1 + + + + You are already executing SQL statements. Do you want to stop them in order to execute the current statements instead? Note that this might leave the database in an inconsistent state. + ì´ë¯¸ SQL ëª…ë ¹ë¬¸ì„ ì‹¤í–‰í•˜ì˜€ìŠµë‹ˆë‹¤. 현재 ëª…ë ¹ë¬¸ì„ ëŒ€ì‹  실행하기 위해 기존 ì‹¤í–‰ì„ ì¤‘ë‹¨í•˜ì‹œê² ìŠµë‹ˆê¹Œ? ì´ë¡œ ì¸í•´ ë°ì´í„°ë² ì´ìŠ¤ê°€ ì¼ê´€ì„±ì´ 없는 ìƒíƒœê°€ ë  ìˆ˜ 있습니다. + + + + -- EXECUTING SELECTION IN '%1' +-- + -- '%1ì˜ ì„ íƒ í•­ëª© 실행 +-- + + + + -- EXECUTING LINE IN '%1' +-- + --'%1'ì—서 ë¼ì¸ 실행 중 +-- + + + + -- EXECUTING ALL IN '%1' +-- + -- '%1'로부터 ì „ì²´ 실행 +-- + + + + + At line %1: + %1번째 줄: + + + + Result: %1 + ê²°ê³¼: %1 + + + + Result: %2 + ê²°ê³¼: %2 + + + + Setting PRAGMA values or vacuuming will commit your current transaction. +Are you sure? + PRAGMA ê°’ì„ ì§€ì •í•˜ì§€ 않으면 현재 íŠ¸ëžœìž­ì…˜ì— DB íŒŒì¼ ì²­ì†Œ 작업(Vacuum)ì´ ì»¤ë°‹ë©ë‹ˆë‹¤. 진행할까요? + + + + Opened '%1' in read-only mode from recent file list + 최근 íŒŒì¼ ëª©ë¡ì—서 ì½ê¸° ì „ìš© 모드로 '%1'ì„(를) 열었습니다 + + + + Opened '%1' from recent file list + 최근 íŒŒì¼ ëª©ë¡ì—서 '%1'ì„(를) 열었습니다 + + + + This action will open a new SQL tab with the following statements for you to edit and run: + ì´ ìž‘ì—…ì„ ìˆ˜í–‰í•˜ë©´ 편집하거나 실행할 수 있는 ë‹¤ìŒ ëª…ë ¹ë¬¸ì´ í¬í•¨ëœ 새 SQL íƒ­ì´ ì—´ë¦½ë‹ˆë‹¤: + + + + Rename Tab + 탭 ì´ë¦„ 변경 + + + + Duplicate Tab + 탭 복제 + + + + Close Tab + 탭 닫기 + + + + Opening '%1'... + '%1' 여는 중... + + + + There was an error opening '%1'... + '%1'ì„ ì—¬ëŠ” 중 ì—러가 ë°œìƒí–ˆìŠµë‹ˆë‹¤... + + + + Value is not a valid URL or filename: %1 + 올바른 URL ë˜ëŠ” íŒŒì¼ ì´ë¦„ì´ ì•„ë‹™ë‹ˆë‹¤: %1 + + + + %1 rows returned in %2ms + %2msì˜ ì‹œê°„ì´ ê±¸ë ¤ì„œ %1 í–‰ì´ ë°˜í™˜ë˜ì—ˆìŠµë‹ˆë‹¤ + + + + Choose text files + í…스트 íŒŒì¼ ì„ íƒ + + + + Import completed. Some foreign key constraints are violated. Please fix them before saving. + 가져오기가 완료ë˜ì—ˆìŠµë‹ˆë‹¤. ì¼ë¶€ 외래 í‚¤ì˜ ì œì•½ ì¡°ê±´ì´ ìœ„ë°˜ë˜ì—ˆìŠµë‹ˆë‹¤. 저장 하기 ì „ì— ìˆ˜ì •í•˜ì‹­ì‹œì˜¤. + + + + The statements in this tab are still executing. Closing the tab will stop the execution. This might leave the database in an inconsistent state. Are you sure you want to close the tab? + ì´ íƒ­ì˜ ëª…ë ¹ë¬¸ì€ ì—¬ì „ížˆ 실행 중입니다. íƒ­ì„ ë‹«ìœ¼ë©´ ì‹¤í–‰ì´ ì¤‘ë‹¨ë©ë‹ˆë‹¤. ì´ë¡œ ì¸í•´ ë°ì´í„°ë² ì´ìŠ¤ê°€ ì¼ê´€ì„±ì´ 없는 ìƒíƒœê°€ ë  ìˆ˜ 있습니다. ì •ë§ë¡œ íƒ­ì„ ë‹«ìœ¼ì‹œê² ìŠµë‹ˆê¹Œ? + + + + Select SQL file to open + ì—´ SQL 파ì¼ì„ ì„ íƒí•˜ì„¸ìš” + + + + Select file name + íŒŒì¼ ì´ë¦„ì„ ì„ íƒí•˜ì„¸ìš” + + + + Select extension file + íŒŒì¼ í™•ìž¥ìžë¥¼ ì„ íƒí•˜ì„¸ìš” + + + + Extension successfully loaded. + í™•ìž¥ê¸°ëŠ¥ì„ ì„±ê³µì ìœ¼ë¡œ 불러왔습니다. + + + + Error loading extension: %1 + 확장기능 불러오기 ì—러: %1 + + + + + Don't show again + 다시 ë³´ì§€ 않기 + + + + New version available. + ì´ìš© 가능한 새 ë²„ì „ì´ ìžˆìŠµë‹ˆë‹¤. + + + + A new DB Browser for SQLite version is available (%1.%2.%3).<br/><br/>Please download at <a href='%4'>%4</a>. + ì´ìš© 가능한 새 ë²„ì „ì´ ìžˆìŠµë‹ˆë‹¤ (%1.%2.%3).<br/><br/><a href='%4'>%4</a>ì—서 다운로드하세요. + + + + This project file is using an old file format because it was created using DB Browser for SQLite version 3.10 or lower. Loading this file format is still fully supported but we advice you to convert all your project files to the new file format because support for older formats might be dropped at some point in the future. You can convert your files by simply opening and re-saving them. + ì´ í”„ë¡œì íЏ 파ì¼ì€ DB Browser for SQLite 버전 3.10 ì´í•˜ë¥¼ 사용하여 ìƒì„±ë˜ì—ˆê¸° ë•Œë¬¸ì— ì´ì „ íŒŒì¼ í˜•ì‹ì„ 사용하고 있습니다. ì´ íŒŒì¼ í˜•ì‹ì„ 불러오는 ê²ƒì€ ì—¬ì „ížˆ 완벽하게 ì§€ì›ë˜ì§€ë§Œ ì´ì „ 형ì‹ì— 대한 ì§€ì›ì´ 추후 ì¤‘ë‹¨ë  ìˆ˜ 있으므로 모든 프로ì íЏ 파ì¼ì„ ì‹ ê·œ íŒŒì¼ í˜•ì‹ìœ¼ë¡œ 변환하는 ê²ƒì´ ì¢‹ìŠµë‹ˆë‹¤. 파ì¼ì„ ì—´ê³  다시 저장하기만하면 파ì¼ì„ 변환할 수 있습니다. + + + + Project saved to file '%1' + '%1' 파ì¼ë¡œ 프로ì íŠ¸ê°€ 저장ë˜ì—ˆìŠµë‹ˆë‹¤ + + + + Collation needed! Proceed? + 콜레ì´ì…˜ì´ 필요합니다! 진행할까요? + + + + A table in this database requires a special collation function '%1' that this application can't provide without further knowledge. +If you choose to proceed, be aware bad things can happen to your database. +Create a backup! + ì´ ë°ì´í„°ë² ì´ìŠ¤ì˜ í…Œì´ë¸”ì€ ì´ ì• í”Œë¦¬ì¼€ì´ì…˜ì—서 잘 알지 못하는 특별한 함수 '%1'ê°€ 필요합니다. +ì´ëŒ€ë¡œ ê³„ì† ì§„í–‰í•  수는 있습니다만 ì—¬ëŸ¬ë¶„ì˜ ë°ì´í„°ë² ì´ìŠ¤ì— ë‚˜ìœ ì˜í–¥ì´ ê°ˆ ìˆ˜ë„ ìžˆìŠµë‹ˆë‹¤. +ë°±ì—…ì„ ìƒì„±í•˜ì„¸ìš”! + + + + creating collation + 콜레ì´ì…˜ ìƒì„± + + + + Set a new name for the SQL tab. Use the '&&' character to allow using the following character as a keyboard shortcut. + SQL íƒ­ì˜ ìƒˆ ì´ë¦„ì„ ì„¤ì •í•˜ì„¸ìš”. '&&' 문ìžë¥¼ 사용하여 다ìŒì— ë”°ë¼ì˜¤ëŠ” 문ìžë¥¼ 키보드 단축키로서 사용할 수 있습니다. + + + + Please specify the view name + ë·° ì´ë¦„ì„ ì§€ì •í•´ì£¼ì„¸ìš” + + + + There is already an object with that name. Please choose a different name. + ì´ë¯¸ ê°™ì€ ì´ë¦„ì˜ ê°ì²´ê°€ 존재합니다. 다른 ì´ë¦„ì„ ê³ ë¥´ì„¸ìš”. + + + + View successfully created. + ë·°ê°€ 성공ì ìœ¼ë¡œ ìƒì„±ë˜ì—ˆìŠµë‹ˆë‹¤. + + + + Error creating view: %1 + ë·° ìƒì„± ì—러: %1 + + + + This action will open a new SQL tab for running: + ì´ ìž‘ì—…ì€ ë‹¤ìŒì„ 실행하는 새 SQL íƒ­ì„ ì—½ë‹ˆë‹¤: + + + + Press Help for opening the corresponding SQLite reference page. + 해당 SQLite 참조 페ì´ì§€ë¥¼ 열려면 ë„움ë§ì„ 누르십시오. + + + + DB Browser for SQLite project file (*.sqbpro) + DB Browser for SQLite 프로ì íЏ íŒŒì¼ (*.sqbpro) + + + + Error checking foreign keys after table modification. The changes will be reverted. + í…Œì´ë¸” 수정 후 외래 키를 확ì¸í•˜ëŠ” 중 오류가 ë°œìƒí•˜ì˜€ìŠµë‹ˆë‹¤. 변경 ì‚¬í•­ì´ ë˜ëŒë ¤ì§‘니다. + + + + This table did not pass a foreign-key check.<br/>You should run 'Tools | Foreign-Key Check' and fix the reported issues. + ì´ í…Œì´ë¸”ì€ ì™¸ëž˜ 키 검사를 통과하지 못했습니다.<br/>'ë„구 -> 외래 키 검사'를 실행하여 ë³´ê³ ëœ ë¬¸ì œë¥¼ 해결하십시오. + + + + Execution finished with errors. + ì—러가 ë°œìƒí•˜ì—¬ 실행 중단ë¨. + + + + Execution finished without errors. + ì—러 ì—†ì´ ì‹¤í–‰ 완료. + + + + NullLineEdit + + + Set to NULL + NULL로 변경하기 + + + + Alt+Del + + + + + PlotDock + + + Plot + 플롯 + + + + <html><head/><body><p>This pane shows the list of columns of the currently browsed table or the just executed query. You can select the columns that you want to be used as X or Y axis for the plot pane below. The table shows detected axis type that will affect the resulting plot. For the Y axis you can only select numeric columns, but for the X axis you will be able to select:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Date/Time</span>: strings with format &quot;yyyy-MM-dd hh:mm:ss&quot; or &quot;yyyy-MM-ddThh:mm:ss&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Date</span>: strings with format &quot;yyyy-MM-dd&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Time</span>: strings with format &quot;hh:mm:ss&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Label</span>: other string formats. Selecting this column as X axis will produce a Bars plot with the column values as labels for the bars</li><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Numeric</span>: integer or real values</li></ul><p>Double-clicking the Y cells you can change the used color for that graph.</p></body></html> + <html><head/><body><p>ì´ í™”ë©´ì€ í˜„ìž¬ ë³´ê³  있는 í…Œì´ë¸” ë˜ëŠ” 방금 실행한 ì¿¼ë¦¬ì˜ í•„ë“œ 목ë¡ì„ ë³´ì—¬ì¤ë‹ˆë‹¤. 아래 플롯 í™”ë©´ì— Xì¶• ë˜ëŠ” Y축으로 사용할 필드를 ì„ íƒí•  수 있습니다. ì´ í‘œëŠ” ê²°ê³¼ í”Œë¡¯ì— ì˜í–¥ì„ 줄 수 있다고 ì¸ì‹ëœ ì¶•ì˜ ì¢…ë¥˜ë¥¼ ë³´ì—¬ì¤ë‹ˆë‹¤. Yì¶•ì€ ìˆ«ìž íƒ€ìž… 필드만 ì„ íƒí•  수 있지만 Xì¶•ì€ ë‹¤ìŒê³¼ ê°™ì€ í•„ë“œ íƒ€ìž…ì„ ì„ íƒí•  수 있습니다:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Date/Time</span>: strings with format &quot;yyyy-MM-dd hh:mm:ss&quot; or &quot;yyyy-MM-ddThh:mm:ss&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">ë‚ ì§œ</span>: 문ìžì—´ í¬ë§· &quot;yyyy-MM-dd&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">시간</span>: 문ìžì—´ í¬ë§· &quot;hh:mm:ss&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">ë¼ë²¨</span>: ì´ í•„ë“œë¥¼ X축으로 ì„ íƒí•˜ë©´ 필드 ê°’ì´ ë§‰ëŒ€ì˜ ë ˆì´ë¸”로 í‘œì‹œëœ ë§‰ëŒ€ 그래프가 ìƒì„±ë©ë‹ˆë‹¤.</li><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">숫ìž</span>: 정수 ë˜ëŠ” 실수</li></ul><p>Y ì…€ì„ ë”블 í´ë¦­í•˜ë©´ ê·¸ëž˜í”„ì— ì‚¬ìš©ëœ ìƒ‰ì„ ë³€ê²½í•  수 있습니다.</p></body></html> + + + + Columns + 필드 + + + + X + X + + + + Y1 + Y1 + + + + Y2 + Y2 + + + + Axis Type + ì¶• 타입 + + + + Here is a plot drawn when you select the x and y values above. + +Click on points to select them in the plot and in the table. Ctrl+Click for selecting a range of points. + +Use mouse-wheel for zooming and mouse drag for changing the axis range. + +Select the axes or axes labels to drag and zoom only in that orientation. + 위ì—서 x와 y ê°’ì„ ì„ íƒí•˜ë©´ ì—¬ê¸°ì— í”Œë¡¯ì´ ê·¸ë ¤ì§‘ë‹ˆë‹¤. + +플롯과 í…Œì´ë¸”ì—서 í•­ëª©ì„ í´ë¦­í•˜ë©´ ì„ íƒë©ë‹ˆë‹¤. 여러 ë²”ìœ„ì˜ í•­ëª©ì„ ì„ íƒí•˜ë ¤ë©´ Control+í´ë¦­ì„ 하세요. + +확대/축소를 하려면 마우스 íœ ì„ ì´ìš©í•˜ê³  ì¶• 범위를 바꾸려면 마우스를 드래그하세요. + +한 방향으로만 드래그 ë˜ëŠ” 확대/축소를 하고 싶다면 ì¶• ë˜ëŠ” ì¶• ë¼ë²¨ì„ ì„ íƒí•˜ì„¸ìš”. + + + + Line type: + í–‰ 타입: + + + + + None + 사용하지 ì•ŠìŒ + + + + Line + í–‰ + + + + StepLeft + 왼쪽으로 + + + + StepRight + 오른쪽으로 + + + + StepCenter + 중앙으로 + + + + Impulse + 임펄스(Impulse) + + + + Point shape: + í¬ì¸íЏ 모양: + + + + Cross + ì‹­ìžê°€ + + + + Plus + ë”하기 + + + + Circle + ì› + + + + Disc + 디스í¬(Disc) + + + + Square + 정사ê°í˜• + + + + Diamond + 마름모 + + + + Star + 별 + + + + Triangle + 삼ê°í˜• + + + + TriangleInverted + 역삼ê°í˜• + + + + CrossSquare + CrossSquare + + + + PlusSquare + PlusSquare + + + + CrossCircle + CrossCircle + + + + PlusCircle + PlusCircle + + + + Peace + Peace + + + + <html><head/><body><p>Save current plot...</p><p>File format chosen by extension (png, jpg, pdf, bmp)</p></body></html> + <html><head/><body><p>현재 플롯 저장하기...</p><p>íŒŒì¼ í¬ë§· 확장ìžë¥¼ ì„ íƒí•˜ì„¸ìš” (png, jpg, pdf, bmp)</p></body></html> + + + + Save current plot... + 현재 플롯 저장하기... + + + + + Load all data and redraw plot + 모든 ë°ì´í„°ë¥¼ 불러와서 í”Œë¡¯ì„ ë‹¤ì‹œ 그립니다 + + + + + + Row # + í–‰ # + + + + Copy + 복사 + + + + Print... + ì¸ì‡„하기... + + + + Show legend + 범례 표시 + + + + Stacked bars + ëˆ„ì  ë§‰ëŒ€ + + + + Date/Time + ë‚ ì§œ/시간 + + + + Date + ë‚ ì§œ + + + + Time + 시간 + + + + + Numeric + ìˆ«ìž + + + + Label + ë ˆì´ë¸” + + + + Invalid + 올바르지 ì•ŠìŒ + + + + Load all data and redraw plot. +Warning: not all data has been fetched from the table yet due to the partial fetch mechanism. + 모든 ë°ì´í„°ë¥¼ 불러와서 í”Œë¡¯ì„ ë‹¤ì‹œ 그립니다. +주ì˜: ì´ ê¸°ëŠ¥ì€ ë¶€ë¶„ë§Œ 가져오는 메커니즘으로 ì¸í•˜ì—¬ í…Œì´ë¸”ì—서 모든 ë°ì´í„°ê°€ 가져와지지는 않습니다. + + + + Choose an axis color + ì¶• ìƒ‰ê¹”ì„ ì„ íƒí•˜ì„¸ìš” + + + + Choose a filename to save under + 저장하려는 파ì¼ëª…ì„ ì„ íƒí•˜ì„¸ìš” + + + + PNG(*.png);;JPG(*.jpg);;PDF(*.pdf);;BMP(*.bmp);;All Files(*) + PNG(*.png);;JPG(*.jpg);;PDF(*.pdf);;BMP(*.bmp);;모든 파ì¼(*) + + + + There are curves in this plot and the selected line style can only be applied to graphs sorted by X. Either sort the table or query by X to remove curves or select one of the styles supported by curves: None or Line. + í”Œë¡¯ì— ìžˆëŠ” 곡선들 ì¤‘ì— X축으로 ì •ë ¬ëœ ê·¸ëž˜í”„ë§Œ ì„ íƒí•œ ì„ ì˜ ìŠ¤íƒ€ì¼ì„ 변경할 수 있습니다. X로 표 ë˜ëŠ” 쿼리를 정렬하여 ê³¡ì„ ì„ ì œê±°í•˜ë ¤ë©´ '사용하지 않ìŒ'ì„, ê³¡ì„ ì´ ì§€ì›í•˜ëŠ” ìŠ¤íƒ€ì¼ ì¤‘ 하나를 ì„ íƒí•˜ë ¤ë©´ 'í–‰'ì„ ì„ íƒí•˜ì„¸ìš”. + + + + Loading all remaining data for this table took %1ms. + í…Œì´ë¸”ì˜ ë‚˜ë¨¸ì§€ ë°ì´í„°ë¥¼ ë¶ˆëŸ¬ì˜¤ëŠ”ë° %1msê°€ 소요ë˜ì—ˆìŠµë‹ˆë‹¤. + + + + PreferencesDialog + + + Preferences + 환경설정 + + + + &General + ì¼ë°˜(&G) + + + + Remember last location + 마지막 위치를 기억 + + + + Always use this location + í•­ìƒ ì´ ìœ„ì¹˜ë¥¼ 사용 + + + + Remember last location for session only + ê°™ì€ ì„¸ì…˜ì—서만 마지막 위치를 기억 + + + + + + ... + ... + + + + Default &location + 기본 위치(&L) + + + + Lan&guage + 언어(&G) + + + + Automatic &updates + ìžë™ ì—…ë°ì´íЏ(&U) + + + + + + + + + + + + enabled + 사용하기 + + + + Show remote options + ì›ê²© 옵션 보기 + + + + &Database + ë°ì´í„°ë² ì´ìФ(&D) + + + + Database &encoding + ë°ì´í„°ë² ì´ìФ ì¸ì½”딩(&E) + + + + Open databases with foreign keys enabled. + 외래키 ê¸°ëŠ¥ì„ ì‚¬ìš©í•˜ë©° ë°ì´í„°ë² ì´ìŠ¤ë¥¼ 엽니다. + + + + &Foreign keys + 외래키(&F) + + + + Data &Browser + ë°ì´í„° 보기(&B) + + + + Remove line breaks in schema &view + 스키마 ë·°ì—서 ê°œí–‰ì„ ì œê±°í•©ë‹ˆë‹¤(&V) + + + + Prefetch block si&ze + 프리패치 í•  블럭 í¬ê¸°(&Z) + + + + SQ&L to execute after opening database + ë°ì´í„°ë² ì´ìŠ¤ë¥¼ ì—° 후 SQLì„ ì‹¤í–‰(&L) + + + + Default field type + 기본 필드 타입 + + + + Font + 글꼴 + + + + &Font + 글꼴(&F) + + + + Content + ë‚´ìš© + + + + Symbol limit in cell + ì…€ 안 심볼 한계 + + + + NULL + NULL + + + + Regular + 보통 + + + + Binary + ë°”ì´ë„ˆë¦¬ + + + + Background + 배경색 + + + + Filters + í•„í„° + + + + Toolbar style + 툴바 ìŠ¤íƒ€ì¼ + + + + + + + + Only display the icon + ì•„ì´ì½˜ë§Œ 표시 + + + + + + + + Only display the text + í…스트만 표시 + + + + + + + + The text appears beside the icon + í…스트를 ì•„ì´ì½˜ 옆으로 + + + + + + + + The text appears under the icon + í…스트가 ì•„ì´ì½˜ 아래로 + + + + + + + + Follow the style + 애플리케ì´ì…˜ ìŠ¤íƒ€ì¼ ì ìš© + + + + DB file extensions + ë°ì´í„°ë² ì´ìФ íŒŒì¼ í™•ìž¥ìž + + + + Manage + 관리 + + + + Main Window + ë©”ì¸ ì°½ + + + + Database Structure + ë°ì´í„°ë² ì´ìФ 구조 + + + + Browse Data + ë°ì´í„° 보기 + + + + Execute SQL + SQL 실행 + + + + Edit Database Cell + ë°ì´í„°ë² ì´ìФ ì…€ 수정 + + + + When this value is changed, all the other color preferences are also set to matching colors. + ì´ ê°’ì´ ë³€ê²½ë˜ë©´ 다른 모든 색ìƒë“¤ë„ ì´ì— ì¼ì¹˜í•˜ëŠ” 색ìƒìœ¼ë¡œ 설정ë©ë‹ˆë‹¤. + + + + Follow the desktop style + ë°ìФí¬í†± ìŠ¤íƒ€ì¼ ì ìš© + + + + Dark style + 어둡게 + + + + Application style + 애플리케ì´ì…˜ ìŠ¤íƒ€ì¼ + + + + This sets the font size for all UI elements which do not have their own font size option. + 개별 글꼴 í¬ê¸° ì˜µì…˜ì´ ì—†ëŠ” 모든 UI ìš”ì†Œì˜ ê¸€ê¼´ í¬ê¸°ë¥¼ 설정합니다. + + + + Font size + 글꼴 í¬ê¸° + + + + When enabled, the line breaks in the Schema column of the DB Structure tab, dock and printed output are removed. + 활성화ë˜ë©´ DB 구조 íƒ­ì˜ ìŠ¤í‚¤ë§ˆ ì—´ì—서 줄 바꿈, ë… ë° ì¸ì‡„ëœ ì¶œë ¥ì´ ì œê±°ë©ë‹ˆë‹¤. + + + + Database structure font size + ë°ì´í„°ë² ì´ìФ 구조 글꼴 í¬ê¸° + + + + Font si&ze + 글꼴 í¬ê¸°(&Z) + + + + This is the maximum number of items allowed for some computationally expensive functionalities to be enabled: +Maximum number of rows in a table for enabling the value completion based on current values in the column. +Maximum number of indexes in a selection for calculating sum and average. +Can be set to 0 for disabling the functionalities. + ì—°ì‚°ì´ ë§Žì´ ê±¸ë¦¬ëŠ” ì¼ë¶€ ê¸°ëŠ¥ì„ í™œì„±í™”í•˜ëŠ”ë° í—ˆìš©ë˜ëŠ” 최대 항목 수입니다. +ì—´ì˜ í˜„ìž¬ ê°’ì„ ê¸°ë°˜ìœ¼ë¡œ ê°’ ì™„ì„±ì„ í™œì„±í™”í•˜ê¸° 위한 í…Œì´ë¸”ì˜ ìµœëŒ€ í–‰ì˜ ê°¯ìˆ˜ìž…ë‹ˆë‹¤. +합계 ë° í‰ê· ì„ 계산하려는 ì„ íƒ í•­ëª©ì˜ ìµœëŒ€ ì¸ë±ìФ 수입니다. +기능 비활성화하려면 0으로 설정하세요. + + + + This is the maximum number of rows in a table for enabling the value completion based on current values in the column. +Can be set to 0 for disabling completion. + ì—´ì˜ í˜„ìž¬ ê°’ì„ ê¸°ë°˜ìœ¼ë¡œ ê°’ ì™„ì„±ì„ í™œì„±í™”í•˜ê¸° 위한 í…Œì´ë¸”ì˜ ìµœëŒ€ í–‰ 수입니다. +비활성화하려면 0으로 설정하세요. + + + + Close button on tabs + íƒ­ì— ë‹«ê¸° 버튼 + + + + If enabled, SQL editor tabs will have a close button. In any case, you can use the contextual menu or the keyboard shortcut to close them. + 활성화ë˜ë©´ SQL 편집기 íƒ­ì— ë‹«ê¸° ë²„íŠ¼ì´ ìƒê¹ë‹ˆë‹¤. ì–´ë–¤ 경우든 컨í…스트 메뉴나 키보드 단축기를 사용하여 ë‹«ì„ ìˆ˜ 있습니다. + + + + Proxy + 프ë¡ì‹œ + + + + Configure + 설정 + + + + Field display + 필드 출력 + + + + Displayed &text + 출력 í…스트(&T) + + + + + + + + + Click to set this color + ì„ íƒí•˜ì—¬ ì´ ìƒ‰ìƒì„ ì„ íƒí•˜ì„¸ìš” + + + + Text color + 글ìžìƒ‰ + + + + Background color + 배경색 + + + + Preview only (N/A) + 미리보기만 출력 (N/A) + + + + Escape character + ì´ìŠ¤ì¼€ì´í”„ ë¬¸ìž + + + + Delay time (&ms) + 대기 시간 (&ms) + + + + Set the waiting time before a new filter value is applied. Can be set to 0 for disabling waiting. + 새로운 í•„í„° ê°’ì„ ì ìš©í•˜ê¸° ì „ì— ëŒ€ê¸°í•  ì‹œê°„ì„ ì„¤ì •í•˜ì„¸ìš”. 대기 ì‹œê°„ì„ 0으로 하면 대기하지 않습니다. + + + + &SQL + SQL(&S) + + + + Settings name + 설정 ì´ë¦„ + + + + Context + ë‚´ìš© + + + + Colour + 색깔 + + + + Bold + 진하게 + + + + Italic + 기울게 + + + + Underline + 밑줄 + + + + Keyword + 키워드 + + + + Function + 함수 + + + + Table + í…Œì´ë¸” + + + + Comment + ì£¼ì„ + + + + Identifier + ì‹ë³„ìž + + + + String + 문ìžì—´ + + + + Current line + 현재 í–‰ + + + + SQL &editor font size + SQL ì—디터 글꼴 í¬ê¸°(&E) + + + + Tab size + 탭 í¬ê¸° + + + + &Wrap lines + 줄 바꿈(&W) + + + + Never + 사용 안 함 + + + + At word boundaries + 단어 경계ì—서 + + + + At character boundaries + ë¬¸ìž ê²½ê³„ì—서 + + + + At whitespace boundaries + 공백ì—서 + + + + &Quotes for identifiers + ì‹ë³„ìž êµ¬ë¶„ 기호(&Q) + + + + Choose the quoting mechanism used by the application for identifiers in SQL code. + SQL ì½”ë“œì˜ ì‹ë³„ìžì— 대해 ì‘ìš© 프로그램ì—서 사용하는 기호를 ì„ íƒí•©ë‹ˆë‹¤. + + + + "Double quotes" - Standard SQL (recommended) + "í° ë”°ì˜´í‘œ" - SQL 표준 (권장ë¨) + + + + `Grave accents` - Traditional MySQL quotes + 'ìž‘ì€ ë”°ì˜´í‘œ' - MySQL 전통 ì¸ìš© 부호 + + + + [Square brackets] - Traditional MS SQL Server quotes + [대괄호] - MS SQL 전통 ì¸ìš© 부호 + + + + Keywords in &UPPER CASE + í‚¤ì›Œë“œì— ëŒ€í•´ 대문ìž(&U) + + + + When set, the SQL keywords are completed in UPPER CASE letters. + 활성화ë˜ë©´ SQL 키워드가 대문ìžë¡œ 완성ë©ë‹ˆë‹¤. + + + + When set, the SQL code lines that caused errors during the last execution are highlighted and the results frame indicates the error in the background + 활성화ë˜ë©´ 마지막 실행 ì¤‘ì— ì˜¤ë¥˜ë¥¼ ì¼ìœ¼í‚¨ SQL 코드 ì¤„ì´ ê°•ì¡° 표시ë˜ê³  ê²°ê³¼ í”„ë ˆìž„ì€ ë°±ê·¸ë¼ìš´ë“œì— 오류를 나타냅니다 + + + + <html><head/><body><p>SQLite provides an SQL function for loading extensions from a shared library file. Activate this if you want to use the <span style=" font-style:italic;">load_extension()</span> function from SQL code.</p><p>For security reasons, extension loading is turned off by default and must be enabled through this setting. You can always load extensions through the GUI, even though this option is disabled.</p></body></html> + <html><head/><body><p>SQLite는 공유 ë¼ì´ë¸ŒëŸ¬ë¦¬ 파ì¼ì—서 í™•ìž¥ì„ ë¡œë“œí•˜ê¸° 위한 SQL 함수를 제공합니다. SQL 코드ì—서 <span style=" font-style:italic;">load_extension()</span> 함수를 사용하려면 ì´ ê¸°ëŠ¥ì„ í™œì„±í™”í•˜ì‹­ì‹œì˜¤.</p><p>보안 ìƒì˜ ì´ìœ ë¡œ 확장 로드는 기본ì ìœ¼ë¡œ 비활성화ë˜ì–´ 있으며 ì„¤ì •ì„ í†µí•´ 활성화해야 합니다. ì´ ì˜µì…˜ì´ ë¹„í™œì„±í™”ë˜ì–´ 있ë”ë¼ë„ í•­ìƒ GUI를 통해 í™•ìž¥ì„ ë¡œë“œí•  수 있습니다.</p></body></html> + + + + Allow loading extensions from SQL code + SQL 코드ì—서 í™•ìž¥ê¸°ëŠ¥ì„ ë¶ˆëŸ¬ì˜¤ëŠ” ê²ƒì„ í—ˆìš© + + + + Remote + ì›ê²© + + + + CA certificates + CA ì¸ì¦ì„œ + + + + + Subject CN + 제목 CN + + + + Common Name + ì¼ë°˜ ì´ë¦„ + + + + Subject O + 제목 O + + + + Organization + 기관 + + + + + Valid from + 유효날짜(시작) + + + + + Valid to + 유효날짜(ë) + + + + + Serial number + 시리얼 넘버 + + + + Your certificates + ë‹¹ì‹ ì˜ ì¸ì¦ì„œ + + + + File + íŒŒì¼ + + + + Subject Common Name + 주제 ì¼ë°˜ ì´ë¦„ + + + + Issuer CN + ì´ìŠˆ 등ë¡ìž CN + + + + Issuer Common Name + ì´ìŠˆ 등ë¡ìž ì¼ë°˜ ì´ë¦„ + + + + Clone databases into + ë°ì´í„°ë² ì´ìФ 복제하기 + + + + SQL editor &font + SQL 편집기 글꼴(&F) + + + + Error indicators + ì—러 표시 + + + + Hori&zontal tiling + 화면 ìˆ˜í‰ ë‚˜ëˆ„ê¸°(&Z) + + + + If enabled the SQL code editor and the result table view are shown side by side instead of one over the other. + 활성화ë˜ë©´ SQL 코드 편집기와 ê²°ê³¼ í…Œì´ë¸” ë·°ê°€ 나란히 표시ë©ë‹ˆë‹¤. + + + + Code co&mpletion + 코드 완성(&M) + + + + Threshold for completion and calculation on selection + ì„ íƒì— 대한 완료 ë° ì—°ì‚° 임계 ê°’ + + + + Show images in cell + ì…€ì— ì´ë¯¸ì§€ 표시 + + + + Enable this option to show a preview of BLOBs containing image data in the cells. This can affect the performance of the data browser, however. + ì…€ì— ì´ë¯¸ì§€ ë°ì´í„°ê°€ í¬í•¨ëœ BLOBì˜ ë¯¸ë¦¬ë³´ê¸°ë¥¼ 표시하려면 ì´ ì˜µì…˜ì„ í™œì„±í™”í•©ë‹ˆë‹¤. 그러나 ì´ëŠ” ë°ì´í„° 브ë¼ìš°ì €ì˜ ì„±ëŠ¥ì— ì˜í–¥ì„ ë¼ì¹  수 있습니다. + + + + Foreground + 전경색 + + + + SQL &results font size + SQL ê²°ê³¼ 글꼴 í¬ê¸°(&R) + + + + &Extensions + 확장기능(&E) + + + + Select extensions to load for every database: + 불러올 í™•ìž¥ê¸°ëŠ¥ì„ ì„ íƒí•˜ì„¸ìš”(í™•ìž¥ê¸°ëŠ¥ì€ ëª¨ë“  ë°ì´í„°ë² ì´ìŠ¤ì— ë°˜ì˜ë©ë‹ˆë‹¤): + + + + Add extension + 확장기능 추가 + + + + Remove extension + 확장기능 제거 + + + + <html><head/><body><p>While supporting the REGEXP operator SQLite doesn't implement any regular expression<br/>algorithm but calls back the running application. DB Browser for SQLite implements this<br/>algorithm for you to let you use REGEXP out of the box. However, as there are multiple possible<br/>implementations of this and you might want to use another one, you're free to disable the<br/>application's implementation and load your own by using an extension. Requires restart of the application.</p></body></html> + <html><head/><body><p>SQLiteì—서는 기본ì ìœ¼ë¡œ ì •ê·œ í‘œí˜„ì‹ ê¸°ëŠ¥ì„ ì œê³µí•˜ì§€ 않습니다만 애플리케ì´ì…˜ì„ 실행하여 호출하는 ê²ƒì€ ê°€ëŠ¥í•©ë‹ˆë‹¤. DB Browser for SQLiteì—서는 ì´ ì•Œê³ ë¦¬ì¦˜ì„ ë°•ìŠ¤ ë°–ì—ì„œë„ ì •ê·œ 표현ì‹ì„ 사용할 수 있ë„ë¡ ì´ ì•Œê³ ë¦¬ì¦˜ì„ êµ¬í˜„í•´ì¤ë‹ˆë‹¤. 하지만 í™•ìž¥ê¸°ëŠ¥ì„ ì‚¬ìš©í•˜ì—¬ 외부ì—서 만든 알고리즘 êµ¬í˜„ì„ ì‚¬ìš©í•˜ê³ ìž í•œë‹¤ë©´ DB Browser for SQLiteì—서 제공하는 구현 ì‚¬ìš©ì„ ìžìœ ë¡­ê²Œ ëŒ ìˆ˜ 있습니다. ì´ ê¸°ëŠ¥ì€ ì• í”Œë¦¬ì¼€ì´ì…˜ì„ 재시작해야 합니다.</p></body></html> + + + + Disable Regular Expression extension + ì •ê·œ í‘œí˜„ì‹ í™•ìž¥ê¸°ëŠ¥ 비활성화 + + + + + Choose a directory + 디렉터리를 ì„ íƒí•˜ì„¸ìš” + + + + The language will change after you restart the application. + 언어 ë³€ê²½ì€ ì• í”Œë¦¬ì¼€ì´ì…˜ì„ 재시작해야 ë°˜ì˜ë©ë‹ˆë‹¤. + + + + Select extension file + 확장기능 파ì¼ì„ ì„ íƒí•˜ì„¸ìš” + + + + Extensions(*.so *.dylib *.dll);;All files(*) + 확장기능(*.so *.dylib *dll);;모든 파ì¼(*) + + + + Import certificate file + ì¸ì¦ì„œ íŒŒì¼ ê°€ì ¸ì˜¤ê¸° + + + + No certificates found in this file. + ì´ íŒŒì¼ì—는 ì¸ì¦ì„œê°€ 없습니다. + + + + Are you sure you want do remove this certificate? All certificate data will be deleted from the application settings! + ì •ë§ë¡œ ì´ ì¸ì¦ì„œë¥¼ 삭제하겠습니까? 애플리케ì´ì…˜ 설정ì—서 모든 ì¦ëª… ë°ì´í„°ê°€ ì‚­ì œë  ê²ƒìž…ë‹ˆë‹¤! + + + + Are you sure you want to clear all the saved settings? +All your preferences will be lost and default values will be used. + ì €ìž¥ëœ ëª¨ë“  ì„¤ì •ì„ ì •ë§ë¡œ 초기화하시겠습니까? +모든 ì„¤ì •ì´ ì´ˆê¸°í™”ë˜ê³  기본값으로 대체ë©ë‹ˆë‹¤. + + + + ProxyDialog + + + Proxy Configuration + 프ë¡ì‹œ 설정 + + + + Pro&xy Type + 프ë¡ì‹œ 종류(&X) + + + + Host Na&me + 서버 주소(&M) + + + + Port + í¬íЏ + + + + Authentication Re&quired + ì¸ì¦ ì •ë³´ í•„ìš”(&Q) + + + + &User Name + 사용ìžëª…(&U) + + + + Password + 암호 + + + + None + 사용하지 ì•ŠìŒ + + + + System settings + 시스템 설정 + + + + HTTP + HTTP + + + + Socks v5 + Socks v5 + + + + QObject + + + Error importing data + ë°ì´í„° 가져오기 ì—러 + + + + from record number %1 + 레코드 넘버: %1 + + + + . +%1 + . +%1 + + + + Importing CSV file... + CSV íŒŒì¼ ê°€ì ¸ì˜¤ê¸°... + + + + Cancel + 취소 + + + + All files (*) + 모든 파ì¼(*) + + + + SQLite database files (*.db *.sqlite *.sqlite3 *.db3) + SQLite ë°ì´í„°ë² ì´ìФ 파ì¼(*.db *.sqlite *.sqlite3 *.db3) + + + + Left + 왼쪽 + + + + Right + 오른쪽 + + + + Center + 중앙 + + + + Justify + ì •ë ¬ + + + + SQLite Database Files (*.db *.sqlite *.sqlite3 *.db3) + SQLite ë°ì´í„°ë² ì´ìФ íŒŒì¼ (*.db *.sqlite *.sqlite3 *.db3) + + + + DB Browser for SQLite Project Files (*.sqbpro) + DB Browser for SQLite 프로ì íЏ íŒŒì¼ (*.sqbpro) + + + + SQL Files (*.sql) + SQL íŒŒì¼ (*.sql) + + + + All Files (*) + 모든 íŒŒì¼ (*) + + + + Text Files (*.txt) + í…스트 íŒŒì¼ (*.txt) + + + + Comma-Separated Values Files (*.csv) + 쉼표로 êµ¬ë¶„ëœ íŒŒì¼ (*.csv) + + + + Tab-Separated Values Files (*.tsv) + 탭으로 ë¶„ë¦¬ëœ íŒŒì¼ (*.tsv) + + + + Delimiter-Separated Values Files (*.dsv) + 구분ìžë¡œ êµ¬ë¶„ëœ íŒŒì¼ (*.dsv) + + + + Concordance DAT files (*.dat) + Concordance DAT íŒŒì¼ (*.dat) + + + + JSON Files (*.json *.js) + JSON íŒŒì¼ (*.json *.js) + + + + XML Files (*.xml) + XML íŒŒì¼ (*.xml) + + + + Binary Files (*.bin *.dat) + ë°”ì´ë„ˆë¦¬ íŒŒì¼ (*bin *.dat) + + + + SVG Files (*.svg) + SVG íŒŒì¼ (*.svg) + + + + Hex Dump Files (*.dat *.bin) + Hex ë¤í”„ íŒŒì¼ (*.dat *bin) + + + + Extensions (*.so *.dylib *.dll) + 확장기능 (*.so *.dylib *.dll) + + + + RemoteCommitsModel + + + Commit ID + 커밋 ID + + + + Message + 메시지 + + + + Date + ë‚ ì§œ + + + + Author + ì €ìž + + + + Size + í¬ê¸° + + + + Authored and committed by %1 + %1ì— ì˜í•´ 작성ë˜ê³  ì»¤ë°‹ë¨ + + + + Authored by %1, committed by %2 + %1ì— ì˜í•´ 작성ë˜ê³ , %2ì— ì˜í•´ ì»¤ë°‹ë¨ + + + + RemoteDatabase + + + Error opening local databases list. +%1 + 로컬 ë°ì´í„°ë² ì´ìФ 목ë¡ì„ ì—´ë˜ ì¤‘ ì—러가 ë°œìƒí–ˆìŠµë‹ˆë‹¤. %1 + + + + Error creating local databases list. +%1 + 로컬 ë°ì´í„°ë² ì´ìФ 목ë¡ì„ ìƒì„±í•˜ë˜ 중 ì—러가 ë°œìƒí–ˆìŠµë‹ˆë‹¤. %1 + + + + RemoteDock + + + Remote + ì›ê²© + + + + Local + 로컬 + + + + Identity + ì‹ ì› + + + + Push currently opened database to server + 현재 열린 ë°ì´ë² ì´ìŠ¤ë¥¼ 서버로 ë°˜ì˜í•©ë‹ˆë‹¤ + + + + DBHub.io + DBHub.io + + + + <html><head/><body><p>In this pane, remote databases from dbhub.io website can be added to DB Browser for SQLite. First you need an identity:</p><ol style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Login to the dbhub.io website (use your GitHub credentials or whatever you want)</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Click the button to &quot;Generate client certificate&quot; (that's your identity). That'll give you a certificate file (save it to your local disk).</li><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Go to the Remote tab in DB Browser for SQLite Preferences. Click the button to add a new certificate to DB Browser for SQLite and choose the just downloaded certificate file.</li></ol><p>Now the Remote panel shows your identity and you can add remote databases.</p></body></html> + <html><head/><body><p>ì´ ì°½ì—서는 DBHub.io 웹 사ì´íŠ¸ì˜ ì›ê²© ë°ì´í„°ë² ì´ìŠ¤ë¥¼ DB Browser for SQLiteì— ì¶”ê°€í•  수 있습니다.</p><ol style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">DBHub.io 웹 사ì´íŠ¸ì— ë¡œê·¸ì¸(ì›í•˜ì‹œë©´ GitHub ìžê²© ì¦ëª…ì„ ì‚¬ìš©í•  수 있습니다)</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">ë²„íŠ¼ì„ í´ë¦­í•˜ì—¬ &quot;í´ë¼ì´ì–¸íЏ ì¸ì¦ì„œ ìƒì„±&quot; (ë‹¹ì‹ ì˜ ì‹ ì› ì •ë³´). 그러면 ì¸ì¦ì„œ 파ì¼ì´ 제공ë©ë‹ˆë‹¤(로컬 디스í¬ì— 저장)</li><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">DB Browser for SQLite ì„¤ì •ì˜ ì›ê²© 탭으로 ì´ë™í•©ë‹ˆë‹¤. ë²„íŠ¼ì„ í´ë¦­í•˜ì—¬ DB Browser for SQLiteì— ìƒˆ ì¸ì¦ì„œë¥¼ 추가하고 방금 다운로드한 ì¸ì¦ì„œ 파ì¼ì„ ì„ íƒí•©ë‹ˆë‹¤.</li></ol><p>ì´ì œ ì›ê²© 패ë„ì— IDê°€ 표시ë˜ê³  ì›ê²© ë°ì´í„°ë² ì´ìŠ¤ë¥¼ 추가할 수 있습니다.</p></body></html> + + + + Current Database + 현재 ë°ì´í„°ë² ì´ìФ + + + + Clone + 복제 + + + + User + ì‚¬ìš©ìž + + + + Database + ë°ì´í„°ë² ì´ìФ + + + + Branch + 브랜치 + + + + Commits + 커밋 + + + + Commits for + 커밋 조회할 브랜치 + + + + Delete Database + ë°ì´í„°ë² ì´ìФ ì‚­ì œ + + + + Delete the local clone of this database + ì´ ë°ì´í„°ë² ì´ìŠ¤ì˜ ë¡œì»¬ 복제본 ì‚­ì œ + + + + Open in Web Browser + 웹 브ë¼ìš°ì €ì—서 열기 + + + + Open the web page for the current database in your browser + 브ë¼ìš°ì €ì—서 현재 ë°ì´í„°ë² ì´ìŠ¤ì˜ ì›¹ 페ì´ì§€ë¥¼ 엽니다 + + + + Clone from Link + 주소로부터 복제 + + + + Use this to download a remote database for local editing using a URL as provided on the web page of the database. + ì´ë¥¼ 사용하여 로컬 íŽ¸ì§‘ì„ ìœ„í•´ ë°ì´í„°ë² ì´ìŠ¤ì˜ ì›¹ 페ì´ì§€ì—서 ì œê³µëœ URLì„ ì‚¬ìš©í•˜ì—¬ ì›ê²© ë°ì´í„°ë² ì´ìŠ¤ë¥¼ 다운로드 합니다. + + + + Refresh + 새로고침 + + + + Reload all data and update the views + 모든 ë°ì´í„°ë¥¼ 다시 로드하고 뷰를 ì—…ë°ì´íŠ¸í•©ë‹ˆë‹¤ + + + + F5 + + + + + Clone Database + ë°ì´í„°ë² ì´ìФ 복제 + + + + Open Database + ë°ì´í„°ë² ì´ìФ 열기 + + + + Open the local copy of this database + ì´ ë°ì´í„°ë² ì´ìŠ¤ì˜ ë¡œì»¬ ë³µì œë³¸ì„ ì—½ë‹ˆë‹¤ + + + + Check out Commit + 커밋 ì²´í¬ì•„웃 + + + + Download and open this specific commit + ì´ íŠ¹ì • ì»¤ë°‹ì„ ë‹¤ìš´ë¡œë“œí•˜ì—¬ 엽니다 + + + + Check out Latest Commit + 최신 커밋 í™•ì¸ + + + + Check out the latest commit of the current branch + ì´ ë¸Œëžœì¹˜ì˜ ìµœì‹  커밋 í™•ì¸ + + + + Save Revision to File + ë¦¬ë¹„ì „ì„ íŒŒì¼ì— 저장 + + + + Saves the selected revision of the database to another file + ë°ì´í„°ë² ì´ìŠ¤ì˜ ì„ íƒí•œ ë¦¬ë¹„ì „ì„ ë‹¤ë¥¸ 파ì¼ì— 저장합니다 + + + + Upload Database + ë°ì´í„°ë² ì´ìФ 업로드 + + + + Upload this database as a new commit + ì´ ë°ì´í„°ë² ì´ìŠ¤ë¥¼ 새 커밋으로 업로드 + + + + <html><head/><body><p>You are currently using a built-in, read-only identity. For uploading your database, you need to configure and use your DBHub.io account.</p><p>No DBHub.io account yet? <a href="https://dbhub.io/"><span style=" text-decoration: underline; color:#007af4;">Create one now</span></a> and import your certificate <a href="#preferences"><span style=" text-decoration: underline; color:#007af4;">here</span></a> to share your databases.</p><p>For online help visit <a href="https://dbhub.io/about"><span style=" text-decoration: underline; color:#007af4;">here</span></a>.</p></body></html> + <html><head/><body><p>현재 기본으로 제공ë˜ëŠ” ì½ê¸° ì „ìš© ID를 사용하고 있습니다. ë°ì´í„°ë² ì´ìŠ¤ë¥¼ 업로드하려면 DBHub.io ê³„ì •ì„ êµ¬ì„±í•˜ê³  사용해야 합니다.</p><p>ì•„ì§ DBHub.io ê³„ì •ì´ ì—†ìœ¼ì‹­ë‹ˆê¹Œ? <a href="https://dbhub.io/"><span style=" text-decoration: underline; color:#007af4;">지금 만들어</span></a> ì¸ì¦ì„œë¥¼ 가져옵니다. <a href="#preferences"><span style=" text-decoration: underline; color:#007af4;">여기</span></a>ì—서 ë°ì´í„°ë² ì´ìŠ¤ë¥¼ 공유하세요.</p><p>온ë¼ì¸ ë„움ë§ì„ 보려면 <a href="https://dbhub.io/about"><span style=" text-decoration: underline; color:#007af4;">여기</span></a>를 방문하세요.</p></body></html> + + + + Back + 뒤로가기 + + + + Select an identity to connect + ì—°ê²°í•  ID를 ì„ íƒí•˜ì„¸ìš” + + + + Public + 공개 + + + + This downloads a database from a remote server for local editing. +Please enter the URL to clone from. You can generate this URL by +clicking the 'Clone Database in DB4S' button on the web page +of the database. + 로컬 íŽ¸ì§‘ì„ ìœ„í•´ ì›ê²© 서버ì—서 ë°ì´í„°ë² ì´ìŠ¤ë¥¼ 다운로드합니다. +복제하려는 URLì„ ìž…ë ¥í•˜ì„¸ìš”. ë°ì´í„°ë² ì´ìŠ¤ì˜ ì›¹ 페ì´ì§€ì—서 +'DB4Sì—서 ë°ì´í„°ë² ì´ìФ 복제' ë²„íŠ¼ì„ í´ë¦­í•˜ì—¬ +ì´ëŸ¬í•œ URLì„ ìƒì„±í•  수 있습니다. + + + + Invalid URL: The host name does not match the host name of the current identity. + ìž˜ëª»ëœ URL: 호스트 ì´ë¦„ì´ í˜„ìž¬ IDì˜ í˜¸ìŠ¤íŠ¸ ì´ë¦„ê³¼ ì¼ì¹˜í•˜ì§€ 않습니다. + + + + Invalid URL: No branch name specified. + ìž˜ëª»ëœ URL: ì§€ì •ëœ ë¸Œëžœì¹˜ ì´ë¦„ì´ ì—†ìŠµë‹ˆë‹¤. + + + + Invalid URL: No commit ID specified. + ìž˜ëª»ëœ URL: 커밋 IDê°€ 지정ë˜ì§€ 않았습니다. + + + + You have modified the local clone of the database. Fetching this commit overrides these local changes. +Are you sure you want to proceed? + ë°ì´í„°ë² ì´ìŠ¤ì˜ ë¡œì»¬ ë³µì œë³¸ì„ ìˆ˜ì •í–ˆìŠµë‹ˆë‹¤. ì´ ì»¤ë°‹ì„ ê°€ì ¸ì˜¤ë©´ ì´ëŸ¬í•œ 로컬 변경 ì‚¬í•­ì´ ë¬´ì‹œë©ë‹ˆë‹¤. +계ì†í•˜ì‹œê² ìŠµë‹ˆê¹Œ? + + + + The database has unsaved changes. Are you sure you want to push it before saving? + ë°ì´í„°ë² ì´ìŠ¤ì— ì €ìž¥ë˜ì§€ ì•Šì€ ë³€ê²½ ì‚¬í•­ì´ ìžˆìŠµë‹ˆë‹¤. 저장하기 ì „ì— í‘¸ì‹œí•˜ì‹œê² ìŠµë‹ˆê¹Œ? + + + + The database you are trying to delete is currently opened. Please close it before deleting. + 삭제하려는 ë°ì´í„°ë² ì´ìŠ¤ê°€ 현재 열려있습니다. 삭제하기 ì „ì— ë‹«ìœ¼ì‹­ì‹œì˜¤. + + + + This deletes the local version of this database with all the changes you have not committed yet. Are you sure you want to delete this database? + ì´ë ‡ê²Œí•˜ë©´ ì•„ì§ ì»¤ë°‹í•˜ì§€ ì•Šì€ ëª¨ë“  변경 사항과 함께 ì´ ë°ì´í„°ë² ì´ìŠ¤ì˜ ë¡œì»¬ ë²„ì „ì´ ì‚­ì œë©ë‹ˆë‹¤. ì •ë§ë¡œ ë°ì´í„°ë² ì´ìŠ¤ë¥¼ 삭제하시겠습니까? + + + + RemoteLocalFilesModel + + + Name + ì´ë¦„ + + + + Branch + 브랜치 + + + + Last modified + 마지막 ìˆ˜ì •ì¼ + + + + Size + í¬ê¸° + + + + Commit + 커밋 + + + + File + íŒŒì¼ + + + + RemoteModel + + + Name + ì´ë¦„ + + + + Last modified + 마지막 수정 + + + + Size + í¬ê¸° + + + + Commit + 커밋 + + + + Size: + í¬ê¸°: + + + + Last Modified: + 마지막 수정: + + + + Licence: + ë¼ì´ì„¼ìФ: + + + + Default Branch: + 기본 브랜치: + + + + RemoteNetwork + + + Choose a location to save the file + 파ì¼ì„ 저장할 위치를 ì„ íƒí•˜ì„¸ìš” + + + + Error opening remote file at %1. +%2 + %1 ì— ìžˆëŠ” ì›ê²© 파ì¼ì„ ì—´ë˜ ì¤‘ ì—러가 ë°œìƒí–ˆìŠµë‹ˆë‹¤. +%2 + + + + Error: Invalid client certificate specified. + ì—러: 올바르지 ì•Šì€ í´ë¼ì´ì–¸íЏ ì¸ì¦ì„œìž…니다. + + + + Please enter the passphrase for this client certificate in order to authenticate. + ì¸ì¦ì„ 위한 í´ë¼ì´ì–¸íЏ ì¸ì¦ì„œ 암호를 입력해주세요. + + + + Cancel + 취소 + + + + Uploading remote database to +%1 + %1로 +ì›ê²© ë°ì´í„°ë² ì´ìŠ¤ë¥¼ 업로드 중입니다 + + + + Downloading remote database from +%1 + %1 ì—서 ì›ê²© ë°ì´í„°ë² ì´ìŠ¤ë¥¼ 다운로드 중입니다. {1?} + + + + + Error: The network is not accessible. + ì—러: 네트워í¬ì— 접근할 수 없습니다. + + + + Error: Cannot open the file for sending. + ì—러: 보내려는 파ì¼ì„ ì—´ 수 없습니다. + + + + RemotePushDialog + + + Push database + ë°ì´í„°ë² ì´ìФ 푸시(Push) + + + + Database na&me to push to + 푸시할 ë°ì´í„°ë² ì´ìФ ì´ë¦„(&M) + + + + Commit message + 커밋 메시지 + + + + Database licence + ë°ì´í„°ë² ì´ìФ ë¼ì´ì„¼ìФ + + + + Public + 공개 + + + + Branch + 브랜치 + + + + Force push + ê°•ì œ 푸시 + + + + Username + 사용ìžëª… + + + + Database will be public. Everyone has read access to it. + 공개 ë°ì´í„°ë² ì´ìŠ¤ë¡œ 지정합니다. 누구나 ì½ê¸° ì ‘ê·¼ì´ ê°€ëŠ¥í•©ë‹ˆë‹¤. + + + + Database will be private. Only you have access to it. + 비공개 ë°ì´í„°ë² ì´ìŠ¤ë¡œ 지정합니다. 당신만 접근할 수 있습니다. + + + + Use with care. This can cause remote commits to be deleted. + 주ì˜í•´ì„œ 사용하세요. ì›ê²© ì»¤ë°‹ì„ ì‚­ì œí•˜ëŠ” 결과를 초래할 수 있습니다. + + + + RunSql + + + Execution aborted by user + 사용ìžì— ì˜í•´ì„œ ì‹¤í–‰ì´ ì·¨ì†Œë˜ì—ˆìŠµë‹ˆë‹¤ + + + + , %1 rows affected + , %1 í–‰ì´ ì˜í–¥ 받았습니다 + + + + query executed successfully. Took %1ms%2 + %2 ë°ì´í„°ë² ì´ìŠ¤ì— ì¿¼ë¦¬ê°€ 성공ì ìœ¼ë¡œ 실행ë˜ì—ˆìŠµë‹ˆë‹¤. %1ms 걸렸습니다 + + + + executing query + 쿼리 실행 중 + + + + SelectItemsPopup + + + A&vailable + 사용 가능한(&V) + + + + Sele&cted + ì„ íƒë¨(&C) + + + + SqlExecutionArea + + + Form + í¼ + + + + Find previous match [Shift+F3] + ì´ì „ 찾기 [Shift+F3] + + + + Find previous match with wrapping + 랩핑(Wrapping)ëœ ì´ì „ ì¼ì¹˜ë‚´ì—­ 검색하기 + + + + Shift+F3 + + + + + The found pattern must be a whole word + 온전한 ë‚±ë§ ì¼ì¹˜ 검색패턴 + + + + Whole Words + 온전한 ë‚±ë§ ì¼ì¹˜ + + + + Text pattern to find considering the checks in this frame + ì´ í”„ë ˆìž„ 안ì—서 확ì¸í•˜ê¸° 위해 ê²€ìƒ‰í•˜ê³ ìž í•˜ëŠ” 문ìžì—´ 패턴 + + + + Find in editor + 편집기 ë‚´ì—서 찾기 + + + + The found pattern must match in letter case + ëŒ€ì†Œë¬¸ìž ì¼ì¹˜ 검색패턴 + + + + Case Sensitive + ëŒ€ì†Œë¬¸ìž ì¼ì¹˜ + + + + Find next match [Enter, F3] + ë‹¤ìŒ ì°¾ê¸° [Enter,F3] + + + + Find next match with wrapping + 랩핑(Wrapping)으로 ë‹¤ìŒ ì°¾ê¸° + + + + F3 + + + + + Interpret search pattern as a regular expression + 검색 패턴 ì •ê·œ í‘œí˜„ì‹ ì‚¬ìš© + + + + <html><head/><body><p>When checked, the pattern to find is interpreted as a UNIX regular expression. See <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>.</p></body></html> + <html><head/><body><p>ì„ íƒí•˜ë©´ ì°¾ì„ íŒ¨í„´ì´ UNIX ì •ê·œ 표현ì‹ìœ¼ë¡œ í•´ì„ë©ë‹ˆë‹¤. <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>를 참고하십시오.</p></body></html> + + + + Regular Expression + ì •ê·œ í‘œí˜„ì‹ + + + + + Close Find Bar + 검색바 닫기 + + + + <html><head/><body><p>Results of the last executed statements.</p><p>You may want to collapse this panel and use the <span style=" font-style:italic;">SQL Log</span> dock with <span style=" font-style:italic;">User</span> selection instead.</p></body></html> + <html><head/><body><p>마지막으로 ì‹¤í–‰ëœ ëª…ë ¹ë¬¸ì˜ ê²°ê³¼ìž…ë‹ˆë‹¤.</p><p>ì´ íŒ¨ë„ì„ ì¶•ì†Œí•˜ê³  대신 <span style=" font-style:italic;">사용ìž</span> ì„ íƒê³¼ 함께 <span style=" font-style:italic;">SQL 로그</span> ë…ì„ ì‚¬ìš©í•  수 있습니다.</p></body></html> + + + + Results of the last executed statements + 가장 최근 실행 구문 ê²°ê³¼ + + + + This field shows the results and status codes of the last executed statements. + ì´ í•„ë“œëŠ” 가장 ìµœê·¼ì— ì‹¤í–‰ëœ êµ¬ë¬¸ì˜ ê²°ê³¼ì™€ ìƒíƒœ 코드를 ë³´ì—¬ì¤ë‹ˆë‹¤. + + + + Couldn't read file: %1. + 파ì¼ì„ ì½ì„ 수 없습니다: %1. + + + + + Couldn't save file: %1. + 파ì¼ì„ 저장할 수 없습니다: %1. + + + + Your changes will be lost when reloading it! + 다시 불러오면 변경 ì‚¬í•­ì„ ìžƒìŠµë‹ˆë‹¤! + + + + The file "%1" was modified by another program. Do you want to reload it?%2 + "%1" 파ì¼ì´ 다른 í”„ë¡œê·¸ëž¨ì— ì˜í•´ 수정ë˜ì—ˆìŠµë‹ˆë‹¤. 다시 불러오겠습니까?%2 + + + + SqlTextEdit + + + Ctrl+/ + + + + + SqlUiLexer + + + (X) The abs(X) function returns the absolute value of the numeric argument X. + (X) abs(X) 함수는 ìˆ«ìž ë§¤ê°œë³€ìˆ˜ Xì˜ ì ˆëŒ€ê°’ì„ ë°˜í™˜í•©ë‹ˆë‹¤. + + + + () The changes() function returns the number of database rows that were changed or inserted or deleted by the most recently completed INSERT, DELETE, or UPDATE statement. + () changes() 함수는 가장 ìµœê·¼ì— ì‹¤í–‰ëœ INSERT, DELETE, UPDATE 구문ì—서 ë°ì´í„°ë² ì´ìФì—서 변경ë˜ê±°ë‚˜ 추가ë˜ê±°ë‚˜ ì‚­ì œëœ í–‰ 수를 반환합니다. + + + + (X1,X2,...) The char(X1,X2,...,XN) function returns a string composed of characters having the unicode code point values of integers X1 through XN, respectively. + (X1,X2,...) char(X1,X2,...,XN) 함수는 ê°ê°ì˜ X1ì—서 XN ìˆ«ìž ê°’ì˜ ìœ ë‹ˆì½”ë“œ í¬ì¸íЏ ê°’ì„ ê°€ì§„ 문ìžë“¤ë¡œ êµ¬ì„±ëœ ë¬¸ìžì—´ì„ 반환합니다. + + + + (X,Y,...) The coalesce() function returns a copy of its first non-NULL argument, or NULL if all arguments are NULL + (X,Y,...) coalesce() 함수는 첫번째 NULLì´ ì•„ë‹Œ ì¸ìž ê°’ì˜ ì‚¬ë³¸ì„ ë°˜í™˜í•©ë‹ˆë‹¤. 만약 ì¸ìž ê°’ì´ ëª¨ë‘ NULLì´ë¼ë©´ NULLì„ ë°˜í™˜í•©ë‹ˆë‹¤ + + + + (X,Y) The glob(X,Y) function is equivalent to the expression "Y GLOB X". + (X,Y) glob(X,Y) 함수는 "Y GLOB X" 표현ì‹ê³¼ 같습니다. + + + + (X,Y) The ifnull() function returns a copy of its first non-NULL argument, or NULL if both arguments are NULL. + (X,Y) ifnull() 함수는 첫번째 NULLì´ ì•„ë‹Œ ì¸ìž ê°’ì˜ ì‚¬ë³¸ì„ ë°˜í™˜í•©ë‹ˆë‹¤. 만약 ì¸ìžê°’ 둘 다 NULLì´ë¼ë©´ NULLì„ ë°˜í™˜í•©ë‹ˆë‹¤. + + + + (X,Y) The instr(X,Y) function finds the first occurrence of string Y within string X and returns the number of prior characters plus 1, or 0 if Y is nowhere found within X. + (X,Y) instr(X,Y) 함수는 문ìžì—´ Xì—서 문ìžì—´ Yê°€ 있다면 첫 ê¸€ìž ìœ„ì¹˜ + 1 ê°’ì„ ë¦¬í„´í•©ë‹ˆë‹¤. 만약 문ìžì—´ Xì—서 문ìžì—´ Yê°€ 발견ë˜ì§€ 않는다면 0ì„ ë°˜í™˜í•©ë‹ˆë‹¤. + + + + (X) The hex() function interprets its argument as a BLOB and returns a string which is the upper-case hexadecimal rendering of the content of that blob. + (X) hex() 함수는 매개변수를 BLOB으로 변환한 후 blobì˜ ë‚´ìš©ì„ ëŒ€ë¬¸ìž 16진수 문ìžì—´ë¡œ 변환하여 반환합니다. + + + + () The last_insert_rowid() function returns the ROWID of the last row insert from the database connection which invoked the function. + () last_insert_rowid() 함수는 함수가 í˜¸ì¶œëœ ë°ì´í„°ë² ì´ìФ ì—°ê²°ì—서 가장 ìµœê·¼ì— ì¶”ê°€ëœ í–‰ì˜ ROWID를 반환합니다. + + + + (X) For a string value X, the length(X) function returns the number of characters (not bytes) in X prior to the first NUL character. + (X) 문ìžì—´ 변수 X를 위한 것으로 length(X) 함수는 첫 번째 NUL 문ìžë¥¼ 만날 ë•Œê¹Œì§€ì˜ (ë°”ì´íЏ 수가 아닌)ë¬¸ìž ìˆ˜ë¥¼ 반환합니다. + + + + (X,Y) The like() function is used to implement the "Y LIKE X" expression. + (X,Y) like() 함수는 "Y LIKE X" 표현ì‹ì„ 구현하기위해 사용합니다. + + + + (X,Y,Z) The like() function is used to implement the "Y LIKE X ESCAPE Z" expression. + (X,Y,Z) like() 함수는 "Y LIKE X ESCAPE Z" 표현ì‹ì„ 구현하기 위해 사용합니다. + + + + (X) The load_extension(X) function loads SQLite extensions out of the shared library file named X. +Use of this function must be authorized from Preferences. + (X) load_extension(X) 함수는 Xë¼ëŠ” 공유 ë¼ì´ë¸ŒëŸ¬ë¦¬ 파ì¼ì—서 SQLite í™•ìž¥ì„ ë¡œë“œí•©ë‹ˆë‹¤. +ì´ ê¸°ëŠ¥ì˜ ì‚¬ìš©ì€ í™˜ê²½ì„¤ì •ì—서 승ì¸í•˜ì—¬ì•¼ 합니다. + + + + (X,Y) The load_extension(X) function loads SQLite extensions out of the shared library file named X using the entry point Y. +Use of this function must be authorized from Preferences. + (X,Y) The load_extension(X) 함수는 ì§„ìž…ì  Y를 사용하여 Xë¼ëŠ” 공유 ë¼ì´ë¸ŒëŸ¬ë¦¬ 파ì¼ì—서 SQLite í™•ìž¥ì„ ë¡œë“œí•©ë‹ˆë‹¤. +ì´ ê¸°ëŠ¥ì˜ ì‚¬ìš©ì€ í™˜ê²½ì„¤ì •ì—서 승ì¸ë˜ì–´ì•¼ 합니다. + + + + (X) The lower(X) function returns a copy of string X with all ASCII characters converted to lower case. + (X) lower(X) 함수는 문ìžì—´ Xì—서 모든 ASCII 문ìžë¥¼ 소문ìžë¡œ 변경한 문ìžì—´ ì‚¬ë³¸ì„ ë°˜í™˜í•©ë‹ˆë‹¤. + + + + (X) ltrim(X) removes spaces from the left side of X. + (X) ltrim(X) 함수는 Xì˜ ì¢Œì¸¡ì˜ ê³µë°± ì—¬ë°±ì„ ì œê±°í•©ë‹ˆë‹¤. + + + + (X,Y) The ltrim(X,Y) function returns a string formed by removing any and all characters that appear in Y from the left side of X. + (X,Y) ltrim(X,Y) 함수는 Xì˜ ì¢Œì¸¡ì—서 Yì— ìžˆëŠ” 모든 문ìžë¥¼ 제거한 문ìžì—´ì„ 반환합니다. + + + + (X,Y,...) The multi-argument max() function returns the argument with the maximum value, or return NULL if any argument is NULL. + (X,Y,...) 다중 ì¸ìžë¥¼ 제공하는 max() 함수는 주어진 ì¸ìž ê°’ 중ì—서 가장 í° ê°’ì„ ë°˜í™˜í•©ë‹ˆë‹¤. 만약 주어진 ì¸ìž ì¤‘ì— NULL ê°’ì´ í•˜ë‚˜ë¼ë„ 있으면 NULLì„ ë°˜í™˜í•©ë‹ˆë‹¤. + + + + (X,Y,...) The multi-argument min() function returns the argument with the minimum value. + (X,Y,...) 다중 ì¸ìžë¥¼ 제공하는 min() 함수는 주어진 ì¸ìž ê°’ 중ì—서 가장 ìž‘ì€ ê°’ì„ ë°˜í™˜í•©ë‹ˆë‹¤. + + + + (X,Y) The nullif(X,Y) function returns its first argument if the arguments are different and NULL if the arguments are the same. + Y) nullif(X,Y) 함수는 ë‘ ì¸ìž ê°’ì´ ì„œë¡œ 다르면 X를 반환하고 ë‘ ì¸ìž ê°’ì´ ê°™ìœ¼ë©´ NULLì„ ë°˜í™˜í•©ë‹ˆë‹¤. + + + + (FORMAT,...) The printf(FORMAT,...) SQL function works like the sqlite3_mprintf() C-language function and the printf() function from the standard C library. + (FORMAT,...) printf(FORMAT,...) SQL 함수는 sqlite3_mprintf() C-언어 함수와 표준 C ë¼ì´ë¸ŒëŸ¬ë¦¬ì—ì„œì˜ printf() 함수처럼 ë™ìž‘합니다. + + + + (X) The quote(X) function returns the text of an SQL literal which is the value of its argument suitable for inclusion into an SQL statement. + (X) quote(X) 함수는 X를 SQL문 ì•ˆì— í¬í•¨ë˜ê¸°ì— ì ì ˆí•˜ë„ë¡ SQL 리터럴 문ìžì—´ë¡œ 반환합니다. + + + + () The random() function returns a pseudo-random integer between -9223372036854775808 and +9223372036854775807. + () random() 함수는 -9223372036854775808와 +9223372036854775807 사ì´ì˜ pseudo-ëžœë¤ ì •ìˆ˜ë¥¼ 반환합니다. + + + + (N) The randomblob(N) function return an N-byte blob containing pseudo-random bytes. + (N) randomblob(N) 함수는 psedo-ëžœë¤ ë°”ì´íŠ¸ë¥¼ í¬í•¨í•œ N-ë°”ì´íЏ blobì„ ë°˜í™˜í•©ë‹ˆë‹¤. + + + + (X,Y,Z) The replace(X,Y,Z) function returns a string formed by substituting string Z for every occurrence of string Y in string X. + (X,Y,Z) replace(X,Y,Z) 함수는 문ìžì—´ Xì— ìžˆëŠ” 모든 문ìžì—´ Y를 Z로 치환한 문ìžì—´ì„ 반환합니다. + + + + (X) The round(X) function returns a floating-point value X rounded to zero digits to the right of the decimal point. + (X) round(X) 함수는 ë¶€ë™ì†Œìˆ˜ì  ê°’ X를 0ì˜ ìžë¦¬ì—서 반올림한 ê°’ì„ ë°˜í™˜í•©ë‹ˆë‹¤. + + + + (X,Y) The round(X,Y) function returns a floating-point value X rounded to Y digits to the right of the decimal point. + (X,Y) round(X,Y) 함수는 ë¶€ë™ì†Œìˆ˜ì  ê°’ X를 ì†Œìˆ˜ì  ìš°ì¸¡ì—서 Yìžë¦¬ì—서 반올림한 ê°’ì„ ë°˜í™˜í•©ë‹ˆë‹¤. + + + + (X) rtrim(X) removes spaces from the right side of X. + (X) rtrim(X)ì€ Xì˜ ìš°ì¸¡ ê³µë°±ì„ ì œê±°í•©ë‹ˆë‹¤. + + + + (X,Y) The rtrim(X,Y) function returns a string formed by removing any and all characters that appear in Y from the right side of X. + (X,Y) rtrim(X,Y) 함수는 Xì˜ ìš°ì¸¡ì—서 Yì— ìžˆëŠ” 모든 문ìžë¥¼ 삭제한 문ìžì—´ì„ 반환합니다. + + + + (X) The soundex(X) function returns a string that is the soundex encoding of the string X. + (X) soundex(X) 함수는 문ìžì—´ Xì˜ ì‚¬ìš´ë±ìФ(Soundex) ì¸ì½”딩 문ìžì—´ì„ 반환합니다. + + + + (X,Y) substr(X,Y) returns all characters through the end of the string X beginning with the Y-th. + (X,Y) substr(X,Y) 함수는 문ìžì—´ Xì—서 Y번째부터 ë까지 모든 문ìžì—´ì„ 반환합니다. + + + + (X,Y,Z) The substr(X,Y,Z) function returns a substring of input string X that begins with the Y-th character and which is Z characters long. + (X,Y,Z) substr(X,Y,Z) 함수는 문ìžì—´ Xì—서 Y번째 문ìžë¶€í„° Zë¬¸ìž ìˆ˜ë§Œí¼ ë°˜í™˜í•©ë‹ˆë‹¤. + + + + () The total_changes() function returns the number of row changes caused by INSERT, UPDATE or DELETE statements since the current database connection was opened. + () total_changes() 함수는 현재 ë°ì´í„°ë² ì´ìФ ì—°ê²°ì´ ì—´ë¦° 후 INSERT, UPDATE, DELETE êµ¬ë¬¸ì— ì˜í•´ì„œ ë³€ê²½ëœ ë ˆì½”ë“œ í–‰ 수를 반환합니다. + + + + (X) trim(X) removes spaces from both ends of X. + (X) trim(X) 함수는 Xì˜ ì–‘ìª½ ê³µë°±ì„ ì œê±°í•©ë‹ˆë‹¤. + + + + (X,Y) The trim(X,Y) function returns a string formed by removing any and all characters that appear in Y from both ends of X. + (X,Y) trim(X,Y) 함수는 Xì˜ ì–‘ëì—서 Yì— í•´ë‹¹í•˜ëŠ” 문ìžë“¤ì„ 삭제한 문ìžì—´ì„ 반환합니다. + + + + (X) The typeof(X) function returns a string that indicates the datatype of the expression X. + (X) typeof(X) 함수는 í‘œí˜„ì‹ Xì˜ ë°ì´í„° íƒ€ìž…ì„ ë‚˜íƒ€ë‚´ëŠ” 문ìžì—´ì„ 반환합니다. + + + + (X) The unicode(X) function returns the numeric unicode code point corresponding to the first character of the string X. + (X) unicode(X) 함수는 문ìžì—´ Xì˜ ì²« 글ìžì— 해당하는 ìˆ«ìž ìœ ë‹ˆì½”ë“œ í¬ì¸íŠ¸ë¥¼ 반환합니다. + + + + (X) The upper(X) function returns a copy of input string X in which all lower-case ASCII characters are converted to their upper-case equivalent. + (X) upper(X) 함수는 ìž…ë ¥ 문ìžì—´ Xì—서 ASCII 문ìžì— 해당하는 글ìžë¥¼ 대문ìžë¡œ 변경한 문ìžì—´ ì‚¬ë³¸ì„ ë°˜í™˜í•©ë‹ˆë‹¤. + + + + (N) The zeroblob(N) function returns a BLOB consisting of N bytes of 0x00. + (N) zeroblob(N) 함수는 N ë°”ì´íŠ¸ì˜ 0x00으로 ì´ë£¨ì–´ì§„ BLOBì„ êµ¬ì„±í•˜ì—¬ 반환합니다. + + + + + + + (timestring,modifier,modifier,...) + (timestring,modifier,modifier,...) + + + + (format,timestring,modifier,modifier,...) + (format,timestring,modifier,modifier,...) + + + + (X) The avg() function returns the average value of all non-NULL X within a group. + (X) avg() 함수는 그룹ì—서 모든 NULLì´ ì•„ë‹Œ Xì˜ ê°’ì˜ í‰ê· ì„ 반환합니다. + + + + (X) The count(X) function returns a count of the number of times that X is not NULL in a group. + (X) count(X) 함수는 그룹ì—서 NULLì´ ì•„ë‹Œ 개수를 세어 반환합니다. + + + + (X) The group_concat() function returns a string which is the concatenation of all non-NULL values of X. + (X) group_concat() 함수는 Xì˜ ëª¨ë“  NULLì´ ì•„ë‹Œ ê°’ë“¤ì˜ ë¬¸ìžì—´ë¡œ í•©ì³ì„œ 반환합니다. + + + + (X,Y) The group_concat() function returns a string which is the concatenation of all non-NULL values of X. If parameter Y is present then it is used as the separator between instances of X. + (X,Y) group_concat() 함수는 Xì˜ ëª¨ë“  NULLì´ ì•„ë‹Œ ê°’ë“¤ì˜ ë¬¸ìžì—´ë¡œ í•©ì³ì„œ 반환합니다. 만약 매개변수 Yê°€ 있다면 ê°’ë“¤ì„ ë¬¸ìžì—´ë¡œ í•©ì¹  때 구분ìžë¡œ 사용합니다. + + + + (X) The max() aggregate function returns the maximum value of all values in the group. + (X) max() 집계 함수는 그룹ì—서 모든 값들 중 가장 í° ê°’ì„ ë°˜í™˜í•©ë‹ˆë‹¤. + + + + (X) The min() aggregate function returns the minimum non-NULL value of all values in the group. + (X) min() 집계 함수는 그룹ì—서 NULLì´ ì•„ë‹Œ 모든 값들 중 가장 ìž‘ì€ ê°’ì„ ë°˜í™˜í•©ë‹ˆë‹¤. + + + + + (X) The sum() and total() aggregate functions return sum of all non-NULL values in the group. + (X) sum(x)ê³¼ total() 집계 함수는 ê·¸ë£¹ì˜ ëª¨ë“  NULLì´ ì•„ë‹Œ ê°’ë“¤ì˜ í•©ì„ ë°˜í™˜í•©ë‹ˆë‹¤. + + + + () The number of the row within the current partition. Rows are numbered starting from 1 in the order defined by the ORDER BY clause in the window definition, or in arbitrary order otherwise. + () 현재 파티션 ë‚´ì˜ í–‰ 번호입니다. í–‰ì€ ì°½ ì •ì˜ì˜ ORDER BY ì ˆì— ì •ì˜ëœ 순서대로 1부터 시작하거나 ìž„ì˜ì˜ 순서로 번호가 지정ë©ë‹ˆë‹¤. + + + + () The row_number() of the first peer in each group - the rank of the current row with gaps. If there is no ORDER BY clause, then all rows are considered peers and this function always returns 1. + () ê° ê·¸ë£¹ì˜ ì²« 번째 í”¼ì–´ì˜ row_number ()-ê°„ê²©ì´ ìžˆëŠ” 현재 í–‰ì˜ ìˆœìœ„. ORDER BY ì ˆì´ ì—†ìœ¼ë©´ 모든 í–‰ì´ í”¼ì–´ë¡œ 간주ë˜ê³  ì´ í•¨ìˆ˜ëŠ” í•­ìƒ 1ì„ ë°˜í™˜í•©ë‹ˆë‹¤. + + + + () The number of the current row's peer group within its partition - the rank of the current row without gaps. Partitions are numbered starting from 1 in the order defined by the ORDER BY clause in the window definition. If there is no ORDER BY clause, then all rows are considered peers and this function always returns 1. + () 파티션 ë‚´ 현재 í–‰ì˜ í”¼ì–´ 그룹 번호 - ê°„ê²©ì´ ì—†ëŠ” 현재 í–‰ì˜ ìˆœìœ„, íŒŒí‹°ì…˜ì€ ì°½ ì •ì˜ì˜ ORDER BYì ˆì— ì •ì˜ëœ 순서대로 1부터 시작ë©ë‹ˆë‹¤. ORDER BY ì ˆì´ ì—†ìœ¼ë©´ 모든 í–‰ì´ í”¼ì–´ë¡œ 간주ë˜ì–´ ì´ í•¨ìˆ˜ëŠ” í•­ìƒ 1ì„ ë°˜í™˜í•©ë‹ˆë‹¤. + + + + () Despite the name, this function always returns a value between 0.0 and 1.0 equal to (rank - 1)/(partition-rows - 1), where rank is the value returned by built-in window function rank() and partition-rows is the total number of rows in the partition. If the partition contains only one row, this function returns 0.0. + () ì´ë¦„ì—ë„ ë¶ˆêµ¬í•˜ê³  ì´ í•¨ìˆ˜ëŠ” í•­ìƒ (rank - 1)/(partition-rows - 1)ê³¼ ê°™ì€ 0.0ì—서 1.0 사ì´ì˜ ê°’ì„ ë°˜í™˜í•©ë‹ˆë‹¤. 여기서 rank는 내장 ì°½ 함수 rank() ë° partitionì—서 반환한 값입니다. rows는 íŒŒí‹°ì…˜ì˜ ì´ í–‰ 수 입니다. íŒŒí‹°ì…˜ì— í–‰ì´ í•˜ë‚˜ë§Œ í¬í•¨ëœ 경우 ì´ í•¨ìˆ˜ëŠ” 0.0ì„ ë°˜í™˜í•©ë‹ˆë‹¤. + + + + () The cumulative distribution. Calculated as row-number/partition-rows, where row-number is the value returned by row_number() for the last peer in the group and partition-rows the number of rows in the partition. + () ëˆ„ì  ë¶„í¬. row-number/partition-rows로 계산ë©ë‹ˆë‹¤. 여기서 row-number는 ê·¸ë£¹ì˜ ë§ˆì§€ë§‰ í”¼ì–´ì— ëŒ€í•´ row_number()ì—서 반환한 ê°’ì´ê³  partition-rows는 íŒŒí‹°ì…˜ì˜ í–‰ 수입니다. + + + + (N) Argument N is handled as an integer. This function divides the partition into N groups as evenly as possible and assigns an integer between 1 and N to each group, in the order defined by the ORDER BY clause, or in arbitrary order otherwise. If necessary, larger groups occur first. This function returns the integer value assigned to the group that the current row is a part of. + (N) ì¸ìž Nì€ ì •ìˆ˜ë¡œ 취급ë©ë‹ˆë‹¤. ì´ í•¨ìˆ˜ëŠ” ORDER BY êµ¬ë¬¸ì´ ìžˆë‹¤ë©´ ê·¸ 순서대로, 없다면 ìž„ì˜ì˜ 순서로 가능하면 균등하게 Nê°œì˜ ê·¸ë£¹ìœ¼ë¡œ 나누고 ê° ê·¸ë£¹ì— 1부터 N 사ì´ì˜ 정수를 할당합니다. 필요한 경우 í° ê·¸ë£¹ì´ ë¨¼ì € 나옵니다. ì´ í•¨ìˆ˜ëŠ” 현재 í–‰ì´ ì†í•´ìžˆëŠ” ê·¸ë£¹ì´ í• ë‹¹ëœ ì •ìˆ˜ë¥¼ 반환합니다. + + + + (expr) Returns the result of evaluating expression expr against the previous row in the partition. Or, if there is no previous row (because the current row is the first), NULL. + (expr) íŒŒí‹°ì…˜ì˜ ì´ì „ í–‰ì— ëŒ€í•´ expr 표현ì‹ì„ í‰ê°€í•œ 결과를 반환합니다. ë˜ëŠ” ì´ì „ í–‰ì´ ì—†ëŠ” 경우(현재 í–‰ì´ ì²«ë²ˆì§¸ì¼ ë•Œ) NULL 반환ë©ë‹ˆë‹¤. + + + + (expr,offset) If the offset argument is provided, then it must be a non-negative integer. In this case the value returned is the result of evaluating expr against the row offset rows before the current row within the partition. If offset is 0, then expr is evaluated against the current row. If there is no row offset rows before the current row, NULL is returned. + (expr,offset) offset ì¸ìˆ˜ê°€ 제공ë˜ë©´ ìŒì´ 아닌 정수여야합니다. ì´ ê²½ìš° ë°˜í™˜ëœ ê°’ì€ íŒŒí‹°ì…˜ ë‚´ì˜ í˜„ìž¬ í–‰ ì´ì „ì— í–‰ 오프셋 í–‰ì— ëŒ€í•´ expr를 í‰ê°€í•œ 결과입니다. ì˜¤í”„ì…‹ì´ 0ì´ë©´ exprì´ í˜„ìž¬ í–‰ì— ëŒ€í•´ í‰ê°€ë©ë‹ˆë‹¤. 현재 í–‰ ì•žì— í–‰ 오프셋 í–‰ì´ ì—†ìœ¼ë©´ NULLì´ ë°˜í™˜ë©ë‹ˆë‹¤. + + + + + (expr,offset,default) If default is also provided, then it is returned instead of NULL if the row identified by offset does not exist. + (expr,offset,default) defaultë„ ì œê³µë˜ë©´ offset으로 ì‹ë³„ëœ í–‰ì´ ì¡´ìž¬í•˜ì§€ ì•Šì•˜ì„ ë•Œ NULL 대신 반환ë©ë‹ˆë‹¤. + + + + (expr) Returns the result of evaluating expression expr against the next row in the partition. Or, if there is no next row (because the current row is the last), NULL. + (expr) íŒŒí‹°ì…˜ì˜ ë‹¤ìŒ í–‰ì— ëŒ€í•´ expr 표현ì‹ì„ í‰ê°€í•œ 결과를 반환합니다. ë˜ëŠ” ë‹¤ìŒ í–‰ì´ ì—†ëŠ” 경우(현재 í–‰ì´ ë§ˆì§€ë§‰ í–‰ì¼ ë•Œ) NULLì´ ë°˜í™˜ë©ë‹ˆë‹¤. + + + + (expr,offset) If the offset argument is provided, then it must be a non-negative integer. In this case the value returned is the result of evaluating expr against the row offset rows after the current row within the partition. If offset is 0, then expr is evaluated against the current row. If there is no row offset rows after the current row, NULL is returned. + (expr,offset) offset ì¸ìˆ˜ê°€ 제공ë˜ë©´ ìŒì´ 아닌 정수여야 합니다. ì´ ê²½ìš° ë°˜í™˜ëœ ê°’ì€ íŒŒí‹°ì…˜ ë‚´ì—서 현재 í–‰ ë’¤ì— ìžˆëŠ” í–‰ 오프셋 í–‰ì— ëŒ€í•´ exprì„ í‰ê°€í•œ 결과입니다. ì˜¤í”„ì…‹ì´ 0ì´ë©´ exprì´ í˜„ìž¬ í–‰ì— ëŒ€í•´ í‰ê°€ë©ë‹ˆë‹¤. 현재 í–‰ ë’¤ì— í–‰ 오프셋 í–‰ì´ ì—†ìœ¼ë©´ NULLì´ ë°˜í™˜ë©ë‹ˆë‹¤. + + + + (expr) This built-in window function calculates the window frame for each row in the same way as an aggregate window function. It returns the value of expr evaluated against the first row in the window frame for each row. + (expr)ì´ ë‚´ìž¥ ì°½ 함수는 집계 ì°½ 함수와 ë™ì¼í•œ ë°©ì‹ìœ¼ë¡œ ê° í–‰ì˜ ì°½ í”„ë ˆìž„ì„ ê³„ì‚°í•©ë‹ˆë‹¤. ê° í–‰ì˜ ì°½ 프레임ì—서 첫 번째 í–‰ì— ëŒ€í•´ í‰ê°€ëœ exprì˜ ê°’ì„ ë¦¬í„´í•©ë‹ˆë‹¤. + + + + (expr) This built-in window function calculates the window frame for each row in the same way as an aggregate window function. It returns the value of expr evaluated against the last row in the window frame for each row. + (expr)ì´ ë‚´ìž¥ ì°½ 함수는 집계 ì°½ 함수와 ë™ì¼í•œ ë°©ì‹ìœ¼ë¡œ ê° í–‰ì˜ ì°½ í”„ë ˆìž„ì„ ê³„ì‚°í•©ë‹ˆë‹¤. ê° í–‰ì˜ ì°½ 프레임ì—서 마지막 í–‰ì— ëŒ€í•´ í‰ê°€ ëœ exprì˜ ê°’ì„ ë¦¬í„´í•©ë‹ˆë‹¤. + + + + (expr,N) This built-in window function calculates the window frame for each row in the same way as an aggregate window function. It returns the value of expr evaluated against the row N of the window frame. Rows are numbered within the window frame starting from 1 in the order defined by the ORDER BY clause if one is present, or in arbitrary order otherwise. If there is no Nth row in the partition, then NULL is returned. + (expr,N)ì´ ë‚´ìž¥ ì°½ 함수는 집계 ì°½ 함수와 ë™ì¼í•œ ë°©ì‹ìœ¼ë¡œ ê° í–‰ì˜ ì°½ í”„ë ˆìž„ì„ ê³„ì‚°í•©ë‹ˆë‹¤. ì°½ í”„ë ˆìž„ì˜ N í–‰ì— ëŒ€í•´ í‰ê°€ ëœ exprì˜ ê°’ì„ ë¦¬í„´í•©ë‹ˆë‹¤. í–‰ì€ ORDER BY ì ˆì— ì •ì˜ ëœ ìˆœì„œëŒ€ë¡œ 1부터 시작하여 ì°½ 프레임 ë‚´ì—서 번호가 매겨집니다. 그렇지 않으면 ìž„ì˜ì˜ 순서로 번호가 매겨집니다. íŒŒí‹°ì…˜ì— N 번째 í–‰ì´ ì—†ìœ¼ë©´ NULLì´ ë°˜í™˜ë©ë‹ˆë‹¤. + + + + SqliteTableModel + + + reading rows + í–‰ì„ ì½ëŠ” 중 + + + + loading... + 로딩 중... + + + + References %1(%2) +Hold %3Shift and click to jump there + 참조 %1(%2) +%3Shift를 누른 ìƒíƒœì—서 ì´ë™í•˜ê³ ìž 하는 ê³³ì„ í´ë¦­í•˜ì„¸ìš” + + + + Error changing data: +%1 + ë°ì´í„° 수정 ì—러: +%1 + + + + retrieving list of columns + ì»¬ëŸ¼ì€ í•„ë“œë¡œ 표현합니다. + 필드 ëª©ë¡ ê°€ì ¸ì˜¤ê¸° + + + + Fetching data... + ë°ì´í„°ë¥¼ 가져오는 중입니다... + + + + + Cancel + 취소 + + + + TableBrowser + + + Browse Data + ë°ì´í„° íƒìƒ‰ + + + + &Table: + í…Œì´ë¸”(&T): + + + + Select a table to browse data + íƒìƒ‰í•˜ë ¤ëŠ” ë°ì´í„°ê°€ 있는 í…Œì´ë¸”ì„ ì„ íƒí•˜ì„¸ìš” + + + + Use this list to select a table to be displayed in the database view + 리스트ì—서 í…Œì´ë¸”ì„ ì„ íƒí•˜ë©´ ë°ì´í„°ë² ì´ìФ ë·°ì—서 ë³¼ 수 있습니다 + + + + This is the database table view. You can do the following actions: + - Start writing for editing inline the value. + - Double-click any record to edit its contents in the cell editor window. + - Alt+Del for deleting the cell content to NULL. + - Ctrl+" for duplicating the current record. + - Ctrl+' for copying the value from the cell above. + - Standard selection and copy/paste operations. + ì´ê²ƒì€ ë°ì´í„°ë² ì´ìŠ¤ì˜ í…Œì´ë¸” 뷰입니다. ë‹¤ìŒ ìž‘ì—…ì„ ìˆ˜í–‰í•  수 있습니다: + - ê°’ì„ ì¸ë¼ì¸ìœ¼ë¡œ 편집하기 위한 ìž‘ì„±ì„ ì‹œìž‘í•©ë‹ˆë‹¤. + - ì…€ 편집기 ì°½ì—서 ë‚´ìš©ì„ íŽ¸ì§‘í•˜ë ¤ë©´ 레코드를 ë”블 í´ë¦­í•©ë‹ˆë‹¤. + - ì…€ ë‚´ìš©ì„ NULL 값으로 삭제하려면 Alt+Del + - Ctrl + "는 현재 레코드를 복제합니다. + - ìœ„ì˜ ì…€ì—서 ê°’ì„ ë³µì‚¬í•˜ë ¤ë©´ Ctrl + ' + - 표준 ì„ íƒ ë° ë³µì‚¬ / 붙여넣기 작업. + + + + Text pattern to find considering the checks in this frame + ì´ í”„ë ˆìž„ 안ì—서 확ì¸í•˜ê¸° 위해 ê²€ìƒ‰í•˜ê³ ìž í•˜ëŠ” 문ìžì—´ 패턴 + + + + Find in table + í…Œì´ë¸”ì—서 찾기 + + + + Find previous match [Shift+F3] + ì´ì „ 찾기 [Shift+F3] + + + + Find previous match with wrapping + ëž©í•‘ëœ ì´ì „ ì¼ì¹˜ë‚´ì—­ 검색하기 + + + + Shift+F3 + + + + + Find next match [Enter, F3] + ë‹¤ìŒ ì°¾ê¸° [Enter, F3] + + + + Find next match with wrapping + 랩핑(Wrapping)으로 ë‹¤ìŒ ì°¾ê¸° + + + + F3 + + + + + The found pattern must match in letter case + ëŒ€ì†Œë¬¸ìž ì¼ì¹˜ 검색패턴 + + + + Case Sensitive + ëŒ€ì†Œë¬¸ìž ì¼ì¹˜ + + + + The found pattern must be a whole word + 온전한 ë‚±ë§ ì¼ì¹˜ 검색패턴 + + + + Whole Cell + ì „ì²´ ì…€ + + + + Interpret search pattern as a regular expression + 검색 íŒ¨í„´ì„ ì •ê·œ 표현ì‹ìœ¼ë¡œ í•´ì„ + + + + <html><head/><body><p>When checked, the pattern to find is interpreted as a UNIX regular expression. See <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>.</p></body></html> + <html><head/><body><p>ì„ íƒí•˜ë©´ 찾으려는 íŒ¨í„´ì´ UNIX ì •ê·œì‹ìœ¼ë¡œ í•´ì„ë©ë‹ˆë‹¤. <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>ì„ ì°¸ê³ í•˜ì„¸ìš”.</p></body></html> + + + + Regular Expression + ì •ê·œ í‘œí˜„ì‹ + + + + + Close Find Bar + 검색바 닫기 + + + + Text to replace with + 바꾸려는 í…스트 + + + + Replace with + ~로 바꾸기 + + + + Replace next match + ì¼ì¹˜í•˜ëŠ” ë‹¤ìŒ í…스트 바꾸기 + + + + + Replace + 바꾸기 + + + + Replace all matches + ì¼ì¹˜í•˜ëŠ” 모든 í…스트 바꾸기 + + + + Replace all + ëª¨ë‘ ë°”ê¾¸ê¸° + + + + <html><head/><body><p>Scroll to the beginning</p></body></html> + <html><head/><body><p>첫 페ì´ì§€ë¡œ 갑니다.</p></body></html> + + + + <html><head/><body><p>Clicking this button navigates to the beginning in the table view above.</p></body></html> + <html><head/><body><p>í…Œì´ë¸” ë·° 맨 위로 가기 위해서는 ì´ ë²„íŠ¼ì„ í´ë¦­í•˜ì„¸ìš”.</p></body></html> + + + + |< + |< + + + + Scroll one page upwards + 한 페ì´ì§€ 위로 스í¬ë¡¤í•©ë‹ˆë‹¤ + + + + <html><head/><body><p>Clicking this button navigates one page of records upwards in the table view above.</p></body></html> + <html><head/><body><p>위 í…Œì´ë¸” ë·°ì—서 레코드를 한 페ì´ì§€ 앞으로 가려면 ì´ ë²„íŠ¼ì„ í´ë¦­í•˜ì„¸ìš”.</p></body></html> + + + + < + < + + + + 0 - 0 of 0 + 0 - 0 of 0 + + + + Scroll one page downwards + 한 페ì´ì§€ 아래로 스í¬ë¡¤í•©ë‹ˆë‹¤ + + + + <html><head/><body><p>Clicking this button navigates one page of records downwards in the table view above.</p></body></html> + <html><head/><body><p>위 í…Œì´ë¸” ë·°ì—서 레코드를 한 페ì´ì§€ 뒤로 가려면 ì´ ë²„íŠ¼ì„ í´ë¦­í•˜ì„¸ìš”.</p></body></html> + + + + > + > + + + + Scroll to the end + 마지막 페ì´ì§€ë¡œ ì´ë™ + + + + <html><head/><body><p>Clicking this button navigates up to the end in the table view above.</p></body></html> + <html><head/><body><p>í…Œì´ë¸” ë·° 맨 아래로 가기 위해서는 ì´ ë²„íŠ¼ì„ í´ë¦­í•˜ì„¸ìš”.</p></body></html> + + + + >| + >| + + + + <html><head/><body><p>Click here to jump to the specified record</p></body></html> + <html><head/><body><p>특정 레코드로 ì´ë™í•˜ë ¤ë©´ 여기를 í´ë¦­í•˜ì„¸ìš”</p></body></html> + + + + <html><head/><body><p>This button is used to navigate to the record number specified in the Go to area.</p></body></html> + <html><head/><body><p>ì´ ë²„íŠ¼ì€ íŠ¹ì • ìœ„ì¹˜ì˜ ë ˆì½”ë“œ 넘버로 가기 위해서 사용합니다.</p></body></html> + + + + Go to: + 특정 레코드 행으로 가기: + + + + Enter record number to browse + ì°¾ì„ ë ˆì½”ë“œ í–‰ 번호를 입력하세요 + + + + Type a record number in this area and click the Go to: button to display the record in the database view + 레코드 í–‰ 번호를 입력하고 '특정 레코드 행으로 가기:' ë²„íŠ¼ì„ í´ë¦­í•˜ë©´ ë°ì´í„°ë² ì´ìФ ë·°ì— ë ˆì½”ë“œê°€ 표시ë©ë‹ˆë‹¤ + + + + 1 + 1 + + + + Show rowid column + ì»¬ëŸ¼ì˜ rowid 표시하기 + + + + Toggle the visibility of the rowid column + rowid ì»¬ëŸ¼ì„ í‘œì‹œí•˜ê±°ë‚˜ 숨ê¹ë‹ˆë‹¤ + + + + Unlock view editing + ë·° 수정 잠금 해제하기 + + + + This unlocks the current view for editing. However, you will need appropriate triggers for editing. + ìˆ˜ì •ì„ ìœ„í•˜ì—¬ 현재 ë·°ì˜ ìž ê¸ˆì„ í•´ì œí•©ë‹ˆë‹¤. 하지만 ìˆ˜ì •ì„ ìœ„í•´ì„œëŠ” ì ì ˆí•œ 트리거가 필요할 것입니다. + + + + Edit display format + 표시 í˜•ì‹ ë³€ê²½ + + + + Edit the display format of the data in this column + ì´ ì»¬ëŸ¼ì— ìžˆëŠ” ë°ì´í„°ì˜ 표시 형ì‹ì„ 수정합니다 + + + + + New Record + 새 레코드 + + + + + Insert a new record in the current table + 현재 í…Œì´ë¸”ì— ìƒˆ 레코드를 추가합니다 + + + + <html><head/><body><p>This button creates a new record in the database. Hold the mouse button to open a pop-up menu of different options:</p><ul><li><span style=" font-weight:600;">New Record</span>: insert a new record with default values in the database.</li><li><span style=" font-weight:600;">Insert Values...</span>: open a dialog for entering values before they are inserted in the database. This allows to enter values acomplishing the different constraints. This dialog is also open if the <span style=" font-weight:600;">New Record</span> option fails due to these constraints.</li></ul></body></html> + <html><head/><body><p>ì´ ë²„íŠ¼ì€ ë°ì´í„°ë² ì´ìŠ¤ì— ìƒˆ 레코드를 ìƒì„±í•©ë‹ˆë‹¤.</p><ul><li><span style=" font-weight:600;">새 레코드</span>: ë°ì´í„°ë² ì´ìŠ¤ì˜ ê¸°ë³¸ê°’ìœ¼ë¡œ 새 레코드를 ìƒì„±í•©ë‹ˆë‹¤.</li><li><span style=" font-weight:600;">ê°’ 삽입...</span>: ë°ì´í„°ë² ì´ìŠ¤ì— ê°’ì„ ì‚½ìž…í•˜ê¸° ì „ì— ê°’ì„ ìž…ë ¥í•  수 있는 대화ìƒìžë¥¼ 엽니다. ì´ë¥¼ 통해 다양한 제약 ì¡°ê±´ì— ì¶©ì¡±í•˜ëŠ” ê°’ì„ ìž…ë ¥í•  수 있습니다. ì´ëŸ¬í•œ 제약으로 ì¸í•´ <span style=" font-weight:600;">새 레코드</span> ì˜µì…˜ì´ ì‹¤íŒ¨í•œ 경우ì—ë„ ì´ ëŒ€í™”ìƒìžê°€ 열립니다.</li></ul></body></html> + + + + + Delete Record + 레코드 ì‚­ì œ + + + + Delete the current record + 현재 레코드 삭제하기 + + + + + This button deletes the record or records currently selected in the table + ì´ ë²„íŠ¼ì€ í…Œì´ë¸”ì—서 현재 ì„ íƒëœ 레코드를 삭제합니다 + + + + + Insert new record using default values in browsed table + 현재 íƒìƒ‰í•œ í…Œì´ë¸”ì˜ ê¸°ë³¸ê°’ì„ ì‚¬ìš©í•˜ì—¬ 새 레코드 삽입 + + + + Insert Values... + ê°’ 추가... + + + + + Open a dialog for inserting values in a new record + 새 ë ˆì½”ë“œì˜ ê°’ì„ ì‚½ìž…í•˜ê¸° 위한 대화ìƒìžë¥¼ 엽니다 + + + + Export to &CSV + CSV로 내보내기(&C) + + + + + Export the filtered data to CSV + 필러ë§ëœ ë°ì´í„°ë¥¼ CSV로 내보내기 + + + + This button exports the data of the browsed table as currently displayed (after filters, display formats and order column) as a CSV file. + ì´ ë²„íŠ¼ì€ í˜„ìž¬ 표시ëœëŒ€ë¡œ(í•„í„°, 표시 í˜•ì‹ ë° ì—´ 순서) íƒìƒ‰ëœ í…Œì´ë¸”ì˜ ë°ì´í„°ë¥¼ CSV 파ì¼ë¡œ 내보냅니다. + + + + Save as &view + 뷰로 저장하기(&V) + + + + + Save the current filter, sort column and display formats as a view + 현재 í•„í„°, ì—´ ì •ë ¬ ë° í‘œì‹œ 형ì‹ì„ 뷰로 저장 + + + + This button saves the current setting of the browsed table (filters, display formats and order column) as an SQL view that you can later browse or use in SQL statements. + ì´ ë²„íŠ¼ì€ ê²€ìƒ‰ëœ í…Œì´ë¸”ì˜ í˜„ìž¬ 설정(í•„í„°, 표시 í˜•ì‹ ë° ì—´ 순서)ì„ ë‚˜ì¤‘ì— SQL 문ì—서 검색하거나 사용할 수 있는 SQL 뷰로 저장합니다. + + + + Save Table As... + 다른 ì´ë¦„으로 í…Œì´ë¸” 저장... + + + + + Save the table as currently displayed + 현재 ì¶œë ¥ëœ í˜•íƒœë¡œ í…Œì´ë¸” 저장 + + + + <html><head/><body><p>This popup menu provides the following options applying to the currently browsed and filtered table:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Export to CSV: this option exports the data of the browsed table as currently displayed (after filters, display formats and order column) to a CSV file.</li><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Save as view: this option saves the current setting of the browsed table (filters, display formats and order column) as an SQL view that you can later browse or use in SQL statements.</li></ul></body></html> + <html><head/><body><p>ì´ íŒì—… 메뉴는 현재 íƒìƒ‰ ë° í•„í„°ë§ëœ í‘œì— ì ìš©ë˜ëŠ” ë‹¤ìŒ ì˜µì…˜ì„ ì œê³µí•©ë‹ˆë‹¤.</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">CSV로 내보내기: ì´ ì˜µì…˜ì€ í˜„ìž¬ 표시ëœëŒ€ë¡œ(í•„í„°, 표시 í˜•ì‹ ë° ì—´ 순서) íƒìƒ‰ëœ í…Œì´ë¸”ì˜ ë°ì´í„°ë¥¼ CSV 파ì¼ë¡œ 내보냅니다.</li><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">뷰로 저장: ì´ ì˜µì…˜ì€ ê²€ìƒ‰ëœ í…Œì´ë¸”ì˜ í˜„ìž¬ 설정(í•„í„°, 표시 í˜•ì‹ ë° ì—´ 순서)ì„ ë‚˜ì¤‘ì— SQL 문ì—서 검색하거나 사용할 수 있는 SQL 뷰로 저장합니다.</li></ul></body></html> + + + + Hide column(s) + 컬럼(들) 숨기기 + + + + Hide selected column(s) + ì„ íƒí•œ 컬럼(들)ì„ ìˆ¨ê¸°ê¸° + + + + Show all columns + ì „ì²´ 컬럼 보기 + + + + Show all columns that were hidden + 숨겨진 ì „ì²´ 컬럼 보기 + + + + + Set encoding + ì¸ì½”딩 지정하기 + + + + Change the encoding of the text in the table cells + í…Œì´ë¸” ì…€ ì•ˆì˜ í…스트 ì¸ì½”ë”©ì„ ë³€ê²½í•©ë‹ˆë‹¤ + + + + Set encoding for all tables + 모든 í…Œì´ë¸”ì˜ ì¸ì½”딩 지정하기 + + + + Change the default encoding assumed for all tables in the database + ë°ì´í„°ë² ì´ìФ ì•ˆì— ìžˆëŠ” 모든 í…Œì´ë¸”ì˜ ê¸°ë³¸ ì¸ì½”ë”©ì„ ë³€ê²½í•©ë‹ˆë‹¤ + + + + Clear Filters + í•„í„° 지우기 + + + + Clear all filters + 모든 í•„í„° 지우기 + + + + + This button clears all the filters set in the header input fields for the currently browsed table. + ì´ ë²„íŠ¼ì€ í˜„ìž¬ íƒìƒ‰ëœ í…Œì´ë¸”ì˜ í—¤ë” ìž…ë ¥ í•„ë“œì— ì„¤ì •ëœ ëª¨ë“  필터를 ì§€ì›ë‹ˆë‹¤. + + + + Clear Sorting + ì •ë ¬ 초기화 + + + + Reset the order of rows to the default + í–‰ 순서를 기본값으로 재설정 + + + + + This button clears the sorting columns specified for the currently browsed table and returns to the default order. + ì´ ë²„íŠ¼ì€ í˜„ìž¬ ê²€ìƒ‰ëœ í…Œì´ë¸”ì— ì§€ì •ëœ ì—´ ì •ë ¬ì„ ì§€ìš°ê³  기본 순서로 ëŒì•„갑니다. + + + + Print + ì¸ì‡„하기 + + + + Print currently browsed table data + 현재 íƒìƒ‰í•œ í…Œì´ë¸” ë°ì´í„°ë¥¼ ì¸ì‡„합니다 + + + + Print currently browsed table data. Print selection if more than one cell is selected. + 현재 찾아본 í…Œì´ë¸” ë°ì´í„°ë¥¼ ì¸ì‡„합니다. 둘 ì´ìƒì˜ ì…€ì´ ì„ íƒëœ 경우 ì„ íƒ í•­ëª©ë§Œ ì¸ì‡„합니다. + + + + Ctrl+P + + + + + Refresh + 새로고침 + + + + Refresh the data in the selected table + ì„ íƒí•œ í…Œì´ë¸”ì˜ ë°ì´í„° 새로고치기 + + + + This button refreshes the data in the currently selected table. + ì´ ë²„íŠ¼ì€ í˜„ìž¬ ì„ íƒëœ í…Œì´ë¸”ì˜ ë°ì´í„°ë¥¼ 새로고칩니다. + + + + F5 + + + + + Find in cells + ì…€ì—서 찾기 + + + + Open the find tool bar which allows you to search for values in the table view below. + 아래 표 보기ì—서 ê°’ì„ ê²€ìƒ‰í•  수 있는 ë„구 모ìŒì„ 엽니다. + + + + + Bold + 진하게 + + + + Ctrl+B + + + + + + Italic + 기울임 + + + + + Underline + 밑줄 + + + + Ctrl+U + + + + + + Align Right + 우측으로 ì •ë ¬ + + + + + Align Left + 좌측으로 ì •ë ¬ + + + + + Center Horizontally + ê°€ìš´ë° ì •ë ¬ + + + + + Justify + ì •ë ¬ + + + + + Edit Conditional Formats... + ì¡°ê±´ë¶€ ì„œì‹ íŽ¸ì§‘... + + + + Edit conditional formats for the current column + ì´ ì»¬ëŸ¼ì˜ ì¡°ê±´ë¶€ ì„œì‹ íŽ¸ì§‘ + + + + Clear Format + ì„œì‹ ì§€ìš°ê¸° + + + + Clear All Formats + 모든 í•„í„° 지우기 + + + + + Clear all cell formatting from selected cells and all conditional formats from selected columns + ì„ íƒí•œ ì…€ì˜ ëª¨ë“  ì…€ 서ì‹ê³¼ ì„ íƒí•œ ì—´ì˜ ëª¨ë“  ì¡°ê±´ë¶€ ì„œì‹ ì§€ìš°ê¸° + + + + + Font Color + 글ìžìƒ‰ + + + + + Background Color + 배경색 + + + + Toggle Format Toolbar + ì„œì‹ íˆ´ë°” 토글 + + + + Show/hide format toolbar + ì„œì‹ íˆ´ë°” 표시/숨기기 + + + + + This button shows or hides the formatting toolbar of the Data Browser + ì´ ë²„íŠ¼ì€ ë°ì´í„° 브ë¼ìš°ì €ì˜ ì„œì‹ ë„구 모ìŒì„ 표시하거나 숨ê¹ë‹ˆë‹¤ + + + + Select column + 컬럼 ì„ íƒ + + + + Ctrl+Space + + + + + Replace text in cells + ì…€ì˜ í…스트 바꾸기 + + + + Filter in any column + 모든 ì—´ì—서 í•„í„°ë§ + + + + Ctrl+R + + + + + %n row(s) + + %n ì—´(들) + + + + + , %n column(s) + + , %n 컬럼(들) + + + + + . Sum: %1; Average: %2; Min: %3; Max: %4 + . 합계: %1, í‰ê· : %2, 최소값: %3, 최대값: %4 + + + + Conditional formats for "%1" + "%1"ì— ëŒ€í•œ ì¡°ê±´ë¶€ ì„œì‹ + + + + determining row count... + í–‰ 개수 ê²°ì • 중... + + + + %1 - %2 of >= %3 + %1 - %2 of >= %3 + + + + %1 - %2 of %3 + %1 - %2 of %3 + + + + Please enter a pseudo-primary key in order to enable editing on this view. This should be the name of a unique column in the view. + ì´ ë·°ì—서 ìˆ˜ì •ì„ í™œì„±í™”í•˜ê¸° 위하여 pseudo-primary key를 입력하시기 ë°”ëžë‹ˆë‹¤. ì´ê²ƒì€ ë·°ì—서 유ì¼í•œ ì´ë¦„ì´ì–´ì•¼ 합니다. + + + + Delete Records + 레코드 ì‚­ì œ + + + + Duplicate records + 레코드 복제하기 + + + + Duplicate record + 레코드 복제하기 + + + + Ctrl+" + + + + + Adjust rows to contents + ë‚´ìš©ì— ë§žê²Œ í–‰ í¬ê¸° ì¡°ì ˆ + + + + Error deleting record: +%1 + 레코드 추가 ì—러: +%1 + + + + Please select a record first + 레코드를 먼저 ì„ íƒí•˜ì„¸ìš” + + + + There is no filter set for this table. View will not be created. + ì´ í…Œì´ë¸”ì„ ìœ„í•œ í•„í„°ê°€ 설정ë˜ì§€ 않았습니다. ë·°ê°€ ìƒì„±ë˜ì§€ 않습니다. + + + + Please choose a new encoding for all tables. + 모든 í…Œì´ë¸”ì— ì„¤ì •í•  새 ì¸ì½”ë”©ì„ ì„ íƒí•˜ì„¸ìš”. + + + + Please choose a new encoding for this table. + ì´ í…Œì´ë¸”ì— ì ìš©í•  새 ì¸ì½”ë”©ì„ ì„ íƒí•˜ì„¸ìš”. + + + + %1 +Leave the field empty for using the database encoding. + %1 +ë°ì´í„°ë² ì´ìФ ì¸ì½”ë”©ì„ ì‚¬ìš©í•˜ê¸° 위해 필드를 비워둡니다. + + + + This encoding is either not valid or not supported. + ì´ ì¸ì½”ë”©ì€ ì˜¬ë°”ë¥´ì§€ 않거나 ì§€ì›ë˜ì§€ 않습니다. + + + + %1 replacement(s) made. + %1ê°œì˜ êµì²´ê°€ ì´ë£¨ì–´ì¡ŒìŠµë‹ˆë‹¤. + + + + VacuumDialog + + + Compact Database + ë°ì´í„°ë² ì´ìФ í¬ê¸° 줄ì´ê¸°(Vacuum) + + + + Warning: Compacting the database will commit all of your changes. + 주ì˜: ë°ì´í„°ë² ì´ìФ í¬ê¸° 줄ì´ê¸°ë¥¼ 하면 저장ë˜ì§€ ì•Šì€ ëª¨ë“  ìˆ˜ì •ì‚¬í•­ì´ ë°˜ì˜ë©ë‹ˆë‹¤. + + + + Please select the databases to co&mpact: + í¬ê¸°ë¥¼ ì¤„ì¼ ë°ì´í„°ë² ì´ìŠ¤ë¥¼ ì„ íƒí•˜ì„¸ìš”(&M): + + + diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/translations/sqlb_nl.qm b/src/WBCLFZSystemModule/SqliteDBProcess/src/translations/sqlb_nl.qm new file mode 100644 index 0000000000000000000000000000000000000000..928c3c6ed662eb207c0fbb1707ad48c7abc3c9a4 GIT binary patch literal 253683 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 literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/translations/sqlb_nl.ts b/src/WBCLFZSystemModule/SqliteDBProcess/src/translations/sqlb_nl.ts new file mode 100644 index 0000000..9e6d4ed --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/translations/sqlb_nl.ts @@ -0,0 +1,7076 @@ + + + + + AboutDialog + + + About DB Browser for SQLite + Over DB-browser voor SQLite + + + + Version + Versie + + + + <html><head/><body><p>DB Browser for SQLite is an open source, freeware visual tool used to create, design and edit SQLite database files.</p><p>It is bi-licensed under the Mozilla Public License Version 2, as well as the GNU General Public License Version 3 or later. You can modify or redistribute it under the conditions of these licenses.</p><p>See <a href="http://www.gnu.org/licenses/gpl.html">http://www.gnu.org/licenses/gpl.html</a> and <a href="https://www.mozilla.org/MPL/2.0/index.txt">https://www.mozilla.org/MPL/2.0/index.txt</a> for details.</p><p>For more information on this program please visit our website at: <a href="http://sqlitebrowser.org">http://sqlitebrowser.org</a></p><p><span style=" font-size:small;">This software uses the GPL/LGPL Qt Toolkit from </span><a href="http://qt-project.org/"><span style=" font-size:small;">http://qt-project.org/</span></a><span style=" font-size:small;"><br/>See </span><a href="http://qt-project.org/doc/qt-5/licensing.html"><span style=" font-size:small;">http://qt-project.org/doc/qt-5/licensing.html</span></a><span style=" font-size:small;"> for licensing terms and information.</span></p><p><span style=" font-size:small;">It also uses the Silk icon set by Mark James licensed under a Creative Commons Attribution 2.5 and 3.0 license.<br/>See </span><a href="http://www.famfamfam.com/lab/icons/silk/"><span style=" font-size:small;">http://www.famfamfam.com/lab/icons/silk/</span></a><span style=" font-size:small;"> for details.</span></p></body></html> + <html><head/><body><p>DB-browser voor SQLite is een open source en freeware visuele tool om SQLite databasebestanden mee te creëren, te ontwerpen en te bewerken.</p><p>Het is uitgebracht onder een duolicentie: Mozilla Public License versie 2 en GNU General Public License versie 3 of hoger. Je mag het aanpassen en herdistribueren onder de voorwaarden van deze licenties.</p><p>Zie <a href="http://www.gnu.org/licenses/gpl.html">http://www.gnu.org/licenses/gpl.html</a> en <a href="https://www.mozilla.org/MPL/2.0/index.txt">https://www.mozilla.org/MPL/2.0/index.txt</a> voor de details.</p><p>Bezoek onze website op <a href="http://sqlitebrowser.org">http://sqlitebrowser.org</a> voor meer informatie over dit programma.</p><p><span style=" font-size:small;">Deze software maakt gebruik van de GPL/LGPL Qt Toolkit van </span><a href="http://qt-project.org/"><span style=" font-size:small;">http://qt-project.org/</span></a><span style=" font-size:small;"><br/>Zie </span><a href="http://qt-project.org/doc/qt-5/licensing.html"><span style=" font-size:small;">http://qt-project.org/doc/qt-5/licensing.html</span></a><span style=" font-size:small;"> voor de licentievoorwaarden en informatie.</span></p><p><span style=" font-size:small;">Het maakt tevens gebruik van de Silk iconenset van Mark James, uitgebracht onder de Creative Commons Attribution 2.5 en 3.0 licenties.<br/>Zie </span><a href="http://www.famfamfam.com/lab/icons/silk/"><span style=" font-size:small;">http://www.famfamfam.com/lab/icons/silk/</span></a><span style=" font-size:small;"> voor de details.</span></p></body></html> + + + + AddRecordDialog + + + Add New Record + Nieuw record toevoegen + + + + Enter values for the new record considering constraints. Fields in bold are mandatory. + Voer waarden in voor het nieuwe record, rekening houdend met beperkingen. Vette velden zijn verplicht. + + + + In the Value column you can specify the value for the field identified in the Name column. The Type column indicates the type of the field. Default values are displayed in the same style as NULL values. + In de Waarde-kolom kun je de waarde opgegeven voor het veld geïdentificeerd in de Naam-kolom. De Type-kolom geeft het type van het veld aan. Standaardwaarden worden in dezelfde stijl getoond als NULL-waarden. + + + + Name + Naam + + + + Type + Type + + + + Value + Waarde + + + + Values to insert. Pre-filled default values are inserted automatically unless they are changed. + In te voeren waarden. Vooringevulde standaardwaarden worden automatisch ingevoerd, tenzij ze aanpast worden. + + + + When you edit the values in the upper frame, the SQL query for inserting this new record is shown here. You can edit manually the query before saving. + Wanneer je waarden in het kader hierboven bewerkt, dan wordt de SQL-opdracht voor het invoegen van een nieuw record hier getoond. Je kunt de opdracht dan nog bewerken, voordat je deze opslaat. + + + + <html><head/><body><p><span style=" font-weight:600;">Save</span> will submit the shown SQL statement to the database for inserting the new record.</p><p><span style=" font-weight:600;">Restore Defaults</span> will restore the initial values in the <span style=" font-weight:600;">Value</span> column.</p><p><span style=" font-weight:600;">Cancel</span> will close this dialog without executing the query.</p></body></html> + <html><head/><body><p><span style=" font-weight:600;">Opslaan</span> verstuurt de SQL-instructie voor het invoeren van een nieuw record naar de database.</p><p><span style=" font-weight:600;">Standaardwaarden herstellen</span> herstelt de initiële waarden van de <span style=" font-weight:600;">Value</span>-kolom.</p><p><span style=" font-weight:600;">Annuleren</span> sluit dit venster zonder de opdracht uit te voeren.</p></body></html> + + + + Auto-increment + + Automatisch ophogen + + + + + Unique constraint + + Uniciteitsbeperking + + + + + Check constraint: %1 + + Controlebeperking: %1 + + + + + Foreign key: %1 + + Vreemde sleutel: %1 + + + + + Default value: %1 + + Standaardwaarde: %1 + + + + + Error adding record. Message from database engine: + +%1 + Fout bij toevoegen record. Melding van de database: + +%1 + + + + Are you sure you want to restore all the entered values to their defaults? + Weet je zeker dat je alle ingevoerde waarden wilt herstellen naar hun standaardwaarden? + + + + Application + + + Usage: %1 [options] [<database>|<project>] + + Gebruik: %1 [opties] [<database>|<project>] + + + + + Possible command line arguments: + Mogelijke opdrachtregelargumenten: + + + + -h, --help Show command line options + -h, --help Toon opdrachtregelargumenten + + + + -q, --quit Exit application after running scripts + -q, --quit Sluit applicatie nadat scripts uitgevoerd zijn + + + + -s, --sql <file> Execute this SQL file after opening the DB + -s, --sql <bestand> Voer dit SQL-bestand uit nadat de database geopend is + + + + -t, --table <table> Browse this table after opening the DB + -t, --table <tabel> Blader door deze tabel nadat de database geopend is + + + + -R, --read-only Open database in read-only mode + -R, --read-only Open database in alleen-lezenmodus + + + + -o, --option <group>/<setting>=<value> + -o, --option <groep>/<instelling>=<waarde> + + + + Run application with this setting temporarily set to value + Applicatie uitvoeren met tijdelijke waarde voor deze instelling + + + + -O, --save-option <group>/<setting>=<value> + -O, --save-option <groep>/<instelling>=<waarde> + + + + Run application saving this value for this setting + Applicatie uitvoeren met waarde voor deze instelling permanent opgeslagen + + + + -v, --version Display the current version + -v, --version Toon de huidige versie + + + + <database> Open this SQLite database + <database> Open deze SQLite-database + + + + <project> Open this project file (*.sqbpro) + <project> Open dit projectbestand (*.sqbpro) + + + + The -s/--sql option requires an argument + De -s/--sql optie vereist een argument + + + + The file %1 does not exist + Het bestand %1 bestaat niet + + + + The -t/--table option requires an argument + De -t/--table optie vereist een argument + + + + The -o/--option and -O/--save-option options require an argument in the form group/setting=value + De -o/--option and -O/--save-option opties vereisen een argument in de vorm van groep/instelling=waarde + + + + Invalid option/non-existant file: %1 + Ongeldige optie of niet bestaand bestand: %1 + + + + SQLite Version + SQLite-versie + + + + SQLCipher Version %1 (based on SQLite %2) + SQLCipher-versie %1 (gebaseerd op SQLite %2) + + + + DB Browser for SQLite Version %1. + DB-browser voor SQLite versie %1. + + + + Built for %1, running on %2 + Gebouwd voor %1, draaiend op %2 + + + + Qt Version %1 + Qt-versie %1 + + + + CipherDialog + + + SQLCipher encryption + SQLCipher encryptie + + + + &Password + &Wachtwoord + + + + &Reenter password + Wa&chtwoord herhalen + + + + Passphrase + Toegangsfrase + + + + Raw key + Onbewerkte sleutel + + + + Encr&yption settings + Encr&yptie-instellingen + + + + SQLCipher &3 defaults + SQLCipher &3 standaardwaarden + + + + SQLCipher &4 defaults + SQLCipher &4 standaardwaarden + + + + Custo&m + &Aangepast + + + + Page si&ze + &Paginagrootte + + + + &KDF iterations + KDF &iteraties + + + + HMAC algorithm + &HMAC-algoritme + + + + KDF algorithm + &KDF-algoritme + + + + Plaintext Header Size + Platte-&tekstheadergrootte + + + + Please set a key to encrypt the database. +Note that if you change any of the other, optional, settings you'll need to re-enter them as well every time you open the database file. +Leave the password fields empty to disable the encryption. +The encryption process might take some time and you should have a backup copy of your database! Unsaved changes are applied before modifying the encryption. + Geef een sleutel op om de database mee te versleutelen. +Wees je ervan bewust dat als je een van de andere, optionele, opties wijzigt, je die iedere keer opnieuw moet invoeren als je het databasebestand wilt openen. +Laat wachtwoordvelden leeg om de versleuteling uit te schakelen. +Versleuteling kan wat tijd in beslag nemen en je doet er tevens verstandig aan een backup van je database te hebben! Onopgeslagen wijzigingen worden toegepast voordat de versleuteling aangepast wordt. + + + + Please enter the key used to encrypt the database. +If any of the other settings were altered for this database file you need to provide this information as well. + Voer de sleutel in waarmee database is versleuteld. +Indien enige andere opties voor dit databasebestand gewijzigd waren dan dien je die gegevens hier nu ook opnieuw in te voeren. + + + + ColumnDisplayFormatDialog + + + Choose display format + Kies een opmaak + + + + Display format + Opmaak + + + + Choose a display format for the column '%1' which is applied to each value prior to showing it. + Kies een opmaak voor de kolom '%1' die op iedere waarde wordt toegepast voordat deze getoond wordt. + + + + Default + Standaard + + + + Decimal number + Decimaal getal + + + + Exponent notation + Wetenschappelijke E-notatie + + + + Hex blob + Hexadecimale blob + + + + Hex number + Hexadecimaal getal + + + + Octal number + Octaal getal + + + + Round number + Afgerond getal + + + + Apple NSDate to date + Apple NSDate naar datum + + + + Java epoch (milliseconds) to date + Java-epoch (milliseconden) naar datum + + + + .NET DateTime.Ticks to date + .NET DateTime.Ticks naar datum + + + + Julian day to date + Juliaanse dag naar datum + + + + Unix epoch to date + Unix-epoch naar datum + + + + Unix epoch to local time + Unix-epoch naar lokale tijd + + + + Windows DATE to date + Windows DATE naar datum + + + + Date as dd/mm/yyyy + Datum als dd/mm/jjjj + + + + Lower case + onderkast + + + + Upper case + BOVENKAST + + + + Custom + Aangepast + + + + Custom display format must contain a function call applied to %1 + Aangepaste opmaak moet bestaan uit een functie-aanroep die toegepast wordt op %1 + + + + Error in custom display format. Message from database engine: + +%1 + Fout in de aangepaste opmaak. Melding van de database: + +%1 + + + + Custom display format must return only one column but it returned %1. + Aangepaste opmaak moet slechts één kolom retourneren, maar retourneerde er %1. + + + + CondFormatManager + + + Conditional Format Manager + Voorwaardelijke-opmaakbeheerder + + + + This dialog allows creating and editing conditional formats. Each cell style will be selected by the first accomplished condition for that cell data. Conditional formats can be moved up and down, where those at higher rows take precedence over those at lower. Syntax for conditions is the same as for filters and an empty condition applies to all values. + Dit dialoogvenster stelt je in staat om voorwaardelijke opmaakregels te creëren en te bewerken. Iedere celstijl zal worden geselecteerd op basis van de eerst vervulde voorwaarde voor diens celwaarde. De voorwaardelijke opmaakregels kunnen omhoog en omlaag verplaatst worden. Hoger geplaatste regels hebben hogere prioriteit. De syntaxis voor de voorwaarden in dezelfde als voor filters en een lege voorwaarde wordt toegepast op alle waarden. + + + + Add new conditional format + Nieuwe voorwaardelijke-opmaakregel toevoegen + + + + &Add + &Toevoegen + + + + Remove selected conditional format + Verwijder de geselecteerde voorwaardelijke-opmaakregel + + + + &Remove + &Verwijderen + + + + Move selected conditional format up + Verplaats de geselecteerde voorwaardelijke-opmaakregel omhoog + + + + Move &up + Om&hoog verplaatsen + + + + Move selected conditional format down + Verplaats de geselecteerde voorwaardelijke-opmaakregel omlaag + + + + Move &down + Om&laag verplaatsen + + + + Foreground + Voorgrond + + + + Text color + Tekstkleur + + + + Background + Achtergrond + + + + Background color + Achtergrondkleur + + + + Font + Lettertype + + + + Size + Grootte + + + + Bold + Vet + + + + Italic + Cursief + + + + Underline + Onderstreept + + + + Alignment + Uitlijning + + + + Condition + Voorwaarde + + + + + Click to select color + Klik om een kleur te selecteren + + + + Are you sure you want to clear all the conditional formats of this field? + Weet je zeker dat je alle voorwaardelijke-opmaakregels voor dit veld wilt verwijderen? + + + + DBBrowserDB + + + This database has already been attached. Its schema name is '%1'. + Deze database is al gekoppeld. Diens schemanaam is '%1'. + + + + Please specify the database name under which you want to access the attached database + Geef de databasenaam zoals je de gekoppelde database wilt benaderen + + + + Invalid file format + Ongeldig bestandsformaat + + + + Do you really want to close this temporary database? All data will be lost. + Weet je zeker dat je deze tijdelijke database wilt sluiten? Alle gegevens zullen verloren gaan. + + + + Do you want to save the changes made to the database file %1? + Wil je de wijzigingen opslaan die je de gemaakt hebt voor database %1? + + + + Database didn't close correctly, probably still busy + Database is niet goed afgesloten; waarschijnlijk nog steeds bezig + + + + The database is currently busy: + De database is momenteel bezig: + + + + Do you want to abort that other operation? + Wil je die andere handeling afbreken? + + + + Exporting database to SQL file... + Database wordt geëxporteerd naar SQL-bestand... + + + + + Cancel + Annuleren + + + + + No database file opened + Er is geen databasebestand open + + + + Executing SQL... + SQL wordt uitgevoerd... + + + + Action cancelled. + Handeling geannuleerd. + + + + + Error in statement #%1: %2. +Aborting execution%3. + Fout in instructie #%1: %2. +Uitvoering wordt afgebroken%3. + + + + + and rolling back + en teruggedraaid + + + + didn't receive any output from %1 + Geen uitvoer ontvangen van %1 + + + + could not execute command: %1 + kon opdracht niet uitvoeren: %1 + + + + Cannot delete this object + Kan dit object niet verwijderen + + + + Cannot set data on this object + Kan de gegevens niet toepassen op dit object + + + + + A table with the name '%1' already exists in schema '%2'. + Er bestaat al een tabel met de naam '%1' in schema '%2'. + + + + No table with name '%1' exists in schema '%2'. + Er bestaat geen tabel met de naam '%1' in schema '%2'. + + + + + Cannot find column %1. + Kan kolom %1 niet vinden. + + + + Creating savepoint failed. DB says: %1 + Het maken van een herstelpunt is niet gelukt. Melding van de database: %1 + + + + Renaming the column failed. DB says: +%1 + Het hernoemen van de kolom is niet gelukt. Melding van de database: %1 + + + + + Releasing savepoint failed. DB says: %1 + Het opheffen van een herstelpunt is niet gelukt. Melding van de database: %1 + + + + Creating new table failed. DB says: %1 + Het maken van de nieuwe tabel is niet gelukt. Melding van de database: %1 + + + + Copying data to new table failed. DB says: +%1 + Het kopiëren van de gegevens naar de nieuwe tabel is niet gelukt. Melding van de database: %1 + + + + Deleting old table failed. DB says: %1 + Het verwijderen van de oude tabel is niet gelukt. Melding van de database: %1 + + + + Restoring some of the objects associated with this table failed. This is most likely because some column names changed. Here's the SQL statement which you might want to fix and execute manually: + + + Fout bij het het herstellen van sommige objecten die met deze tabel geassocieerd zijn. Dit gebeurde hoogstwaarschijnlijk omdat kolomnamen gewijzigd zijn. Dit is de SQL-instructie die je wellicht aan wilt passen om het nogmaals mee te proberen: + + + + + + Error renaming table '%1' to '%2'. +Message from database engine: +%3 + Fout bij het hernoemen van tabel '%1' naar '%2'. +Melding van de database: +%3 + + + + could not get list of db objects: %1 + Fout bij het verkrijgen van lijst met database-objecten: %1 + + + + could not get list of databases: %1 + Fout bij het verkrijgen van lijst met databases: %1 + + + + Error setting pragma %1 to %2: %3 + Fout bij het omzetten van pragma %1 naar %2: %3 + + + + File not found. + Bestand niet gevonden. + + + + Error loading extension: %1 + Fout bij het laden van extensie: %1 + + + + could not get column information + Fout bij het verkrijgen van kolominformatie + + + + DbStructureModel + + + Name + Naam + + + + Object + Object + + + + Type + Type + + + + Schema + Schema + + + + Database + Database + + + + Browsables + Doorbladerbare + + + + All + Alle + + + + Temporary + Tijdelijke + + + + Tables (%1) + Tabellen (%1) + + + + Indices (%1) + Indices (%1) + + + + Views (%1) + Views (%1) + + + + Triggers (%1) + Triggers (%1) + + + + EditDialog + + + Edit database cell + Databasecel bewerken + + + + This area displays information about the data present in this database cell + Dit gebied toont informatie over de aanwezige gegevens in de databasecel + + + + Mode: + Modus: + + + + This is the list of supported modes for the cell editor. Choose a mode for viewing or editing the data of the current cell. + Dit is de lijst van ondersteunde modi voor de celbewerker. Kies een modus om de gegevens van de huidige cel te bekijken of te bewerken. + + + + Text + Tekst + + + + RTL Text + Rechts-naar-linkstekst + + + + Binary + Binair + + + + + Image + Afbeelding + + + + JSON + JSON + + + + XML + XML + + + + + Automatically adjust the editor mode to the loaded data type + De bewerker automatisch aanpassen aan het geladen gegevenstype + + + + This checkable button enables or disables the automatic switching of the editor mode. When a new cell is selected or new data is imported and the automatic switching is enabled, the mode adjusts to the detected data type. You can then change the editor mode manually. If you want to keep this manually switched mode while moving through the cells, switch the button off. + Deze aanvinkbare knop zet het automatisch wisselen van de bewerkingsmodus aan of uit. Wanneer een nieuwe cel wordt geselecteerd of nieuwe gegevens worden geïmporteerd en automatisch wisselen aangevinkt is, dan verandert de modus naar het gedetecteerde gegevenstype. Je kunt de bewerkingsmodus dan alsnog handmatig aanpassen. Vink de knop uit als je handmatig wisselen wilt gebruiken tijdens het navigeren door de cellen. + + + + Auto-switch + Automatisch wisselen + + + + The text editor modes let you edit plain text, as well as JSON or XML data with syntax highlighting, automatic formatting and validation before saving. + +Errors are indicated with a red squiggle underline. + De tekstbewerkingsmodi stellen je in staat om platte tekst te bewerken, maar ook JSON en XML met syntaxiskleuring en automatisch formatteren en validatie voordat je het opslaat. + +Fouten worden aangegeven met rode kronkelige onderstreping. + + + + This Qt editor is used for right-to-left scripts, which are not supported by the default Text editor. The presence of right-to-left characters is detected and this editor mode is automatically selected. + Deze Qt-bewerker wordt voor rechts-naar-linksteksten gebruikt, omdat dit niet ondersteund wordt door de standaard tekstbewerker. Er werden rechts-naar-linkstekens gedetecteerd en daarom is deze bewerkingsmodus automatisch geselecteerd. + + + + Type of data currently in cell + Het gegevenstype van de huidige gegevens in de cel + + + + Size of data currently in table + De grootte van de huidige gegevens in de tabel + + + + Apply data to cell + Gegevens toepassen op cel + + + + This button saves the changes performed in the cell editor to the database cell. + Deze knop slaat de wijzigingen die aangebracht zijn in de celbewerker op in de cel. + + + + Apply + Toepassen + + + + + Print... + Afdrukken... + + + + Open preview dialog for printing displayed image + Open voorvertoningsdialoogvenster om getoonde afbeelding af te drukken + + + + Open preview dialog for printing displayed text + Open voorvertoningsdialoogvenster om getoonde tekst af te drukken + + + + Open preview dialog for printing the data currently stored in the cell + Opent een voorvertoningsdialoogvenster voor het afdrukken van de de huidige gegevens in de cel + + + + + Ctrl+P + + + + + Copy Hex and ASCII + HEX en ASCII kopiëren + + + + Copy selected hexadecimal and ASCII columns to the clipboard + De geselecteerde hexadecimale en ASCII kolommen kopiëren naar het klembord + + + + Ctrl+Shift+C + + + + + Autoformat + Auto-opmaak + + + + Auto-format: pretty print on loading, compact on saving. + Auto-opmaak: mooi opmaken bij het laden, comprimeren bij het opslaan. + + + + When enabled, the auto-format feature formats the data on loading, breaking the text in lines and indenting it for maximum readability. On data saving, the auto-format feature compacts the data removing end of lines, and unnecessary whitespace. + Indien geselecteerd zal de auto-opmaakfunctie de gegevens bij het laden mooi opmaken, door de tekst op te delen in regels en deze dan in te laten springen. Bij het opslaan zal de auto-opmaakfunctie de gegevens comprimeren door regeleinden en onnodige witruimte te verwijderen. + + + + &Export... + &Exporteren... + + + + Export to file + Naar bestand exporteren + + + + Opens a file dialog used to export the contents of this database cell to a file. + Opent een bestandsdialoogvenster om de inhoud van deze databasecel naar een bestand te exporteren. + + + + + &Import... + &Importeren... + + + + + Import from file + Uit bestand importeren + + + + + Opens a file dialog used to import any kind of data to this database cell. + Opent een bestandsdialoogvenster om gegevens van een willekeurig gegevenstype naar deze databasecel te importeren. + + + + Set as &NULL + Omzetten naar &NULL + + + + Erases the contents of the cell + Wist de inhoud van de cel + + + + Word Wrap + Woordterugloop + + + + Wrap lines on word boundaries + Past regelterugloop toe op woordbegrenzingen + + + + + Open in default application or browser + In standaard applicatie of browser openen + + + + Open in application + In applicatie openen + + + + The value is interpreted as a file or URL and opened in the default application or web browser. + De waarde wordt geïnterpreteerd als bestand of URL en wordt geopend in de standaard applicatie of webbrower. + + + + Save file reference... + Bestandsreferentie opslaan... + + + + Save reference to file + Referentie in bestand opslaan + + + + + Open in external application + In externe applicatie openen + + + + + Image data can't be viewed in this mode. + Afbeeldingsgegevens kunnen niet worden getoond in deze modus. + + + + + Try switching to Image or Binary mode. + Probeer te wisselen naar Afbeeldings- of Binaire modus. + + + + + Binary data can't be viewed in this mode. + Binaire gegevens kunnen niet worden getoond in deze modus. + + + + + Try switching to Binary mode. + Probeer te wisselen naar Binaire modus. + + + + + Image files (%1) + Afbeeldingbestanden (%1) + + + + Choose a file to import + Kies een bestand om te importeren + + + + %1 Image + %1 Afbeelding + + + + Binary files (*.bin) + Binaire bestanden (*.bin) + + + + Choose a filename to export data + Kies een bestandsnaam om naar te exporteren + + + + Invalid data for this mode + Ongeldige gegevens voor deze modus + + + + The cell contains invalid %1 data. Reason: %2. Do you really want to apply it to the cell? + De cel bevat ongeldige %1 gegevens. Reden: %2. Weet je zeker dat je het op de cel wilt toepassen? + + + + + Type of data currently in cell: Text / Numeric + Gegevenstype van de huidige gegevens in de cel: tekst / numeriek + + + + + + %n character(s) + + %n teken + %n tekens + + + + + Type of data currently in cell: %1 Image + Gegevenstype van de huidige gegevens in de cel: %1 afbeelding + + + + %1x%2 pixel(s) + %1x%2 pixel(s) + + + + Type of data currently in cell: NULL + Gegevenstype van de huidige gegevens in de cel: NULL + + + + + %n byte(s) + + %n byte + %n bytes + + + + + Type of data currently in cell: Valid JSON + Gegevenstype van de huidige gegevens in de cel: geldige JSON + + + + Type of data currently in cell: Binary + Gegevenstype van de huidige gegevens in de cel: binair + + + + Couldn't save file: %1. + Kon het bestand niet opslaan: %1. + + + + The data has been saved to a temporary file and has been opened with the default application. You can now edit the file and, when you are ready, apply the saved new data to the cell editor or cancel any changes. + De gegevens zijn in een tijdelijk bestand opgeslagen en is geopend in de standaard applicatie. Je kunt het bestand nu bewerken en, wanneer je klaar bent, de opgeslagen nieuwe gegevens toepassen op de cel of de wijzingen annuleren. + + + + EditIndexDialog + + + Edit Index Schema + Schema-index bewerken + + + + &Name + &Naam + + + + &Table + &Tabel + + + + &Unique + &Uniek + + + + For restricting the index to only a part of the table you can specify a WHERE clause here that selects the part of the table that should be indexed + Om de index slechts op een gedeelte van de tabel toe te passen kun je hier een WHERE clausule opgeven die slechts dát gedeelte van de tabel selecteert dat geïndexeerd dient te worden + + + + Partial inde&x clause + Gedeeltelijke inde&x-clausule + + + + Colu&mns + &Kolommen + + + + Table column + Tabelkolom + + + + Type + Type + + + + Add a new expression column to the index. Expression columns contain SQL expression rather than column names. + Voeg een nieuwe expressiekolom toe aan de index. Expressiekolommen bevatten SQL-expressies in plaats van kolomnamen. + + + + Index column + Indexkolom + + + + Order + Sortering + + + + Deleting the old index failed: +%1 + Het verwijderen van de oude index is mislukt: +%1 + + + + Creating the index failed: +%1 + Het maken van de index is mislukt: +%1 + + + + EditTableDialog + + + Edit table definition + Tabeldefinitie bewerken + + + + Table + Tabel + + + + Advanced + Geavanceerd + + + + Database sche&ma + Database&schema + + + + Without Rowid + Zonder &rowid + + + + Make this a 'WITHOUT rowid' table. Setting this flag requires a field of type INTEGER with the primary key flag set and the auto increment flag unset. + Maak van deze tabel een 'WITHOUT rowid'-tabel. Om deze optie toe te kunnen passen is een primair sleutelveld van het type INTEGER nodig, waarop geen automatische ophoging wordt toegepast. + + + + Fields + Velden + + + + Add + Toevoegen + + + + Remove + Verwijderen + + + + Move to top + Bovenaan plaatsen + + + + Move up + Omhoog verplaatsen + + + + Move down + Omlaag verplaatsen + + + + Move to bottom + Onderaan plaatsen + + + + + Name + Naam + + + + + Type + Type + + + + NN + NN + + + + Not null + Niet NULL + + + + PK + PS + + + + Primary key + Primaire sleutel + + + + AI + AO + + + + Autoincrement + Automatisch ophogen + + + + U + U + + + + + + Unique + Uniek + + + + Default + Standaard + + + + Default value + Standaardwaarde + + + + + + Check + Controle + + + + Check constraint + Controlebeperking + + + + Collation + Collatie + + + + + + Foreign Key + Vreemde sleutel + + + + Constraints + Beperkingen + + + + Add constraint + Beperking toevoegen + + + + Remove constraint + Beperking verwijderen + + + + Columns + Kolommen + + + + SQL + SQL + + + + <html><head/><body><p><span style=" font-weight:600; color:#ff0000;">Warning: </span>There is something with this table definition that our parser doesn't fully understand. Modifying and saving this table might result in problems.</p></body></html> + <html><head/><body><p><span style=" font-weight:600; color:#ff0000;">Waarschuwing: </span>Er is iets aan deze tabeldefinitie dat onze parser niet volledig begrijpt. Het aanpassen en opslaan van deze tabel kan problemen opleveren.</p></body></html> + + + + + Primary Key + Primaire sleutel + + + + Add a primary key constraint + Voeg een primaire sleutelbeperking toe + + + + Add a foreign key constraint + Voeg een vreemde sleutelbeperking toe + + + + Add a unique constraint + Voeg een uniciteitsbeperking toe + + + + Add a check constraint + Voeg een controlebeperking toe + + + + + There can only be one primary key for each table. Please modify the existing primary key instead. + Er kan maar een primairesleutel per tabel bestaan. Pas in plaats daarvan de al bestaande primaire sleutel aan. + + + + Error creating table. Message from database engine: +%1 + Fout bij maken van de tabel. Melding van de database: +%1 + + + + There already is a field with that name. Please rename it first or choose a different name for this field. + Er bestaat al een veld met die naam. Hernoem dat veld eerst of kies een andere naam voor dit veld. + + + + This column is referenced in a foreign key in table %1 and thus its name cannot be changed. + Naar deze kolom wordt verwezen in een vreemde sleutel in tabel %1 en kan daarom niet aangepast worden. + + + + There is at least one row with this field set to NULL. This makes it impossible to set this flag. Please change the table data first. + Er is tenminste een record waarin de waarde van dit veld NULL is. Dit maakt het onmogelijk om deze optie toe te passen. Pas de tabelgegevens eerst aan. + + + + There is at least one row with a non-integer value in this field. This makes it impossible to set the AI flag. Please change the table data first. + Er is tenminste een record waarin de waarde van dit veld geen geheel getal is. Dit maakt het onmogelijk om de AO-optie toe te passen. Pas de tabelgegevens eerst aan. + + + + Column '%1' has duplicate data. + + Kolom '%1' heeft gedupliceerde waarden. + + + + + This makes it impossible to enable the 'Unique' flag. Please remove the duplicate data, which will allow the 'Unique' flag to then be enabled. + Dit maakt het onmogelijk om de Uniek-optie toe te passen. Verwijder eerst de gedupliceerde waarden, zodat de Uniek-optie toe kan worden gepast. + + + + Are you sure you want to delete the field '%1'? +All data currently stored in this field will be lost. + Weet je zeker dat je het veld '%1' wilt verwijderen? +Alle waarden die momenteel opgeslagen zijn in dit veld zullen verloren gaan. + + + + Please add a field which meets the following criteria before setting the without rowid flag: + - Primary key flag set + - Auto increment disabled + Voeg eerste een veld toe dat aan de volgende criteria voldoet, voordat je de 'Zonder rowid' optie toepast: + - Primaire sleutel ingeschakeld + - Automatisch ophogen uitgeschakeld + + + + ExportDataDialog + + + Export data as CSV + Gegevens exporteren als CSV + + + + Tab&le(s) + &Tabel(-len) + + + + Colu&mn names in first line + &Kolomnamen op eerste regel + + + + Fie&ld separator + &Veldscheidingsteken + + + + , + , + + + + ; + ; + + + + Tab + Tab + + + + | + | + + + + + + Other + Anders + + + + &Quote character + &Scheidingsteken tekenreeks + + + + " + " + + + + ' + ' + + + + New line characters + Nieuwe-regeltekens + + + + Windows: CR+LF (\r\n) + Windows: CR+LF (\r\n) + + + + Unix: LF (\n) + Unix: LF (\n) + + + + Pretty print + Mooi opmaken + + + + Export data as JSON + Exporteer de gegevens als JSON + + + + exporting CSV + CSV wordt geëxporteerd + + + + + Could not open output file: %1 + Kon het uitvoerbestand niet openen: %1 + + + + exporting JSON + JSON wordt geëxporteerd + + + + + Choose a filename to export data + Kies een bestandsnaam om naar te exporteren + + + + Please select at least 1 table. + Selecteerd tenminste één tabel. + + + + Choose a directory + Kies een map + + + + Export completed. + Het exporteren is voltooid. + + + + ExportSqlDialog + + + Export SQL... + SQL exporteren... + + + + Tab&le(s) + &Tabel(-len) + + + + Select All + Alles selecteren + + + + Deselect All + Alles deselecteren + + + + &Options + &Opties + + + + Keep column names in INSERT INTO + Kolomnamen behouden in INSERT INTO + + + + Multiple rows (VALUES) per INSERT statement + Meervoudige records (VALUES) per INSERT-instructie + + + + Export everything + Alles exporteren + + + + Export schema only + Alleen het schema exporteren + + + + Export data only + Alleen de gegevens exporteren + + + + Keep old schema (CREATE TABLE IF NOT EXISTS) + Ouder schema behouden (CREATE TABLE IF NOT EXISTS) + + + + Overwrite old schema (DROP TABLE, then CREATE TABLE) + Ouder schema overschrijven (DROP TABLE, daarna CREATE TABLE) + + + + Please select at least one table. + Selecteer tenminste één tabel. + + + + Choose a filename to export + Kies een bestandsnaam om naar te exporteren + + + + Export completed. + Het exporteren is voltooid. + + + + Export cancelled or failed. + Het exporteren is geannuleerd of niet gelukt. + + + + ExtendedScintilla + + + + Ctrl+H + + + + + Ctrl+F + + + + + + Ctrl+P + + + + + Find... + Zoeken... + + + + Find and Replace... + Zoeken en Vervangen... + + + + Print... + Afdrukken... + + + + ExtendedTableWidget + + + Use as Exact Filter + Als exact filter gebruiken + + + + Containing + Bevat + + + + Not containing + Bevat niet + + + + Not equal to + Niet gelijk aan + + + + Greater than + Groter dan + + + + Less than + Kleiner dan + + + + Greater or equal + Groter dan of gelijk aan + + + + Less or equal + Kleiner dan of gelijk aan + + + + Between this and... + Binnen het bereik van dit en... + + + + Regular expression + Als reguliere expressie + + + + Edit Conditional Formats... + Voorwaardelijke opmaakregels bewerken... + + + + Set to NULL + Omzetten naar NULL + + + + Copy + Kopiëren + + + + Copy with Headers + Kopiëren met kolomnamen + + + + Copy as SQL + Kopiëren als SQL + + + + Paste + Plakken + + + + Print... + Afdrukken... + + + + Use in Filter Expression + Gebruiken in filterexpressie + + + + Alt+Del + + + + + Ctrl+Shift+C + + + + + Ctrl+Alt+C + + + + + The content of the clipboard is bigger than the range selected. +Do you want to insert it anyway? + De inhoud van het klembord is groter dan het geselecteerde bereik. +Wil je het desondanks invoegen? + + + + <p>Not all data has been loaded. <b>Do you want to load all data before selecting all the rows?</b><p><p>Answering <b>No</b> means that no more data will be loaded and the selection will not be performed.<br/>Answering <b>Yes</b> might take some time while the data is loaded but the selection will be complete.</p>Warning: Loading all the data might require a great amount of memory for big tables. + <p>Niet alle gegevens zijn geladen. <b>Wil je alle gegevens laden voordat alle records geselecteerd worden?</b><p><p> <b>Nee</b> betekent dat gegevens laden gestopt wordt en de selectie niet toegepast zal worden.<br/> <b>Ja</b> betekent dat het een tijd kan duren totdat alle gegevens geladen zijn, maar de selectie wel toegepast zal worden.</p>Waarschuwing: Alle gegevens laden kan een grote hoeveelheid werkgeheugen vereisen voor grote tabellen. + + + + Cannot set selection to NULL. Column %1 has a NOT NULL constraint. + Kan de selectie niet omzetten naar NULL. Kolom %1 heeft een NIET NULL-beperking. + + + + FileExtensionManager + + + File Extension Manager + Bestandsextensiebeheerder + + + + &Up + Om&hoog + + + + &Down + Om&laag + + + + &Add + &Toevoegen + + + + &Remove + &Verwijderen + + + + + Description + Omschrijving + + + + Extensions + Extensies + + + + *.extension + *.extensie + + + + FilterLineEdit + + + Filter + Filter + + + + These input fields allow you to perform quick filters in the currently selected table. +By default, the rows containing the input text are filtered out. +The following operators are also supported: +% Wildcard +> Greater than +< Less than +>= Equal to or greater +<= Equal to or less += Equal to: exact match +<> Unequal: exact inverse match +x~y Range: values between x and y +/regexp/ Values matching the regular expression + Deze invoervelden stellen je in staat om snelfilters toe te passen op de huidig geselecteerde tabel. +Gewoonlijk worden records die de ingevoerde tekst bevatten gefilterd. +De volgende operatoren worden ook ondersteund: +% Jokerteken +> Groter dan +< Kleiner dan +>= Groter dan of gelijk aan +<= Kleiner dan of gelijk aan += Gelijk aan: exacte overeenkomst +<> Niet gelijk aan: inverse van exacte overeenkomst +x~y Bereik: waarden tussen x en y +/regexp/ Waarden die voldoen aan de reguliere expressie + + + + Set Filter Expression + Filterexpressie toepassen + + + + What's This? + Wat is dit? + + + + Is NULL + Is NULL + + + + Is not NULL + Is niet NULL + + + + Is empty + Is leeg + + + + Is not empty + Is niet leeg + + + + Not containing... + Bevat niet... + + + + Equal to... + Gelijk aan... + + + + Not equal to... + Niet gelijk aan... + + + + Greater than... + Groter dan... + + + + Less than... + Kleiner dan... + + + + Greater or equal... + Groter dan of gelijk aan... + + + + Less or equal... + Kleiner dan of gelijk aan... + + + + In range... + Binnen het bereik... + + + + Regular expression... + Reguliere expressie... + + + + Clear All Conditional Formats + Verwijder alle voorwaardelijke opmaakregels + + + + Use for Conditional Format + Gebruiken voor voorwaardelijke opmaak + + + + Edit Conditional Formats... + Voorwaardelijke opmaakregels bewerken... + + + + FindReplaceDialog + + + Find and Replace + Zoeken en vervangen + + + + Fi&nd text: + Zoek &tekst: + + + + Re&place with: + Vervang &door: + + + + Match &exact case + Identieke onder-/boven&kast + + + + Match &only whole words + Alleen &hele woorden + + + + When enabled, the search continues from the other end when it reaches one end of the page + Indien geselecteerd zal het zoeken aan het andere einde doorgaan zodra een einde bereikt is + + + + &Wrap around + Door&gaan na einde + + + + When set, the search goes backwards from cursor position, otherwise it goes forward + Indien geselecteerd zal, ten opzichte van de cursorpositie, achteruit in plaats van vooruit gezocht worden + + + + Search &backwards + &Omgekeerd zoeken + + + + <html><head/><body><p>When checked, the pattern to find is searched only in the current selection.</p></body></html> + <html><head/><body><p>Indien geselecteerd wordt alleen gezocht in de huidige selectie.</p></body></html> + + + + &Selection only + Alleen in &selectie + + + + <html><head/><body><p>When checked, the pattern to find is interpreted as a UNIX regular expression. See <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>.</p></body></html> + <html><head/><body><p>Indien geselecteerd wordt de zoekterm geïnterpreteerd als een UNIX reguliere expressie. Zie hiervoor <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Reguliere Expressies in Wikibooks (Engels)</a>.</p></body></html> + + + + Use regular e&xpressions + Gebruik reguliere e&xpressies + + + + Find the next occurrence from the cursor position and in the direction set by "Search backwards" + Zoek de eerstvolgende overeenkomst vanaf de cursorpositie, in de richting aangegeven door de optie "Omgekeerd zoeken" + + + + &Find Next + Volgende &zoeken + + + + F3 + + + + + &Replace + &Vervangen + + + + Highlight all the occurrences of the text in the page + Markeer alle overeenkomsten met de tekst in de pagina + + + + F&ind All + Alles z&oeken + + + + Replace all the occurrences of the text in the page + Vervang alle overeenkomsten met de tekst in de pagina + + + + Replace &All + Alles v&ervangen + + + + The searched text was not found + De gezochte tekst is niet gevonden + + + + The searched text was not found. + De gezochte tekst is niet gevonden. + + + + The searched text was replaced one time. + De gezochte tekst is één keer vervangen. + + + + The searched text was found one time. + De gezochte tekst is één keer gevonden. + + + + The searched text was replaced %1 times. + De gezochte tekst is %1 keer vervangen. + + + + The searched text was found %1 times. + De gezochte tekst is %1 keer gevonden. + + + + ForeignKeyEditor + + + &Reset + &Herstellen + + + + Foreign key clauses (ON UPDATE, ON DELETE etc.) + Vreemde-sleutelclausules (ON UPDATE, ON DELETE, etc.) + + + + ImportCsvDialog + + + Import CSV file + CSV-bestand importeren + + + + Table na&me + &Tabelnaam + + + + &Column names in first line + &Kolomnamen op eerste regel + + + + Field &separator + &Veldscheidingsteken + + + + , + , + + + + ; + ; + + + + + Tab + Tab + + + + | + | + + + + + Other (printable) + Anders (afdrukbaar) + + + + + Other (code) + Anders (code) + + + + &Quote character + &Scheidingsteken tekenreeks + + + + " + " + + + + ' + ' + + + + &Encoding + &Encodering + + + + UTF-8 + UTF-8 + + + + UTF-16 + UTF-16 + + + + ISO-8859-1 + ISO-8859-1 + + + + Other + Anders + + + + Trim fields? + Velden trimmen? + + + + Separate tables + Tabellen scheiden + + + + Advanced + Geavanceerd + + + + When importing an empty value from the CSV file into an existing table with a default value for this column, that default value is inserted. Activate this option to insert an empty value instead. + Indien geselecteerd dan wordt een lege waarde in plaats van de standaardwaarde ingevoerd voor bestaande tabellen die een standaardwaarde hebben voor deze kolom. + + + + Ignore default &values + &Negeer standaardwaarden + + + + Activate this option to stop the import when trying to import an empty value into a NOT NULL column without a default value. + Indien geselecteerd dan wordt het importeren afgebroken zodra een lege waarde wordt geprobeerd in te voeren in een NIET NULL veld die geen standaardwaarde kent. + + + + Fail on missing values + Afbreken bij afwezige waarden + + + + Disable data type detection + Gegevenstypedetectie uitschakelen + + + + Disable the automatic data type detection when creating a new table. + Schakel automatische gegevenstypedetectie uit als een nieuwe tabel wordt gemaakt. + + + + When importing into an existing table with a primary key, unique constraints or a unique index there is a chance for a conflict. This option allows you to select a strategy for that case: By default the import is aborted and rolled back but you can also choose to ignore and not import conflicting rows or to replace the existing row in the table. + Tijdens het importeren in bestaande tabellen kunnen er conflicten optreden met primaire sleutels, unieke beperkingen en unieke indices. Deze instelling geeft je de keuze om daar een strategie voor te kiezen: standaard wordt het importeren afgebroken en teruggedraaid, maar je kunt ook kiezen om conflicterende records te negeren en dus niet te importeren, of om bestaande records te laten overschrijven door geïmporteerde records. + + + + Abort import + Importeren afbreken + + + + Ignore row + Record negeren + + + + Replace existing row + Bestaand record vervangen + + + + Conflict strategy + Conflictstrategie + + + + + Deselect All + Alles deselecteren + + + + Match Similar + Overeenkomende selecteren + + + + Select All + Alles selecteren + + + + There is already a table named '%1' and an import into an existing table is only possible if the number of columns match. + Er bestaat al een tabel met de naam '%1' en importeren in een al bestaande tabel is alleen mogelijk als het aantal kolommen overeenkomt. + + + + There is already a table named '%1'. Do you want to import the data into it? + Er bestaat al een tabel met de naam '%1'. Wil je de gegevens hierin importeren? + + + + Creating restore point failed: %1 + Maken van een herstelpunt is mislukt: %1 + + + + Creating the table failed: %1 + Maken van de tabel is mislukt: %1 + + + + importing CSV + CSV wordt geïmporteerd + + + + Inserting row failed: %1 + Invoegen van record is mislukt: %1 + + + + Importing the file '%1' took %2ms. Of this %3ms were spent in the row function. + Het importeren van het bestand '%1' duurde %2ms. Hiervan werd %3ms gebruikt voor de rijfunctie. + + + + MainWindow + + + DB Browser for SQLite + DB-browser voor SQLite + + + + + Database Structure + This has to be equal to the tab title in all the main tabs + Databasestructuur + + + + This is the structure of the opened database. +You can drag SQL statements from an object row and drop them into other applications or into another instance of 'DB Browser for SQLite'. + + Dit is de structuur van de geopende database. +Je kunt SQL-instructies vanuit een objectrij naar andere applicaties of andere vensters van 'DB-browser voor SQLite' verslepen. + + + + + + Browse Data + This has to be equal to the tab title in all the main tabs + Gegevensbrowser + + + + + Edit Pragmas + This has to be equal to the tab title in all the main tabs + Pragma's bewerken + + + + Warning: this pragma is not readable and this value has been inferred. Writing the pragma might overwrite a redefined LIKE provided by an SQLite extension. + Waarschuwing: dit pragma kan niet uitgelezen worden en de waarde is daarom afgeleid. Dit pragma wijzigen kan ervoor zorgen dat een door een SQLite-extensie hergedefinieerde LIKE overschreven wordt. + + + + + Execute SQL + This has to be equal to the tab title in all the main tabs + SQL uitvoeren + + + + toolBar1 + werkbalk1 + + + + &File + &Bestand + + + + &Import + &Importeren + + + + &Export + &Exporteren + + + + &Edit + Be&werken + + + + &View + Bee&ld + + + + &Help + &Help + + + + &Tools + E&xtra + + + + DB Toolbar + Databasewerkbalk + + + + Edit Database &Cell + Database&cel bewerken + + + + SQL &Log + SQL-&log + + + + Show S&QL submitted by + Toon S&QL van + + + + User + Gebruiker + + + + Application + Applicatie + + + + Error Log + Foutenlog + + + + This button clears the contents of the SQL logs + Deze knop leegt de inhoud van de SQL-logs + + + + &Clear + &Legen + + + + This panel lets you examine a log of all SQL commands issued by the application or by yourself + In dit kader kun je de logs inspecteren van alle SQL-opdrachten die door de applicatie of door jezelf zijn uitgevoerd + + + + &Plot + &Plot + + + + DB Sche&ma + Databasesche&ma + + + + This is the structure of the opened database. +You can drag multiple object names from the Name column and drop them into the SQL editor and you can adjust the properties of the dropped names using the context menu. This would help you in composing SQL statements. +You can drag SQL statements from the Schema column and drop them into the SQL editor or into other applications. + + Dit is de structuur van de geopende database. +Je kunt meerdere objectnamen vanuit de Naam-kolom naar de SQL-bewerker verslepen en je kunt hun eigenschappen dan bewerken met behulp van contextmenu's. Dit vergemakkelijkt het opstellen van SQL-instructies. +Je kunt SQL-instructies vanuit de Schema-kolom naar de SQL-bewerker of naar andere applicaties verslepen. + + + + + &Remote + Toegang op &afstand + + + + + Project Toolbar + Projectwerkbalk + + + + Extra DB toolbar + Werkbalk voor gekoppelde databases + + + + + + Close the current database file + Sluit het huidige databasebestand + + + + &New Database... + &Nieuwe database... + + + + + Create a new database file + Maak een nieuw databasebestand + + + + This option is used to create a new database file. + Deze optie wordt gebruikt om een nieuw databasebestand te maken. + + + + Ctrl+N + + + + + + &Open Database... + &Database openen... + + + + + + + + Open an existing database file + Een bestaand databasebestand openen + + + + + + This option is used to open an existing database file. + Deze optie wordt gebruikt om een bestaand databasebestand te openen. + + + + Ctrl+O + + + + + &Close Database + Database &sluiten + + + + This button closes the connection to the currently open database file + Deze knop verbreekt de verbinding met het huidig geopende databasebestand + + + + Ctrl+F4 + + + + + &Revert Changes + Wijzigingen &terugdraaien + + + + + Revert database to last saved state + Database terugdraaien naar de laatst opgeslagen staat + + + + This option is used to revert the current database file to its last saved state. All changes made since the last save operation are lost. + Deze optie wordt gebruikt om het huidig geopende databasebestand terug te draaien naar de laatst opgeslagen staat. Alle wijzigingen die gemaakt zijn sinds de laatste opslag gaan verloren. + + + + &Write Changes + &Wijzigingen opslaan + + + + + Write changes to the database file + Wijzigingen opslaan in het databasebestand + + + + This option is used to save changes to the database file. + Deze optie wordt gebruikt om wijzigingen op te slaan in het databasebestand. + + + + Ctrl+S + + + + + Compact &Database... + &Database comprimeren... + + + + Compact the database file, removing space wasted by deleted records + Comprimeer het databasebestand door lege ruimte van verwijderde records te op te schonen + + + + + Compact the database file, removing space wasted by deleted records. + Comprimeer het databasebestand door lege ruimte van verwijderde records te op te schonen. + + + + E&xit + A&fsluiten + + + + Ctrl+Q + + + + + &Database from SQL file... + &Database vanuit SQL-bestand... + + + + Import data from an .sql dump text file into a new or existing database. + Importeer gegevens vanuit een .sql dump tekstbestand naar een nieuwe of bestaande database. + + + + This option lets you import data from an .sql dump text file into a new or existing database. SQL dump files can be created on most database engines, including MySQL and PostgreSQL. + Deze optie stelt je in staat om gegevens vanuit een .sql dump tekstbestand te importeren naar een nieuwe of bestaande database. De meeste databaseprogramma's kunnen SQL-dumpbestanden maken, waaronder MySQL en PostgreSQL. + + + + &Table from CSV file... + &Tabel vanuit CSV-bestand... + + + + Open a wizard that lets you import data from a comma separated text file into a database table. + Open een assistent om gegevens uit een kommagescheiden tekstbestand te importeren naar een databasetabel. + + + + Open a wizard that lets you import data from a comma separated text file into a database table. CSV files can be created on most database and spreadsheet applications. + Open een assistent om gegevens uit een kommagescheiden tekstbestand (CSV) te importeren naar een databasetabel. De meeste database- en spreadsheetprogramma's kunnen CSV-bestanden maken. + + + + &Database to SQL file... + &Database naar SQL-bestand... + + + + Export a database to a .sql dump text file. + Exporteer een database naar een .sql dump tekstbestand. + + + + This option lets you export a database to a .sql dump text file. SQL dump files contain all data necessary to recreate the database on most database engines, including MySQL and PostgreSQL. + Deze optie stelt je in staat om een database te exporteren naar een .sql dump tekstbestand. SQL-dumpbestanden bevatten de benodigde gegevens om de database opnieuw te maken in de meeste databaseprogramma's, waaronder MySQL en PostgreSQL. + + + + &Table(s) as CSV file... + &Tabel(-len) naar CSV-bestand... + + + + Export a database table as a comma separated text file. + Exporteer een databasetabel naar een kommagescheiden tekstbestand. + + + + Export a database table as a comma separated text file, ready to be imported into other database or spreadsheet applications. + Exporteer een databasetabel naar een kommagescheiden tekstbestand, om deze te kunnen importeren in ander database- of spreadsheetprogramma. + + + + &Create Table... + Tabel &maken... + + + + Open the Create Table wizard, where it is possible to define the name and fields for a new table in the database + Open de tabel-makenassistent, waarin je namen en velden voor een nieuwe databasetabel kunt definiëren + + + + &Delete Table... + Tabel &verwijderen... + + + + + Delete Table + Tabel verwijderen + + + + Open the Delete Table wizard, where you can select a database table to be dropped. + Open de tabel-verwijderassistent, waarin je databasetabellen kunt selecteren om te verwijderen. + + + + &Modify Table... + Tabel &wijzigen... + + + + Open the Modify Table wizard, where it is possible to rename an existing table. It is also possible to add or delete fields form a table, as well as modify field names and types. + Open de tabel-wijzigingenassistent, waarin je een databasetabel kunt hernoemen. Het is hierin ook mogelijk om velden toe te voegen en te verwijderen en om veldnamen en -typen te wijzigen. + + + + Create &Index... + &Index maken... + + + + Open the Create Index wizard, where it is possible to define a new index on an existing database table. + Open de index-makenassistent, waarin je een nieuwe index voor een bestaande databasetabel kunt definiëren. + + + + &Preferences... + I&nstellingen... + + + + + Open the preferences window. + Open het instellingenvenster. + + + + &DB Toolbar + &Databasewerkbalk + + + + Shows or hides the Database toolbar. + Toont of verbergt de databasewerkbalk. + + + + W&hat's This? + W&at is dit? + + + + Shift+F1 + + + + + &About + &Over + + + + &Recently opened + &Recent geopend + + + + Open &tab + &Tabblad openen + + + + This button opens a new tab for the SQL editor + Deze knop opent een nieuw tabblad in de SQL-bewerker + + + + Ctrl+T + + + + + &Execute SQL + SQL &uitvoeren + + + + Execute all/selected SQL + Voer alle of de geselecteerde SQL uit + + + + This button executes the currently selected SQL statements. If no text is selected, all SQL statements are executed. + Deze knop voert de huidig geselecteerde SQL-instructies uit. Indien geen tekst geselecteerd is worden alle SQL-instructies uitgevoerd. + + + + Ctrl+Return + + + + + Open SQL file(s) + SQL-bestand(-en) openen + + + + This button opens files containing SQL statements and loads them in new editor tabs + Deze knop opent bestanden die SQL-instructies bevatten en laadt deze in nieuwe bewerkerstabbladen + + + + + + Save SQL file + SQL-bestand opslaan + + + + &Load Extension... + Extensie &laden... + + + + + Execute current line + Huidige regel uitvoeren + + + + Execute line + Regel uitvoeren + + + + This button executes the SQL statement present in the current editor line + Deze knop voert de SQL-instructies uit die zich op de huidige bewerkingsregel bevindt + + + + Shift+F5 + + + + + Export as CSV file + Exporteren als CSV-bestand + + + + Export table as comma separated values file + Tabel exporteren als bestand met kommagescheiden waarden + + + + &Wiki + &Wiki + + + + F1 + + + + + Bug &Report... + Bugs &rapporteren... + + + + Feature Re&quest... + Functionaliteit &verzoeken... + + + + Web&site + Web&site + + + + &Donate on Patreon... + &Doneren op Patreon... + + + + Sa&ve Project + P&roject opslaan + + + + + Save the current session to a file + De huidige sessie oplaan in een bestand + + + + This button lets you save all the settings associated to the open DB to a DB Browser for SQLite project file + Deze knop stelt je in staat om alle instellingen met betrekking tot de geopende database op te slaan in een DB-browser voor SQLite-projectbestand + + + + Open &Project... + &Project openen... + + + + + Load a working session from a file + Een sessie laden vanuit een bestand + + + + This button lets you open a DB Browser for SQLite project file + Deze knop stelt je in staat om DB-browser voor SQLite-projectbestand te openen + + + + &Attach Database... + Database &koppelen... + + + + + Add another database file to the current database connection + Koppel nog een databasebestand aan de huidige databaseverbinding + + + + This button lets you add another database file to the current database connection + Deze knop stelt je in staat om nog een databasebestand aan de huidige databaseverbinding te koppelen + + + + &Set Encryption... + Encr&yptie instellen... + + + + + Save SQL file as + SQL-bestand opslaan als + + + + This button saves the content of the current SQL editor tab to a file + Deze knop slaat de inhoud van het huidige SQL-bewerkingstabblad op in een bestand + + + + &Browse Table + &Bladeren door tabel + + + + Copy Create statement + CREATE-instructie kopiëren + + + + Copy the CREATE statement of the item to the clipboard + De CREATE-instructie van het item kopiëren naar het klembord + + + + SQLCipher &FAQ + SQLCipher &FAQ + + + + Opens the SQLCipher FAQ in a browser window + Opent de SQLCipher FAQ in een browservenster + + + + Table(&s) to JSON... + Tabel(-&len) naar JSON-bestand... + + + + Export one or more table(s) to a JSON file + Exporteer een of meerdere tabel(-len) naar een JSON-bestand + + + + Open Data&base Read Only... + Database als &alleen-lezen openen... + + + + Open an existing database file in read only mode + Een bestaand databasebestand openen in alleen-lezenmodus + + + + Ctrl+Shift+O + + + + + Save results + Resultaten opslaan + + + + Save the results view + Het resultatenoverzicht opslaan + + + + This button lets you save the results of the last executed query + Deze knop stelt je in staat om de resultaten van de laatst uitgevoerde opdracht op te slaan + + + + + Find text in SQL editor + Tekst zoeken in de SQL-bewerker + + + + Find + Zoeken + + + + This button opens the search bar of the editor + Deze knop opent de zoekbalk van de bewerker + + + + Ctrl+F + + + + + + Find or replace text in SQL editor + Tekst zoeken of vervangen in de SQL-bewerker + + + + Find or replace + Zoeken of vervangen + + + + This button opens the find/replace dialog for the current editor tab + Deze knop opent het zoek-en-vervangdialoogvenster voor het huidige bewerkerstabblad + + + + Ctrl+H + + + + + Export to &CSV + Exporteren naar &CSV + + + + Save as &view + Opslaan als &view + + + + Save as view + Opslaan als view + + + + Shows or hides the Project toolbar. + Toont of verbergt de projectwerkbalk. + + + + Extra DB Toolbar + Gekoppelde-databaseswerkbalk + + + + New In-&Memory Database + Nieuwe werk&geheugendatabase + + + + Drag && Drop Qualified Names + Gekwalificeerde namen verslepen + + + + + Use qualified names (e.g. "Table"."Field") when dragging the objects and dropping them into the editor + Gebruik gekwalificeerde namen (bijv. "Tabel"."Veld") wanneer ik objecten versleep naar de bewerker + + + + Drag && Drop Enquoted Names + Aangehaalde namen verslepen + + + + + Use escaped identifiers (e.g. "Table1") when dragging the objects and dropping them into the editor + Gebruik aangehaalde entiteitsnamen (bijv. "Tabel1") wanneer ik objecten versleep naar de bewerker + + + + &Integrity Check + &Integriteit controleren + + + + Runs the integrity_check pragma over the opened database and returns the results in the Execute SQL tab. This pragma does an integrity check of the entire database. + Voert het pragma integrity_check uit op de geopende database en toont de resultaten in het tabblad SQL uitvoeren. Dit pragma doet een integriteitscontrole over de gehele database. + + + + &Foreign-Key Check + &Vreemde sleutels controleren + + + + Runs the foreign_key_check pragma over the opened database and returns the results in the Execute SQL tab + Voert het pragma foreign_key_check uit op de geopende database en toont de resultaten in het tabblad SQL uitvoeren + + + + &Quick Integrity Check + Integriteit &snel controleren + + + + Run a quick integrity check over the open DB + Voert een snelle integriteitscontrole uit op de geopende database + + + + Runs the quick_check pragma over the opened database and returns the results in the Execute SQL tab. This command does most of the checking of PRAGMA integrity_check but runs much faster. + Voert het pragma quick_check uit op de geopende database en toont de resultaten in het tabblad SQL uitvoeren. Dit commando voert veel van de controles uit die het pragma integrity_check ook uitvoert, maar verloopt veel sneller. + + + + &Optimize + &Optimaliseren + + + + Attempt to optimize the database + Probeert de database te optimaliseren + + + + Runs the optimize pragma over the opened database. This pragma might perform optimizations that will improve the performance of future queries. + Voert het pragma optimize uit op de geopende database. Dit pragma kan optimalisaties uitvoeren die de prestaties van toekomstige SQL-opdrachten mogelijk verbeteren. + + + + + Print + Afdrukken + + + + Print text from current SQL editor tab + Tekst uit het huidige SQL-bewerkerstabblad afdrukken + + + + Open a dialog for printing the text in the current SQL editor tab + Opent een dialoogvenster voor het afdrukken van tekst uit het huidige SQL-bewerkerstabblad + + + + + Ctrl+P + + + + + Print the structure of the opened database + De structuur van de geopende database afdrukken + + + + Open a dialog for printing the structure of the opened database + Opent een dialoogvenster voor het afdrukken van de structuur van de geopende database + + + + Un/comment block of SQL code + Blok SQL-code wel/niet commentaar + + + + Un/comment block + Blok wel/niet commentaar + + + + Comment or uncomment current line or selected block of code + De huidige regel of het geselecteerde codeblok wel/niet markeren als commentaar + + + + Comment or uncomment the selected lines or the current line, when there is no selection. All the block is toggled according to the first line. + Markeert het geselecteerde codeblok, of de huidige regel indien er geen selectie is, wel/niet als commentaar. Het gehele blok wordt omgezet op basis van de eerste regel. + + + + Ctrl+/ + + + + + Stop SQL execution + SQL uitvoeren stoppen + + + + Stop execution + Uitvoeren stoppen + + + + Stop the currently running SQL script + Stop het SQL script dat nu uitgevoerd wordt + + + + &Save Project As... + Pr&oject opslaan als... + + + + + + Save the project in a file selected in a dialog + Het project opslaan in een bestand dat je selecteert in een dialoogvenster + + + + Save A&ll + A&lles opslaan + + + + + + Save DB file, project file and opened SQL files + Het databasebestand, projectbestand en alle geopende SQL-bestanden opslaan + + + + Ctrl+Shift+S + + + + + Browse Table + Bladeren door tabel + + + + + Ctrl+W + + + + + Ctrl+L + + + + + Ctrl+D + + + + + Ctrl+I + + + + + Ctrl+E + + + + + Window Layout + Vensterindeling + + + + Reset Window Layout + Vensterindeling herstellen + + + + Alt+0 + + + + + Simplify Window Layout + Vensterindeling versimpelen + + + + Shift+Alt+0 + + + + + Dock Windows at Bottom + Vensters dokken aan onderzijde + + + + Dock Windows at Left Side + Vensters dokken aan de linkerzijde + + + + Dock Windows at Top + Vensters dokken aan de bovenzijde + + + + The database is currenctly busy. + De database is momenteel bezig. + + + + Click here to interrupt the currently running query. + Klik hier om het SQL script dat nu uitgevoerd wordt te onderbreken. + + + + Encrypted + Versleuteld + + + + Database is encrypted using SQLCipher + Database is versleuteld met SQLCipher + + + + Read only + Aleen-lezen + + + + Database file is read only. Editing the database is disabled. + Het databasebestand is alleen-lezen. Het bewerken van de database is uitgeschakeld. + + + + Database encoding + Databasecodering + + + + + Choose a database file + Kies een databasebestand + + + + Could not open database file. +Reason: %1 + Kon het databasebestand niet openen. +Reden: %1 + + + + + + Choose a filename to save under + Kies een bestandsnaam om in op te slaan + + + + In-Memory database + Werkgeheugendatabase + + + + You are still executing SQL statements. Closing the database now will stop their execution, possibly leaving the database in an inconsistent state. Are you sure you want to close the database? + Je voert nog steeds SQL-instructies uit. Het sluiten van de database zal het uitvoeren stoppen en de database daarmee mogelijk inconsistent maken. Weet je zeker dat je de database wilt sluiten? + + + + Do you want to save the changes made to the project file '%1'? + Wil je de wijzigingen opslaan die je de gemaakt hebt voor projectbestand %1? + + + + Are you sure you want to delete the table '%1'? +All data associated with the table will be lost. + Weet je zeker dat je de tabel '%1' wilt verwijderen? +Alle gegevens die met deze tabel geassocieerd worden zullen verloren gaan. + + + + Are you sure you want to delete the view '%1'? + Weet je zeker dat je de view '%1' wilt verwijderen? + + + + Are you sure you want to delete the trigger '%1'? + Weet je zeker dat je de trigger '%1' wilt verwijderen? + + + + Are you sure you want to delete the index '%1'? + Weet je zeker dat je de index '%1' wilt verwijderen? + + + + Error: could not delete the table. + Fout: kon de tabel niet verwijderen. + + + + Error: could not delete the view. + Fout: kon de view niet verwijderen. + + + + Error: could not delete the trigger. + Fout: kon de trigger niet verwijderen. + + + + Error: could not delete the index. + Fout: kon de index niet verwijderen. + + + + Message from database engine: +%1 + Melding van de database: +%1 + + + + Editing the table requires to save all pending changes now. +Are you sure you want to save the database? + Het bewerken van de tabel vereist dat niet-opgeslagen wijzigingen nu opgeslagen worden. +Weet je zeker dat de database op wilt slaan? + + + + Error checking foreign keys after table modification. The changes will be reverted. + Fout bij het controleren van vreemde sleutels na tabelwijzigingen. De wijzigingen zullen teruggedraaid worden. + + + + This table did not pass a foreign-key check.<br/>You should run 'Tools | Foreign-Key Check' and fix the reported issues. + Deze tabel kwam niet door de vreemde-sleutelscontrole.<br/>Voer 'Extra | Vreemde sleutels controleren' uit en repareer de gerapporteerde problemen. + + + + Edit View %1 + View %1 bewerken + + + + Edit Trigger %1 + Trigger %1 bewerken + + + + You are already executing SQL statements. Do you want to stop them in order to execute the current statements instead? Note that this might leave the database in an inconsistent state. + Je voert momenteel al SQL-instructies uit. Wil je deze stoppen en in plaats daarvan de huidige instructies uitvoeren? Wees je ervan bewust dat dit ervoor kan zorgen dat de database inconsistent wordt. + + + + -- EXECUTING SELECTION IN '%1' +-- + -- SELECTIE WORDT UITGEVOERD IN '%1' +-- + + + + -- EXECUTING LINE IN '%1' +-- + -- REGEL WORDT UITGEVOERD IN '%1' +-- + + + + -- EXECUTING ALL IN '%1' +-- + -- ALLES WORDT UITGEVOERD IN '%1' +-- + + + + + At line %1: + In regel %1: + + + + Result: %1 + Resultaat: %1 + + + + Result: %2 + Resultaat: %2 + + + + %1 rows returned in %2ms + %1 records geretourneerd in %2ms + + + + Setting PRAGMA values or vacuuming will commit your current transaction. +Are you sure? + Vacuümeren of pragma's omzetten zal jouw huidige transactie committeren. +Weet je het zeker? + + + + Execution finished with errors. + Uitvoering voltooid met fouten. + + + + Execution finished without errors. + Uitvoering voltooid zonder fouten. + + + + Choose text files + Kies tekstbestanden + + + + Error while saving the database file. This means that not all changes to the database were saved. You need to resolve the following error first. + +%1 + Er zijn fouten opgetreden tijdens het opslaan van het databasebestand. Daarom zijn niet alle wijzigingen opgeslagen. Je dient de volgende fouten eerst op te lossen: + +%1 + + + + Are you sure you want to undo all changes made to the database file '%1' since the last save? + Weet je zeker dat je alle wijzigingen die je gemaakt hebt in databasebestand '%1', nadat je deze voor het laatst opgeslagen hebt, ongedaan wilt maken? + + + + Choose a file to import + Kies een bestand om te importeren + + + + Do you want to create a new database file to hold the imported data? +If you answer no we will attempt to import the data in the SQL file to the current database. + Wil je een nieuw databasebestand aanmaken om de geïmporteerde gegevens in te bewaren? +Als je nee antwoordt, wordt geprobeerd om de gegevens uit het SQL-bestand te importeren in de huidige database. + + + + File %1 already exists. Please choose a different name. + Bestand %1 bestaat al. Kies een andere naam. + + + + Error importing data: %1 + Fout bij het importeren van de gegevens: %1 + + + + Import completed. Some foreign key constraints are violated. Please fix them before saving. + Importeren voltooid. Sommige vreemde-sleutelbeperkingen werden echter geschonden. Repareer deze voordat je opslaat. + + + + Import completed. + Importeren voltooid. + + + + Delete View + View verwijderen + + + + Modify View + View wijzigen + + + + Delete Trigger + Trigger verwijderen + + + + Modify Trigger + Trigger wijzigen + + + + Delete Index + Index verwijderen + + + + Modify Index + Index wijzigen + + + + Modify Table + Tabel wijzigen + + + + Opened '%1' in read-only mode from recent file list + '%1' geopend vanuit recent-geopende-bestandenlijst in alleen-lezenmodus + + + + Opened '%1' from recent file list + '%1' geopend vanuit recent-geopende-bestandenlijst + + + + &%1 %2%3 + &%1 %2%3 + + + + (read only) + (alleen-lezen) + + + + Open Database or Project + Database of project openen + + + + Attach Database... + Database koppelen... + + + + Import CSV file(s)... + CSV-bestand(-en) importeren... + + + + Select the action to apply to the dropped file(s). <br/>Note: only 'Import' will process more than one file. + + Selecteer de handeling die toegepast moet worden op het gesleepte bestand. <br/>Let op: alleen 'Importeren' kan op meerdere bestanden tegelijk toegepast worden. + Selecteer de handeling die toegepast moet worden op de gesleepte bestanden). <br/>Let op: alleen 'Importeren' kan op meerdere bestanden tegelijk toegepast worden. + + + + + Setting PRAGMA values will commit your current transaction. +Are you sure? + Pragma's omzetten zal jouw huidige transactie committeren. +Weet je het zeker? + + + + Do you want to save the changes made to SQL tabs in a new project file? + Wil je de wijzigingen die je in de SQL-tabbladen gemaakt hebt opslaan in een nieuw projectbestand? + + + + Do you want to save the changes made to SQL tabs in the project file '%1'? + Wil je de wijzigingen die je in de SQL-tabbladen gemaakt hebt opslaan in het projectbestand '%1'? + + + + Do you want to save the changes made to the SQL file %1? + Wil je de wijzigingen die je in SQL-bestand %1 gemaakt hebt opslaan? + + + + The statements in this tab are still executing. Closing the tab will stop the execution. This might leave the database in an inconsistent state. Are you sure you want to close the tab? + De instructies in dit tabblad worden nog steeds uitgevoerd. Het sluiten van het tabblad zal het uitvoeren stoppen en de database daarmee mogelijk inconsistent maken. Weet je zeker dat je het tabblad wilt sluiten? + + + + This project file is using an old file format because it was created using DB Browser for SQLite version 3.10 or lower. Loading this file format is still fully supported but we advice you to convert all your project files to the new file format because support for older formats might be dropped at some point in the future. You can convert your files by simply opening and re-saving them. + Dit projectbestand gebruikt een oud bestandsformaat, omdat het gemaakt is met versie 3.10 of lager van DB-browser voor SQLite. Dit bestandsformaat wordt nog steeds volledig ondersteund, maar we adviseren je om al jouw projectbestanden om te zetten naar het nieuwe bestandsformaat, omdat oudere formaten in de toekomst mogelijk niet meer ondersteund zullen worden. Je kunt je bestanden omzetten door ze simpelweg te openen en opnieuw op te slaan. + + + + Select SQL file to open + Selecteer SQL-bestanden om te openen + + + + Text files(*.sql *.txt);;All files(*) + Tekstbestanden(*.sql *.txt);;Alle bestanden(*) + + + + Select file name + Selecteer bestandsnaam + + + + Select extension file + Selecteer extensiebestand + + + + Extension successfully loaded. + Extensie laden gelukt. + + + + Error loading extension: %1 + Fout bij het laden van extensie: %1 + + + + Could not find resource file: %1 + Kon het bronbestand niet vinden: %1 + + + + + Don't show again + Toon dit niet nogmaals + + + + New version available. + Nieuwe versie beschikbaar. + + + + A new DB Browser for SQLite version is available (%1.%2.%3).<br/><br/>Please download at <a href='%4'>%4</a>. + Er is een nieuwe versie van DB-browser voor SQLite beschikbaar (%1.%2.%3).<br/><br/>Je kunt deze downloaden op <a href='%4'>%4</a>. + + + + Choose a project file to open + Kies een projectbestand om te openen + + + + DB Browser for SQLite project file (*.sqbpro) + DB-browser voor SQLite-projectbestanden (*.sqbpro) + + + + Could not open project file for writing. +Reason: %1 + Kon het projectbestand niet openen om naar te schrijven. +Reden: %1 + + + + Project saved to file '%1' + Project opgeslagen in bestand '%1' + + + + Collation needed! Proceed? + Collatie vereist! Doorgaan? + + + + A table in this database requires a special collation function '%1' that this application can't provide without further knowledge. +If you choose to proceed, be aware bad things can happen to your database. +Create a backup! + Een table in deze database vereist een speciale collatiefunctie '%1' die deze applicatie niet kan bieden zonder extra informatie. +Wees je er bewust van dat als je doorgaat er slechte dingen kunnen gebeuren met jouw database. +Maak een backup! + + + + creating collation + collatie aan het maken + + + + Set a new name for the SQL tab. Use the '&&' character to allow using the following character as a keyboard shortcut. + Geef een nieuwe naam voor het SQL-tabblad. Gebruik het '&&'-teken om de een van de volgende tekens als sneltoets in te stellen. + + + + Please specify the view name + Geef de viewnaam op + + + + There is already an object with that name. Please choose a different name. + Er bestaat al een object met die naam. Kies een andere naam. + + + + View successfully created. + View maken gelukt. + + + + Error creating view: %1 + Fout bij het maken van view: %1 + + + + This action will open a new SQL tab for running: + Deze handeling opent een nieuw SQL-tabblad om het volgende uit te voeren: + + + + This action will open a new SQL tab with the following statements for you to edit and run: + Deze handeling opent een nieuw SQL-tabblad met volgende instructies die je zodoende kunt bewerken en uitvoeren: + + + + Press Help for opening the corresponding SQLite reference page. + Druk op Help om de bijbehorende SQLlite-referentiepagina te openen. + + + + Busy (%1) + Bezig (%1) + + + + Rename Tab + Tabblad hernoemen + + + + Duplicate Tab + Tabblad dupliceren + + + + Close Tab + Tabblad sluiten + + + + Opening '%1'... + Opent '%1'... + + + + There was an error opening '%1'... + Fout bij het openen van '%1'... + + + + Value is not a valid URL or filename: %1 + Waarde is geen geldige URL of bestandsnaam: %1 + + + + NullLineEdit + + + Set to NULL + Omzetten naar NULL + + + + Alt+Del + + + + + PlotDock + + + Plot + Plot + + + + <html><head/><body><p>This pane shows the list of columns of the currently browsed table or the just executed query. You can select the columns that you want to be used as X or Y axis for the plot pane below. The table shows detected axis type that will affect the resulting plot. For the Y axis you can only select numeric columns, but for the X axis you will be able to select:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Date/Time</span>: strings with format &quot;yyyy-MM-dd hh:mm:ss&quot; or &quot;yyyy-MM-ddThh:mm:ss&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Date</span>: strings with format &quot;yyyy-MM-dd&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Time</span>: strings with format &quot;hh:mm:ss&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Label</span>: other string formats. Selecting this column as X axis will produce a Bars plot with the column values as labels for the bars</li><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Numeric</span>: integer or real values</li></ul><p>Double-clicking the Y cells you can change the used color for that graph.</p></body></html> + <html><head/><body><p>Dit paneel toont de lijst van kolommen van de tabel die nu doorgebladerd wordt of van de zojuist uitgevoerde SQL-opdracht. Je kunt de kolommen selecteren die je wilt gebruiken als X- of Y-assen in de plot hieronder. De tabel toont gedetecteerde astypen die de plot zullen beïnvloeden. Voor de Y-as kun je alleen numerieke kolommen gebruiken, maar voor de X-as kun je de volgende gegevenstypen selecteren:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Datum/Tijd</span>: tekenreeksen volgens het formaat &quot;yyyy-MM-dd hh:mm:ss&quot; of &quot;yyyy-MM-ddThh:mm:ss&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Datum</span>: tekenreeksen volgens het formaat &quot;yyyy-MM-dd&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Tijd</span>: tekenreeksen volgens het formaat &quot;hh:mm:ss&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Label</span>: andersoortige tekenreeksformaten. Als je dit selecteert voor de X-as dan wordt een staafdiagram geplot met de kolomwaarden als labels voor de staven</li><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Numeriek</span>: gehele of reële getallen</li></ul><p>Door dubbel te klikken op de Y-cellen kun je de kleur voor die grafiek aanpassen.</p></body></html> + + + + Columns + Kolommen + + + + X + X + + + + Y1 + Y1 + + + + Y2 + Y2 + + + + Axis Type + Astype + + + + Here is a plot drawn when you select the x and y values above. + +Click on points to select them in the plot and in the table. Ctrl+Click for selecting a range of points. + +Use mouse-wheel for zooming and mouse drag for changing the axis range. + +Select the axes or axes labels to drag and zoom only in that orientation. + Hier wordt de plot getekend zodra je hierboven x- en y-waarden selecteert. + +Klik op punten om deze in de plot en in de tabel te selecteren. Ctrl+klik om meerdere punten te selecteren. + +Gebruik het muiswiel om te zoomen en sleep met de muis om het asbereik te veranderen. + +Selecteer de as of aslabels om alleen in die richting te slepen en te zoomen. + + + + Line type: + Lijntype: + + + + + None + Geen + + + + Line + Lijn + + + + StepLeft + Stap links + + + + StepRight + Stap rechts + + + + StepCenter + Stap gecentreerd + + + + Impulse + Impuls + + + + Point shape: + Puntvorm: + + + + Cross + Kruis + + + + Plus + Plus + + + + Circle + Cirkel + + + + Disc + Discus + + + + Square + Vierkant + + + + Diamond + Diamant + + + + Star + Ster + + + + Triangle + Driehoek + + + + TriangleInverted + Geïnverteerde driehoek + + + + CrossSquare + Vierkant met kruis + + + + PlusSquare + Vierkant met plus + + + + CrossCircle + Cirkel met kruis + + + + PlusCircle + Cirkel met plus + + + + Peace + Vredesteken + + + + <html><head/><body><p>Save current plot...</p><p>File format chosen by extension (png, jpg, pdf, bmp)</p></body></html> + <html><head/><body><p>Huidige plot opslaan...</p><p>Bestandsformaat volgens extensie (png, jpg, pdf, bmp)</p></body></html> + + + + Save current plot... + Huidige plot opslaan... + + + + + Load all data and redraw plot + Laad alle gegevens en teken plot opnieuw + + + + Copy + Kopiëren + + + + Print... + Afdrukken... + + + + Show legend + Legenda tonen + + + + Stacked bars + Gestapelde staven + + + + Date/Time + Datum/Tijd + + + + Date + Datum + + + + Time + Tijd + + + + + Numeric + Numeriek + + + + Label + Label + + + + Invalid + Ongeldig + + + + + + Row # + Record # + + + + Load all data and redraw plot. +Warning: not all data has been fetched from the table yet due to the partial fetch mechanism. + Laad alle gegevens en teken plot opnieuw. +Waarschuwing: door het partiële laadmechanisme zijn nog niet alle gegevens zijn uit de tabel opgehaald. + + + + Choose an axis color + Kies een askleur + + + + Choose a filename to save under + Kies een bestandsnaam om in op te slaan + + + + PNG(*.png);;JPG(*.jpg);;PDF(*.pdf);;BMP(*.bmp);;All Files(*) + PNG(*.png);;JPG(*.jpg);;PDF(*.pdf);;BMP(*.bmp);;Alle bestanden(*) + + + + There are curves in this plot and the selected line style can only be applied to graphs sorted by X. Either sort the table or query by X to remove curves or select one of the styles supported by curves: None or Line. + Dit plot bevat curves, maar de geselecteerde lijnstijl kan alleen toegepast worden op diagrammen die gesorteerd worden op X. Sorteer daarom de tabel of SQL-opdracht op X of selecteer een stijl die curves ondersteunt: Geen of Lijn. + + + + Loading all remaining data for this table took %1ms. + Het laden van alle overgebleven gegevens voor deze tabel duurde %1ms. + + + + PreferencesDialog + + + Preferences + Voorkeuren + + + + &General + &Algemeen + + + + Default &location + Standaard&locatie + + + + Remember last location + Onthoud laatste locatie + + + + Always use this location + Gebruik altijd deze locatie + + + + Remember last location for session only + Onthoud laatste locatie alleen gedurende sessie + + + + + + ... + ... + + + + Lan&guage + &Taal + + + + Toolbar style + Werkbalkstijl + + + + + + + + Only display the icon + Toon alleen het icoon + + + + + + + + Only display the text + Toon alleen de tekst + + + + + + + + The text appears beside the icon + Toon de tekst naast het icoon + + + + + + + + The text appears under the icon + Toon de tekst onder het icoon + + + + + + + + Follow the style + Volg de stijl + + + + Show remote options + Toon 'Toegang op afstand'-opties + + + + + + + + + + + + enabled + inschakelen + + + + Automatic &updates + Automatische &updates + + + + DB file extensions + Databasebestandsextensies + + + + Manage + Beheren + + + + Main Window + Hoofdvenster + + + + Database Structure + Databasestructuur + + + + Browse Data + Gegevensbrowser + + + + Execute SQL + SQL uitvoeren + + + + Edit Database Cell + Databasecel bewerken + + + + When this value is changed, all the other color preferences are also set to matching colors. + Indien deze waarde aangepast wordt, dan worden alle andere kleurvoorkeuren ook aangepast naar die stijl. + + + + Follow the desktop style + Volg de desktopstijl + + + + Dark style + Donkere stijl + + + + Application style + Applicatiestijl + + + + This sets the font size for all UI elements which do not have their own font size option. + Dit bepaalt het lettertypegrootte voor gebruikersinterface-elementen die geen eigen lettertypegrootte-instelling hebben. + + + + Font size + Lettertypegrootte + + + + &Database + &Database + + + + Database &encoding + Database&codering + + + + Open databases with foreign keys enabled. + Databases openen met vreemde-sleutelondersteuning ingeschakeld. + + + + &Foreign keys + &Vreemde sleutels + + + + Remove line breaks in schema &view + Verwijder regeleinden in schema&weergave + + + + Prefetch block si&ze + Prefetch-&blokgrootte + + + + Default field type + Standaard veldgegevenstype + + + + When enabled, the line breaks in the Schema column of the DB Structure tab, dock and printed output are removed. + Indien geselecteerd worden de regeleinden verwijderd uit de schemakolom van het databasestructuurtabblad, -dock en uit geprinte afdrukken. + + + + Database structure font size + Lettertypegrootte databasestructuur + + + + SQ&L to execute after opening database + S&QL uitvoeren na het openen van database + + + + Data &Browser + Gegevens&browser + + + + Font + Lettertype + + + + &Font + &Lettertype + + + + Font si&ze + Lettertype&grootte + + + + Content + Inhoud + + + + Symbol limit in cell + Symboollimiet in cel + + + + This is the maximum number of items allowed for some computationally expensive functionalities to be enabled: +Maximum number of rows in a table for enabling the value completion based on current values in the column. +Maximum number of indexes in a selection for calculating sum and average. +Can be set to 0 for disabling the functionalities. + Dit bepaalt het maximum aantal items dat voor sommige functionaliteiten met intensieve berekeningen toegestaan is: +Het maximum aantal records in een tabel om waarde-aanvulling in te schakelen aan de hand van de huidige invoer in de kolom. +Het maximaal aantal indices in een selectie om sommen en gemiddelden berekenen in te schakelen. +Voer 0 in om deze functionaliteiten uit te schakelen. + + + + This is the maximum number of rows in a table for enabling the value completion based on current values in the column. +Can be set to 0 for disabling completion. + Dit bepaalt het maximum aantal records in een tabel om waarde-aanvulling in te schakelen aan de hand van de huidige invoer in de kolom. +Voer 0 in om waarde-aanvulling uit te schakelen. + + + + Threshold for completion and calculation on selection + Drempelwaarde voor aanvullingen en berekeningen op selecties + + + + Show images in cell + Toon afbeeldingen in cel + + + + Enable this option to show a preview of BLOBs containing image data in the cells. This can affect the performance of the data browser, however. + Indien geselecteerd wordt in de cellen een voorvertoning getoond van BLOBs die afbeeldingsgegevens bevatten. Dit kan de prestaties van de gegevensbrowser echter beïnvloeden. + + + + Field display + Veldweergave + + + + Displayed &text + Weergegeven &tekst + + + + Binary + Binair + + + + NULL + NULL + + + + Regular + Gewoon + + + + + + + + + Click to set this color + Klik om een kleur te selecteren + + + + Text color + Tekstkleur + + + + Background color + Achtergrondkleur + + + + Preview only (N/A) + Enkel voorvertoning (N/B) + + + + Filters + Filters + + + + Escape character + Escape-teken + + + + Delay time (&ms) + Vertragingstijd (&ms) + + + + Set the waiting time before a new filter value is applied. Can be set to 0 for disabling waiting. + Bepaalt de tijd die gewacht wordt voordat een nieuw filter wordt toegepast. Voer 0 in om wachten uit te schakelen. + + + + &SQL + &SQL + + + + Settings name + Instellingsnaam + + + + Context + Context + + + + Colour + Kleur + + + + Bold + Vet + + + + Italic + Cursief + + + + Underline + Onderstreept + + + + Keyword + Sleutelwoord + + + + Function + Functie + + + + Table + Tabel + + + + Comment + Commentaar + + + + Identifier + Entiteitsnaam + + + + String + Tekenreeks + + + + Current line + Huidige regel + + + + Background + Achtergrond + + + + Foreground + Voorgrond + + + + SQL editor &font + &Lettertype SQL-bewerker + + + + SQL &editor font size + Lettertypegrootte SQL-b&ewerker + + + + SQL &results font size + Lettertypegrootte SQL-&resultaten + + + + Tab size + Tabbreedte + + + + &Wrap lines + Regelteru&gloop toepassen + + + + Never + Nooit + + + + At word boundaries + Op woordbegrenzingen + + + + At character boundaries + Op letterbegrenzingen + + + + At whitespace boundaries + Op witruimtebegrenzingen + + + + &Quotes for identifiers + &Aanhalingstekens voor entiteitsnamen + + + + Choose the quoting mechanism used by the application for identifiers in SQL code. + Kies het aanhalingstekensbeleid van de applicatie voor het demarceren van entiteitsnamen in SQL-code. + + + + "Double quotes" - Standard SQL (recommended) + "Dubbele aanhalingstekens" - Standaard SQL (aanbevolen) + + + + `Grave accents` - Traditional MySQL quotes + `Accent graves` - Traditionele MySQL aanhalingstekens + + + + [Square brackets] - Traditional MS SQL Server quotes + [Rechte haakjes] - Traditionele MS SQL-Server aanhalingstekens + + + + Code co&mpletion + Code-aan&vulling + + + + Keywords in &UPPER CASE + Sleutelwoorden in &BOVENKAST + + + + When set, the SQL keywords are completed in UPPER CASE letters. + Indien geselecteerd worden SQL-sleutelwoorden voltooid in BOVENKAST-letters. + + + + Error indicators + Foutindicatoren + + + + When set, the SQL code lines that caused errors during the last execution are highlighted and the results frame indicates the error in the background + Indien geselecteerd dan worden de SQL-coderegels die de fouten tijdens de laatste uitvoering veroorzaakten gemarkeerd en het resultatenkader toont de fout op de achtergrond + + + + Hori&zontal tiling + Hori&zontaal tegelen + + + + If enabled the SQL code editor and the result table view are shown side by side instead of one over the other. + Indien geselecteerd worden de SQL-bewerker en de resultatenweergavetabel naast elkaar, in plaats van over elkaar heen, getoond. + + + + Close button on tabs + Sluitknoppen op tabbladen + + + + If enabled, SQL editor tabs will have a close button. In any case, you can use the contextual menu or the keyboard shortcut to close them. + Indien geselecteerd krijgen SQL-bewerkingstabbladen een sluitknop. Je kunt echter ook altijd het contextmenu of sneltoetsen gebruiken om ze te sluiten. + + + + &Extensions + &Extensies + + + + Select extensions to load for every database: + Selecteer extensies die voor iedere database geladen dienen te worden: + + + + Add extension + Extensie toevoegen + + + + Remove extension + Extensie verwijderen + + + + <html><head/><body><p>While supporting the REGEXP operator SQLite doesn't implement any regular expression<br/>algorithm but calls back the running application. DB Browser for SQLite implements this<br/>algorithm for you to let you use REGEXP out of the box. However, as there are multiple possible<br/>implementations of this and you might want to use another one, you're free to disable the<br/>application's implementation and load your own by using an extension. Requires restart of the application.</p></body></html> + <html><head/><body><p>Hoewel SQLite de REGEXP operator ondersteunt heeft ze geen reguliere-expressiesalgoritme<br/>geïmplementeerd, maar doet ze hiervoor een beroep op de hostapplicatie. DB-browser voor SQLite<br/>implementeert dit algoritme voor jou, zodat je REGEXP direct kunt gebruiken.<br/>Omdat er echter meerdere implementaties mogelijk zijn en je mogelijk een andere implementatie<br/>wilt gebruiken, staat het je vrij om onze implementatie uit te schakelen en je eigen implementatie te laden<br/>via een extensie. Hiervoor is een herstart van de applicatie nodig.</p></body></html> + + + + Disable Regular Expression extension + Schakel extensie voor reguliere expressies uit + + + + <html><head/><body><p>SQLite provides an SQL function for loading extensions from a shared library file. Activate this if you want to use the <span style=" font-style:italic;">load_extension()</span> function from SQL code.</p><p>For security reasons, extension loading is turned off by default and must be enabled through this setting. You can always load extensions through the GUI, even though this option is disabled.</p></body></html> + <html><head/><body><p>SQLite biedt een SQL-functie om extensies te laden vanuit een gedeelde bibliotheek. Activeer deze optie als je de <span style=" font-style:italic;">load_extension()</span> functie vanuit SQL-code wilt aanroepen.</p><p>Om veiligheidsredenen is deze manier van extensies laden standaard uitgeschakeld en dient via deze optie in te worden geschakeld. Je kunt extensies echter altijd laden via de gebruikersinterface, zelfs als deze optie uitgeschakeld is.</p></body></html> + + + + Allow loading extensions from SQL code + Extensies laden vanuit SQL-code toestaan + + + + Remote + Toegang op afstand + + + + Your certificates + Jouw certificaten + + + + File + Bestand + + + + + Subject CN + Subject GN + + + + Subject Common Name + Subject Gebruikelijk Naam + + + + Issuer CN + Verstrekker GN + + + + Issuer Common Name + Verstrekker Gebruikelijke Naam + + + + + Valid from + Geldig vanaf + + + + + Valid to + Geldig tot + + + + + Serial number + Serienummer + + + + CA certificates + CA-certificaten + + + + Common Name + Gebruikelijke naam + + + + Subject O + Subject O + + + + Organization + Organisatie + + + + Clone databases into + Database klonen naar + + + + Proxy + Proxy + + + + Configure + Instellen + + + + + Choose a directory + Kies een map + + + + The language will change after you restart the application. + De taal verandert nadat je de applicatie opnieuw hebt opgestart. + + + + Select extension file + Selecteer extensiebestand + + + + Extensions(*.so *.dylib *.dll);;All files(*) + Extensies(*.so *.dylib *.dll);;Alle bestanden(*) + + + + Import certificate file + Certificaatbestand importeren + + + + No certificates found in this file. + Geen certificaten gevonden in dit bestand. + + + + Are you sure you want do remove this certificate? All certificate data will be deleted from the application settings! + Weet je zeker dat je dit certificaat wilt verwijderen? Alle certificaatgegevens zullen worden verwijderd uit de applicatie-instellingen! + + + + Are you sure you want to clear all the saved settings? +All your preferences will be lost and default values will be used. + Weet je zeker dat je alle opgeslagen instellingen wilt verwijderen? +Al jouw instellingen zullen worden verwijderd en de standaardinstellingen zullen worden gebruikt. + + + + ProxyDialog + + + Proxy Configuration + Proxy-instellingen + + + + Pro&xy Type + Pro&xytype + + + + Host Na&me + &Hostnaam + + + + Port + &Poort + + + + Authentication Re&quired + &Authenticatie vereist + + + + &User Name + &Gebruikersnaam + + + + Password + &Wachtwoord + + + + None + Geen + + + + System settings + Systeeminstellingen + + + + HTTP + HTTP + + + + Socks v5 + Socks v5 + + + + QObject + + + Left + Links + + + + Right + Rechts + + + + Center + Gecentreerd + + + + Justify + Uitgevuld + + + + All files (*) + Alle bestanden (*) + + + + SQLite Database Files (*.db *.sqlite *.sqlite3 *.db3) + SQLite-databasebestanden (*.db *.sqlite *.sqlite3 *.db3) + + + + DB Browser for SQLite Project Files (*.sqbpro) + DB-browser voor SQLite-projectbestanden (*.sqbpro) + + + + SQL Files (*.sql) + SQL-bestanden (*.sql) + + + + All Files (*) + Alle bestanden (*) + + + + Text Files (*.txt) + Tekstbestanden (*.txt) + + + + Comma-Separated Values Files (*.csv) + Kommagescheiden bestanden (*.csv) + + + + Tab-Separated Values Files (*.tsv) + Tabgescheiden bestanden (*.tsv) + + + + Delimiter-Separated Values Files (*.dsv) + Scheidingstekengescheiden bestanden (*.dsv) + + + + Concordance DAT files (*.dat) + Concordance-DAT-bestanden (*.dat) + + + + JSON Files (*.json *.js) + JSON-bestanden (*.json *.js) + + + + XML Files (*.xml) + XML-bestanden (*.xml) + + + + Binary Files (*.bin *.dat) + Binaire bestanden (*.bin *.dat) + + + + SVG Files (*.svg) + SVG-bestanden (*.svg) + + + + Hex Dump Files (*.dat *.bin) + Hexdump-bestand (*.dat *.bin) + + + + Extensions (*.so *.dylib *.dll) + Extensies (*.so *.dylib *.dll) + + + + Error importing data + Fout bij het importeren van de gegevens + + + + from record number %1 + van recordnummer %1 + + + + . +%1 + . +%1 + + + + Importing CSV file... + CSV-bestand importeren... + + + + Cancel + Annuleren + + + + SQLite database files (*.db *.sqlite *.sqlite3 *.db3) + SQLite-databasebestanden (*.db *.sqlite *.sqlite3 *.db3) + + + + RemoteCommitsModel + + + Commit ID + Commit ID + + + + Message + Bericht + + + + Date + Datum + + + + Author + Auteur + + + + Size + Grootte + + + + Authored and committed by %1 + Geautoriseerd en gecommitteerd door %1 + + + + Authored by %1, committed by %2 + Geautoriseerd door %1, gecommitteerd door %2 + + + + RemoteDatabase + + + Error opening local databases list. +%1 + Fout bij het openen van lijst met lokale databases. +%1 + + + + Error creating local databases list. +%1 + Fout bij het maken van lijst met lokale databases. +%1 + + + + RemoteDock + + + Remote + Toegang op afstand + + + + Identity + Identiteit + + + + Push currently opened database to server + Push huidig geopende database naar server + + + + DBHub.io + DBHub.io + + + + <html><head/><body><p>In this pane, remote databases from dbhub.io website can be added to DB Browser for SQLite. First you need an identity:</p><ol style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Login to the dbhub.io website (use your GitHub credentials or whatever you want)</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Click the button to &quot;Generate client certificate&quot; (that's your identity). That'll give you a certificate file (save it to your local disk).</li><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Go to the Remote tab in DB Browser for SQLite Preferences. Click the button to add a new certificate to DB Browser for SQLite and choose the just downloaded certificate file.</li></ol><p>Now the Remote panel shows your identity and you can add remote databases.</p></body></html> + <html><head/><body><p>In dit paneel kun je externe databases van de dbhub.io website toevoegen aan DB-browser voor SQLite. Allereerst heb je een identiteit nodig:</p><ol style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Log in op de dbhub.io website (gebruik bijvoorbeeld jouw GitHub account of wat je maar wilt)</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Klik de knop &quot;Generate client certificate&quot; (dat is jouw identiteit). Daarmee krijg je een certificaatbestand (sla deze op, op jouw lokale schijf).</li><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Ga vervolgens naar het tabblad 'Toegang op afstand', in het instellingenvenster van DB-browser voor SQLite. Klik op de knop om een nieuw certificaat toe te voegen aan DB-browser for SQLite en kies dan het zojuist gedownloade certificaatbestand.</li></ol><p>Nu toont het paneel 'Toegang op afstand' jouw identiteit en kun je externe databases toevoegen.</p></body></html> + + + + Local + Lokaal + + + + Current Database + Huidige database + + + + Clone + Klonen + + + + User + Gebruiker + + + + Database + Database + + + + Branch + Tak + + + + Commits + Commits + + + + Commits for + Commits voor + + + + <html><head/><body><p>You are currently using a built-in, read-only identity. For uploading your database, you need to configure and use your DBHub.io account.</p><p>No DBHub.io account yet? <a href="https://dbhub.io/"><span style=" text-decoration: underline; color:#007af4;">Create one now</span></a> and import your certificate <a href="#preferences"><span style=" text-decoration: underline; color:#007af4;">here</span></a> to share your databases.</p><p>For online help visit <a href="https://dbhub.io/about"><span style=" text-decoration: underline; color:#007af4;">here</span></a>.</p></body></html> + <html><head/><body><p>Je gebruikt momenteel een ingebouwde, alleen-lezenindentiteit. Om jouw database te uploaden dien je jouw DBHub.io-account in te stellen en te gebruiken.</p><p>Nog geen DBHub.io account? <a href="https://dbhub.io/"><span style=" text-decoration: underline; color:#007af4;">Maak er nu een aan</span></a> en importeer jouw certificaat <a href="#preferences"><span style=" text-decoration: underline; color:#007af4;">hier</span></a> om jouw databases te delen.</p><p>Bezoek <a href="https://dbhub.io/about"><span style=" text-decoration: underline; color:#007af4;">deze link</span></a> voor online hulp.</p></body></html> + + + + Back + Terug + + + + Delete Database + Database verwijderen + + + + Delete the local clone of this database + De lokale kloon van deze database verwijderen + + + + Open in Web Browser + In webbrowser openen + + + + Open the web page for the current database in your browser + De webpagina van de huidige database openen in je browser + + + + Clone from Link + Van link klonen + + + + Use this to download a remote database for local editing using a URL as provided on the web page of the database. + Hiermee download je een externe database om lokaal te bewerken aan de hand van de URL die verstrekt werd op de webpagina van de database. + + + + Refresh + Verversen + + + + Reload all data and update the views + Alle gegevens herladen en de views updaten + + + + F5 + + + + + Clone Database + Database klonen + + + + Open Database + Database openen + + + + Open the local copy of this database + Lokale kopie van deze database openen + + + + Check out Commit + Commit inladen + + + + Download and open this specific commit + Deze specifieke downloaden en openen + + + + Check out Latest Commit + Laatste commit inladen + + + + Check out the latest commit of the current branch + De laatste commit van de huidige tak inladen + + + + Save Revision to File + Revisie opslaan in bestand + + + + Saves the selected revision of the database to another file + Slaat de geselecteerde revisie van de database op in een ander bestand + + + + Upload Database + Database uploaden + + + + Upload this database as a new commit + Deze database uploaden als een nieuwe commit + + + + Select an identity to connect + Selecteer een identiteit om te verbinden + + + + Public + Openbaar + + + + This downloads a database from a remote server for local editing. +Please enter the URL to clone from. You can generate this URL by +clicking the 'Clone Database in DB4S' button on the web page +of the database. + Dit downloadt een database van een externe server om lokaal te bewerken. +Voer een URL in van waaruit gekloond moet worden. Je kunt deze URL +genereren door te klikken op de 'Clone Database in DB4S'-knop op de +webpagina van de database. + + + + Invalid URL: The host name does not match the host name of the current identity. + Ongeldige URL: De hostnaam komt niet overeen met de hostnaam van de huidige identiteit. + + + + Invalid URL: No branch name specified. + Ongeldige URL: Geen taknaam opgegeven. + + + + Invalid URL: No commit ID specified. + Ongeldige URL: Geen commit-ID opgegeven. + + + + You have modified the local clone of the database. Fetching this commit overrides these local changes. +Are you sure you want to proceed? + Je hebt de lokale kloon van de database aangepast. Als je deze commit inlaadt overschrijft dit lokale wijzigingen. +Weet je zeker dat je door wilt gaan? + + + + The database has unsaved changes. Are you sure you want to push it before saving? + De database heeft niet-opgeslagen wijzigingen. Weet je zeker dat je wilt pushen voordat je opslaat? + + + + The database you are trying to delete is currently opened. Please close it before deleting. + De database die je probeert te verwijderen is op het ogenblik geopend. Sluit deze voordat je deze verwijdert. + + + + This deletes the local version of this database with all the changes you have not committed yet. Are you sure you want to delete this database? + Dit verwijdert de lokale database met alle wijzigingen die je nog niet gecommitteerd hebt. Weet je zeker dat je deze database wilt verwijderen? + + + + RemoteLocalFilesModel + + + Name + Naam + + + + Branch + Tak + + + + Last modified + Laatst gewijzigd + + + + Size + Grootte + + + + Commit + Commit + + + + File + Bestand + + + + RemoteModel + + + Name + Naam + + + + Last modified + Laatst gewijzigd + + + + Size + Grootte + + + + Commit + Commit + + + + Size: + Grootte: + + + + Last Modified: + Laatst gewijzigd: + + + + Licence: + Licentie: + + + + Default Branch: + Standaardtak: + + + + RemoteNetwork + + + Choose a location to save the file + Kies een locatie om het bestand in op te slaan + + + + Error opening remote file at %1. +%2 + Fout bij het openen van extern bestand %1. +%2 + + + + Error: Invalid client certificate specified. + Fout: ongeldig certificaatbestand opgegeven. + + + + Please enter the passphrase for this client certificate in order to authenticate. + Geef de toegangsfrase voor dit client-certificaat op om te authenticeren. + + + + Cancel + Annuleren + + + + Uploading remote database to +%1 + Externe database wordt geüploadt naar +%1 + + + + Downloading remote database from +%1 + Externe database wordt gedownload vanaf +%1 + + + + + Error: The network is not accessible. + Fout: het netwerk is niet toegankelijk. + + + + Error: Cannot open the file for sending. + Fout: kan het te verzenden bestand niet openen. + + + + RemotePushDialog + + + Push database + Database pushen + + + + Database na&me to push to + Database&naam om naar te pushen + + + + Commit message + Commitbericht + + + + Database licence + Databaselicentie + + + + Public + Openbaar + + + + Branch + Tak + + + + Force push + Push forceren + + + + Username + Gebruikersnaam + + + + Database will be public. Everyone has read access to it. + Database wordt openbaar. Iedereen zal leestoegang hebben. + + + + Database will be private. Only you have access to it. + Database wordt privé. Alleen jij zal leestoegang hebben. + + + + Use with care. This can cause remote commits to be deleted. + Wees hier voorzichtig mee; dit kan ervoor zorgen dat externe commits verwijderd worden. + + + + RunSql + + + Execution aborted by user + Uitvoering afgebroken door gebruiker + + + + , %1 rows affected + , %1 records getroffen + + + + query executed successfully. Took %1ms%2 + Opdracht succesvol uitgevoerd. Duurde %1ms%2 + + + + executing query + opdracht wordt uitgevoerd + + + + SelectItemsPopup + + + A&vailable + Beschi&kbaar + + + + Sele&cted + Gese&lecteerd + + + + SqlExecutionArea + + + Form + Formulier + + + + Find previous match [Shift+F3] + Vorige overeenkomst zoeken [Shift+F3] + + + + Find previous match with wrapping + Vorige overeenkomst zoeken met terugloop + + + + Shift+F3 + + + + + The found pattern must be a whole word + Het gevonden patroon moet een heel woord zijn + + + + Whole Words + Hele woorden + + + + Text pattern to find considering the checks in this frame + Zoekterm die gezocht moet worden met de geselecteerde opties in dit kader + + + + Find in editor + Zoek in bewerker + + + + The found pattern must match in letter case + De gevonden overeenkomst moet identiek zijn in onder- en bovenkast + + + + Case Sensitive + Identieke onder-/bovenkast + + + + Find next match [Enter, F3] + Volgende overeenkomst zoeken [Enter, F3] + + + + Find next match with wrapping + Volgende overeenkomst zoeken met terugloop + + + + F3 + + + + + Interpret search pattern as a regular expression + Interpreteer zoekterm als reguliere expressie + + + + <html><head/><body><p>When checked, the pattern to find is interpreted as a UNIX regular expression. See <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>.</p></body></html> + <html><head/><body><p>Indien geselecteerd wordt de zoekterm geïnterpreteerd als een UNIX reguliere expressie. Zie hiervoor <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Reguliere Expressies in Wikibooks (Engels)</a>.</p></body></html> + + + + Regular Expression + Reguliere expressie + + + + + Close Find Bar + Zoekbalk sluiten + + + + <html><head/><body><p>Results of the last executed statements.</p><p>You may want to collapse this panel and use the <span style=" font-style:italic;">SQL Log</span> dock with <span style=" font-style:italic;">User</span> selection instead.</p></body></html> + <html><head/><body><p>Resultaten van de laatst uitgevoerde opdrachten.</p><p>Je kunt dit paneel ook inklappen en in plaats daarvan het <span style=" font-style:italic;">SQL-log</span>dock gebruiken met <span style=" font-style:italic;">Gebruiker</span> geselecteerd.</p></body></html> + + + + This field shows the results and status codes of the last executed statements. + Dit veld toont de resultaten en statuscodes van de laatst uitgevoerde opdrachten. + + + + Results of the last executed statements + Resultaten van de laatst uitgevoerde opdrachten + + + + Couldn't read file: %1. + Kon het bestand niet lezen: %1. + + + + + Couldn't save file: %1. + Kon het bestand niet opslaan: %1. + + + + Your changes will be lost when reloading it! + Jouw wijzigingen zullen verloren gaan als je het opnieuw laadt! + + + + The file "%1" was modified by another program. Do you want to reload it?%2 + Het bestand '%1' is aangepast door een ander programma. Wil je het herladen?%2 + + + + SqlTextEdit + + + Ctrl+/ + + + + + SqlUiLexer + + + (X) The abs(X) function returns the absolute value of the numeric argument X. + (X) De abs(X) functie retourneert de absolute waarde van het numerieke argument X. + + + + () The changes() function returns the number of database rows that were changed or inserted or deleted by the most recently completed INSERT, DELETE, or UPDATE statement. + () De changes() functie retourneert het aantal databaserecords dat gewijzigd, ingevoegd +of verwijderd is door de meest recent voltooide INSERT-, DELETE- of UPDATE-instructie. + + + + (X1,X2,...) The char(X1,X2,...,XN) function returns a string composed of characters having the unicode code point values of integers X1 through XN, respectively. + (X1,X2,...) De char(X1,X2,...,XN) functie retourneert een tekenreeks bestaande uit tekens +met de respectievelijke unicode-codepuntwaarden van de gehele getallen X1 tot en met XN. + + + + (X,Y,...) The coalesce() function returns a copy of its first non-NULL argument, or NULL if all arguments are NULL + (X,Y,...) De coalesce(X,Y,...) functie retourneert een kopie van het eerste niet-NULL argument, of NULL als alle argument NULL zijn + + + + (X,Y) The glob(X,Y) function is equivalent to the expression "Y GLOB X". + (X,Y) De glob(X,Y) functie is het equivalent van de expressie "Y GLOB X". + + + + (X,Y) The ifnull() function returns a copy of its first non-NULL argument, or NULL if both arguments are NULL. + (X,Y) De ifnull(X,Y) functie retourneert een kopie van het eerste niet-NULL argument, of NULL als beide argumenten NULL zijn. + + + + (X,Y) The instr(X,Y) function finds the first occurrence of string Y within string X and returns the number of prior characters plus 1, or 0 if Y is nowhere found within X. + (X,Y) De instr(X,Y) functie zoekt het eerste voorkomen van tekenreeks Y in tekenreeks X +en retourneert het aantal voorgaande tekens plus 1, of 0 als Y niet voorkomt in X. + + + + (X) The hex() function interprets its argument as a BLOB and returns a string which is the upper-case hexadecimal rendering of the content of that blob. + (X) De hex(X) functie interpreteert het argument als een BLOB en retourneert de +hexadecimale voorstelling van de BLOB-inhoud als tekenreeks in bovenkast. + + + + () The last_insert_rowid() function returns the ROWID of the last row insert from the database connection which invoked the function. + () De last_insert_rowid() functie retourneert het ROWID van het laatste record dat +door de databaseverbinding die de functie aanriep is ingevoegd. + + + + (X) For a string value X, the length(X) function returns the number of characters (not bytes) in X prior to the first NUL character. + (X) Voor een tekenreeks X, retourneert de length(X) functie het aantal tekens (en niet bytes) in X voor het eerste NUL-teken. + + + + (X,Y) The like() function is used to implement the "Y LIKE X" expression. + (X,Y) De like(X,Y) functie wordt gebruikt als implementatie voor de expressie "Y LIKE X". + + + + (X,Y,Z) The like() function is used to implement the "Y LIKE X ESCAPE Z" expression. + (X,Y,Z) De like(X,Y,Z) functie wordt gebruikt als implementatie voor de expressie "Y LIKE X ESCAPE Z". + + + + (X) The load_extension(X) function loads SQLite extensions out of the shared library file named X. +Use of this function must be authorized from Preferences. + (X) De load_extension(X) functie laadt SQLite extensies uit een gedeeld biblitheekbestand genaamd X. +Voor het gebruik van deze functie is autorisatie vanuit Instellingen nodig. + + + + (X,Y) The load_extension(X) function loads SQLite extensions out of the shared library file named X using the entry point Y. +Use of this function must be authorized from Preferences. + (X,Y) De load_extension(X,Y) functie laadt SQLite extensies uit een gedeeld biblitheekbestand +genaamd X gebruikmakend van toegangspunt Y. +Voor het gebruik van deze functie is autorisatie vanuit Instellingen nodig. + + + + (X) The lower(X) function returns a copy of string X with all ASCII characters converted to lower case. + (X) De lower(X) functie retourneert een kopie van de tekenreeks X waarbij alle ASCII-tekens omgezet worden naar onderkast. + + + + (X) ltrim(X) removes spaces from the left side of X. + (X) ltrim(X) verwijdert alle spaties aan de linkerkant van X. + + + + (X,Y) The ltrim(X,Y) function returns a string formed by removing any and all characters that appear in Y from the left side of X. + (X,Y) De ltrim(X,Y) functie retourneert een tekenreeks die gevormd wordt door alle +tekens die in Y voorkomen te verwijderen van de linkerkant van X. + + + + (X,Y,...) The multi-argument max() function returns the argument with the maximum value, or return NULL if any argument is NULL. + (X,Y,...) De max(X,Y,...) functie accepteert een variabel aantal argumenten en +retourneert het argument met de hoogste waarde, of NULL als enig argument NULL is. + + + + (X,Y,...) The multi-argument min() function returns the argument with the minimum value. + (X,Y,...) De min(X,Y,...) functie accepteert een variabel aantal argumenten en retourneert het argument met de laagste waarde. + + + + (X,Y) The nullif(X,Y) function returns its first argument if the arguments are different and NULL if the arguments are the same. + (X,Y) De nullif(X,Y) functie retourneert het eerste argument als de argumenten +verschillend zijn en NULL als de argumenten hetzelfde zijn. + + + + (FORMAT,...) The printf(FORMAT,...) SQL function works like the sqlite3_mprintf() C-language function and the printf() function from the standard C library. + (FORMAT,...) De printf(FORMAT,...) SQL functie werkt zoals de sqlite3_mprintf() functie +in de C-taal en de printf() functie uit de standaard C-bibliotheek. + + + + (X) The quote(X) function returns the text of an SQL literal which is the value of its argument suitable for inclusion into an SQL statement. + (X) De quote(X) functie retourneert de tekst van een SQL literaal met de waarde van +het argument, geschikt om in te sluiten in een SQL-instructie. + + + + () The random() function returns a pseudo-random integer between -9223372036854775808 and +9223372036854775807. + () De random() functie retourneert een pseudowillekeurig geheel getal tussen -9223372036854775808 en +9223372036854775807. + + + + (N) The randomblob(N) function return an N-byte blob containing pseudo-random bytes. + (N) De randomblob(N) functie retourneert een N-byte blob met pseudowillekeurige bytes. + + + + (X,Y,Z) The replace(X,Y,Z) function returns a string formed by substituting string Z for every occurrence of string Y in string X. + (X,Y,Z) De replace(X,Y,Z) functie retourneert een tekenreeks samengesteld door alle +voorvallen van tekenreeks Y in tekenreeks X te vervangen door tekenreeks Z. + + + + (X) The round(X) function returns a floating-point value X rounded to zero digits to the right of the decimal point. + (X) De round(X) functie retourneert het zwevendekommagetal X afgerond naar nul cijfers achter de komma. + + + + (X,Y) The round(X,Y) function returns a floating-point value X rounded to Y digits to the right of the decimal point. + (X,Y) De round(X,Y) functie retourneert het zwevendekommagetal X afgerond naar Y cijfers achter de komma. + + + + (X) rtrim(X) removes spaces from the right side of X. + (X) rtrim(X) verwijdert alle spaties aan de rechterkant van X. + + + + (X,Y) The rtrim(X,Y) function returns a string formed by removing any and all characters that appear in Y from the right side of X. + (X,Y) De rtrim(X,Y) functie retourneert een tekenreeks die gevormd wordt door alle +tekens die in Y voorkomen te verwijderen van de rechterkant van X. + + + + (X) The soundex(X) function returns a string that is the soundex encoding of the string X. + (X) De soundex(X) functie retourneert de soundex-codering van tekenreeks X als tekenreeks. + + + + (X,Y) substr(X,Y) returns all characters through the end of the string X beginning with the Y-th. + (X,Y) substr(X,Y) retourneert alle tekens van de tekenreeks X, van het Y-ste teken tot en met het laatste. + + + + (X,Y,Z) The substr(X,Y,Z) function returns a substring of input string X that begins with the Y-th character and which is Z characters long. + (X,Y,Z) De substr(X,Y,Z) functie retourneert het deel van de tekenreeks X, vanaf het Y-ste teken, en met lengte Z. + + + + () The total_changes() function returns the number of row changes caused by INSERT, UPDATE or DELETE statements since the current database connection was opened. + () De total_changes() functie retourneert het aantal databaserecords dat gewijzigd is +door INSERT-, DELETE- of UPDATE-instructies sinds de databaseconnectie geopend werd. + + + + (X) trim(X) removes spaces from both ends of X. + (X) trim(X) verwijdert alle spaties aan beide kanten van X. + + + + (X,Y) The trim(X,Y) function returns a string formed by removing any and all characters that appear in Y from both ends of X. + (X,Y) De trim(X,Y) functie retourneert een tekenreeks die gevormd wordt door alle tekens +die in Y voorkomen te verwijderen van beide kanten van X. + + + + (X) The typeof(X) function returns a string that indicates the datatype of the expression X. + (X) De typeof(X) functie retourneert een tekenreeks die aangeeft wat het gegevenstype van expressie X is. + + + + (X) The unicode(X) function returns the numeric unicode code point corresponding to the first character of the string X. + (X) De unicode(X) functie retourneert het numerieke unicode-codepunt van het eerste teken in de tekenreeks X. + + + + (X) The upper(X) function returns a copy of input string X in which all lower-case ASCII characters are converted to their upper-case equivalent. + (X) De upper(X) functie retourneert een kopie van de tekenreeks X waarbij alle +onderkast ASCII-tekens omgezet worden naar hun bovenkast equivalent. + + + + (N) The zeroblob(N) function returns a BLOB consisting of N bytes of 0x00. + (N) De zeroblob(N) functie retourneert een blob met N 0x00 bytes. + + + + + + + (timestring,modifier,modifier,...) + (tijdtekenreeks,modificator,modificator,...) + + + + (format,timestring,modifier,modifier,...) + (formaat,tijdtekenreeks,modificator,modificator,...) + + + + (X) The avg() function returns the average value of all non-NULL X within a group. + (X) De avg() functie retourneert de gemiddelde waarde van alle niet-NULL X in een groep. + + + + (X) The count(X) function returns a count of the number of times that X is not NULL in a group. + (X) De count(X) functie retourneert het aantal maal dat X niet NULL is in een groep. + + + + (X) The group_concat() function returns a string which is the concatenation of all non-NULL values of X. + (X) De group_concat(X) functie retourneert een tekenreeks die de aaneenschakeling is van alle niet-NULL waarden van X. + + + + (X,Y) The group_concat() function returns a string which is the concatenation of all non-NULL values of X. If parameter Y is present then it is used as the separator between instances of X. + (X,Y) De group_concat(X,Y) functie retourneert een tekenreeks die de aaneenschakeling +is van alle niet-NULL waarden van X, met Y als scheidingsteken(-reeks). + + + + (X) The max() aggregate function returns the maximum value of all values in the group. + (X) De max(X) aggregaatfunctie retourneert de hoogste waarde van alle waarden in de groep. + + + + (X) The min() aggregate function returns the minimum non-NULL value of all values in the group. + (X) De min(X) aggregaatfunctie retourneert de laagste niet-NULL waarde van alle waarden in de groep. + + + + + (X) The sum() and total() aggregate functions return sum of all non-NULL values in the group. + (X) De sum(X) en total(X) aggregaatfuncties retourneren de opsomming van alle niet-NULL waarden in de groep. + + + + () The number of the row within the current partition. Rows are numbered starting from 1 in the order defined by the ORDER BY clause in the window definition, or in arbitrary order otherwise. + () Het nummer van de rij binnen de huidige partitie. Rijen worden genummerd vanaf 1 +in de volgorde zoals gedefinieerd door de ORDER BY clausule in de vensterdefinitie, +of anders in arbitraire volgorde. + + + + () The row_number() of the first peer in each group - the rank of the current row with gaps. If there is no ORDER BY clause, then all rows are considered peers and this function always returns 1. + () Het row_number() van de eerste peer in elke groep - de rang van de huidige rij +met hiaten. Als er geen ORDER BY clausule is, dan worden alle rijen als peer +beschouwd en retourneert deze functie altijd 1. + + + + () The number of the current row's peer group within its partition - the rank of the current row without gaps. Partitions are numbered starting from 1 in the order defined by the ORDER BY clause in the window definition. If there is no ORDER BY clause, then all rows are considered peers and this function always returns 1. + () Het nummer van de peergroep van de huidige rij, binnen diens partitie - de rang +van de huidige rij zonder hiaten. Partities worden genummerd vanaf 1 in de volgorde +zoals gedefinieerd door de ORDER BY clausule in de vensterdefinitie. Als er geen +ORDER BY clausule is, dan worden alle rijen als peer beschouwd en retourneert deze functie altijd 1. + + + + () Despite the name, this function always returns a value between 0.0 and 1.0 equal to (rank - 1)/(partition-rows - 1), where rank is the value returned by built-in window function rank() and partition-rows is the total number of rows in the partition. If the partition contains only one row, this function returns 0.0. + () Ondanks de naam retourneert deze functie altijd een waarde tussen 0,0 en 1,0 +gelijk aan (rang - 1)/(partitierijen - 1), waarbij rang de waarde is die geretourneerd +wordt door de ingebouwde vensterfunctie rank() en partitierijen het totaal aantal +rijen in de partitie is. Wanneer de partitie maar een rij bevat dan retourneert deze functie 0,0. + + + + () The cumulative distribution. Calculated as row-number/partition-rows, where row-number is the value returned by row_number() for the last peer in the group and partition-rows the number of rows in the partition. + () De cumulatieve distributie. Berekend als rijnummer/partitierijen, waarbij rijnummer +de waarde is die geretourneerd wordt door row_number() voor de laatste peer in de +groep en partitierijen het aantal rijen in de partitie is. + + + + (N) Argument N is handled as an integer. This function divides the partition into N groups as evenly as possible and assigns an integer between 1 and N to each group, in the order defined by the ORDER BY clause, or in arbitrary order otherwise. If necessary, larger groups occur first. This function returns the integer value assigned to the group that the current row is a part of. + (N) Argument N wordt behandeld als geheel getal. Deze functie deelt de partitie zo +evenredig als mogelijk op in N groepen en kent aan elke groep een getal tussen +1 en N toe , in de volgorde zoals gedefinieerd door de ORDER BY clausule, indien +aanwezig, en anders in arbitraire volgorde.. Indien nodig komen grote groepen eerst. +Deze functie retourneert het gehele getal dat toegekend is aan de groep waar de +huidige rij deel van uit maakt. + + + + (expr) Returns the result of evaluating expression expr against the previous row in the partition. Or, if there is no previous row (because the current row is the first), NULL. + (expr) Evalueert de expressie expr tegen de vorige rij in de partitie en retourneert +het resultaat. Of NULL, indien er geen vorige rij bestaat (omdat de huidige rij de eerste is). + + + + (expr,offset) If the offset argument is provided, then it must be a non-negative integer. In this case the value returned is the result of evaluating expr against the row offset rows before the current row within the partition. If offset is 0, then expr is evaluated against the current row. If there is no row offset rows before the current row, NULL is returned. + (expr,verschuiving) Indien het argument verschuiving wordt meegegeven dan dient +dit een niet-negatief geheel getal te zijn. In dat geval wordt de expressie expr tegen +de rij met afstand verschuiving voor de huidige rij in de partitie geëvalueerd en het +resultaat retourneerd. Als verschuiving 0 is dan wordt tegen de huidige rij geëvalueerd. +Indien er geen rij met afstand verschuiving voor de huidige rij bestaat, wordt NULL geretourneerd. + + + + + (expr,offset,default) If default is also provided, then it is returned instead of NULL if the row identified by offset does not exist. + (expr,verschuiving,standaardwaarde) Retourneert standaardwaarde als deze meegegeven +is of anders NULL wanneer de rij volgens de verschuiving niet bestaat. + + + + (expr) Returns the result of evaluating expression expr against the next row in the partition. Or, if there is no next row (because the current row is the last), NULL. + (expr) Evalueert de expressie expr tegen de volgende rij in de partitie en retourneert +het resultaat. Of NULL, indien er geen volgende rij bestaat (omdat de huidige rij de laatste is). + + + + (expr,offset) If the offset argument is provided, then it must be a non-negative integer. In this case the value returned is the result of evaluating expr against the row offset rows after the current row within the partition. If offset is 0, then expr is evaluated against the current row. If there is no row offset rows after the current row, NULL is returned. + (expr,verschuiving) Indien het argument verschuiving wordt meegegeven dan +dient dit een niet-negatief geheel getal te zijn. In dat geval wordt de expressie +expr tegen de rij met afstand verschuiving na de huidige rij in de partitie +geëvalueerd en het resultaat retourneerd. Als verschuiving 0 is dan wordt tegen +de huidige rij geëvalueerd. Indien er geen rij met afstand verschuiving na de +huidige rij bestaat, wordt NULL geretourneerd. + + + + (expr) This built-in window function calculates the window frame for each row in the same way as an aggregate window function. It returns the value of expr evaluated against the first row in the window frame for each row. + (expr) Deze ingebouwde vensterfunctie berekent het vensterkader voor elke rij, +op dezelfde manier als een geaggregeerde vensterfunctie. Evalueert voor elke rij +de expressie expr tegen de eerste rij in het vensterkader en retourneert de waarde. + + + + (expr) This built-in window function calculates the window frame for each row in the same way as an aggregate window function. It returns the value of expr evaluated against the last row in the window frame for each row. + (expr) Deze ingebouwde vensterfunctie berekent het vensterkader voor elke rij, +op dezelfde manier als een geaggregeerde vensterfunctie. Evalueert voor elke rij +de expressie expr tegen de laatste rij in het vensterkader en retourneert de waarde. + + + + (expr,N) This built-in window function calculates the window frame for each row in the same way as an aggregate window function. It returns the value of expr evaluated against the row N of the window frame. Rows are numbered within the window frame starting from 1 in the order defined by the ORDER BY clause if one is present, or in arbitrary order otherwise. If there is no Nth row in the partition, then NULL is returned. + (expr,N) Deze ingebouwde vensterfunctie berekent het vensterkader voor elke rij, +op dezelfde manier als een geaggregeerde vensterfunctie. Evalueert de expressie +expr tegen rij N van het vensterkader en retourneert de waarde. Rijen worden binnen +het vensterkader genummerd vanaf 1 in de volgorde zoals gedefinieerd door de +ORDER BY clausule,indien aanwezig, en anders in arbitraire volgorde. Als rij N niet +bestaat in de partitie dan wordt NULL geretourneerd. + + + + SqliteTableModel + + + reading rows + records lezen + + + + loading... + aan het laden... + + + + References %1(%2) +Hold %3Shift and click to jump there + Verwijst naar %1(%2) +Houdt %3Shift ingedrukt terwijl je klikt om er naartoe te springen + + + + Error changing data: +%1 + Fout bij het aanpassen van gegevens: +%1 + + + + retrieving list of columns + lijst met kolommen aan het ophalen + + + + Fetching data... + Gegevens aan het ophalen... + + + + + Cancel + Annuleren + + + + TableBrowser + + + Browse Data + Gegevensbrowser + + + + &Table: + &Tabel: + + + + Select a table to browse data + Selecteer een tabel om door gegevens te bladeren + + + + Use this list to select a table to be displayed in the database view + Gebruik deze lijst om een tabel te selecteren die getoond zal worden in de gegevensbrowser + + + + This is the database table view. You can do the following actions: + - Start writing for editing inline the value. + - Double-click any record to edit its contents in the cell editor window. + - Alt+Del for deleting the cell content to NULL. + - Ctrl+" for duplicating the current record. + - Ctrl+' for copying the value from the cell above. + - Standard selection and copy/paste operations. + Dit is het databasetabeloverzicht: Je kunt hier de volgende handelingen uitvoeren: + - Beginnen met typen om waarden in de regel te bewerken. + - Dubbelklikken op een willekeurig record om diens inhoud te bewerken in het celbewerkingsvenster. + - Alt-Del om de celinhoud om te zetten naar NULL. + - Ctrl+" om het huidige record te dupliceren. + - Ctrl+' om de celwaarde boven te kopiëren. + - Gebruikelijke kopiëren/plakken handelingen. + + + + Text pattern to find considering the checks in this frame + Zoekterm die gezocht moet worden met de geselecteerde opties in dit kader + + + + Find in table + Zoek in tabel + + + + Find previous match [Shift+F3] + Vorige overeenkomst zoeken [Shift+F3] + + + + Find previous match with wrapping + Vorige overeenkomst zoeken met terugloop + + + + Shift+F3 + + + + + Find next match [Enter, F3] + Volgende overeenkomst zoeken [Enter, F3] + + + + Find next match with wrapping + Volgende overeenkomst zoeken met terugloop + + + + F3 + + + + + The found pattern must match in letter case + De gevonden overeenkomst moet identiek zijn in onder-/bovenkast + + + + Case Sensitive + Identieke onder-/bovenkast + + + + The found pattern must be a whole word + Het gevonden patroon moet een heel woord zijn + + + + Whole Cell + Gehele cel + + + + Interpret search pattern as a regular expression + Interpreteer zoekterm als reguliere expressie + + + + <html><head/><body><p>When checked, the pattern to find is interpreted as a UNIX regular expression. See <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>.</p></body></html> + <html><head/><body><p>Indien geselecteerd wordt de zoekterm geïnterpreteerd als een UNIX reguliere expressie. Zie hiervoor <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Reguliere Expressies in Wikibooks (Engels)</a>.</p></body></html> + + + + Regular Expression + Reguliere expressie + + + + + Close Find Bar + Zoekbalk sluiten + + + + Text to replace with + Tekst om mee te vervangen + + + + Replace with + Vervangen met + + + + Replace next match + Vervang volgende overeenkomst + + + + + Replace + Vervangen + + + + Replace all matches + Alle overeenkomsten vervangen + + + + Replace all + Alles vervangen + + + + <html><head/><body><p>Scroll to the beginning</p></body></html> + <html><head/><body><p>Blader naar het begin</p></body></html> + + + + <html><head/><body><p>Clicking this button navigates to the beginning in the table view above.</p></body></html> + <html><head/><body><p>Klikken op deze knop brengt je naar het begin van het hierboven getoonde tabeloverzicht.</p></body></html> + + + + |< + |< + + + + Scroll one page upwards + Blader één pagina omhoog + + + + <html><head/><body><p>Clicking this button navigates one page of records upwards in the table view above.</p></body></html> + <html><head/><body><p>Klikken op deze knop bladert één pagina omhoog in het hierboven getoonde tabeloverzicht.</p></body></html> + + + + < + < + + + + 0 - 0 of 0 + 0 - 0 van 0 + + + + Scroll one page downwards + Blader één pagina omlaag + + + + <html><head/><body><p>Clicking this button navigates one page of records downwards in the table view above.</p></body></html> + <html><head/><body><p>Klikken op deze knop bladert één pagina omlaag in het hierboven getoonde tabeloverzicht.</p></body></html> + + + + > + > + + + + Scroll to the end + Blader naar het einde + + + + <html><head/><body><p>Clicking this button navigates up to the end in the table view above.</p></body></html> + <html><head/><body><p>Klikken op deze knop brengt je naar het einde van het hierboven getoonde tabeloverzicht.</p></body></html> + + + + >| + >| + + + + <html><head/><body><p>Click here to jump to the specified record</p></body></html> + <html><head/><body><p>Klik op deze knop om naar een specifiek record te springen</p></body></html> + + + + <html><head/><body><p>This button is used to navigate to the record number specified in the Go to area.</p></body></html> + <html><head/><body><p>Deze knop wordt gebruikt om naar het specifieke record van het Ga-naar-veld te springen.</p></body></html> + + + + Go to: + Ga naar: + + + + Enter record number to browse + Voer een recordnummer in om te browsen + + + + Type a record number in this area and click the Go to: button to display the record in the database view + Voer een specifiek recordnummer in dit veld in en klik op de Ga naar-knop, om het record in het tabeloverzicht te tonen + + + + 1 + 1 + + + + Show rowid column + De rowid-kolom tonen + + + + Toggle the visibility of the rowid column + De zichtbaarheid van de rowid-kolom omschakelen + + + + Unlock view editing + Viewbewerking ontgrendelen + + + + This unlocks the current view for editing. However, you will need appropriate triggers for editing. + Dit ontgrendelt de huidige view om deze te bewerken. Je hebt echter de juiste triggers nodig om te kunnen bewerken. + + + + Edit display format + Opmaak bewerken + + + + Edit the display format of the data in this column + De opmaak van de gegevens in deze kolom bewerken + + + + + New Record + Nieuw record + + + + + Insert a new record in the current table + Een nieuw record in de huidige tabel invoegen + + + + <html><head/><body><p>This button creates a new record in the database. Hold the mouse button to open a pop-up menu of different options:</p><ul><li><span style=" font-weight:600;">New Record</span>: insert a new record with default values in the database.</li><li><span style=" font-weight:600;">Insert Values...</span>: open a dialog for entering values before they are inserted in the database. This allows to enter values acomplishing the different constraints. This dialog is also open if the <span style=" font-weight:600;">New Record</span> option fails due to these constraints.</li></ul></body></html> + <html><head/><body><p>Deze knop maakt een nieuw record aan in de database. Houd de muis ingedrukt om een popupmenu met opties te openen:</p><ul><li><span style=" font-weight:600;">Nieuw record</span>: een nieuw record met standaardwaarden invoegen.</li><li><span style=" font-weight:600;">Waarden invoeren...</span>: opent een dialoogvenster om waarden in te voeren voordat ze in de database worden ingevoegd. Hiermee kun je waarden invoeren die aan de beperkingen voldoen. Dit dialoogvenster wordt tevens geopend als <span style=" font-weight:600;">Nieuw record</span> mislukte door deze beperkingen.</li></ul></body></html> + + + + + Delete Record + Record verwijderen + + + + Delete the current record + Het huidige record verwijderen + + + + + This button deletes the record or records currently selected in the table + Deze knop verwijdert huidig in de tabel geselecteerde records + + + + + Insert new record using default values in browsed table + Nieuw record invoegen met de standaardwaarden die gelden voor de getoonde tabel + + + + Insert Values... + Waarden invoeren... + + + + + Open a dialog for inserting values in a new record + Open een dialoogvenster om waarden voor een nieuw record in te voeren + + + + Export to &CSV + Exporteren als &CSV + + + + + Export the filtered data to CSV + De gefilterde gegevens exporteren naar CSV + + + + This button exports the data of the browsed table as currently displayed (after filters, display formats and order column) as a CSV file. + Deze knop exporteert de gegevens van de tabel zoals deze nu getoond worden (door filters, opmaak en kolomsorteringen) naar een CSV-bestand. + + + + Save as &view + Opslaan als &view + + + + + Save the current filter, sort column and display formats as a view + De huidige filters, kolomsorteringen en opmaak opslaan als view + + + + This button saves the current setting of the browsed table (filters, display formats and order column) as an SQL view that you can later browse or use in SQL statements. + Deze knop slaat de gegevens van de tabel zoals deze nu getoond worden (door filters, opmaak en kolomsorteringen) op als SQL-view zodat je er later doorheen kunt bladeren of deze in SQL-instructies kunt gebruiken. + + + + Save Table As... + Tabel opslaan als... + + + + + Save the table as currently displayed + Tabel opslaan zoals deze op het ogenblik wordt getoond + + + + <html><head/><body><p>This popup menu provides the following options applying to the currently browsed and filtered table:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Export to CSV: this option exports the data of the browsed table as currently displayed (after filters, display formats and order column) to a CSV file.</li><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Save as view: this option saves the current setting of the browsed table (filters, display formats and order column) as an SQL view that you can later browse or use in SQL statements.</li></ul></body></html> + <html><head/><body><p>Dit popupmenu biedt de volgende opties om toe te passen op de huidig getoonde en gefilterde tabel:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Exporteren naar CSV: Deze optie exporteert de gegevens van de tabel zoals deze nu getoond worden (door filters, opmaak en kolomsorteringen) naar een CSV-bestand.</li><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Opslaan als view: Deze optie slaat de gegevens van de tabel zoals deze nu getoond worden (door filters, opmaak en kolomsorteringen) op als SQL-view zodat je er later doorheen kunt bladeren of deze in SQL-instructies kunt gebruiken.</li></ul></body></html> + + + + Hide column(s) + Kolom(-men) verbergen + + + + Hide selected column(s) + Geselecteerde kolom(-men) verbergen + + + + Show all columns + Alle kolommen tonen + + + + Show all columns that were hidden + Alle kolommen tonen die verborgen waren + + + + + Set encoding + Encodering aanpassen + + + + Change the encoding of the text in the table cells + Encodering van de tekst in de tabelcellen aanpassen + + + + Set encoding for all tables + Encodering van alle tabellen aanpassen + + + + Change the default encoding assumed for all tables in the database + De standaard veronderstelde encodering voor alle tabellen aanpassen + + + + Clear Filters + Filters wissen + + + + Clear all filters + Alle filters wissen + + + + + This button clears all the filters set in the header input fields for the currently browsed table. + Deze knop wist alle filters onder de kolomkoppen voor de huidig getoonde tabel. + + + + Clear Sorting + Sortering opheffen + + + + Reset the order of rows to the default + Herstelt de sortering van de records naar de standaardsortering + + + + + This button clears the sorting columns specified for the currently browsed table and returns to the default order. + Deze knop heft alle sorteringen voor de huidig getoonde tabel op en zet deze terug naar de standaardsortering. + + + + Print + Afdrukken + + + + Print currently browsed table data + De huidig getoonde tabelgegevens afdrukken + + + + Print currently browsed table data. Print selection if more than one cell is selected. + De huidig getoonde tabelgegevens afdrukken. Drukt selectie af als meer dan één cel geselecteerd is. + + + + Ctrl+P + + + + + Refresh + Verversen + + + + Refresh the data in the selected table + Ververs de gegevens van de huidig geselecteerde tabel + + + + This button refreshes the data in the currently selected table. + Deze knop ververst de gegevens van de huidig geselecteerde tabel. + + + + F5 + + + + + Find in cells + In cellen zoeken + + + + Open the find tool bar which allows you to search for values in the table view below. + Open de zoekwerkbalk die je in staat stelt waarden te zoeken in het hieronder getoonde overzicht. + + + + + Bold + Vet + + + + Ctrl+B + + + + + + Italic + Cursief + + + + + Underline + Onderstreept + + + + Ctrl+U + + + + + + Align Right + Rechts uitlijnen + + + + + Align Left + Links uitlijnen + + + + + Center Horizontally + Horizontaal centreren + + + + + Justify + Uitvullen + + + + + Edit Conditional Formats... + Voorwaardelijke opmaakregels bewerken... + + + + Edit conditional formats for the current column + Voorwaardelijke opmaakregels voor de huidige kolom bewerken + + + + Clear Format + Opmaak wissen + + + + Clear All Formats + Alle opmaak wissen + + + + + Clear all cell formatting from selected cells and all conditional formats from selected columns + Wis alle celopmaak van geselecteerde cellen en wis alle voorwaardelijke opmaak van geselecteerde kolommen + + + + + Font Color + Tekstkleur + + + + + Background Color + Achtergrondkleur + + + + Toggle Format Toolbar + Toon/verberg opmaakwerkbalk + + + + Show/hide format toolbar + Toont of verbergt de opmaakwerkbalk + + + + + This button shows or hides the formatting toolbar of the Data Browser + Deze knop toont of verbergt de opmaakwerkbalk van de Gegevensbrowser + + + + Select column + Kolom selecteren + + + + Ctrl+Space + + + + + Replace text in cells + Tekst in cellen vervangen + + + + Filter in any column + Willekeurige kolom filteren + + + + Ctrl+R + + + + + %n row(s) + + %n record + %n records + + + + + , %n column(s) + + , %n kolom + , %n kolommen + + + + + . Sum: %1; Average: %2; Min: %3; Max: %4 + . Som: %1; Gemiddelde: %2; Min.: %3; Max.: %4 + + + + Conditional formats for "%1" + Voorwaardelijke opmaakregels voor "%1" + + + + determining row count... + aantal records bepalen... + + + + %1 - %2 of >= %3 + %1 - %2 van >= %3 + + + + %1 - %2 of %3 + %1 - %2 van %3 + + + + Please enter a pseudo-primary key in order to enable editing on this view. This should be the name of a unique column in the view. + Voer een pseudo-primaire sleutel in om het bewerken van deze view in te schakelen. Dit dient de naam van een unieke-waardenkolom in de view te zijn. + + + + Delete Records + Records verwijderen + + + + Duplicate records + Records dupliceren + + + + Duplicate record + Record dupliceren + + + + Ctrl+" + + + + + Adjust rows to contents + Rijen aanpassen aan inhoud + + + + Error deleting record: +%1 + Fout bij het verwijderen van record: +%1 + + + + Please select a record first + Selecteer eerst een record + + + + There is no filter set for this table. View will not be created. + Er is geen filter voor deze tabel ingesteld. View wordt niet gemaakt. + + + + Please choose a new encoding for all tables. + Kies een nieuwe codering voor alle tabellen. + + + + Please choose a new encoding for this table. + Kies een nieuwe codering voor deze tabel. + + + + %1 +Leave the field empty for using the database encoding. + %1 +Laat het veld leeg om de databasecodering te gebruiken. + + + + This encoding is either not valid or not supported. + De codering is niet geldig of wordt niet ondersteund. + + + + %1 replacement(s) made. + %1 vervangin(-en) gedaan. + + + + VacuumDialog + + + Compact Database + Database comprimeren + + + + Warning: Compacting the database will commit all of your changes. + Waarschuwing: wanneer je de database comprimeert zullen al jouw gemaakte wijzigingen gecommitteerd worden. + + + + Please select the databases to co&mpact: + Selecteer de databases om te co&mprimeren: + + + diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/translations/sqlb_pl.qm b/src/WBCLFZSystemModule/SqliteDBProcess/src/translations/sqlb_pl.qm new file mode 100644 index 0000000000000000000000000000000000000000..5d3d670759617b21754e0a90a6fff26f6a1e86b7 GIT binary patch literal 224964 zcmce931CxI*8h1gNt>o=ipVZtKq!dNA_B@{6)3Avkwp|0N!zpyv`J}Fptx`2zKo9h ziW{!DD~<{-IF7qA?h9_Hj0=vUqcbZ0f4_U*lC%lnH}jwI`*=P;>lUtj?EO_D;%jO+dgk=;BK?2Dr@kVOSl5655uXQ$Jld$QKd;Ai zFg{)vAiy(6w;@cm=@`U^jg#rGp|Ef-JTKwRgd-Ev$H6XP4)E60jFwMJcy zj;D!u4;Q%}eS43@{nK&%qZsoq!1W@Lub)v@Gj^G}dO9D7>&0Tu+CyDEovSg3Qjyh@ zaXkpv4@B~R5znLxMfQ4Jtj3 z*E#%LA;u98i}#H=A{C?6)!g*~T+bD=VTO3$zCg?|QStr+I#PRzFLa6+lfD(-UayH+ z(Ja296UF#sfcQoS#q9p9_@;~y*?pD1)^^a>)l1aXoO8Fn&b?NAhvK=<9#U6x%=_X? z)`+ng?I)kY^-%FG{gaqu$B1vG4?L|=S98iTeVwyeU+2CkzS~X~LT66#YcM#te&eDDe}_WZYW*w9Hl`Gcj?Q@zEgDUq(r%Ejoln{<70i+BdK zO856#ME$&KLe$RgSEv6n@<-7ACct%UsDBZD5?DDnuec> z`7yegG6?fw{NrjF^!JBFp7~7%eKi!{Uo3l(zn2xtUgTGgt+Ln4&xp}GE_;309oK85 zY?sbr_Bl*OZ1#vT`4}0yxKhl1y=78|Um)j8W%5%`i}CT=?AV7PsK$tbKloRnn%eYV~RxXjLNL# zkD|SQ$?R8e5=q`GbLO7~IhiAKUU*W>9z`;DH01w-z2s2;#bUfWSq?o5_q{n5*C$1; z3CW?WaeaKVx*EQ><GPq?yX0SD_WGL~_UreMyX)of@{M9F zSs;hU_7LOmr^)=*{v!8wP*-!{pJo1;elZG1$dM=C2>Kq8BTsoiBz%%Ac&}W{d9AXr z2z2aUC{;6V6?6P|QuV?qnBQNe_8QD*=T~IW!qs9NI$z>*z7=Eo(ULl7y?6=_l4Gud z9oRK0#}(Z#o}Tx~al2z4KDkIvng4`H{5*YqtXxiAdcMf#cgh*zN|A{d$e%7id)0rG zKfP>Y`%Drl*o-MWK-Z?F*|%FU;YgKFI*)*90Yw2 zuaVzwUoGZppZxYJ?C}0q7l{G*JrH-|&tZZi&8__!E<7URHOXNza>jmE@@ zhL|6pYaII1w<1@bW5loACbIEjW9i1Q7;7Ffj{O>bV(-5hC%sqzecHu1b+?zrIJ?0( zwfb@~KY!Rb{cXtgHIt1qK1F{Q_chMm^(FBPImtMGEynlo6~?OgHZhMKY}|ckNX)z= zj5WQE6?5%;){#o}MF(=hvJjW?-1{%4e{b-NqSj z{4_!2yYC^7OXjZMQV#kl2cM*XWI@pez^S@ z=>Mxv8 zx*PnMy~qrG-6AsR&t`|$JBw%6q}j_mS9!Wa4!3O#Ik9 zc56z^$U5^6eP)W8yvsb}x{YF9`;>Xkm3>624>HfIggl)eHUD@UOgnSg zf#xH%`@r6gFdu8J67$gY=Guc7h*`hdd}1N^Tm6ptWKnN1N?Xh)zr?sc`oLWOXWFlX zx&Eu}VorG1eCEhzF&BPdK6Cf+VxDx7`OIVJ|NEEB=k5aC9}G2LTRsZEpKZQT9TB

n zd-BhSi{UTvbbk9+F?PSy(_{8aVje!;)AQZFVipeb^eO^&*>s_&@7};#)9>@_aaFmP zBda_mD;^hf^Xs00pMlO*2Y5#2^%nESk39PxW{C9L%`;{`#`n!8&)84@2LJP+=fK6V z%jF+L@f`JdKQTsj@Ekn| zpYLk+ENr&_e`(*1tV%JMiM zXtihMt!u?RfoP4F{@#$!1x0Rl!x;`MrUbUXTHp7@*f0yUgS9~Hzoa5Q> z^EKk>_@w8fs&g^#|MYCCt%tD-c{ar{f1eNae0O1)80S3U`Qfio@eHr?{B!PU`2Aqd zZ^xY{=7M*;=9LRXo*V2nuLb7a|7ou;e+Klule&7k^z#-!JrOwJMQ_(mKZv>OTyM`c z@GBEP_4Zyf71w^=aOe;*y#Mxw?+3PBH{aW50Qh|MOWu;_z?Y-uc=tNffF1bRTecqd zuJ_a4eK*yJY<|FTBLDowyL7|h(1&90^0lvu{I`3d4F-t4_>>Z2l+-PF}Qpj2Py{-&=V&-7k)>Se&+ z59#adFZFf)qu$F_LVkwK@m_I$rI`2s+k4ggC&fIV%6rZ5-YHn3|yf%qwd7@pCZp!sH-t*1Fnd< zo^MiDV{|WE|0Txg@woniYaOnzkE74Q^*3Da@!k&jB27>0>+@Hst1c#b4Tz&ZdI9!2W#)|ijBcLar-Q&IE_M?D<|KPow_F+Pc_kl|I z?WqgAYdU`>o=$b%hifb0f4}vv?K27STakC|8wA*wXfAc=EE(H8>w)eR+ zV7D$m&im3Y*Mon(yf5GUsh9Q^!rsp|e7?s*Vm3}yS5LoVeEIk+Z$97) zoV*qB)mn8myBX^0>1p`7?lMA*YtQoShImA_T;S_D4tm+~2j8AELGK@j`v$!YIS60j z8~hLOw`amP{IXeM968*#-^jIMc)s@SH~Dqoy0d+wDq&B~Zt{(<93f`c%Y8Gvry%y+ z%{TKs#0BS7`{w;&ff&ag={vmeMv>YHzWI;G#prUg@5pVhAznSsw{Y)MMShy|~uUG5sbn22b)eRh=hhQLV4#O3-!0fxe}8pDLaX=lhl!*NAcSINvcBZbh7YoW3rY z;5+W`Q8AkD^PM&hdb|JA>S`8#>pShn*Tq=0+IP;Ro5bAx41Jw_46aWjKA!J8_xU=E zqr!LI#Xd3Tf9pH%3&dAFn|*)!?Ikf+MtzrmwKwQqfh+9F*kgUy{RMJ5@fqLsvoPNM z3w_uB26~qr>$~NGNn!+k^W6g6WqdK;ciS_ciW$7wciS5m0T)m7-9EwuKJD+j{Q}^Z zk_Ub3inoA2fAKxlQZDB6OMFlL^#;VHANtnUgI@>V>wDS{{d^?qd%5{3G4@&Md-cWR zfeSsp4Z9DAd_3se@aRdvxjx_Du7lhxdCK?E5L{RJd>^lQQ;ZW|@NGWfMflIoz8}Uw zE-u>S+jb@TdoY~0OMMb_Psr>22K-Xvy1ao8?ISX;TV84Z*X&ybI235}CA5-o^J$6yws{^DgNPKXlJId6#w=FGkt;yqn)cF6NCu-d%4aem?ih zy!($B20yk(-a`j&5%bofyeH3U1+IHD@0o!oB2KHwd#373;OwD!FCXv~@+nW`y?oqU z;O7Z>Z(fG{$;mzP-u&oN$am+wcaC@)aad8_N5{P`o&qCp^T3PX-;BI3-awA$*!6i| ze_koZrrqBj^!?(hoR^<==_!Kcm-Jd_9 z=w;~V)%g=Y`%28vy!^>0+%M+Qcjr&O8TvM`K7aCOFJPWK=T}bZj5zB3{8=ZgN1XI+ z{(`-_i+Nyq{=(O)pjW-~tAT6H#+&nN=X`^_z=r&~US|S#_sU<4`SWymCx7w#+mI({ z$Y1;sjLkn`GA zvo-m54~`-(yDR^mzXLBU{3QRrx8QdsZ_0llbhsFQygUEl8-XWB+>-y7d5H5PCHc>t zc)XbZIw1e$%VBTLP5Cdc42q|}KmV0WVaG3u=D&Il@O{mq{0+0ghX=3Ef9D|h3GCNLw48KcTdXyA`E-jkMR4t zc0eBGK7ZaM*r~|z{=!b+#|`WJMYY?+Slr_8aQTgh-yiaK*ys~uzwi8AKfwHdw2!~X zQPAI`hWLA(aUT5KC;r|K?J4HCsDHq>kn0P__{*vi@SE%W!~TGA?7GxH><#d1Y1F^Z zK3ha?>f|5!?_We-eOO(M_2>G>es!vtP1DrXQ+B0)d_HhXYM_6@ZMOn{AL^eHe+lh; z;h%as@ieIontS-`I`oEqt?}1y1ig&~ z{-xtz67#U9{Kxd(h`7+}KW0%W;*&@GC;EYR?kez~xdgau*c1Mc9H$(7$gs`B$AYLL_>sx|)Z4=3jOF2;|2K{kMIx32{Mz|MsFy$kScmzw`NtnE%K9 zcXin)@;a`Y>JV@K+kgMPvtYMB@jrMiRSwtC+JVtE*>^NBwJ` z+yFe=!Tpi>r zU%d?R%s<}ozdI|5xabrA$EE!--&6dbcE)@*oT09s-75T_-g>IYij(}Cd))~9U+&+$ z2>7#Li+}T-7>ghVH;G|bB2R=Qa;N%;6i}~V-1sA-5&)*zTaK*pS@BVuf zT=fC?oI1JSkw4#s{K~xrk8Xkg>hgKP6H|Z}CwD1$_P7ONJoR(I^9LYK?Dt5)8*5$% z|5g{g^YabJr(IC+?ySE-KPD8scV9^4d+}?a<3;HI z$Daec-LM6Di6;Vmwm>iDg#sntVm=PvD=_%Gn}ECa4Gi%?u2wY$O3woy{x~U6`q@;- z_3?qS2=aP|jtcBI=W;Q3IVMmZM%=mYZ-E1ffZGpzJ23IbxEL4C3QW1x5aXnxz`;Y2 zPZ<8kz`S1|Z*Nows@Lx-a!UtwHQrkms2SS{am^=z=sb^@zWW2wJMg(+HLmbS1z!hh z@7xF+`$%BXhtTIirv;83e~rlf4+f6?qAUFE3e}MClw%`SQ7YhUYQsL_XNJI<>$VEul@Rxx9T) zVYl1M5g-1waJLgziP3UPVb9|ck59g-FkDbB#u2*|4*1tKV$2*>IOw)Y@f>(>VcAKL zr{1#*%PvH_x78L7ozffe#xI3K&)Fizm7&5humjSvrEvVIagqDZF07cp7V-5{g_9mB zz&hTi>T2fs3a7>n5p&Ajg)?qyL0;NZcre%P-s-Hb#`*^eXPyqeJ^E{5)g2q4kMY8D zCY=WP8G-AkST~!YukU(Ox{N8VF-|35d1v>sl#?(RLrI3--T?kU)>@xK;6jr9$=Y2-_=>)68&deJ z=@n0(mcr-0gnT`9OW_O0N0EQ*Soq>~)SIb=FTHUw@{2DPz8X0me*Kuj4U@pnudgnA zGun*2>fZ|AT7QU0)%e1VyI@|g-&*)_1MYh&QuxW=wqUJrWZ|a1Tf{SBcHw9D!*4At zDEvJ2uozeESNQc>&{2_6SF_W&!fy{+2fo%8{_y!(SbyjclwUBPw;d5Q&*>;e^`@YA z!%HGBTo=q+G+aC-n}YsVyNlF58w?zEA=Yhv3>NRR0QlpkV23SNit*6X!CgJ~h|Ib^ z*nQSo@$7P2u*c)2;QJoI9^YV%^o=`$;q{oe-TDXnM=nSF@p5p_B|l((rv(QsdK-GN zS8%UOA%Fen1c!_QfA-uvIOJ5=i~T+e4y){gI4%!Y%+s=Q!C_zS37qK-4nGd^_TZht z(SHITA2}nq|APmM%r$}s+zNi2{!nnj(LabBaCC6O>WRpAEelS*5O!*GJUIE6n{d57 zIPH$}kgq;Fc-X2r(C3qa^N)mmpD{gn)Io@&-u)_gbbSTl+-u?tclMaZD?4_C3L~j|HDag6CqMJ!3`$|FjhN@zIBa7b6ZfsvZqq zI`Ddtx336Zeh2b8qelf-KHL>@woF|;16~VWANmyfxH)*U`7G8`jtt&>>AlEHt`FY+ zW;y)+TfzG#gP!xp1Rt2&S*A{C!stT;J~w;G^2$ zv)4iYcO4dd0eKARyGQWVmq72;Yl9n30NB`4jHSi<}Sm7UwyDeq`5Bm&As5~=KX>{4u+i`enar*d*6aw-5%Wb z#*v8g9w_qM@i*Y#M~l2mDj|1$ihNUE!g|JQMFszaoOSu8DA>1Dq{mxD-HLt?v+hH6 z_4q4_x{W?wjMF_uJ-0wFM!r$B$M>)|+svW?uRty?7*aH3P(R?nzZ8{rh5RKu6_xGx zG4k@0)zwqADW z_G`Bm%{uidPYV@(+70p3?V;j{o8YIe4|S~g2=?uQQ0Lw7{DrTE zc7F@{6WJ09dtjfd_73$~k8$ifG1T{%kKqr(`ug+I(BNZU!#c=8p?!yh;6Ijy_Pqo2 zzyFuee*Ml9<17h{Sq}ab)`!OY?Eoz{-l4`u;Qb4)3MCHz zPGo{Vl)Np3Jjl-Cn;Ha&Thkp&n0&9Q;J+p@+&LuRn(#z65@3)}f(iU%>pI zbVlg;rt`!zbW7-k@6i4iXNO*W^Hlh^Q$w%szW{OC=Fr>IT96-qIQ0HAcfjv|6?*^O zN-=IP3T=AuS@Cr58T#TYjBnB#p)X@t|9WO@=sWtAXs^)sRjVN%pM<`@Itko^QpeRKSf+~cs7 zhyy+^?s*yP!QSr{57>GU)?L>W4@#XTo;|)RF6*%k<2t8!*z>!K@x;Bw<370$@#NOx zaa(cSXLj+_hWpX~jm6WB`V;11pW=faDFt4+qj=Vu*;uFRUOYF5dA!+QJTHKJPLD;! zM|}YQ&}Vb;(Z`>ReCrd%)w>)g=CBirqo4Ige&wm+df+C{US}4^OF{pF6N{JJwifZv z%f+o&Px6dU6}SF?_SZy;FZ%m+SQna5e91!_#awo3@nu(+iuqV+@#U`oPZs4BUm1ct zbU&>4rpGW}mt9_b^9{&@E`C^DJzXCuzGXDp9dc>$EwQCy+&!xJwz`|d`0cpjJEpY2 z4u4R5XSW#eaZB-?qgs*o{=E3!ZJk7x-c|g_ns>ywWMT0OzUi`|S zYefFuU0uy+2X*y$jx2uV?cZHN&;g<+L zFUG%NnJtINbcvy*C_XL1ze)TZw(e;}JIl~cBfd%C`(^6Ml=Dp!+DV|*W_+*jjYu4= zMb#7hmA$UOcM++^HG#i$Yc=>gY&}_vC-`d|_b$S>QAK+-{*K`j|DQc4tk&2*DR08a zV;IF&{1%ofe76E^Ys%S6HF%OazEbe149}5YHdkEg*&?~tfd1>O9{70~dRXMp#y+cY zM;!lZ`dW-*(OU|XkXL&A5gCoXXG#m`(obj}gso5Z^Bl(vJhuX^HmKjiG7qgcV-^-E z8iwHx{AACc8H_29m z6mupQsU9Lyitj-ydZvu5z^4_MW!|A?#K^avr9`Yyyv(Exv!?FJlo^}rq=Zu0g4QUR zY?(botnanV@jK2oKk50+oDWJ_Jt)nb=lP(B@9#X= zu+lrqRt@AZ3|b?64z`QWr!XV1Bu00|oj5*IhG{)g_)+M&wh!(U(Bwr(-*w%5%AxA+=mMPUOO8;}unwGSrEKyR$R;tvPs4*Oi zJ#XzLYRAvm9M9B&v1qwTQLZ`Iik_oN`oquy+U1lC!96iGGo$er$4#3wMoGpTHOfSr zak>_dywsMEdK{L?mb^{3{tCm-kc(_5fmRozCw^XGajMLrkJfqn8oET$syR-NRgKR! z$I2A7|LJHmwRrpekAfETmEyJ{(nh6y(ZBXy(RG^k$G<4olVBez)3d_ zDRXdAxu2=KJQ3fwW9w6m4dr9&qmi1j^08Hkn%45MP30Bi!{eJ1%aYONaBZSFJo}L8 zu~al1ONJxyaH1(14<{2X&DGJt;o9bCbXlZ18eSSpwnQ4jsYIe7+>(se;ID9Xb2O5| zO*PSEtS*jcYr@f*Sjuj$CX$L&MUv5QZLA@hEFD|c#IC2N*iTh#NJFeT8fQx_@fy&P zs*i?eBv!;48Y1DDEmin6JYC-rJ~Y~#j3wgXVS~ewWO!M$p@COEFu8JWcycrzZ3byM z9@;020XBfn=F;%tiI#9RhS->>iPg69hh`9*Of|=4jz+^{BjNhyXzl)e>r<(w(Pd@JmMtr-i?@^}n(NB!`^)N@8cI14eam;|uCZm2 za>dPzwv$%ljhacSgBdfYmklc&S{4HfmzSoNr*sE9b*t)yvtJWUMPd!kpeEs~#ssE3 z7RRrR5%M66|4Y?l-kO>dbF$k<}PBezcma)O|44#6eOHxBHs72B0l;UXL@*VYS&0w47?AA&D z4hSDx)m&DtL}#Zcs!3Fn$Ptz_#o~3ADD9}9?1biM?sw3yOokS15EF)GHPUd@qzeqR zU2|J2{fi*l{VX(#mL*j!?wyQ##asvUEo?Kpn1)H0u8=txhzSHAJe)NKUdW3ChZL zT1s}@5 z-6RzqPeu~Qb{(>tY9yT1Rb=fXn4Vd2n#s4UceY17qX9e!S$8hUwsUZf36~gvHQOC6 zBLQ!QS|QeaK#wN;Mkkx;)Lkfs)QC#J&@s0fN6{Oi1Kc>d$ z(sQNC2o1^a2EZ}99a7_lyKy{E`gO=lfJY$NjCNZT#lIKY=H`W#g;w+iP^-dr(%z`X z+@MC9okP|W7>7<30rUdCG+DgSDJCQdz&U+K+g5dYiK8MH8u1+Y`=8G2Jn*m?GlG6G zmQ2d|>A%M}%8;g+iLeMjTV`*1UcpDq979LYgntwG#JQzxXt>V=OO+bCO71CnU`mdy zrzdN62=RHrgBz;DedO2Z#}k0D84|v>8J@ly}>0Rwo)-8sj@l*@Q^EI@(}AtN2sh zkO1OQD5yqRR8Rss@6jSYWgz2cf zV?jfBC|n8V>L+PPv$pdmM2*@t%XNbToKZ|0hly?l08h49e=Lh=v9c!`uue@Yq%8_uZcnxr zyclt+mXZTU65s zdj@H2o}qq?@&;OiM@s=%+8@UN1f1@=OsJ1mFAftpq?#kKcxrS(xc}a{dmRiH>aaS? zWN_J|eJ{IO`lC6vgD%zs1~6u%>Du1RZqF6b$kA~yC#Fa1|K?+!eWaGqZt|o*Agk# z#}HrANV(IHEDcYJMH_0ADXB^{)Px!1HUh*(V31l%bBe`s=qepn7_N&eHF}(Ma^R?% zuuP}THJy3NtZPT89TfRTF=Ez(ywR>AJ8T#&0Sc8f;*k@Zn=#BtO$~=++1v1pXfhe8 zL#WM2$Fb4TcwH^6%s{oVVK61%Ly$q7@wFn%ci(oZk&$)T;+Ifs`iu04?_Cs0F?=54kXzWt!5I0 z`l8&b3NQGnmYNZU(!^6S{LQ#d-BpR`%W9=GJO?+GEC8#$=JdzX z1d$>`L899t!6aL&z+C0d7#P;5Z?$-};@c?fGVil(a(jVJQ&X!iTg2VIZ1L72%@q-P z=D2D(YKe3`zM=iIaSAILR12U$uQIwT;hGv(%#T(Kf#4+|g#@If;hD|RA;>y5K(s8> zkS=%nF8me&7+`{{8qlK^xj&>SmHf6UcTim)iPuGIa>|}jj>R@6*0rsm1kjLk_O)AZ zmj@Pu>0EXs+v$4KBSvk_$XfoQr-jQRlqcJgWjYldW9Vt56V?vczPJ695RlPs@fX@I zdpciGkbykQ^{((bb*vO6Qk_323`~;O{I>vb-7CB zDBKCWWL`Z|&cuc)ee75y2k5snH8E3-#3QoJ{F$MN!r97brH3KN38r~}W(ZX*Qx8Px z=6_W;@b<`PW8T@IZmcQ_1OW>aSqk5pbKd1h3k29G5S|EPs`<-UuL&H~#U-@aRp10? zm01ajwEkPq8AaPJvl)%Q(;a=ksd3olSPc^LOu?4L6Y(L@<;YeOHZ!F@8c>pEpm1DM z6LMlIQLC~&Q=|e^(8tkN+Oti|R0n#vw4}WzO#_Ym@A&IgfL-eew)Z~zZ@fkuFwZGKAC4ugi zw8S8gaMw1gZD-8Xe7LST(b80g3@L-p{goHb%00R-S14J9U~`1^5gZ$VhUP$)(L2-+ zRMaO)?UDvdE^Q){=~QN=VtgAaQWh07pseB|yxLhx1}REXpag475KD`j7Q=Q-%RodR zTvO$GD?>J0MY$@Prlb;e#@>THQthC1;hF@1PCUWT9}1auw08AaN*P#sSKG9g0C88y zB&X%#l7lKHVetv8SZckA%>^gKnqafivIIdXktyI*lBULawxDEYB$-@>oJ;nnda6i^ zz+@|)Cp2MYR@+u~DVY_88pFmmZMQW*67D9xd}G&&`a zyjrD2bWVyxPOF_JB1|u7Ro0Ko02K0M_AYv0vAY3kN3~~WmZ*6O{MR^CNQ0YP3YE~5 z8RI5knV~MxjJ!<_TDxUwD08-oI9WSrrMH5ZB^aMh={18KN)@d|I^O~_8M7s0B`Xy4 zY(MFNEK`n$lF6p}W~{$uXU2i5_w>FAN9r(h%*g0ilgF;V7LXwyv#|n~wO6AGlE(32R#gUowi19wfdWV3zy|^y4GlQ|?PedpWsieP z5eFl`1xQW3WeYn(h<05kU7QXBwY#Iv+i=USDy8jV2BIxK=ACxnsqF=Q0eQvnFgvCA z9vmRhV$U2UvjuEjSGTpVBT45~O2I685mt>gE4vIhffilBv~s3ie$_ggf?+~P?kvkk zp*GMOg=_3oKxtrVEetf)ywzHEIDv3ZRqyur_IU%eVrI#8`tL*c4{Zio+q=*h~nj9@VQ0B2LG9i%!g##OB(GnQYsy97^wNp4m6F z6jZXpJhL*KxPuaCgGScR1^~0t7nYb7VLdaG2DGYn6;&>Mqx3o2gePnmNI>Y$iiU@J zJPZ#4)?DgrGVNP-ZEm!J2(9z1!qheaOIjEqZ2{v!`V<>w>F_yOzh>jtJ)?m(< z9bD(qLIyDN)oc*Xl6vT$vP^d6s^+#1RcN_%O*N>&UF5S4TBz&k6{vc=q;-X|cUZ(x zHjWks!H(*IBVa9P65r`++4T8h8jRfHLLjR&DS0|5&^*#1lN~i@%A~R^mh@zoPA!qS zEE6eXUplSSe#S_P&8G~WSQI)o$T-WgL0q4YDEkAuklplDCQulXs*j-Zr&i~mRAk-G z9u2l&T%=*JYnoto24G>pwmb;z9jn*qlmkVVV$CI-iXnYOGo?zHXcjXpSZQE-6d+sK zMH}bn>{K!wZEQ-Rfdq3>3Q+QCYcvSHN&|B;KGOhJGg;8c6}50GvKVeWf!-AfjE_hL zLeCat((2i1BwQ7#Ufj}z0IEq@VcdWv4XZ?|Pk3&e0YFVyCmjG_X^cXsv+1U78Ke>zgBM57hZ zCfWzvW7Vk7E-voG$UGXZoLzy;sFE&R*?9K}Dj8d$6QIbeBMaqXeZvb2!F(8PgU0OC zYIkDjAzXC8DsT7_AR}!ZS*+kDl5G5<5s*%F^Z5ZP?irx+Z}b&R1M&NG?4nUCah6VQ zXus&TsC|^iLT%GdOjV~_8`s0wwoZG?_O$Eo9ZMrePpD6D=`~^}jG6QS!<>Y*mDwK9 zfA0a|W%aS@dR572DG#ku1YfD>7jJ*RfsNPBWn z0%{V7CA8F0A8O&vxzEVP9+U)*AzhZV+~`zkdgALqJ({+&-G~^IiE|VyA{`R0ZHZT_ z(nKb29aD*!)k(1(@ZnGY1wJ?{pvwR2B^qj(-sOi}y7JR$dIxMktsoX*{KaZ=;0*9h z=OA2(pST?kG)Ge{%`C`7<}!gCoF)7yU}gQP{uMr>|K2+z*TXFnMv@5pTyf9*npVx!4%U=2Mpzo&sRid9C}Cd(&^6puZa^g@ zxJE%2p_Yjp7Vk1~c@xAPsc)p+RGw@n=CPlQhcD!swvJC2jVl3DS88Uu74=VvE)Q2V zB&v3z<&ri+tnoZ&Pun@&wkya1w!PCre4yF`vQ(*uURu;SP_dQQGOJ!N$$Dxa0Et6108DXG;~S=B1Q#>(8(kn zaGkSf7`2(JK4961O~Pas)=Dt?{)+JS`iZZl0= z72_H~w*oXytHFb-Q@_W`^lQ^D-5Xc`nxWFz0*=4atypkY0(%^Ge){_%VM+~H4j!aW ze-1ulO?kOB#SCC}j?bgF+edmx&e3q5byX-rVTWtoGJ9@Fz!j?qXeSh?3uKB3fSmI@ zSFQQ&|Eldsd);A`)Dv+$iWgo1Gms0ZQ- z;C7n05F67Nl`+Xd3!=*sIT)sX(#sJEB$d_IbrT9!=_H*lFtn2;u4_ymzQ!&bQj;A z$aIA7;$S$t7zELQ!}ktu3&ej31&ng^-bJkdaix+=(Tpfn{N=Re9gp(2?M&Y=l}6x7 z8J}BZAy~cln-k_{^a$rbuhHFUyYmFBOD|U8R-Y<5VjUGqZ61_$RfR6w;-Lc1MG zrzkjqcv;~pJNBejWEU8n-_vm`JGAhCG&qDs+d zNum;*+%wM6v@sFRnEER!l1fsUiL*t{v6EQ#-R^MbXC=`Z?0<>KJ$6XscDXpoc0>Oq za{6i?hIB3UJ1f_=GpC`BsnKw7ab3B0;FZc}av@?B# z_H0i_A(=Fh=1GbdtRUGLhpf42g8|3ZFkfQ1e5))?t)+0(v_M+ZnLnw+-#TTWox2Sz zbSWEW1koP&$ILD^#+q;<~<$4B7=J%As&HtF(hBBslRS&=wqs6vKscx_TI}_<9=%1wg*3Y;qMH-Q1YkC~CdCE| zE5=*r0aT1v0ZT0`BiBi}MoFn9Sf|D^Z%M6j*AFPs4CLBXPT?DB8FzJX;fU73PAYQk zVHj2*9Ql(`<1j@m$xB`b0ATcz|P4cOmX)2eH&R845Ix<1+%!LP#xD7LmEe~^NL z3h1itX})xNr0o$yE(yDgv-8Q^`i0Wr>`ixU*R&f3=IL!?Svfj7>&_8sIk2Z?`P@*2 zIVJTF>yGwWbyfqtQcJ3k%|sRVuK$iM^+9Pca>fc}ZnepC7lv34=W?Zs)nzTh zW%^TYA+U1G?YKTO=Mb&38r5H>Gtq8oq8?R34?rP27DnJgVL0c*NcCq){xo?*5Y z=USYs07>F5>SUxfIojHZ(~fm^Npa@BBG#GMIHUFdNNW1ZN{QYn4@z@WXsw^Lqi{i1 zcDARGo{Lcrt7P;583#woXTj5N(FSn{Csg_mR&B**5Gm>sm z=>O^Se~)ly%ti%G4P~2~(d-sht5AbmbNM;~eVk=aiH5J%tBVBvknZybiYq*xOXo_Wxo_bW@@^f|3(z zJSX#j@Hh*!IN%4mKy(sFAXa6?ip?Oe9!7iC;M1?9b7m=ntFNA8W*v>x0nv7LAt@%X%tns2|lej&A zRrXeA=n=Enb#Ih2)=LnZ({V8qrU$9N({`ah&)0G^e{W|^&D~YMNB_OCjbm780Ecbp zo%Ggb@I74u?}$p`X;9|q5eg_M}sWOSrt9=G(iuoISMFA3#P4?f|QUF1s((2U&idePgYztvmFZW1!TpC}PO=k3+m}uLtiq>oiPJ%ciOyLC zD10g{%`Ren&Fs=uw&F=te1hd#Cfc))bGX&8?c3drT%4@*>`mIZ9A55fZ_rXU#$8Hj zXGsr5UQjbdtAKW4K6H_3?`$yPCJ+cQXpZb(5>P0e4uErX2mi^qr)>HvxRAu$s z5%YT@JG0J{~HD#VaWGU=eS zb%$M%YK0^0nm3J%G8dv+lqprq+sXz}vVo+~N0XW~3LV;16&y6XbZ)vGivnkA=Gs-V zX}hf*(O0~Ha3U3<%hp&l>bUD_RbWbI7D=U$U_rLSeln|7${s>6U}s7TQ>ljXpThG2 zvj7MqN!rujkI$k_Rhr(j3BJ(>t6ZQKye1r1tpY!R~)r|ChxP8HI?BB6p_D57qPm5x#)z3jF^ zu>kaNn+fS~69@GBOpkKOnEr7ciXsalrat1Fbb5RPe>v-AjOpH@|QWsll zz~<6x2h;W@96kEBJD9ml)&d(_j}{?<&=MZG;qKXAuTLpb63-HEdk2lmyC4UcOeU&h zD7vVzb5~3ls$7;WZ7R2lZyOO2VB_rKD58q0Xmtdq-RY`vOFC%}kl(bnony;Yb98`C zKGH+FpwTrJy8PTW8MUYbQMp>>|(%+BgDQ6~K-TXQklSoD{ST)a@iALUy)K@H`ZW}dXuXrw0|buxmB z6D|OCvBEf={I=urdSrR+oMRRCMLPDkG(0th4dpudsEjwpNj#YyU6flYVv8ZgJUvp- zHjXABJ?3Z+(R)>^Z3M(JIyi84Vdn(tm07!P>(<(BG6Sa4sor!gMjFzcWtWsXq~a{O zP1^vLb(W{6QzQC-AX=%+h=m9VRzTS^?M5^4k;cmIK{$J4(t`B_1h%z~k4)xdP6jz@ zmywMQ+**coV%nSSDiGh6oPIgTsj@P(x#`hoY|s!A-f08OY`IEVgFamlY41X!(WdFO zjk5|WoC)ex)$CMr zOEt=mqcajnL92y=Qf%sWQ`PiEwD3CaVUTPuWm+Mj(`rDiH_%L~%_7+w?~>g-IF0x# zES=3wUpJWwc5zD_0~*pdP#A^n=`<3Y%A;#wcn9|1d(YerZTFy=?Boa2dE@k#cd(PO z&;D3H<=oP30%gO28F1mqPq@v^R`w`2;a$>}a@bJY@fXffv#^8VcS0-7(Wj;3(vq45 zbL@;*ZaR7^Or@tIJct-*}*wJ*?HRqMDXA!rle@>+AXe^55 z!tIMfCnZ6A1q1VL`s^t;!Rtr3KD800e`G~qBGygaojuZ9J-QtK^1U<6j8iPR$~F-H zxdC=Y4Q(N7Q57iDG~c-&Sg|8q$#(a8fV zNzj%X-O$8T$fupM$kxDAW^GeB8t9)~;yXCHTQsT6$MPW3XQUf&>O*Wo;c znqZnvRM&2#>uX2VnsQUj>Tszso1k2Q`c*EjBye0wdLn}Hg0`hm<$`$l2$wD>MjF>M z7T_mtTyP^5H$Uhm=olYB39MoOyPDg5hVALWr9b0N$$siEMVYi34~==gcxQ`vqE@9a;cA-6WK&s@bPR{jQq@GWiqjw`=SDL>9&%3jtxvk5*&hVsLfjHh zGrFCu9+}UB4;WNh6^myzyEbsa@lXJ4aAAi@~L zl!3}N2@Bfw$l<`5s<7DZoeFK&6%i+DL(rCn?TKGFgC-T@fUc-Y+p3w!MqCNYqaaWe zGTL39y}}n?>1vd5_;mto^HfLJI&!@n;jNBV$IYHFb!xU|SF~%ET-82?>ZG%7ZL>oR z{0J=C?!}={YIWs&IYi-aJ!3jtM^<=p%XB+L!&ZrocEbt)g~NsKrUY=8AaL)r+nZ7!Fb$)Cw47hoMe;E%*)pb9kON zA=TWl*UWZ&&bTS4Zkk;mt4-}Sq1~;(62oCk>@*#<*mZGMd7_#i9R)b~EQf}U1Vc`M zmechO)eDc7TheRvcGBBk70T$?>0tMXJQYW$Oi+%6r7XnjR=y^eqwSXkdDt@H=#|q$ zNP`f1ZZbX_j{*wy(=V)W9`oe{gbUrfp|Ba2RO;XWIehJhv}9znr#9f&zC9hNX!t*x z(-N3dVpSSbeJnCzFSSrF>9)nu9du`wCA9*pwz?2*huHM`NPD)UIYKub!{%aqdCt`w zGAI+9Wnq;wSv~A^9j3FavP8?(WSeh4_QcJ`ELJ)Vc&E)ixH8+V0R&MRLbylk`4~&9 z^YhxWrym++)W@Cqv{}TIG!xo1s0DwCIi2o$FyGt5t)x}d?vQRMq9qMLy4V&(#$(sn{SDGas`%gYXHPh8k26ns9ig~%wbyV z1sQmaR@^4ujV#=f#IoN(JP#7f#{9GXOSIb)WP`0NKnK&49;n%iOHPTsBSDjPI4--) zBrVge-e%yOmz>MvT(F(tazfk`2^TC_i=vlEv=nB?be#5fo)XW}UT649e72|Fh8Qli zn8`sW!!UYWJhvp#e%qG?0u{o^@U5_oPU4?qrgPLyw8tdC5P#Ut@CjOZ;5!w~1=al9 zoi%2mI4nJk?Er1uLz9`li0FjlX?SYd_6DsHxk{rhW(BO3VCE3j*=HF8&pOc~+Qc6RkPGM4|e|kzN0+In%@30FzDGMyADsWGWlh z;Tx-L^b#gz$@Vj>+f2{HbeYY%D+kJ@j41&wVp0JJzL|;Eh)3+z57xu+y_31N_i`7Co)cYsz@<4`aWk!w zTjn=^4nruK5h8e;^}-SnY@xtG$UJxzkgPO33l#{eL~R%P@Mxy-Hu8dC?2KK;1 z^H^(0ORcl`nbYY)MYgAfj4SNA(m<=H-ju}W8qhmU4>vctqjBBR-zX9ajB{yLEy*(U zRVPtK@cucw7*`o3hULy}3HUSI=WHs;f=As`!Q+W#?g8X>TWVL4KAfCKvZET>llriq(s3t$)jhwK$3T6qzxST&ogfGpbK0p}{6$Beb<$8=to{;>U~L|xsW zpV9}0lAD~@9LKymhY?Xl7b9=!D!pydtjGraxv7)GWCjdsKuM3nkL~ax=TdJpWY2o} zGNyXd+u#y8GunC&h%Nou-m{}ywgV9QL|0<@8w+#;sy@@Mjj^`^($TpatZWTu2upoq zl@v3xpaA2s*QXfps#YCa`vPT=K-QjK=40_rLO2yxZ>f{z@lp$#aNGn*NjfhqWmHIM zIBdprEi6hblX}w`H>=?=g?iT7<0(4{%s2qqU{!%n$ySC?9e)Eoz;7rZ(JA#nK$VUr z)xm*4D(Yn%mgGkuwl(1-&JwSy1FlmQXWUAbO$gd(n%0S}Mlm50Fy9X7W&0R&7Cz})zes3MCF`ei1cfy(j!XFDqetU$F^$vdxk(*EdZ!g%q}{kGHb&NUZ_M8VF^zU zZ-LS0PG(yLY#!3!XS%7jW+>AL(ODhrKpi_Xr{U3JpakuTeh>ZHVd|wTWw;<6Hcujs zxk@*ToabDtMoI=$eq8gC29)lOqtICxU|UDApHoFZcxfzE81o6iP>~OmEQ|%|`qU7- zIIJOBi?nNXbF3+qq-Wq+gLDh5%}L@d706LRh^*bNwxAH5S*_~#=0MhxdKYSKo2H$G zQb;ADDu|@oR8P%U;f6(uFBY=parFUT@Z!I zMMk!FaB;5v4X2!J&Wx+mQ$q(SHiKsoJF7tj)K-qKYsD@V)T*Rxhp$RRO5?o>$^x9nJlqjvF+4%l@ClU8JM zS98b}x0#9$IJGaOmqqQYwJQF@dzPck%KpG~;z% zjL#C@*uXPWkaYgp&O(yf>}zap3$|cphH&&iws@d-hjs@7SXKqK;?7tVG{`Yp{bDZL zs%R@}FCEiU+Tvyhh?+C5g>x-a+w$FXy2-Cfj2SJ%s_~Vp^q+Q+pna$oXcfh)6j%+YXjQE}kycA=)wZ4K&+{3Vo0dF)b1bN3DYDKfa84+P>8iq* zl=m@AAvbiiNDrCaKGL6`<{YE3ysp@mK?ZV*2(P)#lpY|=*s6nhE z0G54lTYWYHPEZ9NBD{92eLy&8R2VQ4C9bZRNCu zR6_T?@-NhyptgB9p!dZ?~iSQ6iNkHc2;ex)1x1+H_@O8~W&j_Wq1!$Pqj_ zMhPC~m11RAp}Jr|#|K0a{5{Q#<8%xATw^r{yoDK+#lH4Brmm}2EoGg7 zNieE9Do2jWutA-zxK+x$IynmPM<RJ$&kKqoVOx8sCgI{@G?ueW+f zqMbF)Nbyk=vLToh!X$0@G*+^Hkmr8^>D1wLirO1vYkS)V!A zCi^NU|4#-&dzhKtCS+;5YCmX4!#PwXp>wS58y{L&mgvbv*f#bd!qJLM#HPcnY-ODq zQB(bic!>3wFCj*vJJYy`DQF$NbGI~FHkf21TH|V=4#4aJP+BHC->(Zqbz5#akFDzB zIK7ymQ^KzMBl=pTqK76>Lo`QBZd1a_Wngv7jnFCE&L=Z9NBgQ%Y1ueo<7~FC$E~YM zh!<@B4SOvIgq~Pu68tX;T z8N8F~8EHp+YKh0OcLZ;fhSvuy#2bB4yqn$6_fTsm6fdR#DHiJGbQDg-c?Z6FuM+*Lg?Z<0Ur8nQ>+$~LiAWh?7fEz^TBUyo56!_t`Y<7v zA$cWgzeUdHdaKST+mzC_uM~DGcJoX0yM%K#w4wds!72@?S6tM2PbxXazzglik0@PQamc7J%f-4)gNsym0BB)v?tJp?oIFNROw1k zq32w$Ta#Cwf!Ai6ZOKPI(H!LaU6!i z^Wtzqiqn+Zk*P3l);aE=)>lbhiDro-9R3M7DyyV1t~NJieReve!#>+ddkKnrCd(B| zl$F!6z#|Xz3ay>nZ2NZjUd{(`}e6Uh#kEoAauCr$rT z()u_@36V4&C$!V#4Q-P<=OU}U^k@rF26@gr>_XKHE8Psc8>O=Gz~HMNbpnKke^P4M zv~qMR@sQpDoh;wTPF=FK1$P?Vop_48)2h#8Q~Gvy>Q;KKFZZU}d09>~6LriX+Ve0E z)zlM#lP0!F?{ft%9coZ-EgGyuiAw>UuDvk8`x@~iU1xe_DO*b)qqD^0F!Q2G@I+9y z6wsVNMd}_?zAa&2=%XfI4rSkA&wZH{UXzS3%2r}sE zxJd1$+Bc(4F0x*!g^d78c=Q<;*`^aat`i!LjPWwsV>;E9A4SV^u`(MPZ;CbqT0dtjpPH&vs)^6Gw;g zpmIbz8u<>k*=6Is@tlkWV&!XC8>C$Q9fff5MKb)v0xzzF@$V+}FBf{LZrbQjv7&f` za$kHVM&`?^hbSh+pqOlTG+xLw6#tFE9o0%@Xbnc=tfpH0$6xfXebM?{JgMJoJQ{b8 z1r2s@f+f)~hvu7F}B3~6P zpdWHW&p=tmtdzO4=Sa&>W9w6m4dr9&aTaG;`PiyNO>6nsrt-0Xhfr-E`?`N$K-G9^ z$g(Jx%SMkJI&=($E73f9kJ{Ry_}`emovs}Z)%mo$Xug~M<+wV317CKja+ zZSM@YP|V?{$9iK#)(6JA4`7)KEl2?GcpCcc3<*y2AvV7gt#(tP7U4Oqiu*=Cw`$)%u4X9< zmDIUWSq0?o?bP~NvAK1EqYY%-<2DXJS&lxTG3}562)CORu_JwkcXWz&mV>yMc?^5c zhHjf_V+X+S1YLZl&C}rqy+-%U$p zOzDCA)Yf2g;IR&EaOY>aP(qEdFl`VYJQhH@8;fe-6s1D^3jt)6R6;|Pt zD!j@`OQ{v>aZ!$qWsCLFaF5e`XBFwSg$y~nIo8@NmKmGTfY_m>-oKpIm9^%`oCRYz z!maBQ3#K9iG6mhw#TE4gU@0}Y zMsO}XKF@7$JknaOMT|gH&)}M#f&p!vk{9hAC^>A=UgM*;n2IUqE5RnKa9UGpwPPj5 zn91Qt_;edsfp6&HY;y+xqMl*@>226GGTN89W}f|n&h$zXJnts7E}6ksNGpJfbM5C% zoipX&xpVmHf>_M}jf3%e0-Ud)Q^xc@4Usy;;;88ah*dR<^j(a*Q7#akS~+LpHIk|@@n4cp)=nRRG?l} zW4|*eo9N*6wr!iy0Z(Q_A=MCQtV*C6u@`?{e*yS-FGWu>z=)}Azu zux(TMsww@-ovh7xA#|0FKADx3IW5w54;aeYb_d6XwOv{CSE3*>j;JVSZ(eZzAeXM0 z2j#lc(9VGlh9Re|Ug;SnI$K5}II=^9x_0K*cEGkr&0(Mszy;~9E&)G+m1Txw_dRBQ7ODqz|n#5kTAA~wbNRDPn4LZ zuvTGHZrt7t*u}PO=?rmK6AJCFwqxk!cQj+YV?L|c`ju^m)o>V@=e`Ls>l1zLCor8k zf?=nvU92}!?LqtuyaDLd-W;9nDe1Ea5{7vI$G2VE%Dw(&^zAC9SrGpG?|rAOnqvHWwo!IaC(K4 z&hgvY?K-AKIzwZhhX~ITaUvh}rj`f{4c5U*!Q*ACIo7A@~`y-aBQlGGF3+KS)61K^sZHe(F;CFqRA!*k1P?&WllPzd$m)%J? zW*+ykdUdL5v$CC1ST(T*(W&c_(y^&4?icE*qnP8UR%|omu~pdig{@&KFBw6pe|!jc zjNpVidkcwGo35o82chEWM!-2#gd(?y&1qPjL~@Z^5sA9!6~;|fM&3~xy(>)pqy$2* z>njDyJ=Z+T?teYk)|+6}oLZpczcQ1y`E#8<<>Nn_%hPr+m#*p2^O6X&-ili^b~J(b zogn%@nm+k+MnZuhhhCLq(1I8g>f$aOFy2hJTf93h?}|^f{^=sEs`}LTx>!alHm#=R z0noaux?17*3)NgNL%<}cbwpau^ykto-4TjcNb>WwP~eKQSNs35_iizEp67nwj4Vpz zh>|Gk7+Kq1rlmz%CWkuN+o5R5JWAB2NSZSgWqD`YYYrqwnv-VDh@{}=B4`6ND3YQ` zfuIeF-6CjjiXtdlG)U1PNQ+z)!A7r&jkG8VG#9<);Bkg_}=Fds>_Ad>Glkw(D~n_M+xN@T>zt*mI90V8D=t&mFnljEJ;)O zn|+Ap=|#p7j(VcU(I(DW3XkW2H+@*KF3CKTDhv|qg5@+u31!jiz&j)|b@CZ$KGy|{ zU`eOdKTNt@r{eR_)Q$Ay^o`EPUJ4eB0~`FssPtwkS;=~&mFZ$SR}qMLN&Vg2KDZ=J z0a|d42(gt%dHklXmP5(Dj#b^cq=%-CS%gx`e@&C$MbW?`<{C{KlgU`b4MgXnwp|cLY#-|PJ=C$ z#yOnQ)tBURSX7OiwF|66=aY$n1KTmhGuDaX6^Tly=bC~DTc!(moFZoCISt!iX+b%E zo?`8eUUl{5oi)+Y&N1>N9_OW5s|Jf)ohtDvAM>|y04vqU_!z}(LGdN0t{d|8yYdLm zHvNw!s8EJJ4H+gdCl5ap)>eat1eWhue>f{iq;OU7Qg8n(7{!*@b)dWin?7$^T|2(=l+%bJ1G?FhN?Kzl^?C5{mh(idES`0)Cq5?w?W44@!(k3frj+ac z+}uaq@FitvZNZ?=^yGCatr9k zCH3x|8eG0OIQEC$hO|D`t2z!(ZGtC^ZNzgD**{d$ejInJHTJVNl|H3=aZe4-UH_rY zu+=-q5n*&mP0WZQ<^d&g{3Nn{Sr+?FZge3J|75)%s z%8}FkYF)RjT+$FQv7O9)zFNrrN$f8rTOCX>Pbe|-w8C#Ep*ktUSo@RCjG9Y0qJ_g} zm>3fq#CIu$k#9XK(gX+3tJa*m*}0&wbHq05cP~>RbTvn2%T2G@fA!TpJ@|8a-vRL^s?^5zAuA# z{dVWTZLvMM=&`UdUiG}4;1b0)L1QrLuJmbNZ0fG)sKC2=JJgTb3dSQL4NSV7Rnx3XJZ9i`gL_gY zd>xJGdmS1Pj>xPNRnPs10d#MYVP*rllm2~Uv3t4~vTMHq3`ihwwFhf)U_d<9O zw8`^h6=5mV@v)MR{f>Fmu*P9#By&c6I*n<5t@em8mmsP1Tcli%6_lk3Wmva81~any z?6SE(^{!26(4DTc&=Us?IccOY>af86G8?w6g!I8Ad`@q9Ip2^u$n!3a+YkX~l{;1rwr z_&2rgjI};%9YdOH$vg81k!AlFj;bxEIj=Y`ZVe9UxcZA415v%5CubK$p1%=KJXxt( zwVVE1N^~cqLf%x@z*2)jzky?RaC+gL*7ekUlV6C<+KlBA)nh2!vWhH?-&Ml7<fEE%$wWLrprAz-lg#oO)`vfW&MbSNExhvj>7#Jv9`X zJ-x7XvN_K$md8F3dHWJE%0wa^f3Urxf4nsaOSMVmq$+9d~ZS#XNk=V^V1Ow(4R9=QY)BS{2cn3RRW7tvJG9VI^GQJT{+z+%zsmWNxo6 z-&|SJg>)@J^5~h>?H{V@3`tUdTwfe9mDBM8qY5=M#!tCiuM_StNdHtN22|O{EyDXyfHE4UGZM{JAB?bX-o;Aw~??a zE%+&$#Dd80D}=B6&AM0LP={vhQVvl0+#cVUxW=P%L+|Kxf+D2l*BTN;mW;*V`CABJ z7V8tsDm(sB-}XAhHJ!+KbkHh%^^|$wTkK9AsaRJMp=0 zHthz75YKLU6R&sQAR|j6PiNoI!8jWAzP%&8tcItqC46dnQU59*zpQHHy)E&D%D~M< z9_~iR}r5mlC4(LU1vua1#Cp8N~pv@L?~+sPrJoMp{$C|9#h#Okn|$ zPGs0~tMtwhhMKrp&F=Ou4!9jH2rQPHC@t#n_2t_;t0Uo4suJ(r*mtD9;A3;oMCK>$ z{L9DYNc3Ev@I18>dZY_1LSk>Yl1g zDYV!A-S3xuh>|eQ@5=RUty*_|_XT;BYU{{2Gm{{0V!L}=-q8e)+ddrxWN8}`h&rY) z`AgdzzmB8qX!0CKEwl;yAB4m1hr=~vfo4^O@|3nc1xu`pdba~xqCUa%_s%IHZi_gA zs;DL;J*#@cG5xY)k0=C&l|PfC)B7H~!?->(Yx3N}udZa&W;fu; zm~>E4YH!cTVH@~If`STaBEzV?f_F75G;FJ_(6n`@r=ubg)ta6Ky)-ep3xK9J_GBCp z{@XL!i$=QOXcQ7?d(E*PyR<$q?%gxaVfE6A0;(+uAH6g-Q=$t!o+;kl6emRpW%;~c zZ>zokwrTn`aKD%|pDZKWOL$C!U=`U?x}i3wIw=?uqM%;MXz%P&=Thrr25uz#dcV^$5foTN+oV&@DTEJXO^cs zljZMylRTokAlh^rEUyQ}Fv}J95m+D8>EB4|L}z7oWT{)Jl)v*5arp)k#w2JGjRhCM zt}@2Yd?k$MN+70`E1}I@U=YO?^GgNXSZ6NcW(`;6h^)1s_qW-JW{`pl>3Qx9b7TGc zMFD=}$bIEF%*gX`Ab8+O!1Fbes+paw_)%u$ay-z%HD~0MJkUu{y!lgop9M(f<(e(2 z;mexibmx;fwca5-(|Yoh*4|WI{j_mb;>3lmF+RJvVwjMri+7`T(R}`%`n})R8=q*D z$lH0^MXXik3Qur?f}2g}7x%W3gy(JzAb2v+9(THK>M!7#43;!bSZ}~U-xV`9b!Dhv zl9FX!L;*YfAIZ2dy?Ij(M$4%m<1JMhD`opKs)8$XAfMslXL_1Zdcb7ggDQJ28ZymO!w$1|t1O+WL_PY*;b1dqXO_ixOcZhpKfhr&$$=#-3A z3>Udq7VpfQe&@iAbu-H2=ejLP@K85r`~Kcvy?@|3*4HVoR^a{|_hI_&yZ2{KZmE{x z-sZ^z>TkKDq6K>o4>aJ^cNP1%!tADgRv1Yj^aJUb*q0Fjre4Hs!s9!sWp-&1&&jlP zQu2a_^s2#nc?1qmeA31yuo|U+3!B=wH=DlM)>y|a8 zV(;7HgJjyB)PEetticmWO>-++O5t!}U$^xHvWf3bN|uzKs9(u6f}_F@$NG=b&IZ@!r$1o$IvhVk> z>o;{Hk*-yR8Q&siz5@HzC+ftQF44Jh<g37g z_1U{CpRFuxY$4B0YYF_>jAIr`7_UV(OcRIQ_)e(B? z|NfmoXw(C4myO6=W`l9arGn?_=yjrcup{688b>~sH$Z41>8N}(&Y+OLIhOQbXF&o> z$$^``i=hxb8;1uj4naQoBf1!ABaZUW#W%a26AyoBg8Ae2bd5J(*8JGTl_5U3trLN3EK;E04aUrY!k9KRd2d1 z?QnyHUU8#o7%ohT&sZ%Or;)^(#FC`yq7vpld3?4{pP@XKSsycET`;bQ%kh>eS7|v* zfQoM_*Vz2pU;yf@3#x;SMc3dKr2=eitVNs}OC3-lrMH12(jCyvOHt(D6T+!_?Ec`$ zoMGi)VYK+!U8!GVE8*!lrv;1sF3BKs^I=;MW$&!N*`=xrvKdKm0)x2)+&F_I^?&rf zqU(0UTZ;YXy^f<7J+^`d9-H#)_8`Ptk_lKlvIiss{is0<--`7n4Guso%WWwmvZ2y) zp862=a4>XTa&a{7n<{G~LrqDJ2|2n5Rp8>LLhdE-d>Go;!reO?@?p}9*&L@G2l0#u zCZ%L)SQMU2bx&Mh9$G?{)!_CK9_$0Zd5&pL9A<*R!Jvf=hCLiaoMFM%7Rlcy@ z`MW|A{$j^bm-Fm~n70s6C#Tv>y)rM%Pm;yR;qFM~wkV~fA&`^e2_PM)^#0dgnlCCR zcK0sHk}|a>%Yx`w(mTmXISC8MDY8pMe`Mtup1IQOyLH&$+cfy}9N5pk-V%xfk_}Zm zptOiSKs*@Q1Tr?(wj0_UtFLOy6FGkym{VI_8*_GB)n1V2$HHgaUhWJ^95)3YVJSn= za%otUwyFgolNmqEnsg7g{E5j$cLqAjBC}neh-O=tl+Pv_rX8e@KyuV}&V$|%4L&pk zSOZxz5%s0n$mF5Xe<@2b@X$9HgUXP7GOZ-^q?_Q#Li%>Smnr!dlQ%awt1&;&$~x|k zq;+g;(+!>r67F*6mV(oA&q&{utX3j+xHv)2>?WuG`PTp@8%FX3kElT8@(1p~kz{~2 zt9I+Eo%?&+;D>+HZ^;kkzJ5|NPXl2G_~iWlq^D;3OLYXPXY)t)yiVh&kp zccm_Od|+U{yMo7Wdth(K^@HZtgP(_l@fgHo{h#*f*@^Lpd@EW8?;cVL620rx(THH= zh6l-S*=c}s__ecwoO;-5*SS9oa6Bfj^%ecRp*PQmx(*=epPrWuPj!b^d!T1+%IeOA z1}DQRy#K7V?H&(~=_248*Uqb~Z^~vDm-!a28g*E1(Rw`V8E03_rkU4l}K?fOb5CnOvBmYa&L^DH1w}c@wG8he3 z#h>1k9jmbS7-PwJ3J%Mz6+;gxENVNOj3~I@%+1q$Q%E}l6^DlRY~cAE zmvVG$kD6KdZ_eoIfiIK>DD_xwrwyyt#1Wd8E4bLAT9lU! z`mI&n${;W(DzSXq>jP`k%qLCI!;U_|jwWq49`H;I_$!C*j#1BdMK(L@B&bw2ANbxm zVi-gZ99X z%Tm5xfo%=yXYq@q?w_v3;ZKR-QTLE+84*IdpN3++qUs^B(Qlvki%dNs-}-&}jiDjW zsS4e{)>=U9ZHNKizYvbUSVn;ioKEw^cs8~ufbW&3mudKX+yLZC^HGJIRu*g9aVk#j zaYuIFYEc7M1NCKbNz_UBn1hnC6fQW%2^Nb!{Psh%oY4 zoDUr&owL1Qsu#iLR+FAI;!GG(q1nz+j%dwUnEI+?T|JebWyg>JHadk6%QY8Q6_o!$ zW6(lE3nX!HaJ$)n{8Qcc&vd73Q`>|g25`G(>4PJRemsbp~a_^4B;wx{ijRz_ulBKQ| zFm}TQv?jRfu8eg_(2ezOVfKMog_M3_X|&uTck(h~CvyJ`wP7!e_=QWB;%kC|MeHsP zj#}t6f@u@JP8b2yyU&T$`!@g!3Ar_h!P&e8< z>ND?HSzuHG)-%!5nEFii6CM89QuFNgtG4TkYv90oYB5Bk8njodT2JeIa?Ts%gwkho zB3DnTtAR`P;TH=d3H_>&Q)%YM=B-=Z`e+z#`KxW@|B})Y7tKJCtYZt;l4ZokuZ=@8 zj3DCDrJP5+Z@gtk>#B0Gbd8d|FJ)4hD^fY1;I@E|KLx7~H^PGU5F<*ivg7-qpSq_o z!@TgcWM*`KK3?1tJHw7V&&Il7`6U`wN-c$Z#T9ZPvvh6g-}hF=-pAbFixN-#Fty2C zfrlv?w6nHAtCsQVoEpL`ggy9qkw;()7Ak_vq%C>V&aHG!D)1Ex#fdm%+ciR zlgoPm*6g5N6X8$;6kd1<_*S+pd!>rgvHLl-gBbH}^SNy}DpqrFUR|Xn4!IVfd$fb{ zcg!pOSt`ZUj}uKia%2ADiPwMJ$y;aATR%zf?BkuEbiFeD_ky_$$R_}-ZMbi5H=`3* zSShGY571|RBzvPB#%LI$qB1n~hC*ncMI{n3kJi*QcHPa^l%UX8rcG$JHJ5!-%q7$U z8PA9|feh$JP|LE3^mkS;V8o0kCU58%Ak|*GzVmf?T$4RP`El&b+T*nsrDGw}{eN$c zKBs7edCQ(o&eN!Ikrz^<`p`@_s*a{PTF#fLFHZ6J5=Yxfz4T`+)r4vxl@SfPd;y`J zsI|C8^W+LMf9Rj=2^Aj%r2t|q2#tQ$>|JzMdcC1JN>;2KfSQ+tYGfn0+T}dPl`jq- zS(R8TqaXW~+QMXW30!x2k+~(Rq&_%KaIL zxsr6e@GQC(vfmlRKd;%dA>zBPvj>D*Cavfv$)P|hF` z_YK1gN(Tv0{>*|du7Wa>k|2!a3jNC9oEl-m!dL5wNjLxb+`66}_5l#(qs;;R5QGw88xJi|9L4JJiD=UTCu>Jq4>Nq?_#Gdgzj1plH)F zeLSG6iY{He=sSglad2=bRv?nIA;}bEA zjOR4W{-MTs<&9S?iL3n@cWgnIIMC>Uka9rM>yHfOV&AdAQ2XWMFq^_Rhc=9*3$tP% z*aga9voPxE;hF7i#RCWD!!28(*rYxB%NpaFF=&|Jst6fpTEjUu{g=`*A0M6tR?7o3 zKI#yXCsAXX^ln_R^~lf)^lC31Gdpoj5(M7NVVUa1tnM@V$Ow=h71l91cxnHJI5ncxFgeo9~+)O zJDA_tSY2@2zkLpGs0|w?ETXS5g8pu6kJjL@*uaa!2nG*gs!xRZlRCEYR?k#Un5C-P zp6rD@nK;reQ_)CtD5!bQa)gu_&@J%W&D;Ipe@(-j*XvLaH0}yv)Dk!vViU{84Vr}T ztO|_R3CPGfdTq45wJhJ#teI);BOoE(i$U#jw{&#-h6HG97)FzA&>aOEeFe;IcAq>r zyl`)MaYxgK<{j-xpRq|%olutuz?JdhNA)@})Y{}!MPD-;Id_xYr_6u%Bev&xOHa=k z3qo1KZqDiw-YUY)uJB|9FnfIu4?~>zgu>NoY#pv|Y)^7f3);{`(oCin3;4aiylUmv z?dK2c*-Lu5zIE4uYg<3w+6o-PxjSI|Go3@!VU&`a)^TWfiHkARRj+3YAX?e=i6aH+ zCab{P-FFTTX(5#Bp*yh5GkMX^mZxzvcM*kO5$ue%V<>p{6|D{RFmfQb+>%r%xWu6$ zjh7>*=os>thP>L~nUkDYe7G3)DYc|k{>d)mzGUNWYGjM|8rs6_nv{0H+S{(Jd}*%m zHnw;%zsG}=T#?Ro-|*V%MwLXEHP=ysA>c{-;GP_+2eV!Lv#8v?I&V0wk>-R1bfb?I zk8Ybxl2aQ8GX_4VmirWi?Ew!t2DhC3dL~S@4LcaNK}Hp4oI~`7lv%PUU%FgXv{m<8 za@!Du*?eN+X_c2XeV20pe(m;IJa9y#%@Ug z!sghARid;#Q2xi(eGA!lpaJADuVLK{46U_gv+2Z%7eLjh#cLpJ-XuAHyJ8L#-!N07gU99?W`Q{y^^ByE*j>W%`f-^$Y!eMn5k} zvh(?zCi;c`o!9q#_MU0xH}zeNoy{;tTJ*P1oKQF03+HakU%K+%;EXzpUAkgnt(g-i zYFqi)t}9^H>$Z+FwxX_?Uuw*J`O+12*X^Bpx6OYdKzt%loRO{fi53A+`j_y%#uDa~ z26k@#k`luD*YQuxIYQ8fv_N;`WCsYwn#(KNbP-0RERF^vsOY5)vSo}mC{)5F+%(vc z*k7~y_YM2^&8Z*gCw(@(UuFIcRm7^2Y-Fd@cDWpf{+5pZ9s8Ne($ev-ow1OoY7aV)#_1Rb6n0@8VA9yE2YiAfb=5p7l_g&mhC1yuo zdF$vque@btVHJd${`)O{<1Q8V>$=SWGlNqknXkWa9_2e{`HP4?&DVjxzugY(0{!Hx z)$cAUGkW4j-ZoRp--o@D&=rk^Ak6hyRL0yv75SKt9sIiHn936mj;Eb0W%^{?SdvNnA6U) z83`1{tIP&RiSa0~W)Y0PmvHBQI}<`q=A03dECowko`!TUuHxT|E9&zim$F|so&w+@ zc#ezNoX(?7zX=?STO6$)-PX-}8(*v}sd^=(gWcNM!tFKqY<=UdTu--`XJ;WO+I+OGK8l;Db9z(`tF5%=*_mJ?kIbXBv-!OW zvQGUqBYlnpwb{cC9F2Q4Bceo5V=On(Hj2CK?#O6Z78p93_<^-XN#H-NhE#IId75+r zy`?2+bHuGeEq>Y~S=Q^)EJB`AL#8!K_4d*2@U|P<~XJ{lMV~RQ93td3XQ=noo_kMMtG!#9ygs zC)DEM68m))DE)JW{z8P!)A4oHC-Z-^T4;939(F!_VIm+jbZoo<8c z{XK&VW^9$=Vp}Yq4HrO5+jxCX+t~6>cAdxQt+Sz#-H-~VYwBIOp0t|Ty{zU7X@d^a z8h-z?9uNVPU|JZTo=D#?3}}W&+?|Rp0WXjE11FCZNRX<^B#JG@5(N$d{~qsHQG@=9 z7vs8L#5p}-kDVf1{Z~2xql&N%tEKcC14$4Nvkttc$&fg{fztLArU2(wxz}?nTc=8y z-WJPcq^DuAX0)PQlK9veT@T6?ORv0c^@weBeYMA@ob`y7iL^I|@;j!={h0wCP}Xh! zrpvUD0tw>=nvOuT+^3+z~-O0M3jS=Nt1I!RedwnX*V->AT zQFQ}+DWegYwIXF4CErN_QH;h{)_1_1*$p)&p6LUNN8qCiW-knACIcpQ1}j;u7uN)j zU0Uf|=Tu1W*}&qvVhsu$FK=z_z$dawCnwm}&N|Jz)rCnn2UXqu)bfzEl7mk033=cP zo$Y`}ndHK$ftvQz%@MFTDc#zW!kf1AU7w}cK-Nh)i`v}R#F;=G2Q%5Gu054D9Go2M z@OwgYo|Yaa%?iuqQGEhI_%W$eu8?Ris<0~9BI`00mY2SV%MGicDvthUL+6h|S1NiijKj(dVP`8;;ao=bxrblL{ic}|2q;t_W zv^-}JI3XT@l|#(~nSoAIc-e)2nXz(LVIg=Ih?I-+{0y3>mgUyptim4rPVnXc#w2c( zSkH&t4{TQ$gai)VDd8`X6mH#JdBcxOM)mf_?c3y8j20Kw!~u#A8dfd`tWy8%^d~Jw zX7bL^v>AVGisWaswN3h)r7&oRVE*HY39=-}Qx!^yovj;s@JBDfaH#<&#fZuh0%FI( zL%(oyZv+Mq`7TyPFdEHK;m$K6q|nKhC?z+nl>xLg%$axw_2V{KZl2AZTR zsfAv3c8{ta0Pa<3@t^#zL!i*K&VK_isN&gM@*M$k2q;#AG_Nq@C{v-5__HFhiHSXH zw=x9ROXI?_wvzSnp5|%ZJmwd$tqCdCwSugWH2S-zwfxxD0*-`R$I^OYcNjTE)e$E+ zS5{Xx7dAqjbbGNErAN5ivdm#~&LwBw^p_@}BE7IM9T#zg9uH7LjgC{Lbt@w6S zlw?gFXj!DUzDo6YiK@?oyaQPJRZ6Dn52;pf-Go!rYq z=lAl^g}ppvx6w6_wy~y1?cSA(Z|!9$yR5EzDBs?ty^M5uFArVW%R_dz)u41Cuu=WpWu2A~}}bNvsMciQZ-v+~hhM)j%Z z`=|DYZcaQTAoRIIEKf=FD9s=N<=JYWt2Xk-GAN>>V3OZl6R6QyazbHOFz;1yqVd${ z;_E(2c3hmOu7v*rN3Jocy-SjJsTvu<@#cjc&c5a;Y1fa8)M6n zkjxb~2(#hw)3g_JlgK_uiNv!5viQtEDAioza$c{#RMp=Wie$+GdW{via?(yR0ohCq zS6V*EhQdQ58z;PT`g>DZyE3ZMNxYI)uT|+V$VHL1y<-L43Ob)#*_7L(Mvl)(HcG4; zMiwGAjjU_7E%0OVb+-Yk&doAMvo-*?-NzN+>S=^H(mI}q!+6}HHqbMTf!Zl2kA(p` z5>KXwDae3VDpvnD6**iV5J*oHQOD%I3b+!Sj0EdURDQH|k7cymOJpG!_JQ=;UmDMh z0do9h-XX=Gbq7uiJ}B5{2vnbiXX6T;52NQbJu7(U>ZFhzch# zZ%e-%hJCLETk{;V|8_tK7-+ZFB;FxkO1Y}n?eF}#L!fWZMFcaE`UhWS_duuIdv`Q( z^BV_%^W}Kp<#vg!O5_-S#di5N?_{O&p7e0xZwNq+e3)_jKdq0_D$z&x1 z2Ztklfni4c?Sy20>4YkWl%cPDmhl}`GL3Gl)TbsFaCk>voZ9QzutVu{c)L_u8am2` zSdTs>9K5LSJei2QJ)Db+#?$oQKEE|mm~A*Xzoi~c7uG-D*+A@G8L5?LZ6#N}!b(uS zkR!3`Fzck*5BE}I9Y5FgPb(^e?pcU;EO967s)nA7Up#(($Fqj4x}vrj&+Me7yzUf8 zAlY|ec&}da@MFb1VjMoY-PbHDj0}&Oz-bolJdGBXvc(6(bIaZzyRC0}#KMama}p3J zz+K8Jy-aI8Xd_J?s2Cik!rI5+HmFE{BMB**NdOg{>|5mM(AH zt|98*o;qu4|B|5C%)HMhl}lHEINm}!jQDxMe4xRIyzYN2aRH+wBezp*QyT+UVg@_` zx2#9a`PyYcE`ElMAtxEl9cinm?9f|^QHD&SH8mK#wX&#=QiL<+3vD3g7;RYsz3Rtn zP*9mzff7!&G?9j;bw8pb=%#T^K!M<8b}25~7(|a8*3q}Uk}F!pr(!aEOR$c$xX^^T zxCEx3iW@|67S^utl2{Mj8Dj4*CmZf8C3=Bh9M?N6ZKmPh{@V_1zldGjWWvP86c6>* zjl1Ig!urUiLfjy7q0k;m$rfs)@C)TK5{t%2z_-7u6buxSeBIHqu?~y*&CblcVm-y$ zBITWg(;!SdmJ;DY#H^BLDUW&Lc1LW(r<5)lgAPlrw8|>!UVOmmcQf63mto?ex{UJ= zxQq#7UdWPR@p2z5w%y9FF5~nAFC#OyJpK3jriZ^(=YCNNTr&m-Z8QrvAKRsF^JkXm zLu3!?LA!0M3Cp_V1|E`mgL|vmGrbUJlI%X2;^Q(LYW&}`d&+4`n;#}p#N-pkJ`<-X z(;sTXbAe|}(}}xsULpfK4R&jNkPENp07KJu72w zZLthoBWv%c-==16GR;f%IbuOUoW~eeTK18SS!ku&J<;^X@>I6!bH!cZtf3CfRJJ;` z=2A9zZ*-V9ld!ywA=XxKge6M?gC+#9Nkh0hzP{ip)?bA8d=6w0nbpq2eQo%KQI#-& zqEZyoY)B+PWx$OR-@=;Unhw9x5=F`r`5E(V&Bl0`Rp3YN83_Vf7FBElt0%J)jrB4v zQZFC>zu`sB@;W8%@9M28+SI>8sXHU(fNYLv9V;2YJuJu+vJ*y2_Yn%JW^hGA-&-q@ zR@y(AKDwi6v?SD0onKK)QAe)-^tXQIIRCym2>$+8gJ6|Aep=ak&^jiJlbW}riQTcP zoQq)a19+Z+2Ypr(Y5uUX{tcbI!aK^%-&s@ZD@Mu=o2-YXE{kMzvQz#w$glS}zP0!I~!X)&*c#n8Q9=(N_~RSB!ZI9{Pi5Lx|(tG-~+4A~2|n=O*YL(jvA-0|hL5B8#f) zHugdh19BLa-<%dkkHN8f5HnA>-O<0K5ift}VpaR5>YH9;t=xARNkbDy_)^fx+tv9` zUzE8@9g}WZQZldVZ|W8L*LBKKz~Zn)^zLYMgrtlc8ymW$@|#NFX4<<6Qj5579G)kh z1=R0f6xDIPPwXaX&6m{BHWYR)dVQVb*UBwxB(QCLCabLKpy0q9O^4gVTr*aq>%HF9 z_N3iYCdLtZMAgQk^>mtAK!|J$RKWi8Casx&Bg+TI=19ek3F>YA^+;=GXVoft#P_{y zS6kE;gCntA%!5w*yiIFjVb{54+g(Pqt;hn82|s?Izm2U3H_G~pXD@k|%UD(~R@{Mo zuQg`KkwQ1}xiDfwl!k-Ajev|>PlY+eBR4IjvWhi-s;Fpl40P&JF$Alx6bHEyTnUj? z(?vb{ETiq~KeOuT>f)CgX`<_&@d@{+MUkGpZP2XG&TQUw0ZPk)038rKRX z@Rt*C7|d;~S>LwkNuxlMo@~%4+`}=jCWR0W96nLGBdQSn zdyNzG0EH{aer6d%i1KCZ7Nc?& z8Fd}}FQqRN$>W$uGpRQ2Jx?Pe;omSI;Q1Z|#J3ygYIdA}L7^BpxkmpdA}N#IbIcU` zJftQMRU&#>+I%zD6|ByAxJ}7&$eJdp@sMS+bqJLgTSIz$Z-}Qho%;bFNUC=2&_8I6 zFqH3C>P^Lt+a+VGNY?$f%?QkO7o!r=uG6aVs(NI1?BaB54P7gUEV2Q%w9gmPtTw55 zTYz0{+kZVw>8>k~i--vPn8Su4tm=1iIY5cXubXY}T^EH>G&A(jqf4J#PZm*H{JXaJ zk<`P{>V^e}l;t2P7G32MYM#>o`GML&P|GjT;k6F4Q>rnb8cj(CHX>3iU zaMF2tW|#d&tqmW3bV+7y5wo|p<3H}%F#!rOc*&Z~(p?IdI+8Pjc(P4~(~vuYfa`-1 zHxkPg_C%)DGSCXP@vE@^yDML+0zw+eNafheQd(%ru;Mx;XB#AWw~H%^^N0xU5vcK> z>0ke@Lq~9ed7x zDKtp^$U+2t{f_5Od(Y$1~z7enX;*rzN7TybRUKsZ)%e-^;c>* zNu%;(sQ>KjGcwA^nNqw7j=j`2gEEU}6LTpB-y8!cDAqV{ z2H-yPsmx4$DCzc_K;?WJyZocwfPE38p>GFi{3PQvx{Z&F^o3r)^m4Q>-JmlnX;6qU zW?X;Zy!*)ESokm9zw>9Jn|yHpWjeTMMph1Pl7lGaTiKQkmf@UYaLKrhHO((s&PdI@ zWCMi6i%cds1MJP?0|gK7D!GuK;^!;3?mIOZamjro>f&y~di?LzfEZCsW>y4<0i3BJ z)8~t=zm&GFNMmd#E8eL#K=m|)XfZ}B1r7yFV>hU##rPz{V=&MxsKeBnpTOsfYDo5T zjX6LS;%cjEEAh1-vI14yi}OfX_hOX6#WO#L9gPMH))-!;p|;@~OQNN1 zmTE4!Vn-Ih2}Ud2oaTEeIQ6VYo{o=+$?32YtWEIO%>mkMPjXFzx?$jG@AuWV zs+!lAn;V|0DR|ORGU1I~+Fccs2Nl@yk~X<46R7rG!${kdgt?rS>bR z3~uOoHz7it(f2=T=E;4bSwm)a!{wN=pa7YOREZ$1cX<^as=J4Vo)EG zaZ<1GYj`9I1bs5NAo>Dvr!{Kn25P&(-6g@l$?2)z0}Du7doj*LwyveYp=lc{s2%!1 zO+)vl79TM04L6+C$6@iM{Bl2eK#{@?r80Ko;8JyJ19?Ia1I3#>b=1>m1#bcakUcDD zJ?;1D>s*sQ@GCzCmq!xyRqQ@&fjpGvD3b#L=QIPL^TEu4^-^B zw%mVSEEha;{i2zu=bxdCPy_%=x+V0XugQu&S)clqP-$5Q^DB9RD6U-8-_b_u+K@}X zLX+1UXjAydnThM9k(T!Z!;j-NJz_+Z9n`tM)g;SY5s+Mjh79pvDMS2M4x>#gVQ7M? zZ~~gj;+NF;2$CPdZ>t(ZqQs;;9BER4DiEG75n}HU#&$w%aB~eJ?spElrYX-04_rW( zMI)2=!a4dmMF>0yQ3w~rwt9TNg+loE(pe{J_^q6D$gK|Ov$UbUN+WfpZd0J&TdCU0 z6&dl7mDF^M>6gC}A$qGv+^t;C0^r>>v3If~h}?aQ?kHs3e1vYQbTygu3)5nFn>Qip z+&r+gmD_jJ%z1fB z9APcCy0rQb$XuRdD-4m>SnZxY?L9m@qF<;wmfhO1{1`gjt<>$A>Hpy?o#^M%ZMlK< zv)?s#`ZWo@z=0GKb_Ta$#xW&6C6+}-;RZEAB}-0lB@3h7Sf#V3Xh=gDXynX>HG!yc zs{&lbv5jxVLoS~djOD*g7-z!vx5-p2b5EwSaTW7D3*pRuiIqHJ zQm#Ce2m!a%Q)YgG>Y>J%avRl#eYv&3oKibPw3xb|FG%ra$^kXRZ&4fXNauKyqaCyb zYP7DwyrXH}GqTNXqnx+ng9O#FwxXZ3R+L(rnz-ZwJYCsg_PLuj@rbhD=7_D+m_%si z5VLhGjkzmE^l>q9#@m9HgmLbJ@sspWHC^O!O?tSG{wh3E2Kn>C979={WT|x#GS8Kn z(y8#qKJq|)4Lq+_R+)~^FEsZ5>@uD6FhBl+B7C{5$7gtyp0xR_F#peNW$dj z=TwiT7L}1cNFRs#YWsPkXGUOOx%Vv1^K6($srg=DX@p&y#qIxcUr4*?{F_9fLt$h) z8XOC?LI2sr(mj@jhVI-Qh81u0wf+FcP;(Y$yPF3JXud$^hENI7KC(*MGSGOmkvn)) zZ@J32EJmH&iiQjxQgM4hq-gobShhr^*6lq%-q~-d$I_pC%?(9OHNw;DHUIUNL`vIo zseJ>dlu&;)ASld4-C#*Ygt_U4535Jw;}Ccvp&;Uftj}S8* z9TxR7T3Ya;a5KAENKmiFk{Bo}h5<0TEHVd9>^dzDm@FpY*IOE$ygL$zJ(6Nc95!3_ zp6_rY+sIjP5zD9!3`y!0qCQ{;Zb_(Z0R8IGU*&vSJg_y`)2V(t`p9W zNsf*v&$lL}^d8yT);*n7SpVYBR`U8QGkbmP#L($KgsRPjYJlMn;}pW=NCS~-2nLbq1C_y9a%=|f zqe;bmT;Ow!rR#u*dobT5VPe)Vv!F5Y;yb!8%blm^L(Z_+h26kjOtP4t#Uhu}F6cU%8m&!#X|z`Q z?jd`OIb3r&FdZ|HVFD0402?P)ZZiUtYyFy^J6)jByHG70d(+fI7MG0`8!d?e-bX@# zD?ET9TqGi<#0oJ^gA%4$c+#DU*@<1su`(}>weekfi!~?%B;0v38LvXQJEv8nx&ar~ z)$B86s|$TiP}|b#^m`Wn|6pE(liIq6$db-a>Xy}8jki~XM1jCnS2f_`l9P^^MHuZf%N7B#bvqIs(d z#w{6XP?)np4=2WwQ1BQq!jAEAWh4W97A4TPfc1+02F*Y~yt|$m5}p$9GBf``z#~0U zdgUsqr1y!!Y%G|cAzUXXXFjTIDpz}uy3yIxFeN(W*nlf~?#Ha>4IS}i>E;I3V|^~n z8L&$#(XT@!re;z%vS$PrOP4efoU}VgHFKLHizlKs`L43p=I;PAH=+!IEJo~_e^B-< zeMY`y5}>LVnqARyqebn;3RH-!fbv8cDMK7uEfjY%XS^B&bGa=oPuk+-$=;TQw3QX)Mh&0PlJC;PVU2eSJ^z1gHKveb$&Kn3d8mw^Pa^EpM0%sd| zkI4w9YosWp{aq^e=X@ya(6j(DChR^SrRt4gHzA`oCNO!~vR$E9Q;z=Cp7zM<+ULfa zbEqda1ZqQpH?!IPLCgc!r%|V?kAtLiwZgN@V`wR+pE&c%r+|)#t~1%X$R%4_8izF{ zC~tQ{Ib+S(e38NNpJmJJKzGxsQ?Qo;jnlXw2FQ`7@COB6UFS|lh$d6k&LI5o0mj;8X8{HTtSfcf(hn5kNbMAvWZ z7F+ok|D6Yf6o}>#g=|oOKp^60))5XQN6yCkGLfcj6f5(cir`z?`_HO-A4f$Yy3GT# zwcMwO4}Qa2jY|KhXRFRXqXaEQ7#p#~chi!P2qlN{#D=ELF9y)^ zhVWlJz)~^Ek+{t$2P!0_?94^YCGbIyK7{1p zutCa!rZ`QzqBqm4Q&&abU>tPbzEERw7gauI9>@=k6Qez|19u!rQIqbdFpI&YTNJuN z&=&utCJ(2^RBDELd|cQ6eP+|+g(z)M`vd$y!fGi^yi2| zjv|P2__~{Ou8G0#Jsk|bj(+Ka9~A+wS$>}1`%$S!G9<$>GTf-Oxgz372>O6n{G09n zyVGYy2%f*9&_J?Unken9xEy`+4k4XLRP1fd5D=o^o3d=dP1|{W%2ObyuZhGa(B9wB zYDEyy2NUC(j@0p)4h>PEiLX!U?X&S~>9B54HFhWVz7xv9nY}QBWaLlZ{~AQOrfl66 z_4tWS0bBuNF9C?SRAe`k zoT$oGrvAD_FW3v-JL@i;l~D^sNnGqW~#hA5$(9nhh`7cBb?!w%9w z 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 + + + + AboutDialog + + + About DB Browser for SQLite + O PrzeglÄ…darce SQLite + + + + Version + Wersja + + + + <html><head/><body><p>DB Browser for SQLite is an open source, freeware visual tool used to create, design and edit SQLite database files.</p><p>It is bi-licensed under the Mozilla Public License Version 2, as well as the GNU General Public License Version 3 or later. You can modify or redistribute it under the conditions of these licenses.</p><p>See <a href="http://www.gnu.org/licenses/gpl.html">http://www.gnu.org/licenses/gpl.html</a> and <a href="https://www.mozilla.org/MPL/2.0/index.txt">https://www.mozilla.org/MPL/2.0/index.txt</a> for details.</p><p>For more information on this program please visit our website at: <a href="http://sqlitebrowser.org">http://sqlitebrowser.org</a></p><p><span style=" font-size:small;">This software uses the GPL/LGPL Qt Toolkit from </span><a href="http://qt-project.org/"><span style=" font-size:small;">http://qt-project.org/</span></a><span style=" font-size:small;"><br/>See </span><a href="http://qt-project.org/doc/qt-5/licensing.html"><span style=" font-size:small;">http://qt-project.org/doc/qt-5/licensing.html</span></a><span style=" font-size:small;"> for licensing terms and information.</span></p><p><span style=" font-size:small;">It also uses the Silk icon set by Mark James licensed under a Creative Commons Attribution 2.5 and 3.0 license.<br/>See </span><a href="http://www.famfamfam.com/lab/icons/silk/"><span style=" font-size:small;">http://www.famfamfam.com/lab/icons/silk/</span></a><span style=" font-size:small;"> for details.</span></p></body></html> + <html><head/><body><p>PrzeglÄ…darka SQLite jest darmowym otwartym oprogramowaniem przeznaczonym do graficznej edycji i tworzenia plików bazy danych SQLite.</p><p>Program podlega podwójnej licencji użytkowania: Publiczna licencja Mozilli Wersja 2 jak również Powszechna Licencja Publiczna GNU wersja 3 i późniejsza. Możesz zmieniać i rozpowszechniać program pod warunkami zawartymi w tych licencjach.</p><p>Zobacz <a href="http://www.gnu.org/licenses/gpl.html">http://www.gnu.org/licenses/gpl.html</a> i <a href="https://www.mozilla.org/MPL/2.0/index.txt">https://www.mozilla.org/MPL/2.0/index.txt</a> dla szczegółów.</p><p>Odwiedź naszÄ… stronÄ™ internetowÄ… aby zapoznać siÄ™ ze szczegółami na temat dziaÅ‚ania tego programu: <a href="http://sqlitebrowser.org">http://sqlitebrowser.org</a></p><p><span style=" font-size:small;">To oprogramowanie używa GPL/LGPL Qt Toolkit z: </span><a href="http://qt-project.org/"><span style=" font-size:small;">http://qt-project.org/</span></a><span style=" font-size:small;"><br/>Zobacz </span><a href="http://qt-project.org/doc/qt-5/licensing.html"><span style=" font-size:small;">http://qt-project.org/doc/qt-5/licensing.html</span></a><span style=" font-size:small;"> na temat licencji i użytkowania.</span></p><p><span style=" font-size:small;">Używany również jest zestaw ikon Silk stworzony przez Mark James pod licencjÄ… Creative Commons Attribution 2.5 i 3.0.<br/>Zobacz </span><a href="http://www.famfamfam.com/lab/icons/silk/"><span style=" font-size:small;">http://www.famfamfam.com/lab/icons/silk/</span></a><span style=" font-size:small;"> po wiÄ™cej szczegółów.</span></p></body></html> + + + + AddRecordDialog + + + Add New Record + Nowy rekord + + + + Enter values for the new record considering constraints. Fields in bold are mandatory. + Podaj wartoÅ›ci dla nowego rekordu zwracajÄ…c uwagÄ™ na ograniczenia.Pola wytÅ‚usczone sÄ… obowiÄ…zkowe. + + + + In the Value column you can specify the value for the field identified in the Name column. The Type column indicates the type of the field. Default values are displayed in the same style as NULL values. + W kolumnie Wartość możesz podać wartość dla pola identyfikowanego w kolumnie Nazwa. Kolumna Rodzaj wskazuje rodzaj pola. WartoÅ›ci domyÅ›lne sÄ… wyÅ›wietlane w tym samym stylu, co wartoÅ›ci NULL. + + + + Name + Nazwa + + + + Type + Rodzaj + + + + Value + Wartość + + + + Values to insert. Pre-filled default values are inserted automatically unless they are changed. + WartoÅ›ci do wstawienia. Uprzednio wypeÅ‚nione domyÅ›lne wartoÅ›ci sÄ… wstawiane samoczynnie, chyba że zostaÅ‚y zmienione. + + + + When you edit the values in the upper frame, the SQL query for inserting this new record is shown here. You can edit manually the query before saving. + Tutaj pokazana jest kwerenda SQL dla dodania nowego rekordu zawierajÄ…cego wartoÅ›ci wprowadzone w górnej ramce. Możesz jÄ… rÄ™cznie zmienić przed zapisem rekordu. + + + + <html><head/><body><p><span style=" font-weight:600;">Save</span> will submit the shown SQL statement to the database for inserting the new record.</p><p><span style=" font-weight:600;">Restore Defaults</span> will restore the initial values in the <span style=" font-weight:600;">Value</span> column.</p><p><span style=" font-weight:600;">Cancel</span> will close this dialog without executing the query.</p></body></html> + <html><head/><body><p><span style=" font-weight:600;">Zapisz</span> przekaże wyÅ›wietlone zapytanie SQL do bazy danych w celu zapisania nowego rekordu</p><p><span style=" font-weight:600;">Przywróć domyÅ›lne</span> przywróci wstÄ™pne wartoÅ›ci domyÅ›lne w kolumnie<span style=" font-weight:600;">Wartość</span></p><p><span style=" font-weight:600;">Zaniechaj</span> zamyka to okno bez robienia zmian.</p></body></html> + + + + Auto-increment + + Samoprzyrost + + + + Unique constraint + + Ograniczenie niepowtarzalnoÅ›ci + + + + + Check constraint: %1 + + Ograniczenie sprawdzania: %1 + + + + + Foreign key: %1 + + Klucz obcy: %1 + + + + + Default value: %1 + + Wartość domyÅ›lna: %1 + + + + + Error adding record. Message from database engine: + +%1 + Nie można dodać rekordu. Wiadomość z silnika bazy danych: +%1 + + + + Are you sure you want to restore all the entered values to their defaults? + JesteÅ› pewien że chcesz przywrócić domyÅ›lne wartoÅ›ci dla wszystich wpisów? + + + + Application + + + Possible command line arguments: + Dozwolone argumenty wiersza poleceÅ„: + + + + Usage: %1 [options] [<database>|<project>] + + + + + + -h, --help Show command line options + + + + + -q, --quit Exit application after running scripts + + + + + -s, --sql <file> Execute this SQL file after opening the DB + + + + + -t, --table <table> Browse this table after opening the DB + + + + + -R, --read-only Open database in read-only mode + + + + + -o, --option <group>/<setting>=<value> + + + + + Run application with this setting temporarily set to value + + + + + -O, --save-option <group>/<setting>=<value> + + + + + Run application saving this value for this setting + + + + + -v, --version Display the current version + + + + + <database> Open this SQLite database + + + + + <project> Open this project file (*.sqbpro) + + + + + The -s/--sql option requires an argument + Opcja -s/--sql wymaga argumentu + + + + The file %1 does not exist + Plik %1 nie istnieje + + + + The -t/--table option requires an argument + Opcja -t/--table wymaga argumentu + + + + The -o/--option and -O/--save-option options require an argument in the form group/setting=value + Ustawienia -o/--option oraz -O/--save-option wymagajÄ… argumentu w postaci group/setting=wartość + + + + Invalid option/non-existant file: %1 + NieprawidÅ‚owa opcja lub nieistniejÄ…cy plik: %1 + + + + SQLite Version + Wersja SQLite + + + + SQLCipher Version %1 (based on SQLite %2) + + + + + DB Browser for SQLite Version %1. + + + + + Built for %1, running on %2 + + + + + Qt Version %1 + + + + + CipherDialog + + + SQLCipher encryption + Szyfrowanie SQLCipher + + + + &Password + &HasÅ‚o + + + + &Reenter password + Powtó&rz hasÅ‚o + + + + Encr&yption settings + Ustawienia sz&yfrowania + + + + SQLCipher &3 defaults + DomyÅ›lne SQLCipher &3 + + + + SQLCipher &4 defaults + DomyÅ›lne SQLCipher &4 + + + + Custo&m + WÅ‚as&ny + + + + Page si&ze + Ro&zmiar strony + + + + &KDF iterations + Powtórzenia &KDF + + + + HMAC algorithm + Algorytm HMAC + + + + KDF algorithm + Algorytm KDF + + + + Plaintext Header Size + Rozmiar nagłówka zwykÅ‚ego tekstu + + + + Passphrase + HasÅ‚o + + + + Raw key + Klucz + + + + Please set a key to encrypt the database. +Note that if you change any of the other, optional, settings you'll need to re-enter them as well every time you open the database file. +Leave the password fields empty to disable the encryption. +The encryption process might take some time and you should have a backup copy of your database! Unsaved changes are applied before modifying the encryption. + ProszÄ™ podaj klucz do zaszyfrowania bazy danych. +Zwróć uwagÄ™ na to że wszelkie zmiany wprowadzone tutaj do opcjonalnych ustawieÅ„ bedÄ… wymagane przy każdym otwarciu pliku. +W celu deaktywacji szyfrowania pozostaw pola klucza puste. +Proces szyfrowania może zabrać dużo czasu w zależnoÅ›ci od wielkoÅ›ci bazy danych. Zaleca siÄ™ aby przed rozpoczÄ™ciem tego procesu zrobić kopiÄ™ zapasowÄ… pliku. Wszelkie nie zapisane zmiany bÄ™dÄ… wprowadzone do bazy danych zanim szyfrowanie siÄ™ rozpocznie. + + + + Please enter the key used to encrypt the database. +If any of the other settings were altered for this database file you need to provide this information as well. + ProszÄ™ podać hasÅ‚o do zaszyfrowania bazy danych. +JeÅ›li zostaÅ‚y zmienione jakiekolwiek dodatkowe ustawienia dla pliku tej bazy danych bÄ™dziesz musiaÅ‚ również podać tÄ… informacjÄ™. + + + + ColumnDisplayFormatDialog + + + Choose display format + Wybierz format wyÅ›wietlania + + + + Display format + Format wyÅ›wietlania + + + + Choose a display format for the column '%1' which is applied to each value prior to showing it. + Wybierz domyÅ›lny format wyÅ›wietlania dla kolumny '%1', który bÄ™dzie stosowany dla każdej wartoÅ›ci, zanim zostanie ona wyÅ›wietlona. + + + + Default + DomyÅ›lny + + + + Decimal number + Liczba dziesiÄ™tna + + + + Exponent notation + Zapis wykÅ‚adniczy + + + + Hex blob + Blob szestnastkowy + + + + Hex number + Liczba szesnastkowa + + + + Octal number + Liczba ósemkowa + + + + Round number + Liczba zaokrÄ…glona + + + + Apple NSDate to date + Apple NSDate do daty + + + + Java epoch (milliseconds) to date + Java epoch (milisekundy) do daty + + + + .NET DateTime.Ticks to date + + + + + Julian day to date + Data JuliaÅ„ska do daty + + + + Unix epoch to date + Unix epoch do daty + + + + Unix epoch to local time + Unix epoch do czasu lokalnego + + + + Windows DATE to date + Windows DATE do daty + + + + Date as dd/mm/yyyy + Data w formacie dd/mm/rrrr + + + + Lower case + MaÅ‚e litery + + + + Upper case + Duże litery + + + + Custom + Niestandardowy + + + + Custom display format must contain a function call applied to %1 + WÅ‚asny format wyÅ›wietlania musi zawierać wywoÅ‚anie funkcji zastosowanej na %1 + + + + Error in custom display format. Message from database engine: + +%1 + Błąd we wÅ‚asnym formacie wyÅ›wietlania. Wiadomość z silnika bazy danych: + +%1 + + + + Custom display format must return only one column but it returned %1. + WÅ‚asny format wyÅ›wietlania musi zwracać tylko jednÄ… kolumnÄ™, a zwróciÅ‚ %1. + + + + CondFormatManager + + + Conditional Format Manager + ZarzÄ…dzanie formatowaniem warunkowym + + + + This dialog allows creating and editing conditional formats. Each cell style will be selected by the first accomplished condition for that cell data. Conditional formats can be moved up and down, where those at higher rows take precedence over those at lower. Syntax for conditions is the same as for filters and an empty condition applies to all values. + To okno dialogowe umożliwia tworzenie i zmianÄ™ formatowania warunkowego. WyglÄ…d komórki bÄ™dzie bÄ™dzie okreÅ›lony pierwszym speÅ‚nionym warunkiem dla danych komórki. Formatowania warunkowe można przesunąć w górÄ™ i w dół, gdzie te na górze sÄ… przetwarzane w pierwszej kolejnoÅ›ci. SkÅ‚adnia dla warunków jest taka sama jak dla filtrów, a pusty warunek bÄ™dzie pasowaÅ‚ do wszystkich wartoÅ›ci. + + + + Add new conditional format + Dodaj nowe formatowanie warunkowe + + + + &Add + Dod&aj + + + + Remove selected conditional format + UsuÅ„ wybrane formatowanie warunkowe + + + + &Remove + &UsuÅ„ + + + + Move selected conditional format up + PrzesuÅ„ w górÄ™ wybrane formatowanie warunkowe + + + + Move &up + PrzesuÅ„ w &górÄ™ + + + + Move selected conditional format down + PrzesuÅ„ w dół wybrane formatowanie warunkowe + + + + Move &down + PrzesuÅ„ w &dół + + + + Foreground + Pierwszy plan + + + + Text color + Barwa tekstu + + + + Background + TÅ‚o + + + + Background color + Barwa tÅ‚a + + + + Font + Czcionka + + + + Size + Rozmiar + + + + Bold + Pogrubienie + + + + Italic + Kursywa + + + + Underline + PodkreÅ›lenie + + + + Alignment + Wyrównanie + + + + Condition + Warunek + + + + + Click to select color + Kliknij, aby wybrać barwÄ™ + + + + Are you sure you want to clear all the conditional formats of this field? + Czy na pewno chcesz wyczyÅ›cić wszystkie formatowania warunkowe tego pola? + + + + DBBrowserDB + + + This database has already been attached. Its schema name is '%1'. + Baza danych zostaÅ‚a już dołączona. Nazwa jej schematu to '%1'. + + + + Please specify the database name under which you want to access the attached database + ProszÄ™ podaj nazwÄ™ bazy danych za pomocÄ… której chcesz uzyskać dostÄ™p do załączonej bazy + + + + Invalid file format + NieprawidÅ‚owy format pliku + + + + Do you really want to close this temporary database? All data will be lost. + Czy na pewno chcesz zamknąć tÄ™ tymczasowÄ… bazÄ™ danych? Wszelkie zmiany bedÄ… zapomniane. + + + + Do you want to save the changes made to the database file %1? + Czy na pewno chcesz zapisać zmiany dokonane w pliku bazy danych %1? + + + + Database didn't close correctly, probably still busy + Baza danych nie zostaÅ‚a zamkniÄ™ta poprawnie, prawdopodobnie byÅ‚a nadal zajÄ™ta + + + + The database is currently busy: + Baza danych jest obecnie zajÄ™ta: + + + + Do you want to abort that other operation? + Czy na pewno chcesz przerwać tÄ… innÄ… operacjÄ™? + + + + Exporting database to SQL file... + Eksportowanie bazy danych do pliku SQL… + + + + + Cancel + Zaniechaj + + + + + No database file opened + Plik z bazÄ… danych nie jest obecnie otwarty + + + + Executing SQL... + Wykonywanie SQL… + + + + Action cancelled. + Zaniechano dziaÅ‚ania. + + + + + Error in statement #%1: %2. +Aborting execution%3. + Błąd w poleceniu #%1: %2. +Przerywam wykonywanie%3. + + + + + and rolling back + i przywracam + + + + didn't receive any output from %1 + nie otrzymano żadnego wyniku z %1 + + + + could not execute command: %1 + nie można wykonać polecenia: %1 + + + + Cannot delete this object + Nie można usunąć tego obiektu + + + + Cannot set data on this object + Nie można ustawić danych na tym objekcie + + + + + A table with the name '%1' already exists in schema '%2'. + Tabela o nazwie '%1' już istnieje w schemacie '%2'. + + + + No table with name '%1' exists in schema '%2'. + Tabela o nazwie '%1' nie istnieje w schemacie '%2'. + + + + + Cannot find column %1. + Nie można znaleźć kolumny %1. + + + + Creating savepoint failed. DB says: %1 + Nie można utworzyć punktu zapisu. BD zwraca: %1 + + + + Renaming the column failed. DB says: +%1 + Nie można przemianować tej kolumny. BD zwraca: +%1 + + + + + Releasing savepoint failed. DB says: %1 + Nie można zwolnić punktu zapisu. BD zwraca: %1 + + + + Creating new table failed. DB says: %1 + Nie można utworzyć nowej tabeli. BD zwraca: %1 + + + + Copying data to new table failed. DB says: +%1 + Nie można skopiować nowej tabeli. BD zwraca: +%1 + + + + Deleting old table failed. DB says: %1 + Nie można usunąć starej tabeli. BD zwraca: %1 + + + + Error renaming table '%1' to '%2'. +Message from database engine: +%3 + Błąd przemianowywania tabeli z '%1' na '%2'. +Wiadomość z silnika bazy danych: +%3 + + + + could not get list of db objects: %1 + nie można pobrać listy obiektów bd: %1 + + + + Restoring some of the objects associated with this table failed. This is most likely because some column names changed. Here's the SQL statement which you might want to fix and execute manually: + + + WystÄ…piÅ‚ błąd przy odtworzeniu niektórych obiektów powiÄ…zanych z tÄ… bazÄ… danych. Błędy tego rodzaju wystÄ™pujÄ… za zwyczaj w przypadku zmiany nazw niektórych kolumn. Sprawdź dokÅ‚adnie nastÄ™pujÄ…cÄ… kwerendÄ™ SQL. Po dokonaniu zmian możesz jÄ… rÄ™cznie uruchomić: + + + + + + could not get list of databases: %1 + nie mogÄ™ odczytać listy baz danych: %1 + + + + Error setting pragma %1 to %2: %3 + Błąd przy ustawianiu pragmy %1 do %2: %3 + + + + File not found. + Nie znaleziono pliku. + + + + Error loading extension: %1 + Nie można wczytać rozszerzenia: %1 + + + + could not get column information + nie można uzyskać informacji o kolumnie + + + + DbStructureModel + + + Name + Nazwa + + + + Object + Obiekt + + + + Type + Rodzaj + + + + Schema + Polecenie tworzÄ…ce + + + + Database + Baza danych + + + + Browsables + Obiekty do przeglÄ…dania + + + + All + Wszystkie + + + + Temporary + Tymczasowa + + + + Tables (%1) + Tabele (%1) + + + + Indices (%1) + Indeksy (%1) + + + + Views (%1) + Widoki (%1) + + + + Triggers (%1) + Wyzwalacze (%1) + + + + EditDialog + + + Edit database cell + Zmiana komórki bazy danych + + + + Mode: + Tryb: + + + + This is the list of supported modes for the cell editor. Choose a mode for viewing or editing the data of the current cell. + To jest lista dostÄ™pnych trybów dla edytora komórek. Wybierz tryb do wyÅ›wietlania lub edycji danych dla tej komórki. + + + + Text + Tekst + + + + RTL Text + Tekst od prawej do lewej + + + + Binary + Zapis dwójkowy + + + + + Image + Obraz + + + + JSON + JSON + + + + XML + XML + + + + + Automatically adjust the editor mode to the loaded data type + Sam dostosuj tryb edytora w zależnoÅ›ci od wczytanych danych + + + + This checkable button enables or disables the automatic switching of the editor mode. When a new cell is selected or new data is imported and the automatic switching is enabled, the mode adjusts to the detected data type. You can then change the editor mode manually. If you want to keep this manually switched mode while moving through the cells, switch the button off. + To pole zaznaczane włącza lub wyłącza samoczynne przełączanie do trybu edytora. Po wybraniu nowej komórki lub zaimportowaniu nowych danych i przy włączonym samoczynnym przełączaniu, tryb dostosowuje siÄ™ do wykrytego rodzaju danych. NastÄ™pnie można zmienić tryb edytora rÄ™cznie. Aby zapamiÄ™tać ten try rÄ™czny przy przechodzeniu po komórkach, wystarczy odznaczyć to pole. + + + + Auto-switch + Sam przełączaj + + + + The text editor modes let you edit plain text, as well as JSON or XML data with syntax highlighting, automatic formatting and validation before saving. + +Errors are indicated with a red squiggle underline. + Tryby edytora tekstu umożliwiajÄ… edycjÄ™ zwykÅ‚ego tekstu, a także danych JSON oraz XML +z podÅ›wietlaniem skÅ‚adni, samoformatowaniem oraz sprawdzaniem przed zapisem. + +Błędy sÄ… podkreÅ›lane czerwonym Å›laczkiem. + + + + This Qt editor is used for right-to-left scripts, which are not supported by the default Text editor. The presence of right-to-left characters is detected and this editor mode is automatically selected. + Edytor Qt jest używany do pism od-prawej-do-lewej, które nie sÄ… obsÅ‚ugiwane przez domyÅ›lny edytor tekstu. Obecność znaków pism od-prawej-do-lewej jest wykrywana, a edytor sam przełącza siÄ™ do tego trybu. + + + + Open preview dialog for printing the data currently stored in the cell + Otwiera okno dialogowe do podglÄ…du drukowanych danych z danej komórki + + + + Auto-format: pretty print on loading, compact on saving. + Auto-formatowanie: upiÄ™ksza tekst przy wczytywaniu i Å›ciska przy zapisywaniu. + + + + When enabled, the auto-format feature formats the data on loading, breaking the text in lines and indenting it for maximum readability. On data saving, the auto-format feature compacts the data removing end of lines, and unnecessary whitespace. + Po zaznaczeniu, dane sÄ… formatowane podczas ich wczytywania, Å‚amiÄ…c tekst w wierszach oraz wcinajÄ…c go dla najlepszej czytelnoÅ›ci. Przed zapisaniem, dane sÄ… oczyszczane poprzez usuniÄ™cie zakoÅ„czeÅ„ wierszy oraz niepotrzebnych biaÅ‚ych znaków. + + + + Word Wrap + Zawijaj sÅ‚owa + + + + Wrap lines on word boundaries + Zawijaj wiersze na granicach słów + + + + + Open in default application or browser + Otwórz w domyÅ›lnej aplikacji lub przeglÄ…darce + + + + Open in application + Otwórz w aplikacji + + + + The value is interpreted as a file or URL and opened in the default application or web browser. + Wartość jest traktowana jako plik lub adres URL i otwierana w domyÅ›lnej aplikacji lub przeglÄ…darce sieciowej. + + + + Save file reference... + Zapisz odniesienie pliku... + + + + Save reference to file + Zapisz odniesienie do pliku + + + + + Open in external application + Otwórz w zewnÄ™trznej aplikacji + + + + Autoformat + Sam formatuj + + + + &Export... + &Eksportuj... + + + + + &Import... + &Importuj... + + + + + Import from file + Importuj z pliku + + + + + Opens a file dialog used to import any kind of data to this database cell. + Otwiera okno wyboru pliku z danymi do zaimportowania w tej komórce. + + + + Export to file + Eksportuj do pliku + + + + Opens a file dialog used to export the contents of this database cell to a file. + Otwiera okno pozwalajÄ…ce na wyeksportowanie zawartoÅ›ci komórki do pliku. + + + + Erases the contents of the cell + CzyÅ›ci zawartość komórki + + + + Set as &NULL + Ustaw jako &NULL + + + + This area displays information about the data present in this database cell + Tutaj wyÅ›wietlane sÄ… informacje o danych obecnych w tej komórce + + + + Type of data currently in cell + Rodzaj danych obecnie znajdujÄ…cych siÄ™ w komórce + + + + Size of data currently in table + Rozmiar danych znajdujÄ…cych siÄ™ obecnie w tabeli + + + + Apply data to cell + Zapisz dane w komórce + + + + This button saves the changes performed in the cell editor to the database cell. + Ten przycisk zapisuje zmiany wykonane w edytorze komórki w komórce bazy danych. + + + + Apply + Zastosuj + + + + + Print... + Drukuj... + + + + Open preview dialog for printing displayed image + Otwórz podglÄ…d wydruku dla aktualnie wyÅ›wietlonego obrazu + + + + + Ctrl+P + + + + + Open preview dialog for printing displayed text + Otwiera okno dialogowe do podglÄ…du wyÅ›wietlanego tekstu + + + + Copy Hex and ASCII + Skopiuj Hex i ASCII + + + + Copy selected hexadecimal and ASCII columns to the clipboard + Skopiuj zaznaczone kolumny szesnastkowe oraz ASCII do schowka + + + + Ctrl+Shift+C + + + + + + Image data can't be viewed in this mode. + Obrazy nie mogÄ… zostać wyÅ›wietlone w tym trybie. + + + + + Try switching to Image or Binary mode. + Przejdź do trybu obrazu lub wartoÅ›ci binarnej. + + + + + Binary data can't be viewed in this mode. + Wartość dwójkowa nie może być wyÅ›wietlona w tym trybie. + + + + + Try switching to Binary mode. + Przejdź do trybu wartoÅ›ci binarnej. + + + + + Image files (%1) + Piki graficzne (%1) + + + + Binary files (*.bin) + Pliki Binarne (*.bin) + + + + Choose a file to import + Wybierz plik do zaimportowania + + + + %1 Image + %1 Grafika + + + + Choose a filename to export data + Wybierz nazwÄ™ pliku dla wyeksportowanych danych + + + + Invalid data for this mode + NieprawidÅ‚owe dane w tym trybie + + + + The cell contains invalid %1 data. Reason: %2. Do you really want to apply it to the cell? + Komórka zawiera nieprawidÅ‚owe dane %1. Powód: %2. Czy na pewno wstawić je do komórki? + + + + + Type of data currently in cell: Text / Numeric + Rodzaj danych obecnie znajdujÄ…cych siÄ™ w komórce: Tekst/Liczba + + + + + + %n character(s) + + %n znak + %n znaki + %n znaków + + + + + Type of data currently in cell: %1 Image + Rodzaj danych obecnie znajdujÄ…cych siÄ™ w komórce: Obraz %1 + + + + %1x%2 pixel(s) + %1x%2 piksel(e) + + + + Type of data currently in cell: NULL + Rodzaj danych obecnie znajdujÄ…cych siÄ™ w komórce: NULL + + + + + %n byte(s) + + %n bajt + %n bajty + %n bajtów + + + + + Type of data currently in cell: Valid JSON + Rodzaj danych obecnie znajdujÄ…cych siÄ™ w komórce: PrawidÅ‚owy JSON + + + + Type of data currently in cell: Binary + Rodzaj danych obecnie znajdujÄ…cych siÄ™ w komórce: dwójkowa + + + + Couldn't save file: %1. + Nie można zapisać pliku: %1. + + + + The data has been saved to a temporary file and has been opened with the default application. You can now edit the file and, when you are ready, apply the saved new data to the cell editor or cancel any changes. + Zapisano dane do pliku tymczasowego i otwarto je w domyÅ›lnej aplikacji. Teraz możesz wprowadzić zmiany w pliku, a gdy bÄ™dziesz gotowy, zapisz nowe dane w edytorze komórki lub zaniechaj jakichkolwiek zmian. + + + + EditIndexDialog + + + Edit Index Schema + Edytor tworzenia indeksu + + + + &Name + &Nazwa + + + + &Table + &Tabela + + + + &Unique + &Niepowtarzalny + + + + For restricting the index to only a part of the table you can specify a WHERE clause here that selects the part of the table that should be indexed + Aby ograniczyć indeks tylko do części tabeli można dopisać tutaj polecenie WHERE, które +zaznacza część tabeli, która ma zostać zaindeksowana + + + + Partial inde&x clause + Polecenie częściowego &indeksu + + + + Colu&mns + Kolu&mny + + + + Table column + Kolumna tabeli + + + + Type + Rodzaj + + + + Add a new expression column to the index. Expression columns contain SQL expression rather than column names. + Dodaj nowÄ… kolumnÄ™ wyrażenia do indeksu. Kolumny wyrażeÅ„ zawierajÄ… raczej wyrażenia SQL niż nazwy kolumn. + + + + Index column + Kolumna indeksu + + + + Order + PorzÄ…dek + + + + Deleting the old index failed: +%1 + Usuwanie starego indeksu nie powiodÅ‚o siÄ™: +%1 + + + + Creating the index failed: +%1 + Tworzenie indeksu nie powiodÅ‚o siÄ™: +%1 + + + + EditTableDialog + + + Edit table definition + Edycja tworzenia tabeli + + + + Table + Tabela + + + + Advanced + Zaawansowane + + + + Without Rowid + Bez ID wiersza + + + + Make this a 'WITHOUT rowid' table. Setting this flag requires a field of type INTEGER with the primary key flag set and the auto increment flag unset. + UczyÅ„ z tej tabeli tablÄ™ 'WITHOUT rowid'. Ustawienie tej flagi wymaga pola rodzaju INTEGER z flagÄ… klucza głównego ustawionÄ… i flagÄ… samoprzyrostu wyłączonÄ…. + + + + Fields + Pola + + + + Database sche&ma + Sche&mat bazy danych + + + + Add + Dodaj + + + + Remove + UsuÅ„ + + + + Move to top + PrzesuÅ„ na górÄ™ + + + + Move up + PrzesuÅ„ w górÄ™ + + + + Move down + PrzesuÅ„ w dół + + + + Move to bottom + PrzesuÅ„ na dół + + + + + Name + Nazwa + + + + + Type + Rodzaj + + + + NN + NN + + + + Not null + Nie NULL + + + + PK + PK + + + + Primary key + Klucz główny + + + + AI + AI + + + + Autoincrement + Samoprzyrostowa + + + + U + U + + + + + + Unique + Niepowtarzalna + + + + Default + DomyÅ›lna + + + + Default value + DomyÅ›lna wartość + + + + + + Check + Sprawdzenie + + + + Check constraint + Ograniczenie sprawdzenia + + + + Collation + Zestawienie + + + + + + Foreign Key + Obcy klucz + + + + Constraints + Ograniczenia + + + + Add constraint + Dodaj ograniczenie + + + + Remove constraint + UsuÅ„ ograniczenie + + + + Columns + Kolumny + + + + SQL + SQL + + + + <html><head/><body><p><span style=" font-weight:600; color:#ff0000;">Warning: </span>There is something with this table definition that our parser doesn't fully understand. Modifying and saving this table might result in problems.</p></body></html> + <html><head/><body><p><span style=" font-weight:600; color:#ff0000;">Uwaga: </span>W okreÅ›leniu tabeli jest coÅ›, czego nasze przetwarzanie skÅ‚adni nie rozumie. Zmiana i zapis tej tabeli może skutkować kÅ‚opotami.</p></body></html> + + + + + Primary Key + Klucz główny + + + + Add a primary key constraint + Dodaj ograniczenie klucza głównego + + + + Add a foreign key constraint + Dodaj ograniczenie klucza obcego + + + + Add a unique constraint + Dodaj ograniczenie niepowtarzalnoÅ›ci + + + + Add a check constraint + Dodaj ograniczenie sprawdzania + + + + + There can only be one primary key for each table. Please modify the existing primary key instead. + Dla każdej tabeli może być tylko jeden klucz główny. ZmieÅ„ istniejÄ…cy klucz główny. + + + + Error creating table. Message from database engine: +%1 + Nie można utworzyć tabeli. Wiadomość z silnika bazy danych: +%1 + + + + There already is a field with that name. Please rename it first or choose a different name for this field. + Istnieje już pole o tej nazwie. Przemianuj je najpierw lub wybierz innÄ… nazwÄ™ dla tego pola. + + + + This column is referenced in a foreign key in table %1 and thus its name cannot be changed. + Kolumna ma odwoÅ‚anie do klucza obcego w tabeli %1 wiÄ™c jej nazwa nie można zmienić jej nazwy. + + + + There is at least one row with this field set to NULL. This makes it impossible to set this flag. Please change the table data first. + W tym polu istnieje co najmniej jeden wiersz z wartoÅ›ciÄ… równÄ… NULL. Czyni to niemożliwym ustawienie tej flagi. Najpierw zmieÅ„ dane tabeli. + + + + There is at least one row with a non-integer value in this field. This makes it impossible to set the AI flag. Please change the table data first. + W tym polu istnieje co najmniej jeden wiersz z wartoÅ›ciÄ… nie bÄ™dÄ…cÄ… liczbÄ… caÅ‚kowitÄ…. Czyni to niemożliwym ustawienie flagi AI. Najpierw zmieÅ„ dane tabeli. + + + + Column '%1' has duplicate data. + + Kolumna '%1' zawiera powielone dane. + + + + + This makes it impossible to enable the 'Unique' flag. Please remove the duplicate data, which will allow the 'Unique' flag to then be enabled. + Czyni to niemożliwym nadanie flagi 'Unique'. UsuÅ„ powielone dane, aby móc nadać flagÄ™ 'Unique'. + + + + Are you sure you want to delete the field '%1'? +All data currently stored in this field will be lost. + Czy na pewno usunąć pole '%1'? +Wszystkie dane przechowywane w tym polu zostanÄ… utracone. + + + + Please add a field which meets the following criteria before setting the without rowid flag: + - Primary key flag set + - Auto increment disabled + Dodaj pola, które speÅ‚niajÄ… dane warunki przed ustawieniem flagi bez rowid: + - Ustawiono flagÄ™ głównego klucza + - Wyłączono samoprzyrost + + + + ExportDataDialog + + + Export data as CSV + Eksport danych jako CSV + + + + Tab&le(s) + Tabe&la/e + + + + Colu&mn names in first line + Nazwy kolu&mn w pierwszym wierszu + + + + Fie&ld separator + Znak oddzie&lajÄ…cy pola + + + + , + , + + + + ; + ; + + + + Tab + Tab + + + + | + | + + + + + + Other + Inny + + + + &Quote character + &Znak cytatu + + + + " + " + + + + ' + ' + + + + New line characters + Znak nowego wiersza + + + + Windows: CR+LF (\r\n) + Windows: CR+LF (\r\n) + + + + Unix: LF (\n) + Unix: LF (\n) + + + + Pretty print + UpiÄ™ksz wydruk + + + + Export data as JSON + Eksport danych jako JSON + + + + exporting CSV + eksportowanie CSV + + + + + Could not open output file: %1 + Nie można otworzyć pliku wyjÅ›ciowego: %1 + + + + exporting JSON + eksportowanie JSON + + + + + Choose a filename to export data + Wybierz nazwÄ™ pliku dla eksportowanych danych + + + + Please select at least 1 table. + Wybierz przynajmniej jednÄ… tabelÄ™. + + + + Choose a directory + Wybierz poÅ‚ożenie + + + + Export completed. + Eksportowanie zakoÅ„czone. + + + + ExportSqlDialog + + + Export SQL... + Eksportuj danych jako SQL + + + + Tab&le(s) + Tabel&a/e + + + + Select All + Zaznacz wszystkie + + + + Deselect All + Odznacz wszystkie + + + + &Options + &Opcje + + + + Keep column names in INSERT INTO + Pozostaw nazwy kolumn w INSERT INTO + + + + Multiple rows (VALUES) per INSERT statement + Wiele rzÄ™dów (WartoÅ›ci) dla polecenia INSERT + + + + Export everything + Eksportuj wszystko + + + + Export schema only + Eksportuj tylko schemat + + + + Export data only + Eksportuj tylko dane + + + + Keep old schema (CREATE TABLE IF NOT EXISTS) + Zachowaj poprzedni schemat (CREATE TABLE IF NOT EXISTS) + + + + Overwrite old schema (DROP TABLE, then CREATE TABLE) + ZastÄ…p poprzedni schemat (DROP TABLE, then CREATE TABLE) + + + + Please select at least one table. + Wybierz przynajmniej jednÄ… tabelÄ™. + + + + Choose a filename to export + Wybierz nazwÄ™ eksportowanego pliku + + + + Export completed. + Eksportowanie zakoÅ„czono. + + + + Export cancelled or failed. + Eksportowanie nie udaÅ‚o siÄ™ lub zostaÅ‚o zaniechane. + + + + ExtendedScintilla + + + + Ctrl+H + + + + + Ctrl+F + + + + + + Ctrl+P + + + + + Find... + Znajdź... + + + + Find and Replace... + Znajdź i zamień… + + + + Print... + Drukuj... + + + + ExtendedTableWidget + + + Use as Exact Filter + Użyj jako dokÅ‚adnego filtra + + + + Containing + Zawiera + + + + Not containing + Nie zawiera + + + + Not equal to + Nierówny + + + + Greater than + WiÄ™kszy niż + + + + Less than + Mniejszy niż + + + + Greater or equal + WiÄ™kszy lub równy + + + + Less or equal + Mniejszy lub równy + + + + Between this and... + PomiÄ™dzy tym a... + + + + Regular expression + Wyrażenie regularne + + + + Edit Conditional Formats... + ZmieÅ„ formatowanie warunkowe... + + + + Set to NULL + Ustaw jako NULL + + + + Copy + Skopiuj + + + + Copy with Headers + Skopiuj wraz z nagłówkami + + + + Copy as SQL + Skopiuj jako SQL + + + + Paste + Wklej + + + + Print... + Drukuj... + + + + Use in Filter Expression + Użyj w wyrażeniu filtra + + + + <p>Not all data has been loaded. <b>Do you want to load all data before selecting all the rows?</b><p><p>Answering <b>No</b> means that no more data will be loaded and the selection will not be performed.<br/>Answering <b>Yes</b> might take some time while the data is loaded but the selection will be complete.</p>Warning: Loading all the data might require a great amount of memory for big tables. + <p>Nie wczytano wszystkich danych. <b>Czu chcesz wczytać wszystkie dane przez zaznaczeniem wszystkich wierszy?</b><p><p>Odpowiedź <b>Nie</b> oznacza, że nie +zostanie wczytanych wiÄ™cej danych i nie zostanie nic zaznaczone.<br/>Odpowiedź <b>Tak</b> oznacza, że trochÄ™ czasu może być potrzebne na wczytanie danych za to zaznaczenie bÄ™dzie peÅ‚ne.</p>Uwaga: Wczytanie wszystkich danych może wymagać dużej iloÅ›ci pamiÄ™ci dla dużych tabel. + + + + Cannot set selection to NULL. Column %1 has a NOT NULL constraint. + Nie można ustawić zaznaczonych na NULL. Kolumna %1 ma ograniczenie NOT NULL. + + + + Alt+Del + + + + + Ctrl+Shift+C + + + + + Ctrl+Alt+C + + + + + The content of the clipboard is bigger than the range selected. +Do you want to insert it anyway? + Zawartość schowka jest wiÄ™ksza niż zaznaczony zakres. +Czy chcesz go wstawić mimo tego? + + + + FileExtensionManager + + + File Extension Manager + ZarzÄ…dzanie Rozszerzeniami Plików + + + + &Up + &W górÄ™ + + + + &Down + W &dół + + + + &Add + Dod&aj + + + + &Remove + &UsuÅ„ + + + + + Description + Opis + + + + Extensions + Rozszerzenia + + + + *.extension + *.rozszerzenie + + + + FilterLineEdit + + + Filter + Filtr + + + + These input fields allow you to perform quick filters in the currently selected table. +By default, the rows containing the input text are filtered out. +The following operators are also supported: +% Wildcard +> Greater than +< Less than +>= Equal to or greater +<= Equal to or less += Equal to: exact match +<> Unequal: exact inverse match +x~y Range: values between x and y +/regexp/ Values matching the regular expression + Te pola wejÅ›ciowe umożliwiajÄ… szybkie filtrowanie na bieżącej tabeli. +DomyÅ›lnie, wiersze zawierajÄ…ce tekst wejÅ›ciowy sÄ… odfiltrowywane. +ObsÅ‚ugiwane sÄ… nastÄ™pujÄ…ce operatory: +% Znak wieloznaczny +> WiÄ™ksze niż +< Mniejsze niż +>= Równe lub wiÄ™ksze +<= Równe lub mniejsze += Równe: dokÅ‚adnie pasuje +<> Nierówne: nie pasuje +x~y Zakres: wartoÅ›ci pomiÄ™dzy x oraz y +/regexp/ WartoÅ›ci pasujÄ…ce do wyrażenia regularnego + + + + Clear All Conditional Formats + Wyczyść wszystkie formatowania warunkowe + + + + Use for Conditional Format + Użyj do formatowania warunkowego + + + + Edit Conditional Formats... + Edytuj formatowanie warunkowe... + + + + Set Filter Expression + Ustaw wyrażenia filtra + + + + What's This? + Co to jest? + + + + Is NULL + Jest NULL + + + + Is not NULL + Nie jest NULL + + + + Is empty + Jest puste + + + + Is not empty + Nie jest puste + + + + Not containing... + Nie zawiera... + + + + Equal to... + Równe... + + + + Not equal to... + Nierówne... + + + + Greater than... + WiÄ™ksze niż... + + + + Less than... + Mniejsze niż... + + + + Greater or equal... + WiÄ™ksze lub równe... + + + + Less or equal... + Mniejsze lub równe... + + + + In range... + W zakresie... + + + + Regular expression... + Wyrażenie regularne... + + + + FindReplaceDialog + + + Find and Replace + Znajdź i zastÄ…p + + + + Fi&nd text: + Z&najdź tekst: + + + + Re&place with: + ZamieÅ„ &z: + + + + Match &exact case + Rozróżniaj wielkość lit&er + + + + Match &only whole words + Tylk&o caÅ‚e wyrazy + + + + When enabled, the search continues from the other end when it reaches one end of the page + Po zaznaczeniu, wyszukiwanie jest wznawiane od przeciwlegÅ‚ego koÅ„ca strony po osiÄ…gniÄ™ciu koÅ„ca strony. + + + + &Wrap around + Za&wijaj + + + + When set, the search goes backwards from cursor position, otherwise it goes forward + Po zaznaczeniu, wyszukiwanie postÄ™puje wstecz od poÅ‚ożenia wskaźnika, w przeciwnym przypadku postÄ™puje wprzód + + + + Search &backwards + Szukaj &na odwrót + + + + <html><head/><body><p>When checked, the pattern to find is searched only in the current selection.</p></body></html> + <html><head/><body><p>Po zaznaczeniu, wzorzec do znalezienia jest szukany tylko w bieżącym zaznaczeniu.</p></body></html> + + + + &Selection only + Tylko &zaznaczenie + + + + <html><head/><body><p>When checked, the pattern to find is interpreted as a UNIX regular expression. See <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>.</p></body></html> + <html><head/><body><p>Po zaznaczeniu, wzorzec do znalezienia jest rozważany jako wyrażenie regularne UNIX. Zajrzyj do <a href="https://en.wikibooks.org/wiki/Regular_Expressions">WyrażeÅ„ Regularnych w Wikibooks</a>.</p></body></html> + + + + Use regular e&xpressions + Stosuj wyrażenie &regularne + + + + Find the next occurrence from the cursor position and in the direction set by "Search backwards" + Szukaj kolejnego wystÄ…pienia od poÅ‚ożenia wskaźnika i w stronÄ™ okreÅ›lonÄ… poprzez +"Wyszukiwanie wstecz" + + + + &Find Next + Z&najdź nastÄ™pne + + + + F3 + + + + + &Replace + &ZastÄ…p + + + + Highlight all the occurrences of the text in the page + PodÅ›wietl wszystkie wystÄ…pienia tekstu na stronie + + + + F&ind All + Znajdź wszystk&ie + + + + Replace all the occurrences of the text in the page + ZastÄ…p wszystkie wystÄ…pienia w tekÅ›cie na stronie + + + + Replace &All + Z&amieÅ„ wszystkie + + + + The searched text was not found + Nie znaleziono szukanego tekstu + + + + The searched text was not found. + Nie znaleziono szukanego tekstu. + + + + The searched text was found one time. + Szukany tekst zostaÅ‚ znaleziony raz. + + + + The searched text was found %1 times. + Szukany tekst zostaÅ‚ znaleziony %1 razy. + + + + The searched text was replaced one time. + Szukany tekst zostaÅ‚ zamieniony raz. + + + + The searched text was replaced %1 times. + Szukany tekst zostaÅ‚ zamieniony %1 razy. + + + + ForeignKeyEditor + + + &Reset + &Resetuj + + + + Foreign key clauses (ON UPDATE, ON DELETE etc.) + Polecenia obcego klucza (ON UPDATE, ON DELETE itp.) + + + + ImportCsvDialog + + + Import CSV file + Importuj plik CSV + + + + Table na&me + &Nazwa tabeli + + + + &Column names in first line + &Nazwy kolumn w pierwszej linii + + + + Field &separator + &Znak oddzielajÄ…cy pola + + + + , + , + + + + ; + ; + + + + + Tab + Tab + + + + | + | + + + + Other + Inny + + + + &Quote character + Znak &cytatów + + + + + Other (printable) + Inne (drukowalne) + + + + + Other (code) + Inny (kod) + + + + " + " + + + + ' + ' + + + + &Encoding + Kodowani&e + + + + UTF-8 + UTF-8 + + + + UTF-16 + UTF-16 + + + + ISO-8859-1 + ISO-8859-1 + + + + Trim fields? + Przycinać pola? + + + + Separate tables + Oddzielaj tabele + + + + Advanced + Zaawansowane + + + + When importing an empty value from the CSV file into an existing table with a default value for this column, that default value is inserted. Activate this option to insert an empty value instead. + Przy importowaniu pustej wartoÅ›ci z pliku CSV do istniejÄ…cej tabeli z domyÅ›lnÄ… wartoÅ›ciÄ… dla tej kolumny, wstawiana jest ta domyÅ›lna wartość. Aby zamiast tego wstawić pustÄ… wartość, wystarczy zaznaczyć to pole. + + + + Ignore default &values + Ignoruj domyÅ›lne &wartoÅ›ci + + + + Activate this option to stop the import when trying to import an empty value into a NOT NULL column without a default value. + Zaznacz to pole, aby zatrzymać importowanie, podczas importowania pustej wartoÅ›ci do kolumny NOT NULL bez domyÅ›lnej wartoÅ›ci. + + + + Fail on missing values + ZgÅ‚aszaj błąd dla brakujÄ…cych wartoÅ›ci + + + + Disable data type detection + Wyłącz wykrywanie rodzajów danych + + + + Disable the automatic data type detection when creating a new table. + Wyłącz samowykrywanie rodzaju danych przy tworzeniu nowej tabeli. + + + + When importing into an existing table with a primary key, unique constraints or a unique index there is a chance for a conflict. This option allows you to select a strategy for that case: By default the import is aborted and rolled back but you can also choose to ignore and not import conflicting rows or to replace the existing row in the table. + Przy importowaniu do istniejÄ…cej tabeli o głównym kluczu, ograniczeniu lub indeksie niepowtarzalnoÅ›ci istnieje szansa na sprzeczność. To ustawienie umożliwia wybranie strategii dla tego przypadku. DomyÅ›lnie importowanie jest przerywane, a zmiany wycofywane, lecz można także pominąć wiersze bÄ™dÄ…ce w sprzecznoÅ›ci lub zastÄ…pić istniejÄ…cy wiersz w tabeli. + + + + Abort import + Przerwij importowanie + + + + Ignore row + PomiÅ„ wiersz + + + + Replace existing row + ZastÄ…p istniejÄ…cy wiersz + + + + Conflict strategy + Strategia na sprzecznoÅ›ci + + + + + Deselect All + Odznacz wszystkie + + + + Match Similar + Dopasuj do podobnych + + + + Select All + Zaznacz wszystkie + + + + There is already a table named '%1' and an import into an existing table is only possible if the number of columns match. + Tabela o nazwie '%1' już istnieje i importowanie do istniejÄ…cej tabeli jest możliwe tylko gdy liczba kolumn zgadza siÄ™. + + + + There is already a table named '%1'. Do you want to import the data into it? + Tabela o nazwie '%1' już istnieje. Czy chcesz zaimportować dane do niej? + + + + Creating restore point failed: %1 + Nie można utworzyć punktu przywracania: %1 + + + + Creating the table failed: %1 + Tworzenie tabeli nie powiodÅ‚o siÄ™: %1 + + + + importing CSV + importowanie CSV + + + + Inserting row failed: %1 + Wstawianie rzÄ™du nie powiodÅ‚o siÄ™: %1 + + + + Importing the file '%1' took %2ms. Of this %3ms were spent in the row function. + Importowanie pliku '%1' zajęło %2ms. Z tego %3ms spÄ™dzono na funkcji wiersza. + + + + MainWindow + + + DB Browser for SQLite + PrzeglÄ…darka SQLite + + + + + Database Structure + This has to be equal to the tab title in all the main tabs + Struktura danych + + + + Warning: this pragma is not readable and this value has been inferred. Writing the pragma might overwrite a redefined LIKE provided by an SQLite extension. + Uwaga: to polecenie pragma nie jest czytelne, wiÄ™c ta wartość powstaÅ‚a z domysÅ‚u. Zapisanie polecenie pragma może zastÄ…pić LIKE dostarczony przez rozszerzenie SQLite. + + + + toolBar1 + toolBar1 + + + + This is the structure of the opened database. +You can drag SQL statements from an object row and drop them into other applications or into another instance of 'DB Browser for SQLite'. + + Oto struktura bieżącej bazy danych. +Można przeciÄ…gać polecenia SQL z wiersza obiektu i upuszczać je na innych aplikacjach lub wstawiać je do innego wystÄ…pienia 'PrzeglÄ…darki SQLite'. + + + + + Browse Data + This has to be equal to the tab title in all the main tabs + PrzeglÄ…darka danych + + + + Execute line + Wykonaj wiersz + + + + Un/comment block of SQL code + Dodaj/UsuÅ„ uwagÄ™ do kawaÅ‚ka kodu SQL + + + + Un/comment block + Dodaj/UsuÅ„ uwagÄ™ do kawaÅ‚ka kodu + + + + Comment or uncomment current line or selected block of code + Dodaj lub usuÅ„ uwagÄ™ do bieżącego wiersza lub zaznaczonego kawaÅ‚ka kodu + + + + Comment or uncomment the selected lines or the current line, when there is no selection. All the block is toggled according to the first line. + Dodaj lub usuÅ„ uwagÄ™ do bieżącego wiersza lub zaznaczonych wierszy, gdy jest coÅ› zaznaczone. CaÅ‚y kawaÅ‚ek przełączany jest wg pierwszego wiersza. + + + + Ctrl+/ + + + + + Stop SQL execution + Zatrzymaj wykonywanie SQL + + + + Stop execution + Zatrzymaj wykonywanie + + + + Stop the currently running SQL script + Zatrzymaj wykonywanie bieżącego skryptu SQL + + + + + Edit Pragmas + This has to be equal to the tab title in all the main tabs + Polecenia Pragmy + + + + + Execute SQL + This has to be equal to the tab title in all the main tabs + Polecenia SQL + + + + &File + &Plik + + + + &Import + &Importuj + + + + &Export + &Eksportuj + + + + &Edit + &Edycja + + + + &View + &Widok + + + + &Help + Po&moc + + + + &Tools + &NarzÄ™dzia + + + + DB Toolbar + Pasek zadaÅ„ bazy danych + + + + Edit Database &Cell + Zmiana komórki bazy dany&ch + + + + SQL &Log + Dziennik SQ&L + + + + Show S&QL submitted by + Pokaż S&QL wydane przez + + + + User + Użytkownika + + + + Application + AplikacjÄ™ + + + + Error Log + Dziennik błędów + + + + This button clears the contents of the SQL logs + Ten przycisk czyÅ›ci zawartość logów SQL + + + + &Clear + Wy&czyść + + + + This panel lets you examine a log of all SQL commands issued by the application or by yourself + Ten panel umożliwia przeglÄ…d dziennika wszystkich poleceÅ„ SQL wydanych przez aplikacjÄ™ lub przez ciebie + + + + &Plot + &Wykres + + + + DB Sche&ma + Struktura da&nych + + + + &Remote + &Zdalne BD + + + + + Project Toolbar + Pasek zadaÅ„ projektu + + + + Extra DB toolbar + Dodatkowy pasek zadaÅ„ bazy danych + + + + + + Close the current database file + Zamknij obecny plik bazy danych + + + + &New Database... + &Nowa baza danych… + + + + + Create a new database file + Utwórz nowy plik bazy danych + + + + This option is used to create a new database file. + Ta opcja jest wykorzystywana do tworzenia nowego pliku bazy danych. + + + + Ctrl+N + + + + + + &Open Database... + &Otwórz bazÄ™ danych… + + + + + + + + Open an existing database file + Otwórz istniejÄ…cÄ… bazÄ™ danych + + + + + + This option is used to open an existing database file. + Ta opcja otwiera istniejÄ…cy plik bazy danych. + + + + Ctrl+O + + + + + &Close Database + Zamknij bazÄ™ dany&ch + + + + This button closes the connection to the currently open database file + Ten przycisk koÅ„czy połączenie z obecnie otwartym plikiem bazy danych + + + + Open SQL file(s) + + + + + This button opens files containing SQL statements and loads them in new editor tabs + + + + + This button lets you save all the settings associated to the open DB to a DB Browser for SQLite project file + + + + + This button lets you open a DB Browser for SQLite project file + + + + + Browse Table + PrzeglÄ…daj tabelÄ™ + + + + + Ctrl+W + + + + + &Revert Changes + &Wycofaj zmiany + + + + + Revert database to last saved state + Przywróć bazÄ™ danych do ostatniego zapisanego stanu + + + + This option is used to revert the current database file to its last saved state. All changes made since the last save operation are lost. + Ten dziaÅ‚anie sÅ‚uży do przywrócenia bieżącej bazy danych do ostatnio zapisanego stanu. Wszystkie zmiany od czasu ostatniego zapisu zostanÄ… utracone. + + + + &Write Changes + &Zapisz zmiany + + + + + Write changes to the database file + Zapisz zmiany w pliku bazy danych + + + + This option is used to save changes to the database file. + Ta opcja zapisuje zmiany w pliku bazy danych. + + + + Ctrl+S + + + + + Ctrl+Shift+O + + + + + &Save Project As... + Zapi&sz projekt jako... + + + + + + Save the project in a file selected in a dialog + Zapisuje projekt w pliku wskazanym w dialogu + + + + Save A&ll + Zapisz w&szystko + + + + + + Save DB file, project file and opened SQL files + Zapisuje plik bazy danych, projektu i otwarte pliki SQL + + + + Ctrl+Shift+S + + + + + This is the structure of the opened database. +You can drag multiple object names from the Name column and drop them into the SQL editor and you can adjust the properties of the dropped names using the context menu. This would help you in composing SQL statements. +You can drag SQL statements from the Schema column and drop them into the SQL editor or into other applications. + + Oto struktura bieżącej bazy danych. +Można przeciÄ…gać wiele nazw obiektów z kolumny nazwy i upuszczać je w edytorze SQL. NastÄ™pnie można dostosować wÅ‚aÅ›ciwoÅ›ci upuszczonych nazw poprzez menu podrÄ™czne. To ma na celu pomoc w tworzeniu polecenia SQL. +Można przeciÄ…gać polecenia SQL z kolumny schematu i upuszczać je w edytorze SQL lub innych aplikacjach. + + + + Compact &Database... + ÅšciÅ›nij bazÄ™ &danych... + + + + Compact the database file, removing space wasted by deleted records + ÅšciÅ›nij plik bazÄ™ danych, usuwajÄ…c przestrzenie marnowane przez usuniÄ™te rekordy + + + + + Compact the database file, removing space wasted by deleted records. + ÅšciÅ›nij plik bazÄ™ danych, usuwajÄ…c przestrzenie marnowane przez usuniÄ™te rekordy. + + + + E&xit + &Wyjdź + + + + Ctrl+Q + + + + + &Database from SQL file... + Baza &danych z pliku SQL… + + + + Import data from an .sql dump text file into a new or existing database. + Importuj dane z pliku tekstowego zrzutu .sql do nowej lub istniejÄ…cej bazy danych. + + + + This option lets you import data from an .sql dump text file into a new or existing database. SQL dump files can be created on most database engines, including MySQL and PostgreSQL. + To dziaÅ‚anie, umożliwia importowanie danych z pliku tekstowego zrzutu .sql do nowej lub istniejÄ…cej bazy danych. Pliki zrzutu SQL można utworzyć w wiÄ™kszoÅ›ci silników baz danych, włączajÄ…c w to MySQL oraz PostgreSQL. + + + + &Table from CSV file... + &Tabela z pliku CSV… + + + + Open a wizard that lets you import data from a comma separated text file into a database table. + Otwiera okno pomocnika do importowania danych z pliku CSV do tabeli bazy danych. + + + + Open a wizard that lets you import data from a comma separated text file into a database table. CSV files can be created on most database and spreadsheet applications. + Otwiera okno pomocnika do importowania danych z pliku CSV do tabeli bazy danych. +Plik CSV można stworzyć na podstawie wiÄ™kszoÅ›ci baz danych i aplikacji arkuszy kalkulacyjnych. + + + + &Database to SQL file... + Baza &danych do pliku SQL… + + + + Export a database to a .sql dump text file. + Eksportuj bazÄ™ danych do pliku tekstowego zrzutu .sql + + + + This option lets you export a database to a .sql dump text file. SQL dump files contain all data necessary to recreate the database on most database engines, including MySQL and PostgreSQL. + To dziaÅ‚anie umożliwia eksportowanie bazy danych do pliku tekstowego zrzutu .sql. Plik zrzutu SQL zawiera wszystkie dane niezbÄ™dne do odtworzenia bazy danych na wiÄ™kszoÅ›ci silników baz danych, włączajÄ…c w to MySQL oraz PostgreSQL. + + + + &Table(s) as CSV file... + &Tabele do pliku CSV… + + + + Export a database table as a comma separated text file. + Eksportuje tabelÄ™ bazy danych jako plik tekstowy, oddzielajÄ…c wartoÅ›ci przecinkami. + + + + Export a database table as a comma separated text file, ready to be imported into other database or spreadsheet applications. + Eksportuje tabelÄ™ bazy danych jako plik tekstowym który można zaimportować w innych aplikacjach bazodanowych lub arkuszach kalkulacyjnych; oddzielajÄ…c wartoÅ›ci przecinkami. + + + + &Create Table... + &Utwórz tabelę… + + + + Open the Create Table wizard, where it is possible to define the name and fields for a new table in the database + Otwiera okno tworzenia tabel, gdzie można zdefiniować nazwÄ™ i pola w nowej tabeli w bazie danych + + + + &Delete Table... + U&suÅ„ tabelę… + + + + + Delete Table + UsuÅ„ tabelÄ™ + + + + Open the Delete Table wizard, where you can select a database table to be dropped. + Otwiera pomocnika do UsuniÄ™cia Tabeli, gdzie można wybrać tabelÄ™ bazy danych do usuniÄ™cia. + + + + &Modify Table... + Z&mieÅ„ tabelę… + + + + Open the Modify Table wizard, where it is possible to rename an existing table. It is also possible to add or delete fields form a table, as well as modify field names and types. + Otwiera pomocnika do Zmiany Tabeli, gdzie można przemianować istniejÄ…cÄ… tabelÄ…. +Można także dodawać i usuwać pola z tabli, a także zmieniać nazwy oraz rodzaje pól. + + + + Create &Index... + Utwórz &indeks… + + + + Open the Create Index wizard, where it is possible to define a new index on an existing database table. + Otwiera pomocnika do Tworzenia Indeksu, gdzie można okreÅ›lić nowy indeks na istniejÄ…cej tabeli bazy danych. + + + + &Preferences... + &Ustawienia... + + + + + Open the preferences window. + Otwórz okno ustawieÅ„. + + + + &DB Toolbar + Pasek narzÄ™dzi bazy &danych + + + + Shows or hides the Database toolbar. + Pokazuje lub ukrywa pasek narzÄ™dzi Baza danych + + + + Ctrl+T + + + + + W&hat's This? + &Co to jest? + + + + Ctrl+F4 + + + + + Shift+F1 + + + + + &About + O progr&amie + + + + &Load Extension... + &Wczytaj rozszerzenia... + + + + &Wiki + &Wiki + + + + F1 + + + + + Bug &Report... + &ZgÅ‚oszenie błędu... + + + + Feature Re&quest... + ZgÅ‚oszenie ż&yczenia... + + + + Web&site + Strona &sieciowa + + + + &Donate on Patreon... + &Darowizna na Patreon... + + + + Open &Project... + Otwórz &projekt... + + + + &Attach Database... + Dołącz bazÄ™ d&anych... + + + + &Set Encryption... + U&staw szyfrowanie... + + + + This button saves the content of the current SQL editor tab to a file + Ten przycisk zapisuje treść bieżącej karty edytora SQL do pliku + + + + SQLCipher &FAQ + &Najczęściej zadawane pytania SQLCipher + + + + New In-&Memory Database + Nowa baza danych w-pa&miÄ™ci + + + + Drag && Drop Qualified Names + PrzeciÄ…gnij && upuść nazwy ze struktury + + + + + Use qualified names (e.g. "Table"."Field") when dragging the objects and dropping them into the editor + Używaj nazw ze struktury (np. "Tabela"."Pole") przy przeciÄ…ganiu obiektów i upuszczaniu ich w edytorze + + + + Drag && Drop Enquoted Names + PrzeciÄ…gnij && upuść nazw w cudzysÅ‚owach + + + + + Use escaped identifiers (e.g. "Table1") when dragging the objects and dropping them into the editor + Używaj nazw w cudzysÅ‚owach (np. "Tabela1") przy przeciÄ…ganiu obiektów i upuszczaniu ich w edytorze + + + + &Integrity Check + Sprawdzanie spójnoÅ›c&i + + + + Runs the integrity_check pragma over the opened database and returns the results in the Execute SQL tab. This pragma does an integrity check of the entire database. + Wykonuje polecenie pragma integrity_check na bieżącej bazie danych i zwraca wynik na karcie Wykonywania SQL. To polecenie pragma wykonuje sprawdzenie spójnoÅ›ci caÅ‚ej bazy danych. + + + + &Foreign-Key Check + &Sprawdzenie obcego klucza + + + + Runs the foreign_key_check pragma over the opened database and returns the results in the Execute SQL tab + Wykonuje polecenie pragma foreign_key_check na bieżącej bazie danych i zwraca wynik na karcie Wykonywania SQL + + + + &Quick Integrity Check + &Szybkie sprawdzenie spójnoÅ›ci + + + + Run a quick integrity check over the open DB + Wykonaj sprawdzenie spójnoÅ›ci bieżącej bazy danych + + + + Runs the quick_check pragma over the opened database and returns the results in the Execute SQL tab. This command does most of the checking of PRAGMA integrity_check but runs much faster. + Wykonuje polecenie pragma quick_check na bieżącej bazie danych i zwraca wynik na karcie Wykonywania SQL. To polecenie pragma wykonuje wiÄ™kszość tego, co wykonuje polecenie pragma integrity_check lecz robi to znacznie szybciej. + + + + &Optimize + &Optymalizacja + + + + Attempt to optimize the database + Próba optymalizacji bazy danych + + + + Runs the optimize pragma over the opened database. This pragma might perform optimizations that will improve the performance of future queries. + Wykonuje polecenie pragma optimize na bieżącej bazie danych. To polecenie może wykonać optymalizacje, które zwiÄ™kszÄ… wydajność przyszÅ‚ych zapytaÅ„. + + + + + Print + Drukuj + + + + Print text from current SQL editor tab + Drukuj tekst z bieżącej karty edytora SQL + + + + Open a dialog for printing the text in the current SQL editor tab + Otwiera okno dialogowe do drukowania tekstu w bieżącej karcie edytora SQL + + + + Print the structure of the opened database + Drukuj strukturÄ™ bieżącej bazy danych + + + + Open a dialog for printing the structure of the opened database + Otwiera okno dialogowe do drukowania struktury bieżącej bazy danych + + + + &Recently opened + Ostatnio otwie&rane + + + + Open &tab + Otwórz kar&tÄ™ + + + + This button opens a new tab for the SQL editor + Ten przycisk otwiera nowÄ… tabelÄ™ w edytorze SQL + + + + &Execute SQL + &Wykonaj SQL + + + + Execute all/selected SQL + Wykonaj wszystkie/zaznaczone SQL + + + + This button executes the currently selected SQL statements. If no text is selected, all SQL statements are executed. + Ten przycisk wykona obecnie zaznaczone polecenia SQL. JeÅ›li nie zaznaczone tekstu, to zostanÄ… wykonane wszystkie polecenia SQL. + + + + + + Save SQL file + Zapisz plik SQL + + + + + Execute current line + Wykonaj bieżący wiersz + + + + This button executes the SQL statement present in the current editor line + Ten przycisk wykonuje polecenie SQL z obecnego wiersza edytora + + + + Shift+F5 + + + + + Export as CSV file + Eksportuj do pliku CSV + + + + Export table as comma separated values file + Eksportuj tabelÄ™ jako plik z wartoÅ›ciami oddzielonymi przecinkami + + + + Sa&ve Project + &Zapisz projekt + + + + + Save the current session to a file + Zapisz obecnÄ… sesjÄ™ do pliku + + + + + Load a working session from a file + Wczytaj otoczenie pracy z pliku + + + + + Add another database file to the current database connection + Dodaj kolejny plik bazy danych do połączenia bieżącej bazy danych + + + + This button lets you add another database file to the current database connection + Ten przycisk umożliwia dodanie kolejnego pliku bazy danych do połączenia bieżącej bazy danych + + + + + Save SQL file as + Zapisz plik SQL jako + + + + &Browse Table + &PrzeglÄ…daj tabelÄ™ + + + + Copy Create statement + Skopiuj polecenie tworzÄ…ce + + + + Copy the CREATE statement of the item to the clipboard + Skopiuj polecenie CREATE elementu do schowka + + + + Opens the SQLCipher FAQ in a browser window + Otwiera FAQ SQLCipher w oknie przeglÄ…darki + + + + Table(&s) to JSON... + Tabele do pliku J&SON… + + + + Export one or more table(s) to a JSON file + Eksportuj jednÄ… lub wiÄ™cej tabel do pliku JSON + + + + Open Data&base Read Only... + Otwórz &bazÄ™ danych tylko do odczytu… + + + + Open an existing database file in read only mode + Otwórz istniejÄ…cy plik bazy danych w trybie tylko do odczytu + + + + Save results + Zapisz wyniki + + + + Save the results view + Zapisuje widok wyniku + + + + This button lets you save the results of the last executed query + Ten przycisk umożliwia zapisanie wyników ostatnio wykonanego zapytania + + + + + Find text in SQL editor + Znajdź tekst w edytorze SQL + + + + Find + Znajdź + + + + This button opens the search bar of the editor + Ten przycisk otwiera pasek wyszukiwania edytora + + + + Ctrl+F + + + + + + Find or replace text in SQL editor + Znajdź lub zastÄ…p tekst w edytorze SQL + + + + Find or replace + Znajdź i zastÄ…p + + + + This button opens the find/replace dialog for the current editor tab + Ten przycisk otwiera okno dialogowe znajdowania/zastÄ™powania dla bieżącej karty edytora + + + + Ctrl+H + + + + + Export to &CSV + Eksportuj do &CSV + + + + Save as &view + Zapisz jako &widok + + + + Save as view + Zapisz jako widok + + + + Shows or hides the Project toolbar. + Pokazuje lub ukrywa pasek narzÄ™dzi Projekt. + + + + Extra DB Toolbar + Dodatkowy pasek narzÄ™dzi bazy danych + + + + Ctrl+Return + Ctrl+Return + + + + Ctrl+L + + + + + + Ctrl+P + + + + + Ctrl+D + + + + + Ctrl+I + + + + + Ctrl+E + + + + + Reset Window Layout + Wyzeruj ukÅ‚ad okien + + + + Alt+0 + + + + + The database is currenctly busy. + Baza danych jest obecnie zajÄ™ta. + + + + Click here to interrupt the currently running query. + NaciÅ›nij tutaj, aby przerwać wykonywanie bieżącego zapytania. + + + + Encrypted + Szyfrowana + + + + Database is encrypted using SQLCipher + Baza danych jest zaszyfrowana z użyciem SQLCipher + + + + Read only + Tylko do odczytu + + + + Database file is read only. Editing the database is disabled. + Plik bazy danych jest tylko do odczytu. Edytowanie bazy danych jest wyłączone. + + + + Database encoding + Kodowanie bazy danych + + + + + Choose a database file + Wybierz plik bazy danych + + + + Could not open database file. +Reason: %1 + Nie można otworzyć pliku bazy danych. +Powód: %1 + + + + + + Choose a filename to save under + Wybierz nazwÄ™ pliku do zapisu + + + + Setting PRAGMA values or vacuuming will commit your current transaction. +Are you sure? + Ustawianie wartoÅ›ci PRAGMA lub odkurzanie spowoduje wdrożenie twoich zmian +z bieżącej transakcji. +Czy na pewno? + + + + In-Memory database + Baza danych w-pamiÄ™ci + + + + Do you want to save the changes made to the project file '%1'? + Czy chcesz zapisać zmiany wprowadzone w plik projektu '%1'? + + + + Are you sure you want to delete the table '%1'? +All data associated with the table will be lost. + Czy na pewno usunąć tabelÄ™ '%1'? +Wszystkie dane skojarzone z tÄ… tabelÄ… zostanÄ… utracone. + + + + Are you sure you want to delete the view '%1'? + Czy na pewno usunąć widok '%1'? + + + + Are you sure you want to delete the trigger '%1'? + Czy na pewno usunąć wyzwalacz '%1'? + + + + + Are you sure you want to delete the index '%1'? + Czy na pewno usunąć indeks '%1'? + + + + Error: could not delete the table. + Błąd: nie można usunąć bazy danych. + + + + Error: could not delete the view. + Błąd: nie można usunąć widoku. + + + + Error: could not delete the trigger. + Błąd: nie można usunąć wyzwalacza. + + + + Error: could not delete the index. + Błąd: nie można usunąć indeksu. + + + + Message from database engine: +%1 + Wiadomość z silnika bazy danych: +%1 + + + + Editing the table requires to save all pending changes now. +Are you sure you want to save the database? + Zmiana tabeli wymaga zapisania wszystkich oczekujÄ…cych zmian. +Czy na pewno zapisać bazÄ™ danych? + + + + Error checking foreign keys after table modification. The changes will be reverted. + Błąd sprawdzania kluczy obcych po zmianie tabeli. Zmiany zostanÄ… wycofane. + + + + This table did not pass a foreign-key check.<br/>You should run 'Tools | Foreign-Key Check' and fix the reported issues. + Tabela nie przeszÅ‚a sprawdzenia klucza obcego.<br/>Należy wykonać 'NarzÄ™dzia | Sprawdzenie obcego klucza' i naprawić zgÅ‚oszone kÅ‚opoty. + + + + Edit View %1 + + + + + Edit Trigger %1 + + + + + You are already executing SQL statements. Do you want to stop them in order to execute the current statements instead? Note that this might leave the database in an inconsistent state. + Już wykonujesz polecenia SQL. Czy zatrzymać je, aby wykonać bieżące polecenia? DziaÅ‚anie to może spowodować niespójność w bazie danych. + + + + -- EXECUTING SELECTION IN '%1' +-- + -- WYKONYWANIE ZAZNACZENIA W '%1' +-- + + + + -- EXECUTING LINE IN '%1' +-- + -- WYKONYWANIE WIERSZA W '%1' +-- + + + + -- EXECUTING ALL IN '%1' +-- + -- WYKONYWANIE WSZYSTKIEGO W '%1' +-- + + + + + At line %1: + W wierszu %1: + + + + Result: %1 + Wynik: %1 + + + + Result: %2 + Wynik: %2 + + + + %1 rows returned in %2ms + Zwrócono %1 wierszy w czasie %2ms + + + + Choose text files + Wybierz pliki tekstowe + + + + Opened '%1' in read-only mode from recent file list + + + + + Opened '%1' from recent file list + + + + + Project saved to file '%1' + Projekt zapisano do pliku '%1' + + + + This action will open a new SQL tab with the following statements for you to edit and run: + + + + + Rename Tab + Przemianuj kartÄ™ + + + + Duplicate Tab + Powiel kartÄ™ + + + + Close Tab + Zamknij kartÄ™ + + + + Opening '%1'... + Otwieranie '%1'... + + + + There was an error opening '%1'... + Błąd otwierania '%1'... + + + + Value is not a valid URL or filename: %1 + Wartość nie jest prawidÅ‚owym adresem URL lub nazwÄ… pliku: %1 + + + + Error while saving the database file. This means that not all changes to the database were saved. You need to resolve the following error first. + +%1 + Nie można zapisać bazy danych. Oznacza to, że nie wszystkie zmiany daÅ‚o siÄ™ zapisać w bazie danych. Najpierw trzeba pozbyć siÄ™ nastÄ™pujÄ…cych kÅ‚opotów. + +%1 + + + + Are you sure you want to undo all changes made to the database file '%1' since the last save? + Czy na pewno wycofać wszystkie zmiany wprowadzone w pliku bazy danych '%1' od czasu ostatniego zapisu? + + + + Choose a file to import + Wybierz pliki do zaimportowania + + + + &%1 %2%3 + &%1 %2%3 + + + + (read only) + (tylko do odczytu) + + + + Open Database or Project + Otwórz bazÄ™ danych lub projekt + + + + Attach Database... + Dołącz bazÄ™ danych... + + + + Import CSV file(s)... + Importuj plik(i) CSV... + + + + Select the action to apply to the dropped file(s). <br/>Note: only 'Import' will process more than one file. + + Wybierz dziaÅ‚anie dla upuszczonego pliku. <br/>Uwaga: tylko 'Import' przetworzy wiÄ™cej niż jeden plik. + Wybierz dziaÅ‚anie dla upuszczonych plików. <br/>Uwaga: tylko 'Import' przetworzy wiÄ™cej niż jeden plik. + Wybierz dziaÅ‚anie dla upuszczonych plików. <br/>Uwaga: tylko 'Import' przetworzy wiÄ™cej niż jeden plik. + + + + + Do you want to save the changes made to SQL tabs in the project file '%1'? + Czy chcesz zapisać zmiany wprowadzone w tabelach SQL do pliku projektu '%1'? + + + + Text files(*.sql *.txt);;All files(*) + Pliki tekstowe(*.sql *.txt);;Wszystkie pliki(*) + + + + Do you want to create a new database file to hold the imported data? +If you answer no we will attempt to import the data in the SQL file to the current database. + Czy utworzyć plik nowej bazy danych do przechowania zaimportowanych danych? +JeÅ›li nie, to dane zostanÄ… zaimportowane do pliku bieżącej bazy danych. + + + + Window Layout + + + + + Simplify Window Layout + + + + + Shift+Alt+0 + + + + + Dock Windows at Bottom + + + + + Dock Windows at Left Side + + + + + Dock Windows at Top + + + + + You are still executing SQL statements. Closing the database now will stop their execution, possibly leaving the database in an inconsistent state. Are you sure you want to close the database? + Nadal wykonujesz polecenia SQL. Wykonywanie tych poleceÅ„ zostanie zatrzymane, po zamkniÄ™ciu bazy danych, co może spowodować w niej niespójnoÅ›ci. Czy na pewno zamknąć tÄ™ bazÄ™ danych? + + + + File %1 already exists. Please choose a different name. + Plik %1 już istnieje. Wybierz innÄ… nazwÄ™. + + + + Error importing data: %1 + Błąd importowania danych: %1 + + + + Import completed. Some foreign key constraints are violated. Please fix them before saving. + UkoÅ„czono import. NastÄ…piÅ‚o przekroczenie niektórych z ograniczeÅ„ obcego klucza. Napraw je przed zapisaniem. + + + + Import completed. + Importowanie zakoÅ„czone. + + + + Delete View + UsuÅ„ widok + + + + Modify View + ZmieÅ„ widok + + + + Delete Trigger + UsuÅ„ wyzwalacz + + + + Modify Trigger + ZmieÅ„ wyzwalacz + + + + Delete Index + UsuÅ„ indeks + + + + Modify Index + ZmieÅ„ indeks + + + + Modify Table + ZmieÅ„ tabelÄ™ + + + + Setting PRAGMA values will commit your current transaction. +Are you sure? + Ustawianie wartoÅ›ci PRAGMA spowoduje wdrożenie twoich zmian +z bieżącej transakcji. +Czy na pewno? + + + + Select SQL file to open + Wybierz plik SQL do otworzenia + + + + Select file name + Wybierz nazwÄ™ pliku + + + + Select extension file + Wybierz plik rozszerzenia + + + + Execution finished with errors. + Wykonano z błędami. + + + + Execution finished without errors. + Wykonano bez błędów. + + + + Do you want to save the changes made to SQL tabs in a new project file? + Czy chcesz zapisać zmiany wprowadzone w tabelach SQL do nowego pliku projektu? + + + + Do you want to save the changes made to the SQL file %1? + Czy chcesz zapisać zmiany wprowadzone w SQL do pliku %1? + + + + The statements in this tab are still executing. Closing the tab will stop the execution. This might leave the database in an inconsistent state. Are you sure you want to close the tab? + Polecenia w tej karcie nadal sÄ… wykonywane. Wykonywanie tych poleceÅ„ zostanie zatrzymane, po zamkniÄ™ciu karty, co może spowodować niespójnoÅ›ci w bazie danych. Czy na pewno zamknąć tÄ™ kartÄ™? + + + + Extension successfully loaded. + PomyÅ›lnie wczytano rozszerzenie. + + + + Error loading extension: %1 + Nie można wczytać rozszerzenia: %1 + + + + Could not find resource file: %1 + Nie można znaleźć pliku zasobów: %1 + + + + + Don't show again + Nie pokazuj ponownie + + + + New version available. + Nowa wersja jest dostÄ™pna. + + + + A new DB Browser for SQLite version is available (%1.%2.%3).<br/><br/>Please download at <a href='%4'>%4</a>. + DostÄ™pna jest nowa wersja PrzeglÄ…darki SQLite (%1.%2.%3).<br/><br/>Pobierz z <a href='%4'>%4</a>. + + + + Choose a project file to open + Wybierz plik projektu do otworzenia + + + + DB Browser for SQLite project file (*.sqbpro) + Plik projektu PrzeglÄ…darki SQLite (*.sqbpro) + + + + This project file is using an old file format because it was created using DB Browser for SQLite version 3.10 or lower. Loading this file format is still fully supported but we advice you to convert all your project files to the new file format because support for older formats might be dropped at some point in the future. You can convert your files by simply opening and re-saving them. + Ten plik projektu używa starego formatu pliku, bo zostaÅ‚ stworzony przy użyciu PrzeglÄ…darki SQLite w wersji 3.10 lub niższej. Wczytywanie tego formatu pliku jest nadal w peÅ‚ni obsÅ‚ugiwane, lecz zalecamy przeksztaÅ‚cenie wszystkich plików projektu na nowy format pliku, bo obsÅ‚uga starych formatów może zniknąć w przyszÅ‚oÅ›ci. Aby przeksztaÅ‚cić plik, wystarczy go otworzyć i zapisać. + + + + Could not open project file for writing. +Reason: %1 + Nie można otworzyć pliku projektu do zapisu. +Powód: %1 + + + + Collation needed! Proceed? + Potrzebne zestawianie! PostÄ…pić naprzód? + + + + A table in this database requires a special collation function '%1' that this application can't provide without further knowledge. +If you choose to proceed, be aware bad things can happen to your database. +Create a backup! + Tabela w tej bazie danych wymaga wyjÄ…tkowej funkcji zestawienia '%1' której ta aplikacja nie może dostarczyć bez dalszej wiedzy. +PójÅ›cia z tym dalej, może spowodować uszkodzenia w bazie danych. +Stwórz kopiÄ™ zapasowÄ…! + + + + creating collation + tworzenie zestawienia + + + + Set a new name for the SQL tab. Use the '&&' character to allow using the following character as a keyboard shortcut. + Przemianowuje kartÄ™ SQL. Wstaw znaku '&&' aby móc wykorzystać nastÄ™pujÄ…cy po nim znak jako skrót klawiszowy. + + + + Please specify the view name + OkreÅ›l nazwÄ™ widoku + + + + There is already an object with that name. Please choose a different name. + Istnieje już obiekt o tej nazwie. Nadaj innÄ… nazwÄ™. + + + + View successfully created. + PomyÅ›lnie utworzono widok. + + + + Error creating view: %1 + Błąd tworzenia widoku: %1 + + + + This action will open a new SQL tab for running: + To dziaÅ‚anie otworzy nowÄ… kartÄ™ SQL aby wykonać: + + + + Press Help for opening the corresponding SQLite reference page. + NaciÅ›nij Pomoc, aby otworzyć powiÄ…zanÄ… stronÄ™ w podrÄ™czniku SQLite. + + + + Busy (%1) + ZajÄ™ty (%1) + + + + NullLineEdit + + + Set to NULL + Ustaw na NULL + + + + Alt+Del + + + + + PlotDock + + + Plot + Wykres + + + + <html><head/><body><p>This pane shows the list of columns of the currently browsed table or the just executed query. You can select the columns that you want to be used as X or Y axis for the plot pane below. The table shows detected axis type that will affect the resulting plot. For the Y axis you can only select numeric columns, but for the X axis you will be able to select:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Date/Time</span>: strings with format &quot;yyyy-MM-dd hh:mm:ss&quot; or &quot;yyyy-MM-ddThh:mm:ss&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Date</span>: strings with format &quot;yyyy-MM-dd&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Time</span>: strings with format &quot;hh:mm:ss&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Label</span>: other string formats. Selecting this column as X axis will produce a Bars plot with the column values as labels for the bars</li><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Numeric</span>: integer or real values</li></ul><p>Double-clicking the Y cells you can change the used color for that graph.</p></body></html> + <html><head/><body><p>To okno pokazuje wykaz wszystkich kolumn w bieżącej tabeli lub wÅ‚aÅ›nie wykonane zapytanie. Można wybrać kolumny wykorzystywane jako oÅ› X lub Y do okna wykresu poniżej. Tabela pokazuje wykryty rodzaj osi, który wpÅ‚ynie na wynikowy wykres. Dla osi Y można wybrać tylko kolumny liczbowe, a dla osi X można wybrać:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Data/Czas</span>: ciÄ…gi znaków o formacie &quot;yyyy-MM-dd hh:mm:ss&quot; lub &quot;yyyy-MM-ddThh:mm:ss&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Data</span>: ciÄ…gi znaków o formacie &quot;yyyy-MM-dd&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Czas</span>: ciÄ…gi znaków o formacie &quot;hh:mm:ss&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Etykieta</span>: inne ciÄ…gi znaków. Wybranie tej kolumny jako osi X utworzy wykres sÅ‚upkowy z wartoÅ›ciami z kolumny bÄ™dÄ…cymi etykietami dla sÅ‚upków</li><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Liczbowe</span>: liczby caÅ‚kowite lub rzeczywiste</li></ul><p>Aby zmienić barwy wykresu, należy kliknąć dwukrotnie na komórkach Y.</p></body></html> + + + + Columns + Kolumny + + + + X + X + + + + Y1 + + + + + Y2 + + + + + Axis Type + Rodzaj osi + + + + Here is a plot drawn when you select the x and y values above. + +Click on points to select them in the plot and in the table. Ctrl+Click for selecting a range of points. + +Use mouse-wheel for zooming and mouse drag for changing the axis range. + +Select the axes or axes labels to drag and zoom only in that orientation. + Tutaj rysowany jest wykres po wybraniu wartoÅ›ci x oraz y powyżej. + +Aby zaznaczyć punkt na wykresie i w tabeli, należy kliknąć na niego. Ctrl+Klik aby zaznaczyć zakres punktów. + +Aby zmienić zakres osi, należy kliknąć i przeciÄ…gnąć myszÄ…. Aby powiÄ™kszyć należy przewinąć rolkÄ… myszy. + +Aby przeciÄ…gnąć i powiÄ™kszyć tylko w jednÄ… stronÄ™, należy wybrać osie lub etykiety osi. + + + + Line type: + Rodzaj linii: + + + + + None + Brak + + + + Line + Linia + + + + StepLeft + Krok w lewo + + + + StepRight + Krok w prawo + + + + StepCenter + Krok do Å›rodka + + + + Impulse + Impuls + + + + Point shape: + KsztaÅ‚t punktu: + + + + Cross + Krzyż + + + + Plus + Plus + + + + Circle + Kółko + + + + Disc + Dysk + + + + Square + Kwadrat + + + + Diamond + Diament + + + + Star + Gwiazda + + + + Triangle + TrójkÄ…t + + + + TriangleInverted + TrójkÄ…t odwrócony + + + + CrossSquare + Krzyż w kwadracie + + + + PlusSquare + Plus w kwadracie + + + + CrossCircle + Krzyż w okrÄ™gu + + + + PlusCircle + Plus w okrÄ™gu + + + + Peace + Znak pokoju + + + + <html><head/><body><p>Save current plot...</p><p>File format chosen by extension (png, jpg, pdf, bmp)</p></body></html> + <html><head/><body><p>Zapisz bieżący wykres...</p><p>Format pliku wybierany na podstawie rozszerzenia (png, jpg, pdf, bmp)</p></body></html> + + + + Save current plot... + Zapisz bieżący wykres… + + + + + Load all data and redraw plot + Wczytaj wszystkie dane i przerysuj wykres + + + + Copy + Skopiuj + + + + Print... + Drukuj... + + + + Show legend + Pokaż legendÄ™ + + + + Stacked bars + SÅ‚upki na stosie + + + + Date/Time + Data/Czas + + + + Date + Data + + + + Time + Czas + + + + + Numeric + Liczbowa + + + + Label + Podpis + + + + Invalid + NieprawidÅ‚owy + + + + + + Row # + Nr wiersza + + + + Load all data and redraw plot. +Warning: not all data has been fetched from the table yet due to the partial fetch mechanism. + Wczytaj wszystkie dane i przerysuj wykres. +Uwaga: jeszcze nie wczytano wszystkich danych z tabeli ze wzglÄ™du na mechanizm częściowego wczytywania. + + + + Choose an axis color + Wybierz barwÄ™ osi + + + + Choose a filename to save under + Wybierz nazwÄ™ pliku do zapisu + + + + PNG(*.png);;JPG(*.jpg);;PDF(*.pdf);;BMP(*.bmp);;All Files(*) + PNG(*.png);;JPG(*.jpg);;PDF(*.pdf);;BMP(*.bmp);;Wszystkie pliki(*) + + + + There are curves in this plot and the selected line style can only be applied to graphs sorted by X. Either sort the table or query by X to remove curves or select one of the styles supported by curves: None or Line. + W tym wykresie wystÄ™pujÄ… krzywe, a wybrany wyglÄ…d linii można zastosować tylko dla wykresów uszeregowanych po X. Uszereguj tabelÄ™ lub zapytaj po X, aby usunąć krzywe lub wybierz jeden z wyglÄ…dów obsÅ‚ugiwanych przez krzywe: Brak lub Linia. + + + + Loading all remaining data for this table took %1ms. + Wczytywanie wszystkich pozostaÅ‚ych danych dla tej tabeli zajęło %1ms. + + + + PreferencesDialog + + + Preferences + Ustawienia + + + + &General + O&gólne + + + + Default &location + DomyÅ›&lne poÅ‚ożenie + + + + Remember last location + PamiÄ™taj ostatnie poÅ‚ożenie + + + + Always use this location + Zawsze używaj poniższego poÅ‚ożenia + + + + Remember last location for session only + Zapomnij ostatnie poÅ‚ożenie, dopiero po zamkniÄ™ciu programu + + + + + + ... + … + + + + Lan&guage + &JÄ™zyk + + + + Toolbar style + WyglÄ…d paska narzÄ™dzi + + + + + + + + Only display the icon + WyÅ›wietl tylko ikonÄ™ + + + + + + + + Only display the text + WyÅ›wietl tylko tekst + + + + + + + + The text appears beside the icon + Tekst obok ikony + + + + + + + + The text appears under the icon + Tekst pod ikonÄ… + + + + + + + + Follow the style + DomyÅ›lnie dla wyglÄ…du + + + + Show remote options + Pokaż ustawienia zdalnych BD + + + + + + + + + + + + enabled + włączone + + + + Automatic &updates + Sam &uaktualniaj + + + + DB file extensions + Rozszerzenia plików bazy danych + + + + Manage + ZarzÄ…dzaj + + + + Main Window + Główne okno + + + + Database Structure + Struktura danych + + + + Browse Data + PrzeglÄ…darka danych + + + + Execute SQL + Wykonaj SQL + + + + Edit Database Cell + Zmiana komórki bazy danych + + + + When this value is changed, all the other color preferences are also set to matching colors. + Po zmianie tej wartoÅ›ci, wszystkie inne ustawienia barw zostanÄ… także ustawione na +pasujÄ…ce barwy. + + + + Follow the desktop style + Zgodny z systemem + + + + Dark style + Ciemny + + + + Application style + WyglÄ…d programu + + + + This sets the font size for all UI elements which do not have their own font size option. + + + + + Font size + + + + + &Database + Baza &danych + + + + Database &encoding + Kodowani&e bazy danych + + + + Open databases with foreign keys enabled. + Otwiera bazy danych z włączonymi kluczami obcymi. + + + + &Foreign keys + &Obce klucze + + + + Remove line breaks in schema &view + UsuÅ„ podziaÅ‚y wierszy w &widoku schematu + + + + When enabled, the line breaks in the Schema column of the DB Structure tab, dock and printed output are removed. + Po zaznaczeniu, usuwany jest znak Å‚amania wiersza w kolumnie schematu karty struktury bazy danych, doku oraz drukowanym wyniku. + + + + Prefetch block si&ze + Ro&zmiar obszaru wczytanego z wyprzedzeniem + + + + SQ&L to execute after opening database + SQ&L do wykonania po otworzeniu bazy danych + + + + Default field type + DomyÅ›lny rodzaj pola + + + + Data &Browser + &PrzeglÄ…darka danych + + + + Font + Czcionka + + + + &Font + &Czcionka + + + + Font si&ze + Ro&zmiar czcionki + + + + Content + Zawartość + + + + Symbol limit in cell + Graniczna liczba znaków w komórce + + + + This is the maximum number of items allowed for some computationally expensive functionalities to be enabled: +Maximum number of rows in a table for enabling the value completion based on current values in the column. +Maximum number of indexes in a selection for calculating sum and average. +Can be set to 0 for disabling the functionalities. + Jest to graniczna liczba elementów, która jest dozwolona dla niektórych obliczeniowo pracochÅ‚onnych dziaÅ‚aÅ„: +Graniczna liczba wierszy w tabeli do włączenia uzupeÅ‚niania wartoÅ›ci na podstawie bieżących wartoÅ›ci w kolumnie. +Graniczna liczba indeksów w zaznaczeniu do obliczenia sumy i Å›redniej. +Można ustawić na 0, aby wyłączyć wszystkie te dziaÅ‚ania. + + + + This is the maximum number of rows in a table for enabling the value completion based on current values in the column. +Can be set to 0 for disabling completion. + Jest to graniczna liczba wierszy w tabeli do włączenia uzupeÅ‚niania wartoÅ›ci na podstawie wartoÅ›ci znajdujÄ…cych siÄ™ już w kolumnie. +Można ustawić na 0, aby wyłączyć uzupeÅ‚nianie. + + + + Close button on tabs + + + + + If enabled, SQL editor tabs will have a close button. In any case, you can use the contextual menu or the keyboard shortcut to close them. + + + + + Proxy + PoÅ›rednik + + + + Configure + Ustawienia + + + + Field display + WyÅ›wietlanie pola + + + + Displayed &text + WyÅ›wietlany &tekst + + + + Binary + Dane dwójkowe + + + + NULL + WartoÅ›ci NULL + + + + Regular + ZwykÅ‚e dane + + + + + + + + + Click to set this color + NaciÅ›nij, aby ustawić tÄ™ barwÄ™ + + + + Text color + Barwa tekstu + + + + Background color + Barwa tÅ‚a + + + + Preview only (N/A) + Tylko do podglÄ…du (ND) + + + + Filters + Filtry + + + + Escape character + Znak wyjÅ›cia + + + + Delay time (&ms) + Czas opóźnienia (&ms) + + + + Set the waiting time before a new filter value is applied. Can be set to 0 for disabling waiting. + Ustaw czas oczekiwania przed zastosowaniem nowej wartoÅ›ci filtra. Może być ustawiony na 0, aby wyłączyć oczekiwanie. + + + + &SQL + &SQL + + + + Settings name + Nazwa ustawienia + + + + Context + WystÄ™powanie + + + + Colour + Barwa + + + + Bold + Pogrubienie + + + + Italic + Pochylenie + + + + Underline + PodkreÅ›lenie + + + + Keyword + SÅ‚owo kluczowe + + + + Function + Funkcja + + + + Table + Tabela + + + + Comment + Uwaga + + + + Identifier + Identyfikator + + + + String + CiÄ…g znaków + + + + Current line + Bieżący wiersz + + + + Background + TÅ‚o + + + + Foreground + Pierwszy plan + + + + SQL &editor font size + Rozmiar czcionki &edytora SQL + + + + SQL &results font size + &Rozmiar czcionki wyników SQL + + + + Tab size + Rozmiar tabulatora + + + + SQL editor &font + &Czcionka edytora SQL + + + + Database structure font size + + + + + Threshold for completion and calculation on selection + UzupeÅ‚niaj i obliczaj do tej liczby wierszy + + + + Show images in cell + Pokaż obrazy w komórce + + + + Enable this option to show a preview of BLOBs containing image data in the cells. This can affect the performance of the data browser, however. + Włącz to, aby pokazać podglÄ…d obiektów BLOB zawierajÄ…cych dane obrazów w komórkach. Może to jednak wpÅ‚ynąć na wydajność przeglÄ…darki danych. + + + + &Wrap lines + Za&wijaj wiersze + + + + &Quotes for identifiers + &CudzysÅ‚owy dla identyfikatorów + + + + Choose the quoting mechanism used by the application for identifiers in SQL code. + Wybierz zapis cudzysÅ‚owów stosowany w aplikacji do identyfikatorów w kodzie SQL. + + + + "Double quotes" - Standard SQL (recommended) + "Podwójne cudzysÅ‚owy" - Standard SQL (zalecane) + + + + `Grave accents` - Traditional MySQL quotes + `Pojedyncze cudzysÅ‚owy` - Tradycyjne cudzysÅ‚owy MySQL + + + + [Square brackets] - Traditional MS SQL Server quotes + [Nawiasy kwadratowe] - Tradycyjne cudzysÅ‚owy MS SQL Server + + + + Code co&mpletion + UzupeÅ‚nianie &kodu + + + + Keywords in &UPPER CASE + SÅ‚owa kl&uczowe WIELKIMI LITERAMI + + + + When set, the SQL keywords are completed in UPPER CASE letters. + Po zaznaczeniu, polecenia SQL sÄ… uzupeÅ‚niane wielkimi literami. + + + + Error indicators + Wskaźniki błędów + + + + When set, the SQL code lines that caused errors during the last execution are highlighted and the results frame indicates the error in the background + Po zaznaczeniu, wiersze kodu SQL, które powodowaÅ‚y błędy podczas ostatniego wykonywania, sÄ… podÅ›wietlana, a okno wyniku pokazuje błąd w tle + + + + Hori&zontal tiling + Kafelki w po&ziomie + + + + If enabled the SQL code editor and the result table view are shown side by side instead of one over the other. + Po zaznaczeniu, edytor kodu SQL oraz widok tabeli wynikowej bÄ™dÄ… wyÅ›wietlane obok siebie zamiast jedno nad drugim. + + + + Never + Nigdy + + + + At word boundaries + Na granicach słów + + + + At character boundaries + Na granicach znaków + + + + At whitespace boundaries + Na granicach biaÅ‚ych znaków + + + + &Extensions + Rozsz&erzenia + + + + Select extensions to load for every database: + Wybierz rozszerzenia wczytywane dla każdej bazy danych: + + + + Add extension + Dodaj rozszerzenie + + + + Remove extension + UsuÅ„ rozszerzenie + + + + <html><head/><body><p>While supporting the REGEXP operator SQLite doesn't implement any regular expression<br/>algorithm but calls back the running application. DB Browser for SQLite implements this<br/>algorithm for you to let you use REGEXP out of the box. However, as there are multiple possible<br/>implementations of this and you might want to use another one, you're free to disable the<br/>application's implementation and load your own by using an extension. Requires restart of the application.</p></body></html> + <html><head/><body><p>Mimo obsÅ‚ugi polecenia REGEXP, SQLite nie implementuje żadnego z algorytmu wyrażeÅ„ regularnych<br/>lecz zwraca siÄ™ z powrotem do aplikacji, która je uruchomiÅ‚a. PrzeglÄ…darka SQLite implementuje ten<br/>algorytm, aby móc od razu korzystać z REGEXP. Jednakże, ze wzglÄ™du na to, że istnieje wiele możliwych<br/>implementacji wyrażeÅ„ regularnych, to można wyłączyć ten wbudowany<br/>i wczytać swój wÅ‚asny. Wymaga to jednak ponownego uruchomienia aplikacji.</p></body></html> + + + + Disable Regular Expression extension + Wyłącz rozszerzenie wyrażeÅ„ regularnych + + + + <html><head/><body><p>SQLite provides an SQL function for loading extensions from a shared library file. Activate this if you want to use the <span style=" font-style:italic;">load_extension()</span> function from SQL code.</p><p>For security reasons, extension loading is turned off by default and must be enabled through this setting. You can always load extensions through the GUI, even though this option is disabled.</p></body></html> + <html><head/><body><p>SQLite dostarcza funkcjÄ™ SQL do wczytywania rozszerzeÅ„ z pliku biblioteki współdzielonej. Zaznacz to, aby używać funkcji <span style=" font-style:italic;">load_extension()</span> z kodu SQL.</p><p>Ze wzglÄ™du na bezpieczeÅ„stwo, wczytywanie rozszerzeÅ„ jest domyÅ›lnie wyłączone i musi zostać włączone przez to ustawienie. Zawsze można wczytywać rozszerzenia przez interfejs użytkownika, nawet gdy pole to jest odznaczone.</p></body></html> + + + + Allow loading extensions from SQL code + Zezwól na wczytywanie rozszerzeÅ„ z kodu SQL + + + + Remote + Zdalne BD + + + + CA certificates + Certyfikaty UC + + + + + Subject CN + NP podmiotu + + + + Common Name + Nazwa powszechna + + + + Subject O + O podmiotu + + + + Organization + Organizacja + + + + + Valid from + Ważny od + + + + + Valid to + Ważny do + + + + + Serial number + Numer seryjny + + + + Your certificates + Twoje certyfikaty + + + + File + Plik + + + + Subject Common Name + Nazwa powszechna podmiotu + + + + Issuer CN + NP wydawcy + + + + Issuer Common Name + Nazwa powszechna wydawcy + + + + Clone databases into + Pobieraj bazy danych do + + + + + Choose a directory + Wybierz katalog + + + + The language will change after you restart the application. + JÄ™zyk zmieni siÄ™ po ponownym uruchomieniu aplikacji. + + + + Select extension file + Wybierz plik rozszerzenia + + + + Extensions(*.so *.dylib *.dll);;All files(*) + Rozszerzenia(*.so *.dylib *.dll);;Wszystkie pliki(*) + + + + Import certificate file + Importuj plik certyfikatu + + + + No certificates found in this file. + Nie znaleziono certyfikatów w tym pliku. + + + + Are you sure you want do remove this certificate? All certificate data will be deleted from the application settings! + Czy na pewno usunąć ten certyfikat? Wszystkie dane certyfikatu zostanÄ… usuniÄ™te z ustawieÅ„ aplikacji! + + + + Are you sure you want to clear all the saved settings? +All your preferences will be lost and default values will be used. + Czy na pewno wyczyÅ›cić wszystkie zapisane ustawienia? +Wszystkie zapisane ustawienia zostanÄ… utracone i zastÄ…pione domyÅ›lnymi. + + + + ProxyDialog + + + Proxy Configuration + Ustawienia proxy + + + + Pro&xy Type + &Rodzaj poÅ›rednika: + + + + Host Na&me + Nazwa &gospodarza + + + + Port + Port + + + + Authentication Re&quired + &Wymagane uwierzytelnienie + + + + &User Name + Nazwa &użytkownika + + + + Password + HasÅ‚o + + + + None + Brak + + + + System settings + Ustawienia systemowe + + + + HTTP + HTTP + + + + Socks v5 + Socks v5 + + + + QObject + + + All files (*) + Wszystkie pliki (*) + + + + Error importing data + Błąd importowania danych + + + + from record number %1 + z rekordu o numerze %1 + + + + . +%1 + . +%1 + + + + Importing CSV file... + Importowanie pliku CSV… + + + + Cancel + Zaniechaj + + + + SQLite database files (*.db *.sqlite *.sqlite3 *.db3) + Pliki bazy danych SQLite (*.db *.sqlite *.sqlite3 *.db3) + + + + Left + Do lewej + + + + Right + Do prawej + + + + Center + Do Å›rodka + + + + Justify + Wyjustuj + + + + SQLite Database Files (*.db *.sqlite *.sqlite3 *.db3) + Pliki bazy danych SQLite (*.db *.sqlite *.sqlite3 *.db3) + + + + DB Browser for SQLite Project Files (*.sqbpro) + PrzeglÄ…darka BD dla plików projektu SQLite (*.sqbpro) + + + + SQL Files (*.sql) + Pliki SQL (*.sql) + + + + All Files (*) + Wszystkie pliki (*) + + + + Text Files (*.txt) + Pliki tekstowe (*.txt) + + + + Comma-Separated Values Files (*.csv) + Pliki z wartoÅ›ciami oddzielonymi przecinkiem (*.csv) + + + + Tab-Separated Values Files (*.tsv) + Pliki z wartoÅ›ciami oddzielonymi tabulatorem (*.tsv) + + + + Delimiter-Separated Values Files (*.dsv) + Pliki z wartoÅ›ciami oddzielonymi rozdzielaczem (*.dsv) + + + + Concordance DAT files (*.dat) + Pliki Concordance DAT (*.dat) + + + + JSON Files (*.json *.js) + Pliki JSON (*.json *.js) + + + + XML Files (*.xml) + Pliki XML (*.xml) + + + + Binary Files (*.bin *.dat) + Pliki dwójkowe (*.bin *.dat) + + + + SVG Files (*.svg) + Pliki SVG (*.svg) + + + + Hex Dump Files (*.dat *.bin) + Pliki zrzutu szesnastkowego (*.dat *.bin) + + + + Extensions (*.so *.dylib *.dll) + Rozszerzenia (*.so *.dylib *.dll) + + + + RemoteCommitsModel + + + Commit ID + + + + + Message + + + + + Date + Data + + + + Author + + + + + Size + Rozmiar + + + + Authored and committed by %1 + + + + + Authored by %1, committed by %2 + + + + + RemoteDatabase + + + Error opening local databases list. +%1 + Nie można otworzyć wykazu lokalnych baz danych. +%1 + + + + Error creating local databases list. +%1 + Nie można utworzyć wykazu lokalnych baz danych. +%1 + + + + RemoteDock + + + Remote + Zdalne BD + + + + Identity + Tożsamość + + + + Push currently opened database to server + Wypchnij bieżącÄ… bazÄ™ danych na serwer + + + + DBHub.io + + + + + <html><head/><body><p>In this pane, remote databases from dbhub.io website can be added to DB Browser for SQLite. First you need an identity:</p><ol style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Login to the dbhub.io website (use your GitHub credentials or whatever you want)</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Click the button to &quot;Generate client certificate&quot; (that's your identity). That'll give you a certificate file (save it to your local disk).</li><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Go to the Remote tab in DB Browser for SQLite Preferences. Click the button to add a new certificate to DB Browser for SQLite and choose the just downloaded certificate file.</li></ol><p>Now the Remote panel shows your identity and you can add remote databases.</p></body></html> + + + + + Local + + + + + Current Database + + + + + Clone + + + + + User + Użytkownika + + + + Database + Baza danych + + + + Branch + Gałąź + + + + Commits + + + + + Commits for + + + + + Delete Database + + + + + Delete the local clone of this database + + + + + Open in Web Browser + + + + + Open the web page for the current database in your browser + + + + + Clone from Link + + + + + Use this to download a remote database for local editing using a URL as provided on the web page of the database. + + + + + Refresh + OdÅ›wież + + + + Reload all data and update the views + + + + + F5 + + + + + Clone Database + + + + + Open Database + + + + + Open the local copy of this database + + + + + Check out Commit + + + + + Download and open this specific commit + + + + + Check out Latest Commit + + + + + Check out the latest commit of the current branch + + + + + Save Revision to File + + + + + Saves the selected revision of the database to another file + + + + + Upload Database + + + + + Upload this database as a new commit + + + + + <html><head/><body><p>You are currently using a built-in, read-only identity. For uploading your database, you need to configure and use your DBHub.io account.</p><p>No DBHub.io account yet? <a href="https://dbhub.io/"><span style=" text-decoration: underline; color:#007af4;">Create one now</span></a> and import your certificate <a href="#preferences"><span style=" text-decoration: underline; color:#007af4;">here</span></a> to share your databases.</p><p>For online help visit <a href="https://dbhub.io/about"><span style=" text-decoration: underline; color:#007af4;">here</span></a>.</p></body></html> + <html><head/><body><p>Obecnie używasz wbudowanej tożsamoÅ›ci, która jest tylko do odczytu. Aby wysÅ‚ać bazÄ™ danych musisz posÅ‚użyć siÄ™ kontem z DBHub.io.</p><p>Nie masz jeszcze konta DBHub.io? <a href="https://dbhub.io/"><span style=" text-decoration: underline; color:#007af4;">Utwórz je teraz</span></a> i zaimportuj swój certyfikat<a href="#preferences"><span style=" text-decoration: underline; color:#007af4;">tutaj</span></a>, aby móc dzielić siÄ™ swoimi bazami danych.</p><p>Aby uzyskać pomoc w sieci, zajrzyj <a href="https://dbhub.io/about"><span style=" text-decoration: underline; color:#007af4;">tutaj</span></a>.</p></body></html> + + + + Back + Wstecz + + + + Select an identity to connect + + + + + Public + Publiczna + + + + This downloads a database from a remote server for local editing. +Please enter the URL to clone from. You can generate this URL by +clicking the 'Clone Database in DB4S' button on the web page +of the database. + + + + + Invalid URL: The host name does not match the host name of the current identity. + + + + + Invalid URL: No branch name specified. + + + + + Invalid URL: No commit ID specified. + + + + + You have modified the local clone of the database. Fetching this commit overrides these local changes. +Are you sure you want to proceed? + + + + + The database has unsaved changes. Are you sure you want to push it before saving? + + + + + The database you are trying to delete is currently opened. Please close it before deleting. + + + + + This deletes the local version of this database with all the changes you have not committed yet. Are you sure you want to delete this database? + + + + + RemoteLocalFilesModel + + + Name + Nazwa + + + + Branch + Gałąź + + + + Last modified + Ostatnia zmiana + + + + Size + Rozmiar + + + + Commit + + + + + File + Plik + + + + RemoteModel + + + Name + Nazwa + + + + Commit + Wdroż + + + + Last modified + Ostatnia zmiana + + + + Size + Rozmiar + + + + Size: + + + + + Last Modified: + + + + + Licence: + + + + + Default Branch: + + + + + RemoteNetwork + + + Choose a location to save the file + + + + + Error opening remote file at %1. +%2 + WystÄ…piÅ‚ błąd podczas otwierania zdalnego pliku w %1. +%2 + + + + Error: Invalid client certificate specified. + Błąd: Podano nieprawidÅ‚owy certyfikat klienta. + + + + Please enter the passphrase for this client certificate in order to authenticate. + Podaj hasÅ‚o dla certyfikatu tego klienta, aby siÄ™ uwierzytelnić. + + + + Cancel + Zaniechaj + + + + Uploading remote database to +%1 + WysyÅ‚anie zdalnej bazy danych do +%1 + + + + Downloading remote database from +%1 + Pobieranie zdalnej bazy danych z +%1 + + + + + Error: The network is not accessible. + Błąd: Sieć jest niedostÄ™pna. + + + + Error: Cannot open the file for sending. + Błąd: Nie można otworzyć pliku do wysÅ‚ania. + + + + RemotePushDialog + + + Push database + Wypchnij bazÄ™ danych + + + + Database na&me to push to + &Nazwa bazy danych, do której wypchnąć + + + + Commit message + Opis wdrożenia + + + + Database licence + Licencja bazy danych + + + + Public + Publiczna + + + + Branch + Gałąź + + + + Force push + WymuÅ› wypchniÄ™cie + + + + Username + + + + + Database will be public. Everyone has read access to it. + Baza danych bÄ™dzie publiczna. Każdy bÄ™dzie mógÅ‚ uzyskać do niej dostÄ™p. + + + + Database will be private. Only you have access to it. + Baza danych bÄ™dzie prywatna. Tylko Ty bÄ™dziesz mieć do niej dostÄ™p. + + + + Use with care. This can cause remote commits to be deleted. + BÄ…dź ostrożny. Może to usunąć wdrożenia ze zdalnych miejsc. + + + + RunSql + + + Execution aborted by user + Wykonywanie przerwane przez użytkownika + + + + , %1 rows affected + , dotyczyÅ‚o %1 wiersza + + + + query executed successfully. Took %1ms%2 + pomyÅ›lnie wykonano zapytanie. Zajęło to %1ms%2 + + + + executing query + wykonywanie zapytania + + + + SelectItemsPopup + + + A&vailable + &DostÄ™pne + + + + Sele&cted + &Wybrane + + + + SqlExecutionArea + + + Form + Formularz + + + + Find previous match [Shift+F3] + Znajdź poprzednie trafienie [Shift+F3] + + + + Find previous match with wrapping + Znajdź poprzednie pasujÄ…ce z zawijaniem + + + + Shift+F3 + + + + + The found pattern must be a whole word + Wzorzec do znalezienia musi być caÅ‚ym sÅ‚owem + + + + Whole Words + CaÅ‚e sÅ‚owa + + + + Text pattern to find considering the checks in this frame + Wzorzec tekstu do znalezienia, biorÄ…c pod uwagÄ™ pola zaznaczone w tym oknie + + + + Find in editor + Znajdź w edytorze + + + + The found pattern must match in letter case + Wzorzec do znalezienia musi pasować wielkoÅ›ciÄ… liter + + + + Case Sensitive + Rozróżniaj wielkość znaków + + + + Find next match [Enter, F3] + Znajdź nastÄ™pne trafienie [Enter, F3] + + + + Find next match with wrapping + Znajdź nastÄ™pne pasujÄ…ce z zawijaniem + + + + F3 + + + + + Interpret search pattern as a regular expression + Rozpatrz wzorzec wyszukiwania jako wyrażenie regularne + + + + <html><head/><body><p>When checked, the pattern to find is interpreted as a UNIX regular expression. See <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>.</p></body></html> + <html><head/><body><p>Po zaznaczeniu, wzorzec do znalezienia jest rozważany jako wyrażenie regularne UNIX. Zajrzyj do <a href="https://en.wikibooks.org/wiki/Regular_Expressions">WyrażeÅ„ Regularnych w Wikibooks</a>.</p></body></html> + + + + Regular Expression + Wyrażenie regularne + + + + + Close Find Bar + Zamknij pasek wyszukiwania + + + + <html><head/><body><p>Results of the last executed statements.</p><p>You may want to collapse this panel and use the <span style=" font-style:italic;">SQL Log</span> dock with <span style=" font-style:italic;">User</span> selection instead.</p></body></html> + <html><head/><body><p>Wynik ostatnio wykonanych poleceÅ„.</p><p>Zalecamy zwiniÄ™cie tego okna i otworzenie doku <span style=" font-style:italic;">Dziennika SQL</span> z wyborem <span style=" font-style:italic;">Użytkownika</span>.</p></body></html> + + + + Results of the last executed statements + Wyniki ostatnio wykonanych poleceÅ„ + + + + This field shows the results and status codes of the last executed statements. + To pole pokazuje wyniki i kody wyjÅ›cia ostatnio wykonanych poleceÅ„ + + + + Couldn't read file: %1. + Nie można odczytać pliku: %1. + + + + + Couldn't save file: %1. + Nie można zapisać pliku: %1. + + + + Your changes will be lost when reloading it! + Utracisz swoje zmiany po ponownym wczytaniu! + + + + The file "%1" was modified by another program. Do you want to reload it?%2 + Inny program zmieniÅ‚ plik "%1". Czy chcesz wczytać go ponownie?%2 + + + + SqlTextEdit + + + Ctrl+/ + + + + + SqlUiLexer + + + (X) The abs(X) function returns the absolute value of the numeric argument X. + (X) Funkcja abs(X) zwraca wartość bezwzglÄ™dnÄ… argumentu liczbowego X. + + + + () The changes() function returns the number of database rows that were changed or inserted or deleted by the most recently completed INSERT, DELETE, or UPDATE statement. + () Funkcja changes() zwraca liczbÄ™ wierszy bazy danych, które zostaÅ‚y wstawiony lub usuniÄ™te przez ostatnio ukoÅ„czone polecenie INSERT, DELETE, or UPDATE. + + + + (X1,X2,...) The char(X1,X2,...,XN) function returns a string composed of characters having the unicode code point values of integers X1 through XN, respectively. + (X1,X2,...) Funkcja char(X1,X2,...,XN) zwraca ciÄ…g znaków skÅ‚adajÄ…cy siÄ™ ze znaków majÄ…cych wartoÅ›ci punków kodu unikod bÄ™dÄ…cych liczbami caÅ‚kowitymi w zakresie od X1 do XN, odpowiednio. + + + + (X,Y,...) The coalesce() function returns a copy of its first non-NULL argument, or NULL if all arguments are NULL + (X,Y,...) Funkcja coalesce() zwraca kopiÄ™ swojego pierwszego argumentu nie-NULL lub NULL, jeÅ›li wszystkie argumenty sÄ… NULL + + + + (X,Y) The glob(X,Y) function is equivalent to the expression "Y GLOB X". + (X,Y) Funkcja glob(X,Y) jest tożsama wyrażeniu "Y GLOB X". + + + + (X,Y) The ifnull() function returns a copy of its first non-NULL argument, or NULL if both arguments are NULL. + (X,Y) Funkcja ifnull() zwraca kopiÄ™ swojego pierwszego argumentu nie-NULL lub NULL, jeÅ›li oba argumenty sÄ… NULL. + + + + (X,Y) The instr(X,Y) function finds the first occurrence of string Y within string X and returns the number of prior characters plus 1, or 0 if Y is nowhere found within X. + (X,Y) Funkcja instr(X,Y) znajduje pierwsze wystÄ…pienie ciÄ…gu znaków Y wewnÄ…trz ciÄ…gu znaków X i zwraca liczbÄ™ znaków poprzedzajÄ…cych plus 1, lub 0, jeÅ›li nie można znaleźć Y w X. + + + + (X) The hex() function interprets its argument as a BLOB and returns a string which is the upper-case hexadecimal rendering of the content of that blob. + (X) Funkcja hex() interpretuje swoje argumenty jako KAWAÅKI i zwraca ciÄ…gi znaków, które sÄ… przedstawieniem szesnastkowym treÅ›ci kawaÅ‚ka, zapisanym wielkimi literami. + + + + () The last_insert_rowid() function returns the ROWID of the last row insert from the database connection which invoked the function. + () Funkcja last_insert_rowid() zwraca ROWID ostatniego wstawionego wiersza z połączenia bazy danych, która wywoÅ‚aÅ‚a tÄ™ funkcjÄ™. + + + + (X) For a string value X, the length(X) function returns the number of characters (not bytes) in X prior to the first NUL character. + (X) Dla wartoÅ›ci ciÄ…gu znaków X, funkcja length(X) zwraca liczbÄ™ znaków (nie bajtów) w X do chwili napotkania pierwszego znaku NUL. + + + + (X,Y) The like() function is used to implement the "Y LIKE X" expression. + (X,Y) Funkcja like() jest używana do implementacji wyrażenia "Y LIKE X". + + + + (X,Y,Z) The like() function is used to implement the "Y LIKE X ESCAPE Z" expression. + (X,Y,Z) Funkcja like() jest używana do implementacji wyrażenia "Y LIKE X ESCAPE Z". + + + + (X) The load_extension(X) function loads SQLite extensions out of the shared library file named X. +Use of this function must be authorized from Preferences. + (X) Funkcja load_extension(X) wczytuje rozszerzenia SQLite z pliku biblioteki współdzielonej o nazwie X. +Aby użyć tej funkcji, należy wyrazić zgodÄ™ w Ustawieniach. + + + + (X,Y) The load_extension(X) function loads SQLite extensions out of the shared library file named X using the entry point Y. +Use of this function must be authorized from Preferences. + (X,Y) Funkcja load_extension(X) wczytuje rozszerzenia SQLite z pliku biblioteki współdzielonej o nazwie X przy użyciu punktu wejÅ›ciowego Y. +Aby użyć tej funkcji, należy wyrazić zgodÄ™ w Ustawieniach. + + + + (X) The lower(X) function returns a copy of string X with all ASCII characters converted to lower case. + (X) Funkcja lower(X) zwraca kopiÄ™ ciÄ…gu znaków X po przeksztaÅ‚ceniu wszystkich znaków ASCII na pisane maÅ‚ymi literami. + + + + (X) ltrim(X) removes spaces from the left side of X. + (X) ltrim(X) usuwa odstÄ™py z lewej strony X. + + + + (X,Y) The ltrim(X,Y) function returns a string formed by removing any and all characters that appear in Y from the left side of X. + (X,Y) Funkcja ltrim(X,Y) zwraca ciÄ…g znaków utworzony po usuniÄ™ciu dowolnego i wszystkich znaków, które ukazujÄ… siÄ™ w Y z lewej strony X. + + + + (X,Y,...) The multi-argument max() function returns the argument with the maximum value, or return NULL if any argument is NULL. + (X,Y,...) Funkcja wieloargumentowa max() zwraca argument o wartoÅ›ci najwiÄ™kszej lub NULL, jeÅ›li dowolny argument jest NULL. + + + + (X,Y,...) The multi-argument min() function returns the argument with the minimum value. + (X,Y,...) Funkcja wieloargumentowa min() zwraca argument o wartoÅ›ci najmniejszej. + + + + (X,Y) The nullif(X,Y) function returns its first argument if the arguments are different and NULL if the arguments are the same. + (X,Y) Funkcja nullif(X,Y) zwraca swój pierwszy argument, jeÅ›li argumenty sÄ… różne i NULL, jeÅ›li argumenty sÄ… te same. + + + + (FORMAT,...) The printf(FORMAT,...) SQL function works like the sqlite3_mprintf() C-language function and the printf() function from the standard C library. + (FORMAT,...) Funkcja SQL printf(FORMAT,...) dziaÅ‚a jak funkcja sqlite3_mprintf() jÄ™zyka C oraz printf() ze standardowej biblioteki C. + + + + (X) The quote(X) function returns the text of an SQL literal which is the value of its argument suitable for inclusion into an SQL statement. + (X) Funkcja quote(X) zwraca dosÅ‚owny tekst SQL, który jest wartoÅ›ciÄ… jego argumentów +gotowÄ… do wstawienia w polecenie SQL. + + + + () The random() function returns a pseudo-random integer between -9223372036854775808 and +9223372036854775807. + () Funkcja random() zwraca pseudo-losowÄ… liczbÄ™ caÅ‚kowitÄ… z zakresu od -9223372036854775808 do +9223372036854775807. + + + + (N) The randomblob(N) function return an N-byte blob containing pseudo-random bytes. + (N) Funkcja randomblob(N) zwraca N-bajtowy kawaÅ‚ek zawierajÄ…cy pseudo-losowe bajty. + + + + (X,Y,Z) The replace(X,Y,Z) function returns a string formed by substituting string Z for every occurrence of string Y in string X. + (X,Y,Z) Funkcja replace(X,Y,Z) zwraca ciÄ…g znaków utworzony poprzez podmianÄ™ ciÄ…gu znaków Z dla każdego wystÄ…pienia ciÄ…gu znaków Y w ciÄ…gu znaków X. + + + + (X) The round(X) function returns a floating-point value X rounded to zero digits to the right of the decimal point. + (X) Funkcja round(X) zwraca wartość liczby zmiennoprzecinkowej X zaokrÄ…glonej do części caÅ‚kowitej. + + + + (X,Y) The round(X,Y) function returns a floating-point value X rounded to Y digits to the right of the decimal point. + (X,Y) Funkcja round(X,Y) zwraca wartość liczby zmiennoprzecinkowej X zaokrÄ…glonej do liczby znaków dziesiÄ™tnych okreÅ›lonych przez Y. + + + + (X) rtrim(X) removes spaces from the right side of X. + (X) rtrim(X) usuwa odstÄ™py z prawej strony X. + + + + (X,Y) The rtrim(X,Y) function returns a string formed by removing any and all characters that appear in Y from the right side of X. + (X,Y) Funkcja rtrim(X,Y) zwraca ciÄ…g znaków utworzony po usuniÄ™ciu dowolnego i wszystkich znaków, które ukazujÄ… siÄ™ w Y z prawej strony X. + + + + (X) The soundex(X) function returns a string that is the soundex encoding of the string X. + (X) Funkcja soundex(X) zwraca ciÄ…g znaków X zakodowany jako soundex. + + + + (X,Y) substr(X,Y) returns all characters through the end of the string X beginning with the Y-th. + (X,Y) substr(X,Y) zwraca wszystkie znaki do koÅ„ca ciÄ…gu znaków X zaczynajÄ…c od Y-tego. + + + + (X,Y,Z) The substr(X,Y,Z) function returns a substring of input string X that begins with the Y-th character and which is Z characters long. + (X,Y,Z) Funkcja substr(X,Y,Z) zwraca podciÄ…g znaków ciÄ…gu wejÅ›ciowego znaków X, który zaczyna siÄ™ na Y-tym znaku i który jest dÅ‚ugi na Z znaków. + + + + () The total_changes() function returns the number of row changes caused by INSERT, UPDATE or DELETE statements since the current database connection was opened. + () Funkcja total_changes() zwraca liczbÄ™ zmienionych wierszy przez polecenia INSERT, UPDATE lub DELETE od chwili nawiÄ…zania połączenia z bazÄ… danych. + + + + (X) trim(X) removes spaces from both ends of X. + (X) trim(X) usuwa odstÄ™py z obu stron X. + + + + (X,Y) The trim(X,Y) function returns a string formed by removing any and all characters that appear in Y from both ends of X. + (X,Y) Funkcja trim(X,Y) zwraca ciÄ…g znaków utworzony po usuniÄ™ciu dowolnego i wszystkich znaków, które ukazujÄ… siÄ™ w Y z obu stron X. + + + + (X) The typeof(X) function returns a string that indicates the datatype of the expression X. + (X) Funkcja typeof(X) zwraca ciÄ…g znaków, który wskazuje na rodzaj danych wyrażenia X. + + + + (X) The unicode(X) function returns the numeric unicode code point corresponding to the first character of the string X. + (X) Funkcja unicode(X) zwraca punkt numerycznego kodu unikodu odpowiadajÄ…cy pierwszemu znakowi ciÄ…gu X. + + + + (X) The upper(X) function returns a copy of input string X in which all lower-case ASCII characters are converted to their upper-case equivalent. + (X) Funkcja upper(X) zwraca kopiÄ™ ciÄ…gu znaków X po przeksztaÅ‚ceniu wszystkich znaków ASCII na pisane wielkimi literami. + + + + (N) The zeroblob(N) function returns a BLOB consisting of N bytes of 0x00. + (N) Funkcja zeroblob(N) zwraca KAWAÅEK skÅ‚adajÄ…cy siÄ™ z N bajtów 0x00. + + + + + + + (timestring,modifier,modifier,...) + (ciÄ…g_znaków_czasu,zmieniacz,zmieniacz,...) + + + + (format,timestring,modifier,modifier,...) + (format,ciÄ…g_znaków_czasu,zmieniacz,zmieniacz,...) + + + + (X) The avg() function returns the average value of all non-NULL X within a group. + (X) Funkcja avg() zwraca wartość Å›redniÄ… wszystkich nie-NULL X wewnÄ…trz grupy. + + + + (X) The count(X) function returns a count of the number of times that X is not NULL in a group. + (X) Funkcja count(X) zwraca liczbÄ™ tego ile razy X nie jest NULL w grupie. + + + + (X) The group_concat() function returns a string which is the concatenation of all non-NULL values of X. + (X) Funkcja group_concat() zwraca ciÄ…g znaków, który jest złączeniem wszystkich wartoÅ›ci nie-NULL X. + + + + (X,Y) The group_concat() function returns a string which is the concatenation of all non-NULL values of X. If parameter Y is present then it is used as the separator between instances of X. + (X,Y) Funkcja group_concat() zwraca ciÄ…g znaków bÄ™dÄ…cy złączeniem wszystkich wartoÅ›ci nie-NULL X. JeÅ›li obecne jest Y, to sÅ‚uży jako znak oddzielajÄ…cy wystÄ…pienia X. + + + + (X) The max() aggregate function returns the maximum value of all values in the group. + (X) Funkcja max() zwraca najwyższÄ… wartość z wartoÅ›ci w grupie. + + + + (X) The min() aggregate function returns the minimum non-NULL value of all values in the group. + (X) Funkcja min() zwraca najmniejszÄ… wartość nie-NULL z wartoÅ›ci w grupie. + + + + + (X) The sum() and total() aggregate functions return sum of all non-NULL values in the group. + (X) Funkcje sum() oraz total() zwracajÄ… sumÄ™ wszystkich wartoÅ›ci nie-NULL w grupie. + + + + () The number of the row within the current partition. Rows are numbered starting from 1 in the order defined by the ORDER BY clause in the window definition, or in arbitrary order otherwise. + () Numer wiersza wewnÄ…trz bieżącej partycji. Partycje sÄ… ponumerowane od 1 w kolejnoÅ›ci okreÅ›lonej przez wyrażenie ORDER BY w okreÅ›leniu okna lub w dowolnej kolejnoÅ›ci. + + + + () The row_number() of the first peer in each group - the rank of the current row with gaps. If there is no ORDER BY clause, then all rows are considered peers and this function always returns 1. + () Numer wiersza row_number() pierwszego czÅ‚onka w każdej grupie - ranga bieżącego wiersza w rozstÄ™pach. JeÅ›li brak polecenia ORDER BY, to wszystkie wiersze sÄ… rozważane jako czÅ‚onkowie i funkcja zawsze zwraca 1. + + + + () The number of the current row's peer group within its partition - the rank of the current row without gaps. Partitions are numbered starting from 1 in the order defined by the ORDER BY clause in the window definition. If there is no ORDER BY clause, then all rows are considered peers and this function always returns 1. + () Numer grupy bieżącego wiersza wewnÄ…trz jego partycji - ranga bieżącego wiersza bez przerw. Partycje sÄ… ponumerowane od 1 w kolejnoÅ›ci okreÅ›lonej przez wyrażenie ORDER BY w okreÅ›leniu okna. JeÅ›li brak wyrażenia ORDER BY, to wszystkie wiersze sÄ… rozważane jako leżące obok siebie, a funkcja ta zwraca 1. + + + + () Despite the name, this function always returns a value between 0.0 and 1.0 equal to (rank - 1)/(partition-rows - 1), where rank is the value returned by built-in window function rank() and partition-rows is the total number of rows in the partition. If the partition contains only one row, this function returns 0.0. + () Pomimo nazwy, funkcja ta zawsze zwraca wartość pomiÄ™dzy 0.0 oraz 1.0 równÄ… (rank - 1)/(wiersze-partycji - 1), gdzie rank jest wartoÅ›ciÄ… zwracanÄ… przez wbudowanÄ… funkcjÄ™ rank() okna, a wiersze-partycji jest caÅ‚kowitÄ… liczbÄ… wierszy w partycji. JeÅ›li partycja zawiera tylko jeden wiersz, to ta funkcja zwraca 0.0. + + + + () The cumulative distribution. Calculated as row-number/partition-rows, where row-number is the value returned by row_number() for the last peer in the group and partition-rows the number of rows in the partition. + () RozkÅ‚ad nagromadzony. Obliczany jako numer-wiersza/wiersze-partycji, gdzie +numer-wiersza jest wartoÅ›ciÄ… zwracanÄ… przez row_number() dla ostatniego +elementu w grupie, a wiersze-partycji to liczba wierszy w partycji. + + + + (N) Argument N is handled as an integer. This function divides the partition into N groups as evenly as possible and assigns an integer between 1 and N to each group, in the order defined by the ORDER BY clause, or in arbitrary order otherwise. If necessary, larger groups occur first. This function returns the integer value assigned to the group that the current row is a part of. + (N) Argument N jest rozważany jako liczba caÅ‚kowita. Ta funkcja dzieli partycjÄ™ na N grup tak równo jak to możliwe i przypisuje liczbÄ™ caÅ‚kowitÄ… z zakresu od 1 do N każdej grupie w kolejnoÅ›ci okreÅ›lonej przez polecenie ORDER BY lub dowolnej. JeÅ›li zajdzie taka potrzeba, to wiÄ™ksze grupy wystÄ…piÄ… jako pierwsze. Ta funkcja zwraca liczbÄ™ caÅ‚kowitÄ… przypisanÄ… do grupy, do której bieżący wiersz należy. + + + + (expr) Returns the result of evaluating expression expr against the previous row in the partition. Or, if there is no previous row (because the current row is the first), NULL. + (expr) Zwraca wynik obliczania wyrażenia expr na poprzednim wierszu w partycji. Lub, jeÅ›li nie ma poprzedniego wiersza (bo bieżący wiersz jest pierwszym), NULL. + + + + (expr,offset) If the offset argument is provided, then it must be a non-negative integer. In this case the value returned is the result of evaluating expr against the row offset rows before the current row within the partition. If offset is 0, then expr is evaluated against the current row. If there is no row offset rows before the current row, NULL is returned. + (expr,przesuniÄ™cie) JeÅ›li podano argument przesuniÄ™cia, to musi on być nieujemnÄ… liczbÄ… caÅ‚kowitÄ…. W tym przypadku wartoÅ›ciÄ… zwracanÄ… jest wynik obliczenia wyrażenia na wierszu przesuniÄ™tym o danÄ… liczbÄ™ wierszy wstecz wzglÄ™dem bieżącego wiersza. JeÅ›li nie bÄ™dzie takiego wiersza, to zwracane jest NULL. + + + + + (expr,offset,default) If default is also provided, then it is returned instead of NULL if the row identified by offset does not exist. + (expr,przesuniÄ™cie,domyÅ›lne) JeÅ›li podano także domyÅ›lne, to jest to wartoÅ›ci zwracana zamiast NULL, jeÅ›li wiersz okreÅ›lony przez przesuniÄ™cie nie istnieje. + + + + (expr) Returns the result of evaluating expression expr against the next row in the partition. Or, if there is no next row (because the current row is the last), NULL. + (expr) Zwraca wynik obliczania wyrażenia expr na nastÄ™pnym wierszu w partycji. Lub, jeÅ›li nie ma nastÄ™pnego wiersza (bo bieżący wiersz jest ostatnim), NULL. + + + + (expr,offset) If the offset argument is provided, then it must be a non-negative integer. In this case the value returned is the result of evaluating expr against the row offset rows after the current row within the partition. If offset is 0, then expr is evaluated against the current row. If there is no row offset rows after the current row, NULL is returned. + (expr,przesuniÄ™cie) JeÅ›li podano argument przesuniÄ™cia, to musi on być nieujemnÄ… liczbÄ… caÅ‚kowitÄ…. W tym przypadku wartoÅ›ciÄ… zwracanÄ… jest wynik obliczenia wyrażenia na wierszu przesuniÄ™tym o danÄ… liczbÄ™ wierszy wprzód wzglÄ™dem bieżącego wiersza. JeÅ›li nie bÄ™dzie takiego wiersza, to zwracane jest NULL. + + + + (expr) This built-in window function calculates the window frame for each row in the same way as an aggregate window function. It returns the value of expr evaluated against the first row in the window frame for each row. + (expr) Ta wbudowana funkcja okna oblicza ramÄ™ okna dla każdego wiersza w ten sam sposób jak funkcja okna zÅ‚ożonego. Zwraca wartość expr obliczonÄ… na pierwszym wierszu ramy okna dla każdego wiersza. + + + + (expr) This built-in window function calculates the window frame for each row in the same way as an aggregate window function. It returns the value of expr evaluated against the last row in the window frame for each row. + (expr) Ta wbudowana funkcja okna oblicza ramÄ™ okna dla każdego wiersza w ten sam sposób jak funkcja okna zÅ‚ożonego. Zwraca wartość expr obliczonÄ… na ostatnim wierszu ramy okna dla każdego wiersza. + + + + (expr,N) This built-in window function calculates the window frame for each row in the same way as an aggregate window function. It returns the value of expr evaluated against the row N of the window frame. Rows are numbered within the window frame starting from 1 in the order defined by the ORDER BY clause if one is present, or in arbitrary order otherwise. If there is no Nth row in the partition, then NULL is returned. + (expr,N) Ta wbudowana funkcja okna oblicza ramÄ™ okna dla każdego wiersza w ten sam sposób jak funkcja okna zÅ‚ożonego. Zwraca wartość expr obliczonÄ… na N-tym wierszu ramy okna. Wiersze sÄ… numerowane wewnÄ…trz ramy okna poczynajÄ…c od 1 w kolejnoÅ›ci okreÅ›lonej przez polecenie ORDER BY jeÅ›li jest obecne lub w dowolnej kolejnoÅ›ci. JeÅ›li N-ty wiersz nie istnieje w partycji, to zwracane jest NULL. + + + + SqliteTableModel + + + reading rows + czytanie wierszy + + + + loading... + wczytywanie... + + + + References %1(%2) +Hold %3Shift and click to jump there + OdwoÅ‚ania %1(%2) +PrzyciÅ›nij %3Shift i kliknij, aby tu przejść + + + + Error changing data: +%1 + WystÄ…piÅ‚ błąd podczas zmiany danych: +%1 + + + + retrieving list of columns + uzyskiwanie listy kolumn + + + + Fetching data... + Uzyskiwanie danych… + + + + + Cancel + Zaniechaj + + + + TableBrowser + + + Browse Data + PrzeglÄ…daj dane + + + + &Table: + &Tabela: + + + + Select a table to browse data + Wybierz tabelÄ™, aby przeglÄ…dać dane + + + + Use this list to select a table to be displayed in the database view + Użyj tej listy, aby zaznaczyć tabelÄ™ wyÅ›wietlanÄ… w widoku bazy danych + + + + This is the database table view. You can do the following actions: + - Start writing for editing inline the value. + - Double-click any record to edit its contents in the cell editor window. + - Alt+Del for deleting the cell content to NULL. + - Ctrl+" for duplicating the current record. + - Ctrl+' for copying the value from the cell above. + - Standard selection and copy/paste operations. + Oto widok tabeli bazy danych. Możliwe sÄ… nastÄ™pujÄ…ce dziaÅ‚ania: + - Pisanie do przeedytowania wartoÅ›ci w-wierszu. + - Dwukrotne klikniÄ™cie na rekordzie, aby edytować jego zawartość w edytorze komórek. + - Alt+Del do usuniÄ™cia treÅ›ci komórki i ustawienia NULL. + - Ctrl+" do powielenia bieżącego rekordu. + - Ctrl+' do skopiowania wartoÅ›ci z komórki powyżej. + - Standardowe zaznaczanie/kopiowanie/wklejanie. + + + + Text pattern to find considering the checks in this frame + Wzorzec tekstu do znalezienia, biorÄ…c pod uwagÄ™ pola zaznaczone w tym oknie + + + + Find in table + Znajdź w tabeli + + + + Find previous match [Shift+F3] + Znajdź poprzednie pasujÄ…ce [Shift+F3] + + + + Find previous match with wrapping + Znajdź poprzednie pasujÄ…ce z mapowaniem + + + + Shift+F3 + + + + + Find next match [Enter, F3] + Znajdź nastÄ™pne pasujÄ…ce [Enter, F3] + + + + Find next match with wrapping + Znajdź nastÄ™pne pasujÄ…ce z nawracaniem + + + + F3 + + + + + The found pattern must match in letter case + Wzorzec do znalezienia musi pasować wielkoÅ›ciÄ… liter + + + + Case Sensitive + Rozróżniaj wielkość liter + + + + The found pattern must be a whole word + Wzorzec do znalezienia musi być caÅ‚ym sÅ‚owem + + + + Whole Cell + CaÅ‚a komórka + + + + Interpret search pattern as a regular expression + Rozpatrz wzorzec wyszukiwania jako wyrażenie regularne + + + + <html><head/><body><p>When checked, the pattern to find is interpreted as a UNIX regular expression. See <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>.</p></body></html> + <html><head/><body><p>Po zaznaczeniu, wzorzec do znalezienia jest rozważany jako wyrażenie regularne UNIX. Zajrzyj do <a href="https://en.wikibooks.org/wiki/Regular_Expressions">WyrażeÅ„ Regularnych w Wikibooks</a>.</p></body></html> + + + + Regular Expression + Wyrażenie regularne + + + + + Close Find Bar + Zamknij pasek wyszukiwania + + + + Text to replace with + Tekst do zastÄ…pienia + + + + Replace with + ZastÄ…p + + + + Replace next match + ZastÄ…p nastÄ™pne pasujÄ…ce wyrażenie + + + + + Replace + ZastÄ…p + + + + Replace all matches + ZastÄ…p wszystkie pasujÄ…ce wyrażenia + + + + Replace all + ZastÄ…p wszystkie + + + + <html><head/><body><p>Scroll to the beginning</p></body></html> + <html><head/><body><p>PrzewiÅ„ do poczÄ…tku</p></body></html> + + + + <html><head/><body><p>Clicking this button navigates to the beginning in the table view above.</p></body></html> + <html><head/><body><p>NaciÅ›niÄ™cie tego przycisku kieruje na poczÄ…tek powyższego widoku tabeli.</p></body></html> + + + + |< + |< + + + + Scroll one page upwards + PrzewiÅ„ jednÄ… stronÄ™ w górÄ™ + + + + <html><head/><body><p>Clicking this button navigates one page of records upwards in the table view above.</p></body></html> + <html><head/><body><p>NaciÅ›niÄ™cie tego przycisku przenosi o jednÄ… stronÄ™ wyżej w powyższym widoku tabeli.</p></body></html> + + + + < + < + + + + 0 - 0 of 0 + 0 - 0 z 0 + + + + Scroll one page downwards + PrzewiÅ„ jednÄ… stronÄ™ w dół + + + + <html><head/><body><p>Clicking this button navigates one page of records downwards in the table view above.</p></body></html> + <html><head/><body><p>NaciÅ›niÄ™cie tego przycisku przenosi o jednÄ… stronÄ™ niżej w powyższym widoku tabeli.</p></body></html> + + + + > + > + + + + Scroll to the end + PrzewiÅ„ na koniec + + + + <html><head/><body><p>Clicking this button navigates up to the end in the table view above.</p></body></html> + + + + + >| + >| + + + + <html><head/><body><p>Click here to jump to the specified record</p></body></html> + <html><head/><body><p>NaciÅ›nij tutaj, aby przejść do danego rekordu</p></body></html> + + + + <html><head/><body><p>This button is used to navigate to the record number specified in the Go to area.</p></body></html> + <html><head/><body><p>Ten przycisk sÅ‚uży to przejÅ›cia do rekordu o numerze podanym w obszarze PrzejÅ›cia.</p></body></html> + + + + Go to: + Przejdź do: + + + + Enter record number to browse + Wprowadź numer rekordu do przejrzenia + + + + Type a record number in this area and click the Go to: button to display the record in the database view + Wpisz numer rekordu w tym obszarze i naciÅ›nij na Przejdź Do, aby wyÅ›wietlić rekord w widoku bazy danych + + + + 1 + 1 + + + + Show rowid column + Pokaż kolumnÄ™ ID wiersza + + + + Toggle the visibility of the rowid column + Pokaż/Ukryj kolumnÄ™ ID wiersza + + + + Unlock view editing + Odblokuj zmianÄ™ widoku + + + + This unlocks the current view for editing. However, you will need appropriate triggers for editing. + To umożliwia wprowadzanie zmian w bieżącym widoku. Jednakże potrzebne bÄ™dÄ… odpowiednie wyzwalacze do zmiany. + + + + Edit display format + ZmieÅ„ format wyÅ›wietlania + + + + Edit the display format of the data in this column + ZmieÅ„ sposób wyÅ›wietlania danych w tej kolumnie + + + + + New Record + Nowy rekord + + + + + Insert a new record in the current table + Wstaw nowy rekord bieżącej tabeli + + + + <html><head/><body><p>This button creates a new record in the database. Hold the mouse button to open a pop-up menu of different options:</p><ul><li><span style=" font-weight:600;">New Record</span>: insert a new record with default values in the database.</li><li><span style=" font-weight:600;">Insert Values...</span>: open a dialog for entering values before they are inserted in the database. This allows to enter values acomplishing the different constraints. This dialog is also open if the <span style=" font-weight:600;">New Record</span> option fails due to these constraints.</li></ul></body></html> + <html><head/><body><p>Ten przycisk tworzy nowy rekord w bazie danych. PrzyciÅ›nij przycisk myszy, aby otworzyć menu podrÄ™czne z różnymi ustawieniami:</p><ul><li><span style=" font-weight:600;">Nowy rekord</span>: wstawia nowy rekord o domyÅ›lnych wartoÅ›ciach do bazy danych.</li><li><span style=" font-weight:600;">Wstaw wartoÅ›ci...</span>: otwiera okno dialogowe do wpisywania wartoÅ›ci przed ich wstawieniem do bazy danych. Umożliwia to wpisanie wartoÅ›ci przy zachowaniu różnych ograniczeÅ„. To okno dialogowe jest także otwarte, gdy nie powiedzie siÄ™ wykonanie polecenia <span style=" font-weight:600;">Nowy rekord</span> ze wzglÄ™du na te ograniczenia .</li></ul></body></html> + + + + + Delete Record + UsuÅ„ rekord + + + + Delete the current record + UsuÅ„ bieżący rekord + + + + + This button deletes the record or records currently selected in the table + Ten przycisk usuwa obecnie zaznaczony rekord lub rekordy z tabeli + + + + + Insert new record using default values in browsed table + Wstaw nowy rekord przy użyciu domyÅ›lnych wartoÅ›ci bieżącej tabeli + + + + Insert Values... + Wstaw wartoÅ›ci... + + + + + Open a dialog for inserting values in a new record + Otwiera okno dialogowe do wstawiania wartoÅ›ci do nowego rekordu + + + + Export to &CSV + Eksportuj do &CSV + + + + + Export the filtered data to CSV + Eksportuj przefiltrowane dane do CSV + + + + This button exports the data of the browsed table as currently displayed (after filters, display formats and order column) as a CSV file. + Ten przycisk wyeksportuje dane bieżącej tabeli tak jak sÄ… obecnie wyÅ›wietlane (po filtrach, z formatami wyÅ›wietlania i kolejnoÅ›ciÄ… kolumn) jako plik CSV. + + + + Save as &view + Zapisz jako &widok + + + + + Save the current filter, sort column and display formats as a view + Zapisuje bieżący filtr, kolumnÄ™ do szeregowania oraz formaty wyÅ›wietlania jako widok + + + + This button saves the current setting of the browsed table (filters, display formats and order column) as an SQL view that you can later browse or use in SQL statements. + Ten przycisk zapisuje bieżące ustawienia oglÄ…danej tabeli (filtry, formaty wyÅ›wietlania i kolejność kolumn) jako widok SQL, który można później przeglÄ…dać lub wstawić do polecenia SQL. + + + + Save Table As... + Zapisz tabelÄ™ jako... + + + + + Save the table as currently displayed + Zapisz tabelÄ™ tak, jak jest obecnie wyÅ›wietlana + + + + <html><head/><body><p>This popup menu provides the following options applying to the currently browsed and filtered table:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Export to CSV: this option exports the data of the browsed table as currently displayed (after filters, display formats and order column) to a CSV file.</li><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Save as view: this option saves the current setting of the browsed table (filters, display formats and order column) as an SQL view that you can later browse or use in SQL statements.</li></ul></body></html> + <html><head/><body><p>To menu podrÄ™czne zawiera nastÄ™pujÄ…ce ustawienie stosujÄ…ce siÄ™ do obecnie oglÄ…danej i filtrowanej tabeli:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Eksportuj do CSV: eksportuje dane oglÄ…danej tabeli tak jak jest obecnie wyÅ›wietlana (po filtrach, z formatami wyÅ›wietlania i kolejnoÅ›ciÄ… kolumn) do pliku CSV.</li><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Zapisz jako widok: zapisuje bieżące ustawienia oglÄ…danej tabeli (filtry, formaty wyÅ›wietlania i kolejność kolumn) jako widok SQL, który można później przeglÄ…dać lub wstawić do polecenia SQL.</li></ul></body></html> + + + + Hide column(s) + Ukryj kolumnÄ™/y + + + + Hide selected column(s) + Ukryj zaznaczonÄ…/e kolumnÄ™/y + + + + Show all columns + Pokaż wszystkie kolumny + + + + Show all columns that were hidden + Pokaż wszystkie ukryte kolumny + + + + + Set encoding + Ustaw kodowanie + + + + Change the encoding of the text in the table cells + ZmieÅ„ kodowanie tekstu w komórkach tabeli + + + + Set encoding for all tables + Ustaw kodowanie dla wszystkich tabel + + + + Change the default encoding assumed for all tables in the database + ZmieÅ„ domyÅ›lne kodowanie przyjÄ™te dla wszystkich table w bazie danych + + + + Clear Filters + Wyczyść filtry + + + + Clear all filters + Wyczyść wszystkie filtry + + + + + This button clears all the filters set in the header input fields for the currently browsed table. + Ten przycisk wyczyÅ›ci wszystkie filtry ustawione na polach wejÅ›ciowych nagłówka dla bieżącej tabeli. + + + + Clear Sorting + Wyczyść szeregowanie + + + + Reset the order of rows to the default + Przywróć porzÄ…dek wierszy do domyÅ›lnego + + + + + This button clears the sorting columns specified for the currently browsed table and returns to the default order. + Ten przycisk czyÅ›ci kolumny szeregowania dla danej tabeli i powraca do domyÅ›lnego porzÄ…dku. + + + + Print + Drukuj + + + + Print currently browsed table data + WyÅ›wietl dane bieżącej tabeli + + + + Print currently browsed table data. Print selection if more than one cell is selected. + Drukuj dane bieżącej tabeli. Drukuj zaznaczenie, jeÅ›li zaznaczono wiÄ™cej niż jednÄ… komórkÄ™. + + + + Ctrl+P + + + + + Refresh + OdÅ›wież + + + + Refresh the data in the selected table + OdÅ›wież dane w zaznaczonej tabeli + + + + This button refreshes the data in the currently selected table. + Ten przycisk odÅ›wieża dane w obecnie zaznaczonej tabeli. + + + + F5 + + + + + Find in cells + Znajdź w komórkach + + + + Open the find tool bar which allows you to search for values in the table view below. + Otwórz pasek wyszukiwania, który umożliwi wyszukiwanie wartoÅ›ci w poniższym widoku tabeli. + + + + + Bold + Pogrubienie + + + + Ctrl+B + + + + + + Italic + Kursywa + + + + + Underline + PodkreÅ›lenie + + + + Ctrl+U + + + + + + Align Right + Wyrównaj do prawej + + + + + Align Left + Wyrównaj do lewej + + + + + Center Horizontally + WyÅ›rodkuj w poziomie + + + + + Justify + Justowanie + + + + + Edit Conditional Formats... + Edytuj formatowanie warunkowe... + + + + Edit conditional formats for the current column + ZmieÅ„ formatowania warunkowe dla bieżącej kolumny + + + + Clear Format + Wyczyść format + + + + Clear All Formats + Wyczyść wszystkie formatowania + + + + + Clear all cell formatting from selected cells and all conditional formats from selected columns + Wyczyść wszystkie formatowania warunkowe dla zaznaczonej komórki i wszystkie formatowania warunkowe dla zaznaczonych kolumn + + + + + Font Color + Barwa czcionki + + + + + Background Color + Barwa tÅ‚a + + + + Toggle Format Toolbar + Pokaż pasek formatowania + + + + Show/hide format toolbar + Pokaż/ukryj pasek formatu + + + + + This button shows or hides the formatting toolbar of the Data Browser + Ten przycisk pokazuje lub ukrywa pasek formatowania dla przeglÄ…darki danych + + + + Select column + Zaznacz kolumnÄ™ + + + + Ctrl+Space + Ctrl+Spacja + + + + Replace text in cells + ZastÄ…p tekst w komórkach + + + + Filter in any column + + + + + Ctrl+R + + + + + %n row(s) + + %n wiersz + %n wiersze + %n wierszy + + + + + , %n column(s) + + , %n kolumna + , %n kolumny + , %n kolumn + + + + + . Sum: %1; Average: %2; Min: %3; Max: %4 + . Suma: %1; Åšrednia: %2; Min: %3; Maks: %4 + + + + Conditional formats for "%1" + Formatowania warunkowe dla "%1" + + + + determining row count... + okreÅ›lanie liczby wierszy… + + + + %1 - %2 of >= %3 + %1 - %2 z >= %3 + + + + %1 - %2 of %3 + %1 - %2 z %3 + + + + Please enter a pseudo-primary key in order to enable editing on this view. This should be the name of a unique column in the view. + Podaj pseudo-główny klucz, aby rozpocząć edytowanie w tym widoku. Powinna to być nazwa niepowtarzalnej kolumny w widoku. + + + + Delete Records + UsuÅ„ rekordy + + + + Duplicate records + Powielone rekordy + + + + Duplicate record + Powiel rekord + + + + Ctrl+" + + + + + Adjust rows to contents + Dostosuj wiersze do treÅ›ci + + + + Error deleting record: +%1 + Błąd usuwania rekordu: +%1 + + + + Please select a record first + Najpierw wybierz rekord + + + + There is no filter set for this table. View will not be created. + Nie ustawiono filtru dla tej tabeli. Widok nie zostanie utworzony. + + + + Please choose a new encoding for all tables. + Wybierz nowe kodowanie dla wszystkich tabel. + + + + Please choose a new encoding for this table. + Wybierz kodowanie dla tej tabeli. + + + + %1 +Leave the field empty for using the database encoding. + %1 +Pozostaw pole pustym, aby użyć kodowania bazy danych. + + + + This encoding is either not valid or not supported. + To kodowanie jest nieprawidÅ‚owe lub nieobsÅ‚ugiwane + + + + %1 replacement(s) made. + Wykonano %1 zastÄ…pieÅ„ + + + + VacuumDialog + + + Compact Database + ÅšciÅ›nij bazÄ™ danych... + + + + Warning: Compacting the database will commit all of your changes. + Uwaga: Åšciskanie bazy danych spowoduje wdrożenie wszystkich twoich zmian. + + + + Please select the databases to co&mpact: + Wybierz bazÄ™ danych do Å›ciÅ›&niÄ™cia: + + + diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/translations/sqlb_pt_BR.qm b/src/WBCLFZSystemModule/SqliteDBProcess/src/translations/sqlb_pt_BR.qm new file mode 100644 index 0000000000000000000000000000000000000000..c869afe8d8774e04322d185d8e7aa4c814e603a3 GIT binary patch literal 236318 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 literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/translations/sqlb_pt_BR.ts b/src/WBCLFZSystemModule/SqliteDBProcess/src/translations/sqlb_pt_BR.ts new file mode 100644 index 0000000..cc8776f --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/translations/sqlb_pt_BR.ts @@ -0,0 +1,7023 @@ + + + + + AboutDialog + + + About DB Browser for SQLite + Sobre DB Browser para SQLite + + + + Version + Versão + + + + <html><head/><body><p>DB Browser for SQLite is an open source, freeware visual tool used to create, design and edit SQLite database files.</p><p>It is bi-licensed under the Mozilla Public License Version 2, as well as the GNU General Public License Version 3 or later. You can modify or redistribute it under the conditions of these licenses.</p><p>See <a href="http://www.gnu.org/licenses/gpl.html">http://www.gnu.org/licenses/gpl.html</a> and <a href="https://www.mozilla.org/MPL/2.0/index.txt">https://www.mozilla.org/MPL/2.0/index.txt</a> for details.</p><p>For more information on this program please visit our website at: <a href="http://sqlitebrowser.org">http://sqlitebrowser.org</a></p><p><span style=" font-size:small;">This software uses the GPL/LGPL Qt Toolkit from </span><a href="http://qt-project.org/"><span style=" font-size:small;">http://qt-project.org/</span></a><span style=" font-size:small;"><br/>See </span><a href="http://qt-project.org/doc/qt-5/licensing.html"><span style=" font-size:small;">http://qt-project.org/doc/qt-5/licensing.html</span></a><span style=" font-size:small;"> for licensing terms and information.</span></p><p><span style=" font-size:small;">It also uses the Silk icon set by Mark James licensed under a Creative Commons Attribution 2.5 and 3.0 license.<br/>See </span><a href="http://www.famfamfam.com/lab/icons/silk/"><span style=" font-size:small;">http://www.famfamfam.com/lab/icons/silk/</span></a><span style=" font-size:small;"> for details.</span></p></body></html> + <html><head/><body><p>DB Browser para SQLite é uma ferramenta de código livre gratuita usada para criar, projetar e editar bancos de dados SQLite.</p><p>Ela é bi-licensiada sob a Mozilla Public License Version 2 e sob a GNU General Public License Version 3 ou posterior. Você pode modificar ou redistribuir ela sob as condições de qualquer uma dessas licenças.</p><p>Veja <a href="http://www.gnu.org/licenses/gpl.html">http://www.gnu.org/licenses/gpl.html</a> e <a href="https://www.mozilla.org/MPL/2.0/index.txt">https://www.mozilla.org/MPL/2.0/index.txt</a> para mais detalhes.</p><p>Para mais informações sobre esse programa visite nosso site em: <a href="http://sqlitebrowser.org">http://sqlitebrowser.org</a></p><p><span style=" font-size:small;">Esse software usa o GPL/LGPL Qt Toolkit de </span><a href="http://qt-project.org/"><span style=" font-size:small;">http://qt-project.org/</span></a><span style=" font-size:small;"><br/>Veja </span><a href="http://qt-project.org/doc/qt-5/licensing.html"><span style=" font-size:small;">http://qt-project.org/doc/qt-5/licensing.html</span></a><span style=" font-size:small;"> para termos de licença e informação.</span></p><p><span style=" font-size:small;">Ele também usa o conjunto de ícones Silk por Mark James licenciado sob a Creative Commons Attribution 2.5 e 3.0.<br/>Veja </span><a href="http://www.famfamfam.com/lab/icons/silk/"><span style=" font-size:small;">http://www.famfamfam.com/lab/icons/silk/</span></a><span style=" font-size:small;"> para detalhes.</span></p></body></html> + + + + AddRecordDialog + + + Add New Record + Adicionar novo registro + + + + Enter values for the new record considering constraints. Fields in bold are mandatory. + Entre valores para o novo registro considerando as restriões. Campos em negrito são obrigatórios. + + + + In the Value column you can specify the value for the field identified in the Name column. The Type column indicates the type of the field. Default values are displayed in the same style as NULL values. + Na coluna Valor você pode especificar o valor para o campo identificado na coluna Nome. A coluna Tipo indica qual o tipo do campo. Valores padrão são exibidos no mesmo estilo que valores nulos. + + + + Name + Nome + + + + Type + Tipo + + + + Value + Valor + + + + Values to insert. Pre-filled default values are inserted automatically unless they are changed. + Valores para inserir. Valores padrão pré-preenchidos são inseridos automaticamente a não ser que sejam alterados. + + + + When you edit the values in the upper frame, the SQL query for inserting this new record is shown here. You can edit manually the query before saving. + Quando você edita os valores no frame acima, a consulta SQL para inserir esse novo registro é exibida aqui. Você pode editar manualmente a consulta antes de salvar. + + + + <html><head/><body><p><span style=" font-weight:600;">Save</span> will submit the shown SQL statement to the database for inserting the new record.</p><p><span style=" font-weight:600;">Restore Defaults</span> will restore the initial values in the <span style=" font-weight:600;">Value</span> column.</p><p><span style=" font-weight:600;">Cancel</span> will close this dialog without executing the query.</p></body></html> + <html><head/><body><p><span style=" font-weight:600;">Salvar</span> irá enviar o comando SQL exibido para o banco de dados para a inserção do novo registro.</p><p><span style=" font-weight:600;">Restaurar Padrões</span> irá restaurar os valores iniciais na coluna <span style=" font-weight:600;">Valor</span>.</p><p><span style=" font-weight:600;">Cancelar</span> irá fechar esse diálogo sem executar a consulta.</p></body></html> + + + + Auto-increment + + Auto-incremento + + + + + Unique constraint + + Restrição de unicidade + + + + + Check constraint: %1 + + Restrição de condição %1 + + + + + Foreign key: %1 + + Chave estrangeira: %1 + + + + + Default value: %1 + + Valor padrão: %1 + + + + + Error adding record. Message from database engine: + +%1 + Erro adicionando registro. Mensagem do banco de dados: + +%1 + + + + Are you sure you want to restore all the entered values to their defaults? + Você tem certeza que deseja restaurar todos os valores inseridos para os seus valores padrão? + + + + Application + + + Possible command line arguments: + Possíveis argumentos da linha de comando: + + + + Usage: %1 [options] [<database>|<project>] + + Uso: %1 [opções] [<banco de dados>|<projeto>] + + + + + -h, --help Show command line options + -h, --help Exibir opções de linha de comando + + + + -q, --quit Exit application after running scripts + -q, --quit Sair do programa após executar os scripts + + + + -s, --sql <file> Execute this SQL file after opening the DB + -s, --sql <arquivo> Executar esse arquivo de SQL após abrir o BD + + + + -t, --table <table> Browse this table after opening the DB + -t, --table <tabela> Navegar essa tabela após abrir o banco de dados + + + + -R, --read-only Open database in read-only mode + -R, --read-only Abrir o banco de dados em modo somente leitura + + + + -o, --option <group>/<setting>=<value> + -o, -option <grupo>/<configuração>=valor + + + + Run application with this setting temporarily set to value + Roda a aplicação com esse valor para essa configuração temporariamente + + + + -O, --save-option <group>/<setting>=<value> + -O, --save-option <grupo>/<configuração>=valor + + + + Run application saving this value for this setting + Roda a aplicação salvando esse valor para essa configuração + + + + -v, --version Display the current version + -v, --version Exibir a versão atual + + + + <database> Open this SQLite database + <banco de dados> Abre esse banco de dados SQLite + + + + <project> Open this project file (*.sqbpro) + <projeto> Abre esse projeto (*.sqbpro) + + + + The -s/--sql option requires an argument + A opção -s/--sql requer um argumento + + + + The file %1 does not exist + O arquivo %1 não existe + + + + The -o/--option and -O/--save-option options require an argument in the form group/setting=value + As opções -o/--option e -O/--save-option requerem um argumento no formato grupo/configuração=valor + + + + Invalid option/non-existant file: %1 + Opção inválida/arquivo inexistente: %1 + + + + SQLite Version + Versão do SQLite + + + + SQLCipher Version %1 (based on SQLite %2) + SQLCipher versão %1 (baseado em SQLite %2) + + + + DB Browser for SQLite Version %1. + DB Browser para SQLite versão %1. + + + + Built for %1, running on %2 + Compilado para %1, rodando em %2 + + + + Qt Version %1 + Versão do Qt: %1 + + + + The -t/--table option requires an argument + A opção -t/--table requer um argumento + + + + CipherDialog + + + SQLCipher encryption + Encriptação SQLCipher + + + + &Password + &Senha + + + + &Reenter password + &Entre a senha novamente + + + + Encr&yption settings + &Configurações de encriptação + + + + SQLCipher &3 defaults + Padrões do SQLCipher &3 + + + + SQLCipher &4 defaults + Padrões do SQLCipher &4 + + + + Custo&m + Custo&mizado + + + + &KDF iterations + Iterações &KDF + + + + HMAC algorithm + Algoritmo de HMAC + + + + KDF algorithm + Algoritmo de KDF + + + + Plaintext Header Size + Tamanho do cabeçalho de texto + + + + Please enter the key used to encrypt the database. +If any of the other settings were altered for this database file you need to provide this information as well. + Por favor, entre a chave usada para encriptar o banco de dados. +Se quaisquer das outras configurações foram alteradas você terá de prover essas informações também. + + + + Please set a key to encrypt the database. +Note that if you change any of the other, optional, settings you'll need to re-enter them as well every time you open the database file. +Leave the password fields empty to disable the encryption. +The encryption process might take some time and you should have a backup copy of your database! Unsaved changes are applied before modifying the encryption. + Por favor, selecione uma chave para encriptar o banco de dados. +Note que se você alterar quaisquer configurações opcionais você terá de entrá-las todas as vezes que você abrir o arquivo do banco de dados. +Deixe os campos de senha em branco para desativar a encriptação. +O processo de encriptação pode demorar alguns minutos e você deve ter um backup do seu banco de dados! Alterações não salvas são aplicadas antes de se modificar a encriptação. + + + + Page si&ze + &Tamanho da página + + + + Passphrase + Palavra chave + + + + Raw key + Chave desencriptada + + + + ColumnDisplayFormatDialog + + + Choose display format + Escolha um formato de exibição + + + + Display format + Formato de exibição + + + + Choose a display format for the column '%1' which is applied to each value prior to showing it. + Escolha um formato de exibição para a coluna '%1' que será aplicado a cada valor antes de exibí-lo. + + + + Default + Padrão + + + + Decimal number + Número decimal + + + + Exponent notation + Notação exponencial + + + + Hex blob + BLOB hexadecimal + + + + Hex number + Número hexadecimal + + + + .NET DateTime.Ticks to date + .NET DateTime.Ticks até a data + + + + Julian day to date + Dia juliano para data + + + + Lower case + Caixa baixa + + + + Custom display format must contain a function call applied to %1 + Formato de exibição customizado precisa conter uma função aplicada a %1 + + + + Error in custom display format. Message from database engine: + +%1 + Erro em formato de exibição customizado. Mensagem da engine da base de dados: + +%1 + + + + Custom display format must return only one column but it returned %1. + Formato de exibição customizado precisa retornar apenas uma coluna mas retornou %1. + + + + Octal number + Octal + + + + Round number + Número arredondado + + + + Unix epoch to date + Era unix para data + + + + Upper case + Caixa alta + + + + Windows DATE to date + DATE do Windows para data + + + + Custom + Personalizado + + + + Apple NSDate to date + NSDate da Apple para date + + + + Java epoch (milliseconds) to date + Época Java (ms) para data + + + + Unix epoch to local time + Época Unix para tempo local + + + + Date as dd/mm/yyyy + Data como dd/mm/yyyy + + + + CondFormatManager + + + Conditional Format Manager + Gerenciador de formato condicional + + + + This dialog allows creating and editing conditional formats. Each cell style will be selected by the first accomplished condition for that cell data. Conditional formats can be moved up and down, where those at higher rows take precedence over those at lower. Syntax for conditions is the same as for filters and an empty condition applies to all values. + Esse diálogo permite a criação e edição de formatos condicionais. O estilo de cada célula será escolhido pela primeira condição satisfeita pelo valor daquela célula. Formatos condicionais podem ser movidos para cima e para baixo, tendo precedência os formatos localizados mais acima. A sintaxe para as condições é a mesma utilizada para os filtros e uma condição vazia é sempre satisfeita. + + + + Add new conditional format + Adicionar novo formato condicional + + + + &Add + &Adicionar + + + + Remove selected conditional format + Remover formato condicional selecionado + + + + &Remove + &Remover + + + + Move selected conditional format up + Mover formato condicional selecionado para cima + + + + Move &up + Mover para &cima + + + + Move selected conditional format down + Mover formato condicional selecionado para baixo + + + + Move &down + Mover para &baixo + + + + Foreground + Plano de frente + + + + Text color + Cor do texto + + + + Background + Fundo + + + + Background color + Cor do plano de fundo + + + + Font + Fonte + + + + Size + Tamanho + + + + Bold + Negrito + + + + Italic + Itálico + + + + Underline + Sublinhado + + + + Alignment + Alinhamento + + + + Condition + Condição + + + + + Click to select color + Clique para selecionar a cor + + + + Are you sure you want to clear all the conditional formats of this field? + Você tem certeza de que deseja limpar todos os formatos condicionais deste campo? + + + + DBBrowserDB + + + Please specify the database name under which you want to access the attached database + Por favor, especifique o nome do banco de dados sob o qual você quer acessar o banco de dados anexado + + + + Do you want to save the changes made to the database file %1? + Você quer salvar as alterações feitas ao arquivo de banco de dados %1? + + + + Exporting database to SQL file... + Exportando banco de dados para arquivo SQL... + + + + + Cancel + Cancelar + + + + Executing SQL... + Executando SQL... + + + + Action cancelled. + Ação cancelada. + + + + Restoring some of the objects associated with this table failed. This is most likely because some column names changed. Here's the SQL statement which you might want to fix and execute manually: + + + A restauração de alguns dos objetos associados com essa tabela falhou. Provavelmente porque os nomes de algumas colunas mudaram. Aqui está a consulta que você pode querer corrigir e executar manualmente: + + + + + + Error setting pragma %1 to %2: %3 + Erro definindo pragma %1 para %2: %3 + + + + File not found. + Arquivo não encontrado. + + + + Invalid file format + Formato de arquivo inválido + + + + + Error in statement #%1: %2. +Aborting execution%3. + Erro no comando #%1: %2. +Aborting execution%3. + + + + + and rolling back + e revertendo + + + + Cannot set data on this object + Não se pode definir dados nesse objeto + + + + could not get column information + não pôde obter informação sobre a coluna + + + + This database has already been attached. Its schema name is '%1'. + Esse banco de dados já foi anexado. O seu nome de esquema e '%1'. + + + + Do you really want to close this temporary database? All data will be lost. + Você realmente quer fechar esse banco de dados temporário? Todos os dados serão perdidos. + + + + Database didn't close correctly, probably still busy + A base de dados não fechou corretamente, provavelmente ainda ocupada + + + + The database is currently busy: + O banco de dados está ocupado: + + + + Do you want to abort that other operation? + Você quer abortar a outra operação? + + + + + No database file opened + Não há um arquivo de banco de dados aberto + + + + didn't receive any output from %1 + não recebeu nenhuma saída de %1 + + + + could not execute command: %1 + não pode executar comando: %1 + + + + Cannot delete this object + Não pode deletar esse objeto + + + + + A table with the name '%1' already exists in schema '%2'. + Uma tabela com o nome '%1' já existe no esquema '%2'. + + + + No table with name '%1' exists in schema '%2'. + Nem uma tabela chamada '%1' existe no esquema '%2'. + + + + + Cannot find column %1. + Não pode encontrar coluna %1. + + + + Creating savepoint failed. DB says: %1 + Criação de savepoint falhou. BD diz: %1 + + + + Renaming the column failed. DB says: +%1 + Renomeação de coluna falhou. BD diz: +%1 + + + + + Releasing savepoint failed. DB says: %1 + Liberação de savepoint falhou. BD diz: %1 + + + + Creating new table failed. DB says: %1 + Criação de tabela falhou. BD diz: %1 + + + + Copying data to new table failed. DB says: +%1 + Cópia de dados para uma nova tabela falhou. BD diz: +%1 + + + + Deleting old table failed. DB says: %1 + Deletando tabela antiga falhou. BD diz: %1 + + + + Error renaming table '%1' to '%2'. +Message from database engine: +%3 + Erro renomeando tabela de '%1' para '%2'. +Mensagem da engine do banco de dados: +%3 + + + + could not get list of db objects: %1 + não conseguiu listar objetos da BD: %1 + + + + could not get list of databases: %1 + não pôde obter a lista de bancos de dados: %1 + + + + Error loading extension: %1 + Erro carregado extensão: %1 + + + + DbStructureModel + + + Name + Nome + + + + Object + Objeto + + + + Type + Tipo + + + + Schema + Esquema + + + + Tables (%1) + Tabelas (%1) + + + + Indices (%1) + Ãndices (%1) + + + + Views (%1) + Vistas (%1) + + + + Triggers (%1) + Gatilhos (%1) + + + + All + Todos + + + + Database + Banco de dados + + + + Browsables + Navegáveis + + + + Temporary + Temporário + + + + EditDialog + + + Edit database cell + Editar célula + + + + Text + Texto + + + + Binary + Binário + + + + Erases the contents of the cell + Apaga os conteúdos da célula + + + + This area displays information about the data present in this database cell + Essa área exibe informação sobre os dados presentes nessa célula + + + + Type of data currently in cell + Tipo de dados atualmente na célula + + + + Size of data currently in table + Tamanho dos dados atualmente na célula + + + + Choose a filename to export data + Escolha um arquivo para exportar dados + + + + + Type of data currently in cell: Text / Numeric + Tipo de dados atualmente na célula: Texto / Numérico + + + + + + %n character(s) + + %n char + %n chars + + + + + Type of data currently in cell: Binary + Tipo de dados atualmente na célula: Binário + + + + + %n byte(s) + + %n byte + %n bytes + + + + + Mode: + Modo: + + + + + Image + Imagem + + + + Set as &NULL + Definir como &NULL + + + + Apply + Aplicar + + + + Type of data currently in cell: %1 Image + Tipo de dado atualmente na célula: %1 Imagem + + + + %1x%2 pixel(s) + %1x%2 pixel(s) + + + + Type of data currently in cell: NULL + Tipo de dado atualmente na célula: NULL + + + + This is the list of supported modes for the cell editor. Choose a mode for viewing or editing the data of the current cell. + Essa é a lista de modos suportados pelo editor de célula. Escolha um modo para visualizar ou editar os dados da célula atual. + + + + RTL Text + Texto para a esquerda + + + + JSON + JSON + + + + XML + XML + + + + + Automatically adjust the editor mode to the loaded data type + Automaticamente ajustar o modo do editor para o tipo de dado carregado + + + + This checkable button enables or disables the automatic switching of the editor mode. When a new cell is selected or new data is imported and the automatic switching is enabled, the mode adjusts to the detected data type. You can then change the editor mode manually. If you want to keep this manually switched mode while moving through the cells, switch the button off. + Esse botão assinalável ativa ou desativa a troca automática do modo do editor. Quando uma nova célula é selecionado ou novos dados são importados e a troca automática está habilitada, o modo ajusta para o tipo detectado. Você pode então mudar o modo do editor manualmente. Se você quer manter o modo manualmente escolhido enquanto movendo pelas células, desmarque essa opção. + + + + Auto-switch + Auto-trocar + + + + The text editor modes let you edit plain text, as well as JSON or XML data with syntax highlighting, automatic formatting and validation before saving. + +Errors are indicated with a red squiggle underline. + O modo do editor de texto deixa você editar tanto texto simples como JSON e XML com realce de sintaxe, formatação automática e validação antes de salvar. + +Erros são indicados com um sublinhado vermelho. + + + + This Qt editor is used for right-to-left scripts, which are not supported by the default Text editor. The presence of right-to-left characters is detected and this editor mode is automatically selected. + Esse editor do QT é usado para scripts da direita para a esquerda, que não são suportados pelo editor de texto padrão. Quando a presença de caracteres da direita para a esquerda é detectada, esse modo é automaticamente selecionado. + + + + Open preview dialog for printing the data currently stored in the cell + Abrir diálogo de prévia para impressão dos dados atualmente armazenados na célula + + + + Auto-format: pretty print on loading, compact on saving. + Auto-formatar: exibir formatado ao carregar, compactar ao salvar. + + + + When enabled, the auto-format feature formats the data on loading, breaking the text in lines and indenting it for maximum readability. On data saving, the auto-format feature compacts the data removing end of lines, and unnecessary whitespace. + Quando ativado, a funcionalidade de auto-formatar formata os dados ao carregar, quebrando o texto em linhas e indentando ele para melhor legibilidade. Ao salvar os dados, o auto-formatador compacta os dados removendo espaços em branco desnecessários. + + + + Word Wrap + Quebra de linha + + + + Wrap lines on word boundaries + Quebra de linha em limites de palavras + + + + + Open in default application or browser + Abrir em aplicação padrão ou navegador + + + + Open in application + Abrir em aplicação + + + + The value is interpreted as a file or URL and opened in the default application or web browser. + O valor é interpretado como um arquivo ou URL e aberto na aplicação padrão ou navegador. + + + + Save file reference... + Salvar referência de arquivo... + + + + Save reference to file + Salvar referência para arquivo + + + + + Open in external application + Abrir em aplicação externa + + + + Autoformat + Autoformatar + + + + &Export... + &Exportar... + + + + + &Import... + &Importar... + + + + + Import from file + Importar do arquivo + + + + + Opens a file dialog used to import any kind of data to this database cell. + Abre um seletor de arquivos usado para importar qualquer tipo de dado para essa célula. + + + + Export to file + Exportar para arquivo + + + + Opens a file dialog used to export the contents of this database cell to a file. + Abre um seletor de arquivo para exportar os conteúdos dessa célula para um arquivo. + + + + Apply data to cell + Aplicar dados à célula + + + + This button saves the changes performed in the cell editor to the database cell. + Esse botão salva as modificações realizadas no editor da célula para a célula do banco de dados. + + + + + Image data can't be viewed in this mode. + Dados de imagem não podem ser visualizados nesse modo. + + + + + Try switching to Image or Binary mode. + Tente mudar para modo de Imagem ou Binário. + + + + + Binary data can't be viewed in this mode. + Dados binários não podem ser visualizados nesse modo. + + + + + Try switching to Binary mode. + Tente mudar para modo binário. + + + + Couldn't save file: %1. + Não pôde salvar arquivo: %1. + + + + The data has been saved to a temporary file and has been opened with the default application. You can now edit the file and, when you are ready, apply the saved new data to the cell editor or cancel any changes. + Os dados foram salvos em um arquivo temporário e este foi aberto com a aplicação padrão. Você pode agora editar os dados e, quando você estiver pronto, salvar suas mudanças para o editor de células ou cancelar quaisquer mudanças. + + + + + Image files (%1) + Arquivos de imagem (%1) + + + + Binary files (*.bin) + Arquivos binários (*.bin) + + + + Choose a file to import + Escolha um arquivo para importar + + + + %1 Image + %1 Imagem + + + + Invalid data for this mode + Dados inválidos para esse modo + + + + The cell contains invalid %1 data. Reason: %2. Do you really want to apply it to the cell? + A célula contém dados inválidos %1. Motivo: %2. Você realmente quer aplicar isso? + + + + Type of data currently in cell: Valid JSON + Tipo de dados atualmente na célula: JSON válido + + + + + Print... + Imprimir... + + + + Open preview dialog for printing displayed image + Abrir diálogo de prévia para imprimir imagem exibida + + + + + Ctrl+P + + + + + Open preview dialog for printing displayed text + Abrir diálogo de prévia para imprimir texto exibido + + + + Copy Hex and ASCII + Copiar Hex e ASCII + + + + Copy selected hexadecimal and ASCII columns to the clipboard + Copiar colunas hexadecimal e ASCII selecionadas para a área de transferência + + + + Ctrl+Shift+C + + + + + EditIndexDialog + + + &Name + &Nome + + + + Order + Ordem + + + + &Table + &Tabela + + + + &Unique + &Único + + + + Creating the index failed: +%1 + Criação de índice falhou: +%1 + + + + Edit Index Schema + Editar esquema do índice + + + + For restricting the index to only a part of the table you can specify a WHERE clause here that selects the part of the table that should be indexed + Para restringir o índice para somente uma parte da tabela você pode especificar uma cláusula WHERE aqui que seleciona a parte da tabela que deveria ser indexada + + + + Partial inde&x clause + Cláusula de índi&ce parcial + + + + Colu&mns + Colu&nas + + + + Table column + Coluna da tabela + + + + Type + Tipo + + + + Add a new expression column to the index. Expression columns contain SQL expression rather than column names. + Adicionar uma nova coluna de expressão para o índice. Colunas de expressão contêm expressões SQL em vez de nomes de coluna. + + + + Index column + Indexar coluna + + + + Deleting the old index failed: +%1 + Deletar o índice antigo falhou: +%1 + + + + EditTableDialog + + + Edit table definition + Editar definição da tabela + + + + Table + Tabela + + + + Advanced + Avançado + + + + Database sche&ma + Esque&ma do banco de dados + + + + Make this a 'WITHOUT rowid' table. Setting this flag requires a field of type INTEGER with the primary key flag set and the auto increment flag unset. + Fazer dessa uma tabela 'SEM rowid'. Definir essa flag requer um campo do tipo INTEGER com a primary key flag definida e a auto increment flag não. + + + + Without Rowid + Sem Rowid + + + + Fields + Campos + + + + Add + Adicionar + + + + Remove + Remover + + + + Move to top + Mover para o topo + + + + Move up + Mover para cima + + + + Move down + Mover para baixo + + + + Move to bottom + Mover para o fundo + + + + + Name + Nome + + + + + Type + Tipo + + + + Not null + Não null + + + + PK + PK + + + + Primary key + Primary key + + + + AI + AI + + + + Autoincrement + Autoincrement + + + + U + U + + + + + + Unique + Unique + + + + Default + Default + + + + Default value + Default value + + + + + + Check + Check + + + + Check constraint + Check constraint + + + + Collation + Agrupamento + + + + + + Foreign Key + Foreign Key + + + + Constraints + Restrições + + + + Add constraint + Adicionar restrição + + + + Remove constraint + Remover restrição + + + + Columns + Colunas + + + + SQL + SQL + + + + + Primary Key + Chave primária + + + + Add a primary key constraint + Adicionar restrição de chave primária + + + + Add a foreign key constraint + Adicionar restrição de chave estrangeira + + + + Add a unique constraint + Adicionar uma restrição de unicidade + + + + Add a check constraint + Adicionar uma restrição de verificação + + + + + There can only be one primary key for each table. Please modify the existing primary key instead. + Cada tabela pode ter apenas uma chave primária. Por favor, modifique a chave primária existente. + + + + Error creating table. Message from database engine: +%1 + Erro criando tabela. Mensagem da engine do banco de dados: +%1 + + + + There is at least one row with this field set to NULL. This makes it impossible to set this flag. Please change the table data first. + Há pelo menos uma linha com esse campo definido NULL. Logo, é impossível definir essa flag. Por favor, mude os dados da tabela primeiro. + + + + There is at least one row with a non-integer value in this field. This makes it impossible to set the AI flag. Please change the table data first. + Há pelo menos uma linha com um valor não-inteiro nesse campo. Logo, é impossível definir essa flag. Por favor, mude os dados da tabela primeiro. + + + + Column '%1' has duplicate data. + + Coluna '%1' tem dados duplicados. + + + + + This makes it impossible to enable the 'Unique' flag. Please remove the duplicate data, which will allow the 'Unique' flag to then be enabled. + Isso faz com que seja impossível de se habilitar a flag de unicidade. Por favor, remova os dados duplicados para permitir que a flag seja habilitada. + + + + Are you sure you want to delete the field '%1'? +All data currently stored in this field will be lost. + Você tem certeza de que deseja deletar o campo '%1? +Todos os dados atualmente armazenados nesse campo serão perdidos. + + + + There already is a field with that name. Please rename it first or choose a different name for this field. + Já existe um campo com este nome. Por favor, renomeie-o primeiro ou escolha um nome diferente para esse campo. + + + + Please add a field which meets the following criteria before setting the without rowid flag: + - Primary key flag set + - Auto increment disabled + Por favor, adicione um campo que atende aos seguintes critérios antes de definir a flag "without rowid": + - Flag "primary key" definida + - Incremento automático desativado + + + + This column is referenced in a foreign key in table %1 and thus its name cannot be changed. + Essa coluna é referenciada em uma chave estrangeira na tabela %1 e portanto seu nome não pode ser alterado. + + + + <html><head/><body><p><span style=" font-weight:600; color:#ff0000;">Warning: </span>There is something with this table definition that our parser doesn't fully understand. Modifying and saving this table might result in problems.</p></body></html> + <html><head/><body><p><span style=" font-weight:600; color:#ff0000;">Alerta: </span>Nosso parser não entende algo dessa definição de tabela. Modificar e salvar essa tabela pode causar problemas.</p></body></html> + + + + NN + NN + + + + ExportDataDialog + + + Export data as CSV + Exportar dados como CSV + + + + , + , + + + + ; + ; + + + + Tab + Tab + + + + | + | + + + + + + Other + Outro + + + + &Quote character + &Ãspas + + + + " + " + + + + ' + ' + + + + + Could not open output file: %1 + Não pôde abrir arquivo de saída: %1 + + + + + Choose a filename to export data + Escolha um arquivo para exportar dados + + + + Please select at least 1 table. + Por favor, selecione pelo menos uma tabela. + + + + Choose a directory + Escolha um diretório + + + + Export completed. + Exportação completa. + + + + New line characters + Caracteres de nova linha + + + + Windows: CR+LF (\r\n) + Windows: CR+LF (\r\n) + + + + Unix: LF (\n) + Unix: LF (\n) + + + + Tab&le(s) + Tabe&las(s) + + + + Colu&mn names in first line + &Nomes das colunas na primeira linha + + + + Fie&ld separator + Se&parador de campo + + + + Pretty print + Otimizar para leitura humana + + + + Export data as JSON + Exportar dados como JSON + + + + exporting CSV + exportando CSV + + + + exporting JSON + exportando JSON + + + + ExportSqlDialog + + + Export SQL... + Exportar SQL... + + + + &Options + &Opções + + + + Keep column names in INSERT INTO + Manter nomes de colunas em INSERT INTO + + + + Export schema only + Exportar somente esquema + + + + Choose a filename to export + Escolha um arquivo para exportar + + + + Export completed. + Exportação completa. + + + + Export cancelled or failed. + Exportação falhou ou foi cancelada. + + + + Tab&le(s) + Tabe&las(s) + + + + Select All + Selecionar tudo + + + + Deselect All + Limpar seleção + + + + Multiple rows (VALUES) per INSERT statement + Múltiplas linhas (VALUES) por INSERT + + + + Export everything + Exportar tudo + + + + Export data only + Exportar somente dados + + + + Keep old schema (CREATE TABLE IF NOT EXISTS) + Manter esquema antigo (CREATE TABLE IF NOT EXISTS) + + + + Overwrite old schema (DROP TABLE, then CREATE TABLE) + Sobrescrever esquema antigo (DROP TABLE, then CREATE TABLE) + + + + Please select at least one table. + Por favor selecione pelo menos uma tabela. + + + + ExtendedScintilla + + + + Ctrl+H + + + + + Ctrl+F + + + + + + Ctrl+P + + + + + Find... + Encontrar... + + + + Find and Replace... + Encontrar e substituir... + + + + Print... + Imprimir... + + + + ExtendedTableWidget + + + Set to NULL + Definir como NULL + + + + Copy + Copiar + + + + Paste + Colar + + + + The content of the clipboard is bigger than the range selected. +Do you want to insert it anyway? + O conteúdo da área de transferência é maior do que o intervalo selecionado. +Deseja inserir mesmo assim? + + + + Use as Exact Filter + Usar como filtro exato + + + + Containing + Contendo + + + + Not containing + Não contendo + + + + Not equal to + Diferente de + + + + Greater than + Maior que + + + + Less than + Menor que + + + + Greater or equal + Maior ou igual a + + + + Less or equal + Menor ou igual a + + + + Between this and... + Entre isso e... + + + + Regular expression + Expressão regular + + + + Edit Conditional Formats... + Editar formatos condicionais... + + + + Copy with Headers + Copiar com cabeçalhos + + + + Copy as SQL + Copiar como SQL + + + + Print... + Imprimir... + + + + Use in Filter Expression + Usar na expressão de filtro + + + + Alt+Del + + + + + Ctrl+Shift+C + + + + + Ctrl+Alt+C + + + + + <p>Not all data has been loaded. <b>Do you want to load all data before selecting all the rows?</b><p><p>Answering <b>No</b> means that no more data will be loaded and the selection will not be performed.<br/>Answering <b>Yes</b> might take some time while the data is loaded but the selection will be complete.</p>Warning: Loading all the data might require a great amount of memory for big tables. + <p>Nem todos os dados foram carregados. <b>Você quer carregar todos os dados antes de selecionar todas as linhas?</b><p><p>Respondendo <b>Não</b> significa que mais dados não serão carregados e a seleção não será executada.<br/>Respondendo <b>Sim</b> pode levar algum tempo enquanto os dados são carregados mas a seleção será incompleta.</p>Aviso: carregar todos os dados pode exigir uma grande quantidade de memória para tabelas grandes. + + + + Cannot set selection to NULL. Column %1 has a NOT NULL constraint. + Não é possível definir a seleção como NULL. Coluna %1 tem uma restrição de nulidade. + + + + FileExtensionManager + + + File Extension Manager + Gerenciador de extensão de arquivo + + + + &Up + &Subir + + + + &Down + &Descer + + + + &Add + &Adicionar + + + + &Remove + &Remover + + + + + Description + Descrição + + + + Extensions + Extensões + + + + *.extension + *.extensão + + + + FilterLineEdit + + + Filter + Filtro + + + + These input fields allow you to perform quick filters in the currently selected table. +By default, the rows containing the input text are filtered out. +The following operators are also supported: +% Wildcard +> Greater than +< Less than +>= Equal to or greater +<= Equal to or less += Equal to: exact match +<> Unequal: exact inverse match +x~y Range: values between x and y +/regexp/ Values matching the regular expression + Esses campos de entrada permitem você realizar filtros rápidos na tabela atualmente selecionada. +Por padrão, as linhas que contém o texto de entrada são filtradas +Os seguintes operadores também são suportados: +% Curinga +> Maior que +< Menor que +>= Maior ou igual a +<= Menor ou igual a += Igual +<> Diferente +x~y Intervalo: valores entre x e y +/regexp/ Valores satisfazendo a expressão regular + + + + Clear All Conditional Formats + Limpar todos os formatos condicionais + + + + Use for Conditional Format + Usar para formato condicional + + + + Edit Conditional Formats... + Editar formatos condicionais... + + + + Set Filter Expression + Definir expressão de filtro + + + + What's This? + O que é isso? + + + + Is NULL + É NULL + + + + Is not NULL + Não é NULL + + + + Is empty + É vazio + + + + Is not empty + Não é vazio + + + + Not containing... + Não contendo... + + + + Equal to... + Igual a... + + + + Not equal to... + Diferente de... + + + + Greater than... + Maior que... + + + + Less than... + Menor que... + + + + Greater or equal... + Maior ou igual... + + + + Less or equal... + Menor ou igual... + + + + In range... + No intervalo... + + + + Regular expression... + Expressão regular... + + + + FindReplaceDialog + + + Find and Replace + Encontrar e substituir + + + + Fi&nd text: + E&ncontrar texto: + + + + Re&place with: + Su&bstituir com: + + + + Match &exact case + Casar caixa &exata + + + + Match &only whole words + Casar s&omente palavras inteiras + + + + When enabled, the search continues from the other end when it reaches one end of the page + Quando ativado, a busca continua do outro fim quando ela atinge um fim da página + + + + &Wrap around + &Envolver em torno + + + + When set, the search goes backwards from cursor position, otherwise it goes forward + Quando ativado, a busca retrocede a partir do cursor em vez de ir para frente + + + + Search &backwards + Buscar para &trás + + + + <html><head/><body><p>When checked, the pattern to find is searched only in the current selection.</p></body></html> + <html><head/><body><p>Quando selecionado, o padrão procurado é testado somente na seleção atual.</p></body></html> + + + + &Selection only + &Somente seleção + + + + <html><head/><body><p>When checked, the pattern to find is interpreted as a UNIX regular expression. See <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>.</p></body></html> + <html><head/><body><p>Quando selecionado, o padrão a ser encontrado é interpretado como uma expressão regular UNIX. Veja <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression nos Wikibooks</a>.</p></body></html> + + + + Use regular e&xpressions + Usar e&xpressões regulares + + + + Find the next occurrence from the cursor position and in the direction set by "Search backwards" + Encontrar a próxima ocorrência a partir da posição do cursor na direção selecionada por "Buscar para trás" + + + + &Find Next + &Encontrar próximo + + + + F3 + + + + + &Replace + &Substituir + + + + Highlight all the occurrences of the text in the page + Realçar todas as ocorrências do texto na página + + + + F&ind All + Encontrar &todos + + + + Replace all the occurrences of the text in the page + Substituir todas as ocorrências do texto na página + + + + Replace &All + Substituir &todos + + + + The searched text was not found + O texto procurado não foi encontrado + + + + The searched text was not found. + O texto procurado não foi encontrado. + + + + The searched text was found one time. + O texto procurado foi encontrado uma vez. + + + + The searched text was found %1 times. + O texto procurado foi encontrado %1 vezes. + + + + The searched text was replaced one time. + O texto procurado foi substituído uma vez. + + + + The searched text was replaced %1 times. + O texto procurado foi substituído %1 vezes. + + + + ForeignKeyEditor + + + &Reset + &Resetar + + + + Foreign key clauses (ON UPDATE, ON DELETE etc.) + Cláusulas de chave estrangeira (ON UPDATE, ON DELETE etc.) + + + + ImportCsvDialog + + + Import CSV file + Importar arquivo CSV + + + + &Column names in first line + Nomes das &colunas na primeira linha + + + + Field &separator + &Separador de campos + + + + , + , + + + + ; + ; + + + + + Tab + Tab + + + + | + | + + + + Other + Outro + + + + &Quote character + &Ãspas + + + + + Other (printable) + Outro (imprimível) + + + + + Other (code) + Outro (código) + + + + " + " + + + + ' + ' + + + + &Encoding + &Encoding + + + + UTF-8 + UTF-8 + + + + UTF-16 + UTF-16 + + + + ISO-8859-1 + ISO-8859-1 + + + + Trim fields? + Trim fields? + + + + Creating restore point failed: %1 + Criação de ponto de restauração falhou: %1 + + + + Creating the table failed: %1 + Criação de tabela falhou: %1 + + + + Inserting row failed: %1 + Inserir linha falhou: %1 + + + + Separate tables + Tabelas separadas + + + + When importing into an existing table with a primary key, unique constraints or a unique index there is a chance for a conflict. This option allows you to select a strategy for that case: By default the import is aborted and rolled back but you can also choose to ignore and not import conflicting rows or to replace the existing row in the table. + Quando importando em uma tabela existente com uma chave primária, restrições de unicidade ou índice único há uma chance para conflitos. Essa opção permite a você selecionar uma estratégia para esse caso. Por padrão, a importação é abortada e revertida, mas você também pode escolher ignorar e não importar linhas conflitantes ou substituir as entradas existentes na tabela. + + + + Abort import + Abortar importação + + + + Ignore row + Ignorar linha + + + + Replace existing row + Substituir linhas existentes + + + + Conflict strategy + Estratégia para conflitos + + + + + Deselect All + Limpar seleção + + + + Match Similar + Detectar similares + + + + Select All + Selecionar tudo + + + + Table na&me + No&me da tabela + + + + Advanced + Avançado + + + + When importing an empty value from the CSV file into an existing table with a default value for this column, that default value is inserted. Activate this option to insert an empty value instead. + Quando importando um valor em branco do arquivo CSV em uma tabela existente com um valor padrão para essa coluna, aquele valor padrão é inserido. Ative essa opção para inserir um valor em branco em vez. + + + + Ignore default &values + Ignorar &valores padrão + + + + Activate this option to stop the import when trying to import an empty value into a NOT NULL column without a default value. + Ative essa opção para parar a importação quando tentando importar um valor em branco em uma coluna NOT NULL sem um valor padrão. + + + + Fail on missing values + Falhar em valores faltando + + + + Disable data type detection + Desativar detecção de tipo de dados + + + + Disable the automatic data type detection when creating a new table. + Desativa a detecção automática de tipo de dados quando criando uma nova tabela. + + + + There is already a table named '%1' and an import into an existing table is only possible if the number of columns match. + Já existe uma tabela chamada '%1' e uma importação em uma tabela existente só é possível se o número de colunas bate. + + + + There is already a table named '%1'. Do you want to import the data into it? + Já existe uma tabela chamada '%1'. Você quer importar os dados nela? + + + + importing CSV + Importando CSV + + + + Importing the file '%1' took %2ms. Of this %3ms were spent in the row function. + Importando o arquivo '%1' levou %2 ms. Desses, %3 ms foram gastos na função da linha. + + + + MainWindow + + + DB Browser for SQLite + DB Browser para SQLite + + + + toolBar1 + toolBar1 + + + + &File + &Arquivo + + + + &Import + &Importar + + + + &Export + E&xportar + + + + &Edit + &Editar + + + + &View + &Exibir + + + + &Help + A&juda + + + + DB Toolbar + Barra de ferramentas do banco de dados + + + + User + Usuário + + + + Application + Aplicativo + + + + &Clear + &Limpar + + + + &New Database... + &Novo banco de dados... + + + + + Create a new database file + Criar um novo arquivo de banco de dados + + + + This option is used to create a new database file. + Essa opção e utilizada para criar um novo arquivo de banco de dados. + + + + Ctrl+N + + + + + + &Open Database... + &Abrir banco de dados... + + + + + + + + Open an existing database file + Abre um arquivo de banco de dados existente + + + + + + This option is used to open an existing database file. + Esta opção abre um arquivo de banco de dados existente. + + + + Ctrl+O + + + + + &Close Database + &Fechar banco de dados + + + + + Ctrl+W + + + + + + Revert database to last saved state + Reverter banco de dados para o último estado salvo + + + + This option is used to revert the current database file to its last saved state. All changes made since the last save operation are lost. + Essa opção é usada para reverter o atual arquivo de banco de dados para seu último estado salvo. Todas as modificações feitas desde a última operação de salvamento são perdidas. + + + + + Write changes to the database file + Salva modificações para o arquivo de banco de dados + + + + This option is used to save changes to the database file. + Essa opção é usada para salvar modificações para o arquivo de banco de dados. + + + + Ctrl+S + + + + + Compact the database file, removing space wasted by deleted records + Compactar o arquivo do banco de dados, removendo espaço desperdiçado por registros deletados + + + + + Compact the database file, removing space wasted by deleted records. + Compactar o arquivo do banco de dados, removendo espaço desperdiçado por registros deletados. + + + + E&xit + &Sair + + + + Ctrl+Q + + + + + Import data from an .sql dump text file into a new or existing database. + Importar dados de um arquivo de texto .sql em um banco de dados. + + + + This option lets you import data from an .sql dump text file into a new or existing database. SQL dump files can be created on most database engines, including MySQL and PostgreSQL. + Essa opção deixa você importar dados de um arquivo SQL em um banco de dados. Arquivos de SQL podem ser criados na maioria dos bancos de dados, como MySQL e PostgreSQL. + + + + Open a wizard that lets you import data from a comma separated text file into a database table. + Abre um assistente que permite você importar dados de um arquivo CSV em uma tabela de banco de dados. + + + + Open a wizard that lets you import data from a comma separated text file into a database table. CSV files can be created on most database and spreadsheet applications. + Abre um assistente que permite você importar dados de um arquivo CSV em uma tabela de banco de dados. Arquivos CSV podem ser criados pela maioria dos programas de banco de dados e planilhas. + + + + Export a database to a .sql dump text file. + Exportar o banco de dados para um arquivo de texto .sql. + + + + This option lets you export a database to a .sql dump text file. SQL dump files contain all data necessary to recreate the database on most database engines, including MySQL and PostgreSQL. + Essa opção permite você exportar um banco de dados para um arquivo de texto .sql. Arquivos de despejo SQL contêm todos os dados necessários para recriar o banco de dados na maioria dos motores de banco de dados, incluindo MySQL e PostgreSQL. + + + + Export a database table as a comma separated text file. + Exportar uma tabela de banco de dados como um arquivo CSV. + + + + Export a database table as a comma separated text file, ready to be imported into other database or spreadsheet applications. + Exportar uma tabela de banco de dados como um arquivo CSV, pronto para ser importado por outro banco de dados ou planilhas. + + + + Open the Create Table wizard, where it is possible to define the name and fields for a new table in the database + Abre o assistente de criação de tabelas, em que é possível definir o nome e os campos para uma nova tabela no banco de dados + + + + + Delete Table + Deletar tabela + + + + Open the Delete Table wizard, where you can select a database table to be dropped. + Abre o assistente de deleção de tabelas, em que você pode selecionar uma tabela para ser eliminada. + + + + Open the Modify Table wizard, where it is possible to rename an existing table. It is also possible to add or delete fields form a table, as well as modify field names and types. + Abre o assistente de modificação de tabelas, em que você pode renomear uma tabela existente. Também é possível adicionar ou deletar campos de uma tabela, assim como modificar nomes e tipos de campos. + + + + Open the Create Index wizard, where it is possible to define a new index on an existing database table. + Abre o assistente de criação de índice, em que é possível definir um novo índice em um tabela de banco de dados já existente. + + + + &Preferences... + &Configurações... + + + + + Open the preferences window. + Abre a janela de configurações. + + + + &DB Toolbar + Barra de ferramentas do banco de &dados + + + + Shows or hides the Database toolbar. + Exibe ou oculta a barra de ferramentas do banco de dados. + + + + Shift+F1 + + + + + &Recently opened + &Recentemente aberto + + + + Open &tab + Abrir &aba + + + + Ctrl+T + + + + + &Execute SQL + &Executar SQL + + + + + Execute SQL + This has to be equal to the tab title in all the main tabs + Executar SQL + + + + + + Save SQL file + Salvar arquivo SQL + + + + + Execute current line + Executar linha atual + + + + Ctrl+E + + + + + Export as CSV file + Exportar como arquivo CSV + + + + Export table as comma separated values file + Exportar tabela como CSV + + + + + Save the current session to a file + Salvar a atual sessão para um arquivo + + + + + Load a working session from a file + Carregar uma sessão de um arquivo + + + + + Save SQL file as + Salvar arquivo SQL como + + + + &Browse Table + &Navegar tabela + + + + Copy Create statement + Copiar comando Create + + + + Copy the CREATE statement of the item to the clipboard + Copia o comando CREATE do item para a área de transferência + + + + Ctrl+Return + Ctrl+ENTER + + + + Ctrl+L + + + + + + Ctrl+P + + + + + Ctrl+D + + + + + Ctrl+I + + + + + Reset Window Layout + Resetar layout da janela + + + + Alt+0 + + + + + The database is currenctly busy. + O banco de dados está ocupado. + + + + Click here to interrupt the currently running query. + Clique aqui para interromper a consulta atual. + + + + Database encoding + Codificação do banco de dados + + + + Database is encrypted using SQLCipher + Banco de dados encriptado usando SQLCipher + + + + + Choose a database file + Escolha um arquivo de banco de dados + + + + + + Choose a filename to save under + Escolha um nome de arquivo para salvar + + + + Are you sure you want to undo all changes made to the database file '%1' since the last save? + Você tem certeza de que deseja desfazer todas as modificações feitas no arquivo de banco de dados '%1' desde o último salvamento? + + + + Choose a file to import + Escolha um arquivo para importar + + + + Text files(*.sql *.txt);;All files(*) + Arquivos de texto(*.sql *.txt);;Todos os arquivos(*) + + + + Do you want to create a new database file to hold the imported data? +If you answer no we will attempt to import the data in the SQL file to the current database. + Você deseja criar um novo arquivo de banco de dados para armazenar os dados importados? +Se você disser que não, tentaremos importar os dados do arquivo SQL para o banco de dados atual. + + + + Window Layout + Layout da janela + + + + Simplify Window Layout + Simplificar layout da janela + + + + Shift+Alt+0 + + + + + Dock Windows at Bottom + Encaixar janelas embaixo + + + + Dock Windows at Left Side + Encaixar janelas à esquerda + + + + Dock Windows at Top + Encaixar janelas no topo + + + + You are still executing SQL statements. Closing the database now will stop their execution, possibly leaving the database in an inconsistent state. Are you sure you want to close the database? + Você ainda está executando comandos SQL. Fechar o banco de dados agora fará a execução parar, talvez deixando o banco de dados em um estado inconsistente. Você tem certeza de que deseja fechar o banco de dados? + + + + Do you want to save the changes made to the project file '%1'? + Você quer salvar as modificações feitas para o arquivo de projeto '%1'? + + + + Result: %1 + Resulto: %1 + + + + File %1 already exists. Please choose a different name. + Arquivo %1 já existe. Por favor, escolha um nome diferente. + + + + Error importing data: %1 + Erro importando dados: %1 + + + + Import completed. + Importação completa. + + + + Delete View + Deletar vista + + + + Delete Trigger + Deletar gatilho + + + + Delete Index + Deletar índice + + + + Setting PRAGMA values will commit your current transaction. +Are you sure? + Definir valores de PRAGMA vai cometer sua transação atual. +Você tem certeza? + + + + Do you want to save the changes made to SQL tabs in the project file '%1'? + Você quer salvar as mudanças feitas nas abas de SQL no arquivo de projeto '%1'? + + + + Select SQL file to open + Selecione arquivo SQL para abrir + + + + Select file name + Selecione o nome do arquivo + + + + Select extension file + Selecione o arquivo de extensão + + + + Extension successfully loaded. + Extensão carregada com sucesso. + + + + Error loading extension: %1 + Erro carregado extensão: %1 + + + + + Don't show again + Não mostrar novamente + + + + New version available. + Nova versão disponível. + + + + A new DB Browser for SQLite version is available (%1.%2.%3).<br/><br/>Please download at <a href='%4'>%4</a>. + Uma nova vesão do DB Browser para SQLite está disponível (%1.%2.%3)<br/><br/>Por favor, baixe em <a href='%4'>%4</a>. + + + + DB Browser for SQLite project file (*.sqbpro) + Arquivo de projeto DB Browser para SQLite (*.sqbpro) + + + + SQL &Log + &Log do SQL + + + + Show S&QL submitted by + Exibir S&QL enviado por + + + + &Plot + &Plotar + + + + &Revert Changes + &Reverter modificações + + + + &Write Changes + &Escrever modificações + + + + &Database from SQL file... + &Banco de dados a partir de arquivo SQL... + + + + &Table from CSV file... + &Tabela a partir de arquivo CSV... + + + + &Database to SQL file... + &Banco de dados para arquivo SQL... + + + + &Table(s) as CSV file... + &Tabela para arquivo CSV... + + + + &Create Table... + &Criar tabela... + + + + &Delete Table... + &Deletar tabela... + + + + &Modify Table... + &Modificar tabela... + + + + Create &Index... + &Criar índice... + + + + W&hat's This? + O &que é isso? + + + + Sa&ve Project + &Salvar projeto + + + + Encrypted + Encriptado + + + + Read only + Somente leitura + + + + Database file is read only. Editing the database is disabled. + Arquivo de banco de dados é somente leitura. Edição do banco de dados está desativada. + + + + Execution finished with errors. + Execução finalizada com erros. + + + + Execution finished without errors. + Execução finalizada sem erros. + + + + + Database Structure + This has to be equal to the tab title in all the main tabs + Estrutura do banco de dados + + + + + Browse Data + This has to be equal to the tab title in all the main tabs + Navegar dados + + + + + Edit Pragmas + This has to be equal to the tab title in all the main tabs + Editar pragmas + + + + Edit Database &Cell + Editar &célula do banco de dados + + + + DB Sche&ma + Esque&ma do banco de dados + + + + Open SQL file(s) + Abrir arquivo(s) SQL + + + + This button opens files containing SQL statements and loads them in new editor tabs + Este botão abre arquivos SQL e carrega eles em novas abas no editor + + + + Shift+F5 + + + + + Opens the SQLCipher FAQ in a browser window + Abre o FAQ do SQLCipher em uma janela do navegador + + + + Export one or more table(s) to a JSON file + Exporta uma ou mais tabela(s) para um arquivo JSON + + + + Error while saving the database file. This means that not all changes to the database were saved. You need to resolve the following error first. + +%1 + Erro enquanto salvava o banco de dados. Isso indica que nem todas as mudanças foram salvas. Você precisa resolver o seguinte erro primeiro. + +%1 + + + + &Remote + &Remoto + + + + Open an existing database file in read only mode + Abre um banco de dados existente em modo somente leitura + + + + Could not open database file. +Reason: %1 + Não pôde abrir arquivo do banco de dados. +Motivo: %1 + + + + Choose text files + Escolha arquivos de texto + + + + Modify View + Modificar vista + + + + Modify Trigger + Modificar gatilho + + + + Modify Index + Modificar índice + + + + Modify Table + Modificar tabela + + + + Setting PRAGMA values or vacuuming will commit your current transaction. +Are you sure? + Definir valores de PRAGMA ou fazer vacuum irá commitar sua transação atual. +Deseja continuar? + + + + This is the structure of the opened database. +You can drag SQL statements from an object row and drop them into other applications or into another instance of 'DB Browser for SQLite'. + + Essa é a estrutura do banco de dados aberto. +Você pode arrastar comandos SQL de uma linha e soltá-los em outras aplicações ou em outra instância do DB Browser para SQLite. + + + + + Warning: this pragma is not readable and this value has been inferred. Writing the pragma might overwrite a redefined LIKE provided by an SQLite extension. + Alerta: esse pragma não é legível e esse valor foi inferido. Escrever o pragma pode sobrescrever um LIKE redefinido provido por uma extensão SQL. + + + + &Tools + Ferramen&tas + + + + Error Log + Log de erros + + + + This button clears the contents of the SQL logs + Esse botão limpa os logs do SQL + + + + This panel lets you examine a log of all SQL commands issued by the application or by yourself + Esse painel deixa você examinar um log de todos os comandos SQL dados pela aplicação ou por você + + + + This is the structure of the opened database. +You can drag multiple object names from the Name column and drop them into the SQL editor and you can adjust the properties of the dropped names using the context menu. This would help you in composing SQL statements. +You can drag SQL statements from the Schema column and drop them into the SQL editor or into other applications. + + Essa é a estrutura do banco de dados aberto. +Você pode arrastar múltiplos nomes de objetos da coluna Nome e largá-los no editor SQL e você pode ajustar as propriedades dos nomes largados usando o menu de contexto. Isso ajudaria você a compor comandos SQL. +Você pode arrastar comandos SQL da coluna Esquema e largá-los no editor SQL ou em outras aplicações. + + + + + + Project Toolbar + Barra de ferramentas do projeto + + + + Extra DB toolbar + Barra de ferramentas do banco de dados extra + + + + + + Close the current database file + Fechar o arquivo de banco de dados aberto + + + + This button closes the connection to the currently open database file + Esse botão fecha a conexão com o arquivo aberto + + + + Ctrl+F4 + + + + + Compact &Database... + Compactar banco de &dados... + + + + &About + &Sobre + + + + This button opens a new tab for the SQL editor + Esse botão abre uma nova aba para o editor SQL + + + + Execute all/selected SQL + Executar todo/selecionado SQL + + + + This button executes the currently selected SQL statements. If no text is selected, all SQL statements are executed. + Esse botão executa o SQL selecionado. Se não existe SQL selecionado, todo o SQL é executado. + + + + &Load Extension... + &Carregar extensão... + + + + Execute line + Executar linha + + + + This button executes the SQL statement present in the current editor line + Esse botão executa o comando SQL presente na linha atual do editor + + + + &Wiki + &Wiki + + + + F1 + + + + + Bug &Report... + &Reportar bug... + + + + Feature Re&quest... + Re&quisitar feature... + + + + Web&site + &Site + + + + &Donate on Patreon... + &Doar no Patreon... + + + + Open &Project... + Abrir &projeto... + + + + &Attach Database... + &Anexar banco de dados... + + + + + Add another database file to the current database connection + Adiciona outro arquivo de banco de dados para a conexão atual + + + + This button lets you add another database file to the current database connection + Esse botão deixa você adicionar outro banco de dados para a conexão atual com o banco de dados + + + + &Set Encryption... + Definir en&criptação... + + + + This button saves the content of the current SQL editor tab to a file + Esse botão salva o conteúdo do editor SQL para um arquivo + + + + SQLCipher &FAQ + &FAQ do SQLCipher + + + + Table(&s) to JSON... + Tabela(&s) para JSON... + + + + Open Data&base Read Only... + Abrir &banco de dados somente leitura... + + + + Ctrl+Shift+O + + + + + Save results + Salvar resultados + + + + Save the results view + Salvar a vista de resultados + + + + This button lets you save the results of the last executed query + Esse botão deixa você salvar os resultados da última consulta executada + + + + + Find text in SQL editor + Encontrar texto no editor SQL + + + + Find + Encontrar + + + + This button opens the search bar of the editor + Esse botão abre a barra de busca do editor + + + + Ctrl+F + + + + + + Find or replace text in SQL editor + Encontrar ou substituir texto no editor SQL + + + + Find or replace + Encontrar ou substituir + + + + This button opens the find/replace dialog for the current editor tab + Esse botão abre o diálogo de encontrar/substituir para a aba atual do editor + + + + Ctrl+H + + + + + Export to &CSV + Exportar para &CSV + + + + Save as &view + Salvar como &vista + + + + Save as view + Salvar como vista + + + + Shows or hides the Project toolbar. + Mostra ou oculta a barra de ferramentos do Projeto. + + + + Extra DB Toolbar + Barra de ferramentas do banco de dados extra + + + + This button lets you save all the settings associated to the open DB to a DB Browser for SQLite project file + Este botão lhe permite salvar todas as configurações associadas ao banco de dados aberto a um arquivo de projeto do DB Browser para SQLite + + + + This button lets you open a DB Browser for SQLite project file + Este botão lhe permite abrir um arquivo de projeto do DB Browser para SQLite + + + + New In-&Memory Database + Nova tabela em &memória + + + + Drag && Drop Qualified Names + Arrastar e soltar nomes qualificados + + + + + Use qualified names (e.g. "Table"."Field") when dragging the objects and dropping them into the editor + Use nomes qualificados (p.e. "Tabela"."Campo") quando arrastando objetos e soltando eles no editor + + + + Drag && Drop Enquoted Names + Arrastar e soltar nomes entre áspas + + + + + Use escaped identifiers (e.g. "Table1") when dragging the objects and dropping them into the editor + Use identificadores escapados (p.e. "Tabela1") quando arrastando e soltando objetos no editor + + + + &Integrity Check + Teste de &integridade + + + + Runs the integrity_check pragma over the opened database and returns the results in the Execute SQL tab. This pragma does an integrity check of the entire database. + Roda o teste de integridade sobre o banco de dados aberto e retorna os resultados na aba Executar SQL. + + + + &Foreign-Key Check + Teste de chave &estrangeira + + + + Runs the foreign_key_check pragma over the opened database and returns the results in the Execute SQL tab + Roda o teste de chave estrangeira sobre o banco de dados aberto e retorna os resultados na aba Executar SQL + + + + &Quick Integrity Check + Teste de integridade &rápido + + + + Run a quick integrity check over the open DB + Roda um teste de integridade rápido sobre o banco de dados aberto + + + + Runs the quick_check pragma over the opened database and returns the results in the Execute SQL tab. This command does most of the checking of PRAGMA integrity_check but runs much faster. + Roda um outro pragma para a verificação de integridade do banco de dados. Faz quase tantos testes quando o outro PRAGMA mas executa muito mais rápido. + + + + &Optimize + &Otimizar + + + + Attempt to optimize the database + Tenta otimizar o banco de dados + + + + Runs the optimize pragma over the opened database. This pragma might perform optimizations that will improve the performance of future queries. + Roda o pragma de otimização sobre o banco de dados aberto. Esse pragma pode realizar otimizações que vão melhorar a performance de consultas futuras. + + + + + Print + Imprimir + + + + Print text from current SQL editor tab + Imprimir texto do editor SQL + + + + Open a dialog for printing the text in the current SQL editor tab + Abre um diálogo para imprimir o texto na aba atual do editor SQL + + + + Print the structure of the opened database + Imprime a estrutura do banco de dados aberto + + + + Open a dialog for printing the structure of the opened database + Abre um diálogo para imprimir a estrutura do banco de dados aberto + + + + Un/comment block of SQL code + Comentar bloco de SQL + + + + Un/comment block + Comentar bloco + + + + Comment or uncomment current line or selected block of code + Comentar ou remover comentário da linha ou bloco atualmente selecionado + + + + Comment or uncomment the selected lines or the current line, when there is no selection. All the block is toggled according to the first line. + Comentar ou remover comentários das linhas selecionadas ou da linha atual, se não há seleção. Todo o bloco é alterado de acordo com a primeira linha. + + + + Ctrl+/ + + + + + Stop SQL execution + Parar execução do SQL + + + + Stop execution + Parar execução + + + + Stop the currently running SQL script + Parar o script de SQL atualmente executando + + + + &Save Project As... + &Salvar projeto como... + + + + + + Save the project in a file selected in a dialog + Salvar o projeto em um arquivo selecionado em um diálogo + + + + Save A&ll + Salvar &todos + + + + + + Save DB file, project file and opened SQL files + Salvar arquivo do BD, arquivo do projeto e arquivos SQL abertos + + + + Ctrl+Shift+S + + + + + Browse Table + Navegar tabelas + + + + In-Memory database + Banco de dados em memória + + + + Are you sure you want to delete the table '%1'? +All data associated with the table will be lost. + Você tem certeza de que deseja deletar a tabela '%1'? +Todos os dados associados com a tabela serão perdidos. + + + + Are you sure you want to delete the view '%1'? + Você tem certeza que deseja deletar a vista '%1'? + + + + Are you sure you want to delete the trigger '%1'? + Você tem certeza que deseja deletar o gatilho '%1'? + + + + Are you sure you want to delete the index '%1'? + Você tem certeza que deseja deletar o índice '%1'? + + + + Error: could not delete the table. + Erro: não pôde deletar a tabela. + + + + Error: could not delete the view. + Erro: não pôde deletar a vista. + + + + Error: could not delete the trigger. + Erro: não pôde deletar o gatilho. + + + + Error: could not delete the index. + Erro: não pôde deletar o índice. + + + + Message from database engine: +%1 + Mensagem do banco de dados: +%1 + + + + Editing the table requires to save all pending changes now. +Are you sure you want to save the database? + Editar a tabela requer salvar todas as mudanças pendentes agora. +Você tem certeza que quer salvar o banco de dados? + + + + Edit View %1 + Editar vista %1 + + + + Edit Trigger %1 + Editar gatilho %1 + + + + You are already executing SQL statements. Do you want to stop them in order to execute the current statements instead? Note that this might leave the database in an inconsistent state. + Você já está executando comandos SQL. Você quer pará-los para executar os comandos atuais? Fechar o banco de dados agora pode deixá-lo em um estado inconsistente. + + + + -- EXECUTING SELECTION IN '%1' +-- + -- EXECUTANDO SELEÇÃO EM '%1' +-- + + + + -- EXECUTING LINE IN '%1' +-- + -- EXECUTANDO LINHA EM '%1' +-- + + + + -- EXECUTING ALL IN '%1' +-- + -- EXECUTANDO TUDO EM '%1' +-- + + + + Opened '%1' in read-only mode from recent file list + Abiu '%1' em modo somente leitura a partir da lista de arquivos recentes + + + + Opened '%1' from recent file list + Abiu '%1' a partir da lista de arquivos recentes + + + + Project saved to file '%1' + Projeto salvo no arquivo '%1' + + + + This action will open a new SQL tab with the following statements for you to edit and run: + Esta ação abrirá uma nova aba SQL com os seguintes comandos para você editar e executar: + + + + Rename Tab + Renomear aba + + + + Duplicate Tab + Duplicar aba + + + + Close Tab + Fechar aba + + + + Opening '%1'... + Abrindo '%1'... + + + + There was an error opening '%1'... + Houve um erro abrindo '%1'... + + + + Value is not a valid URL or filename: %1 + Valor não é uma URL ou nome de arquivo válido: %1 + + + + %1 rows returned in %2ms + %1 linhas retornadas em %2 ms + + + + + At line %1: + Na linha %1: + + + + Result: %2 + Resultado: %2 + + + + Import completed. Some foreign key constraints are violated. Please fix them before saving. + Importação completa. Algumas chaves estrangeiras são violadas. Por favor corrija-as antes de salvar. + + + + &%1 %2%3 + &%1 %2%3 + + + + (read only) + (somente leitura) + + + + Open Database or Project + Abrir banco de dados ou projeto + + + + Attach Database... + Anexar banco de dados... + + + + Import CSV file(s)... + Importar arquivo(s) CSV... + + + + Select the action to apply to the dropped file(s). <br/>Note: only 'Import' will process more than one file. + + Selecione a ação para aplicar ao %n arquivo dropado. <br/>Note que só 'Importar' vai processar mais de um arquivo. + Selecione a ação para aplicar aos %n arquivos dropados. <br/>Note que só 'Importar' vai processar mais de um arquivo. + + + + + Do you want to save the changes made to SQL tabs in a new project file? + Você quer salvar as mudanças feitas nas abas de SQL no arquivo de projeto? + + + + Do you want to save the changes made to the SQL file %1? + Você quer salvar as alterações feitas ao arquivo SQL %1? + + + + The statements in this tab are still executing. Closing the tab will stop the execution. This might leave the database in an inconsistent state. Are you sure you want to close the tab? + Os comandos nessa aba ainda estão executando. Fechar a aba vai parar a execução. Isso pode deixar o banco de dados em um estado inconsistente. Você tem certeza de que deseja fechar a aba? + + + + Could not find resource file: %1 + Não pôde encontrar o arquivo de recursos: %1 + + + + Choose a project file to open + Escolha um arquivo de projeto para abrir + + + + This project file is using an old file format because it was created using DB Browser for SQLite version 3.10 or lower. Loading this file format is still fully supported but we advice you to convert all your project files to the new file format because support for older formats might be dropped at some point in the future. You can convert your files by simply opening and re-saving them. + Esse arquivo de projeto está usando um formato de arquivo mais velho porque ele foi criado usando DB Browser para SQLite versão 3.10 ou menor. Esse arquivo é suportado mas nós aconselhamos converter todos os projetos para o novo formato de arquivos porque o suporte para arquivos antigos pode ser abandonado no futuro. Você pode converter seus arquivos simplesmente abrindo e salvando eles. + + + + Could not open project file for writing. +Reason: %1 + Não pôde abrir arquivo de projeto para a escrita. +Motivo: %1 + + + + Collation needed! Proceed? + Função de comparação necessária! Proceder? + + + + A table in this database requires a special collation function '%1' that this application can't provide without further knowledge. +If you choose to proceed, be aware bad things can happen to your database. +Create a backup! + Uma tabela nesse banco de dados requer uma função de comparação especial '%1' que esse aplicativo não pode prover. +So você optar por proceder, esteja avisado de que coisas ruins podem acontecer para o seu banco de dados. +Faça um backup! + + + + creating collation + criando função de comparação + + + + Set a new name for the SQL tab. Use the '&&' character to allow using the following character as a keyboard shortcut. + Defina um novo nome para a aba de SQL. Use o caractere '&&' para poder usar o seguinte caractere como um atalho de teclado. + + + + Please specify the view name + Por favor, especifique o nome da vista + + + + There is already an object with that name. Please choose a different name. + Já existe um objeto com esse nome. Por favor, escolha um nome diferente. + + + + View successfully created. + Vista criada com sucesso. + + + + Error creating view: %1 + Erro criando vista: %1 + + + + This action will open a new SQL tab for running: + Essa ação irá abrir uma nova aba SQL para rodar: + + + + Press Help for opening the corresponding SQLite reference page. + Pressione Help para abrir a página de referência SQL correspondente. + + + + Busy (%1) + Ocupado (%1) + + + + Error checking foreign keys after table modification. The changes will be reverted. + Erro verificando as chaves estrangeiras após modificação. Mudanças serão revertidas. + + + + This table did not pass a foreign-key check.<br/>You should run 'Tools | Foreign-Key Check' and fix the reported issues. + Essa tabela não passou um teste de chave estrangeira.<br/>Você deveria rodar 'Ferramentas | Teste de Chave Estrangeira| e corrigir os problemas reportados. + + + + NullLineEdit + + + Set to NULL + Definir como NULL + + + + Alt+Del + + + + + PlotDock + + + Plot + Plotar + + + + Columns + Colunas + + + + X + X + + + + Line type: + Tipo da linha: + + + + + None + Nenhum + + + + Line + Linha + + + + StepLeft + Passo à esquerda + + + + StepRight + Passo à direita + + + + StepCenter + Passo centralizado + + + + Impulse + Impulso + + + + Point shape: + Ponto: + + + + Cross + Cruz + + + + Plus + Mais + + + + Circle + Círculo + + + + Disc + Disco + + + + Square + Quadrado + + + + Diamond + Diamante + + + + Star + Estrela + + + + Triangle + Triângulo + + + + TriangleInverted + Triângulo Invertido + + + + CrossSquare + Cruz Quadrado + + + + PlusSquare + Mais Quadrado + + + + CrossCircle + Cruz Círculo + + + + PlusCircle + Mais Círculo + + + + Peace + Paz + + + + <html><head/><body><p>Save current plot...</p><p>File format chosen by extension (png, jpg, pdf, bmp)</p></body></html> + <html><head/><body><p>Salvar plotagem atual...</p><p>Formato de arquivo definido pela extensão (png, jpg, pdf, bmp)</p></body></html> + + + + Save current plot... + Salvar plotagem atual... + + + + + + Row # + Coluna # + + + + Choose a filename to save under + Escolha um nome de arquivo para salvar + + + + PNG(*.png);;JPG(*.jpg);;PDF(*.pdf);;BMP(*.bmp);;All Files(*) + PNG(*.png);;JPG(*.jpg);;PDF(*.pdf);;BMP(*.bmp);;Todos os arquivos(*) + + + + <html><head/><body><p>This pane shows the list of columns of the currently browsed table or the just executed query. You can select the columns that you want to be used as X or Y axis for the plot pane below. The table shows detected axis type that will affect the resulting plot. For the Y axis you can only select numeric columns, but for the X axis you will be able to select:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Date/Time</span>: strings with format &quot;yyyy-MM-dd hh:mm:ss&quot; or &quot;yyyy-MM-ddThh:mm:ss&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Date</span>: strings with format &quot;yyyy-MM-dd&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Time</span>: strings with format &quot;hh:mm:ss&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Label</span>: other string formats. Selecting this column as X axis will produce a Bars plot with the column values as labels for the bars</li><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Numeric</span>: integer or real values</li></ul><p>Double-clicking the Y cells you can change the used color for that graph.</p></body></html> + <html><head/><body><p>Esse painel mostra a lista de colunas da tabela atualmente exibida ou a consulta recém executada. Você pode selecionar as colunas que você quer que sejam utilizadas como os eixos X e Y para o painel de plotagem abaixo. A tabela mostra o tipo detectado de exio que será utilizado na plotagem. For o eixo Y você só pode selecionar colunas numéricas, mas para o eixo X você pode selecionar:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Data/Hora</span>: strings com o formato &quot;yyyy-MM-dd hh:mm:ss&quot; ou &quot;yyyy-MM-ddThh:mm:ss&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Data</span>: strings com o formato &quot;yyyy-MM-dd&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Hora</span>: strings com o formato &quot;hh:mm:ss&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Rótulo</span>: outros formatos de string. Selecionando essa coluna como X vai produzir um gráfico de barras com as colunas como rótulos para as barras</li><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Numérico</span>: valores inteiros ou reais</li></ul><p>Clicando duas vezes nas células Y você pode mudar a cor usada para aquele gráfico.</p></body></html> + + + + Y1 + Y1 + + + + Y2 + Y2 + + + + Axis Type + Tipo do eixo + + + + Here is a plot drawn when you select the x and y values above. + +Click on points to select them in the plot and in the table. Ctrl+Click for selecting a range of points. + +Use mouse-wheel for zooming and mouse drag for changing the axis range. + +Select the axes or axes labels to drag and zoom only in that orientation. + Aqui está um gráfico feito quando você seleciona os valores X e Y acima. + +Clique nos pontos para selecioná-los no gráfico e na tabela. Ctrl+Clique para selecionar um intervalo de pontos. + +Use o scroll do mouse para dar zoom e arraste o mouse para alterar o intervalo dos eixos. + +Selecione os eixos ou rótulos dos eixos para arrastar e dar zoom somente naquela orientação. + + + + + Load all data and redraw plot + Carregar todos os dados e plotar de novo + + + + Copy + Copiar + + + + Show legend + Mostrar legenda + + + + Stacked bars + Barras empilhadas + + + + Date/Time + Data/Hora + + + + Date + Data + + + + Time + Hora + + + + + Numeric + Numérico + + + + Label + Rótulo + + + + Invalid + Inválido + + + + Load all data and redraw plot. +Warning: not all data has been fetched from the table yet due to the partial fetch mechanism. + Carregar todos os dados e plotar de novo. +Aviso: nem todos os dados foram obtidos da tabela ainda devido ao mecanismo de obtenção parcial. + + + + Choose an axis color + Escolher a cor do eixo + + + + There are curves in this plot and the selected line style can only be applied to graphs sorted by X. Either sort the table or query by X to remove curves or select one of the styles supported by curves: None or Line. + Existem curvas nesse gráfico e o estilo de linha selecionado só pode ser aplicado para gráficos ordenados por X. Ou ordene a tabela ou consulte por X para remover curvas ou selecione um dos estilos suportados por curvas: Nenhum ou Linha. + + + + Loading all remaining data for this table took %1ms. + Carregar os dados restantes para essa tabela levou %1ms. + + + + Print... + Imprimir... + + + + PreferencesDialog + + + Preferences + Configurações + + + + &General + &Geral + + + + Remember last location + Lembrar do último diretório + + + + Always use this location + Sempre usar esse diretório + + + + Remember last location for session only + Lembrar do último diretório somente nessa sessão + + + + + + ... + ... + + + + Default &location + Diretório &padrão + + + + Lan&guage + &Idioma + + + + Automatic &updates + &Atualizações automáticas + + + + + + + + + + + + enabled + ativado + + + + &Database + &Banco de dados + + + + Database &encoding + &Codificação do banco de dados + + + + Open databases with foreign keys enabled. + Abrir bancos de dados com chaves estrangeiras ativado. + + + + &Foreign keys + &Chaves estrangeiras + + + + Data &Browser + Navegador de &dados + + + + &SQL + &SQL + + + + Settings name + Settings name + + + + Context + Context + + + + Colour + Cor + + + + Bold + Negrito + + + + Italic + Itálico + + + + Underline + Underline + + + + Keyword + Palavra-chave + + + + Function + Função + + + + Table + Tabela + + + + Comment + Comentário + + + + Identifier + Identificador + + + + String + String + + + + Current line + Linha atual + + + + SQL &editor font size + Tamanho da fonte do &editor de SQL + + + + SQL editor &font + &Fonte do editor de SQL + + + + &Extensions + &Extensões + + + + Select extensions to load for every database: + Selecione extensões para carregar para todos os bancos de dados: + + + + Add extension + Adicionar extensão + + + + Remove extension + Remover extensão + + + + <html><head/><body><p>While supporting the REGEXP operator SQLite doesn't implement any regular expression<br/>algorithm but calls back the running application. DB Browser for SQLite implements this<br/>algorithm for you to let you use REGEXP out of the box. However, as there are multiple possible<br/>implementations of this and you might want to use another one, you're free to disable the<br/>application's implementation and load your own by using an extension. Requires restart of the application.</p></body></html> + <html><head/><body><p>Embora suporte o operador REGEXP, SQLite não implementa expressões regulares mas recorre ao aplicativo em execução.<br/>DB Browser para SQLite implementa esse algoritmo para você poder utilizar REGEXP.<br/>Todavia, como existem múltiplas implementações possíveis desse algoritmo e você pode querer usar outra, você pode desativar a implementação do aplicativo e carregar a sua própria implementação através de uma extensão.<br/>Requer que o programa seja reiniciado.</p></body></html> + + + + Disable Regular Expression extension + Desativar extensão de expressões regulares + + + + + Choose a directory + Escolha um diretório + + + + The language will change after you restart the application. + A linguagem mudará após reiniciar o programa. + + + + Select extension file + Selecione arquivo de extensão + + + + Extensions(*.so *.dylib *.dll);;All files(*) + Extensões(*.so *.dylib *.dll);;Todos os arquivos(*) + + + + Remove line breaks in schema &view + Remover quebras de linhas em &vista de esquema + + + + Prefetch block si&ze + &Tamanho de bloco de prefetch + + + + Default field type + Tipo padrão de campo + + + + Font + Fonte + + + + &Font + &Fonte + + + + NULL + NULL + + + + Regular + Regular + + + + Binary + Binário + + + + Background + Fundo + + + + Filters + Filtros + + + + Escape character + Caractere de escape + + + + Delay time (&ms) + Tempo de delay (&ms) + + + + Set the waiting time before a new filter value is applied. Can be set to 0 for disabling waiting. + Definir o tempo de espera antes de aplicar um novo filtro de valor. Pode ser definido para zero para desativar espera. + + + + Tab size + Tamanho de tabulação + + + + Error indicators + Indicadores de erro + + + + Hori&zontal tiling + Disposição &horizontal + + + + If enabled the SQL code editor and the result table view are shown side by side instead of one over the other. + Se ativados, o editor de SQL e a tabela de resultados são exibidos lado a lado em vez de um sobre o outro. + + + + Code co&mpletion + Co&mpletação de código + + + + Show remote options + Mostrar opções remotas + + + + SQ&L to execute after opening database + SQ&L para executar após abrir o banco de dados + + + + Content + Conteúdo + + + + Symbol limit in cell + Limite de símbolos na célula + + + + Threshold for completion and calculation on selection + Limite de compleção e cálculo em seleção + + + + Show images in cell + Mostrar imagens na célula + + + + Enable this option to show a preview of BLOBs containing image data in the cells. This can affect the performance of the data browser, however. + Habilite essa opção para mostrar uma prévia de BLOBs contendo dados de imagens nas células. Isso pode afetar a performance do visualizados de dados. + + + + Remote + Remoto + + + + CA certificates + Certificados CA + + + + + Subject CN + Nome comum do sujeito + + + + Common Name + Nome comum + + + + Subject O + O do sujeito + + + + Organization + Organização + + + + + Valid from + Válido de + + + + + Valid to + Válido para + + + + + Serial number + Número serial + + + + Your certificates + Seus certificados + + + + File + Arquivo + + + + Subject Common Name + Nome comum do sujeito + + + + Issuer CN + CN do emissor + + + + Issuer Common Name + Nome Comum do emissor + + + + Import certificate file + Importar certificado + + + + No certificates found in this file. + Nem um certificado encontrado nesse arquivo. + + + + Are you sure you want do remove this certificate? All certificate data will be deleted from the application settings! + Você tem certeza de que deseja remover esse certificado? Todos os dados do certificado serão deletados das configurações da aplicação! + + + + Clone databases into + Clonar bancos de dados em + + + + Toolbar style + Estilo da barra de ferramentas + + + + + + + + Only display the icon + Exibir apenas o ícone + + + + + + + + Only display the text + Exibir apenas o texto + + + + + + + + The text appears beside the icon + O texto aparece ao lado do ícone + + + + + + + + The text appears under the icon + O texto aparece sob o ícone + + + + + + + + Follow the style + Seguir o estilo + + + + DB file extensions + Extensões de arquivo de bancos de dados + + + + Manage + Gerenciar + + + + Main Window + Janela principal + + + + Database Structure + Estrutura do banco de dados + + + + Browse Data + Navegar dados + + + + Execute SQL + Executar SQL + + + + Edit Database Cell + Editar célula do banco de dados + + + + When this value is changed, all the other color preferences are also set to matching colors. + Quando este valor é alterado, todas as outras preferências de cor são definidas para cores compatíveis. + + + + Follow the desktop style + Seguir o estilo do desktop + + + + Dark style + Estilo escuro + + + + Application style + Estilo da aplicação + + + + This sets the font size for all UI elements which do not have their own font size option. + Isso define o tamanho da fonte para todos os elementos da interface que não possuem sua própria opção de tamanho de fonte. + + + + Font size + Tamanho da fonte + + + + Database structure font size + Tamanho da fonte da estrutura do banco de dados + + + + Font si&ze + &Tamanho da fonte + + + + This is the maximum number of items allowed for some computationally expensive functionalities to be enabled: +Maximum number of rows in a table for enabling the value completion based on current values in the column. +Maximum number of indexes in a selection for calculating sum and average. +Can be set to 0 for disabling the functionalities. + Esse é o número máximo de itens permitidos para que algumas funcionalidades computacionalmente caras sejam habilitadas: +Número máximo de linhas em uma tabela para habilitar compleção de valores baseada nos valores atualmente na coluna. +Número máximo de índices em uma seleção para se calcular soma e média. +Pode ser deixado em 0 para se desabilitar as funcionalidades. + + + + This is the maximum number of rows in a table for enabling the value completion based on current values in the column. +Can be set to 0 for disabling completion. + Esse é o número máximo de linhas na tabela para preencher baseado nos valores atualmente na coluna. +Pode ser 0 para desabilitar preenchimento. + + + + Field display + Exibição do campo + + + + Displayed &text + &Texto exibido + + + + + + + + + Click to set this color + Clique para definir essa cor + + + + Text color + Cor do texto + + + + Background color + Cor do plano de fundo + + + + Preview only (N/A) + Somente prévia (N/D) + + + + Foreground + Plano de frente + + + + SQL &results font size + Tamanho da fonte dos &resultados do SQL + + + + &Wrap lines + &Quebra de linhas + + + + Never + Nunca + + + + At word boundaries + Nos limites de palavras + + + + At character boundaries + Nos limites de caractere + + + + At whitespace boundaries + Nos limites de espaço em branco + + + + &Quotes for identifiers + Ãspas &para identificadores + + + + Choose the quoting mechanism used by the application for identifiers in SQL code. + Escolha as áspas utilizadas pela aplicação para identificadores no código SQL. + + + + "Double quotes" - Standard SQL (recommended) + "Ãspas duplas" - SQL Padrão (recomendado) + + + + `Grave accents` - Traditional MySQL quotes + `Crases`- MySQL tradicional + + + + [Square brackets] - Traditional MS SQL Server quotes + [Colchetes] - MS SQL Server tradicional + + + + Keywords in &UPPER CASE + Palavras-chave em &CAIXA ALTA + + + + When set, the SQL keywords are completed in UPPER CASE letters. + Quando definido, as palavras-chave SQL serão completadas em CAIXA ALTA. + + + + When set, the SQL code lines that caused errors during the last execution are highlighted and the results frame indicates the error in the background + Quando definido, as linhas de código SQL que causaram erros durante a última execução são destacadas e os resultados indicam os erros no fundo + + + + Close button on tabs + Botão para fechar abas + + + + If enabled, SQL editor tabs will have a close button. In any case, you can use the contextual menu or the keyboard shortcut to close them. + Se ativado, as abas do editor de SQL terão um botão para fechá-las. De qualquer forma, você pode usar o menu de contexto ou o atalho de teclado para fechá-las. + + + + Proxy + Proxy + + + + Configure + Configurar + + + + Are you sure you want to clear all the saved settings? +All your preferences will be lost and default values will be used. + Você tem certeza que deseja limpar as configurações salvas? +Todas as suas preferências serão perdidas e os valores padrão serão utilizados. + + + + When enabled, the line breaks in the Schema column of the DB Structure tab, dock and printed output are removed. + Quando ativado, as quebras de linha na coluna Esquema da aba Estrutura do banco de dados e nas saídas impressas são removidas. + + + + <html><head/><body><p>SQLite provides an SQL function for loading extensions from a shared library file. Activate this if you want to use the <span style=" font-style:italic;">load_extension()</span> function from SQL code.</p><p>For security reasons, extension loading is turned off by default and must be enabled through this setting. You can always load extensions through the GUI, even though this option is disabled.</p></body></html> + <html><head/><body><p>SQLite provê uma função SQL para carregar extensões de um arquivo de biblioteca. Ative isso se você quer usar a função <span style=" font-style:italic;">load_extension()</span> a partir de código SQL.</p><p>Por motivos de segurança, carregamento de extensões é desabilitado por padrão e precisa ser habilitado através dessa configuração. Você sempre pode carregar extensões através da interface gráfica, mesmo com essa opção desabilitada.</p></body></html> + + + + Allow loading extensions from SQL code + Permitir o carregamento de extensões a partir de código SQL + + + + ProxyDialog + + + Proxy Configuration + Configuração do proxy + + + + Pro&xy Type + Tipo do pro&xy + + + + Host Na&me + No&me do host + + + + Port + Porta + + + + Authentication Re&quired + Au&tenticação necessária + + + + &User Name + Nome do &usuário + + + + Password + Senha + + + + None + Nenhum + + + + System settings + Configurações do sistema + + + + HTTP + HTTP + + + + Socks v5 + Socks v5 + + + + QObject + + + Error importing data + Erro importando dados + + + + from record number %1 + a partir de registro número %1 + + + + . +%1 + . +%1 + + + + Cancel + Cancelar + + + + All files (*) + Todos arquivos (*) + + + + Importing CSV file... + Importando arquivo CSV... + + + + SQLite database files (*.db *.sqlite *.sqlite3 *.db3) + Bancos de dados SQLite (*.db *.sqlite *.sqlite3 *.db3) + + + + Left + Esquerda + + + + Right + Direita + + + + Center + Centro + + + + Justify + Justificar + + + + SQLite Database Files (*.db *.sqlite *.sqlite3 *.db3) + Arquivos de banco de dados SQL (*.db *.sqlite *.sqlite3 *.db3) + + + + DB Browser for SQLite Project Files (*.sqbpro) + Arquivo de projeto DB Browser para SQLite (*.sqbpro) + + + + SQL Files (*.sql) + Arquivos SQL (*.sql) + + + + All Files (*) + Todos arquivos (*) + + + + Text Files (*.txt) + Arquivos de texto (*.txt) + + + + Comma-Separated Values Files (*.csv) + Arquivos de valores separados por vírgulas (*.csv) + + + + Tab-Separated Values Files (*.tsv) + Arquivos de valores separados por tabs (*.tsv) + + + + Delimiter-Separated Values Files (*.dsv) + Arquivos de valores separados por delimitadores (*.dsv) + + + + Concordance DAT files (*.dat) + Arquivos DAT Concordance (*.dat) + + + + JSON Files (*.json *.js) + Arquivos JSON (*.json) + + + + XML Files (*.xml) + Arquivos XML (*.xml) + + + + Binary Files (*.bin *.dat) + Arquivos binários (*.bin) + + + + SVG Files (*.svg) + Arquivos SVG (*.svg) + + + + Hex Dump Files (*.dat *.bin) + Arquivos de dump hexadecimal (*.dat *.bin) + + + + Extensions (*.so *.dylib *.dll) + Extensões (*.so *.dylib *.dll) + + + + RemoteCommitsModel + + + Commit ID + ID do commit + + + + Message + Mensagem + + + + Date + Data + + + + Author + Autor + + + + Size + Tamanho + + + + Authored and committed by %1 + Autorado e cometido por %1 + + + + Authored by %1, committed by %2 + Autorado por %1, cometido por %2 + + + + RemoteDatabase + + + Error opening local databases list. +%1 + Erro abrindo lista local de bancos de dados. +%1 + + + + Error creating local databases list. +%1 + Erro criando lista local de bancos de dados. +%1 + + + + RemoteDock + + + Remote + Remoto + + + + Local + Local + + + + Identity + Identidade + + + + Push currently opened database to server + Enviar o banco de dados aberto para o servidor + + + + DBHub.io + DBHub.io + + + + <html><head/><body><p>In this pane, remote databases from dbhub.io website can be added to DB Browser for SQLite. First you need an identity:</p><ol style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Login to the dbhub.io website (use your GitHub credentials or whatever you want)</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Click the button to &quot;Generate client certificate&quot; (that's your identity). That'll give you a certificate file (save it to your local disk).</li><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Go to the Remote tab in DB Browser for SQLite Preferences. Click the button to add a new certificate to DB Browser for SQLite and choose the just downloaded certificate file.</li></ol><p>Now the Remote panel shows your identity and you can add remote databases.</p></body></html> + <html><head/><body><p>Neste painel, bancos de dados remotos do dbhub.io podem ser adicionados ao DB Browser para SQLite. Primeiro você precisa adicionar uma identidade:</p><ol style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Entre no dbhub.io (use suas credenciais do GitHub ou algum outro método)</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Clique o botão &quot;Gerar certificado do cliente&quot; (essa é sua identidade). Isto te dará um certificado (salve-o no disco local).</li><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Vá para a aba Remoto nas configurações do DB Browser para SQLite. Clique no botão para adicionar um novo certificado ao DB Browser para SQLite e escolha o arquivo recém baixado.</li></ol><p>Agora o painel remoto mostra sua identidade e você pode adicionar bancos de dados remotos.</p></body></html> + + + + Current Database + Banco de dados atual + + + + Clone + Clonar + + + + User + Usuário + + + + Database + Banco de dados + + + + Branch + Ramo + + + + Commits + Commits + + + + Commits for + Commits para + + + + <html><head/><body><p>You are currently using a built-in, read-only identity. For uploading your database, you need to configure and use your DBHub.io account.</p><p>No DBHub.io account yet? <a href="https://dbhub.io/"><span style=" text-decoration: underline; color:#007af4;">Create one now</span></a> and import your certificate <a href="#preferences"><span style=" text-decoration: underline; color:#007af4;">here</span></a> to share your databases.</p><p>For online help visit <a href="https://dbhub.io/about"><span style=" text-decoration: underline; color:#007af4;">here</span></a>.</p></body></html> + <html><head/><body><p>Você está utilizando uma identidade somente leitura. Para fazer upload do seu banco de dados, você precisa configurar e usar a sua conta no DBHub.io.</p><p>Se você ainda não tem uma conta no DBHub, <a href="https://dbhub.io/"><span style=" text-decoration: underline; color:#007af4;">crie uma agora</span></a> e importe seu certificado <a href="#preferences"><span style=" text-decoration: underline; color:#007af4;">aqui</span></a> para compartilhar os seus bancos de dados.</p><p>Para ajuda online, visite <a href="https://dbhub.io/about"><span style=" text-decoration: underline; color:#007af4;">este link</span></a>.</p></body></html> + + + + Back + Voltar + + + + Delete Database + Deletar banco de dados + + + + Delete the local clone of this database + Deletar o clone local desse banco de dados + + + + Open in Web Browser + Abrir no navegador Web + + + + Open the web page for the current database in your browser + Abrir a página da Web do banco de dados atual no seu navegador + + + + Clone from Link + Clonar a partir de um link + + + + Use this to download a remote database for local editing using a URL as provided on the web page of the database. + Use isso para baixar um banco de dados remoto para edição local usando uma URL encontrada na página na Web do banco de dados. + + + + Refresh + Atualizar + + + + Reload all data and update the views + Recarregar todos os dados e atualizar as vistas + + + + F5 + + + + + Clone Database + Clonar banco de dados + + + + Open Database + Abrir banco de dados + + + + Open the local copy of this database + Abrir a cópia local desse banco de dados + + + + Check out Commit + Ver commit + + + + Download and open this specific commit + Baixar e abrir esse commit específico + + + + Check out Latest Commit + Ver último commit + + + + Check out the latest commit of the current branch + Ver último commit do ramo atual + + + + Save Revision to File + Salvar revisão em arquivo + + + + Saves the selected revision of the database to another file + Salva a revisão selecionada do banco de dados em outro arquivo + + + + Upload Database + Fazer upload do banco de dados + + + + Upload this database as a new commit + Fazer upload desse banco de dados como um novo commit + + + + Select an identity to connect + Selecione uma identidade para se conectar + + + + Public + Público + + + + This downloads a database from a remote server for local editing. +Please enter the URL to clone from. You can generate this URL by +clicking the 'Clone Database in DB4S' button on the web page +of the database. + Isso baixa um banco de dados de um servidor remoto para edição local. +Por favor ,entre a URL a partir da qual o clone será feito. Você pode gerar +essa URL clicando no botão 'Clone Database in DB4S' na página na Web +do banco de dados. + + + + Invalid URL: The host name does not match the host name of the current identity. + URL inválida: o nome do host não confere com o nome do host da identidade atual. + + + + Invalid URL: No branch name specified. + URL inválida: ramo não especificado. + + + + Invalid URL: No commit ID specified. + URL inválida: ID do commit não especificada. + + + + You have modified the local clone of the database. Fetching this commit overrides these local changes. +Are you sure you want to proceed? + Você modificou seu clone local do banco de dados. Obter esse commit sobrescreve essas mudanças locais. +Você tem certeza de que deseja continuar? + + + + The database has unsaved changes. Are you sure you want to push it before saving? + O banco de dados tem mudanças não salvas. Você tem certeza de que deseja fazer o push antes de salvar? + + + + The database you are trying to delete is currently opened. Please close it before deleting. + O banco de dados que você está tentando deletar está atualmente aberto. Por favor, feche-o antes de deletar. + + + + This deletes the local version of this database with all the changes you have not committed yet. Are you sure you want to delete this database? + Isso deleta a versão local desse banco de dados com todas as mudanças que você ainda não cometeu. Você tem certeza de que deseja deletar esse banco de dados? + + + + RemoteLocalFilesModel + + + Name + Nome + + + + Branch + Ramo + + + + Last modified + Última modificação + + + + Size + Tamanho + + + + Commit + Commit + + + + File + Arquivo + + + + RemoteModel + + + Name + Nome + + + + Last modified + Última modificação + + + + Size + Tamanho + + + + Size: + Tamanho: + + + + Last Modified: + Última modificação: + + + + Licence: + licença: + + + + Default Branch: + Ramo padrão: + + + + Commit + Commit + + + + RemoteNetwork + + + Choose a location to save the file + Escolha um lugar para salvar o arquivo + + + + Error opening remote file at %1. +%2 + Erro abrindo arquivo remoto em %1. +%2 + + + + Error: Invalid client certificate specified. + Erro: Certificado de cliente inválido especificado. + + + + Please enter the passphrase for this client certificate in order to authenticate. + Por favor entre a frase chave para esse certificado de cliente para se autenticar. + + + + Cancel + Cancelar + + + + Uploading remote database to +%1 + Enviando banco de dados remoto para +%1 + + + + Downloading remote database from +%1 + Baixando banco de dados remoto de +%1 + + + + + Error: The network is not accessible. + Erro: A rede não é acessível. + + + + Error: Cannot open the file for sending. + Erro: Não pôde abrir o arquivo para envio. + + + + RemotePushDialog + + + Push database + Enviar banco de dados + + + + Database na&me to push to + No&me do banco de dados para enviar + + + + Commit message + Mensagem de commit + + + + Username + Nome de usuário + + + + Database licence + Licença do banco de dados + + + + Public + Público + + + + Database will be public. Everyone has read access to it. + Banco de dados será público. Todos poderão lê-lo. + + + + Database will be private. Only you have access to it. + Banco de dados será privado. Somente você terá acesso a ele. + + + + Branch + Ramo + + + + Force push + Forçar envio + + + + Use with care. This can cause remote commits to be deleted. + Use com cuidado. Isso pode causar a perda de commits remotos. + + + + RunSql + + + Execution aborted by user + Execução abortada pelo usuário + + + + , %1 rows affected + , %1 linhas afetadas + + + + query executed successfully. Took %1ms%2 + consulta executada com sucesso. Levou %1ms%2 + + + + executing query + executando consulta + + + + SelectItemsPopup + + + A&vailable + &Disponível + + + + Sele&cted + &Selecionado + + + + SqlExecutionArea + + + Form + Formulário + + + + <html><head/><body><p>Results of the last executed statements.</p><p>You may want to collapse this panel and use the <span style=" font-style:italic;">SQL Log</span> dock with <span style=" font-style:italic;">User</span> selection instead.</p></body></html> + <html><head/><body><p>Resultados dos últimos comandos executados.</p><p>Você pode querer colapsar esse painel e usar o dock <span style=" font-style:italic;">Log SQL</span> com seleção <span style=" font-style:italic;">Usuário</span> em vez disso.</p></body></html> + + + + Results of the last executed statements + Resultados dos últimos comandos executados + + + + This field shows the results and status codes of the last executed statements. + Esse campo mostra os resultados e códigos de status dos últimos comandos executados. + + + + Find previous match [Shift+F3] + Encontrar resultado anterior [Shift+F3] + + + + Find previous match with wrapping + Encontrar resultado anterior com mapeamento + + + + Shift+F3 + + + + + The found pattern must be a whole word + O padrão encontrado precisa ser uma palavra inteira + + + + Whole Words + Palavras inteiras + + + + Text pattern to find considering the checks in this frame + Padrão de texto para encontrar considerando os testes nesse frame + + + + Find in editor + Encontrar no editor + + + + The found pattern must match in letter case + O padrão encontrado precisa casar em capitalização + + + + Case Sensitive + Sensível à capitalização + + + + Find next match [Enter, F3] + Encontrar próxima correspondência [Enter, F3] + + + + Find next match with wrapping + Encontrar próxima correspondência no arquivo inteiro + + + + F3 + + + + + Interpret search pattern as a regular expression + Interpretar padrão de busca como expressão regular + + + + <html><head/><body><p>When checked, the pattern to find is interpreted as a UNIX regular expression. See <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>.</p></body></html> + <html><head/><body><p>Quando assinalado, o padrão a ser buscado é interpretado como uma expressão regular UNIX. Veja <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression nos Wikibooks</a>.</p></body></html> + + + + Regular Expression + Expressão Regular + + + + + Close Find Bar + Fechar barra de busca + + + + Couldn't read file: %1. + Não pôde ler arquivo: %1. + + + + + Couldn't save file: %1. + Não pôde salvar arquivo: %1. + + + + Your changes will be lost when reloading it! + Suas modificações serão perdidas quando recarregando! + + + + The file "%1" was modified by another program. Do you want to reload it?%2 + O arquivo "%1" foi modificado por outro programa. Você quer recarregá-lo?%2 + + + + SqlTextEdit + + + Ctrl+/ + + + + + SqlUiLexer + + + (X) The abs(X) function returns the absolute value of the numeric argument X. + (X) A função abs(X) retorna o valor absoluto do argumento numérico X. + + + + () The changes() function returns the number of database rows that were changed or inserted or deleted by the most recently completed INSERT, DELETE, or UPDATE statement. + + + + + (X1,X2,...) The char(X1,X2,...,XN) function returns a string composed of characters having the unicode code point values of integers X1 through XN, respectively. + (X1,X2,...) The char(X1,X2,...,XN) function returns a string composed of characters having the unicode code point values of integers X1 through XN, respectively. + + + + (X,Y,...) The coalesce() function returns a copy of its first non-NULL argument, or NULL if all arguments are NULL + (X,Y,...) The coalesce() function returns a copy of its first non-NULL argument, or NULL if all arguments are NULL + + + + (X,Y) The glob(X,Y) function is equivalent to the expression "Y GLOB X". + (X,Y) The glob(X,Y) function is equivalent to the expression "Y GLOB X". + + + + (X,Y) The ifnull() function returns a copy of its first non-NULL argument, or NULL if both arguments are NULL. + (X,Y) The ifnull() function returns a copy of its first non-NULL argument, or NULL if both arguments are NULL. + + + + (X,Y) The instr(X,Y) function finds the first occurrence of string Y within string X and returns the number of prior characters plus 1, or 0 if Y is nowhere found within X. + (X,Y) The instr(X,Y) function finds the first occurrence of string Y within string X and returns the number of prior characters plus 1, or 0 if Y is nowhere found within X. + + + + (X) The hex() function interprets its argument as a BLOB and returns a string which is the upper-case hexadecimal rendering of the content of that blob. + (X) The hex() function interprets its argument as a BLOB and returns a string which is the upper-case hexadecimal rendering of the content of that blob. + + + + () The last_insert_rowid() function returns the ROWID of the last row insert from the database connection which invoked the function. + () The last_insert_rowid() function returns the ROWID of the last row insert from the database connection which invoked the function. + + + + (X) For a string value X, the length(X) function returns the number of characters (not bytes) in X prior to the first NUL character. + + + + + (X,Y) The like() function is used to implement the "Y LIKE X" expression. + + + + + (X,Y,Z) The like() function is used to implement the "Y LIKE X ESCAPE Z" expression. + + + + + (X) The lower(X) function returns a copy of string X with all ASCII characters converted to lower case. + + + + + (X) ltrim(X) removes spaces from the left side of X. + + + + + (X,Y) The ltrim(X,Y) function returns a string formed by removing any and all characters that appear in Y from the left side of X. + + + + + (X,Y,...) The multi-argument max() function returns the argument with the maximum value, or return NULL if any argument is NULL. + + + + + (X,Y,...) The multi-argument min() function returns the argument with the minimum value. + + + + + (X,Y) The nullif(X,Y) function returns its first argument if the arguments are different and NULL if the arguments are the same. + + + + + (FORMAT,...) The printf(FORMAT,...) SQL function works like the sqlite3_mprintf() C-language function and the printf() function from the standard C library. + + + + + (X) The quote(X) function returns the text of an SQL literal which is the value of its argument suitable for inclusion into an SQL statement. + + + + + () The random() function returns a pseudo-random integer between -9223372036854775808 and +9223372036854775807. + + + + + (N) The randomblob(N) function return an N-byte blob containing pseudo-random bytes. + + + + + (X,Y,Z) The replace(X,Y,Z) function returns a string formed by substituting string Z for every occurrence of string Y in string X. + + + + + (X) The round(X) function returns a floating-point value X rounded to zero digits to the right of the decimal point. + + + + + (X,Y) The round(X,Y) function returns a floating-point value X rounded to Y digits to the right of the decimal point. + + + + + (X) rtrim(X) removes spaces from the right side of X. + + + + + (X,Y) The rtrim(X,Y) function returns a string formed by removing any and all characters that appear in Y from the right side of X. + + + + + (X) The soundex(X) function returns a string that is the soundex encoding of the string X. + + + + + (X,Y) substr(X,Y) returns all characters through the end of the string X beginning with the Y-th. + + + + + (X,Y,Z) The substr(X,Y,Z) function returns a substring of input string X that begins with the Y-th character and which is Z characters long. + + + + + () The total_changes() function returns the number of row changes caused by INSERT, UPDATE or DELETE statements since the current database connection was opened. + + + + + (X) trim(X) removes spaces from both ends of X. + + + + + (X,Y) The trim(X,Y) function returns a string formed by removing any and all characters that appear in Y from both ends of X. + + + + + (X) The typeof(X) function returns a string that indicates the datatype of the expression X. + + + + + (X) The unicode(X) function returns the numeric unicode code point corresponding to the first character of the string X. + + + + + (X) The upper(X) function returns a copy of input string X in which all lower-case ASCII characters are converted to their upper-case equivalent. + + + + + (N) The zeroblob(N) function returns a BLOB consisting of N bytes of 0x00. + + + + + + + + (timestring,modifier,modifier,...) + + + + + (format,timestring,modifier,modifier,...) + + + + + (X) The avg() function returns the average value of all non-NULL X within a group. + + + + + (X) The count(X) function returns a count of the number of times that X is not NULL in a group. + + + + + (X) The group_concat() function returns a string which is the concatenation of all non-NULL values of X. + + + + + (X,Y) The group_concat() function returns a string which is the concatenation of all non-NULL values of X. If parameter Y is present then it is used as the separator between instances of X. + + + + + (X) The max() aggregate function returns the maximum value of all values in the group. + + + + + (X) The min() aggregate function returns the minimum non-NULL value of all values in the group. + + + + + + (X) The sum() and total() aggregate functions return sum of all non-NULL values in the group. + + + + + () The number of the row within the current partition. Rows are numbered starting from 1 in the order defined by the ORDER BY clause in the window definition, or in arbitrary order otherwise. + () O número de linhas dentro da partição atual. Linhas são numeradas de 1 na ordem definida pela cláusula ORDER BY na definição da janela, ou de forma arbitrária. + + + + () The row_number() of the first peer in each group - the rank of the current row with gaps. If there is no ORDER BY clause, then all rows are considered peers and this function always returns 1. + () O row_number() do primeiro elemento de cada grupo - o rank da linha atual com gaps. Se não há uma cláusula ORDER BY, então todas as linhas são consideradas elementos e essa função sempre retorna 1. + + + + () The number of the current row's peer group within its partition - the rank of the current row without gaps. Partitions are numbered starting from 1 in the order defined by the ORDER BY clause in the window definition. If there is no ORDER BY clause, then all rows are considered peers and this function always returns 1. + () O número do grupo de colegas da linha atual dentro da sua partição - o rank da linha atual sem intervalos. Partições são numeradas a partir de 1 na ordem definida pela cláusula ORDER BY na definição. Se não há ORDER BY, então todas as linhas são consideradas colegas e essa função sempre retorna 1. + + + + () Despite the name, this function always returns a value between 0.0 and 1.0 equal to (rank - 1)/(partition-rows - 1), where rank is the value returned by built-in window function rank() and partition-rows is the total number of rows in the partition. If the partition contains only one row, this function returns 0.0. + () Apesar do nome, essa função sempre retorna um valor entre 0.0 e 1.0 igual a (rank - 1)/(linhas-na-partição - 1), onde rank é o valor retornado pela built-in rank() e linhas-na-partição é o número total de linhas na partição. Se a partição contém somente uma linha, essa função retorna 0. + + + + () The cumulative distribution. Calculated as row-number/partition-rows, where row-number is the value returned by row_number() for the last peer in the group and partition-rows the number of rows in the partition. + () A distribuição cumulativa. Calculada como número-da-linha/linhas-na-partição em que número-da-linha é o valor retornado por row_number() para o último elemento do grupo e linhas-na-partição é o número de linhas na partição. + + + + (N) Argument N is handled as an integer. This function divides the partition into N groups as evenly as possible and assigns an integer between 1 and N to each group, in the order defined by the ORDER BY clause, or in arbitrary order otherwise. If necessary, larger groups occur first. This function returns the integer value assigned to the group that the current row is a part of. + (N) Argumento N é interpretado como um inteiro. Essa função divide a partição em N grupos tão igualmente como possível e atribui um inteiro entre 1 e N para cada grupo, na ordem definida pela cláusula ORDER BY, ou em ordem arbitrária. Se necessário, grupos maiores ocorrem primeiro. Essa função retorna o valor inteiro atribuido ao grupo que a linha atual é parte de. + + + + (expr) Returns the result of evaluating expression expr against the previous row in the partition. Or, if there is no previous row (because the current row is the first), NULL. + (expr) Retorna o resultado de avaliar expressão expr contra a linha anterior na partição. Ou, se não há linha anterior, NULL. + + + + (expr,offset) If the offset argument is provided, then it must be a non-negative integer. In this case the value returned is the result of evaluating expr against the row offset rows before the current row within the partition. If offset is 0, then expr is evaluated against the current row. If there is no row offset rows before the current row, NULL is returned. + (expr,offset) Se o offset é fornecido, então ele precisa ser um inteiro não-negativo. Nesse caso, o valor retornado é o resultado de avaliar expr contra a linha offset linhas antes da linha atual dentro da partição. Se offset é 0, então expr é avaliada contra a linha atual. Se não há linha offset linhas antes da linha atual, NULL é retornado. + + + + + (expr,offset,default) If default is also provided, then it is returned instead of NULL if the row identified by offset does not exist. + (expr,offset,default) Se default também é fornecido, ele é retornado em vez de NULL se a linha identificada por offset não existe. + + + + (expr) Returns the result of evaluating expression expr against the next row in the partition. Or, if there is no next row (because the current row is the last), NULL. + (expr) Retorna o resultado de avaliar a expressão expr contra a próxima linha na partição. Ou, se não há próxima linha, NULL. + + + + (expr,offset) If the offset argument is provided, then it must be a non-negative integer. In this case the value returned is the result of evaluating expr against the row offset rows after the current row within the partition. If offset is 0, then expr is evaluated against the current row. If there is no row offset rows after the current row, NULL is returned. + (expr,offset) Se o offset é fornecido, então ele precisa ser um inteiro não-negativo. Nesse caso, o valor retornado é o resultado de avaliar expr contra a linha offset linhas após a linha atual dentro da partição. Se offset é 0, então expr é avaliada contra a linha atual. Se não há linha offset linhas após a linha atual, NULL é retornado. + + + + (expr) This built-in window function calculates the window frame for each row in the same way as an aggregate window function. It returns the value of expr evaluated against the first row in the window frame for each row. + (expr) Essa função de janela built-in calcula o frame da janela para cada linha na mesma forma que uma função de janela agregada. Ela retorna o valor de expr avaliada contra a primeira linha do frame da janela para cada linha. + + + + (expr) This built-in window function calculates the window frame for each row in the same way as an aggregate window function. It returns the value of expr evaluated against the last row in the window frame for each row. + (expr) Essa função de janela built-in calcula o frame da janela para cada linha na mesma forma que uma função de janela agregada. Ela retorna o valor de expr avaliada contra a última linha do frame da janela para cada linha. + + + + (expr,N) This built-in window function calculates the window frame for each row in the same way as an aggregate window function. It returns the value of expr evaluated against the row N of the window frame. Rows are numbered within the window frame starting from 1 in the order defined by the ORDER BY clause if one is present, or in arbitrary order otherwise. If there is no Nth row in the partition, then NULL is returned. + (expr) Essa função de janela built-in calcula o frame da janela para cada linha na mesma forma que uma função de janela agregada. Ela retorna o valor de expr avaliada contra a linha N do frame da janela para cada linha.Linhas são numeradas dentro do frame da janela começando em 1 na ordem definida pela cláusula ORDER BY se uma está presente, ou em ordem arbitrária, caso contrário. Se não há uma N-ésima linha na partição, NULL é retornado. + + + + (X) The load_extension(X) function loads SQLite extensions out of the shared library file named X. +Use of this function must be authorized from Preferences. + (X) A função load_extension(X) carrega extensões para SQLite a partir de um arquivo chamado X. +Uso dessa função precisa ser autorizado em Preferências. + + + + (X,Y) The load_extension(X) function loads SQLite extensions out of the shared library file named X using the entry point Y. +Use of this function must be authorized from Preferences. + (X,Y) A função load_extension(X) carrega extensões para SQLite a partir de um arquivo chamado X usando o ponto de entrada Y. +Uso dessa função precisa ser autorizado em Preferências. + + + + SqliteTableModel + + + Error changing data: +%1 + Erro modificando dados: +%1 + + + + reading rows + lendo linhas + + + + loading... + carregando... + + + + References %1(%2) +Hold %3Shift and click to jump there + Referencia %1(%2) +Segure %3Shift e clique para ir para lá + + + + retrieving list of columns + obtendo lista de colunas + + + + Fetching data... + Obtendo dados... + + + + + Cancel + Cancelar + + + + TableBrowser + + + Browse Data + Navegar dados + + + + &Table: + &Tabela: + + + + Select a table to browse data + Selecione uma tabela para navegar + + + + Use this list to select a table to be displayed in the database view + Use esta lista para selecionar uma tabela para ser exibida na vista do banco de dados + + + + This is the database table view. You can do the following actions: + - Start writing for editing inline the value. + - Double-click any record to edit its contents in the cell editor window. + - Alt+Del for deleting the cell content to NULL. + - Ctrl+" for duplicating the current record. + - Ctrl+' for copying the value from the cell above. + - Standard selection and copy/paste operations. + Essa é a vista de tabela do banco de dados. Você pode fazer as seguintes ações: + - Começar a escrever para editar o valor. + - Clicar duas vezes em qualquer registro para editar seus conteúdos no editor de célula. + - Alt+Del para deletar o conteúdo da célula para NULL. + - Ctrl+" para duplicar o registro atual. + - Ctrl+' para copiar o valor da célula de cima. + - Seleção normal para copiar e colar. + + + + Text pattern to find considering the checks in this frame + Padrão de texto para encontrar considerando os testes nesse frame + + + + Find in table + Encontrar na tabela + + + + Find previous match [Shift+F3] + Encontrar resultado anterior [Shift+F3] + + + + Find previous match with wrapping + Encontrar resultado anterior com mapeamento + + + + Shift+F3 + + + + + Find next match [Enter, F3] + Encontrar próxima correspondência [Enter, F3] + + + + Find next match with wrapping + Encontrar próxima correspondência com quebra de linha + + + + F3 + + + + + The found pattern must match in letter case + O padrão encontrado precisa casar em capitalização + + + + Case Sensitive + Sensível à capitalização + + + + The found pattern must be a whole word + O padrão encontrado precisa ser uma palavra inteira + + + + Whole Cell + Célula inteira + + + + Interpret search pattern as a regular expression + Interpretar padrão de busca como expressão regular + + + + <html><head/><body><p>When checked, the pattern to find is interpreted as a UNIX regular expression. See <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>.</p></body></html> + <html><head/><body><p>Quando marcado, o padrão para ser encontrado é interpretado como uma expressão regular do UNIX. Veja <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>.</p></body></html> + + + + Regular Expression + Expressão regular + + + + + Close Find Bar + Fechar barra de busca + + + + Text to replace with + Texto para substituir com + + + + Replace with + Substituir com + + + + Replace next match + Substituir próxima correspondência + + + + + Replace + Substituir + + + + Replace all matches + Substituir todas as correspondências + + + + Replace all + Substituir todos + + + + <html><head/><body><p>Scroll to the beginning</p></body></html> + <html><head/><body><p>Rolar para o começo</p></body></html> + + + + <html><head/><body><p>Clicking this button navigates to the beginning in the table view above.</p></body></html> + <html><head/><body><p>Clicar nesse botão navega até o começo da vista de tabela acima.</p></body></html> + + + + |< + |< + + + + Scroll one page upwards + Rolar uma página para cima + + + + <html><head/><body><p>Clicking this button navigates one page of records upwards in the table view above.</p></body></html> + <html><head/><body><p>Clicando nesse botão navega uma página de registros para cima.</p></body></html> + + + + < + < + + + + 0 - 0 of 0 + 0 - 0 de 0 + + + + Scroll one page downwards + Rolar uma página para baixo + + + + <html><head/><body><p>Clicking this button navigates one page of records downwards in the table view above.</p></body></html> + <html><head/><body><p>Clicando nesse botão navega uma página de registros para baixo.</p></body></html> + + + + > + > + + + + Scroll to the end + Rolar para o fim + + + + <html><head/><body><p>Clicking this button navigates up to the end in the table view above.</p></body></html> + <html><head/><body><p>Clicar nesse botão navega para o fim da tabela acima.</p></body></html> + + + + >| + >| + + + + <html><head/><body><p>Click here to jump to the specified record</p></body></html> + <html><head/><body><p>Clique aqui para pular para o registro especificado</p></body></html> + + + + <html><head/><body><p>This button is used to navigate to the record number specified in the Go to area.</p></body></html> + <html><head/><body><p>Esse botão navega para o registro especificado na área Ir para.</p></body></html> + + + + Go to: + Ir para: + + + + Enter record number to browse + Entre o número do registro para navegar + + + + Type a record number in this area and click the Go to: button to display the record in the database view + Digite o número de um registro nessa área e clique no botão Ir para: para exibir o registro na vista do banco de dados + + + + 1 + 1 + + + + Show rowid column + Mostrar coluna rowid + + + + Toggle the visibility of the rowid column + Alternar a visibilidade da coluna rowid + + + + Unlock view editing + Liberar edição da vista + + + + This unlocks the current view for editing. However, you will need appropriate triggers for editing. + Isso libera a vista atual para edição. Todavia, você vai precisar dos gatilhos apropriados para editar. + + + + Edit display format + Editar formato de exibição + + + + Edit the display format of the data in this column + Editar o formato de exibição dos dados nessa coluna + + + + + New Record + Novo registro + + + + + Insert a new record in the current table + Inserir um novo registro na tabela atual + + + + <html><head/><body><p>This button creates a new record in the database. Hold the mouse button to open a pop-up menu of different options:</p><ul><li><span style=" font-weight:600;">New Record</span>: insert a new record with default values in the database.</li><li><span style=" font-weight:600;">Insert Values...</span>: open a dialog for entering values before they are inserted in the database. This allows to enter values acomplishing the different constraints. This dialog is also open if the <span style=" font-weight:600;">New Record</span> option fails due to these constraints.</li></ul></body></html> + <html><head/><body><p>Esse botão cria um novo registro no banco de dados. Segure o botão do mouse para abrir um menu de opções diferentes:</p><ul><li><span style=" font-weight:600;">Novo Registro</span>: insere um novo registro com valores padrão no banco de dados.</li><li><span style=" font-weight:600;">Inserir Valores...</span>: abre um diálogo para novos valores antes de serem inseridos no banco de dados. Isso permite a entrada de valores de acordo com as restrições. Esse diálogo também é abaerto se a opção<span style=" font-weight:600;">Novo Registro</span> falha devido a essas restrições.</li></ul></body></html> + + + + + Delete Record + Deletar registro + + + + Delete the current record + Deletar o registro atual + + + + + This button deletes the record or records currently selected in the table + Esse botão deleta o registro ou registros selecionados + + + + + Insert new record using default values in browsed table + Inserir novo registro usando valores padrão na tabela + + + + Insert Values... + Inserir valores... + + + + + Open a dialog for inserting values in a new record + Abre um diálogo para inserir valores em um novo registro + + + + Export to &CSV + Exportar para &CSV + + + + + Export the filtered data to CSV + Exportar dados filtrados para CSV + + + + This button exports the data of the browsed table as currently displayed (after filters, display formats and order column) as a CSV file. + Esse botão exporta os dados da tabela como atualmente exibidos como um arquivo CSV. + + + + Save as &view + Salvar como &vista + + + + + Save the current filter, sort column and display formats as a view + Salva o filtro, ordenação e formato como uma vista + + + + This button saves the current setting of the browsed table (filters, display formats and order column) as an SQL view that you can later browse or use in SQL statements. + Esse botão salva as configurações da tabela exibida como uma vista SQL que você pode utilizar em comandos SQL depois. + + + + Save Table As... + Salvar tabela como... + + + + + Save the table as currently displayed + Salva a tabela como atualmente exibida + + + + <html><head/><body><p>This popup menu provides the following options applying to the currently browsed and filtered table:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Export to CSV: this option exports the data of the browsed table as currently displayed (after filters, display formats and order column) to a CSV file.</li><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Save as view: this option saves the current setting of the browsed table (filters, display formats and order column) as an SQL view that you can later browse or use in SQL statements.</li></ul></body></html> + <html><head/><body><p>Esse Menu provê as seguintes opções para a tabela atual:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Exportar para CSV: essa opção exporta os dados como estão exibidos para um arquivo CSV.</li><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Salvar como vista: essa opção salva a configuração atual da tabela como uma vista SQL que você depois pode consultar em comandos SQL.</li></ul></body></html> + + + + Hide column(s) + Ocultar coluna(s) + + + + Hide selected column(s) + Ocultar coluna(s) selecionada(s) + + + + Show all columns + Mostrar todas as colunas + + + + Show all columns that were hidden + Mostrar todas as colunas ocultas + + + + + Set encoding + Definir codificação + + + + Change the encoding of the text in the table cells + Modificar a codificação do texto nas células da tabela + + + + Set encoding for all tables + Modificar codificação para todas as tabelas + + + + Change the default encoding assumed for all tables in the database + Modificar a codificação padrão assumida para todas as tabelas no banco de dados + + + + Clear Filters + Limpar filtros + + + + Clear all filters + Limpar todos os filtros + + + + + This button clears all the filters set in the header input fields for the currently browsed table. + Esse botão limpa todos os filtros definidos no cabeçalho para a tabela atualmente navegada. + + + + Clear Sorting + Limpar ordenamento + + + + Reset the order of rows to the default + Resetar a ordem das linhas para o padrão + + + + + This button clears the sorting columns specified for the currently browsed table and returns to the default order. + Esse botão limpa o ordenamento especificado para a tabela atual e volta para a ordem padrão. + + + + Print + Imprimir + + + + Print currently browsed table data + Imprimir dados da tabela atual + + + + Print currently browsed table data. Print selection if more than one cell is selected. + Imprimir dados da tabela atual. Imprime a seleção se mais de uma célula está selecionada. + + + + Ctrl+P + + + + + Refresh + Atualizar + + + + Refresh the data in the selected table + Atualizar os dados na tabela selecionada + + + + This button refreshes the data in the currently selected table. + Este botão atualiza os dados na tabela atualmente selecionada. + + + + F5 + + + + + Find in cells + Encontrar em células + + + + Open the find tool bar which allows you to search for values in the table view below. + Abre a barra de ferramentas para buscar que permite que você busque por valores na vista da tabela abaixo. + + + + + Bold + Negrito + + + + Ctrl+B + + + + + + Italic + Itálico + + + + + Underline + Sublinhado + + + + Ctrl+U + + + + + + Align Right + Alinhar à direita + + + + + Align Left + Alinhar à esquerda + + + + + Center Horizontally + Centralizar horizontalmente + + + + + Justify + Justificar + + + + + Edit Conditional Formats... + Editar formatos condicionais... + + + + Edit conditional formats for the current column + Editar os formatos condicionais para a coluna atual + + + + Clear Format + Limpar formato + + + + Clear All Formats + Limpar todos os formatos + + + + + Clear all cell formatting from selected cells and all conditional formats from selected columns + Limpa toda a formatação das células selecionadas e todos os formatos condicionais das colunas selecionadas + + + + + Font Color + Cor do texto + + + + + Background Color + Cor do plano de fundo + + + + Toggle Format Toolbar + Alterar barra de ferramentas de formatação + + + + Show/hide format toolbar + Mostrar/esconder barra de ferramentas de formatação + + + + + This button shows or hides the formatting toolbar of the Data Browser + Esse botão mostra ou esconde a barra de ferramentas de formatação do navegador de dados + + + + Select column + Selecionar coluna + + + + Ctrl+Space + + + + + Replace text in cells + Substituir texto em células + + + + Filter in any column + Filtrar em qualquer coluna + + + + Ctrl+R + + + + + %n row(s) + + %n linha(s) + %n linhas + + + + + , %n column(s) + + , %n coluna(s) + , %n colunas + + + + + . Sum: %1; Average: %2; Min: %3; Max: %4 + . Soma: %1; Média: %2; Mínimo: %3; Máximo: %4 + + + + Conditional formats for "%1" + Formatos condicionais para "%1" + + + + determining row count... + determinando número de linhas... + + + + %1 - %2 of >= %3 + %1 - %2 de >= %3 + + + + %1 - %2 of %3 + %1 - %2 de %3 + + + + Please enter a pseudo-primary key in order to enable editing on this view. This should be the name of a unique column in the view. + Por favor, entre uma pseudo-chave primária para habilitar edição nessa vista. Isso deveria ser o nome de uma coluna única na vista. + + + + Delete Records + Deletar registros + + + + Duplicate records + Duplicar registros + + + + Duplicate record + Duplicar registro + + + + Ctrl+" + + + + + Adjust rows to contents + Ajustar linhas aos conteúdos + + + + Error deleting record: +%1 + Erro deletando registro: +%1 + + + + Please select a record first + Por favor, selecione um registro primeiro + + + + There is no filter set for this table. View will not be created. + Não há filtro para essa tabela. Vista não será criada. + + + + Please choose a new encoding for all tables. + Por favor, escolha uma nova codificação para todas tabelas. + + + + Please choose a new encoding for this table. + Por favor, escolha uma nova codificação para essa tabela. + + + + %1 +Leave the field empty for using the database encoding. + %1 +Deixe o campo em branco para usar a codificação do banco de dados. + + + + This encoding is either not valid or not supported. + Essa codificação é inválida ou não suportada. + + + + %1 replacement(s) made. + %1 substituição(ões) feita(s). + + + + VacuumDialog + + + Compact Database + Compactar banco de dados + + + + Warning: Compacting the database will commit all of your changes. + Alerta: compactando o banco de dados irá confirmar todas as suas modificações. + + + + Please select the databases to co&mpact: + Por favor selecione o banco de dados para co&mpactar: + + + diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/translations/sqlb_ru.qm b/src/WBCLFZSystemModule/SqliteDBProcess/src/translations/sqlb_ru.qm new file mode 100644 index 0000000000000000000000000000000000000000..37b587aae6db2874293a61002e1c1a80a682cdac GIT binary patch literal 177150 zcmdRX31C#!_4j>~nJkk@!VV(f5FsFvg&jf&goGs!5`+MX>m->Z1IbLBnXtIvUYAi7HI`?i^RlR(@5|NFjD^OBkO?sD!~e&^hC z&#Sn%WysTix#FVVj~w>kQClB)=SCrfC)$1FvK4cM7%>Nb6$)|If$DnqA8{Rnzi&|2 zdk5k=9)CZluJ@MXIzhN2H`5@PF43@cw~r#~sgLX5YzScuh8AI!@$+&63#;_?c4 z)nZM;ebeMYvyU6r$WKuiBOW!1WhGd-*cq{uccl ze4y~;gGPTJB0OdDgtl>q@Ra+6b}gp2a0-^DQ(YHLR@W1U%B%L!YwG&&9m2B`&mC8# zuD`urcw#L=JN_J8AH@~zZS|o4hvZe;ajd#N?A5Pt3D35Zg?7Rx!gK3apwWZEbNdvb zo$`k8JQPI#m#gdIYt?lfp5y0dt`MH59ueBgE7kSET_W=jM+otY0(HG$hsYnwryhQ!Xt#{c~KNy2l`B0AP#uoc_H>~7vt`%2R}S5 z#@)RO>pEYIyWcIuvpd8%&{O>W6fq9;)PCj?<39PV5Etzd<32AF;<3+?<9MeS#o3vq0rSak8VLW^A@>gL=i zT<0AomQH(Bh?V`tvJE@X&beawi`NUW>UPn%`Yfz-y=Z(E^tyJOSW$kM5ZC=&tjq>q zAN{#lc^2;5;>Q&-(>+S8+>Yxxx$64R7h>f-xbOHjvFcpRd*5^9)zy8jIHYoy(Ds=n z4hdmgn?4b%H-bJVe=D!r_Or$6GqZ(wyh0py@^u)`QR1*uej~*GgT)bVR|@UXDsfaE z`kgvhG(8Lcdvc{{-7-RmXZngYM{O74rw2s1@oz$WGgTaW1>|kuH{$rbyM*iLf#Uf6 zz+cCV5T~quScqk<>iY9;aq7Brgt*}eapAe!g_ire*t!z(_{2uB^;g#k@#0!>Ll)@$ z!=d7qvD<{$euTL7{4Ajzu%Fm|$8OnE-7NT*WylO8j)e4%?-c|Q%`#gQR za2>a=Hgx<}p=~bK{IC95hzn29Mg~Jz-|w`dekH=SUz0W_3jW>wFKz6CtwQ``r#AMW zABEQK(Mkg`As%kkW*_yC&{hPrIsKQTy6rWHF{W7Xd`C0Mi-whw436t zl5s}}S8SQ9%Ik&rqK~WUFs$b>ue;_B!uT#;{K z>yYu)(C5dxRzF-R#P_$jI_tLx?O!Ll!heSD?|#Jfvyn@M_Qnj?8CUNTF4tMEvo8mK zE!^(fTn~Dde&{-H8=jlscAbCAvqJpP>ALaa#~>fyxwaj6vJg+b?z;CW{C#(>>psd` zWU}l2)=AJWXSp8O*d(+^9&_z%I6`R8zv+79GmPhkRj$YG`=`)u7~p#1FwF0ndt6W4 zzDZ~wJ>Yucfz3kPagpokUtt`x4tBlP91!C80@oWKqW^W%UGH?mCN5s(dgt|5V3MzJ zy<4{nCihv_dpTjD-CyYX_>@l}_aWEktytG>qg{WSSqppjg6pS4zz-+>n2~WzSh%Kt zpOHCXjS%}?oso4$ScpevW(<7eUqZa{LB`PK&k5~ukumJ8LZMxHaK`YwKM7aW=NW|) zVAp4!ma+d8l|sAw$&8|79ulsajTuujM+jHe@4Vov6p6CJrMGB-UVOnL zM2$D&rSG>0SKCt=AGEd$vHR4Fzn@L@h z=^GT{9*=u*2=gneb{~A|*FuDH-K(p96fS?jedw=1?+f;I9~r+D&}^Z*?Y*z?e5QNN zm^XzO-q+pz;%Fg$eY$(yONW5(2D>-xd=Yf~$$k7ikHX$Q;yxt=d7bk+_nE)hEnNMN za-X~KG9i}UB(K^9t?rATsTQu*!R||IcK|=_l2`4%Gt~8wTzPfP-r>IV)Jui-z~9vM zp?%f$cVYLXTd|%89^?MyIrYLdV4{1=5)e|3SM2f434Yc%Yw$9?_JPRBe? zcHc1d5y<^-+&4@o-<{;Xp~fw=hgPWT!!_<3UV?tO_$K#_>oyDV-5~ePO}m7)|I6-M zHoqiXE$`y`t`HxOmRIeK{jAiepFXL_^(S0o?pt6MMdNAedfAQY`pKp8>IxR)3VHhE0bE_^zY$m9 zlTUrPx^X=nR}VhF0oN@2eXIM{TY!ZpKIHyQy#_iibKg7gBk;w~+&f3k2fp^YcfJOB z`gOJY;X2saVfVWqelQ<)&*Ogj4CsX^o88a-a1H1++Wq_^zlOef&;3F<@W!<*?w1B` z7uxMp-7k$k0D9yob-k>g`}Nzu0ls#sLYo=z>f4N zXZqBgLOeLeGkw9Uzy*(ZX4FG||GLey#0^|ib**RV+xrNumahds;kbTw@j+AlBmbYBiR{oTi&b+?}i z{(jQ4UfUwHtfM{0p8qBMlAG1_si5chPl7@lTIM;e3jFwar@U&H4fdRN9mdt~63^N5 zuZP?|r>+lP=GlCa2kl<#+5G7M;p%$UbKy_Wdl}z)F8h1}#`jBHAYMOo5zS753b6F6`-T7kVBn*bRGD z?s>GkQn z&kH>-?Knxej=jM1UU9w9=Dz89|K8VyRy5r6@d>|&{fK+Mo{9DRXNBj-%hAuW=FAbV zy&=RwTQf^WFBjT*hi8_o*(F?OR%A|zKtEmg_spqL_>Q*}W={J9*8S-5nKM4B7vh2` znU&9k;YYlgS^K*YLfiGP%%hID2>NM9=27RoC$!ap%$D-0upghut82}$%(f$sgWtC> zGj#X};fh|887?>QHmixyoLj3K~ ztjzLVz+2B{_4~~>p;au&8gMAaE1u07ebZymZ|AA&!|SpRocyJ5RqxIk|NbdLyZ5=Q z>OA1ZCyKM?ee}7|F8@W=f)nl%+S9wU7Tf^-*#}}PjP-o{ z%dB&EKM%icS=L4S%@*24f62P+1IYC=CueQ>cC^rL{VMC)O~9{z8IX1DtDx7CC0W;h z4?aKs!>pVBa;6ZMG-TaA9&+)*+^jo3IT!k7VAgN)4-s0~U$cID-6-IS^Rj-o>Tg2J zsmpr$#7)B0*qQbGWzZKpCuhBINxl$kCuF^}{6`^v7R-8cG4%iYw`aY3_K!mQ{H?4% zWkRkGI5z9UxriJ5@fCU1qC>Ji^`8d2^Jvx=7YzjtI3epFjW@&Jct1OL0OpmMpPko= z=li#2_u1tU;?K8d4}Nz9a9=_8@G~&4>#DNH{0;K)%>~&Le}-{9`Dpf}NxKpE*qlA} zJJ^d~M&(soy*<0)^HYWP+FE&aZF)U>ZWiQu-v_g+x7`ff)SkUC{2cJ-wCvi`_lF-k zHhcNyEs)=jvk!?kLQZF8xAhqT{(LLDeHZ#)`dRk6xz7phu`{!e9kENe@*1*_T~mT} z+c*2fY}myUcV?e?^ku*a{j<+nv{Q(;4#~cZ_;Bs5*;jtDLWo=cm3`ycQxHeFNnW*` z{_GpCnIg2);@P+4eSr0D&%W)MdBC5evVS#bmk?Kcm;I{`+Jx(ztFrID3VgC=boPCt zvw$mqo&CVsPYUh9W_fk3U!A@4k(Ypn*JM9F=UO2)-;w>q=+VF-%d&s3{S*G{ZP_ng z`ZDmwjO@3T#lSbyvfnQOU&KAx9}cV(+RM+%t1I$m_Q%7o15T^W{&)>=NAvO7AK!*~ zJpV!VC$;&&onK{taWkH8Da!t4?M~sEC$hh-0sVr1&i=OcBB7n?&hf0ZS7@$@$0q z&=2np_qy-iF2s*tdOgR*gm%yM-s}fwfUocH_PgK+_-o&I_q}#E{Hb4gNA3oniIBJG zZ<~Pg=Xl5e{d(BXKHg$azHsFn;Vs!*FSLJL=q(MvuYaW4Tj}2-TtCbA&dviq`pc2t zg*O8i6|MF*ltEA3^`dvx51`AHmw1~W>koh8etFemW!{#G0l<%+c!R4l;6Ly04c>~s zFBy;PUAT67*ZdLuf51%dadWo_aq0!$<31e>dHv3N>PNo;Kd$qhxdD3ap)0%>cLjuY z-+kW8KRrUYhLm})o(lZlss+y2FlULVy zL%h$gy9;(`iTCx`WFeNe->VPEt7}uS_ivzwYuV%8 zFFmk7MqJ1^H0$2`@-CD+wlD6X}P5* zfgU$ppIdr9+VNeMTefh75OYt?Ejt^0Gwp!fnUE84@TT1P_vZ-l^AYl@T^P@;4IL!3 z9e3s~xxQOyhg_N4z&P@jtK?N%{aWtQ({~AN)n&O&x4s12H6-`!`KKY?^a!pW!Vc}D zu3I~S4epowK_RZEtj_)DF6hx`s&fAv|E8~RWQ#?j*QKZg0daF=g%;4?CrkUH)9@0 z?dPjL@@vH3i+$DG=fN+I`4*i23gUC^zD2ig1}=NZckqpk;QKp$s}F-d`gVWc;fsM6 zuj%j|*7Lw!F#?m0MQ!uJc(`HZuD7p{93{L|pOX#V4fTMqMGGWHrF zuI}U8`rE-+#}nn%wc!}w4X&pUm+SAl;gUOnFaPTM^#Y8e?N7entQZKtBir|I!Q*X0+%3MhPDeZU zp6Yw&5zz7a6~51Y4P5ZUEP2(gxW)JRySov0T;ls?Jlgr-Qs0lS9R|F5cV5P=u#;D| z<#`r9hxpT&yqtd=fjIfxJYQi6{P|6JL-Ih6=L_Z4)zpx;|5up*FPiekya0LmI+j;F zZWQGG>b#P{_# z<`XzL?=<*f+Nrbie!f4}{mI(AU!43S?Dyont+CC}yIpy|DIS41^@n*o=lv*Lg^%Yw zIvDct)X(!CyF83|P-os_PrnVEa7NyfzH^24{&#uLXWxkR`XKMUlOoXfZ|A*t(KMlX z@5_7doyUM*kIwt}p7#+qd^_*s&o*J5*X4cx#B;EtcjkTn`jLpA{E+vr)9!?x{bPOx z;zh2}f6LG1Iz0Phe(r~`r#ZjLFPI11bIu$2`~3lQ^?LLD8IV73AiwZfw0qWab-m}& z{PD-Wg1BB`{+!LKgLpFRrn8+Ud7%ng{|_ z`uzESr<{z+U)A{@D8bTiPKnmwcOl&plYLU)-Pn)U#NZqSN!A>Dnw@Cl1Pgb=DEEdt3A0Skw(1 zaBluPPuvRs^4a`%-l`Ycg2VDZxce#Shcog&3oR9{QSo|JNGW>5>z01>e7VF0LN@eM5ox<{kL?hZcCLf6xD= zy57I8Ab)FIh*<*)@}ETjw~o>s}$nS3kv$p4kDiBEf~}Sx-Kj#7;+%y z`Q4y`efrm;zwClxmtx)Syscnd{50WOe||yfQ1DgfUkhqGu&)vPeZiu`FGTxi7A(HM z1a@g$!Loao3-R6u1uJ}@U-p!ORbKdW;Xf7}{x0;=>xUE^x#?t~d4dJu67>7jH3dg+ z+bP73>Vl15vf_TIxav`%PsLkezP*bV(~X~AtXHp1@qFSzr^ z0YV&dY{C8azA3bcodwUrK8x#rSMdCB%rpDAf)~bZ0j_>iUbScE%d6{%PYYgn1NXfd zD|qc)(CII~E_ka3`fBK3qfgND}9uxu5B1+|7O(KHd zH_G3;M5TL#dxE>tJr8i@@Vh7D+93R5xj0DFi4a;0;;&+Svjlfl z;yMBMR=H>6K0Y@KKXE_)o`V)A;b)n<0{_aeZ|!$i;lE1URgTXWgflsF6`FZ$! zGM-kSl*_*=@hzWXTT|q>Wf&uSSb)E0nSJSFL@S)bWPCphZE_UT@t=CO41LbUryLb$ zXxuRYzfZ$m>M8a=FKM+wh;{D+oF@pjBIC|boVWMEKo;#lo+tbD0hFaMQ@Hqf*i zBOz_t@VQzYV^w1Kqz%t>;0{Cb3MJRX@M%D0Q?Fb1#eP6=~@`S zSG()M;nVS34ZfX2eF}XuU4F{-Q2cJ`q$x@AP_64tC8nR^EN!m3q3 z=R~m*TPq>Ix+x|F5iG?;~|y9e!%+eNe=Z1V4UDl;c*+ zIE>GV@l6Q49t168u)Wm29ZDwM#h|g%T0x(J_Oy$JC7q(%x9Re8T1Ukbby&q}>M}^* z0$q0M^xyoj&vAU-h>=h?ti?F^ck;~At*X*=N6R^M$<L^AmB!wv@V}++ zdY(lxMU+na4_DWc9QXcqtA=$=v}CkYQvUuI)~f}a&=ujKwhgPhr?%?< zkJa6~Iseb_g3{`SworESzpF;bUr_u3te6gj7ELps5i)a66?>AcMxY&{}5>` zhsL1ZpeBNb0op5rr2$65?*rH-tV9K^1@0XSyc&R(z};dIe(Qv;h=~IvT2JJ6j#1%l zV(S@bi@Izwu8H@db+lEDHtDAj0jcS& ziNtQ5QWgW415ppr9A`(YrPkp8A6@&O&or5`{~djtUIt4+b<6uLHT7R55;TR#M5^!K zD%#_n9hDXB!9YuCWkpk@Wn*PUS7psy|J-O~eJmLDw??A=IlY4DoVT9b#0veG=+*gLe0T2Tj~zCU>x!Gpnpl^m{3PYz`wM+ z3E%qb)E)kn!DuWL3Hv9G_XlGB^}&t~UirX+`W5~K!Ei8&p{03fk{=W7z&N8N{zD?& z{$@M%1>MH{kydtwiReQ%=dwH)^j8G@?a^TC ztitwqysNylbp87EC2isEl1Q|z)VRO2t*fJi3sG3PCwEnp1}Y^r6WWgHjdv;{$qtq* ztt*{aQdSxQ2{)9)H^fy3dvvSpg{$8Zj0Zv;=A`E1qs|DHJQT*aodMFokN?Npv2I<_ zNLw_}>F??Ya%I64AR2fDtI~vDgZ@CgJcT5&qdV|blVUiI+ayEEHyo7CC>60TELAMN zu_HLE5NsNb7so=!1j}QcfsT%ug_VsQPb|_Jm;4Ey)L8-~savqL&VNwc-w1A9ivhMq zBc1+=QZ`tbKvR(P=y)+EwIkmN&{jp%&-?Y)cBoJNeUli!X_qtRWiX-5!rXC8d3;L@got+fes<;wqsWeKa z$iYo2DKnld>1_ol!>xf%_5YIQNM~tBpsAF@iIv7MveG@~l3rUf>C`*lNV;3XYSFh; zsr6E+>akZXa;usm-SL`Gpd-?zA%rUCyGKa4k_fX1t@bKhYM2$Vuk66@Xhs|d;B)r_ z>Y4)tg7}!(OqQwCe%HLU0w>Zn>B$gH1BbKA38C&pw4)pIU^bTw1=ft z=ov5>410Gx#=;(&E2obperllI?gek7%-A0?uk&f=p@ScvW zIuLFSb{Nk}`ZRY$fQ}?$YLQwPWQ(^$C;NjNg3a9~8IJA_MmMT{Qj~Z>RZGh?th>^`=P?O`PU$6G(s6M>rXbP&j zy+*w+EZo`Ux-M(Lg91FVFFho{+xP zsqSRWCPNWekW?M*)L(yHh7^r@>Fkf-3blsDs;91>Va${vNi|+-x3pT)k|vQmrAEAm zrq-Y__s0A(y1|`V?w3*tl6z(*aL`mdGe`0hTUv+xBY+&!ht zG)U!X?L=UI7ACjET-BBH$T|k&&@-aqur!ripb&gjDlu!ZVkQ3hp1H+l~oH{QW#pD7lEu4t1h5bu{u~?uD&N_W1Q*#HyZJ}_m-0K}ZA?-Xy zfkSAb7UJi030%rS{d%0fb7H=}@GoIo!v3|vjXkrT_A_@sOp6$WxL^Xer6D_oDcoO( zyTB;;sWwizMM~vUO~UGn&TZX9#^oIb<0?C=Sk8KiBqWFwaS)CTL}rEk(5fAF_l%8WF<(p}+S zt&|Qw1ScF1;dlCp@~(P#b9yT!{zlx`xUtLl0Qa;jI~eCTDh#8VD=~0@A+D4; zgmSt%0voL!V(dXi5EwA3Ur|@5-=1D5Gu?7cO<{3!lxbN%(=FH6x|>r-d-o7*s8B@6 zl}JgE+*Jj0X<34PE5adQ0-JV8Zw2}!amf^O6dt)iX@{{p=|QrWAqa`?h|x4{8 zJ!|PtvX0VDYM1xlv+)#N<%T5dY+@YAzUY~3ODjP&A;OuGFE>h6 z-`pMuw*_0$@|3pBJyhxuB<5g%N>e4L^2p6lskKrhQR*IrAm(98Q>6K3j)1st8PiNSr-gD5r6EQlPdtn#;?3*z()K|FDJ<_$NVjwbn&WogsX`RW$4+|J|^(*?&@Nc8$nA%s`)it z6^Xm0g0j0Mh$q^tJ)?`#w`m8Sv|`7y8(4Ql!@&z|P&L*R1Y&@;39N%vO~VU6;eV!- zj;akqPlj3$aA%0MG#m*R2R9%ZO<>EAc{xBJg*dmWs|ztN8Hm*~658-Djl^Q1rVeV1 zPC^cZxWWj+M%%gxOk?G#&!fR%_F#<32YN!BIlcmYSHOtAr#6)^l(E#{#j(=jVgz;d zIRRW8-5ml#M+D9sR4?s}lkLRO4t5VPF-4t!r=_86iG&0l{VfrUA{?Ou1`?-^0c6P+ zMZliaa@1#*|CCd-G!Toehp)=VeAS^YaD>e#8)1J6&4n&fFFLHiah3t~~g zja@yq=Xd-0oD3!~cvJ)-FmlhBo443((Yut0Efy*|MjD;ep?Te-Fdd13><`6aUF}iC z?;Yo(EtCkHP+}&8Sb2gilGFZ;i#sf>hp!(-^pes{jzyl#vZ6_nq;L0!&m& z^k3=csxTcbAXS#pe)@bSOG#~AsQiR`{F>WnLHLmyyHqsA0Ny3u+Exe+_Ne6E zlRtuoqKt(zbih3@sG2~B@^qD_0(E6PteBoUF&u>Tg1y5I$2tHos4LuN-`COi)1;()}JR_4!IH>(YX$Vkm%t}WJ>_=2HSW{1(n8=y&1Jee=5 zB`Q$sIYk;$`>IYr%QTP-+D^nj?w=bg$u%Y~5tdDrYpwiKE4O#L{9a}W>+V1e?wx^g zQZAf$YaUzzFZ?@$YwC1L&Bk-Oe!-KoF)H4nGKDQflS)M*8<>9lRECuEG0Zx9+E2F1 zyj=ufahK@`;ddH+D{GYif`L{-1dfDl(p&>pNNH6_O37R$eC9;F$NTuS3Up4Eqad}c zd}Spayl)!*n}fCu5Wwdco2tkCb`!4*KV@ttr4IK)@?qph;=bW>e90idh$LBDq@JR- zNsk)2Qsjba$py)6+K{4lmM*W{dkRQdg$y~1X?+Bnp7HhocC}lTFC@`mitLWp4OyUL zyd}mE(J=^H8Bz)`YHEm1bE`YJ4lzQ1JOo#UA}zP)sX`K@y~JA=M37eE5yQGDPbuaP zc6Pg7vN@N33 z%MgQU)v}fa)^nwt?;qv_|Ir;4g3+A#Rz~EU{eBU%$KtzO7snT-oeC)zY1=Q7$ZEB=9$E7~^inX2HLd zC_`gf**?^2iJ;$-2Ls$w`i#vL$T({8F$g(EYE4TYsJte-wv^gYmv^*^o{(W>*OkmE z!nmkM5?z;i8%#g4x;?^>c))Pd3BEB!Gf1FE6UL05Fvh>WJ=EMTvr%*=q4Wjtk%}vH zMMI3uMI<~Y%Y@?6e)U4assA1c&7~WtPeG3|=o8q3wHqK$8xU>SR?KWRv$`7_8=ZU5 z&P2riB{!iZhIVYNN$O9A!&Hiu!iEs6l>BG*(ogamtbI#MX=i8YM*MFNdStd7Eefpw z{cpN~T;~P&OP+Ty+t05-^aqI<{&06^Q!u&*Z4V)~KwBvxEwjxmJxsj^jg11%HIm8G z3WM2jzAj~ZzJw)6c`nD48Ka{Coh3nu0Z7y_AuCX8xek5jZRm=Gq15SmNC$2YCNlzC z#LSN;QZOu?fi|&&VooD_VQ_=LsUy;~2W^%>0dghPsiw&oJ~>Hglb+Vq%RcsaO-INK z%5~6we(1t3#hHme>J%p%RC=OQ6uWb28D?f_%2U^N( zp^w!9!}<|v1=95Ha}UChm42IHw&0$N?XwZo;IOCRK#kKiB+N7pOTtMrr_)y^ z*+nDJ8(yT@g;mo6PXel7~59Wa=()l zV5Woa$Mb0fhv~Tz%oEX0#7`^kGNTIa3xkNvzL1_pm^(reWCl8rHQ2II#RFxuIM&=A z>pv41X~QwjrM`!Hb|N%#F^Fd zNk=+X=${2$fiU_=tH9GO%Kw{Jnms!mlD}y z91QSStCJYGNK9NIRx=K6GnmJ5(Ty=|5!ccPTQFab`?LMPY+P|06vJQkkOI-60#yxo z+7?g{i)$j%YX-}4*TBeKv84$ibE+#64ZzdqteG}H+h2v)fTV%UDQZIgc_gM>ofOub zqmv+Unig{!%VJE_N>Nm2FRe_Qar#h=F$S6{TTxq2%P$SHcG{2CQoBe9)hYbt@p8uP5AF*DpC#odTFbOspwOwLMETLaG1XiZAa z;J^^Ngc4>GE;hFURL2Y?a4;2=RY^7J#!9*= z`b{#aF;Wdck9Q*?6=;KI#x@StaP&kBW0IqS8cQiK32pEmqZ`;t)Pp@GSR{+=edd|@ zcnJ8ElsHp$uFd_MBcq3D_)_=FCI6=BaU@+rwVH;cb5`7yY#S_rH8R0e;rN6OZDfiS={Kjz^3TnO>X(V>*A^)3qqy_HY_YLD(%Fa-3pDX~A@|*fWBuheiS+l#5h_PO1?|Zl^oLdWj&>QJm~G0O zCRzFDm&6@21jAu^vAMoB2=m<(Y!2Y0ifU31T$1NvdW0K~EyM=h7?rz3$+mR5#gHnz zZm?x5ylBSOm4=u3gEGSasdr9XDF*512&~PWGOBTN<}#tm;A>8xxjPy~Ad189j%_UW zJGQ!79_=TeD7iHNxZ)!6E8Qsa5={pWrTSIA6s{@+YyfiVc$C&L!Mvq%t0YOyp|v9@ zX<+dt?2nsLS>msaBLzc&aw*c71);mMPGj~VnU}zHk_2{ywpP5-i=!(Q zOWzn-Ql=VU6)ccE&m2m2jgD;7H!%dJnfYg6 z(bOgPt_%ecSnGMghv|rN2!O7Y`=(=Ub49ZOA!|DkKqFba^Kih|w#TNL*dPHZ4JQ*d zAxd&=7HRWGPuMVeqQ5J&A=oiCCRs4Kp?owEh7b@Wq8tqm;PpxT$X&({`z3t{Yif?v zJ35SGkMUrdE{sPRi>iRg!XUH70eXwJk5yNL9KNu3SAg!|EJXv&$SFzJr(887RwH$p zIb09-HRYC4GBGBmK9!&!sI#H{u*bywPGY`Sk?3ftoJ^XP3NR954cvI4o|VxNiM*su zmAxltINA>-OqWMZ6xc3@BZLf~jkw^D2qPo9hc+I@sj~}f$IomTh{@XuI!3-LZ(7L1G zXEM4IO-3L*NJ&&1J4WEkjCh#T$ebGrBhcg2L>MMiB6ZBgVe3!M&IWRHSCr)kQ}ceQ z`(RxpLRX#yBN3#SqTdvo*LZ*$l9Dt8EXUx?HBa{k*JIK$U0*`rmY~F5$?G@XVbq5E zsO;M~AjKxRgJN0o0eYYGCZXNOl{AIIj_R}whK{)pbO+Q#^~UAG%9@UnA;>83&TYZO z!DiNhbXlQ7LX5J>=w|XH7Nzt;CZh{wOohy41u~88VA-Sm##m_!@%R(^mlzgf2+9C} zq_qQaWRyn1>f0!aIYVu7YP(Eow!r$yEKSnR~r@i8tN2$PxGrliG_+P{1RRIKjsCgR2Sf$?P&)z~Uzj@3VR!%K;>k$)#f2MoX z=}hyu#K>7PQ`_TZWCiHu=-2sZACtH#LhBJmfjd@#2gtf(38b0sG5qTp(gad?Mvx)~Bxu*I+}L}o0pfQ&2IDg$QL;Xb;1#*suPez0n5lr^x9 z696NvII`|o3q%r7f=5Qg^h7pV_;fDOb^p&!-f2s`bT6hH$EJo8dpv8Kv5JIH6WA&= zfc&XTZc2)bY^vxbW28ozOD+b6?^R5h$v#fkyjR5C{7Xc6$aZ3E3_>6Vf*h_k7a z0Xj1nWxRAeB28|BT8E&SVLB>!YGlYTJ@mgqI-)W|Z4r?fCr21Gx50d!6eJ%v zb}i!ZFK6OeA<9KPkxM~Hnc%$^IX^~Nj>J&~AM_}fw8M^s>IawD5OSQa~ zr|$wK>mn7dBYP=7Ljl7gSSce!MyTPyj1qOckB85|5+(j+ zD48brP$%N_vSU5~lj1kB44vd9)u7y-PG*E_%s4%b1Gm-n$O6cdY%oZ)^r3IN$c)FG z+&5AM>>B_SF-f#cC&f%viCWE3oXoXeEaUyi`8RXFla3&oCKFl2qRdgda^f^#4G>*25I6DVfeVn?fQZO4 z!Z(~^@^|UZ;3y-QCiaB3YzR>Q%W#lXaEDSo6g^I&!ou%%ua$qRfREbvw8+bEjEeqt z>tTUj6(~_pr^Id4b}icYcV}hMj%-vZ+cRe>N3Fz{@eO19#W=8S1hZ6~SLSi3FBkW>KDk%-8lCw zC$_GRhZ|VdnJ3H*Y&>n;K~XhopOF8+t@vqMZJd9gA|r1Yd?_(FKC}3|+7dP`DuoTZ zHqC2gvY;+@!LZteK_n1JS^X}v28^(wUxh~rrFAdZ7C0>N%Y*3wd7@kz2B0Z3{(&}m z(p)M$e6An`#F?>>bba7HHKZ1Gj$MW)Rn*c9nV>qL3b4qQ8K|@luA^NU<43K6lqjch zo*jFx>J*!?Exk4v>{77CxJ92e1}g`E{cPl$AlH~=h_@quxJ_kRa?UZFb(0}v*`ZF? zNNcN;Iub8Qb;QL?+#aPm!qFBiy9!ZQ`;&xxCR5=q=3hzHhee`r8;oz>gKsT2E7b)v zlmzcL6pvj=sN>9bQDg1{v5iVkO|*>mDE_gM#jt{0Tw^mghSCIZrgcijbniAnnU`1* zL`iLEeHoRNJQtNE4;0bw;i6Q{q zRBa4R1TtCr$pX_OSS-dFOjCHAu+IEF>%vIrL&r|@wT3XZ=OHi}nts1@;hqm>4|hh2 zdK->f0w>B$-1EVtxJ#pY>o%PmwP?>f#htnngos@!7G?~1MV_I9r2;N8;c`iDgOPdv zrT%(U_=u`=2g%;S-q2zZb`lyyz1jV^-nvH-9n>sI6J2u^CgC$fkyyy52I__dKAHGN zwUQoHsQ^g&{Y5^V{H<{|z*5pgJ_;i^ZP5~QO_Sz=W`!*(g${QLzbhEe2%RePN`qry zUOHUWXjyrZDw@gdO9po2_9SqUD)B@$sd9f9cPA#}vn=VV`>43uk&|*m*pD>}_Wa+a z92Gy)?^QaNf%B~%l_O)ECtxi-x`U)9x3!r7HeZfgr;fy29J5LdQ}r|ymNv``Gb!vz z@n1=Vlz?dhz*fa-quAeyqRuS#sQy%@Q^FeizIPMcNhV{1I2>fADO36Zl2FME8}ts=FCl83aqtqycuh7=dJO^VSm9kyQN2-^jJrR` ziVAM9<+AW-Si(sgQ@}HeWOfmCXo1s{gXEzyZbMmR%Iv8{Sw*TwS=t6ZPd?8knZk;i zTFG`QghQvWSi*G*qmf%L9Tq&v$OW+<#7YVb-9L4V-FjMq{p6=j=SQ-swaLY4slb_0 z|B9}H{b{O!i83ZYK_w!kKtn9?n|<`U$Ean6EeUvT&W$X%7&lX<2RLpiP<*WDr!67S7*&#p!TMV(=pz~}fZ z_Xk;d#HdF}os{$rLTfSLe>2tAURQFss>7}eqnxZ?rO}ofi)V)_2%gS zk3+FAHhx`MX!;JG!%6(VrKeZWkizKud9Vv7+8a;jof zrmC~$urT2jSshCJ(<R&6zytX^7%5MB0Z7p)|(mykjIU5wzGSZZ zFTe`93KgmZ59WI(yk0<-k5%=N_!dLnMKon?|0U23->7O1jIgOPuEi8ZDV9cASBCNz z;(JwdikYm;&QWO&45}C-VuY7ibQnG(8mz&8G?E5F=Q!;6RH4B1BQsTu>|3b^wyRW( zfd-lJ%cEd>Rlr_+`|lL6CtF3L<@>j`mf?S>XTK^C4MRWRO*QH*C5=+X8K6U*qj)=2 zhkjz1AsZPKM0rqISRUY0orOe&Bj^CWL5ZaWnMBmut*V1U)L6t3r$Cm-_YAQ)B0>c( z@wnNjIsyWXg@X1FDD2ipu!+{GzltZdB0RZV3W^Qsxsg0M#FQgfl}!7R8YlVAp%R#J z<&)pZX}&K?WLLGUrhHhfH&AtteZhc`#}U%|=Bsr{l7TN?&;g^s&gP5^5n% zLN9~Lhg_t#W$207`HwI`8Z>;axR8mBYF^4~*|S5r!73pBv0sG0RjJtb?*r<#H7w2zKUeH6rW!XH+MqK|A6Qf1VuPuqGv%#y+=JS}DwuFN7BwPVrb8SPzl zAV>O+ODc0rgrWig=}QjfB~->wJFS{tke~{!(ziA$*Q;1Zf(|!VXrM%h@gy~qw(||W z!t{i0q-r0D6{W*(Y@Co5YEy=3O00APg^$l1cXEwrqB&r_fV_PDn}k^$I9x_!${j@X~0`L0M*gv8oB@$Rck8_K-aRH8FY1 z-%*yzPDX6eiZQqkRSof5RF;7Wp&X2=pJqS0D6OyFqS9?Vu&LlI-*;V$@M9wY^a2T_ z$&%dI;3BXbklNMLqh=fv{nwZ^l$e)QIpc?;$(Gc06~rx7|Cicd~-&S=D99PAS4gLMhg>==|r)7h*r@S27HL6J(RX3&6 zg6v7Y37zjYwo=ox>v85U40E2gXE#`Os5Qo=i__hyRp3spFth>IjL}7|9q|>9o)8V` z!3Eep#dkHZrZ^~%Z&Ue=7L=AQwK{LLyj$TcV#B%wEQmLMO5vxKwJNA6o6DoTjOHa< zXXQN0W1JY9s?N?WHMJeo1K&#i^McoL02Deh+Fibd+{4e>j-0Lq!CHPb( z=I1oPHvZLjg44qzzVRikK%3LawRM+{b3}fc2%bk8%e0TZrfXB`c&ZPoF&6$I+Zn8; zn9w-g>%<%?IPJt}YT>7tZCSgAYJtf{EI^|Q_%e!+ShmtA@2p}591$ZM2AdcGXe%** z;L^TBw??6L}0LL#Qf0@YES4Lv?>ubs5K=@u!Rchk(ra+RtXI8f9xM{CgJY z<2?)!OGPOgw8Csj@I)I1T;n8A3SSV*F>RYHub`|{0GK5mEEV0L=*_|3w7aAjQ(CxU z642smz*%LMtle*dVYbT+1>5!!J~b-v7*RB?AYb6k^;fAa24J@o3|t4jJ(a5pI^*w= z9HWdTsRGAVh7?=iD2-K85Z-Pm?E(JtO}`3D!nNS}v>+u<84rX@QS%<@jzJtT)r)%? zX_%cjGO|7g*~ z4yOLu*ij|cF)V3Rx@Bq|3vIAoJZ-LJzgU;r0YIu{kV0crDFegH3{%7Q>OQB;D^^7h z3?+sZ@w`3$VFfWQA)Thk7}B?`?)v_js70zXW$seuZx1x-dE;yF@UFq!6v zMdOfZs}|rlYty7p(LvoT@NFKAPT!SvxtY{5G@n)!0F^v%{Wg)qr-8*FZ!cChUB63|W6$7K-OE|jQeV@||M zXX4=@$+J-8*zw|_BJRPaA5bNhY=|BaV)GVuHOkP?+cHq8dh3H_WGyb-m!SvjgGq^D zCNjVSQGrqa(3xQtra5k?uq=yxDeO)bQt8t)xitPdu~MAq5%Tb%tS%DaNgZI)F2GXK z#VGFKJe0!3BX#J)z8l86Jys@`tUnCWa_5>Q{**#+Zg+lSyO0jz6Q)I|sU_Nc65F19 zK_yv@T#}XMTK7|ur?%E{7@>Ok%Ji#Su~(gwzZpSKPG0Gs)TNQ7;ymF|;3)bYYST;A zOq6C+@{x>b+DdBlK}ezqUPmm5urJ^2mwqyZX`3|}(xg&g37h?0idYMGw+9)=&4As-g87)ZT^JLKMf6i*jze3R+#F=eC^M^SyBXQels5W~ zgl)!=4kHc3p2NJa-Z4NX(^G*?;VkQA($dcAKQ~s6vzwkcyA)fc_8g472%F_H7eyCM zWu2HBkah~Adg+U=FSOu=VR7YKTi_mr+tM~%(@VpNlQ0UaQ59PgvY?e=ZuNp`Jx*z% zN+v@~&M1mJOvP*@V_^qa#;upjn02H6SEH~3_Ws2@D4_c=#B~x`)z&Ycx2%y7$o>o&8?f~ubuC&Z)o(-JGgdv<8oP|#E~fv zCPoBBmH%llpK0>tI9Fn1bz%j^f&M{%84OCKtu%pl>RZfp;1X;Uhk)c5LqW}yl~r{s z<}E*f=fOZ^No%vxU|NE2HaBoBV$-%0SJY!jiFV$A)GB;!ZIQ^OU`!FjuL1EJ#8Uij z5uWIRxKs~#r(GZ`=svjtFFIP!$gSVL5;e;jma27-iJ4)TN^5D-FUJ2Y<{6m=^Dw++ zp&myr8KfI5uCU=V*cFI(dGEGjPZ3M%01^O;s$?>soC39ldLAfow7ePdIJ}V~ko2ZW zb??HxxK~z4acWlr83b6?Ozyg<4P*Qm>*o41&*B$5A;mJOoc!&MRpabA$2q zEO9BrX3P*#vq;-;9|S1~z^NHooyAHF@K&pgQQf|zZDD}SGD|8ZWEw#?tMc?XwNXyb zV`_#6CNYZHUaqY2178o|q{n8<(lpEc3Th2(6v^NPk4};=tcVQWCxJRgGCOBs5H*CN z5*j+sKVc=kvLX+cQ`Y0zgC|mI_&7fU&fxJ~4!8~*(u@Ea(26q7IHQ$c(`NxP&-n^a zU?*&_26|?!0ZHvL71Vm=g3oA+`N2Jso4H+#I`%%kygI)5Z4U>R*l6P5a%4ljj;xO! zS4pLmk9)9^L^uuKCQ94jrAboHcrv-ltg$7-Ys^|u3X{<=mdCUBPc8*MC62Rl zP>k#X?h*5K%Y^;N0>oB>m91s2gM2!Hsu>hk! z1cM5rq(t%^oR(MCe+6Gh7eh8a>n6?*@nxz#ve}#-x@9!1Un*#}cWg_?9m1{=cvPL* z&I9z={~o<5XaL#_N;}2#2TN=(3-ZFj9u7JH)0-^mDXNLAm#QQEbHp0Gzho%=^X!+T zfo3%O%_v&Y#kr<=DnW1Ojw`{j9`*i#9-cvKe3Oc*tE}>8t^RW1fg>kCh7x*iV}K0Z zCA}ZP9Jkk`th735hL534))g*O!01FV@s^^M)G$6ZV(DOFvztL&M6iWEYrnpXJ&(MP z9J#bMkZAlfo6DU?Lj%>L!;O5!cXbFla%V_F7@wV0%_otDWr&5-Lq$pEDaGt14Wz$e zunhas!+?e+wXIZI;=~G!_NZriXbbN<2c-?Q$AGUqz?L+++}g0xQ$4hloubvVYGbBG zccPIOEUET;EfA26XXHy+xuQ-F<-=Appq^qv@E|w%3=`t?Y#;TkL$^Nt=^nc->J2I+ zQLRq`VCaE#Lz5bIT2P+}8hU7GP%>ml8c~5AIP}oY^fcKK$$Ffo*JeO$dVC-)x)PBj zCGNa1GT9KV6~ho!+RUkM6;7AnZ2{Z|mZs0?@nO>Z(7s8p5n7c|Al>Gh66-CJo>Dzj zCYh@*|I%G1ThNqmy0;uI>zqh-k$!Iv&kog}HKH7R=d`{_WRAjDv??0t!h3$rx5+t< zLwkE~PH4zD5nV-ffjkVz#xDPo_Edc8>UY#Q7=VXUH2eAS`z2zg>9AdtHt z&#rXgH-5sIw1|!RU*?G$lN;W0KC>ZD|H`T>LA|0$7hcE`i~=#T@F)EJ5QB*L1ji*= zB?DkB;9pT+doVI2+PXUe@Sx0-l+0ia`YQtdc4SY?Dr}F(yJF>~rNMB?`q0`?QzWuB zRuYM}mGZCBW$N)G5zy8TV#W$9^$%@=Oo+D1c)FrAP+3w@+ErPRax5c_kPU#IGGiPN zn#4G9&io=yQQr}8Y9avzx#mymK_EPg#7*Gw;(?as4f6UDR`|uf+YymVbQ>29r7*j0aka!V6C~CrG1T4_58X^e|18d!H$A9Qk4$W%g+o;r8FvavE2jfyCi_> z^8O;!f`$iXyoohU)6BS}f`_Srnl0iy@Hh9Yu#V=82J21Av!3hQBY@HCBcN~(OgYL) za?k;pK>62;ZFOSvmj#Pt08)madJ>XoFq?>M-YL*3K~!K76isdDa+jMnT!>*II^!U8bzjT^ssW% z^{#kM%&3ND=|Cz0*hFwX*SPjbR&2=CZ!SfMKbz&SQ+`|H2Jo<5H_+(dKiKV zMMxg(Z3vhz^&SDrUJXNTDPSBu4WpzNN>EwY=wb5Te$Ml!iy>*y!_3R}u1g!y0dt** zZg$$!M9X{Z)e>1)4)7hTy{A%ptaJZSwXx8$N9$g>H{Oq7VF~ys7C}ES?ajr7@0v zSjkz-CHatvud3$gq-(>8Xbavb`XwQx@#<}|>q88M;stAb0;eyChkD>aW(k?mc2kXI z!fnM6_*@_T*dI>)F}4*^FG^n|U3~=~9Y&Xc z@>R-mfhw|J9b0E}*`aYvFhO^gP>LLHy@gRNDji%h48z_E_wkI0WnuR%Qb%vorN26M zJ^)=0MWZxeDpvzOwMqV*qIuzFoOIVyU7SY$ALU!84k?jnGTFMfo5qtndb>%cS*PA4 zgeGuUn=f&qvQcpZqhuntd%5jP6-38`DHQfIpp-MB5=t+hSAIHEsTBmGWbqyq*lgj+_giyl41r&NUGejYRDSoL#-4$osuD8`g>K-y-$ zkE=p$m37#|grb9k9+5$Hy6iX#&r+cfXZ4Ne1KXs`K@Cr;Me=`46#kjilQLXpc+~@adoV1nHpmvlo=kAmhU2S znwCNv=5c#fWz3dlM8R3xw+rg9%VA1}h?YvnpaIC%$A zmVy|Qua9+<#J$g|N7`LcLRNihy9o;4Tf4lWc>44yGm6s-&3pj#NpcyWS;1xYJ>ta4 z0_niIrO|sP83xt1g(MKSv*35L6an5?k3p)sdZ-gC`IfIW;5U3vJCQmMu)%cTH<~LIM=~(K zF?_3_CwbpO9rok-DliR^wRopHir)Ae2%ce6Mo;RD`PZ}TRtzU& z^j86>bEB=@VVIvtSUQQRd;)bjF^TaRc2&6{N^9GPm#iv>)S@zhdN(@{sp`e+dQ#5n zHQdAkoI10$h>{ULlx`7hhRH#BDm1k`)EPqPI_)as>YoJU38x08F`!JaDi=r41W=ECnhSZIJR>ht#adx!=baJ z$E+~Ckt)pOVU>Yzp6-@CBqM#=8-vZ1H*8szjfieQa3Dp-0r`M_Vw73gElTDXodysK zDWC=%0t^ORwgGRMmI5kE(Gc9RWS)8CI;4EtaCc`D6WCgHu!eV|Gme{HA}{{0Eduu0 z7!JqJ#P<%^mL)~kS{OoxMDQ$^c8YELwQdhcX1=k-D2%Vuj<#FYj+I0V#pU*`BP$Y5 zF$jtiuF?~z!$_!7S=_*SkBkp5T<(N+40g1rt>DzQ5^Q1SipKfH6Q(+=lY~1xymPwq zjc{gK-L$^Z!5Gj)<@nKPT@P+0{p)X@z_aRNArYj?WTHZ1KTGWY!HygxmKFKKZ2 zG#(7-$IzXu4ihV!a1#A3kR|CzX`V#|{XAPQ;-OBQrQSrhN)Hd4cmRu_RJ0LkQ-Mth znJlnm+MgjffiF*CU~{@V8is1cejjlRMa;VduYgjA`(%0*lIT=-#9TyIW;5AEXlL}q z(QQ>o5At0@2xeJU zqkmCVJdQ}FpXcP8@Rm+XQpTxkRknKPJ<~zt3+?A z-mxN+9US1mYXZUg6iJ6(pI#bjm7vl6FjN{GBx7>1c8$!F06S7wy83Bu-iOknrYCu#fE+q1nUGB7+zzIE#FJ3CYt;WU}5JD2%Rc zG)9LUyy?$4b~eQ742r3juDB2h>85DD=Y^03oqJx0`B+@cXx@fkb2o;jAHhf-5Yu^!F%+{_gZXF{ z9%UT{r$I1@cNC_8SJ9gHdys0Tzws|g+m%VZLy|HYEz_^?yuD%{!|K+nA*_?^{fhLc zdNBg{C>Ehtu5_BjNU0SW!m-DqJw*$H9Wu8#`5ETC4Y6#EIgP9$WtW_$omd>xm`ITn zXSE^4Ko14lI-t_0sFnqdaE`5q2{18$N{lMK8ggtbDucv{Il_FEA^w@e?N?NXSJ7L^ z!D;x8S`se3u4Ihndln>BtyU@QG|h6aakwrlbj_6FP1Zt*Bkohg5(kF9Nz*V@rHT<+ zwKN>HdJ;MM;($1I;(BSF-sA}I3nPm-Ohm;gWA&DIo+A&McjE1qPJBS#>5ruD94;4=AroxJfJ^zt5BpLU6rr+#Ug{^7hA!o3r!S;m84Xn?okl%D zxZFK+P+>fq|*B?_w!YgKIz$8H*?7cN3NCQWaWlU7z z;AGh&6fu-Kjh=B51u+WDMXCw2!7Mb`iJCi3>pLB}M92^u$B(H9D;g+mN_|{fd|YjNPy3M!5}=W)Ugvg`k~LP>K$0 zI-e=AgTd-$9m+@>06$GH;~jcQG|tK^OYC8Y>S1i`0OnWr(uIo3q(T^LI~{Kq0d8?5 zG~Z#;5A(J*k3B^z@os9Tg;s|~h+Hkj>M3F}rqkVI3u;s2@P{&x>DeM5>B&51+yhrk zMeRyfuk7bO5XNkTdtY$LK>RnvJy3o+Qe9zxjnJx>PncZ1Z*eisi_fcG(O6r*z+Z)( zt=f7Sd+`<*J58aY$Nolwef${3P+6|8U)o-WCG=WXTaUBrJ$8%Dz8we4=`g>EqH%F#sa_ zRZ#|pc{wJ;0MTo50yr6CGT5V1Ud_~LlSMkKqbJMMWe29y z<|k++(t-LynO(*t5`jJq*%W+hykd(fNF40&vL`FKOD()~8$dFK9TbbHBxMzlC!;Z-O&^Kwv0^0)U{uH# zD_Kz@R#$WYn{MMH^nTmIBk+vyAP7I0iG)a}9 zZJeGzn3@d}qtiJ#CuwLX4h{Yn1MxHK_;Zd@ax-sP)4#}8y^?!kQ49-o$KTOJTktgiY z#G>l3b=qZa{f|dVrAzsw7h+e|jL;hR$70QrJsI^nAiwmSxgC}{8Rj#BPGymT>m;XC zNoir>bc?HO=vO}Jtn;lYC?2D|VL!?`sq-mRODc{}RW%RfP*FW)^{lBMo_6Zp;T8nt zamqqfX62?C6uGX!64e?P(vMsVoG&3icCc>2S_IuDTB;64&k5K zO8(sLHb1;I2B6aTH)UjFXav$;A$&9JsAHBSYi>3^$gJ&VOi$Vmr_oN-JE59M?Z()k zvhP_~d60w6Ze(@?NUOFhocdA6dhC;7n+=kcNg+h`B*b8Nm=Tfx!`{2a*mb4(eML2! zQd1XG9Nk8(mX0W?L`f_bN!=)lO^H{D5=F8}N}|-$qd8S|imX;uol>1DQS6M3ffE}} z;3SCQ1cM|9?7;vY3+2;c;HFoM7cj6q;eUJ@V=Mv#Xf4}Q%5_kHWO_gVW? zkuCMO9ZMitbajn9K)F@uaer8a`bQWDBD9y+M18BA8&%Qe}Fe*dYfq*+alrv?*o_R{93 z&uV`6@02R;g(5=yr1E!z;s5PX*A(8l7)$;g6VW1k6I6>U|uvD*0pE4d3Q4j z#Xdrc3k^KRmTlY9vP945Q{t9I3!SvKH*9TSO6W6}))#9#WS*<$GngLBOKWq(P_xip z{BMg7ph!e)#n>eXSaMB%&zz{PpkS236SyG=vw)jd%iQAqtxnPn6hFB8iY{IluEw6y z?L|Ic*t@}RCXSJ9kEWR36An!=4z9AT$Gnb@4e72OuhH9Lx9K3BOy=jRG{wfA#+Yuy zs`E~Dv)g&-%yu3+yPb!uiCzP?jWykC&BxBYww?bg6vp*63WBJiSu2EHHiC47-!$3I?5!Tk(X}gQt^x zGZpser}nD$o{3()s~hW^^W0HiJA#)@bTulbw7n{aPY3*P8d}$Xq>8FG$kxoFlD1>$ z5-l=9>Yg?i(@CS2PJ&u=(30NP({I=fm3#z!>sl0+nqL-J-c<7Av_8}4<>6HQqlzAt zCaP=AmB0|wyA!*{3F`G4o&?t3%R=W~SVubo$BuCokurq-T=suMOO(KuN5T_cPOFQ_ zntHGdrq&aDUr6iMx&&gvc2f5?t*}9!_tQ&jp^<)jolm9sWmKRG2VELp)iB($;J1C( zkmBjFVM?#p>9K)2lc#C}p&uIzqS~5X9$OO}qw4NS!>Xa0ZL}kPx8w3J zqXL-XUuIR7K9>ysdfH%2TrUjcDZG(6j)3|_dPCv>#283~~-9ADpPe7J!F= z!za;3;bozMzn|^JAD&t7%NaG@JF~8e#5zYwP$#oSso=M?!uG!LK`C z4Jldm^*q&B&rj6LZ%GN_6Bb03G`=z-3`Mm4?DRMF6tg3fMS@1VB-4XP21zVU8T}iu z{gi*xn?9|p0ct>cz)To2o|He5&iMg*`?BD@(yzkyU&!a^fmmlrHK|2Fwq&EY0dd%3 z-WdpV9`YRM(;6d*Ze_9osdYbOt%$r5aop9+7yyDAc?zfKoO)-0p4u9SjAbYCjZ%_& zG$LKbDw;M&9-d^m(kQx49%Tgq5AN=CK-+7j2c+sQdd&P}ZMmCU7yck5yVUc1{y>Ut zygI_!rPBd4=cq#fHQu_`N&?jRxKGU8?={#rPZ?e239*t!?vFkzgGMm>{CycTx_Wkf zUGa8nKn4^Qe2=%RDdxUNk7kGc3YWNtI4n2Y*-brU6FJ9JSasc!jKbwgZOwt&*Agb2 zzh@c4wLF=iE^aT4mGV9w)(p>Q%>+@p4EuLm^VUUGTtgO@XUArJ!e@1Pz_hUXu4#|A zrbUg5S&ohZFzjZI8@=u?u=z=Z0$ z#MGo)NS${L<3vJ7lG=Cc|I(TCHy!f2TUP~|;u(OyBqno;}yjNs)d3(9msZDMCIh^E_{;9#W}uGSvTEfROL% zvDPA=BvL}MWa9N(MG|$*4BGn6uY{mxS7^$3%cYP$Y(7o;a@a84$An@lbf_@QC7oMn z+3#^VUuUwzRyTgOc|)5Aw3id%pNOYTI-z$+SK$2Rt>LdaO5;EY1P=ueXt&d$CbUgV z$7J5NRZfq~d9v#JVh~t|SylCrW$F2R`fOA|d!xIjI9HsO62`$1I{iMo3-CDP?-tSFzVSl$1t6xX8F0m2sy62p=W@(?q%OOo4rkpNI zk$a&`4!$VDE;ECEH?W>~HOBNt zV?lR5?c?4f8UDKET$t_2d#g>cZO{0Be`o9d;`833LX2cB-(TEDt3RDEo*aO7*npd; z4*B0?kGd5_7I#ds0s&%?HF|`1xp5PHlG_4QdPZ;7?$`A|1(w+nUB2WTpLS ziC(2kh}C%@Bg^BTjzOV!b*Ss!3zvlq7nRzt%Tubm;QOMMua}0(62jaH*txj$4aUrh zbQRtUwp|rD|FDFoR@2lNv#S7z$>!DH310*Ua_~J@vaqv*tac=JZ?7x2QIBgAX|`AE z8bXH7`vE%WZeA#*r1px)4}B5LQ7-aG-AU36e?f?Xxn_KJBf)#6}-U zB++Bs+Cc~o9l2>QTVMvys7LpF5)pwWc~*fSc6+Sl66k%TvDNt7$Bx_V4OVaH2AN|W z=K0II?!y~Kwq4?GcOdUVetX)}1EB)dl1pk}Jg~)}`wXD?;m;MeQXKXgMKpIaELKD% zv=-}SyF+V7w^(nd*_%Lef0(2r&^GnF*fu2RDn-Io$y8$FZESs%vxqa zN9GZwV(lTR4<{|0M&sFj{(%oCO|^y)xDy-WI2X_Yw-aG6wU-~-Jiu8k&7~Y%87N+U ziFkQEcWS+unN#&pBv}N+myEF*gLPqbOhkm{8jWj&3XutMC}SthLA+AIY36$splzj1YhnNXBw1VG>jPLiq#rCKt)MGc8f8@qbE}3y|5dSXXLw|=LQN9;7HTe44^9F@;Y~YR#k<0}*PSIk zUQG-qF%ivEjf>=J8*+80N~Yp30!(f#{X)5o?%|dCHKIZ+b`3)gL}}Bu^OBhzWo{B0 zW*XMm!H$JrM~Dfw&+A;(76X+sImgIT=FT0YDo%bsu`==lEpjsXz8?J2;D`9CJ|A~$ zfg^Tq`Zu3FPA%cN{=PGp*WdY$PdHVQdyS#|W1gr$vXJ}~s%S|lK{L8La*lm4hAB1W z@u-z~28xKV3$faiGnKf&(+-cK30_)Xmn!vp-`+B`ylC7Jgq8`YPqq{_Y4L|9FCK#o zgVo#lDV$kVg8tdqc1n)r%4suh3C2dA?2Y@`MCNPWQyyBdru_Pj{^9q z2Qy|WdrWezcD|GdHaMGp+lsH#?8T^UA7XHa%n>Ut>0lG>q3 z(+xQ`77PN5X>}GmCMIO*e>(|8=;!|HAl#NtZ^+Jeq@z z)P!Q@O9T^{t>85Y;nv!4yk_<3+k_+Vx2hy4-&-A8>3h-F7?kC)2-lj3{i7`a8UufB zQI98yc$C6HS|VwV@i^Nqj$tSDGIb=&N?3c|ELN{1u*Iyr3fK^_lx2JD2yaqQ(nC6e zM;jKDnzUATJnkR_-_%~4lw1o_mz(@>3v7$73u9CPk7BJ{jZ)pvFJ>@@4CZ0v3)DIR zRxgq!4LZ67A}}MbaCd6`FqwfkuzUUTF0t5sO!uvMW(wJ(&O^`>Nd{D6U*YZhd+D&E zomV-mabBTZIQje<%)xm=@4WGq{_;pQ`9m4&GDgiuzaYk}%63nv%;d15qqjE?(3s_x z(yI7Z+tAHAQ`jOulGl=G)D` ze;HG;2BFW(=e47#GKgID8)WLA{4z$I`~sRig!j0UFNVdpw$zTcmd6p4>HkQ?^4R!pDJk0kjmu-cVjKV<*s{B6zh0|NU~o;$ZImaRxx* zENzAs?Y7u~svB;oFXb1ysdb>cSHGB=w_1mJ{a#;g!drdMmRyUBy>8=NXy!uP*sNxn@mD4QakDPqi9>G}xb zO}h7m8(Q3~bG@-X7n9(HahNKb9^3NG^rU`K!wCf}=dd`{O zP(xkY;kt&52^nD_xh{mYgr!N1j?$U^VLG#fvERvwkvfZAVy6BkeDg@5yZwjhKvQRr zEoiTKG%I!??Al;mG`teKgIE`;kn3rMB1(5sGb&Hq4A1uISfXnI7B?+kuVDT9Qe7+E zv9=9H_m!@{UJ_gT^3RvKHAoca2F4UliY_9}E3q;6heado40^Z5xm zP^eSRy?(!Z<>Y%Goy>e7END)bf2|`-RyNg@e37;c>oqPg^_YS(kBOepNE9Lw3{5B{ z_I4ivLp^hEj7f|}!pcK>ELa-TGBw5?R;4OUOrO>H$9(c^k|wPz&HCWg{zT$8xyRI`=fjm4R7X>e1@ZF&WH*b~URicck&< z%Y2>2ma5J1#-urnY$ng}fNexGbWO0oIzdIGhM~U(V;YEqPmM3c|uY= z2KBLi)6t{}_t_qdKtfGj4C-4dU)Ras`OY3q6GbJf3u?zgk`(;LIapeDQ2t7Z>iM>W zJIZE2k6)E*Lrr8N_TuzF2d;rMwgJlX@l&%}1fYgh6qisw8fH-fl9!5fQp&!uJw-?9 z_^5lrsKCC<1+ZhU2{Zhpv0)^F8)42;_~|`F&MT{EzYqu>)4j>1bD4bu8_1C$StZO@XZ4#O9+^ z9-h|!D0pr*=Dj1;QMudesgmLH;-v*h++9Dt+{7(izriUbtFi0lUk!> zuv!#IqoX?qU76JI))-yF?d_BN*=x-fo*g6xKfWu;&n`Yy_3Z3Mb#h(?1tbJ zdb`j|X_7`X_+SBm3lisLrC7&J=VCo;M{cj1CsKkZUmqO? zrr#rud!|9@iapz0v-0xOnnP=7RE$E`4)<3ims6+u`1>8OE}3@p*WnZb+VEaw>qp3% z?&dlJ@zQt|uWMqSw}OR`ck6LVP!Y|;?*{ig3iJjWyHJJCmwO-hbwIv*PAK=YQ)q8g zT(25+1FsS2brlrecL)2=J8%L5M&9!@cj;)ss0e1E3gose86v>J^=ojT4F_-qofQ4l zby{JOJ}c)IdD|J}!tES#iF#Nj;pWL+)a)mv@n%7?(FyMWQsI_I^Su%@AAxE|)URFb zS3JpZlpa&eSIoF^T%Oh+j92Pj4Ms&fwQxM-o{L|IJ0^KnB*5q6%#oZrp_Zih zlM*~Bi?FY-cmLb!>Mrlh-?)Rl!(iH;mx?DqPylk#P=XmbLX`;N`dO@aa4rv#O6^Y! z^xY~1M!0m~K+y;fY}EQa$8%ONX|P@m#NF)Ja1K#rjyge5iO-JrSD~^*8VD6ulm87fZl zmhEs=3H{E+X|vB?CLTl#I3!MHCiz|qgr+EviIkWKg;OCnZ_4qYLi876&2k>n{D^bh zK>IXbR<8HydoVW600F0hNudQ1AmA2xwu@I+DcZI0(Sj$Tq+X4-@TGGx7nUZSH zee8sYNql4U6+#AbBcZRY#c?6HJ7N zlL7+QyJ-n#%?g(^6`4~$o!;RK9HulI%Kp^*vZZ_xP{+uwEm8I=%$whrM zKH4UU`9`#^XwXbdsS~%O@4xM8Pqj}Fntb-z}PN_pK4UXK`M zbNX&hy;Po~%*;9I89IgfYf5FkydZlU-s*svnUitrf)D(w0kkS+*Y^mHwH*d1iyohR zSLc{xV6MqbN&sZxnnI|bfA_7hm=u06}>h&0^wHxqD`SQ z<({98ztKF*{4&NY>#%lu%V|9D;~4pTO|u`B#}vJVld}=@Z(hsU;8}{-TU*kX(tB

r(eu1Lzq{I zw`I1|!=|sc1sX$loTxrb+20ME87tKDg8$J03D)`LO>4~f(QQOJvi!2B=*Id$zgF?= z_o^JUhG*!%d|tz{3}v{UYr{?KirQoJ4CBRc{PI&RJt0wx>aJO-V>LW9U~1AW3ys;Z zqEhpz&!tD(x32G#09e+1{%UaRzpmnz()koSH_Qq}y?56`V+`?R-AyX~{3UQ|>K`PW z8uy&ExmRf^U?Y&khd15(KRXXA;vhOD<1$z<$$BV~{{oGF*r5Ahhe$Wi&FDM^7BS6M zQFIUaZ99v#{_0@4SCDyM!F$RLslu02FuH<6J{{`&Xj4j>ZYhFbi)M1zzWS6jpIGTiRkE68(e$MbL#{0w`KhLG`JdRs?IDg+rtU$UK(b#*l=7@t|1Bx?J)4 zS)a<()8E$hRR0$2nBVlLIV&!HPqFZ}{%5ANX8qv?id!OTD=5+dnENsuQn&$FZ=!PG zF~R(MRYK)@Z6fw9!P;?$cS9;dcqV5=120!>$6XihU~qgGS6gaubNq!KOl8q* z**f8QGtu-Z&^W^Cv|~R>&M>OKezh5%x+KY)L|b2*AJO1yZ75G3c07E})5^VlFiyj`8e560IpTdINwN^jb+A%ZG9%^K z_di&vswdv<8SDdt593~O=bBCyRl_MM-c;_tIZi2^OW)`IV9`uV>K~X{+&yk>=k!Lr z-p>=fa&`bXYP2m+>=T+D94ymtgyB=atM{MLr_M3ng<7^)!#?8;&R^joxzHAzMQQeS zP&n=Ket`r0tt^ZE#&B2>AK~f3lDA4;(>1yhS2|8QsLv=L&r`hpmh#VpJj%?Yud;F& zdM|SM&Zzghy>sF55B2!zn}hi;Uo=HB^eNM+1ynR?S1)e;A0*7kVsbIz0Ew(IW}!IS zhY90n^cxyrFHX3|n5OpYJ1?j3x2!{p{B+l*`nvRJS)%5!etXG88w`a?e8!C)Jdh>_ z0HU1><47)jWAd=JF|S^7o-dFKIT+3NRoLBA_LOR1R1U0Ui~WOxHxBmpS^m)BeJ|0c zzAr4*7(zenlsk`ulf!fyFieMqFUu)Hzi&3szk@{( zOIHvW#D2XrKtfyC9NmCzwgt*-1JCe)NucU zPy$v0ehdGYp@5~$>Zj}rIGZNi$F8X_>f8MsK_N-*5|o76QYc|b>919(3l}<^rn!&w z&{O^O@gBF0Jm7mzE^oY|P9IG9z(utSz96&itU9pn_#Wj%9cj*DbyF9oKAyTTm5b}| zCyQRYx%lyg3)Rtf?39XeQ~snCG20XN^FXp|VQSWXo0G}3AP*GZtWBNRqHe{#(wIbt zq{JUp>9i%X>fKr14r4qoc2P6`P=?6z!b6ye8@X2}gZ&zFRemt3-BUl;&;HYz*1Kq* z&1p|-lD&EMS;^$QpV_?cbU?R`-`rSPK5_h}=wPFyA9COVYYmWQ+w zK0dp~SLX`7Tj`?8i^GsksNdVawtC}0@8@g!Yi(iiKyPkk?InA4)(4-p2|1hlE^FX3 z!}%{c<%bSw-P=ExADLF+<|ih0MoSlq=q#Q;N3+?;I58gm-eV;b=q)o_B!Y-Ny7;`ZWw2Mzl`wKalQZpcbFi{^^e-odc8L;C+}h#8>G}#VH_QF`x$E2nX~hFMWj*1h zF#^+IYc$4_#VQTHkLWE7)VMo#| z3OM4isW)_*%%JzxYZmG!wQsK|1x|FyFeHw8f)g_wgmZbb4qS#!ClhMbv`%T$u;Fb{ zhy5?r2EpX^v-)b-&j27<6N6K4$=x7Kw91jF67gh zgx_6H{p*AYK=9i?{qn5;%^BS-wSJp4I*A(p%?aJ@3GEXPg}a^Fl8e%e1Sfti+<{rW z*R*-*Ui#TJQ-8A52i(N>5Kq>s&@#uXVoNW^QOf}=bQsgL9yV#bpO|ZTfe9iMo+}fY4hvYn+Qjb z=MLqnpJ-9w#KHBH5z)vtCB{Vn0?Up;1=|jHteqdqi(}` z2uTrRyBygQt(TXSJ*hyk=P9Pl$y|NpJrm_JGUt)vLO6si=dxL6l7lN=uVl}~QSF{b zB0;zMwA!;v&lH|g8PBM9onX^vy}tV4T6~A`F|gG|P%E7qC=NxArZP-y1quhKNO(b4 zrK{Lq1MnIxEH$4(KYkIluFz4_2nO={7(Ci$vlBS5&%=ByiFgnl>tff`)y)+(ADWL4 zk-e^Xmf{ok-gTeQwnFSnfhSv)w&dGBW|sZtvSMSmmj^%Ix6)sir+sE)xOS{}XziP~ zd*Oq*p-LiGnx8EX7B`xo=z55o@uQiqHfA`j8M+9s>eIt-?>ljPc`42mM`o(SN5-cr zXSbQk4}2o~gn8zc<%Eb69eUep%+jwKS`&|SJZb7hMvhtMO9$IaP?=3TJW_hZ%8r|W+H>mu( z$L5R97!#zd|DHneB2onxmeo6CS$C}Y9%eV?LR~v?X1J+f@67!2(!AX?1WW#`H?M}o zejkLz;?3i3+|@*aV5nlnLXb>IEieyCfP9NTb=st zpqoaY61Kbd`He|1Ih6&wzx1+EHG(D@(>0=`&ryZkz3Q3M@nSau2t*f=ewJ^$DK>7A zy@uCUzJ1r4N&JagNY)h0Qcb#5ZS2h0lqYufy z@7_E-z#pa;?mazR-dtI=`uyg4AJO0hyBb-&>Ajt&hig`X+I(rZt;kfj^yv3budB87 z_>!K?&!TkMVc2eVW-#Ax?{;mfR~Z4dkMb8>N9}R0DjvLE0nUBV)s)t}6EQcw}UzsL^um*+)#f%nc!So>>~rk3D$LKM_jF-7Ux! zN~Ni=?p#L2##u`o%lgIGcc6SsR&Z5Ue<#N;MiB~fTh;E#-6vv_GwrtiEl1Rx8^Y@Cq*h(cPKU1q4RR@sn47)S9d_8SIU zv)QfBLy&+KdG#;>6yowe8$>}6fPfZzc|tHN)%w_Q3#bvnCx1{sYcyiHo?jQ$eDWTN z>iSAE;b3;;3^5o0P%hI$;uAimX9~tqv+3axY(}c>1QtRl$M><<&a`AUZt%LBG(HP^ z^z6s{Nt`!Eyz49FRJPi0Gkm}q<}em#qKp8Y0^^4^SCN!<9Dm<#-5`U=q^*iUZ>@Tc z3o3eHiF{-EEw_V^lG3hNw(f^Njb!3R4oeraJhc4MN=zTKv5A|9bTYF<4)#uOtS`Uf zBOtE)MRWv3$B80iSNXV_i9C~)p(NalQgD>B%NxHK4wbG;0^fpv=hduyWpQZNH>6O& z+-*n=XgN@IM`6(rIKOk_uz<%0cx z8hL(a6Ge7OY6-;Yh<9Gph1p{#DTqgJ)`|4!y+L6ffBGBM@LW{mUhl@`ISkf;OYOfd zr_Vj3!9Tw|bw&ws@pEw0%^2PVm!b_P6YTot1WqwwIf_}by z<{Y0dEb8Y|A6?eZq$_xXFA^Qp_{$o6wW0Ksj{DuT_3vLE^ye#JdSK^on9gOXA?fLz zmt`r9L+L(Y@!P8W%X~-=ZdNqJC*p&kmHv>{DQ&mV>vr>EmwNd0*z0xW&<5$!4gLDa z%oxNDwUVqgWRCQ}Wy?$+-Bhk-g(vORYSI-M64LrV0qQ=xEh4mjYo5R!Q`|kkshOvq zOD}!@irODMHxAx<+gxdNf*%#M9jQEN+(&9DG2_!bB(_XqGaN)5HNAd6E%a2ma$``_ zZ6A`#UYtUDYgZTi9}p|W32a5p>G7RcH~JMDi-yO3Hz}*~TQ5n@$E)ieU;NLg973ct z*zT(vgSFEVpEa|Mp3GfCx&vF=NkiSoP#5Ix8;2K-qPqtoE9LLuQPIfyYfy26=}p6ZpIkJ zFS)QAlq4-tN1KWs5tVX1_|}=3%p9cayZX0OjxkNxgPo9aZ-_7<@)d#7Pvsk@NhLI+ zz*TJ4sat*ZR8(V&?4n{sW-rZ;SY8q}gEov9*JpQWR;tn7j-PBE$wB>n(sqMs@K(e# z(L=ky2gM!}C(lH*id>S5mI*Pi@iebKxnMaYgMvT&uh*=vGKZE(mHF_=`QTD$r{8$e;%UkGgmOa|!ce`cNhGdUKRXg!b zj#0tXW70W!6p`RLXy9yS$oE}aUy{0BbB7$Nzp6ussvtav8Xj8lDQ7pWWltPbs<7%_ z1{GcSo~i5U@g3L4*S#oT5b-HGrNrV2;*;Rod%}>T%6{o7Ge!okCWl7RSfLs>;$xa{ zPbv58AJf!n@-;0N(-Nx8-8~QNb9bH2akw!U?d#3-#6DLSxW<)I-TkWdRX%oHQ z01xYisCdDbyc8-qwCvO;l-5fe*7d=xMdw`GA56;y(&tiRcHJ?|V>`(*Zzq0cGvNN| zv$0>d=>#3aJfK0?Kh+yqjr;!eIfX1H%>I<+CQD70c>}uO>xgwZ`3m<3HH;Om&`5f# zRbb5^Ri0Qxa}HKK&CrP%}A; z+K>smf6`!2j(lnoDKxXP`ZVm$X(7dgF@PYd45)|FPs$Zc&~%hE%Kg)y%E4=#XcGK( zwKSpc1tq8swC^2PxODrevmDI!yH=S15^_VBbiQ%}41+NHgWQ|u$&tC$1>%oBSyz<( z|DOI_m+G#j>^epS1mp>9Fr|;GNju{0M<&|P$w*H-uH@x)h05_sfsani)K4O~SPur5 zUyX=a2KJV9n21Rb=}i;dm|`w$P_!TrSO{xGhvw9{HXI|){Vo`7k(gu3M{94UYy`zY zPkWmuVEY<#HFm%p*#vaz0@u7FZmh-dG|?{D0->kEe%Tv}L!wdrjEaKm;C&PQ<2$;j z?^$iv`0Up$30sx1+I$AMNy5n(j8J8`kkCD6s3WWg`2eGhooHf>ALr1l>`+@!t!1zN zWOWVA5%XIK+xi^ZQMH6ViOf68Ax8A!F*W*WggKd7e>e0r0F_aL;R zi|WeR_s(9w9NMEuY=;66?r&LrQFWNAtQ<&m$Yfu=E!E)0=5l{sIr8+89jSZJ@wxTc z6aD2I@=tBtT(OY*yo`I5ru5~XLum;;jLVYsgSrZ>(vmGtMvBAIs5Lg;HJpP|QB*f? zKguiDiyKg|Uv4{QoEv^~u=l>IU?sp0kg0&$Bkf3kQah`78>h{YHW_X_vT>w*;fiBM zFQSPl5KJ2T%t_Zdz#}he?8Wtg`6(8bMxI)5bKpBbE1S2WRan)W%cfXXr7nXgA}1%P z)G)91RhT~2A{^{p8R+gF0iDbU*+yxzMJIrcU|XHlipf7BL?Z7W zEog%Lcug7}p6VEbaO#fjo}IdzEyP8oNv=F`a`{&OwzZ@(Bv3iC!*0Ti|BTR^CFZV+Hcub5MX+t~j`u~%AGpKK0^XEe z+ugH;zpX$dY5aE0#OT>>pznCXRn;(2~BeAri%HLc%*EMZOwwJh0q+I1rc11zL(L5GKsb|?jiBVXEg$N6}<>< z7qN2GVrq2)rU_)(wAg!cQwd^X_w&8!%{4i>CqikLx(Z1xOn}~fN^#sfG}xq!ISy5prHZ2O>Nj>{R#fJJm&1QNN`zcb!^VRo|!yD|$c|vf=ZAcC#_P z^OTxCOnmDRqZy<4G~4~&t+j`(IpO7}bU=FqfEo|Z2@rqb^hxEdB(69KV`JVkJR;Vm zVYg$WgG)ILV{gpgP&*7ILbSv7TPrxhY&9=EvSV*!OR1zfyiq*N8YEhPs^T4Ac< z$HE0MKU{EUPzNF&l*Nfwj^-bik3|4#gI00dxY)`*^N*Zf#@$3H39kfxvyI^doY}u~ zj|fM$lE|BG9B%nxZw2FAVg`T|tKvSY#;_ShP*A#pZImH?ZJx-X&0cw}k?GWlNBwm37leG`_#P z)wQ8SRPM6R>p|F1Z#s04p0M--8i2DzU?AY)bz`X5y7kF0dwlr43=i)1rU$Dc6Oq}3 zIi9c}1N1=N4Oh4z{7Q<*<6VudxF?MFn%3+9cS{ki#F&vff(1(Q*Y+IBCgZ=?quOT-J@##z8INY z(7pZBE2Bvs(ksHAaaRRgyXg{u!}qj`S9L_Vnp`fjTOis6LvmrYl~9Evl4=&(4NOh`!8s|HSJt#=QLN5Oc?r*ZH8k5>mqi$vddO;nFR`U z0~=|5V1nFG{In8CC(PsBkDwnHyZF_hn-d{bMa4V`_x7A!Uq{xgE@15p*C!MGvl=s9 zrzk%SVH#h*Q>y=*ebjr-T1%d+^G;axu9koG{0fBm%9c^Lx5;AVN#&1uTOCd>IX+lLTKVqtsXNt# zwg1n>?M;!-yHR*aVi&GoKHCl#unccLiJDZdSuB3RH@OW2yl-k&0 z3s)hZd)-nIpevmrt|?9an_LhulIP`gza-n=b9Dnh(hIr^)Z|c6cpwZXt?%pcw+*pi9^F@ncNA5HUz)h4imufw#l*Shj>a zWEVJi@1YzpEYI>0n^I|?Ju6$>QaY3G=d$^Th1??7$KI9tlD4u};~ML=>d^fcXHQPj z=^rwS(6g0GpVz%X51#;x6QP|M_B#nx(P@MN2a|F&;-VG2yH$vNO{5kDCC5A-yP^== z%A6#CU2d=qV`}b~n^}m)Dso$==yO4Us6C2Smpu?K)>mg)3GuReAUy$4T<;8{agV9_ z2%!v3_O56{f2XtCrOA}UGGVOe(^%0j>r$Rjw3q zHZ#zT=W@I)a&0e zxf9iDGD@0kqnJ2>=`kDD6)4Ipw;mUdOG**)4Fm=;Y59AYC#-&&X(j;dP~p0b)E#7` z<{L-6Y_vTZ$~_X|ZKZ1crDCe+C9X_hajP=d5&hQ_2(bCxh3c2ZMWV(^qf>(C@7Lv2 zHmqmb3%BALi&5j;MX8Vg4o)k}gYHmF{#Y9VnL1oCQrd&5B}l@`5rL3zAYoI^JW5aExP|5h z+PTQhF20l&1Jzm4EO#e`q)Sy5DPXVQoML#;=po~eQdDF!K%HU0N#gkl)9i^fB1$5s zk;q6S@}QQ7BVL_BRgpRYZ=aG-b8|~cE-d>p->b``f6}giX zQ=k%g!uGKMN-YKZ8M_c)oRy-b)!%nb_n2X{>Q`!QN5_lGBO?J%?KdPZRJj%_$gp?2a129-!&4Nr*lolb*%HM5ZupA{%GY~`V^96)s&7~ z&2Pxgb37|=ZQx0B_i070%t6SgLChU@QSw~p=AJ$=zK@J~f6JQOh@W!ID=M5^*<9(V zr3+fId?dOG)Rd-vaIKgq!XE=~L*&WZ9Jn7-yv!^fqy;`V^KRt>_2%NQ>1cnV0c0-;)b5_n{O|`K(}Mtg zasm_lm&SI>EG*=!W6TLtBccQbUrsjFTR+tnW{~rmue5xTXN-|M))H#5YwGPO@VyzO zsw*BZvJ$<4dU8zJvtkSOJ8Sa-pJ*cS$d2QU(|{k3QxYjj zd~Tc~xC1aeL|Y*|&l4EaWHCcc7(K4##A04EOTwvS?JG$JjfRHh?c5lNZ@9xI(kU|- z?oUysBHHAhGUO{Unvp+ zSX+2J3z7cLILK7%v`8(+#ul>}^6?=2ac>8j&G5T3=rgv>!7wVuRE28qzRZDBRI#96|^;6W{ zOxV!}Q@;}mXvwubIrTeX?fXPH+giKU9PScKYkc{4-dm@)d4GOh=^>-vX|K?3>DzK; zdjz43fr4`y|K7kiCv2;;##+wA;WxL7(xT@%JpFNPl$0iL2Dt+{P+Rdr(QE%PuL4(Q z75REW33$Oe@8A2AOLIS0#?_ARHC!V*5AJS%FL%e2!cXC)W{Q4oxp1uLIu}npNTwy8 zX6JceE8BFWQG8q#v9cAMAinQL`8(5zAH>^hR#unYW|`}LTKBf zHE=Ji?Xh{@DC0n_k+o$tPq{kvNwIYd=CUUFQI7^O{^_fq7zjdbPGdW(F{X@u5ZF;7v_2|9~^zP z%(wA}SM}4v+^gp2Z7hF6>z}>2y&z@%-;m{cZVH? zI~G(M`mi{s*hv%p(yRByy^p=z;2ZaxdwuKy&9+lly`0HodE|S;JlyStQ1(wVUAOs6 zS4}VOx~wj09w%+TcHH<1ID(9dp6qO{sU$)>0}sqz*55U6`TonBqnpvd2{)igkSCgv zA4<0ng)m@y39z=9%G_ja3Vo=UWmEc0#hFK$1gx0%3>KbD4YB| zaxJyrd`iv%z=H|z(qhNMUZyLjw;#NKTDhXcJ>{oaBzwXjyWGQN_IIreJj*2bRPVnbukZ%YI}=v%os*pOyx*RUwq@hsdVSunZwF4~OP zJa|zM#7=5dbT--Ub7z#gf%hApyY8;iL|-(k35rK$0c}m7$!VE1swLuL@cO{>bE3s_ zO`aO2M_cL1(s|*q`27*^wlewW4RJ($k?>Z3``$Aw%0*qsOVUrJHzzVGk|?v!X1^`( z7@lvM`oQ|lGO`8Yq0yB(z|Cxk${L#@i8U4}W%>ptjLnhtydZb0I&wQ+g8FgCS755goMd{7hhld_ExdcOU! zxSl0n&C7X4e|xd?c}0Hx+U6jkX)l(zl-Zu6gddvblQoE4N}#$)0L^cfnDBLu3&5nufGbJQJw9K$YYcN)Z=&+_fR`;m$-Z4u%>Fbl5@>O!18TX~pC}l%U zAx7#mHLL%*lkA}G+gh6XQh&G|ZK$6{`fRATZs>{l-K<)f4D<;%YH;V;7gJ}|{&&sB z9_fuG>sd9jTe_apk)kBK%0p8SJQXwt7H#TJueF=lnxwg#OFN+}W13T+cCL^n7k%BI zbw}+krv78L|_lSoXpdcncEYOE~+Ks(xxFP^_HZrtv3 zK_~e^?|8p=Q}x(C-gk3jV{LS7c6P9O@Yd3oOLIcO(ZS*Rjah!14Vi;qprG@ zWpF3*WB54}!I-GuXGd{2G1cmrTSsZK$4_&$IQ>aXZenj7!yLNvSmKxj#-K4B)ukM*hukxH zL~!@Y4+|tt{ZyQQd;5rq91y=bC#USs65M}ildqDTp$c~;?*8;FR>6VZxmSPIy^_zj zy%J&}9*FeTNC*>TF&qaS89WC(iSwqF{iwY%lhL=-qKa$LyVrK1u{IZu%JkGaTsJ7; zRIaWkNL>{NUJ@_fP6Rq|VV1R#$H>EpEIr5mdi*m&?&nndIFbu%4|g zZ<_$yt#|;+nDSl{@KvI3oA_dPj0IE$h&EkQ3%EM?`;J z=o$rp6mBlUZZrArEl`%cEuozzSD3(u&-}i7_)l#3MskCtV*rOpxkL|;p)D0kkadaM zZs{fHro||Qd!#-g>6R!TjM*sX87 zYNl1@j3}7W+d2RW$zoZOOos&cX`DY^1rry&vMGPDtb)FJoebs3iv>^>xXW<++{{w+ zuTX@e^N#7T#S)E9nu|oT!QJ6nk;)J&ubMb7wS!kW7U?WrqQ+AJWa4<=$NEbDRaTdOZgPE?)Dk07{_(9)AW4KvuD*95ZXr=>zAN~!iKwOMw^$DQ<>*EXEE`d zJP>u*+7RC+wPZ`0nV@t$Ee{dlJ#AeZct$^wX_E}tgeCWXYMAgTIT;;z+91JQc7eex zkKQjG3!0$L8ny7A&lTT(NwZ1G66iu{jCqFKV?j9D8;jr+WL;+jWQweEaV9Rpm^Vf? z4%tSSCNy~PBW&goa@3fqcur1BX&}_h$U0JUYI}jFhq~Cmp4TeZrRuNBK$+1qTCr4r zKIKB;b%|8s#cqbo==Y&amr-~U&cW&!C63{#Am--Ox9!#O#`r$0O@@6FO>U0|c$$0( z6)R#g<7riKZPrrGZ17HNY_5c46j(7LJ)H|atO+?^v2$PJC zg(Z7xF_br}v6Z!PlknYKUq#${g65nY;RD%ahYlXHjH|=?SDoz?$rdx;uW;{|%40eF z((Hcg^iQ_UjHQ0^;Q=lPA={3pG#69*s6LA#pQ^5%+f;(S?!1$iW_3Yz=V?W}riDY_ zt--@s8$*hv$8%1ZC%tj7r%K?)Ct?$-vQ|B>-`IgiPfKpYBLYGjKiGqEcZ+gAUb-MD zybj^+I28!DQ8z9`o0paeq1=#8J_^r_BQwXpJp}VKOc1ijJu$T4eNYJFkMHw+5=}pp z_fA7pW2wbNV5*}?fdx^cZ3jW|dD3IjcYdElcN$_(evgaNu+Pdk65$2#2EOXn?drKQ?76DZ-&3yqtgJAPXDMU%Yzu%C!T%GiNWHy>|8hqkMe%%*ktKO~9DS zWzwUK3ja79Gqu;p^@p+r+)0#+y0ZvQfXmeF#G(O!ag3gQd$OTj5wr4WN_0apmSKcUZz>-%?fc;(7k=dxZf^^PFuh9;j!DL{;~y<_&WJ@P7eH2gdA%&9+(D7mQ~ zr0Nc*%smwcsdPrSl#0tyKD0c~H^Lj@0mEA}j-IoL^%y5iOfWsr%?dTh7d{9SV4*sy zJA|xj1I6XUBcTFvSl4Q7u}LDvhQljqNj3DH`cFGJ8NSAm#QGN!?5p~TW92s&?@JP` ze#lksCO&XUokr~yXchBzxD7Wi}9yuk3~SDw(ng!@W8`xuy32}&KQ`!8S|W5)9p*b7-Ys3je1HqKl}d2 zNAa9D>=YE_rotsBC+pI>%Q#VvGU22{!H+(B?Lt`EoY$34snj-7RK$>ykwNF=`Z^2q zZUKzLTiwdrmTJ2x<5`V66KEidK`1_!%Lu*IuGkoba|j$nqJQFAiT-;thR~*wh02NI zeG8PSOrm$AzoxrbFLQYlBq4QBvel;*NmxH)(rfJQr^AsidGdf-oGQ29G&@#z>B<@P z>^P;nNSFIGVh#)`=z8|BO%c^J%_Hq@b=ZE<0s<-mQ1Y)aHqV52H-ctk+ghbm#fe(& z;kqjKRE2~SDe4G8@RC&V9yEy&G<;UiB$-?#A`7Ve3Q5RNFsOJ=wyGuy`*B8qq6qu; zWLD`H`W9xLNjbCN|E`LDaMgfmB{n9EQzvXJ_U{~lOj{Fn_1EW?HrCbrG$gZFf1X=Q zBTr*#Yi_$bMBlop@Ys$klZ2dL1rZ++TS1>e!|^WiTqNR}pL?7++Dfp*Zu_kt46Z`sR^CufB2g z_1E5f^Yx>Ljv8UUGXBMzHG#V0?{=OEmV8aitSTS|W!H4UX^)|gs~Aq*=-9dBJ_~74 zixsVGSIm+C;hZ5ho3XYq`ZRk5CJCvwX#6!0P)TF{?<4M%T5J$9i%aW;7OOk!ZU!}W zYk3rekz4WKwRor*`g0xlxFPPaAwIDzocuP8{-*IB!v$a#904!bd4<<53Nza#cWGQ_ zle;v;kq8wvPLeA+sTm)t@!U+TC=ce8@(&rpTBsk5UBj%6i$2FMR(DxM2ZdXHR1SF5 zTImA`hyHfJA#?3~v2Aw%LMS{O>j`D*M{_>d@Uo}eu+P@KuEbhWrk?3UQ4gw`1bsP+ zlr0-dMq5&3>i-djoHIr8BXeyWkXp+B_;uUvA(A#Qr#2Lb?0yR#Lh1$%8&_ZX3D`~%D<7S_c0k2Q?!>Wr+r`Gm)O|)HiU5il>MSpP>2M!eWzef% ztc3So>YbiR9Szb;uG-13M=|eWDVWj)q*6=$4z1G~T!nz^w`=0%dj|yei*_`7v^Da2 z0=kQ!L{!?W_w@#eW3I-yGbW044g;GA(M}$WXSgA-ONTUIa~H9~XZqPigngplOu*aR zN$}{?NO%zB8yuiM^K2e>Pcw!)nA}$LCpbC-JMX z58DMJC|bamCmDlQ4A{6N%W{S=xl0-YhhDUV<0+6+<;C3T)Z{yzgaLImC7w*gq8QWw zv*Ic88FQumYNd=;KATtJ&jH8mA$G-w-EpysXQ8@#F*EkDZs3{Bcl@RO7hmd~T)(kt zcMDy_NYhom3$)i1Z|uv=bUiR+SSGq%So&I#UibYcn}COhy^F2_=u8ds~SB$N8yRDxXlJGG_7)i!o1C_36 z^KL6)}$zX9@w=-`EFoBAM)f>`WZl;l| z*ko+S>nkU=kJ6PhZVN>KqQ7A0MjbV>Vc0VQ!L=2)wX;R%@q)5Bl~}hrll+!|t=s() z-u*lKufNn&=93_bA76lUn!IklB_&O)-q^UwGc8PX=9QgpQZ)Tu9aW%H9Aqc)5}fBc z>IrUpCvG=-)D9Ni)L*F`lz38zdUJ z$q67Iu~`VQKR4>!x4s)L)4b4u73?`dL+Ly7^0owtaJ{;-KS^sJ-`Uqfr3vu^u^jgv zBd=?+5RJ;w+LDlVdcHDGM$O3btVE$7i;)4FCZe~!@fj{x5?sE%QEHkcTUSNPIxV*n zRPao$D*8?LUm-$piS?bsSAp}#oxqtF$KEs>Ve-*$72$$&H`M?K$#s41lovrI<+1=2 z@09992F(`{H1p~dyirA(zF3vMi=mfHH{93&EvXXnx;uF{dIl}Lb`#+AUv$FhhJ~Uw zWd&h@4+XJ#NxqFO&?@qh)7qt5OBsR2P(%dNhE)@-GHi@@Ku#vqzYxP#^;`{q68{O2 zCTB4Iyqb7e5K45`z$n8r$g=!*PG|M$NsAxQ;CjIH!yK^lnMtrx~J^5Rw#~^!TTqk+$n+qkFRl>oerj^)z~aK{co=NWI>sIAkih+jnFsG~Lg0_&Xvo4f+S z69iI2$bJ&xp&ofc%l?fU%41g6KwZm-jr1B~CD48dof&tjZvU^{#rAO?O_IVmfH?AY z+r;f{K8cH!rPXb0ereUa2u3k_S5Wvz2?}kU<0}bOT(*PsME%Iy4p=Xu$wVgp7Kkj{ z*ZxfDtAWqqKOnT0OZCu0;EjHJ8@zP9?ke-Ne?KCR^@XYu6K11z#YAGPT9+$2?dY!a zn8@JbCBd@61V@`oYL=(0X0lD>3SHJ!wn~98`#g+BZf$4kQ(+3Up}iiI7_vlMe?@_R zSDNap=xriRDf;>*1gorGgxI{R^G*CJTb`QMVdf*36;xr;?=7mT99wB-ZK%COMPH#~ zdWM?yjm@Quo*SX;6ELpRSuW}=k;mHrRdV}-w6XTqM``OWdMByxpwJ{f&iA-$uz%bO zOL_)eAD&DPKCA5zj}r%yvEZ8Hf(iYMNS{YU8W{w>=>S`>i%drgNtWS-UcBrq!Y4dh z*G95xJI;vRF;FsMgx1JX$D9-Kdk(JDxs$wc+CF|hoYbaq=(pFi6;PhS87o&Zh z;{nE-r9NI2D96=Dz}Zv_@s*QX95b*8!pHbZl!;VmyBQW0%;?EyOfvCBx|+GPO5@iEVLUZ%c|oyMXrMo%8HBCsr2V@$=bj#vk9j*!Zif0{I_U}w-^7qt$C}( zyTG2j`sAzJa_t`Z^wdZ!Agin`I^D} zfYKmqG2|P`ZH=wx&u~W~!7g+J@AQp;Y_ojn4Qdjg2vCa-H$d)tw{I03H&^LDZNROW7lo zi2jcMKa@_je2UT6UwT>pVF6Gwx4%Qj5b-KSj8xqt1EBXAPBvB3s;QT5xS+E(cQK6o zDrk8>5MHAJ&vP$K%-`akI~t{SBj=8LCY~Y{))WFP>;Jm$=F*^)NNs2SxSyx(gbQ{; zq2-kcj)Wb&vIPQ$)zn6GMr00-VjK~<5l*eND*BQ$mtD=LyR^8vxs1A)s3kj;fG_fU3vGE8YC7S6o=2EQ$HyZ zrQ!{FOwqC|bmb16U^*E;hXu7n`yvz|qI z8!A9G$mk;oRWm>M%LU9_2WTK#<_H0a5~u zXt1B%kq-AyCjvXNYgqTzTp}{-53O9M#aIQ_OsTE!%)jhH)wzuOmibvA7Wzf@T8=^f zvkpc_fENS`htEi_DS-Za8R)R!C7G^OsN?H#0*|Z}QUq<|@6Kw~8+K9Egc6&aL*&Wh z&+*Af(zc4>ap;tWMug6(h=YTa+~D6X;Qg!O2HP=; z{@;nvufd*p9J+AKC+z0A##JRrP!lHe-?o7TVI$L`wVNF?e8PBH#c(eoCxxHgv;9m4 zm|t*Q@hDH_FXmJERUFDT%sn!dl5%FgQ1U*ur?j<|C*)pTvUMnK!q}Ore9L^J?+_bp z&L!O`NwT(-5@WfcmZf5iGI879EtwfNmR9ZhOVk~E?6aATn^g{)v2;>GHGzMU@Ts<+ zPdZSYSAaj!*&fAMlBtSgY(dP<=sHA2v{L1WNQ<8!;|Csi;5zO7GW(5nD^V`(OWi_6YRRX83(sUDc6 zV94DF=$iWP&nK^~Ai(7^&f9einJZj}D|Ca& zLcYnw+5$`=^lMSd>h^yxvB(2cpI5zNcVh%Wc4Aza)i)vN-u=<|kIbj`N? zx%!}aRtPTIc6mt2q0V^tS$G&*gz(IG=?!LB`4cTCWw|c z)QLg%Qm~{xw-~lxciUmV%WR6adlkq2bW0o~OxYIAlfm5riG?b^9q|l5Bn$xIa;R?^ zrqUavsW@e@|MdvtYZxv`n0GW{jFFA7x&LAkP-7*-k0L?eqMFYJY~| zj)8W@whNoX;&9hh-a3iTdBL4Kwc5|~wkO8dDInuCx)Pc#pXAOsF~A;=sR>TN9+RZX zjyxWaCsvkk%_SJw;qjyl#pchS9k@Q88&Bq1KxCTNsE?~D zT7|Pf9oIQHWKtzAXoxNiMJr@CP|t?b zX|Fam-gk^}V54=Mo+Ks_W475D(~eZYndA5lT6fEk>P+MBcEb!n?Y;#sw37EvpF9D5 znC6hZ5>X+WJRYXp{$OIGHj>73%&0e+-J-r9OWVMelu-&68cT+x_~{$IZ@$CYUt(2J z=_^>{-`S7f?4{n7qVJJTLn;VlIN<0kv!!sa*^kOBqo5*z_)6@Is2HqAOyovRYp%#UYXrrR8UR^56j`x4%IDr93Q;*yLR$Q<+jXTGR ztw!v|i%Er4b)3jG>0Q|HUw#|dkowwg8zUNTY=sr(QJaJo|9cB9X5h9uCel&ea{?Q{ zwFjv@ZB~B%z2zHfu#Xr!&+oWX@=1-QyC^kUjFaaah9-jGS~Po2|592DcjsA3ZQC<5 zi|a^-WC?9?(6m{pAbEg-D5?Cfmq zr>nlaca{fTV&^}*!IexztLQ7R6(?&?{Ru;@VNRlrZ-y?0>LNp9H*aAG$1+K0j8jZC za!*Oil3BV(xR@;tI<}me(zt{2gm^*-!pYcuM&he%-U;L#r%JIH@j9Q2<29K1%j0$T z8anV=yV@pJCrE6KtK%ZE&A7i^%>1)oKg=xJmYEp8BgFjPi2^ZQ*Z8i{GqH_rF^z7< zd&dYG#7Rv9{naquD9HRib=Ynu-RNLU(9vqqO`i?I&#M}1P1l?`BMy#>O~8sHyMVk9 znCQ__aLSGI9kyd*#;ijlED$(N2R!BWr}dQA4Bt&bzwek)@#Mu0nusK{b?>dz?y?J; zC^diJ6m)#)*E3^H1=&f3ow=qyu95HfBV!x~tY}#dx?c~WhB&(zz3(O8sP*G2`gfI& z%EqJvob1TEY4oIk zDAhT=8FI*kp6*@s-VgqBG>Or`U=Mrs$J())MpmMK4Sk~?IL_|IjZt*FhEc9H#$Fw9 z70ED965UBNGdgvW&gM2#8c_48}-uj>D zq`bwgok+Rf!qH$Fm6N!g2%0XAvV0=2vq@`gu4nr@%kG8{CDuI6-87&U+!c4ipnmQQ zYPh&K8f?52`(695Dazx?fJ3@*`0YxT4wx@DAYQaeWg4AsgIh@IH2woIJu7|83bm`) z(xdeipLRMZ8j3cw99E?t<-}SfO_BFYUqiu+62)70$ndJBJQO$po)VT2ydo{Vz8G|@ zyX3Z(;+_sBi2JP>0QdYa-ztmwHw-2wQ*4L9crS=aWc%yLTJQ_Wt2L1!dFbU1nTrXo zJ7F!$zox8ZZXh>8v#%Q@|L4M6>TB5^bJ_961m=QKM|squ;(z2@w>27AiAN}qZR47O z`;4fdLwlj?6*ByyAxTv5JCQ}Q7s-!4pwW}s+%yvkZNWy37t*5Ib3HBjtEl?;va-jI zcr@~rb%j=kV-k~jg#7xO?4NeG=j@OAt0e*-P`}~6Jn1GQ!_Tny{_<$3O!>BOEEvBe z;%H;gw=j$Aot`%cQc0rfretoDCyg^msfD33=;;nK_(olO#^pxiewdf`6WZ)=9IzG{ z%1K(iaUk4Kzn*`f!QNPgMq`|P`|o@JE}ONRVLhUYMwBlJ+;y5#fMsUo5+T(UU!z($ zUqJsxZuBT2JQnVKuFtsN?&W#S9I#}1 zn-f%MkY~X@)c+}wX3x2SuD*+-3yR&_`KvO@PfBZ4_cv`I25-ziXEz$|=bBU54ZH0M zsyDP%(;$WaFQ^r7zF$s&(31RyZv3xYJ4}Ll*GJoC8AP} z@xtN#FC2Mk_xr=;h29IV+NE9=V$~(-^IuYm^YhJ>HMFVqbYJB7c|B$ZjQ4hV6N9D& ztKH!??uk%((%cSs%{{X^Q+dAl>j5r$1mVCs;fMOYTldF;*D(avKD zFi%P&TVK+3eVSoe1cs$MuRcX9s}m;sBRj+0LRnUf^>9J|!b8l?(!X#WuJPd~ZnC2P zBbHHie0YjcIQ7Q4*6RJiBfl+^ZR9d;0B^JD?{WT{QTMGE4)4A&;Pz~^WWNDxu(Gys z+j1RLtFP_zP3l=1tF#TrA24D)#R>SGHB(O-1gyHrFgaujg1rf}59+4kncfRW0O<>_ za&+V4*tNgHdR0j^#yO#TZjBbwXnTs$PW-rYz`eQ=eV>5ky-8&%Pvx_|ciQ%GtiF^- zs1C7(08&pr%>=ajkoIzjtsJVqe$Uk5wALMmyPnAx#O*jn;FL+JSuGpNjPcop~4S@^66FqQ2P(i7q&`&Ukh>fsq z!ZTc=d}mi3|HTR5b>fwhp&Mm3)O2H2IU96_QDTN1XKQp96W%(MM?GDQwR)?s3+E{Q zfabk#$Ja}PTk7AY+TM=Kh{uWd|Nd9@Bto$_(Ebk2;@|q#&SG=z+c}B<_B%ZZRCjCi zDpmZL-as|Kg5z6=TntNg@;{)ox^Vcp)GK%{bpQ7MNA)vtoNa-CvHB z^6Lw+*pNw}O`Z+JqF0+bBacZk{NSl zx!jM+=RD<(q9aqs1fwYNu!E6xBm?vBNRp7-_~kEv%JU0UDPGbg0wyKRbY{~ zXHJsARKl9jr(IUL3!b>I_-|ar-R*C0T6Ls=#{-*)=9@RN2flG8-)}xm&qJZY0cHbx zQNYuFi`_Y$5rK(K9|Yn&3h?Oc@-%-UEkG5uADDO-5mou<=MvJa(u)XTXAkdu#PAd< z0KRDR@p_w>QE^1?2exRn{LK~lMXQ`j{M>Vr+L#EQ64vE&)CV#?-Q0yvY<^p76C$wN zV?>GU?MMv)emV)CJ=q$+BJ5=+@0ceBERQ}Fb_ORXI^gSD6r~w(SwEwad1H(kB-E?L zs3hX)ta+%mrIX$>SLdW5rO0%pd6}1JN`0j|-U>QWRE(lAbg*Z(GP=@=Zgp25Y1gyF zin+@{@2(BkW^|RFikCN0wQ||#aLum0I%ZsYbNR&a<)stH)jEaz@!QLTAMca>wYo8L zYe2`aV{aTf^!C0J7qyTpK_%wV6UT5GsdY?qkyiE;eNQ0~H;BHp@Z+=0w~aZ^`vjjT zDO5eM4@w0LGlvZ>EcKU%3g41aMH@_1&M;^8N-C?0kZZgyv%MH~2sRg)8s#Y1qi*XA z6i4aX<(W$(bFY{sno4KYxKTOE%1PbORbn;9 z!*bScXII_NAz zGZoBsiinC5NyZJFHiMz;XGx)qV?W%?=g4mdRau{3lH%zO)rPOw(t9*QfC}?rvb^0= zO#c6ePtO*o8`b`JqJ~R`L8y1gvr;+4kZjcvXRXy2S-Vn{^MuaQvaAlIb-0ZDW zl~ZNReXIoq0^Mr26Po~w*UcKYbEP>Nwp&W;@4Y`kT1(@N3U7#ahPFrYQRp^hsfR)J z?Wxnu@@;cbnqC!CbaYA2oCOq=L$C7w#ieCwgUEg2f>B?NTJnl&rk7S{Him1*dWY7& zd0VB^_JKMgYz$YLpV5f0`H3~M2p`RSwJ}4SXGV>hq<|jl9hSx|4LQyfM`o(SN5-dW zd}dRX>+zZF6DCsE_W3X4Oo!gK_R8s3jlJ*0*>Bc{QtYL-oWACq2_K|wORD}#=*1y4j@1ufA4#3zHqBd zy*=Di%G#<5*05C^^a30zDpn%b(WSQ5qX4z-8VP@PN6P0jD0Rk0-WBt32e+qkzc0p# zk{&Zi-CF{?foZrvBe@%9`mTv^7!Tq<8x>g;lQ6_xFLh+}XQ%AmNelg6S4Jl0{34vMtj|z5B9y0oiEt#P()K4RQHZ(PIHhnicbwy9# zFgqUw@(Y#DdwD3GIYxRLf7{6XYR?7#inBt$)sFkr%rhcr5pgYdAYIsXRRGel*IHr)yP$Vew6el2i(r%m( zMT4Eak1w9TE+@r}P2C_?)NLN@T^$U1$NRmT>x0D~@4LCNu{Jt3J3ClCcx&m)rMcno z%hAE%`i)tBo4w+%e<9Wrx~h%#od_TH@`s@Jr}6FMv;7m>HL9lWDWZZqI)Zo)?0n2H z5O3^T$voV7N;wJjsNVxS9}$|HlWynh>4p0}Cfz$D{#bu+pPbF4B1iX=BZ{L1uhs|rg-U_n3@T_=dYUo$(=P7y_jpV`SHWRMdY|z^ZPq&|t5x55 zTIi|Mq`7!3KYD;-z+Q-=R^mb!d^L1uF*%WfebF^k-`pp~=3E~#ds9rHOgYG!nYpUN zlB1L55|{`oS#@J!;Q*$e-SA*1ziO*1@ndRYbZy>k%nss4Ip_(qP^uG1Uq z%dhO)-eae>_t@p_J$7ZQ$9CJ=uCA$@##WE|Ha@OAri72DEYyQ5KOR!{M&;zN2hR+a z)o3<2J-0j3<2r(nsF07KF;WNa92i?vHZ#UzENST93`3)1MAgF`QuPHtErxa4q|%Se?RBJu*dSw)GyALdxGkV6GeqO(N5WmL}aV^5%g!u%Vsh>){#XHH>3rgCW zI;RBCpQYvh(8P%~){x<*+wOmAxO1R)?$w{wSMm9_S3y#DT!&^h_T+SQ!I}d=ttcbO zlt`=kQF~PujJmZhTVL2!U)P1kx*(2bzYP#2!lzsr5XuR$ue9Lvw5=qynFuhlq}EqD zLG)X9xs*Et(zCUtZ39q`RDvuyiE)>OIXZF}pHkX!sk+p;;zRFqO@p(${Ub{SALjsv zT0>zox#KM;;X1DR@Q>T@Be9x!ZoAlGp8eviG296%={Xwzctus8pxTfpxwB>iltb!~iMWlMR zW^XtNqcn7fhsv#Hb^Xn-)gmjV8l!oQW~p~EhcLQJl>tHvw)L58S^Q*aK^tkOM=p7; zLy-#Lp?>sjJ(@{Rib-eWxxW zssm9H_{B3v_U{CC}kD2hc-k>1B(S5>< z3FZHCz#Gq0QJT+au(>dt(VYy6KiuwpIk=6N%>C%nTXp3wHy{pVAwd($#J01+n;a5X zMmL9>s=AqT*Uc);h~)j~(^~H)r2uWz-#AvhVQ&fIO{3BScW!H!k|ztXZMWtWM&HAg?dl(?Vm4X_oPxc@e45&6aX8qCzcvufbK8s(#L6wmSiq z$`PnZ)f%pMkdAJDe0E9ekrkkH#LSpJ*?OA?d;W|cncb2dWinO`C)iktQpXKjWXKABl zX~(Rmm|RgNa=38EIXgMf?JgMjrJq|YRO#Y~ml7yX+5SoonA`3LdLyEk zfqfBMY&wV(x*&Sd4V2G2fRZa`5cg0g8EsJ!L|DCLR8FDqIE%3ylC=02(&C+mXi1gG zY5mZi)cVYYBl58ZECA1belv~#n;}6z)!d{)oBEj8YU5*u%9S+gAxP>J-a?#%3TK)f%%uj>~D4>WXY4q9%f8ly>@_+dF| zE8tS!f)^cwz=-E&+``2Lhg7;S_guZH(r~-NCzqv;o9kCh$=k-jV;L$a+Ne_Wx5Wb! z{RbbWZ9dyxf;hMCq}Q$Ny2XBJL3tGQ%^otVCFfkl4VN1gu;usSruwC+g*4;CHlxx* zmZJZlKEvgm`vu0y!EY2@`hCIBT^BIcr=7BM$JZE6&z|GAuF?568j8ZsMZ!8{1j~0~ z>CeUn3E+m^p-kqh)S}*8EH4nU>)*b>(peXe)@}24VD*)b z1-iFR>aM)f2(Yh)Z?GCM-w74p>7I@lzZkMo1@ zoKVEAPA3UG?8=nT+w9cutkI~2`u48&MaDY~8iE^JO3a3Fg2F88eL`*JttDw`G;)yk z?^Op29g5mN?Z^l}VOV@#N9D^h=G5Gr6a&ZilF_*_69#&Pp_{=eqVW=EftPJR6Ad zPy5{oKMj!e_W`m-CM62A8^=l0j{>~B>fpbNcinw}v{A-*Q{<(a2)y*Uahv<7+|!aK z(c|rwFqWw)l}^P;)1>`>EpVxrxsYoZI*(Qc=FcgA-LhbBz1SM=RF%hzAtH~=vW05{ z08IuU+M|1sZx{@!c?fzrqRkRt_U!o@v^dwV&cncrk6O{f(uztnSE8U->k`mIJ{%w7{6xqtT#MT~8-e4P0JnC$1zAW+ zI8di1kf>egyKdH@jnOk!in(zIQ2mU+TCA0^rR4n4^2GnTaq7(M&cEu%N)YFtAiV zA0Fz!csbgoL+OGOaN;ME7J^Mf90Z?qB{+AxD%7QK=lLgl%SS{cxJmIlS-1$J;fllU z@YfyHd@hSu{q*azq8t%qe(!b!-U`GR@M1Vx?7LYbR?Ql86BxA8$hVy_Ds!qfv%v!2 z(3<7j{TxP*J*G`x?3WT!fiCP8u(+ILLO<6R+L?%*{nEoHtLY@3Jroc%PL* zw+7Hn9YuFIbe?0jSOc!~kLI%O49@@!U1fFj)MQm63jD;b-6OB$AqRk9g`uGK(>r3oUJhfsrTXS48f zFH`g%lu|Xa8}^&o)DE}x;n?%-?(=pxN0rB&HkUkT*aqj#W(qm>x7CuSM1To$6GY?z zmk)JRjItz$6P+#({rZ8z(mxjWzh-QU=p}=>xF+LXx6rg1+lDP$AWVxv3`h&Mwu}vD`|L02 z?uLK~jrxV5*t`CSv&=4z*~{Qg=tN~1D%F`D98PyAJX8m?`}ZgE!x~N;pz||}V`L^I zn|A;;V_$Kr798B9+YSxd9mR+t)M?vT<+q~s|)r1wrZ`XdpakRI#9)yw-h-%Dt#IkFy#`} z(rk8zR-`piiJ+QS3(LE=bexsx?X6ociO~sFOn%*ySwKI0qZa|X zTox_xr@nr-76u}qS?BdhH@A(Dg;+^N9%z~$+mO6;Zeb{YTIvKZiPymKV91y+ag5iX zgYHK45OpNBfwLA>*b`D9(58w5nF2*yZ4*f`s2zIzs--#g-st(KCtsX->+R + + + + AboutDialog + + + About DB Browser for SQLite + О программе Обозреватель Ð´Ð»Ñ SQLite + + + + Version + ВерÑÐ¸Ñ + + + + <html><head/><body><p>DB Browser for SQLite is an open source, freeware visual tool used to create, design and edit SQLite database files.</p><p>It is bi-licensed under the Mozilla Public License Version 2, as well as the GNU General Public License Version 3 or later. You can modify or redistribute it under the conditions of these licenses.</p><p>See <a href="http://www.gnu.org/licenses/gpl.html">http://www.gnu.org/licenses/gpl.html</a> and <a href="https://www.mozilla.org/MPL/2.0/index.txt">https://www.mozilla.org/MPL/2.0/index.txt</a> for details.</p><p>For more information on this program please visit our website at: <a href="http://sqlitebrowser.org">http://sqlitebrowser.org</a></p><p><span style=" font-size:small;">This software uses the GPL/LGPL Qt Toolkit from </span><a href="http://qt-project.org/"><span style=" font-size:small;">http://qt-project.org/</span></a><span style=" font-size:small;"><br/>See </span><a href="http://qt-project.org/doc/qt-5/licensing.html"><span style=" font-size:small;">http://qt-project.org/doc/qt-5/licensing.html</span></a><span style=" font-size:small;"> for licensing terms and information.</span></p><p><span style=" font-size:small;">It also uses the Silk icon set by Mark James licensed under a Creative Commons Attribution 2.5 and 3.0 license.<br/>See </span><a href="http://www.famfamfam.com/lab/icons/silk/"><span style=" font-size:small;">http://www.famfamfam.com/lab/icons/silk/</span></a><span style=" font-size:small;"> for details.</span></p></body></html> + <html><head/><body><p>Обозреватель Ð´Ð»Ñ SQLite - Ñто беÑÐ¿Ð»Ð°Ñ‚Ð½Ð°Ñ Ð¿Ñ€Ð¾Ð³Ñ€Ð°Ð¼Ð¼Ð°, Ñ Ð¾Ñ‚ÐºÑ€Ñ‹Ñ‚Ñ‹Ð¼ иÑходным кодом, Ð¿Ñ€ÐµÐ´Ð½Ð°Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ð°Ñ Ð´Ð»Ñ ÑÐ¾Ð·Ð´Ð°Ð½Ð¸Ñ Ð¸ Ñ€ÐµÐ´Ð°ÐºÑ‚Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ Ð±Ð°Ð· данных SQLite.</p><p>Программа лицензирована по двум лицензиÑм: Mozilla Public License Version 2 и GNU General Public License Version 3 or later. Можно изменÑть или раÑпроÑтранÑть её на уÑловиÑÑ… Ñтих лицензий.</p><p>Лицензии можно проÑмотреть по ÑÑылкам <a href="http://www.gnu.org/licenses/gpl.html"><span style=" text-decoration: underline; color:#0000ff;">http://www.gnu.org/licenses/gpl.html</span></a> и <a href="https://www.mozilla.org/MPL/2.0/index.txt"><span style=" text-decoration: underline; color:#0000ff;">https://www.mozilla.org/MPL/2.0/index.txt</span></a>.</p><p>Дополнительную информацию о программе можно узнать на веб-Ñайте:<br/><a href="https://sqlitebrowser.org"><span style=" text-decoration: underline; color:#0000ff;">https://sqlitebrowser.org</span></a></p><p><span style=" font-size:small;">Это программное обеÑпечение иÑпользует GPL/LGPL Qt Toolkit </span><a href="http://qt-project.org/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://qt-project.org/</span></a><span style=" font-size:small;"><br/>УÑÐ»Ð¾Ð²Ð¸Ñ Ð»Ð¸Ñ†ÐµÐ½Ð·Ð¸Ð¸ на Qt Toolkit </span><a href="http://qt-project.org/doc/qt-5/licensing.html"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://qt-project.org/doc/qt-5/licensing.html</span></a><span style=" font-size:small;">.</span></p><p><span style=" font-size:small;">Эта программа также иÑпользует набор иконок Silk от Марка ДжеймÑа (Mark James), лицензированный под лицензией Creative Commons Attribution 2.5 and 3.0.<br/>ÐŸÐ¾Ð´Ñ€Ð¾Ð±Ð½Ð°Ñ Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð¿Ð¾ адреÑу </span><a href="http://www.famfamfam.com/lab/icons/silk/"><span style=" font-size:small; text-decoration: underline; color:#0000ff;">http://www.famfamfam.com/lab/icons/silk/</span></a><span style=" font-size:small;">.</span></p></body></html> + + + + AddRecordDialog + + + Add New Record + Добавить Ðовую ЗапиÑÑŒ + + + + Enter values for the new record considering constraints. Fields in bold are mandatory. + Введите Ð·Ð½Ð°Ñ‡ÐµÐ½Ð¸Ñ Ð´Ð»Ñ Ð½Ð¾Ð²Ð¾Ð¹ запиÑи Ñ ÑƒÑ‡ÐµÑ‚Ð¾Ð¼ ограничений. ПолÑ, выделенные жирным шрифтом, ÑвлÑÑŽÑ‚ÑÑ Ð¾Ð±Ñзательными. + + + + In the Value column you can specify the value for the field identified in the Name column. The Type column indicates the type of the field. Default values are displayed in the same style as NULL values. + Ð’ Ñтолбце "Значение" вы можете указать значение Ð´Ð»Ñ Ð¿Ð¾Ð»Ñ, указанного в Ñтолбце "ИмÑ". Ð’ Ñтолбце "Тип" указываетÑÑ Ñ‚Ð¸Ð¿ полÑ. Ð—Ð½Ð°Ñ‡ÐµÐ½Ð¸Ñ Ð¿Ð¾ умолчанию отображаютÑÑ Ð² том же Ñтиле, что и Ð·Ð½Ð°Ñ‡ÐµÐ½Ð¸Ñ NULL. + + + + Name + Ð˜Ð¼Ñ + + + + Type + Тип + + + + Value + Значение + + + + Values to insert. Pre-filled default values are inserted automatically unless they are changed. + Ð—Ð½Ð°Ñ‡ÐµÐ½Ð¸Ñ Ð´Ð»Ñ Ð²Ñтавки. Предварительно заполненные Ð·Ð½Ð°Ñ‡ÐµÐ½Ð¸Ñ Ð¿Ð¾ умолчанию вÑтавлÑÑŽÑ‚ÑÑ Ð°Ð²Ñ‚Ð¾Ð¼Ð°Ñ‚Ð¸Ñ‡ÐµÑки, еÑли они не изменены. + + + + When you edit the values in the upper frame, the SQL query for inserting this new record is shown here. You can edit manually the query before saving. + Когда вы редактируете Ð·Ð½Ð°Ñ‡ÐµÐ½Ð¸Ñ Ð² верхнем фрейме, здеÑÑŒ отображаетÑÑ Ð·Ð°Ð¿Ñ€Ð¾Ñ SQL Ð´Ð»Ñ Ð²Ñтавки Ñтой новой запиÑи. Ð’Ñ‹ можете вручную отредактировать Ð·Ð°Ð¿Ñ€Ð¾Ñ Ð¿ÐµÑ€ÐµÐ´ Ñохранением. + + + + <html><head/><body><p><span style=" font-weight:600;">Save</span> will submit the shown SQL statement to the database for inserting the new record.</p><p><span style=" font-weight:600;">Restore Defaults</span> will restore the initial values in the <span style=" font-weight:600;">Value</span> column.</p><p><span style=" font-weight:600;">Cancel</span> will close this dialog without executing the query.</p></body></html> + <html><head/><body><p><span style=" font-weight:600;">Сохранение</span> отправит показанный оператор SQL в БД Ð´Ð»Ñ Ð²Ñтавки новой запиÑи.</p><p><span style=" font-weight:600;">ВоÑÑтановить Ð·Ð½Ð°Ñ‡ÐµÐ½Ð¸Ñ Ð¿Ð¾ умолчанию</span> воÑÑтановит иÑходные Ð·Ð½Ð°Ñ‡ÐµÐ½Ð¸Ñ Ð² колонке <span style=" font-weight:600;">Значение</span>.</p><p><span style=" font-weight:600;">Отмена</span> закрывает Ñтот диалог без Ð²Ñ‹Ð¿Ð¾Ð»Ð½ÐµÐ½Ð¸Ñ Ð·Ð°Ð¿Ñ€Ð¾Ñов.</p></body></html> + + + + Auto-increment + + Ðвто-увеличение + + + + + Unique constraint + + УникальноÑÑŒ + + + + + Check constraint: %1 + + Проверка: %1 + + + + + Foreign key: %1 + + Внешний ключ: %1 + + + + + Default value: %1 + + Значение по умолчанию: %1 + + + + + Error adding record. Message from database engine: + +%1 + Ошибка Ð´Ð¾Ð±Ð°Ð²Ð»ÐµÐ½Ð¸Ñ Ð·Ð°Ð¿Ð¸Ñи. Сообщение из базы данных: + +%1 + + + + Are you sure you want to restore all the entered values to their defaults? + Ð’Ñ‹ дейÑтвительно хотите воÑÑтановить вÑе введенные Ð·Ð½Ð°Ñ‡ÐµÐ½Ð¸Ñ Ð¿Ð¾ умолчанию? + + + + Application + + + Possible command line arguments: + + + + + Usage: %1 [options] [<database>|<project>] + + + + + + -h, --help Show command line options + + + + + -q, --quit Exit application after running scripts + + + + + -s, --sql <file> Execute this SQL file after opening the DB + + + + + -t, --table <table> Browse this table after opening the DB + + + + + -R, --read-only Open database in read-only mode + + + + + -o, --option <group>/<setting>=<value> + + + + + Run application with this setting temporarily set to value + + + + + -O, --save-option <group>/<setting>=<value> + + + + + Run application saving this value for this setting + + + + + -v, --version Display the current version + + + + + <database> Open this SQLite database + + + + + <project> Open this project file (*.sqbpro) + + + + + The -s/--sql option requires an argument + + + + + The file %1 does not exist + + + + + The -t/--table option requires an argument + + + + + The -o/--option and -O/--save-option options require an argument in the form group/setting=value + + + + + Invalid option/non-existant file: %1 + + + + + SQLite Version + ВерÑÐ¸Ñ SQLite + + + + SQLCipher Version %1 (based on SQLite %2) + + + + + DB Browser for SQLite Version %1. + + + + + Built for %1, running on %2 + + + + + Qt Version %1 + + + + + CipherDialog + + + SQLCipher encryption + Шифрование SQLCipher + + + + &Password + &Пароль + + + + &Reenter password + Пароль &ещё раз + + + + Encr&yption settings + + + + + SQLCipher &3 defaults + + + + + SQLCipher &4 defaults + + + + + Custo&m + + + + + Page si&ze + Размер &Ñтраницы + + + + &KDF iterations + + + + + HMAC algorithm + + + + + KDF algorithm + + + + + Plaintext Header Size + + + + + Passphrase + Фраза + + + + Raw key + Ключ + + + + Please set a key to encrypt the database. +Note that if you change any of the other, optional, settings you'll need to re-enter them as well every time you open the database file. +Leave the password fields empty to disable the encryption. +The encryption process might take some time and you should have a backup copy of your database! Unsaved changes are applied before modifying the encryption. + ПожалуйÑта укажите ключ шифрованиÑ. +ЕÑли вы измените какую-либо опциональную наÑтройку, то ее нужно будет вводить при каждом открытии Ñтого файла базы данных. +ОÑтавьте пароль пуÑтым еÑли шифрование не требуетÑÑ. +ПроцеÑÑ Ð¼Ð¾Ð¶ÐµÑ‚ занÑть некоторое Ð²Ñ€ÐµÐ¼Ñ Ð¸ наÑтоÑтельно рекомендуем Ñоздать резервную копию перед продолжением! Ðе Ñохраненные Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ð°Ð²Ñ‚Ð¾Ð¼Ð°Ñ‚Ð¸Ñ‡ÐµÑки будут Ñохранены. + + + + Please enter the key used to encrypt the database. +If any of the other settings were altered for this database file you need to provide this information as well. + ПожалуйÑта введите ключ Ð´Ð»Ñ ÑˆÐ¸Ñ„Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ Ð±Ð°Ð·Ñ‹ данных. +ЕÑли любые другие наÑтройки были изменены Ð´Ð»Ñ Ð´Ð°Ð½Ð½Ð¾Ð¹ базы данный то нужно так же предоÑтавить данную информацию. + + + + ColumnDisplayFormatDialog + + + Choose display format + Выберите формат Ð¾Ñ‚Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ + + + + Display format + Формат Ð¾Ñ‚Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ + + + + Choose a display format for the column '%1' which is applied to each value prior to showing it. + Выберите формат Ð¾Ñ‚Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ Ð´Ð»Ñ ÐºÐ¾Ð»Ð¾Ð½ÐºÐ¸ '%1', который будет применен к каждому ее значению. + + + + Default + По умолчанию + + + + Decimal number + ДеÑÑтичное чиÑло + + + + Exponent notation + ЭкÑÐ¿Ð¾Ð½ÐµÐ½Ñ†Ð¸Ð°Ð»ÑŒÐ½Ð°Ñ Ð·Ð°Ð¿Ð¸ÑÑŒ + + + + Hex blob + Бинарные данные + + + + Hex number + ШеÑтнадцатеричное чиÑло + + + + Apple NSDate to date + Apple NSDate дата + + + + Java epoch (milliseconds) to date + Java epoch дата + + + + .NET DateTime.Ticks to date + + + + + Julian day to date + ЮлианÑÐºÐ°Ñ Ð´Ð°Ñ‚Ð° + + + + Unix epoch to local time + Unix-Ð²Ñ€ÐµÐ¼Ñ + + + + Date as dd/mm/yyyy + Дата в формате дд/мм/гггг + + + + Lower case + Ðижний региÑтр + + + + Custom display format must contain a function call applied to %1 + + + + + Error in custom display format. Message from database engine: + +%1 + + + + + Custom display format must return only one column but it returned %1. + + + + + Octal number + ВоÑьмеричное чиÑло + + + + Round number + Округленное чиÑло + + + + Unix epoch to date + Unix-дата + + + + Upper case + Верхний региÑтр + + + + Windows DATE to date + Windows дата + + + + Custom + Мой формат + + + + CondFormatManager + + + Conditional Format Manager + + + + + This dialog allows creating and editing conditional formats. Each cell style will be selected by the first accomplished condition for that cell data. Conditional formats can be moved up and down, where those at higher rows take precedence over those at lower. Syntax for conditions is the same as for filters and an empty condition applies to all values. + + + + + Add new conditional format + + + + + &Add + &Добавить + + + + Remove selected conditional format + + + + + &Remove + &Удалить + + + + Move selected conditional format up + + + + + Move &up + + + + + Move selected conditional format down + + + + + Move &down + + + + + Foreground + Передний план + + + + Text color + Цвет текÑта + + + + Background + Фон + + + + Background color + Цвет фона + + + + Font + Шрифт + + + + Size + Размер + + + + Bold + Жирный + + + + Italic + КурÑив + + + + Underline + Подчёркивание + + + + Alignment + + + + + Condition + + + + + + Click to select color + + + + + Are you sure you want to clear all the conditional formats of this field? + + + + + DBBrowserDB + + + Please specify the database name under which you want to access the attached database + + + + + Invalid file format + Ошибочный формат файла + + + + Do you want to save the changes made to the database file %1? + Сохранить Ñделанные Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ð² файле базы данных %1? + + + + Exporting database to SQL file... + ЭкÑпорт базы данных в файл SQL... + + + + + Cancel + Отменить + + + + Executing SQL... + Выполнить код SQL... + + + + Action cancelled. + ДейÑтвие отменено. + + + + This database has already been attached. Its schema name is '%1'. + Эта БД уже приÑоединена. Ð˜Ð¼Ñ ÐµÐµ Ñхемы - '%1'. + + + + Do you really want to close this temporary database? All data will be lost. + Ð’Ñ‹ дейÑтвительно хотите закрыть Ñту временную БД? Ð’Ñе данные будут потерÑны. + + + + Database didn't close correctly, probably still busy + + + + + The database is currently busy: + БД занÑта: + + + + Do you want to abort that other operation? + Ð’Ñ‹ хотите отменить Ñту операцию? + + + + + No database file opened + Файл БД не открыт + + + + + Error in statement #%1: %2. +Aborting execution%3. + Ошибка в выражении #%1: %2. +Прерываем выполнение%3. + + + + + and rolling back + и отменÑем + + + + didn't receive any output from %1 + + + + + could not execute command: %1 + + + + + Cannot delete this object + Ðе удаетÑÑ ÑƒÐ´Ð°Ð»Ð¸Ñ‚ÑŒ Ñтот объект + + + + Cannot set data on this object + Ðевозможно назначить данные Ð´Ð»Ñ Ñтого объекта + + + + + A table with the name '%1' already exists in schema '%2'. + Таблица Ñ Ð¸Ð¼ÐµÐ½ÐµÐ¼ '%1' уже ÑущеÑтвует в Ñхеме '%2'. + + + + No table with name '%1' exists in schema '%2'. + + + + + + Cannot find column %1. + + + + + Creating savepoint failed. DB says: %1 + + + + + Renaming the column failed. DB says: +%1 + + + + + + Releasing savepoint failed. DB says: %1 + + + + + Creating new table failed. DB says: %1 + + + + + Copying data to new table failed. DB says: +%1 + + + + + Deleting old table failed. DB says: %1 + + + + + Error renaming table '%1' to '%2'. +Message from database engine: +%3 + + + + + could not get list of db objects: %1 + + + + + Restoring some of the objects associated with this table failed. This is most likely because some column names changed. Here's the SQL statement which you might want to fix and execute manually: + + + Ошибка воÑÑÑ‚Ð°Ð½Ð¾Ð²Ð»ÐµÐ½Ð¸Ñ Ð½ÐµÐºÐ¾Ñ‚Ð¾Ñ€Ñ‹Ñ… объектов, аÑÑоциированных Ñ Ñтой таблицей. Ðаиболее вероÑÑ‚Ð½Ð°Ñ Ð¿Ñ€Ð¸Ñ‡Ð¸Ð½Ð° Ñтого - изменение имён некоторых Ñтолбцов таблицы. Вот SQL оператор, который нужно иÑправить и выполнить вручную: + + + + + + could not get list of databases: %1 + не могу получить ÑпиÑок БД: %1 + + + + Error loading extension: %1 + Ошибка загрузки раÑширениÑ: %1 + + + + could not get column information + не могу полчить информацию о колонке + + + + Error setting pragma %1 to %2: %3 + Ошибка уÑтановки прагмы %1 в %2: %3 + + + + File not found. + Файл не найден. + + + + DbStructureModel + + + Name + Ð˜Ð¼Ñ + + + + Object + Объект + + + + Type + Тип + + + + Schema + Схема + + + + Database + База данных + + + + Browsables + ПроÑматриваемые + + + + All + Ð’Ñе + + + + Temporary + Временный + + + + Tables (%1) + Таблицы (%1) + + + + Indices (%1) + ИндекÑÑ‹ (%1) + + + + Views (%1) + ПредÑÑ‚Ð°Ð²Ð»ÐµÐ½Ð¸Ñ (%1) + + + + Triggers (%1) + Триггеры (%1) + + + + EditDialog + + + Edit database cell + Редактирование Ñчейки базы данных + + + + Mode: + Режим: + + + + + Image + Изображение + + + + Set as &NULL + ПриÑвоить &NULL + + + + Apply data to cell + Применить данные к Ñчейке + + + + This button saves the changes performed in the cell editor to the database cell. + Ðажав Ñту кнопку, вы Ñохраните Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ð¿Ñ€Ð¾Ð¸Ð·Ð²ÐµÐ´ÐµÐ½Ð½Ñ‹Ðµ в Ñтом редакторе, в ÑоответÑтвующую Ñчейку БД. + + + + Apply + Применить + + + + Text + ТекÑÑ‚ + + + + This is the list of supported modes for the cell editor. Choose a mode for viewing or editing the data of the current cell. + Это ÑпиÑок поддерживаемых режимов. Выбирете режим Ð´Ð»Ñ Ð¿Ñ€Ð¾Ñмотра или Ñ€ÐµÐ´Ð°ÐºÑ‚Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ Ð´Ð°Ð½Ð½Ñ‹Ñ… текущей Ñчейки. + + + + RTL Text + + + + + Binary + Двоичные данные + + + + JSON + + + + + XML + + + + + + Automatically adjust the editor mode to the loaded data type + ÐвтоматичеÑки подбор режима редактора на оÑнове данных + + + + This checkable button enables or disables the automatic switching of the editor mode. When a new cell is selected or new data is imported and the automatic switching is enabled, the mode adjusts to the detected data type. You can then change the editor mode manually. If you want to keep this manually switched mode while moving through the cells, switch the button off. + Эта кнопка позволÑет включать или отключать автоматичеÑкое переключение режима редактора. Когда выбрана Ð½Ð¾Ð²Ð°Ñ Ñчейка или импортированы новые данные, а автоматичеÑкое переключение включено, режим наÑтраиваетÑÑ Ð½Ð° обнаруженный тип данных. Ð’Ñ‹ можете вручную изменить режим редактора. ЕÑли вы хотите Ñохранить Ñтот режим ручного Ð¿ÐµÑ€ÐµÐºÐ»ÑŽÑ‡ÐµÐ½Ð¸Ñ Ð¿Ñ€Ð¸ перемещении по Ñчейкам, выключите кнопку. + + + + Auto-switch + Ðвтопереключение + + + + The text editor modes let you edit plain text, as well as JSON or XML data with syntax highlighting, automatic formatting and validation before saving. + +Errors are indicated with a red squiggle underline. + + + + + This Qt editor is used for right-to-left scripts, which are not supported by the default Text editor. The presence of right-to-left characters is detected and this editor mode is automatically selected. + + + + + Open preview dialog for printing the data currently stored in the cell + + + + + Auto-format: pretty print on loading, compact on saving. + ÐвтоматичеÑкое форматирование: ÑтилиÑтичеÑкое форматирование при загрузке, компактноÑть - при Ñохранении. + + + + When enabled, the auto-format feature formats the data on loading, breaking the text in lines and indenting it for maximum readability. On data saving, the auto-format feature compacts the data removing end of lines, and unnecessary whitespace. + Когда включено, Ñ„ÑƒÐ½ÐºÑ†Ð¸Ñ Ð°Ð²Ñ‚Ð¾Ð¼Ð°Ñ‚Ð¸Ñ‡ÐµÑкого Ñ„Ð¾Ñ€Ð¼Ð°Ñ‚Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ Ñ„Ð¾Ñ€Ð¼Ð°Ñ‚Ð¸Ñ€ÑƒÐµÑ‚ данные по загрузке, Ñ€Ð°Ð·Ð±Ð¸Ð²Ð°Ñ Ñ‚ÐµÐºÑÑ‚ в Ñтроках и отÑтупы Ð´Ð»Ñ Ð¼Ð°ÐºÑимальной читаемоÑти. При Ñохранении данных Ñ„ÑƒÐ½ÐºÑ†Ð¸Ñ Ð°Ð²Ñ‚Ð¾Ð¼Ð°Ñ‚Ð¸Ñ‡ÐµÑкого Ñ„Ð¾Ñ€Ð¼Ð°Ñ‚Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ Ð¾Ð±ÑŠÐµÐ´Ð¸Ð½Ñет данные, удалÑющие конец Ñтрок, и ненужные пробелы. + + + + Word Wrap + + + + + Wrap lines on word boundaries + + + + + + Open in default application or browser + + + + + Open in application + + + + + The value is interpreted as a file or URL and opened in the default application or web browser. + + + + + Save file reference... + + + + + Save reference to file + + + + + + Open in external application + + + + + Autoformat + Ðвтоформатирование + + + + &Export... + + + + + + &Import... + + + + + + Import from file + Импортировать из файла + + + + + Opens a file dialog used to import any kind of data to this database cell. + Открывает диалоговое окно файла, иÑпользуемое Ð´Ð»Ñ Ð¸Ð¼Ð¿Ð¾Ñ€Ñ‚Ð° любых данных в Ñту Ñчейку базы данных. + + + + Export to file + ЭкÑпортировать в файл + + + + Opens a file dialog used to export the contents of this database cell to a file. + Открывает диалоговое окно файла, иÑпользуемое Ð´Ð»Ñ ÑкÑпорта Ñодержимого Ñтой Ñчейки базы данных в файл. + + + + Erases the contents of the cell + ОчищаетÑÑ Ñодержимое Ñчейки + + + + This area displays information about the data present in this database cell + Эта облаÑть отображает информацию о данных, находÑщихÑÑ Ð² Ñтой Ñчейке базы данных + + + + Type of data currently in cell + Тип данных в Ñчейке + + + + Size of data currently in table + Размер данных в таблице + + + + + Print... + Печать... + + + + Open preview dialog for printing displayed image + Открыть диалоговое окно предварительного проÑмотра Ð´Ð»Ñ Ð¿ÐµÑ‡Ð°Ñ‚Ð¸ отображаемого Ð¸Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ + + + + + Ctrl+P + + + + + Open preview dialog for printing displayed text + Открыть диалоговое окно предварительного проÑмотра Ð´Ð»Ñ Ð¿ÐµÑ‡Ð°Ñ‚Ð¸ отображаемого текÑта + + + + Copy Hex and ASCII + Копировать HEX и ASCII + + + + Copy selected hexadecimal and ASCII columns to the clipboard + Копировать выбранные HEX и ASCII Ñтолбцы в буфер обмена + + + + Ctrl+Shift+C + + + + + Choose a filename to export data + Выбрать Ð¸Ð¼Ñ Ñ„Ð°Ð¹Ð»Ð° Ð´Ð»Ñ ÑкÑпорта данных + + + + Type of data currently in cell: %1 Image + Тип данных в Ñчейке: %1 Изображение + + + + %1x%2 pixel(s) + %1x%2 пикÑелей + + + + Type of data currently in cell: NULL + Тип данных в Ñчейке: NULL + + + + + Type of data currently in cell: Text / Numeric + Тип данных в Ñчейке: ТекÑÑ‚ / ЧиÑловое + + + + + Image data can't be viewed in this mode. + Изображение не может быть отображено в Ñтом режиме. + + + + + Try switching to Image or Binary mode. + Попробуйте переключитьÑÑ Ð² Бинарный режим или режим ИзображениÑ. + + + + + Binary data can't be viewed in this mode. + Бинарные данные не могут быть отображены в Ñтом режиме. + + + + + Try switching to Binary mode. + Попробуйте переключитьÑÑ Ð² Бинарный режим. + + + + Couldn't save file: %1. + Ðе удалоÑÑŒ Ñохранить файл:%1. + + + + The data has been saved to a temporary file and has been opened with the default application. You can now edit the file and, when you are ready, apply the saved new data to the cell editor or cancel any changes. + + + + + + Image files (%1) + Файлы изображений (%1) + + + + Binary files (*.bin) + Бинарные файлы (*.bin) + + + + Choose a file to import + Выбрать файл Ð´Ð»Ñ Ð¸Ð¼Ð¿Ð¾Ñ€Ñ‚Ð° + + + + %1 Image + %1 Изображение + + + + Invalid data for this mode + Ошибочные данные Ð´Ð»Ñ Ñтого режима + + + + The cell contains invalid %1 data. Reason: %2. Do you really want to apply it to the cell? + Ячейка Ñодержит ошибочные %1 данные. Причина: %2. Ð’Ñ‹ дейÑтвительно хотите применить их? + + + + + + %n character(s) + + %n Ñимвол + %n Ñимвола + %n Ñимволов + + + + + Type of data currently in cell: Valid JSON + Тип данных в Ñчейке: JSON + + + + Type of data currently in cell: Binary + Тип данных в Ñчейке: Двоичные данные + + + + + %n byte(s) + + %n байт + %n байта + %n байтов + + + + + EditIndexDialog + + + &Name + &Ð˜Ð¼Ñ + + + + Order + Сортировка + + + + &Table + &Таблица + + + + Edit Index Schema + Редактирование ИндекÑа + + + + &Unique + &Уникальный + + + + For restricting the index to only a part of the table you can specify a WHERE clause here that selects the part of the table that should be indexed + Ð”Ð»Ñ Ð¾Ð³Ñ€Ð°Ð½Ð¸Ñ‡ÐµÐ½Ð¸Ñ Ð¸Ð½Ð´ÐµÐºÑа только чаÑтью таблицы вы можете указать здеÑÑŒ выражение WHERE, которое выбирает чаÑть таблицы, ÐºÐ¾Ñ‚Ð¾Ñ€Ð°Ñ Ð´Ð¾Ð»Ð¶Ð½Ð° быть проиндекÑирована + + + + Partial inde&x clause + &ЧаÑтичный Ð¸Ð½Ð´ÐµÐºÑ + + + + Colu&mns + &Колонки + + + + Table column + Колонка таблицы + + + + Type + Тип + + + + Add a new expression column to the index. Expression columns contain SQL expression rather than column names. + Добавить новое колоночное-выражение в индекÑ. Колоночное выражение может Ñодержкать SQL Ð²Ñ‹Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ Ð²Ð¼ÐµÑто имен колонок. + + + + Index column + Колонка индекÑа + + + + Deleting the old index failed: +%1 + Удаление Ñтарого индекÑа завершилоÑÑŒ Ñ Ð¾ÑˆÐ¸Ð±ÐºÐ¾Ð¹: +%1 + + + + Creating the index failed: +%1 + Ошибка ÑÐ¾Ð·Ð´Ð°Ð½Ð¸Ñ Ð¸Ð½Ð´ÐµÐºÑа: +%1 + + + + EditTableDialog + + + Edit table definition + Редактирование Ð¾Ð¿Ñ€ÐµÐ´ÐµÐ»ÐµÐ½Ð¸Ñ Ñ‚Ð°Ð±Ð»Ð¸Ñ†Ñ‹ + + + + Table + Таблица + + + + Advanced + Дополнительно + + + + Make this a 'WITHOUT rowid' table. Setting this flag requires a field of type INTEGER with the primary key flag set and the auto increment flag unset. + Чтобы Ñоздать таблицу 'без rowid', нужно чтобы в ней был INTEGER первичный ключ Ñ Ð¾Ñ‚ÐºÐ»ÑŽÑ‡ÐµÐ½Ð½Ñ‹Ð¼ автоинкрементом. + + + + Without Rowid + Без rowid + + + + Database sche&ma + + + + + Fields + ÐŸÐ¾Ð»Ñ + + + + Add + + + + + Remove + + + + + Move to top + + + + + Move up + + + + + Move down + + + + + Move to bottom + + + + + + Name + Ð˜Ð¼Ñ + + + + + Type + Тип + + + + NN + ÐП + + + + Not null + Ðе пуÑтое (null) + + + + PK + ПК + + + + Primary key + Первичный ключ + + + + AI + ÐИ + + + + Autoincrement + Ðвтоинкремент + + + + U + У + + + + + + Unique + Уникальное + + + + Default + По умолчанию + + + + Default value + Значение по умолчанию + + + + + + Check + Проверить + + + + Check constraint + Проверить ограничение + + + + Collation + + + + + + + Foreign Key + Внешний ключ + + + + Constraints + + + + + Add constraint + + + + + Remove constraint + + + + + Columns + Столбцы + + + + SQL + + + + + <html><head/><body><p><span style=" font-weight:600; color:#ff0000;">Warning: </span>There is something with this table definition that our parser doesn't fully understand. Modifying and saving this table might result in problems.</p></body></html> + <html><head/><body><p><span style=" font-weight:600; color:#ff0000;">Внимание: </span>Ð’ опиÑании Ñтой таблицы еÑть что-то, что наш парÑер не понимает. ÐœÐ¾Ð´Ð¸Ñ„Ð¸ÐºÐ°Ñ†Ð¸Ñ Ð¸ Ñохрание Ñтой таблицы может породить проблемы.</p></body></html> + + + + + Primary Key + + + + + Add a primary key constraint + + + + + Add a foreign key constraint + + + + + Add a unique constraint + + + + + Add a check constraint + + + + + Error creating table. Message from database engine: +%1 + Ошибка ÑÐ¾Ð·Ð´Ð°Ð½Ð¸Ñ Ñ‚Ð°Ð±Ð»Ð¸Ñ†Ñ‹. Сообщение от движка базы данных: %1 + + + + There already is a field with that name. Please rename it first or choose a different name for this field. + Поле Ñ Ñ‚Ð°ÐºÐ¸Ð¼ именем уже ÑущеÑтвует. ПожалуйÑта переименуйте его, либо выберите другое Ð¸Ð¼Ñ Ð´Ð»Ñ Ð´Ð°Ð½Ð½Ð¾Ð³Ð¾ полÑ. + + + + + There can only be one primary key for each table. Please modify the existing primary key instead. + + + + + This column is referenced in a foreign key in table %1 and thus its name cannot be changed. + Ðа данную колонку ÑÑылкаетÑÑ Ð²Ð½ÐµÑˆÐ½Ð¸Ð¹ ключ в таблице %1, поÑтому ее Ð¸Ð¼Ñ Ð½Ðµ может быть изменено. + + + + There is at least one row with this field set to NULL. This makes it impossible to set this flag. Please change the table data first. + СущеÑтвует по крайней мере одна Ñтрока, где Ñто поле уÑтановлено в NULL. УÑтановить Ñтот флаг нельзÑ. Сначала измените данные таблицы. + + + + There is at least one row with a non-integer value in this field. This makes it impossible to set the AI flag. Please change the table data first. + СущеÑтвует по крайней мере одна Ñтрока, где Ñто поле Ñодержит нечиÑловое значение. УÑтановить флаг ÐИ нельзÑ. Сначала измените данные таблицы. + + + + Column '%1' has duplicate data. + + + + + + This makes it impossible to enable the 'Unique' flag. Please remove the duplicate data, which will allow the 'Unique' flag to then be enabled. + + + + + Are you sure you want to delete the field '%1'? +All data currently stored in this field will be lost. + Удалить поле '%1'? +Ð’Ñе данные, которые в наÑтоÑщий момент Ñохранены в Ñтом поле, будут потерÑны. + + + + Please add a field which meets the following criteria before setting the without rowid flag: + - Primary key flag set + - Auto increment disabled + Перед тем как применÑть флаг без rowid, пожалуйÑта убедитеÑÑŒ, что ÑущеÑтвует Ñтолбец, который: + - ÑвлÑетÑÑ Ð¿ÐµÑ€Ð²Ð¸Ñ‡Ð½Ñ‹Ð¹ ключом + - Ð´Ð»Ñ Ð½ÐµÐ³Ð¾ отключен автоинкремент + + + + ExportDataDialog + + + Export data as CSV + ЭкÑпортировать данные в формате CSV + + + + Tab&le(s) + &Таблицы + + + + Colu&mn names in first line + &Имена Ñтолбцов в первой Ñтроке + + + + Fie&ld separator + &Разделитель полей + + + + , + , + + + + ; + ; + + + + Tab + ТабулÑÑ†Ð¸Ñ + + + + | + | + + + + + + Other + Другой + + + + &Quote character + &Символ кавычки + + + + " + " + + + + ' + ' + + + + New line characters + Разделитель Ñтрок + + + + Windows: CR+LF (\r\n) + + + + + Unix: LF (\n) + + + + + Pretty print + КраÑивый вывод + + + + + Could not open output file: %1 + Ðе удалоÑÑŒ открыть выходной файл: %1 + + + + + Choose a filename to export data + Выберите Ð¸Ð¼Ñ Ñ„Ð°Ð¹Ð»Ð° Ð´Ð»Ñ ÑкÑпорта данных + + + + Export data as JSON + ЭкÑпортировать данные как JSON + + + + exporting CSV + ÑкÑпортирование CSV + + + + exporting JSON + ÑкÑпортирование JSON + + + + Please select at least 1 table. + ПожалуйÑта, выберите Ñ…Ð¾Ñ‚Ñ Ð±Ñ‹ одну таблицу. + + + + Choose a directory + Выберать каталог + + + + Export completed. + ЭкÑпорт завершён. + + + + ExportSqlDialog + + + Export SQL... + ЭкÑпорт SQL.... + + + + Tab&le(s) + &Таблицы + + + + Select All + Выбрать вÑе + + + + Deselect All + Отменить выбор + + + + &Options + &Опции + + + + Keep column names in INSERT INTO + Ð˜Ð¼Ñ Ñтолбцов в выражении INSERT INTO + + + + Multiple rows (VALUES) per INSERT statement + ÐеÑколько Ñтрок (VALUES) на INSERT выражение + + + + Export everything + ЭкÑпортировать вÑе + + + + Export data only + ЭкÑпортировать только данные + + + + Keep old schema (CREATE TABLE IF NOT EXISTS) + ПроверÑть ÑущеÑтвоватние таблицы (CREATE TABLE IF NOT EXISTS) + + + + Overwrite old schema (DROP TABLE, then CREATE TABLE) + УдалÑть Ñтарую таблицу перед Ñозданием (DROP TABLE, затем CREATE TABLE) + + + + Export schema only + ЭкÑпортировать только Ñхему данных + + + + Please select at least one table. + ПожалуйÑта, выберите Ñ…Ð¾Ñ‚Ñ Ð±Ñ‹ одну таблицу. + + + + Choose a filename to export + Выберите Ð¸Ð¼Ñ Ñ„Ð°Ð¹Ð»Ð° Ð´Ð»Ñ ÑкÑпорта + + + + Export completed. + ЭкÑпорт завершён. + + + + Export cancelled or failed. + ЭкÑпорт отменён или возникли ошибки. + + + + ExtendedScintilla + + + + Ctrl+H + + + + + Ctrl+F + + + + + + Ctrl+P + + + + + Find... + + + + + Find and Replace... + Ðайти и Заменить... + + + + Print... + Печать... + + + + ExtendedTableWidget + + + Use as Exact Filter + ИÑпользовать как Точный Фильтр + + + + Containing + Содержит + + + + Not containing + + + + + Not equal to + Ðе равно + + + + Greater than + Больше чем + + + + Less than + Меньше чем + + + + Greater or equal + Больше или равно + + + + Less or equal + Меньше или равно + + + + Between this and... + Между Ñтим и... + + + + Regular expression + + + + + Edit Conditional Formats... + + + + + Set to NULL + СброÑить в NULL + + + + Copy + Копировать + + + + Copy with Headers + Копировать Ñ Ð·Ð°Ð³Ð¾Ð»Ð¾Ð²ÐºÐ°Ð¼Ð¸ + + + + Copy as SQL + Копировать как SQL + + + + Paste + Ð’Ñтавить + + + + Print... + Печать... + + + + Use in Filter Expression + ИÑпользовать в Выражении Фильтра + + + + Alt+Del + + + + + Ctrl+Shift+C + + + + + Ctrl+Alt+C + + + + + The content of the clipboard is bigger than the range selected. +Do you want to insert it anyway? + Содержимое буфера обмена больше чем выделенный диапозон. +Ð’Ñе равно вÑтавить? + + + + <p>Not all data has been loaded. <b>Do you want to load all data before selecting all the rows?</b><p><p>Answering <b>No</b> means that no more data will be loaded and the selection will not be performed.<br/>Answering <b>Yes</b> might take some time while the data is loaded but the selection will be complete.</p>Warning: Loading all the data might require a great amount of memory for big tables. + + + + + Cannot set selection to NULL. Column %1 has a NOT NULL constraint. + + + + + FileExtensionManager + + + File Extension Manager + Менеджер раÑÑˆÐ¸Ñ€ÐµÐ½Ð¸Ñ Ñ„Ð°Ð¹Ð»Ð¾Ð² + + + + &Up + &Выше + + + + &Down + &Ðиже + + + + &Add + &Добавить + + + + &Remove + &Удалить + + + + + Description + ОпиÑание + + + + Extensions + РаÑÑˆÐ¸Ñ€ÐµÐ½Ð¸Ñ + + + + *.extension + + + + + FilterLineEdit + + + Filter + Фильтр + + + + These input fields allow you to perform quick filters in the currently selected table. +By default, the rows containing the input text are filtered out. +The following operators are also supported: +% Wildcard +> Greater than +< Less than +>= Equal to or greater +<= Equal to or less += Equal to: exact match +<> Unequal: exact inverse match +x~y Range: values between x and y +/regexp/ Values matching the regular expression + + + + + Clear All Conditional Formats + + + + + Use for Conditional Format + + + + + Edit Conditional Formats... + + + + + Set Filter Expression + УÑтановить Выражение Фильтра + + + + What's This? + Что Это? + + + + Is NULL + NULL + + + + Is not NULL + не NULL + + + + Is empty + пуÑто + + + + Is not empty + не пуÑто + + + + Not containing... + + + + + Equal to... + Равно... + + + + Not equal to... + Ðе равно... + + + + Greater than... + Больше чем... + + + + Less than... + Меньше чем... + + + + Greater or equal... + Больше или равно... + + + + Less or equal... + Меньше или равно... + + + + In range... + Ð’ диапазоне... + + + + Regular expression... + + + + + FindReplaceDialog + + + Find and Replace + ПоиÑк и Замена + + + + Fi&nd text: + &ТекÑÑ‚ Ð´Ð»Ñ Ð¿Ð¾Ð¸Ñка: + + + + Re&place with: + ТекÑÑ‚ Ð´Ð»Ñ &замены: + + + + Match &exact case + Учитывать &региÑтр + + + + Match &only whole words + Слова &целиком + + + + When enabled, the search continues from the other end when it reaches one end of the page + Когда отмечено, поиÑк продолжаетÑÑ Ñ Ð´Ñ€ÑƒÐ³Ð¾Ð³Ð¾ конца, когда он доÑтигает противоположного конца Ñтраницы + + + + &Wrap around + &Закольцевать + + + + When set, the search goes backwards from cursor position, otherwise it goes forward + Когда отмечено, поиÑк возвращаетÑÑ Ð½Ð°Ð·Ð°Ð´ из Ð¿Ð¾Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ ÐºÑƒÑ€Ñора, в противном Ñлучае он идет вперед + + + + Search &backwards + ИÑкать в &обратном порÑдке + + + + <html><head/><body><p>When checked, the pattern to find is searched only in the current selection.</p></body></html> + + + + + &Selection only + + + + + <html><head/><body><p>When checked, the pattern to find is interpreted as a UNIX regular expression. See <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>.</p></body></html> + <html><head/><body><p>При проверке шаблон Ð´Ð»Ñ Ð¿Ð¾Ð¸Ñка интерпретируетÑÑ ÐºÐ°Ðº регулÑрное выражение UNIX. <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Узнать больше о РегулÑрных выражениÑÑ… на Wikibooks.org</a>.</p></body></html> + + + + Use regular e&xpressions + &РегулÑрные Ð²Ñ‹Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ + + + + Find the next occurrence from the cursor position and in the direction set by "Search backwards" + Ðайдите Ñледующее вхождение из позиции курÑора и в направлении, заданном "ИÑкать назад" + + + + &Find Next + ИÑкать &дальше + + + + F3 + + + + + &Replace + &Замена + + + + Highlight all the occurrences of the text in the page + Выделить вÑе Ð²Ñ…Ð¾Ð¶Ð´ÐµÐ½Ð¸Ñ Ñ‚ÐµÐºÑта на Ñтранице + + + + F&ind All + Ðайти &вÑе + + + + Replace all the occurrences of the text in the page + Заменить вÑе Ð²Ñ…Ð¾Ð¶Ð´ÐµÐ½Ð¸Ñ Ñ‚ÐµÐºÑта на Ñтранице + + + + Replace &All + За&менить вÑе + + + + The searched text was not found + ИÑкомый текÑÑ‚ не найден + + + + The searched text was not found. + ИÑкомый текÑÑ‚ не найден. + + + + The searched text was found one time. + ИÑкомый текÑÑ‚ найден один раз. + + + + The searched text was found %1 times. + ИÑкомый текÑÑ‚ найден %1 раз. + + + + The searched text was replaced one time. + ИÑкомый текÑÑ‚ заменен один раз. + + + + The searched text was replaced %1 times. + ИÑкомый текÑÑ‚ заменен %1 раз. + + + + ForeignKeyEditor + + + &Reset + &Ð¡Ð±Ñ€Ð¾Ñ + + + + Foreign key clauses (ON UPDATE, ON DELETE etc.) + УÑÐ»Ð¾Ð²Ð¸Ñ (ON UPDATE, ON DELETE и Ñ‚.д.) + + + + ImportCsvDialog + + + Import CSV file + Импортировать файл в формате CSV + + + + Table na&me + &Ð˜Ð¼Ñ Ñ‚Ð°Ð±Ð»Ð¸Ñ†Ñ‹ + + + + &Column names in first line + И&мена Ñтолбцов в первой Ñтроке + + + + Field &separator + &Разделитель полей + + + + , + + + + + ; + + + + + + Tab + ТабулÑÑ†Ð¸Ñ + + + + | + + + + + Other + Другой + + + + &Quote character + &Символ кавычки + + + + + Other (printable) + + + + + + Other (code) + + + + + " + + + + + ' + + + + + &Encoding + &Кодировка + + + + UTF-8 + + + + + UTF-16 + + + + + ISO-8859-1 + + + + + Trim fields? + Обрезать полÑ? + + + + Separate tables + Отдельные таблицы + + + + Advanced + Дополнительно + + + + When importing an empty value from the CSV file into an existing table with a default value for this column, that default value is inserted. Activate this option to insert an empty value instead. + При импорте пуÑтого Ð·Ð½Ð°Ñ‡ÐµÐ½Ð¸Ñ Ð¸Ð· файла CSV в ÑущеÑтвующую таблицу Ð´Ð»Ñ Ñтолбца Ñ ÑƒÐºÐ°Ð·Ð°Ð½Ð½Ñ‹Ð¼ значением по умолчанию оно будет вÑтавлено. Ðктивируйте Ñту опцию, чтобы вмеÑто Ñтого вÑтавить пуÑтое значение. + + + + Ignore default &values + Игнорировать значение &по-умолчанию + + + + Activate this option to stop the import when trying to import an empty value into a NOT NULL column without a default value. + Ðктивируйте Ñту опцию чтобы прекратить импорт при попытке импорта пуÑтого Ð·Ð½Ð°Ñ‡ÐµÐ½Ð¸Ñ Ð² NOT NULL колонку без Ð·Ð½Ð°Ñ‡ÐµÐ½Ð¸Ñ Ð¿Ð¾-умолчанию. + + + + Fail on missing values + Ошибка при отÑутÑтвии значений + + + + Disable data type detection + Отключить определение типа данных + + + + Disable the automatic data type detection when creating a new table. + Отключить автоматичеÑкое определение типа при Ñоздании новой таблицы. + + + + When importing into an existing table with a primary key, unique constraints or a unique index there is a chance for a conflict. This option allows you to select a strategy for that case: By default the import is aborted and rolled back but you can also choose to ignore and not import conflicting rows or to replace the existing row in the table. + + + + + Abort import + + + + + Ignore row + + + + + Replace existing row + + + + + Conflict strategy + + + + + + Deselect All + Отменить Выбор + + + + Match Similar + Ðайти Ð¡Ð¾Ð²Ð¿Ð°Ð´ÐµÐ½Ð¸Ñ + + + + Select All + Выбрать Ð’Ñе + + + + There is already a table named '%1' and an import into an existing table is only possible if the number of columns match. + Уже ÑущеÑтвует таблица Ñ Ð¸Ð¼ÐµÐ½ÐµÐ¼ '%1' и импорт в ÑущеÑтвующую таблицу возможен, только еÑли чиÑло Ñтолбцов Ñовпадает. + + + + There is already a table named '%1'. Do you want to import the data into it? + Уже ÑущеÑтвует таблица Ñ Ð¸Ð¼ÐµÐ½ÐµÐ¼ '%1'. Ð’Ñ‹ хотите импортировать данные в нее? + + + + Creating restore point failed: %1 + Ошибка ÑÐ¾Ð·Ð½Ð°Ð½Ð¸Ñ Ñ‚Ð¾Ñ‡ÐºÐ¸ воÑÑтановлениÑ: %1 + + + + Creating the table failed: %1 + Ошибка ÑÐ¾Ð·Ð´Ð°Ð½Ð¸Ñ Ñ‚Ð°Ð±Ð»Ð¸Ñ†Ñ‹: %1 + + + + importing CSV + импортирование CSV + + + + Importing the file '%1' took %2ms. Of this %3ms were spent in the row function. + Импорт файла '%1' занÑл %2мÑ. Из них %3Ð¼Ñ Ð±Ñ‹Ð»Ð¾ потрачено в функции Ñтроки. + + + + Inserting row failed: %1 + Ошибка вÑтавки Ñтроки: %1 + + + + MainWindow + + + DB Browser for SQLite + Обозреватель Ð´Ð»Ñ SQLite + + + + toolBar1 + панельИнÑтрументов1 + + + + Warning: this pragma is not readable and this value has been inferred. Writing the pragma might overwrite a redefined LIKE provided by an SQLite extension. + Предупреждение: Ñта прагма не читаетÑÑ, и Ñто значение было выведено. Применение прагмы может перезапиÑать переопределенный LIKE, предоÑтавлÑемый раÑширением SQLite. + + + + &Tools + &ИнÑтрументы + + + + Error Log + + + + + This button clears the contents of the SQL logs + Эта кнопка очищает Ñодержимое журналов SQL + + + + This panel lets you examine a log of all SQL commands issued by the application or by yourself + Эта панель позволÑет вам проÑматривать журнал вÑех SQL-команд, выданных приложением или вами + + + + This is the structure of the opened database. +You can drag multiple object names from the Name column and drop them into the SQL editor and you can adjust the properties of the dropped names using the context menu. This would help you in composing SQL statements. +You can drag SQL statements from the Schema column and drop them into the SQL editor or into other applications. + + Это Ñтруктура открытой БД. +Ð’Ñ‹ можете перетащить неÑколько имен объектов из Ñтолбца "ИмÑ" и отброÑить их в редактор SQL, и вы можете наÑтроить ÑвойÑтва Ñброшенных имен Ñ Ð¿Ð¾Ð¼Ð¾Ñ‰ÑŒÑŽ контекÑтного меню. Это поможет вам при ÑоÑтавлении SQL-инÑтрукций. +Ð’Ñ‹ можете перетаÑкивать операторы SQL из Ñтолбца "Схема" и переноÑить их в редактор SQL или в другие приложениÑ. + + + + + + Project Toolbar + Панель ИнÑтрументов Проекта + + + + Extra DB toolbar + Ð”Ð¾Ð¿Ð¾Ð»Ð½Ð¸Ñ‚ÐµÐ»ÑŒÐ½Ð°Ñ ÐŸÐ°Ð½ÐµÐ»ÑŒ ИнÑтрументов БД + + + + + + Close the current database file + Закрыть файл текущей БД + + + + Ctrl+F4 + + + + + &About + О &программе + + + + This button opens a new tab for the SQL editor + Эта кнопка открывает новую вкладку Ð´Ð»Ñ Ñ€ÐµÐ´Ð°ÐºÑ‚Ð¾Ñ€Ð° SQL + + + + Execute all/selected SQL + Выполнить вÑе/выбранный SQL + + + + This button executes the currently selected SQL statements. If no text is selected, all SQL statements are executed. + Эта кнопка выполнÑет текущие выбранные операторы SQL. ЕÑли в текÑтовом редакторе ничего не выбрано , вÑе инÑтрукции SQL выполнÑÑŽÑ‚ÑÑ. + + + + &Load Extension... + &Загрузить раÑширение... + + + + Execute line + + + + + This button executes the SQL statement present in the current editor line + Эта кнопка выполнÑет оператор SQL, приÑутÑтвующий в текущей Ñтроке редактора + + + + &Wiki + &Вики + + + + F1 + + + + + Bug &Report... + Баг &репорт... + + + + Feature Re&quest... + ЗапроÑить &функцию... + + + + Web&site + &Веб-Ñайт + + + + &Donate on Patreon... + Сделать &пожертвование в Patreon... + + + + Open &Project... + Открыть &проект... + + + + &Attach Database... + &Прикрепить БД... + + + + + Add another database file to the current database connection + Добавить другой файл БД в текущее Ñоединение + + + + This button lets you add another database file to the current database connection + Эта кнопка позволÑет добавить другой файл БД в текущее Ñоединение Ñ Ð‘Ð” + + + + &Set Encryption... + Ðазначитть &шифрование... + + + + This button saves the content of the current SQL editor tab to a file + Эта кнопка ÑохранÑет Ñодержимое текущей вкладки редактора SQL в файл + + + + SQLCipher &FAQ + + + + + Table(&s) to JSON... + Таблицы в файл &JSON... + + + + Open Data&base Read Only... + Открыть БД &только Ð´Ð»Ñ Ñ‡Ñ‚ÐµÐ½Ð¸Ñ... + + + + Ctrl+Shift+O + + + + + Save results + Сохранить результаты + + + + Save the results view + Сохранить результаты + + + + This button lets you save the results of the last executed query + Эта кнопка позволÑет Ñохранить результаты поÑледнего выполненного запроÑа + + + + + Find text in SQL editor + Ðайти текÑÑ‚ в редакторе SQL + + + + Find + + + + + This button opens the search bar of the editor + Эта кнопка открывает панель поиÑка редактора + + + + Ctrl+F + + + + + + Find or replace text in SQL editor + Ðайти или заменить текÑÑ‚ в редакторе SQL + + + + Find or replace + + + + + This button opens the find/replace dialog for the current editor tab + Эта кнопка открывает диалог поиÑка/замены Ð´Ð»Ñ Ñ‚ÐµÐºÑƒÑ‰ÐµÐ¹ вкладки редактора + + + + Ctrl+H + + + + + Export to &CSV + ЭкÑпортировать в &CSV + + + + Save as &view + Сохранить как &предÑтавление + + + + Save as view + Сохранить как предÑтавление + + + + Shows or hides the Project toolbar. + Показывает или Ñкрывает панель инÑтрументов Проекта. + + + + Extra DB Toolbar + Ð”Ð¾Ð¿Ð¾Ð»Ð½Ð¸Ñ‚ÐµÐ»ÑŒÐ½Ð°Ñ ÐŸÐ°Ð½ÐµÐ»ÑŒ ИнÑтрументов БД + + + + Open SQL file(s) + + + + + This button opens files containing SQL statements and loads them in new editor tabs + + + + + This button lets you open a DB Browser for SQLite project file + + + + + New In-&Memory Database + ÐÐ¾Ð²Ð°Ñ Ð‘Ð” в &ПамÑти + + + + Drag && Drop Qualified Names + Квалифицированные имена при перетакÑкивании + + + + + Use qualified names (e.g. "Table"."Field") when dragging the objects and dropping them into the editor + Квалифицированные имена (например, "Table"."Field") при перетаÑкивании объектов в редактор + + + + Drag && Drop Enquoted Names + Экранированные имена при перетаÑкивании + + + + + Use escaped identifiers (e.g. "Table1") when dragging the objects and dropping them into the editor + Экранировать имена идентификаторов (например, "Table1"), когда перетаÑкиваютÑÑ Ð¾Ð±ÑŠÐµÐºÑ‚Ñ‹ в редактор + + + + &Integrity Check + Проверка &ЦелоÑтноÑти + + + + Runs the integrity_check pragma over the opened database and returns the results in the Execute SQL tab. This pragma does an integrity check of the entire database. + ВыполнÑет прагму integrity_check Ð´Ð»Ñ Ð¾Ñ‚ÐºÑ€Ñ‹Ñ‚Ð¾Ð¹ БД и возвращает результаты во вкладке "SQL". Эта прагма выполнÑет проверку целоÑтноÑти вÑей базы данных. + + + + &Foreign-Key Check + Проверка &Внешних ключей + + + + Runs the foreign_key_check pragma over the opened database and returns the results in the Execute SQL tab + ЗапуÑкает прагму foreign_key_check Ð´Ð»Ñ Ð¾Ñ‚ÐºÑ€Ñ‹Ñ‚Ð¾Ð¹ БД и возвращает результаты во вкладке "SQL" + + + + &Quick Integrity Check + &БыÑÑ‚Ñ€Ð°Ñ ÐŸÑ€Ð¾Ð²ÐµÑ€ÐºÐ° ЦелоÑтноÑти + + + + Run a quick integrity check over the open DB + ЗапуÑк быÑтрой проверки целоÑтноÑти Ð´Ð»Ñ Ð¾Ñ‚ÐºÑ€Ñ‹Ñ‚Ñ‹Ð¹ БД + + + + Runs the quick_check pragma over the opened database and returns the results in the Execute SQL tab. This command does most of the checking of PRAGMA integrity_check but runs much faster. + ЗапуÑкает прагму quick_check Ð´Ð»Ñ Ð¾Ñ‚ÐºÑ€Ñ‹Ñ‚Ð¾Ð¹ БД и возвращает результаты во вкладке "SQL". Эта команда выполнÑет большую чаÑть проверки PRAGMA integrity_check, но работает намного быÑтрее. + + + + &Optimize + &ÐžÐ¿Ñ‚Ð¸Ð¼Ð¸Ð·Ð°Ñ†Ð¸Ñ + + + + Attempt to optimize the database + Попытка оптимизации БД + + + + Runs the optimize pragma over the opened database. This pragma might perform optimizations that will improve the performance of future queries. + ВыполнÑет прагму optimize Ð´Ð»Ñ Ð¾Ñ‚ÐºÑ€Ñ‹Ñ‚Ð¾Ð¹ БД. Эта прагма может выполнÑть оптимизацию, ÐºÐ¾Ñ‚Ð¾Ñ€Ð°Ñ ÑƒÐ»ÑƒÑ‡ÑˆÐ¸Ñ‚ производительноÑть будущих запроÑов. + + + + + Print + Печать + + + + Print text from current SQL editor tab + Печать текÑта изтекущей вкладки редактора SQL + + + + Open a dialog for printing the text in the current SQL editor tab + Открывает диалоговое окно Ð´Ð»Ñ Ð¿ÐµÑ‡Ð°Ñ‚Ð¸ текÑта из текущей вкладки редактора SQL + + + + Print the structure of the opened database + Печать Ñтруктуры открытой БД + + + + Open a dialog for printing the structure of the opened database + Открывает диалоговое окно Ð´Ð»Ñ Ð¿ÐµÑ‡Ð°Ñ‚Ð¸ Ñтруктуры текущей БД + + + + Un/comment block of SQL code + + + + + Un/comment block + + + + + Comment or uncomment current line or selected block of code + + + + + Comment or uncomment the selected lines or the current line, when there is no selection. All the block is toggled according to the first line. + + + + + Ctrl+/ + + + + + Stop SQL execution + + + + + Stop execution + + + + + Stop the currently running SQL script + + + + + Browse Table + + + + + &Save Project As... + + + + + + + Save the project in a file selected in a dialog + + + + + Save A&ll + + + + + + + Save DB file, project file and opened SQL files + + + + + Ctrl+Shift+S + + + + + &File + &Файл + + + + &Import + &Импорт + + + + &Export + &ЭкÑпорт + + + + &Edit + &Редактирование + + + + &View + &Вид + + + + &Help + &Справка + + + + DB Toolbar + Панель инÑтрументов БД + + + + Edit Database &Cell + Редактирование &Ñчейки БД + + + + DB Sche&ma + Схе&ма БД + + + + &Remote + &Удаленный Ñервер + + + + + Execute current line + Выполнить текущую Ñтроку + + + + Shift+F5 + + + + + Sa&ve Project + &Сохранить проект + + + + Open an existing database file in read only mode + Открыть ÑущеÑтвующий файл базы данных в режиме только Ð´Ð»Ñ Ñ‡Ñ‚ÐµÐ½Ð¸Ñ + + + + Opens the SQLCipher FAQ in a browser window + Открыть SQLCiphier FAQ в браузере + + + + Export one or more table(s) to a JSON file + ЭкÑпортировать таблицы в JSON файл + + + + + Save SQL file as + Сохранить файл SQL как + + + + &Browse Table + Пр&оÑмотр данных + + + + User + Пользователем + + + + Application + Приложением + + + + &Clear + О&чиÑтить + + + + &New Database... + &ÐÐ¾Ð²Ð°Ñ Ð±Ð°Ð·Ð° данных... + + + + + Create a new database file + Создать новый файл базы данных + + + + This option is used to create a new database file. + Эта Ð¾Ð¿Ñ†Ð¸Ñ Ð¸ÑпользуетÑÑ, чтобы Ñоздать новый файл базы данных. + + + + Ctrl+N + + + + + + &Open Database... + &Открыть базу данных... + + + + + + + + Open an existing database file + Открыть ÑущеÑтвующий файл базы данных + + + + + + This option is used to open an existing database file. + Эта Ð¾Ð¿Ñ†Ð¸Ñ Ð¸ÑпользуетÑÑ, чтобы открыть ÑущеÑтвующий файл базы данных. + + + + Ctrl+O + + + + + &Close Database + &Закрыть базу данных + + + + This button closes the connection to the currently open database file + Эта кнопка закрывает Ñоединение Ñ Ñ‚ÐµÐºÑƒÑ‰Ð¸Ð¼ файлом БД + + + + + Ctrl+W + + + + + + Revert database to last saved state + Вернуть базу данных в поÑледнее Ñохранённое ÑоÑтоÑние + + + + This option is used to revert the current database file to its last saved state. All changes made since the last save operation are lost. + Эта Ð¾Ð¿Ñ†Ð¸Ñ Ð¸ÑпользуетÑÑ, чтобы вернуть текущий файл базы данных в его поÑледнее Ñохранённое ÑоÑтоÑние. Ð’Ñе изменениÑ, Ñделаные Ñ Ð¿Ð¾Ñледней операции ÑÐ¾Ñ…Ñ€Ð°Ð½ÐµÐ½Ð¸Ñ Ñ‚ÐµÑ€ÑÑŽÑ‚ÑÑ. + + + + + Write changes to the database file + ЗапиÑать Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ð² файл базы данных + + + + This option is used to save changes to the database file. + Эта Ð¾Ð¿Ñ†Ð¸Ñ Ð¸ÑпользуетÑÑ, чтобы Ñохранить Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ð² файле базы данных. + + + + Ctrl+S + + + + + Compact &Database... + &Уплотнить базу данных... + + + + Compact the database file, removing space wasted by deleted records + Уплотнить базу данных, удалÑÑ Ð¿Ñ€Ð¾ÑтранÑтво, занимаемое удалёнными запиÑÑми + + + + + Compact the database file, removing space wasted by deleted records. + Уплотнить базу данных, удалÑÑ Ð¿Ñ€Ð¾ÑтранÑтво, занимаемое удалёнными запиÑÑми. + + + + E&xit + &Выход + + + + Ctrl+Q + + + + + Import data from an .sql dump text file into a new or existing database. + Импортировать данные из текÑтового файла sql в новую или ÑущеÑтвующую базу данных. + + + + This option lets you import data from an .sql dump text file into a new or existing database. SQL dump files can be created on most database engines, including MySQL and PostgreSQL. + Эта Ð¾Ð¿Ñ†Ð¸Ñ Ð¿Ð¾Ð·Ð²Ð¾Ð»Ñет импортировать данные из текÑтового файла sql в новую или ÑущеÑтвующую базу данных. Файл SQL может быть Ñоздан на большинÑтве движков баз данных, Ð²ÐºÐ»ÑŽÑ‡Ð°Ñ MySQL и PostgreSQL. + + + + Open a wizard that lets you import data from a comma separated text file into a database table. + Открыть маÑтер, который позволÑет импортировать данные из файла CSV в таблицу базы данных. + + + + Open a wizard that lets you import data from a comma separated text file into a database table. CSV files can be created on most database and spreadsheet applications. + Открыть маÑтер, который позволÑет импортировать данные из файла CSV в таблицу базы данных. Файлы CSV могут быть Ñозданы в большинÑтве приложений баз данных и Ñлектронных таблиц. + + + + Export a database to a .sql dump text file. + ЭкÑпортировать базу данных в текÑтовый файл .sql. + + + + This option lets you export a database to a .sql dump text file. SQL dump files contain all data necessary to recreate the database on most database engines, including MySQL and PostgreSQL. + Эта Ð¾Ð¿Ñ†Ð¸Ñ Ð¿Ð¾Ð·Ð²Ð¾Ð»Ñет ÑкÑпортировать базу данных в текÑтовый файл .sql. Файлы SQL Ñодержат вÑе данные, необходимые Ð´Ð»Ñ ÑÐ¾Ð·Ð´Ð°Ð½Ð¸Ñ Ð±Ð°Ð·Ñ‹ данных в большиÑтве движков баз данных, Ð²ÐºÐ»ÑŽÑ‡Ð°Ñ MySQL и PostgreSQL. + + + + Export a database table as a comma separated text file. + ЭкÑпортировать таблицу базы данных как CSV текÑтовый файл. + + + + Export a database table as a comma separated text file, ready to be imported into other database or spreadsheet applications. + ЭкÑпортировать таблицу базы данных как CSV текÑтовый файл, готовый Ð´Ð»Ñ Ð¸Ð¼Ð¿Ð¾Ñ€Ñ‚Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ Ð² другие базы данных или Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ñлектронных таблиц. + + + + Open the Create Table wizard, where it is possible to define the name and fields for a new table in the database + Открыть маÑтер ÑÐ¾Ð·Ð´Ð°Ð½Ð¸Ñ Ñ‚Ð°Ð±Ð»Ð¸Ñ†, где возможно определить Ð¸Ð¼Ñ Ð¸ Ð¿Ð¾Ð»Ñ Ð´Ð»Ñ Ð½Ð¾Ð²Ð¾Ð¹ таблиы в базе данных + + + + Open the Delete Table wizard, where you can select a database table to be dropped. + Открыть маÑтер ÑƒÐ´Ð°Ð»ÐµÐ½Ð¸Ñ Ñ‚Ð°Ð±Ð»Ð¸Ñ†Ñ‹, где можно выбрать таблицу базы данных Ð´Ð»Ñ ÑƒÐ´Ð°Ð»ÐµÐ½Ð¸Ñ. + + + + Open the Modify Table wizard, where it is possible to rename an existing table. It is also possible to add or delete fields form a table, as well as modify field names and types. + Открыть маÑтер Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ñ‚Ð°Ð±Ð»Ð¸Ñ†Ñ‹, где возможно переименовать ÑущеÑтвующую таблиц. Можно добавить или удалить Ð¿Ð¾Ð»Ñ Ñ‚Ð°Ð±Ð»Ð¸Ñ†Ñ‹, так же изменÑть имена полей и типы. + + + + Open the Create Index wizard, where it is possible to define a new index on an existing database table. + Открыть маÑтер ÑÐ¾Ð·Ð´Ð°Ð½Ð¸Ñ Ð¸Ð½Ñ‚ÐµÐºÑа, в котором можно определить новый Ð¸Ð½Ð´ÐµÐºÑ Ð´Ð»Ñ ÑущеÑтвующей таблиц базы данных. + + + + &Preferences... + &ÐаÑтройки... + + + + + Open the preferences window. + Открыть окно наÑтроек. + + + + &DB Toolbar + &Панель инÑтрументов БД + + + + Shows or hides the Database toolbar. + Показать или Ñкрыть панель инÑтрументов База данных. + + + + Shift+F1 + + + + + &Recently opened + &Ðедавно открываемые + + + + Open &tab + Открыть &вкладку + + + + Ctrl+T + + + + + + Database Structure + This has to be equal to the tab title in all the main tabs + Структура БД + + + + This is the structure of the opened database. +You can drag SQL statements from an object row and drop them into other applications or into another instance of 'DB Browser for SQLite'. + + Это Ñтруктура открытой БД. +Ð’Ñ‹ можете перетаÑкивать операторы SQL из Ñтроки "объект" и переноÑить их в другие Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð¸Ð»Ð¸ в другой ÑкземплÑÑ€ "Обозреватель Ð´Ð»Ñ SQLite". + + + + + + Browse Data + This has to be equal to the tab title in all the main tabs + Данные + + + + + Edit Pragmas + This has to be equal to the tab title in all the main tabs + Прагмы + + + + + Execute SQL + This has to be equal to the tab title in all the main tabs + SQL + + + + SQL &Log + &Журнал SQL + + + + Show S&QL submitted by + По&казывать SQL, выполненный + + + + &Plot + &График + + + + &Revert Changes + &Отменить Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ + + + + &Write Changes + &ЗапиÑать Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ + + + + &Database from SQL file... + &База данных из файла SQL... + + + + &Table from CSV file... + &Таблицы из файла CSV... + + + + &Database to SQL file... + Базу &данных в файл SQL... + + + + &Table(s) as CSV file... + &Таблицы в файл CSV... + + + + &Create Table... + &Создать таблицу... + + + + &Delete Table... + &Удалить таблицу... + + + + &Modify Table... + &Изменить таблицу... + + + + Create &Index... + Создать и&ндекÑ... + + + + W&hat's This? + Что &Ñто такое? + + + + &Execute SQL + Ð’&ыполнить код SQL + + + + + + Save SQL file + Сохранить файл SQL + + + + Ctrl+E + + + + + Export as CSV file + ЭкÑпортировать в файл CSV + + + + Export table as comma separated values file + ЭкÑпортировать таблицу как CSV файл + + + + + Save the current session to a file + Сохранить текущее ÑоÑтоÑние в файл + + + + This button lets you save all the settings associated to the open DB to a DB Browser for SQLite project file + + + + + + Load a working session from a file + Загрузить рабочее ÑоÑтоÑние из файла + + + + Copy Create statement + Копировать CREATE выражение + + + + Copy the CREATE statement of the item to the clipboard + Копировать CREATE выражение Ñлемента в буффер обмена + + + + Ctrl+Return + + + + + Ctrl+L + + + + + + Ctrl+P + + + + + Ctrl+D + + + + + Ctrl+I + + + + + Reset Window Layout + + + + + Alt+0 + + + + + The database is currenctly busy. + + + + + Click here to interrupt the currently running query. + + + + + Encrypted + Зашифровано + + + + Read only + Только Ð´Ð»Ñ Ñ‡Ñ‚ÐµÐ½Ð¸Ñ + + + + Database file is read only. Editing the database is disabled. + База данных только Ð´Ð»Ñ Ñ‡Ñ‚ÐµÐ½Ð¸Ñ. Редактирование запрещено. + + + + Database encoding + Кодировка базы данных + + + + Database is encrypted using SQLCipher + База данных зашифрована Ñ Ð¸Ñпользованием SQLCipher + + + + + Choose a database file + Выбрать файл базы данных + + + + Could not open database file. +Reason: %1 + Ðе удалоÑÑŒ открыть файл базы данных. +Причина:%1 + + + + + + Choose a filename to save under + Выбрать имÑ, под которым Ñохранить данные + + + + A new DB Browser for SQLite version is available (%1.%2.%3).<br/><br/>Please download at <a href='%4'>%4</a>. + Вышла Ð½Ð¾Ð²Ð°Ñ Ð²ÐµÑ€ÑÐ¸Ñ ÐžÐ±Ð¾Ð·Ñ€ÐµÐ²Ð°Ñ‚ÐµÐ»Ñ Ð´Ð»Ñ SQLite (%1.%2.%3).<br/><br/>Она доÑтупна Ð´Ð»Ñ ÑÐºÐ°Ñ‡Ð¸Ð²Ð°Ð½Ð¸Ñ Ð¿Ð¾ адреÑу <a href='%4'>%4</a>. + + + + DB Browser for SQLite project file (*.sqbpro) + Файл проекта ÐžÐ±Ð¾Ð·Ñ€ÐµÐ²Ð°Ñ‚ÐµÐ»Ñ Ð´Ð»Ñ SQLite (*.sqbpro) + + + + Error while saving the database file. This means that not all changes to the database were saved. You need to resolve the following error first. + +%1 + Ошибка при Ñохранении файла базы данных. Это означает, что не вÑе Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ð² базе данных были Ñохранены. Сначала вам необходимо разрешить Ñледующую ошибку. + +%1 + + + + Are you sure you want to undo all changes made to the database file '%1' since the last save? + Отменить вÑе изменениÑ, Ñделанные в файле базы данных '%1' поÑле поÑледнего ÑохранениÑ? + + + + Choose a file to import + Выберать файл Ð´Ð»Ñ Ð¸Ð¼Ð¿Ð¾Ñ€Ñ‚Ð° + + + + Text files(*.sql *.txt);;All files(*) + ТекÑтовые файлы(*.sql *.txt);;Ð’Ñе файлы(*) + + + + Do you want to create a new database file to hold the imported data? +If you answer no we will attempt to import the data in the SQL file to the current database. + Создать новый файл базы данных, чтобы Ñохранить импортированные данные? +ЕÑли ответить Ðет, будет выполнена попытка импортировать данные файла SQL в текущую базу данных. + + + + Window Layout + + + + + Simplify Window Layout + + + + + Shift+Alt+0 + + + + + Dock Windows at Bottom + + + + + Dock Windows at Left Side + + + + + Dock Windows at Top + + + + + You are still executing SQL statements. Closing the database now will stop their execution, possibly leaving the database in an inconsistent state. Are you sure you want to close the database? + + + + + Do you want to save the changes made to the project file '%1'? + + + + + Edit View %1 + + + + + Edit Trigger %1 + + + + + File %1 already exists. Please choose a different name. + Файл %1 уже ÑущеÑтвует. Выберите другое имÑ. + + + + Error importing data: %1 + Ошибка Ð¸Ð¼Ð¿Ð¾Ñ€Ñ‚Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ Ð´Ð°Ð½Ð½Ñ‹Ñ…: %1 + + + + Import completed. + Импорт завершён. + + + + Delete View + Удалить предÑтавление + + + + Modify View + Модифицировать предÑтавление + + + + Delete Trigger + Удалить триггер + + + + Modify Trigger + Модифицировать триггер + + + + Delete Index + Удалить Ð¸Ð½Ð´ÐµÐºÑ + + + + Opened '%1' in read-only mode from recent file list + + + + + Opened '%1' from recent file list + + + + + &%1 %2%3 + &%1 %2%3 + + + + (read only) + + + + + Open Database or Project + + + + + Attach Database... + + + + + Import CSV file(s)... + + + + + Select the action to apply to the dropped file(s). <br/>Note: only 'Import' will process more than one file. + + + + + + + + + Do you want to save the changes made to SQL tabs in a new project file? + + + + + Do you want to save the changes made to the SQL file %1? + + + + + The statements in this tab are still executing. Closing the tab will stop the execution. This might leave the database in an inconsistent state. Are you sure you want to close the tab? + + + + + Could not find resource file: %1 + + + + + Choose a project file to open + Выберите файл проекта Ð´Ð»Ñ Ð¾Ñ‚ÐºÑ€Ñ‹Ñ‚Ð¸Ñ + + + + This project file is using an old file format because it was created using DB Browser for SQLite version 3.10 or lower. Loading this file format is still fully supported but we advice you to convert all your project files to the new file format because support for older formats might be dropped at some point in the future. You can convert your files by simply opening and re-saving them. + Этот файл проекта иÑпользует Ñтарый формат файла, потому что он был Ñоздан Ñ Ð¸Ñпользованием DB Browser Ð´Ð»Ñ SQLite верÑии 3.10 или ниже. Загрузка Ñтого формата по-прежнему полноÑтью поддерживаетÑÑ, но мы Ñоветуем вам преобразовать вÑе ваши файлы проекта в новый формат файла, поÑкольку поддержка более Ñтарых форматов может быть удалена в какой-то момент в будущем. Ð’Ñ‹ можете конвертировать ваши файлы, проÑто Ð¾Ñ‚ÐºÑ€Ñ‹Ð²Ð°Ñ Ð¸ повторно ÑохранÑÑ Ð¸Ñ…. + + + + Could not open project file for writing. +Reason: %1 + + + + + Busy (%1) + + + + + Error checking foreign keys after table modification. The changes will be reverted. + Ошибка проверки внешних ключей поÑле Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ñ‚Ð°Ð±Ð»Ð¸Ñ†Ñ‹. Ð˜Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ð±ÑƒÐ´ÑƒÑ‚ отменены. + + + + This table did not pass a foreign-key check.<br/>You should run 'Tools | Foreign-Key Check' and fix the reported issues. + Эта таблица не прошла проверку внешнего ключа. <br/> Ð’Ñ‹ должны запуÑтить "ИнÑтрументы | Проверка внешнего ключа"и иÑправить Ñообщенные проблемы. + + + + Execution finished with errors. + + + + + Execution finished without errors. + + + + + + Delete Table + Удалить таблицу + + + + Setting PRAGMA values will commit your current transaction. +Are you sure? + УÑтановка значений PRAGMA завершит текущую транзакцию. УÑтановить значениÑ? + + + + In-Memory database + БД в памÑти + + + + Are you sure you want to delete the table '%1'? +All data associated with the table will be lost. + Ð’Ñ‹ дейÑтвительно хотите удалить таблицу '%1'? +Ð’Ñе данные, ÑвÑзанные Ñ Ñ‚Ð°Ð±Ð»Ð¸Ñ†ÐµÐ¹, будут потерÑны. + + + + Are you sure you want to delete the view '%1'? + Ð’Ñ‹ дейÑтвительно хотите удалить предÑтавление '%1'? + + + + Are you sure you want to delete the trigger '%1'? + Ð’Ñ‹ дейÑтвительно хотите удалить триггер '%1'? + + + + Are you sure you want to delete the index '%1'? + Ð’Ñ‹ дейÑтвительно хотите удалить Ð¸Ð½Ð´ÐµÐºÑ '%1'? + + + + Error: could not delete the table. + Ошибка: не удалоÑÑŒ удалить таблицу. + + + + Error: could not delete the view. + Ошибка: не удалоÑÑŒ удалить предÑтавление. + + + + Error: could not delete the trigger. + Ошибка: не удалоÑÑŒ удалить триггер. + + + + Error: could not delete the index. + Ошибка: не удалоÑÑŒ удалить индекÑ. + + + + Message from database engine: +%1 + Сообщение от СУБД: +%1 + + + + Editing the table requires to save all pending changes now. +Are you sure you want to save the database? + Ð”Ð»Ñ Ñ€ÐµÐ´Ð°ÐºÑ‚Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ Ñ‚Ð°Ð±Ð»Ð¸Ñ†Ñ‹ необходимо Ñохранить вÑе ожидающие Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ ÑейчаÑ. +Ð’Ñ‹ дейÑтвительно хотите Ñохранить БД? + + + + You are already executing SQL statements. Do you want to stop them in order to execute the current statements instead? Note that this might leave the database in an inconsistent state. + + + + + -- EXECUTING SELECTION IN '%1' +-- + -- ВЫПОЛÐЕÐИЕ ВЫБОРКИ Ð’ '%1' +-- + + + + -- EXECUTING LINE IN '%1' +-- + -- ВЫПОЛÐЕÐИЕ СТРОКИ Ð’ '%1' +-- + + + + -- EXECUTING ALL IN '%1' +-- + -- ВЫПОЛÐЕÐИЕ ВСЕ Ð’ '%1' +-- + + + + + At line %1: + + + + + Result: %1 + + + + + Result: %2 + + + + + Setting PRAGMA values or vacuuming will commit your current transaction. +Are you sure? + УÑтановка значений PRAGMA или Ð²Ð°ÐºÑƒÑƒÐ¼Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ Ð¿Ñ€Ð¸Ð²ÐµÐ´ÐµÑ‚ к фикÑации текущей транзакции. +Уверены ли вы? + + + + This action will open a new SQL tab with the following statements for you to edit and run: + + + + + Rename Tab + + + + + Duplicate Tab + + + + + Close Tab + + + + + Opening '%1'... + + + + + There was an error opening '%1'... + + + + + Value is not a valid URL or filename: %1 + + + + + %1 rows returned in %2ms + %1 Ñтрок возвращено за %2Ð¼Ñ + + + + Choose text files + Выберите текÑтовые файлы + + + + Import completed. Some foreign key constraints are violated. Please fix them before saving. + Импорт завершен. Ðарушены некоторые Ð¾Ð³Ñ€Ð°Ð½Ð¸Ñ‡ÐµÐ½Ð¸Ñ Ð²Ð½ÐµÑˆÐ½Ð¸Ñ… ключей. ПожалуйÑта, иÑправьте их перед Ñохранением. + + + + Modify Index + Модифицировать Ð˜Ð½Ð´ÐµÐºÑ + + + + Modify Table + Модифицировать Таблицу + + + + Do you want to save the changes made to SQL tabs in the project file '%1'? + + + + + Select SQL file to open + Выбрать файл SQL Ð´Ð»Ñ Ð¾ÐºÑ‚Ñ€Ñ‹Ñ‚Ð¸Ñ + + + + Select file name + Выбрать Ð¸Ð¼Ñ Ñ„Ð°Ð¹Ð»Ð° + + + + Select extension file + Выбрать раÑширение файла + + + + Extension successfully loaded. + РаÑширение уÑпешно загружено. + + + + Error loading extension: %1 + Ошибка загрузки раÑширениÑ: %1 + + + + + Don't show again + Ðе показывать Ñнова + + + + New version available. + ДоÑтупна Ð½Ð¾Ð²Ð°Ñ Ð²ÐµÑ€ÑиÑ. + + + + Project saved to file '%1' + + + + + Collation needed! Proceed? + Ðужно выполнить ÑопоÑтавление! Продолжить? + + + + A table in this database requires a special collation function '%1' that this application can't provide without further knowledge. +If you choose to proceed, be aware bad things can happen to your database. +Create a backup! + Таблица в базе данных требует Ð²Ñ‹Ð¿Ð¾Ð»Ð½ÐµÐ½Ð¸Ñ Ñпециальной функции ÑопоÑÑ‚Ð°Ð²Ð»ÐµÐ½Ð¸Ñ '%1'. +ЕÑли вы продолжите, то возможна порча вашей базы данных. +Создайте резервную копию! + + + + creating collation + + + + + Set a new name for the SQL tab. Use the '&&' character to allow using the following character as a keyboard shortcut. + Задайте новое Ð¸Ð¼Ñ Ð´Ð»Ñ Ð²ÐºÐ»Ð°Ð´ÐºÐ¸ SQL. ИÑпользуйте Ñимвол '&&', чтобы разрешить иÑпользование Ñледующего Ñимвола в качеÑтве ÑÐ¾Ñ‡ÐµÑ‚Ð°Ð½Ð¸Ñ ÐºÐ»Ð°Ð²Ð¸Ñˆ. + + + + Please specify the view name + Укажите Ð¸Ð¼Ñ Ð¿Ñ€ÐµÐ´ÑÑ‚Ð°Ð²Ð»ÐµÐ½Ð¸Ñ + + + + There is already an object with that name. Please choose a different name. + Объект Ñ ÑƒÐºÐ°Ð·Ð°Ð½Ð½Ñ‹Ð¼ именем уже ÑущеÑтвует. Выберите другое имÑ. + + + + View successfully created. + ПредÑтавление уÑпешно Ñоздано. + + + + Error creating view: %1 + Ошибка ÑÐ¾Ð·Ð´Ð°Ð½Ð¸Ñ Ð¿Ñ€ÐµÐ´ÑтавлениÑ: %1 + + + + This action will open a new SQL tab for running: + Это дейÑтвие откроет новую вкладку SQL Ð´Ð»Ñ Ð·Ð°Ð¿ÑƒÑка: + + + + Press Help for opening the corresponding SQLite reference page. + Ðажмите "Справка" Ð´Ð»Ñ Ð¾Ñ‚ÐºÑ€Ñ‹Ñ‚Ð¸Ñ ÑоответÑтвующей Ñправочной Ñтраницы SQLite. + + + + NullLineEdit + + + Set to NULL + УÑтановить в NULL + + + + Alt+Del + + + + + PlotDock + + + Plot + График + + + + <html><head/><body><p>This pane shows the list of columns of the currently browsed table or the just executed query. You can select the columns that you want to be used as X or Y axis for the plot pane below. The table shows detected axis type that will affect the resulting plot. For the Y axis you can only select numeric columns, but for the X axis you will be able to select:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Date/Time</span>: strings with format &quot;yyyy-MM-dd hh:mm:ss&quot; or &quot;yyyy-MM-ddThh:mm:ss&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Date</span>: strings with format &quot;yyyy-MM-dd&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Time</span>: strings with format &quot;hh:mm:ss&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Label</span>: other string formats. Selecting this column as X axis will produce a Bars plot with the column values as labels for the bars</li><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Numeric</span>: integer or real values</li></ul><p>Double-clicking the Y cells you can change the used color for that graph.</p></body></html> + <html><head/><body><p>Ðа Ñтой панели отображаетÑÑ ÑпиÑок Ñтолбцов текущей проÑматриваемой таблицы или только что выполненного запроÑа. Ð’Ñ‹ можете выбрать Ñтолбцы, которые вы хотите иÑпользовать в качеÑтве оÑи X или Y Ð´Ð»Ñ Ð³Ñ€Ð°Ñ„Ð¸ÐºÐ° ниже. Ð’ таблице показан тип обнаруженной оÑи, который повлиÑет на итоговый график. Ð”Ð»Ñ Ð¾Ñи Y вы можете выбирать только чиÑловые Ñтолбцы, но Ð´Ð»Ñ Ð¾Ñи X вы можете выбрать:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Дата/ВремÑ</span>: Ñтроки Ñ Ñ„Ð¾Ñ€Ð¼Ð°Ñ‚Ð¾Ð¼ &quot;гггг-ММ-дд чч:мм:ÑÑ&quot; или &quot;гггг-ММ-ддTчч:мм:ÑÑ&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Дата</span>: Ñтроки Ñ Ñ„Ð¾Ñ€Ð¼Ð°Ñ‚Ð¾Ð¼ &quot;гггг-ММ-дд&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">ВремÑ</span>: Ñтроки Ñ Ñ„Ð¾Ñ€Ð¼Ð°Ñ‚Ð¾Ð¼ &quot;чч:мм:ÑÑ&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">ТекÑÑ‚</span>: Ñтроки лубого формата. Выбор Ñтого Ñтолбца по оÑи X приведет к Ñозданию графика Баров, Ñо значениÑми Ñтолбцов в качеÑтве меток Ð´Ð»Ñ Ð±Ð°Ñ€Ð¾Ð²</li><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">ЧиÑла</span>: целочиÑленные или вещеÑтвенные значениÑ</li></ul><p>Дважды щелкните по Ñчейкам Y, вы можете изменить иÑпользуемый цвет Ð´Ð»Ñ Ñтого графика.</p></body></html> + + + + Columns + Столбцы + + + + X + X + + + + Y1 + + + + + Y2 + + + + + Axis Type + ОÑÑŒ + + + + Here is a plot drawn when you select the x and y values above. + +Click on points to select them in the plot and in the table. Ctrl+Click for selecting a range of points. + +Use mouse-wheel for zooming and mouse drag for changing the axis range. + +Select the axes or axes labels to drag and zoom only in that orientation. + Вот график, нариÑованный, когда вы выбираете Ð·Ð½Ð°Ñ‡ÐµÐ½Ð¸Ñ x и y выше. + +Ðажмите на пункты, чтобы выбрать их на графике и в таблице. Ctrl + Click Ð´Ð»Ñ Ð²Ñ‹Ð±Ð¾Ñ€Ð° диапазона точек. + +ИÑпользуйте колеÑико мыши Ð´Ð»Ñ Ð¼Ð°ÑÑˆÑ‚Ð°Ð±Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ Ð¸ перетаÑÐºÐ¸Ð²Ð°Ð½Ð¸Ñ Ð¼Ñ‹ÑˆÑŒÑŽ Ð´Ð»Ñ Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ð´Ð¸Ð°Ð¿Ð°Ð·Ð¾Ð½Ð° оÑей. + +Выберите метки оÑей или оÑей Ð´Ð»Ñ Ð¿ÐµÑ€ÐµÑ‚Ð°ÑÐºÐ¸Ð²Ð°Ð½Ð¸Ñ Ð¸ маÑÑˆÑ‚Ð°Ð±Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ Ñ‚Ð¾Ð»ÑŒÐºÐ¾ в Ñтой ориентации. + + + + Line type: + ЛиниÑ: + + + + + None + Ðет + + + + Line + ÐžÐ±Ñ‹Ñ‡Ð½Ð°Ñ + + + + StepLeft + СтупенчатаÑ, Ñлева + + + + StepRight + СтупенчатаÑ, Ñправа + + + + StepCenter + СтупенчатаÑ, по центру + + + + Impulse + Ð˜Ð¼Ð¿ÑƒÐ»ÑŒÑ + + + + Point shape: + ОтриÑовка точек: + + + + Cross + КреÑÑ‚ + + + + Plus + ÐŸÐ»ÑŽÑ + + + + Circle + Круг + + + + Disc + ДиÑк + + + + Square + Квадрат + + + + Diamond + Ромб + + + + Star + Звезда + + + + Triangle + Треугольник + + + + TriangleInverted + Треугольник перевернутый + + + + CrossSquare + КреÑÑ‚ в квадрате + + + + PlusSquare + ÐŸÐ»ÑŽÑ Ð² квадрате + + + + CrossCircle + КреÑÑ‚ в круге + + + + PlusCircle + ÐŸÐ»ÑŽÑ Ð² круге + + + + Peace + Мир + + + + <html><head/><body><p>Save current plot...</p><p>File format chosen by extension (png, jpg, pdf, bmp)</p></body></html> + <html><head/><body><p>Сохранить текущий график...</p><p>Формат файла выбираетÑÑ Ñ€Ð°Ñширением (png, jpg, pdf, bmp)</p></body></html> + + + + Save current plot... + Сохранить текущий график... + + + + + Load all data and redraw plot + Загрузить вÑе данные и перериÑовать + + + + + + Row # + Строка # + + + + Copy + Копировать + + + + Print... + Печать... + + + + Show legend + Легенда + + + + Stacked bars + + + + + Date/Time + Дата/Ð’Ñ€ÐµÐ¼Ñ + + + + Date + Дата + + + + Time + Ð’Ñ€ÐµÐ¼Ñ + + + + + Numeric + ЧиÑло + + + + Label + ТекÑÑ‚ + + + + Invalid + Ошибка + + + + Load all data and redraw plot. +Warning: not all data has been fetched from the table yet due to the partial fetch mechanism. + Загружает вÑе данные и перериÑовыет график. +Предупреждение: не вÑе данные были получены из таблицы из-за механизма чаÑтичной выборки. + + + + Choose an axis color + Выберите цвет оÑи + + + + Choose a filename to save under + Выбрать Ð¸Ð¼Ñ Ñ„Ð°Ð¹Ð»Ð°, под которым Ñохранить данные + + + + PNG(*.png);;JPG(*.jpg);;PDF(*.pdf);;BMP(*.bmp);;All Files(*) + PNG(*.png);;JPG(*.jpg);;PDF(*.pdf);;BMP(*.bmp);;Ð’Ñе файлы(*) + + + + There are curves in this plot and the selected line style can only be applied to graphs sorted by X. Either sort the table or query by X to remove curves or select one of the styles supported by curves: None or Line. + Ðа Ñтом графике еÑть кривые, и выбранный Ñтиль линии может применÑтьÑÑ Ñ‚Ð¾Ð»ÑŒÐºÐ¾ к графикам, отÑортированным по X. Либо Ñортируйте таблицу или Ð·Ð°Ð¿Ñ€Ð¾Ñ Ð¿Ð¾ X, чтобы удалить кривые, либо выберите один из Ñтилей, поддерживаемых кривыми: None или Line. + + + + Loading all remaining data for this table took %1ms. + + + + + PreferencesDialog + + + Preferences + ÐаÑтройки + + + + &Database + &База данных + + + + Database &encoding + &Кодировка базы данных + + + + Open databases with foreign keys enabled. + Открывать базы данных Ñ Ð²ÐºÐ»ÑŽÑ‡ÐµÐ½Ð½Ñ‹Ð¼Ð¸ внешними ключами. + + + + &Foreign keys + &Внешние ключи + + + + + + + + + + + + enabled + включены + + + + Default &location + &РаÑположение +по умолчанию + + + + + + ... + ... + + + + &General + &Общие + + + + Remember last location + Запоминать поÑледнюю директорию + + + + Always use this location + Ð’Ñегда открывать указанную + + + + Remember last location for session only + Запоминать поÑледнюю директорию только Ð´Ð»Ñ ÑеÑÑий + + + + Lan&guage + &Язык + + + + Automatic &updates + &Следить за обновлениÑми + + + + SQ&L to execute after opening database + + + + + Data &Browser + Обозреватель &данных + + + + Remove line breaks in schema &view + Удалить переводы Ñтроки в &Ñхеме данных + + + + Show remote options + Опции "облака" + + + + Prefetch block si&ze + Размер блока &упреждающей выборки + + + + Default field type + Тип данных по умолчанию + + + + Font + Шрифт + + + + &Font + &Шрифт + + + + Content + Содержимое + + + + Symbol limit in cell + КоличеÑтво Ñимволов в Ñчейке + + + + NULL + + + + + Regular + Обычные + + + + Binary + Двоичные данные + + + + Background + Фон + + + + Filters + Фильтры + + + + Threshold for completion and calculation on selection + + + + + Show images in cell + + + + + Enable this option to show a preview of BLOBs containing image data in the cells. This can affect the performance of the data browser, however. + + + + + Escape character + Символ ÑÐºÑ€Ð°Ð½Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ + + + + Delay time (&ms) + Ð’Ñ€ÐµÐ¼Ñ Ð·Ð°Ð´ÐµÑ€Ð¶ÐºÐ¸ (&мÑ) + + + + Set the waiting time before a new filter value is applied. Can be set to 0 for disabling waiting. + Ð’Ñ€ÐµÐ¼Ñ Ð·Ð°Ð´ÐµÑ€Ð¶ÐºÐ¸ перед применением нового фильтра. Ðулевое значение отключает ожидание. + + + + &SQL + Р&едактор SQL + + + + Settings name + Ð˜Ð¼Ñ Ð½Ð°Ñтроек + + + + Context + КонтекÑÑ‚ + + + + Colour + Цвет + + + + Bold + Жирный + + + + Italic + КурÑив + + + + Underline + Подчёркивание + + + + Keyword + Ключевое Ñлово + + + + Function + Ð¤ÑƒÐ½ÐºÑ†Ð¸Ñ + + + + Table + Таблица + + + + Comment + Комментарий + + + + Identifier + Идентификатор + + + + String + Строка + + + + Current line + Ð¢ÐµÐºÑƒÑ‰Ð°Ñ Ñтрока + + + + SQL &editor font size + Размер шрифта в &редакторе SQL + + + + Tab size + Размер табулÑции + + + + SQL editor &font + &Шрифт в редакторе SQL + + + + Error indicators + Индикаторы ошибок + + + + Hori&zontal tiling + Гори&зонтальное раÑпределение + + + + If enabled the SQL code editor and the result table view are shown side by side instead of one over the other. + ЕÑли Ð´Ð°Ð½Ð½Ð°Ñ Ð¾Ð¿Ñ†Ð¸Ñ Ð²ÐºÐ»ÑŽÑ‡ÐµÐ½Ð°, то SQL редактор и результат запроÑа будут раÑположены Ñ€Ñдом по горизонтали. + + + + Code co&mpletion + Ðвто&дополнение кода + + + + Toolbar style + Стиль тулбара + + + + + + + + Only display the icon + Только иконки + + + + + + + + Only display the text + Только текÑÑ‚ + + + + + + + + The text appears beside the icon + ТекÑÑ‚ над иконкой + + + + + + + + The text appears under the icon + ТекÑÑ‚ под иконкой + + + + + + + + Follow the style + Указано в Ñтиле + + + + DB file extensions + РаÑÑˆÐ¸Ñ€ÐµÐ½Ð¸Ñ Ñ„Ð°Ð¹Ð»Ð¾Ð² БД + + + + Manage + ÐаÑтроить + + + + Main Window + + + + + Database Structure + Структура БД + + + + Browse Data + Данные + + + + Execute SQL + SQL + + + + Edit Database Cell + Редактирование Ñчейки БД + + + + When this value is changed, all the other color preferences are also set to matching colors. + + + + + Follow the desktop style + + + + + Dark style + + + + + Application style + + + + + This sets the font size for all UI elements which do not have their own font size option. + + + + + Font size + + + + + When enabled, the line breaks in the Schema column of the DB Structure tab, dock and printed output are removed. + Когда отмечено, переноÑÑ‹ Ñтрок в Ñтолбце 'Схема' во вкладке 'Структура базы данных', 'док' и 'печатный результат' удалÑÑŽÑ‚ÑÑ. + + + + Database structure font size + + + + + Font si&ze + Ра&змер шрифта + + + + This is the maximum number of items allowed for some computationally expensive functionalities to be enabled: +Maximum number of rows in a table for enabling the value completion based on current values in the column. +Maximum number of indexes in a selection for calculating sum and average. +Can be set to 0 for disabling the functionalities. + + + + + This is the maximum number of rows in a table for enabling the value completion based on current values in the column. +Can be set to 0 for disabling completion. + МакÑимальное количеÑтво Ñтрок в таблице Ð´Ð»Ñ Ð²ÐºÐ»ÑŽÑ‡ÐµÐ½Ð¸Ñ Ð·Ð°Ð²ÐµÑ€ÑˆÐµÐ½Ð¸Ñ Ð·Ð½Ð°Ñ‡ÐµÐ½Ð¸Ñ Ð½Ð° оÑнове текущих значений в Ñтолбце. +Может быть уÑтановлено в 0 Ð´Ð»Ñ Ð¾Ñ‚ÐºÐ»ÑŽÑ‡ÐµÐ½Ð¸Ñ Ð·Ð°Ð²ÐµÑ€ÑˆÐµÐ½Ð¸Ñ. + + + + Field display + Отображение Ð¿Ð¾Ð»Ñ + + + + Displayed &text + Отображаемый &текÑÑ‚ + + + + + + + + + Click to set this color + + + + + Text color + Цвет текÑта + + + + Background color + Цвет фона + + + + Preview only (N/A) + Предв. проÑмотр + + + + Foreground + Передний план + + + + SQL &results font size + &Размер шрифта + + + + &Wrap lines + &ÐŸÐµÑ€ÐµÐ½Ð¾Ñ Ñтрок + + + + Never + Ðикогда + + + + At word boundaries + Ðа границах Ñлов + + + + At character boundaries + Ðа границах Ñимволов + + + + At whitespace boundaries + Ðа границах пробелов + + + + &Quotes for identifiers + Обравмление &идентификаторов + + + + Choose the quoting mechanism used by the application for identifiers in SQL code. + Выберите механизм обрамлениÑ, иÑпользуемый приложением Ð´Ð»Ñ Ð¸Ð´ÐµÐ½Ñ‚Ð¸Ñ„Ð¸ÐºÐ°Ñ‚Ð¾Ñ€Ð¾Ð² в коде SQL. + + + + "Double quotes" - Standard SQL (recommended) + "Двойные кавычки" - Cтандартный SQL (рекомендуетÑÑ) + + + + `Grave accents` - Traditional MySQL quotes + `ГравиÑ` - Традиционные кавычки MySQL + + + + [Square brackets] - Traditional MS SQL Server quotes + [Квадратные Ñкобки] - традиционные кавычки Ð´Ð»Ñ MS SQL Server + + + + Keywords in &UPPER CASE + Ключевые Ñлова в &ВЕРХÐЕМ РЕГИСТРЕ + + + + When set, the SQL keywords are completed in UPPER CASE letters. + Когда отмечено, ключевые Ñлова SQL будут в ВЕРХÐЕМ РЕГИСТРЕ. + + + + When set, the SQL code lines that caused errors during the last execution are highlighted and the results frame indicates the error in the background + Когда уÑтановлено, Ñтроки кода SQL, вызвавшие ошибки во Ð²Ñ€ÐµÐ¼Ñ Ð¿Ð¾Ñледнего выполнениÑ, подÑвечиваютÑÑ, а виджет результатов указывает на ошибку в фоновом режиме + + + + Close button on tabs + + + + + If enabled, SQL editor tabs will have a close button. In any case, you can use the contextual menu or the keyboard shortcut to close them. + + + + + &Extensions + Р&аÑÑˆÐ¸Ñ€ÐµÐ½Ð¸Ñ + + + + Select extensions to load for every database: + Выберите раÑширениÑ, чтобы загружать их Ð´Ð»Ñ ÐºÐ°Ð¶Ð´Ð¾Ð¹ базы данных: + + + + Add extension + Добавить раÑширение + + + + Remove extension + Удалить раÑширение + + + + <html><head/><body><p>While supporting the REGEXP operator SQLite doesn't implement any regular expression<br/>algorithm but calls back the running application. DB Browser for SQLite implements this<br/>algorithm for you to let you use REGEXP out of the box. However, as there are multiple possible<br/>implementations of this and you might want to use another one, you're free to disable the<br/>application's implementation and load your own by using an extension. Requires restart of the application.</p></body></html> + <html><head/><body><p>Обозреватель Ð´Ð»Ñ SQLite позволÑет иÑпользовать оператор REGEXP 'из коробки'. Ðо тем <br/>не менее, возможны неÑколько различных вариантов реализаций данного оператора и вы Ñвободны <br/>в выборе какую именно иÑпользовать. Можно отключить нашу реализацию и иÑпользовать другую - <br/>путем загрузки ÑоответÑвующего раÑширениÑ. Ð’ Ñтом Ñлучае требуетÑÑ Ð¿ÐµÑ€ÐµÐ·Ð°Ð³Ñ€ÑƒÐ·ÐºÐ° приложениÑ.</p></body></html> + + + + Disable Regular Expression extension + Отключить раÑширение РегулÑрных Выражений + + + + <html><head/><body><p>SQLite provides an SQL function for loading extensions from a shared library file. Activate this if you want to use the <span style=" font-style:italic;">load_extension()</span> function from SQL code.</p><p>For security reasons, extension loading is turned off by default and must be enabled through this setting. You can always load extensions through the GUI, even though this option is disabled.</p></body></html> + + + + + Allow loading extensions from SQL code + + + + + Remote + Удаленный Ñервер + + + + CA certificates + СРÑертификаты + + + + Proxy + + + + + Configure + + + + + + Subject CN + + + + + Common Name + + + + + Subject O + + + + + Organization + + + + + + Valid from + + + + + + Valid to + + + + + + Serial number + + + + + Your certificates + Ваши Ñертификаты + + + + File + Файл + + + + Subject Common Name + + + + + Issuer CN + + + + + Issuer Common Name + + + + + Clone databases into + Путь Ð´Ð»Ñ ÐºÐ»Ð¾Ð½Ð¸Ñ€ÑƒÐµÐ¼Ñ‹Ñ… БД + + + + + Choose a directory + Выберать каталог + + + + The language will change after you restart the application. + Язык будет применен поÑле перезапуÑка приложениÑ. + + + + Select extension file + Выберать файл раÑÑˆÐ¸Ñ€ÐµÐ½Ð¸Ñ + + + + Extensions(*.so *.dylib *.dll);;All files(*) + + + + + Import certificate file + Импорт файла Ñертификата + + + + No certificates found in this file. + Ð’ данном файле не найден Ñертификат. + + + + Are you sure you want do remove this certificate? All certificate data will be deleted from the application settings! + Ð’Ñ‹ дейÑтвительно хотите удалить Ñтот Ñертификат? Ð’Ñе данные Ñертификата будут удалены из наÑтроек приложениÑ! + + + + Are you sure you want to clear all the saved settings? +All your preferences will be lost and default values will be used. + Ð’Ñ‹ дейÑтвительно хотите удалить вÑе Ñохраненные наÑтройки? +Ð’Ñе ваши Ð¿Ñ€ÐµÐ´Ð¿Ð¾Ñ‡Ñ‚ÐµÐ½Ð¸Ñ Ð±ÑƒÐ´ÑƒÑ‚ потерÑны, и будут иÑпользоватьÑÑ Ð·Ð½Ð°Ñ‡ÐµÐ½Ð¸Ñ Ð¿Ð¾ умолчанию. + + + + ProxyDialog + + + Proxy Configuration + + + + + Pro&xy Type + + + + + Host Na&me + + + + + Port + + + + + Authentication Re&quired + + + + + &User Name + + + + + Password + + + + + None + Ðет + + + + System settings + + + + + HTTP + + + + + Socks v5 + + + + + QObject + + + Error importing data + Ошибка Ð¸Ð¼Ð¿Ð¾Ñ€Ñ‚Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ Ð´Ð°Ð½Ð½Ñ‹Ñ… + + + + from record number %1 + Ñ Ð·Ð°Ð¿Ð¸Ñи номер %1 + + + + . +%1 + + + + + Importing CSV file... + Импортирование CSV файла... + + + + Cancel + Отменить + + + + All files (*) + Ð’Ñе файлы (*) + + + + SQLite database files (*.db *.sqlite *.sqlite3 *.db3) + Файлы SQLite баз данных (*.db *.sqlite *.sqlite3 *.db3) + + + + Left + + + + + Right + + + + + Center + + + + + Justify + + + + + SQLite Database Files (*.db *.sqlite *.sqlite3 *.db3) + + + + + DB Browser for SQLite Project Files (*.sqbpro) + + + + + SQL Files (*.sql) + + + + + All Files (*) + + + + + Text Files (*.txt) + + + + + Comma-Separated Values Files (*.csv) + + + + + Tab-Separated Values Files (*.tsv) + + + + + Delimiter-Separated Values Files (*.dsv) + + + + + Concordance DAT files (*.dat) + + + + + JSON Files (*.json *.js) + + + + + XML Files (*.xml) + + + + + Binary Files (*.bin *.dat) + + + + + SVG Files (*.svg) + + + + + Hex Dump Files (*.dat *.bin) + + + + + Extensions (*.so *.dylib *.dll) + + + + + RemoteCommitsModel + + + Commit ID + + + + + Message + + + + + Date + Дата + + + + Author + + + + + Size + Размер + + + + Authored and committed by %1 + + + + + Authored by %1, committed by %2 + + + + + RemoteDatabase + + + Error opening local databases list. +%1 + Ошибка при открытии ÑпиÑка локальных БД. +%1 + + + + Error creating local databases list. +%1 + Ошибка при Ñоздании ÑпиÑка локальных БД. +%1 + + + + RemoteDock + + + Remote + Удаленный Ñервер + + + + Identity + ID + + + + Push currently opened database to server + Отправить текущую БД на Ñервер + + + + DBHub.io + + + + + <html><head/><body><p>In this pane, remote databases from dbhub.io website can be added to DB Browser for SQLite. First you need an identity:</p><ol style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Login to the dbhub.io website (use your GitHub credentials or whatever you want)</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Click the button to &quot;Generate client certificate&quot; (that's your identity). That'll give you a certificate file (save it to your local disk).</li><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Go to the Remote tab in DB Browser for SQLite Preferences. Click the button to add a new certificate to DB Browser for SQLite and choose the just downloaded certificate file.</li></ol><p>Now the Remote panel shows your identity and you can add remote databases.</p></body></html> + + + + + Local + + + + + Current Database + + + + + Clone + + + + + User + Пользователем + + + + Database + База данных + + + + Branch + Ветка + + + + Commits + + + + + Commits for + + + + + Delete Database + + + + + Delete the local clone of this database + + + + + Open in Web Browser + + + + + Open the web page for the current database in your browser + + + + + Clone from Link + + + + + Use this to download a remote database for local editing using a URL as provided on the web page of the database. + + + + + Refresh + Обновить + + + + Reload all data and update the views + + + + + F5 + + + + + Clone Database + + + + + Open Database + + + + + Open the local copy of this database + + + + + Check out Commit + + + + + Download and open this specific commit + + + + + Check out Latest Commit + + + + + Check out the latest commit of the current branch + + + + + Save Revision to File + + + + + Saves the selected revision of the database to another file + + + + + Upload Database + + + + + Upload this database as a new commit + + + + + <html><head/><body><p>You are currently using a built-in, read-only identity. For uploading your database, you need to configure and use your DBHub.io account.</p><p>No DBHub.io account yet? <a href="https://dbhub.io/"><span style=" text-decoration: underline; color:#007af4;">Create one now</span></a> and import your certificate <a href="#preferences"><span style=" text-decoration: underline; color:#007af4;">here</span></a> to share your databases.</p><p>For online help visit <a href="https://dbhub.io/about"><span style=" text-decoration: underline; color:#007af4;">here</span></a>.</p></body></html> + + + + + Back + + + + + Select an identity to connect + + + + + Public + Публичный + + + + This downloads a database from a remote server for local editing. +Please enter the URL to clone from. You can generate this URL by +clicking the 'Clone Database in DB4S' button on the web page +of the database. + + + + + Invalid URL: The host name does not match the host name of the current identity. + + + + + Invalid URL: No branch name specified. + + + + + Invalid URL: No commit ID specified. + + + + + You have modified the local clone of the database. Fetching this commit overrides these local changes. +Are you sure you want to proceed? + + + + + The database has unsaved changes. Are you sure you want to push it before saving? + + + + + The database you are trying to delete is currently opened. Please close it before deleting. + + + + + This deletes the local version of this database with all the changes you have not committed yet. Are you sure you want to delete this database? + + + + + RemoteLocalFilesModel + + + Name + Ð˜Ð¼Ñ + + + + Branch + Ветка + + + + Last modified + Изменен + + + + Size + Размер + + + + Commit + Коммит + + + + File + + + + + RemoteModel + + + Name + Ð˜Ð¼Ñ + + + + Last modified + Изменен + + + + Size + Размер + + + + Commit + Коммит + + + + Size: + + + + + Last Modified: + + + + + Licence: + + + + + Default Branch: + + + + + RemoteNetwork + + + Choose a location to save the file + + + + + Error opening remote file at %1. +%2 + Ошибка Ð¾Ñ‚ÐºÑ€Ñ‹Ñ‚Ð¸Ñ Ñ„Ð°Ð¹Ð»Ð° %1. +%2 + + + + Error: Invalid client certificate specified. + Ошибка: Указан неверный Ñертификат клиента. + + + + Please enter the passphrase for this client certificate in order to authenticate. + ПожалуйÑта введите ключевую фразу Ð´Ð»Ñ Ñтого Ñертификата клиента. + + + + Cancel + Отменить + + + + Uploading remote database to +%1 + ЗагружаетÑÑ ÑƒÐ´Ð°Ð»ÐµÐ½Ð½Ð°Ñ Ð‘Ð” в +%1 + + + + Downloading remote database from +%1 + СкачиваетÑÑ ÑƒÐ´Ð°Ð»ÐµÐ½Ð½Ð°Ñ Ð‘Ð” из +%1 + + + + + Error: The network is not accessible. + Ошибка: Ñеть недоÑтупна. + + + + Error: Cannot open the file for sending. + Ошибка: не удаетÑÑ Ð¾Ñ‚ÐºÑ€Ñ‹Ñ‚ÑŒ файл Ð´Ð»Ñ Ð¾Ñ‚Ð¿Ñ€Ð°Ð²ÐºÐ¸. + + + + RemotePushDialog + + + Push database + Отправить БД + + + + Database na&me to push to + &Ð˜Ð¼Ñ Ð‘Ð” + + + + Commit message + Сообщение + + + + Database licence + Ð›Ð¸Ñ†ÐµÐ½Ð·Ð¸Ñ + + + + Public + Публичный + + + + Branch + Ветка + + + + Force push + Принудительно + + + + Username + + + + + Database will be public. Everyone has read access to it. + БД будет публичной. У каждого будет доÑтуп на чтение к ней. + + + + Database will be private. Only you have access to it. + БД будет конфиденциальной. Только у Ð²Ð°Ñ Ð±ÑƒÐ´ÐµÑ‚ доÑтуп к ней. + + + + Use with care. This can cause remote commits to be deleted. + ИÑпользуйте Ñ Ð¾ÑторожноÑтью. Это может привеÑти к удалению ÑущеÑтвующих коммитов. + + + + RunSql + + + Execution aborted by user + Выполнение прервано пользователем + + + + , %1 rows affected + , %1 Ñтрок изменено + + + + query executed successfully. Took %1ms%2 + Ð·Ð°Ð¿Ñ€Ð¾Ñ ÑƒÑпешно выполнен. ЗанÑло %1мÑ%2 + + + + executing query + + + + + SelectItemsPopup + + + A&vailable + + + + + Sele&cted + + + + + SqlExecutionArea + + + Form + Форма + + + + Find previous match [Shift+F3] + Ðайти предыдущее Ñовпадение [Shift+F3] + + + + Find previous match with wrapping + Ðайти предыдущее Ñовпадение, закольцевав поиÑк + + + + Shift+F3 + + + + + The found pattern must be a whole word + Ðайденный шаблон должен быть целым Ñловом + + + + Whole Words + Слова ПолноÑтью + + + + Text pattern to find considering the checks in this frame + Шаблон Ð´Ð»Ñ Ð¿Ð¾Ð¸Ñка, ÑƒÑ‡Ð¸Ñ‚Ñ‹Ð²Ð°Ñ Ð²Ñе проверки + + + + Find in editor + Ðайти в редакторе + + + + The found pattern must match in letter case + У найденного шаблона должен Ñовпадать региÑтр + + + + Case Sensitive + Учитывать РегиÑтр + + + + Find next match [Enter, F3] + Ðайти Ñледующее Ñовпдение [Enter, F3] + + + + Find next match with wrapping + Ðайти Ñледующее Ñовпадение, закольцевав поиÑк + + + + F3 + + + + + Interpret search pattern as a regular expression + Интерпретировать шаблон поиÑка как регулÑрное выражение + + + + <html><head/><body><p>When checked, the pattern to find is interpreted as a UNIX regular expression. See <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>.</p></body></html> + <html><head/><body><p>При проверке шаблон Ð´Ð»Ñ Ð¿Ð¾Ð¸Ñка интерпретируетÑÑ ÐºÐ°Ðº регулÑрное выражение UNIX. <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Узнать больше о РегулÑрных выражениÑÑ… на Wikibooks.org</a>.</p></body></html> + + + + Regular Expression + РегулÑрное выражение + + + + + Close Find Bar + Закрыть ПоиÑковую Панель + + + + <html><head/><body><p>Results of the last executed statements.</p><p>You may want to collapse this panel and use the <span style=" font-style:italic;">SQL Log</span> dock with <span style=" font-style:italic;">User</span> selection instead.</p></body></html> + + + + + Results of the last executed statements + Результаты поÑледних выполненных операторов + + + + This field shows the results and status codes of the last executed statements. + Это поле показывает результаты и коды ÑтатуÑов поÑледних выполненных операторов. + + + + Couldn't read file: %1. + Ðе удалоÑÑŒ прочитать файл:%1. + + + + + Couldn't save file: %1. + Ðе удалоÑÑŒ Ñохранить файл:%1. + + + + Your changes will be lost when reloading it! + + + + + The file "%1" was modified by another program. Do you want to reload it?%2 + + + + + SqlTextEdit + + + Ctrl+/ + + + + + SqlUiLexer + + + (X) The abs(X) function returns the absolute value of the numeric argument X. + (X) Ð¤ÑƒÐ½ÐºÑ†Ð¸Ñ abs(X) возвращает модуль чиÑла аргумента X. + + + + () The changes() function returns the number of database rows that were changed or inserted or deleted by the most recently completed INSERT, DELETE, or UPDATE statement. + () Ð¤ÑƒÐ½ÐºÑ†Ð¸Ñ changes() возвращает количеÑтво Ñтрок в базе данных, которые были изменены, вÑтавлены или удалены поÑле удачного Ð²Ñ‹Ð¿Ð¾Ð»Ð½ÐµÐ½Ð¸Ñ INSERT, DELETE или UPDATE. + + + + (X1,X2,...) The char(X1,X2,...,XN) function returns a string composed of characters having the unicode code point values of integers X1 through XN, respectively. + (X1,X2,...) Ð¤ÑƒÐ½ÐºÑ†Ð¸Ñ char(X1,X2,...,XN) возвращает Ñтроку ÑоÑтавленную из Ñимволов, переданных в качеÑтве аргументов. + + + + (X,Y,...) The coalesce() function returns a copy of its first non-NULL argument, or NULL if all arguments are NULL + (X,Y,...) Ð¤ÑƒÐ½ÐºÑ†Ð¸Ñ coalesce() возвращает копию первого аргумента не равного NULL иначе еÑли такого нет то возвращаетÑÑ NULL + + + + (X,Y) The glob(X,Y) function is equivalent to the expression "Y GLOB X". + (X,Y) Ð¤ÑƒÐ½ÐºÑ†Ð¸Ñ glob(X,Y) Ñквивалент выражению "Y GLOB X". + + + + (X,Y) The ifnull() function returns a copy of its first non-NULL argument, or NULL if both arguments are NULL. + (X,Y) Ð¤ÑƒÐ½ÐºÑ†Ð¸Ñ ifnull() возвращает копию первого аргумента не равного NULL иначе еÑли оба аргумента равны NULL то возвращает NULL. + + + + (X,Y) The instr(X,Y) function finds the first occurrence of string Y within string X and returns the number of prior characters plus 1, or 0 if Y is nowhere found within X. + (X,Y) Ð¤ÑƒÐ½ÐºÑ†Ð¸Ñ instr(X,Y) возвращает количеÑтво Ñимволов, Ð½Ð°Ñ‡Ð¸Ð½Ð°Ñ Ñ ÐºÐ¾Ñ‚Ð¾Ñ€Ð¾Ð³Ð¾ в Ñтроке X найденна подÑтрока Y или 0 еÑли Ñ‚Ð°ÐºÐ¾Ð²Ð°Ñ Ð½Ðµ обнаружена. + + + + (X) The hex() function interprets its argument as a BLOB and returns a string which is the upper-case hexadecimal rendering of the content of that blob. + (X) Ð¤ÑƒÐ½ÐºÑ†Ð¸Ñ hex() интерпретирует аргумент как BLOB и возвращает Ñтроку в 16-ричной ÑиÑтеме ÑчиÑÐ»ÐµÐ½Ð¸Ñ Ñ Ñодержимым аргумента. + + + + () The last_insert_rowid() function returns the ROWID of the last row insert from the database connection which invoked the function. + () Ð¤ÑƒÐ½ÐºÑ†Ð¸Ñ last_insert_rowid() возвращает ROWID поÑледней вÑтавленной Ñтроки. + + + + (X) For a string value X, the length(X) function returns the number of characters (not bytes) in X prior to the first NUL character. + (X) Ð”Ð»Ñ Ñтрокового Ð·Ð½Ð°Ñ‡ÐµÐ½Ð¸Ñ X, Ñ„ÑƒÐ½ÐºÑ†Ð¸Ñ length(X) возвращает количеÑтво Ñимволов (не байт) от начала Ñтроки до первого Ñимвола '\0'. + + + + (X,Y) The like() function is used to implement the "Y LIKE X" expression. + (X,Y) Ð¤ÑƒÐºÐ½Ñ†Ð¸Ñ like() Ñквивалент выражению "Y LIKE X". + + + + (X,Y,Z) The like() function is used to implement the "Y LIKE X ESCAPE Z" expression. + (X,Y,Z) Ð¤ÑƒÐ½ÐºÑ†Ð¸Ñ like() Ñквивалент Ð²Ñ‹Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ "Y LIKE X ESCAPE Z". + + + + (X) The load_extension(X) function loads SQLite extensions out of the shared library file named X. +Use of this function must be authorized from Preferences. + + + + + (X,Y) The load_extension(X) function loads SQLite extensions out of the shared library file named X using the entry point Y. +Use of this function must be authorized from Preferences. + + + + + (X) The lower(X) function returns a copy of string X with all ASCII characters converted to lower case. + (X) Ð¤ÑƒÐ½ÐºÑ†Ð¸Ñ lower(X) возвращает копию Ñтроки X, в которой вÑе ACSII Ñимволы переведены в нижний региÑтр. + + + + (X) ltrim(X) removes spaces from the left side of X. + (X) ltrim(X) удалÑет Ñимволы пробелов Ñлева Ð´Ð»Ñ Ñтроки X. + + + + (X,Y) The ltrim(X,Y) function returns a string formed by removing any and all characters that appear in Y from the left side of X. + (X,Y) Ð¤ÑƒÐ½ÐºÑ†Ð¸Ñ ltrim(X,Y) возвращает новую Ñтроку путем ÑƒÐ´Ð°Ð»ÐµÐ½Ð¸Ñ Ð¸Ð· Ñтроки X Ñлева любого Ñимвола из Y. + + + + (X,Y,...) The multi-argument max() function returns the argument with the maximum value, or return NULL if any argument is NULL. + (X,Y,...) Ð¤ÑƒÐ½ÐºÑ†Ð¸Ñ max() возвращает аргумент Ñ Ð¼Ð°ÐºÑимальным значением, либо NULL еÑли хотÑбы один аргумент равен NULL. + + + + (X,Y,...) The multi-argument min() function returns the argument with the minimum value. + (X,Y,...) Ð¤ÑƒÐ½ÐºÑ†Ð¸Ñ min() возвращает аргумент Ñ Ð¼Ð¸Ð½Ð¸Ð¼Ð°Ð»ÑŒÐ½Ñ‹Ð¼ значением. + + + + (X,Y) The nullif(X,Y) function returns its first argument if the arguments are different and NULL if the arguments are the same. + (X,Y) Ð¤ÑƒÐ½ÐºÑ†Ð¸Ñ nullif(X,Y) возвращает первый аргумент еÑли аргументы различны либо NULL еÑли они одинаковы. + + + + (FORMAT,...) The printf(FORMAT,...) SQL function works like the sqlite3_mprintf() C-language function and the printf() function from the standard C library. + (FORMAT,...) Ð¤ÑƒÐ½ÐºÑ†Ð¸Ñ printf(FORMAT,...) работает так же как printf() из Ñтандартной библиотеки Ñзыка Ð¿Ñ€Ð¾Ð³Ñ€Ð°Ð¼Ð¼Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ Ð¡Ð¸. + + + + (X) The quote(X) function returns the text of an SQL literal which is the value of its argument suitable for inclusion into an SQL statement. + (X) Ð¤ÑƒÐ½ÐºÑ†Ð¸Ñ quote(X) возвращает измененную Ñтроку X, которую можно иÑпользовать в SQL выражениÑÑ…. + + + + () The random() function returns a pseudo-random integer between -9223372036854775808 and +9223372036854775807. + () Ð¤ÑƒÐ½ÐºÑ†Ð¸Ñ random() возвращает пÑевдо Ñлучайное целочиÑленное значение из диапозона от-9223372036854775808 до +9223372036854775807. + + + + (N) The randomblob(N) function return an N-byte blob containing pseudo-random bytes. + (N) Ð¤ÑƒÐ½ÐºÑ†Ð¸Ñ randomblob(N) возвращает N-байтный BLOB, Ñодержащий пÑевдо Ñлучайные байты. + + + + (X,Y,Z) The replace(X,Y,Z) function returns a string formed by substituting string Z for every occurrence of string Y in string X. + (X,Y,Z) Ð¤ÑƒÐ½ÐºÑ†Ð¸Ñ replace(X,Y,Z) возвращает новую Ñтроку на оÑнове Ñтроки X, заменой вÑех подÑтрок Y на Z. + + + + (X) The round(X) function returns a floating-point value X rounded to zero digits to the right of the decimal point. + (X) Ð¤ÑƒÐ½ÐºÑ†Ð¸Ñ round(X) округлÑет X до целого значениÑ. + + + + (X,Y) The round(X,Y) function returns a floating-point value X rounded to Y digits to the right of the decimal point. + (X,Y) Ð¤ÑƒÐ½ÐºÑ†Ð¸Ñ round(X,Y) округлÑет X до Y чиÑел поÑле запÑтой Ñправа. + + + + (X) rtrim(X) removes spaces from the right side of X. + (X) rtrim(X) удалÑет Ñимволы пробела Ñправа Ñтроки X. + + + + (X,Y) The rtrim(X,Y) function returns a string formed by removing any and all characters that appear in Y from the right side of X. + (X,Y) Ð¤ÑƒÐ½ÐºÑ†Ð¸Ñ rtrim(X,Y) возвращает новую Ñтроку путем ÑƒÐ´Ð°Ð»ÐµÐ½Ð¸Ñ Ð¸Ð· Ñтроки X Ñправа любого Ñимвола из Ñтроки Y. + + + + (X) The soundex(X) function returns a string that is the soundex encoding of the string X. + (X) Ð¤ÑƒÐ½ÐºÑ†Ð¸Ñ soundex(X) возвращает копию Ñтроки X, кодированную в формате soundex. + + + + (X,Y) substr(X,Y) returns all characters through the end of the string X beginning with the Y-th. + (X,Y) substr(X,Y) возвращает подÑтроку из Ñтроки X, Ð½Ð°Ñ‡Ð¸Ð½Ð°Ñ Ñ Y-го Ñимвола. + + + + (X,Y,Z) The substr(X,Y,Z) function returns a substring of input string X that begins with the Y-th character and which is Z characters long. + (X,Y,Z) Ð¤ÑƒÐ½ÐºÑ†Ð¸Ñ substr(X,Y,Z) возвращает подÑтроку из Ñтроки X, Ð½Ð°Ñ‡Ð¸Ð½Ð°Ñ Ñ Y-го Ñимвола, длинной Z-Ñимволов. + + + + () The total_changes() function returns the number of row changes caused by INSERT, UPDATE or DELETE statements since the current database connection was opened. + () Ð¤ÑƒÐ½ÐºÑ†Ð¸Ñ total_changes() возвращает количеÑтво Ñтрок измененных Ñ Ð¿Ð¾Ð¼Ð¾Ñ‰ÑŒÑŽ INSERT, UPDATE или DELETE, Ð½Ð°Ñ‡Ð¸Ð½Ð°Ñ Ñ Ñ‚Ð¾Ð³Ð¾ момента как текущее подключение к базе данных было открыто. + + + + (X) trim(X) removes spaces from both ends of X. + (X) trim(X) удалÑет пробелы Ñ Ð¾Ð±Ð¾Ð¸Ñ… Ñторон Ñтроки X. + + + + (X,Y) The trim(X,Y) function returns a string formed by removing any and all characters that appear in Y from both ends of X. + (X,Y) Ð¤ÑƒÐ½ÐºÑ†Ð¸Ñ trim(X,Y) Ñоздает новую Ñтроку из X, путем ÑƒÐ´Ð°Ð»ÐµÐ½Ð¸Ñ Ñ Ð¾Ð±Ð¾Ð¸Ñ… концов Ñимволов, которые приÑутÑвуют в Ñтроке Y. + + + + (X) The typeof(X) function returns a string that indicates the datatype of the expression X. + (X) Ð¤ÑƒÐ½ÐºÑ†Ð¸Ñ typeof(X) возвращает Ñтроку Ñ Ñ‚Ð¸Ð¿Ð¾Ð¼ данных Ð²Ñ‹Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ X. + + + + (X) The unicode(X) function returns the numeric unicode code point corresponding to the first character of the string X. + (X) Ð¤ÑƒÐ½ÐºÑ†Ð¸Ñ unicode(X) возвращает чиÑловое значение UNICODE кода Ñимвола. + + + + (X) The upper(X) function returns a copy of input string X in which all lower-case ASCII characters are converted to their upper-case equivalent. + (X) Ð¤ÑƒÐ½ÐºÑ†Ð¸Ñ upper(X) возвращает копию Ñтроки X, в которой Ð´Ð»Ñ ÐºÐ°Ð¶Ð´Ð¾Ð³Ð¾ ASCII Ñимвола региÑтр будет перобразован из нижнего в верхний. + + + + (N) The zeroblob(N) function returns a BLOB consisting of N bytes of 0x00. + (N) Ð¤ÑƒÐ½ÐºÑ†Ð¸Ñ zeroblob(N) возвращает BLOB размером N байт Ñо значениÑми 0x00. + + + + + + + (timestring,modifier,modifier,...) + + + + + (format,timestring,modifier,modifier,...) + + + + + (X) The avg() function returns the average value of all non-NULL X within a group. + (X) Ð¤ÑƒÐ½ÐºÑ†Ð¸Ñ avg() возвращает Ñреднее значение Ð´Ð»Ñ Ð²Ñех не равных NULL значений группы. + + + + (X) The count(X) function returns a count of the number of times that X is not NULL in a group. + (X) Ð¤ÑƒÐ½ÐºÑ†Ð¸Ñ count(X) возвращает количеÑтво Ñтрок, в которых X не равно NULL в группе. + + + + (X) The group_concat() function returns a string which is the concatenation of all non-NULL values of X. + (X) Ð¤ÑƒÐ½ÐºÑ†Ð¸Ñ group_concat() возвращает Ñтроку из вÑех значений X не равных NULL. + + + + (X,Y) The group_concat() function returns a string which is the concatenation of all non-NULL values of X. If parameter Y is present then it is used as the separator between instances of X. + (X,Y) Ð¤ÑƒÐ½ÐºÑ†Ð¸Ñ group_concat() возвращает Ñтроку из вÑех значений X не равных NULL. Y - разделитель между значениÑми X. + + + + (X) The max() aggregate function returns the maximum value of all values in the group. + (X) ÐÐ³Ð³Ñ€ÐµÐ³Ð°Ñ‚Ð½Ð°Ñ Ñ„ÑƒÐ½ÐºÑ†Ð¸Ñ max() возвращает макÑимальное значение Ð´Ð»Ñ X. + + + + (X) The min() aggregate function returns the minimum non-NULL value of all values in the group. + (X) ÐÐ³Ð³Ñ€ÐµÐ³Ð°Ñ‚Ð½Ð°Ñ Ñ„ÑƒÐ½ÐºÑ†Ð¸Ñ min() возвращает минимальное значение Ð´Ð»Ñ X. + + + + + (X) The sum() and total() aggregate functions return sum of all non-NULL values in the group. + (X) Ðггрегатные функции sum() и total() возвращают Ñумму вÑех не NULL значений Ð´Ð»Ñ X. + + + + () The number of the row within the current partition. Rows are numbered starting from 1 in the order defined by the ORDER BY clause in the window definition, or in arbitrary order otherwise. + () ЧиÑло Ñтрок в текущем разделе. Строки нумеруютÑÑ Ð½Ð°Ñ‡Ð¸Ð½Ð°Ñ Ñ 1 в порÑдке, определенном выражением ORDER BY, или иначе в произвольном порÑдке. + + + + () The row_number() of the first peer in each group - the rank of the current row with gaps. If there is no ORDER BY clause, then all rows are considered peers and this function always returns 1. + () Ð¤ÑƒÐ½ÐºÑ†Ð¸Ñ row_number() возвращает номер первой Ñтроки в каждой группе - ранг текущей Ñтроки Ñ Ñ€Ð°Ð·Ñ€Ñ‹Ð²Ð°Ð¼Ð¸. ЕÑли не ÑущеÑтвует Ð²Ñ‹Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ ORDER BY, вÑе Ñтроки ÑчитаютÑÑ Ð¾Ð´Ð½Ð¾Ñ€Ð°Ð½Ð³Ð¾Ð²Ñ‹Ð¼Ð¸, и Ñта Ñ„ÑƒÐ½ÐºÑ†Ð¸Ñ Ð²Ñегда возвращает 1. + + + + () The number of the current row's peer group within its partition - the rank of the current row without gaps. Partitions are numbered starting from 1 in the order defined by the ORDER BY clause in the window definition. If there is no ORDER BY clause, then all rows are considered peers and this function always returns 1. + () ЧиÑло одноранговой группы текущей Ñтроки в Ñвоем разделе - ранг текущей Ñтроки без пробелов. Разделы нумеруютÑÑ, Ð½Ð°Ñ‡Ð¸Ð½Ð°Ñ Ñ 1 в порÑдке, определенном выражением ORDER BY в определении окна. ЕÑли не ÑущеÑтвует Ð¿Ñ€ÐµÐ´Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ ORDER BY, вÑе Ñтроки ÑчитаютÑÑ Ð¾Ð´Ð½Ð¾Ñ€Ð°Ð½Ð³Ð¾Ð²Ñ‹Ð¼Ð¸, и Ñта Ñ„ÑƒÐ½ÐºÑ†Ð¸Ñ Ð²Ñегда возвращает 1. + + + + () Despite the name, this function always returns a value between 0.0 and 1.0 equal to (rank - 1)/(partition-rows - 1), where rank is the value returned by built-in window function rank() and partition-rows is the total number of rows in the partition. If the partition contains only one row, this function returns 0.0. + () ÐеÑÐ¼Ð¾Ñ‚Ñ€Ñ Ð½Ð° имÑ, Ñта Ñ„ÑƒÐ½ÐºÑ†Ð¸Ñ Ð²Ñегда возвращает значение между 0.0 и 1.0, равное (rank-1) / (partition-rows-1), где rank - Ñто значение, возвращаемое вÑтроенной функцией window rank () rows - Ñто общее количеÑтво Ñтрок в разделе. ЕÑли раздел Ñодержит только одну Ñтроку, Ñта Ñ„ÑƒÐ½ÐºÑ†Ð¸Ñ Ð²Ð¾Ð·Ð²Ñ€Ð°Ñ‰Ð°ÐµÑ‚ 0.0. + + + + () The cumulative distribution. Calculated as row-number/partition-rows, where row-number is the value returned by row_number() for the last peer in the group and partition-rows the number of rows in the partition. + () КумулÑтивное раÑпределение. РаÑÑчитываетÑÑ ÐºÐ°Ðº номер-Ñтроки / Ñтроки-раздела, где номер-Ñтроки - Ñто значение, возвращаемое row_number() Ð´Ð»Ñ Ð¿Ð¾Ñледнего однорангового узла в группе, а Ñтроки-раздела- количеÑтво Ñтрок в разделе. + + + + (N) Argument N is handled as an integer. This function divides the partition into N groups as evenly as possible and assigns an integer between 1 and N to each group, in the order defined by the ORDER BY clause, or in arbitrary order otherwise. If necessary, larger groups occur first. This function returns the integer value assigned to the group that the current row is a part of. + (N) Ðргумент N обрабатываетÑÑ ÐºÐ°Ðº целое чиÑло. Эта Ñ„ÑƒÐ½ÐºÑ†Ð¸Ñ Ð´ÐµÐ»Ð¸Ñ‚ раздел на N групп как можно более равномерно и назначает целое чиÑло от 1 до N каждой группе в порÑдке, определенном выражением ORDER BY, или в произвольном порÑдке, при его отÑутÑтвии. При необходимоÑти Ñначала поÑвлÑÑŽÑ‚ÑÑ Ð±Ð¾Ð»ÑŒÑˆÐ¸Ðµ группы. Эта Ñ„ÑƒÐ½ÐºÑ†Ð¸Ñ Ð²Ð¾Ð·Ð²Ñ€Ð°Ñ‰Ð°ÐµÑ‚ целочиÑленное значение, приÑвоенное группе, в которой находитÑÑ Ñ‚ÐµÐºÑƒÑ‰Ð°Ñ Ñтрока. + + + + (expr) Returns the result of evaluating expression expr against the previous row in the partition. Or, if there is no previous row (because the current row is the first), NULL. + (expr) Возвращает результат вычиÑÐ»ÐµÐ½Ð¸Ñ Ð²Ñ‹Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ expr в предыдущей Ñтроке раздела. Или, еÑли нет предыдущей Ñтроки (поÑкольку Ñ‚ÐµÐºÑƒÑ‰Ð°Ñ Ñтрока ÑвлÑетÑÑ Ð¿ÐµÑ€Ð²Ð¾Ð¹), NULL. + + + + (expr,offset) If the offset argument is provided, then it must be a non-negative integer. In this case the value returned is the result of evaluating expr against the row offset rows before the current row within the partition. If offset is 0, then expr is evaluated against the current row. If there is no row offset rows before the current row, NULL is returned. + (expr, offset) ЕÑли аргумент offset укзан, то он должен быть неотрицательным целым чиÑлом. Ð’ Ñтом Ñлучае возвращаемое значение ÑвлÑетÑÑ Ñ€ÐµÐ·ÑƒÐ»ÑŒÑ‚Ð°Ñ‚Ð¾Ð¼ вычиÑÐ»ÐµÐ½Ð¸Ñ expr в Ñтроках ÑÐ¼ÐµÑ‰ÐµÐ½Ð¸Ñ Ñтрок до текущей Ñтроки в разделе. ЕÑли Ñмещение равно 0, то expr вычиÑлÑетÑÑ Ð¾Ñ‚Ð½Ð¾Ñительно текущей Ñтроки. ЕÑли перед текущей Ñтрокой нет Ñтрок ÑÐ¼ÐµÑ‰ÐµÐ½Ð¸Ñ Ñтрок, возвращаетÑÑ NULL. + + + + + (expr,offset,default) If default is also provided, then it is returned instead of NULL if the row identified by offset does not exist. + (expr, offset, default) ЕÑли задано значение по умолчанию, оно возвращаетÑÑ Ð²Ð¼ÐµÑто NULL, еÑли Ñтрока, Ð¸Ð´ÐµÐ½Ñ‚Ð¸Ñ„Ð¸Ñ†Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð½Ð°Ñ Ñ Ð¿Ð¾Ð¼Ð¾Ñ‰ÑŒÑŽ ÑмещениÑ, не ÑущеÑтвует. + + + + (expr) Returns the result of evaluating expression expr against the next row in the partition. Or, if there is no next row (because the current row is the last), NULL. + (expr) Возвращает результат вычиÑÐ»ÐµÐ½Ð¸Ñ Ð²Ñ‹Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ expr в Ñледующей Ñтроке раздела. Или, еÑли нет Ñледующей Ñтроки (поÑкольку поÑледнÑÑ Ñтрока ÑвлÑетÑÑ Ð¿Ð¾Ñледней), NULL. + + + + (expr,offset) If the offset argument is provided, then it must be a non-negative integer. In this case the value returned is the result of evaluating expr against the row offset rows after the current row within the partition. If offset is 0, then expr is evaluated against the current row. If there is no row offset rows after the current row, NULL is returned. + (expr, offset) ЕÑли аргумент offset указан, то он должен быть неотрицательным целым чиÑлом. Ð’ Ñтом Ñлучае возвращаемое значение ÑвлÑетÑÑ Ñ€ÐµÐ·ÑƒÐ»ÑŒÑ‚Ð°Ñ‚Ð¾Ð¼ вычиÑÐ»ÐµÐ½Ð¸Ñ expr в Ñтроках ÑÐ¼ÐµÑ‰ÐµÐ½Ð¸Ñ Ñтрок поÑле текущей Ñтроки в разделе. ЕÑли Ñмещение равно 0, то expr вычиÑлÑетÑÑ Ð¾Ñ‚Ð½Ð¾Ñительно текущей Ñтроки. ЕÑли поÑле текущей Ñтроки нет Ñтрок ÑÐ¼ÐµÑ‰ÐµÐ½Ð¸Ñ Ñтроки, возвращаетÑÑ NULL. + + + + (expr) This built-in window function calculates the window frame for each row in the same way as an aggregate window function. It returns the value of expr evaluated against the first row in the window frame for each row. + (expr) Эта вÑÑ‚Ñ€Ð¾ÐµÐ½Ð½Ð°Ñ ÐžÐºÐ¾Ð½Ð½Ð°Ñ Ð¤ÑƒÐ½ÐºÑ†Ð¸Ñ Ð²Ñ‹Ñ‡Ð¸ÑлÑет Оконный Кадр Ð´Ð»Ñ ÐºÐ°Ð¶Ð´Ð¾Ð¹ Ñтроки так же, как Ð¤ÑƒÐ½ÐºÑ†Ð¸Ñ ÐžÐºÐ½Ð° агрегата. Она возвращает значение Ð²Ñ‹Ð¿Ð¾Ð»Ð½ÐµÐ½Ð¸Ñ Ð²Ñ‹Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ expr, оцениваемое по отношению к первой Ñтроке в оконном фрейме Ð´Ð»Ñ ÐºÐ°Ð¶Ð´Ð¾Ð¹ Ñтроки. + + + + (expr) This built-in window function calculates the window frame for each row in the same way as an aggregate window function. It returns the value of expr evaluated against the last row in the window frame for each row. + (expr) Эта вÑÑ‚Ñ€Ð¾ÐµÐ½Ð½Ð°Ñ ÐžÐºÐ¾Ð½Ð½Ð°Ñ Ð¤ÑƒÐ½ÐºÑ†Ð¸Ñ Ð²Ñ‹Ñ‡Ð¸ÑлÑет Оконный Кадр Ð´Ð»Ñ ÐºÐ°Ð¶Ð´Ð¾Ð¹ Ñтроки так же, как Ð¤ÑƒÐ½ÐºÑ†Ð¸Ñ ÐžÐºÐ½Ð° агрегата. Она возвращает значение Ð²Ñ‹Ð¿Ð¾Ð»Ð½ÐµÐ½Ð¸Ñ Ð²Ñ‹Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ expr, оцениваемое по отношению к поÑледней Ñтроке в оконном фрейме Ð´Ð»Ñ ÐºÐ°Ð¶Ð´Ð¾Ð¹ Ñтроки. + (expr) Эта вÑÑ‚Ñ€Ð¾ÐµÐ½Ð½Ð°Ñ Ñ„ÑƒÐ½ÐºÑ†Ð¸Ñ Ð¾ÐºÐ½Ð° вычиÑлÑет оконный кадр Ð´Ð»Ñ ÐºÐ°Ð¶Ð´Ð¾Ð¹ Ñтроки так же, как Ñ„ÑƒÐ½ÐºÑ†Ð¸Ñ Ð¾ÐºÐ½Ð° агрегата. Он возвращает значение expr, оцениваемое по поÑледней Ñтроке в оконном фрейме Ð´Ð»Ñ ÐºÐ°Ð¶Ð´Ð¾Ð¹ Ñтроки. + + + + (expr,N) This built-in window function calculates the window frame for each row in the same way as an aggregate window function. It returns the value of expr evaluated against the row N of the window frame. Rows are numbered within the window frame starting from 1 in the order defined by the ORDER BY clause if one is present, or in arbitrary order otherwise. If there is no Nth row in the partition, then NULL is returned. + (expr, N) Эта вÑÑ‚Ñ€Ð¾ÐµÐ½Ð½Ð°Ñ Ñ„ÑƒÐ½ÐºÑ†Ð¸Ñ Ð¾ÐºÐ½Ð° вычиÑлÑет оконный фрейм Ð´Ð»Ñ ÐºÐ°Ð¶Ð´Ð¾Ð¹ Ñтроки так же, как Ñ„ÑƒÐ½ÐºÑ†Ð¸Ñ Ð¾ÐºÐ½Ð° агрегата. Она возвращает значение Ð²Ñ‹Ð¿Ð¾Ð»Ð½ÐµÐ½Ð¸Ñ Ð²Ñ‹Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ expr, оцениваемое по Ñтроке N оконного фрейма. Строки нумеруютÑÑ Ð² рамке окна, Ð½Ð°Ñ‡Ð¸Ð½Ð°Ñ Ñ 1 в порÑдке, определенном выражением ORDER BY, еÑли оно приÑутÑтвует, или в произвольном порÑдке в противном Ñлучае. ЕÑли в разделе нет N-й Ñтроки, возвращаетÑÑ NULL. + + + + SqliteTableModel + + + reading rows + читаем Ñтроки + + + + loading... + загрузка... + + + + References %1(%2) +Hold %3Shift and click to jump there + СÑылаетÑÑ Ð½Ð° %1(%2) +Ðажмите %3Shift и клик чтобы перемеÑтитьÑÑ Ñ‚ÑƒÐ´Ð° + + + + Error changing data: +%1 + Ошибка Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ð´Ð°Ð½Ð½Ñ‹Ñ…: +%1 + + + + retrieving list of columns + получаем ÑпиÑок колонок + + + + Fetching data... + Подгружаем данные... + + + + + Cancel + Отменить + + + + TableBrowser + + + Browse Data + Данные + + + + &Table: + &Таблица: + + + + Select a table to browse data + Выберите таблицу Ð´Ð»Ñ Ð¿Ñ€Ð¾Ñмотра данных + + + + Use this list to select a table to be displayed in the database view + ИÑпользуйте Ñтот ÑпиÑок, чтобы выбрать таблицу, ÐºÐ¾Ñ‚Ð¾Ñ€Ð°Ñ Ð´Ð¾Ð»Ð¶Ð½Ð° быть отображена в предÑтавлении базы данных + + + + This is the database table view. You can do the following actions: + - Start writing for editing inline the value. + - Double-click any record to edit its contents in the cell editor window. + - Alt+Del for deleting the cell content to NULL. + - Ctrl+" for duplicating the current record. + - Ctrl+' for copying the value from the cell above. + - Standard selection and copy/paste operations. + Это предÑтавление таблицы БД. Ð’Ñ‹ можете выполнить Ñледующие дейÑтвиÑ: + - Ðачните пиÑать Ð´Ð»Ñ Ñ€ÐµÐ´Ð°ÐºÑ‚Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ, Ð²Ð²ÐµÐ´Ñ Ð·Ð½Ð°Ñ‡ÐµÐ½Ð¸Ðµ. + - Дважды щелкните любую запиÑÑŒ, чтобы отредактировать ее Ñодержимое в окне редактора Ñчеек. + - Alt + Del Ð´Ð»Ñ Ð¾Ð±Ð½ÑƒÐ»ÐµÐ½Ð¸Ñ Ñодержимого Ñчейки в NULL. + - Ctrl + " Ð´Ð»Ñ Ð´ÑƒÐ±Ð»Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ Ñ‚ÐµÐºÑƒÑ‰ÐµÐ¹ запиÑи. + - Ctrl + ' Ð´Ð»Ñ ÐºÐ¾Ð¿Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ Ð·Ð½Ð°Ñ‡ÐµÐ½Ð¸Ñ Ð¸Ð· Ñчейки выше. + - Стандартные операции выбора и копированиÑ/вÑтавки. + + + + Text pattern to find considering the checks in this frame + Шаблон Ð´Ð»Ñ Ð¿Ð¾Ð¸Ñка, ÑƒÑ‡Ð¸Ñ‚Ñ‹Ð²Ð°Ñ Ð²Ñе проверки + + + + Find in table + + + + + Find previous match [Shift+F3] + Ðайти предыдущее Ñовпадение [Shift+F3] + + + + Find previous match with wrapping + Ðайти предыдущее Ñовпадение, закольцевав поиÑк + + + + Shift+F3 + + + + + Find next match [Enter, F3] + Ðайти Ñледующее Ñовпдение [Enter, F3] + + + + Find next match with wrapping + Ðайти Ñледующее Ñовпадение, закольцевав поиÑк + + + + F3 + + + + + The found pattern must match in letter case + У найденного шаблона должен Ñовпадать региÑтр + + + + Case Sensitive + Учитывать РегиÑтр + + + + The found pattern must be a whole word + Ðайденный шаблон должен быть целым Ñловом + + + + Whole Cell + + + + + Interpret search pattern as a regular expression + Интерпретировать шаблон поиÑка как регулÑрное выражение + + + + <html><head/><body><p>When checked, the pattern to find is interpreted as a UNIX regular expression. See <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>.</p></body></html> + <html><head/><body><p>При проверке шаблон Ð´Ð»Ñ Ð¿Ð¾Ð¸Ñка интерпретируетÑÑ ÐºÐ°Ðº регулÑрное выражение UNIX. <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Узнать больше о РегулÑрных выражениÑÑ… на Wikibooks.org</a>.</p></body></html> + + + + Regular Expression + РегулÑрное выражение + + + + + Close Find Bar + Закрыть ПоиÑковую Панель + + + + Text to replace with + + + + + Replace with + + + + + Replace next match + + + + + + Replace + + + + + Replace all matches + + + + + Replace all + + + + + <html><head/><body><p>Scroll to the beginning</p></body></html> + <html><head/><body><p>Прокрутить к началу</p></body></html> + + + + <html><head/><body><p>Clicking this button navigates to the beginning in the table view above.</p></body></html> + <html><head/><body><p>Ðажатие Ñтой кнопки переводит к началу в таблице выше.</p></body></html> + + + + |< + + + + + Scroll one page upwards + Страница вверх + + + + <html><head/><body><p>Clicking this button navigates one page of records upwards in the table view above.</p></body></html> + <html><head/><body><p>Ðажатие Ñтой кнопки перемещает одну Ñтраницу запиÑей вверх в виде таблицы выше.</p></body></html> + + + + < + < + + + + 0 - 0 of 0 + 0 - 0 из 0 + + + + Scroll one page downwards + Страница вниз + + + + <html><head/><body><p>Clicking this button navigates one page of records downwards in the table view above.</p></body></html> + <html><head/><body><p>Ðажатие Ñтой кнопки перемещает одну Ñтраницу запиÑей вниз в виде таблицы выше.</p></body></html> + + + + > + > + + + + Scroll to the end + Прокрутить к концу + + + + <html><head/><body><p>Clicking this button navigates up to the end in the table view above.</p></body></html> + + + + + >| + + + + + <html><head/><body><p>Click here to jump to the specified record</p></body></html> + <html><head/><body><p>Ðажмите здеÑÑŒ, чтобы перейти к указанной запиÑи</p></body></html> + + + + <html><head/><body><p>This button is used to navigate to the record number specified in the Go to area.</p></body></html> + <html><head/><body><p>Эта кнопка иÑпользуетÑÑ, чтобы перемеÑтитьÑÑ Ðº запиÑи, номер которой указан в облаÑти Перейти к</p></body></html> + + + + Go to: + Перейти к: + + + + Enter record number to browse + Введите номер запиÑи Ð´Ð»Ñ Ð¿Ñ€Ð¾Ñмотра + + + + Type a record number in this area and click the Go to: button to display the record in the database view + Ðапечатайте номер запиÑи в Ñтой облаÑти и нажмите кнопку Перейти к:, чтобы отобразить запиÑÑŒ в предÑтавлении базы данных + + + + 1 + 1 + + + + Show rowid column + Отображать колонку rowid + + + + Toggle the visibility of the rowid column + + + + + Unlock view editing + Разблокировать возможноÑть Ñ€ÐµÐ´Ð°ÐºÑ‚Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ + + + + This unlocks the current view for editing. However, you will need appropriate triggers for editing. + Разблокировать текущий вид Ð´Ð»Ñ Ñ€ÐµÐ´Ð°ÐºÑ‚Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ. Однако Ð´Ð»Ñ Ñ€ÐµÐ´Ð°ÐºÑ‚Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ Ð²Ð°Ð¼ понадобÑÑ‚ÑÑ ÑоответÑтвующие триггеры. + + + + Edit display format + Формат Ð¾Ñ‚Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ + + + + Edit the display format of the data in this column + Редактирование формата Ð¾Ñ‚Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ Ð´Ð»Ñ Ð´Ð°Ð½Ð½Ñ‹Ñ… из Ñтой колонки + + + + + New Record + Добавить запиÑÑŒ + + + + + Insert a new record in the current table + Добавить новую запиÑÑŒ в текущую таблицу + + + + <html><head/><body><p>This button creates a new record in the database. Hold the mouse button to open a pop-up menu of different options:</p><ul><li><span style=" font-weight:600;">New Record</span>: insert a new record with default values in the database.</li><li><span style=" font-weight:600;">Insert Values...</span>: open a dialog for entering values before they are inserted in the database. This allows to enter values acomplishing the different constraints. This dialog is also open if the <span style=" font-weight:600;">New Record</span> option fails due to these constraints.</li></ul></body></html> + <html><head/><body><p>Эта кнопка Ñоздает новую запиÑÑŒ в базе данных. Удерживайте кнопку мыши, чтобы открыть вÑплывающее меню различных параметров:</p><ul><li><span style=" font-weight:600;">ÐÐ¾Ð²Ð°Ñ Ð—Ð°Ð¿Ð¸ÑÑŒ</span>: вÑтавлÑет новую запиÑÑŒ Ñо значениÑми по умолчанию.</li><li><span style=" font-weight:600;">Ð’Ñтавить ЗначениÑ...</span>: открывает диалог Ð´Ð»Ñ Ð²Ð²Ð¾Ð´Ð° значений перед тем, как они будут вÑтавленны в БД. Это позволÑет вводить значениÑ, Ð½Ð°Ð·Ð½Ð°Ñ‡Ð°Ñ Ñ€Ð°Ð·Ð»Ð¸Ñ‡Ð½Ñ‹Ðµ ограничениÑ. Этот диалог также открываетÑÑ, еÑли <span style=" font-weight:600;">ÐÐ¾Ð²Ð°Ñ Ð—Ð°Ð¿Ð¸ÑÑŒ</span> Ð¾Ð¿Ñ†Ð¸Ñ Ð½Ðµ Ñрабатывает из-за Ñтих ограничений.</li></ul></body></html> + + + + + Delete Record + Удалить запиÑÑŒ + + + + Delete the current record + Удалить текущую запиÑÑŒ + + + + + This button deletes the record or records currently selected in the table + Эта кнопка удалÑет запиÑÑŒ или запиÑи, выбранные в наÑтоÑщее Ð²Ñ€ÐµÐ¼Ñ Ð² таблице + + + + + Insert new record using default values in browsed table + Ð’ÑтавлÑет новую запиÑÑŒ, иÑÐ¿Ð¾Ð»ÑŒÐ·ÑƒÑ Ð·Ð½Ð°Ñ‡ÐµÐ½Ð¸Ñ Ð¿Ð¾ умолчанию в проÑматриваемой таблице + + + + Insert Values... + Ð’Ñтавить ЗначениÑ... + + + + + Open a dialog for inserting values in a new record + Открывает диалоговое окно Ð´Ð»Ñ Ð²Ñтавки значений в новую запиÑÑŒ + + + + Export to &CSV + ЭкÑпортировать в &CSV + + + + + Export the filtered data to CSV + ЭкÑпортировать отфильтрованные данные в CSV + + + + This button exports the data of the browsed table as currently displayed (after filters, display formats and order column) as a CSV file. + Эта кнопка ÑкÑпортирует данные проÑматриваемой таблицы так как отображаетÑÑ (поÑле обработки фильтрами, форматами Ð¾Ñ‚Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ Ð¸ Ñ‚.д.) в виде файла CSV. + + + + Save as &view + Сохранить как &предÑтавление + + + + + Save the current filter, sort column and display formats as a view + Сохранить текущие фильтры, Ñтолбецы Ñортировки и форматы Ð¾Ñ‚Ð¾Ð±Ñ€Ð°Ð¶Ð°Ð½Ð¸Ñ Ð² виде предÑÑ‚Ð°Ð²Ð»ÐµÐ½Ð¸Ñ + + + + This button saves the current setting of the browsed table (filters, display formats and order column) as an SQL view that you can later browse or use in SQL statements. + Эта кнопка ÑохранÑет текущие наÑтройки проÑматриваемой таблицы (фильтры, форматы Ð¾Ñ‚Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ Ð¸ Ñтолбец Ñортировки) в виде предÑÑ‚Ð°Ð²Ð»ÐµÐ½Ð¸Ñ SQL, которое вы можете впоÑледÑтвии проÑмотреть или иÑпользовать в операторах SQL. + + + + Save Table As... + + + + + + Save the table as currently displayed + Сохранить таблицу так как ÑÐµÐ¹Ñ‡Ð°Ñ Ð¾Ñ‚Ð¾Ð±Ñ€Ð°Ð¶Ð°ÐµÑ‚ÑÑ + + + + <html><head/><body><p>This popup menu provides the following options applying to the currently browsed and filtered table:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Export to CSV: this option exports the data of the browsed table as currently displayed (after filters, display formats and order column) to a CSV file.</li><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Save as view: this option saves the current setting of the browsed table (filters, display formats and order column) as an SQL view that you can later browse or use in SQL statements.</li></ul></body></html> + <html><head/><body><p>Это вÑплывающее меню предоÑтавлÑет Ñледующие параметры, применÑемые к текущей проÑматриваемой и отфильтрованной таблице:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">ЭкÑпортировать ввиде CSV: данные проÑматриваемой таблицы ÑохранÑетÑÑ Ñ‚Ð°Ðº как отображаетÑÑ (поÑле Ð¿Ñ€Ð¸Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ñ„Ð¸Ð»ÑŒÑ‚Ñ€Ð¾Ð², форматов Ð¾Ñ‚Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ Ð¸ порÑдка колонок) в CSV файл.</li><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Сохранить как вид: Ñта Ð¾Ð¿Ñ†Ð¸Ñ ÑохранÑет наÑтройки текущей отображаемой таблицы (фильтры, форматы Ð¾Ñ‚Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ Ð¸ порÑдок колонок) как SQL вид, который вы позже можете проÑматривать или иÑпользовать в SQL выражениÑÑ….</li></ul></body></html> + + + + Hide column(s) + Скрыть колонки + + + + Hide selected column(s) + Скрыть выбранные колонки + + + + Show all columns + Показать вÑе колонки + + + + Show all columns that were hidden + Показать вÑе колонки, которые были Ñкрыты + + + + + Set encoding + Кодировка + + + + Change the encoding of the text in the table cells + Изменение кодировки текÑта в данной таблице + + + + Set encoding for all tables + УÑтановить кодировку Ð´Ð»Ñ Ð²Ñех таблиц + + + + Change the default encoding assumed for all tables in the database + Изменить кодировку по умолчанию Ð´Ð»Ñ Ð²Ñех таблиц в базе данных + + + + Clear Filters + + + + + Clear all filters + ОчиÑтить вÑе фильтры + + + + + This button clears all the filters set in the header input fields for the currently browsed table. + Эта кнопка очищает вÑе фильтры, уÑтановленные в полÑÑ… ввода заголовка Ð´Ð»Ñ Ñ‚ÐµÐºÑƒÑ‰ÐµÐ¹ проÑматриваемой таблицы. + + + + Clear Sorting + + + + + Reset the order of rows to the default + + + + + + This button clears the sorting columns specified for the currently browsed table and returns to the default order. + + + + + Print + Печать + + + + Print currently browsed table data + Печатать отображаемую таблицу + + + + Print currently browsed table data. Print selection if more than one cell is selected. + РаÑпечатывайте текущие данные таблицы. Выбор печати, еÑли выбрано неÑколько Ñчеек. + + + + Ctrl+P + + + + + Refresh + Обновить + + + + Refresh the data in the selected table + Обновить данные в выбранной таблице + + + + This button refreshes the data in the currently selected table. + Эта кнопка обновлÑет данные выбранной в данный момент таблицы. + + + + F5 + + + + + Find in cells + + + + + Open the find tool bar which allows you to search for values in the table view below. + + + + + + Bold + Жирный + + + + Ctrl+B + + + + + + Italic + КурÑив + + + + + Underline + Подчёркивание + + + + Ctrl+U + + + + + + Align Right + + + + + + Align Left + + + + + + Center Horizontally + + + + + + Justify + + + + + + Edit Conditional Formats... + + + + + Edit conditional formats for the current column + + + + + Clear Format + + + + + Clear All Formats + + + + + + Clear all cell formatting from selected cells and all conditional formats from selected columns + + + + + + Font Color + + + + + + Background Color + + + + + Toggle Format Toolbar + + + + + Show/hide format toolbar + + + + + + This button shows or hides the formatting toolbar of the Data Browser + + + + + Select column + + + + + Ctrl+Space + + + + + Replace text in cells + + + + + Filter in any column + + + + + Ctrl+R + + + + + %n row(s) + + + + + + + + + , %n column(s) + + + + + + + + + . Sum: %1; Average: %2; Min: %3; Max: %4 + + + + + Conditional formats for "%1" + + + + + determining row count... + определÑем количеÑтво Ñтрок... + + + + %1 - %2 of >= %3 + %1 - %2 из >= %3 + + + + %1 - %2 of %3 + %1 - %2 из %3 + + + + Please enter a pseudo-primary key in order to enable editing on this view. This should be the name of a unique column in the view. + ПожалуйÑта, введите пÑевдо-первичный ключ, чтобы разрешить редактирование в Ñтом предÑтавлении. Это должно быть Ð¸Ð¼Ñ ÑƒÐ½Ð¸ÐºÐ°Ð»ÑŒÐ½Ð¾Ð³Ð¾ Ñтолбца в предÑтавлении. + + + + Delete Records + Удалить ЗапиÑи + + + + Duplicate records + Дублированные запиÑи + + + + Duplicate record + Дубликат запиÑи + + + + Ctrl+" + + + + + Adjust rows to contents + + + + + Error deleting record: +%1 + Ошибка ÑƒÐ´Ð°Ð»ÐµÐ½Ð¸Ñ Ð·Ð°Ð¿Ð¸Ñи: %1 + + + + Please select a record first + Сначала выберите запиÑÑŒ + + + + There is no filter set for this table. View will not be created. + Ð”Ð»Ñ Ñтой таблицы не уÑтановлен фильтр. ПредÑтавление не будет Ñоздано. + + + + Please choose a new encoding for all tables. + ПожалуйÑта выбирите новую кодировку Ð´Ð»Ñ Ð²Ñех таблиц. + + + + Please choose a new encoding for this table. + ПожалуйÑта выбирите новую кодировку Ð´Ð»Ñ Ð´Ð°Ð½Ð½Ð¾Ð¹ таблицы. + + + + %1 +Leave the field empty for using the database encoding. + %1 +ОÑтавьте Ñто поле пуÑтым еÑли хотите чтобы иÑпользовалаÑÑŒ кодировка по умолчанию. + + + + This encoding is either not valid or not supported. + ÐÐµÐ²ÐµÑ€Ð½Ð°Ñ ÐºÐ¾Ð´Ð¸Ñ€Ð¾Ð²ÐºÐ° либо она не поддерживаетÑÑ. + + + + %1 replacement(s) made. + + + + + VacuumDialog + + + Compact Database + Ðе понÑтно, что лучше "уплотнение" или "Ñжатие"? + Уплотнение базы данных + + + + Warning: Compacting the database will commit all of your changes. + Предупреждение: Уплотнение базы данных зафикÑирует вÑе изменениÑ, которые были Ñделаны. + + + + Please select the databases to co&mpact: + Выберите объекты Ð´Ð»Ñ &уплотнениÑ: + + + diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/translations/sqlb_tr.qm b/src/WBCLFZSystemModule/SqliteDBProcess/src/translations/sqlb_tr.qm new file mode 100644 index 0000000000000000000000000000000000000000..21ab22af34089015fc04810b93d7c4b4da833be3 GIT binary patch literal 225322 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 + + + + AboutDialog + + + About DB Browser for SQLite + SQLite DB Browser Hakkında + + + + Version + Versiyon + + + + <html><head/><body><p>DB Browser for SQLite is an open source, freeware visual tool used to create, design and edit SQLite database files.</p><p>It is bi-licensed under the Mozilla Public License Version 2, as well as the GNU General Public License Version 3 or later. You can modify or redistribute it under the conditions of these licenses.</p><p>See <a href="http://www.gnu.org/licenses/gpl.html">http://www.gnu.org/licenses/gpl.html</a> and <a href="https://www.mozilla.org/MPL/2.0/index.txt">https://www.mozilla.org/MPL/2.0/index.txt</a> for details.</p><p>For more information on this program please visit our website at: <a href="http://sqlitebrowser.org">http://sqlitebrowser.org</a></p><p><span style=" font-size:small;">This software uses the GPL/LGPL Qt Toolkit from </span><a href="http://qt-project.org/"><span style=" font-size:small;">http://qt-project.org/</span></a><span style=" font-size:small;"><br/>See </span><a href="http://qt-project.org/doc/qt-5/licensing.html"><span style=" font-size:small;">http://qt-project.org/doc/qt-5/licensing.html</span></a><span style=" font-size:small;"> for licensing terms and information.</span></p><p><span style=" font-size:small;">It also uses the Silk icon set by Mark James licensed under a Creative Commons Attribution 2.5 and 3.0 license.<br/>See </span><a href="http://www.famfamfam.com/lab/icons/silk/"><span style=" font-size:small;">http://www.famfamfam.com/lab/icons/silk/</span></a><span style=" font-size:small;"> for details.</span></p></body></html> + <html> <head /> <body> <p> DB Browser for SQLite, SQLite veritabanı dosyaları oluÅŸturmak, tasarlamak ve düzenlemek için kullanılan açık kaynak kodlu, ücretsiz bir araçtır. </p> <p> 'Mozilla Kamu Lisansı Sürüm 2' ve 'GNU Genel Kamu Lisansı Sürüm 3 veya üstü' olmak üzere iki lisansa sahiptir. Bu lisansların koÅŸulları çerçevesinde yazılımı düzenleyebilir veya yeniden dağıtabilirsiniz. </p> <p> Detaylar için, lütfen <a href="http://www.gnu.org/licenses/gpl.html" >http://www.gnu.org/licenses/gpl.html</a > ve <a href="https://www.mozilla.org/MPL/2.0/index.txt" >https://www.mozilla.org/MPL/2.0/index.txt</a > adreslerini ziyaret ediniz. </p> <p> Bu yazılım hakkında detaylı bilgi için lütfen internet sitemizi ziyaret ediniz: <a href="http://sqlitebrowser.org">http://sqlitebrowser.org</a> </p> <p> <span style=" font-size:small;" >Bu yazılım GPL/LGPL lisansına sahip Qt Araç Kitini (<a href="http://qt-project.org/" ><span style=" font-size:small;">http://qt-project.org/</span></a>) kullanmaktadır.</span> <br /> <span style=" font-size:small;">Lisans koÅŸulları ve bilgiler için </span ><a href="http://qt-project.org/doc/qt-5/licensing.html" ><span style=" font-size:small;" >http://qt-project.org/doc/qt-5/licensing.html</span ></a ><span style=" font-size:small;"> adresini ziyaret ediniz.</span > </p> <p> <span style=" font-size:small;" > Bu yazılım ayrıca, Mark James tarafından hazırlanan, 'Creative Commons Attribution 2.5 veya 3.0' lisansına sahip Silk ikon setini kullanmaktadır. <br />Detaylar için </span ><a href="http://www.famfamfam.com/lab/icons/silk/" ><span style=" font-size:small;" >http://www.famfamfam.com/lab/icons/silk/</span ></a ><span style=" font-size:small;"> adresini ziyaret ediniz.</span> </p> </body> </html> + + + + AddRecordDialog + + + Add New Record + Yeni Kayıt Ekle + + + + Enter values for the new record considering constraints. Fields in bold are mandatory. + Yeni kayıt için kısıtlamaları göz önüne alarak yeni deÄŸerleri giriniz. Kalın vurgulu alanlar zorunludur. + + + + In the Value column you can specify the value for the field identified in the Name column. The Type column indicates the type of the field. Default values are displayed in the same style as NULL values. + DeÄŸer sütununda, isim sütunuyla belirtilen alan için deÄŸer belirtebilirsiniz. Tip sütunu alanın tipini belirtir. Varsayılan deÄŸerler NULL ile aynı stilde görüntülenir. + + + + Name + İsim + + + + Type + Tip + + + + Value + DeÄŸer + + + + Values to insert. Pre-filled default values are inserted automatically unless they are changed. + Eklenecek deÄŸerler. Varsayılan olarak doldurulmuÅŸ deÄŸerler, deÄŸiÅŸtirilmedikleri takdirde otomatik olarak ekleneceklerdir. + + + + When you edit the values in the upper frame, the SQL query for inserting this new record is shown here. You can edit manually the query before saving. + Üstteki bölümdeki deÄŸerleri deÄŸiÅŸtirdiÄŸinizde, yeni kaydı eklemek için kullanılacak sorgu burada görüntülenir. Kaydet butonuna basmadan önce manuel olarak bu sorguyu düzenleyebilirsiniz. + + + + <html><head/><body><p><span style=" font-weight:600;">Save</span> will submit the shown SQL statement to the database for inserting the new record.</p><p><span style=" font-weight:600;">Restore Defaults</span> will restore the initial values in the <span style=" font-weight:600;">Value</span> column.</p><p><span style=" font-weight:600;">Cancel</span> will close this dialog without executing the query.</p></body></html> + <html> <head /> <body> <p> <span style=" font-weight:600;">Kaydet</span> butonu yeni kaydı eklemek için ilgili SQL ifadesini veritabanına gönderir. </p> <p> <span style=" font-weight:600;">Varsayılanları Yükle</span> butonu <span style=" font-weight:600;">DeÄŸer</span> sütunundakileri varsayılanlarına yükler. </p> <p> <span style=" font-weight:600;">İptal</span> butonu sorguyu çalıştırmadan bu pencereyi kapatır. </p> </body> </html> + + + + Auto-increment + + Otomatik-Artan + + + + + Unique constraint + + Benzersiz kısıtı + + + + + Check constraint: %1 + + Kısıtlamayı kontrol et: %1 + + + + + Foreign key: %1 + + Yabancı anahatar: %1 + + + + + Default value: %1 + + Varsayılan deÄŸer: %1 + + + + + Error adding record. Message from database engine: + +%1 + Kayıt eklenirken hata oluÅŸtu. Veritabanı motoru mesajı: + +%1 + + + + Are you sure you want to restore all the entered values to their defaults? + Girilen bütün deÄŸerleri varsayılanlarına döndürmek istediÄŸinize emin misiniz? + + + + Application + + + Possible command line arguments: + Muhtemel komut satırı argümanları: + + + + Usage: %1 [options] [<database>|<project>] + + + + + + -h, --help Show command line options + + + + + -q, --quit Exit application after running scripts + + + + + -s, --sql <file> Execute this SQL file after opening the DB + + + + + -t, --table <table> Browse this table after opening the DB + + + + + -R, --read-only Open database in read-only mode + + + + + -o, --option <group>/<setting>=<value> + + + + + Run application with this setting temporarily set to value + + + + + -O, --save-option <group>/<setting>=<value> + + + + + Run application saving this value for this setting + + + + + -v, --version Display the current version + + + + + <database> Open this SQLite database + + + + + <project> Open this project file (*.sqbpro) + + + + + The -s/--sql option requires an argument + -s/--sql opsiyonu bir argüman gerektirir + + + + The file %1 does not exist + %1 dosyası mevcut deÄŸil + + + + The -t/--table option requires an argument + -t/--table opsiyonu bir argüman gerektirir + + + + The -o/--option and -O/--save-option options require an argument in the form group/setting=value + -o/--option ve -O/--save-option opsiyonları grup/ayar=deÄŸer formatında bir argüman gerektirir + + + + Invalid option/non-existant file: %1 + Geçersiz seçenek veya mevcut olmayan dosya: %1 + + + + SQLite Version + SQLite Versiyonu + + + + SQLCipher Version %1 (based on SQLite %2) + + + + + DB Browser for SQLite Version %1. + + + + + Built for %1, running on %2 + %1 için derlendi, %2 üzerinde çalışıyor + + + + Qt Version %1 + + + + + CipherDialog + + + SQLCipher encryption + SQLCipher ÅŸifrelemesi + + + + &Password + &Parola + + + + &Reenter password + Pa&rolayı tekrar girin + + + + Encr&yption settings + Åžifreleme A&yarları + + + + SQLCipher &3 defaults + SQLCipher &3 varsayılanları + + + + SQLCipher &4 defaults + SQLCipher &4 varsayılanları + + + + Custo&m + &Özel + + + + Page si&ze + &Sayfa boyutu + + + + &KDF iterations + &KDF yinelemeleri + + + + HMAC algorithm + HMAC algoritması + + + + KDF algorithm + KDF algoritması + + + + Plaintext Header Size + Düz Metin Üstbilgi Boyutu + + + + Passphrase + Parola + + + + Raw key + Ham anahtar + + + + Please set a key to encrypt the database. +Note that if you change any of the other, optional, settings you'll need to re-enter them as well every time you open the database file. +Leave the password fields empty to disable the encryption. +The encryption process might take some time and you should have a backup copy of your database! Unsaved changes are applied before modifying the encryption. + Lütfen veritabanını ÅŸifrelemek için anahtar ayarlayın. +Unutmayın, bunun dışında isteÄŸe baÄŸlı yapacağınız herhangi deÄŸiÅŸikliklerde, veritabanı dosyasını her açtığınızda ÅŸifrenizi yeniden girmeniz gerekecektir. +Åžifrelemeyi devre dışı bırakmak için parola alanını boÅŸ bırakınız. +Åžifreleme iÅŸlemi biraz zaman alabilir ve bu iÅŸlemi yapmadan önce veritabanınızın yedeÄŸini almalısınız! KaydedilmemiÅŸ deÄŸiÅŸiklikler ÅŸifreniz deÄŸiÅŸtirilmeden önce kaydedilir. + + + + Please enter the key used to encrypt the database. +If any of the other settings were altered for this database file you need to provide this information as well. + Lütfen veritabanınızı ÅŸifrelemek için kullandığınız anahtarı giriniz. +Bu veritabanı için herhangi bir baÅŸka ayar daha yapılmışsa, bu bilgileri de saÄŸlamalısınız. + + + + ColumnDisplayFormatDialog + + + Choose display format + Görüntüleme formatını seçiniz + + + + Display format + Görüntüleme formatı + + + + Choose a display format for the column '%1' which is applied to each value prior to showing it. + '%1' sütunu için görüntülemeden önce uygulanacak bir görüntüleme formatı seçin. + + + + Default + Varsayılan + + + + Decimal number + Ondalık sayı + + + + Exponent notation + Üslü gösterim + + + + Hex blob + Onaltılık ikili veri + + + + Hex number + Onaltılık sayı + + + + Apple NSDate to date + Apple NSDate tipinden tarih tipine + + + + Java epoch (milliseconds) to date + Java epoch (milisaniye) tipinden tarih tipine + + + + .NET DateTime.Ticks to date + + + + + Julian day to date + Julian day tipinden tarih tipine + + + + Unix epoch to local time + Unix epoch tipinden yerel zaman tipine + + + + Date as dd/mm/yyyy + dd/mm/yyyy tarih formatı + + + + Lower case + Küçük harf + + + + Custom display format must contain a function call applied to %1 + Özel görüntüleme formatı, %1 için uygulanan fonksiyon çaÄŸrısı içermelidir + + + + Error in custom display format. Message from database engine: + +%1 + Özel görüntüleme formatınde hata oluÅŸtu. Veritabanı motoru mesajı: + +%1 + + + + Custom display format must return only one column but it returned %1. + Özel görüntüleme formatı sadece bir sütun döndürmeli: %1. + + + + Octal number + Sekizlik sayı + + + + Round number + Küsüratsız sayı + + + + Unix epoch to date + Unix epoch tipinden tarih tipine + + + + Upper case + Büyük harf + + + + Windows DATE to date + Windows DATE tipinden tarih tipine + + + + Custom + Özel + + + + CondFormatManager + + + Conditional Format Manager + KoÅŸullu Biçim Yöneticisi + + + + This dialog allows creating and editing conditional formats. Each cell style will be selected by the first accomplished condition for that cell data. Conditional formats can be moved up and down, where those at higher rows take precedence over those at lower. Syntax for conditions is the same as for filters and an empty condition applies to all values. + Bu iletiÅŸim kutusu koÅŸullu biçimler oluÅŸturmaya ve düzenlemeye izin verir. Her hücre stili, hücre verisi için ilk saÄŸlanan koÅŸul tarafından seçilecektir. KoÅŸullu biçimler yukarı ve aÅŸağı taşınabilir, üst sıralardakiler alt sıralardakilere göre önceliklidir. KoÅŸullar için sözdizimi, filtreler ile aynıdır ve boÅŸ koÅŸullar tüm hücreler için geçerlidir. + + + + Add new conditional format + Yeni koÅŸullu biçim oluÅŸtur + + + + &Add + &Ekle + + + + Remove selected conditional format + Seçilen koÅŸullu biçimi sil + + + + &Remove + &Sil + + + + Move selected conditional format up + Seçilen koÅŸullu biçimi yukarı taşı + + + + Move &up + Y&ukarı taşı + + + + Move selected conditional format down + Seçilen koÅŸullu biçimi aÅŸağı taşı + + + + Move &down + AÅŸağı &Taşı + + + + Foreground + Ön plan + + + + Text color + Yazı rengi + + + + Background + Arka plan + + + + Background color + Arka plan rengi + + + + Font + Yazı tipi + + + + Size + Boyut + + + + Bold + Kalın + + + + Italic + İtalik + + + + Underline + Altı çizili + + + + Alignment + Hizalama + + + + Condition + KoÅŸul + + + + + Click to select color + Renk seçmek için tıklayın + + + + Are you sure you want to clear all the conditional formats of this field? + Bu alanın tüm koÅŸullu biçimlerini silmek istediÄŸinizden emin misiniz? + + + + DBBrowserDB + + + Please specify the database name under which you want to access the attached database + Lütfen veritabanının ismini eriÅŸmek istediÄŸiniz baÄŸlı veritabanının altında belirtin + + + + Invalid file format + Geçersiz dosya formatı + + + + Do you want to save the changes made to the database file %1? + %1 veritabanı dosyasında yaptığınız deÄŸiÅŸiklikleri kaydetmek istiyor musunuz? + + + + Exporting database to SQL file... + veritabanı, SQL dosyası olarak dışa aktarılıyor... + + + + + Cancel + İptal + + + + Executing SQL... + SQL yürütülüyor... + + + + Action cancelled. + İşlem iptal edildi. + + + + This database has already been attached. Its schema name is '%1'. + Bu veritabanı zaten mevcut ve ÅŸemasının ismi '%1'. + + + + Do you really want to close this temporary database? All data will be lost. + Gerçekten geçici veritabanını kapatmak istiyor musunuz? Bütün veriler kaybedilecek. + + + + Database didn't close correctly, probably still busy + Veritabanı doÄŸru bir ÅŸekilde kapatılamadı, muhtemelen hâlâ kullanımda + + + + The database is currently busy: + Veritabanı ÅŸu anda meÅŸgul: + + + + Do you want to abort that other operation? + DiÄŸer iÅŸlemi iptal etmek istiyor musunuz? + + + + + No database file opened + Hiçbir veritabanı dosyası açılmamış + + + + + Error in statement #%1: %2. +Aborting execution%3. + Belirtilen ifadede hata oluÅŸtu: #%1: %2 +Yürütme durduruluyor %3. + + + + + and rolling back + ve iÅŸlem geri alınıyor + + + + didn't receive any output from %1 + %1 sorgusundan herhangi bir çıktı alınamadı + + + + could not execute command: %1 + komut iÅŸletilemedi: %1 + + + + Cannot delete this object + Bu obje silinemiyor + + + + Cannot set data on this object + Bu objeye veri atanamıyor + + + + + A table with the name '%1' already exists in schema '%2'. + '%2' ÅŸemasında '%1' isimli tablo zaten mevcut. + + + + No table with name '%1' exists in schema '%2'. + '%2' ÅŸeması içerisinde '%1' isminde bir tablo yok. + + + + + Cannot find column %1. + %1 sütunu bulunamadı. + + + + Creating savepoint failed. DB says: %1 + Kayıt noktası oluÅŸturulamadı. Veritabanı mesajı: %1 + + + + Renaming the column failed. DB says: +%1 + Sütun yeniden adlandırılamadı. Veritabanı motoru mesajı: +%1 + + + + + Releasing savepoint failed. DB says: %1 + Kayıt noktası serbest bırakılamadı. Veritabanı motoru mesajı: %1 + + + + Creating new table failed. DB says: %1 + Veri tabanı oluÅŸturulamadı. Veritabanı mesajı: %1 + + + + Copying data to new table failed. DB says: +%1 + Yeni tabloya veri kopyalanamadı. Veritabanı mesajı: +%1 + + + + Deleting old table failed. DB says: %1 + Eski tablolar silinemedi: Veritabanı mesajı: %1 + + + + Error renaming table '%1' to '%2'. +Message from database engine: +%3 + '%1' tablosu '%2' olarak adlandırılırken hata oluÅŸtu. +Veritabanı motoru mesajı: +%3 + + + + could not get list of db objects: %1 + veritabanı objelerinin listesi alınamadı: %1 + + + + Restoring some of the objects associated with this table failed. This is most likely because some column names changed. Here's the SQL statement which you might want to fix and execute manually: + + + Bu tabloyla iliÅŸkili bazı objelerin restore iÅŸlemi baÅŸarısız. Bu hata büyük olasılıkla sütunların isminin deÄŸiÅŸimden kaynaklanıyor. SQL sorgusunu elle düzeltmek ve yürütmek isterseniz: + + + + + + could not get list of databases: %1 + veri tabanı listesi alınamadı: %1 + + + + Error loading extension: %1 + Eklenti yüklenirken hata oluÅŸtu: %1 + + + + could not get column information + sütun bilgisi alınamadı + + + + Error setting pragma %1 to %2: %3 + Belirtilen pragma ayarlanırken hata oluÅŸtu: %1 > %2: %3 + + + + File not found. + Dosya bulunamadı. + + + + DbStructureModel + + + Name + İsim + + + + Object + Obje + + + + Type + Tip + + + + Schema + Åžema + + + + Database + Veritabanı + + + + Browsables + Görüntülenebilir olanlar + + + + All + Tümü + + + + Temporary + Geçici + + + + Tables (%1) + Tablolar (%1) + + + + Indices (%1) + İndisler (%1) + + + + Views (%1) + Görünümler (%1) + + + + Triggers (%1) + Tetikleyiciler (%1) + + + + EditDialog + + + Edit database cell + Veritabanı hücresini düzenle + + + + Mode: + Mod: + + + + This is the list of supported modes for the cell editor. Choose a mode for viewing or editing the data of the current cell. + Bu, hücre düzenleyicisi için desteklenen modların listesidir. Geçerli hücrenin verilerini görüntülemek veya düzenlemek için bir mod seçin. + + + + RTL Text + SaÄŸdan Sola Okunan Metin + + + + + Image + Görüntü + + + + JSON + JSON + + + + XML + XML + + + + + Automatically adjust the editor mode to the loaded data type + Düzenleyici modunu otomatik olarak yüklenen veri tipine ayarlar + + + + This checkable button enables or disables the automatic switching of the editor mode. When a new cell is selected or new data is imported and the automatic switching is enabled, the mode adjusts to the detected data type. You can then change the editor mode manually. If you want to keep this manually switched mode while moving through the cells, switch the button off. + Bu onay kutusu, editör modunun otomatik olarak deÄŸiÅŸtirilmesini etkinleÅŸtirir veya devre dışı bırakır. Bu kutucuk iÅŸaretliyken, yeni bir hücre seçildiÄŸinde veya yeni veriler içe aktarıldığında, mod algılanan veri türüne göre ayarlanır. Daha sonra editör modunu manuel olarak deÄŸiÅŸtirebilirsiniz. Hücreler arasında hareket ederken bu manuel modu korumak isterseniz, kutucuÄŸun iÅŸaretini kaldırın. + + + + Auto-switch + Otomatik geçiÅŸ + + + + The text editor modes let you edit plain text, as well as JSON or XML data with syntax highlighting, automatic formatting and validation before saving. + +Errors are indicated with a red squiggle underline. + Metin editorü modları,otomatik biçimlendirme, metin, JSON veya XML verilerinizi vurgulu olarak düzenlemenizi ve kayıttan önce formatlamanızı ve doÄŸrulamanızı saÄŸlar . + +Hatalar, kırmızı dalgalı alt çizgiyle belirtilir. + + + + This Qt editor is used for right-to-left scripts, which are not supported by the default Text editor. The presence of right-to-left characters is detected and this editor mode is automatically selected. + Qt editör, varsayılan metin editörü tarafından desteklenmeyen saÄŸdan sola okunan dillde yazılmış betikleri için kullanılır. + + + + Open preview dialog for printing the data currently stored in the cell + Åžu anda hücrede saklanan veriyi yazdırmak için önizleme penceresini aç + + + + Auto-format: pretty print on loading, compact on saving. + Otomatik format: yüklenirken aÅŸamasında kaliteli baskı, kayıt açısından da tasarrufludur. + + + + When enabled, the auto-format feature formats the data on loading, breaking the text in lines and indenting it for maximum readability. On data saving, the auto-format feature compacts the data removing end of lines, and unnecessary whitespace. + EtkinleÅŸtirildiÄŸinde, otomatik biçimlendirme özelliÄŸi yükleme sırasında verileri biçimlendirir, metni satırlara böler ve maksimum okunabilirlik için girintili yapar. Veri kaydederken otomatik biçimlendirme özelliÄŸi, satır sonu karakterlerini ve gereksiz boÅŸlukları kaldırarak verileri sıkıştırır. + + + + Word Wrap + Kelime Kaydırma + + + + Wrap lines on word boundaries + Kelime sınırlarında kelimeyi kaydırır + + + + + Open in default application or browser + Varsayılan program veya görüntüleyicide aç + + + + Open in application + Uygualamada aç + + + + The value is interpreted as a file or URL and opened in the default application or web browser. + DeÄŸe,r bir dosya veya URL olarak yorumlanır ve varsayılan uygulamada veya web tarayıcısında açılır. + + + + Save file reference... + Dosya referansını kaydet... + + + + Save reference to file + Referansı dosyaya kaydet + + + + + Open in external application + Harici bir programda aç + + + + Autoformat + Otomatik format + + + + &Export... + D&ışa aktar... + + + + + &Import... + &İçe aktar... + + + + + Import from file + Dosyadan içe aktar + + + + + Opens a file dialog used to import any kind of data to this database cell. + Veritabanı hücresine herhangi bir tipte veri yüklemek için bir dosya iletiÅŸim kutusu açar. + + + + Export to file + Dosyaya aktar + + + + Opens a file dialog used to export the contents of this database cell to a file. + Veritabanı hücresinin içeriÄŸini bir dosyaya aktarmak için kullanılan bir dosya iletiÅŸim kutusu açar. + + + + + Print... + Yazdır... + + + + Open preview dialog for printing displayed image + Görüntülenen resmi yazdırmak için önizleme penceresini aç + + + + + Ctrl+P + + + + + Open preview dialog for printing displayed text + Görüntülenen yazıyı yazdırmak için önizleme penceresini aç + + + + Copy Hex and ASCII + Onaltılık ve ASCII deÄŸerini kopyala + + + + Copy selected hexadecimal and ASCII columns to the clipboard + Seçilen onaltılık ve ASCII sütunlarını panoya kopyala + + + + Ctrl+Shift+C + + + + + Set as &NULL + &NULL olarak ayarla + + + + Apply data to cell + Veriyi hücreye uygula + + + + This button saves the changes performed in the cell editor to the database cell. + Bu buton, hücre editöründe yapılan deÄŸiÅŸiklikleri veritabanı hücresine kaydeder. + + + + Apply + Uygula + + + + Text + Metin + + + + Binary + İkili + + + + Erases the contents of the cell + Hücre içeriÄŸini siler + + + + This area displays information about the data present in this database cell + Bu alan veritabanı hücresinin içindeki içerik hakkında bilgileri görüntüler + + + + Type of data currently in cell + Åžu anda hücrenin içinde bulunan veri tipi + + + + Size of data currently in table + Åžuan da tablonun içinde bulunan verinin boyutu + + + + Choose a filename to export data + Veriyi dışa aktarmak için dosya ismi seçiniz + + + + + Image data can't be viewed in this mode. + Imaj verisi bu modda görüntülenemiyor. + + + + + Try switching to Image or Binary mode. + Görüntü veya İkili mod arasında geçiÅŸ yapın. + + + + + Binary data can't be viewed in this mode. + İkili veri bu modda görüntülenemiyor. + + + + + Try switching to Binary mode. + İkili veri moduna geçmeyi deneyin. + + + + + Image files (%1) + Görüntü dosyaları (%1) + + + + Binary files (*.bin) + İkili dosyalar (*.bin) + + + + Choose a file to import + İçe aktarmak için dosya seçiniz + + + + %1 Image + %1 imajı + + + + Invalid data for this mode + Bu mod için geçersiz veri + + + + The cell contains invalid %1 data. Reason: %2. Do you really want to apply it to the cell? + Hücre geçersiz %1 verisi içeriyor. Sebep: %2. Bu deÄŸiÅŸikliÄŸi hücreye gerçekten uygulamak istiyor musunuz? + + + + Type of data currently in cell: %1 Image + Åžu anda hücrenin içinde bulunan veri tipi: %1 Imajı + + + + %1x%2 pixel(s) + %1x%2 piksel + + + + Type of data currently in cell: NULL + Åžu anda hücrenin içinde bulunan veri tipi: NULL + + + + Type of data currently in cell: Valid JSON + Åžu anda hücrenin içinde bulunan veri tipi: DoÄŸrulanmış JSON + + + + Couldn't save file: %1. + Dosya kaydedilemedi: %1. + + + + The data has been saved to a temporary file and has been opened with the default application. You can now edit the file and, when you are ready, apply the saved new data to the cell editor or cancel any changes. + Veriler geçici bir dosyaya kaydedildi ve varsayılan uygulama ile açıldı. Artık dosyayı düzenleyebilir ve hazır olduÄŸunuzda, kaydedilen yeni verileri hücre editörüne uygulayabilir veya deÄŸiÅŸiklikleri iptal edebilirsiniz. + + + + + Type of data currently in cell: Text / Numeric + Åžuan da hücresinin içinde bulunan verinin tipi: Metin / Nümerik + + + + + + %n character(s) + + %n karakter + + + + + Type of data currently in cell: Binary + Åžuan da hücresinin içinde bulunan verinin tipi: İkili Veri + + + + + %n byte(s) + + %n bayt + + + + + EditIndexDialog + + + &Name + &İsim + + + + Order + Sırala + + + + &Table + &Tablo + + + + Edit Index Schema + Index Åžemasını Düzenle + + + + &Unique + Benzersi&z + + + + For restricting the index to only a part of the table you can specify a WHERE clause here that selects the part of the table that should be indexed + Index'i tablonun yalnızca bir bölümüyle sınırlamak için, burada tablonun dizine alınması gereken kısmını seçen bir WHERE deyimi belirtebilirsiniz + + + + Partial inde&x clause + Kısmi inde&x hükmü + + + + Colu&mns + Sütu&nlar + + + + Table column + Tablo sütunu + + + + Type + Tip + + + + Add a new expression column to the index. Expression columns contain SQL expression rather than column names. + Index için yeni bir ifade sütunu ekleyin. İfade sütunları, sütun adları deÄŸil SQL ifadesi içerir. + + + + Index column + Index sütunu + + + + Deleting the old index failed: +%1 + Eski index silinemedi: +%1 + + + + Creating the index failed: +%1 + İndeks oluÅŸturma hatası: %1 + + + + EditTableDialog + + + Edit table definition + Tablo tanımını düzenle + + + + Table + Tablo + + + + Advanced + GeliÅŸmiÅŸ + + + + Make this a 'WITHOUT rowid' table. Setting this flag requires a field of type INTEGER with the primary key flag set and the auto increment flag unset. + Tabloyu satır ID'si olmadan ayarlayın. Bu ayar için, Tamsayı(Integer) tipinde otomatik arttır özelliÄŸi olmayan ve birincil anahtar olarak ayarlanmış bir alan gerekli. + + + + Without Rowid + Satır ID(Rowid) Kullanma + + + + Database sche&ma + Veritabanı &Åžeması + + + + Fields + Alanlar + + + + Add + Ekle + + + + Remove + Sil + + + + Move to top + En yukarı taşı + + + + Move up + Yukarı taşı + + + + Move down + AÅŸağı taşı + + + + Move to bottom + En aÅŸağı taşı + + + + + Name + İsim + + + + + Type + Tip + + + + NN + NN + + + + Not null + NULL Olamaz + + + + PK + Birincil Anahtar + + + + Primary key + Birincil Anahtar + + + + AI + Otomatik Arttırma + + + + Autoincrement + Otomatik Arttırma + + + + U + Benzersiz + + + + + + Unique + Benzersiz + + + + Default + Varsayılan + + + + Default value + Varsayılan deÄŸer + + + + + + Check + Kontrol + + + + Check constraint + Kısıtlama Kontrol + + + + Collation + KarşılaÅŸtırma + + + + + + Foreign Key + Yabancı Anahtar + + + + Constraints + Kısıtlar + + + + Add constraint + Kısıt ekle + + + + Remove constraint + Kısıtı kaldır + + + + Columns + Sütunlar + + + + SQL + SQL + + + + <html><head/><body><p><span style=" font-weight:600; color:#ff0000;">Warning: </span>There is something with this table definition that our parser doesn't fully understand. Modifying and saving this table might result in problems.</p></body></html> + <html> <head /> <body> <p> <span style=" font-weight:600; color:#ff0000;">Uyarı: </span>Bu tablo tanımında ayrıştırıcının tam olarak anlayamadığı bir ÅŸey var. Bu tabloyu deÄŸiÅŸtirmek ve kaydetmek sorunlara neden olabilir. </p> </body> </html> + + + + + Primary Key + Birincil Anahtar + + + + Add a primary key constraint + Birinci anahtar kısıtlaması ekle + + + + Add a foreign key constraint + Yabancı anahtar kısıtı ekle + + + + Add a unique constraint + Benzersiz kısıtı ekle + + + + Add a check constraint + Kontrol kısıtı ekle + + + + + There can only be one primary key for each table. Please modify the existing primary key instead. + Her tabloda yalnızca bir birincil anahtar bulunabilir. Mevcut birincil anahtarı düzenlemeyi denedin. + + + + Error creating table. Message from database engine: +%1 + Tablo oluÅŸturma hatası. veritabanı motorunun mesajı: %1 + + + + There already is a field with that name. Please rename it first or choose a different name for this field. + Bu isme sahip alan zaten var. Lütfen bu alan için farklı bir isim kullanın veya aynı isme sahip alanı yeniden adlandırın. + + + + There is at least one row with this field set to NULL. This makes it impossible to set this flag. Please change the table data first. + Tablonuzun en az bir satırında boÅŸ bırakılmış alan var. Bu sebeple bu özelliÄŸi etkinleÅŸtirmek imkansız. Lütfen ilk önce tablonuzdaki veriyi deÄŸiÅŸtirin. + + + + There is at least one row with a non-integer value in this field. This makes it impossible to set the AI flag. Please change the table data first. + Tablonuzun en az bir satırında tamsayı dışında deÄŸer içeren alan var. Bu sebeÄŸle otomatik arttır özelliÄŸini etkinleÅŸtirmek imkansız. Lütfen ilk önce tablonuzdaki veriyi deÄŸiÅŸtirin. + + + + Column '%1' has duplicate data. + + '%1' sütununda yinelenen veriler var. + + + + + This makes it impossible to enable the 'Unique' flag. Please remove the duplicate data, which will allow the 'Unique' flag to then be enabled. + Åžu anda 'Benzersiz' kısıtı eklenmesi imkansız.'Benzersiz' kısıtını ekleyebilmek için lütfen yinelenen deÄŸerleri silin. + + + + This column is referenced in a foreign key in table %1 and thus its name cannot be changed. + Bu sütun%1 tablosundaki yabancı bir anahtar tarafından referans alınıyor, bu nedenle adı deÄŸiÅŸtirilemez. + + + + Are you sure you want to delete the field '%1'? +All data currently stored in this field will be lost. + Gerçekten '%1' alanını silmek istediÄŸinize emin misiniz? Bu alanda mevcut bütün verilerinizi kaybedeceksiniz. + + + + Please add a field which meets the following criteria before setting the without rowid flag: + - Primary key flag set + - Auto increment disabled + Lütfen 'Satır ID(Rowid) Kullanma' özelliÄŸini etkinleÅŸtirmek için öncelikle aÅŸağıdaki ölçütleri karşılayan alan ekleyin: +- Birincil anahtar ayarlayın +- Otomatik arttır ayarını devre dışı bırakın + + + + ExportDataDialog + + + Export data as CSV + Veriyi CSV olarak dışa aktar + + + + Tab&le(s) + Tab&lolar + + + + Colu&mn names in first line + Sütu&n isimleri ilk satırda + + + + Fie&ld separator + &Alan ayracı + + + + , + , + + + + ; + ; + + + + Tab + Tab karakteri + + + + | + | + + + + + + Other + DiÄŸer + + + + &Quote character + &Tırnak karakteri + + + + " + " + + + + ' + ' + + + + New line characters + Yeni satır karakterleri + + + + Windows: CR+LF (\r\n) + Windows: CR+LF (\r\n) + + + + Unix: LF (\n) + Unix: LF (\n) + + + + Pretty print + Düzenli baskı + + + + + Could not open output file: %1 + OluÅŸturulan dosya açılamadı: %1 + + + + + Choose a filename to export data + Verileri dışarı aktarmak için dosya ismi seçiniz + + + + Export data as JSON + Veriyi JSON olarak dışa aktar + + + + exporting CSV + CSV dışa aktarılıyor + + + + exporting JSON + JSON dışa aktarılıyor + + + + Please select at least 1 table. + Lütfen en az 1 tablo seçiniz. + + + + Choose a directory + Dizin seçiniz + + + + Export completed. + Dışa aktarma tamamlandı. + + + + ExportSqlDialog + + + Export SQL... + SQL dosyasını dışa aktar... + + + + Tab&le(s) + Tablo&lar + + + + Select All + Tümünü Seç + + + + Deselect All + Tüm Seçimi İptal Et + + + + &Options + &Seçenekler + + + + Keep column names in INSERT INTO + INSERT ve INTO komutlarında sütun isimlerini tut + + + + Multiple rows (VALUES) per INSERT statement + Tek INSERT ifadesi için çok satırlı (VALUES) ifade + + + + Export everything + Her ÅŸeyi dışa aktar + + + + Export data only + Sadece veriyi dışa aktar + + + + Keep old schema (CREATE TABLE IF NOT EXISTS) + Eski ÅŸemayı tut (CREATE TABLE IF NOT EXISTS) + + + + Overwrite old schema (DROP TABLE, then CREATE TABLE) + Eski ÅŸemanın üzerine yaz (DROP TABLE, then CREATE TABLE) + + + + Export schema only + Sadece ÅŸemayı dışa aktar + + + + Please select at least one table. + Lütfen en az bir tablo seçiniz. + + + + Choose a filename to export + Dışa aktarmak için dosya ismi seçiniz + + + + Export completed. + Dışa aktarma tamamlandı. + + + + Export cancelled or failed. + Dışa aktarma iptal edildi veya baÅŸarısız. + + + + ExtendedScintilla + + + + Ctrl+H + + + + + Ctrl+F + + + + + + Ctrl+P + + + + + Find... + Bul... + + + + Find and Replace... + Bul ve DeÄŸiÅŸtir... + + + + Print... + Yazdır... + + + + ExtendedTableWidget + + + Use as Exact Filter + Tam Filtre Olarak Kullan + + + + Containing + İçersin + + + + Not containing + İçermesin + + + + Not equal to + EÅŸit deÄŸil + + + + Greater than + Büyüktür + + + + Less than + Küçüktür + + + + Greater or equal + Büyük eÅŸit + + + + Less or equal + Küçük eÅŸit + + + + Between this and... + Åžunların arasında... + + + + Regular expression + Düzenli ifadeler (RegEx) + + + + Edit Conditional Formats... + KoÅŸullu Biçimleri Düzenle... + + + + Set to NULL + NULL olarak ayarla + + + + Copy + Kopyala + + + + Copy with Headers + Üst BaÅŸlıklarla Kopyala + + + + Copy as SQL + SQL olarak Kopyala + + + + Paste + Yapıştır + + + + Print... + Yazdır... + + + + Use in Filter Expression + Filtre İfadesinde Kullan + + + + Alt+Del + Alt+De + + + + Ctrl+Shift+C + + + + + Ctrl+Alt+C + + + + + The content of the clipboard is bigger than the range selected. +Do you want to insert it anyway? + Pano içeriÄŸi seçilen aralıktan daha büyük. + Yine de eklemek istiyor musunuz? + + + + <p>Not all data has been loaded. <b>Do you want to load all data before selecting all the rows?</b><p><p>Answering <b>No</b> means that no more data will be loaded and the selection will not be performed.<br/>Answering <b>Yes</b> might take some time while the data is loaded but the selection will be complete.</p>Warning: Loading all the data might require a great amount of memory for big tables. + <p> Tüm veriler yüklenmedi. <b>Tüm satırları seçmeden önce tüm verileri yüklemek istiyor musunuz?</b> </p> <p></p> <p> <b>Hayır</b> olarak cevaplamak, tüm verileri yüklemeyecek ve seçim iÅŸlemini uygulanmayacak. <br /> <b>Evet</b> seçeneÄŸi biraz zaman alabilir ama seçim iÅŸlemini gerçekleÅŸtirecektir. </p> Uyarı: Tüm verilerin yüklenmesi büyük tablolar için büyük miktarda bellek gerektirebilir. + + + + Cannot set selection to NULL. Column %1 has a NOT NULL constraint. + Seçim NULL olarak ayarlanamıyor. %1 sütununda NOT NULL kısıtlaması var. + + + + FileExtensionManager + + + File Extension Manager + Dosya Uzantı Yöneticisi + + + + &Up + &Yukarı + + + + &Down + &AÅŸağı + + + + &Add + &Ekle + + + + &Remove + &Sil + + + + + Description + Açıklama + + + + Extensions + Uzantılar + + + + *.extension + *.uzantı + + + + FilterLineEdit + + + Filter + Filtre + + + + These input fields allow you to perform quick filters in the currently selected table. +By default, the rows containing the input text are filtered out. +The following operators are also supported: +% Wildcard +> Greater than +< Less than +>= Equal to or greater +<= Equal to or less += Equal to: exact match +<> Unequal: exact inverse match +x~y Range: values between x and y +/regexp/ Values matching the regular expression + Bu giriÅŸ alanları, seçili tabloda hızlı filtreler gerçekleÅŸtirmenizi saÄŸlar. +Varsayılan olarak, metin içeren satırlar filtrelenir. +Ayrıca aÅŸağıdaki operatörler de destekleniyor: +% Joker +> Büyüktür +< Küçüktür +>= Büyük eÅŸit +<= Küçük eÅŸit += EÅŸittir +<> EÅŸit deÄŸil +x~y Aralık: deÄŸerler x ve y arasında +/regexp/ Kurallı ifadelerle(RegExp) eÅŸleÅŸen deÄŸerler + + + + Clear All Conditional Formats + Tüm KoÅŸullu Biçimleri Temizle + + + + Use for Conditional Format + KoÅŸullu Biçim için Kullan + + + + Edit Conditional Formats... + KoÅŸullu Biçimleri Düzenle... + + + + Set Filter Expression + Filtre İfadesi Ayarla + + + + What's This? + Bu nedir? + + + + Is NULL + NULL mu + + + + Is not NULL + NULL deÄŸil mi + + + + Is empty + BoÅŸ mu + + + + Is not empty + BoÅŸ deÄŸil mi + + + + Not containing... + İçermiyor... + + + + Equal to... + Åžuna eÅŸit... + + + + Not equal to... + Åžuna eÅŸit deÄŸil... + + + + Greater than... + Büyüktür... + + + + Less than... + Küçüktür... + + + + Greater or equal... + Büyük eÅŸit... + + + + Less or equal... + Küçük eÅŸit... + + + + In range... + Aralıkta mı... + + + + Regular expression... + Düzenli ifade (RegEx)... + + + + FindReplaceDialog + + + Find and Replace + Bul ve DeÄŸiÅŸtir + + + + Fi&nd text: + &Aranan Metin: + + + + Re&place with: + Åžununla d&eÄŸiÅŸtir: + + + + Match &exact case + Büyük kü&çük harfe duyarlı + + + + Match &only whole words + Kelimenin ta&mamını eÅŸleÅŸtir + + + + When enabled, the search continues from the other end when it reaches one end of the page + EtkinleÅŸtirildiÄŸinde, arama sayfanın bir ucuna ulaÅŸtığında diÄŸer uçtan devam eder + + + + &Wrap around + Ba&ÅŸa dön + + + + When set, the search goes backwards from cursor position, otherwise it goes forward + Ayarlandığında, arama imleç konumundan geriye doÄŸru gider, aksi takdirde ileri gider + + + + Search &backwards + Geri&ye doÄŸru ara + + + + <html><head/><body><p>When checked, the pattern to find is searched only in the current selection.</p></body></html> + <html><head/><body><p>İşaretlendiÄŸinde, girilen desen yalnızca geçerli seçimde aranır.</p></body></html> + + + + &Selection only + Sadece se&çimde ara + + + + <html><head/><body><p>When checked, the pattern to find is interpreted as a UNIX regular expression. See <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>.</p></body></html> + <html> <head /> <body> <p> İşaretlendiÄŸinde, girilen desen UNIX düzenli ifadesi olarak yorumlanır. <a href="https://en.wikibooks.org/wiki/Regular_Expressions" >Wikibooks</a > üzerinden düzenli ifadeleri inceleyebilirsiniz. </p> </body> </html> + + + + Use regular e&xpressions + Düzenli ifadeleri &kullan + + + + Find the next occurrence from the cursor position and in the direction set by "Search backwards" + İmleç konumundan itibaren belirtilen yönde bir sonraki eÅŸleÅŸmeyi bulur + + + + &Find Next + Sonrakini &Bul + + + + F3 + + + + + &Replace + &DeÄŸiÅŸtir + + + + Highlight all the occurrences of the text in the page + EÅŸleÅŸen tüm kelimeleri vurgula + + + + F&ind All + Tüm&ünü Bul + + + + Replace all the occurrences of the text in the page + Sayfadaki bulunan metinlerin tümünü deÄŸiÅŸtir + + + + Replace &All + &Tümünü DeÄŸiÅŸtir + + + + The searched text was not found + Aranan metin bulunamadı + + + + The searched text was not found. + The searched text was not found. + + + + The searched text was found one time. + Aranan metin bir kez bulundu. + + + + The searched text was found %1 times. + Aranan metin %1 kez bulundu. + + + + The searched text was replaced one time. + Aranan metin bir kez deÄŸiÅŸtirildi. + + + + The searched text was replaced %1 times. + Aranan metin %1 kez deÄŸiÅŸtirildi. + + + + ForeignKeyEditor + + + &Reset + &Sıfırla + + + + Foreign key clauses (ON UPDATE, ON DELETE etc.) + Yabancı anahtar hükümleri (ON UPDATE, ON DELETE vb.) + + + + ImportCsvDialog + + + Import CSV file + CSV dosyasını içe aktar + + + + Table na&me + Tablo İs&mi + + + + &Column names in first line + İlk satır &sütun isimleri içeriyor + + + + Field &separator + Alan &ayracı + + + + , + , + + + + ; + ; + + + + + Tab + Tab karakteri + + + + | + | + + + + Other + DiÄŸer + + + + &Quote character + &Tırnak karakteri + + + + + Other (printable) + DiÄŸer (yazdırılabilir) + + + + + Other (code) + DiÄŸer (Kod) + + + + " + " + + + + ' + ' + + + + &Encoding + &Kodlama + + + + UTF-8 + UTF-8 + + + + UTF-16 + UTF-16 + + + + ISO-8859-1 + ISO-8859-1 + + + + Trim fields? + Alanlar biçimlendirilsin mi? + + + + Separate tables + Tablolar ayrılmış + + + + Advanced + GeliÅŸmiÅŸ + + + + When importing an empty value from the CSV file into an existing table with a default value for this column, that default value is inserted. Activate this option to insert an empty value instead. + CSV dosyasından boÅŸ bir deÄŸer alındığında, sütunun varsayılan deÄŸeri kullanılır. Varsayılan deÄŸer yerine boÅŸ bir deÄŸer eklemek için bu seçeneÄŸi etkinleÅŸtirin. + + + + Ignore default &values + &Varsayılan deÄŸerleri yoksay + + + + Activate this option to stop the import when trying to import an empty value into a NOT NULL column without a default value. + Varsayılan deÄŸeri olmayan NOT NULL kısıtına sahip bir sütuna, boÅŸ bir deÄŸer içe aktarmaya çalışırken içe aktarmayı durdurmak için bu seçeneÄŸi etkinleÅŸtirin. + + + + Fail on missing values + Eksik deÄŸerde iÅŸlemi durdur + + + + Disable data type detection + Veri tipi algılamayı devre dışı bırak + + + + Disable the automatic data type detection when creating a new table. + Yeni bir tablo oluÅŸtururken otomatik veri tipi algılamayı devre dışı bırakın. + + + + When importing into an existing table with a primary key, unique constraints or a unique index there is a chance for a conflict. This option allows you to select a strategy for that case: By default the import is aborted and rolled back but you can also choose to ignore and not import conflicting rows or to replace the existing row in the table. + Birincil anahtar, benzersiz kısıtı veya benzersiz index kısıtına sahip mevcut bir tablo içe aktarırken çakışma meydana gelebilir. Bu seçenek, bu durum için bir strateji seçmenize olanak tanır: Varsayılan olarak iÅŸlem iptal edilir ve geri alınır, ancak isterseniz çakışmaları yoksayıp içe aktarmazsınız veya yeni satırları mevcut olanlarla deÄŸiÅŸtirebilirsiniz. + + + + Abort import + İçe aktarmayı iptal et + + + + Ignore row + Satırı yoksay + + + + Replace existing row + Varolan kaydı deÄŸiÅŸtir + + + + Conflict strategy + Çakışma stratejisi + + + + + Deselect All + Tüm seçimi iptal et + + + + Match Similar + Benzerleri EÅŸleÅŸtir + + + + Select All + Tümünü Seç + + + + There is already a table named '%1' and an import into an existing table is only possible if the number of columns match. + '%1' isminde bir tablo zaten var, var olan bir tablo için içe aktarma, yalnızca sütun sayıları eÅŸitse mümkün olabilir. + + + + There is already a table named '%1'. Do you want to import the data into it? + '%1' adında bir tablo zaten var. Verileri içe aktarmak istiyor musunuz? + + + + Creating restore point failed: %1 + Geri yükleme noktası oluÅŸturma baÅŸarısız: %1 + + + + Creating the table failed: %1 + Tablo oluÅŸturma baÅŸarısız: %1 + + + + importing CSV + CSV İçe Aktarma + + + + Importing the file '%1' took %2ms. Of this %3ms were spent in the row function. + '%1' dosyasını içe aktarmak %2ms sürdü. %3ms satır fonksiyonunda harcandı. + + + + Inserting row failed: %1 + Satır ekleme baÅŸarısız: %1 + + + + MainWindow + + + DB Browser for SQLite + SQLite DB Browser + + + + toolBar1 + toolBar1 + + + + Opens the SQLCipher FAQ in a browser window + SQLCipher Hakkında SSS bölümünü tarayıcı penceresinde açar + + + + Export one or more table(s) to a JSON file + Bir veya daha fazla tabloyu JSON dosyası olarak dışa aktarın + + + + Open an existing database file in read only mode + Mevcut bir veritabanı dosyasını salt okunur modda açar + + + + &File + &Dosya + + + + &Import + &İçe Aktar + + + + &Export + &Dışa Aktar + + + + &Edit + Düz&enle + + + + &View + &Görünüm + + + + &Help + &Yardım + + + + DB Toolbar + Veritabanı Araç ÇubuÄŸu + + + + Edit Database &Cell + Veritabanı Hü&cresini Düzenle + + + + DB Sche&ma + Veritabanı Åže&ması + + + + &Remote + &Uzak Bilgisayar + + + + + Execute current line + Geçerli satırı yürüt + + + + This button executes the SQL statement present in the current editor line + Bu buton, geçerli editör satırında bulunan SQL ifadesini yürütür + + + + Shift+F5 + + + + + Sa&ve Project + Projeyi &Kaydet + + + + User + Kullanıcı + + + + Application + Uygulama + + + + &Clear + &Temizle + + + + &New Database... + Ye&ni Veritabanı... + + + + + Create a new database file + Yeni bir veritabanı dosyası oluÅŸtur + + + + This option is used to create a new database file. + Bu seçenek yeni bir veritabanı dosyası oluÅŸturmak için kullanılır. + + + + Ctrl+N + + + + + + &Open Database... + &Veritabanı Aç... + + + + + + + + Open an existing database file + Mevcut veritabanı dosyasını aç + + + + + + This option is used to open an existing database file. + Bu seçenek mevcut veritabanı dosyasını açmak için kullanılır. + + + + Ctrl+O + + + + + &Close Database + Veritabanı &Kapat + + + + + Ctrl+W + + + + + + Revert database to last saved state + Veritabanını en son kaydedilen duruma döndür + + + + This option is used to revert the current database file to its last saved state. All changes made since the last save operation are lost. + Bu seçenek veritabanını en son kaydedilen durumuna döndürür. Geçerli kayıttan sonra yaptığınız tüm deÄŸiÅŸiklikler kaybolacaktır. + + + + + Write changes to the database file + DeÄŸiÅŸiklikleri veritabanı dosyasına kaydet + + + + This option is used to save changes to the database file. + Bu seçenek deÄŸiÅŸiklikleri veritabanı dosyasına kaydetmenizi saÄŸlar. + + + + Ctrl+S + + + + + Compact the database file, removing space wasted by deleted records + Veritabanı dosyasını geniÅŸletmek, silinen kayıtlardan dolayı meydana gelen boÅŸlukları temizler + + + + + Compact the database file, removing space wasted by deleted records. + Veritabanı dosyasını geniÅŸletmek, silinen kayıtlardan dolayı meydana gelen boÅŸlukları temizler. + + + + E&xit + &Çıkış + + + + Ctrl+Q + + + + + Import data from an .sql dump text file into a new or existing database. + Verileri .sql uzantılı döküm dosyasından varolan veya yeni veritabanına aktarın. + + + + This option lets you import data from an .sql dump text file into a new or existing database. SQL dump files can be created on most database engines, including MySQL and PostgreSQL. + Bu seçenek verileri .sql döküm dosyasından varolan veya yeni veritabanına aktarmanıza olanak saÄŸlar. SQL dosyaları MySQL ve PostgreSQL dahil olmak üzere birçok veritabanı motorları tarafından oluÅŸtururlar. + + + + Open a wizard that lets you import data from a comma separated text file into a database table. + Virgülle ayrılmış metin dosyalarını veritabanınızın içine aktarmanızı saÄŸlayan sihirbazı açar. + + + + Open a wizard that lets you import data from a comma separated text file into a database table. CSV files can be created on most database and spreadsheet applications. + Virgülle ayrılmış metin dosyalarını veritabanınızın içine aktarmanızı saÄŸlayan sihirbazı açar. CSV dosyaları çoÄŸu veritabanı motorları ve elektronik tablo uygulamaları tarafından oluÅŸtururlar. + + + + Export a database to a .sql dump text file. + Veritabanını .sql döküm dosyası olarak dışa aktar. + + + + This option lets you export a database to a .sql dump text file. SQL dump files contain all data necessary to recreate the database on most database engines, including MySQL and PostgreSQL. + Bu seçenek veritabanını .sql döküm dosyası olarak dışa aktarmanızı saÄŸlar. SQL döküm dosyaları veritabanını, MySQL ve PostgreSQL dahil birçok veritabanı motorunda yeniden oluÅŸturmak için gereken verilerin tümünü içerir. + + + + Export a database table as a comma separated text file. + Veritabanı tablosunu virgülle ayrılmış metin dosyası olarak dışa aktar. + + + + Export a database table as a comma separated text file, ready to be imported into other database or spreadsheet applications. + Veritabanını virgülle ayrılmış metin dosyası olarak diÄŸer veritabanı veya elektronik tablo uygulamalarına aktarmaya hazır olacak ÅŸekilde dışa aktarın. + + + + Open the Create Table wizard, where it is possible to define the name and fields for a new table in the database + Tablo OluÅŸturma sihirbazı, veritabanı için alanlarını ve ismini ayarlayabileceÄŸiniz, yeni bir tablo oluÅŸturmanızı saÄŸlar + + + + + Delete Table + Tabloyu Sil + + + + Open the Delete Table wizard, where you can select a database table to be dropped. + Tablo Silme sihirbazı, seçtiÄŸiniz tabloları silmenizi saÄŸlar. + + + + Open the Modify Table wizard, where it is possible to rename an existing table. It is also possible to add or delete fields form a table, as well as modify field names and types. + Tablo Düzenleme sihirbazı, varolan tablonuzu yeniden adlandırmanıza olanak saÄŸlar. Ayrıca yeni alan ekleyebilir, silebilir hatta alanların ismini ve tipini de düzenleyebilirsiniz. + + + + Open the Create Index wizard, where it is possible to define a new index on an existing database table. + İndeks OluÅŸturma sihirbazı, varolan veritabanı tablosuna yeni indeks tanımlamanıza olanak saÄŸlar. + + + + &Preferences... + &Tercihler... + + + + + Open the preferences window. + Tercihler penceresini açar. + + + + &DB Toolbar + &Veritabanı Araç ÇubuÄŸu + + + + Shows or hides the Database toolbar. + Veritabanı araç çubuÄŸunu gösterir veya gizler. + + + + Shift+F1 + + + + + &Recently opened + En son açılanla&r + + + + Open &tab + Se&kme Aç + + + + Ctrl+T + + + + + + Database Structure + This has to be equal to the tab title in all the main tabs + Veritabanı Yapısı + + + + This is the structure of the opened database. +You can drag SQL statements from an object row and drop them into other applications or into another instance of 'DB Browser for SQLite'. + + Bu, açılan veritabanının yapısıdır. +SQL ifadelerini bir nesne satırından sürükleyip baÅŸka uygulamalara veya 'DB Browser for SQLite programının baÅŸka bir penceresine bırakabilirsiniz. + + + + + + Browse Data + This has to be equal to the tab title in all the main tabs + Veriyi Görüntüle + + + + Un/comment block of SQL code + Kod bloÄŸunu yorum satırına dönüştür/yorum satırını iptal et + + + + Un/comment block + Yorum satırına dönüştür/yorum satırını iptal et + + + + Comment or uncomment current line or selected block of code + Geçerli satırı veya kod bloÄŸunu, yorum satırına dönüştür veya yorum satırını iptal et + + + + Comment or uncomment the selected lines or the current line, when there is no selection. All the block is toggled according to the first line. + Geçerli satırı veya kod bloÄŸunu, yorum satırına dönüştür veya yorum satırını iptal et. Hiç seçim yoksa tüm bloklar ilk satır baz alınarak deÄŸiÅŸtirilir. + + + + Ctrl+/ + + + + + Stop SQL execution + SQL yürütmesini durdur + + + + Stop execution + Yürütmeyi durdur + + + + Stop the currently running SQL script + Åžu anda çalışan SQL betiÄŸini durdur + + + + + Edit Pragmas + This has to be equal to the tab title in all the main tabs + Pragmaları Düzenle + + + + Warning: this pragma is not readable and this value has been inferred. Writing the pragma might overwrite a redefined LIKE provided by an SQLite extension. + Uyarı: Bu pragma okunamaz ve bu deÄŸer çıkartıldı. Bu pragmayı yazmak, bir SQLite eklentisi tarafından saÄŸlanan yeniden tanımlanmış bir LIKE'nin üzerine yazabilir. + + + + + Execute SQL + This has to be equal to the tab title in all the main tabs + SQL kodunu yürüt + + + + &Tools + Ara&çlar + + + + SQL &Log + SQL &Günlüğü + + + + Show S&QL submitted by + Åžuna ait S&QL'i göster + + + + Error Log + Hata Günlüğü + + + + This button clears the contents of the SQL logs + Bu buton SQL günlüğünün içeriÄŸini temizler + + + + This panel lets you examine a log of all SQL commands issued by the application or by yourself + Bu panel, uygulama veya kendiniz tarafından verilen tüm SQL komutlarının bir günlüğünü incelemenizi saÄŸlar + + + + &Plot + &Çizim + + + + This is the structure of the opened database. +You can drag multiple object names from the Name column and drop them into the SQL editor and you can adjust the properties of the dropped names using the context menu. This would help you in composing SQL statements. +You can drag SQL statements from the Schema column and drop them into the SQL editor or into other applications. + + Bu, açılan veritabanının yapısıdır. +Birden çok nesne adını Ad sütunundan sürükleyip SQL editörüne bırakabilir ve bırakılan adların özelliklerini baÄŸlam menüsünü kullanarak ayarlayabilirsiniz. Bu, SQL ifadeleri oluÅŸturmanıza yardımcı olacaktır. +SQL deyimlerini Åžema sütunundan sürükleyip SQL editörüne veya diÄŸer uygulamalara bırakabilirsiniz. + + + + + + Project Toolbar + Proje Araç ÇubuÄŸu + + + + Extra DB toolbar + Ekstra Veritabanı araç çubuÄŸu + + + + + + Close the current database file + Geçerli veritabano dosyasını kapat + + + + This button closes the connection to the currently open database file + Bu buton, ÅŸu anda açık olan veritabanı dosyasına ait baÄŸlantıyı kapatır + + + + Ctrl+F4 + + + + + &Revert Changes + DeÄŸiÅŸiklikleri &Geri Al + + + + &Write Changes + DeÄŸiÅŸiklikleri &Kaydet + + + + Compact &Database... + Veriabanını &Sıkıştır... + + + + Execute all/selected SQL + Tüm/seçin SQL sorgusunu yürüt + + + + This button executes the currently selected SQL statements. If no text is selected, all SQL statements are executed. + Bu buton seçili olan SQL ifadesini yürütür. Hiçbir metin seçilmezse, tüm SQL ifadeleri yürütülür. + + + + Open SQL file(s) + + + + + This button opens files containing SQL statements and loads them in new editor tabs + + + + + &Load Extension... + Ek&lenti Yükle... + + + + Execute line + Tek satır yürüt + + + + &Wiki + &Wiki + + + + F1 + + + + + Bug &Report... + Hata &Raporu... + + + + Feature Re&quest... + &Özellik Talebi... + + + + Web&site + Web &Sitesi + + + + &Donate on Patreon... + &Patreon üzerinden Bağış Yapın... + + + + Open &Project... + &Proje Aç... + + + + &Attach Database... + &Veritabanı Ekle... + + + + + Add another database file to the current database connection + Åžu anki veritabanı baÄŸÄŸlantısına baÅŸka bir veritabanı dosyası ekle + + + + This button lets you add another database file to the current database connection + Bu buton, geçerli veritabanı baÄŸlantısına baÅŸka bir veritabanı dosyası eklemenizi saÄŸlar + + + + &Set Encryption... + &Åžifreleme Belirtle... + + + + SQLCipher &FAQ + SQLCipher &SSS + + + + Table(&s) to JSON... + Tablodan &JSON dosyasına... + + + + Open Data&base Read Only... + Salt &Okunur Veritabanı Aç... + + + + Ctrl+Shift+O + + + + + Save results + Sonuçları kaydet + + + + Save the results view + Sonuç görünümünü kaydet + + + + This button lets you save the results of the last executed query + Bu buton son yürütülen sorgunun sonuçlarını kaydetmenizi saÄŸlar + + + + + Find text in SQL editor + SQL editörünte metin ara + + + + Find + Bul + + + + This button opens the search bar of the editor + Bu buton editörün arama çubuÄŸunu açar + + + + Ctrl+F + + + + + + Find or replace text in SQL editor + SQL editöründe metin bul veya deÄŸiÅŸtir + + + + Find or replace + Bul veya deÄŸiÅŸtir + + + + This button opens the find/replace dialog for the current editor tab + Bu buton, geçerli editör sekmesi için bul / deÄŸiÅŸtir iletiÅŸim kutusunu açar + + + + Ctrl+H + + + + + Export to &CSV + &CSV dosyası olarak dışa aktar + + + + Save as &view + &Görünüm olarak kaydet + + + + Save as view + Görünüm olarak kaydet + + + + Browse Table + Tabloyu Görüntüle + + + + Shows or hides the Project toolbar. + Proje araç çubuÄŸunu gösterir veya gizler. + + + + This button lets you save all the settings associated to the open DB to a DB Browser for SQLite project file + + + + + This button lets you open a DB Browser for SQLite project file + + + + + Extra DB Toolbar + Ekstra Veritabanı Araç ÇubuÄŸu + + + + New In-&Memory Database + &Yeni Bellek İçi Veritabanı + + + + Drag && Drop Qualified Names + Nitelikli İsimleri Sürükle && Bırak + + + + + Use qualified names (e.g. "Table"."Field") when dragging the objects and dropping them into the editor + Nesneleri sürükleyip düzenleyiciye bırakırken özel isimleri kullanın (örn. "Tablo". "Alan") + + + + Drag && Drop Enquoted Names + İsimleri Sürükle && Bırak + + + + + Use escaped identifiers (e.g. "Table1") when dragging the objects and dropping them into the editor + Nesneleri sürükleyip editöre bırakırken çıkış karakter belirleyicilerini kullanın(ör. "Tablo1") kullanın + + + + &Integrity Check + &Bütünlük Denetimi + + + + Runs the integrity_check pragma over the opened database and returns the results in the Execute SQL tab. This pragma does an integrity check of the entire database. + integrity_check pragmasını açılan veritabanı üzerinde çalıştırır ve 'SQL Kodunu Yürüt' sekmesinde sonuçları döndürür. Bu pragma veritabanının tamamının bütünlüğünü kontrol eder. + + + + &Foreign-Key Check + &Yabancı anahtar kontrolü + + + + Runs the foreign_key_check pragma over the opened database and returns the results in the Execute SQL tab + Foreign_key_check pragmasını açık veritabanı üzerinde çalıştırır ve 'SQL Kodunu Yürüt' sekmesinde sonuçları döndürür + + + + &Quick Integrity Check + &Hızlı Bütünlük Testi + + + + Run a quick integrity check over the open DB + Açık veritabanı üzerinde hızlı bir bütünlük denetimi yapın + + + + Runs the quick_check pragma over the opened database and returns the results in the Execute SQL tab. This command does most of the checking of PRAGMA integrity_check but runs much faster. + quick_check pragmasını açık veritabanı üzerinde çalıştırır ve 'SQL Kodunu Yürüt' sekmesinde sonuçları döndürür. Bu komut PRAGMA integrity_check denetiminin çoÄŸunu yapar, ancak çok daha hızlı çalışır. + + + + &Optimize + &Optimize + + + + Attempt to optimize the database + Veritabanını optimize etmeyi dene + + + + Runs the optimize pragma over the opened database. This pragma might perform optimizations that will improve the performance of future queries. + Açılan veritabanı üzerinden optimizasyon pragmasını çalıştırır. Bu uygulama gelecekteki sorguların performansını artırmaya yardımcı olabilir. + + + + + Print + Yazdır + + + + Print text from current SQL editor tab + Geçerli SQL düzenleyici sekmesinden metni yazdırın + + + + Open a dialog for printing the text in the current SQL editor tab + Geçerli SQL düzenleyici sekmesindeki metni yazdırmak için bir iletiÅŸim kutusu açın + + + + Print the structure of the opened database + Åžu anda açık olan veritabanı yapısını yazdırın + + + + Open a dialog for printing the structure of the opened database + Açılan veritabanının yapısını yazdırmak için bir bir iletiÅŸim kutusu açın + + + + &Save Project As... + Projeyi &Farklı Kaydet... + + + + + + Save the project in a file selected in a dialog + Projeyi iletiÅŸim kutusunda seçilen bir dosyaya kaydedin + + + + Save A&ll + Tümünü &Kaydet + + + + + + Save DB file, project file and opened SQL files + Veritabanı dosyasını, proje dosyasını ve açılan SQL dosyalarını kaydedin + + + + Ctrl+Shift+S + + + + + &Database from SQL file... + SQL &dosyasından veritabanı... + + + + &Table from CSV file... + CSV dosyasından &tablo... + + + + &Database to SQL file... + Veritabanından SQL &dosyası... + + + + &Table(s) as CSV file... + &Tablodan CSV dosyası olarak... + + + + &Create Table... + &Tablo OluÅŸtur... + + + + &Delete Table... + &Tabloyu Sil... + + + + &Modify Table... + Tabloyu &Düzenle... + + + + Create &Index... + &Index OluÅŸtur... + + + + W&hat's This? + Bu &nedir? + + + + &About + &İptal + + + + This button opens a new tab for the SQL editor + Bu buton SQL editörü için yeni bir sekme açar + + + + &Execute SQL + &SQL kodunu yürüt + + + + + + Save SQL file + SQL dosyasını kaydet + + + + Ctrl+E + + + + + Export as CSV file + CSV dosyası olarak dışa aktar + + + + Export table as comma separated values file + Tabloyu virgülle ayrılmış girdiler dosyası olarak dışa aktar + + + + + Save the current session to a file + Geçerli oturumu dosyaya kaydet + + + + + Load a working session from a file + Dosyadan çalışma oturumunu yükle + + + + + Save SQL file as + SQL dosyasını bu ÅŸekilde kaydet + + + + This button saves the content of the current SQL editor tab to a file + Bu buton geçerli SQL editörü sekmesinin içeriÄŸini bir dosyaya kaydeder + + + + &Browse Table + &Tabloyu Görüntüle + + + + Copy Create statement + 'Create' ifadesini kopyala + + + + Copy the CREATE statement of the item to the clipboard + Objenin 'Create' ifadesini panoya kopyala + + + + Ctrl+Return + + + + + Ctrl+L + + + + + + Ctrl+P + + + + + Ctrl+D + + + + + Ctrl+I + + + + + Encrypted + ÅžifrelenmiÅŸ + + + + Read only + Salt okunur + + + + Database file is read only. Editing the database is disabled. + Veritabanı salt okunur. Veritabanı düzenleme devre dışı. + + + + Database encoding + Veritabanı kodlaması + + + + Database is encrypted using SQLCipher + Veritabanı SQLCipher kullanılırak ÅŸifrelendi + + + + + Choose a database file + Veritabanı dosyasını seçiniz + + + + + + Choose a filename to save under + Kaydetmek için dosya ismi seçiniz + + + + Error while saving the database file. This means that not all changes to the database were saved. You need to resolve the following error first. + +%1 + Veritabanı dosyası kaydedilirken hata oluÅŸtu. Bu, veritabanındaki tüm deÄŸiÅŸikliklerin kaydedilmediÄŸi anlamına gelir. Önce aÅŸağıdaki hatayı çözmeniz gerekir. + +%1 + + + + Are you sure you want to undo all changes made to the database file '%1' since the last save? + Son kayıttan itibaren '%1' dosyasına yaptığınız deÄŸiÅŸiklikleri geri almak istediÄŸinize emin misiniz? + + + + Choose a file to import + İçe aktarmak için dosya seçiniz + + + + &%1 %2%3 + &%1 %2%3 + + + + (read only) + (salt okunur) + + + + Open Database or Project + Veritabanı veya Proje Açın + + + + Attach Database... + Veritabanı Ekle... + + + + Import CSV file(s)... + CSV dosyalarını içe aktarın... + + + + Select the action to apply to the dropped file(s). <br/>Note: only 'Import' will process more than one file. + + Bırakılan dosyalara uygulanacak eylemi seçin. <br/>Not: yalnızca 'İçe Aktar' birden fazla dosyayı iÅŸleyecektir. + + + + + Do you want to save the changes made to SQL tabs in the project file '%1'? + SQL sekmelerinde yapılan deÄŸiÅŸiklikleri '%1' proje dosyasına kaydetmek istiyor musunuz? + + + + Text files(*.sql *.txt);;All files(*) + Metin dosyaları(*.sql *.txt);;Tüm dosyalar(*) + + + + Do you want to create a new database file to hold the imported data? +If you answer no we will attempt to import the data in the SQL file to the current database. + İçeri aktarılan verileri tutmak için yeni bir veritabanı dosyası oluÅŸturmak istiyor musunuz? +EÄŸer cevabınız hayır ise biz SQL dosyasındaki verileri geçerli veritabanına aktarmaya baÅŸlayacağız. + + + + You are still executing SQL statements. Closing the database now will stop their execution, possibly leaving the database in an inconsistent state. Are you sure you want to close the database? + Åžu anda SQL sorgularını yürütüyorsunuz. Veritabanının ÅŸimdi kapatılması, muhtemelen veritabanını tutarsız bir durumda bırakarak yürütmeyi durduracaktır. Veritabanını kapatmak istediÄŸinizden emin misiniz? + + + + Do you want to save the changes made to the project file '%1'? + '%1' proje dosyasında yapılan deÄŸiÅŸiklikleri kaydetmek istiyor musunuz? + + + + File %1 already exists. Please choose a different name. + %1 dosyası zaten mevcut. Lütfen farklı bir isim seçiniz. + + + + Error importing data: %1 + Dosya içeri aktarılırken hata oluÅŸtu: %1 + + + + Import completed. + İçeri aktarma tamamlandı. + + + + Delete View + Görünümü Sil + + + + Modify View + Görünümü Düzenle + + + + Delete Trigger + Tetikleyiciyi Sil + + + + Modify Trigger + Tetikleyiciyi Düzenle + + + + Delete Index + İndeksi Sil + + + + Modify Index + Index'i Düzenle + + + + Modify Table + Tabloyu Düzenle + + + + Do you want to save the changes made to SQL tabs in a new project file? + SQL sekmelerinde yapılan deÄŸiÅŸiklikleri yeni bir proje dosyasına kaydetmek istiyor musunuz? + + + + Do you want to save the changes made to the SQL file %1? + %1 SQL dosyasında yapılan deÄŸiÅŸiklikleri kaydetmek istiyor musunuz? + + + + The statements in this tab are still executing. Closing the tab will stop the execution. This might leave the database in an inconsistent state. Are you sure you want to close the tab? + Bu sekmedeki sorgular hala yürütülüyor. Sekmenin kapatılması yürütmeyi durdurur. Bu durum, veritabanını tutarsız bir durumda bırakabilir. Sekmeyi kapatmak istediÄŸinizden emin misiniz? + + + + Could not find resource file: %1 + Kaynak dosya bulunamadı: %1 + + + + Choose a project file to open + Açmak için bir proje dosyası seçin + + + + This project file is using an old file format because it was created using DB Browser for SQLite version 3.10 or lower. Loading this file format is still fully supported but we advice you to convert all your project files to the new file format because support for older formats might be dropped at some point in the future. You can convert your files by simply opening and re-saving them. + Bu proje dosyası eski bir formatta, çünkü DB Browser for SQLite 3.10 veya daha düşük bir sürüm ile oluÅŸturulmuÅŸ. Bu dosya biçiminin yüklenmesi hala tam olarak desteklenmektedir, ancak gelecekte daha eski biçimlere yönelik destek azalabileceÄŸinden, tüm proje dosyalarınızı yeni dosya biçimine dönüştürmenizi öneririz. Dosyalarınızı açıp yeniden kaydederek dönüştürebilirsiniz. + + + + Could not open project file for writing. +Reason: %1 + Proje dosyası yazmaya açılamadı. +Nedeni: %1 + + + + Busy (%1) + MeÅŸgul (%1) + + + + Setting PRAGMA values will commit your current transaction. +Are you sure? + PRAGMA deÄŸerlerini ayarlamak geçerli iÅŸleminizi yürütmeye alacaktır. +Bunu yapmak istediÄŸinize emin misiniz? + + + + Window Layout + + + + + Reset Window Layout + Pencere Düzenini Sıfırla + + + + Alt+0 + + + + + Simplify Window Layout + + + + + Shift+Alt+0 + + + + + Dock Windows at Bottom + + + + + Dock Windows at Left Side + + + + + Dock Windows at Top + + + + + The database is currenctly busy. + VerÅŸtabanı ÅŸu anda meÅŸgul. + + + + Click here to interrupt the currently running query. + Çalışmakta olan sorguyu kesmek için burayı tıklayın. + + + + Could not open database file. +Reason: %1 + Veritabanı dosyası açılamadı. +Nedeni: %1 + + + + In-Memory database + Bellek İçi Veritabanı + + + + Are you sure you want to delete the table '%1'? +All data associated with the table will be lost. + '%1' tablosunu silmek istediÄŸinizden emin misiniz? +Tabloyla iliÅŸkili tüm veriler kaybedilecektir. + + + + Are you sure you want to delete the view '%1'? + '%1' görünümünü silmek istediÄŸinizden emin misiniz? + + + + Are you sure you want to delete the trigger '%1'? + '%1' tetikleyicisini silmek istediÄŸinizden emin misiniz? + + + + Are you sure you want to delete the index '%1'? + '%1' indexsini silmek istediÄŸinizden emin misiniz? + + + + Error: could not delete the table. + Hata: tablo silinemedi. + + + + Error: could not delete the view. + Hata: görünüm silinemedi. + + + + Error: could not delete the trigger. + Hata: tetikleyici silinemedi. + + + + Error: could not delete the index. + Hata: index silinemedi. + + + + Message from database engine: +%1 + Veritabanı motorundan mesaj: +%1 + + + + Editing the table requires to save all pending changes now. +Are you sure you want to save the database? + Tabloyu düzenlemek için bekleyen tüm deÄŸiÅŸikliklerin ÅŸimdi kaydedilmesi gerekir. +Veritabanını kaydetmek istediÄŸinizden emin misiniz? + + + + Edit View %1 + + + + + Edit Trigger %1 + + + + + You are already executing SQL statements. Do you want to stop them in order to execute the current statements instead? Note that this might leave the database in an inconsistent state. + Åžu anda zaten yürütülen SQL sorguları var. Bunun yerine, ÅŸimdiki sorguları çalıştırmak için ÅŸu anda yürütülen sorguyu durdurmak istiyor musunuz? Bunun veritabanını tutarsız bir durumda bırakabileceÄŸini unutmayın. + + + + -- EXECUTING SELECTION IN '%1' +-- + -- SEÇİM '%1' İÇERİSİNDE YÜRÜTÜLÜYOR +-- + + + + -- EXECUTING LINE IN '%1' +-- + -- SATIR '%1' İÇERİSİNDE YÜRÜTÜLÜYOR +-- + + + + -- EXECUTING ALL IN '%1' +-- + -- TÜMÜ '%1' İÇERİSİNDE YÜRÜTÜLÜYOR +-- + + + + + At line %1: + %1. satırda: + + + + Result: %1 + Sonuç: %1 + + + + Result: %2 + Sonuç: %2 + + + + Setting PRAGMA values or vacuuming will commit your current transaction. +Are you sure? + PRAGMA deÄŸerlerini ayarlamak veya vakumlamak mevcut iÅŸleminizi kaydeder. +Emin misiniz? + + + + Opened '%1' in read-only mode from recent file list + + + + + Opened '%1' from recent file list + + + + + This action will open a new SQL tab with the following statements for you to edit and run: + + + + + Rename Tab + Sekmeyi Yeniden Adlandır + + + + Duplicate Tab + Sekmeyi Klonla + + + + Close Tab + Sekmeyi Kapat + + + + Opening '%1'... + '%1' açılıyor... + + + + There was an error opening '%1'... + '%1' açılırken hata oluÅŸtu... + + + + Value is not a valid URL or filename: %1 + Geçersiz bir URL veya dosya adı: %1 + + + + %1 rows returned in %2ms + %2ms içerisinde %1 tane satır döndürüldü + + + + Choose text files + Metin dosyaları seçin + + + + Import completed. Some foreign key constraints are violated. Please fix them before saving. + İçe aktarma tamamlandı. Bazı yabancı anahtar kısıtları ihlal edildi. Lütfen kaydetmeden önce bunları çözün. + + + + Select SQL file to open + Açmak için SQL dosyasını seçiniz + + + + Select file name + Dosya ismi seçiniz + + + + Select extension file + Eklenti dosyasını seçiniz + + + + Extension successfully loaded. + Eklenti baÅŸarıyla yüklendi. + + + + Error loading extension: %1 + Eklenti yüklenirken hata oluÅŸtu: %1 + + + + + Don't show again + Bir daha gös'terme + + + + New version available. + Yeni sürüm mevcut. + + + + A new DB Browser for SQLite version is available (%1.%2.%3).<br/><br/>Please download at <a href='%4'>%4</a>. + Yeni bir SQLite DB Browser sürümü mevcut (%1.%2.%3).<br/><br/>Lütfen buradan indiriniz: <a href='%4'>%4</a>. + + + + Project saved to file '%1' + Proje '%1' dosyasına kaydedildi + + + + Collation needed! Proceed? + Harmanlama gerekli! Devam edilsin mi? + + + + A table in this database requires a special collation function '%1' that this application can't provide without further knowledge. +If you choose to proceed, be aware bad things can happen to your database. +Create a backup! + Bu veritabanınındaki bir tablo özel '%1' koleksiyon fonksiyonu gerektirmektedir. +Daha fazla bilgi olmadan program bunu saÄŸlayamaz. EÄŸer bu ÅŸekilde devam edecekseniz, veritabanınıza kötü ÅŸeyler olabileceÄŸinin farkında olun ve yedek oluÅŸturun. +Bir yedek oluÅŸturun! + + + + creating collation + harmanlama oluÅŸturuluyor + + + + Set a new name for the SQL tab. Use the '&&' character to allow using the following character as a keyboard shortcut. + SQL sekmesi için yeni bir ad belirleyin. AÅŸağıdaki karakteri klavye kısayolu olarak kullanmak için '&&' karakterini kullanın. + + + + Please specify the view name + Lütfen görünüm ismini belirtin + + + + There is already an object with that name. Please choose a different name. + Bu isme sahip obje zaten mevcut. Lütfen farklı bir isim seçiniz. + + + + View successfully created. + Görünüm baÅŸarıyla oluÅŸturuldu. + + + + Error creating view: %1 + Görünüm oluÅŸturma hatası: %1 + + + + This action will open a new SQL tab for running: + Bu iÅŸlem çalıştırmak için yeni bir SQL sekmesi açar: + + + + Press Help for opening the corresponding SQLite reference page. + İlgili SQLite referans sayfasını açmak için Yardım'a basın. + + + + DB Browser for SQLite project file (*.sqbpro) + SQLite DB Browser proje dosyası (*.sqbpro) + + + + Error checking foreign keys after table modification. The changes will be reverted. + Tablo deÄŸiÅŸikliÄŸinden sonra yabancı anahtarlar kontrol edilirken hata oluÅŸtu. DeÄŸiÅŸiklikler geri alınacak. + + + + This table did not pass a foreign-key check.<br/>You should run 'Tools | Foreign-Key Check' and fix the reported issues. + Bu tablo birincil anahtar kontrolünden geçmedi.<br/>'Araçlar | Birinci Anahat Kontrolü' komutunu çalıştırın ve raporlanan sorunları düzeltin. + + + + Execution finished with errors. + Yürütme hatalarla tamamlandı. + + + + Execution finished without errors. + Yürütme hatasız tamamlandı. + + + + NullLineEdit + + + Set to NULL + NULL olarak ayarlar + + + + Alt+Del + + + + + PlotDock + + + Plot + Grafik Çizimi + + + + <html><head/><body><p>This pane shows the list of columns of the currently browsed table or the just executed query. You can select the columns that you want to be used as X or Y axis for the plot pane below. The table shows detected axis type that will affect the resulting plot. For the Y axis you can only select numeric columns, but for the X axis you will be able to select:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Date/Time</span>: strings with format &quot;yyyy-MM-dd hh:mm:ss&quot; or &quot;yyyy-MM-ddThh:mm:ss&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Date</span>: strings with format &quot;yyyy-MM-dd&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Time</span>: strings with format &quot;hh:mm:ss&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Label</span>: other string formats. Selecting this column as X axis will produce a Bars plot with the column values as labels for the bars</li><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Numeric</span>: integer or real values</li></ul><p>Double-clicking the Y cells you can change the used color for that graph.</p></body></html> + <html> <head /> <body> <p> Bu bölme, o anda taranan tablonun sütunları listesini veya yürütülen sorguyu gösterir. AÅŸağıdaki çizim bölmesi için X veya Y ekseni olarak kullanılmasını istediÄŸiniz sütunları seçebilirsiniz. Tablo, ortaya çıkan grafiÄŸi etkileyecek algılanan eksen tipini gösterir. Y ekseni için yalnızca sayısal sütunlar seçebilirsiniz, ancak X ekseni için aÅŸağıdakileri seçebilirsiniz: </p> <ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;" > <li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;" > <span style=" font-weight:600;">Tarih/Saat</span>: &quot;yyyy-MM-dd hh:mm:ss&quot; veya &quot;yyyy-MM-ddThh:mm:ss&quot; ve string formatında </li> <li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;" > <span style=" font-weight:600;">Tarih</span>: &quot;yyyy-MM-dd&quot; ve string formatında </li> <li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;" > <span style=" font-weight:600;">Saat</span>: &quot;hh:mm:ss&quot; ve string formatında </li> <li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;" > <span style=" font-weight:600;">BaÅŸlık</span>: diÄŸer string formatları. Bu sütunun X ekseni için seçilmesi, sütun deÄŸerlerinin çubukları için etiket oluÅŸturur. </li> <li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;" > <span style=" font-weight:600;">Nümerik</span>: integer veya real tipindeki deÄŸerler </li> </ul> <p> Y hücrelerini çift tıklatarak o grafik için kullanılan rengi deÄŸiÅŸtirebilirsiniz. </p> </body> </html> + + + + Columns + Sütun + + + + X + X + + + + Y1 + + + + + Y2 + + + + + Axis Type + Eksen Tipi + + + + Here is a plot drawn when you select the x and y values above. + +Click on points to select them in the plot and in the table. Ctrl+Click for selecting a range of points. + +Use mouse-wheel for zooming and mouse drag for changing the axis range. + +Select the axes or axes labels to drag and zoom only in that orientation. + Yukarıdaki x ve y deÄŸerlerini seçtiÄŸinizde çizilen bir grafik. + +Noktaları grafikte ve tabloda seçmek için üzerine tıklayın. Nokta aralığı seçmek için Ctrl+Tıklama yapın. + +YakınlaÅŸtırma için fare tekerleÄŸini ve eksen aralığını deÄŸiÅŸtirmek için fare tekerini kullanın. + +Yalnızca geçerli yönde sürüklemek ve yakınlaÅŸtırmak için eksen veya eksen etiketlerini seçin. + + + + Line type: + Çizgi Tipi: + + + + + None + Hiçbiri + + + + Line + Çizgi + + + + StepLeft + Sola Basamakla + + + + StepRight + SaÄŸa Basamakla + + + + StepCenter + Merkeze Basamakla + + + + Impulse + Kaydırmalı + + + + Point shape: + Nokta ÅŸekli: + + + + Cross + Çarpı + + + + Plus + Artı + + + + Circle + Daire + + + + Disc + Disk + + + + Square + Kare + + + + Diamond + Elmas + + + + Star + Yıldız + + + + Triangle + Üçgen + + + + TriangleInverted + Ters Üçgen + + + + CrossSquare + Çapraz Kare + + + + PlusSquare + Kare İçinde Artı + + + + CrossCircle + Daire İçinde Çarpı + + + + PlusCircle + Daire İçinde Artı + + + + Peace + Barış Simgesi + + + + <html><head/><body><p>Save current plot...</p><p>File format chosen by extension (png, jpg, pdf, bmp)</p></body></html> + <html><head/><body><p>Geçerli çizimi kaydet...</p><p>Uzantıya göre seçilen dosya formatları (png, jpg, pdf, bmp)</p></body></html> + + + + Save current plot... + Geçerli çizimi kaydet... + + + + + Load all data and redraw plot + Tüm verileri yükle ve grafiÄŸi yeniden çiz + + + + + + Row # + Satır # + + + + Copy + Kopyala + + + + Print... + Yazdır... + + + + Show legend + Göstergeyi göster + + + + Stacked bars + Yığılmış çubuklar + + + + Date/Time + Tarih/Saat + + + + Date + Tarih + + + + Time + Saat + + + + + Numeric + Nümerik + + + + Label + Etiket + + + + Invalid + Geçersiz + + + + Load all data and redraw plot. +Warning: not all data has been fetched from the table yet due to the partial fetch mechanism. + Tüm verileri yükle ve grafiÄŸi yeniden çiz. +Uyarı: Kısmi yükleme mekanizması nedeniyle tüm veriler tablodan henüz alınmadı. + + + + Choose an axis color + Bir eksen rengi seçin + + + + Choose a filename to save under + Altına kaydetmek için dosya ismi seçiniz + + + + PNG(*.png);;JPG(*.jpg);;PDF(*.pdf);;BMP(*.bmp);;All Files(*) + PNG(*.png);;JPG(*.jpg);;PDF(*.pdf);;BMP(*.bmp);;Tüm dosyalar(*) + + + + There are curves in this plot and the selected line style can only be applied to graphs sorted by X. Either sort the table or query by X to remove curves or select one of the styles supported by curves: None or Line. + Bu grafikte eÄŸriler var ve seçilen çizgi stili yalnızca X'e göre sıralanmış grafiklere uygulanabilir. EÄŸrileri kaldırmak için tabloyu veya sorguyu X'e göre sıralayın veya eÄŸriler tarafından desteklenen stillerden birini seçin: 'Hiçbiri' veya 'Çizgi'. + + + + Loading all remaining data for this table took %1ms. + Bu tablo için kalan tüm verilerin yüklenmesi %1ms sürdü. + + + + PreferencesDialog + + + Preferences + Tercihler + + + + &General + &Genel + + + + Remember last location + Son dizini hatırla + + + + Always use this location + Her zaman bu dizini kullan + + + + Remember last location for session only + Aynı oturum için son dizini hatırla + + + + + + ... + ... + + + + Default &location + Varsayılan &dizin + + + + Lan&guage + Di&l + + + + Automatic &updates + Otomatik &güncellemeler + + + + + + + + + + + + enabled + etkin + + + + Show remote options + Uzak bilgisayar opsiyonlarını göster + + + + &Database + &Veritabanı + + + + Database &encoding + &Veritabanı kodlaması + + + + Open databases with foreign keys enabled. + Veritabanlarını Yabancı Anahtarlar etkin olacak ÅŸekilde aç. + + + + &Foreign keys + &Yabancı Anahtarlar + + + + Data &Browser + Veri &Görüntüleyici + + + + Remove line breaks in schema &view + Åžema &görünümde satır sonlarını kaldır + + + + Prefetch block si&ze + Önceden getirme blo&k boyutu + + + + SQ&L to execute after opening database + Veritabanı açıldıktan sonra yürütülecek SQ&L + + + + Default field type + Varsayılan dosya tipi + + + + Font + Yazı + + + + &Font + &Yazı + + + + Content + İçerik + + + + Symbol limit in cell + Hücredeki sembol limiti + + + + Threshold for completion and calculation on selection + Seçimdeki tamamlama ve hesaplama eÅŸiÄŸi + + + + Show images in cell + Resimleri hücrede göster + + + + Enable this option to show a preview of BLOBs containing image data in the cells. This can affect the performance of the data browser, however. + Hücrelerde görüntü verileri içeren BLOB tipindeki verilerin önizlemesini göstermek için bu seçeneÄŸi etkinleÅŸtirin. Ancak bu, veri görüntüleyicisinin performansını etkileyebilir. + + + + NULL + NULL + + + + Regular + Kurallı + + + + Binary + İkili veri + + + + Background + Arka plan + + + + Filters + Filtreler + + + + Toolbar style + Araç çubuÄŸu stili + + + + + + + + Only display the icon + Sadece ikonu göster + + + + + + + + Only display the text + Sadece metni göster + + + + + + + + The text appears beside the icon + Metin simgenin yanında görünsün + + + + + + + + The text appears under the icon + Metin simgenin altında görünsün + + + + + + + + Follow the style + Stili baz al + + + + DB file extensions + Veritabanı dosya uzantıları + + + + Manage + Yönet + + + + Main Window + Ana Pencere + + + + Database Structure + Veritabanı Yapısı + + + + Browse Data + Verileri Görüntüle + + + + Execute SQL + SQL kodunu yürütme + + + + Edit Database Cell + Veritabanı Hücresini Düzenleme + + + + When this value is changed, all the other color preferences are also set to matching colors. + Bu deÄŸer deÄŸiÅŸtirildiÄŸinde, diÄŸer tüm renk tercihleri de eÅŸleÅŸen renklere ayarlanır. + + + + Follow the desktop style + Masaüstü stilini baz al + + + + Dark style + Koyu Tema + + + + Application style + Uygulama stili + + + + This sets the font size for all UI elements which do not have their own font size option. + + + + + Font size + + + + + When enabled, the line breaks in the Schema column of the DB Structure tab, dock and printed output are removed. + EtkinleÅŸtirildiÄŸinde, Veritabanı Yapısı sekmesinin Åžema sütununda satır sonu karakterleri ve yazdırılan çıktılar kaldırılır. + + + + Database structure font size + + + + + Font si&ze + Yazı B&oyutu + + + + This is the maximum number of items allowed for some computationally expensive functionalities to be enabled: +Maximum number of rows in a table for enabling the value completion based on current values in the column. +Maximum number of indexes in a selection for calculating sum and average. +Can be set to 0 for disabling the functionalities. + Bu, bazı hesaplama açısından pahalı iÅŸlevlerin etkinleÅŸtirilmesine izin verilen maksimum öğe sayısıdır: +Sütundaki geçerli deÄŸerlere dayalı olarak deÄŸer tamamlamayı etkinleÅŸtirmek için bir tablodaki maksimum satır sayısı. +Toplam ve ortalamayı hesaplamak için bir seçimdeki maksimum index sayısı. +İşlevleri devre dışı bırakmak için 0 olarak ayarlanabilir. + + + + This is the maximum number of rows in a table for enabling the value completion based on current values in the column. +Can be set to 0 for disabling completion. + Bu, sütundaki geçerli deÄŸerlere dayalı olarak deÄŸer tamamlamayı etkinleÅŸtirmek için bir tablodaki maksimum satır sayısıdır. +Tamamlamayı devre dışı bırakmak için 0 olarak ayarlanabilir. + + + + Close button on tabs + + + + + If enabled, SQL editor tabs will have a close button. In any case, you can use the contextual menu or the keyboard shortcut to close them. + + + + + Proxy + Proxy + + + + Configure + Yapılandır + + + + Field display + Alan görünümü + + + + Displayed &text + Görün&tülenen metin + + + + + + + + + Click to set this color + Bu rengi ayarlamak için tıklayın + + + + Text color + Metin rengi + + + + Background color + Arka plan rengi + + + + Preview only (N/A) + Sadece önizleme (N/A) + + + + Escape character + Kaçış karakteri + + + + Delay time (&ms) + Gecikme süresi (&ms) + + + + Set the waiting time before a new filter value is applied. Can be set to 0 for disabling waiting. + Yeni bir filtre deÄŸeri uygulanmadan önce bekleme süresini ayarlayın. Beklemeyi devre dışı bırakmak için 0 olarak ayarlanabilir. + + + + &SQL + &SQL + + + + Settings name + Ayarlar ismi + + + + Context + Özellik + + + + Colour + Renk + + + + Bold + Kalın + + + + Italic + İtalik + + + + Underline + Altı çizili + + + + Keyword + Anahtar Kelime + + + + Function + Fonksiyon + + + + Table + Tablo + + + + Comment + Yorum + + + + Identifier + Kimlik + + + + String + String + + + + Current line + Geçerli satır + + + + SQL &editor font size + SQL &Editör yazı boyutu + + + + Tab size + TAB karakter boyutu + + + + &Wrap lines + &Satırları kaydır + + + + Never + Asla + + + + At word boundaries + Kelime dahilinde + + + + At character boundaries + Karakter dahilinde + + + + At whitespace boundaries + Beyaz boÅŸluk dahilinde + + + + &Quotes for identifiers + Tanımlıyıcılar için &tırnaklar + + + + Choose the quoting mechanism used by the application for identifiers in SQL code. + Uygulama tarafından SQL kodundaki tanımlayıcılar için kullanılan tırnak stilini seçin. + + + + "Double quotes" - Standard SQL (recommended) + "Çift tırnak" - Standart SQL (önerilir) + + + + `Grave accents` - Traditional MySQL quotes + `Ters tırnaklar` - Geleneksel MySQL tırnakları + + + + [Square brackets] - Traditional MS SQL Server quotes + [Köşeli parantezler] - Geleneksel MS SQL Server + + + + Keywords in &UPPER CASE + Anahtar kelimeler B&ÜYÜK HARFLİ + + + + When set, the SQL keywords are completed in UPPER CASE letters. + Ayarlandığında, SQL anahtar kelimeleri BÜYÜK HARFLERLE tamamlanır. + + + + When set, the SQL code lines that caused errors during the last execution are highlighted and the results frame indicates the error in the background + Ayarlandığında, son yürütme sırasında hatalara neden olan SQL kod satırları vurgulanır ve sonuç çerçevesi arka plandaki hatayı gösterir + + + + <html><head/><body><p>SQLite provides an SQL function for loading extensions from a shared library file. Activate this if you want to use the <span style=" font-style:italic;">load_extension()</span> function from SQL code.</p><p>For security reasons, extension loading is turned off by default and must be enabled through this setting. You can always load extensions through the GUI, even though this option is disabled.</p></body></html> + <html> <head /> <body> <p> SQLite, paylaşılmış kütüphane dosyasından eklenti yüklemeye yarayan bir fonksiyon sunar. <span style=" font-style:italic;">load_extension()</span> fonksiyonunu SQL kodu içerisinde kullanmak istiyorsanız fonksiyonu aktive edin. </p> <p> Güvenlik nedeniyle, uzantı yüklemesi varsayılan olarak kapalıdır ve bu ayar ile etkinleÅŸtirilmelidir. Bu seçenek devre dışı bırakılmış olsa bile, uzantıları her zaman GUI üzerinden yükleyebilirsiniz. </p> </body> </html> + + + + Allow loading extensions from SQL code + SQL kodundan eklenti yüklemeye izin ver + + + + Remote + Uzak Bilgisayar + + + + CA certificates + CA sertifikaları + + + + + Subject CN + CN Konusu + + + + Common Name + Yaygın İsim + + + + Subject O + Konu O + + + + Organization + Organizasyon + + + + + Valid from + Åžundan tarihten itibaren geçerli + + + + + Valid to + Åžu tarihe kadar geçerli + + + + + Serial number + Seri numarası + + + + Your certificates + Sertifikalarınız + + + + File + Dosya + + + + Subject Common Name + Ortak Konu Adı + + + + Issuer CN + CN SaÄŸlayıcısı + + + + Issuer Common Name + Ortak SaÄŸlayıcı Adı + + + + Clone databases into + Veritabanını ÅŸuraya kopyala + + + + SQL editor &font + SQL Editör &yazı boyutu + + + + Error indicators + Hata belirteçleri + + + + Hori&zontal tiling + Ya&tay Döşeme + + + + If enabled the SQL code editor and the result table view are shown side by side instead of one over the other. + EtkinleÅŸtirilirse, SQL kod düzenleyicisi ve sonuç tablosu görünümü üst üste yerine yan yana gösterilir. + + + + Code co&mpletion + Kod ta&mamlama + + + + Foreground + Ön plan + + + + SQL &results font size + S&QL sonuçları yazı tipi boyutu + + + + &Extensions + &Eklentiler + + + + Select extensions to load for every database: + Her veritabanında kullanmak için eklenti seçiniz: + + + + Add extension + Eklenti Ekle + + + + Remove extension + Eklenti Sil + + + + <html><head/><body><p>While supporting the REGEXP operator SQLite doesn't implement any regular expression<br/>algorithm but calls back the running application. DB Browser for SQLite implements this<br/>algorithm for you to let you use REGEXP out of the box. However, as there are multiple possible<br/>implementations of this and you might want to use another one, you're free to disable the<br/>application's implementation and load your own by using an extension. Requires restart of the application.</p></body></html> + <html><head/><body><p>Kurallı ifade(REGEXP) operatörü aktif edildiÄŸinde SQLite, herhangi bir kurallı ifade uygulamaz ama ÅŸuan da çalışan uygulamayı geri çağırır. <br/>SQLite DB Browser kurallı ifadeyi kutunun dışında kullanmanıza izin vermek için bu algoritmayı uygular. <br/>Birden çok muhtemel uygulama olduÄŸu gibi sizde farklı birini kullanabilirsiniz.<br/>Programın uygulamalarını devre dışı bırakmakta ve kendi eklentinizle kendi uygulamanızı yüklemekte özgürsünüz.<br/>Ayrıca uygulamayı yeniden baÅŸlatmak gerekir.</p></body></html> + + + + Disable Regular Expression extension + Kurallı İfade eklentisini devre dışı bırak + + + + + Choose a directory + Dizin seçiniz + + + + The language will change after you restart the application. + Seçilen dil uygulama yeniden baÅŸlatıldıktan sonra uygulanacaktır. + + + + Select extension file + Eklenti dosyası seçiniz + + + + Extensions(*.so *.dylib *.dll);;All files(*) + Eklentiler(*.so *.dylib *.dll);;Tüm dosyalar(*) + + + + Import certificate file + Sertifika dosyası içe aktar + + + + No certificates found in this file. + Bu dosyada sertifika bulunamadı. + + + + Are you sure you want do remove this certificate? All certificate data will be deleted from the application settings! + Bu sertifikayı kaldırmak istediÄŸinizden emin misiniz? Tüm sertifika verileri uygulama ayarlarından silinecektir! + + + + Are you sure you want to clear all the saved settings? +All your preferences will be lost and default values will be used. + Kaydedilen tüm ayarları silmek istediÄŸinizden emin misiniz? +Tüm tercihleriniz kaybolacak ve varsayılan deÄŸerler kullanılacak. + + + + ProxyDialog + + + Proxy Configuration + Proxy Yapılandırması + + + + Pro&xy Type + Pro&xy Tipi + + + + Host Na&me + A&na Bilgisayar Adı + + + + Port + Port + + + + Authentication Re&quired + Kimlik &DoÄŸrulaması Gerekli + + + + &User Name + K&ullanıcı Adı + + + + Password + Parola + + + + None + Hiçbiri + + + + System settings + Sistem ayarları + + + + HTTP + HTTP + + + + Socks v5 + Socks v5 + + + + QObject + + + Error importing data + Veriyi içe aktarılırken hata oluÅŸtu + + + + from record number %1 + kayıt numarasından: %1 + + + + . +%1 + . %1 + + + + Importing CSV file... + CSV dosyası içe aktarılıyor... + + + + Cancel + İptal + + + + All files (*) + Tüm dosyalar (*) + + + + SQLite database files (*.db *.sqlite *.sqlite3 *.db3) + SQLite veritabanı dosyaları (*.db *.sqlite *.sqlite3 *.db3) + + + + Left + Sola Hizala + + + + Right + SaÄŸa Hizala + + + + Center + Ortala + + + + Justify + İki yana yasla + + + + SQLite Database Files (*.db *.sqlite *.sqlite3 *.db3) + SQLite Veritabanı Dosyaları (*.db *.sqlite *.sqlite3 *.db3) + + + + DB Browser for SQLite Project Files (*.sqbpro) + DB Browser for SQLite Proje Dosyaları (*.sqbpro) + + + + SQL Files (*.sql) + SQL Dosyaları (*.sql) + + + + All Files (*) + Tüm Dosyalar (*) + + + + Text Files (*.txt) + Metin Dosyaları (*.txt) + + + + Comma-Separated Values Files (*.csv) + Virgülle Ayrılmış DeÄŸerler Dosyaları (* .csv) + + + + Tab-Separated Values Files (*.tsv) + Tab ile Ayrılmış DeÄŸerler Dosyaları (*.tsv) + + + + Delimiter-Separated Values Files (*.dsv) + Sınırlayıcı ile Ayrılmış DeÄŸerler Dosyaları (* .dsv) + + + + Concordance DAT files (*.dat) + Uyumluluk DAT dosyaları (* .dat) + + + + JSON Files (*.json *.js) + JSON dosyaları (*.json *.js) + + + + XML Files (*.xml) + XML Dosyaları (*.xml) + + + + Binary Files (*.bin *.dat) + İkili Dosyalar (*.bin *.dat) + + + + SVG Files (*.svg) + SVG Dosyaları (*.svg) + + + + Hex Dump Files (*.dat *.bin) + Onaltılık Döküm Dosyaları (* .dat * .bin) + + + + Extensions (*.so *.dylib *.dll) + Eklentiler (* .so * .dylib * .dll) + + + + RemoteCommitsModel + + + Commit ID + + + + + Message + + + + + Date + Tarih + + + + Author + + + + + Size + Boyut + + + + Authored and committed by %1 + + + + + Authored by %1, committed by %2 + + + + + RemoteDatabase + + + Error opening local databases list. +%1 + Yerel veritabanı listesi açılamadı. +%1 + + + + Error creating local databases list. +%1 + Yerel veritabanı listesi oluÅŸturulamadı. +%1 + + + + RemoteDock + + + Remote + Uzak Bilgisayar + + + + Identity + Kmlik + + + + Push currently opened database to server + Åžu anda açık olan veritabanını sunucuya aktar + + + + DBHub.io + + + + + <html><head/><body><p>In this pane, remote databases from dbhub.io website can be added to DB Browser for SQLite. First you need an identity:</p><ol style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Login to the dbhub.io website (use your GitHub credentials or whatever you want)</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Click the button to &quot;Generate client certificate&quot; (that's your identity). That'll give you a certificate file (save it to your local disk).</li><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Go to the Remote tab in DB Browser for SQLite Preferences. Click the button to add a new certificate to DB Browser for SQLite and choose the just downloaded certificate file.</li></ol><p>Now the Remote panel shows your identity and you can add remote databases.</p></body></html> + + + + + Local + + + + + Current Database + + + + + Clone + + + + + User + Kullanıcı + + + + Database + Veritabanı + + + + Branch + Branch + + + + Commits + + + + + Commits for + + + + + Delete Database + + + + + Delete the local clone of this database + + + + + Open in Web Browser + + + + + Open the web page for the current database in your browser + + + + + Clone from Link + + + + + Use this to download a remote database for local editing using a URL as provided on the web page of the database. + + + + + Refresh + Yenile + + + + Reload all data and update the views + + + + + F5 + + + + + Clone Database + + + + + Open Database + + + + + Open the local copy of this database + + + + + Check out Commit + + + + + Download and open this specific commit + + + + + Check out Latest Commit + + + + + Check out the latest commit of the current branch + + + + + Save Revision to File + + + + + Saves the selected revision of the database to another file + + + + + Upload Database + + + + + Upload this database as a new commit + + + + + <html><head/><body><p>You are currently using a built-in, read-only identity. For uploading your database, you need to configure and use your DBHub.io account.</p><p>No DBHub.io account yet? <a href="https://dbhub.io/"><span style=" text-decoration: underline; color:#007af4;">Create one now</span></a> and import your certificate <a href="#preferences"><span style=" text-decoration: underline; color:#007af4;">here</span></a> to share your databases.</p><p>For online help visit <a href="https://dbhub.io/about"><span style=" text-decoration: underline; color:#007af4;">here</span></a>.</p></body></html> + <html> <head /> <body> <p> Åžu anda dahili, salt okunur kimlik kullanıyorsunuz. Kendi veritabanınızı yüklemek için DBHub.io hesabı kullanıp konfigure etmeniz gerekiyor. </p> <p> Henüz DBHub.io hesabınız yok mu? <a href="https://dbhub.io/" ><span style=" text-decoration: underline; color:#007af4;" >Åžimdi bir tane oluÅŸturun</span ></a > ve veritabanınızı paylaÅŸmak için <a href="#preferences" ><span style=" text-decoration: underline; color:#007af4;" >buradan</span ></a > sertifikanızı içe aktarın. </p> <p> Çevrimiçi yardım için <a href="https://dbhub.io/about" ><span style=" text-decoration: underline; color:#007af4;" >burayı</span ></a > ziyaret edin. </p> </body> </html> + + + + Back + Geri + + + + Select an identity to connect + + + + + Public + + + + + This downloads a database from a remote server for local editing. +Please enter the URL to clone from. You can generate this URL by +clicking the 'Clone Database in DB4S' button on the web page +of the database. + + + + + Invalid URL: The host name does not match the host name of the current identity. + + + + + Invalid URL: No branch name specified. + + + + + Invalid URL: No commit ID specified. + + + + + You have modified the local clone of the database. Fetching this commit overrides these local changes. +Are you sure you want to proceed? + + + + + The database has unsaved changes. Are you sure you want to push it before saving? + + + + + The database you are trying to delete is currently opened. Please close it before deleting. + + + + + This deletes the local version of this database with all the changes you have not committed yet. Are you sure you want to delete this database? + + + + + RemoteLocalFilesModel + + + Name + İsim + + + + Branch + Branch + + + + Last modified + Son deÄŸiÅŸtirilme + + + + Size + Boyut + + + + Commit + Commit + + + + File + + + + + RemoteModel + + + Name + İsim + + + + Commit + Commit + + + + Last modified + Son deÄŸiÅŸtirilme + + + + Size + Boyut + + + + Size: + + + + + Last Modified: + + + + + Licence: + + + + + Default Branch: + + + + + RemoteNetwork + + + Choose a location to save the file + + + + + Error opening remote file at %1. +%2 + %1 adresinde bulunan dosya açılamadı. %2 + + + + Error: Invalid client certificate specified. + Hata: Geçersiz istemci sertifikası belirtildi. + + + + Please enter the passphrase for this client certificate in order to authenticate. + Kimlik doÄŸrulaması için lütfen istemci sertifikasının parolasını girin. + + + + Cancel + İptal + + + + Uploading remote database to +%1 + Uzak veritabanı karşıya yükleniyor +%1 + + + + Downloading remote database from +%1 + Uzaktaki sunucu indiriliyor: +%1 + + + + + Error: The network is not accessible. + Hata: AÄŸa eriÅŸilemiyor. + + + + Error: Cannot open the file for sending. + Hata: Dosya gönderim için açılamadı. + + + + RemotePushDialog + + + Push database + Veritabanını aktar + + + + Database na&me to push to + Aktarılacak veritaba&nı adı + + + + Commit message + Commit mesajı + + + + Database licence + Veritabanı lisansı + + + + Public + Halka açık + + + + Branch + Branch + + + + Force push + Aktarmaya zorla + + + + Username + + + + + Database will be public. Everyone has read access to it. + Veritabanı halka açık olacak. Herkes okuma iznine sahip olacak. + + + + Database will be private. Only you have access to it. + Veritabanı özel olacak. Sadece sizin eriÅŸiminiz olacak. + + + + Use with care. This can cause remote commits to be deleted. + Dikkatlice kullanın. Bu, uzaktaki deÄŸiÅŸikliklerin silinmesine sebep olabilir. + + + + RunSql + + + Execution aborted by user + Yürütme kullanıcı tarafından durduruldu + + + + , %1 rows affected + , %1 satır etkilendi + + + + query executed successfully. Took %1ms%2 + sorgu baÅŸarıyla yürütüldü. %1ms%2 sürdü + + + + executing query + sorgu yürütülüyor + + + + SelectItemsPopup + + + A&vailable + &Kullanılabilir + + + + Sele&cted + &Seçilen + + + + SqlExecutionArea + + + Form + Form + + + + Find previous match [Shift+F3] + Önceki eÅŸleÅŸmeyi bul [Shift, F3] + + + + Find previous match with wrapping + Sarmalayarak bir önceki eÅŸleÅŸmeyi bul + + + + Shift+F3 + + + + + The found pattern must be a whole word + Bulunan desen tam bir kelime olmalıdır + + + + Whole Words + Kelimenin Tamamı + + + + Text pattern to find considering the checks in this frame + Bu alandaki kontrolleri baz alarak bulunacak metin deseni + + + + Find in editor + Editörde ara + + + + The found pattern must match in letter case + Bulunan desen büyük küçük harfe duyarlı olmalıdır + + + + Case Sensitive + Büyük küçük harfe duyarı + + + + Find next match [Enter, F3] + Sonraki eÅŸleÅŸmeyi bul [Enter, F3] + + + + Find next match with wrapping + Sarmalayarak bir sonraki eÅŸleÅŸmeyi bul + + + + F3 + + + + + Interpret search pattern as a regular expression + Arama desenini düzenli ifade(RegEx) olarak yorumla + + + + <html><head/><body><p>When checked, the pattern to find is interpreted as a UNIX regular expression. See <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>.</p></body></html> + <html> <head /> <body> <p> İşaretlendiÄŸinde, girilen desen UNIX düzenli ifadesi olarak yorumlanır. <a href="https://en.wikibooks.org/wiki/Regular_Expressions" >Wikibooks</a > üzerinden düzenli ifadeleri inceleyebilirsiniz. </p> </body> </html> + + + + Regular Expression + Kurallı İfade (RegEx) + + + + + Close Find Bar + Araba çubuÄŸunu kapat + + + + <html><head/><body><p>Results of the last executed statements.</p><p>You may want to collapse this panel and use the <span style=" font-style:italic;">SQL Log</span> dock with <span style=" font-style:italic;">User</span> selection instead.</p></body></html> + <html> <head /> <body> <p>Son yürütülen ifadelerin sonuçları.</p> <p> Bu paneli daraltmak ve bunun yerine <span style=" font-style:italic;">SQL Log Günlüğünü</span> <span style=" font-style:italic;">Kullanıcı</span> seçimi ile kullanmak isteyebilirsiniz. </p> </body> </html> + + + + Results of the last executed statements + Son yürütülen ifadenin sonucu + + + + This field shows the results and status codes of the last executed statements. + Bu alan son yürütülen ifadenin durum kodlarını ve sonuçlarını gösterir. + + + + Couldn't read file: %1. + Dosya okunamadı: %1. + + + + + Couldn't save file: %1. + Dosya kaydedilemedi: %1. + + + + Your changes will be lost when reloading it! + Yeniden yüklerken deÄŸiÅŸiklikleriniz kaybolacak! + + + + The file "%1" was modified by another program. Do you want to reload it?%2 + "%1" dosyası baÅŸka bir program tarafından deÄŸiÅŸtirildi. Yeniden yüklemek istiyor musunuz?%2 + + + + SqlTextEdit + + + Ctrl+/ + + + + + SqlUiLexer + + + (X) The abs(X) function returns the absolute value of the numeric argument X. + (X) abs(X) fonksiyonu X sayısal argümanının mutlak deÄŸerini döndürür. + + + + () The changes() function returns the number of database rows that were changed or inserted or deleted by the most recently completed INSERT, DELETE, or UPDATE statement. + () changes() fonksiyonu en son yürütülen INSERT, DELETE veya UPDATE ifadesinden etkilenen veritabanı satırlarının sayısını döndürür. + + + + (X1,X2,...) The char(X1,X2,...,XN) function returns a string composed of characters having the unicode code point values of integers X1 through XN, respectively. + (X1,X2,...) char(X1,X2,...,XN) fonksiyonu sırasıyla X1'den XN'e kadar olan tamsayıların unicode karakter karşılıklarından oluÅŸan dizeyi döndürür. + + + + (X,Y,...) The coalesce() function returns a copy of its first non-NULL argument, or NULL if all arguments are NULL + (X,Y,...) coalesce() fonksiyonu NULL olmayan ilk argümanı döndürür. EÄŸer tüm argümanlar NULL ise NULL deÄŸerini döndürür + + + + (X,Y) The glob(X,Y) function is equivalent to the expression "Y GLOB X". + (X,Y) glob(X,Y) fonksiyonu "Y GLOB X" ifadesinin eÅŸdeÄŸerini döndürür. + + + + (X,Y) The ifnull() function returns a copy of its first non-NULL argument, or NULL if both arguments are NULL. + (X,Y) ifnull() fonksiyonu NULL olmayan ilk argümanı döndürür. EÄŸer her iki argüman da NULL ise NULL deÄŸerini döndürür. + + + + (X,Y) The instr(X,Y) function finds the first occurrence of string Y within string X and returns the number of prior characters plus 1, or 0 if Y is nowhere found within X. + (X,Y) instr(X,Y) fonksiyonu ilk önce X dizesinin içinde Y dizesinin içeriÄŸini arar ve eÅŸleÅŸen yerden önceki karakterlerin sayısının 1 fazlasını döndürür. EÄŸer Y, X içerisinde bulunmazsa 0 deÄŸerini döndürür. + + + + (X) The hex() function interprets its argument as a BLOB and returns a string which is the upper-case hexadecimal rendering of the content of that blob. + (X) hex() fonksiyonu argümanı BLOB olarak yorumlar ve BLOB içeriÄŸinin büyük harf onaltılık kısmını dize olarak döndürür. + + + + () The last_insert_rowid() function returns the ROWID of the last row insert from the database connection which invoked the function. + () last_insert_rowid() fonksiyonu çaÄŸrılan veritabanı baÄŸlantısından en son eklenen satırın ROWID deÄŸerini döndürür. + + + + (X) For a string value X, the length(X) function returns the number of characters (not bytes) in X prior to the first NUL character. + (X) length() fonksiyonu X dize deÄŸeri için NULL ifadesine kadar olan karakter sayısını döndürür (bayt olarak deÄŸil). + + + + (X,Y) The like() function is used to implement the "Y LIKE X" expression. + (X,Y) like() fonksiyonu "Y LIKE X" ifadesini uygulamak için kullanılır. + + + + (X,Y,Z) The like() function is used to implement the "Y LIKE X ESCAPE Z" expression. + (X,Y,Z) like() fonksiyonu "Y LIKE X ESCAPE Z" ifadesini uygulamak için kullanılır. + + + + (X) The load_extension(X) function loads SQLite extensions out of the shared library file named X. +Use of this function must be authorized from Preferences. + (X) load_extension(X) fonksiyonu, SQLite eklentilerini X adlı paylaşılan kitaplık dosyasından yükler. Bu iÅŸlevin kullanımına Tercihler'den izin verilmelidir. + + + + (X,Y) The load_extension(X) function loads SQLite extensions out of the shared library file named X using the entry point Y. +Use of this function must be authorized from Preferences. + (X, Y) load_extension(X) iÅŸlevi, Y giriÅŸ noktasını kullanarak X adlı paylaşılan kitaplık dosyasından SQLite eklentilerini yükler. +Bu iÅŸlevin kullanımına Tercihler'den izin verilmelidir. + + + + (X) The lower(X) function returns a copy of string X with all ASCII characters converted to lower case. + (X) lower(X) fonksiyonu tüm X dizesinin tüm ASCII karakterlerinin küçük harfe dönüştürülmüş karşılığını döndürür. + + + + (X) ltrim(X) removes spaces from the left side of X. + (X) ltrim(X) fonksiyonu X'in sol tarafındaki boÅŸlukları siler. + + + + (X,Y) The ltrim(X,Y) function returns a string formed by removing any and all characters that appear in Y from the left side of X. + (X,Y) ltrim(X,Y) fonksiyonu X'in sol tarafındaki Y'de bulunan tüm karakterlerin silinmiÅŸ halini dize halinde döndürür. + + + + (X,Y,...) The multi-argument max() function returns the argument with the maximum value, or return NULL if any argument is NULL. + (X,Y,...) Çok argümanlı max() fonksiyonu en büyük deÄŸere sahip argümanı döndürür. EÄŸer herhangi bir argüman NULL ise NULL deÄŸerini döndürür. + + + + (X,Y,...) The multi-argument min() function returns the argument with the minimum value. + (X,Y,...) Çok argümanlı min() fonksiyonu en küçük deÄŸere sahip argümanı döndürür. + + + + (X,Y) The nullif(X,Y) function returns its first argument if the arguments are different and NULL if the arguments are the same. + (X,Y) nullif(X,Y) fonksiyonu eÄŸer argümanlar farklı ise ilk argümanı, eÄŸer argümanlar aynı ise NULL döndürür. + + + + (FORMAT,...) The printf(FORMAT,...) SQL function works like the sqlite3_mprintf() C-language function and the printf() function from the standard C library. + (FORMAT,...) printf(FORMAT,...) SQL fonksiyonu C dilindeki sqlite3_mprintf() fonksiyonu ve standard C kütüphanesindeki printf() fonksiyonu ile aynı mantıkta çalışır. + + + + (X) The quote(X) function returns the text of an SQL literal which is the value of its argument suitable for inclusion into an SQL statement. + (X) quote(X) fonksiyonu girilen argümanlardan SQL ifadesi olarak tam anlamıyla dahil edilmeye uygun olanları döndürür. + + + + () The random() function returns a pseudo-random integer between -9223372036854775808 and +9223372036854775807. + () random() fonksiyonu -9223372036854775808 ve +9223372036854775807 tamsayı deÄŸerli arasında rastgele deÄŸer döndürür. + + + + (N) The randomblob(N) function return an N-byte blob containing pseudo-random bytes. + (N) randomblob(N) fonksiyonu rastgele bayt içeren N-byte türünde blob döndürür. + + + + (X,Y,Z) The replace(X,Y,Z) function returns a string formed by substituting string Z for every occurrence of string Y in string X. + (X,Y,Z) replace(X,Y,Z) fonksiyonu X içindeki her Y argümanını, Z argümanıyla deÄŸiÅŸtirmesiyle oluÅŸan dizeyi döndürür. + + + + (X) The round(X) function returns a floating-point value X rounded to zero digits to the right of the decimal point. + (X) round(X) fonksiyonu X ondalıklı sayısının ondalıklı kısmın sıfıra yuvarlanmasıyla oluÅŸan deÄŸeri döndürür. + + + + (X,Y) The round(X,Y) function returns a floating-point value X rounded to Y digits to the right of the decimal point. + (X,Y) round(X,Y) fonksiyonu X ondalıklı sayısının Y kadar sağındaki ondalıklı kısmı sıfıra yuvarlanmasıyla oluÅŸan deÄŸeri döndürür. + + + + (X) rtrim(X) removes spaces from the right side of X. + (X) rtrim(X) fonksiyonu X'in saÄŸ tarafındaki boÅŸlukları siler. + + + + (X,Y) The rtrim(X,Y) function returns a string formed by removing any and all characters that appear in Y from the right side of X. + (X,Y) rtrim(X,Y) fonksiyonu X'in saÄŸ tarafındaki Y'de bulunan tüm karakterlerin silinmiÅŸ halini dize halinde döndürür. + + + + (X) The soundex(X) function returns a string that is the soundex encoding of the string X. + (X) soundex(X) fonksiyonu X dizesinin soundex kodlamasını string olarak döndürür. + + + + (X,Y) substr(X,Y) returns all characters through the end of the string X beginning with the Y-th. + (X,Y) substr(X,Y) fonksiyonu X dizesinin baÅŸlangıcından Y. indekse kadar olan string bölümünü döndürür. + + + + (X,Y,Z) The substr(X,Y,Z) function returns a substring of input string X that begins with the Y-th character and which is Z characters long. + (X,Y,Z) substr(X,Y,Z) fonksiyonu X dizesinin Y. indeksinden baÅŸlayarak Z uzunluÄŸu kadar olan string bölümünü döndürür. + + + + () The total_changes() function returns the number of row changes caused by INSERT, UPDATE or DELETE statements since the current database connection was opened. + () total_changes() fonksiyonu geçerli veritabanı baÄŸlantısı açıldığından itibaren INSERT, UPDATE veya DELETE ifadelerinden etkilenen toplam satır sayısını döndürür. + + + + (X) trim(X) removes spaces from both ends of X. + (X) trim(X) fonksiyonu X'in içinde bulunan boÅŸlukları siler. + + + + (X,Y) The trim(X,Y) function returns a string formed by removing any and all characters that appear in Y from both ends of X. + (X,Y) trim(X,Y) fonksiyonu X'in içindeki Y'de bulunan tüm karakterlerin silinmiÅŸ halini dize halinde döndürür. + + + + (X) The typeof(X) function returns a string that indicates the datatype of the expression X. + (X) typeof(X) fonksiyonu X ifadesinin veri tipini gösteren dizeyi döndürür. + + + + (X) The unicode(X) function returns the numeric unicode code point corresponding to the first character of the string X. + (X) unicode(X) fonksiyonu X'in ilk karakterine karşılık gelen unicode kod noktasını döndürür. + + + + (X) The upper(X) function returns a copy of input string X in which all lower-case ASCII characters are converted to their upper-case equivalent. + (X) upper(X) fonksiyonu tüm X dizesinin tüm küçük ASCII karakterlerinin büyük harf karşılığına çevrilmiÅŸ kopyasını döndürür. + + + + (N) The zeroblob(N) function returns a BLOB consisting of N bytes of 0x00. + (N) zeroblob(N) fonksiyonu 0x00'ın N bayt kadar meydana gelmiÅŸ halini BLOB olarak döndürür. + + + + + + + (timestring,modifier,modifier,...) + + + + + (format,timestring,modifier,modifier,...) + + + + + (X) The avg() function returns the average value of all non-NULL X within a group. + (X) avg() fonksiyonu bir gruptaki NULL olmayan tüm X deÄŸerlerinin ortalama deÄŸerini döndürür. + + + + (X) The count(X) function returns a count of the number of times that X is not NULL in a group. + (X) count(X) fonksiyonu bir gruptaki X'in kaç kere NULL olmadığının sayısını döndürür. + + + + (X) The group_concat() function returns a string which is the concatenation of all non-NULL values of X. + (X) group_concat() fonksiyonu X'in NULL olmayan tüm deÄŸerlerle birleÅŸimini dize olarak döndürür. + + + + (X,Y) The group_concat() function returns a string which is the concatenation of all non-NULL values of X. If parameter Y is present then it is used as the separator between instances of X. + (X,Y) group_concat() fonksiyonu X'in NULL olmayan tüm deÄŸerlerle birleÅŸimini dize olarak döndürür. EÄŸer Y parametresi mevcutsa X'in örnekleri arasında ayraç olarak kullanılır. + + + + (X) The max() aggregate function returns the maximum value of all values in the group. + (X) max() küme fonksiyonu gruptaki tüm deÄŸerler arasından en büyük deÄŸeri döndürür. + + + + (X) The min() aggregate function returns the minimum non-NULL value of all values in the group. + (X) min() küme fonksiyonu gruptaki NULL olmayan tüm deÄŸerler arasından en küçük deÄŸeri döndürür. + + + + + (X) The sum() and total() aggregate functions return sum of all non-NULL values in the group. + (X) sum() ve total() küme fonksiyonları gruptaki NULL olmayan tüm deÄŸerlerin toplamını döndürür. + + + + () The number of the row within the current partition. Rows are numbered starting from 1 in the order defined by the ORDER BY clause in the window definition, or in arbitrary order otherwise. + () Geçerli bölümdeki satır sayısı. Satırlar, 1'den baÅŸlayarak, tanım penceresinde ORDER BY ifadesi tarafından tanımlanan sırada veya aksi takdirde rastgele sırada numaralandırılır. + + + + () The row_number() of the first peer in each group - the rank of the current row with gaps. If there is no ORDER BY clause, then all rows are considered peers and this function always returns 1. + () row_number() her gruptaki ilk eÅŸin - boÅŸlukları olan geçerli satırın sırası. ORDER BY ifadesi yoksa, tüm satırlar eÅŸ olarak kabul edilir ve bu iÅŸlev her zaman 1 deÄŸerini döndürür. + + + + () The number of the current row's peer group within its partition - the rank of the current row without gaps. Partitions are numbered starting from 1 in the order defined by the ORDER BY clause in the window definition. If there is no ORDER BY clause, then all rows are considered peers and this function always returns 1. + () Geçerli satırın kendi bölümündeki eÅŸ grubunun sayısı - boÅŸluklar olmadan geçerli satırın sırası. Bölümler, 1'den baÅŸlayarak, tanım penceresindeki ORDER BY ifadesi tarafından tanımlanan sırada numaralandırılır. ORDER BY iifadesi yoksa, tüm satırlar eÅŸ olarak kabul edilir ve bu iÅŸlev her zaman 1 deÄŸerini döndürür. + + + + () Despite the name, this function always returns a value between 0.0 and 1.0 equal to (rank - 1)/(partition-rows - 1), where rank is the value returned by built-in window function rank() and partition-rows is the total number of rows in the partition. If the partition contains only one row, this function returns 0.0. + () İsme raÄŸmen, bu iÅŸlev her zaman 0.0 ile 1.0 arasında (sıralama - 1) / (bölüm satırları - 1) deÄŸerine bir deÄŸer döndürür; burada sıralama, yerleÅŸik pencere rank() fonksiyonu ve bölüm- tarafından döndürülen deÄŸerdir. satırlar, bölümdeki toplam satır sayısıdır. Bölüm yalnızca bir satır içeriyorsa, bu iÅŸlev 0,0 deÄŸerini döndürür. + + + + () The cumulative distribution. Calculated as row-number/partition-rows, where row-number is the value returned by row_number() for the last peer in the group and partition-rows the number of rows in the partition. + () Kümülatif dağılım. Satır-sayısı/bölüm-satırları olarak hesaplanır; burada satır-sayısı, gruptaki son eÅŸ için row_number() tarafından döndürülen deÄŸerdir ve bölüm-satırdaki bölüm sayısıdır. + + + + (N) Argument N is handled as an integer. This function divides the partition into N groups as evenly as possible and assigns an integer between 1 and N to each group, in the order defined by the ORDER BY clause, or in arbitrary order otherwise. If necessary, larger groups occur first. This function returns the integer value assigned to the group that the current row is a part of. + (N) N argümanı bir tamsayı olarak ele alınır. Bu iÅŸlev, bölümü olabildiÄŸince eÅŸit bir ÅŸekilde N gruplarına böler ve ORDER BY ifadesi tarafından tanımlanan sırada veya aksi takdirde rasgele sırayla her gruba 1 ve N arasında bir tam sayı atar. Gerekirse, önce daha büyük gruplar oluÅŸur. Bu iÅŸlev, geçerli satırın parçası olduÄŸu gruba atanan tamsayı deÄŸerini döndürür. + + + + (expr) Returns the result of evaluating expression expr against the previous row in the partition. Or, if there is no previous row (because the current row is the first), NULL. + (expr) Bölümdeki önceki satıra göre expr ifade deÄŸerlendirmesinin sonucunu döndürür. Veya, önceki satır yoksa (geçerli satır ilk satır olduÄŸu için), NULL. + + + + (expr,offset) If the offset argument is provided, then it must be a non-negative integer. In this case the value returned is the result of evaluating expr against the row offset rows before the current row within the partition. If offset is 0, then expr is evaluated against the current row. If there is no row offset rows before the current row, NULL is returned. + (expr,offset) Uzaklık deÄŸiÅŸkeni saÄŸlanırsa, negatif olmayan bir tam sayı olmalıdır. Bu durumda, döndürülen deÄŸer, bölüm içindeki geçerli satırdan önce satır ofseti satırlarına göre ifade deÄŸerlendirmesinin sonucudur. Ofset 0 ise, ifade geçerli satıra göre deÄŸerlendirilir. Geçerli satırdan önce satır kaydırma satırları yoksa, NULL döndürülür. + + + + + (expr,offset,default) If default is also provided, then it is returned instead of NULL if the row identified by offset does not exist. + (expr,offset,default) Varsayılan da saÄŸlanmışsa, ofset ile tanımlanan satır yoksa NULL döndürülür. + + + + (expr) Returns the result of evaluating expression expr against the next row in the partition. Or, if there is no next row (because the current row is the last), NULL. + (expr) Bölümdeki bir sonraki satıra göre expr ifade deÄŸerlendirmesinin sonucunu döndürür. Veya, bir sonraki satır yoksa (geçerli satır son olduÄŸu için), NULL. + + + + (expr,offset) If the offset argument is provided, then it must be a non-negative integer. In this case the value returned is the result of evaluating expr against the row offset rows after the current row within the partition. If offset is 0, then expr is evaluated against the current row. If there is no row offset rows after the current row, NULL is returned. + (expr,offset) Uzaklık deÄŸiÅŸkeni saÄŸlanırsa, negatif olmayan bir tam sayı olmalıdır. Bu durumda, döndürülen deÄŸer, bölüm içindeki geçerli satırdan sonra ifade ofset satırlarına göre ifade deÄŸerlendirmesinin sonucudur. Ofset 0 ise, ifade geçerli satıra göre deÄŸerlendirilir. Geçerli satırdan sonra satır ofseti satırı yoksa, NULL döndürülür. + + + + (expr) This built-in window function calculates the window frame for each row in the same way as an aggregate window function. It returns the value of expr evaluated against the first row in the window frame for each row. + (expr) Bu yerleÅŸik pencere iÅŸlevi, her satır için pencere çerçevesini birleÅŸtirilmiÅŸ pencere iÅŸlevi ile aynı ÅŸekilde hesaplar. Her satır için pencere çerçevesindeki ilk satıra karşı deÄŸerlendirilen ifade deÄŸerini döndürür. + + + + (expr) This built-in window function calculates the window frame for each row in the same way as an aggregate window function. It returns the value of expr evaluated against the last row in the window frame for each row. + (expr) Bu yerleÅŸik pencere iÅŸlevi, her satır için pencere çerçevesini birleÅŸtirilmiÅŸ pencere iÅŸlevi ile aynı ÅŸekilde hesaplar. Her satır için pencere çerçevesindeki son satıra göre deÄŸerlendirilen ifade deÄŸerini döndürür. + + + + (expr,N) This built-in window function calculates the window frame for each row in the same way as an aggregate window function. It returns the value of expr evaluated against the row N of the window frame. Rows are numbered within the window frame starting from 1 in the order defined by the ORDER BY clause if one is present, or in arbitrary order otherwise. If there is no Nth row in the partition, then NULL is returned. + (expr,N) Bu yerleÅŸik pencere iÅŸlevi, her satır için pencere çerçevesini birleÅŸtirilmiÅŸ pencere iÅŸlevi ile aynı ÅŸekilde hesaplar. Pencere çerçevesinin N satırına göre deÄŸerlendirilen ifade deÄŸerini döndürür. Satırlar, pencere çerçevesi içinde 1'den baÅŸlayarak, ORDER BY deyimi tarafından varsa veya baÅŸka bir ÅŸekilde rastgele sırada numaralandırılır. Bölümde N'inci satırı yoksa, NULL döndürülür. + + + + SqliteTableModel + + + reading rows + satırlar okunuyor + + + + loading... + yükleniyor... + + + + References %1(%2) +Hold %3Shift and click to jump there + Referanslar %1(%2) +Buraya atlamak için %3Shift'e basılı tutun ve tıklayın + + + + Error changing data: +%1 + Veri deÄŸiÅŸtirme hatası: %1 + + + + retrieving list of columns + sütunların listesi alınıyor + + + + Fetching data... + Veri alınıyor... + + + + + Cancel + İptal + + + + TableBrowser + + + Browse Data + Veriyi Görüntüle + + + + &Table: + &Tablo: + + + + Select a table to browse data + Verileri görüntülemek için tablo seçiniz + + + + Use this list to select a table to be displayed in the database view + Veritabanı görünümünde gösterilecek tabloyu seçmek için bu listeyi kullanın + + + + This is the database table view. You can do the following actions: + - Start writing for editing inline the value. + - Double-click any record to edit its contents in the cell editor window. + - Alt+Del for deleting the cell content to NULL. + - Ctrl+" for duplicating the current record. + - Ctrl+' for copying the value from the cell above. + - Standard selection and copy/paste operations. + Bu veritabanı tablosu görünümüdür. AÅŸağıdaki iÅŸlemleri yapabilirsiniz: +  - Satır içi deÄŸeri düzenlemek için yazmaya baÅŸlayın. +  - İçeriklerini hücre düzenleyici penceresinde düzenlemek için herhangi bir kaydı çift tıklayın. +  - Hücre içeriÄŸini NULL'a dönüştürmek için Alt + Del tuÅŸlarına basın. +  - Geçerli kaydı çoÄŸaltmak için Ctrl + "tuÅŸlarına basın. +  - Yukarıdaki hücreden deÄŸeri kopyalamak için Ctrl + '. +  - Standart seçim ve kopyalama / yapıştırma iÅŸlemleri. + + + + Text pattern to find considering the checks in this frame + Bu çerçevedeki kontrolleri baz alarak bulmak için metin deseni + + + + Find in table + Tabloda ara + + + + Find previous match [Shift+F3] + Önceki eÅŸleÅŸmeyi bul [Shift,F3] + + + + Find previous match with wrapping + Sarmalayarak bir önceki eÅŸleÅŸmeyi bul + + + + Shift+F3 + + + + + Find next match [Enter, F3] + Sonraki eÅŸleÅŸmeyi bul [Enter, F3] + + + + Find next match with wrapping + Sarmalayarak bir sonraki eÅŸleÅŸmeyi bul + + + + F3 + + + + + The found pattern must match in letter case + Bulunan desen büyük küçük harfe duyarlı ÅŸekilde eÅŸleÅŸmelidir + + + + Case Sensitive + Büyük Küçük Harfe Duyarlı + + + + The found pattern must be a whole word + Bulunan kalıp tam bir kelime olmalıdır + + + + Whole Cell + Tüm hücre + + + + Interpret search pattern as a regular expression + Arama desenini düzenliifade olarak yorumlama + + + + <html><head/><body><p>When checked, the pattern to find is interpreted as a UNIX regular expression. See <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>.</p></body></html> + <html> <head /> <body> <p> İşaretlendiÄŸinde, girilen desen UNIX düzenli ifadesi olarak yorumlanır. <a href="https://en.wikibooks.org/wiki/Regular_Expressions" >Wikibooks</a > üzerinden düzenli ifadeleri inceleyebilirsiniz. </p> </body> </html> + + + + Regular Expression + Düzenli İfade (RegEx) + + + + + Close Find Bar + Arama ÇubuÄŸunu Kapat + + + + Text to replace with + DeÄŸiÅŸtirilecek metin + + + + Replace with + Åžununla deÄŸiÅŸtir + + + + Replace next match + Sonraki eÅŸleÅŸmeyi deÄŸiÅŸtir + + + + + Replace + DeÄŸiÅŸtir + + + + Replace all matches + Tüm eÅŸleÅŸenleri deÄŸiÅŸtir + + + + Replace all + Tümünü DeÄŸiÅŸtir + + + + <html><head/><body><p>Scroll to the beginning</p></body></html> + <html><head/><body><p>BaÅŸa sürükle</p></body></html> + + + + <html><head/><body><p>Clicking this button navigates to the beginning in the table view above.</p></body></html> + <html><head/><body><p>Bu butona basıldığında üstteki tablo görünümünün baÅŸlangıcına kaydırılır.</p></body></html> + + + + |< + |< + + + + Scroll one page upwards + Bir sayfa yukarı kaydır + + + + <html><head/><body><p>Clicking this button navigates one page of records upwards in the table view above.</p></body></html> + <html><head/><body><p>Bu butona tıklamak, yukarıdaki tablo görünümünde kayıt sayfasını yukarı doÄŸru kaydırır.</p></body></html> + + + + < + < + + + + 0 - 0 of 0 + 0 - 0 / 0 + + + + Scroll one page downwards + Bir sayfa aÅŸağı kaydır + + + + <html><head/><body><p>Clicking this button navigates one page of records downwards in the table view above.</p></body></html> + <html><head/><body><p>Bu butona tıklamak, yukarıdaki tablo görünümünde kayıt sayfasını aÅŸağıya doÄŸru kaydırır.</p></body></html> + + + + > + > + + + + Scroll to the end + Sona sürükle + + + + <html><head/><body><p>Clicking this button navigates up to the end in the table view above.</p></body></html> + + + + + >| + >| + + + + <html><head/><body><p>Click here to jump to the specified record</p></body></html> + <html><head/><body><p>İstediÄŸiniz kayda atlamak için buraya tıklayın</p></body></html> + + + + <html><head/><body><p>This button is used to navigate to the record number specified in the Go to area.</p></body></html> + <html><head/><body><p>Bu buton belirtilen kayıt numarasına gitmek için kullanılır.</p></body></html> + + + + Go to: + Bu kayda gidin: + + + + Enter record number to browse + Görüntülemek için kayıt numarasını giriniz + + + + Type a record number in this area and click the Go to: button to display the record in the database view + Bu alana veritabanı görünümünde görüntülemek istediÄŸiniz kayıt numarasını giriniz ve Bu kayda gidin butonuna tıklayınız + + + + 1 + 1 + + + + Show rowid column + rowid sütununu göster + + + + Toggle the visibility of the rowid column + Rowid sütununun görünürlüğünü ayarla + + + + Unlock view editing + Görünüm düzenlemenin kilidini aç + + + + This unlocks the current view for editing. However, you will need appropriate triggers for editing. + Bu, geçerli görünümün düzenleme için kilidini açar. Ancak, düzenleme için uygun tetikleyicilere ihtiyacınız olacaktır. + + + + Edit display format + Görüntüleme formatını düzenle + + + + Edit the display format of the data in this column + Bu sütundaki verilerin görüntüleme biçimini düzenleyin + + + + + New Record + Yeni Kayıt + + + + + Insert a new record in the current table + Geçerli tabloya yeni bir kayıt ekle + + + + <html><head/><body><p>This button creates a new record in the database. Hold the mouse button to open a pop-up menu of different options:</p><ul><li><span style=" font-weight:600;">New Record</span>: insert a new record with default values in the database.</li><li><span style=" font-weight:600;">Insert Values...</span>: open a dialog for entering values before they are inserted in the database. This allows to enter values acomplishing the different constraints. This dialog is also open if the <span style=" font-weight:600;">New Record</span> option fails due to these constraints.</li></ul></body></html> + <html> <head /> <body> <p> Bu düğme veritabanında yeni bir kayıt oluÅŸturur. Farklı seçeneklerin olduÄŸu açılır menüsüyü görüntülemek için fare düğmesini basılı tutun: </p> <ul> <li> <span style=" font-weight:600;">Yeni Kayıt</span>: veritabanına varsayılan deÄŸerleri olan yeni bir kayıt ekler. </li> <li> <span style=" font-weight:600;">DeÄŸerler Ekleyin...</span>: veritabanına eklenmeden önce deÄŸerleri girmek için bir iletiÅŸim kutusu açın. Bu, farklı kısıtlamaları karşılayan deÄŸerlerin girilmesine izin verir. Bu iletiÅŸim kutusu, bu kısıtlamalar nedeniyle <span style=" font-weight:600;">Yeni Kayıt</span> seçeneÄŸi baÅŸarısız olursa da açılır. </li> </ul> </body> </html> + + + + + Delete Record + Kaydı Sil + + + + Delete the current record + Geçerli kaydı sil + + + + + This button deletes the record or records currently selected in the table + Bu buton tabloda seçili olan kaydı veya kayıtları siler + + + + + Insert new record using default values in browsed table + Görüntülenen tablosundaki varsayılan deÄŸerleri kullanarak yeni kayıt ekle + + + + Insert Values... + DeÄŸerler Ekle... + + + + + Open a dialog for inserting values in a new record + Yeni bir kayda deÄŸer eklemek için bir iletiÅŸim kutusu açın + + + + Export to &CSV + &CSV dosyası olarak dışa aktar + + + + + Export the filtered data to CSV + FiltrelenmiÅŸ veriyi CSV olarak dışa aktar + + + + This button exports the data of the browsed table as currently displayed (after filters, display formats and order column) as a CSV file. + Bu buton, görüntülenen tablonun verilerini ÅŸu anda görüntülendiÄŸi ÅŸekliyle (filtrelerden, görüntüleme biçimlerinden ve sütunların sıralamasına kadar) bir CSV dosyası olarak dışa aktarır. + + + + Save as &view + &Görünüm olarak kaydet + + + + + Save the current filter, sort column and display formats as a view + Geçerli filtreyi, sütunu ve görüntüleme biçimlerini bir görünüm olarak kaydedin + + + + This button saves the current setting of the browsed table (filters, display formats and order column) as an SQL view that you can later browse or use in SQL statements. + Bu buton, görüntülenen tablonun geçerli ayarlarını (filtreler, görüntü formatları ve sütunların sırasına kadar) daha sonra göz atabileceÄŸiniz veya SQL ifadelerinde kullanabileceÄŸiniz bir SQL görünümü olarak kaydeder. + + + + Save Table As... + Tabloyu Farklı Kaydet... + + + + + Save the table as currently displayed + Tabloyu ÅŸu anda gösterilen ÅŸekilde kaydet + + + + <html><head/><body><p>This popup menu provides the following options applying to the currently browsed and filtered table:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Export to CSV: this option exports the data of the browsed table as currently displayed (after filters, display formats and order column) to a CSV file.</li><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Save as view: this option saves the current setting of the browsed table (filters, display formats and order column) as an SQL view that you can later browse or use in SQL statements.</li></ul></body></html> + <html> <head /> <body> <p> Bu açılır menü, o anda görüntülenen ve filtrelenen tablo için geçerli olan aÅŸağıdaki seçenekleri sunar: </p> <ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;" > <li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;" > CSV olarak Dışa Aktar: Bu seçenek, görüntülenen tablonun verilerini ÅŸu anda görüntülendiÄŸi ÅŸekliyle (filtrelerden, görüntüleme biçimlerinden ve sipariÅŸ sütunun sıralamasına kadar) bir CSV dosyasına aktarır. </li> <li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;" > Görünüm olarak kaydet: Bu seçenek, göz atılan tablonun geçerli ayarlarını (filtreler, görüntü formatları ve sipariÅŸ sütun sıralamasına kadar) daha sonra göz atabileceÄŸiniz veya SQL ifadelerinde kullanabileceÄŸiniz bir SQL görünümü olarak kaydeder. </li> </ul> </body> </html> + + + + Hide column(s) + Sütunları gizle + + + + Hide selected column(s) + Seçilen sütunları gizle + + + + Show all columns + Tüm sütunları göster + + + + Show all columns that were hidden + Gizlenen tüm sütunları göster + + + + + Set encoding + Kodlama seç + + + + Change the encoding of the text in the table cells + Tablo hücrelerindeki metnin kodlamasını deÄŸiÅŸtirme + + + + Set encoding for all tables + Tüm tablolar için kodlama seç + + + + Change the default encoding assumed for all tables in the database + Veritabanındaki tüm tablolar için varsayılan kodlamayı deÄŸiÅŸtirme + + + + Clear Filters + Filtreleri Temizle + + + + Clear all filters + Tüm filtreleri temizle + + + + + This button clears all the filters set in the header input fields for the currently browsed table. + Bu buton, o anda görüntülenen tablonun baÅŸlık giriÅŸ alanlarında ayarlanan tüm filtreleri temizler. + + + + Clear Sorting + Sıralamayı Temizle + + + + Reset the order of rows to the default + Satırların sırasını varsayılana sıfırla + + + + + This button clears the sorting columns specified for the currently browsed table and returns to the default order. + Bu buton, o anda görüntülenen tablo için belirtilen sıralama sütunlarını temizler ve varsayılan sıraya geri döner. + + + + Print + Yazdır + + + + Print currently browsed table data + Åžu anda görüntülenen tablo verilerini yazdır + + + + Print currently browsed table data. Print selection if more than one cell is selected. + Åžu anda görüntülenen tablo verilerini yazdırın. Birden fazla hücre seçilirse seçimi yazdırın. + + + + Ctrl+P + + + + + Refresh + Yenile + + + + Refresh the data in the selected table + Seçilen tablodaki verileri yenile + + + + This button refreshes the data in the currently selected table. + Bu buton, seçilen tablodaki verileri yeniler. + + + + F5 + + + + + Find in cells + Hücrelerde ara + + + + Open the find tool bar which allows you to search for values in the table view below. + AÅŸağıdaki tablo görünümünde deÄŸerleri aramanıza izin veren bul araç çubuÄŸunu açın. + + + + + Bold + Kalın + + + + Ctrl+B + + + + + + Italic + İtalik + + + + + Underline + Altı çizili + + + + Ctrl+U + + + + + + Align Right + SaÄŸa Hizala + + + + + Align Left + Sola Hizala + + + + + Center Horizontally + Yatayda Ortala + + + + + Justify + İki yana yasla + + + + + Edit Conditional Formats... + KoÅŸullu Biçimlendirmeyi Düzenle... + + + + Edit conditional formats for the current column + Geçerli sütun için koÅŸullu biçimlendirmeyi düzenle + + + + Clear Format + Biçimlendirmeleri Temizle + + + + Clear All Formats + Tüm Biçimlendirmeleri Temizle + + + + + Clear all cell formatting from selected cells and all conditional formats from selected columns + Seçilen hücrelerdeki tüm hücre biçimlendirmelerini ve seçilen sütunlardaki tüm koÅŸullu biçimleri temizle + + + + + Font Color + Yazı Rengi + + + + + Background Color + Arka Plan Rengi + + + + Toggle Format Toolbar + Biçim Araç ÇubuÄŸunu Aç/Kapat + + + + Show/hide format toolbar + Biçim araç çubuÄŸunu göster/gizle + + + + + This button shows or hides the formatting toolbar of the Data Browser + Bu düğme Veri Görüntüleyici'nin biçimlendirme araç çubuÄŸunu gösterir veya gizler + + + + Select column + Sütun seç + + + + Ctrl+Space + + + + + Replace text in cells + Hücrelerdeki metinleri deÄŸiÅŸtir + + + + Filter in any column + + + + + Ctrl+R + + + + + %n row(s) + + %n satır + + + + + , %n column(s) + + , %n sütun + + + + + . Sum: %1; Average: %2; Min: %3; Max: %4 + . Toplam: %1; Ortalama: %2; Min: %3; Maks: %4 + + + + Conditional formats for "%1" + "%1" için koÅŸullu biçimlendirme + + + + determining row count... + satır sayısı belirleniyor... + + + + %1 - %2 of >= %3 + %1 - %2 >= %3 + + + + %1 - %2 of %3 + %1 - %2 / %3 + + + + Please enter a pseudo-primary key in order to enable editing on this view. This should be the name of a unique column in the view. + Bu görünümde düzenlemeyi etkinleÅŸtirmek için lütfen sözde birincil anahtar girin. Bu, görünümdeki benzersiz bir sütunun adı olmalıdır. + + + + Delete Records + Kayıtları Sil + + + + Duplicate records + Yinelenen kayıtlar + + + + Duplicate record + Yinelenen kayıt + + + + Ctrl+" + + + + + Adjust rows to contents + Satırları içeriklere göre ayarlama + + + + Error deleting record: +%1 + Kayıt silme hatası: +%1 + + + + Please select a record first + Lütfen öncelikle kaydı seçiniz + + + + There is no filter set for this table. View will not be created. + Bu tablo için ayarlanmış filtre yok. Görünüm oluÅŸturulmaz. + + + + Please choose a new encoding for all tables. + Lütfen tüm tablolar için yeni bir kodlama seçin. + + + + Please choose a new encoding for this table. + Lütfen bu tablo için yeni bir kodlama seçin. + + + + %1 +Leave the field empty for using the database encoding. + %1 +Veritabanı kodlamasını kullanmak için alanı boÅŸ bırakın. + + + + This encoding is either not valid or not supported. + Bu kodlama geçerli deÄŸil veya desteklenmiyor. + + + + %1 replacement(s) made. + %1 deÄŸiÅŸimi yapıldı. + + + + VacuumDialog + + + Compact Database + Veritabanını Sıkıştır + + + + Warning: Compacting the database will commit all of your changes. + Uyarı: Veritabanını sıkıştırmak bütün deÄŸiÅŸikliklerinizi kaydedecektir. + + + + Please select the databases to co&mpact: + Sıkıştır&mak istediÄŸiniz veritabanını seçiniz: + + + diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/translations/sqlb_uk_UA.qm b/src/WBCLFZSystemModule/SqliteDBProcess/src/translations/sqlb_uk_UA.qm new file mode 100644 index 0000000000000000000000000000000000000000..dfb5e51d3f6dc3a880c233f2a111cfde4721055c GIT binary patch literal 84283 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 + + + + AboutDialog + + + About DB Browser for SQLite + Про ОглÑдач БД Ð´Ð»Ñ SQLite + + + + Version + ВерÑÑ–Ñ + + + + <html><head/><body><p>DB Browser for SQLite is an open source, freeware visual tool used to create, design and edit SQLite database files.</p><p>It is bi-licensed under the Mozilla Public License Version 2, as well as the GNU General Public License Version 3 or later. You can modify or redistribute it under the conditions of these licenses.</p><p>See <a href="http://www.gnu.org/licenses/gpl.html">http://www.gnu.org/licenses/gpl.html</a> and <a href="https://www.mozilla.org/MPL/2.0/index.txt">https://www.mozilla.org/MPL/2.0/index.txt</a> for details.</p><p>For more information on this program please visit our website at: <a href="http://sqlitebrowser.org">http://sqlitebrowser.org</a></p><p><span style=" font-size:small;">This software uses the GPL/LGPL Qt Toolkit from </span><a href="http://qt-project.org/"><span style=" font-size:small;">http://qt-project.org/</span></a><span style=" font-size:small;"><br/>See </span><a href="http://qt-project.org/doc/qt-5/licensing.html"><span style=" font-size:small;">http://qt-project.org/doc/qt-5/licensing.html</span></a><span style=" font-size:small;"> for licensing terms and information.</span></p><p><span style=" font-size:small;">It also uses the Silk icon set by Mark James licensed under a Creative Commons Attribution 2.5 and 3.0 license.<br/>See </span><a href="http://www.famfamfam.com/lab/icons/silk/"><span style=" font-size:small;">http://www.famfamfam.com/lab/icons/silk/</span></a><span style=" font-size:small;"> for details.</span></p></body></html> + + + + + AddRecordDialog + + + Add New Record + + + + + Enter values for the new record considering constraints. Fields in bold are mandatory. + + + + + In the Value column you can specify the value for the field identified in the Name column. The Type column indicates the type of the field. Default values are displayed in the same style as NULL values. + + + + + Name + Ім'Ñ + + + + Type + Тип + + + + Value + + + + + Values to insert. Pre-filled default values are inserted automatically unless they are changed. + + + + + When you edit the values in the upper frame, the SQL query for inserting this new record is shown here. You can edit manually the query before saving. + + + + + <html><head/><body><p><span style=" font-weight:600;">Save</span> will submit the shown SQL statement to the database for inserting the new record.</p><p><span style=" font-weight:600;">Restore Defaults</span> will restore the initial values in the <span style=" font-weight:600;">Value</span> column.</p><p><span style=" font-weight:600;">Cancel</span> will close this dialog without executing the query.</p></body></html> + + + + + Auto-increment + + + + + + Unique constraint + + + + + + Check constraint: %1 + + + + + + Foreign key: %1 + + + + + + Default value: %1 + + + + + + Error adding record. Message from database engine: + +%1 + + + + + Are you sure you want to restore all the entered values to their defaults? + + + + + Application + + + Possible command line arguments: + ДоÑтупні ключі командного Ñ€Ñдку: + + + + Usage: %1 [options] [<database>|<project>] + + + + + + -h, --help Show command line options + + + + + -q, --quit Exit application after running scripts + + + + + -s, --sql <file> Execute this SQL file after opening the DB + + + + + -t, --table <table> Browse this table after opening the DB + + + + + -R, --read-only Open database in read-only mode + + + + + -o, --option <group>/<setting>=<value> + + + + + Run application with this setting temporarily set to value + + + + + -O, --save-option <group>/<setting>=<value> + + + + + Run application saving this value for this setting + + + + + -v, --version Display the current version + + + + + <database> Open this SQLite database + + + + + <project> Open this project file (*.sqbpro) + + + + + The -s/--sql option requires an argument + -s/--sql Ð¾Ð¿Ñ†Ñ–Ñ Ð²Ð¸Ð¼Ð°Ð³Ð°Ñ” аргумент + + + + The -t/--table option requires an argument + -t/--table параметр таблиці вимагає аргумент + + + + The -o/--option and -O/--save-option options require an argument in the form group/setting=value + + + + + Invalid option/non-existant file: %1 + Ðевірна опціÑ/файл не Ñ–Ñнує: %1 + + + + SQLite Version + ВерÑÑ–Ñ SQLite + + + + SQLCipher Version %1 (based on SQLite %2) + + + + + DB Browser for SQLite Version %1. + + + + + Built for %1, running on %2 + + + + + Qt Version %1 + + + + + The file %1 does not exist + Файл %1 не Ñ–Ñнує + + + + CipherDialog + + + SQLCipher encryption + Ð¨Ð¸Ñ„Ñ€ÑƒÐ²Ð°Ð½Ð½Ñ SQLCipher + + + + &Password + &Пароль + + + + &Reenter password + &Пароль ще раз + + + + Encr&yption settings + + + + + SQLCipher &3 defaults + + + + + SQLCipher &4 defaults + + + + + Custo&m + + + + + Page si&ze + &Розмір Ñторінки + + + + &KDF iterations + + + + + HMAC algorithm + + + + + KDF algorithm + + + + + Plaintext Header Size + + + + + Passphrase + Парольна фраза + + + + Raw key + Ðеоброблений ключ + + + + Please set a key to encrypt the database. +Note that if you change any of the other, optional, settings you'll need to re-enter them as well every time you open the database file. +Leave the password fields empty to disable the encryption. +The encryption process might take some time and you should have a backup copy of your database! Unsaved changes are applied before modifying the encryption. + Будь лаÑка, вкажіть ключ шифруваннÑ. +Якщо Ви зміните будь-Ñке опційне налаштуваннÑ, то його доведетьÑÑ Ð²Ð²Ð¾Ð´Ð¸Ñ‚Ð¸ під Ñ‡Ð°Ñ ÐºÐ¾Ð¶Ð½Ð¾Ð³Ð¾ Ð²Ñ–Ð´ÐºÑ€Ð¸Ñ‚Ñ‚Ñ Ñ†ÑŒÐ¾Ð³Ð¾ файлу бази даних. +Залиште Ð¿Ð¾Ð»Ñ Ð¿Ð°Ñ€Ð¾Ð»ÑŽ порожніми, щоб відімкнути шифруваннÑ. +ÐŸÑ€Ð¾Ñ†ÐµÑ Ð¼Ð¾Ð¶Ðµ тривати деÑкий чаÑ. РекомендуєтьÑÑ Ñтворити резервну копію перед продовженнÑм! Ð’ÑÑ– незбережені зміни збережутьÑÑ Ð°Ð²Ñ‚Ð¾Ð¼Ð°Ñ‚Ð¸Ñ‡Ð½Ð¾. + + + + Please enter the key used to encrypt the database. +If any of the other settings were altered for this database file you need to provide this information as well. + Будь лаÑка, введіть ключ Ð´Ð»Ñ ÑˆÐ¸Ñ„Ñ€ÑƒÐ²Ð°Ð½Ð½Ñ Ð±Ð°Ð·Ð¸ даних. +Якщо будь-Ñкі інші Ð½Ð°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ð±ÑƒÐ»Ð¸ змінені Ð´Ð»Ñ Ñ†Ñ–Ñ”Ñ— бази даних, то потрібно надати цю інформацію також. + + + + ColumnDisplayFormatDialog + + + Choose display format + Оберіть формат показу + + + + Display format + Формат показу + + + + Choose a display format for the column '%1' which is applied to each value prior to showing it. + Оберіть формат показу Ð´Ð»Ñ ÐºÐ¾Ð»Ð¾Ð½ÐºÐ¸ '%1'. Формат заÑтоÑуєтьÑÑ Ð´Ð¾ кожного Ñ—Ñ— значеннÑм. + + + + Default + За замовчуваннÑм + + + + Decimal number + ДеÑÑткове чиÑло + + + + Exponent notation + ЕкÑпоненціальний Ð·Ð°Ð¿Ð¸Ñ + + + + Hex blob + Бінарні дані + + + + Hex number + ШіÑтнадцÑткове чиÑло + + + + Apple NSDate to date + Дата Apple NSDate + + + + Java epoch (milliseconds) to date + + + + + .NET DateTime.Ticks to date + + + + + Julian day to date + Дата за ЮліанÑьким календарем + + + + Unix epoch to local time + + + + + Date as dd/mm/yyyy + + + + + Lower case + Ðижній регіÑтр + + + + Custom display format must contain a function call applied to %1 + + + + + Error in custom display format. Message from database engine: + +%1 + + + + + Custom display format must return only one column but it returned %1. + + + + + Octal number + Ð’Ñ–Ñімкове чиÑло + + + + Round number + Округлене чиÑло + + + + Unix epoch to date + Unix-Ñ‡Ð°Ñ + + + + Upper case + Верхній регіÑтр + + + + Windows DATE to date + Windows дата + + + + Custom + Мій формат + + + + CondFormatManager + + + Conditional Format Manager + + + + + This dialog allows creating and editing conditional formats. Each cell style will be selected by the first accomplished condition for that cell data. Conditional formats can be moved up and down, where those at higher rows take precedence over those at lower. Syntax for conditions is the same as for filters and an empty condition applies to all values. + + + + + Add new conditional format + + + + + &Add + + + + + Remove selected conditional format + + + + + &Remove + + + + + Move selected conditional format up + + + + + Move &up + + + + + Move selected conditional format down + + + + + Move &down + + + + + Foreground + + + + + Text color + + + + + Background + Фон + + + + Background color + + + + + Font + Шрифт + + + + Size + Розмір + + + + Bold + Жирний + + + + Italic + КурÑив + + + + Underline + ПідкреÑÐ»ÐµÐ½Ð½Ñ + + + + Alignment + + + + + Condition + + + + + + Click to select color + + + + + Are you sure you want to clear all the conditional formats of this field? + + + + + DBBrowserDB + + + This database has already been attached. Its schema name is '%1'. + + + + + Please specify the database name under which you want to access the attached database + Будь лаÑка, вкажіть ім'Ñ Ð±Ð°Ð·Ð¸ даних, під Ñким Ви хочете отримати доÑтуп до під'єднаних баз даних + + + + Invalid file format + Ðеправильний формат файлу + + + + Do you really want to close this temporary database? All data will be lost. + + + + + Do you want to save the changes made to the database file %1? + Зберегти зроблені зміни у файлі бази даних %1? + + + + Database didn't close correctly, probably still busy + + + + + The database is currently busy: + + + + + Do you want to abort that other operation? + + + + + Exporting database to SQL file... + ЕкÑпорт бази даних у файл SQL... + + + + + Cancel + СкаÑувати + + + + + No database file opened + + + + + Executing SQL... + Виконати код SQL... + + + + Action cancelled. + Дію ÑкаÑовано. + + + + + Error in statement #%1: %2. +Aborting execution%3. + Помилка в операторі #%1: %2. +Ð’Ð¸ÐºÐ¾Ð½Ð°Ð½Ð½Ñ ÑкаÑовано%3. + + + + + and rolling back + Ñ– відкочено + + + + didn't receive any output from %1 + + + + + could not execute command: %1 + + + + + Cannot delete this object + + + + + Cannot set data on this object + Ðе вдаєтьÑÑ Ð²Ñтановити дані в цей об'єкт + + + + + A table with the name '%1' already exists in schema '%2'. + + + + + No table with name '%1' exists in schema '%2'. + + + + + + Cannot find column %1. + + + + + Creating savepoint failed. DB says: %1 + + + + + Renaming the column failed. DB says: +%1 + + + + + + Releasing savepoint failed. DB says: %1 + + + + + Creating new table failed. DB says: %1 + + + + + Copying data to new table failed. DB says: +%1 + + + + + Deleting old table failed. DB says: %1 + + + + + Error renaming table '%1' to '%2'. +Message from database engine: +%3 + + + + + could not get list of db objects: %1 + + + + + Restoring some of the objects associated with this table failed. This is most likely because some column names changed. Here's the SQL statement which you might want to fix and execute manually: + + + Ðе вдалоÑÑ ÑкаÑувати Ð²Ð¸Ð´Ð°Ð»ÐµÐ½Ð½Ñ Ð´ÐµÑких об'єктів, аÑоційованих із цією таблицею. Ðайімовірніша причина цього - зміна імен деÑких Ñтовпців таблиці. ОÑÑŒ SQL оператор, Ñкий потрібно виправити Ñ– виконати вручну: + + + + could not get list of databases: %1 + + + + + Error loading extension: %1 + Помилка Ð·Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶ÐµÐ½Ð½Ñ Ñ€Ð¾Ð·ÑˆÐ¸Ñ€ÐµÐ½Ð½Ñ: %1 + + + + could not get column information + неможливо отримати інформацію про Ñтовпець + + + + Error setting pragma %1 to %2: %3 + Помилка вÑÑ‚Ð°Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ ÐŸÑ€Ð°Ð³Ð¼Ð¸ %1 в %2: %3 + + + + File not found. + Файл не знайдено. + + + + DbStructureModel + + + Name + Ім'Ñ + + + + Object + Об'єкт + + + + Type + Тип + + + + Schema + Схема + + + + Database + + + + + Browsables + + + + + All + Ð’Ñе + + + + Temporary + + + + + Tables (%1) + Таблиці (%1) + + + + Indices (%1) + ІндекÑи (%1) + + + + Views (%1) + ПереглÑди (%1) + + + + Triggers (%1) + Тригери (%1) + + + + EditDialog + + + Edit database cell + Ð ÐµÐ´Ð°Ð³ÑƒÐ²Ð°Ð½Ð½Ñ ÐºÐ¾Ð¼Ñ–Ñ€ÐºÐ¸ бази даних + + + + Mode: + Режим: + + + + This is the list of supported modes for the cell editor. Choose a mode for viewing or editing the data of the current cell. + + + + + RTL Text + + + + + + Image + Ð—Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð½Ñ + + + + JSON + + + + + XML + + + + + + Automatically adjust the editor mode to the loaded data type + + + + + This checkable button enables or disables the automatic switching of the editor mode. When a new cell is selected or new data is imported and the automatic switching is enabled, the mode adjusts to the detected data type. You can then change the editor mode manually. If you want to keep this manually switched mode while moving through the cells, switch the button off. + + + + + Auto-switch + + + + + The text editor modes let you edit plain text, as well as JSON or XML data with syntax highlighting, automatic formatting and validation before saving. + +Errors are indicated with a red squiggle underline. + + + + + This Qt editor is used for right-to-left scripts, which are not supported by the default Text editor. The presence of right-to-left characters is detected and this editor mode is automatically selected. + + + + + Open preview dialog for printing the data currently stored in the cell + + + + + Auto-format: pretty print on loading, compact on saving. + + + + + When enabled, the auto-format feature formats the data on loading, breaking the text in lines and indenting it for maximum readability. On data saving, the auto-format feature compacts the data removing end of lines, and unnecessary whitespace. + + + + + Word Wrap + + + + + Wrap lines on word boundaries + + + + + + Open in default application or browser + + + + + Open in application + + + + + The value is interpreted as a file or URL and opened in the default application or web browser. + + + + + Save file reference... + + + + + Save reference to file + + + + + + Open in external application + + + + + Autoformat + + + + + &Export... + + + + + + &Import... + + + + + + Import from file + + + + + + Opens a file dialog used to import any kind of data to this database cell. + + + + + Export to file + + + + + Opens a file dialog used to export the contents of this database cell to a file. + + + + + + Print... + + + + + Open preview dialog for printing displayed image + + + + + + Ctrl+P + + + + + Open preview dialog for printing displayed text + + + + + Copy Hex and ASCII + + + + + Copy selected hexadecimal and ASCII columns to the clipboard + + + + + Ctrl+Shift+C + + + + + Set as &NULL + ПриÑвоїти &NULL + + + + Apply data to cell + + + + + This button saves the changes performed in the cell editor to the database cell. + + + + + Apply + ЗаÑтоÑувати + + + + Text + ТекÑÑ‚ + + + + Binary + Двійкові дані + + + + Erases the contents of the cell + ÐžÑ‡Ð¸Ñ‰ÐµÐ½Ð½Ñ Ð²Ð¼Ñ–Ñту комірки + + + + This area displays information about the data present in this database cell + Ð¦Ñ Ð·Ð¾Ð½Ð° показує інформацію про дані, що Ñ” в цій комірці бази даних + + + + Type of data currently in cell + Тип даних у комірці + + + + Size of data currently in table + Розмір даних у таблиці + + + + Choose a filename to export data + Вибрати ім'Ñ Ñ„Ð°Ð¹Ð»Ñƒ Ð´Ð»Ñ ÐµÐºÑпорту даних + + + + Type of data currently in cell: %1 Image + Тип даних у комірці: %1 Ð—Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð½Ñ + + + + %1x%2 pixel(s) + %1x%2 пікÑелів + + + + Type of data currently in cell: NULL + Тип даних у комірці: NULL + + + + + Type of data currently in cell: Text / Numeric + Тип даних у комірці: ТекÑÑ‚ / ЧиÑлове + + + + + Image data can't be viewed in this mode. + + + + + + Try switching to Image or Binary mode. + + + + + + Binary data can't be viewed in this mode. + + + + + + Try switching to Binary mode. + + + + + + Image files (%1) + + + + + Binary files (*.bin) + + + + + Choose a file to import + Оберіть файл Ð´Ð»Ñ Ñ–Ð¼Ð¿Ð¾Ñ€Ñ‚Ñƒ + + + + %1 Image + + + + + Invalid data for this mode + + + + + The cell contains invalid %1 data. Reason: %2. Do you really want to apply it to the cell? + + + + + + + %n character(s) + + %n Ñимвол + %n Ñимволу + %n Ñимволів + + + + + Type of data currently in cell: Valid JSON + + + + + Type of data currently in cell: Binary + Тип даних у комірці: Двійкові дані + + + + Couldn't save file: %1. + Ðеможливо зберегти файл: %1. + + + + The data has been saved to a temporary file and has been opened with the default application. You can now edit the file and, when you are ready, apply the saved new data to the cell editor or cancel any changes. + + + + + + %n byte(s) + + %n байт + %n байта + %n байтів + + + + + EditIndexDialog + + + &Name + &Ім'Ñ + + + + Order + Ð¡Ð¾Ñ€Ñ‚ÑƒÐ²Ð°Ð½Ð½Ñ + + + + &Table + &Ð¢Ð°Ð±Ð»Ð¸Ñ†Ñ + + + + Edit Index Schema + Ð ÐµÐ´Ð°Ð³ÑƒÐ²Ð°Ð½Ð½Ñ Ñ–Ð½Ð´ÐµÐºÑу Ñхеми + + + + &Unique + &Унікальний + + + + For restricting the index to only a part of the table you can specify a WHERE clause here that selects the part of the table that should be indexed + Ð”Ð»Ñ Ð¾Ð±Ð¼ÐµÐ¶ÐµÐ½Ð½Ñ Ñ–Ð½Ð´ÐµÐºÑу чаÑтиною таблиці оберіть пункт WHERE, Ñкий обере чаÑтину таблиці Ð´Ð»Ñ Ñ–Ð½Ð´ÐµÐºÑації + + + + Partial inde&x clause + ЧаÑтковий ÐºÐ»Ð°Ñ Ñ–Ð½Ð´Ðµ&кÑа + + + + Colu&mns + Стов&пці + + + + Table column + Стовпець таблиці + + + + Type + Тип + + + + Add a new expression column to the index. Expression columns contain SQL expression rather than column names. + Додати новий Ñтовпець виразу до індекÑа. Стовпці виразів міÑÑ‚Ñть SQL вирази, а не імена Ñтовпців + + + + Index column + Стовпець індекÑу + + + + Deleting the old index failed: +%1 + Ðевдале Ð²Ð¸Ð´Ð°Ð»ÐµÐ½Ð½Ñ Ñтарого індекÑу: +%1 + + + + Creating the index failed: +%1 + Ðевдале ÑÑ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Ñ–Ð½Ð´ÐµÐºÑу + + + + EditTableDialog + + + Edit table definition + Ð ÐµÐ´Ð°Ð³ÑƒÐ²Ð°Ð½Ð½Ñ Ð²Ð¸Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ñ‚Ð°Ð±Ð»Ð¸Ñ†Ñ– + + + + Table + Ð¢Ð°Ð±Ð»Ð¸Ñ†Ñ + + + + Advanced + Додатково + + + + Make this a 'WITHOUT rowid' table. Setting this flag requires a field of type INTEGER with the primary key flag set and the auto increment flag unset. + Щоб Ñтворити таблицю 'WITHOUT rowid', потрібно, щоб у ній був первинний ключ INTEGER з відімкненим автоінкрементом. + + + + Without Rowid + Без ідентифікатора + + + + Fields + ÐŸÐ¾Ð»Ñ + + + + Database sche&ma + + + + + Add + + + + + Remove + + + + + Move to top + + + + + Move up + + + + + Move down + + + + + Move to bottom + + + + + + Name + Ім'Ñ + + + + + Type + Тип + + + + NN + + + + + Not null + Ðе (null) + + + + PK + ПК + + + + Primary key + Первинний ключ + + + + AI + ÐІ + + + + Autoincrement + Ðвтоінкремент + + + + U + У + + + + + + Unique + Унікальне + + + + Default + За замовчуваннÑм + + + + Default value + Ð—Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ð·Ð° замовчуваннÑм + + + + + + Check + Перевірити + + + + Check constraint + Перевірити Ð¾Ð±Ð¼ÐµÐ¶ÐµÐ½Ð½Ñ + + + + Collation + + + + + + + Foreign Key + Зовнішній ключ + + + + Constraints + + + + + Add constraint + + + + + Remove constraint + + + + + Columns + Стовпці + + + + SQL + + + + + <html><head/><body><p><span style=" font-weight:600; color:#ff0000;">Warning: </span>There is something with this table definition that our parser doesn't fully understand. Modifying and saving this table might result in problems.</p></body></html> + + + + + + Primary Key + + + + + Add a primary key constraint + + + + + Add a foreign key constraint + + + + + Add a unique constraint + + + + + Add a check constraint + + + + + There already is a field with that name. Please rename it first or choose a different name for this field. + Поле з таким ім'Ñм уже Ñ–Ñнує. Будь лаÑка, переіменуйте його або виберіть інше ім'Ñ Ð´Ð»Ñ Ñ†ÑŒÐ¾Ð³Ð¾ полÑ. + + + + + There can only be one primary key for each table. Please modify the existing primary key instead. + + + + + Error creating table. Message from database engine: +%1 + Помилка ÑÑ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Ñ‚Ð°Ð±Ð»Ð¸Ñ†Ñ–. ÐŸÐ¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ Ð²Ñ–Ð´ Ñдра бази даних: +%1 + + + + This column is referenced in a foreign key in table %1 and thus its name cannot be changed. + Ðа цей Ñтовпець поÑилаєтьÑÑ Ð·Ð¾Ð²Ð½Ñ–ÑˆÐ½Ñ–Ð¹ ключ у таблиці %1, тому Ñ—Ñ— ім'Ñ Ð½ÐµÐ¼Ð¾Ð¶Ð»Ð¸Ð²Ð¾ змінити. + + + + There is at least one row with this field set to NULL. This makes it impossible to set this flag. Please change the table data first. + ІÑнує принаймні один Ñ€Ñдок, де це поле вÑтановлено в NULL. Ð’Ñтановити цей прапорець неможливо. Спочатку змініть дані таблиці. + + + + There is at least one row with a non-integer value in this field. This makes it impossible to set the AI flag. Please change the table data first. + ІÑнує принаймні один Ñ€Ñдок, де це поле міÑтить нечиÑлове значеннÑ. Ð’Ñтановити прапорець ÐІ неможливо. Спочатку змініть дані таблиці. + + + + Column '%1' has duplicate data. + + + + + + This makes it impossible to enable the 'Unique' flag. Please remove the duplicate data, which will allow the 'Unique' flag to then be enabled. + + + + + Are you sure you want to delete the field '%1'? +All data currently stored in this field will be lost. + Ви впевнені, що хочете видалити поле '%1'? +Ð’ÑÑ– дані, Ñкі міÑÑ‚ÑтьÑÑ Ð² цьому полі, будуть втрачені. + + + + Please add a field which meets the following criteria before setting the without rowid flag: + - Primary key flag set + - Auto increment disabled + Будь лаÑка, перед вÑтановленнÑм Ð¿Ñ€Ð°Ð¿Ð¾Ñ€Ñ†Ñ Ð±ÐµÐ· rowid додайте поле, Ñке має такі критерії: +- вÑтановлено прапорець первинного ключа +- відімкнений автоінкремент + + + + ExportDataDialog + + + Export data as CSV + ЕкÑпортувати дані у форматі CSV + + + + Tab&le(s) + &Таблиці + + + + Colu&mn names in first line + &Імена Ñтовпців у першому Ñ€Ñдку + + + + Fie&ld separator + &Роздільник полів + + + + , + , + + + + ; + ; + + + + Tab + ТабулÑÑ†Ñ–Ñ + + + + | + | + + + + + + Other + Інший + + + + &Quote character + &Символ лапок + + + + " + " + + + + ' + ' + + + + New line characters + Ðовий роздільник Ñ€Ñдків + + + + Windows: CR+LF (\r\n) + Windows: CR+LF (\r\n) + + + + Unix: LF (\n) + Unix: LF (\n) + + + + Pretty print + Гарний виÑновок + + + + + Could not open output file: %1 + Ðе вдалоÑÑ Ð²Ñ–Ð´ÐºÑ€Ð¸Ñ‚Ð¸ вихідний файл: %1 + + + + + Choose a filename to export data + Виберіть ім'Ñ Ñ„Ð°Ð¹Ð»Ñƒ Ð´Ð»Ñ ÐµÐºÑпорту даних + + + + Export data as JSON + ЕкÑпортувати дані у форматі JSON + + + + exporting CSV + + + + + exporting JSON + + + + + Please select at least 1 table. + Будь лаÑка, оберіть хоча б 1 таблицю. + + + + Choose a directory + Оберіть каталог + + + + Export completed. + ЕкÑпорт завершено. + + + + ExportSqlDialog + + + Export SQL... + ЕкÑпорт SQL... + + + + Tab&le(s) + &Таблиці + + + + Select All + Обрати вÑе + + + + Deselect All + СкаÑувати вибір + + + + &Options + &Опції + + + + Keep column names in INSERT INTO + Імена Ñтовпців у виразі INSERT INTO + + + + Multiple rows (VALUES) per INSERT statement + Кілька Ñ€Ñдків (VALUES) на INSERT вираз + + + + Export everything + ЕкÑпортувати вÑÑ– + + + + Export data only + ЕкÑпортувати тільки дані + + + + Keep old schema (CREATE TABLE IF NOT EXISTS) + Стара Ñхема (CREATE TABLE IF NOT EXISTS) + + + + Overwrite old schema (DROP TABLE, then CREATE TABLE) + ПерезапиÑати Ñтару Ñхему (DROP TABLE, тоді CREATE TABLE) + + + + Export schema only + ЕкÑпортувати тільки Ñхему даних + + + + Please select at least one table. + + + + + Choose a filename to export + Оберіть ім'Ñ Ñ„Ð°Ð¹Ð»Ñƒ Ð´Ð»Ñ ÐµÐºÑпорту + + + + Export completed. + ЕкÑпорт завершено. + + + + Export cancelled or failed. + ЕкÑпорт ÑкаÑовано або виникла помилка. + + + + ExtendedScintilla + + + + Ctrl+H + + + + + Ctrl+F + + + + + + Ctrl+P + + + + + Find... + + + + + Find and Replace... + + + + + Print... + + + + + ExtendedTableWidget + + + Use as Exact Filter + + + + + Containing + + + + + Not containing + + + + + Not equal to + + + + + Greater than + + + + + Less than + + + + + Greater or equal + + + + + Less or equal + + + + + Between this and... + + + + + Regular expression + + + + + Edit Conditional Formats... + + + + + Set to NULL + Ð’Ñтановити в NULL + + + + Copy + Копіювати + + + + Copy with Headers + + + + + Copy as SQL + + + + + Paste + Ð’Ñтавити + + + + Print... + + + + + Use in Filter Expression + + + + + Alt+Del + + + + + Ctrl+Shift+C + + + + + Ctrl+Alt+C + + + + + The content of the clipboard is bigger than the range selected. +Do you want to insert it anyway? + ВміÑÑ‚ буфера обміну більше ніж обраний діапазон. +Ð’Ñе одно вÑтавити? + + + + <p>Not all data has been loaded. <b>Do you want to load all data before selecting all the rows?</b><p><p>Answering <b>No</b> means that no more data will be loaded and the selection will not be performed.<br/>Answering <b>Yes</b> might take some time while the data is loaded but the selection will be complete.</p>Warning: Loading all the data might require a great amount of memory for big tables. + + + + + Cannot set selection to NULL. Column %1 has a NOT NULL constraint. + + + + + FileExtensionManager + + + File Extension Manager + + + + + &Up + + + + + &Down + + + + + &Add + + + + + &Remove + + + + + + Description + + + + + Extensions + + + + + *.extension + + + + + FilterLineEdit + + + Filter + Фільтр + + + + These input fields allow you to perform quick filters in the currently selected table. +By default, the rows containing the input text are filtered out. +The following operators are also supported: +% Wildcard +> Greater than +< Less than +>= Equal to or greater +<= Equal to or less += Equal to: exact match +<> Unequal: exact inverse match +x~y Range: values between x and y +/regexp/ Values matching the regular expression + + + + + Clear All Conditional Formats + + + + + Use for Conditional Format + + + + + Edit Conditional Formats... + + + + + Set Filter Expression + + + + + What's This? + + + + + Is NULL + + + + + Is not NULL + + + + + Is empty + + + + + Is not empty + + + + + Not containing... + + + + + Equal to... + + + + + Not equal to... + + + + + Greater than... + + + + + Less than... + + + + + Greater or equal... + + + + + Less or equal... + + + + + In range... + + + + + Regular expression... + + + + + FindReplaceDialog + + + Find and Replace + + + + + Fi&nd text: + + + + + Re&place with: + + + + + Match &exact case + + + + + Match &only whole words + + + + + When enabled, the search continues from the other end when it reaches one end of the page + + + + + &Wrap around + + + + + When set, the search goes backwards from cursor position, otherwise it goes forward + + + + + Search &backwards + + + + + <html><head/><body><p>When checked, the pattern to find is searched only in the current selection.</p></body></html> + + + + + &Selection only + + + + + <html><head/><body><p>When checked, the pattern to find is interpreted as a UNIX regular expression. See <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>.</p></body></html> + + + + + Use regular e&xpressions + + + + + Find the next occurrence from the cursor position and in the direction set by "Search backwards" + + + + + &Find Next + + + + + F3 + + + + + &Replace + + + + + Highlight all the occurrences of the text in the page + + + + + F&ind All + + + + + Replace all the occurrences of the text in the page + + + + + Replace &All + + + + + The searched text was not found + + + + + The searched text was not found. + + + + + The searched text was found one time. + + + + + The searched text was found %1 times. + + + + + The searched text was replaced one time. + + + + + The searched text was replaced %1 times. + + + + + ForeignKeyEditor + + + &Reset + &Скинути + + + + Foreign key clauses (ON UPDATE, ON DELETE etc.) + + + + + ImportCsvDialog + + + Import CSV file + Імпортувати файл у форматі CSV + + + + Table na&me + + + + + &Column names in first line + І&мена Ñтовпців у першому Ñ€Ñдку + + + + Field &separator + &Роздільник полів + + + + , + , + + + + ; + ; + + + + + Tab + ТабулÑÑ†Ñ–Ñ + + + + | + | + + + + Other + Інший + + + + &Quote character + &Символ лапок + + + + + Other (printable) + + + + + + Other (code) + + + + + " + " + + + + ' + ' + + + + &Encoding + &ÐšÐ¾Ð´ÑƒÐ²Ð°Ð½Ð½Ñ + + + + UTF-8 + UTF-8 + + + + UTF-16 + UTF-16 + + + + ISO-8859-1 + ISO-8859-1 + + + + Trim fields? + Обрізати полÑ? + + + + Separate tables + Розділити таблиці + + + + Advanced + Додатково + + + + When importing an empty value from the CSV file into an existing table with a default value for this column, that default value is inserted. Activate this option to insert an empty value instead. + + + + + Ignore default &values + + + + + Activate this option to stop the import when trying to import an empty value into a NOT NULL column without a default value. + + + + + Fail on missing values + + + + + Disable data type detection + + + + + Disable the automatic data type detection when creating a new table. + + + + + When importing into an existing table with a primary key, unique constraints or a unique index there is a chance for a conflict. This option allows you to select a strategy for that case: By default the import is aborted and rolled back but you can also choose to ignore and not import conflicting rows or to replace the existing row in the table. + + + + + Abort import + + + + + Ignore row + + + + + Replace existing row + + + + + Conflict strategy + + + + + + Deselect All + СкаÑувати вибір + + + + Match Similar + Ð¡Ð¿Ñ–Ð²Ð¿Ð°Ð´Ñ–Ð½Ð½Ñ + + + + Select All + Обрати вÑе + + + + There is already a table named '%1' and an import into an existing table is only possible if the number of columns match. + + + + + There is already a table named '%1'. Do you want to import the data into it? + + + + + Creating restore point failed: %1 + Помилка ÑÑ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Ñ‚Ð¾Ñ‡ÐºÐ¸ відновленнÑ: %1 + + + + Creating the table failed: %1 + Помилка ÑÑ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Ñ‚Ð°Ð±Ð»Ð¸Ñ†Ñ–: %1 + + + + importing CSV + + + + + Importing the file '%1' took %2ms. Of this %3ms were spent in the row function. + + + + + Inserting row failed: %1 + Помилка вÑтавки Ñ€Ñдка: %1 + + + + MainWindow + + + DB Browser for SQLite + ОглÑдач Ð´Ð»Ñ SQLite + + + + toolBar1 + панельІнÑтрументів1 + + + + &Remote + &Віддалений + + + + &File + &Файл + + + + &Import + &Імпорт + + + + &Export + &ЕкÑпорт + + + + &Edit + &Ð ÐµÐ´Ð°Ð³ÑƒÐ²Ð°Ð½Ð½Ñ + + + + &View + &Вид + + + + &Help + &Довідка + + + + &Tools + + + + + DB Toolbar + Панель інÑтрументів БД + + + + Edit Database &Cell + Ð ÐµÐ´Ð°Ð³ÑƒÐ²Ð°Ð½Ð½Ñ &комірки БД + + + + Error Log + + + + + This button clears the contents of the SQL logs + + + + + This panel lets you examine a log of all SQL commands issued by the application or by yourself + + + + + DB Sche&ma + Схе&ма БД + + + + + Execute SQL + This has to be equal to the tab title in all the main tabs + Виконати SQL + + + + + Execute current line + Виконати поточний Ñ€Ñдок + + + + This button executes the SQL statement present in the current editor line + + + + + Shift+F5 + + + + + Sa&ve Project + &Зберегти проект + + + + Opens the SQLCipher FAQ in a browser window + Відкрити SQLCiphier ЧаПи в браузері + + + + Export one or more table(s) to a JSON file + ЕкÑпортувати таблиці в JSON файл + + + + + Save SQL file as + Зберегти файл SQL Ñк + + + + This button saves the content of the current SQL editor tab to a file + + + + + &Browse Table + Пе&реглÑд таблиці + + + + User + КориÑтувачем + + + + Application + Додатком + + + + &Clear + О&чиÑтити + + + + &New Database... + &Ðова база даних... + + + + + Create a new database file + Створити новий файл бази даних + + + + This option is used to create a new database file. + Ð¦Ñ Ð¾Ð¿Ñ†Ñ–Ñ Ð²Ð¸ÐºÐ¾Ñ€Ð¸ÑтовуєтьÑÑ Ñ‰Ð¾Ð± Ñтворити новий файл бази даних. + + + + Ctrl+N + + + + + + &Open Database... + &Відкрити базу даних... + + + + + + + + Open an existing database file + Відкрити Ñ–Ñнуючий файл бази даних + + + + + + This option is used to open an existing database file. + Ð¦Ñ Ð¾Ð¿Ñ†Ñ–Ñ Ð²Ð¸ÐºÐ¾Ñ€Ð¸ÑтовуєтьÑÑ, щоб відкрити Ñ–Ñнуючий файл бази даних. + + + + Ctrl+O + + + + + &Close Database + &Закрити базу даних + + + + This button closes the connection to the currently open database file + + + + + + Ctrl+W + + + + + + Revert database to last saved state + Повернути базу даних до оÑтаннього збереженого Ñтану + + + + This option is used to revert the current database file to its last saved state. All changes made since the last save operation are lost. + Ð¦Ñ Ð¾Ð¿Ñ†Ñ–Ñ Ð²Ð¸ÐºÐ¾Ñ€Ð¸ÑтовуєтьÑÑ, щоб повернути поточний файл бази даних до його оÑтаннього збереженого Ñтану. Ð’ÑÑ– зміни, зроблені з оÑтанньої операції збереженнÑ, буде втрачено. + + + + + Write changes to the database file + ЗапиÑати зміни у файл бази даних + + + + This option is used to save changes to the database file. + Ð¦Ñ Ð¾Ð¿Ñ†Ñ–Ñ Ð²Ð¸ÐºÐ¾Ñ€Ð¸ÑтовуєтьÑÑ, щоб зберегти зміни у файлі бази даних. + + + + Ctrl+S + + + + + Compact &Database... + + + + + Compact the database file, removing space wasted by deleted records + Ущільнити базу даних, видаливши проÑтір, зайнÑтий видаленими запиÑами + + + + + Compact the database file, removing space wasted by deleted records. + Ущільнити базу даних, видаливши проÑтір, зайнÑтий видаленими запиÑами. + + + + E&xit + &Вихід + + + + Ctrl+Q + + + + + Import data from an .sql dump text file into a new or existing database. + Імпортувати дані з текÑтового файлу .sql в нову або Ñ–Ñнуючу базу даних. + + + + This option lets you import data from an .sql dump text file into a new or existing database. SQL dump files can be created on most database engines, including MySQL and PostgreSQL. + Ð¦Ñ Ð¾Ð¿Ñ†Ñ–Ñ Ð´Ð°Ñ” змогу імпортувати дані з текÑтового файлу .sql у нову або Ñ–Ñнуючу базу даних. Файл SQL можна Ñтворити на більшоÑті двигунів баз даних, включно з MySQL Ñ– PostgreSQL. + + + + Open a wizard that lets you import data from a comma separated text file into a database table. + Відкрити майÑтер, Ñкий дає змогу імпортувати дані з файлу CSV у таблицю бази даних. + + + + Open a wizard that lets you import data from a comma separated text file into a database table. CSV files can be created on most database and spreadsheet applications. + Відкрити майÑтер, Ñкий дає змогу імпортувати дані з файлу CSV у таблицю бази даних. Файли CSV можна Ñтворити в більшоÑті програм баз даних Ñ– електронних таблиць. + + + + Export a database to a .sql dump text file. + ЕкÑпортувати базу даних у текÑтовий файл .sql. + + + + This option lets you export a database to a .sql dump text file. SQL dump files contain all data necessary to recreate the database on most database engines, including MySQL and PostgreSQL. + Ð¦Ñ Ð¾Ð¿Ñ†Ñ–Ñ Ð´Ð°Ñ” змогу екÑпортувати базу даних у текÑтовий файл .sql. Файли SQL міÑÑ‚Ñть вÑÑ– дані, необхідні Ð´Ð»Ñ ÑÑ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Ð±Ð°Ð·Ð¸ даних у більшоÑті движків баз даних, включно з MySQL Ñ– PostgreSQL. + + + + &Table(s) as CSV file... + Таблиці у файл CSV... + + + + Export a database table as a comma separated text file. + ЕкÑпортувати таблицю бази даних Ñк CSV текÑтовий файл. + + + + Export a database table as a comma separated text file, ready to be imported into other database or spreadsheet applications. + ЕкÑпортувати таблицю бази даних Ñк CSV текÑтовий файл, готовий Ð´Ð»Ñ Ñ–Ð¼Ð¿Ð¾Ñ€Ñ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ð² інші бази даних або програми електронних таблиць. + + + + Open the Create Table wizard, where it is possible to define the name and fields for a new table in the database + Відкрити майÑтер ÑÑ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Ñ‚Ð°Ð±Ð»Ð¸Ñ†ÑŒ, де можливо визначити ім'Ñ Ñ– Ð¿Ð¾Ð»Ñ Ð´Ð»Ñ Ð½Ð¾Ð²Ð¾Ñ— таблиці в базі даних + + + + Open the Delete Table wizard, where you can select a database table to be dropped. + Відкрити майÑтер Ð²Ð¸Ð´Ð°Ð»ÐµÐ½Ð½Ñ Ñ‚Ð°Ð±Ð»Ð¸Ñ†Ñ–, де можна вибрати таблицю бази даних Ð´Ð»Ñ Ð²Ð¸Ð´Ð°Ð»ÐµÐ½Ð½Ñ. + + + + Open the Modify Table wizard, where it is possible to rename an existing table. It is also possible to add or delete fields form a table, as well as modify field names and types. + Відкрити майÑтер зміни таблиці, де можливо перейменувати Ñ–Ñнуючу таблиць. Можна додати або видалити Ð¿Ð¾Ð»Ñ Ñ‚Ð°Ð±Ð»Ð¸Ñ†Ñ–, так Ñамо змінювати імена полів Ñ– типи. + + + + Open the Create Index wizard, where it is possible to define a new index on an existing database table. + Відкрити майÑтер ÑÑ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Ð†Ð½Ð´ÐµÐºÑу, в Ñкому можна визначити новий Ñ–Ð½Ð´ÐµÐºÑ Ð´Ð»Ñ Ñ–Ñнуючої таблиці бази даних. + + + + &Preferences... + &ÐалаштуваннÑ... + + + + + Open the preferences window. + Відкрити вікно налаштувань. + + + + &DB Toolbar + &Панель інÑтрументів БД + + + + Shows or hides the Database toolbar. + Показати або приховати панель інÑтрументів БД. + + + + Shift+F1 + + + + + Execute all/selected SQL + + + + + This button executes the currently selected SQL statements. If no text is selected, all SQL statements are executed. + + + + + Open SQL file(s) + + + + + This button opens files containing SQL statements and loads them in new editor tabs + + + + + Execute line + + + + + &Wiki + + + + + F1 + + + + + Bug &Report... + + + + + Feature Re&quest... + + + + + Web&site + + + + + &Donate on Patreon... + + + + + &Attach Database... + + + + + + Add another database file to the current database connection + + + + + This button lets you add another database file to the current database connection + + + + + &Set Encryption... + + + + + SQLCipher &FAQ + + + + + Table(&s) to JSON... + + + + + Open Data&base Read Only... + + + + + Ctrl+Shift+O + + + + + Save results + + + + + Save the results view + + + + + This button lets you save the results of the last executed query + + + + + + Find text in SQL editor + + + + + Find + + + + + This button opens the search bar of the editor + + + + + Ctrl+F + + + + + + Find or replace text in SQL editor + + + + + Find or replace + + + + + This button opens the find/replace dialog for the current editor tab + + + + + Ctrl+H + + + + + Export to &CSV + ЕкÑпортувати в &CSV + + + + Save as &view + Зберегти Ñк &виглÑд + + + + Save as view + Зберегти Ñк виглÑд + + + + Browse Table + + + + + Shows or hides the Project toolbar. + + + + + This button lets you save all the settings associated to the open DB to a DB Browser for SQLite project file + + + + + This button lets you open a DB Browser for SQLite project file + + + + + Extra DB Toolbar + + + + + New In-&Memory Database + + + + + Drag && Drop Qualified Names + + + + + + Use qualified names (e.g. "Table"."Field") when dragging the objects and dropping them into the editor + + + + + Drag && Drop Enquoted Names + + + + + + Use escaped identifiers (e.g. "Table1") when dragging the objects and dropping them into the editor + + + + + &Integrity Check + + + + + Runs the integrity_check pragma over the opened database and returns the results in the Execute SQL tab. This pragma does an integrity check of the entire database. + + + + + &Foreign-Key Check + + + + + Runs the foreign_key_check pragma over the opened database and returns the results in the Execute SQL tab + + + + + &Quick Integrity Check + + + + + Run a quick integrity check over the open DB + + + + + Runs the quick_check pragma over the opened database and returns the results in the Execute SQL tab. This command does most of the checking of PRAGMA integrity_check but runs much faster. + + + + + &Optimize + + + + + Attempt to optimize the database + + + + + Runs the optimize pragma over the opened database. This pragma might perform optimizations that will improve the performance of future queries. + + + + + + Print + + + + + Print text from current SQL editor tab + + + + + Open a dialog for printing the text in the current SQL editor tab + + + + + Print the structure of the opened database + + + + + Open a dialog for printing the structure of the opened database + + + + + &Save Project As... + + + + + + + Save the project in a file selected in a dialog + + + + + Save A&ll + + + + + + + Save DB file, project file and opened SQL files + + + + + Ctrl+Shift+S + + + + + &Recently opened + &Ðедавно відкриті + + + + Open &tab + Відкрити &вкладку + + + + Open an existing database file in read only mode + Відкрити Ñ–Ñнуючий файл БД у режимі тільки Ð´Ð»Ñ Ñ‡Ð¸Ñ‚Ð°Ð½Ð½Ñ + + + + Ctrl+T + + + + + + Database Structure + This has to be equal to the tab title in all the main tabs + Структура БД + + + + This is the structure of the opened database. +You can drag SQL statements from an object row and drop them into other applications or into another instance of 'DB Browser for SQLite'. + + + + + + + Browse Data + This has to be equal to the tab title in all the main tabs + ПереглÑнути дані + + + + Un/comment block of SQL code + + + + + Un/comment block + + + + + Comment or uncomment current line or selected block of code + + + + + Comment or uncomment the selected lines or the current line, when there is no selection. All the block is toggled according to the first line. + + + + + Ctrl+/ + + + + + Stop SQL execution + + + + + Stop execution + + + + + Stop the currently running SQL script + + + + + + Edit Pragmas + This has to be equal to the tab title in all the main tabs + Редагувати прагму + + + + Warning: this pragma is not readable and this value has been inferred. Writing the pragma might overwrite a redefined LIKE provided by an SQLite extension. + + + + + SQL &Log + &Журнал SQL + + + + Show S&QL submitted by + По&казати SQL, Ñкий виконано + + + + &Plot + &Графік + + + + This is the structure of the opened database. +You can drag multiple object names from the Name column and drop them into the SQL editor and you can adjust the properties of the dropped names using the context menu. This would help you in composing SQL statements. +You can drag SQL statements from the Schema column and drop them into the SQL editor or into other applications. + + + + + + + Project Toolbar + + + + + Extra DB toolbar + + + + + + + Close the current database file + + + + + Ctrl+F4 + + + + + &Revert Changes + &СкаÑувати зміни + + + + &Write Changes + &ЗапиÑати зміни + + + + &Database from SQL file... + &База даних з файлу SQL... + + + + &Table from CSV file... + &Таблиці з файлу CSV... + + + + &Database to SQL file... + Базу &даних в файл SQL... + + + + &Create Table... + &Створити таблицю... + + + + &Delete Table... + &Видалити таблицю... + + + + &Modify Table... + &Змінити таблицю... + + + + Create &Index... + Створити Ñ–&ндекÑ... + + + + W&hat's This? + Що &це таке? + + + + &About + + + + + This button opens a new tab for the SQL editor + + + + + &Execute SQL + Ви&конати код SQL + + + + + + Save SQL file + Зберегти файл SQL + + + + &Load Extension... + + + + + Ctrl+E + + + + + Export as CSV file + ЕкÑпортувати у файл CSV + + + + Export table as comma separated values file + ЕкÑпортувати таблицю Ñк CSV файл + + + + + Save the current session to a file + Зберегти поточний Ñтан у файл + + + + Open &Project... + + + + + + Load a working session from a file + Завантажити робочий Ñтан із файлу + + + + Copy Create statement + Копіювати CREATE вираз + + + + Copy the CREATE statement of the item to the clipboard + Копіювати CREATE вираз елемента в буффер обміну + + + + Ctrl+Return + + + + + Ctrl+L + + + + + + Ctrl+P + + + + + Ctrl+D + + + + + Ctrl+I + + + + + Encrypted + Зашифрований + + + + Read only + Тільки Ð´Ð»Ñ Ñ‡Ð¸Ñ‚Ð°Ð½Ð½Ñ + + + + Database file is read only. Editing the database is disabled. + База даних тільки Ð´Ð»Ñ Ñ‡Ð¸Ñ‚Ð°Ð½Ð½Ñ. Ð ÐµÐ´Ð°Ð³ÑƒÐ²Ð°Ð½Ð½Ñ Ð·Ð°Ð±Ð¾Ñ€Ð¾Ð½ÐµÐ½Ðµ. + + + + Database encoding + ÐšÐ¾Ð´ÑƒÐ²Ð°Ð½Ð½Ñ Ð±Ð°Ð·Ð¸ даних + + + + Database is encrypted using SQLCipher + База даних зашифрована з викориÑтаннÑм SQLCipher + + + + + Choose a database file + Вибрати файл бази даних + + + + Could not open database file. +Reason: %1 + Ðеможливо відкрити файл бази даних. +Причина: %1 + + + + + + Choose a filename to save under + Вибрати ім'Ñ, під Ñким зберегти дані + + + + A new DB Browser for SQLite version is available (%1.%2.%3).<br/><br/>Please download at <a href='%4'>%4</a>. + Вийшла нова верÑÑ–Ñ Ð¾Ð³Ð»Ñдача Ð´Ð»Ñ SQLite (%1.%2.%3).<br/><br/>Вона доÑтупна Ð´Ð»Ñ ÑÐºÐ°Ñ‡ÑƒÐ²Ð°Ð½Ð½Ñ Ð·Ð° поÑиланнÑм <a href='%4'>%4</a>. + + + + DB Browser for SQLite project file (*.sqbpro) + Файл проекту оглÑдача Ð´Ð»Ñ SQLite (*.sqbpro) + + + + Are you sure you want to undo all changes made to the database file '%1' since the last save? + СкаÑувати вÑÑ– зміни, зроблені у файлі бази даних '%1' піÑÐ»Ñ Ð¾Ñтаннього збереженнÑ? + + + + Choose a file to import + Оберіть файл Ð´Ð»Ñ Ñ–Ð¼Ð¿Ð¾Ñ€Ñ‚Ñƒ + + + + Do you want to create a new database file to hold the imported data? +If you answer no we will attempt to import the data in the SQL file to the current database. + Створити новий файл бази даних Ð´Ð»Ñ Ð·Ð±ÐµÑ€ÐµÐ¶ÐµÐ½Ð½Ñ Ñ–Ð¼Ð¿Ð¾Ñ€Ñ‚Ð¾Ð²Ð°Ð½Ð¸Ñ… даних? +Якщо відповідь ÐÑ–, то здійÑнитьÑÑ Ñпроба імпортувати дані файлу SQL в поточну базу даних. + + + + File %1 already exists. Please choose a different name. + Файл %1 вже Ñ–Ñнує. Оберіть інше ім'Ñ. + + + + Error importing data: %1 + Помилка Ñ–Ð¼Ð¿Ð¾Ñ€Ñ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ð´Ð°Ð½Ð¸Ñ…: %1 + + + + Import completed. + Імпорт завершено. + + + + Delete View + Видалити переглÑд + + + + Delete Trigger + Видалити тригер + + + + Delete Index + Видалити Ñ–Ð½Ð´ÐµÐºÑ + + + + Reset Window Layout + + + + + Alt+0 + + + + + Simplify Window Layout + + + + + Shift+Alt+0 + + + + + Dock Windows at Bottom + + + + + Dock Windows at Left Side + + + + + Dock Windows at Top + + + + + The database is currenctly busy. + + + + + Click here to interrupt the currently running query. + + + + + In-Memory database + + + + + Do you want to save the changes made to the project file '%1'? + + + + + Are you sure you want to delete the table '%1'? +All data associated with the table will be lost. + + + + + Are you sure you want to delete the view '%1'? + + + + + Are you sure you want to delete the trigger '%1'? + + + + + Are you sure you want to delete the index '%1'? + + + + + Error: could not delete the table. + + + + + Error: could not delete the view. + + + + + Error: could not delete the trigger. + + + + + Error: could not delete the index. + + + + + Message from database engine: +%1 + + + + + Editing the table requires to save all pending changes now. +Are you sure you want to save the database? + + + + + Error checking foreign keys after table modification. The changes will be reverted. + + + + + This table did not pass a foreign-key check.<br/>You should run 'Tools | Foreign-Key Check' and fix the reported issues. + + + + + Edit View %1 + + + + + Edit Trigger %1 + + + + + You are already executing SQL statements. Do you want to stop them in order to execute the current statements instead? Note that this might leave the database in an inconsistent state. + + + + + -- EXECUTING SELECTION IN '%1' +-- + + + + + -- EXECUTING LINE IN '%1' +-- + + + + + -- EXECUTING ALL IN '%1' +-- + + + + + + At line %1: + + + + + Result: %1 + + + + + Result: %2 + + + + + Execution finished with errors. + + + + + Execution finished without errors. + + + + + Opened '%1' in read-only mode from recent file list + + + + + Opened '%1' from recent file list + + + + + &%1 %2%3 + &%1 %2%3 + + + + (read only) + + + + + Open Database or Project + + + + + Attach Database... + + + + + Import CSV file(s)... + + + + + Select the action to apply to the dropped file(s). <br/>Note: only 'Import' will process more than one file. + + + + + + + + + Do you want to save the changes made to SQL tabs in the project file '%1'? + + + + + Project saved to file '%1' + + + + + This action will open a new SQL tab with the following statements for you to edit and run: + + + + + Busy (%1) + + + + + Rename Tab + + + + + Duplicate Tab + + + + + Close Tab + + + + + Opening '%1'... + + + + + There was an error opening '%1'... + + + + + Value is not a valid URL or filename: %1 + + + + + %1 rows returned in %2ms + + + + + Window Layout + + + + + You are still executing SQL statements. Closing the database now will stop their execution, possibly leaving the database in an inconsistent state. Are you sure you want to close the database? + + + + + Import completed. Some foreign key constraints are violated. Please fix them before saving. + + + + + Do you want to save the changes made to SQL tabs in a new project file? + + + + + Do you want to save the changes made to the SQL file %1? + + + + + The statements in this tab are still executing. Closing the tab will stop the execution. This might leave the database in an inconsistent state. Are you sure you want to close the tab? + + + + + Could not find resource file: %1 + + + + + Choose a project file to open + + + + + This project file is using an old file format because it was created using DB Browser for SQLite version 3.10 or lower. Loading this file format is still fully supported but we advice you to convert all your project files to the new file format because support for older formats might be dropped at some point in the future. You can convert your files by simply opening and re-saving them. + + + + + Could not open project file for writing. +Reason: %1 + + + + + Collation needed! Proceed? + Потрібно виконати зіÑтавленнÑ! Продовжити? + + + + A table in this database requires a special collation function '%1' that this application can't provide without further knowledge. +If you choose to proceed, be aware bad things can happen to your database. +Create a backup! + Ð¢Ð°Ð±Ð»Ð¸Ñ†Ñ Ð² базі даних вимагає Ð²Ð¸ÐºÐ¾Ð½Ð°Ð½Ð½Ñ Ñпеціальної функції зіÑÑ‚Ð°Ð²Ð»ÐµÐ½Ð½Ñ '%1'. +Якщо Ви продовжите, то можливе пÑÑƒÐ²Ð°Ð½Ð½Ñ Ð’Ð°ÑˆÐ¾Ñ— бази даних. +Створіть резервну копію! + + + + creating collation + + + + + Set a new name for the SQL tab. Use the '&&' character to allow using the following character as a keyboard shortcut. + + + + + Please specify the view name + Вкажіть ім'Ñ Ð²Ð¸Ð³Ð»Ñду + + + + There is already an object with that name. Please choose a different name. + Об'єкт із зазначеним ім'Ñм уже Ñ–Ñнує. Виберіть інше ім'Ñ. + + + + View successfully created. + ВиглÑд уÑпішно Ñтворений. + + + + Error creating view: %1 + Помилка ÑÑ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Ð²Ð¸Ð³Ð»Ñду: %1 + + + + This action will open a new SQL tab for running: + + + + + Press Help for opening the corresponding SQLite reference page. + + + + + + Delete Table + Видалити таблицю + + + + Setting PRAGMA values will commit your current transaction. +Are you sure? + Ð’ÑÑ‚Ð°Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ Ð·Ð½Ð°Ñ‡ÐµÐ½ÑŒ PRAGMA завершить поточну транзакцію. Ð’Ñтановити значеннÑ? + + + + Setting PRAGMA values or vacuuming will commit your current transaction. +Are you sure? + + + + + Choose text files + Оберіть текÑтові файли + + + + Error while saving the database file. This means that not all changes to the database were saved. You need to resolve the following error first. + +%1 + Помилка під Ñ‡Ð°Ñ Ð·Ð±ÐµÑ€ÐµÐ¶ÐµÐ½Ð½Ñ Ñ„Ð°Ð¹Ð»Ñƒ бази даних. Це означає, що не вÑÑ– зміни в базу даних було збережено. Спочатку Вам необхідно розв'Ñзати таку помилку. + +%1 + + + + Text files(*.sql *.txt);;All files(*) + ТекÑтові файли(*.sql *.txt);;Ð’ÑÑ– файли(*) + + + + Modify View + Змінити вид + + + + Modify Trigger + Змінити тригер + + + + Modify Index + Змінити Ñ–Ð½Ð´ÐµÐºÑ + + + + Modify Table + Змінити таблицю + + + + Select SQL file to open + Обрати файл SQL Ð´Ð»Ñ Ð²Ñ–Ð´ÐºÑ€Ð¸Ð²Ð°Ð½Ð½Ñ + + + + Select file name + Обрати ім'Ñ Ñ„Ð°Ð¹Ð»Ñƒ + + + + Select extension file + Обрати Ñ€Ð¾Ð·ÑˆÐ¸Ñ€ÐµÐ½Ð½Ñ Ñ„Ð°Ð¹Ð»Ñƒ + + + + Extension successfully loaded. + Ð Ð¾Ð·ÑˆÐ¸Ñ€ÐµÐ½Ð½Ñ ÑƒÑпішно завантажено. + + + + Error loading extension: %1 + Помилка Ð·Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶ÐµÐ½Ð½Ñ Ñ€Ð¾Ð·ÑˆÐ¸Ñ€ÐµÐ½Ð½Ñ: %1 + + + + + Don't show again + Ðе показувати наÑтупного разу + + + + New version available. + ДоÑтупна нова верÑÑ–Ñ. + + + + NullLineEdit + + + Set to NULL + Ð’Ñтановити в NULL + + + + Alt+Del + + + + + PlotDock + + + Plot + Графік + + + + <html><head/><body><p>This pane shows the list of columns of the currently browsed table or the just executed query. You can select the columns that you want to be used as X or Y axis for the plot pane below. The table shows detected axis type that will affect the resulting plot. For the Y axis you can only select numeric columns, but for the X axis you will be able to select:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Date/Time</span>: strings with format &quot;yyyy-MM-dd hh:mm:ss&quot; or &quot;yyyy-MM-ddThh:mm:ss&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Date</span>: strings with format &quot;yyyy-MM-dd&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Time</span>: strings with format &quot;hh:mm:ss&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Label</span>: other string formats. Selecting this column as X axis will produce a Bars plot with the column values as labels for the bars</li><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Numeric</span>: integer or real values</li></ul><p>Double-clicking the Y cells you can change the used color for that graph.</p></body></html> + + + + + Columns + Стовпці + + + + X + X + + + + Y1 + + + + + Y2 + + + + + Axis Type + + + + + Here is a plot drawn when you select the x and y values above. + +Click on points to select them in the plot and in the table. Ctrl+Click for selecting a range of points. + +Use mouse-wheel for zooming and mouse drag for changing the axis range. + +Select the axes or axes labels to drag and zoom only in that orientation. + + + + + Line type: + Тип лінії: + + + + + None + ÐÑ– + + + + Line + Звичайна + + + + StepLeft + Ступенева, зліва + + + + StepRight + Ступенева, Ñправа + + + + StepCenter + Ступенева, по центру + + + + Impulse + Ð†Ð¼Ð¿ÑƒÐ»ÑŒÑ + + + + Point shape: + Форма точок: + + + + Cross + ХреÑÑ‚ + + + + Plus + ÐŸÐ»ÑŽÑ + + + + Circle + Коло + + + + Disc + ДиÑк + + + + Square + Квадрат + + + + Diamond + Ромб + + + + Star + Зірка + + + + Triangle + Трикутник + + + + TriangleInverted + Трикутник перевернутий + + + + CrossSquare + ХреÑÑ‚ у квадраті + + + + PlusSquare + ÐŸÐ»ÑŽÑ Ñƒ квадраті + + + + CrossCircle + ХреÑÑ‚ у колі + + + + PlusCircle + ÐŸÐ»ÑŽÑ Ñƒ колі + + + + Peace + Світ + + + + <html><head/><body><p>Save current plot...</p><p>File format chosen by extension (png, jpg, pdf, bmp)</p></body></html> + <html><head/><body><p>Зберегти поточний графік...</p><p>Формат файлу вибираєтьÑÑ Ñ€Ð¾Ð·ÑˆÐ¸Ñ€ÐµÐ½Ð½Ñм (png, jpg, pdf, bmp)</p></body></html> + + + + Save current plot... + Зберегти поточний графік... + + + + + Load all data and redraw plot + + + + + + + Row # + РÑдок # + + + + Copy + Копіювати + + + + Print... + + + + + Show legend + + + + + Stacked bars + + + + + Date/Time + + + + + Date + + + + + Time + + + + + + Numeric + + + + + Label + + + + + Invalid + + + + + Load all data and redraw plot. +Warning: not all data has been fetched from the table yet due to the partial fetch mechanism. + + + + + Choose an axis color + + + + + Choose a filename to save under + Вибрати ім'Ñ, під Ñким зберегти дані + + + + PNG(*.png);;JPG(*.jpg);;PDF(*.pdf);;BMP(*.bmp);;All Files(*) + PNG(*.png);;JPG(*.jpg);;PDF(*.pdf);;BMP(*.bmp);;Ð’ÑÑ– файли(*) + + + + There are curves in this plot and the selected line style can only be applied to graphs sorted by X. Either sort the table or query by X to remove curves or select one of the styles supported by curves: None or Line. + + + + + Loading all remaining data for this table took %1ms. + + + + + PreferencesDialog + + + Preferences + ÐÐ°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ + + + + &Database + &База даних + + + + Database &encoding + &ÐšÐ¾Ð´ÑƒÐ²Ð°Ð½Ð½Ñ Ð±Ð°Ð·Ð¸ даних + + + + Open databases with foreign keys enabled. + Відкривати бази даних з увімкненими зовнішніми ключами. + + + + &Foreign keys + &Зовнішні ключі + + + + + + + + + + + + enabled + увімкнені + + + + Default &location + &Ð Ð¾Ð·Ñ‚Ð°ÑˆÑƒÐ²Ð°Ð½Ð½Ñ Ð·Ð° замовчуваннÑм + + + + + + ... + ... + + + + &General + &Загальні + + + + Remember last location + Запам'Ñтовувати оÑтанню директорію + + + + Always use this location + Завжди відкривати це Ñ€Ð¾Ð·Ñ‚Ð°ÑˆÑƒÐ²Ð°Ð½Ð½Ñ + + + + Remember last location for session only + Запам'Ñтовувати оÑтанню директорію тільки Ð´Ð»Ñ ÑеÑÑ–Ñ— + + + + Lan&guage + &Мова + + + + Toolbar style + + + + + + + + + Only display the icon + + + + + + + + + Only display the text + + + + + + + + + The text appears beside the icon + + + + + + + + + The text appears under the icon + + + + + + + + + Follow the style + + + + + Automatic &updates + &Стежити за оновленнÑми + + + + DB file extensions + + + + + Manage + + + + + SQ&L to execute after opening database + SQ&L,Ñкий треба Ð²Ð¸ÐºÐ¾Ð½Ð°Ð½Ð½Ñ Ð¿Ñ–ÑÐ»Ñ Ð²Ñ–Ð´ÐºÑ€Ð¸Ð²Ð°Ð½Ð½Ñ Ð±Ð°Ð·Ð¸ даних + + + + Data &Browser + ОглÑдач &даних + + + + Remove line breaks in schema &view + Видалити розрив Ñ€Ñдка в &Ñхемі даних + + + + Show remote options + Показати віддалені опції + + + + Prefetch block si&ze + Розмір блоку &вибірки + + + + Default field type + Тип даних за замовчуваннÑм + + + + Font + Шрифт + + + + &Font + &Шрифт + + + + Content + ВміÑÑ‚ + + + + Symbol limit in cell + КількіÑть Ñимволів у оÑередку + + + + NULL + NULL + + + + Regular + Звичайні + + + + Binary + Двійкові дані + + + + Background + Фон + + + + Filters + Фільтри + + + + Threshold for completion and calculation on selection + + + + + Show images in cell + + + + + Enable this option to show a preview of BLOBs containing image data in the cells. This can affect the performance of the data browser, however. + + + + + Escape character + Символ ÐµÐºÑ€Ð°Ð½ÑƒÐ²Ð°Ð½Ð½Ñ + + + + Delay time (&ms) + Ð§Ð°Ñ Ð·Ð°Ñ‚Ñ€Ð¸Ð¼ÐºÐ¸ (&мÑ) + + + + Set the waiting time before a new filter value is applied. Can be set to 0 for disabling waiting. + Ð§Ð°Ñ Ð·Ð°Ñ‚Ñ€Ð¸Ð¼ÐºÐ¸ перед заÑтоÑуваннÑм нового фільтра. Ðульове Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ð¿Ñ€Ð¸Ð¿Ð¸Ð½ÑÑ” очікуваннÑ. + + + + &SQL + Р&едактор SQL + + + + Settings name + Ім'Ñ Ð½Ð°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½ÑŒ + + + + Context + КонтекÑÑ‚ + + + + Colour + Колір + + + + Bold + Жирний + + + + Italic + КурÑив + + + + Underline + ПідкреÑÐ»ÐµÐ½Ð½Ñ + + + + Keyword + Ключове Ñлово + + + + Function + Ð¤ÑƒÐ½ÐºÑ†Ñ–Ñ + + + + Table + Ð¢Ð°Ð±Ð»Ð¸Ñ†Ñ + + + + Comment + Коментар + + + + Identifier + Ідентифікатор + + + + String + РÑдок + + + + Current line + Поточна Ñ€Ñдок + + + + SQL &editor font size + Розмір шрифту в &редакторі SQL + + + + Tab size + Розмір табулÑції + + + + SQL editor &font + &Шрифт у редакторі SQL + + + + Error indicators + Індикатори помилок + + + + Hori&zontal tiling + Гори&зонтальний розподіл + + + + If enabled the SQL code editor and the result table view are shown side by side instead of one over the other. + Якщо Ñ†Ñ Ð¾Ð¿Ñ†Ñ–Ñ ÑƒÐ²Ñ–Ð¼ÐºÐ½ÐµÐ½Ð°, то SQL редактор Ñ– результат запиту будуть розташовані поруч по горизонталі. + + + + Code co&mpletion + Ðвто&Ð´Ð¾Ð¿Ð¾Ð²Ð½ÐµÐ½Ð½Ñ ÐºÐ¾Ð´Ñƒ + + + + Main Window + + + + + Database Structure + Структура БД + + + + Browse Data + ПереглÑнути дані + + + + Execute SQL + Виконати SQL + + + + Edit Database Cell + Ð ÐµÐ´Ð°Ð³ÑƒÐ²Ð°Ð½Ð½Ñ ÐºÐ¾Ð¼Ñ–Ñ€ÐºÐ¸ БД + + + + When this value is changed, all the other color preferences are also set to matching colors. + + + + + Follow the desktop style + + + + + Dark style + + + + + Application style + + + + + This sets the font size for all UI elements which do not have their own font size option. + + + + + Font size + + + + + When enabled, the line breaks in the Schema column of the DB Structure tab, dock and printed output are removed. + + + + + Database structure font size + + + + + Font si&ze + + + + + This is the maximum number of items allowed for some computationally expensive functionalities to be enabled: +Maximum number of rows in a table for enabling the value completion based on current values in the column. +Maximum number of indexes in a selection for calculating sum and average. +Can be set to 0 for disabling the functionalities. + + + + + This is the maximum number of rows in a table for enabling the value completion based on current values in the column. +Can be set to 0 for disabling completion. + + + + + Field display + + + + + Displayed &text + + + + + + + + + + Click to set this color + + + + + Text color + + + + + Background color + + + + + Preview only (N/A) + + + + + Foreground + + + + + SQL &results font size + + + + + &Wrap lines + + + + + Never + + + + + At word boundaries + + + + + At character boundaries + + + + + At whitespace boundaries + + + + + &Quotes for identifiers + + + + + Choose the quoting mechanism used by the application for identifiers in SQL code. + + + + + "Double quotes" - Standard SQL (recommended) + + + + + `Grave accents` - Traditional MySQL quotes + + + + + [Square brackets] - Traditional MS SQL Server quotes + + + + + Keywords in &UPPER CASE + + + + + When set, the SQL keywords are completed in UPPER CASE letters. + + + + + When set, the SQL code lines that caused errors during the last execution are highlighted and the results frame indicates the error in the background + + + + + Close button on tabs + + + + + If enabled, SQL editor tabs will have a close button. In any case, you can use the contextual menu or the keyboard shortcut to close them. + + + + + &Extensions + Р&Ð¾Ð·ÑˆÐ¸Ñ€ÐµÐ½Ð½Ñ + + + + Select extensions to load for every database: + Оберіть розширеннÑ, щоб завантажувати Ñ—Ñ… Ð´Ð»Ñ ÐºÐ¾Ð¶Ð½Ð¾Ñ— бази даних: + + + + Add extension + Додати Ñ€Ð¾Ð·ÑˆÐ¸Ñ€ÐµÐ½Ð½Ñ + + + + Remove extension + Видалити Ñ€Ð¾Ð·ÑˆÐ¸Ñ€ÐµÐ½Ð½Ñ + + + + <html><head/><body><p>While supporting the REGEXP operator SQLite doesn't implement any regular expression<br/>algorithm but calls back the running application. DB Browser for SQLite implements this<br/>algorithm for you to let you use REGEXP out of the box. However, as there are multiple possible<br/>implementations of this and you might want to use another one, you're free to disable the<br/>application's implementation and load your own by using an extension. Requires restart of the application.</p></body></html> + <html><head/><body><p>ОглÑдач Ð´Ð»Ñ SQLite дає змогу викориÑтовувати оператор REGEXP 'з коробки'. Ðле попри<br/>це, можливі кілька різних варіантів реалізацій цього оператора й Ви вільні<br/>у виборі, Ñкий Ñаме викориÑтовувати. Можна відімкнути нашу реалізацію та викориÑтовувати іншу -<br/>шлÑхом Ð·Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶ÐµÐ½Ð½Ñ Ð²Ñ–Ð´Ð¿Ð¾Ð²Ñ–Ð´Ð½Ð¾Ð³Ð¾ розширеннÑ. Ð’ цьому випадку потрібно перезавантажити програму.</p></body></html> + + + + <html><head/><body><p>SQLite provides an SQL function for loading extensions from a shared library file. Activate this if you want to use the <span style=" font-style:italic;">load_extension()</span> function from SQL code.</p><p>For security reasons, extension loading is turned off by default and must be enabled through this setting. You can always load extensions through the GUI, even though this option is disabled.</p></body></html> + + + + + Allow loading extensions from SQL code + + + + + Clone databases into + Клонувати бази даних до + + + + Proxy + + + + + Configure + + + + + Disable Regular Expression extension + Відімкнути Ñ€Ð¾Ð·ÑˆÐ¸Ñ€ÐµÐ½Ð½Ñ Ð ÐµÐ³ÑƒÐ»Ñрних Виразів + + + + Remote + Віддалений Ñервер + + + + CA certificates + СÐ-Ñертифікати + + + + + Subject CN + Об'єкт CN + + + + Common Name + Звичайне ім'Ñ + + + + Subject O + Об'єкт O + + + + Organization + ÐžÑ€Ð³Ð°Ð½Ñ–Ð·Ð°Ñ†Ñ–Ñ + + + + + Valid from + ДійÑний з + + + + + Valid to + ДійÑний до + + + + + Serial number + Серійний номер + + + + Your certificates + Ваш Ñертифікат + + + + File + Файл + + + + Subject Common Name + Звичайне ім'Ñ Ð¾Ð±'єкта + + + + Issuer CN + РозповÑюдник CN + + + + Issuer Common Name + Звичайне ім'Ñ Ñ€Ð¾Ð·Ð¿Ð¾Ð²Ñюдника + + + + + Choose a directory + Оберіть каталог + + + + The language will change after you restart the application. + Мова змінитьÑÑ Ð¿Ñ–ÑÐ»Ñ Ð¿ÐµÑ€ÐµÐ·Ð°Ð¿ÑƒÑку програми. + + + + Select extension file + Обираємо файл Ñ€Ð¾Ð·ÑˆÐ¸Ñ€ÐµÐ½Ð½Ñ + + + + Extensions(*.so *.dylib *.dll);;All files(*) + + + + + Import certificate file + Імпортувати файл Ñертифіката + + + + No certificates found in this file. + Ð”Ð»Ñ Ñ†ÑŒÐ¾Ð³Ð¾ файлу не знайдено Ñертифікатів. + + + + Are you sure you want do remove this certificate? All certificate data will be deleted from the application settings! + Ви впевнені, що хочете видалити цей Ñертифікат? Ð’ÑÑ– дані Ñертифіката видалÑтьÑÑ Ð· налаштувань програми! + + + + Are you sure you want to clear all the saved settings? +All your preferences will be lost and default values will be used. + + + + + ProxyDialog + + + Proxy Configuration + + + + + Pro&xy Type + + + + + Host Na&me + + + + + Port + + + + + Authentication Re&quired + + + + + &User Name + + + + + Password + + + + + None + ÐÑ– + + + + System settings + + + + + HTTP + + + + + Socks v5 + + + + + QObject + + + Error importing data + Помилка Ñ–Ð¼Ð¿Ð¾Ñ€Ñ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ð´Ð°Ð½Ð¸Ñ… + + + + from record number %1 + з запиÑу номер %1 + + + + . +%1 + . +%1 + + + + Importing CSV file... + + + + + Cancel + СкаÑувати + + + + All files (*) + + + + + SQLite database files (*.db *.sqlite *.sqlite3 *.db3) + + + + + Left + + + + + Right + + + + + Center + + + + + Justify + + + + + SQLite Database Files (*.db *.sqlite *.sqlite3 *.db3) + + + + + DB Browser for SQLite Project Files (*.sqbpro) + + + + + SQL Files (*.sql) + + + + + All Files (*) + + + + + Text Files (*.txt) + + + + + Comma-Separated Values Files (*.csv) + + + + + Tab-Separated Values Files (*.tsv) + + + + + Delimiter-Separated Values Files (*.dsv) + + + + + Concordance DAT files (*.dat) + + + + + JSON Files (*.json *.js) + + + + + XML Files (*.xml) + + + + + Binary Files (*.bin *.dat) + + + + + SVG Files (*.svg) + + + + + Hex Dump Files (*.dat *.bin) + + + + + Extensions (*.so *.dylib *.dll) + + + + + RemoteCommitsModel + + + Commit ID + + + + + Message + + + + + Date + + + + + Author + + + + + Size + Розмір + + + + Authored and committed by %1 + + + + + Authored by %1, committed by %2 + + + + + RemoteDatabase + + + Error opening local databases list. +%1 + Помилка Ð²Ñ–Ð´ÐºÑ€Ð¸Ð²Ð°Ð½Ð½Ñ ÑпиÑку локальних баз даних. +%1 + + + + Error creating local databases list. +%1 + Помилка ÑÑ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ ÑпиÑку локальних баз даних. +%1 + + + + RemoteDock + + + Remote + Віддалений + + + + Local + Локальний + + + + Identity + Ідентичний + + + + Push currently opened database to server + + + + + DBHub.io + + + + + <html><head/><body><p>In this pane, remote databases from dbhub.io website can be added to DB Browser for SQLite. First you need an identity:</p><ol style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Login to the dbhub.io website (use your GitHub credentials or whatever you want)</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Click the button to &quot;Generate client certificate&quot; (that's your identity). That'll give you a certificate file (save it to your local disk).</li><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Go to the Remote tab in DB Browser for SQLite Preferences. Click the button to add a new certificate to DB Browser for SQLite and choose the just downloaded certificate file.</li></ol><p>Now the Remote panel shows your identity and you can add remote databases.</p></body></html> + + + + + Current Database + + + + + Clone + + + + + User + КориÑтувачем + + + + Database + + + + + Branch + + + + + Commits + + + + + Commits for + + + + + <html><head/><body><p>You are currently using a built-in, read-only identity. For uploading your database, you need to configure and use your DBHub.io account.</p><p>No DBHub.io account yet? <a href="https://dbhub.io/"><span style=" text-decoration: underline; color:#007af4;">Create one now</span></a> and import your certificate <a href="#preferences"><span style=" text-decoration: underline; color:#007af4;">here</span></a> to share your databases.</p><p>For online help visit <a href="https://dbhub.io/about"><span style=" text-decoration: underline; color:#007af4;">here</span></a>.</p></body></html> + + + + + Back + + + + + Delete Database + + + + + Delete the local clone of this database + + + + + Open in Web Browser + + + + + Open the web page for the current database in your browser + + + + + Clone from Link + + + + + Use this to download a remote database for local editing using a URL as provided on the web page of the database. + + + + + Refresh + Оновити + + + + Reload all data and update the views + + + + + F5 + + + + + Clone Database + + + + + Open Database + + + + + Open the local copy of this database + + + + + Check out Commit + + + + + Download and open this specific commit + + + + + Check out Latest Commit + + + + + Check out the latest commit of the current branch + + + + + Save Revision to File + + + + + Saves the selected revision of the database to another file + + + + + Upload Database + + + + + Upload this database as a new commit + + + + + Select an identity to connect + + + + + Public + + + + + This downloads a database from a remote server for local editing. +Please enter the URL to clone from. You can generate this URL by +clicking the 'Clone Database in DB4S' button on the web page +of the database. + + + + + Invalid URL: The host name does not match the host name of the current identity. + + + + + Invalid URL: No branch name specified. + + + + + Invalid URL: No commit ID specified. + + + + + You have modified the local clone of the database. Fetching this commit overrides these local changes. +Are you sure you want to proceed? + + + + + The database has unsaved changes. Are you sure you want to push it before saving? + + + + + The database you are trying to delete is currently opened. Please close it before deleting. + + + + + This deletes the local version of this database with all the changes you have not committed yet. Are you sure you want to delete this database? + + + + + RemoteLocalFilesModel + + + Name + Ім'Ñ + + + + Branch + + + + + Last modified + ВоÑтаннє змінений + + + + Size + Розмір + + + + Commit + + + + + File + + + + + RemoteModel + + + Name + Ім'Ñ + + + + Last modified + ВоÑтаннє змінений + + + + Size + Розмір + + + + Commit + + + + + Size: + + + + + Last Modified: + + + + + Licence: + + + + + Default Branch: + + + + + RemoteNetwork + + + Choose a location to save the file + + + + + Error opening remote file at %1. +%2 + Помилка під Ñ‡Ð°Ñ Ð²Ñ–Ð´ÐºÑ€Ð¸Ð²Ð°Ð½Ð½Ñ Ð²Ñ–Ð´Ð´Ð°Ð»ÐµÐ½Ð¾Ð³Ð¾ файлу %1. +%2 + + + + Error: Invalid client certificate specified. + Помилка: Вказано неправильний Ñертифікат клієнта. + + + + Please enter the passphrase for this client certificate in order to authenticate. + Будь лаÑка, введіть парольну фразу Ð´Ð»Ñ Ñ†ÑŒÐ¾Ð³Ð¾ Ñертифіката клієнта, Ð´Ð»Ñ Ð°Ð²Ñ‚ÐµÐ½Ñ‚Ð¸Ñ„Ñ–ÐºÐ°Ñ†Ñ–Ñ— + + + + Cancel + + + + + Uploading remote database to +%1 + Ð’Ð¸Ð²Ð°Ð½Ñ‚Ð°Ð¶ÐµÐ½Ð½Ñ Ð²Ñ–Ð´Ð´Ð°Ð»ÐµÐ½Ð¾Ñ— бази даних до +%1. {1?} + + + + Downloading remote database from +%1 + Ð—Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶ÐµÐ½Ð½Ñ Ð²Ñ–Ð´Ð´Ð°Ð»ÐµÐ½Ð¾Ñ— бази даних із +%1. {1?} + + + + + Error: The network is not accessible. + Помилка: Мережа не доÑтупна. + + + + Error: Cannot open the file for sending. + Помилка: Ðеможливо відкрити файл Ð´Ð»Ñ Ð²Ñ–Ð´Ð¿Ñ€Ð°Ð²Ð»ÐµÐ½Ð½Ñ. + + + + RemotePushDialog + + + Push database + + + + + Database na&me to push to + + + + + Commit message + + + + + Database licence + + + + + Public + + + + + Branch + + + + + Force push + + + + + Username + + + + + Database will be public. Everyone has read access to it. + + + + + Database will be private. Only you have access to it. + + + + + Use with care. This can cause remote commits to be deleted. + + + + + RunSql + + + Execution aborted by user + Ð’Ð¸ÐºÐ¾Ð½Ð°Ð½Ð½Ñ ÑкаÑовано кориÑтувачем + + + + , %1 rows affected + , %1 Ñ€Ñдків поÑтраждало + + + + query executed successfully. Took %1ms%2 + + + + + executing query + + + + + SelectItemsPopup + + + A&vailable + + + + + Sele&cted + + + + + SqlExecutionArea + + + Form + Форма + + + + Find previous match [Shift+F3] + + + + + Find previous match with wrapping + + + + + Shift+F3 + + + + + The found pattern must be a whole word + + + + + Whole Words + + + + + Text pattern to find considering the checks in this frame + + + + + Find in editor + + + + + The found pattern must match in letter case + + + + + Case Sensitive + + + + + Find next match [Enter, F3] + + + + + Find next match with wrapping + + + + + F3 + + + + + Interpret search pattern as a regular expression + + + + + <html><head/><body><p>When checked, the pattern to find is interpreted as a UNIX regular expression. See <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>.</p></body></html> + + + + + Regular Expression + + + + + + Close Find Bar + + + + + <html><head/><body><p>Results of the last executed statements.</p><p>You may want to collapse this panel and use the <span style=" font-style:italic;">SQL Log</span> dock with <span style=" font-style:italic;">User</span> selection instead.</p></body></html> + + + + + Results of the last executed statements + Результати оÑтанніх виконаних операторів + + + + This field shows the results and status codes of the last executed statements. + Це поле показує результати та коди ÑтатуÑів оÑтанніх виконаних операторів. + + + + Couldn't read file: %1. + Ðеможливо прочитати файл: %1. + + + + + Couldn't save file: %1. + Ðеможливо зберегти файл: %1. + + + + Your changes will be lost when reloading it! + + + + + The file "%1" was modified by another program. Do you want to reload it?%2 + + + + + SqlTextEdit + + + Ctrl+/ + + + + + SqlUiLexer + + + (X) The abs(X) function returns the absolute value of the numeric argument X. + (X) Ð¤ÑƒÐ½ÐºÑ†Ñ–Ñ abs(X) повертає модуль чиÑла аргументу X. + + + + () The changes() function returns the number of database rows that were changed or inserted or deleted by the most recently completed INSERT, DELETE, or UPDATE statement. + () Ð¤ÑƒÐ½ÐºÑ†Ñ–Ñ changes() повертає кількіÑть Ñ€Ñдків у базі даних, Ñкі було змінено, вÑтавлено або видалено піÑÐ»Ñ Ð²Ð´Ð°Ð»Ð¾Ð³Ð¾ Ð²Ð¸ÐºÐ¾Ð½Ð°Ð½Ð½Ñ INSERT, DELETE або UPDATE. + + + + (X,Y,...) The coalesce() function returns a copy of its first non-NULL argument, or NULL if all arguments are NULL + (X,Y,...) Ð¤ÑƒÐ½ÐºÑ†Ñ–Ñ coalesce() повертає копію першого аргументу не-NULL, Ñкщо такого немає, то повертає NULL + + + + (X,Y) The ifnull() function returns a copy of its first non-NULL argument, or NULL if both arguments are NULL. + (X,Y) Ð¤ÑƒÐ½ÐºÑ†Ñ–Ñ ifnull() повертає копію першого аргументу не-NULL, або Ñкщо обидва аргумента NULL, то повертає NULL. + + + + (X,Y) The instr(X,Y) function finds the first occurrence of string Y within string X and returns the number of prior characters plus 1, or 0 if Y is nowhere found within X. + (X,Y) Ð¤ÑƒÐ½ÐºÑ†Ñ–Ñ instr(X,Y) повертає кількіÑть Ñимволів, починаючи з Ñкого в Ñ€Ñдку X знайдено підрÑдок Y, або 0, Ñкщо такого не знайдено. + + + + (X) The hex() function interprets its argument as a BLOB and returns a string which is the upper-case hexadecimal rendering of the content of that blob. + (X) Ð¤ÑƒÐ½ÐºÑ†Ñ–Ñ hex() інтерпретує аргумент Ñк BLOB Ñ– повертає Ñ€Ñдок в 16-ричній ÑиÑтемі чиÑÐ»ÐµÐ½Ð½Ñ Ñ–Ð· вміÑтом аргументу. + + + + () The last_insert_rowid() function returns the ROWID of the last row insert from the database connection which invoked the function. + () Ð¤ÑƒÐ½ÐºÑ†Ñ–Ñ last_insert_rowid() повертає ROWID оÑтаннього вÑтавленого Ñ€Ñдка. + + + + (X) For a string value X, the length(X) function returns the number of characters (not bytes) in X prior to the first NUL character. + (X) Ð”Ð»Ñ Ñтрокового Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ X, Ñ„ÑƒÐ½ÐºÑ†Ñ–Ñ length(X) повертає кількіÑть Ñимволів (ÐЕ байтів) від початку Ñ€Ñдка до першого Ñимволу '\0'. + + + + (X,Y) The like() function is used to implement the "Y LIKE X" expression. + (X,Y) Ñ„ÑƒÐºÐ½Ñ†Ñ–Ñ like() еквівалентна виразу "Y LIKE X". + + + + (X,Y,Z) The like() function is used to implement the "Y LIKE X ESCAPE Z" expression. + (X,Y,Z) Ð¤ÑƒÐ½ÐºÑ†Ñ–Ñ like() еквівалент Ð²Ð¸Ñ€Ð°Ð¶ÐµÐ½Ð½Ñ "Y LIKE X ESCAPE Z". + + + + (X) The lower(X) function returns a copy of string X with all ASCII characters converted to lower case. + (X) Ð¤ÑƒÐ½ÐºÑ†Ñ–Ñ lower(X) повертає копію Ñ€Ñдка X, в Ñкій уÑÑ– ACSII Ñимволи переведені в нижній регіÑтр. + + + + (X) ltrim(X) removes spaces from the left side of X. + (X) ltrim(X) видалÑÑ” Ñимволи пробілів зліва Ð´Ð»Ñ Ñ€Ñдка X. + + + + (X1,X2,...) The char(X1,X2,...,XN) function returns a string composed of characters having the unicode code point values of integers X1 through XN, respectively. + (X1,X2,...) Ð¤ÑƒÐ½ÐºÑ†Ñ–Ñ char(X1,X2,...,XN) повертає Ñ€Ñдок, Ñкладений із Ñимволів, переданих Ñк аргументи. + + + + (X,Y) The glob(X,Y) function is equivalent to the expression "Y GLOB X". + (X,Y) Ñ„ÑƒÐ½ÐºÑ†Ñ–Ñ glob(X,Y) еквівалент Ð²Ð¸Ñ€Ð°Ð¶ÐµÐ½Ð½Ñ "Y GLOB X". + + + + (X) The load_extension(X) function loads SQLite extensions out of the shared library file named X. +Use of this function must be authorized from Preferences. + + + + + (X,Y) The load_extension(X) function loads SQLite extensions out of the shared library file named X using the entry point Y. +Use of this function must be authorized from Preferences. + + + + + (X,Y) The ltrim(X,Y) function returns a string formed by removing any and all characters that appear in Y from the left side of X. + (X,Y) Ð¤ÑƒÐ½ÐºÑ†Ñ–Ñ ltrim (X,Y) повертає новий Ñ€Ñдок шлÑхом Ð²Ð¸Ð´Ð°Ð»ÐµÐ½Ð½Ñ Ð· Ñ€Ñдка X зліва будь-Ñкого Ñимволу з Y. + + + + (X,Y,...) The multi-argument max() function returns the argument with the maximum value, or return NULL if any argument is NULL. + (X,Y,...) Ð¤ÑƒÐ½ÐºÑ†Ñ–Ñ max() повертає аргумент з макÑимальним значеннÑм, або NULL, Ñкщо хоча б один аргумент дорівнює NULL. + + + + (X,Y,...) The multi-argument min() function returns the argument with the minimum value. + (X,Y,...) Ð¤ÑƒÐ½ÐºÑ†Ñ–Ñ min() повертає аргумент з мінімальним значеннÑм. + + + + (X,Y) The nullif(X,Y) function returns its first argument if the arguments are different and NULL if the arguments are the same. + (X,Y) Ð¤ÑƒÐ½ÐºÑ†Ñ–Ñ nullif(X,Y) повертає перший аргумент, Ñкщо аргументи різні, або NULL, Ñкщо вони однакові. + + + + (FORMAT,...) The printf(FORMAT,...) SQL function works like the sqlite3_mprintf() C-language function and the printf() function from the standard C library. + (FORMAT,...) Ð¤ÑƒÐ½ÐºÑ†Ñ–Ñ printf(FORMAT,...) працює так Ñамо, Ñк printf() зі Ñтандартної бібліотеки мови Ð¿Ñ€Ð¾Ð³Ñ€Ð°Ð¼ÑƒÐ²Ð°Ð½Ð½Ñ Ð¡Ñ–. + + + + (X) The quote(X) function returns the text of an SQL literal which is the value of its argument suitable for inclusion into an SQL statement. + (X) Ð¤ÑƒÐ½ÐºÑ†Ñ–Ñ quote(X) повертає змінений Ñ€Ñдок X, Ñкий можна викориÑтовувати в SQL виразах. + + + + () The random() function returns a pseudo-random integer between -9223372036854775808 and +9223372036854775807. + () Ð¤ÑƒÐ½ÐºÑ†Ñ–Ñ random() повертає пÑевдовипадкове цілочиÑельне Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ð· діапозона від -9223372036854775808 до +9223372036854775807. + + + + (N) The randomblob(N) function return an N-byte blob containing pseudo-random bytes. + (N) Ð¤ÑƒÐ½ÐºÑ†Ñ–Ñ randomblob(N) повертає N-байтний BLOB, що міÑтить пÑевдовипадкові байти. + + + + (X,Y,Z) The replace(X,Y,Z) function returns a string formed by substituting string Z for every occurrence of string Y in string X. + (X,Y,Z) Ð¤ÑƒÐ½ÐºÑ†Ñ–Ñ replace(X,Y,Z) повертає новий Ñ€Ñдок на оÑнові Ñ€Ñдка X, заміною вÑÑ–Ñ… підрÑдків Y на Z. + + + + (X) The round(X) function returns a floating-point value X rounded to zero digits to the right of the decimal point. + (X) Ð¤ÑƒÐ½ÐºÑ†Ñ–Ñ round(X) округлює X до цілого значеннÑ. + + + + (X,Y) The round(X,Y) function returns a floating-point value X rounded to Y digits to the right of the decimal point. + (X,Y) Ð¤ÑƒÐ½ÐºÑ†Ñ–Ñ round(X,Y) округлює X до Y чиÑел піÑÐ»Ñ ÐºÐ¾Ð¼Ð¸ праворуч. + + + + (X) rtrim(X) removes spaces from the right side of X. + (X) rtrim(X) видалÑÑ” Ñимволи пробілу праворуч від Ñ€Ñдка X. + + + + (X,Y) The rtrim(X,Y) function returns a string formed by removing any and all characters that appear in Y from the right side of X. + (X,Y) Ð¤ÑƒÐ½ÐºÑ†Ñ–Ñ rtrim(X,Y) повертає новий Ñ€Ñдок шлÑхом Ð²Ð¸Ð´Ð°Ð»ÐµÐ½Ð½Ñ Ð· Ñ€Ñдка X праворуч будь-Ñкого Ñимволу з Ñ€Ñдка Y. + + + + + + + (timestring,modifier,modifier,...) + (timestring,modifier,modifier,...) + + + + (format,timestring,modifier,modifier,...) + (format,timestring,modifier,modifier,...) + + + + () The number of the row within the current partition. Rows are numbered starting from 1 in the order defined by the ORDER BY clause in the window definition, or in arbitrary order otherwise. + + + + + () The row_number() of the first peer in each group - the rank of the current row with gaps. If there is no ORDER BY clause, then all rows are considered peers and this function always returns 1. + + + + + () The number of the current row's peer group within its partition - the rank of the current row without gaps. Partitions are numbered starting from 1 in the order defined by the ORDER BY clause in the window definition. If there is no ORDER BY clause, then all rows are considered peers and this function always returns 1. + + + + + () Despite the name, this function always returns a value between 0.0 and 1.0 equal to (rank - 1)/(partition-rows - 1), where rank is the value returned by built-in window function rank() and partition-rows is the total number of rows in the partition. If the partition contains only one row, this function returns 0.0. + + + + + () The cumulative distribution. Calculated as row-number/partition-rows, where row-number is the value returned by row_number() for the last peer in the group and partition-rows the number of rows in the partition. + + + + + (N) Argument N is handled as an integer. This function divides the partition into N groups as evenly as possible and assigns an integer between 1 and N to each group, in the order defined by the ORDER BY clause, or in arbitrary order otherwise. If necessary, larger groups occur first. This function returns the integer value assigned to the group that the current row is a part of. + + + + + (expr) Returns the result of evaluating expression expr against the previous row in the partition. Or, if there is no previous row (because the current row is the first), NULL. + + + + + (expr,offset) If the offset argument is provided, then it must be a non-negative integer. In this case the value returned is the result of evaluating expr against the row offset rows before the current row within the partition. If offset is 0, then expr is evaluated against the current row. If there is no row offset rows before the current row, NULL is returned. + + + + + + (expr,offset,default) If default is also provided, then it is returned instead of NULL if the row identified by offset does not exist. + + + + + (expr) Returns the result of evaluating expression expr against the next row in the partition. Or, if there is no next row (because the current row is the last), NULL. + + + + + (expr,offset) If the offset argument is provided, then it must be a non-negative integer. In this case the value returned is the result of evaluating expr against the row offset rows after the current row within the partition. If offset is 0, then expr is evaluated against the current row. If there is no row offset rows after the current row, NULL is returned. + + + + + (expr) This built-in window function calculates the window frame for each row in the same way as an aggregate window function. It returns the value of expr evaluated against the first row in the window frame for each row. + + + + + (expr) This built-in window function calculates the window frame for each row in the same way as an aggregate window function. It returns the value of expr evaluated against the last row in the window frame for each row. + + + + + (expr,N) This built-in window function calculates the window frame for each row in the same way as an aggregate window function. It returns the value of expr evaluated against the row N of the window frame. Rows are numbered within the window frame starting from 1 in the order defined by the ORDER BY clause if one is present, or in arbitrary order otherwise. If there is no Nth row in the partition, then NULL is returned. + + + + + (X) The soundex(X) function returns a string that is the soundex encoding of the string X. + (X) Ð¤ÑƒÐ½ÐºÑ†Ñ–Ñ soundex(X) повертає копію Ñ€Ñдка X, кодовану в форматі soundex. + + + + (X,Y) substr(X,Y) returns all characters through the end of the string X beginning with the Y-th. + (X,Y) substr(X,Y) повертає підрÑдок з Ñ€Ñдка X, починаючи з Y-го Ñимволу. + + + + (X,Y,Z) The substr(X,Y,Z) function returns a substring of input string X that begins with the Y-th character and which is Z characters long. + (X,Y,Z) Ð¤ÑƒÐ½ÐºÑ†Ñ–Ñ substr(X,Y,Z) повертає підрÑдок з Ñ€Ñдка X, починаючи з Y-го Ñимволу, завдовжки Z-Ñимволів. + + + + () The total_changes() function returns the number of row changes caused by INSERT, UPDATE or DELETE statements since the current database connection was opened. + () Ð¤ÑƒÐ½ÐºÑ†Ñ–Ñ total_changes() повертає кількіÑть Ñ€Ñдків, змінених за допомогою INSERT, UPDATE або DELETE, починаючи з того моменту, коли під'Ñ”Ð´Ð½Ð°Ð½Ð½Ñ Ð´Ð¾ бази даних було відкрито. + + + + (X) trim(X) removes spaces from both ends of X. + (X) trim(X) видалÑÑ” пробіли з обох Ñторін Ñ€Ñдка X. + + + + (X,Y) The trim(X,Y) function returns a string formed by removing any and all characters that appear in Y from both ends of X. + (X,Y) Ð¤ÑƒÐ½ÐºÑ†Ñ–Ñ trim(X,Y) Ñтворює новий Ñ€Ñдок з X шлÑхом Ð²Ð¸Ð´Ð°Ð»ÐµÐ½Ð½Ñ Ð· обох кінців Ñимволів, Ñкі приÑутні в Ñ€Ñдку Y. + + + + (X) The typeof(X) function returns a string that indicates the datatype of the expression X. + (X) Ð¤ÑƒÐ½ÐºÑ†Ñ–Ñ typeof(X) повертає Ñ€Ñдок із типом даних Ð²Ð¸Ñ€Ð°Ð¶ÐµÐ½Ð½Ñ X. + + + + (X) The unicode(X) function returns the numeric unicode code point corresponding to the first character of the string X. + (X) Ð¤ÑƒÐ½ÐºÑ†Ñ–Ñ unicode(X) повертає чиÑлове Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ UNICODE коду Ñимволу. + + + + (X) The upper(X) function returns a copy of input string X in which all lower-case ASCII characters are converted to their upper-case equivalent. + (X) Ð¤ÑƒÐ½ÐºÑ†Ñ–Ñ upper(X) повертає копію Ñ€Ñдка X, в Ñкій Ð´Ð»Ñ ÐºÐ¾Ð¶Ð½Ð¾Ð³Ð¾ ASCII Ñимволу регіÑтр буде перетворений з нижнього у верхній. + + + + (N) The zeroblob(N) function returns a BLOB consisting of N bytes of 0x00. + (N) Ð¤ÑƒÐ½ÐºÑ†Ñ–Ñ zeroblob(N) повертає BLOB розміром N байт зі значеннÑми 0x00. + + + + (X) The avg() function returns the average value of all non-NULL X within a group. + (X) Ð¤ÑƒÐ½ÐºÑ†Ñ–Ñ avg() повертає Ñереднє Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ð´Ð»Ñ Ð²ÑÑ–Ñ… не-NULL значень групи. + + + + (X) The count(X) function returns a count of the number of times that X is not NULL in a group. + (X) Ð¤ÑƒÐ½ÐºÑ†Ñ–Ñ count(X) повертає кількіÑть Ñ€Ñдків, у Ñких X не-NULL у групі. + + + + (X) The group_concat() function returns a string which is the concatenation of all non-NULL values of X. + (X) Ð¤ÑƒÐ½ÐºÑ†Ñ–Ñ group_concat() повертає Ñ€Ñдок з уÑÑ–Ñ… значень X не-NULL. + + + + (X,Y) The group_concat() function returns a string which is the concatenation of all non-NULL values of X. If parameter Y is present then it is used as the separator between instances of X. + (X,Y) Ð¤ÑƒÐ½ÐºÑ†Ñ–Ñ group_concat() повертає Ñ€Ñдок з уÑÑ–Ñ… значень X не-NULL. Y - роздільник між значеннÑми X. + + + + (X) The max() aggregate function returns the maximum value of all values in the group. + (X) Ðгрегатна Ñ„ÑƒÐ½ÐºÑ†Ñ–Ñ max() повертає макÑимальне Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ð´Ð»Ñ X. + + + + (X) The min() aggregate function returns the minimum non-NULL value of all values in the group. + (X) Ðгрегатна Ñ„ÑƒÐ½ÐºÑ†Ñ–Ñ min() повертає мінімальне не-NULL Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ð´Ð»Ñ X. + + + + + (X) The sum() and total() aggregate functions return sum of all non-NULL values in the group. + (X) Ðгрегатні функції sum() Ñ– total() повертають Ñуму вÑÑ–Ñ… не-NULL значень Ð´Ð»Ñ X. + + + + SqliteTableModel + + + reading rows + + + + + loading... + + + + + References %1(%2) +Hold %3Shift and click to jump there + + + + + Error changing data: +%1 + Помилка зміни даних: +%1 + + + + retrieving list of columns + + + + + Fetching data... + + + + + + Cancel + + + + + TableBrowser + + + Browse Data + ПереглÑнути дані + + + + &Table: + &ТаблицÑ: + + + + Select a table to browse data + Оберіть таблицю Ð´Ð»Ñ Ð¿ÐµÑ€ÐµÐ³Ð»Ñду даних + + + + Use this list to select a table to be displayed in the database view + ВикориÑтовуйте цей ÑпиÑок, щоб вибрати таблицю, Ñку буде показано в переглÑдачі баз даних + + + + This is the database table view. You can do the following actions: + - Start writing for editing inline the value. + - Double-click any record to edit its contents in the cell editor window. + - Alt+Del for deleting the cell content to NULL. + - Ctrl+" for duplicating the current record. + - Ctrl+' for copying the value from the cell above. + - Standard selection and copy/paste operations. + + + + + Text pattern to find considering the checks in this frame + + + + + Find in table + + + + + Find previous match [Shift+F3] + + + + + Find previous match with wrapping + + + + + Shift+F3 + + + + + Find next match [Enter, F3] + + + + + Find next match with wrapping + + + + + F3 + + + + + The found pattern must match in letter case + + + + + Case Sensitive + + + + + The found pattern must be a whole word + + + + + Whole Cell + + + + + Interpret search pattern as a regular expression + + + + + <html><head/><body><p>When checked, the pattern to find is interpreted as a UNIX regular expression. See <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>.</p></body></html> + + + + + Regular Expression + + + + + + Close Find Bar + + + + + Text to replace with + + + + + Replace with + + + + + Replace next match + + + + + + Replace + + + + + Replace all matches + + + + + Replace all + + + + + <html><head/><body><p>Scroll to the beginning</p></body></html> + <html><head/><body><p>Прокрутити на початок</p></body></html> + + + + <html><head/><body><p>Clicking this button navigates to the beginning in the table view above.</p></body></html> + <html><head/><body><p>ÐатиÑÐºÐ°Ð½Ð½Ñ Ñ†Ñ–Ñ”Ñ— кнопки переміщує до початку таблиці.</p></body></html> + + + + |< + |< + + + + Scroll one page upwards + + + + + <html><head/><body><p>Clicking this button navigates one page of records upwards in the table view above.</p></body></html> + + + + + < + < + + + + 0 - 0 of 0 + 0 - 0 з 0 + + + + Scroll one page downwards + + + + + <html><head/><body><p>Clicking this button navigates one page of records downwards in the table view above.</p></body></html> + + + + + > + > + + + + Scroll to the end + Прокрутити до ÐºÑ–Ð½Ñ†Ñ + + + + <html><head/><body><p>Clicking this button navigates up to the end in the table view above.</p></body></html> + + + + + >| + >| + + + + <html><head/><body><p>Click here to jump to the specified record</p></body></html> + <html><head/><body><p>ÐатиÑніть тут, щоб перейти до зазначеного запиÑу</p></body></html> + + + + <html><head/><body><p>This button is used to navigate to the record number specified in the Go to area.</p></body></html> + <html><head/><body><p>Ð¦Ñ ÐºÐ½Ð¾Ð¿ÐºÐ° викориÑтовуєтьÑÑ, щоб переміÑтитиÑÑ Ð´Ð¾ запиÑу, номер Ñкого зазначений в зоні Перейти до </p></body></html> + + + + Go to: + Перейти до: + + + + Enter record number to browse + Введіть номер запиÑу Ð´Ð»Ñ Ð¿ÐµÑ€ÐµÐ³Ð»Ñду + + + + Type a record number in this area and click the Go to: button to display the record in the database view + Ðадрукуйте номер запиÑу в цій зоні й натиÑніть кнопку Перейти до:, щоб показати Ð·Ð°Ð¿Ð¸Ñ Ñƒ базі даних + + + + 1 + 1 + + + + Show rowid column + Показати Ñтовпець rowid + + + + Toggle the visibility of the rowid column + Змінити видиміÑть ÑÑ‚Ð¾Ð²Ð¿Ñ†Ñ rowid + + + + Unlock view editing + Розблокувати Ñ€ÐµÐ´Ð°Ð³ÑƒÐ²Ð°Ð½Ð½Ñ Ð²Ð¸Ð³Ð»Ñду + + + + This unlocks the current view for editing. However, you will need appropriate triggers for editing. + Це розблоковує поточний виглÑд Ð´Ð»Ñ Ñ€ÐµÐ´Ð°Ð³ÑƒÐ²Ð°Ð½Ð½Ñ. Проте вам необхідно виділити тригери Ð´Ð»Ñ Ñ€ÐµÐ´Ð°Ð³ÑƒÐ²Ð°Ð½Ð½Ñ + + + + Edit display format + Формат показу + + + + Edit the display format of the data in this column + Ð ÐµÐ´Ð°Ð³ÑƒÐ²Ð°Ð½Ð½Ñ Ñ„Ð¾Ñ€Ð¼Ð°Ñ‚Ñƒ показу Ð´Ð»Ñ Ð´Ð°Ð½Ð¸Ñ… у цьому Ñтовпці + + + + + New Record + Додати Ð·Ð°Ð¿Ð¸Ñ + + + + + Insert a new record in the current table + Додати новий Ð·Ð°Ð¿Ð¸Ñ Ñƒ поточну таблицю + + + + <html><head/><body><p>This button creates a new record in the database. Hold the mouse button to open a pop-up menu of different options:</p><ul><li><span style=" font-weight:600;">New Record</span>: insert a new record with default values in the database.</li><li><span style=" font-weight:600;">Insert Values...</span>: open a dialog for entering values before they are inserted in the database. This allows to enter values acomplishing the different constraints. This dialog is also open if the <span style=" font-weight:600;">New Record</span> option fails due to these constraints.</li></ul></body></html> + + + + + + Delete Record + Видалити Ð·Ð°Ð¿Ð¸Ñ + + + + Delete the current record + Видалити поточний Ð·Ð°Ð¿Ð¸Ñ + + + + + This button deletes the record or records currently selected in the table + + + + + + Insert new record using default values in browsed table + + + + + Insert Values... + + + + + + Open a dialog for inserting values in a new record + + + + + Export to &CSV + ЕкÑпортувати в &CSV + + + + + Export the filtered data to CSV + + + + + This button exports the data of the browsed table as currently displayed (after filters, display formats and order column) as a CSV file. + + + + + Save as &view + Зберегти Ñк &виглÑд + + + + + Save the current filter, sort column and display formats as a view + + + + + This button saves the current setting of the browsed table (filters, display formats and order column) as an SQL view that you can later browse or use in SQL statements. + + + + + Save Table As... + + + + + + Save the table as currently displayed + + + + + <html><head/><body><p>This popup menu provides the following options applying to the currently browsed and filtered table:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Export to CSV: this option exports the data of the browsed table as currently displayed (after filters, display formats and order column) to a CSV file.</li><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Save as view: this option saves the current setting of the browsed table (filters, display formats and order column) as an SQL view that you can later browse or use in SQL statements.</li></ul></body></html> + + + + + Hide column(s) + + + + + Hide selected column(s) + + + + + Show all columns + + + + + Show all columns that were hidden + + + + + + Set encoding + ÐšÐ¾Ð´ÑƒÐ²Ð°Ð½Ð½Ñ + + + + Change the encoding of the text in the table cells + Змінити ÐºÐ¾Ð´ÑƒÐ²Ð°Ð½Ð½Ñ Ñ‚ÐµÐºÑту в цій комірці таблиці + + + + Set encoding for all tables + Ð’Ñтановити ÐºÐ¾Ð´ÑƒÐ²Ð°Ð½Ð½Ñ Ð´Ð»Ñ Ð²ÑÑ–Ñ… таблиць + + + + Change the default encoding assumed for all tables in the database + Змінити ÐºÐ¾Ð´ÑƒÐ²Ð°Ð½Ð½Ñ Ð·Ð° замовчуваннÑм Ð´Ð»Ñ Ð²ÑÑ–Ñ… таблиць у базі даних + + + + Clear Filters + + + + + Clear all filters + ОчиÑтити вÑÑ– фільтри + + + + + This button clears all the filters set in the header input fields for the currently browsed table. + + + + + Clear Sorting + + + + + Reset the order of rows to the default + + + + + + This button clears the sorting columns specified for the currently browsed table and returns to the default order. + + + + + Print + + + + + Print currently browsed table data + + + + + Print currently browsed table data. Print selection if more than one cell is selected. + + + + + Ctrl+P + + + + + Refresh + Оновити + + + + Refresh the data in the selected table + + + + + This button refreshes the data in the currently selected table. + Ð¦Ñ ÐºÐ½Ð¾Ð¿ÐºÐ° оновлює дані обраної на цей момент таблиці. + + + + F5 + + + + + Find in cells + + + + + Open the find tool bar which allows you to search for values in the table view below. + + + + + + Bold + Жирний + + + + Ctrl+B + + + + + + Italic + КурÑив + + + + + Underline + ПідкреÑÐ»ÐµÐ½Ð½Ñ + + + + Ctrl+U + + + + + + Align Right + + + + + + Align Left + + + + + + Center Horizontally + + + + + + Justify + + + + + + Edit Conditional Formats... + + + + + Edit conditional formats for the current column + + + + + Clear Format + + + + + Clear All Formats + + + + + + Clear all cell formatting from selected cells and all conditional formats from selected columns + + + + + + Font Color + + + + + + Background Color + + + + + Toggle Format Toolbar + + + + + Show/hide format toolbar + + + + + + This button shows or hides the formatting toolbar of the Data Browser + + + + + Select column + + + + + Ctrl+Space + + + + + Replace text in cells + + + + + Filter in any column + + + + + Ctrl+R + + + + + %n row(s) + + + + + + + + + , %n column(s) + + + + + + + + + . Sum: %1; Average: %2; Min: %3; Max: %4 + + + + + Conditional formats for "%1" + + + + + determining row count... + + + + + %1 - %2 of >= %3 + + + + + %1 - %2 of %3 + %1 - %2 з %3 + + + + Please enter a pseudo-primary key in order to enable editing on this view. This should be the name of a unique column in the view. + Будь лаÑка, введіть пÑевдо-первинний ключ Ð´Ð»Ñ Ð¼Ð¾Ð¶Ð»Ð¸Ð²Ð¾Ñті Ñ€ÐµÐ´Ð°Ð³ÑƒÐ²Ð°Ð½Ð½Ñ Ñƒ цьому виді. Це має бути Ñ–'Ð¼Ñ ÑƒÐ½Ñ–ÐºÐ°Ð»ÑŒÐ½Ð¾Ð³Ð¾ ÑÑ‚Ð¾Ð²Ð¿Ñ†Ñ Ñƒ виді + + + + Delete Records + + + + + Duplicate records + + + + + Duplicate record + Дублікат запиÑу + + + + Ctrl+" + + + + + Adjust rows to contents + + + + + Error deleting record: +%1 + Помилка Ð²Ð¸Ð´Ð°Ð»ÐµÐ½Ð½Ñ Ð·Ð°Ð¿Ð¸Ñу: +%1 + + + + Please select a record first + Будь лаÑка, Ñпочатку оберіть Ð·Ð°Ð¿Ð¸Ñ + + + + There is no filter set for this table. View will not be created. + + + + + Please choose a new encoding for all tables. + Оберіть нову ÑиÑтему ÐºÐ¾Ð´ÑƒÐ²Ð°Ð½Ð½Ñ Ð´Ð»Ñ Ð²ÑÑ–Ñ… таблиць. + + + + Please choose a new encoding for this table. + Оберіть нову ÑиÑтему ÐºÐ¾Ð´ÑƒÐ²Ð°Ð½Ð½Ñ Ð´Ð»Ñ Ñ†Ñ–Ñ”Ñ— таблиці. + + + + %1 +Leave the field empty for using the database encoding. + %1 +Залиште це поле порожнім Ñкщо хочете, щоб викориÑтовувалоÑÑ ÐºÐ¾Ð´ÑƒÐ²Ð°Ð½Ð½Ñ Ð·Ð° замовчуваннÑм. + + + + This encoding is either not valid or not supported. + ÐšÐ¾Ð´ÑƒÐ²Ð°Ð½Ð½Ñ Ð½ÐµÐ²Ñ–Ñ€Ð½Ðµ або не підтримуєтьÑÑ. + + + + %1 replacement(s) made. + + + + + VacuumDialog + + + Compact Database + Ð£Ñ‰Ñ–Ð»ÑŒÐ½ÐµÐ½Ð½Ñ Ð‘Ð” + Ð£Ñ‰Ñ–Ð»ÑŒÐ½ÐµÐ½Ð½Ñ Ð±Ð°Ð·Ð¸ даних + + + + Warning: Compacting the database will commit all of your changes. + + + + + Please select the databases to co&mpact: + + + + diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/translations/sqlb_zh.qm b/src/WBCLFZSystemModule/SqliteDBProcess/src/translations/sqlb_zh.qm new file mode 100644 index 0000000000000000000000000000000000000000..2cbe4ece3dec6b936e84c82863688c7946a7f520 GIT binary patch literal 146200 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 literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/translations/sqlb_zh.ts b/src/WBCLFZSystemModule/SqliteDBProcess/src/translations/sqlb_zh.ts new file mode 100644 index 0000000..8ac3fc0 --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/translations/sqlb_zh.ts @@ -0,0 +1,7008 @@ + + + + + AboutDialog + + + About DB Browser for SQLite + 关于 DB Browser for SQLite + + + + Version + 版本 + + + + <html><head/><body><p>DB Browser for SQLite is an open source, freeware visual tool used to create, design and edit SQLite database files.</p><p>It is bi-licensed under the Mozilla Public License Version 2, as well as the GNU General Public License Version 3 or later. You can modify or redistribute it under the conditions of these licenses.</p><p>See <a href="http://www.gnu.org/licenses/gpl.html">http://www.gnu.org/licenses/gpl.html</a> and <a href="https://www.mozilla.org/MPL/2.0/index.txt">https://www.mozilla.org/MPL/2.0/index.txt</a> for details.</p><p>For more information on this program please visit our website at: <a href="http://sqlitebrowser.org">http://sqlitebrowser.org</a></p><p><span style=" font-size:small;">This software uses the GPL/LGPL Qt Toolkit from </span><a href="http://qt-project.org/"><span style=" font-size:small;">http://qt-project.org/</span></a><span style=" font-size:small;"><br/>See </span><a href="http://qt-project.org/doc/qt-5/licensing.html"><span style=" font-size:small;">http://qt-project.org/doc/qt-5/licensing.html</span></a><span style=" font-size:small;"> for licensing terms and information.</span></p><p><span style=" font-size:small;">It also uses the Silk icon set by Mark James licensed under a Creative Commons Attribution 2.5 and 3.0 license.<br/>See </span><a href="http://www.famfamfam.com/lab/icons/silk/"><span style=" font-size:small;">http://www.famfamfam.com/lab/icons/silk/</span></a><span style=" font-size:small;"> for details.</span></p></body></html> + <html><head/><body><p>DB Browser for SQLite 是一个开æºå…费的å¯è§†åŒ–工具,用于创建ã€è®¾è®¡å’Œç¼–辑 SQLite æ•°æ®åº“文件。</p><p>它以第 2 版 Mozilla 公共许å¯ï¼Œä»¥åŠç¬¬ 3 版åŠä¹‹åŽç‰ˆæœ¬çš„ GNU é€šç”¨è®¸å¯æ–¹å¼æŽˆæƒã€‚ä½ å¯ä»¥åœ¨éµå¾ªè¿™äº›è®¸å¯çš„æ¡ä»¶ä¸‹ä¿®æ”¹æˆ–é‡æ–°å‘布它。</p><p>å‚阅 <a href="http://www.gnu.org/licenses/gpl.html">http://www.gnu.org/licenses/gpl.html</a> and <a href="https://www.mozilla.org/MPL/2.0/index.txt">https://www.mozilla.org/MPL/2.0/index.txt</a> 了解细节。</p><p>è¦èŽ·å¾—æœ¬ç¨‹åºçš„æ›´å¤šä¿¡æ¯ï¼Œè¯·è®¿é—®æˆ‘们的网站: <a href="http://sqlitebrowser.org">http://sqlitebrowser.org</a></p><p><span style=" font-size:small;">这个软件使用了æ¥è‡ªäºŽ </span><a href="http://qt-project.org/"><span style=" font-size:small;">http://qt-project.org/</span></a> <span style=" font-size:small;">çš„ GPL/LGPL Qt Toolkit。<br/>å‚阅 </span><a href="http://qt-project.org/doc/qt-5/licensing.html"><span style=" font-size:small;">http://qt-project.org/doc/qt-5/licensing.html</span></a><span style=" font-size:small;"> äº†è§£è®¸å¯æ¡æ¬¾å’Œå…¶ä»–ä¿¡æ¯ã€‚</span></p><p><span style=" font-size:small;">它还使用了 Mark James çš„ Silk 图标集,以第 2.5 å’Œ 3.0 版知识共享署å(CCA)è®¸å¯æ–¹å¼æŽˆæƒã€‚<br/>å‚阅 </span><a href="http://www.famfamfam.com/lab/icons/silk/"><span style=" font-size:small;">http://www.famfamfam.com/lab/icons/silk/</span></a><span style=" font-size:small;"> 了解细节。</span></p></body></html> + + + + AddRecordDialog + + + Add New Record + 新增记录 + + + + Enter values for the new record considering constraints. Fields in bold are mandatory. + 为新增的记录填写满足约æŸçš„值。加粗的字段必须填写。 + + + + In the Value column you can specify the value for the field identified in the Name column. The Type column indicates the type of the field. Default values are displayed in the same style as NULL values. + 在值列,你å¯ä»¥é€‰æ‹©ç»™å¯¹åº”å字列的值。类型列显示了字段的类型。默认值的显示样å¼å’Œ NULL 值一样。 + + + + Name + åç§° + + + + Type + 类型 + + + + Value + 值 + + + + Values to insert. Pre-filled default values are inserted automatically unless they are changed. + è¦æ’入的值。如果没有修改,就会æ’入事先填好的默认值。 + + + + When you edit the values in the upper frame, the SQL query for inserting this new record is shown here. You can edit manually the query before saving. + 当你在上é¢ç¼–辑值时,这里会显示æ’入新记录所用的 SQL 语å¥ã€‚ä½ å¯ä»¥åœ¨ä¿å­˜å‰æ‰‹åŠ¨ä¿®æ”¹è¿™äº›è¯­å¥ã€‚ + + + + <html><head/><body><p><span style=" font-weight:600;">Save</span> will submit the shown SQL statement to the database for inserting the new record.</p><p><span style=" font-weight:600;">Restore Defaults</span> will restore the initial values in the <span style=" font-weight:600;">Value</span> column.</p><p><span style=" font-weight:600;">Cancel</span> will close this dialog without executing the query.</p></body></html> + <html><head/><body><p><span style=" font-weight:600;">ä¿å­˜</span> 将会把显示的 SQL è¯­å¥æäº¤åˆ°æ•°æ®åº“以æ’入新记录。</p><p><span style=" font-weight:600;">æ¢å¤é»˜è®¤</span> 将会把 <span style=" font-weight:600;">值</span> æ¢å¤æˆé»˜è®¤å€¼ã€‚</p><p><span style=" font-weight:600;">å–æ¶ˆ</span> 将会关闭此界é¢ï¼Œä¸æ‰§è¡Œ SQL 语å¥ã€‚</p></body></html> + + + + Auto-increment + + 自增 + + + + + Unique constraint + + å”¯ä¸€çº¦æŸ + + + + + Check constraint: %1 + + 检查约æŸ: %1 + + + + + Foreign key: %1 + + 外键: %1 + + + + + Default value: %1 + + 默认值: %1 + + + + + Error adding record. Message from database engine: + +%1 + 添加记录失败。æ¥è‡ªæ•°æ®åº“引擎的消æ¯: + +%1 + + + + Are you sure you want to restore all the entered values to their defaults? + ä½ ç¡®å®šè¦æŠŠè¾“å…¥çš„æ‰€æœ‰å€¼éƒ½æ¢å¤æˆé»˜è®¤å€¼å—? + + + + Application + + + Possible command line arguments: + å¯ç”¨å‘½ä»¤è¡Œå‚æ•°: + + + + The -o/--option and -O/--save-option options require an argument in the form group/setting=value + -o/--option å’Œ -O/--save-option é€‰é¡¹éœ€è¦ group/setting=value æ ¼å¼çš„傿•° + + + + Usage: %1 [options] [<database>|<project>] + + 用法: %1 [选项] [<æ•°æ®åº“>|<项目>] + + + + + -h, --help Show command line options + -h, --help 显示命令行选项 + + + + -q, --quit Exit application after running scripts + -q, --quit 在è¿è¡Œè„šæœ¬åŽé€€å‡ºåº”ç”¨ç¨‹åº + + + + -s, --sql <file> Execute this SQL file after opening the DB + -s, --sql <文件> 在打开数æ®åº“åŽæ‰§è¡Œæ­¤ SQL 文件 + + + + -t, --table <table> Browse this table after opening the DB + -t, --table <表> 在打开数æ®åº“åŽæµè§ˆæ­¤è¡¨ + + + + -R, --read-only Open database in read-only mode + -R, --read-only 用åªè¯»æ¨¡å¼æ‰“开数æ®åº“ + + + + -o, --option <group>/<setting>=<value> + -o, --option <分组/设置=值> + + + + Run application with this setting temporarily set to value + 临时以此设置è¿è¡Œç¨‹åº + + + + -O, --save-option <group>/<setting>=<value> + -O, --save-option <分组/设置=值> + + + + Run application saving this value for this setting + 以此设置è¿è¡Œç¨‹åºå¹¶ä¿å­˜è®¾ç½® + + + + -v, --version Display the current version + -v, --version 显示当å‰ç‰ˆæœ¬ + + + + <database> Open this SQLite database + <文件> 打开这个 SQLite æ•°æ®åº“ + + + + <project> Open this project file (*.sqbpro) + <项目> 打开这个项目文件 (*.sqbpro) + + + + The -s/--sql option requires an argument + -s/--sql 选项需è¦ä¸€ä¸ªå‚æ•° + + + + The file %1 does not exist + 文件 %1 ä¸å­˜åœ¨ + + + + The -t/--table option requires an argument + -t/--table 选项需è¦ä¸€ä¸ªå‚æ•° + + + + Invalid option/non-existant file: %1 + 无效选项/ä¸å­˜åœ¨çš„æ–‡ä»¶: %1 + + + + SQLite Version + SQLite 版本 + + + + SQLCipher Version %1 (based on SQLite %2) + SQLCipher 版本 %1 (基于 SQLite %2) + + + + DB Browser for SQLite Version %1. + DB Browser for SQLite 版本 %1. + + + + Built for %1, running on %2 + 为 %1 构建,è¿è¡ŒäºŽ %2 + + + + Qt Version %1 + Qt 版本 %1 + + + + CipherDialog + + + SQLCipher encryption + SQLCipher 加密 + + + + &Password + 密ç (&P) + + + + &Reenter password + 确认密ç (&R) + + + + Encr&yption settings + 加密设置(&Y) + + + + SQLCipher &3 defaults + SQLCipher &3 默认 + + + + SQLCipher &4 defaults + SQLCipher &4 默认 + + + + Custo&m + 自定义(&M) + + + + Page si&ze + 页大å°(&Z) + + + + &KDF iterations + KDF迭代(&K) + + + + HMAC algorithm + HMAC算法 + + + + KDF algorithm + KDF算法 + + + + Plaintext Header Size + çº¯æ–‡æœ¬æ–‡ä»¶å¤´å¤§å° + + + + Passphrase + å£ä»¤ + + + + Raw key + 原始密钥 + + + + Please set a key to encrypt the database. +Note that if you change any of the other, optional, settings you'll need to re-enter them as well every time you open the database file. +Leave the password fields empty to disable the encryption. +The encryption process might take some time and you should have a backup copy of your database! Unsaved changes are applied before modifying the encryption. + 请设置密ç ä»¥åŠ å¯†æ•°æ®åº“。 +注æ„å¦‚æžœä¿®æ”¹äº†ä»»ä½•å…¶ä»–é€‰é¡¹è®¾ç½®ï¼Œä»¥åŠæ¯æ¬¡æ‰“开数æ®åº“时,您都需è¦é‡æ–°è¾“入此密ç ã€‚ +ä¸å¡«å¯†ç è¡¨ç¤ºç¦ç”¨åŠ å¯†ã€‚ +加密过程将花费一些时间,您应该在加密之å‰å¤‡ä»½æ•°æ®åº“ï¼ä¿®æ”¹åР坆å‰ï¼Œæœªä¿å­˜çš„æ›´æ”¹å°†ä¼šè¢«åº”用。 + + + + Please enter the key used to encrypt the database. +If any of the other settings were altered for this database file you need to provide this information as well. + 请输入加密数æ®åº“的密ç ã€‚ +如果此数æ®åº“的任何其他设置å‘生å˜åŒ–ï¼Œæ‚¨ä¹Ÿéœ€è¦æä¾›æ­¤ä¿¡æ¯ã€‚ + + + + ColumnDisplayFormatDialog + + + Choose display format + é€‰æ‹©æ˜¾ç¤ºæ ¼å¼ + + + + Display format + æ˜¾ç¤ºæ ¼å¼ + + + + Choose a display format for the column '%1' which is applied to each value prior to showing it. + 为列 '%1' 选择显示格å¼ï¼Œå°†åœ¨æ˜¾ç¤ºä¹‹å‰åº”用到值。 + + + + Default + 默认 + + + + Decimal number + å进制数 + + + + Exponent notation + 指数 + + + + Hex blob + å六进制大型对象 + + + + Hex number + å六进制数 + + + + Apple NSDate to date + 苹果 NSDate 到日期 + + + + Java epoch (milliseconds) to date + Java 时间戳(毫秒)到日期 + + + + .NET DateTime.Ticks to date + .NET 日期时间(Ticks到日期) + + + + Julian day to date + 儒略日 (Julian day) 到日期 + + + + Unix epoch to local time + Unix 时间戳到本地时间 + + + + Date as dd/mm/yyyy + 日期,格å¼ä¸º dd/mm/yyyy + + + + Lower case + å°å†™ + + + + Custom display format must contain a function call applied to %1 + 自定义显示格å¼å¿…须包å«å¤„ç† %1 的函数 + + + + Error in custom display format. Message from database engine: + +%1 + è‡ªå®šä¹‰æ˜¾ç¤ºæ ¼å¼æœ‰è¯¯ã€‚æ•°æ®åº“引擎æä¾›çš„错误信æ¯ä¸ºï¼š\n\n%1 + + + + Custom display format must return only one column but it returned %1. + 自定义显示格å¼å¿…é¡»åªè¿”回1列,但目å‰è¿”回 %1 。 + + + + Octal number + 八进制数 + + + + Round number + å–æ•´æ•° + + + + Unix epoch to date + Unix 时间到日期 + + + + Upper case + 大写 + + + + Windows DATE to date + Windows 日期到日期 + + + + Custom + 自定义 + + + + CondFormatManager + + + Conditional Format Manager + æ¡ä»¶æ ¼å¼ç®¡ç†å™¨ + + + + This dialog allows creating and editing conditional formats. Each cell style will be selected by the first accomplished condition for that cell data. Conditional formats can be moved up and down, where those at higher rows take precedence over those at lower. Syntax for conditions is the same as for filters and an empty condition applies to all values. + æ­¤å¯¹è¯æ¡†ç”¨äºŽåˆ›å»ºå’Œç¼–辑æ¡ä»¶æ ¼å¼ã€‚æ¯ä¸ªå•元格的样å¼å°†è¢«è®¾ç½®ä¸ºé¦–ä¸ªåŒ¹é…æ¡ä»¶çš„æ ¼å¼ã€‚æ¡ä»¶æ ¼å¼å¯ä»¥ä¸Šä¸‹ç§»åŠ¨ï¼Œé å‰çš„行优先生效。æ¡ä»¶çš„语法与过滤器相åŒã€‚空æ¡ä»¶å°†é€‚用于所有值。 + + + + Add new conditional format + 创建新的æ¡ä»¶æ ¼å¼ + + + + &Add + 添加(&A) + + + + Remove selected conditional format + 删除选中的æ¡ä»¶æ ¼å¼ + + + + &Remove + 删除(&R) + + + + Move selected conditional format up + 上移选中的æ¡ä»¶æ ¼å¼ + + + + Move &up + 上移(&U) + + + + Move selected conditional format down + 下移选中的æ¡ä»¶æ ¼å¼ + + + + Move &down + 下移(&D) + + + + Foreground + 剿™¯ + + + + Text color + 文本颜色 + + + + Background + 背景 + + + + Background color + 背景颜色 + + + + Font + 字体 + + + + Size + å¤§å° + + + + Bold + 粗体 + + + + Italic + 斜体 + + + + Underline + 下划线 + + + + Alignment + å¯¹é½ + + + + Condition + æ¡ä»¶ + + + + + Click to select color + 点击选择颜色 + + + + Are you sure you want to clear all the conditional formats of this field? + ç¡®å®žè¦æ¸…除全部æ¡ä»¶æ ¼å¼å—? + + + + DBBrowserDB + + + Please specify the database name under which you want to access the attached database + 请指明想è¦é™„加的数æ®åº“å + + + + Invalid file format + æ— æ•ˆçš„æ–‡ä»¶æ ¼å¼ + + + + Do you want to save the changes made to the database file %1? + æ‚¨æ˜¯å¦æƒ³ä¿å­˜å¯¹æ•°æ®åº“文件 %1 åšå‡ºçš„æ›´æ”¹? + + + + Exporting database to SQL file... + 正在导出数æ®åº“到 SQL 文件... + + + + + Cancel + å–æ¶ˆ + + + + Executing SQL... + 正在执行 SQL... + + + + Action cancelled. + æ“ä½œå·²å–æ¶ˆã€‚ + + + + This database has already been attached. Its schema name is '%1'. + 此数æ®åº“å·²è¢«é™„åŠ ã€‚å®ƒçš„æž¶æž„åæ˜¯ '%1'. + + + + Do you really want to close this temporary database? All data will be lost. + 你确定è¦å…³é—­æ­¤ä¸´æ—¶æ•°æ®åº“å—?所有数æ®éƒ½ä¼šä¸¢å¤±ã€‚ + + + + Database didn't close correctly, probably still busy + æ•°æ®åº“未正确关闭,å¯èƒ½æ­£å¿™ + + + + The database is currently busy: + æ•°æ®åº“正忙: + + + + Do you want to abort that other operation? + ç¡®å®šè¦æ”¾å¼ƒæ“作å—? + + + + + No database file opened + 没有打开数æ®åº“文件 + + + + + Error in statement #%1: %2. +Aborting execution%3. + é”™è¯¯åœ¨è¯­å¥ #%1: %2. +正在放弃执行%3. + + + + + and rolling back + 并回滚 + + + + didn't receive any output from %1 + 未收到æ¥è‡ª %1 的任何输出 + + + + could not execute command: %1 + 未能执行命令: %1 + + + + Cannot delete this object + 无法删除此对象 + + + + Cannot set data on this object + ä¸èƒ½ä¸ºæ­¤æ•°æ®è®¾ç½®å¯¹è±¡ + + + + + A table with the name '%1' already exists in schema '%2'. + 一个与 '%1' åŒå的表已ç»å­˜åœ¨äºŽæž¶æž„ '%2' 中。 + + + + No table with name '%1' exists in schema '%2'. + æž¶æž„ '%2' 中ä¸å­˜åœ¨è¡¨ '%1' 。 + + + + + Cannot find column %1. + 找ä¸åˆ°åˆ— %1 。 + + + + Creating savepoint failed. DB says: %1 + 创建ä¿å­˜ç‚¹å¤±è´¥ã€‚æ•°æ®åº“显示:%1 + + + + Renaming the column failed. DB says: +%1 + é‡å‘½å列失败。数æ®åº“显示:\n%1 + + + + + Releasing savepoint failed. DB says: %1 + 释放ä¿å­˜ç‚¹å¤±è´¥ã€‚æ•°æ®åº“显示:%1 + + + + Creating new table failed. DB says: %1 + 建立新表失败。数æ®åº“显示:%1 + + + + Copying data to new table failed. DB says: +%1 + å¤åˆ¶æ•°æ®åˆ°æ–°è¡¨å¤±è´¥ã€‚æ•°æ®åº“显示:\n%1 + + + + Deleting old table failed. DB says: %1 + 删除旧表失败。数æ®åº“显示:%1 + + + + Error renaming table '%1' to '%2'. +Message from database engine: +%3 + 将表 '%1' é‡å‘½å为 '%2' 时出错。\næ•°æ®åº“引擎的错误信æ¯ï¼š\n%1 + + + + could not get list of db objects: %1 + æœªèƒ½èŽ·å–æ•°æ®åº“对象列表:%1 + + + + Restoring some of the objects associated with this table failed. This is most likely because some column names changed. Here's the SQL statement which you might want to fix and execute manually: + + + 还原æŸäº›å’Œè¿™ä¸ªè¡¨å…³è”的对象失败。这个最å¯èƒ½æ˜¯å› ä¸ºæŸäº›åˆ—çš„å称更改了。这里是您å¯èƒ½éœ€è¦æ‰‹åŠ¨ä¿®å¤å’Œæ‰§è¡Œçš„ SQL 语å¥: + + + + + + could not get list of databases: %1 + æ— æ³•èŽ·å–æ•°æ®åº“列表: %1 + + + + Error loading extension: %1 + 加载扩展时出错: %1 + + + + could not get column information + 无法获å–åˆ—ä¿¡æ¯ + + + + Error setting pragma %1 to %2: %3 + è®¾ç½®æ‚æ³¨ %1 为 %2 时出错: %3 + + + + File not found. + 文件找ä¸åˆ°ã€‚ + + + + DbStructureModel + + + Name + åç§° + + + + Object + 对象 + + + + Type + 类型 + + + + Schema + æž¶æž„ + + + + Database + æ•°æ®åº“ + + + + Browsables + 坿µè§ˆçš„ + + + + All + 所有 + + + + Temporary + 临时的 + + + + Tables (%1) + 表 (%1) + + + + Indices (%1) + 索引 (%1) + + + + Views (%1) + 视图 (%1) + + + + Triggers (%1) + 触å‘器 (%1) + + + + EditDialog + + + Edit database cell + 编辑数æ®åº“å•元格 + + + + Mode: + 模å¼: + + + + + Image + å›¾åƒ + + + + Set as &NULL + 设为&空 + + + + Apply data to cell + 将数æ®åº”用到å•元格 + + + + This button saves the changes performed in the cell editor to the database cell. + 此按钮把å•元格编辑器中的修改应用到数æ®åº“å•元格中。 + + + + Apply + 应用 + + + + Text + 文本 + + + + This is the list of supported modes for the cell editor. Choose a mode for viewing or editing the data of the current cell. + 这是å•元格编辑器支æŒçš„æ¨¡å¼åˆ—è¡¨ã€‚é€‰æ‹©ä¸€ç§æ¨¡å¼ä»¥æŸ¥çœ‹æˆ–编辑当å‰å•元格的数æ®ã€‚ + + + + RTL Text + å³åˆ°å·¦æ–‡æœ¬ + + + + Binary + 二进制 + + + + JSON + JSON + + + + XML + XML + + + + + Automatically adjust the editor mode to the loaded data type + 自动调整编辑器模å¼ä¸ºåŠ è½½çš„æ•°æ®çš„类型 + + + + This checkable button enables or disables the automatic switching of the editor mode. When a new cell is selected or new data is imported and the automatic switching is enabled, the mode adjusts to the detected data type. You can then change the editor mode manually. If you want to keep this manually switched mode while moving through the cells, switch the button off. + æ­¤å¤é€‰æŒ‰é’®å¯å¯ç”¨æˆ–ç¦ç”¨ç¼–辑器模å¼çš„自动切æ¢ã€‚当新å•元格被选中或新数æ®è¢«å¯¼å…¥æ—¶ï¼Œå¦‚æžœå¯ç”¨äº†è‡ªåŠ¨åˆ‡æ¢ï¼Œæ¨¡å¼ä¼šè°ƒæ•´ä¸ºæ£€æµ‹åˆ°çš„æ•°æ®ç±»åž‹ã€‚之åŽä½ ä¹Ÿæ‰‹åŠ¨åˆ‡æ¢ç¼–辑器的模å¼ã€‚如果你希望æµè§ˆå„å•å…ƒæ ¼çš„æ—¶å€™éƒ½ä¿æŒæ‰‹åŠ¨é€‰æ‹©çš„æ¨¡å¼ï¼Œè¯·æŠŠæ­¤æŒ‰é’®åˆ‡åˆ°å…³é—­çжæ€ã€‚ + + + + Auto-switch + è‡ªåŠ¨åˆ‡æ¢ + + + + The text editor modes let you edit plain text, as well as JSON or XML data with syntax highlighting, automatic formatting and validation before saving. + +Errors are indicated with a red squiggle underline. + 此文本编辑器å…许你编辑纯文本。还支æŒJSON或XMLæ ¼å¼çš„代ç é«˜äº®ï¼Œè‡ªåŠ¨æ ¼å¼åŒ–和验è¯ã€‚\n\næ ¼å¼é”™è¯¯ç”¨çº¢è‰²æ³¢æµªçº¿è¡¨ç¤ºã€‚ + + + + This Qt editor is used for right-to-left scripts, which are not supported by the default Text editor. The presence of right-to-left characters is detected and this editor mode is automatically selected. + æ­¤Qt编辑器用于å³åˆ°å·¦çš„æ–‡æœ¬ï¼ˆé»˜è®¤æ–‡æœ¬ç¼–è¾‘å™¨ä¸æ”¯æŒè¿™ç§æ ¼å¼ï¼‰ã€‚当检测到å³åˆ°å·¦å­—符时,会自动选择这ç§ç¼–辑器模å¼ã€‚ + + + + Open preview dialog for printing the data currently stored in the cell + 打å°é¢„览此å•å…ƒæ ¼ä¸­çš„æ•°æ® + + + + Auto-format: pretty print on loading, compact on saving. + 自动格å¼: è¯»å–æ—¶æ ¼å¼åŒ–,存储时紧凑化。 + + + + When enabled, the auto-format feature formats the data on loading, breaking the text in lines and indenting it for maximum readability. On data saving, the auto-format feature compacts the data removing end of lines, and unnecessary whitespace. + 当å¯ç”¨æ—¶ï¼Œè‡ªåŠ¨æ ¼å¼ç‰¹æ€§å°†åœ¨æ•°æ®åŠ è½½æ—¶æ ¼å¼åŒ–æ•°æ®ï¼Œå¢žåŠ æ¢è¡Œå¹¶ç¼©è¿›ä»¥æé«˜å¯è¯»æ€§ã€‚在ä¿å­˜æ•°æ®æ—¶ï¼Œè‡ªåŠ¨æ ¼å¼ç‰¹æ€§ä¼šé€šè¿‡åˆ é™¤æ¢è¡Œã€ä¸å¿…è¦çš„ç©ºç™½å­—ç¬¦çš„æ–¹å¼æ¥ç´§å‡‘化数æ®ã€‚ + + + + Word Wrap + 自动æ¢è¡Œ + + + + Wrap lines on word boundaries + 在å•è¯è¾¹ç•Œè‡ªåЍæ¢è¡Œ + + + + + Open in default application or browser + ç”¨é»˜è®¤ç¨‹åºæˆ–æµè§ˆå™¨æ‰“å¼€ + + + + Open in application + ç”¨å¤–éƒ¨ç¨‹åºæ‰“å¼€ + + + + The value is interpreted as a file or URL and opened in the default application or web browser. + å°†å•元格的值视为文件路径或URLï¼Œåœ¨é»˜è®¤ç¨‹åºæˆ–æµè§ˆå™¨ä¸­æ‰“开。 + + + + Save file reference... + ä¿ç•™æ–‡ä»¶å¼•用... + + + + Save reference to file + I'm not sure + 将引用ä¿å­˜åˆ°æ–‡ä»¶ + + + + + Open in external application + 在外部程åºä¸­ç¼–辑 + + + + Autoformat + è‡ªåŠ¨æ ¼å¼ + + + + &Export... + 导出(&E) + + + + + &Import... + 导入(&I) + + + + + Import from file + 从文件导入 + + + + + Opens a file dialog used to import any kind of data to this database cell. + æ‰“å¼€æ–‡ä»¶é€‰æ‹©å¯¹è¯æ¡†ï¼Œå¯¼å…¥ä»»ä½•类型的数æ®åˆ°æ­¤æ•°æ®åº“å•元格。 + + + + Export to file + 导出到文件 + + + + Opens a file dialog used to export the contents of this database cell to a file. + æ‰“å¼€æ–‡ä»¶é€‰æ‹©å¯¹è¯æ¡†ï¼Œå¯¼å‡ºæ­¤æ•°æ®åº“å•元格的内容到一个文件里。 + + + + Erases the contents of the cell + 删除å•元格的内容 + + + + This area displays information about the data present in this database cell + 这个区域显示存在于这个数æ®åº“å•元格中的数æ®çš„ç›¸å…³ä¿¡æ¯ + + + + Type of data currently in cell + 当å‰åœ¨å•元格中的数æ®çš„类型 + + + + Size of data currently in table + 当å‰åœ¨è¡¨ä¸­çš„æ•°æ®çš„å¤§å° + + + + + Print... + 打å°... + + + + Open preview dialog for printing displayed image + 打开打å°é¢„è§ˆå¯¹è¯æ¡†ï¼Œé¢„è§ˆå›¾åƒ + + + + + Ctrl+P + + + + + Open preview dialog for printing displayed text + 打开打å°é¢„è§ˆå¯¹è¯æ¡†ï¼Œé¢„览文本 + + + + Copy Hex and ASCII + æ‹·è´å六进制和 ASCII + + + + Copy selected hexadecimal and ASCII columns to the clipboard + æ‹·è´é€‰ä¸­çš„å六进制和 ASCII 列到剪贴æ¿ä¸­ + + + + Ctrl+Shift+C + + + + + Choose a filename to export data + 选择一个导出数æ®çš„æ–‡ä»¶å + + + + Type of data currently in cell: %1 Image + 当å‰åœ¨å•元格中的数æ®çš„类型: %1 å›¾åƒ + + + + %1x%2 pixel(s) + %1x%2 åƒç´  + + + + Type of data currently in cell: NULL + 当å‰åœ¨å•元格中的数æ®çš„类型: 空 + + + + + Type of data currently in cell: Text / Numeric + 当å‰åœ¨å•元格中的数æ®çš„类型: 文本/ 数值 + + + + + Image data can't be viewed in this mode. + 此模å¼ä¸‹æ— æ³•æŸ¥çœ‹å›¾åƒæ•°æ®ã€‚ + + + + + Try switching to Image or Binary mode. + å°è¯•切æ¢åˆ°å›¾åƒæˆ–二进制模å¼ã€‚ + + + + + Binary data can't be viewed in this mode. + 此模å¼ä¸‹æ— æ³•查看二进制数æ®ã€‚ + + + + + Try switching to Binary mode. + å°è¯•切æ¢åˆ°äºŒè¿›åˆ¶æ¨¡å¼ã€‚ + + + + Couldn't save file: %1. + + + + + The data has been saved to a temporary file and has been opened with the default application. You can now edit the file and, when you are ready, apply the saved new data to the cell editor or cancel any changes. + å•元格内数æ®å·²è¢«ä¿å­˜åˆ°ä¸´æ—¶æ–‡ä»¶å¹¶ç”¨é»˜è®¤ç¨‹åºæ‰“开。你å¯ä»¥ç¼–辑文件并ä¿å­˜ï¼Œç„¶åŽå°†æ›´æ”¹åº”用到å•元格。 + + + + + Image files (%1) + å›¾åƒæ–‡ä»¶ (%1) + + + + Binary files (*.bin) + 二进制文件 (*.bin) + + + + Choose a file to import + 选择一个è¦å¯¼å…¥çš„æ–‡ä»¶ + + + + %1 Image + %1 å›¾åƒ + + + + Invalid data for this mode + æ•°æ®å¯¹æ­¤æ¨¡å¼éžæ³• + + + + The cell contains invalid %1 data. Reason: %2. Do you really want to apply it to the cell? + å•元格中包å«éžæ³•çš„ %1 æ•°æ®ã€‚原因: %2. 你确实想把它应用到å•元格中å—? + + + + + + %n character(s) + + %n 个字符 + + + + + Type of data currently in cell: Valid JSON + 当å‰åœ¨å•元格中的数æ®çš„类型: åˆæ³•çš„JSON + + + + Type of data currently in cell: Binary + 当å‰åœ¨å•元格中的数æ®çš„类型: 二进制 + + + + + %n byte(s) + + %n 字节 + + + + + EditIndexDialog + + + &Name + åç§°(&N) + + + + Order + é¡ºåº + + + + &Table + 表(&T) + + + + Edit Index Schema + 编辑索引架构 + + + + &Unique + 唯一(&U) + + + + For restricting the index to only a part of the table you can specify a WHERE clause here that selects the part of the table that should be indexed + 为了将索引范围é™åˆ¶åˆ°è¡¨ä¸­çš„一部分,您å¯ä»¥åœ¨æ­¤æŒ‡å®š WHERE å­å¥æ¥åœ¨è¡¨ä¸­é€‰æ‹©éœ€è¦ç´¢å¼•的部分 + + + + Partial inde&x clause + 部分索引å­å¥(&x) + + + + Colu&mns + 列(&m) + + + + Table column + 表中的列 + + + + Type + 类型 + + + + Add a new expression column to the index. Expression columns contain SQL expression rather than column names. + å‘索引中添加一个新的表达å¼åˆ—。表达å¼åˆ—åŒ…å« SQL 表达å¼è€Œä¸æ˜¯åˆ—å。 + + + + Index column + 索引列 + + + + Deleting the old index failed: +%1 + 删除旧索引失败: +%1 + + + + Creating the index failed: +%1 + 创建索引时失败: +%1 + + + + EditTableDialog + + + Edit table definition + 编辑表定义 + + + + Table + 表 + + + + Advanced + 高级 + + + + Make this a 'WITHOUT rowid' table. Setting this flag requires a field of type INTEGER with the primary key flag set and the auto increment flag unset. + 让表'没有 rowid'ã€‚è®¾ç½®æ­¤æ ‡å¿—éœ€è¦æœ‰ä¸€ä¸ª INTEGER 类型并被设为主键ã€éžè‡ªå¢žçš„字段。 + + + + Without Rowid + æ—  Rowid + + + + Fields + 字段 + + + + Database sche&ma + æ•°æ®åº“æž¶æž„(&M) + + + + Add + 增加 + + + + Remove + 删除 + + + + Move to top + 移到最上 + + + + Move up + 上移 + + + + Move down + 下移 + + + + Move to bottom + 移到最下 + + + + + Name + åç§° + + + + + Type + 类型 + + + + NN + éžç©º + + + + Not null + éžNULL + + + + PK + 主键 + + + + Primary key + 主键 + + + + AI + 自增 + + + + Autoincrement + 自动增值 + + + + U + 唯一 + + + + + + Unique + 唯一 + + + + Default + 默认 + + + + Default value + 默认值 + + + + + + Check + 检查 + + + + Check constraint + æ£€æŸ¥çº¦æŸæ¡ä»¶ + + + + Collation + 排åºè§„则 + + + + + + Foreign Key + 外键 + + + + Constraints + çº¦æŸ + + + + Add constraint + å¢žåŠ çº¦æŸ + + + + Remove constraint + åˆ é™¤çº¦æŸ + + + + Columns + 列 + + + + SQL + SQL + + + + <html><head/><body><p><span style=" font-weight:600; color:#ff0000;">Warning: </span>There is something with this table definition that our parser doesn't fully understand. Modifying and saving this table might result in problems.</p></body></html> + <html><head/><body><p><span style=" font-weight:600; color:#ff0000;">警告: </span>表中有一些无法解æžçš„定义。编辑并ä¿å­˜è¡¨å¯èƒ½ä¼šå¸¦æ¥é—®é¢˜ã€‚</p></body></html> + + + + + Primary Key + 主键 + + + + Add a primary key constraint + å¢žåŠ ä¸»é”®çº¦æŸ + + + + Add a foreign key constraint + å¢žåŠ å¤–é”®çº¦æŸ + + + + Add a unique constraint + å¢žåŠ å”¯ä¸€æ€§çº¦æŸ + + + + Add a check constraint + å¢žåŠ æ£€æŸ¥çº¦æŸ + + + + Error creating table. Message from database engine: +%1 + 创建表时出错。æ¥è‡ªæ•°æ®åº“引擎的消æ¯: +%1 + + + + There already is a field with that name. Please rename it first or choose a different name for this field. + 已存在åŒå字段。请先é‡å‘½å已有字段,或为此字段选一个ä¸åŒçš„å字。 + + + + + There can only be one primary key for each table. Please modify the existing primary key instead. + æ¯ä¸ªè¡¨åªèƒ½æœ‰ä¸€ä¸ªä¸»é”®ã€‚请修改已有的主键。 + + + + This column is referenced in a foreign key in table %1 and thus its name cannot be changed. + 此列是表 %1 的外键,因此它的åå­—ä¸èƒ½æ”¹å˜ã€‚ + + + + There is at least one row with this field set to NULL. This makes it impossible to set this flag. Please change the table data first. + 至少有一行带本字段的记录被设为空。这使得它ä¸å¯èƒ½è®¾ç½®è¿™ä¸ªæ ‡å¿—。请首先更改表数æ®ã€‚ + + + + There is at least one row with a non-integer value in this field. This makes it impossible to set the AI flag. Please change the table data first. + åœ¨è¿™ä¸ªå­—æ®µä¸­è‡³å°‘æœ‰ä¸€è¡Œå¸¦æœ‰ä¸€ä¸ªéžæ•´æ•°çš„值。这使得它ä¸å¯èƒ½è®¾ç½®è‡ªå¢žæ ‡å¿—。请首先更改表数æ®ã€‚ + + + + Column '%1' has duplicate data. + + 列 '%1' 有é‡å¤æ•°æ®ã€‚ + + + + This makes it impossible to enable the 'Unique' flag. Please remove the duplicate data, which will allow the 'Unique' flag to then be enabled. + 所以无法å¯ç”¨â€œå”¯ä¸€â€æ ‡è®°ã€‚请删除é‡å¤æ•°æ®æ‰èƒ½å¯ç”¨ã€‚ + + + + Are you sure you want to delete the field '%1'? +All data currently stored in this field will be lost. + 您是å¦ç¡®è®¤æ‚¨æƒ³åˆ é™¤å­—段 '%1'? +当å‰å­˜å‚¨åœ¨è¿™ä¸ªå­—段中的所有数æ®å°†ä¼šä¸¢å¤±ã€‚ + + + + Please add a field which meets the following criteria before setting the without rowid flag: + - Primary key flag set + - Auto increment disabled + 在设置为无 rowid å‰ï¼Œè¯·å…ˆæ·»åŠ ä¸€ä¸ªæ»¡è¶³ä»¥ä¸‹å‡†åˆ™çš„å­—æ®µ: + - 设置为主键 + - ç¦æ­¢è‡ªå¢ž + + + + ExportDataDialog + + + Export data as CSV + 导出数æ®ä¸º CSV + + + + Tab&le(s) + 表(&l) + + + + Colu&mn names in first line + 第一行列å(&m) + + + + Fie&ld separator + 字段分隔符(&l) + + + + , + , + + + + ; + ; + + + + Tab + Tab + + + + | + | + + + + + + Other + 其它 + + + + &Quote character + 引å·(&Q) + + + + " + " + + + + ' + ' + + + + New line characters + æ¢è¡Œç¬¦ + + + + Windows: CR+LF (\r\n) + Windows: 回车+æ¢è¡Œ (\r\n) + + + + Unix: LF (\n) + Unix: æ¢è¡Œ (\n) + + + + Pretty print + 美化输出 + + + + + Could not open output file: %1 + 打ä¸å¼€è¾“出文件: %1 + + + + + Choose a filename to export data + 选择导出数æ®çš„æ–‡ä»¶å + + + + Export data as JSON + 导出为 JSON + + + + exporting CSV + 导出 CSV + + + + exporting JSON + 导出 JSON + + + + Please select at least 1 table. + 请至少选1个表 + + + + Choose a directory + 选择一个目录 + + + + Export completed. + 导出完æˆã€‚ + + + + ExportSqlDialog + + + Export SQL... + 导出 SQL... + + + + Tab&le(s) + 表(&L) + + + + Select All + 全选 + + + + Deselect All + å…¨ä¸é€‰ + + + + &Options + 选项(&O) + + + + Keep column names in INSERT INTO + 在 INSERT INTO 语å¥ä¸­ä¿ç•™åˆ—å + + + + Multiple rows (VALUES) per INSERT statement + æ¯æ¡ INSERT 语å¥ä¸­åŒ…å«å¤šè¡Œ (VALUES) + + + + Export everything + 导出所有 + + + + Export schema only + 仅导出架构 + + + + Export data only + ä»…å¯¼å‡ºæ•°æ® + + + + Keep old schema (CREATE TABLE IF NOT EXISTS) + ä¿æŒæ—§æž¶æž„ (CREATE TABLE IF NOT EXISTS) + + + + Overwrite old schema (DROP TABLE, then CREATE TABLE) + 覆盖旧架构 (DROP TABLE, ç„¶åŽ CREATE TABLE) + + + + Please select at least one table. + 请至少选一个表。 + + + + Choose a filename to export + 选择è¦å¯¼å‡ºçš„æ–‡ä»¶å + + + + Export completed. + 导出完æˆã€‚ + + + + Export cancelled or failed. + å¯¼å‡ºè¢«å–æ¶ˆæˆ–失败。 + + + + ExtendedScintilla + + + + Ctrl+H + + + + + Ctrl+F + + + + + + Ctrl+P + + + + + Find... + 查找... + + + + Find and Replace... + 查找并替æ¢... + + + + Print... + 打å°... + + + + ExtendedTableWidget + + + Use as Exact Filter + 用于精确过滤 + + + + Containing + åŒ…å« + + + + Not containing + ä¸åŒ…å« + + + + Not equal to + ä¸ç­‰äºŽ + + + + Greater than + 大于 + + + + Less than + å°äºŽ + + + + Greater or equal + 大于等于 + + + + Less or equal + å°äºŽç­‰äºŽ + + + + Between this and... + 在此值和...之间 + + + + Regular expression + æ­£åˆ™è¡¨è¾¾å¼ + + + + Edit Conditional Formats... + 编辑æ¡ä»¶æ ¼å¼... + + + + Set to NULL + 设置为 NULL + + + + Copy + å¤åˆ¶ + + + + Copy with Headers + å¸¦è¡¨å¤´ä¸€èµ·æ‹·è´ + + + + Copy as SQL + æ‹·è´ä¸º SQL + + + + Paste + 粘贴 + + + + Print... + 打å°... + + + + Use in Filter Expression + 在过滤器表达å¼ä¸­ä½¿ç”¨ + + + + Alt+Del + + + + + Ctrl+Shift+C + + + + + Ctrl+Alt+C + + + + + The content of the clipboard is bigger than the range selected. +Do you want to insert it anyway? + 剪贴æ¿ä¸­çš„æ•°æ®èŒƒå›´è¶…过了选择的范围。 +是å¦ä»è¦æ’入? + + + + <p>Not all data has been loaded. <b>Do you want to load all data before selecting all the rows?</b><p><p>Answering <b>No</b> means that no more data will be loaded and the selection will not be performed.<br/>Answering <b>Yes</b> might take some time while the data is loaded but the selection will be complete.</p>Warning: Loading all the data might require a great amount of memory for big tables. + <p>éƒ¨åˆ†æ•°æ®æ²¡æœ‰è¢«åŠ è½½ã€‚<b>åœ¨é€‰æ‹©æ‰€æœ‰è¡Œä¹‹å‰æ˜¯å¦è¦åŠ è½½æ‰€æœ‰æ•°æ®ï¼Ÿ</b><p><p>选择<b>å¦</b>表示ä¸åŠ è½½æ•°æ®å¹¶æ”¾å¼ƒå…¨é€‰ã€‚<br/>选择<b>是</b>表示加载所有数æ®ï¼ˆå¯èƒ½èŠ±è´¹ä¸€äº›æ—¶é—´ï¼‰å¹¶è¿›è¡Œå…¨é€‰ã€‚</p>警告:加载所有数æ®å¯¹äºŽå¤§è¡¨æ ¼å¯èƒ½å ç”¨å¤§é‡å†…存。 + + + + Cannot set selection to NULL. Column %1 has a NOT NULL constraint. + ä¸èƒ½å°†å½“å‰å•元格设置为 NULL。列 %1 有 NOT NULL 约æŸã€‚ + + + + FileExtensionManager + + + File Extension Manager + 文件扩展å管ç†å™¨ + + + + &Up + 上(&U) + + + + &Down + 下(&D) + + + + &Add + 添加(&A) + + + + &Remove + 删除(&R) + + + + + Description + æè¿° + + + + Extensions + 扩展å + + + + *.extension + *.扩展å + + + + FilterLineEdit + + + Filter + 过滤 + + + + These input fields allow you to perform quick filters in the currently selected table. +By default, the rows containing the input text are filtered out. +The following operators are also supported: +% Wildcard +> Greater than +< Less than +>= Equal to or greater +<= Equal to or less += Equal to: exact match +<> Unequal: exact inverse match +x~y Range: values between x and y +/regexp/ Values matching the regular expression + è¿™äº›è¾“å…¥æ¡†èƒ½è®©ä½ å¿«é€Ÿåœ¨å½“å‰æ‰€é€‰è¡¨ä¸­è¿›è¡Œè¿‡æ»¤ã€‚ +默认情况下,包å«è¾“入文本的行会被过滤出æ¥ã€‚ +以下æ“作也支æŒ: +% 通é…符 +> 大于 +< å°äºŽ +>= 大于等于 +<= å°äºŽç­‰äºŽ += 等于: ç²¾ç¡®åŒ¹é… +<> ä¸ç­‰äºŽ: 精确åå‘åŒ¹é… +x~y 范围: 值在 x å’Œ y 之间 +/regexp/ å€¼ç¬¦åˆæ­£åˆ™è¡¨è¾¾å¼ + + + + Clear All Conditional Formats + 清除所有æ¡ä»¶æ ¼å¼ + + + + Use for Conditional Format + 用于æ¡ä»¶æ ¼å¼ + + + + Edit Conditional Formats... + 编辑æ¡ä»¶æ ¼å¼... + + + + Set Filter Expression + è®¾ç½®è¿‡æ»¤è¡¨è¾¾å¼ + + + + What's This? + 这是什么? + + + + Is NULL + 为 NULL + + + + Is not NULL + éž NULL + + + + Is empty + 为空 + + + + Is not empty + éžç©º + + + + Not containing... + ä¸åŒ…å«... + + + + Equal to... + 等于... + + + + Not equal to... + ä¸ç­‰äºŽ... + + + + Greater than... + 大于... + + + + Less than... + å°äºŽ... + + + + Greater or equal... + 大于等于... + + + + Less or equal... + å°äºŽç­‰äºŽ... + + + + In range... + 在范围内... + + + + Regular expression... + 正则表达å¼... + + + + FindReplaceDialog + + + Find and Replace + æŸ¥æ‰¾å¹¶æ›¿æ¢ + + + + Fi&nd text: + 查找文本(&N): + + + + Re&place with: + 替æ¢ä¸º(&P): + + + + Match &exact case + 精确匹é…(&E) + + + + Match &only whole words + 全字匹é…(&O) + + + + When enabled, the search continues from the other end when it reaches one end of the page + å¯ç”¨æ—¶ï¼Œæœç´¢åˆ°é¡µç»“尾时,æœç´¢ä¼šç»§ç»­ä»Žå¦ä¸€è¾¹å¼€å§‹ã€‚ + + + + &Wrap around + 循环查找(&W) + + + + When set, the search goes backwards from cursor position, otherwise it goes forward + 设置时,æœç´¢ä»Žå½“å‰ä½ç½®å¾€å›žè¿›è¡Œã€‚å¦åˆ™å‘剿œç´¢ã€‚ + + + + Search &backwards + å呿Ÿ¥æ‰¾(&B) + + + + <html><head/><body><p>When checked, the pattern to find is searched only in the current selection.</p></body></html> + <html><head/><body><p>选中时,åªåœ¨å½“å‰é€‰æ‹©çš„内容中进行æœç´¢ã€‚</p></body></html> + + + + &Selection only + 在所选内容中查找(&S) + + + + <html><head/><body><p>When checked, the pattern to find is interpreted as a UNIX regular expression. See <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>.</p></body></html> + <html><head/><body><p>é€‰ä¸­æ—¶ï¼Œè¦æŸ¥æ‰¾çš„æ¨¡å¼è¢«è§£é‡Šä¸º UNIX 正则表达å¼ã€‚å‚阅 <a href="https://en.wikibooks.org/wiki/Regular_Expressions"> Wikibooks 中的正则表达å¼</a>.</p></body></html> + + + + Use regular e&xpressions + 使用正则表达å¼(&X) + + + + Find the next occurrence from the cursor position and in the direction set by "Search backwards" + 从当å‰ä½ç½®æŸ¥æ‰¾ä¸‹ä¸€å‡ºçŽ°çš„ä½ç½®ï¼ŒæŒ‰ "å呿Ÿ¥æ‰¾" 处所选的方å‘进行查找。 + + + + &Find Next + 查找下一个(&F) + + + + F3 + + + + + &Replace + 替æ¢(&R) + + + + Highlight all the occurrences of the text in the page + 高亮本页中所有出现的文本 + + + + F&ind All + 全部高亮(&I) + + + + Replace all the occurrences of the text in the page + æ›¿æ¢æœ¬é¡µä¸­æ‰€æœ‰å‡ºçŽ°çš„æ–‡æœ¬ + + + + Replace &All + 全部替æ¢(&A) + + + + The searched text was not found + æ— æ³•æ‰¾åˆ°è¦æŸ¥æ‰¾çš„æ–‡æœ¬ + + + + The searched text was not found. + æ— æ³•æ‰¾åˆ°è¦æŸ¥æ‰¾çš„æ–‡æœ¬ã€‚ + + + + The searched text was found one time. + 查找的文本被找到了 1 次。 + + + + The searched text was found %1 times. + 查找的文本被找到了 %1 次。 + + + + The searched text was replaced one time. + 查找的文本被替æ¢äº† 1 次。 + + + + The searched text was replaced %1 times. + 查找的文本被替æ¢äº† %1 次。 + + + + ForeignKeyEditor + + + &Reset + é‡ç½®(&R) + + + + Foreign key clauses (ON UPDATE, ON DELETE etc.) + 外键å­å¥ (ON UPDATE, ON DELETE 等等) + + + + ImportCsvDialog + + + Import CSV file + 导入 CSV 文件 + + + + Table na&me + 表åç§°(&M) + + + + &Column names in first line + 列å在首行(&C) + + + + Field &separator + 字段分隔符(&S) + + + + , + , + + + + ; + ; + + + + + Tab + Tab + + + + | + ; + + + + Other + 其它 + + + + &Quote character + 引å·(&Q) + + + + + Other (printable) + å…¶ä»–(坿‰“å°) + + + + + Other (code) + å…¶ä»–(代ç ) + + + + " + " + + + + ' + ' + + + + &Encoding + ç¼–ç (&E) + + + + UTF-8 + UTF-8 + + + + UTF-16 + UTF-16 + + + + ISO-8859-1 + ISO-8859-1 + + + + Trim fields? + 删除字段头尾空白? + + + + Separate tables + 分离表 + + + + Advanced + 高级 + + + + When importing an empty value from the CSV file into an existing table with a default value for this column, that default value is inserted. Activate this option to insert an empty value instead. + 当从 CSV 文件导入空值到已有表中,并且该列有默认值时,默认值会被æ’å…¥ã€‚é€‰ä¸­æ­¤é¡¹ä»¥åœ¨è¿™ç§æƒ…况下æ’入空值。 + + + + Ignore default &values + 忽略默认值(&V) + + + + Activate this option to stop the import when trying to import an empty value into a NOT NULL column without a default value. + é€‰ä¸­æ­¤é¡¹ä»¥åœ¨å¾€æ²¡æœ‰é»˜è®¤å€¼çš„éž NULL 列导入空值时终止导入。 + + + + Fail on missing values + 缺值时失败 + + + + Disable data type detection + ç¦ç”¨ç±»åž‹æ£€æµ‹ + + + + Disable the automatic data type detection when creating a new table. + ç¦æ­¢åœ¨åˆ›å»ºæ–°è¡¨æ—¶è‡ªåŠ¨æ£€æµ‹æ•°æ®ç±»åž‹ã€‚ + + + + When importing into an existing table with a primary key, unique constraints or a unique index there is a chance for a conflict. This option allows you to select a strategy for that case: By default the import is aborted and rolled back but you can also choose to ignore and not import conflicting rows or to replace the existing row in the table. + 当呿œ‰ä¸»é”®çš„è¡¨ä¸­å¯¼å…¥æ•°æ®æ—¶ï¼Œå¯èƒ½ä¼šäº§ç”Ÿå”¯ä¸€æ€§çº¦æŸæˆ–索引的冲çªã€‚此选项å…许你选择处ç†å†²çªçš„ç­–ç•¥ï¼šé»˜è®¤æƒ…å†µä¸‹ä¼šå–æ¶ˆå¯¼å…¥å¹¶å·å›žï¼Œä¹Ÿå¯ä»¥é€‰æ‹©å¿½ç•¥å¹¶è·³è¿‡å†²çªçš„行,或替æ¢è¡¨ä¸­çŽ°æœ‰çš„è¡Œã€‚ + + + + Abort import + å–æ¶ˆå¯¼å…¥ + + + + Ignore row + 忽略冲çªçš„行 + + + + Replace existing row + 替æ¢çŽ°æœ‰çš„è¡Œ + + + + Conflict strategy + 冲çªç­–ç•¥ + + + + + Deselect All + å…¨ä¸é€‰ + + + + Match Similar + 匹é…相似 + + + + Select All + 全选 + + + + There is already a table named '%1' and an import into an existing table is only possible if the number of columns match. + å·²ç»æœ‰ä¸€å¼ å«åš '%1' çš„è¡¨ã€‚åªæœ‰åˆ—æ•°åŒ¹é…æ—¶ï¼Œæ‰èƒ½å¯¼å…¥åˆ°å·²ç»å­˜åœ¨çš„表中。 + + + + There is already a table named '%1'. Do you want to import the data into it? + å·²ç»æœ‰ä¸€å¼ å«åš '%1' 的表。你想把数æ®å¯¼å…¥åˆ°æ­¤è¡¨ä¸­å—? + + + + Creating restore point failed: %1 + 创建还原点失败: %1 + + + + Creating the table failed: %1 + 创建表失败: %1 + + + + importing CSV + 导入 CSV + + + + Importing the file '%1' took %2ms. Of this %3ms were spent in the row function. + 导入文件 '%1' 用时 %2ms. 其中 %3ms 用在行方程上。 + + + + Inserting row failed: %1 + æ’入行失败: %1 + + + + MainWindow + + + DB Browser for SQLite + DB Browser for SQLite + + + + toolBar1 + 工具æ 1 + + + + &Wiki + 百科(&W) + + + + Bug &Report... + Bug 上报(&R)... + + + + Feature Re&quest... + 特性请求(&Q)... + + + + Web&site + 网站(&S) + + + + &Donate on Patreon... + 在 Patreon 上æèµ (&D)... + + + + Open &Project... + 打开工程(&P)... + + + + &Attach Database... + 附加数æ®åº“(&A)... + + + + + Add another database file to the current database connection + 添加å¦ä¸€ä¸ªæ•°æ®åº“到当å‰çš„æ•°æ®åº“连接中 + + + + This button lets you add another database file to the current database connection + 此按钮能添加å¦ä¸€ä¸ªæ•°æ®åº“到当å‰çš„æ•°æ®åº“连接中 + + + + &Set Encryption... + 设置加密(&S)... + + + + This button saves the content of the current SQL editor tab to a file + æ­¤æŒ‰é’®æŠŠå½“å‰ SQL 编辑器页的内容ä¿å­˜åˆ°ä¸€ä¸ªæ–‡ä»¶ + + + + SQLCipher &FAQ + SQLCipher 常è§é—®é¢˜(&F)... + + + + Table(&s) to JSON... + 表到 JSON (&S)... + + + + Export one or more table(s) to a JSON file + 导出一个或多个表到 JSON 文件 + + + + Un/comment block of SQL code + 注释/å–æ¶ˆæ³¨é‡ŠSQLä»£ç  + + + + Un/comment block + 注释/å–æ¶ˆæ³¨é‡Š + + + + Comment or uncomment current line or selected block of code + æ³¨é‡Šæˆ–å–æ¶ˆæ³¨é‡Šå½“å‰è¡Œæˆ–é€‰ä¸­çš„ä»£ç æ®µ + + + + Comment or uncomment the selected lines or the current line, when there is no selection. All the block is toggled according to the first line. + æ³¨é‡Šæˆ–å–æ¶ˆæ³¨é‡Šå½“å‰é€‰ä¸­çš„ä»£ç æ®µã€‚当没有选中时为当å‰è¡Œã€‚ä»£ç æ®µçš„æ³¨é‡Šçжæ€ç”±ç¬¬ä¸€è¡Œå†³å®šã€‚ + + + + Ctrl+/ + + + + + Stop SQL execution + åœæ­¢æ‰§è¡ŒSQL + + + + Stop execution + åœæ­¢æ‰§è¡Œ + + + + Stop the currently running SQL script + åœæ­¢å½“å‰è¿è¡Œçš„SQL脚本 + + + + &File + 文件(&F) + + + + &Import + 导入(&I) + + + + &Export + 导出(&E) + + + + &Edit + 编辑(&E) + + + + &View + 查看(&V) + + + + &Help + 帮助(&H) + + + + &Remote + 远程(&R) + + + + Execute all/selected SQL + 执行所有/选中的 SQL + + + + This button executes the currently selected SQL statements. If no text is selected, all SQL statements are executed. + 此按钮执行当å‰é€‰ä¸­çš„ SQL 语å¥ã€‚如果没有选中文本,就执行所有的 SQL 语å¥ã€‚ + + + + &Load Extension... + 加载扩展(&L)... + + + + This button executes the SQL statement present in the current editor line + 此按钮执行编辑器当å‰è¡Œä¸­çš„ SQL è¯­å¥ + + + + Shift+F5 + + + + + Sa&ve Project + ä¿å­˜å·¥ç¨‹(&V) + + + + + Save SQL file as + SQL 文件å¦å­˜ä¸º + + + + &Browse Table + æµè§ˆè¡¨ + + + + Copy Create statement + å¤åˆ¶ Create è¯­å¥ + + + + Copy the CREATE statement of the item to the clipboard + å¤åˆ¶é€‰ä¸­é¡¹çš„ CREATE 语å¥åˆ°å‰ªè´´æ¿ + + + + Open an existing database file in read only mode + 用åªè¯»æ–¹å¼æ‰“开一个已有的数æ®åº“文件 + + + + Opens the SQLCipher FAQ in a browser window + 用æµè§ˆå™¨çª—壿‰“å¼€ SQLCipher 常è§é—®é¢˜ + + + + User + 用户 + + + + Application + åº”ç”¨ç¨‹åº + + + + &Clear + 清除(&C) + + + + DB Sche&ma + æ•°æ®åº“æž¶æž„(&M) + + + + &New Database... + 新建数æ®åº“(&N)... + + + + + Create a new database file + 创建一个新的数æ®åº“文件 + + + + This option is used to create a new database file. + 这个选项用于创建一个新的数æ®åº“文件。 + + + + Ctrl+N + + + + + + &Open Database... + 打开数æ®åº“(&O)... + + + + + + + + Open an existing database file + 打开一个现有的数æ®åº“文件 + + + + + + This option is used to open an existing database file. + 这个选项用于打开一个现有的数æ®åº“文件。 + + + + Ctrl+O + + + + + &Close Database + 关闭数æ®åº“(&C) + + + + + Ctrl+W + + + + + + Revert database to last saved state + 把数æ®åº“会退到先å‰ä¿å­˜çš„çŠ¶æ€ + + + + This option is used to revert the current database file to its last saved state. All changes made since the last save operation are lost. + 这个选项用于倒退当å‰çš„æ•°æ®åº“文件为它最åŽçš„ä¿å­˜çжæ€ã€‚从最åŽä¿å­˜æ“作开始åšå‡ºçš„æ‰€æœ‰æ›´æ”¹å°†ä¼šä¸¢å¤±ã€‚ + + + + + Write changes to the database file + 把更改写入到数æ®åº“文件 + + + + This option is used to save changes to the database file. + 这个选项用于ä¿å­˜æ›´æ”¹åˆ°æ•°æ®åº“文件。 + + + + Ctrl+S + + + + + Compact &Database... + 压缩数æ®åº“(&D)... + + + + Compact the database file, removing space wasted by deleted records + 压缩数æ®åº“文件,通过删除记录去掉浪费的空间 + + + + + Compact the database file, removing space wasted by deleted records. + 压缩数æ®åº“文件,通过删除记录去掉浪费的空间。 + + + + E&xit + 退出(&X) + + + + Ctrl+Q + + + + + Import data from an .sql dump text file into a new or existing database. + 从一个 .sql 转储文本文件中导入数æ®åˆ°ä¸€ä¸ªæ–°çš„æˆ–已有的数æ®åº“。 + + + + This option lets you import data from an .sql dump text file into a new or existing database. SQL dump files can be created on most database engines, including MySQL and PostgreSQL. + 这个选项让你从一个 .sql 转储文本文件中导入数æ®åˆ°ä¸€ä¸ªæ–°çš„æˆ–现有的数æ®åº“。SQL 转储文件å¯ä»¥åœ¨å¤§å¤šæ•°æ•°æ®åº“引擎上创建,包括 MySQL å’Œ PostgreSQL。 + + + + Open a wizard that lets you import data from a comma separated text file into a database table. + 打开一个å‘导让您从一个逗å·é—´éš”的文本文件导入数æ®åˆ°ä¸€ä¸ªæ•°æ®åº“表中。 + + + + Open a wizard that lets you import data from a comma separated text file into a database table. CSV files can be created on most database and spreadsheet applications. + 打开一个å‘导让您从一个逗å·é—´éš”的文本文件导入数æ®åˆ°ä¸€ä¸ªæ•°æ®åº“表中。CSV 文件å¯ä»¥åœ¨å¤§å¤šæ•°æ•°æ®åº“和电å­è¡¨æ ¼åº”用程åºä¸Šåˆ›å»ºã€‚ + + + + Export a database to a .sql dump text file. + 导出一个数æ®åº“导一个 .sql 转储文本文件。 + + + + This option lets you export a database to a .sql dump text file. SQL dump files contain all data necessary to recreate the database on most database engines, including MySQL and PostgreSQL. + 这个选项让你导出一个数æ®åº“导一个 .sql 转储文本文件。SQL 转储文件包å«åœ¨å¤§å¤šæ•°æ•°æ®åº“引擎上(包括 MySQL å’Œ PostgreSQL)釿–°åˆ›å»ºæ•°æ®åº“所需的所有数æ®ã€‚ + + + + Export a database table as a comma separated text file. + 导出一个数æ®åº“表为逗å·é—´éš”的文本文件。 + + + + Export a database table as a comma separated text file, ready to be imported into other database or spreadsheet applications. + 导出一个数æ®åº“表为逗å·é—´éš”的文本文件,准备好被导入到其他数æ®åº“或电å­è¡¨æ ¼åº”用程åºã€‚ + + + + Open the Create Table wizard, where it is possible to define the name and fields for a new table in the database + 打开“创建表â€å‘导,在那里å¯ä»¥å®šä¹‰åœ¨æ•°æ®åº“中的一个新表的å称和字段 + + + + Open the Delete Table wizard, where you can select a database table to be dropped. + 打开“删除表â€å‘导,在那里你å¯ä»¥é€‰æ‹©è¦ä¸¢å¼ƒçš„一个数æ®åº“表。 + + + + Open the Modify Table wizard, where it is possible to rename an existing table. It is also possible to add or delete fields form a table, as well as modify field names and types. + 打开“修改表â€å‘导,在其中å¯ä»¥é‡å‘½å一个现有的表。也å¯ä»¥ä»Žä¸€ä¸ªè¡¨ä¸­æ·»åŠ æˆ–åˆ é™¤å­—æ®µï¼Œä»¥åŠä¿®æ”¹å­—段å称和类型。 + + + + Open the Create Index wizard, where it is possible to define a new index on an existing database table. + 打开“创建索引â€å‘导,在那里å¯ä»¥åœ¨ä¸€ä¸ªçŽ°æœ‰çš„æ•°æ®åº“表上定义一个新索引。 + + + + &Preferences... + 首选项(&P)... + + + + + Open the preferences window. + 打开首选项窗å£ã€‚ + + + + &DB Toolbar + æ•°æ®åº“工具æ (&D) + + + + Shows or hides the Database toolbar. + 显示或éšè—æ•°æ®åº“工具æ ã€‚ + + + + Shift+F1 + + + + + &Recently opened + 最近打开(&R) + + + + Open &tab + 打开标签页(&T) + + + + Ctrl+T + + + + + + Database Structure + This has to be equal to the tab title in all the main tabs + æ•°æ®åº“结构 + + + + This is the structure of the opened database. +You can drag SQL statements from an object row and drop them into other applications or into another instance of 'DB Browser for SQLite'. + + 这是打开的数æ®åº“的结构。 +ä½ å¯ä»¥ä»Žä¸€ä¸ªå¯¹è±¡è¡Œä¸­æ‹–动 SQL 语å¥ï¼Œç„¶åŽæ‹–到其他应用中,或者拖到其他 'DB Browser for SQLite' 的实例中。 + + + + + + Browse Data + This has to be equal to the tab title in all the main tabs + æµè§ˆæ•°æ® + + + + + Edit Pragmas + This has to be equal to the tab title in all the main tabs + ç¼–è¾‘æ‚æ³¨ + + + + Warning: this pragma is not readable and this value has been inferred. Writing the pragma might overwrite a redefined LIKE provided by an SQLite extension. + 警告: æ­¤æ‚æ³¨æ— æ³•读å–ï¼Œæ­¤å€¼ä¸ºæŽ¨æ–­å¾—åˆ°ã€‚ç¼–è¾‘æ‚æ³¨å¯èƒ½ä¼šè¦†ç›–ç”± SQLite 扩展é‡å®šä¹‰çš„ LIKE。 + + + + + Execute SQL + This has to be equal to the tab title in all the main tabs + 执行 SQL + + + + &Tools + 工具(&T) + + + + DB Toolbar + æ•°æ®åº“å·¥å…·æ  + + + + Edit Database &Cell + 编辑数æ®åº“å•元格(&C) + + + + SQL &Log + SQL 日志(&L) + + + + Show S&QL submitted by + 显示 SQL æäº¤è‡ª(&Q) + + + + Error Log + 错误记录 + + + + This button clears the contents of the SQL logs + 此按钮清除 SQL 日志的内容 + + + + This panel lets you examine a log of all SQL commands issued by the application or by yourself + æ­¤é¢æ¿å¯ä»¥è®©ä½ è‡ªè¡Œæ£€æŸ¥æœ¬åº”ç”¨ç¨‹åºæ‰§è¡Œçš„æ‰€æœ‰ SQL 命令的日志。 + + + + &Plot + 图表(&P) + + + + This is the structure of the opened database. +You can drag multiple object names from the Name column and drop them into the SQL editor and you can adjust the properties of the dropped names using the context menu. This would help you in composing SQL statements. +You can drag SQL statements from the Schema column and drop them into the SQL editor or into other applications. + + è¿™æ˜¯å½“å‰æ‰“开的数æ®åº“的结构。 +ä½ å¯ä»¥ä»Žå字列拖拽多个对象å字到 SQL 编辑器中,å¯ä»¥ç”¨èœå•调节拖拽å字的属性。这å¯ä»¥å¸®åŠ©ä½ æž„å»º SQL 语å¥ã€‚ +ä½ å¯ä»¥ä»Žæž¶æž„列拖拽 SQL 语å¥åˆ° SQL 编辑器或其他应用中。 + + + + + Project Toolbar + å·¥ç¨‹å·¥å…·æ  + + + + Extra DB toolbar + å…¶ä»–æ•°æ®åº“å·¥å…·æ  + + + + + + Close the current database file + 关闭当剿•°æ®åº“文件 + + + + This button closes the connection to the currently open database file + æ­¤æŒ‰é’®å…³é—­åˆ°å½“å‰æ‰“开的数æ®åº“文件的连接 + + + + Ctrl+F4 + + + + + &Revert Changes + 倒退更改(&R) + + + + &Write Changes + 写入更改(&W) + + + + Open SQL file(s) + 打开 SQL 文件 + + + + This button opens files containing SQL statements and loads them in new editor tabs + æ­¤æŒ‰é’®æ‰“å¼€åŒ…å« SQL 语å¥çš„æ–‡ä»¶ï¼Œå°†å…¶è½½å…¥åˆ°æ–°æ ‡ç­¾é¡µ + + + + Execute line + 执行行 + + + + F1 + + + + + This button lets you save all the settings associated to the open DB to a DB Browser for SQLite project file + 此按钮让你将所有关于打开的数æ®åº“的设置ä¿å­˜åˆ°ä¸€ä¸ª DB Browser for SQLite 工程文件。 + + + + This button lets you open a DB Browser for SQLite project file + 此按钮让你打开一个 DB Browser for SQLite 工程文件。 + + + + Open Data&base Read Only... + åªè¯»æ‰“开数æ®åº“(&B)... + + + + Ctrl+Shift+O + + + + + Save results + ä¿å­˜ç»“æžœ + + + + Save the results view + ä¿å­˜ç»“果视图 + + + + This button lets you save the results of the last executed query + 此按钮让你ä¿å­˜ä¸Šæ¬¡æ‰§è¡Œçš„æŸ¥è¯¢çš„结果 + + + + + Find text in SQL editor + 在 SQL 编辑器中查找文本 + + + + Find + 查找 + + + + This button opens the search bar of the editor + æ­¤æŒ‰é’®æ‰“å¼€ç¼–è¾‘å™¨çš„æŸ¥æ‰¾æ  + + + + Ctrl+F + + + + + + Find or replace text in SQL editor + 在 SQL ç¼–è¾‘å™¨ä¸­æŸ¥æ‰¾æˆ–æ›¿æ¢æ–‡æœ¬ + + + + Find or replace + æŸ¥æ‰¾æˆ–æ›¿æ¢ + + + + This button opens the find/replace dialog for the current editor tab + 此按钮为当å‰çš„编辑器标签页打开查找/替æ¢å¯¹è¯æ¡† + + + + Ctrl+H + + + + + Export to &CSV + 导出到 &CSV + + + + Save as &view + ä¿å­˜ä¸ºè§†å›¾(&V) + + + + Save as view + ä¿å­˜ä¸ºè§†å›¾ + + + + Browse Table + æµè§ˆè¡¨ + + + + Shows or hides the Project toolbar. + 显示或éšè—å·¥ç¨‹å·¥å…·æ  + + + + Extra DB Toolbar + å…¶ä»–æ•°æ®åº“å·¥å…·æ  + + + + New In-&Memory Database + 新建内存数æ®åº“(&M) + + + + Drag && Drop Qualified Names + 拖拽é™å®šåç§° + + + + + Use qualified names (e.g. "Table"."Field") when dragging the objects and dropping them into the editor + 当拖拽对象到编辑器中时,使用é™å®šåç§° (例如 "Table"."Field") + + + + Drag && Drop Enquoted Names + 拖拽引用åå­— + + + + + Use escaped identifiers (e.g. "Table1") when dragging the objects and dropping them into the editor + 当拖拽对象到编辑器中时,使用转移标识符 (例如 "Table1") + + + + &Integrity Check + 完全性检查(&I) + + + + Runs the integrity_check pragma over the opened database and returns the results in the Execute SQL tab. This pragma does an integrity check of the entire database. + 对打开的数æ®åº“è¿è¡Œ integrity_check æ‚æ³¨å¹¶åœ¨æ‰§è¡Œ SQL æ ‡ç­¾é¡µè¿”å›žç»“æžœã€‚æ­¤æ‚æ³¨å¯¹æ•´ä¸ªæ•°æ®åº“进行完全性检查。 + + + + &Foreign-Key Check + 外键检查(&F) + + + + Runs the foreign_key_check pragma over the opened database and returns the results in the Execute SQL tab + 对打开的数æ®åº“è¿è¡Œ foreign_key_check æ‚æ³¨å¹¶åœ¨æ‰§è¡Œ SQL 标签页返回结果。 + + + + &Quick Integrity Check + 快速完全性检查(&Q) + + + + Run a quick integrity check over the open DB + 对打开的数æ®åº“执行快速完全性检查 + + + + Runs the quick_check pragma over the opened database and returns the results in the Execute SQL tab. This command does most of the checking of PRAGMA integrity_check but runs much faster. + 对打开的数æ®åº“è¿è¡Œ quick_check æ‚æ³¨å¹¶åœ¨æ‰§è¡Œ SQL 标签页返回结果。此命令会执行 integrity_check 的多数检查,但是è¦å¿«å¾—多。 + + + + &Optimize + 优化(&O) + + + + Attempt to optimize the database + å°è¯•优化数æ®åº“ + + + + Runs the optimize pragma over the opened database. This pragma might perform optimizations that will improve the performance of future queries. + 对打开的数æ®åº“è¿è¡Œ optimize æ‚æ³¨ã€‚å¯èƒ½ä¼šæ‰§è¡Œå¯¹æœªæ¥æŸ¥è¯¢æ€§èƒ½æœ‰å¸®åŠ©çš„ä¼˜åŒ–ã€‚ + + + + + Print + æ‰“å° + + + + Print text from current SQL editor tab + 从当å‰çš„ SQL ç¼–è¾‘å™¨æ ‡ç­¾é¡µæ‰“å°æ–‡æœ¬ + + + + Open a dialog for printing the text in the current SQL editor tab + æ‰“å¼€å¯¹è¯æ¡†ä»¥ä»Žå½“å‰çš„ SQL ç¼–è¾‘å™¨æ ‡ç­¾é¡µæ‰“å°æ–‡ + + + + Print the structure of the opened database + 打å°å½“剿‰“开的数æ®åº“的结构 + + + + Open a dialog for printing the structure of the opened database + æ‰“å¼€å¯¹è¯æ¡†ä»¥æ‰“å°å½“剿‰“开的数æ®åº“的结构 + + + + &Save Project As... + å¦å­˜ä¸ºå·¥ç¨‹(&S)... + + + + + + Save the project in a file selected in a dialog + 将工程ä¿å­˜ä¸ºæ–‡ä»¶ + + + + Save A&ll + 全部ä¿å­˜(&L) + + + + + + Save DB file, project file and opened SQL files + ä¿å­˜æ•°æ®åº“文件,工程文件,打开的SQL文件 + + + + Ctrl+Shift+S + + + + + &Database from SQL file... + 从 SQL 文件导入数æ®åº“(&D)... + + + + &Table from CSV file... + 从 CSV 文件导入表(&T)... + + + + &Database to SQL file... + 导出数æ®åº“到 SQL 文件(&D)... + + + + &Table(s) as CSV file... + 导出表到 CSV 文件(&T)... + + + + &Create Table... + 创建表(&C)... + + + + &Delete Table... + 删除表(&D)... + + + + &Modify Table... + 修改表(&M)... + + + + Create &Index... + 创建索引(&I)... + + + + W&hat's This? + 这是什么(&W)? + + + + &About + 关于(&A) + + + + This button opens a new tab for the SQL editor + 此按钮打开一个 SQL 编辑器的新标签页 + + + + &Execute SQL + 执行 SQL(&E) + + + + + Save the current session to a file + ä¿å­˜å½“å‰ä¼šè¯åˆ°ä¸€ä¸ªæ–‡ä»¶ + + + + + Load a working session from a file + ä»Žä¸€ä¸ªæ–‡ä»¶åŠ è½½å·¥ä½œä¼šè¯ + + + + + + Save SQL file + ä¿å­˜ SQL 文件 + + + + + Execute current line + 执行当å‰è¡Œ + + + + Ctrl+E + + + + + Export as CSV file + 导出为 CSV 文件 + + + + Export table as comma separated values file + 导出表为逗å·é—´éš”值文件 + + + + Ctrl+L + + + + + + Ctrl+P + + + + + Database encoding + æ•°æ®åº“ç¼–ç  + + + + + Choose a database file + 选择一个数æ®åº“文件 + + + + Ctrl+Return + Ctrl+回车 + + + + Ctrl+D + + + + + Ctrl+I + + + + + Encrypted + 加密的 + + + + Database is encrypted using SQLCipher + æ•°æ®åº“使用 SQLCipher 进行了加密 + + + + Read only + åªè¯» + + + + Database file is read only. Editing the database is disabled. + æ•°æ®åº“是åªè¯»çš„ã€‚ç¼–è¾‘è¢«ç¦æ­¢ã€‚ + + + + Could not open database file. +Reason: %1 + 无法打开数æ®åº“文件。 +原因: %1 + + + + + + Choose a filename to save under + 选择一个文件åä¿å­˜ + + + + Setting PRAGMA values or vacuuming will commit your current transaction. +Are you sure? + è®¾ç½®æˆ–æ¸…é™¤æ‚æ³¨å€¼ä¼šæäº¤ä½ çš„当å‰äº‹åŠ¡ã€‚ +你确定å—? + + + + Error while saving the database file. This means that not all changes to the database were saved. You need to resolve the following error first. + +%1 + ä¿å­˜æ•°æ®åº“æ–‡ä»¶æ—¶å‡ºé”™ã€‚è¿™è¡¨æ˜Žä¸æ˜¯æ‰€æœ‰å¯¹æ•°æ®åº“的更改都被ä¿å­˜äº†ã€‚你需è¦å…ˆè§£å†³ä»¥ä¸‹é”™è¯¯ã€‚ + +%1 + + + + A new DB Browser for SQLite version is available (%1.%2.%3).<br/><br/>Please download at <a href='%4'>%4</a>. + 有新版本的 DB Browser for SQLite (%1.%2.%3)å¯ç”¨ã€‚<br/><br/>请从 <a href='%4'>%4</a> 下载。 + + + + DB Browser for SQLite project file (*.sqbpro) + DB Browser for SQLite 工程文件 (*.sqbpro) + + + + Reset Window Layout + é‡ç½®çª—å£å¸ƒå±€ + + + + Alt+0 + + + + + The database is currenctly busy. + æ•°æ®åº“正忙。 + + + + Click here to interrupt the currently running query. + 点击此处中断当å‰è¿è¡Œçš„æŸ¥è¯¢ã€‚ + + + + You are still executing SQL statements. Closing the database now will stop their execution, possibly leaving the database in an inconsistent state. Are you sure you want to close the database? + 你正在执行SQL语å¥ã€‚关闭数æ®åº“ä¼šåœæ­¢æ‰§è¡Œï¼Œå¯èƒ½ä½¿æ•°æ®åº“处于ä¸å‡†ç¡®çš„状æ€ã€‚确实è¦å…³é—­æ•°æ®åº“å—? + + + + Do you want to save the changes made to the project file '%1'? + 是å¦è¦ä¿å­˜å¯¹å·¥ç¨‹æ–‡ä»¶ '%1' 的修改? + + + + Error checking foreign keys after table modification. The changes will be reverted. + 修改表格åŽçš„外键检查错误。修改会被回退。 + + + + This table did not pass a foreign-key check.<br/>You should run 'Tools | Foreign-Key Check' and fix the reported issues. + 此表格没有通过外键检查。<br/>ä½ éœ€è¦æ‰§è¡Œ '工具 | 外键检查' å¹¶ä¿®å¤å‘现的问题。 + + + + Edit View %1 + 编辑视图 %1 + + + + Edit Trigger %1 + 编辑触å‘器 %1 + + + + + At line %1: + 在行 %1: + + + + Result: %1 + 结果: %1 + + + + Result: %2 + 结果: %2 + + + + Execution finished with errors. + 执行已完æˆï¼Œä½†æœ‰é”™è¯¯ã€‚ + + + + Execution finished without errors. + 执行完æˆã€‚ + + + + Opened '%1' in read-only mode from recent file list + 从最近的文件列表中用åªè¯»æ–¹å¼æ‰“å¼€ %1 + + + + Opened '%1' from recent file list + 从最近的文件列表中打开 %1 + + + + &%1 %2%3 + &%1 %2%3 + + + + (read only) + (åªè¯») + + + + Open Database or Project + 打开数æ®åº“或工程 + + + + Attach Database... + 附加数æ®åº“... + + + + Import CSV file(s)... + 导入CSV文件... + + + + Select the action to apply to the dropped file(s). <br/>Note: only 'Import' will process more than one file. + + 选择è¦åº”用到拖放的文件的æ“作。<br/>注æ„ï¼šåªæœ‰â€œå¯¼å…¥â€ä¼šå¤„ç†å¤šä¸ªæ–‡ä»¶ã€‚ + + + + + Do you want to save the changes made to SQL tabs in a new project file? + 是å¦è¦æŠŠå¯¹SQL的修改ä¿å­˜ä¸ºå·¥ç¨‹æ–‡ä»¶ï¼Ÿ + + + + This action will open a new SQL tab with the following statements for you to edit and run: + 此动作会打开包å«ä¸‹åˆ—语å¥çš„æ–°çš„ SQL 标签页以编辑并è¿è¡Œ: + + + + Rename Tab + é‡å‘½å标签 + + + + Duplicate Tab + å¤åˆ¶æ ‡ç­¾ + + + + Close Tab + 关闭标签 + + + + Opening '%1'... + 正在打开 '%1'... + + + + There was an error opening '%1'... + 打开 '%1' 时出错... + + + + Value is not a valid URL or filename: %1 + 䏿˜¯æ­£ç¡®çš„URL或文件å:%1 + + + + Do you want to save the changes made to the SQL file %1? + 是å¦è¦ä¿å­˜å¯¹SQL文件 %1 的修改? + + + + The statements in this tab are still executing. Closing the tab will stop the execution. This might leave the database in an inconsistent state. Are you sure you want to close the tab? + 此标签内的SQLè¯­å¥æ­£åœ¨è¢«æ‰§è¡Œã€‚å…³é—­æ ‡ç­¾ä¼šåœæ­¢æ‰§è¡Œï¼Œå¯èƒ½ä½¿æ•°æ®åº“处于ä¸å‡†ç¡®çš„状æ€ã€‚确实è¦å…³é—­æ ‡ç­¾å—? + + + + Could not find resource file: %1 + ä¸èƒ½æ‰¾åˆ°èµ„æºæ–‡ä»¶ï¼š%1 + + + + Choose a project file to open + é€‰æ‹©ä¸€ä¸ªè¦æ‰“开的工程文件 + + + + This project file is using an old file format because it was created using DB Browser for SQLite version 3.10 or lower. Loading this file format is still fully supported but we advice you to convert all your project files to the new file format because support for older formats might be dropped at some point in the future. You can convert your files by simply opening and re-saving them. + 此工程文件使用了旧的文件格å¼ï¼Œå› ä¸ºå®ƒæ˜¯ç”± DB Browser for SQLite version 3.10 或更低版本创建的。加载此文件格å¼ä¾ç„¶å®Œå…¨æ”¯æŒï¼Œä½†æˆ‘们建议你把工程转æ¢åˆ°æ–°çš„æ ¼å¼ï¼Œå› ä¸ºæ—§æ ¼å¼æ”¯æŒå°†æ¥å¯èƒ½ä¼šå¤±æ•ˆã€‚ä½ å¯ä»¥é€šè¿‡æ‰“开并釿–°ä¿å­˜çš„æ–¹å¼æ¥è½¬æ¢ã€‚ + + + + Could not open project file for writing. +Reason: %1 + 未能写入工程文件。 +原因:%1 + + + + Busy (%1) + 正忙 (%1) + + + + Are you sure you want to undo all changes made to the database file '%1' since the last save? + 您是å¦ç¡®è®¤æ‚¨æƒ³æ’¤é”€ä»Žä¸Šæ¬¡ä¿å­˜ä»¥æ¥å¯¹æ•°æ®åº“文件‘%1’åšå‡ºçš„æ‰€æœ‰æ›´æ”¹ã€‚? + + + + Choose a file to import + 选择è¦å¯¼å…¥çš„一个文件 + + + + Text files(*.sql *.txt);;All files(*) + 文本文件(*.sql *.txt);;所有文件(*) + + + + Do you want to create a new database file to hold the imported data? +If you answer no we will attempt to import the data in the SQL file to the current database. + 您是å¦ç¡®è®¤æ‚¨æƒ³åˆ›å»ºä¸€ä¸ªæ–°çš„æ•°æ®åº“文件用æ¥å­˜æ”¾å¯¼å…¥çš„æ•°æ®? +如果您会到“å¦â€çš„è¯ï¼Œæˆ‘们将å°è¯•导入 SQL 文件中的数æ®åˆ°å½“剿•°æ®åº“。 + + + + Window Layout + 窗å£å¸ƒå±€ + + + + Simplify Window Layout + 精简窗å£å¸ƒå±€ + + + + Shift+Alt+0 + + + + + Dock Windows at Bottom + åœé çª—å£åˆ°åº•部 + + + + Dock Windows at Left Side + åœé çª—å£åˆ°å·¦ä¾§ + + + + Dock Windows at Top + åœé çª—å£åˆ°é¡¶éƒ¨ + + + + File %1 already exists. Please choose a different name. + 文件 %1 已存在。请选择一个ä¸åŒçš„å称。 + + + + Error importing data: %1 + å¯¼å…¥æ•°æ®æ—¶å‡ºé”™: %1 + + + + Import completed. + 导入完æˆã€‚ + + + + Delete View + 删除视图 + + + + Modify View + 修改视图 + + + + Delete Trigger + 删除触å‘器 + + + + Modify Trigger + 修改触å‘器 + + + + Delete Index + 删除索引 + + + + + Delete Table + 删除表 + + + + Setting PRAGMA values will commit your current transaction. +Are you sure? + 设置 PRAGMA 值将会æäº¤æ‚¨çš„当å‰äº‹åŠ¡ã€‚ +您确定å—? + + + + In-Memory database + 内存数æ®åº“ + + + + Are you sure you want to delete the table '%1'? +All data associated with the table will be lost. + 你确定è¦åˆ é™¤è¡¨ '%1' å—? +所有关è”的数æ®éƒ½ä¼šä¸¢å¤±ã€‚ + + + + Are you sure you want to delete the view '%1'? + 你确定è¦åˆ é™¤è§†å›¾ '%1' å—? + + + + Are you sure you want to delete the trigger '%1'? + 你确定è¦åˆ é™¤è§¦å‘器 '%1' å—? + + + + Are you sure you want to delete the index '%1'? + 你确定è¦åˆ é™¤ç´¢å¼• '%1' å—? + + + + Error: could not delete the table. + 错误: 无法删除表。 + + + + Error: could not delete the view. + 错误: 无法删除视图。 + + + + Error: could not delete the trigger. + 错误: 无法删除触å‘器。 + + + + Error: could not delete the index. + 错误: 无法删除索引。 + + + + Message from database engine: +%1 + æ¥è‡ªæ•°æ®åº“引擎的消æ¯: +%1 + + + + Editing the table requires to save all pending changes now. +Are you sure you want to save the database? + 编辑表格之å‰éœ€è¦ç«‹åˆ»ä¿å­˜æ‰€æœ‰ä¿®æ”¹ã€‚ +你确定è¦ä¿å­˜æ•°æ®åº“å—? + + + + You are already executing SQL statements. Do you want to stop them in order to execute the current statements instead? Note that this might leave the database in an inconsistent state. + ä½ å·²ç»åœ¨æ‰§è¡ŒSQL语å¥ã€‚是å¦è¦åœæ­¢æ‰§è¡Œå¹¶æ”¹ä¸ºæ‰§è¡Œå½“å‰è¯­å¥ï¼Ÿæ³¨æ„,这å¯èƒ½ä½¿æ•°æ®åº“处于ä¸å‡†ç¡®çš„状æ€ã€‚ + + + + -- EXECUTING SELECTION IN '%1' +-- + -- 执行 '%1' 中所选 +-- + + + + -- EXECUTING LINE IN '%1' +-- + -- 执行 '%1' 中的行 +-- + + + + -- EXECUTING ALL IN '%1' +-- + -- 执行 '%1' 中所有 +-- + + + + %1 rows returned in %2ms + %1 行返回,耗时 %2ms + + + + Choose text files + 选择文本文件 + + + + Import completed. Some foreign key constraints are violated. Please fix them before saving. + 导入完æˆã€‚一些外键约æŸè¢«è¿å了。请在ä¿å­˜ä¹‹å‰ä¿®å¤ã€‚ + + + + Modify Index + 修改索引 + + + + Modify Table + 修改表 + + + + Do you want to save the changes made to SQL tabs in the project file '%1'? + 是å¦è¦æŠŠå¯¹SQL的修改ä¿å­˜åˆ°å·¥ç¨‹æ–‡ä»¶ '%1' ? + + + + Select SQL file to open + é€‰æ‹©è¦æ‰“开的 SQL 文件 + + + + Select file name + 选择文件å + + + + Select extension file + 选择扩展文件 + + + + Extension successfully loaded. + 扩展æˆåŠŸåŠ è½½ã€‚ + + + + Error loading extension: %1 + 加载扩展时出错: %1 + + + + + Don't show again + ä¸å†æ˜¾ç¤º + + + + New version available. + 新版本å¯ç”¨ã€‚ + + + + Project saved to file '%1' + 工程已ä¿å­˜åˆ°æ–‡ä»¶ '%1' + + + + Collation needed! Proceed? + éœ€è¦æ•´ç†! ç»§ç»­? + + + + A table in this database requires a special collation function '%1' that this application can't provide without further knowledge. +If you choose to proceed, be aware bad things can happen to your database. +Create a backup! + æ•°æ®åº“中的一个表需è¦ç‰¹å®šçš„æ•´ç†æ–¹æ³• '%1' 但本应用程åºä¸äº†è§£æ•…无法æä¾›ã€‚ +如果您选择继续,å°å¿ƒå¯èƒ½ä¼šæœ‰ä¸å¥½çš„事情å‘生。 +记得备份! + + + + creating collation + åˆ›å»ºæ•´ç† + + + + Set a new name for the SQL tab. Use the '&&' character to allow using the following character as a keyboard shortcut. + 为 SQL 标签页设置新å称。使用 '&&' 字符æ¥å…许它作为键盘快æ·é”®ã€‚ + + + + Please specify the view name + 请指定视图åç§° + + + + There is already an object with that name. Please choose a different name. + 已有åŒå的对象。请选择一个ä¸åŒçš„å称。 + + + + View successfully created. + 视图æˆåŠŸåˆ›å»ºã€‚ + + + + Error creating view: %1 + 创建视图时出错: %1 + + + + This action will open a new SQL tab for running: + 此动作会打开新的 SQL 标签页以è¿è¡Œ: + + + + Press Help for opening the corresponding SQLite reference page. + 按下帮助以打开对应的 SQLite å‚考页。 + + + + NullLineEdit + + + Set to NULL + 设置为 NULL + + + + Alt+Del + + + + + PlotDock + + + Plot + 绘图 + + + + <html><head/><body><p>This pane shows the list of columns of the currently browsed table or the just executed query. You can select the columns that you want to be used as X or Y axis for the plot pane below. The table shows detected axis type that will affect the resulting plot. For the Y axis you can only select numeric columns, but for the X axis you will be able to select:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Date/Time</span>: strings with format &quot;yyyy-MM-dd hh:mm:ss&quot; or &quot;yyyy-MM-ddThh:mm:ss&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Date</span>: strings with format &quot;yyyy-MM-dd&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Time</span>: strings with format &quot;hh:mm:ss&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Label</span>: other string formats. Selecting this column as X axis will produce a Bars plot with the column values as labels for the bars</li><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Numeric</span>: integer or real values</li></ul><p>Double-clicking the Y cells you can change the used color for that graph.</p></body></html> + <html><head/><body><p>æ­¤é¢æ¿æ˜¾ç¤ºå½“å‰è¡¨æˆ–者刚刚执行的查询的列。你å¯ä»¥é€‰æ‹©åˆ—用åšåœ¨ä¸‹é¢ç”»å›¾æ—¶çš„ X è½´å’Œ Y 轴。表中显示检测到的会影å“绘图结果的轴类型。Y è½´åªå…许选择数值类型,但 X è½´å¯ä»¥é€‰æ‹©:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">日期/æ—¶é—´</span>: æ ¼å¼åŒ–的字符串 &quot;yyyy-MM-dd hh:mm:ss&quot; 或 &quot;yyyy-MM-ddThh:mm:ss&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">日期</span>: æ ¼å¼åŒ–的字符串 &quot;yyyy-MM-dd&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">æ—¶é—´</span>: æ ¼å¼åŒ–的字符串 &quot;hh:mm:ss&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">标签</span>: å…¶ä»–æ ¼å¼çš„字符串。选这项作为x轴,会绘制æ¡å½¢å›¾ï¼Œå¹¶ç”¨å€¼ä½œä¸ºæ¡å½¢çš„æ ‡ç­¾</li><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">数值</span>: 整数或实数值</li></ul><p>åŒå‡» Y å•元格å¯ä»¥æ”¹å˜å›¾ä¸­æ‰€ç”¨çš„颜色。</p></body></html> + + + + Columns + 列 + + + + X + X + + + + Y1 + Y1 + + + + Y2 + Y2 + + + + Axis Type + 轴类型 + + + + Here is a plot drawn when you select the x and y values above. + +Click on points to select them in the plot and in the table. Ctrl+Click for selecting a range of points. + +Use mouse-wheel for zooming and mouse drag for changing the axis range. + +Select the axes or axes labels to drag and zoom only in that orientation. + 这是在你在上é¢é€‰æ‹© x å’Œ y 值åŽç»˜åˆ¶å‡ºçš„图。 + +点击点å¯ä»¥åœ¨å›¾å’Œè¡¨æ ¼ä¸­é€‰ä¸­å®ƒä»¬ã€‚Ctrl+点击以选中一批点。 + +使用鼠标滚轮å¯ä»¥ç¼©æ”¾ï¼Œé¼ æ ‡æ‹–拽å¯ä»¥æ”¹å˜å标轴的范围。 + +选择轴或者轴上的标签并拖拽å¯ä»¥ç¼©æ”¾æ­¤æ–¹å‘。 + + + + Line type: + 线形: + + + + + None + æ—  + + + + Line + 折线 + + + + StepLeft + 左阶梯 + + + + StepRight + å³é˜¶æ¢¯ + + + + StepCenter + 中阶梯 + + + + Impulse + 脉冲 + + + + Point shape: + 点形: + + + + Cross + å‰ + + + + Plus + 加 + + + + Circle + 圈 + + + + Disc + 实心点 + + + + Square + 方形 + + + + Diamond + è±å½¢ + + + + Star + 星 + + + + Triangle + 三角 + + + + TriangleInverted + 倒三角 + + + + CrossSquare + å‰ä¸Žæ–¹å½¢ + + + + PlusSquare + 加与方形 + + + + CrossCircle + å‰ä¸Žåœˆ + + + + PlusCircle + 加与圈 + + + + Peace + å’Œå¹³ç¬¦å· + + + + <html><head/><body><p>Save current plot...</p><p>File format chosen by extension (png, jpg, pdf, bmp)</p></body></html> + <html><head/><body><p>ä¿å­˜å½“å‰å›¾è¡¨...</p><p>æ–‡ä»¶æ ¼å¼æŒ‰æ‰©å±•å选择(png, jpg, pdf, bmp)</p></body></html> + + + + Save current plot... + ä¿å­˜å½“å‰å›¾è¡¨... + + + + + Load all data and redraw plot + 载入所有数æ®å¹¶é‡æ–°ç»˜å›¾ + + + + + + Row # + 行 # + + + + Copy + å¤åˆ¶ + + + + Print... + 打å°... + + + + Show legend + 显示图例 + + + + Stacked bars + å †å çš„æ¡å½¢ + + + + Date/Time + 日期/æ—¶é—´ + + + + Date + 日期 + + + + Time + æ—¶é—´ + + + + + Numeric + 数值 + + + + Label + 标签 + + + + Invalid + 无效的 + + + + Load all data and redraw plot. +Warning: not all data has been fetched from the table yet due to the partial fetch mechanism. + 载入所有数æ®å¹¶é‡æ–°ç»˜å›¾ã€‚ +警告:由于部分加载机制,现在并没有加载所有的数æ®ã€‚ + + + + Choose an axis color + é€‰ä¸€ä¸ªåæ ‡è½´é¢œè‰² + + + + Choose a filename to save under + 选择一个文件åä¿å­˜ + + + + PNG(*.png);;JPG(*.jpg);;PDF(*.pdf);;BMP(*.bmp);;All Files(*) + PNG(*.png);;JPG(*.jpg);;PDF(*.pdf);;BMP(*.bmp);;所有文件(*) + + + + There are curves in this plot and the selected line style can only be applied to graphs sorted by X. Either sort the table or query by X to remove curves or select one of the styles supported by curves: None or Line. + 图中有曲线,选择的线形åªèƒ½ç”¨åˆ°æŒ‰ X 排列的图中。è¦ä¹ˆå¯¹è¡¨æŽ’åºæˆ–者用 X 查询,è¦ä¹ˆé€‰ä¸€ç§æ›²çº¿æ”¯æŒçš„线形:无或者折线。 + + + + Loading all remaining data for this table took %1ms. + 加载表中全部剩余数æ®èŠ±è´¹äº†%1毫秒。 + + + + PreferencesDialog + + + Preferences + 首选项 + + + + &General + 通用(&G) + + + + Remember last location + è®°ä½ä¸Šæ¬¡çš„ä½ç½® + + + + Always use this location + 总是使用此ä½ç½® + + + + Remember last location for session only + 仅在会è¯ä¸­è®°ä½ä¸Šæ¬¡çš„ä½ç½® + + + + Lan&guage + 语言(&G) + + + + Automatic &updates + 自动更新(&A) + + + + &Database + æ•°æ®åº“(&D) + + + + Database &encoding + æ•°æ®åº“ç¼–ç (&E) + + + + Open databases with foreign keys enabled. + 打开å¯ç”¨äº†å¤–键的数æ®åº“。 + + + + &Foreign keys + 外键(&F) + + + + + + + + + + + + enabled + å¯ç”¨ + + + + Default &location + 默认ä½ç½®(&L) + + + + + + ... + ... + + + + Remove line breaks in schema &view + 删除架构视图中的æ¢è¡Œ(&V) + + + + Show remote options + 显示远程选项 + + + + Prefetch block si&ze + 预å–å—尺寸(&Z) + + + + SQ&L to execute after opening database + 打开数æ®åº“åŽæ‰§è¡Œçš„ SQL(&L) + + + + Default field type + 默认字段类型 + + + + Data &Browser + æ•°æ®æµè§ˆå™¨(&B) + + + + Font + 字体 + + + + &Font + 字体(&F) + + + + Content + 内容 + + + + Symbol limit in cell + å•元格字符数é™åˆ¶ + + + + NULL + 空 + + + + Regular + 常规 + + + + Binary + 二进制 + + + + Background + 背景 + + + + Filters + 过滤 + + + + Threshold for completion and calculation on selection + 自动完æˆä¸Žæ±‡æ€»é™åˆ¶ + + + + Show images in cell + 显示å•元格中图片 + + + + Enable this option to show a preview of BLOBs containing image data in the cells. This can affect the performance of the data browser, however. + å¯ç”¨æ­¤é€‰é¡¹å¯ä»¥é¢„览å•元格BOLB中包å«çš„å›¾ç‰‡ã€‚ä½†è¿™ä¼šå½±å“æµè§ˆæ•°æ®çš„æ€§èƒ½ã€‚ + + + + Escape character + 转义字符 + + + + Delay time (&ms) + å»¶æ—¶(毫秒)(&M) + + + + Set the waiting time before a new filter value is applied. Can be set to 0 for disabling waiting. + 设置应用新过滤值å‰çš„等待时间。设为0以ç¦ç”¨ç­‰å¾…。 + + + + &SQL + &SQL + + + + Settings name + 设置åç§° + + + + Context + 上下文 + + + + Colour + 颜色 + + + + Bold + 粗体 + + + + Italic + 斜体 + + + + Underline + 下划线 + + + + Keyword + 关键字 + + + + Function + 函数 + + + + Table + 表 + + + + Comment + 注释 + + + + Identifier + 识别符 + + + + String + 字符串 + + + + Current line + 当å‰è¡Œ + + + + SQL &editor font size + SQL 编辑器字体大å°(&E) + + + + Tab size + Tab 长度 + + + + SQL editor &font + SQL 编辑器字体(&F) + + + + Error indicators + 显示代ç é”™è¯¯ + + + + Hori&zontal tiling + 水平平铺(&Z) + + + + If enabled the SQL code editor and the result table view are shown side by side instead of one over the other. + 如果å¯ç”¨ï¼ŒSQL ç¼–è¾‘å™¨å’Œç»“æžœè¡¨è§†å›¾å°†å¹¶æŽ’æ˜¾ç¤ºï¼Œè€Œä¸æ˜¯ä¸Šä¸‹æ˜¾ç¤ºã€‚ + + + + Code co&mpletion + 自动补全(&M) + + + + Toolbar style + 工具æ é£Žæ ¼ + + + + + + + + Only display the icon + 仅显示图标 + + + + + + + + Only display the text + 仅显示文本 + + + + + + + + The text appears beside the icon + æ–‡æœ¬åœ¨å›¾æ ‡æ— + + + + + + + + The text appears under the icon + 文本在图标下 + + + + + + + + Follow the style + éµå¾ªé£Žæ ¼ + + + + DB file extensions + æ•°æ®åº“文件扩展 + + + + Manage + ç®¡ç† + + + + Main Window + ä¸»çª—å£ + + + + Database Structure + æ•°æ®åº“结构 + + + + Browse Data + æµè§ˆæ•°æ® + + + + Execute SQL + 执行 SQL + + + + Edit Database Cell + 编辑数æ®åº“å•元格 + + + + When this value is changed, all the other color preferences are also set to matching colors. + 改å˜è¿™ä¸ªé€‰é¡¹ä¹Ÿä¼šæ”¹å˜å…¶ä»–的颜色风格。 + + + + Follow the desktop style + è·Ÿéšæ¡Œé¢é£Žæ ¼ + + + + Dark style + 黑暗风格 + + + + Application style + 界é¢é£Žæ ¼ + + + + This sets the font size for all UI elements which do not have their own font size option. + 此选项为所有组件设置字体大å°ï¼Œæœ‰å•独的字体大å°é€‰é¡¹çš„组件除外。 + + + + Font size + å­—ä½“å¤§å° + + + + When enabled, the line breaks in the Schema column of the DB Structure tab, dock and printed output are removed. + 当å¯ç”¨æ—¶ï¼Œæ•°æ®åº“结构标签页中的架构列里的æ¢è¡Œï¼Œæ˜¾ç¤ºã€æ‰“å°æ—¶è¢«ç§»é™¤ã€‚ + + + + Database structure font size + æ•°æ®åº“ç»“æž„å­—ä½“å¤§å° + + + + Font si&ze + 字体大å°(&Z) + + + + This is the maximum number of items allowed for some computationally expensive functionalities to be enabled: +Maximum number of rows in a table for enabling the value completion based on current values in the column. +Maximum number of indexes in a selection for calculating sum and average. +Can be set to 0 for disabling the functionalities. + å¯ç”¨ä¸€äº›è€—费资æºçš„计算的最大行数,包括: +å¯ç”¨è‡ªåŠ¨å®Œæˆçš„表中最大行数。 +自动进行求和与平å‡å€¼çš„æœ€å¤§é€‰æ‹©å•元格数é‡ã€‚ +å¯ä»¥è®¾ç½®ä¸º0以ç¦ç”¨è¿™äº›åŠŸèƒ½ã€‚ + + + + This is the maximum number of rows in a table for enabling the value completion based on current values in the column. +Can be set to 0 for disabling completion. + 这是表å¯ç”¨æ ¹æ®å½“å‰å€¼çš„自动补完的最大的列数é‡ã€‚ +设置æˆ0以ç¦ç”¨è¡¥å®Œã€‚ + + + + Field display + 字段显示 + + + + Displayed &text + 显示的文本(&T) + + + + + + + + + Click to set this color + 点击设置颜色 + + + + Text color + 文本颜色 + + + + Background color + 背景颜色 + + + + Preview only (N/A) + 仅预览 (N/A) + + + + Foreground + 剿™¯ + + + + SQL &results font size + SQL 结果的字体大å°(&R) + + + + &Wrap lines + æ¢è¡Œ(&W) + + + + Never + æ°¸ä¸ + + + + At word boundaries + 按照è¯è¾¹ç•Œ + + + + At character boundaries + 按照字æ¯è¾¹ç•Œ + + + + At whitespace boundaries + 按照空白字符边界 + + + + &Quotes for identifiers + 标识转义(&Q) + + + + Choose the quoting mechanism used by the application for identifiers in SQL code. + 选择 SQL 代ç ä¸­æ ‡è¯†çš„转义方å¼ã€‚ + + + + "Double quotes" - Standard SQL (recommended) + "åŒå¼•å·" - 标准 SQL (推è) + + + + `Grave accents` - Traditional MySQL quotes + `é‡éŸ³ç¬¦` - ç»å…¸çš„ MySQL 转义 + + + + [Square brackets] - Traditional MS SQL Server quotes + [方括å·] - ç»å…¸çš„ MS SQL Server 转义 + + + + Keywords in &UPPER CASE + 关键字大写(&U) + + + + When set, the SQL keywords are completed in UPPER CASE letters. + 设置时,SQL 关键字被自动补全为大写字æ¯ã€‚ + + + + When set, the SQL code lines that caused errors during the last execution are highlighted and the results frame indicates the error in the background + 设置时,导致上次执行出错的 SQL 代ç è¡Œä¼šè¢«é«˜äº®ã€‚ + + + + Close button on tabs + 标签显示关闭按钮 + + + + If enabled, SQL editor tabs will have a close button. In any case, you can use the contextual menu or the keyboard shortcut to close them. + 如果å¯ç”¨ï¼ŒSQL 编辑器标签页上将显示关闭按钮。无论是å¦å¯ç”¨ï¼Œä½ éƒ½å¯ä»¥é€šè¿‡å³é”®èœå•或者键盘快æ·é”®æ¥å…³é—­æ ‡ç­¾ã€‚ + + + + &Extensions + 扩展(&E) + + + + Select extensions to load for every database: + 选择æ¯ä¸ªæ•°æ®åº“è¦åŠ è½½çš„æ‰©å±•: + + + + Add extension + 添加扩展 + + + + Remove extension + 删除扩展 + + + + <html><head/><body><p>While supporting the REGEXP operator SQLite doesn't implement any regular expression<br/>algorithm but calls back the running application. DB Browser for SQLite implements this<br/>algorithm for you to let you use REGEXP out of the box. However, as there are multiple possible<br/>implementations of this and you might want to use another one, you're free to disable the<br/>application's implementation and load your own by using an extension. Requires restart of the application.</p></body></html> + <html><head/><body><p>è™½ç„¶æ”¯æŒ REGEXP è¿ç®—符,但是 SQLite 并没有实现任何正则表达å¼ç®—法,<br/>而是回调应用程åºã€‚DB Browser for SQLite 为您实现了算法,以便您å¯ä»¥<br/>打破常规使用 REGEXP。由于算法有多ç§å¯èƒ½çš„实现,您å¯èƒ½æƒ³ç”¨å…¶ä»–的,<br/>所以您å¯ä»¥ç¦ç”¨ç®—法实现并通过扩展加载您的实现。需è¦é‡å¯åº”用程åºã€‚</p></body></html> + + + + Disable Regular Expression extension + ç¦ç”¨æ­£åˆ™è¡¨è¾¾å¼æ‰©å±• + + + + <html><head/><body><p>SQLite provides an SQL function for loading extensions from a shared library file. Activate this if you want to use the <span style=" font-style:italic;">load_extension()</span> function from SQL code.</p><p>For security reasons, extension loading is turned off by default and must be enabled through this setting. You can always load extensions through the GUI, even though this option is disabled.</p></body></html> + <html><head/><body><p>SQLite æä¾›äº† SQL 函数用于从共享库中加载扩展。å¯ç”¨è¿™ä¸ªé€‰é¡¹ä»¥åœ¨SQL代ç ä¸­ä½¿ç”¨ <span style=" font-style:italic;">load_extension()</span> 函数。</p><p>因安全原因,加载扩展功能默认被关闭,须在此处手动å¯ç”¨ã€‚但å³ä½¿æ­¤é€‰é¡¹æœªå¯ç”¨ï¼Œä»èƒ½é€šè¿‡ä¸Šæ–¹çš„界é¢åŠ è½½æ‰©å±•ã€‚</p></body></html> + + + + Allow loading extensions from SQL code + å…许在SQL代ç é‡ŒåŠ è½½æ‰©å±• + + + + Remote + 远程 + + + + CA certificates + CA è¯ä¹¦ + + + + Proxy + ä»£ç†æœåС噍 + + + + Configure + é…ç½® + + + + + Subject CN + 主题 CN (Subject CN) + + + + Common Name + 公用åç§° (Common Name) + + + + Subject O + 主题 O (Subject O) + + + + Organization + 组织 (Organization) + + + + + Valid from + 有效期从 + + + + + Valid to + 有效期到 + + + + + Serial number + åºåˆ—å· + + + + Your certificates + 您的è¯ä¹¦ + + + + File + 文件 + + + + Subject Common Name + 主题公用åç§° (Subject Common Name) + + + + Issuer CN + ç­¾å‘人 CN (Issuer CN) + + + + Issuer Common Name + ç­¾å‘人公用åç§° (Issuer Common Name) + + + + Clone databases into + 克隆数æ®åº“ä¿¡æ¯ + + + + + Choose a directory + 选择一个目录 + + + + The language will change after you restart the application. + 语言将在é‡å¯åº”用程åºåŽæ”¹å˜ã€‚ + + + + Select extension file + 选择扩展文件 + + + + Extensions(*.so *.dylib *.dll);;All files(*) + 扩展(*.so *.dylib *.dll);;所有文件(*) + + + + Import certificate file + 导入è¯ä¹¦æ–‡ä»¶ + + + + No certificates found in this file. + 在文件中找ä¸åˆ°è¯ä¹¦ã€‚ + + + + Are you sure you want do remove this certificate? All certificate data will be deleted from the application settings! + 您确定è¦åˆ é™¤æ­¤è¯ä¹¦å—?所有的è¯ä¹¦æ•°æ®éƒ½ä¼šè¢«ä»Žåº”ç”¨è®¾ç½®ä¸­åˆ é™¤ï¼ + + + + Are you sure you want to clear all the saved settings? +All your preferences will be lost and default values will be used. + ä½ ç¡®å®šè¦æ¸…除所有ä¿å­˜çš„设置å—? +所有你åšçš„设置都会丢失,并使用默认值。 + + + + ProxyDialog + + + Proxy Configuration + ä»£ç†æœåС噍é…ç½® + + + + Pro&xy Type + ä»£ç†æœåŠ¡å™¨ç±»åž‹ + + + + Host Na&me + 主机å + + + + Port + ç«¯å£ + + + + Authentication Re&quired + è¦æ±‚éªŒè¯ + + + + &User Name + 用户å + + + + Password + å¯†ç  + + + + None + æ—  + + + + System settings + è·Ÿéšç³»ç»Ÿè®¾ç½® + + + + HTTP + HTTP + + + + Socks v5 + Socks v5 + + + + QObject + + + Error importing data + å¯¼å…¥æ•°æ®æ—¶å‡ºé”™ + + + + from record number %1 + è‡ªè®°å½•ç¼–å· %1 + + + + . +%1 + . +%1 + + + + Importing CSV file... + 导入CSV文件... + + + + Cancel + å–æ¶ˆ + + + + All files (*) + 所有文件 (*) + + + + SQLite database files (*.db *.sqlite *.sqlite3 *.db3) + SQLite æ•°æ®åº“文件 (*.db *.sqlite *.sqlite3 *.db3) + + + + Left + å·¦ + + + + Right + 有 + + + + Center + 居中 + + + + Justify + 两段 + + + + SQLite Database Files (*.db *.sqlite *.sqlite3 *.db3) + SQLite æ•°æ®åº“文件 (*.db *.sqlite *.sqlite3 *.db3) + + + + DB Browser for SQLite Project Files (*.sqbpro) + DB Browser for SQLite 工程文件 (*.sqbpro) + + + + SQL Files (*.sql) + SQL 文件 (*.sql) + + + + All Files (*) + 所有文件 (*) + + + + Text Files (*.txt) + 纯文本文件 (*.txt) + + + + Comma-Separated Values Files (*.csv) + CSV (逗å·åˆ†éš”)(*.csv) + + + + Tab-Separated Values Files (*.tsv) + TSV (制表符分隔)(*.tsv) + + + + Delimiter-Separated Values Files (*.dsv) + DSV (分隔符分隔)(*.dsv) + + + + Concordance DAT files (*.dat) + Concordance DAT 文件 (*.dat) + + + + JSON Files (*.json *.js) + JSON 文件 (*.json *.js) + + + + XML Files (*.xml) + XML 文件 (*.xml) + + + + Binary Files (*.bin *.dat) + 二进制文件 (*.bin *.dat) + + + + SVG Files (*.svg) + SVG 文件 (*.svg) + + + + Hex Dump Files (*.dat *.bin) + å六进制转储文件 (*.dat *.bin) + + + + Extensions (*.so *.dylib *.dll) + 扩展 (*.so *.dylib *.dll) + + + + RemoteCommitsModel + + + Commit ID + æäº¤ID + + + + Message + 说明 + + + + Date + 日期 + + + + Author + 作者 + + + + Size + å¤§å° + + + + Authored and committed by %1 + ç”± %1 为作者并æäº¤ + + + + Authored by %1, committed by %2 + ç”± %1 为作者,由 %2 æäº¤ + + + + RemoteDatabase + + + Error opening local databases list. +%1 + 打开本地数æ®åº“列表时出错。 +%1 + + + + Error creating local databases list. +%1 + 创建本地数æ®åº“列表时出错。 +%1 + + + + RemoteDock + + + Remote + 远程 + + + + Local + 本地 + + + + Identity + 身份 + + + + Push currently opened database to server + 推é€å½“剿‰“开的数æ®åº“到æœåС噍 + + + + DBHub.io + DBHub.io + + + + <html><head/><body><p>In this pane, remote databases from dbhub.io website can be added to DB Browser for SQLite. First you need an identity:</p><ol style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Login to the dbhub.io website (use your GitHub credentials or whatever you want)</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Click the button to &quot;Generate client certificate&quot; (that's your identity). That'll give you a certificate file (save it to your local disk).</li><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Go to the Remote tab in DB Browser for SQLite Preferences. Click the button to add a new certificate to DB Browser for SQLite and choose the just downloaded certificate file.</li></ol><p>Now the Remote panel shows your identity and you can add remote databases.</p></body></html> + <html><head/><body><p>åœ¨æ­¤é¢æ¿ï¼Œæ¥è‡ª dbhub.io 网站的远程数æ®åº“å¯ä»¥è¢«æ·»åŠ åˆ° DB4S。首先你需è¦ä¸€ä¸ªèº«ä»½:</p><ol style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">登录 dbhub.io 网站 (使用你的 GitHub è®¤è¯æˆ–其他什么)</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">点击按钮创建 DB4S è¯ä¹¦ (那是你的身份)。 这会给你一个è¯ä¹¦æ–‡ä»¶ (ä¿å­˜åˆ°ä½ çš„æœ¬åœ°ç¡¬ç›˜é‡Œ)。</li><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">å‰å¾€ DB4S 的设置中的远程选项å¡ã€‚点击添加è¯ä¹¦ï¼Œé€‰æ‹©åˆšæ‰ä¸‹è½½çš„æ–‡ä»¶ã€‚</li></ol><p>è¿™æ ·ï¼Œè¿œç¨‹é¢æ¿å°±ä¼šæ˜¾ç¤ºä½ çš„身份,之åŽå¯ä»¥æ·»åŠ è¿œç¨‹æ•°æ®åº“。</p></body></html> + + + + Current Database + 当剿•°æ®åº“ + + + + Clone + 克隆 + + + + User + 用户 + + + + Database + æ•°æ®åº“ + + + + Branch + 分支 + + + + Commits + æäº¤è®°å½• + + + + Commits for + æäº¤äºŽ + + + + Delete Database + 删除数æ®åº“ + + + + Delete the local clone of this database + 删除此数æ®åº“的本地克隆 + + + + Open in Web Browser + 在æµè§ˆå™¨ä¸­æ‰“å¼€ + + + + Open the web page for the current database in your browser + 在你的æµè§ˆå™¨ä¸­æ‰“开当剿•°æ®åº“的网页版 + + + + Clone from Link + 从链接克隆 + + + + Use this to download a remote database for local editing using a URL as provided on the web page of the database. + 使用数æ®åº“é¡µé¢æä¾›çš„é“¾æŽ¥ï¼Œå°†æ•°æ®åº“下载到本地以供编辑。 + + + + Refresh + 刷新 + + + + Reload all data and update the views + 釿–°è½½å…¥æ‰€æœ‰æ•°æ®å¹¶æ›´æ–°è§†å›¾ + + + + F5 + + + + + Clone Database + 克隆数æ®åº“ + + + + Open Database + 打开数æ®åº“ + + + + Open the local copy of this database + 打开此数æ®åº“çš„æœ¬åœ°æ‹·è´ + + + + Check out Commit + 签出æŸä¸ªæäº¤ + + + + Download and open this specific commit + 下载并打开特定的æäº¤ç‰ˆæœ¬ + + + + Check out Latest Commit + 签出最新æäº¤ + + + + Check out the latest commit of the current branch + 从当å‰åˆ†æ”¯ç­¾å‡ºæœ€è¿‘一次的æäº¤ç‰ˆæœ¬ + + + + Save Revision to File + 将版本å¦å­˜ä¸ºæ–‡ä»¶ + + + + Saves the selected revision of the database to another file + 将选择的版本的数æ®åº“ä¿å­˜åˆ°å¦ä¸€ä¸ªæ–‡ä»¶ + + + + Upload Database + 上传数æ®åº“ + + + + Upload this database as a new commit + 将当剿•°æ®åº“作为新的æäº¤ä¸Šä¼  + + + + <html><head/><body><p>You are currently using a built-in, read-only identity. For uploading your database, you need to configure and use your DBHub.io account.</p><p>No DBHub.io account yet? <a href="https://dbhub.io/"><span style=" text-decoration: underline; color:#007af4;">Create one now</span></a> and import your certificate <a href="#preferences"><span style=" text-decoration: underline; color:#007af4;">here</span></a> to share your databases.</p><p>For online help visit <a href="https://dbhub.io/about"><span style=" text-decoration: underline; color:#007af4;">here</span></a>.</p></body></html> + <html><head/><body><p>你正在使用内置的,åªè¯»çš„凭æ®ã€‚è¦ä¸Šä¼ ä½ çš„æ•°æ®åº“,你需è¦é…置使用你的 DBHub.io è´¦å·ã€‚</p><p>还没有 DBHub.io è´¦å·ï¼Ÿ<a href="https://dbhub.io/"><span style=" text-decoration: underline; color:#007af4;">注册一个</span></a> 并在 <a href="#preferences"><span style=" text-decoration: underline; color:#007af4;">此处</span></a> 导入你的è¯ä¹¦ã€‚</p><p>è¦èŽ·å¾—åœ¨çº¿å¸®åŠ©ï¼Œç‚¹å‡»<a href="https://dbhub.io/about"><span style=" text-decoration: underline; color:#007af4;">这里</span></a>。</p></body></html> + + + + Back + 返回 + + + + Select an identity to connect + 选择è¦ç”¨äºŽè¿žæŽ¥çš„å‡­æ® + + + + Public + 公用è¯ä¹¦ + + + + This downloads a database from a remote server for local editing. +Please enter the URL to clone from. You can generate this URL by +clicking the 'Clone Database in DB4S' button on the web page +of the database. + 将远程æœåŠ¡å™¨ä¸Šçš„æ•°æ®åº“下载到本地以编辑。 +请输入用于克隆的URL。å¯é€šè¿‡åœ¨ç½‘页上点击 +“Clone Database in DB4Sâ€èŽ·å¾—æ•°æ®åº“çš„URL。 + + + + Invalid URL: The host name does not match the host name of the current identity. + 无效的URL:主机å与凭æ®çš„主机åä¸ç¬¦ã€‚ + + + + Invalid URL: No branch name specified. + 无效的URL:未指定分支å。 + + + + Invalid URL: No commit ID specified. + 无效的URL:未指定æäº¤ID。 + + + + You have modified the local clone of the database. Fetching this commit overrides these local changes. +Are you sure you want to proceed? + ä½ å·²ç»ä¿®æ”¹äº†æœ¬åœ°çš„æ•°æ®åº“。此时获å–远程æäº¤å°†è¦†ç›–本地的更改。 +确实è¦ç»§ç»­å—? + + + + The database has unsaved changes. Are you sure you want to push it before saving? + æ•°æ®åº“有未ä¿å­˜çš„æ›´æ”¹ï¼Œç¡®å®žè¦åœ¨ä¿å­˜å‰æŽ¨é€å—? + + + + The database you are trying to delete is currently opened. Please close it before deleting. + å°è¯•删除的数æ®åº“当å‰å·²è¢«æ‰“开,请先将之关闭。 + + + + This deletes the local version of this database with all the changes you have not committed yet. Are you sure you want to delete this database? + 将删除本地的数æ®åº“,包括你未æäº¤çš„修改。 +确实è¦åˆ é™¤æ­¤æ•°æ®åº“å—? + + + + RemoteLocalFilesModel + + + Name + åç§° + + + + Branch + 分支 + + + + Last modified + 上次修改 + + + + Size + å¤§å° + + + + Commit + æäº¤ + + + + File + 文件 + + + + RemoteModel + + + Name + åç§° + + + + Last modified + 上次修改 + + + + Size + å¤§å° + + + + Commit + æäº¤ + + + + Size: + 大å°ï¼š + + + + Last Modified: + 上次修改: + + + + Licence: + 授æƒï¼š + + + + Default Branch: + 默认分支: + + + + RemoteNetwork + + + Choose a location to save the file + 选择ä¿å­˜ä½ç½® + + + + Error opening remote file at %1. +%2 + 打开远程文件 %1 时出错. +%2 + + + + Error: Invalid client certificate specified. + 错误: 指定了错误的客户端è¯ä¹¦ã€‚ + + + + Please enter the passphrase for this client certificate in order to authenticate. + 请输入客户端è¯ä¹¦çš„å£ä»¤ä»¥è¿›è¡Œèº«ä»½è®¤è¯ã€‚ + + + + Cancel + å–æ¶ˆ + + + + Uploading remote database to +%1 + 正在上传远程数æ®åº“到 +%1. {1?} + + + + Downloading remote database from +%1 + 正在下载远程数æ®åº“于 +%1. {1?} + + + + + Error: The network is not accessible. + 错误: 网络无法访问。 + + + + Error: Cannot open the file for sending. + 错误: 无法打开文件用于å‘é€ã€‚ + + + + RemotePushDialog + + + Push database + æŽ¨é€æ•°æ®åº“ + + + + Database na&me to push to + 推é€çš„æ•°æ®åº“å(&m) + + + + Commit message + æäº¤ä¿¡æ¯ + + + + Database licence + æ•°æ®åº“许å¯åè®® + + + + Public + 公开 + + + + Branch + 分支 + + + + Force push + å¼ºåˆ¶æŽ¨é€ + + + + Username + 用户å + + + + Database will be public. Everyone has read access to it. + æ•°æ®åº“将是公有的。所有人都å¯ä»¥è¯»å–它。 + + + + Database will be private. Only you have access to it. + æ•°æ®åº“å°†æ˜¯ç§æœ‰çš„ã€‚åªæœ‰æ‚¨å¯ä»¥è®¿é—®å®ƒã€‚ + + + + Use with care. This can cause remote commits to be deleted. + å°å¿ƒä½¿ç”¨ã€‚è¿™å¯èƒ½ä¼šå¯¼è‡´è¿œç¨‹æäº¤è¢«åˆ é™¤ã€‚ + + + + RunSql + + + Execution aborted by user + æ“作被用户终止 + + + + , %1 rows affected + ,%1 行数æ®å—å½±å“ + + + + query executed successfully. Took %1ms%2 + 查询执行æˆåŠŸã€‚è€—æ—¶ %1ms%2 + + + + executing query + 执行查询 + + + + SelectItemsPopup + + + A&vailable + å¯ç”¨(&V) + + + + Sele&cted + 已选(&C) + + + + SqlExecutionArea + + + Form + è¡¨å• + + + + Find previous match [Shift+F3] + 查找上一个 [Shift+F3] + + + + Find previous match with wrapping + æŒ‰é¡ºåºæŸ¥æ‰¾ä¸Šä¸€é¡¹ + + + + Shift+F3 + + + + + The found pattern must be a whole word + æ‰¾åˆ°çš„å¿…é¡»æ˜¯ä¸€ä¸ªå®Œæ•´çš„è¯ + + + + Whole Words + å…¨å­—åŒ¹é… + + + + Text pattern to find considering the checks in this frame + 符åˆè¿™é‡Œçš„é€‰æ‹©è¦æŸ¥æ‰¾çš„æ–‡æœ¬ + + + + Find in editor + 在编辑器中查找 + + + + The found pattern must match in letter case + æœç´¢å¿…须大å°å†™åŒ¹é… + + + + Case Sensitive + 大å°å†™æ•感 + + + + Find next match [Enter, F3] + 查找下一个 [Enter, F3] + + + + Find next match with wrapping + 循环查找下一个 + + + + F3 + + + + + Interpret search pattern as a regular expression + è§£æžæŸ¥æ‰¾ç›®æ ‡ä¸ºæ­£åˆ™è¡¨è¾¾å¼ + + + + <html><head/><body><p>When checked, the pattern to find is interpreted as a UNIX regular expression. See <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>.</p></body></html> + <html><head/><body><p>é€‰ä¸­æ—¶ï¼Œè¦æŸ¥æ‰¾çš„æ¨¡å¼è¢«è§£é‡Šä¸º UNIX 正则表达å¼ã€‚å‚阅 <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Wikibooks 中的正则表达å¼</a>.</p></body></html> + + + + Regular Expression + æ­£åˆ™è¡¨è¾¾å¼ + + + + + Close Find Bar + å…³é—­æŸ¥æ‰¾æ  + + + + <html><head/><body><p>Results of the last executed statements.</p><p>You may want to collapse this panel and use the <span style=" font-style:italic;">SQL Log</span> dock with <span style=" font-style:italic;">User</span> selection instead.</p></body></html> + <html><head/><body><p>上次执行的语å¥çš„结果。</p><p>ä½ å¯èƒ½å¸Œæœ›æŠ˜å è¿™ä¸ªçª—格并使用 <span style=" font-style:italic;">SQL 日志</span> 区域查看æäº¤è‡ª <span style=" font-style:italic;">用户</span> 的结果。</p></body></html> + + + + Results of the last executed statements + 上次执行语å¥çš„结果 + + + + This field shows the results and status codes of the last executed statements. + è¿™ä¸ªå­—æ®µæ˜¾ç¤ºæœ€åŽæ‰§è¡Œçš„语å¥çš„结果和状æ€ç ã€‚ + + + + Couldn't read file: %1. + æ— æ³•è¯»å–æ–‡ä»¶: %1。 + + + + + Couldn't save file: %1. + 无法ä¿å­˜æ–‡ä»¶: %1。 + + + + Your changes will be lost when reloading it! + 釿–°åŠ è½½æ—¶ï¼Œä½ çš„æ›´æ”¹å°†ä¼šä¸¢å¤±ï¼ + + + + The file "%1" was modified by another program. Do you want to reload it?%2 + 文件 "%1" 已被其他程åºä¿®æ”¹ã€‚是å¦è¦é‡æ–°åŠ è½½ï¼Ÿ%2 + + + + SqlTextEdit + + + Ctrl+/ + + + + + SqlUiLexer + + + (X) The abs(X) function returns the absolute value of the numeric argument X. + + + + + () The changes() function returns the number of database rows that were changed or inserted or deleted by the most recently completed INSERT, DELETE, or UPDATE statement. + + + + + (X1,X2,...) The char(X1,X2,...,XN) function returns a string composed of characters having the unicode code point values of integers X1 through XN, respectively. + + + + + (X,Y,...) The coalesce() function returns a copy of its first non-NULL argument, or NULL if all arguments are NULL + + + + + (X,Y) The glob(X,Y) function is equivalent to the expression "Y GLOB X". + + + + + (X,Y) The ifnull() function returns a copy of its first non-NULL argument, or NULL if both arguments are NULL. + + + + + (X,Y) The instr(X,Y) function finds the first occurrence of string Y within string X and returns the number of prior characters plus 1, or 0 if Y is nowhere found within X. + + + + + (X) The hex() function interprets its argument as a BLOB and returns a string which is the upper-case hexadecimal rendering of the content of that blob. + + + + + () The last_insert_rowid() function returns the ROWID of the last row insert from the database connection which invoked the function. + + + + + (X) For a string value X, the length(X) function returns the number of characters (not bytes) in X prior to the first NUL character. + + + + + (X,Y) The like() function is used to implement the "Y LIKE X" expression. + + + + + (X,Y,Z) The like() function is used to implement the "Y LIKE X ESCAPE Z" expression. + + + + + (X) The load_extension(X) function loads SQLite extensions out of the shared library file named X. +Use of this function must be authorized from Preferences. + + + + + (X,Y) The load_extension(X) function loads SQLite extensions out of the shared library file named X using the entry point Y. +Use of this function must be authorized from Preferences. + + + + + (X) The lower(X) function returns a copy of string X with all ASCII characters converted to lower case. + + + + + (X) ltrim(X) removes spaces from the left side of X. + + + + + (X,Y) The ltrim(X,Y) function returns a string formed by removing any and all characters that appear in Y from the left side of X. + + + + + (X,Y,...) The multi-argument max() function returns the argument with the maximum value, or return NULL if any argument is NULL. + + + + + (X,Y,...) The multi-argument min() function returns the argument with the minimum value. + + + + + (X,Y) The nullif(X,Y) function returns its first argument if the arguments are different and NULL if the arguments are the same. + + + + + (FORMAT,...) The printf(FORMAT,...) SQL function works like the sqlite3_mprintf() C-language function and the printf() function from the standard C library. + + + + + (X) The quote(X) function returns the text of an SQL literal which is the value of its argument suitable for inclusion into an SQL statement. + + + + + () The random() function returns a pseudo-random integer between -9223372036854775808 and +9223372036854775807. + + + + + (N) The randomblob(N) function return an N-byte blob containing pseudo-random bytes. + + + + + (X,Y,Z) The replace(X,Y,Z) function returns a string formed by substituting string Z for every occurrence of string Y in string X. + + + + + (X) The round(X) function returns a floating-point value X rounded to zero digits to the right of the decimal point. + + + + + (X,Y) The round(X,Y) function returns a floating-point value X rounded to Y digits to the right of the decimal point. + + + + + (X) rtrim(X) removes spaces from the right side of X. + + + + + (X,Y) The rtrim(X,Y) function returns a string formed by removing any and all characters that appear in Y from the right side of X. + + + + + (X) The soundex(X) function returns a string that is the soundex encoding of the string X. + + + + + (X,Y) substr(X,Y) returns all characters through the end of the string X beginning with the Y-th. + + + + + (X,Y,Z) The substr(X,Y,Z) function returns a substring of input string X that begins with the Y-th character and which is Z characters long. + + + + + () The total_changes() function returns the number of row changes caused by INSERT, UPDATE or DELETE statements since the current database connection was opened. + + + + + (X) trim(X) removes spaces from both ends of X. + + + + + (X,Y) The trim(X,Y) function returns a string formed by removing any and all characters that appear in Y from both ends of X. + + + + + (X) The typeof(X) function returns a string that indicates the datatype of the expression X. + + + + + (X) The unicode(X) function returns the numeric unicode code point corresponding to the first character of the string X. + + + + + (X) The upper(X) function returns a copy of input string X in which all lower-case ASCII characters are converted to their upper-case equivalent. + + + + + (N) The zeroblob(N) function returns a BLOB consisting of N bytes of 0x00. + + + + + + + + (timestring,modifier,modifier,...) + + + + + (format,timestring,modifier,modifier,...) + + + + + (X) The avg() function returns the average value of all non-NULL X within a group. + + + + + (X) The count(X) function returns a count of the number of times that X is not NULL in a group. + + + + + (X) The group_concat() function returns a string which is the concatenation of all non-NULL values of X. + + + + + (X,Y) The group_concat() function returns a string which is the concatenation of all non-NULL values of X. If parameter Y is present then it is used as the separator between instances of X. + + + + + (X) The max() aggregate function returns the maximum value of all values in the group. + + + + + (X) The min() aggregate function returns the minimum non-NULL value of all values in the group. + + + + + + (X) The sum() and total() aggregate functions return sum of all non-NULL values in the group. + + + + + () The number of the row within the current partition. Rows are numbered starting from 1 in the order defined by the ORDER BY clause in the window definition, or in arbitrary order otherwise. + + + + + () The row_number() of the first peer in each group - the rank of the current row with gaps. If there is no ORDER BY clause, then all rows are considered peers and this function always returns 1. + + + + + () The number of the current row's peer group within its partition - the rank of the current row without gaps. Partitions are numbered starting from 1 in the order defined by the ORDER BY clause in the window definition. If there is no ORDER BY clause, then all rows are considered peers and this function always returns 1. + + + + + () Despite the name, this function always returns a value between 0.0 and 1.0 equal to (rank - 1)/(partition-rows - 1), where rank is the value returned by built-in window function rank() and partition-rows is the total number of rows in the partition. If the partition contains only one row, this function returns 0.0. + + + + + () The cumulative distribution. Calculated as row-number/partition-rows, where row-number is the value returned by row_number() for the last peer in the group and partition-rows the number of rows in the partition. + + + + + (N) Argument N is handled as an integer. This function divides the partition into N groups as evenly as possible and assigns an integer between 1 and N to each group, in the order defined by the ORDER BY clause, or in arbitrary order otherwise. If necessary, larger groups occur first. This function returns the integer value assigned to the group that the current row is a part of. + + + + + (expr) Returns the result of evaluating expression expr against the previous row in the partition. Or, if there is no previous row (because the current row is the first), NULL. + + + + + (expr,offset) If the offset argument is provided, then it must be a non-negative integer. In this case the value returned is the result of evaluating expr against the row offset rows before the current row within the partition. If offset is 0, then expr is evaluated against the current row. If there is no row offset rows before the current row, NULL is returned. + + + + + + (expr,offset,default) If default is also provided, then it is returned instead of NULL if the row identified by offset does not exist. + + + + + (expr) Returns the result of evaluating expression expr against the next row in the partition. Or, if there is no next row (because the current row is the last), NULL. + + + + + (expr,offset) If the offset argument is provided, then it must be a non-negative integer. In this case the value returned is the result of evaluating expr against the row offset rows after the current row within the partition. If offset is 0, then expr is evaluated against the current row. If there is no row offset rows after the current row, NULL is returned. + + + + + (expr) This built-in window function calculates the window frame for each row in the same way as an aggregate window function. It returns the value of expr evaluated against the first row in the window frame for each row. + + + + + (expr) This built-in window function calculates the window frame for each row in the same way as an aggregate window function. It returns the value of expr evaluated against the last row in the window frame for each row. + + + + + (expr,N) This built-in window function calculates the window frame for each row in the same way as an aggregate window function. It returns the value of expr evaluated against the row N of the window frame. Rows are numbered within the window frame starting from 1 in the order defined by the ORDER BY clause if one is present, or in arbitrary order otherwise. If there is no Nth row in the partition, then NULL is returned. + + + + + SqliteTableModel + + + reading rows + 读å–行 + + + + loading... + 正在加载... + + + + References %1(%2) +Hold %3Shift and click to jump there + 引用 %1(%2) +æŒ‰ä½ %3Shift 并点击以跳转 + + + + Error changing data: +%1 + 更改数æ®åº“时出错: +%1 + + + + retrieving list of columns + 正在检索列的列表 + + + + Fetching data... + æ­£åœ¨æ‹‰å–æ•°æ®... + + + + + Cancel + å–æ¶ˆ + + + + TableBrowser + + + Browse Data + æµè§ˆæ•°æ® + + + + &Table: + 表(&T): + + + + Select a table to browse data + 选择一个表以æµè§ˆæ•°æ® + + + + Use this list to select a table to be displayed in the database view + ä½¿ç”¨è¿™ä¸ªåˆ—è¡¨é€‰æ‹©ä¸€ä¸ªè¦æ˜¾ç¤ºåœ¨æ•°æ®åº“视图中的表 + + + + This is the database table view. You can do the following actions: + - Start writing for editing inline the value. + - Double-click any record to edit its contents in the cell editor window. + - Alt+Del for deleting the cell content to NULL. + - Ctrl+" for duplicating the current record. + - Ctrl+' for copying the value from the cell above. + - Standard selection and copy/paste operations. + 这是数æ®åº“表视图。你å¯ä»¥è¿›è¡Œä»¥ä¸‹æ“作: + - 直接打字以在这里直接编辑。 + - åŒå‡»è®°å½•以打开å•元格编辑窗å£ã€‚ + - Alt+Del 删除å•å…ƒæ ¼å†…å®¹ï¼Œå˜æˆNULL。 + - Ctrl+" é‡å¤ä¸€ä»½å½“å‰è®°å½•。 + - Ctrl+' 从上é¢çš„å•元格拷è´ã€‚ + - 标准的å¤åˆ¶/粘贴æ“作。 + + + + Text pattern to find considering the checks in this frame + 符åˆè¿™é‡Œçš„é€‰æ‹©è¦æŸ¥æ‰¾çš„æ–‡æœ¬ + + + + Find in table + 在表中查找 + + + + Find previous match [Shift+F3] + 查找上一个 [Shift+F3] + + + + Find previous match with wrapping + æŒ‰é¡ºåºæŸ¥æ‰¾ä¸Šä¸€é¡¹ + + + + Shift+F3 + + + + + Find next match [Enter, F3] + 查找下一个 [Enter, F3] + + + + Find next match with wrapping + 循环查找下一个 + + + + F3 + + + + + The found pattern must match in letter case + æœç´¢å¿…须大å°å†™åŒ¹é… + + + + Case Sensitive + 大å°å†™æ•感 + + + + The found pattern must be a whole word + æ‰¾åˆ°çš„å¿…é¡»æ˜¯ä¸€ä¸ªå®Œæ•´çš„è¯ + + + + Whole Cell + å•å…ƒæ ¼åŒ¹é… + + + + Interpret search pattern as a regular expression + è§£æžæŸ¥æ‰¾ç›®æ ‡ä¸ºæ­£åˆ™è¡¨è¾¾å¼ + + + + <html><head/><body><p>When checked, the pattern to find is interpreted as a UNIX regular expression. See <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>.</p></body></html> + <html><head/><body><p>选中时,æœç´¢å…³é”®è¯è¢«è§†ä¸ºUNIX正则表达å¼ã€‚å‚阅<a href="https://en.wikibooks.org/wiki/Regular_Expressions">Wikibooks 上对正则表达å¼çš„介ç»</a>。</p></body></html> + + + + Regular Expression + æ­£åˆ™è¡¨è¾¾å¼ + + + + + Close Find Bar + å…³é—­æŸ¥æ‰¾æ  + + + + Text to replace with + è¦æ›¿æ¢çš„æ–‡æœ¬ + + + + Replace with + æ›¿æ¢ + + + + Replace next match + 替æ¢ä¸‹ä¸ªåŒ¹é…的文本 + + + + + Replace + æ›¿æ¢ + + + + Replace all matches + æ›¿æ¢æ‰€æœ‰åŒ¹é… + + + + Replace all + å…¨éƒ¨æ›¿æ¢ + + + + <html><head/><body><p>Scroll to the beginning</p></body></html> + <html><head/><body><p>滚动到开始</p></body></html> + + + + <html><head/><body><p>Clicking this button navigates to the beginning in the table view above.</p></body></html> + <html><head/><body><p>点击这个按钮在上é¢çš„表视图中导航到最å‰ã€‚</p></body></html> + + + + |< + |< + + + + Scroll one page upwards + 上翻一页 + + + + <html><head/><body><p>Clicking this button navigates one page of records upwards in the table view above.</p></body></html> + <html><head/><body><p>点击按钮将表中显示的记录å‘上翻一页。</p></body></html> + + + + < + < + + + + 0 - 0 of 0 + 0 - 0 / 0 + + + + Scroll one page downwards + 下翻一页 + + + + <html><head/><body><p>Clicking this button navigates one page of records downwards in the table view above.</p></body></html> + <html><head/><body><p>点击按钮将表中显示的记录å‘下翻一页。</p></body></html> + + + + > + > + + + + Scroll to the end + æ»šåŠ¨åˆ°ç»“æŸ + + + + <html><head/><body><p>Clicking this button navigates up to the end in the table view above.</p></body></html> + <html><head/><body><p>点击这个按钮在上é¢çš„表视图中导航到最åŽã€‚</p></body></html> + + + + >| + >| + + + + <html><head/><body><p>Click here to jump to the specified record</p></body></html> + <html><head/><body><p>点击这里跳到指定的记录</p></body></html> + + + + <html><head/><body><p>This button is used to navigate to the record number specified in the Go to area.</p></body></html> + <html><head/><body><p>这个按钮用于导航到在“转到â€åŒºåŸŸä¸­æŒ‡å®šçš„记录å·ã€‚</p></body></html> + + + + Go to: + 转到: + + + + Enter record number to browse + è¾“å…¥è¦æµè§ˆçš„è®°å½•å· + + + + Type a record number in this area and click the Go to: button to display the record in the database view + 在这个区域中输入一个记录å·ï¼Œå¹¶ç‚¹å‡»â€œè½¬åˆ°:â€æŒ‰é’®ä»¥åœ¨æ•°æ®åº“视图中显示记录 + + + + 1 + 1 + + + + Show rowid column + 显示 rowid 列 + + + + Toggle the visibility of the rowid column + åˆ‡æ¢ rowid 列的å¯è§æ€§ + + + + Unlock view editing + è§£é”视图编辑 + + + + This unlocks the current view for editing. However, you will need appropriate triggers for editing. + è§£é”当å‰è§†å›¾ä»¥ç¼–辑。然而,你需è¦åˆé€‚的触å‘器æ¥ç¼–辑。 + + + + Edit display format + ç¼–è¾‘æ˜¾ç¤ºæ ¼å¼ + + + + Edit the display format of the data in this column + 编辑列中数æ®çš„æ˜¾ç¤ºæ ¼å¼ + + + + + New Record + 新建记录 + + + + + Insert a new record in the current table + 在当å‰è¡¨ä¸­æ’å…¥ä¸€æ¡æ–°è®°å½• + + + + <html><head/><body><p>This button creates a new record in the database. Hold the mouse button to open a pop-up menu of different options:</p><ul><li><span style=" font-weight:600;">New Record</span>: insert a new record with default values in the database.</li><li><span style=" font-weight:600;">Insert Values...</span>: open a dialog for entering values before they are inserted in the database. This allows to enter values acomplishing the different constraints. This dialog is also open if the <span style=" font-weight:600;">New Record</span> option fails due to these constraints.</li></ul></body></html> + <html><head/><body><p>此按钮在数æ®åº“中创建新记录。按ä½é¼ æ ‡æŒ‰é’®ä»¥æ‰“å¼€èœå•选择ä¸åŒé€‰é¡¹ï¼š</p><ul><li><span style=" font-weight:600;">新记录</span>: 用默认值æ’å…¥ä¸€æ¡æ–°è®°å½•到数æ®åº“中。</li><li><span style=" font-weight:600;">æ’入值...</span>: æ‰“å¼€å¯¹è¯æ¡†ç¼–è¾‘è¦æ’入的值。å¯ä»¥è¾“入满足约æŸçš„值。如果 <span style=" font-weight:600;">新记录</span> é€‰é¡¹å¤±è´¥ï¼Œå¯¹è¯æ¡†ä¹Ÿä¼šæ‰“开。</li></ul></body></html> + + + + + Delete Record + 删除记录 + + + + Delete the current record + 删除当å‰è®°å½• + + + + + This button deletes the record or records currently selected in the table + 此按钮删除表里当å‰é€‰ä¸­çš„记录 + + + + + Insert new record using default values in browsed table + 用默认值æ’å…¥ä¸€æ¡æ–°è®°å½•åˆ°å½“å‰æµè§ˆçš„表中 + + + + Insert Values... + æ’入值... + + + + + Open a dialog for inserting values in a new record + æ‰“å¼€å¯¹è¯æ¡†ä»¥æ’入值到新记录中 + + + + Export to &CSV + 导出到 &CSV + + + + + Export the filtered data to CSV + å¯¼å‡ºå½“å‰æ•°æ®åˆ° CSV + + + + This button exports the data of the browsed table as currently displayed (after filters, display formats and order column) as a CSV file. + æ­¤æŒ‰é’®å¯¼å‡ºå½“å‰æµè§ˆã€è¿‡æ»¤çš„è¡¨çš„æ•°æ® (过滤åŽï¼Œæ˜¾ç¤ºæ ¼å¼å’Œåˆ—的顺åº) 到一个CSV文件。 + + + + Save as &view + ä¿å­˜ä¸ºè§†å›¾(&V) + + + + + Save the current filter, sort column and display formats as a view + ä¿å­˜å½“å‰è¿‡æ»¤ï¼Œåˆ—排åºå’Œæ˜¾ç¤ºæ ¼å¼ä¸ºè§†å›¾ + + + + This button saves the current setting of the browsed table (filters, display formats and order column) as an SQL view that you can later browse or use in SQL statements. + 此按钮ä¿å­˜å½“剿µè§ˆè¡¨æ ¼çš„设置 (过滤,显示格å¼å’Œåˆ—的顺åº) 为SQL视图,之åŽå¯ä»¥å†ç”¨SQLè¯­å¥æµè§ˆã€‚ + + + + Save Table As... + 表å¦å­˜ä¸º... + + + + + Save the table as currently displayed + æŒ‰å½“å‰æ˜¾ç¤ºçš„æ ·å­ä¿å­˜è¡¨ + + + + <html><head/><body><p>This popup menu provides the following options applying to the currently browsed and filtered table:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Export to CSV: this option exports the data of the browsed table as currently displayed (after filters, display formats and order column) to a CSV file.</li><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Save as view: this option saves the current setting of the browsed table (filters, display formats and order column) as an SQL view that you can later browse or use in SQL statements.</li></ul></body></html> + <html><head/><body><p>æ­¤èœå•æä¾›ä»¥ä¸‹å¯åº”ç”¨åˆ°å½“å‰æµè§ˆã€è¿‡æ»¤çš„表的选项:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">导出到CSV: å¯¼å‡ºå½“å‰æµè§ˆã€è¿‡æ»¤çš„è¡¨çš„æ•°æ® (过滤åŽï¼Œæ˜¾ç¤ºæ ¼å¼å’Œåˆ—的顺åº) 到一个CSV文件。</li><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">ä¿å­˜ä¸ºè§†å›¾: 此选项ä¿å­˜å½“剿µè§ˆè¡¨æ ¼çš„设置 (过滤,显示格å¼å’Œåˆ—的顺åº) 为SQL视图,之åŽå¯ä»¥å†ç”¨SQLè¯­å¥æµè§ˆã€‚</li></ul></body></html> + + + + Hide column(s) + éšè—列 + + + + Hide selected column(s) + éšè—选中的列 + + + + Show all columns + 显示所有列 + + + + Show all columns that were hidden + 显示所有被éšè—的列 + + + + + Set encoding + è®¾ç½®ç¼–ç  + + + + Change the encoding of the text in the table cells + 更改表å•å…ƒæ ¼ä¸­æ–‡æœ¬çš„ç¼–ç  + + + + Set encoding for all tables + è®¾ç½®æ‰€æœ‰è¡¨çš„ç¼–ç  + + + + Change the default encoding assumed for all tables in the database + 修改数æ®åº“ä¸­æ‰€æœ‰è¡¨çš„é»˜è®¤ç¼–ç  + + + + Clear Filters + 清除过滤 + + + + Clear all filters + 清除所有过滤 + + + + + This button clears all the filters set in the header input fields for the currently browsed table. + æ­¤æŒ‰é’®å°†æ¸…é™¤å½“å‰æµè§ˆè¡¨çš„æ‰€æœ‰åœ¨å¤´éƒ¨è¾“入区的过滤器。 + + + + Clear Sorting + æ¸…é™¤æŽ’åº + + + + Reset the order of rows to the default + 将行的顺åºé‡ç½®ä¸ºé»˜è®¤ + + + + + This button clears the sorting columns specified for the currently browsed table and returns to the default order. + æ­¤æŒ‰é’®æ¸…é™¤å½“å‰æµè§ˆçš„表的列排åºï¼Œé‡ç½®ä¸ºé»˜è®¤å€¼ã€‚ + + + + Print + æ‰“å° + + + + Print currently browsed table data + 打å°å½“剿µè§ˆè¡¨ä¸­çš„æ•°æ® + + + + Print currently browsed table data. Print selection if more than one cell is selected. + 打å°å½“剿­£åœ¨æµè§ˆçš„表中的数æ®ã€‚如果选中了多于一个的å•元格,就打å°é€‰ä¸­åŒºåŸŸã€‚ + + + + Ctrl+P + + + + + Refresh + 刷新 + + + + Refresh the data in the selected table + åˆ·æ–°é€‰ä¸­è¡¨ä¸­çš„æ•°æ® + + + + This button refreshes the data in the currently selected table. + 这个按钮刷新在当å‰é€‰æ‹©çš„表中的数æ®ã€‚ + + + + F5 + + + + + Find in cells + 在å•元格中查找 + + + + Open the find tool bar which allows you to search for values in the table view below. + 打开查找æ ï¼Œå¯ä»¥åœ¨å…¶ä¸­æœç´¢è¡¨å†…æ•°æ®ã€‚ + + + + + Bold + 粗体 + + + + Ctrl+B + + + + + + Italic + 斜体 + + + + + Underline + 下划线 + + + + Ctrl+U + + + + + + Align Right + å³å¯¹é½ + + + + + Align Left + å·¦å¯¹é½ + + + + + Center Horizontally + 垂直居中 + + + + + Justify + ä¸¤ç«¯å¯¹é½ + + + + + Edit Conditional Formats... + 编辑æ¡ä»¶æ ¼å¼... + + + + Edit conditional formats for the current column + 为当å‰åˆ—设置æ¡ä»¶æ ¼å¼ + + + + Clear Format + æ¸…é™¤æ ¼å¼ + + + + Clear All Formats + æ¸…é™¤å…¨éƒ¨æ ¼å¼ + + + + + Clear all cell formatting from selected cells and all conditional formats from selected columns + 清除当å‰é€‰æ‹©çš„å•元格的格å¼å’Œå½“å‰é€‰æ‹©çš„列的æ¡ä»¶æ ¼å¼ + + + + + Font Color + 字体颜色 + + + + + Background Color + 背景颜色 + + + + Toggle Format Toolbar + åˆ‡æ¢æ ¼å¼å·¥å…·æ  + + + + Show/hide format toolbar + 显示或éšè—æ ¼å¼å·¥å…·æ  + + + + + This button shows or hides the formatting toolbar of the Data Browser + 此按钮显示或éšè—æµè§ˆæ•°æ®çª—å£çš„æ ¼å¼å·¥å…·æ  + + + + Select column + 选择列 + + + + Ctrl+Space + + + + + Replace text in cells + 在å•å…ƒæ ¼ä¸­æ›¿æ¢ + + + + Filter in any column + 在所有列中过滤 + + + + Ctrl+R + + + + + %n row(s) + + %n 行 + + + + + , %n column(s) + + , %n 列 + + + + + . Sum: %1; Average: %2; Min: %3; Max: %4 + . 求和: %1; å¹³å‡å€¼: %2; 最å°å€¼: %3; 最大值: %4 + . Sum: %1; Average: %2; Min: %3; Max: %4 + + + + Conditional formats for "%1" + "%1" çš„æ¡ä»¶æ ¼å¼ + + + + determining row count... + 正在决定行数... + + + + %1 - %2 of >= %3 + %1 - %2 / 超过 %3 + + + + %1 - %2 of %3 + %1 - %2 / %3 + + + + Please enter a pseudo-primary key in order to enable editing on this view. This should be the name of a unique column in the view. + 请输入一个伪主键以在当å‰è§†å›¾å¯ç”¨ç¼–è¾‘ã€‚è¿™éœ€è¦æ˜¯è§†å›¾ä¸­çš„一个满足唯一性的列的å字。 + + + + Delete Records + 删除记录 + + + + Duplicate records + é‡å¤è®°å½• + + + + Duplicate record + é‡å¤çš„记录 + + + + Ctrl+" + + + + + Adjust rows to contents + 按内容调整行高 + + + + Error deleting record: +%1 + 删除记录时出错: +%1 + + + + Please select a record first + 请首先选择一æ¡è®°å½• + + + + There is no filter set for this table. View will not be created. + 此表没有过滤。视图ä¸ä¼šè¢«åˆ›å»ºã€‚ + + + + Please choose a new encoding for all tables. + 请为所有表选择新的编ç ã€‚ + + + + Please choose a new encoding for this table. + 请为此表选择新的编ç ã€‚ + + + + %1 +Leave the field empty for using the database encoding. + %1 +留空此字段以使用数æ®åº“默认编ç ã€‚ + + + + This encoding is either not valid or not supported. + è¿™ç§ç¼–ç éžæ³•æˆ–è€…ä¸æ”¯æŒã€‚ + + + + %1 replacement(s) made. + 进行了 %1 次替æ¢ã€‚ + + + + VacuumDialog + + + Compact Database + 压缩数æ®åº“ + + + + Warning: Compacting the database will commit all of your changes. + 警告: 压缩数æ®åº“会æäº¤ä½ çš„æ‰€æœ‰ä¿®æ”¹ã€‚ + + + + Please select the databases to co&mpact: + 请选择è¦åŽ‹ç¼©çš„æ•°æ®åº“(&M) + + + diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/translations/sqlb_zh_TW.qm b/src/WBCLFZSystemModule/SqliteDBProcess/src/translations/sqlb_zh_TW.qm new file mode 100644 index 0000000000000000000000000000000000000000..191011b6a2f5b19f1e9e444349ce0e081bf7fd56 GIT binary patch literal 25059 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 CjLbs- literal 0 HcmV?d00001 diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/translations/sqlb_zh_TW.ts b/src/WBCLFZSystemModule/SqliteDBProcess/src/translations/sqlb_zh_TW.ts new file mode 100644 index 0000000..51afd52 --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/translations/sqlb_zh_TW.ts @@ -0,0 +1,6931 @@ + + + + + AboutDialog + + + About DB Browser for SQLite + + + + + Version + 版本 + + + + <html><head/><body><p>DB Browser for SQLite is an open source, freeware visual tool used to create, design and edit SQLite database files.</p><p>It is bi-licensed under the Mozilla Public License Version 2, as well as the GNU General Public License Version 3 or later. You can modify or redistribute it under the conditions of these licenses.</p><p>See <a href="http://www.gnu.org/licenses/gpl.html">http://www.gnu.org/licenses/gpl.html</a> and <a href="https://www.mozilla.org/MPL/2.0/index.txt">https://www.mozilla.org/MPL/2.0/index.txt</a> for details.</p><p>For more information on this program please visit our website at: <a href="http://sqlitebrowser.org">http://sqlitebrowser.org</a></p><p><span style=" font-size:small;">This software uses the GPL/LGPL Qt Toolkit from </span><a href="http://qt-project.org/"><span style=" font-size:small;">http://qt-project.org/</span></a><span style=" font-size:small;"><br/>See </span><a href="http://qt-project.org/doc/qt-5/licensing.html"><span style=" font-size:small;">http://qt-project.org/doc/qt-5/licensing.html</span></a><span style=" font-size:small;"> for licensing terms and information.</span></p><p><span style=" font-size:small;">It also uses the Silk icon set by Mark James licensed under a Creative Commons Attribution 2.5 and 3.0 license.<br/>See </span><a href="http://www.famfamfam.com/lab/icons/silk/"><span style=" font-size:small;">http://www.famfamfam.com/lab/icons/silk/</span></a><span style=" font-size:small;"> for details.</span></p></body></html> + + + + + AddRecordDialog + + + Add New Record + + + + + Enter values for the new record considering constraints. Fields in bold are mandatory. + + + + + In the Value column you can specify the value for the field identified in the Name column. The Type column indicates the type of the field. Default values are displayed in the same style as NULL values. + + + + + Name + å稱 + + + + Type + 類型 + + + + Value + + + + + Values to insert. Pre-filled default values are inserted automatically unless they are changed. + + + + + When you edit the values in the upper frame, the SQL query for inserting this new record is shown here. You can edit manually the query before saving. + + + + + <html><head/><body><p><span style=" font-weight:600;">Save</span> will submit the shown SQL statement to the database for inserting the new record.</p><p><span style=" font-weight:600;">Restore Defaults</span> will restore the initial values in the <span style=" font-weight:600;">Value</span> column.</p><p><span style=" font-weight:600;">Cancel</span> will close this dialog without executing the query.</p></body></html> + + + + + Auto-increment + + + + + + Unique constraint + + + + + + Check constraint: %1 + + + + + + Foreign key: %1 + + + + + + Default value: %1 + + + + + + Error adding record. Message from database engine: + +%1 + + + + + Are you sure you want to restore all the entered values to their defaults? + + + + + Application + + + Possible command line arguments: + å¯ç”¨å‘½ä»¤åˆ—åƒæ•¸: + + + + Usage: %1 [options] [<database>|<project>] + + + + + + -h, --help Show command line options + + + + + -q, --quit Exit application after running scripts + + + + + -s, --sql <file> Execute this SQL file after opening the DB + + + + + -t, --table <table> Browse this table after opening the DB + + + + + -R, --read-only Open database in read-only mode + + + + + -o, --option <group>/<setting>=<value> + + + + + Run application with this setting temporarily set to value + + + + + -O, --save-option <group>/<setting>=<value> + + + + + Run application saving this value for this setting + + + + + -v, --version Display the current version + + + + + <database> Open this SQLite database + + + + + <project> Open this project file (*.sqbpro) + + + + + The -s/--sql option requires an argument + -s/--sql é¸é …需è¦ä¸€å€‹åƒæ•¸ + + + + The file %1 does not exist + 檔案 %1 ä¸å­˜åœ¨ + + + + The -t/--table option requires an argument + + + + + The -o/--option and -O/--save-option options require an argument in the form group/setting=value + + + + + Invalid option/non-existant file: %1 + 無效é¸é …/ä¸å­˜åœ¨çš„æª”案: %1 + + + + SQLite Version + + + + + SQLCipher Version %1 (based on SQLite %2) + + + + + DB Browser for SQLite Version %1. + + + + + Built for %1, running on %2 + + + + + Qt Version %1 + + + + + CipherDialog + + + SQLCipher encryption + + + + + &Password + + + + + &Reenter password + + + + + Encr&yption settings + + + + + SQLCipher &3 defaults + + + + + SQLCipher &4 defaults + + + + + Custo&m + + + + + Page si&ze + + + + + &KDF iterations + + + + + HMAC algorithm + + + + + KDF algorithm + + + + + Plaintext Header Size + + + + + Passphrase + + + + + Raw key + + + + + Please set a key to encrypt the database. +Note that if you change any of the other, optional, settings you'll need to re-enter them as well every time you open the database file. +Leave the password fields empty to disable the encryption. +The encryption process might take some time and you should have a backup copy of your database! Unsaved changes are applied before modifying the encryption. + + + + + Please enter the key used to encrypt the database. +If any of the other settings were altered for this database file you need to provide this information as well. + + + + + ColumnDisplayFormatDialog + + + Choose display format + + + + + Display format + + + + + Choose a display format for the column '%1' which is applied to each value prior to showing it. + + + + + Default + é è¨­ + + + + Decimal number + + + + + Exponent notation + + + + + Hex blob + + + + + Hex number + + + + + Apple NSDate to date + + + + + Java epoch (milliseconds) to date + + + + + .NET DateTime.Ticks to date + + + + + Julian day to date + + + + + Unix epoch to local time + + + + + Date as dd/mm/yyyy + + + + + Lower case + + + + + Custom display format must contain a function call applied to %1 + + + + + Error in custom display format. Message from database engine: + +%1 + + + + + Custom display format must return only one column but it returned %1. + + + + + Octal number + + + + + Round number + + + + + Unix epoch to date + + + + + Upper case + + + + + Windows DATE to date + + + + + Custom + + + + + CondFormatManager + + + Conditional Format Manager + + + + + This dialog allows creating and editing conditional formats. Each cell style will be selected by the first accomplished condition for that cell data. Conditional formats can be moved up and down, where those at higher rows take precedence over those at lower. Syntax for conditions is the same as for filters and an empty condition applies to all values. + + + + + Add new conditional format + + + + + &Add + + + + + Remove selected conditional format + + + + + &Remove + + + + + Move selected conditional format up + + + + + Move &up + + + + + Move selected conditional format down + + + + + Move &down + + + + + Foreground + + + + + Text color + + + + + Background + + + + + Background color + + + + + Font + + + + + Size + + + + + Bold + ç²—é«” + + + + Italic + 斜體 + + + + Underline + 底線 + + + + Alignment + + + + + Condition + + + + + + Click to select color + + + + + Are you sure you want to clear all the conditional formats of this field? + + + + + DBBrowserDB + + + Please specify the database name under which you want to access the attached database + + + + + Invalid file format + + + + + Do you want to save the changes made to the database file %1? + æ‚¨æ˜¯å¦æƒ³å„²å­˜å°è³‡æ–™åº«æª”案 %1 åšå‡ºçš„修改? + + + + Exporting database to SQL file... + 正在匯出資料庫到 SQL 檔案... + + + + + Cancel + å–æ¶ˆ + + + + Executing SQL... + 正在執行 SQL... + + + + Action cancelled. + æ“ä½œå·²å–æ¶ˆã€‚ + + + + This database has already been attached. Its schema name is '%1'. + + + + + Do you really want to close this temporary database? All data will be lost. + + + + + Database didn't close correctly, probably still busy + + + + + The database is currently busy: + + + + + Do you want to abort that other operation? + + + + + + No database file opened + + + + + + Error in statement #%1: %2. +Aborting execution%3. + + + + + + and rolling back + + + + + didn't receive any output from %1 + + + + + could not execute command: %1 + + + + + Cannot delete this object + + + + + Cannot set data on this object + + + + + + A table with the name '%1' already exists in schema '%2'. + + + + + No table with name '%1' exists in schema '%2'. + + + + + + Cannot find column %1. + + + + + Creating savepoint failed. DB says: %1 + + + + + Renaming the column failed. DB says: +%1 + + + + + + Releasing savepoint failed. DB says: %1 + + + + + Creating new table failed. DB says: %1 + + + + + Copying data to new table failed. DB says: +%1 + + + + + Deleting old table failed. DB says: %1 + + + + + Error renaming table '%1' to '%2'. +Message from database engine: +%3 + + + + + could not get list of db objects: %1 + + + + + Restoring some of the objects associated with this table failed. This is most likely because some column names changed. Here's the SQL statement which you might want to fix and execute manually: + + + 還原æŸäº›å’Œé€™å€‹è³‡æ–™è¡¨é—œè¯çš„物件失敗。這個最å¯èƒ½æ˜¯å› ç‚ºæŸäº›åˆ—çš„å稱修改了。這裡是您å¯èƒ½éœ€è¦æ‰‹å‹•修復和執行的 SQL 語å¥: + + + + + + could not get list of databases: %1 + + + + + Error loading extension: %1 + 載入擴充套件時出ç¾éŒ¯èª¤: %1 + + + + could not get column information + + + + + Error setting pragma %1 to %2: %3 + 設定雜注 %1 為 %2 時出ç¾éŒ¯èª¤: %3 + + + + File not found. + 找ä¸åˆ°æª”案。 + + + + DbStructureModel + + + Name + å稱 + + + + Object + å°è±¡ + + + + Type + 類型 + + + + Schema + æž¶æ§‹ + + + + Database + + + + + Browsables + + + + + All + + + + + Temporary + + + + + Tables (%1) + 資料表 (%1) + + + + Indices (%1) + 索引 (%1) + + + + Views (%1) + 視圖 (%1) + + + + Triggers (%1) + 觸發器 (%1) + + + + EditDialog + + + Edit database cell + 編輯資料庫儲存格 + + + + Mode: + + + + + This is the list of supported modes for the cell editor. Choose a mode for viewing or editing the data of the current cell. + + + + + RTL Text + + + + + + Image + + + + + JSON + + + + + XML + + + + + + Automatically adjust the editor mode to the loaded data type + + + + + This checkable button enables or disables the automatic switching of the editor mode. When a new cell is selected or new data is imported and the automatic switching is enabled, the mode adjusts to the detected data type. You can then change the editor mode manually. If you want to keep this manually switched mode while moving through the cells, switch the button off. + + + + + Auto-switch + + + + + The text editor modes let you edit plain text, as well as JSON or XML data with syntax highlighting, automatic formatting and validation before saving. + +Errors are indicated with a red squiggle underline. + + + + + This Qt editor is used for right-to-left scripts, which are not supported by the default Text editor. The presence of right-to-left characters is detected and this editor mode is automatically selected. + + + + + Open preview dialog for printing the data currently stored in the cell + + + + + Auto-format: pretty print on loading, compact on saving. + + + + + When enabled, the auto-format feature formats the data on loading, breaking the text in lines and indenting it for maximum readability. On data saving, the auto-format feature compacts the data removing end of lines, and unnecessary whitespace. + + + + + Word Wrap + + + + + Wrap lines on word boundaries + + + + + + Open in default application or browser + + + + + Open in application + + + + + The value is interpreted as a file or URL and opened in the default application or web browser. + + + + + Save file reference... + + + + + Save reference to file + + + + + + Open in external application + + + + + Autoformat + + + + + &Export... + + + + + + &Import... + + + + + + Import from file + + + + + + Opens a file dialog used to import any kind of data to this database cell. + + + + + Export to file + + + + + Opens a file dialog used to export the contents of this database cell to a file. + + + + + + Print... + + + + + Open preview dialog for printing displayed image + + + + + + Ctrl+P + + + + + Open preview dialog for printing displayed text + + + + + Copy Hex and ASCII + + + + + Copy selected hexadecimal and ASCII columns to the clipboard + + + + + Ctrl+Shift+C + + + + + Set as &NULL + + + + + Apply data to cell + + + + + This button saves the changes performed in the cell editor to the database cell. + + + + + Apply + + + + + Text + 純文字檔案 + + + + Binary + äºŒé€²ä½ + + + + Erases the contents of the cell + 刪除儲存格的內容 + + + + This area displays information about the data present in this database cell + 這個å€åŸŸé¡¯ç¤ºå­˜åœ¨æ–¼é€™å€‹è³‡æ–™åº«å„²å­˜æ ¼ä¸­çš„資料的相關資訊 + + + + Type of data currently in cell + ç›®å‰åœ¨å„²å­˜æ ¼ä¸­çš„資料的類型 + + + + Size of data currently in table + ç›®å‰åœ¨è³‡æ–™è¡¨ä¸­çš„è³‡æ–™çš„å¤§å° + + + + Choose a filename to export data + 鏿“‡ä¸€å€‹åŒ¯å‡ºè³‡æ–™çš„æª”案å稱 + + + + Type of data currently in cell: %1 Image + + + + + %1x%2 pixel(s) + + + + + Type of data currently in cell: NULL + + + + + + Type of data currently in cell: Text / Numeric + ç›®å‰åœ¨å„²å­˜æ ¼ä¸­çš„資料的類型: Text 純文字檔案/ Numeric 數值 + + + + + Image data can't be viewed in this mode. + + + + + + Try switching to Image or Binary mode. + + + + + + Binary data can't be viewed in this mode. + + + + + + Try switching to Binary mode. + + + + + + Image files (%1) + + + + + Binary files (*.bin) + + + + + Choose a file to import + 鏿“‡è¦åŒ¯å…¥çš„一個檔案 + + + + %1 Image + + + + + Invalid data for this mode + + + + + The cell contains invalid %1 data. Reason: %2. Do you really want to apply it to the cell? + + + + + + + %n character(s) + + %n 個字元 + + + + + Type of data currently in cell: Valid JSON + + + + + Couldn't save file: %1. + + + + + The data has been saved to a temporary file and has been opened with the default application. You can now edit the file and, when you are ready, apply the saved new data to the cell editor or cancel any changes. + + + + + Type of data currently in cell: Binary + ç›®å‰åœ¨å„²å­˜æ ¼ä¸­çš„資料的類型: Binary äºŒé€²ä½ + + + + + %n byte(s) + + %n ä½å…ƒçµ„ + + + + + EditIndexDialog + + + &Name + å稱(&N) + + + + Order + é †åº + + + + &Table + 資料表(&T) + + + + Edit Index Schema + + + + + &Unique + 唯一(&U) + + + + For restricting the index to only a part of the table you can specify a WHERE clause here that selects the part of the table that should be indexed + + + + + Partial inde&x clause + + + + + Colu&mns + + + + + Table column + + + + + Type + 類型 + + + + Add a new expression column to the index. Expression columns contain SQL expression rather than column names. + + + + + Index column + + + + + Deleting the old index failed: +%1 + + + + + Creating the index failed: +%1 + 建立索引時失敗: +%1 + + + + EditTableDialog + + + Edit table definition + 編輯資料表定義 + + + + Table + 資料表 + + + + Advanced + + + + + Make this a 'WITHOUT rowid' table. Setting this flag requires a field of type INTEGER with the primary key flag set and the auto increment flag unset. + + + + + Without Rowid + + + + + Database sche&ma + + + + + Fields + æ¬„ä½ + + + + Add + + + + + Remove + + + + + Move to top + + + + + Move up + + + + + Move down + + + + + Move to bottom + + + + + + Name + å稱 + + + + + Type + 類型 + + + + NN + + + + + Not null + éžç©º + + + + PK + PK + + + + Primary key + ä¸»éµ + + + + AI + AI + + + + Autoincrement + 自動增值 + + + + U + + + + + + + Unique + + + + + Default + é è¨­ + + + + Default value + é è¨­å€¼ + + + + + + Check + 檢查 + + + + Check constraint + æª¢æŸ¥ç´„æŸæ¢ä»¶ + + + + Collation + + + + + + + Foreign Key + + + + + Constraints + + + + + Add constraint + + + + + Remove constraint + + + + + Columns + 列列 + + + + SQL + + + + + <html><head/><body><p><span style=" font-weight:600; color:#ff0000;">Warning: </span>There is something with this table definition that our parser doesn't fully understand. Modifying and saving this table might result in problems.</p></body></html> + + + + + + Primary Key + + + + + Add a primary key constraint + + + + + Add a foreign key constraint + + + + + Add a unique constraint + + + + + Add a check constraint + + + + + Error creating table. Message from database engine: +%1 + 建立資料表時出ç¾éŒ¯èª¤ã€‚來自資料庫引擎的消æ¯: +%1 + + + + There already is a field with that name. Please rename it first or choose a different name for this field. + + + + + There is at least one row with this field set to NULL. This makes it impossible to set this flag. Please change the table data first. + 至少有一行帶本欄ä½çš„記錄被設為空。這使得它ä¸å¯èƒ½è¨­å®šé€™å€‹æ¨™èªŒã€‚請首先修改資料表資料。 + + + + There is at least one row with a non-integer value in this field. This makes it impossible to set the AI flag. Please change the table data first. + 在這個欄ä½ä¸­è‡³å°‘æœ‰ä¸€è¡Œå¸¶æœ‰ä¸€å€‹éžæ•´æ•¸çš„值。這使得它ä¸å¯èƒ½è¨­å®š AI 標誌。請首先修改資料表資料。 + + + + Column '%1' has duplicate data. + + + + + + This makes it impossible to enable the 'Unique' flag. Please remove the duplicate data, which will allow the 'Unique' flag to then be enabled. + + + + + This column is referenced in a foreign key in table %1 and thus its name cannot be changed. + + + + + + There can only be one primary key for each table. Please modify the existing primary key instead. + + + + + Are you sure you want to delete the field '%1'? +All data currently stored in this field will be lost. + 您是å¦ç¢ºèªæ‚¨æƒ³åˆªé™¤æ¬„ä½ '%1'? +ç›®å‰å­˜å„²åœ¨é€™å€‹æ¬„ä½ä¸­çš„æ‰€æœ‰è³‡æ–™å°‡æœƒéºå¤±ã€‚ + + + + Please add a field which meets the following criteria before setting the without rowid flag: + - Primary key flag set + - Auto increment disabled + + + + + ExportDataDialog + + + Export data as CSV + 匯出資料為 CSV + + + + Tab&le(s) + + + + + Colu&mn names in first line + + + + + Fie&ld separator + + + + + , + , + + + + ; + ; + + + + Tab + Tab + + + + | + | + + + + + + Other + 其它 + + + + &Quote character + 引號(&Q) + + + + " + " + + + + ' + ' + + + + New line characters + + + + + Windows: CR+LF (\r\n) + + + + + Unix: LF (\n) + + + + + Pretty print + + + + + + Could not open output file: %1 + + + + + + Choose a filename to export data + 鏿“‡åŒ¯å‡ºè³‡æ–™çš„æª”案å稱 + + + + Export data as JSON + + + + + exporting CSV + + + + + exporting JSON + + + + + Please select at least 1 table. + + + + + Choose a directory + 鏿“‡ä¸€å€‹ç›®éŒ„ + + + + Export completed. + 匯出完æˆã€‚ + + + + ExportSqlDialog + + + Export SQL... + + + + + Tab&le(s) + + + + + Select All + + + + + Deselect All + + + + + &Options + + + + + Keep column names in INSERT INTO + + + + + Multiple rows (VALUES) per INSERT statement + + + + + Export everything + + + + + Export schema only + + + + + Export data only + + + + + Keep old schema (CREATE TABLE IF NOT EXISTS) + + + + + Overwrite old schema (DROP TABLE, then CREATE TABLE) + + + + + Please select at least one table. + + + + + Choose a filename to export + 鏿“‡è¦åŒ¯å‡ºçš„æª”案å稱 + + + + Export completed. + 匯出完æˆã€‚ + + + + Export cancelled or failed. + åŒ¯å‡ºå–æ¶ˆæˆ–失敗。 + + + + ExtendedScintilla + + + + Ctrl+H + + + + + Ctrl+F + + + + + + Ctrl+P + + + + + Find... + + + + + Find and Replace... + + + + + Print... + + + + + ExtendedTableWidget + + + Use as Exact Filter + + + + + Containing + + + + + Not containing + + + + + Not equal to + + + + + Greater than + + + + + Less than + + + + + Greater or equal + + + + + Less or equal + + + + + Between this and... + + + + + Regular expression + + + + + Edit Conditional Formats... + + + + + Set to NULL + + + + + Copy + + + + + Copy with Headers + + + + + Copy as SQL + + + + + Paste + + + + + Print... + + + + + Use in Filter Expression + + + + + Alt+Del + + + + + Ctrl+Shift+C + + + + + Ctrl+Alt+C + + + + + The content of the clipboard is bigger than the range selected. +Do you want to insert it anyway? + + + + + <p>Not all data has been loaded. <b>Do you want to load all data before selecting all the rows?</b><p><p>Answering <b>No</b> means that no more data will be loaded and the selection will not be performed.<br/>Answering <b>Yes</b> might take some time while the data is loaded but the selection will be complete.</p>Warning: Loading all the data might require a great amount of memory for big tables. + + + + + Cannot set selection to NULL. Column %1 has a NOT NULL constraint. + + + + + FileExtensionManager + + + File Extension Manager + + + + + &Up + + + + + &Down + + + + + &Add + + + + + &Remove + + + + + + Description + + + + + Extensions + + + + + *.extension + + + + + FilterLineEdit + + + Filter + éŽæ¿¾ + + + + These input fields allow you to perform quick filters in the currently selected table. +By default, the rows containing the input text are filtered out. +The following operators are also supported: +% Wildcard +> Greater than +< Less than +>= Equal to or greater +<= Equal to or less += Equal to: exact match +<> Unequal: exact inverse match +x~y Range: values between x and y +/regexp/ Values matching the regular expression + + + + + Clear All Conditional Formats + + + + + Use for Conditional Format + + + + + Edit Conditional Formats... + + + + + Set Filter Expression + + + + + What's This? + 這是什麼? + + + + Is NULL + + + + + Is not NULL + + + + + Is empty + + + + + Is not empty + + + + + Not containing... + + + + + Equal to... + + + + + Not equal to... + + + + + Greater than... + + + + + Less than... + + + + + Greater or equal... + + + + + Less or equal... + + + + + In range... + + + + + Regular expression... + + + + + FindReplaceDialog + + + Find and Replace + + + + + Fi&nd text: + + + + + Re&place with: + + + + + Match &exact case + + + + + Match &only whole words + + + + + When enabled, the search continues from the other end when it reaches one end of the page + + + + + &Wrap around + + + + + When set, the search goes backwards from cursor position, otherwise it goes forward + + + + + Search &backwards + + + + + <html><head/><body><p>When checked, the pattern to find is searched only in the current selection.</p></body></html> + + + + + &Selection only + + + + + <html><head/><body><p>When checked, the pattern to find is interpreted as a UNIX regular expression. See <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>.</p></body></html> + + + + + Use regular e&xpressions + + + + + Find the next occurrence from the cursor position and in the direction set by "Search backwards" + + + + + &Find Next + + + + + F3 + + + + + &Replace + + + + + Highlight all the occurrences of the text in the page + + + + + F&ind All + + + + + Replace all the occurrences of the text in the page + + + + + Replace &All + + + + + The searched text was not found + + + + + The searched text was not found. + + + + + The searched text was found one time. + + + + + The searched text was found %1 times. + + + + + The searched text was replaced one time. + + + + + The searched text was replaced %1 times. + + + + + ForeignKeyEditor + + + &Reset + + + + + Foreign key clauses (ON UPDATE, ON DELETE etc.) + + + + + ImportCsvDialog + + + Import CSV file + 匯入 CSV 檔案 + + + + Table na&me + + + + + &Column names in first line + 列å在首行(&C) + + + + Field &separator + 欄ä½åˆ†éš”符號(&S) + + + + , + , + + + + ; + ; + + + + + Tab + Tab + + + + | + ; + + + + Other + 其它 + + + + &Quote character + 引號(&Q) + + + + + Other (printable) + + + + + + Other (code) + + + + + " + ; + + + + ' + ' + + + + &Encoding + + + + + UTF-8 + + + + + UTF-16 + + + + + ISO-8859-1 + + + + + Trim fields? + + + + + Separate tables + + + + + Advanced + + + + + When importing an empty value from the CSV file into an existing table with a default value for this column, that default value is inserted. Activate this option to insert an empty value instead. + + + + + Ignore default &values + + + + + Activate this option to stop the import when trying to import an empty value into a NOT NULL column without a default value. + + + + + Fail on missing values + + + + + Disable data type detection + + + + + Disable the automatic data type detection when creating a new table. + + + + + When importing into an existing table with a primary key, unique constraints or a unique index there is a chance for a conflict. This option allows you to select a strategy for that case: By default the import is aborted and rolled back but you can also choose to ignore and not import conflicting rows or to replace the existing row in the table. + + + + + Abort import + + + + + Ignore row + + + + + Replace existing row + + + + + Conflict strategy + + + + + + Deselect All + + + + + Match Similar + + + + + Select All + + + + + There is already a table named '%1' and an import into an existing table is only possible if the number of columns match. + + + + + There is already a table named '%1'. Do you want to import the data into it? + + + + + Creating restore point failed: %1 + + + + + Creating the table failed: %1 + + + + + importing CSV + + + + + Importing the file '%1' took %2ms. Of this %3ms were spent in the row function. + + + + + Inserting row failed: %1 + + + + + MainWindow + + + toolBar1 + + + + + Opens the SQLCipher FAQ in a browser window + + + + + Export one or more table(s) to a JSON file + + + + + DB Browser for SQLite + + + + + Open an existing database file in read only mode + + + + + &File + 檔案(&F) + + + + &Import + 匯入(&I) + + + + &Export + 匯出(&E) + + + + &Edit + 編輯(&E) + + + + &View + 查看(&V) + + + + &Help + 幫助(&H) + + + + Edit Database &Cell + + + + + DB Sche&ma + + + + + &Remote + + + + + + Execute current line + 執行目å‰è¡Œ + + + + This button executes the SQL statement present in the current editor line + + + + + Shift+F5 + + + + + Sa&ve Project + + + + + + Save SQL file as + + + + + This button saves the content of the current SQL editor tab to a file + + + + + &Browse Table + + + + + Copy Create statement + + + + + Copy the CREATE statement of the item to the clipboard + + + + + User + 用戶 + + + + Application + æ‡‰ç”¨ç¨‹å¼ + + + + &Clear + 清除(&C) + + + + &New Database... + 新建資料庫(&N)... + + + + + Create a new database file + 建立一個新的資料庫檔 + + + + This option is used to create a new database file. + 這個é¸é …用於建立一個新的資料庫檔案。 + + + + Ctrl+N + + + + + + &Open Database... + 打開資料庫(&O)... + + + + + + + + Open an existing database file + æ‰“é–‹ä¸€å€‹ç¾æœ‰çš„資料庫檔 + + + + + + This option is used to open an existing database file. + 這個é¸é …ç”¨æ–¼æ‰“é–‹ä¸€å€‹ç¾æœ‰çš„資料庫檔案。 + + + + Ctrl+O + + + + + &Close Database + 關閉資料庫(&C) + + + + + Ctrl+W + + + + + + Revert database to last saved state + 把資料庫退回到先å‰å„²å­˜çš„狀態 + + + + This option is used to revert the current database file to its last saved state. All changes made since the last save operation are lost. + 這個é¸é …用於倒退目å‰çš„資料庫檔為它最後的儲存狀態。從最後儲存æ“作開始åšå‡ºçš„æ‰€æœ‰ä¿®æ”¹å°‡æœƒéºå¤±ã€‚ + + + + + Write changes to the database file + 把修改寫入到資料庫檔 + + + + This option is used to save changes to the database file. + 這個é¸é …用於儲存修改到資料庫檔案。 + + + + Ctrl+S + + + + + Compact the database file, removing space wasted by deleted records + 壓縮資料庫檔,通éŽåˆªé™¤è¨˜éŒ„去掉浪費的空間 + + + + + Compact the database file, removing space wasted by deleted records. + 壓縮資料庫檔,通éŽåˆªé™¤è¨˜éŒ„去掉浪費的空間。 + + + + E&xit + 退出(&X) + + + + Ctrl+Q + + + + + Import data from an .sql dump text file into a new or existing database. + 從一個 .sql 轉儲文字檔中匯入資料到一個新的或已有的資料庫。 + + + + This option lets you import data from an .sql dump text file into a new or existing database. SQL dump files can be created on most database engines, including MySQL and PostgreSQL. + 這個é¸é …讓你從一個 .sql è½‰å„²æ–‡å­—æª”ä¸­åŒ¯å…¥è³‡æ–™åˆ°ä¸€å€‹æ–°çš„æˆ–ç¾æœ‰çš„資料庫。SQL 轉儲檔å¯ä»¥åœ¨å¤§å¤šæ•¸è³‡æ–™åº«å¼•擎上建立,包括 MySQL å’Œ PostgreSQL。 + + + + Open a wizard that lets you import data from a comma separated text file into a database table. + 打開一個引導精éˆè®“您從一個逗號間隔的文字檔匯入資料到一個資料庫資料表中。 + + + + Open a wizard that lets you import data from a comma separated text file into a database table. CSV files can be created on most database and spreadsheet applications. + 打開一個引導精éˆè®“您從一個逗號間隔的文字檔匯入資料到一個資料庫資料表中。CSV 檔å¯ä»¥åœ¨å¤§å¤šæ•¸è³‡æ–™åº«å’Œè©¦ç®—資料表應用程å¼ä¸Šå»ºç«‹ã€‚ + + + + Export a database to a .sql dump text file. + 匯出一個資料庫導一個 .sql 轉儲文字檔案。 + + + + This option lets you export a database to a .sql dump text file. SQL dump files contain all data necessary to recreate the database on most database engines, including MySQL and PostgreSQL. + 這個é¸é …讓你匯出一個資料庫導一個 .sql 轉儲文字檔案。SQL 轉儲檔包å«åœ¨å¤§å¤šæ•¸è³‡æ–™åº«å¼•擎上(包括 MySQL å’Œ PostgreSQL)釿–°å»ºç«‹è³‡æ–™åº«æ‰€éœ€çš„æ‰€æœ‰è³‡æ–™ã€‚ + + + + Export a database table as a comma separated text file. + 匯出一個資料庫資料表為逗號間隔的文字檔案。 + + + + Export a database table as a comma separated text file, ready to be imported into other database or spreadsheet applications. + 匯出一個資料庫資料表為逗號間隔的文字檔,準備好被匯入到其他資料庫或試算資料表應用程å¼ã€‚ + + + + Open the Create Table wizard, where it is possible to define the name and fields for a new table in the database + 打開“建立資料表â€å¼•å°Žç²¾éˆï¼Œåœ¨é‚£è£¡å¯ä»¥å®šç¾©åœ¨è³‡æ–™åº«ä¸­çš„一個新資料表的åç¨±å’Œæ¬„ä½ + + + + Open the Delete Table wizard, where you can select a database table to be dropped. + 打開“刪除資料表â€å¼•å°Žç²¾éˆï¼Œåœ¨é‚£è£¡ä½ å¯ä»¥é¸æ“‡è¦ä¸Ÿæ£„的一個資料庫資料表。 + + + + Open the Modify Table wizard, where it is possible to rename an existing table. It is also possible to add or delete fields form a table, as well as modify field names and types. + 打開“修改資料表â€å¼•å°Žç²¾éˆï¼Œåœ¨å…¶ä¸­å¯ä»¥é‡å‘½åä¸€å€‹ç¾æœ‰çš„資料表。也å¯ä»¥å¾žä¸€å€‹è³‡æ–™è¡¨ä¸­åŠ å…¥æˆ–åˆªé™¤æ¬„ä½ï¼Œä»¥åŠä¿®æ”¹æ¬„ä½å稱和類型。 + + + + Open the Create Index wizard, where it is possible to define a new index on an existing database table. + 打開“建立索引â€å¼•å°Žç²¾éˆï¼Œåœ¨é‚£è£¡å¯ä»¥åœ¨ä¸€å€‹ç¾æœ‰çš„資料庫資料表上定義一個新索引。 + + + + &Preferences... + å好é¸é …(&P)... + + + + + Open the preferences window. + 打開首é¸é …視窗。 + + + + &DB Toolbar + 資料庫工具列(&D) + + + + Shows or hides the Database toolbar. + 顯示或隱è—資料庫工具列。 + + + + Shift+F1 + + + + + &Recently opened + 最近打開(&R) + + + + Open &tab + 打開標籤é (&T) + + + + Ctrl+T + + + + + + Database Structure + This has to be equal to the tab title in all the main tabs + + + + + This is the structure of the opened database. +You can drag SQL statements from an object row and drop them into other applications or into another instance of 'DB Browser for SQLite'. + + + + + + + Browse Data + This has to be equal to the tab title in all the main tabs + + + + + Un/comment block of SQL code + + + + + Un/comment block + + + + + Comment or uncomment current line or selected block of code + + + + + Comment or uncomment the selected lines or the current line, when there is no selection. All the block is toggled according to the first line. + + + + + Ctrl+/ + + + + + Stop SQL execution + + + + + Stop execution + + + + + Stop the currently running SQL script + + + + + + Edit Pragmas + This has to be equal to the tab title in all the main tabs + + + + + Warning: this pragma is not readable and this value has been inferred. Writing the pragma might overwrite a redefined LIKE provided by an SQLite extension. + + + + + + Execute SQL + This has to be equal to the tab title in all the main tabs + 執行 SQL + + + + &Tools + + + + + DB Toolbar + + + + + SQL &Log + + + + + Show S&QL submitted by + + + + + Error Log + + + + + This button clears the contents of the SQL logs + + + + + This panel lets you examine a log of all SQL commands issued by the application or by yourself + + + + + &Plot + + + + + This is the structure of the opened database. +You can drag multiple object names from the Name column and drop them into the SQL editor and you can adjust the properties of the dropped names using the context menu. This would help you in composing SQL statements. +You can drag SQL statements from the Schema column and drop them into the SQL editor or into other applications. + + + + + + + Project Toolbar + + + + + Extra DB toolbar + + + + + + + Close the current database file + + + + + This button closes the connection to the currently open database file + + + + + Ctrl+F4 + + + + + &Revert Changes + + + + + &Write Changes + + + + + Compact &Database... + + + + + Execute all/selected SQL + + + + + This button executes the currently selected SQL statements. If no text is selected, all SQL statements are executed. + + + + + &Load Extension... + + + + + Execute line + + + + + &Wiki + + + + + F1 + + + + + Bug &Report... + + + + + Feature Re&quest... + + + + + Web&site + + + + + &Donate on Patreon... + + + + + Open &Project... + + + + + &Attach Database... + + + + + + Add another database file to the current database connection + + + + + This button lets you add another database file to the current database connection + + + + + &Set Encryption... + + + + + SQLCipher &FAQ + + + + + Table(&s) to JSON... + + + + + Open Data&base Read Only... + + + + + Ctrl+Shift+O + + + + + Save results + + + + + Save the results view + + + + + This button lets you save the results of the last executed query + + + + + + Find text in SQL editor + + + + + Find + + + + + This button opens the search bar of the editor + + + + + Ctrl+F + + + + + + Find or replace text in SQL editor + + + + + Find or replace + + + + + This button opens the find/replace dialog for the current editor tab + + + + + Ctrl+H + + + + + Export to &CSV + 匯出到 &CSV + + + + Save as &view + 儲存為視圖(&V) + + + + Save as view + 儲存為視圖 + + + + Browse Table + + + + + Shows or hides the Project toolbar. + + + + + Open SQL file(s) + + + + + This button opens files containing SQL statements and loads them in new editor tabs + + + + + This button lets you save all the settings associated to the open DB to a DB Browser for SQLite project file + + + + + This button lets you open a DB Browser for SQLite project file + + + + + Extra DB Toolbar + + + + + New In-&Memory Database + + + + + Drag && Drop Qualified Names + + + + + + Use qualified names (e.g. "Table"."Field") when dragging the objects and dropping them into the editor + + + + + Drag && Drop Enquoted Names + + + + + + Use escaped identifiers (e.g. "Table1") when dragging the objects and dropping them into the editor + + + + + &Integrity Check + + + + + Runs the integrity_check pragma over the opened database and returns the results in the Execute SQL tab. This pragma does an integrity check of the entire database. + + + + + &Foreign-Key Check + + + + + Runs the foreign_key_check pragma over the opened database and returns the results in the Execute SQL tab + + + + + &Quick Integrity Check + + + + + Run a quick integrity check over the open DB + + + + + Runs the quick_check pragma over the opened database and returns the results in the Execute SQL tab. This command does most of the checking of PRAGMA integrity_check but runs much faster. + + + + + &Optimize + + + + + Attempt to optimize the database + + + + + Runs the optimize pragma over the opened database. This pragma might perform optimizations that will improve the performance of future queries. + + + + + + Print + + + + + Print text from current SQL editor tab + + + + + Open a dialog for printing the text in the current SQL editor tab + + + + + Print the structure of the opened database + + + + + Open a dialog for printing the structure of the opened database + + + + + &Save Project As... + + + + + + + Save the project in a file selected in a dialog + + + + + Save A&ll + + + + + + + Save DB file, project file and opened SQL files + + + + + Ctrl+Shift+S + + + + + &Database from SQL file... + + + + + &Table from CSV file... + + + + + &Database to SQL file... + + + + + &Table(s) as CSV file... + + + + + &Create Table... + + + + + &Delete Table... + + + + + &Modify Table... + + + + + Create &Index... + + + + + W&hat's This? + + + + + &About + + + + + This button opens a new tab for the SQL editor + + + + + &Execute SQL + 執行 SQL(&E) + + + + + Save the current session to a file + å„²å­˜ç›®å‰æœƒè©±åˆ°ä¸€å€‹æª”案 + + + + + Load a working session from a file + 從一個檔載入工作會話 + + + + + + Save SQL file + 儲存 SQL 檔案 + + + + Ctrl+E + + + + + Export as CSV file + 匯出為 CSV 檔案 + + + + Export table as comma separated values file + 匯出資料表為逗號間隔值檔案 + + + + Ctrl+L + + + + + + Ctrl+P + + + + + Database encoding + 資料庫編碼 + + + + + Choose a database file + 鏿“‡ä¸€å€‹è³‡æ–™åº«æª”案 + + + + Ctrl+Return + + + + + Ctrl+D + + + + + Ctrl+I + + + + + Reset Window Layout + + + + + Alt+0 + + + + + The database is currenctly busy. + + + + + Click here to interrupt the currently running query. + + + + + Encrypted + + + + + Database is encrypted using SQLCipher + + + + + Read only + + + + + Database file is read only. Editing the database is disabled. + + + + + Could not open database file. +Reason: %1 + + + + + + + Choose a filename to save under + 鏿“‡ä¸€å€‹æª”案å稱儲存 + + + + Error while saving the database file. This means that not all changes to the database were saved. You need to resolve the following error first. + +%1 + + + + + Do you want to save the changes made to SQL tabs in the project file '%1'? + + + + + A new DB Browser for SQLite version is available (%1.%2.%3).<br/><br/>Please download at <a href='%4'>%4</a>. + + + + + DB Browser for SQLite project file (*.sqbpro) + + + + + Error checking foreign keys after table modification. The changes will be reverted. + + + + + This table did not pass a foreign-key check.<br/>You should run 'Tools | Foreign-Key Check' and fix the reported issues. + + + + + Execution finished with errors. + + + + + Execution finished without errors. + + + + + Are you sure you want to undo all changes made to the database file '%1' since the last save? + 您是å¦ç¢ºèªæ‚¨æƒ³æ’¤éŠ·å¾žä¸Šæ¬¡å„²å­˜ä»¥ä¾†å°è³‡æ–™åº«æª”‘%1’åšå‡ºçš„æ‰€æœ‰ä¿®æ”¹ã€‚? + + + + Choose a file to import + 鏿“‡è¦åŒ¯å…¥çš„一個檔案 + + + + Text files(*.sql *.txt);;All files(*) + 文字檔案(*.sql *.txt);;所有擋檔案(*) + + + + Do you want to create a new database file to hold the imported data? +If you answer no we will attempt to import the data in the SQL file to the current database. + 您是å¦ç¢ºèªæ‚¨æƒ³å»ºç«‹ä¸€å€‹æ–°çš„資料庫檔用來存放匯入的資料? +如果您會到“å¦â€çš„話,我們將嘗試匯入 SQL 檔中的資料到目å‰è³‡æ–™åº«ã€‚ + + + + File %1 already exists. Please choose a different name. + 檔案 %1 å·²å­˜åœ¨ã€‚è«‹é¸æ“‡ä¸€å€‹ä¸åŒçš„å稱。 + + + + Error importing data: %1 + 匯入資料時出ç¾éŒ¯èª¤: %1 + + + + Import completed. + 匯入完æˆã€‚ + + + + Delete View + 刪除視圖 + + + + Delete Trigger + 刪除觸發器 + + + + Delete Index + 刪除索引 + + + + + Delete Table + 刪除資料表 + + + + Setting PRAGMA values will commit your current transaction. +Are you sure? + 設定 PRAGMA 值將會æäº¤æ‚¨çš„ç›®å‰äº‹å‹™ã€‚. +您確èªå—Ž? + + + + In-Memory database + + + + + Window Layout + + + + + Simplify Window Layout + + + + + Shift+Alt+0 + + + + + Dock Windows at Bottom + + + + + Dock Windows at Left Side + + + + + Dock Windows at Top + + + + + Are you sure you want to delete the table '%1'? +All data associated with the table will be lost. + + + + + Are you sure you want to delete the view '%1'? + + + + + Are you sure you want to delete the trigger '%1'? + + + + + Are you sure you want to delete the index '%1'? + + + + + Error: could not delete the table. + + + + + Error: could not delete the view. + + + + + Error: could not delete the trigger. + + + + + Error: could not delete the index. + + + + + Message from database engine: +%1 + + + + + Editing the table requires to save all pending changes now. +Are you sure you want to save the database? + + + + + Edit View %1 + + + + + Edit Trigger %1 + + + + + You are already executing SQL statements. Do you want to stop them in order to execute the current statements instead? Note that this might leave the database in an inconsistent state. + + + + + -- EXECUTING SELECTION IN '%1' +-- + + + + + -- EXECUTING LINE IN '%1' +-- + + + + + -- EXECUTING ALL IN '%1' +-- + + + + + + At line %1: + + + + + Result: %1 + + + + + Result: %2 + + + + + Setting PRAGMA values or vacuuming will commit your current transaction. +Are you sure? + + + + + Opened '%1' in read-only mode from recent file list + + + + + Opened '%1' from recent file list + + + + + Project saved to file '%1' + + + + + This action will open a new SQL tab with the following statements for you to edit and run: + + + + + Rename Tab + + + + + Duplicate Tab + + + + + Close Tab + + + + + Opening '%1'... + + + + + There was an error opening '%1'... + + + + + Value is not a valid URL or filename: %1 + + + + + %1 rows returned in %2ms + + + + + You are still executing SQL statements. Closing the database now will stop their execution, possibly leaving the database in an inconsistent state. Are you sure you want to close the database? + + + + + Do you want to save the changes made to the project file '%1'? + + + + + Choose text files + + + + + Import completed. Some foreign key constraints are violated. Please fix them before saving. + + + + + Modify View + + + + + Modify Trigger + + + + + Modify Index + + + + + Modify Table + + + + + &%1 %2%3 + &%1 %2%3 + + + + (read only) + + + + + Open Database or Project + + + + + Attach Database... + + + + + Import CSV file(s)... + + + + + Select the action to apply to the dropped file(s). <br/>Note: only 'Import' will process more than one file. + + + + + + + Do you want to save the changes made to SQL tabs in a new project file? + + + + + Do you want to save the changes made to the SQL file %1? + + + + + The statements in this tab are still executing. Closing the tab will stop the execution. This might leave the database in an inconsistent state. Are you sure you want to close the tab? + + + + + Select SQL file to open + 鏿“‡è¦æ‰“é–‹çš„ SQL 檔案 + + + + Select file name + 鏿“‡æª”案å稱 + + + + Select extension file + 鏿“‡æ“´å……套件檔 + + + + Extension successfully loaded. + 擴充套件æˆåŠŸè¼‰å…¥ã€‚ + + + + Error loading extension: %1 + 載入擴充套件時出ç¾éŒ¯èª¤: %1 + + + + Could not find resource file: %1 + + + + + + Don't show again + ä¸å†é¡¯ç¤º + + + + New version available. + 新版本å¯ç”¨ã€‚ + + + + Choose a project file to open + + + + + This project file is using an old file format because it was created using DB Browser for SQLite version 3.10 or lower. Loading this file format is still fully supported but we advice you to convert all your project files to the new file format because support for older formats might be dropped at some point in the future. You can convert your files by simply opening and re-saving them. + + + + + Could not open project file for writing. +Reason: %1 + + + + + Collation needed! Proceed? + + + + + A table in this database requires a special collation function '%1' that this application can't provide without further knowledge. +If you choose to proceed, be aware bad things can happen to your database. +Create a backup! + + + + + creating collation + + + + + Set a new name for the SQL tab. Use the '&&' character to allow using the following character as a keyboard shortcut. + + + + + Please specify the view name + 請指定視圖å稱 + + + + There is already an object with that name. Please choose a different name. + 已有相åŒå稱的å°è±¡ã€‚è«‹é¸æ“‡ä¸€å€‹ä¸åŒçš„å稱。 + + + + View successfully created. + æˆåŠŸå»ºç«‹è¦–åœ–ã€‚ + + + + Error creating view: %1 + 建立視圖時出ç¾éŒ¯èª¤: %1 + + + + This action will open a new SQL tab for running: + + + + + Press Help for opening the corresponding SQLite reference page. + + + + + Busy (%1) + + + + + NullLineEdit + + + Set to NULL + + + + + Alt+Del + + + + + PlotDock + + + Plot + 圖表 + + + + <html><head/><body><p>This pane shows the list of columns of the currently browsed table or the just executed query. You can select the columns that you want to be used as X or Y axis for the plot pane below. The table shows detected axis type that will affect the resulting plot. For the Y axis you can only select numeric columns, but for the X axis you will be able to select:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Date/Time</span>: strings with format &quot;yyyy-MM-dd hh:mm:ss&quot; or &quot;yyyy-MM-ddThh:mm:ss&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Date</span>: strings with format &quot;yyyy-MM-dd&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Time</span>: strings with format &quot;hh:mm:ss&quot;</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Label</span>: other string formats. Selecting this column as X axis will produce a Bars plot with the column values as labels for the bars</li><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Numeric</span>: integer or real values</li></ul><p>Double-clicking the Y cells you can change the used color for that graph.</p></body></html> + + + + + Columns + 列列 + + + + X + X + + + + Y1 + + + + + Y2 + + + + + Axis Type + + + + + Here is a plot drawn when you select the x and y values above. + +Click on points to select them in the plot and in the table. Ctrl+Click for selecting a range of points. + +Use mouse-wheel for zooming and mouse drag for changing the axis range. + +Select the axes or axes labels to drag and zoom only in that orientation. + + + + + Line type: + + + + + + None + ç„¡ + + + + Line + + + + + StepLeft + + + + + StepRight + + + + + StepCenter + + + + + Impulse + + + + + Point shape: + + + + + Cross + + + + + Plus + + + + + Circle + + + + + Disc + + + + + Square + + + + + Diamond + + + + + Star + + + + + Triangle + + + + + TriangleInverted + + + + + CrossSquare + + + + + PlusSquare + + + + + CrossCircle + + + + + PlusCircle + + + + + Peace + + + + + <html><head/><body><p>Save current plot...</p><p>File format chosen by extension (png, jpg, pdf, bmp)</p></body></html> + <html><head/><body><p>儲存目å‰åœ–表...</p><p>æª”æ¡ˆæ ¼å¼æŒ‰å‰¯æª”å鏿“‡(png, jpg, pdf, bmp)</p></body></html> + + + + Save current plot... + 儲存目å‰åœ–表... + + + + + Load all data and redraw plot + + + + + + + Row # + + + + + Copy + + + + + Print... + + + + + Show legend + + + + + Stacked bars + + + + + Date/Time + + + + + Date + + + + + Time + + + + + + Numeric + + + + + Label + + + + + Invalid + + + + + Load all data and redraw plot. +Warning: not all data has been fetched from the table yet due to the partial fetch mechanism. + + + + + Choose an axis color + + + + + Choose a filename to save under + 鏿“‡ä¸€å€‹æª”案å稱儲存 + + + + PNG(*.png);;JPG(*.jpg);;PDF(*.pdf);;BMP(*.bmp);;All Files(*) + PNG(*.png);;JPG(*.jpg);;PDF(*.pdf);;BMP(*.bmp);;所有擋檔案(*) + + + + There are curves in this plot and the selected line style can only be applied to graphs sorted by X. Either sort the table or query by X to remove curves or select one of the styles supported by curves: None or Line. + + + + + Loading all remaining data for this table took %1ms. + + + + + PreferencesDialog + + + Preferences + 首é¸é … + + + + &General + + + + + Remember last location + + + + + Always use this location + + + + + Remember last location for session only + + + + + Lan&guage + + + + + Show remote options + + + + + Automatic &updates + + + + + &Database + 資料庫(&D) + + + + Database &encoding + 資料庫編碼(&E) + + + + Open databases with foreign keys enabled. + 打開啟用了外éµçš„資料庫。 + + + + &Foreign keys + 外éµ(&F) + + + + + + + + + + + + enabled + 啟用 + + + + Default &location + é è¨­ä½ç½®(&L) + + + + + + ... + ... + + + + Remove line breaks in schema &view + + + + + Prefetch block si&ze + + + + + SQ&L to execute after opening database + + + + + Default field type + + + + + Data &Browser + + + + + Font + + + + + &Font + + + + + Content + + + + + Symbol limit in cell + + + + + Threshold for completion and calculation on selection + + + + + Show images in cell + + + + + Enable this option to show a preview of BLOBs containing image data in the cells. This can affect the performance of the data browser, however. + + + + + NULL + + + + + Regular + + + + + Binary + äºŒé€²ä½ + + + + Background + + + + + Filters + + + + + Escape character + + + + + Delay time (&ms) + + + + + Set the waiting time before a new filter value is applied. Can be set to 0 for disabling waiting. + + + + + &SQL + &SQL + + + + Settings name + 設定å稱 + + + + Context + 上下文 + + + + Colour + é¡è‰² + + + + Bold + ç²—é«” + + + + Italic + 斜體 + + + + Underline + 底線 + + + + Keyword + é—œéµå­— + + + + Function + 函數 + + + + Table + 資料表 + + + + Comment + 注釋 + + + + Identifier + 識別符 + + + + String + 字串 + + + + Current line + ç›®å‰è¡Œ + + + + SQL &editor font size + SQL 編輯器字體大å°(&E) + + + + Tab size + + + + + SQL editor &font + + + + + Error indicators + + + + + Hori&zontal tiling + + + + + If enabled the SQL code editor and the result table view are shown side by side instead of one over the other. + + + + + Code co&mpletion + + + + + Toolbar style + + + + + + + + + Only display the icon + + + + + + + + + Only display the text + + + + + + + + + The text appears beside the icon + + + + + + + + + The text appears under the icon + + + + + + + + + Follow the style + + + + + DB file extensions + + + + + Manage + + + + + Main Window + + + + + Database Structure + + + + + Browse Data + + + + + Execute SQL + 執行 SQL + + + + Edit Database Cell + + + + + When this value is changed, all the other color preferences are also set to matching colors. + + + + + Follow the desktop style + + + + + Dark style + + + + + Application style + + + + + This sets the font size for all UI elements which do not have their own font size option. + + + + + Font size + + + + + When enabled, the line breaks in the Schema column of the DB Structure tab, dock and printed output are removed. + + + + + Database structure font size + + + + + Font si&ze + + + + + This is the maximum number of items allowed for some computationally expensive functionalities to be enabled: +Maximum number of rows in a table for enabling the value completion based on current values in the column. +Maximum number of indexes in a selection for calculating sum and average. +Can be set to 0 for disabling the functionalities. + + + + + This is the maximum number of rows in a table for enabling the value completion based on current values in the column. +Can be set to 0 for disabling completion. + + + + + Field display + + + + + Displayed &text + + + + + + + + + + Click to set this color + + + + + Text color + + + + + Background color + + + + + Preview only (N/A) + + + + + Foreground + + + + + SQL &results font size + + + + + &Wrap lines + + + + + Never + + + + + At word boundaries + + + + + At character boundaries + + + + + At whitespace boundaries + + + + + &Quotes for identifiers + + + + + Choose the quoting mechanism used by the application for identifiers in SQL code. + + + + + "Double quotes" - Standard SQL (recommended) + + + + + `Grave accents` - Traditional MySQL quotes + + + + + [Square brackets] - Traditional MS SQL Server quotes + + + + + Keywords in &UPPER CASE + + + + + When set, the SQL keywords are completed in UPPER CASE letters. + + + + + When set, the SQL code lines that caused errors during the last execution are highlighted and the results frame indicates the error in the background + + + + + Close button on tabs + + + + + If enabled, SQL editor tabs will have a close button. In any case, you can use the contextual menu or the keyboard shortcut to close them. + + + + + &Extensions + 擴充套件(&E) + + + + Select extensions to load for every database: + 鏿“‡æ¯å€‹è³‡æ–™åº«è¦è¼‰å…¥çš„æ“´å……套件: + + + + Add extension + 加入擴充套件 + + + + Remove extension + 刪除擴充套件 + + + + <html><head/><body><p>While supporting the REGEXP operator SQLite doesn't implement any regular expression<br/>algorithm but calls back the running application. DB Browser for SQLite implements this<br/>algorithm for you to let you use REGEXP out of the box. However, as there are multiple possible<br/>implementations of this and you might want to use another one, you're free to disable the<br/>application's implementation and load your own by using an extension. Requires restart of the application.</p></body></html> + + + + + Disable Regular Expression extension + + + + + <html><head/><body><p>SQLite provides an SQL function for loading extensions from a shared library file. Activate this if you want to use the <span style=" font-style:italic;">load_extension()</span> function from SQL code.</p><p>For security reasons, extension loading is turned off by default and must be enabled through this setting. You can always load extensions through the GUI, even though this option is disabled.</p></body></html> + + + + + Allow loading extensions from SQL code + + + + + Remote + + + + + CA certificates + + + + + Proxy + + + + + Configure + + + + + + Subject CN + + + + + Common Name + + + + + Subject O + + + + + Organization + + + + + + Valid from + + + + + + Valid to + + + + + + Serial number + + + + + Your certificates + + + + + File + 檔案 + + + + Subject Common Name + + + + + Issuer CN + + + + + Issuer Common Name + + + + + Clone databases into + + + + + + Choose a directory + 鏿“‡ä¸€å€‹ç›®éŒ„ + + + + The language will change after you restart the application. + + + + + Select extension file + 鏿“‡æ“´å……套件檔 + + + + Extensions(*.so *.dylib *.dll);;All files(*) + + + + + Import certificate file + + + + + No certificates found in this file. + + + + + Are you sure you want do remove this certificate? All certificate data will be deleted from the application settings! + + + + + Are you sure you want to clear all the saved settings? +All your preferences will be lost and default values will be used. + + + + + ProxyDialog + + + Proxy Configuration + + + + + Pro&xy Type + + + + + Host Na&me + + + + + Port + + + + + Authentication Re&quired + + + + + &User Name + + + + + Password + + + + + None + ç„¡ + + + + System settings + + + + + HTTP + + + + + Socks v5 + + + + + QObject + + + Error importing data + + + + + from record number %1 + + + + + . +%1 + + + + + Importing CSV file... + + + + + Cancel + å–æ¶ˆ + + + + All files (*) + + + + + SQLite database files (*.db *.sqlite *.sqlite3 *.db3) + + + + + Left + + + + + Right + + + + + Center + + + + + Justify + + + + + SQLite Database Files (*.db *.sqlite *.sqlite3 *.db3) + + + + + DB Browser for SQLite Project Files (*.sqbpro) + + + + + SQL Files (*.sql) + + + + + All Files (*) + + + + + Text Files (*.txt) + + + + + Comma-Separated Values Files (*.csv) + + + + + Tab-Separated Values Files (*.tsv) + + + + + Delimiter-Separated Values Files (*.dsv) + + + + + Concordance DAT files (*.dat) + + + + + JSON Files (*.json *.js) + + + + + XML Files (*.xml) + + + + + Binary Files (*.bin *.dat) + + + + + SVG Files (*.svg) + + + + + Hex Dump Files (*.dat *.bin) + + + + + Extensions (*.so *.dylib *.dll) + + + + + RemoteCommitsModel + + + Commit ID + + + + + Message + + + + + Date + + + + + Author + + + + + Size + + + + + Authored and committed by %1 + + + + + Authored by %1, committed by %2 + + + + + RemoteDatabase + + + Error opening local databases list. +%1 + + + + + Error creating local databases list. +%1 + + + + + RemoteDock + + + Remote + + + + + Identity + + + + + Push currently opened database to server + + + + + DBHub.io + + + + + <html><head/><body><p>In this pane, remote databases from dbhub.io website can be added to DB Browser for SQLite. First you need an identity:</p><ol style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Login to the dbhub.io website (use your GitHub credentials or whatever you want)</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Click the button to &quot;Generate client certificate&quot; (that's your identity). That'll give you a certificate file (save it to your local disk).</li><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Go to the Remote tab in DB Browser for SQLite Preferences. Click the button to add a new certificate to DB Browser for SQLite and choose the just downloaded certificate file.</li></ol><p>Now the Remote panel shows your identity and you can add remote databases.</p></body></html> + + + + + Local + + + + + Current Database + + + + + Clone + + + + + User + 用戶 + + + + Database + + + + + Branch + + + + + Commits + + + + + Commits for + + + + + <html><head/><body><p>You are currently using a built-in, read-only identity. For uploading your database, you need to configure and use your DBHub.io account.</p><p>No DBHub.io account yet? <a href="https://dbhub.io/"><span style=" text-decoration: underline; color:#007af4;">Create one now</span></a> and import your certificate <a href="#preferences"><span style=" text-decoration: underline; color:#007af4;">here</span></a> to share your databases.</p><p>For online help visit <a href="https://dbhub.io/about"><span style=" text-decoration: underline; color:#007af4;">here</span></a>.</p></body></html> + + + + + Back + + + + + Delete Database + + + + + Delete the local clone of this database + + + + + Open in Web Browser + + + + + Open the web page for the current database in your browser + + + + + Clone from Link + + + + + Use this to download a remote database for local editing using a URL as provided on the web page of the database. + + + + + Refresh + + + + + Reload all data and update the views + + + + + F5 + + + + + Clone Database + + + + + Open Database + + + + + Open the local copy of this database + + + + + Check out Commit + + + + + Download and open this specific commit + + + + + Check out Latest Commit + + + + + Check out the latest commit of the current branch + + + + + Save Revision to File + + + + + Saves the selected revision of the database to another file + + + + + Upload Database + + + + + Upload this database as a new commit + + + + + Select an identity to connect + + + + + Public + + + + + This downloads a database from a remote server for local editing. +Please enter the URL to clone from. You can generate this URL by +clicking the 'Clone Database in DB4S' button on the web page +of the database. + + + + + Invalid URL: The host name does not match the host name of the current identity. + + + + + Invalid URL: No branch name specified. + + + + + Invalid URL: No commit ID specified. + + + + + You have modified the local clone of the database. Fetching this commit overrides these local changes. +Are you sure you want to proceed? + + + + + The database has unsaved changes. Are you sure you want to push it before saving? + + + + + The database you are trying to delete is currently opened. Please close it before deleting. + + + + + This deletes the local version of this database with all the changes you have not committed yet. Are you sure you want to delete this database? + + + + + RemoteLocalFilesModel + + + Name + å稱 + + + + Branch + + + + + Last modified + + + + + Size + + + + + Commit + + + + + File + 檔案 + + + + RemoteModel + + + Name + å稱 + + + + Commit + + + + + Last modified + + + + + Size + + + + + Size: + + + + + Last Modified: + + + + + Licence: + + + + + Default Branch: + + + + + RemoteNetwork + + + Choose a location to save the file + + + + + Error opening remote file at %1. +%2 + + + + + Error: Invalid client certificate specified. + + + + + Please enter the passphrase for this client certificate in order to authenticate. + + + + + Cancel + å–æ¶ˆ + + + + Uploading remote database to +%1 + + + + + Downloading remote database from +%1 + + + + + + Error: The network is not accessible. + + + + + Error: Cannot open the file for sending. + + + + + RemotePushDialog + + + Push database + + + + + Database na&me to push to + + + + + Commit message + + + + + Database licence + + + + + Public + + + + + Branch + + + + + Force push + + + + + Username + + + + + Database will be public. Everyone has read access to it. + + + + + Database will be private. Only you have access to it. + + + + + Use with care. This can cause remote commits to be deleted. + + + + + RunSql + + + Execution aborted by user + + + + + , %1 rows affected + + + + + query executed successfully. Took %1ms%2 + + + + + executing query + + + + + SelectItemsPopup + + + A&vailable + + + + + Sele&cted + + + + + SqlExecutionArea + + + Form + 表單 + + + + Find previous match [Shift+F3] + + + + + Find previous match with wrapping + + + + + Shift+F3 + + + + + The found pattern must be a whole word + + + + + Whole Words + + + + + Text pattern to find considering the checks in this frame + + + + + Find in editor + + + + + The found pattern must match in letter case + + + + + Case Sensitive + + + + + Find next match [Enter, F3] + + + + + Find next match with wrapping + + + + + F3 + + + + + Interpret search pattern as a regular expression + + + + + <html><head/><body><p>When checked, the pattern to find is interpreted as a UNIX regular expression. See <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>.</p></body></html> + + + + + Regular Expression + + + + + + Close Find Bar + + + + + <html><head/><body><p>Results of the last executed statements.</p><p>You may want to collapse this panel and use the <span style=" font-style:italic;">SQL Log</span> dock with <span style=" font-style:italic;">User</span> selection instead.</p></body></html> + + + + + Results of the last executed statements + 最後執行語å¥çš„çµæžœ + + + + This field shows the results and status codes of the last executed statements. + 這個欄ä½é¡¯ç¤ºæœ€å¾ŒåŸ·è¡Œçš„語å¥çš„çµæžœå’Œç‹€æ…‹ç¢¼ã€‚ + + + + Couldn't read file: %1. + + + + + + Couldn't save file: %1. + + + + + Your changes will be lost when reloading it! + + + + + The file "%1" was modified by another program. Do you want to reload it?%2 + + + + + SqlTextEdit + + + Ctrl+/ + + + + + SqlUiLexer + + + (X) The abs(X) function returns the absolute value of the numeric argument X. + + + + + () The changes() function returns the number of database rows that were changed or inserted or deleted by the most recently completed INSERT, DELETE, or UPDATE statement. + + + + + (X1,X2,...) The char(X1,X2,...,XN) function returns a string composed of characters having the unicode code point values of integers X1 through XN, respectively. + + + + + (X,Y,...) The coalesce() function returns a copy of its first non-NULL argument, or NULL if all arguments are NULL + + + + + (X,Y) The glob(X,Y) function is equivalent to the expression "Y GLOB X". + + + + + (X,Y) The ifnull() function returns a copy of its first non-NULL argument, or NULL if both arguments are NULL. + + + + + (X,Y) The instr(X,Y) function finds the first occurrence of string Y within string X and returns the number of prior characters plus 1, or 0 if Y is nowhere found within X. + + + + + (X) The hex() function interprets its argument as a BLOB and returns a string which is the upper-case hexadecimal rendering of the content of that blob. + + + + + () The last_insert_rowid() function returns the ROWID of the last row insert from the database connection which invoked the function. + + + + + (X) For a string value X, the length(X) function returns the number of characters (not bytes) in X prior to the first NUL character. + + + + + (X,Y) The like() function is used to implement the "Y LIKE X" expression. + + + + + (X,Y,Z) The like() function is used to implement the "Y LIKE X ESCAPE Z" expression. + + + + + (X) The load_extension(X) function loads SQLite extensions out of the shared library file named X. +Use of this function must be authorized from Preferences. + + + + + (X,Y) The load_extension(X) function loads SQLite extensions out of the shared library file named X using the entry point Y. +Use of this function must be authorized from Preferences. + + + + + (X) The lower(X) function returns a copy of string X with all ASCII characters converted to lower case. + + + + + (X) ltrim(X) removes spaces from the left side of X. + + + + + (X,Y) The ltrim(X,Y) function returns a string formed by removing any and all characters that appear in Y from the left side of X. + + + + + (X,Y,...) The multi-argument max() function returns the argument with the maximum value, or return NULL if any argument is NULL. + + + + + (X,Y,...) The multi-argument min() function returns the argument with the minimum value. + + + + + (X,Y) The nullif(X,Y) function returns its first argument if the arguments are different and NULL if the arguments are the same. + + + + + (FORMAT,...) The printf(FORMAT,...) SQL function works like the sqlite3_mprintf() C-language function and the printf() function from the standard C library. + + + + + (X) The quote(X) function returns the text of an SQL literal which is the value of its argument suitable for inclusion into an SQL statement. + + + + + () The random() function returns a pseudo-random integer between -9223372036854775808 and +9223372036854775807. + + + + + (N) The randomblob(N) function return an N-byte blob containing pseudo-random bytes. + + + + + (X,Y,Z) The replace(X,Y,Z) function returns a string formed by substituting string Z for every occurrence of string Y in string X. + + + + + (X) The round(X) function returns a floating-point value X rounded to zero digits to the right of the decimal point. + + + + + (X,Y) The round(X,Y) function returns a floating-point value X rounded to Y digits to the right of the decimal point. + + + + + (X) rtrim(X) removes spaces from the right side of X. + + + + + (X,Y) The rtrim(X,Y) function returns a string formed by removing any and all characters that appear in Y from the right side of X. + + + + + (X) The soundex(X) function returns a string that is the soundex encoding of the string X. + + + + + (X,Y) substr(X,Y) returns all characters through the end of the string X beginning with the Y-th. + + + + + (X,Y,Z) The substr(X,Y,Z) function returns a substring of input string X that begins with the Y-th character and which is Z characters long. + + + + + () The total_changes() function returns the number of row changes caused by INSERT, UPDATE or DELETE statements since the current database connection was opened. + + + + + (X) trim(X) removes spaces from both ends of X. + + + + + (X,Y) The trim(X,Y) function returns a string formed by removing any and all characters that appear in Y from both ends of X. + + + + + (X) The typeof(X) function returns a string that indicates the datatype of the expression X. + + + + + (X) The unicode(X) function returns the numeric unicode code point corresponding to the first character of the string X. + + + + + (X) The upper(X) function returns a copy of input string X in which all lower-case ASCII characters are converted to their upper-case equivalent. + + + + + (N) The zeroblob(N) function returns a BLOB consisting of N bytes of 0x00. + + + + + + + + (timestring,modifier,modifier,...) + + + + + (format,timestring,modifier,modifier,...) + + + + + (X) The avg() function returns the average value of all non-NULL X within a group. + + + + + (X) The count(X) function returns a count of the number of times that X is not NULL in a group. + + + + + (X) The group_concat() function returns a string which is the concatenation of all non-NULL values of X. + + + + + (X,Y) The group_concat() function returns a string which is the concatenation of all non-NULL values of X. If parameter Y is present then it is used as the separator between instances of X. + + + + + (X) The max() aggregate function returns the maximum value of all values in the group. + + + + + (X) The min() aggregate function returns the minimum non-NULL value of all values in the group. + + + + + + (X) The sum() and total() aggregate functions return sum of all non-NULL values in the group. + + + + + () The number of the row within the current partition. Rows are numbered starting from 1 in the order defined by the ORDER BY clause in the window definition, or in arbitrary order otherwise. + + + + + () The row_number() of the first peer in each group - the rank of the current row with gaps. If there is no ORDER BY clause, then all rows are considered peers and this function always returns 1. + + + + + () The number of the current row's peer group within its partition - the rank of the current row without gaps. Partitions are numbered starting from 1 in the order defined by the ORDER BY clause in the window definition. If there is no ORDER BY clause, then all rows are considered peers and this function always returns 1. + + + + + () Despite the name, this function always returns a value between 0.0 and 1.0 equal to (rank - 1)/(partition-rows - 1), where rank is the value returned by built-in window function rank() and partition-rows is the total number of rows in the partition. If the partition contains only one row, this function returns 0.0. + + + + + () The cumulative distribution. Calculated as row-number/partition-rows, where row-number is the value returned by row_number() for the last peer in the group and partition-rows the number of rows in the partition. + + + + + (N) Argument N is handled as an integer. This function divides the partition into N groups as evenly as possible and assigns an integer between 1 and N to each group, in the order defined by the ORDER BY clause, or in arbitrary order otherwise. If necessary, larger groups occur first. This function returns the integer value assigned to the group that the current row is a part of. + + + + + (expr) Returns the result of evaluating expression expr against the previous row in the partition. Or, if there is no previous row (because the current row is the first), NULL. + + + + + (expr,offset) If the offset argument is provided, then it must be a non-negative integer. In this case the value returned is the result of evaluating expr against the row offset rows before the current row within the partition. If offset is 0, then expr is evaluated against the current row. If there is no row offset rows before the current row, NULL is returned. + + + + + + (expr,offset,default) If default is also provided, then it is returned instead of NULL if the row identified by offset does not exist. + + + + + (expr) Returns the result of evaluating expression expr against the next row in the partition. Or, if there is no next row (because the current row is the last), NULL. + + + + + (expr,offset) If the offset argument is provided, then it must be a non-negative integer. In this case the value returned is the result of evaluating expr against the row offset rows after the current row within the partition. If offset is 0, then expr is evaluated against the current row. If there is no row offset rows after the current row, NULL is returned. + + + + + (expr) This built-in window function calculates the window frame for each row in the same way as an aggregate window function. It returns the value of expr evaluated against the first row in the window frame for each row. + + + + + (expr) This built-in window function calculates the window frame for each row in the same way as an aggregate window function. It returns the value of expr evaluated against the last row in the window frame for each row. + + + + + (expr,N) This built-in window function calculates the window frame for each row in the same way as an aggregate window function. It returns the value of expr evaluated against the row N of the window frame. Rows are numbered within the window frame starting from 1 in the order defined by the ORDER BY clause if one is present, or in arbitrary order otherwise. If there is no Nth row in the partition, then NULL is returned. + + + + + SqliteTableModel + + + reading rows + + + + + loading... + + + + + References %1(%2) +Hold %3Shift and click to jump there + + + + + Error changing data: +%1 + 修改資料庫時出ç¾éŒ¯èª¤: +%1 + + + + retrieving list of columns + + + + + Fetching data... + + + + + + Cancel + å–æ¶ˆ + + + + TableBrowser + + + Browse Data + + + + + &Table: + + + + + Select a table to browse data + 鏿“‡ä¸€å€‹è³‡æ–™è¡¨ä»¥ç€è¦½è³‡æ–™ + + + + Use this list to select a table to be displayed in the database view + ä½¿ç”¨é€™å€‹æ¸…å–®é¸æ“‡ä¸€å€‹è¦é¡¯ç¤ºåœ¨è³‡æ–™åº«è¦–圖中的資料表 + + + + This is the database table view. You can do the following actions: + - Start writing for editing inline the value. + - Double-click any record to edit its contents in the cell editor window. + - Alt+Del for deleting the cell content to NULL. + - Ctrl+" for duplicating the current record. + - Ctrl+' for copying the value from the cell above. + - Standard selection and copy/paste operations. + + + + + Text pattern to find considering the checks in this frame + + + + + Find in table + + + + + Find previous match [Shift+F3] + + + + + Find previous match with wrapping + + + + + Shift+F3 + + + + + Find next match [Enter, F3] + + + + + Find next match with wrapping + + + + + F3 + + + + + The found pattern must match in letter case + + + + + Case Sensitive + + + + + The found pattern must be a whole word + + + + + Whole Cell + + + + + Interpret search pattern as a regular expression + + + + + <html><head/><body><p>When checked, the pattern to find is interpreted as a UNIX regular expression. See <a href="https://en.wikibooks.org/wiki/Regular_Expressions">Regular Expression in Wikibooks</a>.</p></body></html> + + + + + Regular Expression + + + + + + Close Find Bar + + + + + Text to replace with + + + + + Replace with + + + + + Replace next match + + + + + + Replace + + + + + Replace all matches + + + + + Replace all + + + + + <html><head/><body><p>Scroll to the beginning</p></body></html> + + + + + <html><head/><body><p>Clicking this button navigates to the beginning in the table view above.</p></body></html> + + + + + |< + + + + + Scroll one page upwards + + + + + <html><head/><body><p>Clicking this button navigates one page of records upwards in the table view above.</p></body></html> + + + + + < + < + + + + 0 - 0 of 0 + 0 - 0 / 0 + + + + Scroll one page downwards + + + + + <html><head/><body><p>Clicking this button navigates one page of records downwards in the table view above.</p></body></html> + + + + + > + > + + + + Scroll to the end + + + + + <html><head/><body><p>Clicking this button navigates up to the end in the table view above.</p></body></html> + + + + + >| + + + + + <html><head/><body><p>Click here to jump to the specified record</p></body></html> + <html><head/><body><p>點擊這裡跳到指定的記錄</p></body></html> + + + + <html><head/><body><p>This button is used to navigate to the record number specified in the Go to area.</p></body></html> + <html><head/><body><p>這個按鈕用於導航到在“轉到â€å€åŸŸä¸­æŒ‡å®šçš„記錄編號。</p></body></html> + + + + Go to: + 轉到: + + + + Enter record number to browse + 輸入è¦ç€è¦½çš„記錄編號 + + + + Type a record number in this area and click the Go to: button to display the record in the database view + 在這個å€åŸŸä¸­è¼¸å…¥ä¸€å€‹è¨˜éŒ„編號,並點擊“轉到:â€æŒ‰éˆ•以在資料庫視圖中顯示記錄 + + + + 1 + 1 + + + + Show rowid column + + + + + Toggle the visibility of the rowid column + + + + + Unlock view editing + + + + + This unlocks the current view for editing. However, you will need appropriate triggers for editing. + + + + + Edit display format + + + + + Edit the display format of the data in this column + + + + + + New Record + 新建記錄 + + + + + Insert a new record in the current table + 在目å‰è³‡æ–™è¡¨ä¸­æ’å…¥ä¸€æ¢æ–°è¨˜éŒ„ + + + + <html><head/><body><p>This button creates a new record in the database. Hold the mouse button to open a pop-up menu of different options:</p><ul><li><span style=" font-weight:600;">New Record</span>: insert a new record with default values in the database.</li><li><span style=" font-weight:600;">Insert Values...</span>: open a dialog for entering values before they are inserted in the database. This allows to enter values acomplishing the different constraints. This dialog is also open if the <span style=" font-weight:600;">New Record</span> option fails due to these constraints.</li></ul></body></html> + + + + + + Delete Record + 刪除記錄 + + + + Delete the current record + 刪除目å‰è¨˜éŒ„ + + + + + This button deletes the record or records currently selected in the table + + + + + + Insert new record using default values in browsed table + + + + + Insert Values... + + + + + + Open a dialog for inserting values in a new record + + + + + Export to &CSV + 匯出到 &CSV + + + + + Export the filtered data to CSV + + + + + This button exports the data of the browsed table as currently displayed (after filters, display formats and order column) as a CSV file. + + + + + Save as &view + 儲存為視圖(&V) + + + + + Save the current filter, sort column and display formats as a view + + + + + This button saves the current setting of the browsed table (filters, display formats and order column) as an SQL view that you can later browse or use in SQL statements. + + + + + Save Table As... + + + + + + Save the table as currently displayed + + + + + <html><head/><body><p>This popup menu provides the following options applying to the currently browsed and filtered table:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Export to CSV: this option exports the data of the browsed table as currently displayed (after filters, display formats and order column) to a CSV file.</li><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Save as view: this option saves the current setting of the browsed table (filters, display formats and order column) as an SQL view that you can later browse or use in SQL statements.</li></ul></body></html> + + + + + Hide column(s) + + + + + Hide selected column(s) + + + + + Show all columns + + + + + Show all columns that were hidden + + + + + + Set encoding + + + + + Change the encoding of the text in the table cells + + + + + Set encoding for all tables + + + + + Change the default encoding assumed for all tables in the database + + + + + Clear Filters + + + + + Clear all filters + + + + + + This button clears all the filters set in the header input fields for the currently browsed table. + + + + + Clear Sorting + + + + + Reset the order of rows to the default + + + + + + This button clears the sorting columns specified for the currently browsed table and returns to the default order. + + + + + Print + + + + + Print currently browsed table data + + + + + Print currently browsed table data. Print selection if more than one cell is selected. + + + + + Ctrl+P + + + + + Refresh + + + + + Refresh the data in the selected table + + + + + This button refreshes the data in the currently selected table. + 這個按鈕更新在目å‰é¸æ“‡çš„資料表中的資料。 + + + + F5 + + + + + Find in cells + + + + + Open the find tool bar which allows you to search for values in the table view below. + + + + + + Bold + ç²—é«” + + + + Ctrl+B + + + + + + Italic + 斜體 + + + + + Underline + 底線 + + + + Ctrl+U + + + + + + Align Right + + + + + + Align Left + + + + + + Center Horizontally + + + + + + Justify + + + + + + Edit Conditional Formats... + + + + + Edit conditional formats for the current column + + + + + Clear Format + + + + + Clear All Formats + + + + + + Clear all cell formatting from selected cells and all conditional formats from selected columns + + + + + + Font Color + + + + + + Background Color + + + + + Toggle Format Toolbar + + + + + Show/hide format toolbar + + + + + + This button shows or hides the formatting toolbar of the Data Browser + + + + + Select column + + + + + Ctrl+Space + + + + + Replace text in cells + + + + + Filter in any column + + + + + Ctrl+R + + + + + %n row(s) + + + + + + + , %n column(s) + + + + + + + . Sum: %1; Average: %2; Min: %3; Max: %4 + + + + + Conditional formats for "%1" + + + + + determining row count... + + + + + %1 - %2 of >= %3 + + + + + %1 - %2 of %3 + %1 - %2 / %3 + + + + Please enter a pseudo-primary key in order to enable editing on this view. This should be the name of a unique column in the view. + + + + + Delete Records + + + + + Duplicate records + + + + + Duplicate record + + + + + Ctrl+" + + + + + Adjust rows to contents + + + + + Error deleting record: +%1 + 刪除記錄時出ç¾éŒ¯èª¤: +%1 + + + + Please select a record first + è«‹é¦–å…ˆé¸æ“‡ä¸€æ¢è¨˜éŒ„ + + + + There is no filter set for this table. View will not be created. + + + + + Please choose a new encoding for all tables. + + + + + Please choose a new encoding for this table. + + + + + %1 +Leave the field empty for using the database encoding. + + + + + This encoding is either not valid or not supported. + + + + + %1 replacement(s) made. + + + + + VacuumDialog + + + Compact Database + 壓縮資料庫 + + + + Warning: Compacting the database will commit all of your changes. + + + + + Please select the databases to co&mpact: + + + + diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/translations/translations.qrc b/src/WBCLFZSystemModule/SqliteDBProcess/src/translations/translations.qrc new file mode 100644 index 0000000..9dc8486 --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/translations/translations.qrc @@ -0,0 +1,21 @@ + + + sqlb_ar_SA.qm + sqlb_cs.qm + sqlb_ru.qm + sqlb_de.qm + sqlb_fr.qm + sqlb_zh.qm + sqlb_zh_TW.qm + sqlb_pl.qm + sqlb_pt_BR.qm + sqlb_en_GB.qm + sqlb_es_ES.qm + sqlb_ko_KR.qm + sqlb_tr.qm + sqlb_uk_UA.qm + sqlb_it.qm + sqlb_ja.qm + sqlb_nl.qm + + diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/version.h b/src/WBCLFZSystemModule/SqliteDBProcess/src/version.h new file mode 100644 index 0000000..656e171 --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/version.h @@ -0,0 +1,16 @@ +#ifndef GEN_VERSION_H +#define GEN_VERSION_H +#define MAJOR_VERSION 3 +#define MINOR_VERSION 12 +#define PATCH_VERSION 2 + +#define str(s) #s +#define xstr(s) str(s) +#define APP_VERSION xstr(MAJOR_VERSION) "." xstr(MINOR_VERSION) "." xstr(PATCH_VERSION) + +// If it is defined by the compiler, then it is a nightly build, and in the YYYYMMDD format. +#ifndef BUILD_VERSION + #define BUILD_VERSION 0 +#endif + +#endif diff --git a/src/WBCLFZSystemModule/SqliteDBProcess/src/winapp.rc b/src/WBCLFZSystemModule/SqliteDBProcess/src/winapp.rc new file mode 100644 index 0000000..a0559a3 --- /dev/null +++ b/src/WBCLFZSystemModule/SqliteDBProcess/src/winapp.rc @@ -0,0 +1,30 @@ +#include +#include "version.h" + +VS_VERSION_INFO VERSIONINFO +FILEVERSION MAJOR_VERSION, MINOR_VERSION, PATCH_VERSION, 0 +PRODUCTVERSION MAJOR_VERSION, MINOR_VERSION, PATCH_VERSION, 0 +FILEOS VOS_NT_WINDOWS32 +FILETYPE VFT_APP +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "000004B0" + BEGIN + VALUE "FileVersion", APP_VERSION "." xstr(BUILD_VERSION) + VALUE "ProductVersion", APP_VERSION "." xstr(BUILD_VERSION) + VALUE "FileDescription", "DB Browser for SQLite" + VALUE "ProductName", "DB Browser for SQLite" + VALUE "InternalName", "DB Browser for SQLite" + VALUE "OriginalFilename", "DB Browser for SQLite.exe" + VALUE "CompanyName", "DB Browser for SQLite Team" + VALUE "LegalCopyright", "Copyright ?DB Browser for SQLite Team" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x0000, 0x04B0 + END +END + + diff --git a/src/WBCLFZSystemModule/TableProcess/TableFieldConfigClass.cpp b/src/WBCLFZSystemModule/TableProcess/TableFieldConfigClass.cpp new file mode 100644 index 0000000..9cfb64f --- /dev/null +++ b/src/WBCLFZSystemModule/TableProcess/TableFieldConfigClass.cpp @@ -0,0 +1,10 @@ +#include "TableFieldConfigClass.h" + +TableFieldConfigClass::TableFieldConfigClass(QWidget *parent) + : QMainWindow(parent) +{ + ui.setupUi(this); +} + +TableFieldConfigClass::~TableFieldConfigClass() +{} diff --git a/src/WBCLFZSystemModule/TableProcess/TableFieldConfigClass.h b/src/WBCLFZSystemModule/TableProcess/TableFieldConfigClass.h new file mode 100644 index 0000000..f626dc1 --- /dev/null +++ b/src/WBCLFZSystemModule/TableProcess/TableFieldConfigClass.h @@ -0,0 +1,16 @@ +#pragma once + +#include +#include "ui_TableFieldConfigClass.h" + +class TableFieldConfigClass : public QMainWindow +{ + Q_OBJECT + +public: + TableFieldConfigClass(QWidget *parent = nullptr); + ~TableFieldConfigClass(); + +private: + Ui::TableFieldConfigClassClass ui; +}; diff --git a/src/WBCLFZSystemModule/TableProcess/TableFieldConfigClass.ui b/src/WBCLFZSystemModule/TableProcess/TableFieldConfigClass.ui new file mode 100644 index 0000000..6e8d486 --- /dev/null +++ b/src/WBCLFZSystemModule/TableProcess/TableFieldConfigClass.ui @@ -0,0 +1,22 @@ + + TableFieldConfigClassClass + + + TableFieldConfigClassClass + + + + 0 + 0 + 600 + 400 + + + + TableFieldConfigClass + + + + + + diff --git a/src/WBCLFZSystemModule/TableProcess/TableFieldFindTool.cpp b/src/WBCLFZSystemModule/TableProcess/TableFieldFindTool.cpp new file mode 100644 index 0000000..52565e5 --- /dev/null +++ b/src/WBCLFZSystemModule/TableProcess/TableFieldFindTool.cpp @@ -0,0 +1,10 @@ +#include "TableFieldFindTool.h" + +TableFieldFindTool::TableFieldFindTool(QWidget *parent) + : QDialog(parent) +{ + ui.setupUi(this); +} + +TableFieldFindTool::~TableFieldFindTool() +{} diff --git a/src/WBCLFZSystemModule/TableProcess/TableFieldFindTool.h b/src/WBCLFZSystemModule/TableProcess/TableFieldFindTool.h new file mode 100644 index 0000000..c6cb9ca --- /dev/null +++ b/src/WBCLFZSystemModule/TableProcess/TableFieldFindTool.h @@ -0,0 +1,16 @@ +#pragma once + +#include +#include "ui_TableFieldFindTool.h" + +class TableFieldFindTool : public QDialog +{ + Q_OBJECT + +public: + TableFieldFindTool(QWidget *parent = nullptr); + ~TableFieldFindTool(); + +private: + Ui::TableFieldFindToolClass ui; +}; diff --git a/src/WBCLFZSystemModule/TableProcess/TableFieldFindTool.ui b/src/WBCLFZSystemModule/TableProcess/TableFieldFindTool.ui new file mode 100644 index 0000000..be3956e --- /dev/null +++ b/src/WBCLFZSystemModule/TableProcess/TableFieldFindTool.ui @@ -0,0 +1,22 @@ + + TableFieldFindToolClass + + + TableFieldFindToolClass + + + + 0 + 0 + 600 + 400 + + + + TableFieldFindTool + $centralwidget$ + + + + + diff --git a/src/WBCLFZSystemModule/TableProcess/TableMainWindow.cpp b/src/WBCLFZSystemModule/TableProcess/TableMainWindow.cpp new file mode 100644 index 0000000..79cd454 --- /dev/null +++ b/src/WBCLFZSystemModule/TableProcess/TableMainWindow.cpp @@ -0,0 +1,359 @@ +#include "TableMainWindow.h" +#include "TableViewModel.h" +#include "SharedModuleLib/BaseUiTool.h" +#include +#include +#include +#include +#include +#include +#include + +TableMainWindow::TableMainWindow(QWidget* parent) +{ + this->FILEOPENLOCK = false; + this->CheckFieldContextHasEmptyCeilLOCK = false; + this->ui.setupUi(this); + this->initTableViewContextMenu(); + this->initTableViewStatusBarControl(); +} + +TableMainWindow::~TableMainWindow() +{ + delete this->statusprogressBar; + delete this->tableViewContextMenu; + delete this->m_undoStack; +} + +int TableMainWindow::initTableViewContextMenu() +{ + qDebug() << u8"ÕýÔÚ³õʼ»¯contextMenu"; + m_undoStack = new QUndoStack(this); //´æ·ÅÃüÁîµÄÕ» + + this->ui.tableView->setContextMenuPolicy(Qt::CustomContextMenu); + //this->ui.tableView->setFocusPolicy(Qt::NoFocus); // ÔÊÐí¿ì½Ý¼ü + this->tableViewContextMenu = new QMenu(this); // ±í¸ñ¿Ø¼þµÄÓÒ¼ü²Ëµ¥ + + QAction* m_undoAction = m_undoStack->createUndoAction(this, u8"³·Ïú");//Ìí¼ÓQAction£¬Ctrl-Z×÷Ϊ»Ø³·µÄ¿ì½Ý¼ü + m_undoAction->setShortcut(QKeySequence("Ctrl+Z")); + QObject::connect(m_undoAction, SIGNAL(triggered()), this, SLOT(tableView_UndoAction())); + + QAction* m_redoAction = m_undoStack->createRedoAction(this, u8"ÖØ×ö");//Ìí¼ÓQAction£¬Ctrl-Y×óÓÒǰ½øµÄ¿ì½Ý¼ü + m_redoAction->setShortcut(QKeySequence("Ctrl+Y")); + QObject::connect(m_redoAction, SIGNAL(triggered()), this, SLOT(tableView_RedoAction())); + + this->tableViewContextMenu->addAction(m_undoAction); + this->tableViewContextMenu->addAction(m_redoAction); + + + QAction *copyAction= this->tableViewContextMenu->addAction(u8"¸´ÖÆ"); // ¸´ÖÆ + copyAction->setShortcut(QKeySequence("Ctrl+C")); + QObject::connect(copyAction, SIGNAL(triggered()), this, SLOT(tableView_CopyAction())); + + QAction* PasteAction = this->tableViewContextMenu->addAction(u8"Õ³Ìù"); // Õ³Ìù + PasteAction->setShortcut(QKeySequence("Ctrl+V")); + QObject::connect(PasteAction, SIGNAL(triggered()), this, SLOT(tableView_PasteAction())); + + QAction* CheckFieldHasEmptyCeilAction = this->tableViewContextMenu->addAction(u8"¼ì²éµ¥Ôª¸ñΪ¿Õ"); + QObject::connect(CheckFieldHasEmptyCeilAction, SIGNAL(triggered()), this, SLOT(tableView_CheckFieldHasEmptyCeilAction())); + + return 0; +} + +void TableMainWindow::ShowTableViewContextMenu(QPoint p) +{ + qDebug() << u8"ÕýÔÚչʾtableview ÓÒ¼ü²Ëµ¥"; + //Q_UNUSED(pos); + this->tableViewContextMenu->exec(QCursor::pos()); +} + +void TableMainWindow::tableView_CopyAction() +{ + qDebug() << u8"ÕýÔÚÆô¶¯tableview ÓÒ¼ü¸´ÖÆ´úÂë"; + QItemSelectionModel* selectionModel = this->ui.tableView->selectionModel(); + QModelIndexList selectedIndexes = selectionModel->selectedIndexes(); + if (selectedIndexes.count() == 0) { + return; + } + + QTableView* tableView = this->ui.tableView; // Your table view object + + /* + * a\tb\tc\n + * d\tf\te\n + **/ + int min_row, max_row, min_col, max_col; + min_row = selectedIndexes.at(0).row(); + max_row = selectedIndexes.at(0).row(); + min_col = selectedIndexes.at(0).column(); + max_col = selectedIndexes.at(0).column(); + for (int i = 0; i < selectedIndexes.count(); i++) { + min_row = min_row > selectedIndexes.at(i).row() ? selectedIndexes.at(i).row() : min_row; + max_row = max_row < selectedIndexes.at(i).row() ? selectedIndexes.at(i).row() : max_row; + min_col = min_col > selectedIndexes.at(i).column() ? selectedIndexes.at(i).column() : min_col; + max_col = max_col < selectedIndexes.at(i).column() ? selectedIndexes.at(i).column() : max_col; + } + std::vector> copylist(max_row-min_row+1); + for (int i = min_row; i <= max_row; i++) { + copylist[i - min_row] = std::vector(max_col - min_col + 1); + } + qDebug() << u8"minRow"<horizontalHeader(); + //for (int i = 0; i < header->count(); i++) { + // QVariant headerData = header->model()->headerData(i, Qt::Horizontal); + // clipboardData.insert(i, headerData.toString()); + //} + qDebug() << u8"============================"; + qDebug() << clipboardText; + qDebug() << u8"============================"; + + QApplication::clipboard()->setText(clipboardText); +} + +int TableMainWindow::setDragDropOverwriteMode(bool flag) { + this->ui.tableView->setDragDropOverwriteMode(flag); + return 0; +} + +void TableMainWindow::tableView_PasteAction() { + qDebug() << u8"ÕýÔÚÆô¶¯tableview ÓÒ¼üÕ³Ìù´úÂë"; + QTableView* tableview = this->ui.tableView; + QClipboard* clipboard = QApplication::clipboard(); + QString clipboardData = QApplication::clipboard()->text(); + QItemSelectionModel* selectionModel = this->ui.tableView->selectionModel(); + QModelIndexList selectedIndexes = selectionModel->selectedIndexes(); + this->m_undoStack->push(new PasteCommand(this->ui.tableView, selectedIndexes, clipboardData)); + tableview->show(); +} + +void TableMainWindow::tableView_UndoAction() +{ + qDebug() << u8"ÕýÔÚ³·ÏúÃüÁî"; + int index = this->m_undoStack->index(); + this->m_undoStack->setIndex(index); +} + +void TableMainWindow::tableView_RedoAction() +{ + qDebug() << u8"ÕýÔÚÖØ×öÃüÁî"; + int index = this->m_undoStack->index(); + this->m_undoStack->setIndex(index ); +} + + +// ¼ì²é´æÔÚ¿Õµ¥Ôª¸ñµÄÁУ¬²¢ÐÞ¸Äչʾ +void TableMainWindow::tableView_CheckFieldHasEmptyCeilAction() +{ + this->ui.statusbar->showMessage(u8"ÕýÔÚ¼ì²é´æÔÚ¿ÕÊý¾ÝµÄµ¥ÔªÁÐ"); + size_t colcount = this->ui.tableView->model()->columnCount(); + size_t rowcount = this->ui.tableView->model()->rowCount(); + this->statusprogressBar->setRange(0, colcount - 1); + this->statusprogressBar->setValue(0); + QList cellIndexes; + for (int j = 0; j < colcount; j++) { + for (int i = 0; i < rowcount; i++) { + if (this->ui.tableView->model()->index(i, j).data().toString().count() < 1) { + cellIndexes.append(this->ui.tableView->model()->index(i, j)); + break; + } + } + this->statusprogressBar->setValue(j); + } + if (cellIndexes.count() == 0) { + return; + } + else {} + this->ui.statusbar->showMessage(u8"ÕýÔÚÑ¡Ôñ¿Õ¸ñ"); + this->statusprogressBar->setRange(0, cellIndexes.count()-1); + this->statusprogressBar->setValue(0); + QItemSelectionModel* selectionModel = this->ui.tableView->selectionModel(); + for (int i = 0; i < cellIndexes.count(); i++) { + selectionModel->select(cellIndexes[i], QItemSelectionModel::Select); + this->statusprogressBar->setValue(i); + } + this->ui.tableView->show(); + this->ui.tableView->scrollTo(cellIndexes[0], QAbstractItemView::EnsureVisible); + +} + + +int TableMainWindow::LockFileOpen(bool flag) +{ + this->FILEOPENLOCK = flag; + return 0; +} + +int TableMainWindow::setCheckFieldContextHasEmptyCeilLOCK(bool flag) +{ + this->CheckFieldContextHasEmptyCeilLOCK = flag; + return 0; +} + +int TableMainWindow::loadTablemode(std::shared_ptr mode) +{ + this->model = mode; + this->ui.tableView->setModel(this->model.get()); + if (this->model->rowCount() > 1e4) { + this->ui.tableView->horizontalHeader()->setSectionResizeMode(QHeaderView::Interactive); + } + return 0; +} + +int TableMainWindow::setTableViewAutoSort(bool flag) +{ + this->ui.tableView->setSortingEnabled(flag); + return flag; +} + +int TableMainWindow::initTableViewStatusBarControl() +{ + this->statusprogressBar = new QProgressBar(); + this->statusprogressBar->setRange(0, 100); // ÉèÖýø¶ÈÌõ·¶Î§ + this->statusprogressBar->setValue(0); // ÉèÖõ±Ç°½ø¶È + this->ui.statusbar->addPermanentWidget(this->statusprogressBar); // ÔÚ״̬À¸ÖÐÌí¼Ó½ø¶ÈÌõ + + return 0; +} + + + +int TableMainWindow::OpenCSVDialog() +{ + if (this->FILEOPENLOCK) { + return 0; + } + else {} + QString tableFilepath = getOpenFilePath( + this, + QString::fromUtf8(u8"´ò¿ª±í¸ñÎļþ"), + + QString::fromUtf8(u8"csvÎļþ (*.csv);;xlsÎļþ(*.xls)")); + // ¶ÁÈ¡csv Ä£ÐÍ + + return -1; +} + + +int TableMainWindow::SaveCSVDialog() +{ + this->model->saveFilePath(); + return 0; +} + +int TableMainWindow::SaveAsDialog() +{ + QString filepath = getSaveFilePath( + this, + QString::fromUtf8(u8"Áí´æÎª"), + + QString::fromUtf8(u8"csvÎļþ (*.csv)"));//¶à×éÀ©Õ¹ÃûÓÃË«·ÖºÅ";;"¸ô¿ª + this->model->saveAsFilePath(filepath); + return 0; +} + + +/* +* Õ³ÌùÃüÁî +***/ +PasteCommand::PasteCommand(QTableView* tableItem, QModelIndexList selectedIndexes, QString clipboardData, QUndoCommand* parent) : QUndoCommand(parent) +{ + qDebug() << u8"============================"; + qDebug() << clipboardData; + qDebug() << u8"============================"; + this->tableItem = tableItem; + // ½«clipboardData -> ¶þά¾ØÕó + QStringList clipboardList = clipboardData.split("\n"); + if (clipboardList[clipboardList.count() - 1] == u8"") { + clipboardList.removeAt(clipboardList.count() - 1); + } + std::vector> clipboardVec(clipboardList.count()); + for (int i = 0; i < clipboardVec.size(); i++) { + QStringList lineList = clipboardList[i].split("\t"); + clipboardVec[i] = std::vector(lineList.size()); + for (int j = 0; j < lineList.count(); j++) { + clipboardVec[i][j] = lineList[j]; + } + } + this->newText = clipboardVec; + + if (selectedIndexes.count() == 0) { + messageLog(u8"ÇëÑ¡ÖÐÒªÕ³ÌùµÄµ¥Ôª¸ñÇøÓò", 1); + } + else if (selectedIndexes.count() == 1) { // + this->start_row = selectedIndexes.at(0).row(); + this->start_col = selectedIndexes.at(0).column(); + } + else { // + int min_row, max_row, min_col, max_col; + min_row = selectedIndexes.at(0).row(); + max_row = selectedIndexes.at(0).row(); + min_col = selectedIndexes.at(0).column(); + max_col = selectedIndexes.at(0).column(); + for (int i = 0; i < selectedIndexes.count(); i++) { + min_row = min_row > selectedIndexes.at(i).row() ? selectedIndexes.at(i).row() : min_row; + max_row = max_row < selectedIndexes.at(i).row() ? selectedIndexes.at(i).row() : max_row; + min_col = min_col > selectedIndexes.at(i).column() ? selectedIndexes.at(i).column() : min_col; + max_col = max_col < selectedIndexes.at(i).column() ? selectedIndexes.at(i).column() : max_col; + } + if (max_col - min_col + 1 != clipboardVec[0].size() || max_row - min_row + 1 != clipboardVec.size()) { + messageLog(u8"Ñ¡Öе¥Ôª¸ñ·¶Î§´óС²»Æ¥Åä", 1); + } + else {} + this->start_row = selectedIndexes.at(0).row(); + this->start_col = selectedIndexes.at(0).column(); + } + this->oldText = std::vector>(this->newText.size()); + for (int i = 0; i < this->newText.size(); i++) { + this->oldText[i] = std::vector(this->newText[i].size()); + for (int j = 0; j < this->newText[i].size(); j++) { + this->oldText[i][j] = tableItem->model()->index(i + start_row, j + start_col).data().toString(); + } + } +} + +PasteCommand::~PasteCommand() +{ +} + +// ³·Ïú +void PasteCommand::undo() +{ + qDebug() << u8"ÕýÔÚ³·ÏúÃüÁPasteCommand"; + for (int i = 0; i < this->newText.size(); i++) { + this->oldText[i] = std::vector(this->newText[i].size()); + for (int j = 0; j < this->newText[i].size(); j++) { + this->tableItem->model()->setData(tableItem->model()->index(i + start_row, j + start_col), this->oldText[i][j]); + } + } + this->tableItem->show(); +} + +// ÖØ×ö +void PasteCommand::redo() +{ + qDebug() << u8"ÕýÔÚÖØ×öÃüÁPasteCommand"; + for (int i = 0; i < this->newText.size(); i++) { + this->oldText[i] = std::vector(this->newText[i].size()); + for (int j = 0; j < this->newText[i].size(); j++) { + this->tableItem->model()->setData(tableItem->model()->index(i + start_row, j + start_col), this->newText[i][j]); + } + } + this->tableItem->show(); +} diff --git a/src/WBCLFZSystemModule/TableProcess/TableMainWindow.h b/src/WBCLFZSystemModule/TableProcess/TableMainWindow.h new file mode 100644 index 0000000..b770382 --- /dev/null +++ b/src/WBCLFZSystemModule/TableProcess/TableMainWindow.h @@ -0,0 +1,79 @@ +#pragma once +#include +#include "ui_TableMainWindow.h" +#include "TableViewModel.h" +#include +#include +#include +#include + + +/* +* ÃüÁî +***/ + +class PasteCommand : public QUndoCommand { // Õ³ÌùÃüÁî +private: + QTableView* tableItem; + QModelIndexList selectedIndexes; + std::vector> newText; + std::vector> oldText; + size_t start_row, start_col; +public: + PasteCommand(QTableView* tableItem, QModelIndexList selectedIndexes, QString clipboardText, QUndoCommand* parent = 0); + ~PasteCommand(); + //³·Ïú + void undo() override; + //»ØÍË + void redo() override; +}; + + +/* +* ±í¸ñ±à¼­´°ÌåÇé¿ö·ÖÎö +****/ +class TableMainWindow : public QMainWindow +{ + Q_OBJECT +public: + bool FILEOPENLOCK; + bool CheckFieldContextHasEmptyCeilLOCK; +private: + std::shared_ptr model; + QMenu* tableViewContextMenu; + QUndoStack* m_undoStack; + + /*²Ëµ¥*/ + QProgressBar* statusprogressBar; + + +public: + TableMainWindow(QWidget* parent = nullptr); + ~TableMainWindow(); + + int initTableViewStatusBarControl(); + int initTableViewContextMenu(); // ³õʼ»¯ÉÏÏÂÎIJ˵¥ + int LockFileOpen(bool flag=true); // Ëø¶¨Îļþ£¬²»ÔÊÐí½øÐÐÖØÐ´ò¿ªÎļþ + int setCheckFieldContextHasEmptyCeilLOCK(bool flag=true);// ÔÊÐíÆô¶¯µ±Ç°×Ö¶ÎÖдæÔÚ¿Õ¸ñ¼ì²é£¬-- Ìṩ¸øFEKOResult·ÖÎöʹÓà + int loadTablemode(std::shared_ptr mode); // ¼ÓÔØtableview ʹÓõÄmodel + int setTableViewAutoSort(bool flag); + int setDragDropOverwriteMode(bool flag); // ÊÇ·ñ½ûÓÃÁе÷»» +private: + Ui::TableMainWindow ui; + + + +public slots: + int OpenCSVDialog(); + int SaveCSVDialog(); + int SaveAsDialog(); + + // tableview ÓÒ¼ü²Ëµ¥ + void ShowTableViewContextMenu(QPoint p); + void tableView_CopyAction(); + void tableView_PasteAction(); + void tableView_UndoAction(); + void tableView_RedoAction(); + + void tableView_CheckFieldHasEmptyCeilAction(); +}; diff --git a/src/WBCLFZSystemModule/TableProcess/TableMainWindow.ui b/src/WBCLFZSystemModule/TableProcess/TableMainWindow.ui new file mode 100644 index 0000000..33da7ae --- /dev/null +++ b/src/WBCLFZSystemModule/TableProcess/TableMainWindow.ui @@ -0,0 +1,282 @@ + + + TableMainWindow + + + + 0 + 0 + 1014 + 631 + + + + æ•°æ®è¡¨æ ¼ç¼–辑 + + + + + + + + + + + + 0 + 0 + 1014 + 26 + + + + + 文件 + + + + + + + + + 字段 + + + + + + + + + 绘图 + + + + + 工具 + + + + + + + + + + + + + + + + + + + + + + + + + toolBar + + + TopToolBarArea + + + false + + + + + 1 + + + + + + + + 森林目标场景 + + + + + ä»‹ç”µå‚æ•°è¡¨ + + + + + + + + + + 打开文件 + + + + + ä¿å­˜æ–‡ä»¶ + + + + + å¦å­˜ä¸º + + + + + 展示所有字段 + + + + + 添加字段 + + + + + 移除字段 + + + + + 编辑字段 + + + + + 创建新文件 + + + + + FEKO检查 + + + + + 森林目标属性表检查 + + + + + 农作物目标属性表检查 + + + + + è‰åœ°ç›®æ ‡å±žæ€§è¡¨æ£€æŸ¥ + + + + + 水体目标属性表检查 + + + + + 土壤目标属性表检查 + + + + + åŠ¨æ€æ°´ä½“目标属性表检查 + + + + + é“路目标属性表检查 + + + + + 人工目标属性表检查 + + + + + 几何校正场景属性表检查 + + + + + è¾å°„校正场景属性表检查 + + + + + 陆表场景属性表检查 + + + + + 水体场景属性表检查 + + + + + æ¤è¢«åœºæ™¯å±žæ€§è¡¨æ£€æŸ¥ + + + + + + + actionOpen + triggered() + TableMainWindow + OpenCSVDialog() + + + -1 + -1 + + + 312 + 211 + + + + + actionSave + triggered() + TableMainWindow + SaveCSVDialog() + + + -1 + -1 + + + 312 + 211 + + + + + actionSaveAs + triggered() + TableMainWindow + SaveAsDialog() + + + -1 + -1 + + + 312 + 211 + + + + + + OpenCSVDialog() + SaveCSVDialog() + SaveAsDialog() + ShowTableViewContextMenu(QPoint) + + diff --git a/src/WBCLFZSystemModule/TableProcess/TableViewModel.cpp b/src/WBCLFZSystemModule/TableProcess/TableViewModel.cpp new file mode 100644 index 0000000..16d28be --- /dev/null +++ b/src/WBCLFZSystemModule/TableProcess/TableViewModel.cpp @@ -0,0 +1,359 @@ +#include "TableViewModel.h" +#include +#include +#include +#include "SharedModuleLib/BaseUiTool.h" +#include +#include +#include +#include +#include "SharedModuleLib/ProcessOn.h" + +FEKOResultCsvTableModel::FEKOResultCsvTableModel(QObject* parent) +{ +} + +FEKOResultCsvTableModel::~FEKOResultCsvTableModel() +{ +} + +void FEKOResultCsvTableModel::loadFilePath(QString csvPath) +{ + return this->loadCSVFilePath(csvPath); +} + +void FEKOResultCsvTableModel::saveFilePath() +{ + if (!isExists(this->csvPath)) { + this->csvPath = getSaveFilePath( + nullptr, + QString::fromUtf8(u8"Áí´æÎª"), + + QString::fromUtf8(u8"csvÎļþ (*.csv)"));//¶à×éÀ©Õ¹ÃûÓÃË«·ÖºÅ";;"¸ô¿ª + } + return this->saveCSVFilePath(this->csvPath); +} + +void FEKOResultCsvTableModel::saveAsFilePath(QString csvpath) +{ + return this->saveCSVFilePath(csvpath); +} + +void FEKOResultCsvTableModel::loadCSVFilePath(QString csvPath) +{ + this->csvPath = csvPath; + QFile inFile(csvPath); + QStringList colnames; + QVector> datamap(0); + QStringList rowIDlist; + bool hascolnames = true; + size_t rowid = 0; + if (inFile.open(QIODevice::ReadOnly)) + { + QTextStream stream_text(&inFile); + while (!stream_text.atEnd()) + { + QString line = stream_text.readLine(); + QStringList linesplit = line.split(QRegularExpression(",(?!\\s)")); // ×Ö¶ÎÇÐ·Ö + if (hascolnames) { // ÁÐÃû + linesplit[0] = "id"; + for (int col = 0; col < linesplit.size(); col++) { + QString colname_temp = linesplit.at(col); + colnames.append(linesplit.at(col)); // ×·¼Ó×Ö¶ÎÃû³Æ + } + hascolnames = false; + } + else { + QVector mapline(colnames.count()); // µ¥ÐÐÊý¾Ý + mapline[0] =linesplit.at(0); + for (int col = 1; col < colnames.size(); col++) { + mapline[col] = linesplit.at(col); + } + datamap.append(mapline); + rowIDlist.append(QString::number(rowid)); + rowid = rowid + 1; + //qDebug() << line; + } + } + inFile.close(); + } + this->SetData(datamap, colnames, rowIDlist); +} + +void FEKOResultCsvTableModel::saveCSVFilePath(QString csvpath) +{ + qDebug() << u8"ÕýÔÚ±£´æÎª csvÎļþÖÐ"; + QFile file(csvpath); + if (file.open(QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Text)) + { + QTextStream stream(&file); + // дÈë±íÍ· + for (const QString& header : this->m_hor_hedlbls) // дÈë±íÍ· + { + stream << header; + if (&header != &this->m_hor_hedlbls.last()) // Èç¹û²»ÊÇ×îºóÒ»ÁУ¬Ð´È붺ºÅ + stream << ","; + } + stream << "\n"; + // дÈëÊý¾Ý + for (int i = 0; i < this->m_vec_hedlbls.count(); i++) { + for (int j = 0; j < this->m_hor_hedlbls.count()-1; j++) { + stream << this->m_data_map[i][j].toString(); + stream << ","; + } + stream << this->m_data_map[i][this->m_hor_hedlbls.count() - 1].toString(); + stream << "\n"; + } + file.close(); + } + qDebug() << csvpath; +} + +QStringList FEKOResultCsvTableModel::getColumnNames() +{ + return this->m_hor_hedlbls; +} + +QStringList FEKOResultCsvTableModel::getItemDataByColumn(int colidx) +{ + QStringList result; + for (size_t i = 0; i < this->rowCount(); i++) { + result.append(this->m_data_map[i][colidx].toString()); + } + return result; +} + +QString FEKOResultCsvTableModel::getCSVPath() { + return this->csvPath; +} + + +int FEKOResultCsvTableModel::getColumnIdxByColumName(QString ColumnName) { + for (int i = 0; i < this->colCount(); i++) { + if (ColumnName == this->m_hor_hedlbls[i]) { + return i; + } + } + return -1; +} + + +void FEKOResultCsvTableModel::SetData(const QVector>& map,QStringList &colnames, QStringList& rowIds) +{ + beginResetModel(); + m_hor_hedlbls = colnames; // ÁÐÃû + m_data_map = map; + m_vec_hedlbls = rowIds; // ÐÐÃû + this->colorData = QVector>(m_vec_hedlbls.count(), QVector(m_hor_hedlbls.count())); + for (int i = 0; i < m_hor_hedlbls.count(); i++) { + for (int j = 0; j < m_vec_hedlbls.count(); j++) { + this->colorData[j][i] = QColor(255, 255, 255); + } + } + endResetModel(); +} + +void FEKOResultCsvTableModel::setHignlightIndex(QVector > vec_index) +{ + beginResetModel(); + m_highlight_indexs = vec_index; + endResetModel(); +} + +Qt::ItemFlags FEKOResultCsvTableModel::flags(const QModelIndex& index) const +{ + Qt::ItemFlags flags = QAbstractItemModel::flags(index); + flags |= Qt::ItemIsEditable; + return flags; +} + +QVariant FEKOResultCsvTableModel::data(const QModelIndex& _index, int role) const +{ + if (role == Qt::DisplayRole || role == Qt::EditRole) + { + return this->m_data_map[_index.row()][_index.column()]; + } + else if (role == Qt::TextAlignmentRole) return Qt::AlignCenter; // ÎÄ×Ö¾ÓÖÐ + else if (role == Qt::BackgroundColorRole) // ÉèÖñ³¾°É« + { + if (m_highlight_indexs.contains(qMakePair(_index.row(), _index.column()))) + { + return QColor(230, 247, 255); + } + else { + return this->colorData[_index.row()][_index.column()]; + } + } + + // else if(role == Qt::DecorationRole) // ΪitemÌí¼Óͼ±ê + // { + // return QIcon(":/images/device.svg"); + // } + + return QVariant(); +} + +QVariant FEKOResultCsvTableModel::headerData(int section, Qt::Orientation orientation, int role) const +{ + if (orientation == Qt::Horizontal) + { + if (role == Qt::DisplayRole) return m_hor_hedlbls.at(section); + else return QVariant(); + } + + return QAbstractTableModel::headerData(section, orientation, role); // ´¹Ö±±íÍ·µÄÐòºÅ +} + +bool FEKOResultCsvTableModel::setData(const QModelIndex& _index, const QVariant& value, int role) +{ + if (_index.isValid() && role == Qt::EditRole) + { + this->isNeedExtendTable(_index.row(), _index.column()); + if (this->m_data_map[_index.row()][_index.column()]== value) { + return false; + } + else {} + this->m_data_map[_index.row()][_index.column()] = value; + emit dataChanged(_index, _index); + emit itemChanged(_index, value); + return true; + } + else if (role == Qt::BackgroundColorRole) { + this->colorData[_index.row()][_index.column()] = value.value(); + } + return false; +} + +int FEKOResultCsvTableModel::rowCount(const QModelIndex& parent) const +{ + return this->m_vec_hedlbls.count(); +} + +int FEKOResultCsvTableModel::columnCount(const QModelIndex& parent) const +{ + return this->m_hor_hedlbls.count(); +} + +QString FEKOResultCsvTableModel::itemText(int row, int column) const +{ + return this->m_data_map[row][column].toString(); +} + +QString FEKOResultCsvTableModel::itemText(const QModelIndex& index) const +{ + return this->m_data_map[index.row()][index.column()].toString(); +} + +void FEKOResultCsvTableModel::setItemText(const QModelIndex& index, const QString& str) +{ + this->isNeedExtendTable(index.row(), index.column()); + this->m_data_map[index.row()][index.column()] = str; +} + +void FEKOResultCsvTableModel::setItemText(int row, int column, const QString& str) +{ + this->isNeedExtendTable(row, column); + this->m_data_map[row][column] = str; +} + +QVariant FEKOResultCsvTableModel::ItemData(const QModelIndex& index) const +{ + return this->m_data_map[index.row()][index.column()]; +} + +QVariant FEKOResultCsvTableModel::ItemData(int row, int column) const +{ + return this->m_data_map[row][column]; +} + +void FEKOResultCsvTableModel::SetItemData(const QModelIndex& index, const QVariant& data) +{ + this->isNeedExtendTable(index.row(), index.column()); + this->m_data_map[index.row()][index.column()] = data; + +} + +void FEKOResultCsvTableModel::SetItemData(int row, int column, const QVariant& data) +{ + this->isNeedExtendTable(row, column); + this->m_data_map[row][column] = data; +} + +size_t FEKOResultCsvTableModel::rowCount() +{ + return this->m_data_map.count(); +} + + +size_t FEKOResultCsvTableModel::colCount() +{ + return this->m_vec_hedlbls.count(); +} + +void FEKOResultCsvTableModel::isNeedExtendTable(size_t row, size_t column) { + size_t max_colnum = this->m_hor_hedlbls.count() - 1 < column ? column + 1 : this->m_hor_hedlbls.count(); // ÅжÏÊÇ·ñÀ©Õ¹ÁÐÃû + if (this->m_hor_hedlbls.count() <= column) { + for (int i = this->m_hor_hedlbls.count(); i <= column; i++) { + this->m_hor_hedlbls.append(QString::number(i)); + } + } + if (0 > row || column < 0) { + return; + } + else if (row > this->m_vec_hedlbls.count()-1 || column > this->m_hor_hedlbls.count()-1) { + for (int i = 0; i <= row; i++) { + if (i >= this->m_data_map.count()) { + this->m_data_map.append(QVector(max_colnum)); + this->colorData.append(QVector(max_colnum)); + this->m_vec_hedlbls.append(QString::number(i)); + } + else { + if (this->m_data_map[i].count() < column + 1) { // À©³ä + this->m_data_map[i].reserve(max_colnum); + //this->colorData[i].reserve(max_colnum); + for (size_t ci = this->colorData[i].count(); ci < max_colnum; ci++) { + this->colorData[i].append(QColor(255, 255, 255)); + } + } + else { + + } + } + } + } +} + +void FEKOResultCsvTableModel::clear() +{ + beginResetModel(); + //m_table_map.clear(); + m_data_map.clear(); + m_hor_hedlbls.clear(); + m_vec_hedlbls.clear(); + m_highlight_indexs.clear(); + endResetModel(); +} + +QVariant* FEKOResultCsvTableModel::getVariantPtr(size_t row, size_t col) +{ + return &(this->m_data_map[row][col]); + //return nullptr; +} + +void AbstractTableModel::loadFilePath(QString csvPath) +{ +} + +void AbstractTableModel::saveFilePath() +{ + +} + +void AbstractTableModel::saveAsFilePath(QString csvpath) +{ +} + +QString AbstractTableModel::getCSVPath() +{ + return QString(); +} diff --git a/src/WBCLFZSystemModule/TableProcess/TableViewModel.h b/src/WBCLFZSystemModule/TableProcess/TableViewModel.h new file mode 100644 index 0000000..8843dc6 --- /dev/null +++ b/src/WBCLFZSystemModule/TableProcess/TableViewModel.h @@ -0,0 +1,84 @@ +#pragma once +#include "AllHead.h" +#include +#include +#include +#include + +class AbstractTableModel :public QAbstractTableModel { + Q_OBJECT; +public: + virtual void loadFilePath(QString csvPath); // ¼ÓÔØcsvÊý¾Ý + virtual void saveFilePath(); + virtual void saveAsFilePath(QString csvpath); + virtual QString getCSVPath(); +}; + + +// FKEOResult.csv ±í¸ñ¶ÔÓ¦Àà 2023.07.25 ÖØÐ´Àà +class FEKOResultCsvTableModel :public AbstractTableModel { + Q_OBJECT; + +private: + QStringList m_hor_hedlbls; // headerlabels + QStringList m_vec_hedlbls; // oids - map.keys() + QVector> m_data_map; + QVector > m_highlight_indexs; // ±³¾°¸ßÁÁµÄindexs + QVector> colorData; + QString csvPath; + +public: + + explicit FEKOResultCsvTableModel(QObject* parent = NULL); + ~FEKOResultCsvTableModel(); + + virtual void loadFilePath(QString csvPath); // ¼ÓÔØcsvÊý¾Ý + virtual void saveFilePath(); + virtual void saveAsFilePath(QString csvpath); + + void loadCSVFilePath(QString csvPath); // ¼ÓÔØcsvÊý¾Ý + void saveCSVFilePath(QString csvpath); + + QStringList getColumnNames(); + QStringList getItemDataByColumn(int colidx); + int getColumnIdxByColumName(QString ColumnName); + virtual QString getCSVPath(); + + // tableview ±í¸ñÄ£ÐͲÙ×÷ + void SetData(const QVector>& map, QStringList& colnames, QStringList& rowIds); + + void setHignlightIndex(QVector< QPair > vec_index); + + virtual Qt::ItemFlags flags(const QModelIndex& index) const; + virtual QVariant headerData(int section, Qt::Orientation orientation, int role) const; + + virtual int rowCount(const QModelIndex& parent) const; + virtual int columnCount(const QModelIndex& parent) const; + + virtual QVariant data(const QModelIndex& index, int role) const; + virtual bool setData(const QModelIndex& index, const QVariant& value, int role=2); + + QString itemText(int row, int column) const; + QString itemText(const QModelIndex& index) const; + void setItemText(const QModelIndex& index, const QString& str); + void setItemText(int row, int column, const QString& str); + + QVariant ItemData(const QModelIndex& index) const; + QVariant ItemData(int row, int column) const; + void SetItemData(const QModelIndex& index, const QVariant& data); + void SetItemData(int row, int column, const QVariant& data); + + size_t rowCount(); + size_t colCount(); + + void isNeedExtendTable(size_t row, size_t col); + + void clear(); + + QVariant* getVariantPtr(size_t row, size_t col); + +signals: + void itemChanged(const QModelIndex& index, const QVariant& value); + +}; + diff --git a/src/WBCLFZSystemModule/TableProcess/sqliteOperator.cpp b/src/WBCLFZSystemModule/TableProcess/sqliteOperator.cpp new file mode 100644 index 0000000..a5e2444 --- /dev/null +++ b/src/WBCLFZSystemModule/TableProcess/sqliteOperator.cpp @@ -0,0 +1,4 @@ + + + +#include "sqliteOperator.h" diff --git a/src/WBCLFZSystemModule/TableProcess/sqliteOperator.h b/src/WBCLFZSystemModule/TableProcess/sqliteOperator.h new file mode 100644 index 0000000..a077686 --- /dev/null +++ b/src/WBCLFZSystemModule/TableProcess/sqliteOperator.h @@ -0,0 +1,10 @@ +#pragma once + + + + +// ¶¨Òåsqlite ²Ù×÷£¬°üº¬sqlite Êý¾Ý¿âµÄ²Ù×÷ +class sqliteOperator +{ +}; + diff --git a/src/WBCLFZSystemModule/TaskNodeList.cpp b/src/WBCLFZSystemModule/TaskNodeList.cpp new file mode 100644 index 0000000..188c5ed --- /dev/null +++ b/src/WBCLFZSystemModule/TaskNodeList.cpp @@ -0,0 +1,1013 @@ +#include "TaskNodeList.h" + + +// ===================================================================== +// OCCTShapeModelNode +// +// ===================================================================== + +OCCTShapeModelNode::OCCTShapeModelNode(QWidget* parent) : TaskNode(parent) +{ + + this->setChecked(true); + this->Filepath = QString(""); + // °ó¶¨Ê¼þ + QObject::connect(this, &QCheckBox::stateChanged, this, &OCCTShapeModelNode::oncheckBoxStateChanged); + this->initContextMenu(); +} + +OCCTShapeModelNode::~OCCTShapeModelNode() +{ + if ( this->Data_AIS) { + this->myContext->Remove(this->Data_AIS, Standard_False); + this->myContext->UpdateCurrentViewer(); + } +} + +void OCCTShapeModelNode::initContextMenu() +{ + qDebug() << u8"³õʼ»¯initContentListContextMenu£¬Ä£Ðͱ༭ģ¿é"; + this->setContextMenuPolicy(Qt::CustomContextMenu); + //this->setFocusPolicy(Qt::NoFocus); // ÔÊÐí¿ì½Ý¼ü + this->ContentListContextMenu = new QMenu(this); // ±í¸ñ¿Ø¼þµÄÓÒ¼ü²Ëµ¥ + + QAction* show_hideAction = this->ContentListContextMenu->addAction(u8"ÏÔʾ/Òþ²Ø"); // + QObject::connect(show_hideAction, SIGNAL(triggered()), this, SLOT(ShowOrHide())); + + QAction* copyAction = this->ContentListContextMenu->addAction(u8"¸´ÖƶÔÏó"); // + copyAction->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_C)); + QObject::connect(copyAction, SIGNAL(triggered()), this, SLOT(copyItem())); + + QAction* RenameAction = this->ContentListContextMenu->addAction(u8"ÖØÃüÃû"); // + QObject::connect(RenameAction, SIGNAL(triggered()), this, SLOT(renameItem())); + + QAction* showExtendAction = this->ContentListContextMenu->addAction(u8"Ëõ·ÅÖÁ"); // + QObject::connect(showExtendAction, SIGNAL(triggered()), this, SLOT(showExtend())); + + QAction* TranslationdAction = this->ContentListContextMenu->addAction(u8"Ä£ÐͲÙ×÷"); // + QObject::connect(TranslationdAction, SIGNAL(triggered()), this, SLOT(TranslationObject())); + + QAction* removeItemAction = this->ContentListContextMenu->addAction(u8"ÒÆ³ý¶ÔÏó"); // + QObject::connect(removeItemAction, SIGNAL(triggered()), this, SLOT(removeItem())); + + QAction* saveAction = this->ContentListContextMenu->addAction(u8"±£´æ"); // + QObject::connect(saveAction, SIGNAL(triggered()), this, SLOT(saveItem())); + + QAction* saveAsAction = this->ContentListContextMenu->addAction(u8"Áí´æÎª"); // + QObject::connect(saveAsAction, SIGNAL(triggered()), this, SLOT(saveAsItem())); + + QAction* exportAction = this->ContentListContextMenu->addAction(u8"µ¼³ö"); // + QObject::connect(exportAction, SIGNAL(triggered()), this, SLOT(ExportItem())); + + QObject::connect(this, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(ShowContentListContextMenu(QPoint))); + qDebug() << u8"³õʼ»¯contextMenu½áÊø"; +} + +void OCCTShapeModelNode::HideShape() +{ + this->myContext->Erase(this->Data_AIS, Standard_True); + this->setChecked(false); +} + +void OCCTShapeModelNode::ShowShape() +{ + this->myContext->Display(this->Data_AIS, Standard_True); + this->setChecked(true); +} + +void OCCTShapeModelNode::removeDataShapeShow() +{ + if (this->myContext) { + this->myContext->Remove(this->Data_AIS, Standard_False); + this->myContext->UpdateCurrentViewer(); + } +} + +void OCCTShapeModelNode::setContext(Handle(AIS_InteractiveContext) myContext) +{ + this->myContext = myContext; +} + + +void OCCTShapeModelNode::setShape(const TopoDS_Shape& Data_Shape) +{ + this->Data_AIS = new AIS_Shape(Data_Shape); + modelRepair = false; +} + +// ½«Ä£Ðͱ£´æµ½Ö¸¶¨Îļþ·¾¶ÉÏ +void OCCTShapeModelNode::SaveShape(QString Filepath) +{ + SaveTopoDs(Filepath, this->Shape(), this->shapetype); +} + + + +Handle(AIS_Shape)& OCCTShapeModelNode::AIS() +{ + return this->Data_AIS; +} + +const TopoDS_Shape& OCCTShapeModelNode::Shape() +{ + return this->Data_AIS->Shape(); +} + + + +bool OCCTShapeModelNode::setDataFile(QString filepath) +{ + QFileInfo fileinfo(filepath); + QString filename = fileinfo.fileName(); + TopoDS_Shape shape_TopoDs; + this->shapetype = ReadTopoDs_Shape(filepath, shape_TopoDs); + if (this->shapetype == OCCTShapeType::NoneType) { + return false; + } + this->setText(filename); // ÉèÖÃÎļþ + this->setShape(shape_TopoDs); + return true; +} + +bool OCCTShapeModelNode::setSaveFilePath(QString filepath) +{ + this->Filepath = filepath; + return true; +} + +bool OCCTShapeModelNode::SaveFile() +{ + this->SaveShape(this->Filepath); + return false; +} + +bool OCCTShapeModelNode::CheckFilePath() +{ + if (this->Filepath.isEmpty()) { + qDebug() << this->text() + QString(u8", Îļþ·¾¶Îª¿Õ£¡£¡"); + return false; + } + if (!QDir::isAbsolutePath(this->Filepath)) { + qDebug() << this->text() + QString(u8", ²»ÊÇÎļþ·¾¶£¡£¡"); + return false; + } + return true; +} + +int OCCTShapeModelNode::ExcuteTask() +{ + + this->ShowShape(); + this->status = TaskStatusEnum::excuting; + return 0; +} + +int OCCTShapeModelNode::FinishTask() +{ + if (this->modelRepair) { + // ѯÎÊÊÇ·ñ¹Ø±ÕÄ£ÐÍ + QMessageBox msgBox; + msgBox.setText(u8"Ä£ÐÍÒѾ­Ð޸ģ¬ÊÇ·ñ±£´æÄ£ÐÍ"); + msgBox.setInformativeText("Ä£ÐÍÒѾ­Ð޸ģ¬ÊÇ·ñ±£´æÄ£ÐÍ"); + msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No); + msgBox.setDefaultButton(QMessageBox::No); + int ret = msgBox.exec(); + + if (ret == QMessageBox::Yes) { // ±£´æÄ£ÐÍ + this->saveItem(); + } + else if (ret == QMessageBox::No) { // Ñ¡Ôñ²»±£´æÄ£ÐÍ + + } + } + this->myContext->Remove(this->AIS(), Standard_False); // ɾ³ýÄ£ÐÍ + this->myContext->UpdateCurrentViewer(); // ɾ³ýÄ£ÐÍ + this->status = TaskStatusEnum::finish; + QObject::disconnect(this, nullptr, this, nullptr); + return 0; +} + +TaskNode* OCCTShapeModelNode::CopyToNew() +{ + + + + return nullptr; +} + + + +void OCCTShapeModelNode::removeItem() +{ + this->FinishTask(); + emit this->deleteItem(this->text()); +} + +void OCCTShapeModelNode::renameItem() +{ + bool ok; + QString oldname = this->getTaskName(); + QString newName = QInputDialog::getText(this, "Rename Item", "Enter new name:", QLineEdit::Normal, this->text(), &ok); + if (newName.isEmpty()) { + newName = oldname; + return; + } + else {} + emit this->renameItem(newName); +} + +void OCCTShapeModelNode::copyItem() +{ + emit this->copyNew(); +} + +void OCCTShapeModelNode::showExtend() +{ + // Ëõ·Åµ½Ìض¨Ä£ÐÍ + myContext->ClearSelected(Standard_True); + myContext->AddOrRemoveSelected(this->Data_AIS, Standard_True); + emit this->ShowFullExtend(this->Shape()); +} + + +void OCCTShapeModelNode::saveItem() +{ + qDebug() << u8"±£´æÄ£ÐÍ:" << this->Filepath; + QFileInfo fi(this->Filepath); // ÅжÏÎļþÊÇ·ñ´æÔÚ + if (fi.exists()) { + qDebug() << " Path exists." << this->Filepath; + this->SaveFile(); + } + else { + this->saveAsItem(); + } + +} + +void OCCTShapeModelNode::saveAsItem() +{ + qDebug() << "Item SaveAs."; + QString saveFilePath = getSaveFilePath(nullptr, + QString::fromUtf8(u8"Áí±£´æÄ£ÐÍ"), + getOCCTShapeTypeFilterString(this->shapetype)); + // Áí´æÎªÄ£ÐÍ + this->Filepath = saveFilePath; + this->SaveFile(); // ÉèÖÃÎļþ·¾¶£¬ÖØÐ±£´æ + +} + +void OCCTShapeModelNode::ExportItem() { + OcctExportClass exportwindows(this); + exportwindows.setDataShape(this->Shape()); + exportwindows.exec(); +} + +void OCCTShapeModelNode::TranslationObject() +{ + emit this->ModelModify(this); +} + + + +void OCCTShapeModelNode::ShowContentListContextMenu(QPoint p) +{ + this->ContentListContextMenu->exec(QCursor::pos()); +} + +void OCCTShapeModelNode::ShowOrHide() +{ + qDebug() << u8"Çл»ÏÔʾ \n"; + if (this->isChecked()) { // µ±Ç°ÏÔʾ + qDebug() << u8"True \n"; + this->HideShape(); + } + else { + qDebug() << u8"false \n"; + this->ShowShape(); + } +} + + + +void OCCTShapeModelNode::oncheckBoxStateChanged(int state) { + OCCTShapeModelNode* senderCheckBox = qobject_cast(sender()); + + if (senderCheckBox) { + // ¸ù¾Ý״̬±ä»¯µÄ QCheckBox ÏÔʾÏàÓ¦µÄÏûÏ¢ + QString message = QString("%1 state changed to %2").arg(senderCheckBox->text()).arg(state == Qt::Checked ? "Checked" : "Unchecked"); + qDebug() << "Checkbox State Changed\n"; + qDebug() << message; + if (state == Qt::Checked) { + this->ShowShape(); + } + else { + this->HideShape(); + } + } +} + + + + +// ===================================================================== +// DataShowNode +// +// ===================================================================== + + + + + + + + + +// ===================================================================== +// ComplexDataShowNode +// +// ===================================================================== + + + +ComplexDataShowNode::ComplexDataShowNode(QWidget* parent) :TaskNode(parent) +{ + + this->m = nullptr; + this->datapath = QString(); + this->setName("NOData"); + + QAction* action_Load_dB_Image = this->ContentListContextMenu->addAction(u8"¼ÓÔØdB"); + QAction* action_Load_amp_Image = this->ContentListContextMenu->addAction(u8"¼ÓÔØÕñ·ù"); + QAction* action_Load_real_Image = this->ContentListContextMenu->addAction(u8"¼ÓÔØÊµ²¿"); + QAction* action_Load_imag_Image = this->ContentListContextMenu->addAction(u8"¼ÓÔØÐ鲿"); + QAction* action_Load_pha_Image = this->ContentListContextMenu->addAction(u8"¼ÓÔØÏàλ"); + + QObject::connect(action_Load_dB_Image, SIGNAL(triggered()), this, SLOT(Load_dB_Image())); + QObject::connect(action_Load_amp_Image, SIGNAL(triggered()), this, SLOT(Load_amp_Image())); + QObject::connect(action_Load_real_Image, SIGNAL(triggered()), this, SLOT(Load_real_Image())); + QObject::connect(action_Load_imag_Image, SIGNAL(triggered()), this, SLOT(Load_imag_Image())); + QObject::connect(action_Load_pha_Image, SIGNAL(triggered()), this, SLOT(Load_pha_Image())); + +} + + +void ComplexDataShowNode::bangdindWindows(QMainWindow* m) +{ + this->m = m; +} + + +ComplexDataShowNode::~ComplexDataShowNode() +{ + +} + + +void ComplexDataShowNode::loadData() +{ + QFileInfo fileinfo(this->TaskXmlPath); + if (fileinfo.exists()) { + //this->echo = readMatrixXcd2ENVI_CFloat64(this->TaskXmlPath); + } + else {} +} + +void ComplexDataShowNode::OpenData(QString TaskXmlPath) +{ + this->TaskXmlPath = TaskXmlPath; + QFileInfo fileinfo(this->TaskXmlPath); + if (fileinfo.exists()) { + if (fileinfo.makeAbsolute()) { + this->datapath = fileinfo.filePath(); + } + else { + this->datapath = TaskXmlPath; + } + this->setName(fileinfo.fileName()); + } + else {} + +} + +int ComplexDataShowNode::ExcuteTask() +{ + this->status = TaskStatusEnum::excuting; + this->Load_amp_Image(); + return 0; +} + +void ComplexDataShowNode::Load_amp_Image() +{ + ImageShowDialogClass* DataShowDockWidget = new ImageShowDialogClass(this); + gdalImageComplex img(this->TaskXmlPath); + Eigen::MatrixXcd im_final = img.getDataComplex(0, 0, img.height, img.width, 1); + Eigen::MatrixXd gt = img.getGeoTranslation(); + + Eigen::MatrixXd Y(img.height, 1); + Eigen::MatrixXd X(1, img.width); + + for (int i = 0; i < img.height; i++) { + Y(i, 0) = gt(1, 0) + gt(1, 1) * 0 - gt(1, 2) * i; + } + for (int i = 0; i < img.width; i++) { + X(i, 0) = gt(0, 0) + gt(0, 1) * i - gt(0, 2) * 0; + } + + Eigen::MatrixXd im_amp = Complex2Amplitude(im_final); + DataShowDockWidget->load_double_MatrixX_data(X, Y, im_amp, this->getName()); + + DataShowDockWidget->show(); +} + +void ComplexDataShowNode::Load_pha_Image() +{ + ImageShowDialogClass* DataShowDockWidget = new ImageShowDialogClass(this); + gdalImageComplex img(this->TaskXmlPath); + Eigen::MatrixXcd im_final = img.getDataComplex(0, 0, img.height, img.width, 1); + Eigen::MatrixXd gt = img.getGeoTranslation(); + + Eigen::MatrixXd Y(img.height, 1); + Eigen::MatrixXd X(1, img.width); + + for (int i = 0; i < img.height; i++) { + Y(i, 0) = gt(1, 0) + gt(1, 1) * 0 + gt(1, 2) * i; + } + for (int i = 0; i < img.width; i++) { + X(i, 0) = gt(0, 0) + gt(0, 1) * i + gt(0, 2) * 0; + } + + Eigen::MatrixXd im_pha = Complex2phase(im_final); + DataShowDockWidget->load_double_MatrixX_data(X, Y, im_pha, this->getName()); + + + DataShowDockWidget->show(); +} + +void ComplexDataShowNode::Load_real_Image() +{ + ImageShowDialogClass* DataShowDockWidget = new ImageShowDialogClass(this); + gdalImageComplex img(this->TaskXmlPath); + Eigen::MatrixXcd im_final = img.getDataComplex(0, 0, img.height, img.width, 1); + Eigen::MatrixXd gt = img.getGeoTranslation(); + + Eigen::MatrixXd Y(img.height, 1); + Eigen::MatrixXd X(1, img.width); + + for (int i = 0; i < img.height; i++) { + Y(i, 0) = gt(1, 0) + gt(1, 1) * 0 + gt(1, 2) * i; + } + for (int i = 0; i < img.width; i++) { + X(i, 0) = gt(0, 0) + gt(0, 1) * i + gt(0, 2) * 0; + } + + Eigen::MatrixXd im_amp = im_final.array().real(); + DataShowDockWidget->load_double_MatrixX_data(X, Y, im_amp, this->getName()); + + DataShowDockWidget->show(); +} + +void ComplexDataShowNode::Load_imag_Image() +{ + ImageShowDialogClass* DataShowDockWidget = new ImageShowDialogClass(this); + gdalImageComplex img(this->TaskXmlPath); + Eigen::MatrixXcd im_final = img.getDataComplex(0, 0, img.height, img.width, 1); + Eigen::MatrixXd gt = img.getGeoTranslation(); + + Eigen::MatrixXd Y(img.height, 1); + Eigen::MatrixXd X(1, img.width); + + for (int i = 0; i < img.height; i++) { + Y(i, 0) = gt(1, 0) + gt(1, 1) * 0 + gt(1, 2) * i; + } + for (int i = 0; i < img.width; i++) { + X(i, 0) = gt(0, 0) + gt(0, 1) * i + gt(0, 2) * 0; + } + + Eigen::MatrixXd im_amp = im_final.array().imag(); + DataShowDockWidget->load_double_MatrixX_data(X, Y, im_amp, this->getName()); + + DataShowDockWidget->show(); +} + +void ComplexDataShowNode::Load_dB_Image() +{ + ImageShowDialogClass* DataShowDockWidget = new ImageShowDialogClass(this); + gdalImageComplex img(this->TaskXmlPath); + Eigen::MatrixXcd im_final = img.getDataComplex(0, 0, img.height, img.width, 1); + Eigen::MatrixXd gt = img.getGeoTranslation(); + Eigen::MatrixXd Y(img.height, 1); + Eigen::MatrixXd X(1, img.width); + + for (int i = 0; i < img.height; i++) { + Y(i, 0) = gt(1, 0) + gt(1, 1) * 0 + gt(1, 2) * i; + } + for (int i = 0; i < img.width; i++) { + X(i, 0) = gt(0, 0) + gt(0, 1) * i + gt(0, 2) * 0; + } + + Eigen::MatrixXd im_dB = Complex2dB(im_final); + DataShowDockWidget->load_double_MatrixX_data(X, Y, im_dB, this->getName()); + DataShowDockWidget->show(); +} + +DataShowNode::DataShowNode(QWidget* parent) :TaskNode(parent) +{ + this->m = nullptr; + this->datapath = QString(); + this->setName("NOData"); + + QAction* action_Load_Image = this->ContentListContextMenu->addAction(u8"¼ÓÔØÍ¼Ïñ"); + QObject::connect(action_Load_Image, SIGNAL(triggered()), this, SLOT(Load_Image())); +} + +void DataShowNode::Load_Image() +{ + this->loadData(); +} + + + + +DataShowNode::~DataShowNode() +{ +} + +void DataShowNode::bangdindWindows(QMainWindow* m) +{ + +} + +void DataShowNode::loadData() +{ + QFileInfo fileinfo(this->datapath); + if (fileinfo.exists()) { + gdalImage img(this->datapath); + Eigen::MatrixXd im_final = img.getData(0, 0, img.height, img.width, 1); + Eigen::MatrixXd gt = img.getGeoTranslation(); + Eigen::MatrixXd Y(img.height, 1); + Eigen::MatrixXd X(1, img.width); + + for (int i = 0; i < img.height; i++) { + Y(i, 0) = gt(1, 0) + gt(1, 1) * 0 + gt(1, 2) * i; + } + for (int i = 0; i < img.width; i++) { + X(i, 0) = gt(0, 0) + gt(0, 1) * i + gt(0, 2) * 0; + } + + + DataShowDockWidget->load_double_MatrixX_data(X, Y, im_final, this->getName()); + DataShowDockWidget->show(); + + } +} + +void DataShowNode::OpenData(QString TaskXmlPath) +{ + this->TaskXmlPath = TaskXmlPath; + QFileInfo fileinfo(this->TaskXmlPath); + if (fileinfo.exists()) { + if (fileinfo.makeAbsolute()) { + this->datapath = fileinfo.filePath(); + } + else { + this->datapath = TaskXmlPath; + } + + this->setName(fileinfo.fileName()); + } + else {} +} + +int DataShowNode::ExcuteTask() +{ + this->status = TaskStatusEnum::excuting; + this->loadData(); + return 0; +} + +// ===================================================================== +// FEKOResultImportTaskNode +// +// ===================================================================== + + +FEKOResultImportTaskNode::FEKOResultImportTaskNode() +{ +} + +FEKOResultImportTaskNode::~FEKOResultImportTaskNode() +{ + if (nullptr != this->TaskWindows) { + this->TaskWindows->close(); + delete this->TaskWindows; + this->TaskWindows = nullptr; + } +} + +int FEKOResultImportTaskNode::ExcuteTask() +{ + this->status = TaskStatusEnum::excuting; + this->TaskWindows = new FEKOResultImport(); + this->TaskWindows->setAttribute(Qt::WA_DeleteOnClose); // ¹Ø±Õʱ×Ô¶¯ÊÍ·Å + //this->TaskWindows->setWindowModality(Qt::WindowModal); + QObject::connect((this->TaskWindows), SIGNAL(callbackFekoResultImport(FEKOResultImport*)), this, SLOT(getExcuteTaskResult(FEKOResultImport*))); + // ¸üвÎÊý + this->TaskWindows->setFEKOPreProjectFolderPath(this->FolderPath); + this->TaskWindows->setNearFieldNames(this->nearFieldNames); + this->TaskWindows->setFarFieldNames(this->farFieldNames); + this->TaskWindows->setSelectFieldNames(this->selectFieldNames, this->nearField); + this->TaskWindows->setFEKOResultCSVPath(this->outPath); + this->TaskWindows->setFEKOPreFileName(this->prename); + this->TaskWindows->initView(); + this->TaskWindows->show(); // չʾͼÏñ + //FEKOImportWindows->close(); + //delete FEKOImportWindows; + return 0; +} + +int FEKOResultImportTaskNode::loadXmlFile(QString xmlFilePath) +{ + this->TaskXmlPath = xmlFilePath; + if (isExists(xmlFilePath)) { + QDomDocument doc; + this->loadXmlDocument(this->TaskXmlPath, doc); + + // ½âÎöxmlÎļþ + QDomElement root = doc.documentElement(); + // ²ÉÓÃDSF + QDomNodeList rootchild = root.childNodes(); + for (int i = 0; i < rootchild.length(); i++) { + QDomNode tempnode = rootchild.at(i); + if (strcmp(tempnode.nodeName().toUtf8().constData(), "TaskName") == 0) { + this->setName(tempnode.firstChild().nodeValue()); + } + else if (strcmp(tempnode.nodeName().toUtf8().constData(), "Description") == 0) { + this->description = tempnode.firstChild().nodeValue(); + } + else if (strcmp(tempnode.nodeName().toUtf8().constData(), "TaskStatus") == 0) { + QString temptext = tempnode.firstChild().nodeValue(); + if (strcmp(temptext.toUtf8().constData(), "wait") == 0) { + this->status = TaskStatusEnum::wait; + } + else if (strcmp(temptext.toUtf8().constData(), "success") == 0) { + this->status = TaskStatusEnum::success; + } + else if (strcmp(temptext.toUtf8().constData(), "fail") == 0) { + this->status = TaskStatusEnum::fail; + } + else {} + } + else if (strcmp(tempnode.nodeName().toUtf8().constData(), "preName") == 0) { + this->prename = tempnode.firstChild().nodeValue().toUtf8().constData(); + } + else if (strcmp(tempnode.nodeName().toUtf8().constData(), "FEKOProjectFolderPath") == 0) { + this->FolderPath = tempnode.firstChild().nodeValue().toUtf8().constData(); + } + else if (strcmp(tempnode.nodeName().toUtf8().constData(), "NearField") == 0) { + QString temptext = tempnode.firstChild().nodeValue().toUpper().toUtf8().constData(); + if (strcmp(temptext.toUtf8().constData(), "FALSE") == 0) { + this->nearField = false; + } + else if (strcmp(temptext.toUtf8().constData(), "TRUE") == 0) { + this->nearField = true; + } + else { + this->nearField = false; + } + } + else if (strcmp(tempnode.nodeName().toUtf8().constData(), "FarField") == 0) { + QString temptext = tempnode.firstChild().nodeValue().toUpper().toUtf8().constData(); + if (strcmp(temptext.toUtf8().constData(), "FALSE") == 0) { + this->farField = false; + } + else if (strcmp(temptext.toUtf8().constData(), "TRUE") == 0) { + this->farField = true; + } + else { + this->farField = false; + } + } + else if (strcmp(tempnode.nodeName().toUtf8().constData(), "OutPath") == 0) { + this->outPath = tempnode.firstChild().nodeValue().toUtf8().constData(); + } + else if (strcmp(tempnode.nodeName().toUtf8().constData(), "NearFieldNodeList") == 0) { + QDomNodeList tempnodechild = tempnode.childNodes(); + this->nearFieldNames = std::vector(0); + for (int ii = 0; ii < tempnodechild.count(); ii++) { + QDomNode tempnode = tempnodechild.at(ii); + this->nearFieldNames.push_back(tempnode.firstChild().nodeValue().toUtf8().constData()); + } + } + else if (strcmp(tempnode.nodeName().toUtf8().constData(), "FarFieldNodeList") == 0) { + QDomNodeList tempnodechild = tempnode.childNodes(); + this->farFieldNames = std::vector(0); + for (int ii = 0; ii < tempnodechild.count(); ii++) { + QDomNode tempnode = tempnodechild.at(ii); + this->farFieldNames.push_back(tempnode.firstChild().nodeValue().toUtf8().constData()); + } + } + else if (strcmp(tempnode.nodeName().toUtf8().constData(), "SelectNodeList") == 0) { + QDomNodeList tempnodechild = tempnode.childNodes(); + this->selectFieldNames = std::vector(0); + for (int ii = 0; ii < tempnodechild.count(); ii++) { + QDomNode tempnode = tempnodechild.at(ii); + this->selectFieldNames.push_back(tempnode.firstChild().nodeValue().toUtf8().constData()); + } + } + } + + if (this->nearField || this->farField) { + // ±£´æ½á¹û + return -1; + } + else { + QMessageBox::warning(this, u8"´íÎó", u8"request Field ´íÎó"); + return 1; + } + } + else { + this->TaskXmlPath = xmlFilePath; + this->selectFieldNames = std::vector(0); + this->farFieldNames = std::vector(0); + this->nearFieldNames = std::vector(0); + return 0; + } + return 0; +} + +///

+/// Êä³öFEKOResultµ¼ÈëÈÎÎñ +/// +/// +int FEKOResultImportTaskNode::saveXmlFile() +{ + if (isExists(this->TaskXmlPath)) { + removeFile(this->TaskXmlPath); + } + else {} + QDomDocument doc; // ´´½¨ ÈÎÎñÊä³öxml + + QDomProcessingInstruction instruction;// ´´½¨XML´¦ÀíÀ࣬ͨ³£ÓÃÓÚ´¦ÀíµÚÒ»ÐÐÃèÊöÐÅÏ¢ + instruction = doc.createProcessingInstruction("xml", "version=\"1.0\" encoding=\"UTF-8\"");// ´´½¨XMLÍ·²¿¸ñʽ + doc.appendChild(instruction);// Ìí¼Óµ½XMLÎļþÖÐ + + QDomElement root = doc.createElement("FEKOResultImportTaskNode"); // ´´½¨¸ù½Úµã + doc.appendChild(root); + + QDomElement TaskNameNode = doc.createElement("TaskName"); // ÈÎÎñÃû³Æ + TaskNameNode.appendChild(doc.createTextNode(this->getName())); + root.appendChild(TaskNameNode); + + QDomElement DescripNode = doc.createElement("Description"); // ÃèÊö + DescripNode.appendChild(doc.createTextNode(this->description)); + root.appendChild(DescripNode); + + QDomElement TaskStatusNode = doc.createElement("TaskStatus"); // Ö´ÐÐ״̬ + if (this->status == TaskStatusEnum::wait) { + TaskStatusNode.appendChild(doc.createTextNode("wait")); + } + else if (this->status == TaskStatusEnum::success) { + TaskStatusNode.appendChild(doc.createTextNode("success")); + } + else if (this->status == TaskStatusEnum::fail) { + TaskStatusNode.appendChild(doc.createTextNode("fail")); + } + else {} + root.appendChild(TaskStatusNode); + + QDomElement preNameNode = doc.createElement("preName"); // µ¼ÈëÎļþ¹¤³Ì .pre ÎļþÃû + preNameNode.appendChild(doc.createTextNode(this->prename)); + root.appendChild(preNameNode); + + QDomElement FEKOProjectFolderPathNode = doc.createElement("FEKOProjectFolderPath"); // µ¼ÈëÎļþ¹¤³Ì folder ÎļþÃû + FEKOProjectFolderPathNode.appendChild(doc.createTextNode(this->FolderPath)); + root.appendChild(FEKOProjectFolderPathNode); + + QDomElement NearFieldNode = doc.createElement("NearField"); // ÊÇ·ñÊǽü³¡Îļþ + NearFieldNode.appendChild(doc.createTextNode(this->nearField ? "True" : "False")); + root.appendChild(NearFieldNode); + + QDomElement FarFieldNode = doc.createElement("FarField"); // ÊÇ·ñÊÇÔ¶³¡Îļþ + FarFieldNode.appendChild(doc.createTextNode(this->farField ? "True" : "False")); + root.appendChild(FarFieldNode); + + QDomElement outPathNode = doc.createElement("OutPath"); // °üº¬Êä³öÎļþ + outPathNode.appendChild(doc.createTextNode(this->outPath)); + root.appendChild(outPathNode); + + QDomElement NearFieldListNode = doc.createElement("NearFieldNodeList"); // ½ü³¡Êý¾ÝÁбíÐÔÊä³ö + for (int i = 0; i < this->nearFieldNames.size(); i++) { + QDomElement NearFieldMetaNode = doc.createElement("FileNode"); + NearFieldMetaNode.appendChild(doc.createTextNode(this->nearFieldNames[i])); + NearFieldListNode.appendChild(NearFieldMetaNode); + } + root.appendChild(NearFieldListNode); + + QDomElement FarFieldListNode = doc.createElement("FarFieldNodeList"); // ½ü³¡Êý¾ÝÁбíÐÔÊä³ö + for (int i = 0; i < this->farFieldNames.size(); i++) { + QDomElement FarFieldMetaNode = doc.createElement("FileNode"); + FarFieldMetaNode.appendChild(doc.createTextNode(this->farFieldNames[i])); + FarFieldListNode.appendChild(FarFieldMetaNode); + } + root.appendChild(FarFieldListNode); + + QDomElement SelectNodeListNode = doc.createElement("SelectNodeList"); // Éú³ÉËùÑ¡ÔñÊý¾ÝÁбí + for (int i = 0; i < this->selectFieldNames.size(); i++) { + QDomElement SelectMetaNode = doc.createElement("FileNode"); + SelectMetaNode.appendChild(doc.createTextNode(this->selectFieldNames[i])); + SelectNodeListNode.appendChild(SelectMetaNode); + } + root.appendChild(SelectNodeListNode); + + this->writeXmlDocument(doc); + return 0; +} + +int FEKOResultImportTaskNode::FinishTask() +{ + this->status = TaskStatusEnum::finish; + return 0; +} + +void FEKOResultImportTaskNode::getExcuteTaskResult(FEKOResultImport* obj) +{ + // ¸üÐÂ״̬ + this->status = obj->getSaveSucessfully() ? TaskStatusEnum::success : TaskStatusEnum::fail; + this->nearField = obj->getNearChecked(); + this->farField = obj->getFarChecked(); + this->nearFieldNames = obj->getNearFieldNames(); + this->farFieldNames = obj->getFarFieldNames(); + this->prename = obj->getFEKOPreFileName(); + this->selectFieldNames = obj->getSelectFieldNames(); + this->outPath = obj->getFEKOResultCSVPath(); + this->FolderPath = obj->getFEKOPreProjectFolderPath(); + this->saveXmlFile(); + QMessageBox::information(nullptr, u8"ÕýÔÚ´ò¿ªFEKO½á¹ûÎļþ", this->outPath); + // ´ò¿ªtableview½çÃæ½øÐÐÈ·ÈÏÐÞ¸Ä + EchoTableEditWindow* tablewindow = new EchoTableEditWindow(this); // ´ò¿ª»Ø²¨±à¼­Ò³Ãæ + tablewindow->setCheckFieldContextHasEmptyCeilLOCK(true); + tablewindow->setAttribute(Qt::WA_DeleteOnClose);// ¹Ø±Õʱ×Ô¶¯ÊÍ·Å + tablewindow->show(); + tablewindow->setWindowTitle(u8"ÕýÔÚ´ò¿ªÎļþ"); + //FEKOResultCsvTableModel* tablemode = new FEKOResultCsvTableModel(); + std::shared_ptr< FEKOResultCsvTableModel> tablemode = std::make_shared< FEKOResultCsvTableModel>(); + tablemode->loadCSVFilePath((this->outPath)); + tablewindow->loadTablemode(tablemode); + tablewindow->setTableViewAutoSort(true); + tablewindow->LockFileOpen(); + QFileInfo fileInfo((this->outPath)); + QString titletext = QString::QString(u8"ÕýÔڱ༭ ") + fileInfo.fileName(); + tablewindow->setWindowTitle(titletext); + tablewindow->show(); +} + + + + + + + + + + + + + + + + + + + + + + + +// ===================================================================== +// FEKOImageSettingTaskNodeClass +// +// ===================================================================== + + + +FEKOImageSettingTaskNodeClass::FEKOImageSettingTaskNodeClass() +{ + this->simulationparams = std::make_shared(); // ´´½¨ÐéÄâÖ¸Õë + this->TaskWindows = new QtSARAntModelSettingClass(); +} + + +FEKOImageSettingTaskNodeClass::~FEKOImageSettingTaskNodeClass() +{ + +} +int FEKOImageSettingTaskNodeClass::ExcuteTask() +{ + this->status = TaskStatusEnum::excuting; + this->TaskWindows->show(); + return 0; +} + +int FEKOImageSettingTaskNodeClass::FinishTask() +{ + this->status = TaskStatusEnum::finish; + if (this->TaskWindows) { + this->TaskWindows->saveFEKOImageSettingXML(); + this->TaskWindows->close(); + } + return 0; +} + +int FEKOImageSettingTaskNodeClass::loadXmlFile(QString xmlFilePath) +{ + this->TaskWindows->setFEKOSimulationDataparams(this->simulationparams); + this->TaskWindows->loadFEKOImageSettingXML(xmlFilePath); + this->TaskWindows->ReferenceWindows(); + return 0; +} + +int FEKOImageSettingTaskNodeClass::saveXmlFile() +{ + this->TaskWindows->saveFEKOImageSettingXML(); + return 0; +} + +QString FEKOImageSettingTaskNodeClass::getTaskName() +{ + return this->simulationparams->taskName; +} + + + + + + + + +// ===================================================================== +// FEKOScatterSettingTaskNodeClass +// +// ===================================================================== + +FEKOScatterSettingTaskNodeClass::FEKOScatterSettingTaskNodeClass() +{ + + this->TaskWindows = new LAMP_ScatterSettingClass(); +} + +FEKOScatterSettingTaskNodeClass::~FEKOScatterSettingTaskNodeClass() +{ + +} + +int FEKOScatterSettingTaskNodeClass::ExcuteTask() +{ + this->status = TaskStatusEnum::excuting; + this->TaskWindows->show(); + return 0; +} + +int FEKOScatterSettingTaskNodeClass::loadXmlFile(QString xmlFilePath) +{ + QFile file(xmlFilePath); + if (file.exists()) { + if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { + QMessageBox::warning(nullptr, u8"¾¯¸æ", u8"н¨Îļþ"); + return 0; + } + else { + this->TaskWindows->loadxml(xmlFilePath); + return 0; + } + } + else { + bool ok; + QString newName = QInputDialog::getText(nullptr, u8"ÈÎÎñÃû³Æ", u8"ÊäÈëÈÎÎñÃû:", QLineEdit::Normal, u8"TestTask", &ok); + if (newName.isEmpty()) { + newName = u8"TestTask"; + } + else { + + } + + this->setName(newName); + this->TaskWindows->setTaskName(newName); + this->TaskWindows->setWorkSpacePath(xmlFilePath); + return 0; + + + } + + +} + +int FEKOScatterSettingTaskNodeClass::saveXmlFile() +{ + this->TaskWindows->savexml(); + return 0; +} + +QString FEKOScatterSettingTaskNodeClass::getTaskName() +{ + return this->TaskWindows->settingobj->taskName; +} diff --git a/src/WBCLFZSystemModule/TaskNodeList.h b/src/WBCLFZSystemModule/TaskNodeList.h new file mode 100644 index 0000000..a7015c7 --- /dev/null +++ b/src/WBCLFZSystemModule/TaskNodeList.h @@ -0,0 +1,245 @@ +#pragma once +/// +/// ÓÃÓÚ¿Ì»­µ±Ç°ÏîÄ¿ËùÉæ¼°µ½µÄËùÓÐÈÎÎñ +/// +/// +#ifndef TASKNODELIST_H +#define TASKNODELIST_H + +#include "AllHead.h" +#include + +#include "EchoShowProcess/EchoTableEditWindow.h" +#include "OCCViewer/CommonSample.h" +#include "OCCTopoShapeTreeViewer.h" +#include "OCCTBaseOperaorClass.h" +#include "OCCTModelOperator.h" +#include "OCCTopoShapeTreeViewer.h" + +#include "OcctExportClass.h" + +// ÈÎÎñÊý¾Ý½Úµã +#include "TaskXml/TaskTreeClass.h" +#include "ImageShowDialogClass.h" +#include "LAMP_ScatterSettingClass.h" +#include "EchoShowProcess/FEKOResultImport.h" +#include "QtSARAntModelSetting.h" + +// +// Ä£Ðͽڵã +// +class OCCTShapeModelNode : public TaskNode { + Q_OBJECT +public: + Handle(AIS_Shape) Data_AIS; // ¹¹½¨ºËÐÄÊý¾Ý + bool modelRepair; + OCCTShapeType shapetype; + QString Filepath; + //QMenu* ContentListContextMenu; + Handle(AIS_InteractiveContext) myContext; + +public: + Q_INVOKABLE OCCTShapeModelNode(QWidget* parent = nullptr); + ~OCCTShapeModelNode(); + void initContextMenu(); + + void HideShape(); + void ShowShape(); + + void removeDataShapeShow(); + void setContext(Handle(AIS_InteractiveContext) myContext); + + void setShape(const TopoDS_Shape& Data_Shape); + + void SaveShape(QString Filepath); + + Handle(AIS_Shape)& AIS(); + const TopoDS_Shape& Shape(); + + + bool setDataFile(QString filepath); + bool setSaveFilePath(QString filepath); + bool SaveFile(); + bool CheckFilePath(); + + int ExcuteTask() override; + int FinishTask() override; + TaskNode* CopyToNew() override; + +signals: + // ×Ô¶¨ÒåÐźţ¬±íʾ¸´Ñ¡¿ò±»Ë«»÷ + void doubleClicked(); + void deleteItem(QString name); // ɾ³ý¶ÔÏó + void renameItem(QString name); // ÎļþÖØÃüÃû + void copyNew(); + void ShowFullExtend(const TopoDS_Shape& Shape); + void ModelModify(OCCTShapeModelNode* item); +public slots: + void oncheckBoxStateChanged(int state); // Ë«»÷Çл»×´Ì¬ + void ShowContentListContextMenu(QPoint p); + // ÓÒ¼ü²Ëµ¥ + void ShowOrHide(); + void removeItem(); + void renameItem(); + void copyItem(); + void showExtend(); + void saveItem(); + void saveAsItem(); + void ExportItem(); // µ¼³öÄ£ÐÍ + void TranslationObject(); + + + +protected: // ÖØÐ´µ¥Ë«»÷ʼþ + void mouseDoubleClickEvent(QMouseEvent* event) override { + // ¼ì²éÊÇ·ñÊÇË«»÷ʼþ + if (event->button() == Qt::LeftButton) { + + setChecked(!isChecked()); + + emit doubleClicked(); + } + // ½«Ê¼þ´«µÝ¸ø»ùÀà´¦ÀíÆäËû¿ÉÄܵÄʼþ + QCheckBox::mouseDoubleClickEvent(event); + } + void mousePressEvent(QMouseEvent* event) override { + + if (event->button() == Qt::LeftButton) { + // ¸ù¾Ý״̬±ä»¯µÄ QCheckBox ÏÔʾÏàÓ¦µÄÏûÏ¢ + QString message = QString("%1 state changed to %2").arg(this->text()).arg(this->checkState() == Qt::Checked ? "Checked" : "Unchecked"); + qDebug() << "Checkbox State don't change , in click \n"; + qDebug() << message; + } + else { // ÓÒ¼ü²Ëµ¥µ¥¶À´¦Àí + qDebug() << u8"OCCTCheckPointÓÒ¼ü²Ëµ¥Æô¶¯ \n"; + QCheckBox::mousePressEvent(event); // + emit customContextMenuRequested(event->globalPos()); + } + } + void contextMenuEvent(QContextMenuEvent* event) override { + emit customContextMenuRequested(event->globalPos()); + } +}; + +// +// Êý¾Ýչʾ½Úµã +// +class DataShowNode :public TaskNode { // չʾÆÕͨͼÏñµÄ½á¹û + Q_OBJECT +public: + DataShowNode(QWidget* parent = nullptr); + ~DataShowNode();// +public: + QString datapath; + ImageShowDialogClass* DataShowDockWidget; + QMainWindow* m; +public: + void bangdindWindows(QMainWindow* m); + void loadData(); + void OpenData(QString TaskXmlPath); + int ExcuteTask(); // չʾ²¢»æÖÆÍ¼Ïñ +public slots: + void Load_Image(); +}; + +// +// ¸´ÊýÊý¾Ýչʾ½Úµã +// +class ComplexDataShowNode : public TaskNode +{ + Q_OBJECT +public: + ComplexDataShowNode(QWidget* parent = nullptr); + ~ComplexDataShowNode(); +public: + QString datapath; + //ImageShowDialogClass* DataShowDockWidget; + QMainWindow* m; +public: + + void bangdindWindows(QMainWindow* m); + void loadData(); + void OpenData(QString TaskXmlPath); + int ExcuteTask(); // չʾ²¢»æÖÆÍ¼Ïñ + +public slots: // ²ÎÊý¸´Êý + + void Load_amp_Image(); + void Load_pha_Image(); + void Load_real_Image(); + void Load_imag_Image(); + void Load_dB_Image(); +}; + +// +// FEKOÊý¾Ýת»»ÈÎÎñ½Úµã +// +class FEKOResultImportTaskNode :public TaskNode { + Q_OBJECT +public: + FEKOResultImportTaskNode(); + ~FEKOResultImportTaskNode(); + QString FolderPath; + bool nearField; + bool farField; + QString prename; + std::vector nearFieldNames; + std::vector farFieldNames; + std::vector selectFieldNames; + QString outPath; +private: + FEKOResultImport* TaskWindows; +public: + virtual int ExcuteTask(); + virtual int loadXmlFile(QString xmlFilePath); // ¼ÓÔØÈÎÎñÎļþ,±ØÐëÖØÐ´ + virtual int saveXmlFile(); // ±£´æÈÎÎñÎļþ£¬±ØÐëÖØÐ´ + virtual int FinishTask() override; +public slots: + void getExcuteTaskResult(FEKOResultImport* obj); +}; + +// +// FEKO³ÉÏñ²ÎÊýÈÎÎñÉèÖýڵã +// +class FEKOImageSettingTaskNodeClass :public TaskNode, public FEKOBase::FEKOSimulationDataparamsHandler +{ + Q_OBJECT + +public: + FEKOImageSettingTaskNodeClass(); + ~FEKOImageSettingTaskNodeClass(); +public: + QtSARAntModelSettingClass* TaskWindows; // Ä£ÐÍ×Ë̬ÉèÖà + //FEKOBase::FEKOSimulationSARClass simulationSetting; // ·ÂÕæ²ÎÊýÉèÖà +public: + virtual int ExcuteTask() override; + virtual int FinishTask() override; + virtual int loadXmlFile(QString xmlFilePath); // ¼ÓÔØÈÎÎñÎļþ,±ØÐëÖØÐ´ + virtual int saveXmlFile(); // ±£´æÈÎÎñÎļþ£¬±ØÐëÖØÐ´ + QString getTaskName(); + +}; + +// +// É¢Éä×°Ö÷ÂÕæ³ÉÏñ +// +class FEKOScatterSettingTaskNodeClass :public TaskNode { + Q_OBJECT +public: + FEKOScatterSettingTaskNodeClass(); + ~FEKOScatterSettingTaskNodeClass(); +public: + LAMP_ScatterSettingClass* TaskWindows; // Ä£ÐÍ×Ë̬ÉèÖà + //FEKOBase::FEKOSimulationSARClass simulationSetting; // ·ÂÕæ²ÎÊýÉèÖà +public: + virtual int ExcuteTask(); + virtual int loadXmlFile(QString xmlFilePath); // ¼ÓÔØÈÎÎñÎļþ,±ØÐëÖØÐ´ + virtual int saveXmlFile(); // ±£´æÈÎÎñÎļþ£¬±ØÐëÖØÐ´ + QString getTaskName(); +}; + + + + + +#endif \ No newline at end of file diff --git a/src/WBCLFZSystemModule/TaskXml/TaskTreeClass.cpp b/src/WBCLFZSystemModule/TaskXml/TaskTreeClass.cpp new file mode 100644 index 0000000..192abad --- /dev/null +++ b/src/WBCLFZSystemModule/TaskXml/TaskTreeClass.cpp @@ -0,0 +1,226 @@ +#include "TaskTreeClass.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + + + +TaskNode::TaskNode(QWidget* parent) :QCheckBox(parent) +{ + this->status = TaskStatusEnum::wait; + this->setText("TaskNode"); + this->description = "TaskNode"; + this->TaskXmlPath = ""; + + this->setContextMenuPolicy(Qt::CustomContextMenu); + this->ContentListContextMenu = new QMenu(this); // ±í¸ñ¿Ø¼þµÄÓÒ¼ü²Ëµ¥ + QObject::connect(this, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(ShowContentListContextMenu(QPoint))); + + //// ¼ÓÔØÊý¾Ý + //QAction* action_Node_ExcuteTask_Action = this->ContentListContextMenu->addAction(u8"¼ÓÔØ"); + //QObject::connect(action_Node_ExcuteTask_Action, SIGNAL(triggered()), this, SLOT(ExcuteTask())); + + // ÖØÃüÃû + QAction* action_rename=this->ContentListContextMenu->addAction(u8"ÖØÃüÃû"); + QObject::connect(action_rename, SIGNAL(triggered()), this, SLOT(renameNode())); + + // ÒÆ³ý + QAction* action_remove = this->ContentListContextMenu->addAction(u8"ÒÆ³ý"); + QObject::connect(action_remove, SIGNAL(triggered()), this, SLOT(deleteNode())); + +} + +TaskNode::~TaskNode() +{ + this->Nodelist.clear(); +} + +QString TaskNode::getName() +{ + return this->text(); +} + +int TaskNode::setName(QString name) +{ + this->setText(name); + return 0; +} + +QString TaskNode::getTaskName() +{ + return this->text(); +} + +int TaskNode::loadXmlDocument(QString xmlFilePath, QDomDocument& doc) +{ + QFile file(xmlFilePath.toUtf8().constData()); //Ïà¶Ô·¾¶¡¢¾ø¶Ô·¾¶¡¢×ÊԴ·¾¶¶¼¿ÉÒÔ + if (!file.open(QFile::ReadOnly)) //¿ÉÒÔÓÃQIODevice£¬Truncate±íʾÇå¿ÕÔ­À´µÄÄÚÈÝ + { + QString tiptext = "File isn't opened in readonly mode ,file path "+ xmlFilePath; + qDebug() << tiptext.toUtf8().constData(); + return 2; + } + + QTextStream stream(&file); + QTextCodec* codec = QTextCodec::codecForName(u8"UTF-8"); + stream.setCodec(codec); + QString content = stream.readAll(); + file.close(); + if (!doc.setContent(content)) // ¹ØÁªÎļþÁ÷ + { + QString tiptext = u8"File isn't readed in xml format ,file path " + xmlFilePath; + qDebug() << tiptext.toUtf8().constData(); + file.close(); + return 3; + } + file.close(); // Îļþ¶ÁÈ¡½áÊø + return -1; +} + +int TaskNode::writeXmlDocument(QDomDocument& doc) +{ + + QFile wfile(this->TaskXmlPath.toUtf8().constData()); // ±£´æ XML Îļþ + if (wfile.open(QFile::ReadWrite | QFile::Text)) + { + QTextStream out(&wfile); + doc.save(out, QDomNode::EncodingFromDocument); + wfile.close(); + } + return -1; +} + +int TaskNode::loadXmlFile(QString xmlFilePath) +{ + return 0; +} + +int TaskNode::saveXmlFile() +{ + return 0; +} + + +int TaskNode::addNode(std::shared_ptr n) +{ + this->Nodelist.push_back(n); + return 0; +} + +std::shared_ptr TaskNode::getNode(int nid) +{ + if (nid < this->Nodelist.size()) { + return this->Nodelist[nid]; + } + return std::shared_ptr(nullptr); +} + +std::shared_ptr TaskNode::getNode(QString nodename) +{ + for (int i = 0; i < this->Nodelist.size(); i++) { + if (strcmp(nodename.toUtf8().constData(), this->Nodelist[i]->getName().toUtf8().constData()) == 0) { + return this->Nodelist[i]; + } + } + return std::shared_ptr(nullptr); +} + +std::shared_ptr TaskNode::removeAt(int nid) +{ + if (nid < this->Nodelist.size()) { + std::shared_ptr result = this->Nodelist[nid]; + this->Nodelist.erase(this->Nodelist.begin()+nid); // ɾ³ý nid + return result; + } + return std::shared_ptr(nullptr); +} + +std::shared_ptr TaskNode::removeByName(QString nodename) +{ + for (int i = 0; i < this->Nodelist.size(); i++) { + if (strcmp(nodename.toUtf8().constData(), this->Nodelist[i]->getName().toUtf8().constData()) == 0) { + std::shared_ptr result = this->Nodelist[i]; + this->Nodelist.erase(this->Nodelist.begin() + i); // ɾ³ý nid + return result; + } + } + return std::shared_ptr(nullptr); +} + +TaskStatusEnum TaskNode::getStatus() +{ + return this->status; + // return TaskStatusEnum(); +} + +int TaskNode::setStatus(TaskStatusEnum taskstatus) +{ + this->status = taskstatus; + return 0; +} + +void TaskNode::renameNode() +{ + QString newName=QInputDialog::getText(this, u8"ÖØÃüÃû", u8"ÇëÊäÈëеÄÃû³Æ", QLineEdit::Normal, this->text()); + emit this->renameNode(this->text(), newName); +} + +void TaskNode::deleteNode() +{ + this->FinishTask(); + emit this->deleteNode(this->text()); +} + +void TaskNode::copyNewNode() +{ + + emit this->copyNewNode(this->CopyToNew()); +} + +void TaskNode::ShowContentListContextMenu(QPoint p) +{ + this->ContentListContextMenu->exec(QCursor::pos()); +} + +int TaskNode::ExcuteTask() +{ + this->status = TaskStatusEnum::excuting; + return 0; +} + +int TaskNode::FinishTask() +{ + return 0; +} + +TaskNode* TaskNode::CopyToNew() +{ + return nullptr; +} + +int TaskNode::preView() +{ + return 0; +} + + +int TaskTreeClass::loadXmlFile(QString xmlFilePath) +{ + return 0; +} + +int TaskTreeClass::saveXmlFile() +{ + return 0; +} + diff --git a/src/WBCLFZSystemModule/TaskXml/TaskTreeClass.h b/src/WBCLFZSystemModule/TaskXml/TaskTreeClass.h new file mode 100644 index 0000000..3fc1547 --- /dev/null +++ b/src/WBCLFZSystemModule/TaskXml/TaskTreeClass.h @@ -0,0 +1,112 @@ +#pragma once +/* +* ËùÓеŦÄÜÖ¸Õë´«µÝ ¶¼ÊÇʹÓà ¹²ÏíÖ¸Õ룬²»ÊÖ¶¯ÊÍ·Å +* ¶¨Òå¸÷ÖÖÈÎÎñ¹ÜÀíÀà +* ÈÎÎñ¹ÜÀíÀàÒÔÊ÷×´½Úµã½øÐб£´æ£¬ +* Ê÷×´½Úµã¶¼ÊÇÒ»¸öÊ÷£¬¾ßÓÐÍêÕûµÄÈÎÎñ¹ÜÀíÄÜÁ¦ +* ÈÎÎñ°´ÕÕ ÖÆ±¸ÈÎÎñ¡¢²âÁ¿ÈÎÎñ¡¢·ÂÕæÈÎÎñ +* ÈÎÎñ»ùÀࣺ +* 1.ÈÎÎñÃû +* 2. ÈÎÎñÃèÊö +* 3. ×ÓÈÎÎñÏî +* 4. ½ÚµãÀàÐÍ -- Îļþ½Úµã¡¢ÈÎÎñ½Úµã¡¢ +* 5. µ±Ç°½Úµã²Ù×÷´°¿Ú +* ·ÂÕæÈÎÎñ£º +* +* +* +* +***/ + +#ifndef TASKTREECLASS_H +#define TASKTREECLASS_H + +#include "AllHead.h" +#include +#include +#include +#include +#include +#include +#include +#include //rapidxml::file +#include //rapidxml::print +#include // QObject ½èÖú QOject ÖеÄÐźŲۻúÖÆ£¬Íê³ÉÈÎÎñµÄ»Øµ÷£¬Ï൱ÓÚ Ê¼þµÄÁÓ»¯°æ +#include + +enum TaskStatusEnum { + wait, + success, + fail, + excuting, + finish, +}; + + +// ÈÎÎñÁбí +class TaskNode :public QCheckBox +{ + Q_OBJECT // ÿ¸ö×ÓÀà±ØÐëʹÓÃÕâ¸öºê +public: + QString TaskXmlPath; +public: + QMenu* ContentListContextMenu; + QString description; // ÃèÊö + TaskStatusEnum status; + std::vector> Nodelist; +public: + TaskNode(QWidget* parent = nullptr); + ~TaskNode(); +public: + QString getName(); + int setName(QString anme); + QString getTaskName(); + virtual int ExcuteTask(); // ÈÎÎñÖ´ÐвÙ×÷ + virtual int FinishTask(); + virtual TaskNode* CopyToNew(); + + + int loadXmlDocument(QString xmlfilepath, QDomDocument& doc); + int writeXmlDocument(QDomDocument& doc); + virtual int preView(); // Ô¤ÀÀÐÅÏ¢ + + virtual int loadXmlFile(QString xmlFilePath); // ¼ÓÔØÈÎÎñÎļþ,±ØÐëÖØÐ´ + virtual int saveXmlFile(); // ±£´æÈÎÎñÎļþ£¬±ØÐëÖØÐ´ + + virtual int addNode(std::shared_ptr n); + virtual std::shared_ptr getNode(int nid); + virtual std::shared_ptr getNode(QString nodename); + virtual std::shared_ptr removeAt(int nid); + virtual std::shared_ptr removeByName(QString nodename); + virtual TaskStatusEnum getStatus(); + virtual int setStatus(TaskStatusEnum taskstatus); + +public slots: + void ShowContentListContextMenu(QPoint p); + void renameNode(); + void deleteNode(); + void copyNewNode(); + +signals: + void renameNode(QString oldname,QString newname); + void deleteNode(QString name); + void copyNewNode(TaskNode* sendernode); +}; + + +/// +/// ÈÎÎñ¹ÜÀíµØÖ· +/// +class TaskTreeClass +{ +public: + QString TaskName; + std::vector tasknodes; +public: + virtual int loadXmlFile(QString xmlFilePath); // ¼ÓÔØÈÎÎñÎļþ,±ØÐëÖØÐ´ + virtual int saveXmlFile(); // ±£´æÈÎÎñÎļþ£¬±ØÐëÖØÐ´ +}; + + + +#endif \ No newline at end of file diff --git a/src/WBCLFZSystemModule/WBCLFZSystemModule.aps b/src/WBCLFZSystemModule/WBCLFZSystemModule.aps new file mode 100644 index 0000000000000000000000000000000000000000..6263b6870fe489114d34e3af2a1700be5e21e6d2 GIT binary patch literal 1476 zcmb7E%Wm3G5IwXk=xftO*W|GvQi7m~(keS*8`Ubd5jG@6mMjWZLc}97Ml}D@Wk06v zUqs#XFX*{`aB*m;dabcNGiM%mX6^-mB5ApdiNBdOA-7NZfD4@SyIkfHeZG+VAj|{m znR{_w?<&ovdmBt|{C-GYY1F$$Z#ZdYB;>Aw-Z;@`Is0xF`eS1{n2-Dfur4YGeFl9& zIw3jGaLKn06ABt=L#0IKSb@wj@MqI`(D%#Nz?*;CKOq8Gx8EC1`lI>4FYYde6FMtj z@4k9Y%u~|#Tm&NPOBmi$maXge6)uhr>_n0stmV$)d$p$RncAh}wKUsmw-n9m)EaFK z)k+o5*7b^I7&TK()F+h+0Sql2D3z3*1X5B&+uaVPL#j~B7qbn#KRS$54T(lqY{>5QS)@SZ0TZbQ!M$|s7!!lX +#include //Ìí¼ÓQDateTimeÍ·Îļþ +#include +#include +#include +#include +#include +#include "PointCloudProcess/pclvisualizer.h" +#include "modelProcess/ModelProcess.h" +#include "TableProcess/TableMainWindow.h" +#include "SqliteDBProcess/src/Application.h" +#include "SqliteDBProcess/src/sqlite.h" +#include "SqliteDBProcess/src/SqliteDBMainWindow.h" +#include "EchoShowProcess/FEKOResultImport.h" +#include "QConsoleWidget.h" +#include "QConsoleCommandAction.h" +//#include "EchoShowProcess/FEKOResultProcessExportWindow.h" + + +WBCLFZSystemModule::WBCLFZSystemModule(QWidget *parent) + : QMainWindow(parent) +{ + ui.setupUi(this); +} + +WBCLFZSystemModule::~WBCLFZSystemModule() +{ + +} +void WBCLFZSystemModule::on_pushButton_PointCloud_clicked() { + startPointProcess(); +} + + +void WBCLFZSystemModule::on_pushButton_TableProcesss_clicked() +{ + //TableMainWindow* w = new TableMainWindow(); + //w->show(); + // Show main window + SqliteDBMainWindow* w = new SqliteDBMainWindow(this); + w->show(); +} + +void WBCLFZSystemModule::on_pushButton_ModelProcess_clicked() +{ + BandingModelPrcessAndQConsoleWidgetClass* bandingobj = new BandingModelPrcessAndQConsoleWidgetClass(); + bandingobj->createModelProcess(); + bandingobj->createQConsoleWidget(); + bandingobj->bandingModelProcessAndQConsoleWidget(); + bandingobj->getModelProcess()->show(); +} + +void WBCLFZSystemModule::on_pushButton_EchoProcess_clicked() +{ + //qDebug() << u8"Æô¶¯FEKO->csv Îļþ \n"; + //QString xmlfilepath = getOpenFilePath(this, QString::fromUtf8(u8"±£´æFEKO½á¹ûµ¼ÈëÈÎÎñxml"), ".", QString::fromUtf8(u8"xmlÎļþ (*.xml)")); + //qDebug() << u8"Ñ¡Ôñ xmlfile Îļþ·¾¶£º\t " + xmlfilepath + u8"\n"; + //FEKOResultImportTaskNode* fekoresulttask = new FEKOResultImportTaskNode(); + //fekoresulttask->loadXmlFile(xmlfilepath); + //fekoresulttask->ExcuteTask(); + + //// ²ÎÊý + //FEKOResultProcessExportWindow* fekoResultProcessswindws=new FEKOResultProcessExportWindow(); + //fekoResultProcessswindws->show(); + + + FEKOImageSettingTaskNodeClass* test=new FEKOImageSettingTaskNodeClass(); + test->ExcuteTask(); +} + +void startPointProcess() +{ + QPixmap pixmap("logo1.png"); // ¶ÁȡͼƬ + QSplashScreen splash(pixmap); // + + //¶ÁÈ¡iniÎļþÖÐÉÏÒ»´Î¹Ø±ÕÈí¼þʱºòµÄ´°¿ÚλÖúʹóС£º + qDebug() << qApp->applicationDirPath() << endl; + QString wstrFilePath = qApp->applicationDirPath() + "/setting.ini"; + QSettings* settings = new QSettings( + wstrFilePath, QSettings::IniFormat); //ÓÃQSetting»ñÈ¡iniÎļþÖеÄÊý¾Ý + int x = settings->value("WindowGeometry/x").toInt(); + int y = settings->value("WindowGeometry/y").toInt(); + int width = settings->value("WindowGeometry/width").toInt(); + int height = settings->value("WindowGeometry/height").toInt(); + qDebug() << "Position is right:" << x << " " << y << " " << width << " " + << height; + QDesktopWidget* desktopWidget = QApplication::desktop(); + QRect clientRect = desktopWidget->availableGeometry(); + QRect targRect0 = QRect(clientRect.width() / 4, + clientRect.height() / 4, + clientRect.width() / 2, + clientRect.height() / 2); + QRect targRect = QRect(x, y, width, height); + if ( + width == 0 || height == 0 || x < 0 || x > clientRect.width() || y < 0 || + y > clientRect.height()) //Èç¹ûÉÏÒ»´Î¹Ø±ÕÈí¼þµÄʱºò£¬´°¿ÚλÖò»Õý³££¬Ôò±¾´ÎÏÔʾÔÚÏÔʾÆ÷µÄÕýÖÐÑë + { + targRect = targRect0; + qDebug() << "Position is not right:" << x << " " << y << " " << width << " " << height; + } + + PCLVisualizer* w = new PCLVisualizer(); + w->setGeometry(targRect); //ÉèÖÃÖ÷´°¿ÚµÄ´óС + w->show(); + + splash.finish(w); //ÔÚÖ÷Ìå¶ÔÏó³õʼ»¯Íê³Éºó½áÊøÆô¶¯¶¯»­ +} + +void startTableProcess() +{ + +} + +void startModelProcess() +{ + +} + +void startEchoProcess() +{ + +} diff --git a/src/WBCLFZSystemModule/WBCLFZSystemModule.h b/src/WBCLFZSystemModule/WBCLFZSystemModule.h new file mode 100644 index 0000000..d6a67c9 --- /dev/null +++ b/src/WBCLFZSystemModule/WBCLFZSystemModule.h @@ -0,0 +1,40 @@ +#pragma once + +#ifndef WBCLFZSYSTEMMODULE_H +#define WBCLFZSYSTEMMODULE_H + +#include +#include "ui_WBCLFZSystemModule.h" + +class WBCLFZSystemModule : public QMainWindow +{ + Q_OBJECT + +public: + WBCLFZSystemModule(QWidget *parent = nullptr); + ~WBCLFZSystemModule(); + +public slots: + void on_pushButton_PointCloud_clicked(); + void on_pushButton_TableProcesss_clicked(); + void on_pushButton_ModelProcess_clicked(); + void on_pushButton_EchoProcess_clicked(); + +private: + Ui::WBCLFZSystemModuleClass ui; +}; + + +// Æô¶¯µãÔÆ±à¼­Ä£¿é +void startPointProcess(); + +// Æô¶¯±í¸ñ±à¼­Ä£¿é +void startTableProcess(); + +// Æô¶¯Ä£Ðͱ༭ģ¿é +void startModelProcess(); + +// Æô¶¯»Ø²¨´¦ÀíÄ£¿é +void startEchoProcess(); + +#endif \ No newline at end of file diff --git a/src/WBCLFZSystemModule/WBCLFZSystemModule.rc b/src/WBCLFZSystemModule/WBCLFZSystemModule.rc new file mode 100644 index 0000000..0fded0b --- /dev/null +++ b/src/WBCLFZSystemModule/WBCLFZSystemModule.rc @@ -0,0 +1,60 @@ +// Microsoft Visual C++ Éú³ÉµÄ×ÊÔ´½Å±¾¡£ +// + +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// ´Ó TEXTINCLUDE 2 ×ÊÔ´Éú³É¡£ +// +#include "winres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// ÖÐÎÄ(¼òÌ壬Öйú) ×ÊÔ´ + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +LANGUAGE 4, 2 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""winres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + +#endif // ÖÐÎÄ(¼òÌ壬Öйú) ×ÊÔ´ +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// ´Ó TEXTINCLUDE 3 ×ÊÔ´Éú³É¡£ +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // ²»ÊÇ APSTUDIO_INVOKED diff --git a/src/WBCLFZSystemModule/WBCLFZSystemModule.ui b/src/WBCLFZSystemModule/WBCLFZSystemModule.ui new file mode 100644 index 0000000..2ef6a1b --- /dev/null +++ b/src/WBCLFZSystemModule/WBCLFZSystemModule.ui @@ -0,0 +1,73 @@ + + + WBCLFZSystemModuleClass + + + + 0 + 0 + 857 + 367 + + + + WBCLFZSystemModule + + + + + + + 1. ç‚¹äº‘å¤„ç†æ¨¡å— + + + + + + + 1. è¡¨æ ¼ç¼–è¾‘å¤„ç†æ¨¡å— + + + + + + + 2. æ¨¡åž‹å¤„ç†æ¨¡å— + + + + + + + 4. å›žæ³¢å¤„ç†æ¨¡å— + + + + + + + + + 0 + 0 + 857 + 26 + + + + + + TopToolBarArea + + + false + + + + + + + + + + diff --git a/src/WBCLFZSystemModule/WBCLFZSystemModule.vcxproj b/src/WBCLFZSystemModule/WBCLFZSystemModule.vcxproj new file mode 100644 index 0000000..37255f5 --- /dev/null +++ b/src/WBCLFZSystemModule/WBCLFZSystemModule.vcxproj @@ -0,0 +1,548 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {7C7D543D-5E1D-4900-9D3D-96558FF37737} + QtVS_v304 + 10.0.19041.0 + 10.0.19041.0 + 10.0.17763.0 + 10.0.17763.0 + $(MSBuildProjectDirectory)\QtMsBuild + + + + Application + v142 + + + Application + v142 + + + Application + v142 + + + Application + v142 + + + + + + + 5.15.2_msvc2019_64 + core;gui;widgets + debug + + + 5.15.2_msvc2019_64 + core;gui;widgets + debug + + + 5.15.2_msvc2019_64 + core;xml;sql;opengl;gui;svg;xmlpatterns;uitools;widgets;qml;printsupport;sensors;quickwidgets;quick;concurrent;openglextensions;charts;datavisualization + release + true + + + 5.15.2_msvc2019_64 + core;xml;sql;opengl;gui;svg;xmlpatterns;uitools;widgets;qml;printsupport;sensors;quickwidgets;quick;concurrent;openglextensions;charts;datavisualization + release + true + + + + + + + + + + + + + + + + + + + + + + + + + + + C:\OCCT\inc;C:\PCL1p13p1\3rdParty\VTK\include;C:\PCL1p13p1\include\pcl-1.13;C:\PCL1p13p1\3rdParty\Boost\include\boost-1_82;C:\PCL1p13p1\3rdParty\VTK\include\vtk-9.2;C:\PCL1p13p1\3rdParty\FLANN\include\flann;C:\PCL1p13p1\3rdParty\FLANN\include;..\LAMPTool;..\WBCLFZSystemModule;..\json;..\qscintilla2\src;..\qscintilla2\Qt4Qt5;..\qscintilla2\lexlib;..\qscintilla2\lexers;..\qscintilla2\include;..\qhexedit;..\qcustomplot;C:\PCL1p13p1\3rdParty\Qhull\include;$(VC_IncludePath);$(WindowsSDK_IncludePath) + ..\x64\Release;C:\PCL1p13p1\bin;C:\VTK\lib;C:\VTK\lib\vtk-9.2;C:\OCCT\win64\vc14\lib;C:\OCCT\win64\vc14\bin;C:\PCL1p13p1\lib;C:\PCL1p13p1\3rdParty\VTK\lib\vtk;C:\PCL1p13p1\3rdParty\FLANN\lib;$(VC_ReferencesPath_x64) + ..\x64\Release;C:\PCL1p13p1\bin;C:\OCCT\inc;C:\OCCT\win64\vc14\lib;C:\OCCT\win64\vc14\bin;C:\PCL1p13p1\lib;C:\PCL1p13p1\3rdParty\VTK\lib;C:\PCL1p13p1\3rdParty\Qhull\lib;C:\Qt\5.15.2\msvc2019_64\bin;C:\PCL1p13p1\3rdParty\FLANN\lib;$(VC_LibraryPath_x64);$(WindowsSDK_LibraryPath_x64) + $(VC_IncludePath);$(WindowsSDK_IncludePath); + true + true + true + true + + + C:\OCCT\inc;C:\PCL1p13p1\3rdParty\VTK\include;C:\PCL1p13p1\include\pcl-1.13;C:\PCL1p13p1\3rdParty\Boost\include\boost-1_82;C:\PCL1p13p1\3rdParty\VTK\include\vtk-9.2;C:\PCL1p13p1\3rdParty\FLANN\include\flann;C:\PCL1p13p1\3rdParty\FLANN\include;..\LAMPTool;..\WBCLFZSystemModule;..\json;..\qscintilla2\src;..\qscintilla2\Qt4Qt5;..\qscintilla2\lexlib;..\qscintilla2\lexers;..\qscintilla2\include;..\qhexedit;..\qcustomplot;C:\PCL1p13p1\3rdParty\Qhull\include;$(VC_IncludePath);$(WindowsSDK_IncludePath) + ..\x64\Release;C:\PCL1p13p1\bin;C:\VTK\lib;C:\VTK\lib\vtk-9.2;C:\OCCT\win64\vc14\lib;C:\OCCT\win64\vc14\bin;C:\PCL1p13p1\lib;C:\PCL1p13p1\3rdParty\VTK\lib\vtk;C:\PCL1p13p1\3rdParty\FLANN\lib;$(VC_ReferencesPath_x64) + ..\x64\Release;C:\PCL1p13p1\bin;C:\OCCT\inc;C:\OCCT\win64\vc14\lib;C:\OCCT\win64\vc14\bin;C:\PCL1p13p1\lib;C:\PCL1p13p1\3rdParty\VTK\lib;C:\PCL1p13p1\3rdParty\Qhull\lib;C:\Qt\5.15.2\msvc2019_64\bin;C:\PCL1p13p1\3rdParty\FLANN\lib;$(VC_LibraryPath_x64);$(WindowsSDK_LibraryPath_x64) + $(VC_IncludePath);$(WindowsSDK_IncludePath); + true + true + true + true + + + true + + + D:\vcpkg\installed + + + D:\vcpkg\installed + + + + stdc17 + true + true + SCINTILLA_QT;SCI_LEXER;%(PreprocessorDefinitions) + stdcpp14 + + + QtCommandConsole.lib;pcl_common.lib;pcl_commond.lib;pcl_features.lib;pcl_featuresd.lib;pcl_filters.lib;pcl_filtersd.lib;pcl_io.lib;pcl_iod.lib;pcl_io_ply.lib;pcl_io_plyd.lib;pcl_kdtree.lib;pcl_kdtreed.lib;pcl_keypoints.lib;pcl_keypointsd.lib;pcl_ml.lib;pcl_mld.lib;pcl_octree.lib;pcl_octreed.lib;pcl_outofcore.lib;pcl_outofcored.lib;pcl_people.lib;pcl_peopled.lib;pcl_recognition.lib;pcl_recognitiond.lib;pcl_registration.lib;pcl_registrationd.lib;pcl_sample_consensus.lib;pcl_sample_consensusd.lib;pcl_search.lib;pcl_searchd.lib;pcl_segmentation.lib;pcl_segmentationd.lib;pcl_stereo.lib;pcl_stereod.lib;pcl_surface.lib;pcl_surfaced.lib;pcl_tracking.lib;pcl_trackingd.lib;pcl_visualization.lib;pcl_visualizationd.lib;vtkcgns-9.2.lib;vtkChartsCore-9.2.lib;vtkCommonColor-9.2.lib;vtkCommonComputationalGeometry-9.2.lib;vtkCommonCore-9.2.lib;vtkCommonDataModel-9.2.lib;vtkCommonExecutionModel-9.2.lib;vtkCommonMath-9.2.lib;vtkCommonMisc-9.2.lib;vtkCommonSystem-9.2.lib;vtkCommonTransforms-9.2.lib;vtkDICOMParser-9.2.lib;vtkDomainsChemistry-9.2.lib;vtkDomainsChemistryOpenGL2-9.2.lib;vtkDomainsParallelChemistry-9.2.lib;vtkdoubleconversion-9.2.lib;vtkexodusII-9.2.lib;vtkexpat-9.2.lib;vtkFiltersAMR-9.2.lib;vtkFiltersCore-9.2.lib;vtkFiltersExtraction-9.2.lib;vtkFiltersFlowPaths-9.2.lib;vtkFiltersGeneral-9.2.lib;vtkFiltersGeneric-9.2.lib;vtkFiltersGeometry-9.2.lib;vtkFiltersHybrid-9.2.lib;vtkFiltersHyperTree-9.2.lib;vtkFiltersImaging-9.2.lib;vtkFiltersModeling-9.2.lib;vtkFiltersParallel-9.2.lib;vtkFiltersParallelGeometry-9.2.lib;vtkFiltersParallelImaging-9.2.lib;vtkFiltersParallelMPI-9.2.lib;vtkFiltersParallelVerdict-9.2.lib;vtkFiltersPoints-9.2.lib;vtkFiltersProgrammable-9.2.lib;vtkFiltersSelection-9.2.lib;vtkFiltersSMP-9.2.lib;vtkFiltersSources-9.2.lib;vtkFiltersStatistics-9.2.lib;vtkFiltersTexture-9.2.lib;vtkFiltersTopology-9.2.lib;vtkFiltersVerdict-9.2.lib;vtkfmt-9.2.lib;vtkfreetype-9.2.lib;vtkGeovisCore-9.2.lib;vtkgl2ps-9.2.lib;vtkglew-9.2.lib;vtkGUISupportQt-9.2.lib;vtkGUISupportQtQuick-9.2.lib;vtkGUISupportQtSQL-9.2.lib;vtkhdf5-9.2.lib;vtkhdf5_hl-9.2.lib;vtkImagingColor-9.2.lib;vtkImagingCore-9.2.lib;vtkImagingFourier-9.2.lib;vtkImagingGeneral-9.2.lib;vtkImagingHybrid-9.2.lib;vtkImagingMath-9.2.lib;vtkImagingMorphological-9.2.lib;vtkImagingSources-9.2.lib;vtkImagingStatistics-9.2.lib;vtkImagingStencil-9.2.lib;vtkInfovisCore-9.2.lib;vtkInfovisLayout-9.2.lib;vtkInteractionImage-9.2.lib;vtkInteractionStyle-9.2.lib;vtkInteractionWidgets-9.2.lib;vtkIOAMR-9.2.lib;vtkIOAsynchronous-9.2.lib;vtkIOCesium3DTiles-9.2.lib;vtkIOCGNSReader-9.2.lib;vtkIOChemistry-9.2.lib;vtkIOCityGML-9.2.lib;vtkIOCONVERGECFD-9.2.lib;vtkIOCore-9.2.lib;vtkIOEnSight-9.2.lib;vtkIOExodus-9.2.lib;vtkIOExport-9.2.lib;vtkIOExportGL2PS-9.2.lib;vtkIOExportPDF-9.2.lib;vtkIOGeometry-9.2.lib;vtkIOHDF-9.2.lib;vtkIOImage-9.2.lib;vtkIOImport-9.2.lib;vtkIOInfovis-9.2.lib;vtkIOIOSS-9.2.lib;vtkIOLegacy-9.2.lib;vtkIOLSDyna-9.2.lib;vtkIOMINC-9.2.lib;vtkIOMotionFX-9.2.lib;vtkIOMovie-9.2.lib;vtkIOMPIImage-9.2.lib;vtkIONetCDF-9.2.lib;vtkIOOggTheora-9.2.lib;vtkIOParallel-9.2.lib;vtkIOParallelNetCDF-9.2.lib;vtkIOParallelXML-9.2.lib;vtkIOPLY-9.2.lib;vtkIOSegY-9.2.lib;vtkIOSQL-9.2.lib;vtkioss-9.2.lib;vtkIOTecplotTable-9.2.lib;vtkIOVeraOut-9.2.lib;vtkIOVideo-9.2.lib;vtkIOXML-9.2.lib;vtkIOXMLParser-9.2.lib;vtkjpeg-9.2.lib;vtkjsoncpp-9.2.lib;vtkkissfft-9.2.lib;vtklibharu-9.2.lib;vtklibproj-9.2.lib;vtklibxml2-9.2.lib;vtkloguru-9.2.lib;vtklz4-9.2.lib;vtklzma-9.2.lib;vtkmetaio-9.2.lib;vtknetcdf-9.2.lib;vtkogg-9.2.lib;vtkParallelCore-9.2.lib;vtkParallelDIY-9.2.lib;vtkParallelMPI-9.2.lib;vtkpng-9.2.lib;vtkpugixml-9.2.lib;vtkRenderingAnnotation-9.2.lib;vtkRenderingContext2D-9.2.lib;vtkRenderingContextOpenGL2-9.2.lib;vtkRenderingCore-9.2.lib;vtkRenderingFreeType-9.2.lib;vtkRenderingGL2PSOpenGL2-9.2.lib;vtkRenderingHyperTreeGrid-9.2.lib;vtkRenderingImage-9.2.lib;vtkRenderingLabel-9.2.lib;vtkRenderingLICOpenGL2-9.2.lib;vtkRenderingLOD-9.2.lib;vtkRenderingOpenGL2-9.2.lib;vtkRenderingQt-9.2.lib;vtkRenderingSceneGraph-9.2.lib;vtkRenderingUI-9.2.lib;vtkRenderingVolume-9.2.lib;vtkRenderingVolumeOpenGL2-9.2.lib;vtkRenderingVtkJS-9.2.lib;vtksqlite-9.2.lib;vtksys-9.2.lib;vtkTestingRendering-9.2.lib;vtktheora-9.2.lib;vtktiff-9.2.lib;vtkverdict-9.2.lib;vtkViewsContext2D-9.2.lib;vtkViewsCore-9.2.lib;vtkViewsInfovis-9.2.lib;vtkViewsQt-9.2.lib;vtkWrappingTools-9.2.lib;vtkzlib-9.2.lib;TKBin.lib;TKBinL.lib;TKBinTObj.lib;TKBinXCAF.lib;TKBO.lib;TKBool.lib;TKBRep.lib;TKCAF.lib;TKCDF.lib;TKDCAF.lib;TKDraw.lib;TKernel.lib;TKExpress.lib;TKFeat.lib;TKFillet.lib;TKG2d.lib;TKG3d.lib;TKGeomAlgo.lib;TKGeomBase.lib;TKHLR.lib;TKIGES.lib;TKIVtk.lib;TKIVtkDraw.lib;TKLCAF.lib;TKMath.lib;TKMesh.lib;TKMeshVS.lib;TKOffset.lib;TKOpenGl.lib;TKOpenGlTest.lib;TKPrim.lib;TKQADraw.lib;TKRWMesh.lib;TKService.lib;TKShHealing.lib;TKStd.lib;TKStdL.lib;TKSTEP.lib;TKSTEP209.lib;TKSTEPAttr.lib;TKSTEPBase.lib;TKSTL.lib;TKTObj.lib;TKTObjDRAW.lib;TKTopAlgo.lib;TKTopTest.lib;TKV3d.lib;TKVCAF.lib;TKViewerTest.lib;TKVRML.lib;TKXCAF.lib;TKXDE.lib;TKXDECascade.lib;TKXDEDRAW.lib;TKXDEIGES.lib;TKXDESTEP.lib;TKXMesh.lib;TKXml.lib;TKXmlL.lib;TKXmlTObj.lib;TKXmlXCAF.lib;TKXSBase.lib;TKXSDRAW.lib;%(AdditionalDependencies) + D:\codestorage\LAMPSARtool\CPluseCpluse\WBCLFZProgram\WBCLFZProgram\x64\Release;%(AdditionalLibraryDirectories) + + + + + stdc17 + true + true + SCINTILLA_QT;SCI_LEXER;%(PreprocessorDefinitions) + stdcpp14 + + + QtCommandConsole.lib;pcl_common.lib;pcl_commond.lib;pcl_features.lib;pcl_featuresd.lib;pcl_filters.lib;pcl_filtersd.lib;pcl_io.lib;pcl_iod.lib;pcl_io_ply.lib;pcl_io_plyd.lib;pcl_kdtree.lib;pcl_kdtreed.lib;pcl_keypoints.lib;pcl_keypointsd.lib;pcl_ml.lib;pcl_mld.lib;pcl_octree.lib;pcl_octreed.lib;pcl_outofcore.lib;pcl_outofcored.lib;pcl_people.lib;pcl_peopled.lib;pcl_recognition.lib;pcl_recognitiond.lib;pcl_registration.lib;pcl_registrationd.lib;pcl_sample_consensus.lib;pcl_sample_consensusd.lib;pcl_search.lib;pcl_searchd.lib;pcl_segmentation.lib;pcl_segmentationd.lib;pcl_stereo.lib;pcl_stereod.lib;pcl_surface.lib;pcl_surfaced.lib;pcl_tracking.lib;pcl_trackingd.lib;pcl_visualization.lib;pcl_visualizationd.lib;vtkcgns-9.2.lib;vtkChartsCore-9.2.lib;vtkCommonColor-9.2.lib;vtkCommonComputationalGeometry-9.2.lib;vtkCommonCore-9.2.lib;vtkCommonDataModel-9.2.lib;vtkCommonExecutionModel-9.2.lib;vtkCommonMath-9.2.lib;vtkCommonMisc-9.2.lib;vtkCommonSystem-9.2.lib;vtkCommonTransforms-9.2.lib;vtkDICOMParser-9.2.lib;vtkDomainsChemistry-9.2.lib;vtkDomainsChemistryOpenGL2-9.2.lib;vtkDomainsParallelChemistry-9.2.lib;vtkdoubleconversion-9.2.lib;vtkexodusII-9.2.lib;vtkexpat-9.2.lib;vtkFiltersAMR-9.2.lib;vtkFiltersCore-9.2.lib;vtkFiltersExtraction-9.2.lib;vtkFiltersFlowPaths-9.2.lib;vtkFiltersGeneral-9.2.lib;vtkFiltersGeneric-9.2.lib;vtkFiltersGeometry-9.2.lib;vtkFiltersHybrid-9.2.lib;vtkFiltersHyperTree-9.2.lib;vtkFiltersImaging-9.2.lib;vtkFiltersModeling-9.2.lib;vtkFiltersParallel-9.2.lib;vtkFiltersParallelGeometry-9.2.lib;vtkFiltersParallelImaging-9.2.lib;vtkFiltersParallelMPI-9.2.lib;vtkFiltersParallelVerdict-9.2.lib;vtkFiltersPoints-9.2.lib;vtkFiltersProgrammable-9.2.lib;vtkFiltersSelection-9.2.lib;vtkFiltersSMP-9.2.lib;vtkFiltersSources-9.2.lib;vtkFiltersStatistics-9.2.lib;vtkFiltersTexture-9.2.lib;vtkFiltersTopology-9.2.lib;vtkFiltersVerdict-9.2.lib;vtkfmt-9.2.lib;vtkfreetype-9.2.lib;vtkGeovisCore-9.2.lib;vtkgl2ps-9.2.lib;vtkglew-9.2.lib;vtkGUISupportQt-9.2.lib;vtkGUISupportQtQuick-9.2.lib;vtkGUISupportQtSQL-9.2.lib;vtkhdf5-9.2.lib;vtkhdf5_hl-9.2.lib;vtkImagingColor-9.2.lib;vtkImagingCore-9.2.lib;vtkImagingFourier-9.2.lib;vtkImagingGeneral-9.2.lib;vtkImagingHybrid-9.2.lib;vtkImagingMath-9.2.lib;vtkImagingMorphological-9.2.lib;vtkImagingSources-9.2.lib;vtkImagingStatistics-9.2.lib;vtkImagingStencil-9.2.lib;vtkInfovisCore-9.2.lib;vtkInfovisLayout-9.2.lib;vtkInteractionImage-9.2.lib;vtkInteractionStyle-9.2.lib;vtkInteractionWidgets-9.2.lib;vtkIOAMR-9.2.lib;vtkIOAsynchronous-9.2.lib;vtkIOCesium3DTiles-9.2.lib;vtkIOCGNSReader-9.2.lib;vtkIOChemistry-9.2.lib;vtkIOCityGML-9.2.lib;vtkIOCONVERGECFD-9.2.lib;vtkIOCore-9.2.lib;vtkIOEnSight-9.2.lib;vtkIOExodus-9.2.lib;vtkIOExport-9.2.lib;vtkIOExportGL2PS-9.2.lib;vtkIOExportPDF-9.2.lib;vtkIOGeometry-9.2.lib;vtkIOHDF-9.2.lib;vtkIOImage-9.2.lib;vtkIOImport-9.2.lib;vtkIOInfovis-9.2.lib;vtkIOIOSS-9.2.lib;vtkIOLegacy-9.2.lib;vtkIOLSDyna-9.2.lib;vtkIOMINC-9.2.lib;vtkIOMotionFX-9.2.lib;vtkIOMovie-9.2.lib;vtkIOMPIImage-9.2.lib;vtkIONetCDF-9.2.lib;vtkIOOggTheora-9.2.lib;vtkIOParallel-9.2.lib;vtkIOParallelNetCDF-9.2.lib;vtkIOParallelXML-9.2.lib;vtkIOPLY-9.2.lib;vtkIOSegY-9.2.lib;vtkIOSQL-9.2.lib;vtkioss-9.2.lib;vtkIOTecplotTable-9.2.lib;vtkIOVeraOut-9.2.lib;vtkIOVideo-9.2.lib;vtkIOXML-9.2.lib;vtkIOXMLParser-9.2.lib;vtkjpeg-9.2.lib;vtkjsoncpp-9.2.lib;vtkkissfft-9.2.lib;vtklibharu-9.2.lib;vtklibproj-9.2.lib;vtklibxml2-9.2.lib;vtkloguru-9.2.lib;vtklz4-9.2.lib;vtklzma-9.2.lib;vtkmetaio-9.2.lib;vtknetcdf-9.2.lib;vtkogg-9.2.lib;vtkParallelCore-9.2.lib;vtkParallelDIY-9.2.lib;vtkParallelMPI-9.2.lib;vtkpng-9.2.lib;vtkpugixml-9.2.lib;vtkRenderingAnnotation-9.2.lib;vtkRenderingContext2D-9.2.lib;vtkRenderingContextOpenGL2-9.2.lib;vtkRenderingCore-9.2.lib;vtkRenderingFreeType-9.2.lib;vtkRenderingGL2PSOpenGL2-9.2.lib;vtkRenderingHyperTreeGrid-9.2.lib;vtkRenderingImage-9.2.lib;vtkRenderingLabel-9.2.lib;vtkRenderingLICOpenGL2-9.2.lib;vtkRenderingLOD-9.2.lib;vtkRenderingOpenGL2-9.2.lib;vtkRenderingQt-9.2.lib;vtkRenderingSceneGraph-9.2.lib;vtkRenderingUI-9.2.lib;vtkRenderingVolume-9.2.lib;vtkRenderingVolumeOpenGL2-9.2.lib;vtkRenderingVtkJS-9.2.lib;vtksqlite-9.2.lib;vtksys-9.2.lib;vtkTestingRendering-9.2.lib;vtktheora-9.2.lib;vtktiff-9.2.lib;vtkverdict-9.2.lib;vtkViewsContext2D-9.2.lib;vtkViewsCore-9.2.lib;vtkViewsInfovis-9.2.lib;vtkViewsQt-9.2.lib;vtkWrappingTools-9.2.lib;vtkzlib-9.2.lib;TKBin.lib;TKBinL.lib;TKBinTObj.lib;TKBinXCAF.lib;TKBO.lib;TKBool.lib;TKBRep.lib;TKCAF.lib;TKCDF.lib;TKDCAF.lib;TKDraw.lib;TKernel.lib;TKExpress.lib;TKFeat.lib;TKFillet.lib;TKG2d.lib;TKG3d.lib;TKGeomAlgo.lib;TKGeomBase.lib;TKHLR.lib;TKIGES.lib;TKIVtk.lib;TKIVtkDraw.lib;TKLCAF.lib;TKMath.lib;TKMesh.lib;TKMeshVS.lib;TKOffset.lib;TKOpenGl.lib;TKOpenGlTest.lib;TKPrim.lib;TKQADraw.lib;TKRWMesh.lib;TKService.lib;TKShHealing.lib;TKStd.lib;TKStdL.lib;TKSTEP.lib;TKSTEP209.lib;TKSTEPAttr.lib;TKSTEPBase.lib;TKSTL.lib;TKTObj.lib;TKTObjDRAW.lib;TKTopAlgo.lib;TKTopTest.lib;TKV3d.lib;TKVCAF.lib;TKViewerTest.lib;TKVRML.lib;TKXCAF.lib;TKXDE.lib;TKXDECascade.lib;TKXDEDRAW.lib;TKXDEIGES.lib;TKXDESTEP.lib;TKXMesh.lib;TKXml.lib;TKXmlL.lib;TKXmlTObj.lib;TKXmlXCAF.lib;TKXSBase.lib;TKXSDRAW.lib;%(AdditionalDependencies) + D:\codestorage\LAMPSARtool\CPluseCpluse\WBCLFZProgram\WBCLFZProgram\x64\Release;%(AdditionalLibraryDirectories) + + + + + true + true + ProgramDatabase + Disabled + + + Windows + true + + + + + true + true + ProgramDatabase + Disabled + + + Windows + true + + + + + true + true + EditAndContinue + Disabled + + + Console + true + + + + + true + true + EditAndContinue + Disabled + + + Console + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + input + input + %(Filename).moc + %(Filename).moc + input + input + %(Filename).moc + %(Filename).moc + + + + + + + + + + + + + + + + + + + + + + + + + + input + input + %(Filename).moc + %(Filename).moc + input + input + %(Filename).moc + %(Filename).moc + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {901ef323-fb47-4bbd-a6bb-7ddfd876f28e} + + + {cf35028a-1ce3-4fe0-b79b-2c4617f4758a} + + + {52dbe16d-fb8f-4278-8dd1-fbe96d4241fc} + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/WBCLFZSystemModule/WBCLFZSystemModule.vcxproj.filters b/src/WBCLFZSystemModule/WBCLFZSystemModule.vcxproj.filters new file mode 100644 index 0000000..38d9c46 --- /dev/null +++ b/src/WBCLFZSystemModule/WBCLFZSystemModule.vcxproj.filters @@ -0,0 +1,1076 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + qml;cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + qrc;rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + {99349809-55BA-4b9d-BF79-8FDBB0286EB3} + ui + + + {639EADAA-A684-42e4-A9AD-28FC9BCB8F7C} + ts + + + {8acdde24-0c69-42a0-b9ad-ea42af5c423c} + + + {420f5f09-0f15-4498-82ee-668e8c753dc6} + + + {2499eafe-ab98-4571-87b3-22d2ea35c66f} + + + {08fb61d0-8186-407a-9a9e-0526e7bbfb85} + + + {0ace4246-a472-4d52-ae5f-bf64d2e2fff6} + + + {39b7ba80-4871-42a3-a144-f0c88da49c21} + + + {d179610c-1d93-49f5-b8a3-e3eb24b2b6fe} + + + {98fdc707-843e-4892-b2a4-5b4060ca76bc} + + + {fce06cfd-4699-458e-9471-1a4513408ab7} + + + {6da6f318-95f9-45ff-bc54-04d9ed34947a} + + + {7f5217ad-613d-47d2-b88f-235af657b3cf} + + + {ee006833-cb51-4f1c-95af-059be9d57d87} + + + {e86a1a47-022f-48d3-b110-aba930e33af4} + + + {05de7f4a-8fdc-45e2-863d-a8e24fab16b4} + + + {3c4bcd59-3dec-4b8e-91ff-7730f0dc84da} + + + {d1b63122-da6a-4995-b220-4327dc44f741} + + + {1f33fd01-a3e5-4b07-987a-ef421b497e19} + + + {530a3f62-85f5-40e7-a828-f527a487f59c} + + + {8bdde5b0-e50c-4795-ba75-01316629c29c} + + + {f7273920-c86b-4e46-9ede-35ff0b627c42} + + + {e2ac7a81-4b89-4873-bd6e-b07cdf985ecd} + + + {ca6b7ece-496d-464b-9d0f-a5fd01ab3b0d} + + + {11c398a0-cbfc-4ea1-87b8-322f57c808aa} + + + {e144131c-754e-46c7-8d66-0d403c96aa53} + + + {b6f07bf0-7105-47f2-9449-1fce4a308eef} + + + {b9bcd6d4-026f-4b12-a22e-7687d2c80041} + + + {adb237e9-335d-421e-b60a-cab8b4052152} + + + {3dda531e-e209-4656-88f3-2bb41afa3973} + + + {4a5efe8a-9bcb-4944-bd8d-2cb57aca1274} + + + {2c7440df-684f-4d62-b7f5-e44e0ebbeb40} + + + {f491cee1-fa52-4955-9fcd-11d126500142} + + + {b20604d7-70ca-4d1f-8dd3-81d8651535fe} + + + {421f7f6d-f2f7-4604-b3d2-b109cdf71f1e} + + + {d9a1af12-7da0-4202-8dd9-f2929a56dc0f} + + + {4b14b1f2-49bd-4615-b5f3-7f7ccbd923de} + + + {79cac2d0-f69a-4b80-8ade-01aeea3519bb} + + + {90708016-497d-44bc-a013-856ec319d6ff} + + + {9bbed288-9853-41ef-b9a0-3bfa3e802e96} + + + {48481453-661a-4a57-ab39-fcff342b3df5} + + + {ff812d4f-762d-4988-bbf9-a05b4c0a07a1} + + + {002e20d1-0149-4c44-9384-36255e80d7c6} + + + {63f66032-053f-4258-a6c0-ab7c16c2bc48} + + + {9c06e284-7ba3-46f9-975c-a147e1994a58} + + + {225fb9c4-7891-422b-ad6e-b53de34d32d0} + + + + + Resource Files + + + Form Files + + + Header Files + + + Source Files + + + + + Source Files + + + PointCloudProcess\Source Files + + + PointCloudProcess\Source Files + + + PointCloudProcess\Source Files + + + PointCloudProcess\Source Files + + + PointCloudProcess\Source Files + + + PointCloudProcess\Source Files + + + TableProcess\Source Files + + + TableProcess\Source Files + + + SharedModuleLib\Source Files + + + SharedModuleLib\Source Files + + + modelProcess\Source Files + + + SharedModuleLib\OCCViewer\Source Files + + + SharedModuleLib\OCCViewer\Source Files + + + SharedModuleLib\OCCViewer\Source Files + + + SharedModuleLib\OCCViewer\Source Files + + + SharedModuleLib\OCCViewer\Source Files + + + SharedModuleLib\OCCViewer\Source Files + + + SharedModuleLib\OCCViewer\OCCT_Test\Source Files + + + SharedModuleLib\OCCViewer\OCCT_Test\Source Files + + + SharedModuleLib\OCCViewer\OCCT_Test\Source Files + + + EchoShowProcess\Source Files + + + EchoShowProcess\Source Files + + + SharedModuleLib\Source Files + + + TableProcess\Source Files + + + TableProcess\Source Files + + + TableProcess\Source Files + + + SharedModuleLib\OCCViewer\Source Files + + + SqliteDBProcess + + + SqliteDBProcess\Source Files + + + SqliteDBProcess\Source Files + + + SqliteDBProcess\Source Files + + + SqliteDBProcess\Source Files + + + SqliteDBProcess\Source Files + + + SqliteDBProcess\Source Files + + + SqliteDBProcess\Source Files + + + SqliteDBProcess\Source Files + + + SqliteDBProcess\Source Files + + + SqliteDBProcess\Source Files + + + SqliteDBProcess\Source Files + + + SqliteDBProcess\Source Files + + + SqliteDBProcess\Source Files + + + SqliteDBProcess\Source Files + + + SqliteDBProcess\Source Files + + + SqliteDBProcess\Source Files + + + SqliteDBProcess\Source Files + + + SqliteDBProcess\Source Files + + + SqliteDBProcess\Source Files + + + SqliteDBProcess\Source Files + + + SqliteDBProcess\Source Files + + + SqliteDBProcess\Source Files + + + SqliteDBProcess\Source Files + + + SqliteDBProcess\Source Files + + + SqliteDBProcess\Source Files + + + SqliteDBProcess\Source Files + + + SqliteDBProcess\Source Files + + + SqliteDBProcess\Source Files + + + SqliteDBProcess\Source Files + + + SqliteDBProcess\Source Files + + + SqliteDBProcess\Source Files + + + SqliteDBProcess\Source Files + + + SqliteDBProcess\Source Files + + + SqliteDBProcess\Source Files + + + SqliteDBProcess\Source Files + + + SqliteDBProcess\Source Files + + + SqliteDBProcess\Source Files + + + SqliteDBProcess\Source Files + + + SqliteDBProcess\Source Files + + + SqliteDBProcess\Source Files + + + SqliteDBProcess\Source Files + + + SqliteDBProcess\Source Files + + + SqliteDBProcess\Source Files + + + SqliteDBProcess\Source Files + + + SqliteDBProcess\Source Files + + + SqliteDBProcess\Source Files + + + SqliteDBProcess\Source Files + + + SqliteDBProcess\Source Files + + + SqliteDBProcess\Source Files + + + SqliteDBProcess\Source Files + + + SqliteDBProcess\Source Files + + + SqliteDBProcess\Source Files + + + SqliteDBProcess\Source Files + + + SqliteDBProcess\Source Files + + + SqliteDBProcess\Source Files + + + SharedModuleLib\OCCViewer\Source Files + + + SharedModuleLib\OCCViewer\Source Files + + + SharedModuleLib\Source Files + + + TaskXml\Source Files + + + Source Files\ImageSetting + + + Source Files\ImageSetting + + + Source Files\ImageSetting + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + PointCloudProcess\Header Files + + + PointCloudProcess\Header Files + + + Header Files + + + SharedModuleLib\Header Files + + + SharedModuleLib\OCCViewer\Header Files + + + SharedModuleLib\OCCViewer\Header Files + + + SharedModuleLib\OCCViewer\OCCT_Test\Header Files + + + SharedModuleLib\OCCViewer\OCCT_Test\Header Files + + + SharedModuleLib\OCCViewer\OCCT_Test\Header Files + + + TableProcess\Header Files + + + SqliteDBProcess\Header Files + + + SqliteDBProcess\Header Files + + + SqliteDBProcess\Header Files + + + SqliteDBProcess\Header Files + + + SqliteDBProcess\Header Files + + + SqliteDBProcess\Header Files + + + SqliteDBProcess\Header Files + + + SqliteDBProcess\Header Files + + + SqliteDBProcess\Header Files + + + SqliteDBProcess\Header Files + + + SqliteDBProcess\Header Files + + + SqliteDBProcess\Header Files + + + SqliteDBProcess\Header Files + + + SqliteDBProcess\Header Files + + + SqliteDBProcess\Header Files + + + SqliteDBProcess\Header Files + + + SqliteDBProcess\Header Files + + + SqliteDBProcess\Header Files + + + SharedModuleLib\Header Files + + + Header Files + + + Header Files + + + Header Files + + + + + Resource Files + + + SqliteDBProcess + + + SqliteDBProcess + + + + + PointCloudProcess\Header Files + + + PointCloudProcess\Header Files + + + PointCloudProcess\Header Files + + + PointCloudProcess\Header Files + + + TableProcess\Header Files + + + TableProcess\Header Files + + + SharedModuleLib\Header Files + + + modelProcess\Header Files + + + SharedModuleLib\OCCViewer\Header Files + + + SharedModuleLib\OCCViewer\Header Files + + + SharedModuleLib\OCCViewer\Header Files + + + SharedModuleLib\OCCViewer\Header Files + + + SharedModuleLib\OCCViewer\Header Files + + + EchoShowProcess\Header Files + + + EchoShowProcess\Header Files + + + SharedModuleLib\Header Files + + + TableProcess\Header Files + + + TableProcess\Header Files + + + SharedModuleLib\OCCViewer\Header Files + + + SqliteDBProcess\Source Files + + + SqliteDBProcess\Source Files + + + SqliteDBProcess\Header Files + + + SqliteDBProcess\Header Files + + + SqliteDBProcess\Header Files + + + SqliteDBProcess\Header Files + + + SqliteDBProcess\Header Files + + + SqliteDBProcess\Header Files + + + SqliteDBProcess\Header Files + + + SqliteDBProcess\Header Files + + + SqliteDBProcess\Header Files + + + SqliteDBProcess\Header Files + + + SqliteDBProcess\Header Files + + + SqliteDBProcess\Header Files + + + SqliteDBProcess\Header Files + + + SqliteDBProcess\Header Files + + + SqliteDBProcess\Header Files + + + SqliteDBProcess\Header Files + + + SqliteDBProcess\Header Files + + + SqliteDBProcess\Header Files + + + SqliteDBProcess\Header Files + + + SqliteDBProcess\Header Files + + + SqliteDBProcess\Header Files + + + SqliteDBProcess\Header Files + + + SqliteDBProcess\Header Files + + + SqliteDBProcess\Header Files + + + SqliteDBProcess\Header Files + + + SqliteDBProcess\Header Files + + + SqliteDBProcess\Header Files + + + SqliteDBProcess\Header Files + + + SqliteDBProcess\Header Files + + + SqliteDBProcess\Header Files + + + SqliteDBProcess\Header Files + + + SqliteDBProcess\Header Files + + + SqliteDBProcess\Header Files + + + SqliteDBProcess\Header Files + + + SqliteDBProcess\Header Files + + + SqliteDBProcess\Header Files + + + SqliteDBProcess\Header Files + + + SqliteDBProcess\Header Files + + + SqliteDBProcess\Header Files + + + SqliteDBProcess\Header Files + + + SqliteDBProcess\Header Files + + + SqliteDBProcess\Header Files + + + SqliteDBProcess\Header Files + + + SharedModuleLib\OCCViewer\Header Files + + + SharedModuleLib\OCCViewer\Header Files + + + TaskXml\Header Files + + + Header Files\ImageSetting + + + Header Files\ImageSetting + + + Header Files\ImageSetting + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + + + PointCloudProcess\Form Files + + + PointCloudProcess\Form Files + + + PointCloudProcess\Form Files + + + PointCloudProcess\Form Files + + + PointCloudProcess\Form Files + + + PointCloudProcess\Form Files + + + PointCloudProcess\Form Files + + + PointCloudProcess\Form Files + + + TableProcess\Form Files + + + SharedModuleLib\Form Files + + + modelProcess\Form Files + + + EchoShowProcess\Form Files + + + EchoShowProcess\Form Files + + + SharedModuleLib\Form Files + + + TableProcess\Form Files + + + TableProcess\Form Files + + + SqliteDBProcess\Form Files + + + SqliteDBProcess\Form Files + + + SqliteDBProcess\Form Files + + + SqliteDBProcess\Form Files + + + SqliteDBProcess\Form Files + + + SqliteDBProcess\Form Files + + + SqliteDBProcess\Form Files + + + SqliteDBProcess\Form Files + + + SqliteDBProcess\Form Files + + + SqliteDBProcess\Form Files + + + SqliteDBProcess\Form Files + + + SqliteDBProcess\Form Files + + + SqliteDBProcess\Form Files + + + SqliteDBProcess\Form Files + + + SqliteDBProcess\Form Files + + + SqliteDBProcess\Form Files + + + SqliteDBProcess\Form Files + + + SqliteDBProcess\Form Files + + + SqliteDBProcess\Form Files + + + SqliteDBProcess\Form Files + + + SqliteDBProcess\Form Files + + + SqliteDBProcess\Form Files + + + SqliteDBProcess\Form Files + + + SharedModuleLib\OCCViewer\Form Files + + + SharedModuleLib\OCCViewer\Form Files + + + SharedModuleLib\OCCViewer\Form Files + + + Form Files\ImageSetting + + + Form Files\ImageSetting + + + Form Files\ImageSetting + + + EchoShowProcess + + + Form Files + + + Form Files + + + Form Files + + + Form Files + + + Form Files + + + Form Files + + + Form Files + + + Form Files + + + Form Files + + + Form Files + + + + + SharedModuleLib\Resource Files + + + SharedModuleLib\OCCViewer\OCCT_Test + + + + + + SqliteDBProcess + + + SqliteDBProcess + + + SqliteDBProcess + + + SqliteDBProcess + + + SqliteDBProcess + + + SqliteDBProcess + + + SqliteDBProcess + + + + + SqliteDBProcess + + + \ No newline at end of file diff --git a/src/WBCLFZSystemModule/WBCLFZSystemModule.vcxproj.user b/src/WBCLFZSystemModule/WBCLFZSystemModule.vcxproj.user new file mode 100644 index 0000000..6901304 --- /dev/null +++ b/src/WBCLFZSystemModule/WBCLFZSystemModule.vcxproj.user @@ -0,0 +1,26 @@ + + + + false + + + false + WindowsLocalDebugger + + + false + WindowsLocalDebugger + + + 2024-03-11T14:28:13.8563547Z + + + 2024-03-11T14:28:13.5842400Z + + + 2024-03-11T14:28:14.4305103Z + + + 2024-03-11T14:28:14.3381603Z + + \ No newline at end of file diff --git a/src/WBCLFZSystemModule/cpp.hint b/src/WBCLFZSystemModule/cpp.hint new file mode 100644 index 0000000..eaabbfc --- /dev/null +++ b/src/WBCLFZSystemModule/cpp.hint @@ -0,0 +1,4 @@ +// æç¤ºæ–‡ä»¶å¸®åŠ© Visual Studio IDE 解释 Visual C++ 标识符, +// 如函数和å®çš„å称。 +// 有关详细信æ¯ï¼Œè¯·å‚è§ https://go.microsoft.com/fwlink/?linkid=865984 + diff --git a/src/WBCLFZSystemModule/main.cpp b/src/WBCLFZSystemModule/main.cpp new file mode 100644 index 0000000..b296b5c --- /dev/null +++ b/src/WBCLFZSystemModule/main.cpp @@ -0,0 +1,199 @@ +#include "HeaderSort.h" +#include "AllHead.h" +#include "WBCLFZSystemModule.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "SqliteDBProcess/src/Application.h" +#include "SqliteDBProcess/src/sqlite.h" + + + + +void LoadProgramParams() { + + // ´´½¨QSettings¶ÔÏó£¬Ö¸¶¨ÅäÖÃÎļþ·¾¶ + QSettings settings("config.ini", QSettings::IniFormat); + + QString variable = settings.value("variable", "Default Value").toString(); + qDebug() << "Loaded variable:" << variable; + + // Ð޸ijÌÐò±äÁ¿ + variable = "New Value"; + settings.setValue("variable", variable); + qDebug() << "Updated variable:" << variable; +} + + +void TestOCCT() { + gp_Vec Z_vec(gp_Pnt(0, 0, 0), gp_Pnt(0, 0, 1)); + gp_Vec X_vec(gp_Pnt(0, 0, 0), gp_Pnt(1, 0, 0)); + gp_Vec Y_vec(gp_Pnt(0, 0, 0), gp_Pnt(0, 1, 0)); + Standard_Real rotationAngle = 90; + rotationAngle = rotationAngle * M_PI / 180; + + gp_Trsf fly_Z_trsf; + fly_Z_trsf.SetRotation(gp_Ax1(gp_Pnt(0, 0, 0), X_vec), rotationAngle); // Y --> Z ÄæÊ±ÕëΪ Õý + + qDebug() << QString("Y_vec before:( %1 , %2 , %3 )").arg(Y_vec.X()).arg(Y_vec.Y()).arg(Y_vec.Z()); + Y_vec.Transform(fly_Z_trsf); + qDebug() << QString("Y_vec after:( %1 , %2 , %3 )").arg(Y_vec.X()).arg(Y_vec.Y()).arg(Y_vec.Z()); + + qDebug() << QString("X_vec before:( %1 , %2 , %3 )").arg(X_vec.X()).arg(X_vec.Y()).arg(X_vec.Z()); + X_vec.Transform(fly_Z_trsf); + qDebug() << QString("Y_vec after:( %1 , %2 , %3 )").arg(X_vec.X()).arg(X_vec.Y()).arg(X_vec.Z()); + + qDebug() << QString("Z_vec before:( %1 , %2 , %3 )").arg(Z_vec.X()).arg(Z_vec.Y()).arg(Z_vec.Z()); + Z_vec.Transform(fly_Z_trsf); + qDebug() << QString("Z_vec after:( %1 , %2 , %3 )").arg(Z_vec.X()).arg(Z_vec.Y()).arg(Z_vec.Z()); +} + + +// ×Ô¶¨ÒåÏûÏ¢´¦Àí³ÌÐò +void LogTextcustomMessageHandler(QtMsgType type, const QMessageLogContext& context, const QString& msg) +{ + + // -------- ÈÕÖ¾Êä³ö ---------------------------------------------------------------------------------- + + // »ñȡӦÓóÌÐòÖ´ÐÐÎļþµÄ·¾¶ + QString exePath = QCoreApplication::applicationFilePath(); + + // ʹÓÃQFileInfo»ñÈ¡¸¸Ä¿Â¼ + QFileInfo fileInfo(exePath); + QString parentDir = fileInfo.dir().path(); + + // »ñÈ¡µ±Ç°ÈÕÆÚºÍʱ¼ä + QDateTime currentDateTime = QDateTime::currentDateTime(); + // ¸ñʽ»¯ÈÕÆÚºÍʱ¼äΪ×Ö·û´®£¬¾«È·µ½Ãë + QString dateTimeString = currentDateTime.toString("yyyyMMdd_hh"); + // ´´½¨ÎļþÃû + QString fileName = parentDir + "/logs/" + "log_" + dateTimeString + ".log"; + // ´´½¨Ò»¸öÈÕÖ¾Îļþ + QFile logFile(fileName); + logFile.open(QIODevice::WriteOnly | QIODevice::Append); + QTextStream textStream(&logFile); + // Êä³öµ½¿ØÖÆÌ¨ + QTextStream consoleStream(stdout); + + // дÈëÈÕÖ¾ÐÅÏ¢ + switch (type) { + case QtDebugMsg: + textStream << "[Debug] ["+ currentDateTime.toString("yyyy-MM-dd hh:mm:ss")+"] "; + consoleStream << "[Debug] [" + currentDateTime.toString("yyyy-MM-dd hh:mm:ss") + "] "; + break; + case QtWarningMsg: + textStream << "[Warning] [" + currentDateTime.toString("yyyy-MM-dd hh:mm:ss") + "] "; + consoleStream << "[Warning] [" + currentDateTime.toString("yyyy-MM-dd hh:mm:ss") + "] "; + break; + case QtCriticalMsg: + textStream << "[Critical] [" + currentDateTime.toString("yyyy-MM-dd hh:mm:sss") + "] "; + consoleStream << "[Critical] [" + currentDateTime.toString("yyyy-MM-dd hh:mm:sss") + "] "; + break; + case QtFatalMsg: + textStream << "[Fatal] [" + currentDateTime.toString("yyyy-MM-dd hh:mm:ss") + "] "; + consoleStream << "[Fatal] [" + currentDateTime.toString("yyyy-MM-dd hh:mm:ss") + "] "; + break; + } + //QByteArray localMsg = msg.toLocal8Bit(); + //const char* file = context.file ? context.file : ""; + //const char* function = context.function ? context.function : ""; + //localMsg = QString("%1 (%2, %3:%4)\n").arg(msg).arg(function).arg(file).arg(context.line).toLocal8Bit(); + consoleStream << msg << Qt::endl; // Êä³öµ½¿ØÖÆÌ¨ + textStream << msg << Qt::endl;// ÉèÖÃÎı¾Á÷ + +} + + + +static QString message = QString(); + +void db4sMessageOutput(QtMsgType type, const QMessageLogContext& context, const QString& msg) +{ + QByteArray localMsg = msg.toLocal8Bit(); + + // Emulate the default Qt treatment. This might not work in some OS, like Windows. + fprintf(stderr, "%s\n", localMsg.constData()); + + const char* file = context.file ? context.file : ""; + const char* function = context.function ? context.function : ""; + localMsg = QString("%1 (%2, %3:%4)\n").arg(msg).arg(function).arg(file).arg(context.line).toLocal8Bit(); + + // Log using the SQLite log mechanism, so it gets the same treatment than messages + // reported by SQLite itself. This will allow these messages to be seen in our Log window. + // Error code will be the type + sqlite3_log(static_cast(type), localMsg.constData()); +} + +void boxMessageOutput(QtMsgType, const QMessageLogContext&, const QString& msg) +{ + message += msg + "\n"; +} + + + +int ProcessdBTestmain(int argc, char** argv) +{ + +#ifdef Q_OS_WIN + // In Windows, there is no output to terminal for a graphical application, so we install + // the output to message box, until the main window is shown or the application exits. + qInstallMessageHandler(LogTextcustomMessageHandler); +#endif + + // Create application object. All the initialisation stuff happens in there + Application a(argc, argv); + + // If there has been invocations to the message handler, show it to user in a message box. + if (!message.isEmpty()) { + QMessageBox messageBox; + messageBox.setTextFormat(Qt::RichText); + messageBox.setText("
" + message.toHtmlEscaped() + "
"); + messageBox.exec(); + } + + // Quit application now if user doesn't want to see the UI + if (a.dontShowMainWindow()) + return 0; + + qInstallMessageHandler(LogTextcustomMessageHandler); + + // Run application + return a.exec(); +} + + +int main(int argc, char *argv[]) +{ + + // ProcessdBTestmain(argc, argv); + + QApplication a(argc, argv); + qInstallMessageHandler(LogTextcustomMessageHandler); + TestOCCT(); + // ʾÀýÊä³ö + qDebug() << "Program is init debug log out ..."; + qWarning() << "Program is init waring log out ..."; + qCritical() << "Program is init Critical log out ..."; + + // -------- ²âÊÔ³ÌÐòÕýʽִÐÐ ---------------------------------------------------------------------------------- + WBCLFZSystemModule* w=new WBCLFZSystemModule(); // + w->show(); + return a.exec(); + +} + + + + + + + + diff --git a/src/WBCLFZSystemModule/modelProcess/ModelProcess.cpp b/src/WBCLFZSystemModule/modelProcess/ModelProcess.cpp new file mode 100644 index 0000000..06b718b --- /dev/null +++ b/src/WBCLFZSystemModule/modelProcess/ModelProcess.cpp @@ -0,0 +1,454 @@ +#include "ModelProcess.h" +#include "EchoShowProcess/FEKOResultImport.h" +#include "TaskXml/TaskTreeClass.h" +#include +#include +#include + + +ModelProcess::ModelProcess(QWidget *parent) + : QMainWindow(parent) +{ + ui.setupUi(this); + this->initConstVariable(); + // ÉèÖñ³¾°É« + this->showConntentsWindows(); + //this->showModelInfoWindows(); + this->showInnerModelWindow(); + this->initOCCTView(); + //this->initModelInformationShow(); + this->initMenuList(); + this->initBandingEvent(); + this->initTaskDocker(); + + this->initFileOperatorMenu(); +} + +ModelProcess::~ModelProcess() +{ + +} + +void ModelProcess::on_action_Open_triggered() +{ + //myDocument3d->OpenFile(); + this->myGeomWidget->Show3d(); + +} + + +void ModelProcess::on_action_Modelsave_triggered() // ±£´æÕûÌåÄ£ÐÍ +{ + this->myDocument3d->SaveModelFile(); + +} + +void ModelProcess::on_actionCalibrationConstCreate_triggered() +{ + + +} + +void ModelProcess::on_actionImageSetting_triggered() +{ + FEKOImageSettingTaskNodeClass* imageNode = new FEKOImageSettingTaskNodeClass(); + QString xmlfilepath = getSaveFilePath(this, QString::fromUtf8(u8"ÈÎÎñxml"), QString::fromUtf8(u8"xmlÎļþ (*.xml)")); + imageNode->loadXmlFile(xmlfilepath); + imageNode->TaskWindows->setOCCTDocument(this->myDocument3d->myContext); + this->addTaskNode(imageNode); + imageNode->ExcuteTask(); +} + +void ModelProcess::on_action_ScatterExport_triggered() +{ + EchoTableEditWindow* echoEditwindow = new EchoTableEditWindow(this); + + echoEditwindow->show(); + +} + +void ModelProcess::on_actionFEKOImage_triggered() +{ + LAMPImageCreateClass* imagewindows = new LAMPImageCreateClass; + imagewindows->on_pushButton_loadfekosimulationxml_clicked(); + imagewindows->show(); +} + +void ModelProcess::on_action_antScatteringFEKOSetting_triggered() +{ + FEKOScatterSettingTaskNodeClass* scattertasknode=new FEKOScatterSettingTaskNodeClass(); + QString xmlfilepath = getSaveFilePath(this, QString::fromUtf8(u8"ÈÎÎñxml"), QString::fromUtf8(u8"xmlÎļþ (*.xml)")); + scattertasknode->loadXmlFile(xmlfilepath); + scattertasknode->TaskWindows->setDocument3d(this->myDocument3d->myContext); + this->addTaskNode(scattertasknode); + scattertasknode->ExcuteTask(); +} + +void ModelProcess::on_action_openImageShowWindows_triggered() +{ + LAMPDataShowClass* datashowclass=new LAMPDataShowClass(); + datashowclass->show(); +} + +void ModelProcess::ShowTaskListMenu(QPoint p) +{ + qDebug() << u8"³ÉÏñÈÎÎñ¹ÜÀíÓÒ»÷²Ëµ¥"; + this->TaskListContextMenu->exec(QCursor::pos()); +} + +void ModelProcess::ShowTaskWindows() +{ + QList selectNodes = this->ui.treeWidgetTask->selectedItems(); // »ñÈ¡¶¥²ã + QTreeWidgetItem* imageNode = selectNodes.at(0); + imageNode->data(0, Qt::UserRole).value()->ExcuteTask(); +} + +void ModelProcess::addTaskNode(TaskNode* Node) +{ + // ÍùqtTree Ìí¼Ó½Úµã + QTreeWidgetItem* topNode = this->ui.treeWidgetTask->topLevelItem(0); // »ñÈ¡¶¥²ã + QTreeWidgetItem* imageSetNode = new QTreeWidgetItem(); + imageSetNode->setText(0, Node->getTaskName()); + imageSetNode->setData(0, Qt::UserRole, QVariant::fromValue(Node)); + topNode->addChild(imageSetNode); +} + +void ModelProcess::removeTaskNode(TaskNode* Node) +{ + + + + +} + + +bool ModelProcess::showConntentsWindows() +{ + qDebug() << u8"showConntentsWindows\n"; + if (this->dockWidget) { + + } + else { + this->dockWidget = new QDockWidget(this); + this->dockWidget->setObjectName(QString::fromUtf8("dockWidget")); + this->dockWidget->setWindowTitle(QString::fromUtf8(u8"Ä£ÐÍ´°¿ÚÁбí")); + } + if (this->dockWidgetContents) { + + } + else { + this->dockWidgetContents = new QWidget(); + this->dockWidgetContents->setObjectName(QString::fromUtf8("dockWidgetContents")); + this->dockWidgetContents->setWindowTitle(QString::fromUtf8(u8"Ä£ÐÍÏêϸÁбí")); + } + + verticalLayout = new QVBoxLayout(this->dockWidgetContents); + verticalLayout->setSpacing(6); + verticalLayout->setContentsMargins(11, 11, 11, 11); + verticalLayout->setObjectName(QString::fromUtf8("verticalLayout")); + dockWidget->setWidget(this->dockWidgetContents); + this->addDockWidget(Qt::LeftDockWidgetArea, dockWidget); + + return true; +} + +bool ModelProcess::showModelInfoWindows() +{ + qDebug() << u8"showModelInfoWindows\n"; + if (this->dockWidget_modelinfoshow) { + + } + else { + + dockWidget_modelinfoshow = new QDockWidget(this); + dockWidget_modelinfoshow->setObjectName(QString::fromUtf8("dockWidget_modelinfoshow")); + } + if (this->dockWidget_ModelInfoShowWindows) { + + } + else { + dockWidget_ModelInfoShowWindows = new QWidget(); + dockWidget_ModelInfoShowWindows->setObjectName(QString::fromUtf8("dockWidget_ModelInfoShowWindows")); + } + verticalLayout_ModelInfoShowWindows = new QVBoxLayout(dockWidget_ModelInfoShowWindows); + verticalLayout_ModelInfoShowWindows->setSpacing(6); + verticalLayout_ModelInfoShowWindows->setContentsMargins(11, 11, 11, 11); + verticalLayout_ModelInfoShowWindows->setObjectName(QString::fromUtf8("verticalLayout_2")); + dockWidget_modelinfoshow->setWidget(dockWidget_ModelInfoShowWindows); + this->addDockWidget(Qt::RightDockWidgetArea, this->dockWidget_modelinfoshow); + return true; +} + +bool ModelProcess::showInnerModelWindow() +{ + qDebug() << u8"showInnerModelWindow\n"; + if(this->dockWidget_InnerModel){} + else { + dockWidget_InnerModel = new QDockWidget(this); + dockWidget_InnerModel->setObjectName(QString::fromUtf8("dockWidget_InnerModel")); + } + if (this->dockWidget_InnerModelWindows) { + + } + else { + dockWidget_InnerModelWindows = new QWidget(); + dockWidget_InnerModelWindows->setObjectName(QString::fromUtf8("dockWidget_InnerModelWindows")); + } + this->dockWidget_InnerModel->setWindowTitle(u8"ÄÚÖÃģʽ¿â"); + verticalLayout_ModelInfoShowWindows = new QVBoxLayout(dockWidget_InnerModelWindows); + verticalLayout_ModelInfoShowWindows->setSpacing(6); + verticalLayout_ModelInfoShowWindows->setContentsMargins(11, 11, 11, 11); + verticalLayout_ModelInfoShowWindows->setObjectName(QString::fromUtf8("verticalLayout_3")); + dockWidget_InnerModel->setWidget(dockWidget_InnerModelWindows); + this->addDockWidget(Qt::RightDockWidgetArea, dockWidget_InnerModel); + return true; +} + +void ModelProcess::actionOpenRaster() +{ + QString filename = getOpenFilePath(this, u8"´ò¿ªÓ°ÏñÎļþ",u8"ENVI Data (*.dat);;tiff (*.tif);;"); + // ÅжÏÊÇ·ñΪ¸´Êý¶ÔÏó£¿ + qDebug() << filename; + QFileInfo fileinfo(filename); + qDebug() << fileinfo.fileName(); + GDALDataType dataType = getGDALDataType(filename); + if (dataType == GDT_CFloat32 || dataType == GDT_CFloat64) { + ComplexDataShowNode* node = new ComplexDataShowNode(this); + node->bangdindWindows(this); + node->OpenData(filename); + this->myDocument3d->addTaskNode(node); + } + else { + DataShowNode* node = new DataShowNode(this); + node->bangdindWindows(this); + node->OpenData(filename); + this->myDocument3d->addTaskNode(node); + } +} + +void ModelProcess::actionOpenModel() +{ + QString stlpath = getOpenFilePath( + this, + QString::fromUtf8(u8"µ¼ÈëÄ£ÐÍ"), + QString::fromUtf8(u8"STL Files (*.stl);;STL Files (*.stla);;step Files (*.stp);;step Files (*.step);;IGES Files (*.iges);;IGES Files (*.igs)")); + OCCTShapeModelNode* node = new OCCTShapeModelNode(this); + node->setDataFile(stlpath); + this->myDocument3d->addTaskNode(node); +} + +bool ModelProcess::initFileOperatorMenu() +{ + QAction* action_OpenFileRaster=this->ui.menu_FileOpenOperator->addAction(u8"´ò¿ªÓ°Ïñ"); + QObject::connect(action_OpenFileRaster, SIGNAL(triggered()), this, SLOT(actionOpenRaster())); + QAction* action_OpenModelStl = this->ui.menu_FileOpenOperator->addAction(u8"´ò¿ªÄ£ÐÍ"); + QObject::connect(action_OpenModelStl, SIGNAL(triggered()), this, SLOT(actionOpenModel())); + + + return false; +} + +bool ModelProcess::initConstVariable() +{ + // Ä£ÐÍÏà¹Ø½çÃæ + this->dockWidget = nullptr; + this->dockWidgetContents = nullptr; + this->verticalLayout = nullptr; + this->dockWidget_modelinfoshow = nullptr; + this->dockWidget_ModelInfoShowWindows = nullptr; + this->verticalLayout_ModelInfoShowWindows = nullptr; + this->dockWidget_InnerModel = nullptr; + this->dockWidget_InnerModelWindows = nullptr; + this->verticalLayout_InnerModelWindows = nullptr; + this->myDocument3d = nullptr; + this->selectModeMenu = nullptr; // Ñ¡ÔñģʽÇл» + this->showModelMenu = nullptr; + this->myGeomWidget = nullptr; // Ä£ÐÍäÖȾ´®¿Ú + this->TopoShapeTreeViewer = nullptr; + return true; +} + +bool ModelProcess::initOCCTView() +{ + // ³õʼ»¯ OCCT + if (this->myDocument3d) { + + } + else { + this->myDocument3d = new DocumentCommon(this); // 3D Ä£ÐÍ + + } + this->verticalLayout->addWidget(this->myDocument3d); + QVBoxLayout* aViewLayout = new QVBoxLayout(this->ui.OCCViewGLWidget); + aViewLayout->setContentsMargins(0, 0, 0, 0); + this->myGeomWidget = new GeomWidget(myDocument3d, this->ui.OCCViewGLWidget);// ´´½¨Ò»¸öÈýάÏÔʾ¶ÔÏó + aViewLayout->addWidget(this->myGeomWidget); + this->myGeomWidget->setContentsMargins(0, 0, 0, 0); + this->myDocument3d->InitAixs(); // ¼ÆËãÈýÎ¬×ø±êÖá + this->myGeomWidget->FitAll(); + + return true; +} + +void ModelProcess::on_action_FEKO2csv_triggered() { + + qDebug() << u8"Æô¶¯FEKO->csv Îļþ \n"; + QString xmlfilepath = getSaveFilePath(this, QString::fromUtf8(u8"ÉèÖÃFEKO½á¹ûµ¼ÈëÈÎÎñxml"), QString::fromUtf8(u8"xmlÎļþ (*.xml)")); + qDebug() << u8"Ñ¡Ôñ xmlfile Îļþ·¾¶£º\t " + xmlfilepath + u8"\n" ; + FEKOResultImportTaskNode* fekoresulttask = new FEKOResultImportTaskNode(); + fekoresulttask->loadXmlFile(xmlfilepath); + fekoresulttask->ExcuteTask(); + return; +} + +// ³õʼ»¯¶ÔÏóÊý¾Ý +bool ModelProcess::initSelectModeMenu() +{ + this->selectModeMenu = new QMenu(u8"Ä£ÐÍÑ¡Ôñģʽ",this); + QAction* actiion_VerticesSelect3dSample = this->selectModeMenu->addAction(u8"Ñ¡Ôñ¶¥µã"); + QObject::connect(actiion_VerticesSelect3dSample, SIGNAL(triggered()), this->myDocument3d, SLOT(VerticesSelect3dSample())); + + QAction* actiion_EdgesSelect3dSample = this->selectModeMenu->addAction(u8"Ñ¡Ôñ±ß"); + QObject::connect(actiion_EdgesSelect3dSample, SIGNAL(triggered()), this->myDocument3d, SLOT(EdgesSelect3dSample())); + + QAction* actiion_FacesSelect3dSample = this->selectModeMenu->addAction(u8"Ñ¡ÔñÃæ"); + QObject::connect(actiion_FacesSelect3dSample, SIGNAL(triggered()), this->myDocument3d, SLOT(FacesSelect3dSample())); + + QAction* actiion_NeutralPointSelect3dSample = this->selectModeMenu->addAction(u8"Ä£ÐÍÕûÌåÑ¡Ôñ"); + QObject::connect(actiion_NeutralPointSelect3dSample, SIGNAL(triggered()), this->myDocument3d, SLOT(NeutralPointSelect3dSample())); + + return true; +} + +bool ModelProcess::initGeometryShowModelMenu() +{ + this->showModelMenu = new QMenu(u8"ÊÓͼÏÔʾģʽ"); + QAction* actiion_ShowHideMehsGrid = this->showModelMenu->addAction(u8"ÏÔʾ/¹Ø±ÕÆ½ÃæÍø¸ñ"); + QObject::connect(actiion_ShowHideMehsGrid, SIGNAL(triggered()), this->myDocument3d, SLOT(ShowOrHideActivateGridMesh())); + + QAction* actiion_ShowHideAixesGrid = this->showModelMenu->addAction(u8"ÏÔʾ/¹Ø±ÕÁ¢·½Íø¸ñ"); + QObject::connect(actiion_ShowHideMehsGrid, SIGNAL(triggered()), this->myDocument3d, SLOT(ShowOrHideActivateAxisGris())); + + + return true; +} + +bool ModelProcess::initModelInformationShow() +{ + + if (this->TopoShapeTreeViewer) { + + } + else { + this->TopoShapeTreeViewer = new OCCTopoShapeTreeViewer(this); // 3D Ä£ÐÍ + } + this->verticalLayout_ModelInfoShowWindows->addWidget(this->TopoShapeTreeViewer); + this->myDocument3d->setShapeInfomationWindows(this->TopoShapeTreeViewer); + + + return true; +} + +bool ModelProcess::initMenuList() +{ + + + + this->initSelectModeMenu(); + this->initGeometryShowModelMenu(); + this->ui.menu_modelOperator->addMenu(this->selectModeMenu); + this->ui.menu_modelOperator->addMenu(this->showModelMenu); + + return true; +} + +bool ModelProcess::initBandingEvent() +{ + QObject::connect(this->myDocument3d, SIGNAL(ShowSelectItemFullExtend(const TopoDS_Shape &)), this->myGeomWidget, SLOT(ShowExtend(const TopoDS_Shape & ))); + return true; +} + +bool ModelProcess::initTaskDocker() +{ + this->ui.dockWidget_Task->setHidden(false); + this->ui.dockWidget_Task->setWindowTitle(QString::fromUtf8(u8"ÈÎÎñÁбí")); + // ³õʼ»¯ÈÎÎñÁбí + // this->ui.treeWidgetTask->setColumnCount(0); + QStringList headerLabels; + headerLabels <ui.treeWidgetTask->setHeaderLabels(headerLabels); + QTreeWidgetItem* topNode = this->ui.treeWidgetTask->topLevelItem(0); // »ñÈ¡¶¥²ã + if (topNode) { + topNode->setText(0, u8"³ÉÏñÈÎÎñ"); + } + else { + this->ui.treeWidgetTask->insertTopLevelItem(0, new QTreeWidgetItem(this->ui.treeWidgetTask, QStringList(u8"ÈÎÎñ"))); + } + + + this->ui.treeWidgetTask->setContextMenuPolicy(Qt::CustomContextMenu); + + this->TaskListContextMenu = new QMenu(this->ui.treeWidgetTask); + QAction* openTaskNodeAction = this->TaskListContextMenu->addAction(u8"´ò¿ª"); // + QObject::connect(openTaskNodeAction, SIGNAL(triggered()), this, SLOT(ShowTaskWindows())); + + QObject::connect(this->ui.treeWidgetTask, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(ShowTaskListMenu(QPoint))); + + return false; +} + + +QDockWidget* ModelProcess::getdockWidget_command(QString dockerTitle,Qt::DockWidgetArea layoutear) +{ + QDockWidget* dockWidget_command = new QDockWidget(this); + dockWidget_command->setObjectName(dockerTitle); + dockWidget_command->setWindowTitle(dockerTitle); + this->addDockWidget(layoutear, dockWidget_command); + return dockWidget_command; +} + + +/////////////////////////////////////////////////////// +// ModelProcess ³£¼ûÃüÁî +////////////////////////////////////////////////////// + + +QString ModelProcess::moveTopoShape(QString toponame, QString move_x, QString move_y, QString move_z) +{ + // OCCTObjectCheckBox* topoShapeItem = this->getTopoShapeItem(toponame); + + return QString(); +} + + +bool ModelProcess::ShowTopoShape(TopoDS_Shape topoShape, QString topoName, bool isShow) +{ + this->myDocument3d->addOCCTObjItem(topoShape, topoName, isShow); + return true; +} + +bool ModelProcess::removeShape(QString topoName) +{ + this->myDocument3d->removeTaskNode(topoName); + return false; +} + +QString ModelProcess::createBox(QString topoName,double dx,double dy,double dz,double angle) +{ + TopoDS_Shape S = BRepPrimAPI_MakeBox(dx, dy, dz); + BRepOffsetAPI_DraftAngle adraft(S); + TopExp_Explorer Ex; + for (Ex.Init(S, TopAbs_FACE); Ex.More(); Ex.Next()) { + TopoDS_Face F = TopoDS::Face(Ex.Current()); + Handle(Geom_Plane) surf = Handle(Geom_Plane)::DownCast(BRep_Tool::Surface(F)); + gp_Pln apln = surf->Pln(); + gp_Dir dirF = apln.Axis().Direction(); + if (dirF.IsNormal(gp_Dir(0., 0., 1.), Precision::Angular())) + adraft.Add(F, gp_Dir(0., 0., 1.), angle * M_PI / 180, gp_Pln(gp::XOY())); + } + TopoDS_Shape resultShape = adraft.Shape(); + this->myDocument3d->addOCCTObjItem(resultShape, topoName, true); + + return topoName; +} + \ No newline at end of file diff --git a/src/WBCLFZSystemModule/modelProcess/ModelProcess.h b/src/WBCLFZSystemModule/modelProcess/ModelProcess.h new file mode 100644 index 0000000..2765d89 --- /dev/null +++ b/src/WBCLFZSystemModule/modelProcess/ModelProcess.h @@ -0,0 +1,114 @@ +#pragma once +#ifndef MODELPROCESS_H +#define MODELPROCESS_H + +#include "AllHead.h" +#include +#include "OCCViewer\DocumentCommon.h" +#include "OCCViewer\GeomWidget.h" +#include "ui_ModelProcess.h" +#include "OCCTopoShapeTreeViewer.h" +#include "QtSARAntModelSetting.h" +#include "EchoShowProcess/EchoTableEditWindow.h" +#include "LAMPImageCreateClass.h" +#include "LAMP_ScatterSettingClass.h" +#include "LAMPDataShowClass.h" + + +class ModelProcess : public QMainWindow +{ + Q_OBJECT + +public: + Q_INVOKABLE ModelProcess(QWidget *parent = nullptr); + ~ModelProcess(); + +private: + Ui::ModelProcessClass ui; +public: + QMenu* TaskListContextMenu; + +public slots: // ²Ëµ¥Ê¼þ + void on_action_FEKO2csv_triggered(); + void on_action_Open_triggered(); + void on_action_Modelsave_triggered(); + void on_actionCalibrationConstCreate_triggered(); // ´´½¨¶¨±ê³£Êý + void on_actionImageSetting_triggered(); + void on_action_ScatterExport_triggered(); + void on_actionFEKOImage_triggered(); + void on_action_antScatteringFEKOSetting_triggered(); + void on_action_openImageShowWindows_triggered(); // ͼÏñչʾģ¿é + void ShowTaskListMenu(QPoint p); + void ShowTaskWindows(); + +public slots: // ÈÎÎñ¹ÜÀíÆ÷ + void addTaskNode(TaskNode* Node); + void removeTaskNode(TaskNode* Node); + +//////////////////////////////////////////////////////////// +// Ä£ÐͲÙ×÷¹¦ÄÜ +//////////////////////////////////////////////////////////// +public: + DocumentCommon* myDocument3d; // Ä£Ð͹ÜÀí + GeomWidget* myGeomWidget; // Ä£ÐÍäÖȾ´®¿Ú + OCCTopoShapeTreeViewer* TopoShapeTreeViewer; + QMenu* selectModeMenu; // Ñ¡ÔñģʽÇл» + QMenu* showModelMenu; + + // Ä£ÐÍÏà¹Ø½çÃæ + QDockWidget* dockWidget=nullptr; + QWidget* dockWidgetContents = nullptr; + QVBoxLayout* verticalLayout = nullptr; + QDockWidget* dockWidget_modelinfoshow = nullptr; + QWidget* dockWidget_ModelInfoShowWindows = nullptr; + QVBoxLayout* verticalLayout_ModelInfoShowWindows = nullptr; + QDockWidget* dockWidget_InnerModel = nullptr; + QWidget* dockWidget_InnerModelWindows = nullptr; + QVBoxLayout* verticalLayout_InnerModelWindows = nullptr; + + +public slots: + bool showConntentsWindows(); + bool showModelInfoWindows(); + bool showInnerModelWindow(); + + // Îļþ²Ù×÷Àà + void actionOpenRaster(); + void actionOpenModel(); + + + +public: + bool initFileOperatorMenu(); + bool initConstVariable(); + bool initOCCTView(); + bool initSelectModeMenu(); + bool initGeometryShowModelMenu(); + bool initModelInformationShow(); + bool initMenuList(); + bool initBandingEvent(); + bool initTaskDocker(); + + +public: + QDockWidget* getdockWidget_command(QString dockerTitle, Qt::DockWidgetArea layoutear= Qt::BottomDockWidgetArea); + +signals: + void OpenCommandWidget(ModelProcess* modelprocess); + +public slots: // Q_INVOKABLE ¶¨Òå js ²Ù×÷º¯Êý + QString moveTopoShape(QString toponame,QString move_x,QString move_y,QString move_z); + bool ShowTopoShape(TopoDS_Shape topoShape, QString topoName, bool isShow = true); // ÏÔʾģÐÍ + bool removeShape(QString topoName); // ɾ³ýÄ£ÐÍ + QString createBox(QString topoName, double dx, double dy, double dz, double angle); // ²âÊÔÄ£ÐÍ + + + + +// -------------------------------------------------------------- + + +}; + + +#endif diff --git a/src/WBCLFZSystemModule/modelProcess/ModelProcess.ui b/src/WBCLFZSystemModule/modelProcess/ModelProcess.ui new file mode 100644 index 0000000..186da72 --- /dev/null +++ b/src/WBCLFZSystemModule/modelProcess/ModelProcess.ui @@ -0,0 +1,490 @@ + + + ModelProcessClass + + + + 0 + 0 + 967 + 602 + + + + æ¨¡åž‹å¤„ç†æ¨¡å— + + + + + + + QTabWidget::South + + + 0 + + + + ä¸‰ç»´æ¨¡åž‹çª—å£ + + + + + + + + + + + + + + + 0 + 0 + 967 + 22 + + + + + 文件 + + + + 打开 + + + + + + + + + å±žæ€§æ•°æ® + + + + 加载属性数æ®è¡¨ + + + + + + + + + æ¨¡åž‹çª—å£æ“作 + + + + + ä»¿çœŸå‚æ•°è®¾ç½® + + + + 模型导出 + + + + + + + + + FEKO仿真设置 + + + + + + + + + + + çª—å£ + + + + + + + + 图åƒå¤„ç† + + + + + + + + + + + + + + TopToolBarArea + + + false + + + + + + 任务列表 + + + 2 + + + + + + + false + + + + 任务 + + + + + + + + + + ä¿å­˜ + + + + + å¦å­˜ä¸º + + + + + é€‰æ‹©é¢ + + + + + action_selectPoint + + + + + 选择点 + + + + + 编辑 + + + + + åˆ é™¤é¢ + + + + + 删除点 + + + + + 添加点 + + + + + ä¿®æ”¹é¢ + + + + + 修改点 + + + + + 添加线 + + + + + æ·»åŠ é¢ + + + + + 删除线 + + + + + 选择线 + + + + + è‡ªç›¸äº¤é¢æ£€æŸ¥ + + + + + 三角é¢ç‰‡æœ€å°è§’检查 + + + + + 自相交é¢åˆ†å‰² + + + + + è·ç¦»å‘分辨率 + + + + + æ–¹ä½å‘分辨率 + + + + + 全散射装置模å¼å‚数设置 + + + + + æ¡å¸¦æ¨¡å¼å‚数设置 + + + + + ISAR模å¼å‚数设置 + + + + + 圆迹SAR模å¼å‚数仿真 + + + + + æ‰«ææ¨¡å¼å‚数仿真 + + + + + 模型转stl + + + + + æ¨¡åž‹å‚æ•°å¯¼å‡º + + + + + 脉冲åŽå‘散射系数导出 + + + + + æ¡å¸¦æ¨¡å¼æˆåƒ + + + + + æ‰«ææ¨¡å¼æˆåƒ + + + + + ISARæ¨¡å¼æˆåƒ + + + + + 圆迹SARæˆåƒ + + + + + FEKO->csv + + + + + _csv + + + + + csv->echoBin + + + + + FEKOå›žæ³¢è½¬æ¢ + + + + + _selectPoint + + + + + Vertices + + + + + _selectVertices + + + + + _selectEdges + + + + + _selectFaces + + + + + 显示模型列表 + + + + + 显示内置模型列表 + + + + + æ˜¾ç¤ºæ¨¡åž‹ä¿¡æ¯ + + + + + æˆåƒè®¾ç½® + + + + + æˆåƒ + + + + + 散射测é‡è£…ç½®FEKOä»¿çœŸå‚æ•°è®¾ç½® + + + + + å¯åЍ图åƒå±•示工具 + + + QAction::NormalPriority + + + + + _OpenRaster + + + + + _Open3DModel + + + + + + + + + + action_FEKO2csv + triggered() + ModelProcessClass + on_action_FEKO2csv_trigged() + + + -1 + -1 + + + 487 + 339 + + + + + action_showContextListWindows + triggered() + ModelProcessClass + showConntentsWindows() + + + -1 + -1 + + + 484 + 304 + + + + + action_showTopoShapeInfoWindows + triggered() + ModelProcessClass + showModelInfoWindows() + + + -1 + -1 + + + 484 + 304 + + + + + action_showInnerModelWindows + triggered() + ModelProcessClass + showInnerModelWindow() + + + -1 + -1 + + + 484 + 304 + + + + + + on_action_FEKO2csv_trigged() + on_action_Open_trigged() + showConntentsWindows() + showModelInfoWindows() + showInnerModelWindow() + + diff --git a/src/WBCLFZSystemModule/qconsolewidget.pri b/src/WBCLFZSystemModule/qconsolewidget.pri new file mode 100644 index 0000000..d45e11c --- /dev/null +++ b/src/WBCLFZSystemModule/qconsolewidget.pri @@ -0,0 +1,13 @@ +INCLUDEPATH += $$PWD +DEPENDPATH += $$PWD + + +SOURCES += $$PWD/QConsoleWidget.cpp \ + $$PWD/QConsoleIODevice.cpp + +HEADERS += $$PWD/QConsoleWidget.h \ + $$PWD/QConsoleIODevice.h + + + + diff --git a/src/WBCLFZSystemModule/qscriptcompleter.cpp b/src/WBCLFZSystemModule/qscriptcompleter.cpp new file mode 100644 index 0000000..0a50842 --- /dev/null +++ b/src/WBCLFZSystemModule/qscriptcompleter.cpp @@ -0,0 +1,193 @@ +#include "qscriptcompleter.h" + +#include +#include +#include //#include + +#include +#include + +QScriptCompleter::QScriptCompleter() +{ + // https://developer.mozilla.org/en/JavaScript/Reference/Reserved_Words + js_keywords_ << "break"; + js_keywords_ << "case"; + js_keywords_ << "catch"; + js_keywords_ << "continue"; + js_keywords_ << "default"; + js_keywords_ << "delete"; + js_keywords_ << "do"; + js_keywords_ << "else"; + js_keywords_ << "finally"; + js_keywords_ << "for"; + js_keywords_ << "function"; + js_keywords_ << "if"; + js_keywords_ << "in"; + js_keywords_ << "instanceof"; + js_keywords_ << "new"; + js_keywords_ << "return"; + js_keywords_ << "switch"; + js_keywords_ << "this"; + js_keywords_ << "throw"; + js_keywords_ << "try"; + js_keywords_ << "typeof"; + js_keywords_ << "var"; + js_keywords_ << "void"; + js_keywords_ << "while"; + js_keywords_ << "with"; + + js_keywords_ << "true"; + js_keywords_ << "false"; + js_keywords_ << "null"; + +} + +int QScriptCompleter::updateCompletionModel(const QString& code) +{ + // Start by clearing the model + this->setModel(0); + + // Don't try to complete the empty string + if (code.isEmpty()) + { + return 0; + } + + // Search backward through the string for usable characters + QString textToComplete; + for(int i=code.length()-1; i>=0; i--) + { + QChar c = code.at(i); + if (c.isLetterOrNumber() || c == '.' || c == '_') + { + textToComplete.prepend(c); + insert_pos_ = i; + } + else + { + break; + } + } + + // Split the string at the last dot, if one exists + QString lookup; + QString compareText = textToComplete; + int dot = compareText.lastIndexOf('.'); + if (dot != -1) + { + lookup = compareText.mid(0, dot); + compareText = compareText.mid(dot + 1); + insert_pos_ += (dot+1); + } + + // Lookup QtScript names + QStringList found; + if (!lookup.isEmpty() || !compareText.isEmpty()) + { + compareText = compareText.toLower(); + QStringList l = introspection(lookup); + foreach (QString n, l) + if (n.toLower().startsWith(compareText)) found << n; + } + + /* + qDebug() << "lookup : " << lookup; + qDebug() << "compareText : " << compareText; + qDebug() << "insert pos : " << insert_pos_; + qDebug() << "found : " << found.size(); + */ + + // Initialize the completion model + if (!found.isEmpty()) + { + setCompletionMode(QCompleter::PopupCompletion); + setModel(new QStringListModel(found, this)); + setCaseSensitivity(Qt::CaseInsensitive); + setCompletionPrefix(compareText.toLower()); + //if (popup()) + //popup()->setCurrentIndex(completionModel()->index(0, 0)); + } + + return found.size(); +} + +QStringList QScriptCompleter::introspection(const QString &lookup) +{ + // list of found tokens + QStringList properties, children, functions; + + if (!eng) return properties; + + //QScriptValue scriptObj; + QJSValue scriptObj; + if (lookup.isEmpty()) { + properties = js_keywords_; + scriptObj = eng->globalObject(); + } + else { + scriptObj = eng->evaluate(lookup); + // if the engine cannot recognize the variable return + if (scriptObj.isError()) return properties; + } + + // if a QObject add the named children + if (scriptObj.isQObject()) + { + QObject* obj = scriptObj.toQObject(); + + foreach(QObject* ch, obj->children()) + { + QString name = ch->objectName(); + if (!name.isEmpty()) + children << name; + } + + } + + // add the script properties + { + // QScriptValue obj(scriptObj); // the object to iterate over + QJSValue obj = scriptObj; + while (obj.isObject()) { + QJSValueIterator it(obj); + while (it.hasNext()) { + it.next(); + + + + // avoid array indices + //bool isIdx; + //it.scriptName().toArrayIndex(&isIdx); + //if (it.value().isArray()) continue; + + QString propertyName = it.name(); + bool isIdx; + int index = propertyName.toInt(&isIdx); + if (isIdx && index >= 0) continue; + + + // avoid "hidden" properties starting with "__" + if (it.name().startsWith("__")) continue; + + // include in list + if (it.value().isQObject()) children << it.name(); + else if (it.value().isCallable()) functions << it.name(); + else properties << it.name(); + } + obj = obj.prototype(); + } + } + + children.removeDuplicates(); + children.sort(Qt::CaseInsensitive); + functions.removeDuplicates(); + functions.sort(Qt::CaseInsensitive); + properties.removeDuplicates(); + properties.sort(Qt::CaseInsensitive); + + children.append(properties); + children.append(functions); + + return children; + +} diff --git a/src/WBCLFZSystemModule/qscriptcompleter.h b/src/WBCLFZSystemModule/qscriptcompleter.h new file mode 100644 index 0000000..4f3b2b7 --- /dev/null +++ b/src/WBCLFZSystemModule/qscriptcompleter.h @@ -0,0 +1,26 @@ +#ifndef QSCRIPTCOMPLETER_H +#define QSCRIPTCOMPLETER_H + +#include "QConsoleWidget.h" + +class QScriptEngine; + +class QScriptCompleter : public QConsoleWidgetCompleter +{ +public: + QScriptCompleter(); + int updateCompletionModel(const QString& code) override; + int insertPos() override + { return insert_pos_; } + + void seScripttEngine(QJSEngine* e) + { eng = e; } + +private: + QStringList introspection(const QString& lookup); + QJSEngine* eng; + QStringList js_keywords_; + int insert_pos_; +}; + +#endif // QSCRIPTCOMPLETER_H diff --git a/src/WBCLFZSystemModule/readme.md b/src/WBCLFZSystemModule/readme.md new file mode 100644 index 0000000..23a2c9f --- /dev/null +++ b/src/WBCLFZSystemModule/readme.md @@ -0,0 +1,64 @@ +# 功能模å—大类 +| 文件夹åç§° | 模å—åç§° | 测试控件åç§° | +|:--------| :---------:|--------:| +|PointProcess |1.ç‚¹äº‘å¤„ç† | pushButton_PointCloud | +|TableProcess |1.表格编辑 | pushButton_TableProcesss | +|modelProcess |2.æ¨¡åž‹å¤„ç† | pushButton_ModelProcess | +|EchoShowProcess |3.回波图åƒå±•示 | pushButton_EchoProcess | + + + +# 模å—与文件结构 +## 1. ä»»åŠ¡å¤„ç†æ¨¡å— + + +## 1. 点云处ç†ç•Œé¢ + + + +## 1. è¡¨æ ¼ç¼–è¾‘æ¨¡å— + + + +## 2. æ¨¡åž‹å¤„ç†æ¨¡å— + + +## 3. 回波图åƒå±•ç¤ºæ¨¡å— + + + + + + + + + +森林目标 +农作物目标 +è‰åœ°ç›®æ ‡ +水体目标 +土壤目标 +åŠ¨æ€æ°´ä½“目标 +é“路目标 +人工目标 +几何校正场景 +è¾å°„校正场景 +陆表场景 +水体场景 +æ¤è¢«åœºæ™¯ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/WBCLFZSystemModule/resource.h b/src/WBCLFZSystemModule/resource.h new file mode 100644 index 0000000..06d22ca --- /dev/null +++ b/src/WBCLFZSystemModule/resource.h @@ -0,0 +1,14 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by WBCLFZSystemModule.rc + +// жÔÏóµÄÏÂÒ»×éĬÈÏÖµ +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 101 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/src/WBCLFZSystemModule/scriptsession.cpp b/src/WBCLFZSystemModule/scriptsession.cpp new file mode 100644 index 0000000..7553e5b --- /dev/null +++ b/src/WBCLFZSystemModule/scriptsession.cpp @@ -0,0 +1,132 @@ +#include "scriptsession.h" +#include "QConsoleWidget.h" +#include "qscriptcompleter.h" + +#include +#include +#include + +#include + + +#include +#include +#include + + +ScriptSession::ScriptSession(QConsoleWidget *aw) : QObject(), w(aw) +{ + // Create script engine and add extra functions + e = new QJSEngine(this); + e->installExtensions(QJSEngine::AllExtensions); // °²ÑbËùÓеÄÀ©Õ¹ + + // write preample + w->writeStdOut( + "LAMP Command Console :" + " interactive qscript interpreter\n\n" + "Ctrl-Q aborts a qscript evaluation\n\n" + ); + + // Set the completer + QScriptCompleter* c = new QScriptCompleter; + c->seScripttEngine(e); + w->setCompleter(c); + // A "." triggers the completer + QStringList tr; + tr << "."; + w->setCompletionTriggers(tr); + + // init the internal timer for tic()/toc() + tmr_ = new QElapsedTimer(); + +} + +void ScriptSession::tic() +{ + tmr_->start(); +} +qreal ScriptSession::toc() +{ + return 1.e-6*tmr_->nsecsElapsed(); +} + +void ScriptSession::quit() +{ + w->device()->close(); +} + + + +void ScriptSession::settingApplication(QObject* object) +{ + + QJSValue* app = new QJSValue(e->newQObject(object)); + QJSValue global = e->globalObject(); + global.setProperty("app", *app); +} + +void ScriptSession::addJsObeject(const QString& objname, QObject* obj) +{ + + QJSValue* jsobj = new QJSValue(e->newQObject(obj)); + QJSValue global = e->globalObject(); + global.setProperty(objname, *jsobj); + +} + +void ScriptSession::abortEvaluation() +{ + +} + +void ScriptSession::REPL() +{ + QIODevice* d = w->device(); + QTextStream ws(d); + QString multilineCode; + + while(ws.device()->isOpen()) { + + ws << (multilineCode.isEmpty() ? "js> " : "....> ") << flush; + + ws >> inputMode >> waitForInput; + + multilineCode += ws.readAll(); + + if (!multilineCode.isEmpty()) + { + QJSValue res = e->evaluate(multilineCode); + multilineCode = ""; + + // ²âÊÔÊä³ö + qDebug() << "res.isError()" << res.isError(); + qDebug() << "res.isUndefined()" << res.isUndefined(); + qDebug() << "res.isNull()" << res.isNull(); + qDebug() << "res: " << res.toString(); + + if (res.isError()) + { + ws << errChannel; + if (!res.isUndefined()) ws << res.toString(); + ws << endl; + ws << res.property("stack").toString() << endl; + ws << outChannel; + } + else if (!res.isNull()) + { + ws << res.toString() << endl; + } + else if(res.isUndefined()) { + ws << u8"undefined" << endl; + } + else if (res.isNull()) { + ws << u8"null" << endl; + } + } + } + +} + + + + diff --git a/src/WBCLFZSystemModule/scriptsession.h b/src/WBCLFZSystemModule/scriptsession.h new file mode 100644 index 0000000..96dcd92 --- /dev/null +++ b/src/WBCLFZSystemModule/scriptsession.h @@ -0,0 +1,53 @@ +#ifndef SCRIPTSESSION_H +#define SCRIPTSESSION_H +#include "AllHead.h" +#include +#include + +class QElapsedTimer; +class QJSEngine; +class QConsoleWidget; + +class ScriptSession : public QObject +{ + Q_OBJECT +public: + explicit ScriptSession(QConsoleWidget *w); + + QConsoleWidget* widget() { return w; } + + + void tic(); + qreal toc(); + +public slots: + void REPL(); + void quit(); + +private slots: + void abortEvaluation(); + +private: + QConsoleWidget* w; + QJSEngine* e; + QElapsedTimer* tmr_; + + + + + +//-- ¹¹½¨ÔªËØ°ó¶¨ ------------------------- +public: + + void settingApplication(QObject* object); + void addJsObeject(const QString& objname, QObject* obj); + + +//--------------------------- + + + + +}; + +#endif // SCRIPTSESSION_H diff --git a/src/json/CMakeLists.txt b/src/json/CMakeLists.txt new file mode 100644 index 0000000..92418ce --- /dev/null +++ b/src/json/CMakeLists.txt @@ -0,0 +1,30 @@ +#----------------------------------------------------------------------------- +# 头文件æœç´¢è·¯å¾„ +#----------------------------------------------------------------------------- +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/..) + +#----------------------------------------------------------------------------- +# 自动添加include目录 +#----------------------------------------------------------------------------- +set(CMAKE_INCLUDE_CURRENT_DIR ON) + +#----------------------------------------------------------------------------- +# æºç æ‰«æ +#----------------------------------------------------------------------------- +file(GLOB _ui "*.ui") +file(GLOB _header "*.h*") +file(GLOB _source "*.cpp") +qt5_wrap_ui(_interface ${_ui}) + +#----------------------------------------------------------------------------- +# 添加动æ€åº“目标 +#----------------------------------------------------------------------------- +add_library(json + ${_resource} + ${_interface} + ${_header} + ${_source} +) + + +target_include_directories(json PRIVATE ${Qwt_INCLUDE_DIRS}) \ No newline at end of file diff --git a/src/json/json.hpp b/src/json/json.hpp new file mode 100644 index 0000000..d5361c7 --- /dev/null +++ b/src/json/json.hpp @@ -0,0 +1,22875 @@ +/* + __ _____ _____ _____ + __| | __| | | | JSON for Modern C++ +| | |__ | | | | | | version 3.7.3 +|_____|_____|_____|_|___| https://github.com/nlohmann/json + +Licensed under the MIT License . +SPDX-License-Identifier: MIT +Copyright (c) 2013-2019 Niels Lohmann . + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +#ifndef INCLUDE_NLOHMANN_JSON_HPP_ +#define INCLUDE_NLOHMANN_JSON_HPP_ + +#define NLOHMANN_JSON_VERSION_MAJOR 3 +#define NLOHMANN_JSON_VERSION_MINOR 7 +#define NLOHMANN_JSON_VERSION_PATCH 3 + +#include // all_of, find, for_each +#include // assert +#include // and, not, or +#include // nullptr_t, ptrdiff_t, size_t +#include // hash, less +#include // initializer_list +#include // istream, ostream +#include // random_access_iterator_tag +#include // unique_ptr +#include // accumulate +#include // string, stoi, to_string +#include // declval, forward, move, pair, swap +#include // vector + +// #include + + +#include + +// #include + + +#include // transform +#include // array +#include // and, not +#include // forward_list +#include // inserter, front_inserter, end +#include // map +#include // string +#include // tuple, make_tuple +#include // is_arithmetic, is_same, is_enum, underlying_type, is_convertible +#include // unordered_map +#include // pair, declval +#include // valarray + +// #include + + +#include // exception +#include // runtime_error +#include // to_string + +// #include + + +#include // size_t + +namespace nlohmann +{ +namespace detail +{ +/// struct to capture the start position of the current token +struct position_t +{ + /// the total number of characters read + std::size_t chars_read_total = 0; + /// the number of characters read in the current line + std::size_t chars_read_current_line = 0; + /// the number of lines read + std::size_t lines_read = 0; + + /// conversion to size_t to preserve SAX interface + constexpr operator size_t() const + { + return chars_read_total; + } +}; + +} // namespace detail +} // namespace nlohmann + +// #include + + +#include // pair +// #include +/* Hedley - https://nemequ.github.io/hedley + * Created by Evan Nemerson + * + * To the extent possible under law, the author(s) have dedicated all + * copyright and related and neighboring rights to this software to + * the public domain worldwide. This software is distributed without + * any warranty. + * + * For details, see . + * SPDX-License-Identifier: CC0-1.0 + */ + +#if !defined(JSON_HEDLEY_VERSION) || (JSON_HEDLEY_VERSION < 11) +#if defined(JSON_HEDLEY_VERSION) + #undef JSON_HEDLEY_VERSION +#endif +#define JSON_HEDLEY_VERSION 11 + +#if defined(JSON_HEDLEY_STRINGIFY_EX) + #undef JSON_HEDLEY_STRINGIFY_EX +#endif +#define JSON_HEDLEY_STRINGIFY_EX(x) #x + +#if defined(JSON_HEDLEY_STRINGIFY) + #undef JSON_HEDLEY_STRINGIFY +#endif +#define JSON_HEDLEY_STRINGIFY(x) JSON_HEDLEY_STRINGIFY_EX(x) + +#if defined(JSON_HEDLEY_CONCAT_EX) + #undef JSON_HEDLEY_CONCAT_EX +#endif +#define JSON_HEDLEY_CONCAT_EX(a,b) a##b + +#if defined(JSON_HEDLEY_CONCAT) + #undef JSON_HEDLEY_CONCAT +#endif +#define JSON_HEDLEY_CONCAT(a,b) JSON_HEDLEY_CONCAT_EX(a,b) + +#if defined(JSON_HEDLEY_VERSION_ENCODE) + #undef JSON_HEDLEY_VERSION_ENCODE +#endif +#define JSON_HEDLEY_VERSION_ENCODE(major,minor,revision) (((major) * 1000000) + ((minor) * 1000) + (revision)) + +#if defined(JSON_HEDLEY_VERSION_DECODE_MAJOR) + #undef JSON_HEDLEY_VERSION_DECODE_MAJOR +#endif +#define JSON_HEDLEY_VERSION_DECODE_MAJOR(version) ((version) / 1000000) + +#if defined(JSON_HEDLEY_VERSION_DECODE_MINOR) + #undef JSON_HEDLEY_VERSION_DECODE_MINOR +#endif +#define JSON_HEDLEY_VERSION_DECODE_MINOR(version) (((version) % 1000000) / 1000) + +#if defined(JSON_HEDLEY_VERSION_DECODE_REVISION) + #undef JSON_HEDLEY_VERSION_DECODE_REVISION +#endif +#define JSON_HEDLEY_VERSION_DECODE_REVISION(version) ((version) % 1000) + +#if defined(JSON_HEDLEY_GNUC_VERSION) + #undef JSON_HEDLEY_GNUC_VERSION +#endif +#if defined(__GNUC__) && defined(__GNUC_PATCHLEVEL__) + #define JSON_HEDLEY_GNUC_VERSION JSON_HEDLEY_VERSION_ENCODE(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__) +#elif defined(__GNUC__) + #define JSON_HEDLEY_GNUC_VERSION JSON_HEDLEY_VERSION_ENCODE(__GNUC__, __GNUC_MINOR__, 0) +#endif + +#if defined(JSON_HEDLEY_GNUC_VERSION_CHECK) + #undef JSON_HEDLEY_GNUC_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_GNUC_VERSION) + #define JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_GNUC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_MSVC_VERSION) + #undef JSON_HEDLEY_MSVC_VERSION +#endif +#if defined(_MSC_FULL_VER) && (_MSC_FULL_VER >= 140000000) + #define JSON_HEDLEY_MSVC_VERSION JSON_HEDLEY_VERSION_ENCODE(_MSC_FULL_VER / 10000000, (_MSC_FULL_VER % 10000000) / 100000, (_MSC_FULL_VER % 100000) / 100) +#elif defined(_MSC_FULL_VER) + #define JSON_HEDLEY_MSVC_VERSION JSON_HEDLEY_VERSION_ENCODE(_MSC_FULL_VER / 1000000, (_MSC_FULL_VER % 1000000) / 10000, (_MSC_FULL_VER % 10000) / 10) +#elif defined(_MSC_VER) + #define JSON_HEDLEY_MSVC_VERSION JSON_HEDLEY_VERSION_ENCODE(_MSC_VER / 100, _MSC_VER % 100, 0) +#endif + +#if defined(JSON_HEDLEY_MSVC_VERSION_CHECK) + #undef JSON_HEDLEY_MSVC_VERSION_CHECK +#endif +#if !defined(_MSC_VER) + #define JSON_HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (0) +#elif defined(_MSC_VER) && (_MSC_VER >= 1400) + #define JSON_HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (_MSC_FULL_VER >= ((major * 10000000) + (minor * 100000) + (patch))) +#elif defined(_MSC_VER) && (_MSC_VER >= 1200) + #define JSON_HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (_MSC_FULL_VER >= ((major * 1000000) + (minor * 10000) + (patch))) +#else + #define JSON_HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (_MSC_VER >= ((major * 100) + (minor))) +#endif + +#if defined(JSON_HEDLEY_INTEL_VERSION) + #undef JSON_HEDLEY_INTEL_VERSION +#endif +#if defined(__INTEL_COMPILER) && defined(__INTEL_COMPILER_UPDATE) + #define JSON_HEDLEY_INTEL_VERSION JSON_HEDLEY_VERSION_ENCODE(__INTEL_COMPILER / 100, __INTEL_COMPILER % 100, __INTEL_COMPILER_UPDATE) +#elif defined(__INTEL_COMPILER) + #define JSON_HEDLEY_INTEL_VERSION JSON_HEDLEY_VERSION_ENCODE(__INTEL_COMPILER / 100, __INTEL_COMPILER % 100, 0) +#endif + +#if defined(JSON_HEDLEY_INTEL_VERSION_CHECK) + #undef JSON_HEDLEY_INTEL_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_INTEL_VERSION) + #define JSON_HEDLEY_INTEL_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_INTEL_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_INTEL_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_PGI_VERSION) + #undef JSON_HEDLEY_PGI_VERSION +#endif +#if defined(__PGI) && defined(__PGIC__) && defined(__PGIC_MINOR__) && defined(__PGIC_PATCHLEVEL__) + #define JSON_HEDLEY_PGI_VERSION JSON_HEDLEY_VERSION_ENCODE(__PGIC__, __PGIC_MINOR__, __PGIC_PATCHLEVEL__) +#endif + +#if defined(JSON_HEDLEY_PGI_VERSION_CHECK) + #undef JSON_HEDLEY_PGI_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_PGI_VERSION) + #define JSON_HEDLEY_PGI_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_PGI_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_PGI_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_SUNPRO_VERSION) + #undef JSON_HEDLEY_SUNPRO_VERSION +#endif +#if defined(__SUNPRO_C) && (__SUNPRO_C > 0x1000) + #define JSON_HEDLEY_SUNPRO_VERSION JSON_HEDLEY_VERSION_ENCODE((((__SUNPRO_C >> 16) & 0xf) * 10) + ((__SUNPRO_C >> 12) & 0xf), (((__SUNPRO_C >> 8) & 0xf) * 10) + ((__SUNPRO_C >> 4) & 0xf), (__SUNPRO_C & 0xf) * 10) +#elif defined(__SUNPRO_C) + #define JSON_HEDLEY_SUNPRO_VERSION JSON_HEDLEY_VERSION_ENCODE((__SUNPRO_C >> 8) & 0xf, (__SUNPRO_C >> 4) & 0xf, (__SUNPRO_C) & 0xf) +#elif defined(__SUNPRO_CC) && (__SUNPRO_CC > 0x1000) + #define JSON_HEDLEY_SUNPRO_VERSION JSON_HEDLEY_VERSION_ENCODE((((__SUNPRO_CC >> 16) & 0xf) * 10) + ((__SUNPRO_CC >> 12) & 0xf), (((__SUNPRO_CC >> 8) & 0xf) * 10) + ((__SUNPRO_CC >> 4) & 0xf), (__SUNPRO_CC & 0xf) * 10) +#elif defined(__SUNPRO_CC) + #define JSON_HEDLEY_SUNPRO_VERSION JSON_HEDLEY_VERSION_ENCODE((__SUNPRO_CC >> 8) & 0xf, (__SUNPRO_CC >> 4) & 0xf, (__SUNPRO_CC) & 0xf) +#endif + +#if defined(JSON_HEDLEY_SUNPRO_VERSION_CHECK) + #undef JSON_HEDLEY_SUNPRO_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_SUNPRO_VERSION) + #define JSON_HEDLEY_SUNPRO_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_SUNPRO_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_SUNPRO_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_EMSCRIPTEN_VERSION) + #undef JSON_HEDLEY_EMSCRIPTEN_VERSION +#endif +#if defined(__EMSCRIPTEN__) + #define JSON_HEDLEY_EMSCRIPTEN_VERSION JSON_HEDLEY_VERSION_ENCODE(__EMSCRIPTEN_major__, __EMSCRIPTEN_minor__, __EMSCRIPTEN_tiny__) +#endif + +#if defined(JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK) + #undef JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_EMSCRIPTEN_VERSION) + #define JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_EMSCRIPTEN_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_ARM_VERSION) + #undef JSON_HEDLEY_ARM_VERSION +#endif +#if defined(__CC_ARM) && defined(__ARMCOMPILER_VERSION) + #define JSON_HEDLEY_ARM_VERSION JSON_HEDLEY_VERSION_ENCODE(__ARMCOMPILER_VERSION / 1000000, (__ARMCOMPILER_VERSION % 1000000) / 10000, (__ARMCOMPILER_VERSION % 10000) / 100) +#elif defined(__CC_ARM) && defined(__ARMCC_VERSION) + #define JSON_HEDLEY_ARM_VERSION JSON_HEDLEY_VERSION_ENCODE(__ARMCC_VERSION / 1000000, (__ARMCC_VERSION % 1000000) / 10000, (__ARMCC_VERSION % 10000) / 100) +#endif + +#if defined(JSON_HEDLEY_ARM_VERSION_CHECK) + #undef JSON_HEDLEY_ARM_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_ARM_VERSION) + #define JSON_HEDLEY_ARM_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_ARM_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_ARM_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_IBM_VERSION) + #undef JSON_HEDLEY_IBM_VERSION +#endif +#if defined(__ibmxl__) + #define JSON_HEDLEY_IBM_VERSION JSON_HEDLEY_VERSION_ENCODE(__ibmxl_version__, __ibmxl_release__, __ibmxl_modification__) +#elif defined(__xlC__) && defined(__xlC_ver__) + #define JSON_HEDLEY_IBM_VERSION JSON_HEDLEY_VERSION_ENCODE(__xlC__ >> 8, __xlC__ & 0xff, (__xlC_ver__ >> 8) & 0xff) +#elif defined(__xlC__) + #define JSON_HEDLEY_IBM_VERSION JSON_HEDLEY_VERSION_ENCODE(__xlC__ >> 8, __xlC__ & 0xff, 0) +#endif + +#if defined(JSON_HEDLEY_IBM_VERSION_CHECK) + #undef JSON_HEDLEY_IBM_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_IBM_VERSION) + #define JSON_HEDLEY_IBM_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_IBM_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_IBM_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_TI_VERSION) + #undef JSON_HEDLEY_TI_VERSION +#endif +#if defined(__TI_COMPILER_VERSION__) + #define JSON_HEDLEY_TI_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) +#endif + +#if defined(JSON_HEDLEY_TI_VERSION_CHECK) + #undef JSON_HEDLEY_TI_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_TI_VERSION) + #define JSON_HEDLEY_TI_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_TI_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_CRAY_VERSION) + #undef JSON_HEDLEY_CRAY_VERSION +#endif +#if defined(_CRAYC) + #if defined(_RELEASE_PATCHLEVEL) + #define JSON_HEDLEY_CRAY_VERSION JSON_HEDLEY_VERSION_ENCODE(_RELEASE_MAJOR, _RELEASE_MINOR, _RELEASE_PATCHLEVEL) + #else + #define JSON_HEDLEY_CRAY_VERSION JSON_HEDLEY_VERSION_ENCODE(_RELEASE_MAJOR, _RELEASE_MINOR, 0) + #endif +#endif + +#if defined(JSON_HEDLEY_CRAY_VERSION_CHECK) + #undef JSON_HEDLEY_CRAY_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_CRAY_VERSION) + #define JSON_HEDLEY_CRAY_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_CRAY_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_CRAY_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_IAR_VERSION) + #undef JSON_HEDLEY_IAR_VERSION +#endif +#if defined(__IAR_SYSTEMS_ICC__) + #if __VER__ > 1000 + #define JSON_HEDLEY_IAR_VERSION JSON_HEDLEY_VERSION_ENCODE((__VER__ / 1000000), ((__VER__ / 1000) % 1000), (__VER__ % 1000)) + #else + #define JSON_HEDLEY_IAR_VERSION JSON_HEDLEY_VERSION_ENCODE(VER / 100, __VER__ % 100, 0) + #endif +#endif + +#if defined(JSON_HEDLEY_IAR_VERSION_CHECK) + #undef JSON_HEDLEY_IAR_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_IAR_VERSION) + #define JSON_HEDLEY_IAR_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_IAR_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_IAR_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_TINYC_VERSION) + #undef JSON_HEDLEY_TINYC_VERSION +#endif +#if defined(__TINYC__) + #define JSON_HEDLEY_TINYC_VERSION JSON_HEDLEY_VERSION_ENCODE(__TINYC__ / 1000, (__TINYC__ / 100) % 10, __TINYC__ % 100) +#endif + +#if defined(JSON_HEDLEY_TINYC_VERSION_CHECK) + #undef JSON_HEDLEY_TINYC_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_TINYC_VERSION) + #define JSON_HEDLEY_TINYC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TINYC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_TINYC_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_DMC_VERSION) + #undef JSON_HEDLEY_DMC_VERSION +#endif +#if defined(__DMC__) + #define JSON_HEDLEY_DMC_VERSION JSON_HEDLEY_VERSION_ENCODE(__DMC__ >> 8, (__DMC__ >> 4) & 0xf, __DMC__ & 0xf) +#endif + +#if defined(JSON_HEDLEY_DMC_VERSION_CHECK) + #undef JSON_HEDLEY_DMC_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_DMC_VERSION) + #define JSON_HEDLEY_DMC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_DMC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_DMC_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_COMPCERT_VERSION) + #undef JSON_HEDLEY_COMPCERT_VERSION +#endif +#if defined(__COMPCERT_VERSION__) + #define JSON_HEDLEY_COMPCERT_VERSION JSON_HEDLEY_VERSION_ENCODE(__COMPCERT_VERSION__ / 10000, (__COMPCERT_VERSION__ / 100) % 100, __COMPCERT_VERSION__ % 100) +#endif + +#if defined(JSON_HEDLEY_COMPCERT_VERSION_CHECK) + #undef JSON_HEDLEY_COMPCERT_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_COMPCERT_VERSION) + #define JSON_HEDLEY_COMPCERT_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_COMPCERT_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_COMPCERT_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_PELLES_VERSION) + #undef JSON_HEDLEY_PELLES_VERSION +#endif +#if defined(__POCC__) + #define JSON_HEDLEY_PELLES_VERSION JSON_HEDLEY_VERSION_ENCODE(__POCC__ / 100, __POCC__ % 100, 0) +#endif + +#if defined(JSON_HEDLEY_PELLES_VERSION_CHECK) + #undef JSON_HEDLEY_PELLES_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_PELLES_VERSION) + #define JSON_HEDLEY_PELLES_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_PELLES_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_PELLES_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_GCC_VERSION) + #undef JSON_HEDLEY_GCC_VERSION +#endif +#if \ + defined(JSON_HEDLEY_GNUC_VERSION) && \ + !defined(__clang__) && \ + !defined(JSON_HEDLEY_INTEL_VERSION) && \ + !defined(JSON_HEDLEY_PGI_VERSION) && \ + !defined(JSON_HEDLEY_ARM_VERSION) && \ + !defined(JSON_HEDLEY_TI_VERSION) && \ + !defined(__COMPCERT__) + #define JSON_HEDLEY_GCC_VERSION JSON_HEDLEY_GNUC_VERSION +#endif + +#if defined(JSON_HEDLEY_GCC_VERSION_CHECK) + #undef JSON_HEDLEY_GCC_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_GCC_VERSION) + #define JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_GCC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_HAS_ATTRIBUTE) + #undef JSON_HEDLEY_HAS_ATTRIBUTE +#endif +#if defined(__has_attribute) + #define JSON_HEDLEY_HAS_ATTRIBUTE(attribute) __has_attribute(attribute) +#else + #define JSON_HEDLEY_HAS_ATTRIBUTE(attribute) (0) +#endif + +#if defined(JSON_HEDLEY_GNUC_HAS_ATTRIBUTE) + #undef JSON_HEDLEY_GNUC_HAS_ATTRIBUTE +#endif +#if defined(__has_attribute) + #define JSON_HEDLEY_GNUC_HAS_ATTRIBUTE(attribute,major,minor,patch) __has_attribute(attribute) +#else + #define JSON_HEDLEY_GNUC_HAS_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_GCC_HAS_ATTRIBUTE) + #undef JSON_HEDLEY_GCC_HAS_ATTRIBUTE +#endif +#if defined(__has_attribute) + #define JSON_HEDLEY_GCC_HAS_ATTRIBUTE(attribute,major,minor,patch) __has_attribute(attribute) +#else + #define JSON_HEDLEY_GCC_HAS_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_HAS_CPP_ATTRIBUTE) + #undef JSON_HEDLEY_HAS_CPP_ATTRIBUTE +#endif +#if \ + defined(__has_cpp_attribute) && \ + defined(__cplusplus) && \ + (!defined(JSON_HEDLEY_SUNPRO_VERSION) || JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,15,0)) + #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE(attribute) __has_cpp_attribute(attribute) +#else + #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE(attribute) (0) +#endif + +#if defined(JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS) + #undef JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS +#endif +#if !defined(__cplusplus) || !defined(__has_cpp_attribute) + #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS(ns,attribute) (0) +#elif \ + !defined(JSON_HEDLEY_PGI_VERSION) && \ + (!defined(JSON_HEDLEY_SUNPRO_VERSION) || JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,15,0)) && \ + (!defined(JSON_HEDLEY_MSVC_VERSION) || JSON_HEDLEY_MSVC_VERSION_CHECK(19,20,0)) + #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS(ns,attribute) JSON_HEDLEY_HAS_CPP_ATTRIBUTE(ns::attribute) +#else + #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS(ns,attribute) (0) +#endif + +#if defined(JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE) + #undef JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE +#endif +#if defined(__has_cpp_attribute) && defined(__cplusplus) + #define JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) __has_cpp_attribute(attribute) +#else + #define JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE) + #undef JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE +#endif +#if defined(__has_cpp_attribute) && defined(__cplusplus) + #define JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) __has_cpp_attribute(attribute) +#else + #define JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_HAS_BUILTIN) + #undef JSON_HEDLEY_HAS_BUILTIN +#endif +#if defined(__has_builtin) + #define JSON_HEDLEY_HAS_BUILTIN(builtin) __has_builtin(builtin) +#else + #define JSON_HEDLEY_HAS_BUILTIN(builtin) (0) +#endif + +#if defined(JSON_HEDLEY_GNUC_HAS_BUILTIN) + #undef JSON_HEDLEY_GNUC_HAS_BUILTIN +#endif +#if defined(__has_builtin) + #define JSON_HEDLEY_GNUC_HAS_BUILTIN(builtin,major,minor,patch) __has_builtin(builtin) +#else + #define JSON_HEDLEY_GNUC_HAS_BUILTIN(builtin,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_GCC_HAS_BUILTIN) + #undef JSON_HEDLEY_GCC_HAS_BUILTIN +#endif +#if defined(__has_builtin) + #define JSON_HEDLEY_GCC_HAS_BUILTIN(builtin,major,minor,patch) __has_builtin(builtin) +#else + #define JSON_HEDLEY_GCC_HAS_BUILTIN(builtin,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_HAS_FEATURE) + #undef JSON_HEDLEY_HAS_FEATURE +#endif +#if defined(__has_feature) + #define JSON_HEDLEY_HAS_FEATURE(feature) __has_feature(feature) +#else + #define JSON_HEDLEY_HAS_FEATURE(feature) (0) +#endif + +#if defined(JSON_HEDLEY_GNUC_HAS_FEATURE) + #undef JSON_HEDLEY_GNUC_HAS_FEATURE +#endif +#if defined(__has_feature) + #define JSON_HEDLEY_GNUC_HAS_FEATURE(feature,major,minor,patch) __has_feature(feature) +#else + #define JSON_HEDLEY_GNUC_HAS_FEATURE(feature,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_GCC_HAS_FEATURE) + #undef JSON_HEDLEY_GCC_HAS_FEATURE +#endif +#if defined(__has_feature) + #define JSON_HEDLEY_GCC_HAS_FEATURE(feature,major,minor,patch) __has_feature(feature) +#else + #define JSON_HEDLEY_GCC_HAS_FEATURE(feature,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_HAS_EXTENSION) + #undef JSON_HEDLEY_HAS_EXTENSION +#endif +#if defined(__has_extension) + #define JSON_HEDLEY_HAS_EXTENSION(extension) __has_extension(extension) +#else + #define JSON_HEDLEY_HAS_EXTENSION(extension) (0) +#endif + +#if defined(JSON_HEDLEY_GNUC_HAS_EXTENSION) + #undef JSON_HEDLEY_GNUC_HAS_EXTENSION +#endif +#if defined(__has_extension) + #define JSON_HEDLEY_GNUC_HAS_EXTENSION(extension,major,minor,patch) __has_extension(extension) +#else + #define JSON_HEDLEY_GNUC_HAS_EXTENSION(extension,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_GCC_HAS_EXTENSION) + #undef JSON_HEDLEY_GCC_HAS_EXTENSION +#endif +#if defined(__has_extension) + #define JSON_HEDLEY_GCC_HAS_EXTENSION(extension,major,minor,patch) __has_extension(extension) +#else + #define JSON_HEDLEY_GCC_HAS_EXTENSION(extension,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE) + #undef JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE +#endif +#if defined(__has_declspec_attribute) + #define JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE(attribute) __has_declspec_attribute(attribute) +#else + #define JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE(attribute) (0) +#endif + +#if defined(JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE) + #undef JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE +#endif +#if defined(__has_declspec_attribute) + #define JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) __has_declspec_attribute(attribute) +#else + #define JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE) + #undef JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE +#endif +#if defined(__has_declspec_attribute) + #define JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) __has_declspec_attribute(attribute) +#else + #define JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_HAS_WARNING) + #undef JSON_HEDLEY_HAS_WARNING +#endif +#if defined(__has_warning) + #define JSON_HEDLEY_HAS_WARNING(warning) __has_warning(warning) +#else + #define JSON_HEDLEY_HAS_WARNING(warning) (0) +#endif + +#if defined(JSON_HEDLEY_GNUC_HAS_WARNING) + #undef JSON_HEDLEY_GNUC_HAS_WARNING +#endif +#if defined(__has_warning) + #define JSON_HEDLEY_GNUC_HAS_WARNING(warning,major,minor,patch) __has_warning(warning) +#else + #define JSON_HEDLEY_GNUC_HAS_WARNING(warning,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_GCC_HAS_WARNING) + #undef JSON_HEDLEY_GCC_HAS_WARNING +#endif +#if defined(__has_warning) + #define JSON_HEDLEY_GCC_HAS_WARNING(warning,major,minor,patch) __has_warning(warning) +#else + #define JSON_HEDLEY_GCC_HAS_WARNING(warning,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) +#endif + +/* JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_ is for + HEDLEY INTERNAL USE ONLY. API subject to change without notice. */ +#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_) + #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_ +#endif +#if defined(__cplusplus) && JSON_HEDLEY_HAS_WARNING("-Wc++98-compat") +# define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(xpr) \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + _Pragma("clang diagnostic ignored \"-Wc++98-compat\"") \ + xpr \ + JSON_HEDLEY_DIAGNOSTIC_POP +#else +# define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(x) x +#endif + +#if \ + (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) || \ + defined(__clang__) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,0,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) || \ + JSON_HEDLEY_PGI_VERSION_CHECK(18,4,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(6,0,0) || \ + JSON_HEDLEY_CRAY_VERSION_CHECK(5,0,0) || \ + JSON_HEDLEY_TINYC_VERSION_CHECK(0,9,17) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(8,0,0) || \ + (JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) && defined(__C99_PRAGMA_OPERATOR)) + #define JSON_HEDLEY_PRAGMA(value) _Pragma(#value) +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0) + #define JSON_HEDLEY_PRAGMA(value) __pragma(value) +#else + #define JSON_HEDLEY_PRAGMA(value) +#endif + +#if defined(JSON_HEDLEY_DIAGNOSTIC_PUSH) + #undef JSON_HEDLEY_DIAGNOSTIC_PUSH +#endif +#if defined(JSON_HEDLEY_DIAGNOSTIC_POP) + #undef JSON_HEDLEY_DIAGNOSTIC_POP +#endif +#if defined(__clang__) + #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("clang diagnostic push") + #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("clang diagnostic pop") +#elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("warning(push)") + #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("warning(pop)") +#elif JSON_HEDLEY_GCC_VERSION_CHECK(4,6,0) + #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("GCC diagnostic push") + #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("GCC diagnostic pop") +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_PUSH __pragma(warning(push)) + #define JSON_HEDLEY_DIAGNOSTIC_POP __pragma(warning(pop)) +#elif JSON_HEDLEY_ARM_VERSION_CHECK(5,6,0) + #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("push") + #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("pop") +#elif JSON_HEDLEY_TI_VERSION_CHECK(8,1,0) + #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("diag_push") + #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("diag_pop") +#elif JSON_HEDLEY_PELLES_VERSION_CHECK(2,90,0) + #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("warning(push)") + #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("warning(pop)") +#else + #define JSON_HEDLEY_DIAGNOSTIC_PUSH + #define JSON_HEDLEY_DIAGNOSTIC_POP +#endif + +#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED) + #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED +#endif +#if JSON_HEDLEY_HAS_WARNING("-Wdeprecated-declarations") + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("clang diagnostic ignored \"-Wdeprecated-declarations\"") +#elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("warning(disable:1478 1786)") +#elif JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress 1215,1444") +#elif JSON_HEDLEY_GCC_VERSION_CHECK(4,3,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED __pragma(warning(disable:4996)) +#elif JSON_HEDLEY_TI_VERSION_CHECK(8,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress 1291,1718") +#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,13,0) && !defined(__cplusplus) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("error_messages(off,E_DEPRECATED_ATT,E_DEPRECATED_ATT_MESS)") +#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,13,0) && defined(__cplusplus) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("error_messages(off,symdeprecated,symdeprecated2)") +#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress=Pe1444,Pe1215") +#elif JSON_HEDLEY_PELLES_VERSION_CHECK(2,90,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("warn(disable:2241)") +#else + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED +#endif + +#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS) + #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS +#endif +#if JSON_HEDLEY_HAS_WARNING("-Wunknown-pragmas") + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("clang diagnostic ignored \"-Wunknown-pragmas\"") +#elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("warning(disable:161)") +#elif JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress 1675") +#elif JSON_HEDLEY_GCC_VERSION_CHECK(4,3,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("GCC diagnostic ignored \"-Wunknown-pragmas\"") +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS __pragma(warning(disable:4068)) +#elif JSON_HEDLEY_TI_VERSION_CHECK(8,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress 163") +#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress=Pe161") +#else + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS +#endif + +#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES) + #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES +#endif +#if JSON_HEDLEY_HAS_WARNING("-Wunknown-attributes") + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("clang diagnostic ignored \"-Wunknown-attributes\"") +#elif JSON_HEDLEY_GCC_VERSION_CHECK(4,6,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") +#elif JSON_HEDLEY_INTEL_VERSION_CHECK(17,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("warning(disable:1292)") +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(19,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES __pragma(warning(disable:5030)) +#elif JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress 1097") +#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,14,0) && defined(__cplusplus) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("error_messages(off,attrskipunsup)") +#elif JSON_HEDLEY_TI_VERSION_CHECK(8,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress 1173") +#else + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES +#endif + +#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL) + #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL +#endif +#if JSON_HEDLEY_HAS_WARNING("-Wcast-qual") + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL _Pragma("clang diagnostic ignored \"-Wcast-qual\"") +#elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL _Pragma("warning(disable:2203 2331)") +#elif JSON_HEDLEY_GCC_VERSION_CHECK(3,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL _Pragma("GCC diagnostic ignored \"-Wcast-qual\"") +#else + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL +#endif + +#if defined(JSON_HEDLEY_DEPRECATED) + #undef JSON_HEDLEY_DEPRECATED +#endif +#if defined(JSON_HEDLEY_DEPRECATED_FOR) + #undef JSON_HEDLEY_DEPRECATED_FOR +#endif +#if defined(__cplusplus) && (__cplusplus >= 201402L) + #define JSON_HEDLEY_DEPRECATED(since) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[deprecated("Since " #since)]]) + #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[deprecated("Since " #since "; use " #replacement)]]) +#elif \ + JSON_HEDLEY_HAS_EXTENSION(attribute_deprecated_with_message) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,5,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(5,6,0) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,13,0) || \ + JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(8,3,0) + #define JSON_HEDLEY_DEPRECATED(since) __attribute__((__deprecated__("Since " #since))) + #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __attribute__((__deprecated__("Since " #since "; use " #replacement))) +#elif \ + JSON_HEDLEY_HAS_ATTRIBUTE(deprecated) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,1,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(8,0,0) || \ + (JSON_HEDLEY_TI_VERSION_CHECK(7,3,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) + #define JSON_HEDLEY_DEPRECATED(since) __attribute__((__deprecated__)) + #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __attribute__((__deprecated__)) +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(14,0,0) + #define JSON_HEDLEY_DEPRECATED(since) __declspec(deprecated("Since " # since)) + #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __declspec(deprecated("Since " #since "; use " #replacement)) +#elif \ + JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) || \ + JSON_HEDLEY_PELLES_VERSION_CHECK(6,50,0) + #define JSON_HEDLEY_DEPRECATED(since) __declspec(deprecated) + #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __declspec(deprecated) +#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) + #define JSON_HEDLEY_DEPRECATED(since) _Pragma("deprecated") + #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) _Pragma("deprecated") +#else + #define JSON_HEDLEY_DEPRECATED(since) + #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) +#endif + +#if defined(JSON_HEDLEY_UNAVAILABLE) + #undef JSON_HEDLEY_UNAVAILABLE +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(warning) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,3,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) + #define JSON_HEDLEY_UNAVAILABLE(available_since) __attribute__((__warning__("Not available until " #available_since))) +#else + #define JSON_HEDLEY_UNAVAILABLE(available_since) +#endif + +#if defined(JSON_HEDLEY_WARN_UNUSED_RESULT) + #undef JSON_HEDLEY_WARN_UNUSED_RESULT +#endif +#if defined(__cplusplus) && (__cplusplus >= 201703L) + #define JSON_HEDLEY_WARN_UNUSED_RESULT JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard]]) +#elif \ + JSON_HEDLEY_HAS_ATTRIBUTE(warn_unused_result) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,4,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(8,0,0) || \ + (JSON_HEDLEY_TI_VERSION_CHECK(7,3,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,15,0) && defined(__cplusplus)) || \ + JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) + #define JSON_HEDLEY_WARN_UNUSED_RESULT __attribute__((__warn_unused_result__)) +#elif defined(_Check_return_) /* SAL */ + #define JSON_HEDLEY_WARN_UNUSED_RESULT _Check_return_ +#else + #define JSON_HEDLEY_WARN_UNUSED_RESULT +#endif + +#if defined(JSON_HEDLEY_SENTINEL) + #undef JSON_HEDLEY_SENTINEL +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(sentinel) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,0,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(5,4,0) + #define JSON_HEDLEY_SENTINEL(position) __attribute__((__sentinel__(position))) +#else + #define JSON_HEDLEY_SENTINEL(position) +#endif + +#if defined(JSON_HEDLEY_NO_RETURN) + #undef JSON_HEDLEY_NO_RETURN +#endif +#if JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) + #define JSON_HEDLEY_NO_RETURN __noreturn +#elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) + #define JSON_HEDLEY_NO_RETURN __attribute__((__noreturn__)) +#elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L + #define JSON_HEDLEY_NO_RETURN _Noreturn +#elif defined(__cplusplus) && (__cplusplus >= 201103L) + #define JSON_HEDLEY_NO_RETURN JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[noreturn]]) +#elif \ + JSON_HEDLEY_HAS_ATTRIBUTE(noreturn) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,2,0) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(18,0,0) || \ + (JSON_HEDLEY_TI_VERSION_CHECK(17,3,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) + #define JSON_HEDLEY_NO_RETURN __attribute__((__noreturn__)) +#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) + #define JSON_HEDLEY_NO_RETURN _Pragma("does_not_return") +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) + #define JSON_HEDLEY_NO_RETURN __declspec(noreturn) +#elif JSON_HEDLEY_TI_VERSION_CHECK(6,0,0) && defined(__cplusplus) + #define JSON_HEDLEY_NO_RETURN _Pragma("FUNC_NEVER_RETURNS;") +#elif JSON_HEDLEY_COMPCERT_VERSION_CHECK(3,2,0) + #define JSON_HEDLEY_NO_RETURN __attribute((noreturn)) +#elif JSON_HEDLEY_PELLES_VERSION_CHECK(9,0,0) + #define JSON_HEDLEY_NO_RETURN __declspec(noreturn) +#else + #define JSON_HEDLEY_NO_RETURN +#endif + +#if defined(JSON_HEDLEY_NO_ESCAPE) + #undef JSON_HEDLEY_NO_ESCAPE +#endif +#if JSON_HEDLEY_HAS_ATTRIBUTE(noescape) + #define JSON_HEDLEY_NO_ESCAPE __attribute__((__noescape__)) +#else + #define JSON_HEDLEY_NO_ESCAPE +#endif + +#if defined(JSON_HEDLEY_UNREACHABLE) + #undef JSON_HEDLEY_UNREACHABLE +#endif +#if defined(JSON_HEDLEY_UNREACHABLE_RETURN) + #undef JSON_HEDLEY_UNREACHABLE_RETURN +#endif +#if \ + (JSON_HEDLEY_HAS_BUILTIN(__builtin_unreachable) && (!defined(JSON_HEDLEY_ARM_VERSION))) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,5,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(13,1,5) + #define JSON_HEDLEY_UNREACHABLE() __builtin_unreachable() +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) + #define JSON_HEDLEY_UNREACHABLE() __assume(0) +#elif JSON_HEDLEY_TI_VERSION_CHECK(6,0,0) + #if defined(__cplusplus) + #define JSON_HEDLEY_UNREACHABLE() std::_nassert(0) + #else + #define JSON_HEDLEY_UNREACHABLE() _nassert(0) + #endif + #define JSON_HEDLEY_UNREACHABLE_RETURN(value) return value +#elif defined(EXIT_FAILURE) + #define JSON_HEDLEY_UNREACHABLE() abort() +#else + #define JSON_HEDLEY_UNREACHABLE() + #define JSON_HEDLEY_UNREACHABLE_RETURN(value) return value +#endif +#if !defined(JSON_HEDLEY_UNREACHABLE_RETURN) + #define JSON_HEDLEY_UNREACHABLE_RETURN(value) JSON_HEDLEY_UNREACHABLE() +#endif + +#if defined(JSON_HEDLEY_ASSUME) + #undef JSON_HEDLEY_ASSUME +#endif +#if \ + JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) + #define JSON_HEDLEY_ASSUME(expr) __assume(expr) +#elif JSON_HEDLEY_HAS_BUILTIN(__builtin_assume) + #define JSON_HEDLEY_ASSUME(expr) __builtin_assume(expr) +#elif JSON_HEDLEY_TI_VERSION_CHECK(6,0,0) + #if defined(__cplusplus) + #define JSON_HEDLEY_ASSUME(expr) std::_nassert(expr) + #else + #define JSON_HEDLEY_ASSUME(expr) _nassert(expr) + #endif +#elif \ + (JSON_HEDLEY_HAS_BUILTIN(__builtin_unreachable) && !defined(JSON_HEDLEY_ARM_VERSION)) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,5,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(13,1,5) + #define JSON_HEDLEY_ASSUME(expr) ((void) ((expr) ? 1 : (__builtin_unreachable(), 1))) +#else + #define JSON_HEDLEY_ASSUME(expr) ((void) (expr)) +#endif + +JSON_HEDLEY_DIAGNOSTIC_PUSH +#if JSON_HEDLEY_HAS_WARNING("-Wpedantic") + #pragma clang diagnostic ignored "-Wpedantic" +#endif +#if JSON_HEDLEY_HAS_WARNING("-Wc++98-compat-pedantic") && defined(__cplusplus) + #pragma clang diagnostic ignored "-Wc++98-compat-pedantic" +#endif +#if JSON_HEDLEY_GCC_HAS_WARNING("-Wvariadic-macros",4,0,0) + #if defined(__clang__) + #pragma clang diagnostic ignored "-Wvariadic-macros" + #elif defined(JSON_HEDLEY_GCC_VERSION) + #pragma GCC diagnostic ignored "-Wvariadic-macros" + #endif +#endif +#if defined(JSON_HEDLEY_NON_NULL) + #undef JSON_HEDLEY_NON_NULL +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(nonnull) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,3,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) + #define JSON_HEDLEY_NON_NULL(...) __attribute__((__nonnull__(__VA_ARGS__))) +#else + #define JSON_HEDLEY_NON_NULL(...) +#endif +JSON_HEDLEY_DIAGNOSTIC_POP + +#if defined(JSON_HEDLEY_PRINTF_FORMAT) + #undef JSON_HEDLEY_PRINTF_FORMAT +#endif +#if defined(__MINGW32__) && JSON_HEDLEY_GCC_HAS_ATTRIBUTE(format,4,4,0) && !defined(__USE_MINGW_ANSI_STDIO) + #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __attribute__((__format__(ms_printf, string_idx, first_to_check))) +#elif defined(__MINGW32__) && JSON_HEDLEY_GCC_HAS_ATTRIBUTE(format,4,4,0) && defined(__USE_MINGW_ANSI_STDIO) + #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __attribute__((__format__(gnu_printf, string_idx, first_to_check))) +#elif \ + JSON_HEDLEY_HAS_ATTRIBUTE(format) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,1,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(5,6,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(8,0,0) || \ + (JSON_HEDLEY_TI_VERSION_CHECK(7,3,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) + #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __attribute__((__format__(__printf__, string_idx, first_to_check))) +#elif JSON_HEDLEY_PELLES_VERSION_CHECK(6,0,0) + #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __declspec(vaformat(printf,string_idx,first_to_check)) +#else + #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) +#endif + +#if defined(JSON_HEDLEY_CONSTEXPR) + #undef JSON_HEDLEY_CONSTEXPR +#endif +#if defined(__cplusplus) + #if __cplusplus >= 201103L + #define JSON_HEDLEY_CONSTEXPR JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(constexpr) + #endif +#endif +#if !defined(JSON_HEDLEY_CONSTEXPR) + #define JSON_HEDLEY_CONSTEXPR +#endif + +#if defined(JSON_HEDLEY_PREDICT) + #undef JSON_HEDLEY_PREDICT +#endif +#if defined(JSON_HEDLEY_LIKELY) + #undef JSON_HEDLEY_LIKELY +#endif +#if defined(JSON_HEDLEY_UNLIKELY) + #undef JSON_HEDLEY_UNLIKELY +#endif +#if defined(JSON_HEDLEY_UNPREDICTABLE) + #undef JSON_HEDLEY_UNPREDICTABLE +#endif +#if JSON_HEDLEY_HAS_BUILTIN(__builtin_unpredictable) + #define JSON_HEDLEY_UNPREDICTABLE(expr) __builtin_unpredictable(!!(expr)) +#endif +#if \ + JSON_HEDLEY_HAS_BUILTIN(__builtin_expect_with_probability) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(9,0,0) +# define JSON_HEDLEY_PREDICT(expr, value, probability) __builtin_expect_with_probability(expr, value, probability) +# define JSON_HEDLEY_PREDICT_TRUE(expr, probability) __builtin_expect_with_probability(!!(expr), 1, probability) +# define JSON_HEDLEY_PREDICT_FALSE(expr, probability) __builtin_expect_with_probability(!!(expr), 0, probability) +# define JSON_HEDLEY_LIKELY(expr) __builtin_expect(!!(expr), 1) +# define JSON_HEDLEY_UNLIKELY(expr) __builtin_expect(!!(expr), 0) +#if !defined(JSON_HEDLEY_BUILTIN_UNPREDICTABLE) + #define JSON_HEDLEY_BUILTIN_UNPREDICTABLE(expr) __builtin_expect_with_probability(!!(expr), 1, 0.5) +#endif +#elif \ + JSON_HEDLEY_HAS_BUILTIN(__builtin_expect) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,0,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,15,0) && defined(__cplusplus)) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(6,1,0) || \ + JSON_HEDLEY_TINYC_VERSION_CHECK(0,9,27) +# define JSON_HEDLEY_PREDICT(expr, expected, probability) \ + (((probability) >= 0.9) ? __builtin_expect(!!(expr), (expected)) : (((void) (expected)), !!(expr))) +# define JSON_HEDLEY_PREDICT_TRUE(expr, probability) \ + (__extension__ ({ \ + JSON_HEDLEY_CONSTEXPR double hedley_probability_ = (probability); \ + ((hedley_probability_ >= 0.9) ? __builtin_expect(!!(expr), 1) : ((hedley_probability_ <= 0.1) ? __builtin_expect(!!(expr), 0) : !!(expr))); \ + })) +# define JSON_HEDLEY_PREDICT_FALSE(expr, probability) \ + (__extension__ ({ \ + JSON_HEDLEY_CONSTEXPR double hedley_probability_ = (probability); \ + ((hedley_probability_ >= 0.9) ? __builtin_expect(!!(expr), 0) : ((hedley_probability_ <= 0.1) ? __builtin_expect(!!(expr), 1) : !!(expr))); \ + })) +# define JSON_HEDLEY_LIKELY(expr) __builtin_expect(!!(expr), 1) +# define JSON_HEDLEY_UNLIKELY(expr) __builtin_expect(!!(expr), 0) +#else +# define JSON_HEDLEY_PREDICT(expr, expected, probability) (((void) (expected)), !!(expr)) +# define JSON_HEDLEY_PREDICT_TRUE(expr, probability) (!!(expr)) +# define JSON_HEDLEY_PREDICT_FALSE(expr, probability) (!!(expr)) +# define JSON_HEDLEY_LIKELY(expr) (!!(expr)) +# define JSON_HEDLEY_UNLIKELY(expr) (!!(expr)) +#endif +#if !defined(JSON_HEDLEY_UNPREDICTABLE) + #define JSON_HEDLEY_UNPREDICTABLE(expr) JSON_HEDLEY_PREDICT(expr, 1, 0.5) +#endif + +#if defined(JSON_HEDLEY_MALLOC) + #undef JSON_HEDLEY_MALLOC +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(malloc) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,1,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(12,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(8,0,0) || \ + (JSON_HEDLEY_TI_VERSION_CHECK(7,3,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) + #define JSON_HEDLEY_MALLOC __attribute__((__malloc__)) +#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) + #define JSON_HEDLEY_MALLOC _Pragma("returns_new_memory") +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(14, 0, 0) + #define JSON_HEDLEY_MALLOC __declspec(restrict) +#else + #define JSON_HEDLEY_MALLOC +#endif + +#if defined(JSON_HEDLEY_PURE) + #undef JSON_HEDLEY_PURE +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(pure) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(2,96,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(8,0,0) || \ + (JSON_HEDLEY_TI_VERSION_CHECK(7,3,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) + #define JSON_HEDLEY_PURE __attribute__((__pure__)) +#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) + #define JSON_HEDLEY_PURE _Pragma("does_not_write_global_data") +#elif JSON_HEDLEY_TI_VERSION_CHECK(6,0,0) && defined(__cplusplus) + #define JSON_HEDLEY_PURE _Pragma("FUNC_IS_PURE;") +#else + #define JSON_HEDLEY_PURE +#endif + +#if defined(JSON_HEDLEY_CONST) + #undef JSON_HEDLEY_CONST +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(const) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(2,5,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(8,0,0) || \ + (JSON_HEDLEY_TI_VERSION_CHECK(7,3,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) + #define JSON_HEDLEY_CONST __attribute__((__const__)) +#elif \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) + #define JSON_HEDLEY_CONST _Pragma("no_side_effect") +#else + #define JSON_HEDLEY_CONST JSON_HEDLEY_PURE +#endif + +#if defined(JSON_HEDLEY_RESTRICT) + #undef JSON_HEDLEY_RESTRICT +#endif +#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && !defined(__cplusplus) + #define JSON_HEDLEY_RESTRICT restrict +#elif \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,1,0) || \ + JSON_HEDLEY_MSVC_VERSION_CHECK(14,0,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ + JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(8,0,0) || \ + (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,14,0) && defined(__cplusplus)) || \ + JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) || \ + defined(__clang__) + #define JSON_HEDLEY_RESTRICT __restrict +#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,3,0) && !defined(__cplusplus) + #define JSON_HEDLEY_RESTRICT _Restrict +#else + #define JSON_HEDLEY_RESTRICT +#endif + +#if defined(JSON_HEDLEY_INLINE) + #undef JSON_HEDLEY_INLINE +#endif +#if \ + (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) || \ + (defined(__cplusplus) && (__cplusplus >= 199711L)) + #define JSON_HEDLEY_INLINE inline +#elif \ + defined(JSON_HEDLEY_GCC_VERSION) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(6,2,0) + #define JSON_HEDLEY_INLINE __inline__ +#elif \ + JSON_HEDLEY_MSVC_VERSION_CHECK(12,0,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(8,0,0) + #define JSON_HEDLEY_INLINE __inline +#else + #define JSON_HEDLEY_INLINE +#endif + +#if defined(JSON_HEDLEY_ALWAYS_INLINE) + #undef JSON_HEDLEY_ALWAYS_INLINE +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(always_inline) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,0,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(8,0,0) || \ + (JSON_HEDLEY_TI_VERSION_CHECK(7,3,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) + #define JSON_HEDLEY_ALWAYS_INLINE __attribute__((__always_inline__)) JSON_HEDLEY_INLINE +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(12,0,0) + #define JSON_HEDLEY_ALWAYS_INLINE __forceinline +#elif JSON_HEDLEY_TI_VERSION_CHECK(7,0,0) && defined(__cplusplus) + #define JSON_HEDLEY_ALWAYS_INLINE _Pragma("FUNC_ALWAYS_INLINE;") +#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) + #define JSON_HEDLEY_ALWAYS_INLINE _Pragma("inline=forced") +#else + #define JSON_HEDLEY_ALWAYS_INLINE JSON_HEDLEY_INLINE +#endif + +#if defined(JSON_HEDLEY_NEVER_INLINE) + #undef JSON_HEDLEY_NEVER_INLINE +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(noinline) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,0,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(8,0,0) || \ + (JSON_HEDLEY_TI_VERSION_CHECK(7,3,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) + #define JSON_HEDLEY_NEVER_INLINE __attribute__((__noinline__)) +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) + #define JSON_HEDLEY_NEVER_INLINE __declspec(noinline) +#elif JSON_HEDLEY_PGI_VERSION_CHECK(10,2,0) + #define JSON_HEDLEY_NEVER_INLINE _Pragma("noinline") +#elif JSON_HEDLEY_TI_VERSION_CHECK(6,0,0) && defined(__cplusplus) + #define JSON_HEDLEY_NEVER_INLINE _Pragma("FUNC_CANNOT_INLINE;") +#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) + #define JSON_HEDLEY_NEVER_INLINE _Pragma("inline=never") +#elif JSON_HEDLEY_COMPCERT_VERSION_CHECK(3,2,0) + #define JSON_HEDLEY_NEVER_INLINE __attribute((noinline)) +#elif JSON_HEDLEY_PELLES_VERSION_CHECK(9,0,0) + #define JSON_HEDLEY_NEVER_INLINE __declspec(noinline) +#else + #define JSON_HEDLEY_NEVER_INLINE +#endif + +#if defined(JSON_HEDLEY_PRIVATE) + #undef JSON_HEDLEY_PRIVATE +#endif +#if defined(JSON_HEDLEY_PUBLIC) + #undef JSON_HEDLEY_PUBLIC +#endif +#if defined(JSON_HEDLEY_IMPORT) + #undef JSON_HEDLEY_IMPORT +#endif +#if defined(_WIN32) || defined(__CYGWIN__) + #define JSON_HEDLEY_PRIVATE + #define JSON_HEDLEY_PUBLIC __declspec(dllexport) + #define JSON_HEDLEY_IMPORT __declspec(dllimport) +#else + #if \ + JSON_HEDLEY_HAS_ATTRIBUTE(visibility) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,3,0) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(13,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(8,0,0) || \ + (JSON_HEDLEY_TI_VERSION_CHECK(7,3,0) && defined(__TI_EABI__) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) + #define JSON_HEDLEY_PRIVATE __attribute__((__visibility__("hidden"))) + #define JSON_HEDLEY_PUBLIC __attribute__((__visibility__("default"))) + #else + #define JSON_HEDLEY_PRIVATE + #define JSON_HEDLEY_PUBLIC + #endif + #define JSON_HEDLEY_IMPORT extern +#endif + +#if defined(JSON_HEDLEY_NO_THROW) + #undef JSON_HEDLEY_NO_THROW +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(nothrow) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,3,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) + #define JSON_HEDLEY_NO_THROW __attribute__((__nothrow__)) +#elif \ + JSON_HEDLEY_MSVC_VERSION_CHECK(13,1,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) + #define JSON_HEDLEY_NO_THROW __declspec(nothrow) +#else + #define JSON_HEDLEY_NO_THROW +#endif + +#if defined(JSON_HEDLEY_FALL_THROUGH) + #undef JSON_HEDLEY_FALL_THROUGH +#endif +#if JSON_HEDLEY_GNUC_HAS_ATTRIBUTE(fallthrough,7,0,0) && !defined(JSON_HEDLEY_PGI_VERSION) + #define JSON_HEDLEY_FALL_THROUGH __attribute__((__fallthrough__)) +#elif JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS(clang,fallthrough) + #define JSON_HEDLEY_FALL_THROUGH JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[clang::fallthrough]]) +#elif JSON_HEDLEY_HAS_CPP_ATTRIBUTE(fallthrough) + #define JSON_HEDLEY_FALL_THROUGH JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[fallthrough]]) +#elif defined(__fallthrough) /* SAL */ + #define JSON_HEDLEY_FALL_THROUGH __fallthrough +#else + #define JSON_HEDLEY_FALL_THROUGH +#endif + +#if defined(JSON_HEDLEY_RETURNS_NON_NULL) + #undef JSON_HEDLEY_RETURNS_NON_NULL +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(returns_nonnull) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,9,0) + #define JSON_HEDLEY_RETURNS_NON_NULL __attribute__((__returns_nonnull__)) +#elif defined(_Ret_notnull_) /* SAL */ + #define JSON_HEDLEY_RETURNS_NON_NULL _Ret_notnull_ +#else + #define JSON_HEDLEY_RETURNS_NON_NULL +#endif + +#if defined(JSON_HEDLEY_ARRAY_PARAM) + #undef JSON_HEDLEY_ARRAY_PARAM +#endif +#if \ + defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && \ + !defined(__STDC_NO_VLA__) && \ + !defined(__cplusplus) && \ + !defined(JSON_HEDLEY_PGI_VERSION) && \ + !defined(JSON_HEDLEY_TINYC_VERSION) + #define JSON_HEDLEY_ARRAY_PARAM(name) (name) +#else + #define JSON_HEDLEY_ARRAY_PARAM(name) +#endif + +#if defined(JSON_HEDLEY_IS_CONSTANT) + #undef JSON_HEDLEY_IS_CONSTANT +#endif +#if defined(JSON_HEDLEY_REQUIRE_CONSTEXPR) + #undef JSON_HEDLEY_REQUIRE_CONSTEXPR +#endif +/* JSON_HEDLEY_IS_CONSTEXPR_ is for + HEDLEY INTERNAL USE ONLY. API subject to change without notice. */ +#if defined(JSON_HEDLEY_IS_CONSTEXPR_) + #undef JSON_HEDLEY_IS_CONSTEXPR_ +#endif +#if \ + JSON_HEDLEY_HAS_BUILTIN(__builtin_constant_p) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,4,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_TINYC_VERSION_CHECK(0,9,19) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(13,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(6,1,0) || \ + (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) && !defined(__cplusplus)) || \ + JSON_HEDLEY_CRAY_VERSION_CHECK(8,1,0) + #define JSON_HEDLEY_IS_CONSTANT(expr) __builtin_constant_p(expr) +#endif +#if !defined(__cplusplus) +# if \ + JSON_HEDLEY_HAS_BUILTIN(__builtin_types_compatible_p) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,4,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(13,1,0) || \ + JSON_HEDLEY_CRAY_VERSION_CHECK(8,1,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(5,4,0) || \ + JSON_HEDLEY_TINYC_VERSION_CHECK(0,9,24) +#if defined(__INTPTR_TYPE__) + #define JSON_HEDLEY_IS_CONSTEXPR_(expr) __builtin_types_compatible_p(__typeof__((1 ? (void*) ((__INTPTR_TYPE__) ((expr) * 0)) : (int*) 0)), int*) +#else + #include + #define JSON_HEDLEY_IS_CONSTEXPR_(expr) __builtin_types_compatible_p(__typeof__((1 ? (void*) ((intptr_t) ((expr) * 0)) : (int*) 0)), int*) +#endif +# elif \ + (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) && !defined(JSON_HEDLEY_SUNPRO_VERSION) && !defined(JSON_HEDLEY_PGI_VERSION)) || \ + JSON_HEDLEY_HAS_EXTENSION(c_generic_selections) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,9,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(17,0,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(12,1,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(5,3,0) +#if defined(__INTPTR_TYPE__) + #define JSON_HEDLEY_IS_CONSTEXPR_(expr) _Generic((1 ? (void*) ((__INTPTR_TYPE__) ((expr) * 0)) : (int*) 0), int*: 1, void*: 0) +#else + #include + #define JSON_HEDLEY_IS_CONSTEXPR_(expr) _Generic((1 ? (void*) ((intptr_t) * 0) : (int*) 0), int*: 1, void*: 0) +#endif +# elif \ + defined(JSON_HEDLEY_GCC_VERSION) || \ + defined(JSON_HEDLEY_INTEL_VERSION) || \ + defined(JSON_HEDLEY_TINYC_VERSION) || \ + defined(JSON_HEDLEY_TI_VERSION) || \ + defined(__clang__) +# define JSON_HEDLEY_IS_CONSTEXPR_(expr) ( \ + sizeof(void) != \ + sizeof(*( \ + 1 ? \ + ((void*) ((expr) * 0L) ) : \ +((struct { char v[sizeof(void) * 2]; } *) 1) \ + ) \ + ) \ + ) +# endif +#endif +#if defined(JSON_HEDLEY_IS_CONSTEXPR_) + #if !defined(JSON_HEDLEY_IS_CONSTANT) + #define JSON_HEDLEY_IS_CONSTANT(expr) JSON_HEDLEY_IS_CONSTEXPR_(expr) + #endif + #define JSON_HEDLEY_REQUIRE_CONSTEXPR(expr) (JSON_HEDLEY_IS_CONSTEXPR_(expr) ? (expr) : (-1)) +#else + #if !defined(JSON_HEDLEY_IS_CONSTANT) + #define JSON_HEDLEY_IS_CONSTANT(expr) (0) + #endif + #define JSON_HEDLEY_REQUIRE_CONSTEXPR(expr) (expr) +#endif + +#if defined(JSON_HEDLEY_BEGIN_C_DECLS) + #undef JSON_HEDLEY_BEGIN_C_DECLS +#endif +#if defined(JSON_HEDLEY_END_C_DECLS) + #undef JSON_HEDLEY_END_C_DECLS +#endif +#if defined(JSON_HEDLEY_C_DECL) + #undef JSON_HEDLEY_C_DECL +#endif +#if defined(__cplusplus) + #define JSON_HEDLEY_BEGIN_C_DECLS extern "C" { + #define JSON_HEDLEY_END_C_DECLS } + #define JSON_HEDLEY_C_DECL extern "C" +#else + #define JSON_HEDLEY_BEGIN_C_DECLS + #define JSON_HEDLEY_END_C_DECLS + #define JSON_HEDLEY_C_DECL +#endif + +#if defined(JSON_HEDLEY_STATIC_ASSERT) + #undef JSON_HEDLEY_STATIC_ASSERT +#endif +#if \ + !defined(__cplusplus) && ( \ + (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L)) || \ + JSON_HEDLEY_HAS_FEATURE(c_static_assert) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(6,0,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + defined(_Static_assert) \ + ) +# define JSON_HEDLEY_STATIC_ASSERT(expr, message) _Static_assert(expr, message) +#elif \ + (defined(__cplusplus) && (__cplusplus >= 201103L)) || \ + JSON_HEDLEY_MSVC_VERSION_CHECK(16,0,0) || \ + (defined(__cplusplus) && JSON_HEDLEY_TI_VERSION_CHECK(8,3,0)) +# define JSON_HEDLEY_STATIC_ASSERT(expr, message) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(static_assert(expr, message)) +#else +# define JSON_HEDLEY_STATIC_ASSERT(expr, message) +#endif + +#if defined(JSON_HEDLEY_CONST_CAST) + #undef JSON_HEDLEY_CONST_CAST +#endif +#if defined(__cplusplus) +# define JSON_HEDLEY_CONST_CAST(T, expr) (const_cast(expr)) +#elif \ + JSON_HEDLEY_HAS_WARNING("-Wcast-qual") || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,6,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) +# define JSON_HEDLEY_CONST_CAST(T, expr) (__extension__ ({ \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL \ + ((T) (expr)); \ + JSON_HEDLEY_DIAGNOSTIC_POP \ + })) +#else +# define JSON_HEDLEY_CONST_CAST(T, expr) ((T) (expr)) +#endif + +#if defined(JSON_HEDLEY_REINTERPRET_CAST) + #undef JSON_HEDLEY_REINTERPRET_CAST +#endif +#if defined(__cplusplus) + #define JSON_HEDLEY_REINTERPRET_CAST(T, expr) (reinterpret_cast(expr)) +#else + #define JSON_HEDLEY_REINTERPRET_CAST(T, expr) (*((T*) &(expr))) +#endif + +#if defined(JSON_HEDLEY_STATIC_CAST) + #undef JSON_HEDLEY_STATIC_CAST +#endif +#if defined(__cplusplus) + #define JSON_HEDLEY_STATIC_CAST(T, expr) (static_cast(expr)) +#else + #define JSON_HEDLEY_STATIC_CAST(T, expr) ((T) (expr)) +#endif + +#if defined(JSON_HEDLEY_CPP_CAST) + #undef JSON_HEDLEY_CPP_CAST +#endif +#if defined(__cplusplus) + #define JSON_HEDLEY_CPP_CAST(T, expr) static_cast(expr) +#else + #define JSON_HEDLEY_CPP_CAST(T, expr) (expr) +#endif + +#if defined(JSON_HEDLEY_NULL) + #undef JSON_HEDLEY_NULL +#endif +#if defined(__cplusplus) + #if __cplusplus >= 201103L + #define JSON_HEDLEY_NULL JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(nullptr) + #elif defined(NULL) + #define JSON_HEDLEY_NULL NULL + #else + #define JSON_HEDLEY_NULL JSON_HEDLEY_STATIC_CAST(void*, 0) + #endif +#elif defined(NULL) + #define JSON_HEDLEY_NULL NULL +#else + #define JSON_HEDLEY_NULL ((void*) 0) +#endif + +#if defined(JSON_HEDLEY_MESSAGE) + #undef JSON_HEDLEY_MESSAGE +#endif +#if JSON_HEDLEY_HAS_WARNING("-Wunknown-pragmas") +# define JSON_HEDLEY_MESSAGE(msg) \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS \ + JSON_HEDLEY_PRAGMA(message msg) \ + JSON_HEDLEY_DIAGNOSTIC_POP +#elif \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,4,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) +# define JSON_HEDLEY_MESSAGE(msg) JSON_HEDLEY_PRAGMA(message msg) +#elif JSON_HEDLEY_CRAY_VERSION_CHECK(5,0,0) +# define JSON_HEDLEY_MESSAGE(msg) JSON_HEDLEY_PRAGMA(_CRI message msg) +#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) +# define JSON_HEDLEY_MESSAGE(msg) JSON_HEDLEY_PRAGMA(message(msg)) +#elif JSON_HEDLEY_PELLES_VERSION_CHECK(2,0,0) +# define JSON_HEDLEY_MESSAGE(msg) JSON_HEDLEY_PRAGMA(message(msg)) +#else +# define JSON_HEDLEY_MESSAGE(msg) +#endif + +#if defined(JSON_HEDLEY_WARNING) + #undef JSON_HEDLEY_WARNING +#endif +#if JSON_HEDLEY_HAS_WARNING("-Wunknown-pragmas") +# define JSON_HEDLEY_WARNING(msg) \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS \ + JSON_HEDLEY_PRAGMA(clang warning msg) \ + JSON_HEDLEY_DIAGNOSTIC_POP +#elif \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,8,0) || \ + JSON_HEDLEY_PGI_VERSION_CHECK(18,4,0) +# define JSON_HEDLEY_WARNING(msg) JSON_HEDLEY_PRAGMA(GCC warning msg) +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0) +# define JSON_HEDLEY_WARNING(msg) JSON_HEDLEY_PRAGMA(message(msg)) +#else +# define JSON_HEDLEY_WARNING(msg) JSON_HEDLEY_MESSAGE(msg) +#endif + +#if defined(JSON_HEDLEY_REQUIRE) + #undef JSON_HEDLEY_REQUIRE +#endif +#if defined(JSON_HEDLEY_REQUIRE_MSG) + #undef JSON_HEDLEY_REQUIRE_MSG +#endif +#if JSON_HEDLEY_HAS_ATTRIBUTE(diagnose_if) +# if JSON_HEDLEY_HAS_WARNING("-Wgcc-compat") +# define JSON_HEDLEY_REQUIRE(expr) \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + _Pragma("clang diagnostic ignored \"-Wgcc-compat\"") \ + __attribute__((diagnose_if(!(expr), #expr, "error"))) \ + JSON_HEDLEY_DIAGNOSTIC_POP +# define JSON_HEDLEY_REQUIRE_MSG(expr,msg) \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + _Pragma("clang diagnostic ignored \"-Wgcc-compat\"") \ + __attribute__((diagnose_if(!(expr), msg, "error"))) \ + JSON_HEDLEY_DIAGNOSTIC_POP +# else +# define JSON_HEDLEY_REQUIRE(expr) __attribute__((diagnose_if(!(expr), #expr, "error"))) +# define JSON_HEDLEY_REQUIRE_MSG(expr,msg) __attribute__((diagnose_if(!(expr), msg, "error"))) +# endif +#else +# define JSON_HEDLEY_REQUIRE(expr) +# define JSON_HEDLEY_REQUIRE_MSG(expr,msg) +#endif + +#if defined(JSON_HEDLEY_FLAGS) + #undef JSON_HEDLEY_FLAGS +#endif +#if JSON_HEDLEY_HAS_ATTRIBUTE(flag_enum) + #define JSON_HEDLEY_FLAGS __attribute__((__flag_enum__)) +#endif + +#if defined(JSON_HEDLEY_FLAGS_CAST) + #undef JSON_HEDLEY_FLAGS_CAST +#endif +#if JSON_HEDLEY_INTEL_VERSION_CHECK(19,0,0) +# define JSON_HEDLEY_FLAGS_CAST(T, expr) (__extension__ ({ \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + _Pragma("warning(disable:188)") \ + ((T) (expr)); \ + JSON_HEDLEY_DIAGNOSTIC_POP \ + })) +#else +# define JSON_HEDLEY_FLAGS_CAST(T, expr) JSON_HEDLEY_STATIC_CAST(T, expr) +#endif + +#if defined(JSON_HEDLEY_EMPTY_BASES) + #undef JSON_HEDLEY_EMPTY_BASES +#endif +#if JSON_HEDLEY_MSVC_VERSION_CHECK(19,0,23918) && !JSON_HEDLEY_MSVC_VERSION_CHECK(20,0,0) + #define JSON_HEDLEY_EMPTY_BASES __declspec(empty_bases) +#else + #define JSON_HEDLEY_EMPTY_BASES +#endif + +/* Remaining macros are deprecated. */ + +#if defined(JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK) + #undef JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK +#endif +#if defined(__clang__) + #define JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK(major,minor,patch) (0) +#else + #define JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK(major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_CLANG_HAS_ATTRIBUTE) + #undef JSON_HEDLEY_CLANG_HAS_ATTRIBUTE +#endif +#define JSON_HEDLEY_CLANG_HAS_ATTRIBUTE(attribute) JSON_HEDLEY_HAS_ATTRIBUTE(attribute) + +#if defined(JSON_HEDLEY_CLANG_HAS_CPP_ATTRIBUTE) + #undef JSON_HEDLEY_CLANG_HAS_CPP_ATTRIBUTE +#endif +#define JSON_HEDLEY_CLANG_HAS_CPP_ATTRIBUTE(attribute) JSON_HEDLEY_HAS_CPP_ATTRIBUTE(attribute) + +#if defined(JSON_HEDLEY_CLANG_HAS_BUILTIN) + #undef JSON_HEDLEY_CLANG_HAS_BUILTIN +#endif +#define JSON_HEDLEY_CLANG_HAS_BUILTIN(builtin) JSON_HEDLEY_HAS_BUILTIN(builtin) + +#if defined(JSON_HEDLEY_CLANG_HAS_FEATURE) + #undef JSON_HEDLEY_CLANG_HAS_FEATURE +#endif +#define JSON_HEDLEY_CLANG_HAS_FEATURE(feature) JSON_HEDLEY_HAS_FEATURE(feature) + +#if defined(JSON_HEDLEY_CLANG_HAS_EXTENSION) + #undef JSON_HEDLEY_CLANG_HAS_EXTENSION +#endif +#define JSON_HEDLEY_CLANG_HAS_EXTENSION(extension) JSON_HEDLEY_HAS_EXTENSION(extension) + +#if defined(JSON_HEDLEY_CLANG_HAS_DECLSPEC_DECLSPEC_ATTRIBUTE) + #undef JSON_HEDLEY_CLANG_HAS_DECLSPEC_DECLSPEC_ATTRIBUTE +#endif +#define JSON_HEDLEY_CLANG_HAS_DECLSPEC_ATTRIBUTE(attribute) JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE(attribute) + +#if defined(JSON_HEDLEY_CLANG_HAS_WARNING) + #undef JSON_HEDLEY_CLANG_HAS_WARNING +#endif +#define JSON_HEDLEY_CLANG_HAS_WARNING(warning) JSON_HEDLEY_HAS_WARNING(warning) + +#endif /* !defined(JSON_HEDLEY_VERSION) || (JSON_HEDLEY_VERSION < X) */ + + +// This file contains all internal macro definitions +// You MUST include macro_unscope.hpp at the end of json.hpp to undef all of them + +// exclude unsupported compilers +#if !defined(JSON_SKIP_UNSUPPORTED_COMPILER_CHECK) + #if defined(__clang__) + #if (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__) < 30400 + #error "unsupported Clang version - see https://github.com/nlohmann/json#supported-compilers" + #endif + #elif defined(__GNUC__) && !(defined(__ICC) || defined(__INTEL_COMPILER)) + #if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) < 40800 + #error "unsupported GCC version - see https://github.com/nlohmann/json#supported-compilers" + #endif + #endif +#endif + +// C++ language standard detection +#if (defined(__cplusplus) && __cplusplus >= 201703L) || (defined(_HAS_CXX17) && _HAS_CXX17 == 1) // fix for issue #464 + #define JSON_HAS_CPP_17 + #define JSON_HAS_CPP_14 +#elif (defined(__cplusplus) && __cplusplus >= 201402L) || (defined(_HAS_CXX14) && _HAS_CXX14 == 1) + #define JSON_HAS_CPP_14 +#endif + +// disable float-equal warnings on GCC/clang +#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wfloat-equal" +#endif + +// disable documentation warnings on clang +#if defined(__clang__) + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wdocumentation" +#endif + +// allow to disable exceptions +#if (defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND)) && !defined(JSON_NOEXCEPTION) + #define JSON_THROW(exception) throw exception + #define JSON_TRY try + #define JSON_CATCH(exception) catch(exception) + #define JSON_INTERNAL_CATCH(exception) catch(exception) +#else + #include + #define JSON_THROW(exception) std::abort() + #define JSON_TRY if(true) + #define JSON_CATCH(exception) if(false) + #define JSON_INTERNAL_CATCH(exception) if(false) +#endif + +// override exception macros +#if defined(JSON_THROW_USER) + #undef JSON_THROW + #define JSON_THROW JSON_THROW_USER +#endif +#if defined(JSON_TRY_USER) + #undef JSON_TRY + #define JSON_TRY JSON_TRY_USER +#endif +#if defined(JSON_CATCH_USER) + #undef JSON_CATCH + #define JSON_CATCH JSON_CATCH_USER + #undef JSON_INTERNAL_CATCH + #define JSON_INTERNAL_CATCH JSON_CATCH_USER +#endif +#if defined(JSON_INTERNAL_CATCH_USER) + #undef JSON_INTERNAL_CATCH + #define JSON_INTERNAL_CATCH JSON_INTERNAL_CATCH_USER +#endif + +/*! +@brief macro to briefly define a mapping between an enum and JSON +@def NLOHMANN_JSON_SERIALIZE_ENUM +@since version 3.4.0 +*/ +#define NLOHMANN_JSON_SERIALIZE_ENUM(ENUM_TYPE, ...) \ + template \ + inline void to_json(BasicJsonType& j, const ENUM_TYPE& e) \ + { \ + static_assert(std::is_enum::value, #ENUM_TYPE " must be an enum!"); \ + static const std::pair m[] = __VA_ARGS__; \ + auto it = std::find_if(std::begin(m), std::end(m), \ + [e](const std::pair& ej_pair) -> bool \ + { \ + return ej_pair.first == e; \ + }); \ + j = ((it != std::end(m)) ? it : std::begin(m))->second; \ + } \ + template \ + inline void from_json(const BasicJsonType& j, ENUM_TYPE& e) \ + { \ + static_assert(std::is_enum::value, #ENUM_TYPE " must be an enum!"); \ + static const std::pair m[] = __VA_ARGS__; \ + auto it = std::find_if(std::begin(m), std::end(m), \ + [&j](const std::pair& ej_pair) -> bool \ + { \ + return ej_pair.second == j; \ + }); \ + e = ((it != std::end(m)) ? it : std::begin(m))->first; \ + } + +// Ugly macros to avoid uglier copy-paste when specializing basic_json. They +// may be removed in the future once the class is split. + +#define NLOHMANN_BASIC_JSON_TPL_DECLARATION \ + template class ObjectType, \ + template class ArrayType, \ + class StringType, class BooleanType, class NumberIntegerType, \ + class NumberUnsignedType, class NumberFloatType, \ + template class AllocatorType, \ + template class JSONSerializer> + +#define NLOHMANN_BASIC_JSON_TPL \ + basic_json + + +namespace nlohmann +{ +namespace detail +{ +//////////////// +// exceptions // +//////////////// + +/*! +@brief general exception of the @ref basic_json class + +This class is an extension of `std::exception` objects with a member @a id for +exception ids. It is used as the base class for all exceptions thrown by the +@ref basic_json class. This class can hence be used as "wildcard" to catch +exceptions. + +Subclasses: +- @ref parse_error for exceptions indicating a parse error +- @ref invalid_iterator for exceptions indicating errors with iterators +- @ref type_error for exceptions indicating executing a member function with + a wrong type +- @ref out_of_range for exceptions indicating access out of the defined range +- @ref other_error for exceptions indicating other library errors + +@internal +@note To have nothrow-copy-constructible exceptions, we internally use + `std::runtime_error` which can cope with arbitrary-length error messages. + Intermediate strings are built with static functions and then passed to + the actual constructor. +@endinternal + +@liveexample{The following code shows how arbitrary library exceptions can be +caught.,exception} + +@since version 3.0.0 +*/ +class exception : public std::exception +{ + public: + /// returns the explanatory string + JSON_HEDLEY_RETURNS_NON_NULL + const char* what() const noexcept override + { + return m.what(); + } + + /// the id of the exception + const int id; + + protected: + JSON_HEDLEY_NON_NULL(3) + exception(int id_, const char* what_arg) : id(id_), m(what_arg) {} + + static std::string name(const std::string& ename, int id_) + { + return "[json.exception." + ename + "." + std::to_string(id_) + "] "; + } + + private: + /// an exception object as storage for error messages + std::runtime_error m; +}; + +/*! +@brief exception indicating a parse error + +This exception is thrown by the library when a parse error occurs. Parse errors +can occur during the deserialization of JSON text, CBOR, MessagePack, as well +as when using JSON Patch. + +Member @a byte holds the byte index of the last read character in the input +file. + +Exceptions have ids 1xx. + +name / id | example message | description +------------------------------ | --------------- | ------------------------- +json.exception.parse_error.101 | parse error at 2: unexpected end of input; expected string literal | This error indicates a syntax error while deserializing a JSON text. The error message describes that an unexpected token (character) was encountered, and the member @a byte indicates the error position. +json.exception.parse_error.102 | parse error at 14: missing or wrong low surrogate | JSON uses the `\uxxxx` format to describe Unicode characters. Code points above above 0xFFFF are split into two `\uxxxx` entries ("surrogate pairs"). This error indicates that the surrogate pair is incomplete or contains an invalid code point. +json.exception.parse_error.103 | parse error: code points above 0x10FFFF are invalid | Unicode supports code points up to 0x10FFFF. Code points above 0x10FFFF are invalid. +json.exception.parse_error.104 | parse error: JSON patch must be an array of objects | [RFC 6902](https://tools.ietf.org/html/rfc6902) requires a JSON Patch document to be a JSON document that represents an array of objects. +json.exception.parse_error.105 | parse error: operation must have string member 'op' | An operation of a JSON Patch document must contain exactly one "op" member, whose value indicates the operation to perform. Its value must be one of "add", "remove", "replace", "move", "copy", or "test"; other values are errors. +json.exception.parse_error.106 | parse error: array index '01' must not begin with '0' | An array index in a JSON Pointer ([RFC 6901](https://tools.ietf.org/html/rfc6901)) may be `0` or any number without a leading `0`. +json.exception.parse_error.107 | parse error: JSON pointer must be empty or begin with '/' - was: 'foo' | A JSON Pointer must be a Unicode string containing a sequence of zero or more reference tokens, each prefixed by a `/` character. +json.exception.parse_error.108 | parse error: escape character '~' must be followed with '0' or '1' | In a JSON Pointer, only `~0` and `~1` are valid escape sequences. +json.exception.parse_error.109 | parse error: array index 'one' is not a number | A JSON Pointer array index must be a number. +json.exception.parse_error.110 | parse error at 1: cannot read 2 bytes from vector | When parsing CBOR or MessagePack, the byte vector ends before the complete value has been read. +json.exception.parse_error.112 | parse error at 1: error reading CBOR; last byte: 0xF8 | Not all types of CBOR or MessagePack are supported. This exception occurs if an unsupported byte was read. +json.exception.parse_error.113 | parse error at 2: expected a CBOR string; last byte: 0x98 | While parsing a map key, a value that is not a string has been read. +json.exception.parse_error.114 | parse error: Unsupported BSON record type 0x0F | The parsing of the corresponding BSON record type is not implemented (yet). + +@note For an input with n bytes, 1 is the index of the first character and n+1 + is the index of the terminating null byte or the end of file. This also + holds true when reading a byte vector (CBOR or MessagePack). + +@liveexample{The following code shows how a `parse_error` exception can be +caught.,parse_error} + +@sa - @ref exception for the base class of the library exceptions +@sa - @ref invalid_iterator for exceptions indicating errors with iterators +@sa - @ref type_error for exceptions indicating executing a member function with + a wrong type +@sa - @ref out_of_range for exceptions indicating access out of the defined range +@sa - @ref other_error for exceptions indicating other library errors + +@since version 3.0.0 +*/ +class parse_error : public exception +{ + public: + /*! + @brief create a parse error exception + @param[in] id_ the id of the exception + @param[in] pos the position where the error occurred (or with + chars_read_total=0 if the position cannot be + determined) + @param[in] what_arg the explanatory string + @return parse_error object + */ + static parse_error create(int id_, const position_t& pos, const std::string& what_arg) + { + std::string w = exception::name("parse_error", id_) + "parse error" + + position_string(pos) + ": " + what_arg; + return parse_error(id_, pos.chars_read_total, w.c_str()); + } + + static parse_error create(int id_, std::size_t byte_, const std::string& what_arg) + { + std::string w = exception::name("parse_error", id_) + "parse error" + + (byte_ != 0 ? (" at byte " + std::to_string(byte_)) : "") + + ": " + what_arg; + return parse_error(id_, byte_, w.c_str()); + } + + /*! + @brief byte index of the parse error + + The byte index of the last read character in the input file. + + @note For an input with n bytes, 1 is the index of the first character and + n+1 is the index of the terminating null byte or the end of file. + This also holds true when reading a byte vector (CBOR or MessagePack). + */ + const std::size_t byte; + + private: + parse_error(int id_, std::size_t byte_, const char* what_arg) + : exception(id_, what_arg), byte(byte_) {} + + static std::string position_string(const position_t& pos) + { + return " at line " + std::to_string(pos.lines_read + 1) + + ", column " + std::to_string(pos.chars_read_current_line); + } +}; + +/*! +@brief exception indicating errors with iterators + +This exception is thrown if iterators passed to a library function do not match +the expected semantics. + +Exceptions have ids 2xx. + +name / id | example message | description +----------------------------------- | --------------- | ------------------------- +json.exception.invalid_iterator.201 | iterators are not compatible | The iterators passed to constructor @ref basic_json(InputIT first, InputIT last) are not compatible, meaning they do not belong to the same container. Therefore, the range (@a first, @a last) is invalid. +json.exception.invalid_iterator.202 | iterator does not fit current value | In an erase or insert function, the passed iterator @a pos does not belong to the JSON value for which the function was called. It hence does not define a valid position for the deletion/insertion. +json.exception.invalid_iterator.203 | iterators do not fit current value | Either iterator passed to function @ref erase(IteratorType first, IteratorType last) does not belong to the JSON value from which values shall be erased. It hence does not define a valid range to delete values from. +json.exception.invalid_iterator.204 | iterators out of range | When an iterator range for a primitive type (number, boolean, or string) is passed to a constructor or an erase function, this range has to be exactly (@ref begin(), @ref end()), because this is the only way the single stored value is expressed. All other ranges are invalid. +json.exception.invalid_iterator.205 | iterator out of range | When an iterator for a primitive type (number, boolean, or string) is passed to an erase function, the iterator has to be the @ref begin() iterator, because it is the only way to address the stored value. All other iterators are invalid. +json.exception.invalid_iterator.206 | cannot construct with iterators from null | The iterators passed to constructor @ref basic_json(InputIT first, InputIT last) belong to a JSON null value and hence to not define a valid range. +json.exception.invalid_iterator.207 | cannot use key() for non-object iterators | The key() member function can only be used on iterators belonging to a JSON object, because other types do not have a concept of a key. +json.exception.invalid_iterator.208 | cannot use operator[] for object iterators | The operator[] to specify a concrete offset cannot be used on iterators belonging to a JSON object, because JSON objects are unordered. +json.exception.invalid_iterator.209 | cannot use offsets with object iterators | The offset operators (+, -, +=, -=) cannot be used on iterators belonging to a JSON object, because JSON objects are unordered. +json.exception.invalid_iterator.210 | iterators do not fit | The iterator range passed to the insert function are not compatible, meaning they do not belong to the same container. Therefore, the range (@a first, @a last) is invalid. +json.exception.invalid_iterator.211 | passed iterators may not belong to container | The iterator range passed to the insert function must not be a subrange of the container to insert to. +json.exception.invalid_iterator.212 | cannot compare iterators of different containers | When two iterators are compared, they must belong to the same container. +json.exception.invalid_iterator.213 | cannot compare order of object iterators | The order of object iterators cannot be compared, because JSON objects are unordered. +json.exception.invalid_iterator.214 | cannot get value | Cannot get value for iterator: Either the iterator belongs to a null value or it is an iterator to a primitive type (number, boolean, or string), but the iterator is different to @ref begin(). + +@liveexample{The following code shows how an `invalid_iterator` exception can be +caught.,invalid_iterator} + +@sa - @ref exception for the base class of the library exceptions +@sa - @ref parse_error for exceptions indicating a parse error +@sa - @ref type_error for exceptions indicating executing a member function with + a wrong type +@sa - @ref out_of_range for exceptions indicating access out of the defined range +@sa - @ref other_error for exceptions indicating other library errors + +@since version 3.0.0 +*/ +class invalid_iterator : public exception +{ + public: + static invalid_iterator create(int id_, const std::string& what_arg) + { + std::string w = exception::name("invalid_iterator", id_) + what_arg; + return invalid_iterator(id_, w.c_str()); + } + + private: + JSON_HEDLEY_NON_NULL(3) + invalid_iterator(int id_, const char* what_arg) + : exception(id_, what_arg) {} +}; + +/*! +@brief exception indicating executing a member function with a wrong type + +This exception is thrown in case of a type error; that is, a library function is +executed on a JSON value whose type does not match the expected semantics. + +Exceptions have ids 3xx. + +name / id | example message | description +----------------------------- | --------------- | ------------------------- +json.exception.type_error.301 | cannot create object from initializer list | To create an object from an initializer list, the initializer list must consist only of a list of pairs whose first element is a string. When this constraint is violated, an array is created instead. +json.exception.type_error.302 | type must be object, but is array | During implicit or explicit value conversion, the JSON type must be compatible to the target type. For instance, a JSON string can only be converted into string types, but not into numbers or boolean types. +json.exception.type_error.303 | incompatible ReferenceType for get_ref, actual type is object | To retrieve a reference to a value stored in a @ref basic_json object with @ref get_ref, the type of the reference must match the value type. For instance, for a JSON array, the @a ReferenceType must be @ref array_t &. +json.exception.type_error.304 | cannot use at() with string | The @ref at() member functions can only be executed for certain JSON types. +json.exception.type_error.305 | cannot use operator[] with string | The @ref operator[] member functions can only be executed for certain JSON types. +json.exception.type_error.306 | cannot use value() with string | The @ref value() member functions can only be executed for certain JSON types. +json.exception.type_error.307 | cannot use erase() with string | The @ref erase() member functions can only be executed for certain JSON types. +json.exception.type_error.308 | cannot use push_back() with string | The @ref push_back() and @ref operator+= member functions can only be executed for certain JSON types. +json.exception.type_error.309 | cannot use insert() with | The @ref insert() member functions can only be executed for certain JSON types. +json.exception.type_error.310 | cannot use swap() with number | The @ref swap() member functions can only be executed for certain JSON types. +json.exception.type_error.311 | cannot use emplace_back() with string | The @ref emplace_back() member function can only be executed for certain JSON types. +json.exception.type_error.312 | cannot use update() with string | The @ref update() member functions can only be executed for certain JSON types. +json.exception.type_error.313 | invalid value to unflatten | The @ref unflatten function converts an object whose keys are JSON Pointers back into an arbitrary nested JSON value. The JSON Pointers must not overlap, because then the resulting value would not be well defined. +json.exception.type_error.314 | only objects can be unflattened | The @ref unflatten function only works for an object whose keys are JSON Pointers. +json.exception.type_error.315 | values in object must be primitive | The @ref unflatten function only works for an object whose keys are JSON Pointers and whose values are primitive. +json.exception.type_error.316 | invalid UTF-8 byte at index 10: 0x7E | The @ref dump function only works with UTF-8 encoded strings; that is, if you assign a `std::string` to a JSON value, make sure it is UTF-8 encoded. | +json.exception.type_error.317 | JSON value cannot be serialized to requested format | The dynamic type of the object cannot be represented in the requested serialization format (e.g. a raw `true` or `null` JSON object cannot be serialized to BSON) | + +@liveexample{The following code shows how a `type_error` exception can be +caught.,type_error} + +@sa - @ref exception for the base class of the library exceptions +@sa - @ref parse_error for exceptions indicating a parse error +@sa - @ref invalid_iterator for exceptions indicating errors with iterators +@sa - @ref out_of_range for exceptions indicating access out of the defined range +@sa - @ref other_error for exceptions indicating other library errors + +@since version 3.0.0 +*/ +class type_error : public exception +{ + public: + static type_error create(int id_, const std::string& what_arg) + { + std::string w = exception::name("type_error", id_) + what_arg; + return type_error(id_, w.c_str()); + } + + private: + JSON_HEDLEY_NON_NULL(3) + type_error(int id_, const char* what_arg) : exception(id_, what_arg) {} +}; + +/*! +@brief exception indicating access out of the defined range + +This exception is thrown in case a library function is called on an input +parameter that exceeds the expected range, for instance in case of array +indices or nonexisting object keys. + +Exceptions have ids 4xx. + +name / id | example message | description +------------------------------- | --------------- | ------------------------- +json.exception.out_of_range.401 | array index 3 is out of range | The provided array index @a i is larger than @a size-1. +json.exception.out_of_range.402 | array index '-' (3) is out of range | The special array index `-` in a JSON Pointer never describes a valid element of the array, but the index past the end. That is, it can only be used to add elements at this position, but not to read it. +json.exception.out_of_range.403 | key 'foo' not found | The provided key was not found in the JSON object. +json.exception.out_of_range.404 | unresolved reference token 'foo' | A reference token in a JSON Pointer could not be resolved. +json.exception.out_of_range.405 | JSON pointer has no parent | The JSON Patch operations 'remove' and 'add' can not be applied to the root element of the JSON value. +json.exception.out_of_range.406 | number overflow parsing '10E1000' | A parsed number could not be stored as without changing it to NaN or INF. +json.exception.out_of_range.407 | number overflow serializing '9223372036854775808' | UBJSON and BSON only support integer numbers up to 9223372036854775807. | +json.exception.out_of_range.408 | excessive array size: 8658170730974374167 | The size (following `#`) of an UBJSON array or object exceeds the maximal capacity. | +json.exception.out_of_range.409 | BSON key cannot contain code point U+0000 (at byte 2) | Key identifiers to be serialized to BSON cannot contain code point U+0000, since the key is stored as zero-terminated c-string | + +@liveexample{The following code shows how an `out_of_range` exception can be +caught.,out_of_range} + +@sa - @ref exception for the base class of the library exceptions +@sa - @ref parse_error for exceptions indicating a parse error +@sa - @ref invalid_iterator for exceptions indicating errors with iterators +@sa - @ref type_error for exceptions indicating executing a member function with + a wrong type +@sa - @ref other_error for exceptions indicating other library errors + +@since version 3.0.0 +*/ +class out_of_range : public exception +{ + public: + static out_of_range create(int id_, const std::string& what_arg) + { + std::string w = exception::name("out_of_range", id_) + what_arg; + return out_of_range(id_, w.c_str()); + } + + private: + JSON_HEDLEY_NON_NULL(3) + out_of_range(int id_, const char* what_arg) : exception(id_, what_arg) {} +}; + +/*! +@brief exception indicating other library errors + +This exception is thrown in case of errors that cannot be classified with the +other exception types. + +Exceptions have ids 5xx. + +name / id | example message | description +------------------------------ | --------------- | ------------------------- +json.exception.other_error.501 | unsuccessful: {"op":"test","path":"/baz", "value":"bar"} | A JSON Patch operation 'test' failed. The unsuccessful operation is also printed. + +@sa - @ref exception for the base class of the library exceptions +@sa - @ref parse_error for exceptions indicating a parse error +@sa - @ref invalid_iterator for exceptions indicating errors with iterators +@sa - @ref type_error for exceptions indicating executing a member function with + a wrong type +@sa - @ref out_of_range for exceptions indicating access out of the defined range + +@liveexample{The following code shows how an `other_error` exception can be +caught.,other_error} + +@since version 3.0.0 +*/ +class other_error : public exception +{ + public: + static other_error create(int id_, const std::string& what_arg) + { + std::string w = exception::name("other_error", id_) + what_arg; + return other_error(id_, w.c_str()); + } + + private: + JSON_HEDLEY_NON_NULL(3) + other_error(int id_, const char* what_arg) : exception(id_, what_arg) {} +}; +} // namespace detail +} // namespace nlohmann + +// #include + +// #include + + +#include // not +#include // size_t +#include // conditional, enable_if, false_type, integral_constant, is_constructible, is_integral, is_same, remove_cv, remove_reference, true_type + +namespace nlohmann +{ +namespace detail +{ +// alias templates to reduce boilerplate +template +using enable_if_t = typename std::enable_if::type; + +template +using uncvref_t = typename std::remove_cv::type>::type; + +// implementation of C++14 index_sequence and affiliates +// source: https://stackoverflow.com/a/32223343 +template +struct index_sequence +{ + using type = index_sequence; + using value_type = std::size_t; + static constexpr std::size_t size() noexcept + { + return sizeof...(Ints); + } +}; + +template +struct merge_and_renumber; + +template +struct merge_and_renumber, index_sequence> + : index_sequence < I1..., (sizeof...(I1) + I2)... > {}; + +template +struct make_index_sequence + : merge_and_renumber < typename make_index_sequence < N / 2 >::type, + typename make_index_sequence < N - N / 2 >::type > {}; + +template<> struct make_index_sequence<0> : index_sequence<> {}; +template<> struct make_index_sequence<1> : index_sequence<0> {}; + +template +using index_sequence_for = make_index_sequence; + +// dispatch utility (taken from ranges-v3) +template struct priority_tag : priority_tag < N - 1 > {}; +template<> struct priority_tag<0> {}; + +// taken from ranges-v3 +template +struct static_const +{ + static constexpr T value{}; +}; + +template +constexpr T static_const::value; +} // namespace detail +} // namespace nlohmann + +// #include + + +#include // not +#include // numeric_limits +#include // false_type, is_constructible, is_integral, is_same, true_type +#include // declval + +// #include + + +#include // random_access_iterator_tag + +// #include + + +namespace nlohmann +{ +namespace detail +{ +template struct make_void +{ + using type = void; +}; +template using void_t = typename make_void::type; +} // namespace detail +} // namespace nlohmann + +// #include + + +namespace nlohmann +{ +namespace detail +{ +template +struct iterator_types {}; + +template +struct iterator_types < + It, + void_t> +{ + using difference_type = typename It::difference_type; + using value_type = typename It::value_type; + using pointer = typename It::pointer; + using reference = typename It::reference; + using iterator_category = typename It::iterator_category; +}; + +// This is required as some compilers implement std::iterator_traits in a way that +// doesn't work with SFINAE. See https://github.com/nlohmann/json/issues/1341. +template +struct iterator_traits +{ +}; + +template +struct iterator_traits < T, enable_if_t < !std::is_pointer::value >> + : iterator_types +{ +}; + +template +struct iterator_traits::value>> +{ + using iterator_category = std::random_access_iterator_tag; + using value_type = T; + using difference_type = ptrdiff_t; + using pointer = T*; + using reference = T&; +}; +} // namespace detail +} // namespace nlohmann + +// #include + +// #include + +// #include + + +#include + +// #include + + +// http://en.cppreference.com/w/cpp/experimental/is_detected +namespace nlohmann +{ +namespace detail +{ +struct nonesuch +{ + nonesuch() = delete; + ~nonesuch() = delete; + nonesuch(nonesuch const&) = delete; + nonesuch(nonesuch const&&) = delete; + void operator=(nonesuch const&) = delete; + void operator=(nonesuch&&) = delete; +}; + +template class Op, + class... Args> +struct detector +{ + using value_t = std::false_type; + using type = Default; +}; + +template class Op, class... Args> +struct detector>, Op, Args...> +{ + using value_t = std::true_type; + using type = Op; +}; + +template