├── .gitignore ├── LICENSE ├── README.md ├── SqlBrowserFX.exe ├── build.sh ├── create-jre.sh ├── images └── sqlbrowserfx.png ├── increaseVersion.groovy ├── install.sh ├── l4j-config.xml ├── logo.txt ├── pom.xml ├── prepare-version.sh ├── sqlbrowser-for-build.db ├── sqlbrowser-fx.ico ├── sqlbrowserfx.properties ├── src ├── main │ ├── java │ │ ├── gr │ │ │ └── sqlbrowserfx │ │ │ │ ├── GUIStarter.java │ │ │ │ ├── LoggerConf.java │ │ │ │ ├── SqlBrowserFXApp.java │ │ │ │ ├── SqlBrowserFXAppManager.java │ │ │ │ ├── SqlBrowserFXAppWithoutDocking.java │ │ │ │ ├── conn │ │ │ │ ├── DbCash.java │ │ │ │ ├── MysqlConnector.java │ │ │ │ ├── PostgreSqlConnector.java │ │ │ │ ├── ResultSetAction.java │ │ │ │ ├── SqlConnector.java │ │ │ │ ├── SqlServerConnector.java │ │ │ │ ├── SqlTable.java │ │ │ │ ├── SqliteConnector.java │ │ │ │ ├── StatementAction.java │ │ │ │ └── UpdateQuery.java │ │ │ │ ├── dock │ │ │ │ └── nodes │ │ │ │ │ ├── DDBTreePane.java │ │ │ │ │ ├── DDBTreeView.java │ │ │ │ │ ├── DDbDiagramPane.java │ │ │ │ │ ├── DLogConsolePane.java │ │ │ │ │ ├── DSqlConsolePane.java │ │ │ │ │ ├── DSqlConsolePaneNH.java │ │ │ │ │ └── DSqlPane.java │ │ │ │ ├── factories │ │ │ │ └── DialogFactory.java │ │ │ │ ├── listeners │ │ │ │ ├── SimpleEvent.java │ │ │ │ ├── SimpleObservable.java │ │ │ │ ├── SimpleObserver.java │ │ │ │ ├── TableColumnFilteringEvent.java │ │ │ │ └── TableSearchFilteringEvent.java │ │ │ │ ├── nodes │ │ │ │ ├── ColumnCreationBox.java │ │ │ │ ├── ContextMenuOwner.java │ │ │ │ ├── DBTreeView.java │ │ │ │ ├── DbConfigBox.java │ │ │ │ ├── DbDiagramPane.java │ │ │ │ ├── FileSearchPopOver.java │ │ │ │ ├── FilesTreeView.java │ │ │ │ ├── HelpShortcutsTabPane.java │ │ │ │ ├── HelpTabPane.java │ │ │ │ ├── InputMapOwner.java │ │ │ │ ├── LogConsolePane.java │ │ │ │ ├── MySqlConfigBox.java │ │ │ │ ├── NoSelectionModel.java │ │ │ │ ├── PostgreSqlConfigBox.java │ │ │ │ ├── SearchAndReplacePopOver.java │ │ │ │ ├── SimpleTerminalPane.java │ │ │ │ ├── SqlConnectorType.java │ │ │ │ ├── SqlConsolePane.java │ │ │ │ ├── SqlServerConfigBox.java │ │ │ │ ├── SqlTableNode.java │ │ │ │ ├── TableCreationPane.java │ │ │ │ ├── ToolbarOwner.java │ │ │ │ ├── TreeViewFile.java │ │ │ │ ├── codeareas │ │ │ │ │ ├── AutoCompleteCodeArea.java │ │ │ │ │ ├── CodeAreaSyntaxProvider.java │ │ │ │ │ ├── FileCodeArea.java │ │ │ │ │ ├── FormatterMode.java │ │ │ │ │ ├── HighLighter.java │ │ │ │ │ ├── Keyword.java │ │ │ │ │ ├── KeywordType.java │ │ │ │ │ ├── SearchableCodeArea.java │ │ │ │ │ ├── SimpleFileCodeArea.java │ │ │ │ │ ├── SimpleFileCodeAreaSyntaxProvider.java │ │ │ │ │ ├── SuggestionListCell.java │ │ │ │ │ ├── TextAnalyzer.java │ │ │ │ │ ├── java │ │ │ │ │ │ ├── FileJavaCodeArea.java │ │ │ │ │ │ ├── JavaCodeArea.java │ │ │ │ │ │ └── JavaCodeAreaSyntaxProvider.java │ │ │ │ │ ├── log │ │ │ │ │ │ ├── CodeAreaTailerListener.java │ │ │ │ │ │ ├── LogCodeArea.java │ │ │ │ │ │ └── LogCodeAreaSyntaxProvider.java │ │ │ │ │ └── sql │ │ │ │ │ │ ├── CSqlCodeArea.java │ │ │ │ │ │ ├── FileSqlCodeArea.java │ │ │ │ │ │ ├── HistorySqlCodeArea.java │ │ │ │ │ │ ├── PHistorySqlCodeArea.java │ │ │ │ │ │ ├── SimpleLineNumberFactory.java │ │ │ │ │ │ ├── SqlCodeArea.java │ │ │ │ │ │ └── SqlCodeAreaSyntaxProvider.java │ │ │ │ ├── queriesmenu │ │ │ │ │ ├── QueriesMenu.java │ │ │ │ │ └── QueryDTO.java │ │ │ │ ├── sqlpane │ │ │ │ │ ├── CustomPopOver.java │ │ │ │ │ ├── DraggingTabPaneSupport.java │ │ │ │ │ ├── SimpleSqlPane.java │ │ │ │ │ ├── SqlPane.java │ │ │ │ │ ├── SqlTableRowEditBox.java │ │ │ │ │ └── SqlTableTab.java │ │ │ │ └── tableviews │ │ │ │ │ ├── EditableCell.java │ │ │ │ │ ├── HistorySqlTableView.java │ │ │ │ │ ├── JSONTableView.java │ │ │ │ │ ├── MapTableViewRow.java │ │ │ │ │ ├── SqlTableView.java │ │ │ │ │ ├── SqlTableViewCell.java │ │ │ │ │ ├── SqlTableViewEditableCell.java │ │ │ │ │ ├── TableViewCellEditArea.java │ │ │ │ │ ├── TableViewCellEditField.java │ │ │ │ │ └── filter │ │ │ │ │ ├── ColumnFilter.java │ │ │ │ │ ├── DupeCounter.java │ │ │ │ │ ├── FilterPanel.java │ │ │ │ │ ├── FilterValue.java │ │ │ │ │ ├── SqlTableFilter.java │ │ │ │ │ ├── TableFilter.java │ │ │ │ │ └── TableViewUtils.java │ │ │ │ ├── rest │ │ │ │ ├── RESTfulService.java │ │ │ │ └── RESTfulServiceConfig.java │ │ │ │ └── utils │ │ │ │ ├── FilesUtils.java │ │ │ │ ├── HttpClient.java │ │ │ │ ├── JavaFXUtils.java │ │ │ │ ├── MemoryGuard.java │ │ │ │ ├── PropertiesLoader.java │ │ │ │ ├── Property.java │ │ │ │ ├── SqlFormatter.java │ │ │ │ └── mapper │ │ │ │ ├── Column.java │ │ │ │ ├── DTO.java │ │ │ │ └── DTOMapper.java │ │ ├── org │ │ │ └── dockfx │ │ │ │ ├── DockEvent.java │ │ │ │ ├── DockNode.java │ │ │ │ ├── DockPane.java │ │ │ │ ├── DockPos.java │ │ │ │ ├── DockTabPane.java │ │ │ │ ├── DockTitleBar.java │ │ │ │ ├── DockWeights.java │ │ │ │ └── Dockable.java │ │ └── res-to-styles.sh │ └── resources │ │ ├── log4j2.properties │ │ └── styles │ │ ├── classic.css │ │ ├── fix-missing-icons.sh │ │ ├── flat-dark.css │ │ ├── flat-dark │ │ └── icons │ │ │ ├── add.png │ │ │ ├── blue.png │ │ │ ├── chart-pie.png │ │ │ ├── chart.png │ │ │ ├── check.png │ │ │ ├── clear.png │ │ │ ├── close-win-w.png │ │ │ ├── close-win.png │ │ │ ├── close.png │ │ │ ├── code-file.png │ │ │ ├── collapse.png │ │ │ ├── columns.png │ │ │ ├── compare.png │ │ │ ├── console.png │ │ │ ├── copy.png │ │ │ ├── csv-import.png │ │ │ ├── csv.png │ │ │ ├── cut.png │ │ │ ├── database.png │ │ │ ├── details.png │ │ │ ├── diagram.png │ │ │ ├── edit.png │ │ │ ├── filter.png │ │ │ ├── folder.png │ │ │ ├── foreign-key.png │ │ │ ├── format.png │ │ │ ├── function.png │ │ │ ├── green.png │ │ │ ├── help.png │ │ │ ├── icons8-pulse-20.png │ │ │ ├── index.png │ │ │ ├── javalin-logo.png │ │ │ ├── lowercase.png │ │ │ ├── m-database.png │ │ │ ├── magnify.png │ │ │ ├── mariadb.png │ │ │ ├── maximize-win-w.png │ │ │ ├── maximize-win.png │ │ │ ├── maximize.png │ │ │ ├── menu-edit.png │ │ │ ├── menu.png │ │ │ ├── minus.png │ │ │ ├── monitor.png │ │ │ ├── mysql.png │ │ │ ├── next.png │ │ │ ├── no.png │ │ │ ├── old │ │ │ ├── add.png │ │ │ ├── check.png │ │ │ ├── clear.png │ │ │ ├── code-file.png │ │ │ ├── collapse.png │ │ │ ├── columns.png │ │ │ ├── compare.png │ │ │ ├── console.png │ │ │ ├── copy.png │ │ │ ├── csv-import.png │ │ │ ├── csv.png │ │ │ ├── cut.png │ │ │ ├── database.png │ │ │ ├── details.png │ │ │ ├── edit.png │ │ │ ├── filter.png │ │ │ ├── foreign-key.png │ │ │ ├── format.png │ │ │ ├── function.png │ │ │ ├── help.png │ │ │ ├── icons8-lightning-bolt-20.png │ │ │ ├── index.png │ │ │ ├── lowercase.png │ │ │ ├── magnify.png │ │ │ ├── minus.png │ │ │ ├── monitor.png │ │ │ ├── next.png │ │ │ ├── no.png │ │ │ ├── open-view.png │ │ │ ├── openTab.png │ │ │ ├── paste.png │ │ │ ├── play.png │ │ │ ├── primary-key.png │ │ │ ├── procedure.png │ │ │ ├── refresh.png │ │ │ ├── replace.png │ │ │ ├── save.png │ │ │ ├── script.png │ │ │ ├── settings.png │ │ │ ├── stop.png │ │ │ ├── structure.png │ │ │ ├── suggestion.png │ │ │ ├── table-e.png │ │ │ ├── table-settings.png │ │ │ ├── table-y.png │ │ │ ├── table.png │ │ │ ├── thunder.png │ │ │ ├── transaction.png │ │ │ ├── trigger.png │ │ │ ├── uppercase.png │ │ │ ├── view.png │ │ │ ├── web.png │ │ │ ├── yes.png │ │ │ └── zoom.png │ │ │ ├── open-view.png │ │ │ ├── openTab.png │ │ │ ├── paste.png │ │ │ ├── pin.png │ │ │ ├── play.png │ │ │ ├── postgre.png │ │ │ ├── primary-key.png │ │ │ ├── procedure.png │ │ │ ├── red.png │ │ │ ├── refresh.png │ │ │ ├── replace.png │ │ │ ├── restore-win-w.png │ │ │ ├── restore-win.png │ │ │ ├── restore.png │ │ │ ├── save.png │ │ │ ├── script.png │ │ │ ├── settings.png │ │ │ ├── spark.png │ │ │ ├── sqlbrowser-fx.png │ │ │ ├── sqlite.png │ │ │ ├── sqlserver.png │ │ │ ├── stop.png │ │ │ ├── structure.png │ │ │ ├── suggestion.png │ │ │ ├── table-e.png │ │ │ ├── table-settings.png │ │ │ ├── table-y.png │ │ │ ├── table.png │ │ │ ├── thunder.png │ │ │ ├── transaction.png │ │ │ ├── trigger.png │ │ │ ├── uppercase.png │ │ │ ├── var.png │ │ │ ├── view.png │ │ │ ├── web.png │ │ │ ├── yes.png │ │ │ └── zoom.png │ │ ├── flat-dark2.css │ │ ├── flat-gray.css │ │ └── flat-purple.css └── test │ └── java │ └── sqlbrowserfx │ ├── FilesTreeViewTestGui.java │ ├── GuiTestStarter.java │ ├── JavaCodeAreaTestGui.java │ ├── JsonTableViewTestGui.java │ ├── SqlPaneTestGui.java │ └── TableCreationPaneTestGui.java └── starters ├── SqlBrowserFX.exe └── sqlbrowserfx.sh /.gitignore: -------------------------------------------------------------------------------- 1 | .classpath 2 | .project 3 | .settings 4 | logs 5 | out 6 | target 7 | lib 8 | *.log 9 | dist 10 | .gradle/ 11 | .idea/ 12 | sqlbrowserfx.iml 13 | sqlbrowser.db 14 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019-2023 Paris Kolovos 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SqlBrowserFX 2 | 3 | SqlBrowserFX is a feature rich cross platform sql client for SQLite , MySQL, MariaDB and PostgreSQL (partially supported). 4 | 5 | ![](images/sqlbrowserfx.png) 6 | 7 | ### Features 8 | 9 | * Manage data (insert, update, delete) via gui. 10 | * Execute raw sql queries. 11 | * Editor for sql with syntax highlighting, autocomplete, refactoring features. 12 | * Support for sql, java files editing via drag and drop. 13 | * Adjustable responsive ui supporting multiple code areas and tables opened at the same time. 14 | * Graphical representation of database as tree. 15 | * Graphical representation of database as diagram. 16 | * Exposure of database to the web as RESTful service with one click. 17 | * Import, export csv files. 18 | * Queries History. 19 | * Savable queries. 20 | * Support for SQLite. 21 | * Support for MySQL, MariaDB. 22 | * Partial Support for PostgreSQL. 23 | * Cross Platform. 24 | * Css themable (Dark, Light etc). 25 | * Generation of simple database tables diagram. 26 | 27 | ### Prerequisites 28 | 29 | * Java 21 + 30 | * Installation of desired database. 31 | 32 | ### Installing 33 | 34 | Copy sqlbrowser-for-build.db to sqlbrowser.db. 35 | Import the project to your favorite ide as maven project and run GUIStarter class. 36 | You can also run install.sh script , if you are using linux in order to install sqlbrowserfx as cli command 37 | 'sqlfx'. 38 | 39 | ### Compatibility with older versions of java 40 | * Tag 2.5.0 -> Java 17 41 | * Tag 1.5.0 -> Java 8 42 | 43 | 44 | ### Build standalone app 45 | 46 | Run build.sh script, this will generate all files needed in 'dist' folder. 47 | Run SqlBrowserFX.exe for Windows, or run sqlbrowserfx.sh for Linux. 48 | 49 | 50 | ## Awesome projects used 51 | 52 | * [DockFX](https://github.com/RobertBColton/DockFX) - The docking framework used (a moded version actually). 53 | * [RichTextFΧ](https://github.com/FXMisc/RichTextFX) - Library which provides editor with syntax highlighting feature. 54 | * [ControlsFX](https://github.com/controlsfx/controlsfx) - Library which provides many useful custom gui components. 55 | * [Spark Java](https://github.com/perwendel/spark) - The web framework used. (Until version 1.5.0) 56 | * [Javalin](https://github.com/tipsy/javalin) - The NEW web framework used. 57 | * [Icons8](https://icons8.com/) - The icons used. 58 | 59 | 60 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /SqlBrowserFX.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pariskol/sqlbrowserfx/433976953de44268e2e9bca634e12547cd14a886/SqlBrowserFX.exe -------------------------------------------------------------------------------- /build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | get_version_from_pom() { 4 | grep -ioh -m 1 ".*" pom.xml | sed "s///g" | sed "s/<\/version>//g" 5 | } 6 | 7 | cd "$(dirname "$0")" 8 | 9 | pom=pom.xml 10 | [ ! -z "$1" ] && pom=$1 11 | 12 | rm -rf dist 13 | mkdir -p dist/sqlbrowserfx/lib 14 | 15 | mvn clean package -f $pom 16 | if [ $? -ne 0 ] 17 | then 18 | echo "Error : could not package project!" 19 | exit 1 20 | fi 21 | mvn dependency:copy-dependencies 22 | if [ $? -ne 0 ] 23 | then 24 | echo "Error : could not download dependencies!" 25 | exit 2 26 | fi 27 | 28 | 29 | cp target/sqlbrowserfx*.jar dist/sqlbrowserfx/sqlbrowserfx.jar 30 | cp target/dependency/* dist/sqlbrowserfx/lib 31 | cp log4j.properties dist/sqlbrowserfx/ 32 | cp sqlbrowser-for-build.db dist/sqlbrowserfx/sqlbrowser.db 33 | cp starters/* dist/sqlbrowserfx/ 34 | cp sqlbrowserfx.properties dist/sqlbrowserfx/ 35 | 36 | version=$(get_version_from_pom) 37 | chmod +x dist/sqlbrowserfx/*.sh 38 | cd dist 39 | 40 | tar -czvf sqlbrowserfx-$version.tar.gz * 41 | -------------------------------------------------------------------------------- /create-jre.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | modules="java.base,java.datatransfer,java.desktop,jdk.unsupported,java.logging,java.sql" 4 | jlink --no-header-files --no-man-pages --compress=2 --strip-debug --add-modules $modules --output jre 5 | -------------------------------------------------------------------------------- /images/sqlbrowserfx.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pariskol/sqlbrowserfx/433976953de44268e2e9bca634e12547cd14a886/images/sqlbrowserfx.png -------------------------------------------------------------------------------- /increaseVersion.groovy: -------------------------------------------------------------------------------- 1 | 2 | version=args[0] 3 | 4 | split=version.split("\\.") 5 | newMinor=split[2].toInteger() + 1 6 | split[2]=newMinor 7 | 8 | println(split.join(".")) 9 | 10 | -------------------------------------------------------------------------------- /install.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | cat logo.txt 4 | ./build.sh 5 | mkdir -p ~/sqlbrowserfx 6 | cp -r dist/sqlbrowserfx/* ~/sqlbrowserfx/ 7 | cp starters/sqlbrowserfx.sh ~/sqlbrowserfx/ 8 | echo 9 | echo "Fixing starter script.." 10 | #sed -i "s|#JAVA_HOME|export JAVA_HOME=$JAVA_HOME/bin|g" ~/sqlbrowserfx/sqlbrowserfx.sh 11 | chmod +x ~/sqlbrowserfx/sqlbrowserfx.sh 12 | echo "Checking for .bash_aliases..." 13 | [ ! -f .bash_aliases ] && touch ~/.bash_aliases 14 | echo "Adding alias for SqlBrowserFX..." 15 | [ $(grep -c "sqlfx" ~/.bash_aliases) -eq 0 ] && echo "alias sqlfx=~/sqlbrowserfx/sqlbrowserfx.sh" >> ~/.bash_aliases 16 | source ~/.bashrc 17 | echo 18 | echo "Installation finished" 19 | echo 20 | echo "Start sqlbrowserdfx from cli by running sqlfx" -------------------------------------------------------------------------------- /l4j-config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | true 4 | gui 5 | ./sqlbrowserfx.jar 6 | ./SqlBrowserFX.exe 7 | 8 | 9 | . 10 | high 11 | 12 | 13 | false 14 | false 15 | 16 | ./sqlbrowser-fx.ico 17 | 18 | gr.sqlbrowserfx.GUIStarter 19 | ./lib/* 20 | 21 | 22 | jre 23 | false 24 | true 25 | 21 26 | 27 | -Xmx512m -Xms128m -XX:+UseG1GC -XX:MaxGCPauseMillis=100 28 | 29 | 30 | -------------------------------------------------------------------------------- /logo.txt: -------------------------------------------------------------------------------- 1 | _____ _ ____ ________ __ 2 | / ____| | | _ \ | ____\ \ / / 3 | | (___ __ _| | |_) |_ __ _____ _____ ___ _ __| |__ \ V / 4 | \___ \ / _` | | _ <| '__/ _ \ \ /\ / / __|/ _ \ '__| __| > < 5 | ____) | (_| | | |_) | | | (_) \ V V /\__ \ __/ | | | / . \ 6 | |_____/ \__, |_|____/|_| \___/ \_/\_/ |___/\___|_| |_| /_/ \_\ 7 | | | 8 | |_| 9 | -------------------------------------------------------------------------------- /prepare-version.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | cd "$(dirname "$0")" 4 | 5 | version=$1 6 | 7 | if [ -z "$version" ] 8 | then 9 | echo "Provide target version!" 10 | exit 1 11 | fi 12 | # check groovy 13 | groovy -version || exit 2 14 | 15 | sed -i "0,/.*<\/version>/s//$version<\/version>/" pom.xml 16 | git add pom.xml 17 | git commit -m "prepare realase $version" 18 | git tag $version 19 | git push --tags 20 | 21 | newVersion=$(groovy increaseVersion.groovy $version) 22 | sed -i "0,/.*<\/version>/s//$newVersion-SNAPSHOT<\/version>/" pom.xml 23 | git add pom.xml 24 | git commit -m "restore pom after release" 25 | git push origin development 26 | git checkout master 27 | git merge $version 28 | git push origin master 29 | git checkout development 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /sqlbrowser-for-build.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pariskol/sqlbrowserfx/433976953de44268e2e9bca634e12547cd14a886/sqlbrowser-for-build.db -------------------------------------------------------------------------------- /sqlbrowser-fx.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pariskol/sqlbrowserfx/433976953de44268e2e9bca634e12547cd14a886/sqlbrowser-fx.ico -------------------------------------------------------------------------------- /sqlbrowserfx.properties: -------------------------------------------------------------------------------- 1 | # classic, flat-dark, flat-dark2, flat-gray, flat-purple 2 | sqlbrowserfx.css.theme=flat-dark 3 | #sqlbrowserfx.jmetro.theme=dark 4 | # normal, simple, advanced 5 | sqlbrowserfx.mode=advanced 6 | sqlbrowserfx.default.editmode.cell=false 7 | sqlbrowserfx.root.path=/home/paris/eclipse-workspace 8 | sqlconnector.enable.autocommit=true 9 | -------------------------------------------------------------------------------- /src/main/java/gr/sqlbrowserfx/GUIStarter.java: -------------------------------------------------------------------------------- 1 | package gr.sqlbrowserfx; 2 | 3 | import gr.sqlbrowserfx.utils.PropertiesLoader; 4 | 5 | public class GUIStarter { 6 | 7 | public static void main(String[] args) { 8 | if (PropertiesLoader.getProperty("sqlbrowserfx.mode", String.class, "advanced").equals("advanced")) 9 | SqlBrowserFXApp.main(args); 10 | else 11 | SqlBrowserFXAppWithoutDocking.main(args); 12 | } 13 | 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/gr/sqlbrowserfx/LoggerConf.java: -------------------------------------------------------------------------------- 1 | package gr.sqlbrowserfx; 2 | 3 | public class LoggerConf { 4 | 5 | public static final String LOGGER_NAME = "sqlbrowserfx"; 6 | 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/gr/sqlbrowserfx/SqlBrowserFXAppManager.java: -------------------------------------------------------------------------------- 1 | package gr.sqlbrowserfx; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | import java.util.Objects; 6 | import java.util.stream.Collectors; 7 | 8 | import gr.sqlbrowserfx.conn.SqlConnector; 9 | import gr.sqlbrowserfx.conn.SqliteConnector; 10 | import gr.sqlbrowserfx.dock.nodes.DDBTreeView; 11 | import gr.sqlbrowserfx.dock.nodes.DSqlConsolePane; 12 | import gr.sqlbrowserfx.dock.nodes.DSqlPane; 13 | import gr.sqlbrowserfx.nodes.sqlpane.SqlPane; 14 | 15 | public class SqlBrowserFXAppManager { 16 | 17 | public final static String INTERNAL_DB_PATH = "./sqlbrowser.db"; 18 | 19 | private static final SqlConnector SQL_CONNECTOR = new SqliteConnector(INTERNAL_DB_PATH); 20 | private static final List DSQL_PANES = new ArrayList<>(); 21 | private static final List SQL_PANES = new ArrayList<>(); 22 | private static final List DB_TREE_VIEWS = new ArrayList<>(); 23 | private static String DB_TYPE = "sqlite"; 24 | 25 | public static SqlConnector getConfigSqlConnector() { 26 | return SQL_CONNECTOR; 27 | } 28 | 29 | public static void registerDSqlPane(DSqlPane sqlPane) { 30 | DSQL_PANES.add(sqlPane); 31 | DB_TREE_VIEWS.forEach(DDBTreeView::populateSqlPanesMenu); 32 | } 33 | 34 | public static void registerSqlPane(SqlPane sqlPane) { 35 | SQL_PANES.add(sqlPane); 36 | DB_TREE_VIEWS.forEach(DDBTreeView::populateSqlPanesMenu); 37 | } 38 | 39 | public static List getActiveSqlPanes() { 40 | List sqlPanes = DSQL_PANES.stream().map(sp -> (SqlPane) sp).collect(Collectors.toList()); 41 | sqlPanes.addAll(SQL_PANES); 42 | return sqlPanes.stream().filter(Objects::nonNull).collect(Collectors.toList()); 43 | } 44 | 45 | public static long getActiveSqlCodeAreasNum() { 46 | return DSQL_PANES.stream().filter(x -> x.getSqlCodeAreaRef() != null).count(); 47 | } 48 | 49 | public static DSqlConsolePane getFirstActiveDSqlConsolePane() { 50 | DSqlPane activeSqlPane = DSQL_PANES.stream() 51 | .filter(sqlPane -> sqlPane.getSqlConsolePane() != null) 52 | .findFirst() 53 | .orElse(null); 54 | 55 | if (activeSqlPane != null) { 56 | return activeSqlPane.getSqlConsolePane(); 57 | } 58 | 59 | return null; 60 | } 61 | 62 | public static void unregisterDSqlPane(DSqlPane sqlPane) { 63 | DSQL_PANES.remove(sqlPane); 64 | DB_TREE_VIEWS.forEach(DDBTreeView::populateSqlPanesMenu); 65 | } 66 | 67 | public static String getDBtype() { 68 | return DB_TYPE; 69 | } 70 | 71 | public static void setDBtype(String type) { 72 | DB_TYPE = type; 73 | } 74 | 75 | public static void registerDDBTreeView(DDBTreeView treeView) { 76 | DB_TREE_VIEWS.add(treeView); 77 | } 78 | 79 | public static void unregisterDDBTreeView(DDBTreeView treeView) { 80 | DB_TREE_VIEWS.remove(treeView); 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/main/java/gr/sqlbrowserfx/conn/DbCash.java: -------------------------------------------------------------------------------- 1 | package gr.sqlbrowserfx.conn; 2 | 3 | import java.util.HashMap; 4 | import java.util.List; 5 | import java.util.Map; 6 | 7 | public class DbCash { 8 | private static final Map SCHEMAS_MAP = new HashMap<>(); 9 | private static final Map TABLES_MAP = new HashMap<>(); 10 | 11 | 12 | 13 | public static synchronized String getSchemaFor(String table) { 14 | return SCHEMAS_MAP.get(table); 15 | } 16 | 17 | public static synchronized void addSchemaFor(String table, String schema) { 18 | SCHEMAS_MAP.put(table, schema); 19 | } 20 | 21 | public static synchronized void addTable(SqlTable table) { 22 | TABLES_MAP.put(table.getName(), table); 23 | } 24 | 25 | public static synchronized SqlTable getTable(String table) { 26 | return TABLES_MAP.get(table); 27 | } 28 | 29 | public static List getAllTableNames() { 30 | return TABLES_MAP.values().stream().map(SqlTable::getName).toList(); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/gr/sqlbrowserfx/conn/PostgreSqlConnector.java: -------------------------------------------------------------------------------- 1 | package gr.sqlbrowserfx.conn; 2 | 3 | import java.sql.Connection; 4 | import java.sql.Date; 5 | import java.sql.SQLException; 6 | import java.sql.Timestamp; 7 | import java.util.ArrayList; 8 | import java.util.Arrays; 9 | import java.util.List; 10 | 11 | import javax.sql.DataSource; 12 | 13 | import org.apache.commons.dbcp2.BasicDataSource; 14 | import org.slf4j.LoggerFactory; 15 | 16 | import gr.sqlbrowserfx.LoggerConf; 17 | 18 | public class PostgreSqlConnector extends SqlConnector { 19 | 20 | public PostgreSqlConnector(String url, String database, String user, String password) { 21 | super("org.postgresql.Driver", url, user, password); 22 | 23 | } 24 | 25 | @Override 26 | protected DataSource initDatasource() { 27 | BasicDataSource dbcp2DataSource = new BasicDataSource(); 28 | dbcp2DataSource.setDriverClassName(this.getDriver()); 29 | dbcp2DataSource.setUrl(this.getUrl()); 30 | dbcp2DataSource.setUsername(this.getUser()); 31 | dbcp2DataSource.setPassword(this.getPassword()); 32 | dbcp2DataSource.setInitialSize(4); 33 | dbcp2DataSource.setMaxTotal(4); 34 | 35 | return dbcp2DataSource; 36 | } 37 | 38 | @Override 39 | public Object castToDBType(SqlTable table, String label, String value) { 40 | Object actualValue; 41 | if (table.getColumnsMap().get(label).contains("int") && value != null && !value.isEmpty()) { 42 | actualValue = Integer.parseInt(value); 43 | } else if (table.getColumnsMap().get(label).equals("numeric") && value != null && !value.isEmpty()) { 44 | actualValue = Double.parseDouble(value); 45 | } 46 | else if (table.getColumnsMap().get(label).contains("bool") && value != null && !value.isEmpty()) { 47 | actualValue = Boolean.parseBoolean(value); 48 | } 49 | else if (table.getColumnsMap().get(label).contains("date") && value != null && !value.isEmpty()) { 50 | actualValue = Date.valueOf(value); 51 | } 52 | else if (table.getColumnsMap().get(label).contains("stamp") && value != null && !value.isEmpty()) { 53 | actualValue = Timestamp.valueOf(value); 54 | } 55 | else { 56 | actualValue = value; 57 | } 58 | return actualValue; 59 | } 60 | 61 | 62 | @Override 63 | public String getContentsQuery() { 64 | return "select tb.table_name, tb.table_type from INFORMATION_SCHEMA.tables as tb WHERE tb.table_schema = ANY (current_schemas(false))" 65 | + " union " 66 | + "select indexname as table_name , 'INDEX'as table_type from pg_indexes where schemaname = 'public'"; 67 | } 68 | 69 | @Override 70 | public String getDbSchema() { 71 | return "public"; 72 | } 73 | 74 | @Override 75 | public void getTriggers(String table, ResultSetAction action) throws SQLException { 76 | String query = 77 | "select event_object_schema as table_schema, " 78 | + " event_object_table as table_name, " 79 | + " trigger_schema, " 80 | + " trigger_name as TRIGGER_NAME, " 81 | + " string_agg(event_manipulation, ',') as event, " 82 | + " action_timing as activation, " 83 | + " action_condition as condition, " 84 | + " action_statement as ACTION_STATEMENT " 85 | + "from information_schema.triggers " 86 | + "where event_object_table = ? " 87 | + "group by 1,2,3,4,6,7,8 " 88 | + "order by table_schema, " 89 | + " table_name;"; 90 | this.executeQuery(query, Arrays.asList(table), action); 91 | 92 | } 93 | 94 | @Override 95 | public void getSchema(String name, ResultSetAction action) throws SQLException { 96 | this.executeQuery( 97 | "select table_name, view_definition as schema from INFORMATION_SCHEMA.views " 98 | + "WHERE table_schema = ANY (current_schemas(false)) and table_name = ?", 99 | Arrays.asList(name), action); 100 | } 101 | 102 | @Override 103 | public String getTableSchemaColumn() { 104 | return "schema"; 105 | } 106 | 107 | @Override 108 | public String getViewSchemaColumn() { 109 | return "schema"; 110 | } 111 | 112 | @Override 113 | public String getIndexSchemaColumn() { 114 | return "schema"; 115 | } 116 | 117 | @Override 118 | public void commitAll() { 119 | BasicDataSource dataSource = (BasicDataSource) this.getDataSource(); 120 | List connections = new ArrayList<>(); 121 | Connection conn = null; 122 | try { 123 | int activeConnections = dataSource.getNumIdle(); 124 | for (int i = 0; i < activeConnections; i++) { 125 | conn = dataSource.getConnection(); 126 | conn.commit(); 127 | connections.add(conn); 128 | } 129 | LoggerFactory.getLogger(LoggerConf.LOGGER_NAME).debug(activeConnections + " connections commited"); 130 | } catch (SQLException e) { 131 | LoggerFactory.getLogger(LoggerConf.LOGGER_NAME).error("Failed to commit changes , about to rollback", e); 132 | this.rollbackQuietly(conn); 133 | } 134 | for (Connection conn2 : connections) 135 | this.closeQuietly(conn2); 136 | } 137 | 138 | @Override 139 | public void rollbackAll() { 140 | BasicDataSource dataSource = (BasicDataSource) this.getDataSource(); 141 | List connections = new ArrayList<>(); 142 | Connection conn = null; 143 | try { 144 | int activeConnections = dataSource.getNumIdle(); 145 | for (int i = 0; i < activeConnections; i++) { 146 | conn = dataSource.getConnection(); 147 | conn.rollback(); 148 | connections.add(conn); 149 | } 150 | } catch (SQLException e) { 151 | LoggerFactory.getLogger(LoggerConf.LOGGER_NAME).error("Failed to rollback changes", e); 152 | } 153 | for (Connection conn2 : connections) 154 | this.closeQuietly(conn2); 155 | } 156 | 157 | } 158 | -------------------------------------------------------------------------------- /src/main/java/gr/sqlbrowserfx/conn/ResultSetAction.java: -------------------------------------------------------------------------------- 1 | package gr.sqlbrowserfx.conn; 2 | 3 | import java.sql.ResultSet; 4 | import java.sql.SQLException; 5 | 6 | @FunctionalInterface 7 | public interface ResultSetAction { 8 | 9 | public void onResultSet(ResultSet rset) throws SQLException; 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/gr/sqlbrowserfx/conn/SqlTable.java: -------------------------------------------------------------------------------- 1 | package gr.sqlbrowserfx.conn; 2 | 3 | import gr.sqlbrowserfx.LoggerConf; 4 | import org.slf4j.LoggerFactory; 5 | 6 | import java.sql.ResultSetMetaData; 7 | import java.sql.SQLException; 8 | import java.util.ArrayList; 9 | import java.util.LinkedHashMap; 10 | import java.util.List; 11 | import java.util.Map; 12 | import java.util.Set; 13 | 14 | public class SqlTable { 15 | 16 | private String name; 17 | private String primaryKey; 18 | private List foreignKeys; 19 | private List relatedTables; 20 | private LinkedHashMap columnsMap; 21 | 22 | public SqlTable(ResultSetMetaData rsmd) { 23 | 24 | foreignKeys = new ArrayList<>(); 25 | try { 26 | name = rsmd.getTableName(1); 27 | columnsMap = new LinkedHashMap<>(); 28 | for (int i = 1; i <= rsmd.getColumnCount(); i++) { 29 | columnsMap.put(rsmd.getColumnLabel(i), rsmd.getColumnTypeName(i)); 30 | } 31 | 32 | } catch (SQLException e) { 33 | LoggerFactory.getLogger(LoggerConf.LOGGER_NAME).error(e.getMessage(), e); 34 | } 35 | } 36 | 37 | public SqlTable(String tableName, ResultSetMetaData rsmd) { 38 | this(rsmd); 39 | name = tableName; 40 | } 41 | 42 | public String getName() { 43 | return name; 44 | } 45 | 46 | public void setName(String name) { 47 | this.name = name; 48 | } 49 | 50 | public Map getColumnsMap() { 51 | return columnsMap; 52 | } 53 | 54 | public void setColumnsMap(LinkedHashMap columns) { 55 | this.columnsMap = columns; 56 | } 57 | 58 | /* 59 | * Returns tables's primary key , IMPORTANT in case of a composite 60 | * key it returns a comma separated string with the keys 61 | * 62 | */ 63 | public String getPrimaryKey() { 64 | return primaryKey; 65 | } 66 | 67 | public void setPrimaryKey(String primaryKey) { 68 | this.primaryKey = primaryKey; 69 | } 70 | 71 | public Set getColumns() { 72 | return columnsMap.keySet(); 73 | } 74 | 75 | public List getForeignKeys() { 76 | return foreignKeys; 77 | } 78 | 79 | public void setForeignKeys(List foreignKeys) { 80 | this.foreignKeys = foreignKeys; 81 | } 82 | 83 | public void addForeignKey(String foreignKey) { 84 | foreignKeys.add(foreignKey); 85 | } 86 | 87 | public boolean isForeignKey(String key) { 88 | for (String foreignKey : foreignKeys) { 89 | if (key.equals(foreignKey)) { 90 | return true; 91 | } 92 | } 93 | return false; 94 | } 95 | 96 | public boolean isPrimaryKey(String key) { 97 | return (primaryKey != null && primaryKey.equals(key)); 98 | } 99 | 100 | public String columnsToString() { 101 | StringBuilder result = new StringBuilder(); 102 | for (String column : columnsMap.keySet()) { 103 | result.append(column).append(","); 104 | } 105 | return result.substring(0, result.length() - 1); 106 | } 107 | 108 | public List getRelatedTables() { 109 | return this.relatedTables; 110 | } 111 | 112 | public void setRelatedTables(List relatedTables) { 113 | this.relatedTables = relatedTables; 114 | } 115 | 116 | } 117 | -------------------------------------------------------------------------------- /src/main/java/gr/sqlbrowserfx/conn/StatementAction.java: -------------------------------------------------------------------------------- 1 | package gr.sqlbrowserfx.conn; 2 | 3 | import java.sql.Statement; 4 | 5 | @FunctionalInterface 6 | public interface StatementAction { 7 | 8 | void onStatement(Statement stmt); 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/gr/sqlbrowserfx/conn/UpdateQuery.java: -------------------------------------------------------------------------------- 1 | package gr.sqlbrowserfx.conn; 2 | 3 | import java.util.List; 4 | 5 | public class UpdateQuery { 6 | 7 | private String query; 8 | List params; 9 | 10 | 11 | public UpdateQuery(String query, List params) { 12 | this.query = query; 13 | this.params = params; 14 | } 15 | 16 | public String getQuery() { 17 | return query; 18 | } 19 | 20 | public void setQuery(String query) { 21 | this.query = query; 22 | } 23 | 24 | public List getParams() { 25 | return params; 26 | } 27 | 28 | public void setParams(List params) { 29 | this.params = params; 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/gr/sqlbrowserfx/dock/nodes/DDBTreePane.java: -------------------------------------------------------------------------------- 1 | package gr.sqlbrowserfx.dock.nodes; 2 | 3 | import java.sql.SQLException; 4 | 5 | import org.controlsfx.control.PopOver; 6 | import org.dockfx.DockNode; 7 | import org.dockfx.Dockable; 8 | import org.fxmisc.flowless.VirtualizedScrollPane; 9 | import org.fxmisc.wellbehaved.event.EventPattern; 10 | import org.fxmisc.wellbehaved.event.InputMap; 11 | import org.fxmisc.wellbehaved.event.Nodes; 12 | 13 | import gr.sqlbrowserfx.conn.MysqlConnector; 14 | import gr.sqlbrowserfx.conn.SqlConnector; 15 | import gr.sqlbrowserfx.conn.SqliteConnector; 16 | import gr.sqlbrowserfx.factories.DialogFactory; 17 | import gr.sqlbrowserfx.listeners.SimpleEvent; 18 | import gr.sqlbrowserfx.nodes.InputMapOwner; 19 | import gr.sqlbrowserfx.nodes.TableCreationPane; 20 | import gr.sqlbrowserfx.nodes.ToolbarOwner; 21 | import gr.sqlbrowserfx.nodes.codeareas.sql.SqlCodeArea; 22 | import gr.sqlbrowserfx.utils.JavaFXUtils; 23 | import javafx.application.Platform; 24 | import javafx.scene.control.Button; 25 | import javafx.scene.control.ProgressIndicator; 26 | import javafx.scene.control.Tooltip; 27 | import javafx.scene.input.KeyCode; 28 | import javafx.scene.input.KeyCombination; 29 | import javafx.scene.layout.BorderPane; 30 | import javafx.scene.layout.FlowPane; 31 | 32 | public class DDBTreePane extends BorderPane implements Dockable, ToolbarOwner, InputMapOwner { 33 | 34 | private final FlowPane toolBar; 35 | private final DDBTreeView dbTreeView; 36 | private DockNode thisDockNode = null; 37 | private final SqlConnector sqlConnector; 38 | private Button searchButton; 39 | 40 | public DDBTreePane(String dbPath, SqlConnector sqlConnector) { 41 | super(); 42 | this.sqlConnector = sqlConnector; 43 | // when dbTreeView is ready fires a simple event 44 | this.dbTreeView = new DDBTreeView(dbPath, sqlConnector, this); 45 | this.dbTreeView.addEventHandler(SimpleEvent.EVENT_TYPE, simpleEvent -> Platform.runLater(() -> this.setCenter(this.dbTreeView))); 46 | this.toolBar = this.createToolbar(); 47 | 48 | this.setInputMap(); 49 | 50 | this.setTop(toolBar); 51 | this.setLoading(true); 52 | } 53 | 54 | public void setLoading(boolean loading) { 55 | if (loading) { 56 | ProgressIndicator progressIndicator = new ProgressIndicator(); 57 | progressIndicator.setMaxHeight(40); 58 | progressIndicator.setMaxWidth(40); 59 | this.setCenter(progressIndicator); 60 | } 61 | else { 62 | Platform.runLater(() -> this.setCenter(this.dbTreeView)); 63 | } 64 | } 65 | 66 | @Override 67 | public FlowPane createToolbar() { 68 | searchButton = new Button("", JavaFXUtils.createIcon("/icons/magnify.png")); 69 | searchButton.setTooltip(new Tooltip("Search in tree")); 70 | searchButton.setOnAction(actionEvent -> this.dbTreeView.showSearchPopup(searchButton)); 71 | 72 | Button addButton = new Button("", JavaFXUtils.createIcon("/icons/add.png")); 73 | addButton.setOnAction(actionEvent -> { 74 | TableCreationPane tableCreationPane = new TableCreationPane(this.sqlConnector); 75 | tableCreationPane.addObserver(this.dbTreeView); 76 | new DockNode(asDockNode().getDockPane(), tableCreationPane, "Create New Table", JavaFXUtils.createIcon("/icons/add.png"), 1200.0, 600.0); 77 | 78 | }); 79 | addButton.setTooltip(new Tooltip("Open table creator")); 80 | 81 | Button deleteButton = new Button("", JavaFXUtils.createIcon("/icons/minus.png")); 82 | deleteButton.setTooltip(new Tooltip("Drop")); 83 | deleteButton.setOnAction(action -> this.dbTreeView.dropAction()); 84 | 85 | Button scemaDetailsButton = new Button("", JavaFXUtils.createIcon("/icons/details.png")); 86 | scemaDetailsButton.setTooltip(new Tooltip("Show schema")); 87 | scemaDetailsButton.setOnAction(actionEvent -> { 88 | SqlCodeArea codeArea = new SqlCodeArea(this.dbTreeView.copyScemaAction(), false, false, isUsingMysql()); 89 | VirtualizedScrollPane scrollPane = new VirtualizedScrollPane<>(codeArea); 90 | scrollPane.setPrefSize(600, 400); 91 | 92 | PopOver popOver = new PopOver(scrollPane); 93 | popOver.setArrowSize(0); 94 | popOver.setDetachable(false); 95 | popOver.show(scemaDetailsButton); 96 | }); 97 | 98 | Button refreshButton = new Button("", JavaFXUtils.createIcon("/icons/refresh.png")); 99 | refreshButton.setOnAction(event -> { 100 | try { 101 | dbTreeView.refreshItems(); 102 | if (!(sqlConnector instanceof SqliteConnector)) 103 | dbTreeView.refreshFunctionAndProcedures(); 104 | } catch (SQLException e) { 105 | DialogFactory.createErrorDialog(e); 106 | } 107 | }); 108 | refreshButton.setTooltip(new Tooltip("Refresh")); 109 | 110 | FlowPane toolbar = new FlowPane(dbTreeView.getSearchBox(), addButton, refreshButton); 111 | toolbar.setPrefWidth(addButton.getWidth()); 112 | return toolbar; 113 | } 114 | 115 | @Override 116 | public void setInputMap() { 117 | Nodes.addInputMap(this, InputMap.consume(EventPattern.keyPressed(KeyCode.F, KeyCombination.CONTROL_DOWN), 118 | action -> dbTreeView.getSearchField().requestFocus())); 119 | } 120 | 121 | @Override 122 | public DockNode asDockNode() { 123 | if (thisDockNode == null) { 124 | thisDockNode = new DockNode(this, "Structure", JavaFXUtils.createIcon("/icons/structure.png")); 125 | } 126 | return thisDockNode; 127 | } 128 | 129 | public DDBTreeView getDBTreeView() { 130 | return dbTreeView; 131 | } 132 | 133 | private boolean isUsingMysql() { 134 | return sqlConnector instanceof MysqlConnector; 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /src/main/java/gr/sqlbrowserfx/dock/nodes/DDBTreeView.java: -------------------------------------------------------------------------------- 1 | package gr.sqlbrowserfx.dock.nodes; 2 | 3 | import org.dockfx.DockNode; 4 | import org.dockfx.Dockable; 5 | 6 | import gr.sqlbrowserfx.SqlBrowserFXAppManager; 7 | import gr.sqlbrowserfx.conn.SqlConnector; 8 | import gr.sqlbrowserfx.nodes.DBTreeView; 9 | import gr.sqlbrowserfx.nodes.sqlpane.SqlPane; 10 | import gr.sqlbrowserfx.utils.JavaFXUtils; 11 | import javafx.scene.control.ContextMenu; 12 | import javafx.scene.control.Menu; 13 | import javafx.scene.control.MenuItem; 14 | import javafx.scene.control.SeparatorMenuItem; 15 | 16 | public class DDBTreeView extends DBTreeView implements Dockable { 17 | 18 | private DockNode thisDockNode = null; 19 | private Menu openInSqlPaneMenu; 20 | 21 | public DDBTreeView(String dbPath, SqlConnector sqlConnector) { 22 | super(dbPath, sqlConnector); 23 | this.setOnContextMenuRequested(menuRequestedEvent -> { 24 | openInSqlPaneMenu.getItems().clear(); 25 | int i = 1; 26 | for (SqlPane sqlPane : SqlBrowserFXAppManager.getActiveSqlPanes()) { 27 | MenuItem item = new MenuItem("SqlPane " + i++); 28 | item.setOnAction(actionEvent -> sqlPane.createSqlTableTabWithData(this.getSelectionModel().getSelectedItem().getValue())); 29 | openInSqlPaneMenu.getItems().add(item); 30 | } 31 | this.getContextMenu().show(this, menuRequestedEvent.getScreenX(),menuRequestedEvent.getScreenY()); 32 | }); 33 | } 34 | 35 | public DDBTreeView(String dbPath, SqlConnector sqlConnector, DDBTreePane parent) { 36 | super(dbPath, sqlConnector, parent); 37 | } 38 | 39 | @Override 40 | public DockNode asDockNode() { 41 | if (thisDockNode == null) { 42 | thisDockNode = new DockNode(this, "Structure", JavaFXUtils.createIcon("/icons/structure.png")); 43 | } 44 | return thisDockNode; 45 | } 46 | 47 | @Override 48 | public ContextMenu createContextMenu() { 49 | ContextMenu menu = super.createContextMenu(); 50 | openInSqlPaneMenu = new Menu("Open in..." , JavaFXUtils.createIcon("/icons/openTab.png")); 51 | this.populateSqlPanesMenu(); 52 | openInSqlPaneMenu.disableProperty().bind(this.canSelectedOpenProperty().not()); 53 | menu.getItems().add(0, new SeparatorMenuItem()); 54 | menu.getItems().add(0, openInSqlPaneMenu); 55 | return menu; 56 | 57 | } 58 | 59 | public void populateSqlPanesMenu() { 60 | openInSqlPaneMenu.getItems().clear(); 61 | for (SqlPane sqlPane : SqlBrowserFXAppManager.getActiveSqlPanes()) { 62 | MenuItem item = new MenuItem((sqlPane instanceof DSqlPane) ? ((DSqlPane) sqlPane).asDockNode().getTitle() : "SqlPane"); 63 | item.setOnAction(action2 -> { 64 | if (this.tablesRootItem.getChildren().contains(this.getSelectionModel().getSelectedItem()) || 65 | this.viewsRootItem.getChildren().contains(this.getSelectionModel().getSelectedItem()) 66 | ) 67 | sqlPane.createSqlTableTabWithData(this.getSelectionModel().getSelectedItem().getValue()); 68 | }); 69 | openInSqlPaneMenu.getItems().add(item); 70 | } 71 | } 72 | 73 | } 74 | -------------------------------------------------------------------------------- /src/main/java/gr/sqlbrowserfx/dock/nodes/DDbDiagramPane.java: -------------------------------------------------------------------------------- 1 | package gr.sqlbrowserfx.dock.nodes; 2 | 3 | import java.sql.SQLException; 4 | import java.util.ArrayList; 5 | import java.util.List; 6 | import java.util.Map; 7 | import java.util.stream.Collectors; 8 | 9 | import org.dockfx.DockNode; 10 | import org.dockfx.Dockable; 11 | 12 | import gr.sqlbrowserfx.conn.SqlConnector; 13 | import gr.sqlbrowserfx.conn.SqlTable; 14 | import gr.sqlbrowserfx.factories.DialogFactory; 15 | import gr.sqlbrowserfx.nodes.DbDiagramPane; 16 | import gr.sqlbrowserfx.utils.JavaFXUtils; 17 | import javafx.application.Platform; 18 | 19 | public class DDbDiagramPane extends DbDiagramPane implements Dockable { 20 | 21 | private DockNode thisDockNode = null; 22 | 23 | public DDbDiagramPane(SqlConnector sqlConnector) { 24 | super(); 25 | setLoading(true); 26 | sqlConnector.executeAsync(() -> { 27 | var sqlTables = new ArrayList(); 28 | try { 29 | sqlConnector.getContents(rset -> { 30 | String name = rset.getString(1); 31 | String type = rset.getString(2); 32 | 33 | if (type.toLowerCase().contains("table")) { 34 | sqlConnector.executeQueryRaw("select * from " + name + " where 1 = 2", rset2 -> { 35 | SqlTable sqlTable = new SqlTable(rset2.getMetaData()); 36 | sqlTable.setPrimaryKey(sqlConnector.findPrimaryKey(name)); 37 | List> fkeys = sqlConnector.findForeignKeyReferences(name); 38 | sqlTable.setForeignKeys( 39 | fkeys.stream().map(x -> x.get(SqlConnector.FOREIGN_KEY)).collect(Collectors.toList())); 40 | sqlTable.setRelatedTables(fkeys.stream().map(x -> x.get(SqlConnector.REFERENCED_TABLE)).collect(Collectors.toList())); 41 | sqlTables.add(sqlTable); 42 | }); 43 | } 44 | }); 45 | } catch (SQLException e) { 46 | DialogFactory.createErrorDialog(e); 47 | } 48 | 49 | Platform.runLater(() -> init(sqlTables)); 50 | }); 51 | } 52 | 53 | @Override 54 | public DockNode asDockNode() { 55 | if (thisDockNode == null) { 56 | thisDockNode = new DockNode(this, "DB Diagram", JavaFXUtils.createIcon("/icons/diagram.png")); 57 | } 58 | return thisDockNode; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/main/java/gr/sqlbrowserfx/dock/nodes/DLogConsolePane.java: -------------------------------------------------------------------------------- 1 | package gr.sqlbrowserfx.dock.nodes; 2 | 3 | import org.dockfx.DockNode; 4 | import org.dockfx.DockPane; 5 | import org.dockfx.Dockable; 6 | 7 | import gr.sqlbrowserfx.nodes.LogConsolePane; 8 | import gr.sqlbrowserfx.utils.JavaFXUtils; 9 | 10 | public class DLogConsolePane extends LogConsolePane implements Dockable { 11 | private DockNode thisDockNode = null; 12 | private final DockPane dockPane; 13 | 14 | public DLogConsolePane(DockPane dockPane) { 15 | this.dockPane = dockPane; 16 | } 17 | 18 | @Override 19 | public DockNode asDockNode() { 20 | if (thisDockNode == null) { 21 | thisDockNode = new DockNode(dockPane, this, "Log", JavaFXUtils.createIcon("/icons/monitor.png"), 600.0, 400.0); 22 | thisDockNode.setOnClose(this::stopTailing); 23 | } 24 | return thisDockNode; 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/gr/sqlbrowserfx/dock/nodes/DSqlConsolePaneNH.java: -------------------------------------------------------------------------------- 1 | package gr.sqlbrowserfx.dock.nodes; 2 | 3 | import gr.sqlbrowserfx.conn.SqlConnector; 4 | import gr.sqlbrowserfx.nodes.sqlpane.SqlPane; 5 | import javafx.scene.layout.FlowPane; 6 | 7 | public class DSqlConsolePaneNH extends DSqlConsolePane { 8 | 9 | public DSqlConsolePaneNH(SqlConnector sqlConnector, SqlPane sqlPane) { 10 | super(sqlConnector, sqlPane); 11 | } 12 | 13 | @Override 14 | public FlowPane createToolbar() { 15 | FlowPane toolbar = super.createToolbar(); 16 | toolbar.getChildren().remove(historyButton); 17 | return toolbar; 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/gr/sqlbrowserfx/dock/nodes/DSqlPane.java: -------------------------------------------------------------------------------- 1 | package gr.sqlbrowserfx.dock.nodes; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import org.dockfx.DockNode; 7 | import org.dockfx.DockPos; 8 | import org.dockfx.DockWeights; 9 | import org.dockfx.Dockable; 10 | import org.fxmisc.richtext.CodeArea; 11 | 12 | import gr.sqlbrowserfx.SqlBrowserFXAppManager; 13 | import gr.sqlbrowserfx.conn.SqlConnector; 14 | import gr.sqlbrowserfx.listeners.SimpleObservable; 15 | import gr.sqlbrowserfx.listeners.SimpleObserver; 16 | import gr.sqlbrowserfx.nodes.sqlpane.SqlPane; 17 | import gr.sqlbrowserfx.nodes.sqlpane.SqlTableTab; 18 | import gr.sqlbrowserfx.utils.JavaFXUtils; 19 | import javafx.application.Platform; 20 | import javafx.event.ActionEvent; 21 | import javafx.scene.control.TabPane; 22 | 23 | public class DSqlPane extends SqlPane implements Dockable, SimpleObserver, SimpleObservable { 24 | 25 | private List> listeners; 26 | 27 | private DockNode thisDockNode = null; 28 | private DSqlConsolePane sqlConsolePane; 29 | private DockNode dRecordsTabPane = null; 30 | 31 | public DSqlPane() { 32 | this(null); 33 | } 34 | 35 | public DSqlPane(SqlConnector sqlConnector) { 36 | super(sqlConnector); 37 | 38 | listeners = new ArrayList<>(); 39 | } 40 | 41 | 42 | @Override 43 | protected void sqlConsoleButtonAction() { 44 | if (sqlConsolePane == null) { 45 | sqlConsolePane = new DSqlConsolePane(this.sqlConnector, this); 46 | sqlConsolePane.asDockNode().setOnClose(() -> sqlConsolePane = null); 47 | sqlConsolePane.asDockNode().dock(this.asDockNode().getDockPane(), DockPos.TOP, this.asDockNode(), 48 | DockWeights.asDoubleArrray(0.4f, 0.6f)); 49 | } 50 | } 51 | 52 | public final CodeArea getSqlCodeAreaRef() { 53 | return sqlConsolePane != null ? sqlConsolePane.getCodeAreaRef() : null; 54 | } 55 | 56 | 57 | @Override 58 | protected void getDataFromDB(String table, final SqlTableTab sqlTableTab) { 59 | if (table != null && !table.equals("empty")) { 60 | super.getDataFromDB(table, sqlTableTab); 61 | } 62 | } 63 | 64 | @Override 65 | public void openInFullMode(final SqlTableTab tab) { 66 | // super.enableFullMode(tab); 67 | Platform.runLater(() -> { 68 | // tab.setContent(guiState.getSqlTableView()); 69 | if (isInFullMode()) { 70 | // final TabPane recordsTabPane = tab.getRecordsTabPane() != null ? 71 | // tab.getRecordsTabPane() : 72 | // this.createRecordsTabPane(); 73 | TabPane recordsTabPane = this.createRecordsTabPane(); 74 | if (dRecordsTabPane == null) { 75 | dRecordsTabPane = new DockNode(recordsTabPane, this.asDockNode().getTitle() + " : Full mode", 76 | JavaFXUtils.createIcon("/icons/details.png")); 77 | dRecordsTabPane.dock(this.asDockNode().getDockPane(), DockPos.RIGHT, this.asDockNode(), 78 | DockWeights.asDoubleArrray(0.7f, 0.3f)); 79 | dRecordsTabPane.setOnClose(() -> { 80 | dRecordsTabPane = null; 81 | this.setFullMode(false); 82 | this.disableFullMode(); 83 | System.gc(); 84 | }); 85 | } else { 86 | dRecordsTabPane.setContents(recordsTabPane); 87 | } 88 | tab.setRecordsTabPane(recordsTabPane); 89 | } 90 | 91 | sqlQueryRunning = false; 92 | }); 93 | } 94 | 95 | @Override 96 | public void disableFullMode() { 97 | if (dRecordsTabPane != null) { 98 | dRecordsTabPane.close(); 99 | 100 | tablesTabPane.getTabs().forEach(tab -> { 101 | if (tab instanceof SqlTableTab) 102 | ((SqlTableTab)tab).setRecordsTabPane(null); 103 | }); 104 | } 105 | // super.disableFullMode(); 106 | } 107 | 108 | @Override 109 | protected void tablesTabPaneClickAction() { 110 | super.tablesTabPaneClickAction(); 111 | if (dRecordsTabPane != null && getSelectedRecordsTabPane() != null) 112 | dRecordsTabPane.setContents(getSelectedRecordsTabPane()); 113 | } 114 | 115 | @Override 116 | public DockNode asDockNode() { 117 | if (thisDockNode == null) { 118 | thisDockNode = new DockNode(this, "Data Explorer", JavaFXUtils.createIcon("/icons/table.png")); 119 | 120 | thisDockNode.setOnClose(() -> { 121 | SqlBrowserFXAppManager.unregisterDSqlPane(this); 122 | // it does not work as expected 123 | // if (sqlConsoleBox != null) 124 | // sqlConsoleBox.asDockNode().close(); 125 | // if (dRecordsTabPane != null) 126 | // dRecordsTabPane.close(); 127 | // if (dLogListView != null) 128 | // dLogListView.close(); 129 | }); 130 | } 131 | return thisDockNode; 132 | } 133 | 134 | @Override 135 | public void onObservableChange(String tableName) { 136 | if (tablesBox.getSelectionModel().getSelectedItem().equals(tableName)) 137 | tablesBox.getOnAction().handle(new ActionEvent()); 138 | } 139 | 140 | @Override 141 | public void changed() { 142 | listeners.forEach(listener -> listener.onObservableChange(getTablesBox().getValue())); 143 | } 144 | 145 | @Override 146 | public void changed(String data) { 147 | } 148 | 149 | @Override 150 | public void addObserver(SimpleObserver listener) { 151 | listeners.add(listener); 152 | } 153 | 154 | @Override 155 | public void removeObserver(SimpleObserver listener) { 156 | listeners.remove(listener); 157 | } 158 | 159 | public void setFullMode(boolean mode) { 160 | fullModeCheckBox.setSelected(mode); 161 | } 162 | 163 | public void showConsole() { 164 | this.sqlConsoleButtonAction(); 165 | } 166 | 167 | public DSqlConsolePane getSqlConsolePane() { 168 | return sqlConsolePane; 169 | } 170 | 171 | } 172 | -------------------------------------------------------------------------------- /src/main/java/gr/sqlbrowserfx/listeners/SimpleEvent.java: -------------------------------------------------------------------------------- 1 | package gr.sqlbrowserfx.listeners; 2 | 3 | import javafx.event.Event; 4 | import javafx.event.EventType; 5 | 6 | import java.io.Serial; 7 | 8 | public class SimpleEvent extends Event { 9 | 10 | /** 11 | * 12 | */ 13 | @Serial 14 | private static final long serialVersionUID = 1L; 15 | 16 | public static final EventType EVENT_TYPE = new EventType<>("SimpleEvent"); 17 | 18 | public SimpleEvent() { 19 | super(EVENT_TYPE); 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/gr/sqlbrowserfx/listeners/SimpleObservable.java: -------------------------------------------------------------------------------- 1 | package gr.sqlbrowserfx.listeners; 2 | 3 | public interface SimpleObservable { 4 | 5 | void changed(); 6 | void changed(T data); 7 | void addObserver(SimpleObserver listener); 8 | void removeObserver(SimpleObserver listener); 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/gr/sqlbrowserfx/listeners/SimpleObserver.java: -------------------------------------------------------------------------------- 1 | package gr.sqlbrowserfx.listeners; 2 | 3 | public interface SimpleObserver { 4 | 5 | void onObservableChange(T newValue); 6 | } 7 | -------------------------------------------------------------------------------- /src/main/java/gr/sqlbrowserfx/listeners/TableColumnFilteringEvent.java: -------------------------------------------------------------------------------- 1 | package gr.sqlbrowserfx.listeners; 2 | 3 | import javafx.event.Event; 4 | import javafx.event.EventType; 5 | 6 | import java.io.Serial; 7 | 8 | public class TableColumnFilteringEvent extends Event{ 9 | 10 | /** 11 | * 12 | */ 13 | @Serial 14 | private static final long serialVersionUID = 1L; 15 | 16 | public static final EventType EVENT_TYPE = new EventType<>(TableColumnFilteringEvent.class.getSimpleName()); 17 | 18 | public TableColumnFilteringEvent() { 19 | super(EVENT_TYPE); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/gr/sqlbrowserfx/listeners/TableSearchFilteringEvent.java: -------------------------------------------------------------------------------- 1 | package gr.sqlbrowserfx.listeners; 2 | 3 | import javafx.event.Event; 4 | import javafx.event.EventType; 5 | 6 | import java.io.Serial; 7 | 8 | public class TableSearchFilteringEvent extends Event { 9 | /** 10 | * 11 | */ 12 | @Serial 13 | private static final long serialVersionUID = 1L; 14 | 15 | public static final EventType EVENT_TYPE = new EventType<>(TableSearchFilteringEvent.class.getSimpleName()); 16 | 17 | public TableSearchFilteringEvent() { 18 | super(EVENT_TYPE); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/gr/sqlbrowserfx/nodes/ContextMenuOwner.java: -------------------------------------------------------------------------------- 1 | package gr.sqlbrowserfx.nodes; 2 | 3 | import javafx.scene.control.ContextMenu; 4 | 5 | public interface ContextMenuOwner { 6 | 7 | ContextMenu createContextMenu(); 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/gr/sqlbrowserfx/nodes/FileSearchPopOver.java: -------------------------------------------------------------------------------- 1 | package gr.sqlbrowserfx.nodes; 2 | 3 | import java.io.File; 4 | import java.util.Set; 5 | import java.util.concurrent.Executors; 6 | import java.util.concurrent.ScheduledExecutorService; 7 | import java.util.concurrent.TimeUnit; 8 | 9 | import gr.sqlbrowserfx.nodes.sqlpane.CustomPopOver; 10 | import gr.sqlbrowserfx.utils.FilesUtils; 11 | import gr.sqlbrowserfx.utils.JavaFXUtils; 12 | import gr.sqlbrowserfx.utils.PropertiesLoader; 13 | import javafx.application.Platform; 14 | import javafx.collections.FXCollections; 15 | import javafx.scene.control.Button; 16 | import javafx.scene.control.Label; 17 | import javafx.scene.control.ListCell; 18 | import javafx.scene.control.ListView; 19 | import javafx.scene.control.TextField; 20 | import javafx.scene.control.Tooltip; 21 | import javafx.scene.image.ImageView; 22 | import javafx.scene.input.KeyCode; 23 | import javafx.scene.layout.VBox; 24 | import javafx.stage.DirectoryChooser; 25 | import javafx.stage.FileChooser; 26 | 27 | public class FileSearchPopOver extends CustomPopOver { 28 | 29 | @FunctionalInterface 30 | public interface Action { 31 | void run(File selectedFile); 32 | } 33 | 34 | private final Action action; 35 | private ScheduledExecutorService executor; 36 | private final TextField searchField; 37 | private final ListView filesListView; 38 | private String rootPath = ((String) PropertiesLoader.getProperty("sqlbrowserfx.root.path", String.class, "~/")) 39 | .replaceAll("\"", ""); 40 | 41 | public FileSearchPopOver(Action action) { 42 | super(); 43 | 44 | this.action = action; 45 | Button openButton = new Button("", JavaFXUtils.createIcon("/icons/code-file.png")); 46 | openButton.setOnMouseClicked(mouseEvent -> this.openFileAction()); 47 | openButton.setTooltip(new Tooltip("Open file")); 48 | 49 | filesListView = new ListView<>(); 50 | filesListView.setCellFactory(param -> new ListCell<>() { 51 | @Override 52 | protected void updateItem(String item, boolean empty) { 53 | super.updateItem(item, empty); 54 | if (empty || item == null) { 55 | setGraphic(null); 56 | setText(null); 57 | // other stuff to do... 58 | 59 | } else { 60 | 61 | // set the width's 62 | setMinWidth(param.getWidth()); 63 | setMaxWidth(param.getWidth()); 64 | setPrefWidth(param.getWidth()); 65 | 66 | // allow wrapping 67 | setWrapText(true); 68 | 69 | setText(item); 70 | 71 | } 72 | } 73 | }); 74 | filesListView.setPrefSize(600, 400); 75 | 76 | searchField = new TextField(); 77 | // searchField.setPrefWidth(576); 78 | searchField.setPromptText("Search for file..."); 79 | searchField.setOnKeyPressed(keyEvent -> { 80 | if (keyEvent.getCode() == KeyCode.ENTER) { 81 | search(); 82 | } 83 | 84 | if (keyEvent.getCode() != KeyCode.ESCAPE) { 85 | keyEvent.consume(); 86 | } 87 | }); 88 | 89 | // TODO: add open button if has any value 90 | ImageView descIcon = JavaFXUtils.createIcon("/icons/settings.png"); 91 | 92 | Label descLabel = new Label("File Search in: " + rootPath, descIcon); 93 | descLabel.setOnMouseClicked(event -> { 94 | this.hide(); 95 | DirectoryChooser dirChooser = new DirectoryChooser(); 96 | File selectedDir = dirChooser.showDialog(this.getOwnerWindow()); 97 | this.rootPath = selectedDir.getAbsolutePath(); 98 | descLabel.setText("File Search in: " + rootPath); 99 | }); 100 | descLabel.setTooltip(new Tooltip("Click to change root path")); 101 | 102 | this.setContentNode(new VBox(descLabel, searchField, filesListView)); 103 | this.setOnHidden(event -> { 104 | if (executor != null) { 105 | executor.shutdownNow(); 106 | } 107 | }); 108 | 109 | this.setOnShown(event -> searchField.requestFocus()); 110 | this.setHideOnEscape(true); 111 | 112 | filesListView.setOnKeyPressed(keyEvent -> { 113 | if (keyEvent.getCode() == KeyCode.ENTER) { 114 | String filePath = filesListView.getSelectionModel().getSelectedItem(); 115 | action.run(new File(filePath)); 116 | } else if (keyEvent.getCode() == KeyCode.ESCAPE) { 117 | this.hide(); 118 | } 119 | }); 120 | filesListView.setOnMouseClicked(mouseEvent -> { 121 | if (mouseEvent.getClickCount() == 2) { 122 | String filePath = filesListView.getSelectionModel().getSelectedItem(); 123 | action.run(new File(filePath)); 124 | } 125 | }); 126 | } 127 | 128 | private void openFileAction() { 129 | FileChooser fileChooser = new FileChooser(); 130 | File selectedFile = fileChooser.showOpenDialog(null); 131 | action.run(selectedFile); 132 | } 133 | 134 | private void search() { 135 | searchField.setDisable(true); 136 | filesListView.setDisable(true); 137 | 138 | String pattern = searchField.getText(); 139 | 140 | executor = Executors.newSingleThreadScheduledExecutor(); 141 | executor.schedule(() -> { 142 | Set filesPathsFound = FilesUtils.walk(rootPath, pattern); 143 | Platform.runLater(() -> { 144 | filesListView.setItems(FXCollections.observableArrayList(filesPathsFound)); 145 | searchField.setDisable(false); 146 | filesListView.setDisable(false); 147 | }); 148 | }, 0, TimeUnit.SECONDS); 149 | } 150 | } 151 | -------------------------------------------------------------------------------- /src/main/java/gr/sqlbrowserfx/nodes/HelpTabPane.java: -------------------------------------------------------------------------------- 1 | package gr.sqlbrowserfx.nodes; 2 | 3 | import java.io.IOException; 4 | import java.net.URISyntaxException; 5 | import java.nio.file.Files; 6 | import java.nio.file.Paths; 7 | import java.util.stream.Collectors; 8 | 9 | import org.apache.commons.lang3.StringUtils; 10 | import org.slf4j.LoggerFactory; 11 | 12 | import gr.sqlbrowserfx.LoggerConf; 13 | import gr.sqlbrowserfx.utils.HttpClient; 14 | import javafx.scene.control.Tab; 15 | import javafx.scene.control.TabPane; 16 | import javafx.scene.control.TextArea; 17 | 18 | public class HelpTabPane extends TabPane{ 19 | 20 | public HelpTabPane() throws IOException, InterruptedException, URISyntaxException { 21 | super(); 22 | String desc = HttpClient.GET("https://raw.githubusercontent.com/pariskol/sqlbrowserfx/master/README.md"); 23 | String license = HttpClient.GET("https://raw.githubusercontent.com/pariskol/sqlbrowserfx/master/LICENSE"); 24 | 25 | TextArea descTextArea = new TextArea(desc); 26 | descTextArea.setEditable(false); 27 | descTextArea.setWrapText(true); 28 | 29 | TextArea licenseTextArea = new TextArea(license); 30 | licenseTextArea.setEditable(false); 31 | Tab tab = new Tab("Description", descTextArea); 32 | tab.setClosable(false); 33 | this.getTabs().add(tab); 34 | tab = new Tab("Shortcuts", new HelpShortcutsTabPane()); 35 | tab.setClosable(false); 36 | this.getTabs().add(tab); 37 | TextArea restTextArea = new TextArea(""" 38 | SqlBrowserFX provides a simple rest api for fast prototyping 39 | 40 | Available Endpoints: 41 | 42 | /api/tables (get db tables) 43 | /api/get/:table?column1=...&column2=... (with parameters matching table columns) 44 | /api/save/:table (with json body with keys matching table columns) 45 | /api/delete/:table (with json body with keys matching table columns) 46 | """); 47 | restTextArea.setEditable(false); 48 | tab = new Tab("Rest Api", restTextArea); 49 | tab.setClosable(false); 50 | this.getTabs().add(tab); 51 | tab = new Tab("License", licenseTextArea); 52 | tab.setClosable(false); 53 | this.getTabs().add(tab); 54 | 55 | TextArea contactTextArea = new TextArea( 56 | """ 57 | GitHub Page: https://github.com/pariskol/sqlbrowserfx 58 | 59 | Email: pariskolovos@live.com"""); 60 | contactTextArea.setEditable(false); 61 | tab = new Tab("Contact", contactTextArea); 62 | tab.setClosable(false); 63 | this.getTabs().add(tab); 64 | 65 | TextArea propsArea; 66 | try(var lines = Files.lines(Paths.get("./sqlbrowserfx.properties"))) { 67 | String propsStr = StringUtils.join(lines.collect(Collectors.toList()), "\n"); 68 | propsArea = new TextArea(propsStr); 69 | propsArea.setEditable(false); 70 | tab = new Tab("Properties", propsArea); 71 | tab.setClosable(false); 72 | this.getTabs().add(tab); 73 | } catch (IOException e) { 74 | LoggerFactory.getLogger(LoggerConf.LOGGER_NAME).error(e.getMessage()); 75 | } 76 | 77 | } 78 | 79 | } 80 | -------------------------------------------------------------------------------- /src/main/java/gr/sqlbrowserfx/nodes/InputMapOwner.java: -------------------------------------------------------------------------------- 1 | package gr.sqlbrowserfx.nodes; 2 | 3 | public interface InputMapOwner { 4 | 5 | void setInputMap(); 6 | } 7 | -------------------------------------------------------------------------------- /src/main/java/gr/sqlbrowserfx/nodes/LogConsolePane.java: -------------------------------------------------------------------------------- 1 | package gr.sqlbrowserfx.nodes; 2 | 3 | import java.io.File; 4 | 5 | import org.apache.commons.io.input.Tailer; 6 | import org.apache.commons.io.input.TailerListener; 7 | import org.controlsfx.control.PopOver; 8 | import org.fxmisc.flowless.VirtualizedScrollPane; 9 | 10 | import gr.sqlbrowserfx.nodes.codeareas.log.CodeAreaTailerListener; 11 | import gr.sqlbrowserfx.nodes.codeareas.log.LogCodeArea; 12 | import gr.sqlbrowserfx.utils.JavaFXUtils; 13 | import javafx.geometry.Orientation; 14 | import javafx.scene.control.Button; 15 | import javafx.scene.control.CheckBox; 16 | import javafx.scene.control.Tooltip; 17 | import javafx.scene.layout.BorderPane; 18 | import javafx.scene.layout.FlowPane; 19 | import javafx.scene.layout.VBox; 20 | 21 | public class LogConsolePane extends BorderPane implements ToolbarOwner { 22 | private boolean popOverIsShowing = false; 23 | 24 | private final CheckBox wrapTextCheckBox; 25 | private final CheckBox showLinesCheckBox; 26 | private final CheckBox followCarretCheckBox; 27 | private Button settingsButton; 28 | private final LogCodeArea logCodeArea; 29 | 30 | private Thread tailerDaemon; 31 | private Tailer tailer; 32 | 33 | public LogConsolePane() { 34 | logCodeArea = new LogCodeArea(); 35 | wrapTextCheckBox = new CheckBox("Wrap text"); 36 | showLinesCheckBox = new CheckBox("Show line number"); 37 | followCarretCheckBox = new CheckBox("Scroll lock"); 38 | 39 | logCodeArea.wrapTextProperty().bind(this.wrapTextCheckBox.selectedProperty()); 40 | logCodeArea.showLinesProperty().bind(this.showLinesCheckBox.selectedProperty()); 41 | logCodeArea.followCarretProperty().bind(this.followCarretCheckBox.selectedProperty()); 42 | 43 | wrapTextCheckBox.setSelected(true); 44 | showLinesCheckBox.setSelected(true); 45 | followCarretCheckBox.setSelected(true); 46 | 47 | this.setTop(this.createToolbar()); 48 | this.setCenter(new VirtualizedScrollPane<>(logCodeArea)); 49 | 50 | this.startTailing(); 51 | } 52 | 53 | protected void startTailing() { 54 | TailerListener listener = new CodeAreaTailerListener(logCodeArea); 55 | tailer = new Tailer(new File("./logs/sqlbrowserfx.log"), listener, 1000); 56 | tailerDaemon = new Thread(tailer, "Logfile Tailer Daemon"); 57 | tailerDaemon.setDaemon(true); 58 | tailerDaemon.start(); 59 | } 60 | 61 | protected void stopTailing() { 62 | if (tailer != null) { 63 | tailer.stop(); 64 | tailerDaemon.interrupt(); 65 | } 66 | } 67 | 68 | @Override 69 | public FlowPane createToolbar() { 70 | settingsButton = new Button("", JavaFXUtils.createIcon("/icons/settings.png")); 71 | settingsButton.setOnMouseClicked(mouseEvent -> { 72 | if (!popOverIsShowing) { 73 | popOverIsShowing = true; 74 | PopOver popOver = new PopOver(new VBox(wrapTextCheckBox, showLinesCheckBox, followCarretCheckBox)); 75 | popOver.setOnHidden(event -> popOverIsShowing = false); 76 | popOver.show(settingsButton); 77 | } 78 | }); 79 | settingsButton.setTooltip(new Tooltip("Adjust settings")); 80 | FlowPane toolbar = new FlowPane(settingsButton); 81 | return toolbar; 82 | } 83 | 84 | } 85 | -------------------------------------------------------------------------------- /src/main/java/gr/sqlbrowserfx/nodes/MySqlConfigBox.java: -------------------------------------------------------------------------------- 1 | package gr.sqlbrowserfx.nodes; 2 | 3 | public class MySqlConfigBox extends DbConfigBox { 4 | 5 | public String getHistoryQuery() { 6 | return "select url, user, database, timestamp, id from connections_history_localtime" 7 | + " where database_type = '" + getSqlConnectorType() + "' order by timestamp desc"; 8 | } 9 | 10 | 11 | @Override 12 | public String getSqlConnectorType() { 13 | return SqlConnectorType.MYSQL.toString().toLowerCase(); 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/gr/sqlbrowserfx/nodes/NoSelectionModel.java: -------------------------------------------------------------------------------- 1 | package gr.sqlbrowserfx.nodes; 2 | 3 | import javafx.collections.FXCollections; 4 | import javafx.collections.ObservableList; 5 | import javafx.scene.control.MultipleSelectionModel; 6 | 7 | public class NoSelectionModel extends MultipleSelectionModel { 8 | 9 | @Override 10 | public ObservableList getSelectedIndices() { 11 | return FXCollections.emptyObservableList(); 12 | } 13 | 14 | @Override 15 | public ObservableList getSelectedItems() { 16 | return FXCollections.emptyObservableList(); 17 | } 18 | 19 | @Override 20 | public void selectIndices(int index, int... indices) { 21 | } 22 | 23 | @Override 24 | public void selectAll() { 25 | } 26 | 27 | @Override 28 | public void selectFirst() { 29 | } 30 | 31 | @Override 32 | public void selectLast() { 33 | } 34 | 35 | @Override 36 | public void clearAndSelect(int index) { 37 | } 38 | 39 | @Override 40 | public void select(int index) { 41 | } 42 | 43 | @Override 44 | public void select(T obj) { 45 | } 46 | 47 | @Override 48 | public void clearSelection(int index) { 49 | } 50 | 51 | @Override 52 | public void clearSelection() { 53 | } 54 | 55 | @Override 56 | public boolean isSelected(int index) { 57 | return false; 58 | } 59 | 60 | @Override 61 | public boolean isEmpty() { 62 | return true; 63 | } 64 | 65 | @Override 66 | public void selectPrevious() { 67 | } 68 | 69 | @Override 70 | public void selectNext() { 71 | } 72 | } -------------------------------------------------------------------------------- /src/main/java/gr/sqlbrowserfx/nodes/PostgreSqlConfigBox.java: -------------------------------------------------------------------------------- 1 | package gr.sqlbrowserfx.nodes; 2 | 3 | public class PostgreSqlConfigBox extends DbConfigBox { 4 | 5 | @Override 6 | public String getHistoryQuery() { 7 | return "select url, user, database, timestamp, id from connections_history_localtime" 8 | + " where database_type = '" + getSqlConnectorType() + "' order by timestamp desc"; 9 | } 10 | 11 | @Override 12 | public String getSqlConnectorType() { 13 | return SqlConnectorType.POSTGRESQL.toString().toLowerCase(); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/gr/sqlbrowserfx/nodes/SqlConnectorType.java: -------------------------------------------------------------------------------- 1 | package gr.sqlbrowserfx.nodes; 2 | 3 | public enum SqlConnectorType { 4 | 5 | MYSQL, 6 | SQLSERVER, 7 | SQLITE, 8 | POSTGRESQL 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/gr/sqlbrowserfx/nodes/SqlServerConfigBox.java: -------------------------------------------------------------------------------- 1 | package gr.sqlbrowserfx.nodes; 2 | 3 | public class SqlServerConfigBox extends DbConfigBox { 4 | 5 | @Override 6 | public String getHistoryQuery() { 7 | return "select url, user, database, timestamp, id from connections_history_localtime" 8 | + " where database_type = '" + getSqlConnectorType() + "' order by timestamp desc"; 9 | } 10 | 11 | @Override 12 | public String getSqlConnectorType() { 13 | return SqlConnectorType.SQLSERVER.toString().toLowerCase(); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/gr/sqlbrowserfx/nodes/SqlTableNode.java: -------------------------------------------------------------------------------- 1 | package gr.sqlbrowserfx.nodes; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import org.controlsfx.control.PopOver; 7 | import org.fxmisc.flowless.VirtualizedScrollPane; 8 | 9 | import gr.sqlbrowserfx.conn.DbCash; 10 | import gr.sqlbrowserfx.conn.SqlTable; 11 | import gr.sqlbrowserfx.nodes.codeareas.sql.SqlCodeArea; 12 | import gr.sqlbrowserfx.utils.JavaFXUtils; 13 | import javafx.geometry.Insets; 14 | import javafx.geometry.Pos; 15 | import javafx.scene.control.Label; 16 | import javafx.scene.layout.Region; 17 | import javafx.scene.layout.VBox; 18 | import javafx.scene.shape.Line; 19 | 20 | public class SqlTableNode extends VBox { 21 | 22 | private final SqlTable table; 23 | private final String color; 24 | private final List lines = new ArrayList<>(); 25 | 26 | public SqlTableNode(SqlTable table) { 27 | // restore this line to have colorful lines 28 | this.color = "-fx-diagram-color"; 29 | 30 | this.table = table; 31 | this.setMinWidth(150); 32 | var titleLabel = new Label(table.getName(), JavaFXUtils.createIcon("/icons/table.png")); 33 | titleLabel.setPadding(new Insets(0, 0, 6, 0)); 34 | titleLabel.setAlignment(Pos.CENTER); 35 | configureTitleBorder(titleLabel); 36 | var columnsVbox = new VBox(); 37 | table.getColumns().forEach(col -> { 38 | if (table.isPrimaryKey(col)) { 39 | columnsVbox.getChildren() 40 | .add(new Label(table.getPrimaryKey(), JavaFXUtils.createIcon("/icons/primary-key.png"))); 41 | } else if (table.isForeignKey(col)) { 42 | columnsVbox.getChildren().add(new Label(col, JavaFXUtils.createIcon("/icons/foreign-key.png"))); 43 | } else { 44 | columnsVbox.getChildren().add(new Label(col)); 45 | } 46 | }); 47 | 48 | columnsVbox.setPadding(new Insets(6)); 49 | 50 | this.getChildren().addAll(titleLabel, columnsVbox); 51 | 52 | titleLabel.prefWidthProperty().bind(columnsVbox.widthProperty()); 53 | configureBorder(this); 54 | } 55 | 56 | public void showSchemaPopup() { 57 | var schema = DbCash.getSchemaFor(table.getName()); 58 | SqlCodeArea codeArea = new SqlCodeArea(schema, false, false, true); 59 | VirtualizedScrollPane scrollPane = new VirtualizedScrollPane<>(codeArea); 60 | scrollPane.setPrefSize(600, 400); 61 | 62 | PopOver popOver = new PopOver(scrollPane); 63 | popOver.setArrowSize(0); 64 | popOver.setDetachable(false); 65 | popOver.show(this); 66 | } 67 | 68 | public SqlTable getSqlTable() { 69 | return this.table; 70 | } 71 | 72 | public String getColor() { 73 | return this.color; 74 | } 75 | 76 | public List getLines() { 77 | return lines; 78 | } 79 | 80 | public void highlight() { 81 | configureSelectedBorder(this); 82 | } 83 | 84 | public void unhighlight() { 85 | configureBorder(this); 86 | } 87 | 88 | private void configureBorder(final Region region) { 89 | region.setStyle( 90 | // "-fx-border-color: " + color + ";" + 91 | """ 92 | -fx-background-color: -fx-diagram-color; 93 | -fx-background-radius: 6; 94 | -fx-border-width: 1; 95 | -fx-border-radius: 6; 96 | -fx-padding: 6 0 6 0; 97 | """); 98 | } 99 | 100 | private void configureSelectedBorder(final Region region) { 101 | region.setStyle(""" 102 | -fx-border-color: -fx-accent; 103 | -fx-background-color: -fx-diagram-color; 104 | -fx-background-radius: 6; 105 | -fx-border-width: 3; 106 | -fx-border-radius: 6; 107 | -fx-padding: 6 0 6 0; 108 | """); 109 | } 110 | 111 | private void configureTitleBorder(final Region region) { 112 | region.setStyle(""" 113 | -fx-border-color: -fx-base; 114 | -fx-border-width: 0 0 1 0; 115 | """); 116 | } 117 | 118 | 119 | } 120 | -------------------------------------------------------------------------------- /src/main/java/gr/sqlbrowserfx/nodes/ToolbarOwner.java: -------------------------------------------------------------------------------- 1 | package gr.sqlbrowserfx.nodes; 2 | 3 | import javafx.scene.layout.FlowPane; 4 | 5 | public interface ToolbarOwner { 6 | 7 | FlowPane createToolbar(); 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/gr/sqlbrowserfx/nodes/TreeViewFile.java: -------------------------------------------------------------------------------- 1 | package gr.sqlbrowserfx.nodes; 2 | 3 | import java.io.File; 4 | import java.io.Serial; 5 | 6 | public class TreeViewFile extends File { 7 | 8 | @Serial 9 | private static final long serialVersionUID = 1L; 10 | 11 | public TreeViewFile(String pathname) { 12 | super(pathname); 13 | } 14 | 15 | 16 | public File asFile() { 17 | return (File) this; 18 | } 19 | 20 | @Override 21 | public String toString() { 22 | return super.getName(); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/gr/sqlbrowserfx/nodes/codeareas/CodeAreaSyntaxProvider.java: -------------------------------------------------------------------------------- 1 | package gr.sqlbrowserfx.nodes.codeareas; 2 | 3 | import java.util.Set; 4 | import java.util.regex.Matcher; 5 | 6 | public interface CodeAreaSyntaxProvider { 7 | 8 | Set getKeywords(); 9 | Set getKeywords(KeywordType type, T data); 10 | Matcher getPatternMatcher(String text); 11 | String format(String text); 12 | String format(String text, FormatterMode mode); 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/gr/sqlbrowserfx/nodes/codeareas/FileCodeArea.java: -------------------------------------------------------------------------------- 1 | package gr.sqlbrowserfx.nodes.codeareas; 2 | 3 | public interface FileCodeArea { 4 | 5 | boolean isTextDirty(); 6 | String getPath(); 7 | void saveFileAction(); 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/gr/sqlbrowserfx/nodes/codeareas/FormatterMode.java: -------------------------------------------------------------------------------- 1 | package gr.sqlbrowserfx.nodes.codeareas; 2 | 3 | public enum FormatterMode { 4 | DEFAULT, 5 | ALTERNATE, 6 | } 7 | -------------------------------------------------------------------------------- /src/main/java/gr/sqlbrowserfx/nodes/codeareas/HighLighter.java: -------------------------------------------------------------------------------- 1 | package gr.sqlbrowserfx.nodes.codeareas; 2 | 3 | import java.util.Collection; 4 | 5 | import org.fxmisc.richtext.model.StyleSpans; 6 | 7 | public interface HighLighter { 8 | 9 | StyleSpans> computeHighlighting(String text); 10 | 11 | void enableHighlighting(); 12 | void enableShowLineNumbers(boolean enable); 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/gr/sqlbrowserfx/nodes/codeareas/Keyword.java: -------------------------------------------------------------------------------- 1 | package gr.sqlbrowserfx.nodes.codeareas; 2 | 3 | public class Keyword { 4 | 5 | private String keyword; 6 | private String description; 7 | private KeywordType type; 8 | 9 | public Keyword(String keyword, KeywordType type) { 10 | super(); 11 | this.keyword = keyword; 12 | this.type = type; 13 | } 14 | 15 | public Keyword(String keyword, String description, KeywordType type) { 16 | this(keyword, type); 17 | this.description = description; 18 | } 19 | 20 | public Keyword() { 21 | } 22 | 23 | public String getKeyword() { 24 | return keyword; 25 | } 26 | 27 | public void setKeyword(String keyword) { 28 | this.keyword = keyword; 29 | } 30 | 31 | public KeywordType getType() { 32 | return type; 33 | } 34 | 35 | public void setType(KeywordType type) { 36 | this.type = type; 37 | } 38 | 39 | public String getDescription() { 40 | return description; 41 | } 42 | 43 | 44 | public void setDescription(String description) { 45 | this.description = description; 46 | } 47 | 48 | public boolean isFunction() { 49 | return this.type == KeywordType.FUNCTION; 50 | } 51 | 52 | public boolean isKeyword() { 53 | return this.type == KeywordType.KEYWORD; 54 | } 55 | 56 | public boolean isType() { 57 | return this.type == KeywordType.TYPE; 58 | } 59 | 60 | public boolean isTable() { 61 | return this.type == KeywordType.TABLE; 62 | } 63 | 64 | public boolean isQuery() { 65 | return this.type == KeywordType.QUERY; 66 | } 67 | 68 | public boolean isColumn() { 69 | return this.type == KeywordType.COLUMN; 70 | 71 | } 72 | 73 | public boolean isVariable() { 74 | return this.type == KeywordType.VARIABLE; 75 | } 76 | 77 | public boolean isAlias() { 78 | return this.type == KeywordType.ALIAS; 79 | } 80 | 81 | @Override 82 | public int hashCode() { 83 | // return always 0 to always invoke equals in sets 84 | return 0; 85 | } 86 | 87 | @Override 88 | public boolean equals(Object obj) { 89 | if (obj instanceof Keyword) { 90 | Keyword keyword = (Keyword) obj; 91 | return this.getKeyword().equals(keyword.getKeyword()) && this.getType() == keyword.getType(); 92 | } else { 93 | return super.equals(obj); 94 | } 95 | } 96 | 97 | } 98 | -------------------------------------------------------------------------------- /src/main/java/gr/sqlbrowserfx/nodes/codeareas/KeywordType.java: -------------------------------------------------------------------------------- 1 | package gr.sqlbrowserfx.nodes.codeareas; 2 | 3 | public enum KeywordType { 4 | KEYWORD, 5 | FUNCTION, 6 | TABLE, 7 | ALIAS, 8 | VIEW, 9 | COLUMN, 10 | TYPE, 11 | QUERY, 12 | VARIABLE 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/gr/sqlbrowserfx/nodes/codeareas/SearchableCodeArea.java: -------------------------------------------------------------------------------- 1 | package gr.sqlbrowserfx.nodes.codeareas; 2 | 3 | import org.fxmisc.richtext.CodeArea; 4 | import org.fxmisc.wellbehaved.event.EventPattern; 5 | import org.fxmisc.wellbehaved.event.InputMap; 6 | import org.fxmisc.wellbehaved.event.Nodes; 7 | 8 | import gr.sqlbrowserfx.nodes.InputMapOwner; 9 | import gr.sqlbrowserfx.nodes.SearchAndReplacePopOver; 10 | import javafx.scene.input.KeyCode; 11 | import javafx.scene.input.KeyCombination; 12 | 13 | public class SearchableCodeArea extends CodeArea implements InputMapOwner { 14 | 15 | private final SearchAndReplacePopOver searchAndReplacePopOver; 16 | 17 | public SearchableCodeArea() { 18 | searchAndReplacePopOver = new SearchAndReplacePopOver(this, false); 19 | setOnMouseClicked(event -> searchAndReplacePopOver.hide()); 20 | setInputMap(); 21 | } 22 | 23 | private void showSearchAndReplacePopup() { 24 | if (!this.getSelectedText().isEmpty()) { 25 | searchAndReplacePopOver.getFindField().setText(this.getSelectedText()); 26 | searchAndReplacePopOver.getFindField().selectAll(); 27 | } 28 | var boundsInScene = this.localToScreen(this.getBoundsInLocal()); 29 | searchAndReplacePopOver.show(getParent(), boundsInScene.getMaxX() - 400, boundsInScene.getMinY()); 30 | } 31 | 32 | @Override 33 | public void setInputMap() { 34 | var searchAndReplace = InputMap.consume( 35 | EventPattern.keyPressed(KeyCode.F, KeyCombination.CONTROL_DOWN), 36 | action -> this.showSearchAndReplacePopup()); 37 | 38 | Nodes.addInputMap(this, searchAndReplace); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/gr/sqlbrowserfx/nodes/codeareas/SimpleFileCodeArea.java: -------------------------------------------------------------------------------- 1 | package gr.sqlbrowserfx.nodes.codeareas; 2 | 3 | import java.io.File; 4 | import java.io.IOException; 5 | import java.nio.file.Files; 6 | import java.nio.file.Paths; 7 | import java.nio.file.StandardOpenOption; 8 | import java.util.Date; 9 | import java.util.stream.Collectors; 10 | 11 | import org.apache.commons.lang3.StringUtils; 12 | import org.fxmisc.wellbehaved.event.EventPattern; 13 | import org.fxmisc.wellbehaved.event.InputMap; 14 | import org.fxmisc.wellbehaved.event.Nodes; 15 | import org.slf4j.LoggerFactory; 16 | 17 | import gr.sqlbrowserfx.LoggerConf; 18 | import gr.sqlbrowserfx.factories.DialogFactory; 19 | import gr.sqlbrowserfx.utils.JavaFXUtils; 20 | import javafx.event.Event; 21 | import javafx.scene.control.ContextMenu; 22 | import javafx.scene.control.MenuItem; 23 | import javafx.scene.control.SeparatorMenuItem; 24 | import javafx.scene.input.KeyCode; 25 | import javafx.scene.input.KeyCombination; 26 | 27 | public class SimpleFileCodeArea extends AutoCompleteCodeArea implements FileCodeArea { 28 | 29 | private final File file; 30 | private String lastSavedContent; 31 | 32 | public SimpleFileCodeArea(File file) { 33 | super(); 34 | this.file = file; 35 | try(var lines = Files.lines(Paths.get(file.getAbsolutePath()))) { 36 | lastSavedContent = StringUtils.join(lines.collect(Collectors.toList()), "\n"); 37 | } catch (IOException e) { 38 | LoggerFactory.getLogger(LoggerConf.LOGGER_NAME).error("Could not load file " + file.getName(), e); 39 | } 40 | this.replaceText(lastSavedContent); 41 | getUndoManager().forgetHistory(); 42 | } 43 | 44 | public boolean isTextDirty() { 45 | return !this.getText().equals(this.lastSavedContent); 46 | } 47 | 48 | public String getPath() { 49 | return file.getPath(); 50 | } 51 | 52 | public void saveFileAction() { 53 | try { 54 | Files.write(Paths.get(this.getPath()), this.getText().getBytes(), StandardOpenOption.TRUNCATE_EXISTING); 55 | this.lastSavedContent = this.getText(); 56 | getUndoManager().forgetHistory(); 57 | } catch (IOException e) { 58 | DialogFactory.createErrorDialog(e); 59 | } 60 | DialogFactory.createNotification("File saved", "File saved at " + new Date()); 61 | } 62 | 63 | @Override 64 | public ContextMenu createContextMenu() { 65 | var menu = super.createContextMenu(); 66 | var menuItemSave = new MenuItem("Save File", JavaFXUtils.createIcon("/icons/save.png")); 67 | menuItemSave.setOnAction(action -> this.saveFileAction()); 68 | 69 | menu.getItems().addAll(new SeparatorMenuItem(), menuItemSave); 70 | return menu; 71 | } 72 | 73 | @Override 74 | public void setInputMap() { 75 | super.setInputMap(); 76 | InputMap save = InputMap.consume( 77 | EventPattern.keyPressed(KeyCode.S, KeyCombination.CONTROL_DOWN), 78 | action -> this.saveFileAction() 79 | ); 80 | Nodes.addInputMap(this, save); 81 | } 82 | 83 | @Override 84 | protected SimpleFileCodeAreaSyntaxProvider initSyntaxProvider() { 85 | return new SimpleFileCodeAreaSyntaxProvider(); 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /src/main/java/gr/sqlbrowserfx/nodes/codeareas/SimpleFileCodeAreaSyntaxProvider.java: -------------------------------------------------------------------------------- 1 | package gr.sqlbrowserfx.nodes.codeareas; 2 | 3 | import java.util.HashSet; 4 | import java.util.Set; 5 | import java.util.regex.Matcher; 6 | import java.util.regex.Pattern; 7 | 8 | public class SimpleFileCodeAreaSyntaxProvider implements CodeAreaSyntaxProvider{ 9 | 10 | private final Pattern pattern = Pattern.compile(""); 11 | private final Set emptySet = new HashSet<>(); 12 | 13 | @Override 14 | public Set getKeywords() { 15 | return emptySet; 16 | } 17 | 18 | @Override 19 | public Set getKeywords(KeywordType type, String data) { 20 | return emptySet; 21 | } 22 | 23 | @Override 24 | public Matcher getPatternMatcher(String text) { 25 | return pattern.matcher(text); 26 | } 27 | 28 | @Override 29 | public String format(String text) { 30 | return text; 31 | } 32 | 33 | @Override 34 | public String format(String text, FormatterMode mode) { 35 | return text; 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/gr/sqlbrowserfx/nodes/codeareas/SuggestionListCell.java: -------------------------------------------------------------------------------- 1 | package gr.sqlbrowserfx.nodes.codeareas; 2 | 3 | import gr.sqlbrowserfx.utils.JavaFXUtils; 4 | import javafx.beans.value.ObservableValue; 5 | import javafx.geometry.Pos; 6 | import javafx.scene.control.Label; 7 | import javafx.scene.control.ListCell; 8 | import javafx.scene.control.ListView; 9 | import javafx.scene.layout.HBox; 10 | 11 | public class SuggestionListCell extends ListCell{ 12 | 13 | private final ListView listView; 14 | 15 | public SuggestionListCell(ListView listView) { 16 | this.listView = listView; 17 | } 18 | 19 | @Override 20 | protected void updateItem(Keyword item, boolean empty) { 21 | super.updateItem(item, empty); 22 | this.setGraphic(null); 23 | if (item == null || empty) { 24 | setText(null); 25 | } else { 26 | var text = new StringBuilder(item.getKeyword()); 27 | if (item.getDescription() != null) { 28 | text.append(" "); 29 | text.append(item.getDescription()); 30 | } 31 | if(item.isFunction()) { 32 | var hint = new Label(item.getDescription()); 33 | hint.setStyle("-fx-text-fill: -fx-secondary-light-color; -fx-font-size: 10pt;"); 34 | 35 | var hbox = new HBox( 36 | JavaFXUtils.createIcon("/icons/function.png"), 37 | new Label(item.getKeyword()), 38 | hint 39 | ); 40 | hbox.setSpacing(5); 41 | hbox.setAlignment(Pos.CENTER_LEFT); 42 | 43 | this.setGraphic(hbox); 44 | setText(null); 45 | } 46 | else if (item.isTable()) { 47 | setText(text.toString()); 48 | this.setGraphic(JavaFXUtils.createIcon("/icons/table.png")); 49 | } 50 | else if (item.isQuery()) { 51 | setText(text.toString()); 52 | this.setGraphic(JavaFXUtils.createIcon("/icons/thunder.png")); 53 | } 54 | else if (item.isColumn()) { 55 | setText(text.toString()); 56 | this.setGraphic(JavaFXUtils.createIcon("/icons/blue.png")); 57 | } 58 | else if (item.isVariable()) { 59 | setText(text.toString()); 60 | this.setGraphic(JavaFXUtils.createIcon("/icons/var.png")); 61 | } 62 | else if (item.isAlias()) { 63 | setText(text.toString()); 64 | this.setGraphic(JavaFXUtils.createIcon("/icons/table-y.png")); 65 | } 66 | else { 67 | setText(text.toString()); 68 | this.setGraphic(JavaFXUtils.createIcon("/icons/green.png")); 69 | } 70 | 71 | widthProperty().addListener(this::widthChanged); 72 | } 73 | } 74 | 75 | private void widthChanged(ObservableValue observable, Number oldValue, Number newValue) { 76 | double width = getWidth() + listView.getInsets().getLeft() + listView.getInsets().getRight(); 77 | listView.setPrefWidth(Math.max(listView.getPrefWidth(), width)); 78 | 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/main/java/gr/sqlbrowserfx/nodes/codeareas/TextAnalyzer.java: -------------------------------------------------------------------------------- 1 | package gr.sqlbrowserfx.nodes.codeareas; 2 | 3 | public interface TextAnalyzer { 4 | 5 | void startTextAnalyzerDaemon(); 6 | void stopTextAnalyzerDaemon(); 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/gr/sqlbrowserfx/nodes/codeareas/java/FileJavaCodeArea.java: -------------------------------------------------------------------------------- 1 | package gr.sqlbrowserfx.nodes.codeareas.java; 2 | 3 | import java.io.File; 4 | import java.io.IOException; 5 | import java.nio.file.Files; 6 | import java.nio.file.Paths; 7 | import java.nio.file.StandardOpenOption; 8 | import java.util.Date; 9 | import java.util.stream.Collectors; 10 | 11 | import org.apache.commons.lang3.StringUtils; 12 | import org.fxmisc.wellbehaved.event.EventPattern; 13 | import org.fxmisc.wellbehaved.event.InputMap; 14 | import org.fxmisc.wellbehaved.event.Nodes; 15 | import org.slf4j.LoggerFactory; 16 | 17 | import gr.sqlbrowserfx.LoggerConf; 18 | import gr.sqlbrowserfx.factories.DialogFactory; 19 | import gr.sqlbrowserfx.nodes.codeareas.FileCodeArea; 20 | import gr.sqlbrowserfx.utils.JavaFXUtils; 21 | import javafx.scene.control.ContextMenu; 22 | import javafx.scene.control.MenuItem; 23 | import javafx.scene.control.SeparatorMenuItem; 24 | import javafx.scene.input.KeyCode; 25 | import javafx.scene.input.KeyCombination; 26 | 27 | public class FileJavaCodeArea extends JavaCodeArea implements FileCodeArea { 28 | 29 | private final File file; 30 | private String lastSavedContent; 31 | 32 | public FileJavaCodeArea(File file) { 33 | super(); 34 | this.file = file; 35 | try(var lines = Files.lines(Paths.get(file.getAbsolutePath()))) { 36 | lastSavedContent = StringUtils.join(lines.collect(Collectors.toList()), "\n"); 37 | } catch (IOException e) { 38 | LoggerFactory.getLogger(LoggerConf.LOGGER_NAME).error("Could not load file " + file.getName(), e); 39 | } 40 | this.replaceText(lastSavedContent); 41 | getUndoManager().forgetHistory(); 42 | } 43 | 44 | public boolean isTextDirty() { 45 | return !this.getText().equals(this.lastSavedContent); 46 | } 47 | 48 | public String getPath() { 49 | return file.getPath(); 50 | } 51 | 52 | public void saveFileAction() { 53 | try { 54 | Files.write(Paths.get(this.getPath()), this.getText().getBytes(), StandardOpenOption.TRUNCATE_EXISTING); 55 | this.lastSavedContent = this.getText(); 56 | getUndoManager().forgetHistory(); 57 | DialogFactory.createNotification("File saved", "File saved at " + new Date()); 58 | } catch (IOException e) { 59 | DialogFactory.createErrorDialog(e); 60 | } 61 | } 62 | 63 | @Override 64 | public ContextMenu createContextMenu() { 65 | var menu = super.createContextMenu(); 66 | var menuItemSave = new MenuItem("Save File", JavaFXUtils.createIcon("/icons/save.png")); 67 | menuItemSave.setOnAction(action -> this.saveFileAction()); 68 | 69 | menu.getItems().addAll(new SeparatorMenuItem(), menuItemSave); 70 | return menu; 71 | } 72 | 73 | @Override 74 | public void setInputMap() { 75 | super.setInputMap(); 76 | var save = InputMap.consume( 77 | EventPattern.keyPressed(KeyCode.S, KeyCombination.CONTROL_DOWN), 78 | action -> this.saveFileAction() 79 | ); 80 | Nodes.addInputMap(this, save); 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/main/java/gr/sqlbrowserfx/nodes/codeareas/java/JavaCodeAreaSyntaxProvider.java: -------------------------------------------------------------------------------- 1 | package gr.sqlbrowserfx.nodes.codeareas.java; 2 | 3 | import java.util.Arrays; 4 | import java.util.LinkedHashSet; 5 | import java.util.Set; 6 | import java.util.regex.Matcher; 7 | import java.util.regex.Pattern; 8 | 9 | import gr.sqlbrowserfx.nodes.codeareas.CodeAreaSyntaxProvider; 10 | import gr.sqlbrowserfx.nodes.codeareas.FormatterMode; 11 | import gr.sqlbrowserfx.nodes.codeareas.Keyword; 12 | import gr.sqlbrowserfx.nodes.codeareas.KeywordType; 13 | import gr.sqlbrowserfx.utils.SqlFormatter; 14 | 15 | public class JavaCodeAreaSyntaxProvider implements CodeAreaSyntaxProvider { 16 | 17 | 18 | private static final String[] FUNCTIONS = new String[] {}; 19 | private static final String[] KEYWORDS = new String[] { 20 | "abstract", "assert", "boolean", "break", "byte", 21 | "case", "catch", "char", "class", "const", 22 | "continue", "default", "do", "double", "else", 23 | "enum", "extends", "final", "finally", "float", 24 | "for", "goto", "if", "implements", "import", 25 | "instanceof", "int", "interface", "long", "native", 26 | "new", "package", "private", "protected", "public", 27 | "return", "short", "static", "strictfp", "super", 28 | "switch", "synchronized", "this", "throw", "throws", 29 | "transient", "try", "void", "volatile", "while", "var" 30 | }; 31 | 32 | private static final Set KEYWORDS_lIST = new LinkedHashSet<>( 33 | Arrays.asList(KEYWORDS).stream().map(word -> new Keyword(word, KeywordType.KEYWORD)).toList()); 34 | 35 | private static final String KEYWORD_PATTERN = "\\b(" + String.join("|", KEYWORDS) + ")\\b"; 36 | private static final String PAREN_PATTERN = "\\(|\\)"; 37 | private static final String BRACE_PATTERN = "\\{|\\}"; 38 | private static final String BRACKET_PATTERN = "\\[|\\]"; 39 | private static final String SEMICOLON_PATTERN = "\\;"; 40 | private static final String STRING_PATTERN = "\"([^\"\\\\]|\\\\.)*\""; 41 | private static final String STRING_PATTERN_2 = "\"([^\"\\\\]|\\\\.)*\""; 42 | private static final String COMMENT_PATTERN = "//[^\n]*" + "|" + "/\\*(.|\\R)*?\\*/" // for whole text processing (text blocks) 43 | + "|" + "/\\*[^\\v]*" + "|" + "^\\h*\\*([^\\v]*|/)"; // for visible paragraph processing (line by line) 44 | private static final String FUNCTIONS_PATTERN = "\\b(" + String.join("|", FUNCTIONS) + ")\\b"; 45 | private static final String METHOD_PATTERN = "\\.[a-zA-Z0-9_]+"; 46 | 47 | private static final Pattern PATTERN = Pattern.compile( 48 | "(?" + KEYWORD_PATTERN + ")" 49 | + "|(?" + PAREN_PATTERN + ")" 50 | + "|(?" + BRACE_PATTERN + ")" 51 | + "|(?" + BRACKET_PATTERN + ")" 52 | + "|(?" + SEMICOLON_PATTERN + ")" 53 | + "|(?" + STRING_PATTERN + ")" 54 | + "|(?" + STRING_PATTERN_2 + ")" 55 | + "|(?" + COMMENT_PATTERN + ")" 56 | + "|(?" + FUNCTIONS_PATTERN + ")" 57 | + "|(?" + METHOD_PATTERN + ")" 58 | ); 59 | 60 | public static void init(String dbType) { 61 | init(); 62 | } 63 | 64 | private static void init() { 65 | } 66 | 67 | 68 | @Override 69 | public Set getKeywords() { 70 | return KEYWORDS_lIST; 71 | } 72 | 73 | @Override 74 | public Set getKeywords(KeywordType type, String tableAlias) { 75 | return getKeywords(); 76 | } 77 | 78 | @Override 79 | public Matcher getPatternMatcher(String text) { 80 | return PATTERN.matcher(text); 81 | } 82 | 83 | @Override 84 | public String format(String text) { 85 | return SqlFormatter.format(text); 86 | } 87 | 88 | @Override 89 | public String format(String text, FormatterMode mode) { 90 | switch (mode) { 91 | case DEFAULT: 92 | return SqlFormatter.formatDefault(text); 93 | case ALTERNATE: 94 | return SqlFormatter.formatAlternative(text); 95 | default: 96 | return SqlFormatter.format(text); 97 | } 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /src/main/java/gr/sqlbrowserfx/nodes/codeareas/log/CodeAreaTailerListener.java: -------------------------------------------------------------------------------- 1 | package gr.sqlbrowserfx.nodes.codeareas.log; 2 | 3 | import org.apache.commons.io.input.Tailer; 4 | import org.apache.commons.io.input.TailerListener; 5 | import org.fxmisc.richtext.CodeArea; 6 | 7 | import gr.sqlbrowserfx.factories.DialogFactory; 8 | import javafx.application.Platform; 9 | 10 | public class CodeAreaTailerListener implements TailerListener { 11 | 12 | private final CodeArea codeArea; 13 | 14 | public CodeAreaTailerListener(CodeArea codeArea) { 15 | this.codeArea = codeArea; 16 | } 17 | @Override 18 | public void init(Tailer tailer) { 19 | } 20 | 21 | @Override 22 | public void fileNotFound() { 23 | } 24 | 25 | @Override 26 | public void fileRotated() { 27 | } 28 | 29 | @Override 30 | public void handle(String line) { 31 | Platform.runLater(() -> codeArea.appendText(line + "\n")); 32 | } 33 | 34 | @Override 35 | public void handle(Exception ex) { 36 | DialogFactory.createErrorDialog(ex); 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/gr/sqlbrowserfx/nodes/codeareas/log/LogCodeAreaSyntaxProvider.java: -------------------------------------------------------------------------------- 1 | package gr.sqlbrowserfx.nodes.codeareas.log; 2 | 3 | import java.util.Arrays; 4 | import java.util.LinkedHashSet; 5 | import java.util.Set; 6 | import java.util.regex.Matcher; 7 | import java.util.regex.Pattern; 8 | 9 | import gr.sqlbrowserfx.nodes.codeareas.CodeAreaSyntaxProvider; 10 | import gr.sqlbrowserfx.nodes.codeareas.FormatterMode; 11 | import gr.sqlbrowserfx.nodes.codeareas.Keyword; 12 | import gr.sqlbrowserfx.nodes.codeareas.KeywordType; 13 | 14 | @SuppressWarnings("rawtypes") 15 | public class LogCodeAreaSyntaxProvider implements CodeAreaSyntaxProvider { 16 | 17 | private static final String[] FUNCTIONS = {"INFO", "DEBUG"}; 18 | private static final String[] KEYWORDS = {"ERROR", "FATAL"}; 19 | private static final Set KEYWORDS_lIST = new LinkedHashSet<>(); 20 | 21 | private static final String KEYWORD_PATTERN = "\\b(" + String.join("|", KEYWORDS) + ")\\b"; 22 | private static final String FUNCTIONS_PATTERN = "\\b(" + String.join("|", FUNCTIONS) + ")\\b"; 23 | 24 | private static final Pattern PATTERN = Pattern 25 | .compile("(?" + KEYWORD_PATTERN + ")" + 26 | "|(?" + FUNCTIONS_PATTERN + ")"); 27 | 28 | static { 29 | KEYWORDS_lIST.addAll(Arrays.stream(KEYWORDS) 30 | .map(kw -> new Keyword(kw, KeywordType.KEYWORD)).toList()); 31 | KEYWORDS_lIST.addAll(Arrays.stream(FUNCTIONS) 32 | .map(kw -> new Keyword(kw, KeywordType.FUNCTION)).toList()); 33 | 34 | } 35 | 36 | @Override 37 | public Set getKeywords() { 38 | return KEYWORDS_lIST; 39 | } 40 | 41 | @Override 42 | public Set getKeywords(KeywordType type, Object data) { 43 | throw new RuntimeException("Method 'getKeywords' not implemented"); 44 | } 45 | 46 | @Override 47 | public Matcher getPatternMatcher(String text) { 48 | return PATTERN.matcher(text); 49 | } 50 | 51 | @Override 52 | public String format(String text) { 53 | throw new RuntimeException("Method 'format' not implemented"); 54 | } 55 | 56 | @Override 57 | public String format(String text, FormatterMode mode) { 58 | throw new RuntimeException("Method 'format' not implemented"); 59 | } 60 | 61 | } 62 | 63 | -------------------------------------------------------------------------------- /src/main/java/gr/sqlbrowserfx/nodes/codeareas/sql/CSqlCodeArea.java: -------------------------------------------------------------------------------- 1 | package gr.sqlbrowserfx.nodes.codeareas.sql; 2 | 3 | import java.sql.SQLException; 4 | import java.util.Arrays; 5 | 6 | import org.controlsfx.control.PopOver; 7 | import org.fxmisc.wellbehaved.event.EventPattern; 8 | import org.fxmisc.wellbehaved.event.InputMap; 9 | import org.fxmisc.wellbehaved.event.Nodes; 10 | 11 | import gr.sqlbrowserfx.SqlBrowserFXAppManager; 12 | import gr.sqlbrowserfx.factories.DialogFactory; 13 | import gr.sqlbrowserfx.listeners.SimpleEvent; 14 | import gr.sqlbrowserfx.utils.JavaFXUtils; 15 | import javafx.scene.control.Button; 16 | import javafx.scene.control.ComboBox; 17 | import javafx.scene.control.ContextMenu; 18 | import javafx.scene.control.Label; 19 | import javafx.scene.control.MenuItem; 20 | import javafx.scene.control.TextField; 21 | import javafx.scene.input.KeyCode; 22 | import javafx.scene.input.KeyCombination; 23 | import javafx.scene.layout.VBox; 24 | 25 | public class CSqlCodeArea extends SqlCodeArea { 26 | 27 | private PopOver saveQueryPopOver; 28 | 29 | public CSqlCodeArea() { 30 | super(); 31 | } 32 | 33 | @Override 34 | public ContextMenu createContextMenu() { 35 | var menu = super.createContextMenu(); 36 | var menuItemSave = new MenuItem("Save Query", JavaFXUtils.createIcon("/icons/thunder.png")); 37 | menuItemSave.setOnAction(action -> this.saveQueryAction()); 38 | menuItemSave.disableProperty().bind(this.isTextSelectedProperty().not()); 39 | menu.getItems().addAll(menuItemSave); 40 | return menu; 41 | } 42 | 43 | @Override 44 | protected void onMouseClicked() { 45 | super.onMouseClicked(); 46 | if (saveQueryPopOver != null) { 47 | saveQueryPopOver.hide(); 48 | } 49 | } 50 | 51 | @Override 52 | public void setInputMap() { 53 | if (!isEditable()) { 54 | return; 55 | } 56 | 57 | super.setInputMap(); 58 | var saveQuery = InputMap.consume( 59 | EventPattern.keyPressed(KeyCode.S, KeyCombination.CONTROL_DOWN), 60 | action -> this.saveQueryAction() 61 | ); 62 | 63 | Nodes.addInputMap(this, saveQuery); 64 | } 65 | 66 | protected void saveQueryAction() { 67 | final var sqlConnector = SqlBrowserFXAppManager.getConfigSqlConnector(); 68 | var descriptionField = new TextField(); 69 | descriptionField.setPromptText("Description"); 70 | 71 | var categoryField = new ComboBox(); 72 | categoryField.setEditable(true); 73 | try { 74 | sqlConnector.executeQuery("select distinct category from saved_queries", rset -> categoryField.getItems().add(rset.getString(1))); 75 | } catch (SQLException e) { 76 | DialogFactory.createErrorNotification(e); 77 | } 78 | 79 | var addButton = new Button("Save", JavaFXUtils.createIcon("/icons/save.png")); 80 | addButton.setOnAction(event -> { 81 | sqlConnector.executeAsync(() -> { 82 | try { 83 | var query = !this.getSelectedText().isEmpty() ? this.getSelectedText() : this.getText(); 84 | sqlConnector.executeUpdate("insert into saved_queries (query,category,description) values (?,?,?)", 85 | Arrays.asList(query, 86 | categoryField.getSelectionModel().getSelectedItem(), 87 | descriptionField.getText())); 88 | DialogFactory.createNotification("Info", "Query has been saved successfuly"); 89 | this.fireEvent(new SimpleEvent()); 90 | } catch (SQLException e) { 91 | DialogFactory.createErrorNotification(e); 92 | } 93 | }); 94 | }); 95 | 96 | categoryField.setPromptText("Write a name to create new..."); 97 | var vb = new VBox( 98 | new Label("Choose category"), 99 | categoryField, 100 | descriptionField, 101 | addButton); 102 | vb.setPrefWidth(300); 103 | 104 | categoryField.prefWidthProperty().bind(vb.widthProperty()); 105 | saveQueryPopOver = new PopOver(vb); 106 | 107 | categoryField.setOnKeyPressed(keyEvent -> { 108 | if (keyEvent.getCode() == KeyCode.ESCAPE) { 109 | saveQueryPopOver.hide(); 110 | } 111 | }); 112 | descriptionField.setOnKeyPressed(keyEvent -> { 113 | if (keyEvent.getCode() == KeyCode.ESCAPE) { 114 | saveQueryPopOver.hide(); 115 | } 116 | }); 117 | saveQueryPopOver.setArrowSize(0); 118 | var boundsInScene = this.localToScreen(this.getBoundsInLocal()); 119 | saveQueryPopOver.show(getParent(), boundsInScene.getMinX() + saveQueryPopOver.getWidth() / 3, 120 | boundsInScene.getMinY() - saveQueryPopOver.getHeight() / 2); 121 | } 122 | 123 | } 124 | -------------------------------------------------------------------------------- /src/main/java/gr/sqlbrowserfx/nodes/codeareas/sql/FileSqlCodeArea.java: -------------------------------------------------------------------------------- 1 | package gr.sqlbrowserfx.nodes.codeareas.sql; 2 | 3 | import java.io.File; 4 | import java.io.IOException; 5 | import java.nio.file.Files; 6 | import java.nio.file.Paths; 7 | import java.nio.file.StandardOpenOption; 8 | import java.util.Date; 9 | import java.util.stream.Collectors; 10 | 11 | import org.apache.commons.lang3.StringUtils; 12 | import org.fxmisc.wellbehaved.event.EventPattern; 13 | import org.fxmisc.wellbehaved.event.InputMap; 14 | import org.fxmisc.wellbehaved.event.Nodes; 15 | import org.slf4j.LoggerFactory; 16 | 17 | import gr.sqlbrowserfx.LoggerConf; 18 | import gr.sqlbrowserfx.factories.DialogFactory; 19 | import gr.sqlbrowserfx.nodes.codeareas.FileCodeArea; 20 | import gr.sqlbrowserfx.utils.JavaFXUtils; 21 | import javafx.scene.control.ContextMenu; 22 | import javafx.scene.control.MenuItem; 23 | import javafx.scene.control.SeparatorMenuItem; 24 | import javafx.scene.input.KeyCode; 25 | import javafx.scene.input.KeyCombination; 26 | 27 | public class FileSqlCodeArea extends CSqlCodeArea implements FileCodeArea { 28 | 29 | private final File file; 30 | private String lastSavedContent; 31 | 32 | public FileSqlCodeArea(File file) { 33 | super(); 34 | this.file = file; 35 | try(var lines = Files.lines(Paths.get(file.getAbsolutePath()))) { 36 | lastSavedContent = StringUtils.join(lines.collect(Collectors.toList()), "\n"); 37 | } catch (IOException e) { 38 | LoggerFactory.getLogger(LoggerConf.LOGGER_NAME).error("Could not load file " + file.getName(), e); 39 | } 40 | this.replaceText(lastSavedContent); 41 | getUndoManager().forgetHistory(); 42 | } 43 | 44 | public boolean isTextDirty() { 45 | return !this.getText().equals(this.lastSavedContent); 46 | } 47 | 48 | public String getPath() { 49 | return file.getPath(); 50 | } 51 | 52 | public void saveFileAction() { 53 | try { 54 | Files.write(Paths.get(this.getPath()), this.getText().getBytes(), StandardOpenOption.TRUNCATE_EXISTING); 55 | this.lastSavedContent = this.getText(); 56 | getUndoManager().forgetHistory(); 57 | } catch (IOException e) { 58 | DialogFactory.createErrorDialog(e); 59 | } 60 | DialogFactory.createNotification("File saved", "File saved at " + new Date()); 61 | } 62 | 63 | @Override 64 | public ContextMenu createContextMenu() { 65 | var menu = super.createContextMenu(); 66 | var menuItemSave = new MenuItem("Save File", JavaFXUtils.createIcon("/icons/save.png")); 67 | menuItemSave.setOnAction(action -> this.saveFileAction()); 68 | 69 | menu.getItems().addAll(new SeparatorMenuItem(), menuItemSave); 70 | return menu; 71 | } 72 | 73 | @Override 74 | public void setInputMap() { 75 | super.setInputMap(); 76 | var save = InputMap.consume( 77 | EventPattern.keyPressed(KeyCode.S, KeyCombination.CONTROL_DOWN), 78 | action -> this.saveFileAction() 79 | ); 80 | Nodes.addInputMap(this, save); 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/main/java/gr/sqlbrowserfx/nodes/codeareas/sql/HistorySqlCodeArea.java: -------------------------------------------------------------------------------- 1 | package gr.sqlbrowserfx.nodes.codeareas.sql; 2 | 3 | import org.fxmisc.wellbehaved.event.EventPattern; 4 | import org.fxmisc.wellbehaved.event.InputMap; 5 | import org.fxmisc.wellbehaved.event.Nodes; 6 | 7 | import gr.sqlbrowserfx.nodes.SearchAndReplacePopOver; 8 | import gr.sqlbrowserfx.utils.JavaFXUtils; 9 | import javafx.scene.control.ContextMenu; 10 | import javafx.scene.control.MenuItem; 11 | import javafx.scene.input.KeyCode; 12 | import javafx.scene.input.KeyCombination; 13 | import javafx.scene.layout.HBox; 14 | 15 | public class HistorySqlCodeArea extends CSqlCodeArea { 16 | 17 | public HistorySqlCodeArea() { 18 | super(); 19 | searchAndReplacePopOver = new SearchAndReplacePopOver(this, false); 20 | this.setEditable(false); 21 | this.enableShowLineNumbers(true); 22 | this.setOnKeyTyped(keyEvent -> {}); 23 | } 24 | 25 | public HistorySqlCodeArea(String text) { 26 | this(); 27 | this.replaceText(text); 28 | } 29 | 30 | 31 | public HBox getSearchAndReplacePopOver() { 32 | return (HBox) this.searchAndReplacePopOver.getContentNode(); 33 | } 34 | 35 | @Override 36 | public void setInputMap() { 37 | var searchAndReplace = InputMap.consume( 38 | EventPattern.keyPressed(KeyCode.F, KeyCombination.CONTROL_DOWN), 39 | action -> this.showSearchAndReplacePopup() 40 | ); 41 | var goToLine = InputMap.consume( 42 | EventPattern.keyPressed(KeyCode.L, KeyCombination.CONTROL_DOWN), 43 | action -> this.showGoToLinePopOver() 44 | ); 45 | 46 | Nodes.addInputMap(this, searchAndReplace); 47 | Nodes.addInputMap(this, goToLine); 48 | } 49 | 50 | // FIXME: For some reason only if this method is overwritten shows the correct pop over 51 | @Override 52 | protected void showSearchAndReplacePopup() { 53 | if (!this.getSelectedText().isEmpty()) { 54 | searchAndReplacePopOver.getFindField().setText(this.getSelectedText()); 55 | searchAndReplacePopOver.getFindField().selectAll(); 56 | } 57 | var boundsInScene = this.localToScreen(this.getBoundsInLocal()); 58 | searchAndReplacePopOver.show(getParent(), boundsInScene.getMaxX() - searchAndReplacePopOver.getWidth(), 59 | boundsInScene.getMinY()); 60 | } 61 | 62 | @Override 63 | public ContextMenu createContextMenu() { 64 | var menu = new ContextMenu(); 65 | 66 | var menuItemCopy = new MenuItem("Copy", JavaFXUtils.createIcon("/icons/copy.png")); 67 | menuItemCopy.setOnAction(event -> this.copy()); 68 | 69 | var menuItemSearchAndReplace = new MenuItem("Search...", JavaFXUtils.createIcon("/icons/magnify.png")); 70 | menuItemSearchAndReplace.setOnAction(action -> this.showSearchAndReplacePopup()); 71 | 72 | var menuItemSave = new MenuItem("Save Query", JavaFXUtils.createIcon("/icons/save.png")); 73 | menuItemSave.setOnAction(action -> this.saveQueryAction()); 74 | 75 | menu.getItems().addAll(menuItemCopy, menuItemSearchAndReplace, menuItemSave); 76 | return menu; 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/main/java/gr/sqlbrowserfx/nodes/codeareas/sql/PHistorySqlCodeArea.java: -------------------------------------------------------------------------------- 1 | package gr.sqlbrowserfx.nodes.codeareas.sql; 2 | 3 | import gr.sqlbrowserfx.utils.JavaFXUtils; 4 | import javafx.scene.control.ContextMenu; 5 | import javafx.scene.control.MenuItem; 6 | 7 | public class PHistorySqlCodeArea extends HistorySqlCodeArea { 8 | 9 | @Override 10 | public void setInputMap() { 11 | // no map 12 | } 13 | 14 | @Override 15 | public ContextMenu createContextMenu() { 16 | var menu = new ContextMenu(); 17 | 18 | var menuItemCopy = new MenuItem("Copy", JavaFXUtils.createIcon("/icons/copy.png")); 19 | menuItemCopy.setOnAction(event -> this.copy()); 20 | 21 | var menuItemSave = new MenuItem("Save Query", JavaFXUtils.createIcon("/icons/save.png")); 22 | menuItemSave.setOnAction(action -> this.saveQueryAction()); 23 | 24 | menu.getItems().addAll(menuItemCopy, menuItemSave); 25 | return menu; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/gr/sqlbrowserfx/nodes/codeareas/sql/SimpleLineNumberFactory.java: -------------------------------------------------------------------------------- 1 | package gr.sqlbrowserfx.nodes.codeareas.sql; 2 | 3 | import java.util.function.IntFunction; 4 | 5 | import org.fxmisc.richtext.CodeArea; 6 | import org.reactfx.collection.LiveList; 7 | import org.reactfx.value.Val; 8 | 9 | import javafx.geometry.Insets; 10 | import javafx.geometry.Pos; 11 | import javafx.scene.Node; 12 | import javafx.scene.control.Label; 13 | 14 | public class SimpleLineNumberFactory implements IntFunction{ 15 | 16 | private final CodeArea codeArea; 17 | 18 | public SimpleLineNumberFactory(CodeArea codeArea) { 19 | this.codeArea = codeArea; 20 | } 21 | 22 | private String format(int x, int max) { 23 | int digits = (int) Math.floor(Math.log10(max)) + 1; 24 | IntFunction format = (dgts) -> "%1$" + dgts + "s"; 25 | return String.format(format.apply(digits), x); 26 | } 27 | 28 | @Override 29 | public Node apply(int idx) { 30 | Val nParagraphs = LiveList.sizeOf(codeArea.getParagraphs()); 31 | Val formatted = nParagraphs.map(n -> format(idx+1, n)); 32 | 33 | Label lineNo = new Label(); 34 | lineNo.setPadding(new Insets(0, 15, 0, 0)); 35 | lineNo.setAlignment(Pos.TOP_RIGHT); 36 | lineNo.getStyleClass().add("lineno"); 37 | 38 | // bind label's text to a Val that stops observing codeArea's paragraphs 39 | // when lineNo is removed from scene 40 | lineNo.textProperty().bind(formatted.conditionOnShowing(lineNo)); 41 | 42 | return lineNo; 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/gr/sqlbrowserfx/nodes/queriesmenu/QueryDTO.java: -------------------------------------------------------------------------------- 1 | package gr.sqlbrowserfx.nodes.queriesmenu; 2 | 3 | import gr.sqlbrowserfx.utils.mapper.Column; 4 | import gr.sqlbrowserfx.utils.mapper.DTO; 5 | 6 | @DTO 7 | public class QueryDTO { 8 | 9 | @Column("QUERY") 10 | private String sql; 11 | @Column("DESCRIPTION") 12 | private String description; 13 | @Column("CATEGORY") 14 | private String category; 15 | 16 | public String getSql() { 17 | return sql; 18 | } 19 | public void setSql(String sql) { 20 | this.sql = sql; 21 | } 22 | public String getDescription() { 23 | return description; 24 | } 25 | public void setDescription(String description) { 26 | this.description = description; 27 | } 28 | public String getCategory() { 29 | return category; 30 | } 31 | public void setCategory(String category) { 32 | this.category = category; 33 | } 34 | 35 | 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/gr/sqlbrowserfx/nodes/sqlpane/CustomPopOver.java: -------------------------------------------------------------------------------- 1 | package gr.sqlbrowserfx.nodes.sqlpane; 2 | 3 | import org.controlsfx.control.PopOver; 4 | 5 | import javafx.scene.Node; 6 | 7 | public class CustomPopOver extends PopOver{ 8 | 9 | public CustomPopOver() { 10 | this(null); 11 | } 12 | 13 | public CustomPopOver(Node node) { 14 | super(node); 15 | this.setDetachable(false); 16 | this.setArrowSize(0); 17 | this.setHideOnEscape(true); 18 | this.setAutoFix(true); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/gr/sqlbrowserfx/nodes/sqlpane/SimpleSqlPane.java: -------------------------------------------------------------------------------- 1 | package gr.sqlbrowserfx.nodes.sqlpane; 2 | 3 | import gr.sqlbrowserfx.conn.SqlConnector; 4 | import javafx.scene.layout.FlowPane; 5 | 6 | public class SimpleSqlPane extends SqlPane { 7 | 8 | public SimpleSqlPane(SqlConnector sqlConnector) { 9 | super(sqlConnector); 10 | this.fullModeCheckBox.setSelected(true); 11 | } 12 | 13 | @Override 14 | public FlowPane createToolbar() { 15 | FlowPane toolbar = super.createToolbar(); 16 | toolbar.getChildren().removeAll(sqlConsoleButton, columnsSettingsButton); 17 | return toolbar; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/gr/sqlbrowserfx/nodes/sqlpane/SqlTableTab.java: -------------------------------------------------------------------------------- 1 | package gr.sqlbrowserfx.nodes.sqlpane; 2 | 3 | import gr.sqlbrowserfx.nodes.tableviews.SqlTableView; 4 | import gr.sqlbrowserfx.utils.JavaFXUtils; 5 | import javafx.beans.property.StringProperty; 6 | import javafx.scene.Node; 7 | import javafx.scene.control.Label; 8 | import javafx.scene.control.ProgressIndicator; 9 | import javafx.scene.control.Tab; 10 | import javafx.scene.control.TabPane; 11 | import javafx.scene.layout.StackPane; 12 | 13 | public class SqlTableTab extends Tab { 14 | 15 | private SqlTableView sqlTableView; 16 | private TabPane recordsTabPane; 17 | private Label label; 18 | // TODO store columns box 19 | 20 | public SqlTableTab() { 21 | super(); 22 | } 23 | 24 | public SqlTableTab(String text, final SqlTableView sqlTableView) { 25 | super(text, sqlTableView); 26 | this.sqlTableView = sqlTableView; 27 | 28 | Node graphic = JavaFXUtils.createIcon("/icons/table-e.png"); 29 | label = new Label(text, graphic); 30 | label.textProperty().bind(this.getSqlTableView().titleProperty()); 31 | this.setText(null); 32 | this.setGraphic(label); 33 | this.setOnClosed(event -> { 34 | this.sqlTableView = null; 35 | System.gc(); 36 | }); 37 | } 38 | 39 | public SqlTableView getSqlTableView() { 40 | return sqlTableView; 41 | } 42 | 43 | public TabPane getRecordsTabPane() { 44 | return recordsTabPane; 45 | } 46 | 47 | public void setRecordsTabPane(final TabPane tabPane) { 48 | this.recordsTabPane = tabPane; 49 | } 50 | 51 | public StringProperty customTextProperty() { 52 | return label.textProperty(); 53 | } 54 | 55 | public String getCustomText() { 56 | return label.getText(); 57 | } 58 | 59 | public void setCustomGraphic(Node graphic) { 60 | label.setGraphic(graphic); 61 | } 62 | 63 | public void startLoading() { 64 | ProgressIndicator progressIndicator = new ProgressIndicator(); 65 | progressIndicator.setMaxHeight(40); 66 | progressIndicator.setMaxWidth(40); 67 | this.setContent(new StackPane(progressIndicator)); 68 | } 69 | 70 | public void load() { 71 | this.setContent(sqlTableView); 72 | } 73 | 74 | } 75 | -------------------------------------------------------------------------------- /src/main/java/gr/sqlbrowserfx/nodes/tableviews/EditableCell.java: -------------------------------------------------------------------------------- 1 | package gr.sqlbrowserfx.nodes.tableviews; 2 | 3 | import gr.sqlbrowserfx.conn.SqlConnector; 4 | import javafx.application.Platform; 5 | import javafx.geometry.Pos; 6 | import javafx.scene.control.ContentDisplay; 7 | import javafx.scene.control.TableCell; 8 | import javafx.scene.control.TableView; 9 | import javafx.scene.control.TextField; 10 | 11 | public class EditableCell extends TableCell { 12 | 13 | TableView parentTableView; 14 | 15 | public EditableCell() { 16 | super(); 17 | this.setAlignment(Pos.CENTER); 18 | } 19 | 20 | public EditableCell(JSONTableView parentTableView) { 21 | this(); 22 | this.parentTableView = parentTableView; 23 | this.setOnMouseClicked(mouseEvent -> { 24 | // parentTableView.setSelectedCell(this); 25 | if (parentTableView.areCellsEditableByClick() && mouseEvent.getClickCount() == 2) { 26 | this.startEdit(); 27 | } 28 | }); 29 | } 30 | 31 | public EditableCell(JSONTableView parentTable, SqlConnector sqlConnector) { 32 | this(parentTable); 33 | } 34 | 35 | @Override 36 | protected void updateItem(Object item, boolean empty) { 37 | super.updateItem(item, empty); 38 | 39 | if (item == null || empty) { 40 | setText(null); 41 | } else { 42 | setText(item.toString()); 43 | } 44 | } 45 | 46 | @Override 47 | public void startEdit() { 48 | // TablePosition pos = parentTableView.getSelectionModel().getSelectedCells().get(0); 49 | // 50 | // if (pos.getTableColumn().getText().equals(parentTableView.getPrimaryKey())) { 51 | // System.out.println(pos.getTableColumn().getText()); 52 | // return; 53 | // } 54 | 55 | TextField textField = createTextField(); 56 | setGraphic(textField); 57 | setContentDisplay(ContentDisplay.GRAPHIC_ONLY); 58 | Platform.runLater(() -> { 59 | textField.requestFocus(); 60 | textField.selectAll(); 61 | textField.focusedProperty().addListener((observable, oldValue, newValue) -> cancelEdit()); 62 | }); 63 | 64 | } 65 | 66 | @Override 67 | public void commitEdit(Object newValue) { 68 | // Object oldValue = getText(); 69 | // if (newValue != null && !newValue.equals(getText())) { 70 | // String column = this.getTableColumn().getText(); 71 | // parentTableView.getSelectionModel().getSelectedItem().set(column, newValue); 72 | // if (parentTableView.updateSelectedRow() == 0) { 73 | // parentTableView.getSelectionModel().getSelectedItem().set(column, oldValue); 74 | // } 75 | // } 76 | } 77 | 78 | @Override 79 | public void cancelEdit() { 80 | setText(getText()); 81 | setContentDisplay(ContentDisplay.TEXT_ONLY); 82 | } 83 | 84 | protected TextField createTextField() { 85 | TableViewCellEditField textField = new TableViewCellEditField(getText(), this); 86 | 87 | textField.setEditable(true); 88 | 89 | textField.setAlignment(Pos.CENTER); 90 | return textField; 91 | } 92 | 93 | public TableView getParentTable() { 94 | return parentTableView; 95 | } 96 | 97 | 98 | } -------------------------------------------------------------------------------- /src/main/java/gr/sqlbrowserfx/nodes/tableviews/HistorySqlTableView.java: -------------------------------------------------------------------------------- 1 | package gr.sqlbrowserfx.nodes.tableviews; 2 | 3 | import java.awt.Toolkit; 4 | import java.awt.datatransfer.Clipboard; 5 | import java.awt.datatransfer.StringSelection; 6 | 7 | import gr.sqlbrowserfx.conn.SqlConnector; 8 | import gr.sqlbrowserfx.nodes.ContextMenuOwner; 9 | import gr.sqlbrowserfx.utils.JavaFXUtils; 10 | import javafx.application.Platform; 11 | import javafx.scene.control.ContextMenu; 12 | import javafx.scene.control.MenuItem; 13 | 14 | public class HistorySqlTableView extends SqlTableView implements ContextMenuOwner { 15 | 16 | public HistorySqlTableView(SqlConnector sqlConnector) { 17 | super(sqlConnector); 18 | this.setContextMenu(createContextMenu()); 19 | this.enableColumnFiltering(true); 20 | } 21 | 22 | @Override 23 | public ContextMenu createContextMenu() { 24 | MenuItem menuItemDelete = new MenuItem("Delete", JavaFXUtils.createIcon("/icons/minus.png")); 25 | menuItemDelete.setOnAction(event -> { 26 | sqlConnector.executeAsync(() -> { 27 | var selectedRows = this.getSelectionModel().getSelectedItems(); 28 | selectedRows.forEach(this::deleteRecord); 29 | Platform.runLater(() -> this.getSqlTableRows().removeAll(selectedRows)); 30 | }); 31 | }); 32 | 33 | MenuItem menuItemCopy = new MenuItem("Copy row", JavaFXUtils.createIcon("/icons/copy.png")); 34 | menuItemCopy.setOnAction(actionEvent -> { 35 | StringBuilder content = new StringBuilder(); 36 | 37 | this.getSelectionModel().getSelectedItems().forEach(row -> content.append(row.toString()).append("\n")); 38 | 39 | StringSelection stringSelection = new StringSelection(content.toString()); 40 | Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); 41 | clipboard.setContents(stringSelection, null); 42 | }); 43 | return new ContextMenu(menuItemDelete, menuItemCopy); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/gr/sqlbrowserfx/nodes/tableviews/JSONTableView.java: -------------------------------------------------------------------------------- 1 | package gr.sqlbrowserfx.nodes.tableviews; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import org.fxmisc.wellbehaved.event.EventPattern; 7 | import org.fxmisc.wellbehaved.event.InputMap; 8 | import org.fxmisc.wellbehaved.event.Nodes; 9 | import org.json.JSONArray; 10 | 11 | import gr.sqlbrowserfx.nodes.InputMapOwner; 12 | import javafx.application.Platform; 13 | import javafx.collections.FXCollections; 14 | import javafx.collections.ObservableList; 15 | import javafx.scene.control.SelectionMode; 16 | import javafx.scene.control.TableColumn; 17 | import javafx.scene.control.TableView; 18 | import javafx.scene.input.KeyCode; 19 | import javafx.scene.input.KeyCombination; 20 | 21 | public class JSONTableView extends TableView implements InputMapOwner { 22 | 23 | protected List columns; 24 | protected ObservableList rows; 25 | double minWidth, prefWidth, maxWidth; 26 | protected boolean autoResize; 27 | protected final static int NOT_SET = 0; 28 | int currentColumnPos = 0; 29 | 30 | 31 | public JSONTableView() { 32 | 33 | rows = FXCollections.observableArrayList(); 34 | autoResize = false; 35 | minWidth = 0; 36 | prefWidth = 0; 37 | maxWidth = 0; 38 | 39 | this.setInputMap(); 40 | 41 | } 42 | 43 | @SuppressWarnings("unused") 44 | @Deprecated 45 | private void setKeys() { 46 | this.setOnKeyPressed(keyEvent -> { 47 | if (keyEvent.isControlDown()) { 48 | if (keyEvent.getCode() == KeyCode.LEFT) { 49 | if (currentColumnPos < getColumns().size() - 1) 50 | this.scrollToColumn(getColumns().get(currentColumnPos++)); 51 | } 52 | if (keyEvent.getCode() == KeyCode.RIGHT) { 53 | if (currentColumnPos > 0) 54 | this.scrollToColumn(getColumns().get(currentColumnPos--)); 55 | } 56 | } 57 | }); 58 | } 59 | 60 | @Override 61 | public void setInputMap() { 62 | Nodes.addInputMap(this, 63 | InputMap.consume( 64 | EventPattern.keyPressed(KeyCode.LEFT, KeyCombination.CONTROL_DOWN), 65 | action -> { 66 | if (currentColumnPos < getColumns().size() - 1) 67 | this.scrollToColumn(getColumns().get(currentColumnPos++)); 68 | } 69 | )); 70 | Nodes.addInputMap(this, 71 | InputMap.consume( 72 | EventPattern.keyPressed(KeyCode.LEFT, KeyCombination.CONTROL_DOWN), 73 | action -> { 74 | if (currentColumnPos > 0) 75 | this.scrollToColumn(getColumns().get(currentColumnPos--)); 76 | } 77 | )); 78 | } 79 | 80 | public synchronized void setItemsLater(JSONArray jsonArray) { 81 | 82 | rows.clear(); 83 | columns = new ArrayList<>(); 84 | jsonArray.getJSONObject(0).keys().forEachRemaining(columns::add); 85 | 86 | for (int i = 0; i < jsonArray.length(); i++) { 87 | rows.add(new MapTableViewRow(jsonArray.getJSONObject(i).toMap())); 88 | } 89 | 90 | Platform.runLater(() -> { 91 | super.setItems(FXCollections.emptyObservableList()); 92 | this.getColumns().clear(); 93 | 94 | for (String column : columns) { 95 | TableColumn col = new TableColumn<>(column); 96 | col.setCellValueFactory(param -> param.getValue().getObjectProperty(column)); 97 | col.setCellFactory(callback -> new EditableCell(this)); 98 | this.getColumns().add(col); 99 | } 100 | 101 | this.autoResizedColumns(autoResize); 102 | this.setColumnWidth(10, NOT_SET, 300); 103 | this.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE); 104 | super.setItems(rows); 105 | }); 106 | } 107 | 108 | public boolean areCellsEditableByClick() { 109 | return true; 110 | } 111 | 112 | // 0 for no set 113 | public void setColumnWidth(double min, double pref, double max) { 114 | this.minWidth = min; 115 | this.prefWidth = pref; 116 | this.maxWidth = max; 117 | 118 | for (TableColumn column : this.getColumns()) { 119 | if (min > NOT_SET) 120 | column.setMinWidth(minWidth); 121 | if (pref > NOT_SET) 122 | column.setPrefWidth(prefWidth); 123 | if (max > NOT_SET) 124 | column.setMaxWidth(maxWidth); 125 | } 126 | } 127 | 128 | public void autoResizedColumns(boolean autoResize) { 129 | this.autoResize = autoResize; 130 | if (autoResize) { 131 | this.setColumnWidth(NOT_SET, NOT_SET, NOT_SET); 132 | for (TableColumn column : this.getVisibleLeafColumns()) { 133 | column.prefWidthProperty().bind(this.widthProperty().divide(this.getVisibleLeafColumns().size())); 134 | } 135 | } else { 136 | for (TableColumn column : this.getVisibleLeafColumns()) { 137 | column.prefWidthProperty().unbind(); 138 | } 139 | this.setColumnWidth(minWidth, prefWidth, maxWidth); 140 | } 141 | } 142 | 143 | } 144 | -------------------------------------------------------------------------------- /src/main/java/gr/sqlbrowserfx/nodes/tableviews/MapTableViewRow.java: -------------------------------------------------------------------------------- 1 | package gr.sqlbrowserfx.nodes.tableviews; 2 | 3 | import java.util.ArrayList; 4 | import java.util.LinkedHashMap; 5 | import java.util.List; 6 | import java.util.Map; 7 | 8 | import gr.sqlbrowserfx.listeners.SimpleObservable; 9 | import gr.sqlbrowserfx.listeners.SimpleObserver; 10 | import gr.sqlbrowserfx.nodes.sqlpane.SqlTableRowEditBox; 11 | import javafx.beans.property.BooleanProperty; 12 | import javafx.beans.property.SimpleBooleanProperty; 13 | import javafx.beans.property.SimpleObjectProperty; 14 | 15 | 16 | public class MapTableViewRow implements SimpleObservable { 17 | 18 | protected LinkedHashMap> propertiesMap = new LinkedHashMap<>(); 19 | protected List columns; 20 | private List> listeners; 21 | private SimpleBooleanProperty isUpdateByGuiProperty = new SimpleBooleanProperty(true); 22 | 23 | public MapTableViewRow() { 24 | columns = new ArrayList<>(); 25 | listeners = new ArrayList<>(); 26 | } 27 | 28 | public MapTableViewRow(Map entry) { 29 | this(); 30 | this.setMap(entry); 31 | } 32 | 33 | public void refreshMap(Map entry) { 34 | for (String key : entry.keySet()) { 35 | propertiesMap.get(key).set(entry.get(key)); 36 | } 37 | } 38 | 39 | public void refreshMapFromEditBox(SqlTableRowEditBox entry) { 40 | for (String key : entry.getMap().keySet()) { 41 | propertiesMap.get(key).set(entry.getMap().get(key).getText()); 42 | } 43 | } 44 | 45 | public void setMap(Map entry) { 46 | this.columns.addAll(entry.keySet()); 47 | // Collections.reverse(this.columns); 48 | 49 | for (String columnLabel : this.columns) { 50 | propertiesMap.put(columnLabel, 51 | new SimpleObjectProperty(entry.get(columnLabel))); 52 | } 53 | } 54 | 55 | public MapTableViewRow(MapTableViewRow sqlTableRow) { 56 | this(); 57 | this.propertiesMap = sqlTableRow.getStringPropertiesMap(); 58 | this.columns = sqlTableRow.getColumns(); 59 | } 60 | 61 | 62 | public SimpleObjectProperty getObjectProperty(String key) { 63 | return propertiesMap.get(key); 64 | } 65 | 66 | public Object get(String key) { 67 | return propertiesMap.get(key) != null?propertiesMap.get(key).getValue():null; 68 | } 69 | 70 | public void set(String key, Object value) { 71 | propertiesMap.get(key).setValue(value); 72 | } 73 | 74 | public BooleanProperty isUpdatedByGui() { 75 | return isUpdateByGuiProperty; 76 | } 77 | public List getColumns() { 78 | return columns; 79 | } 80 | 81 | public LinkedHashMap> getStringPropertiesMap() { 82 | return propertiesMap; 83 | } 84 | 85 | @Override 86 | public String toString() { 87 | String result = new String(); 88 | for (SimpleObjectProperty property: propertiesMap.values()) { 89 | Object value = property.get(); 90 | if (value instanceof String) 91 | value = value.toString().replaceAll("\n", " ");//.replace(",", " "); 92 | if (value == null) 93 | value = ""; 94 | result += "\"" + value + "\","; 95 | } 96 | return result.substring(0,result.length()-1); 97 | } 98 | 99 | @Override 100 | public void changed() { 101 | listeners.forEach(listener -> listener.onObservableChange(this)); 102 | } 103 | 104 | @Override 105 | public void changed(MapTableViewRow data) { 106 | 107 | } 108 | 109 | @Override 110 | public synchronized void addObserver(SimpleObserver listener) { 111 | listeners.add(listener); 112 | } 113 | 114 | @Override 115 | public synchronized void removeObserver(SimpleObserver listener) { 116 | listeners.remove(listener); 117 | } 118 | 119 | 120 | } 121 | -------------------------------------------------------------------------------- /src/main/java/gr/sqlbrowserfx/nodes/tableviews/SqlTableViewCell.java: -------------------------------------------------------------------------------- 1 | package gr.sqlbrowserfx.nodes.tableviews; 2 | 3 | import javafx.geometry.Pos; 4 | import javafx.scene.control.TableCell; 5 | 6 | public class SqlTableViewCell extends TableCell { 7 | 8 | public SqlTableViewCell() { 9 | super(); 10 | this.setAlignment(Pos.CENTER_LEFT); 11 | } 12 | 13 | @Override 14 | protected void updateItem(Object item, boolean empty) { 15 | if (item == null || empty) { 16 | setText(null); 17 | } else { 18 | setText(item.toString()); 19 | } 20 | } 21 | } -------------------------------------------------------------------------------- /src/main/java/gr/sqlbrowserfx/nodes/tableviews/SqlTableViewEditableCell.java: -------------------------------------------------------------------------------- 1 | package gr.sqlbrowserfx.nodes.tableviews; 2 | 3 | import gr.sqlbrowserfx.conn.SqlConnector; 4 | import gr.sqlbrowserfx.factories.DialogFactory; 5 | import gr.sqlbrowserfx.utils.PropertiesLoader; 6 | import javafx.application.Platform; 7 | import javafx.geometry.Pos; 8 | import javafx.scene.control.ContentDisplay; 9 | import javafx.scene.control.TableCell; 10 | import javafx.scene.control.TablePosition; 11 | import javafx.scene.control.TextField; 12 | 13 | public class SqlTableViewEditableCell extends TableCell { 14 | 15 | SqlTableView parentTableView; 16 | SqlConnector sqlConnector; 17 | 18 | public SqlTableViewEditableCell() { 19 | super(); 20 | this.setAlignment(Pos.CENTER_LEFT); 21 | } 22 | 23 | public SqlTableViewEditableCell(SqlTableView parentTableView) { 24 | this(); 25 | this.parentTableView = parentTableView; 26 | this.setOnMouseClicked(mouseEvent -> { 27 | parentTableView.setSelectedCell(this); 28 | if (((Boolean) PropertiesLoader.getProperty("sqlbrowserfx.default.editmode.cell", Boolean.class, false)) 29 | && parentTableView.areCellsEditableByClick() && mouseEvent.getClickCount() == 2) { 30 | this.startEdit(); 31 | } 32 | }); 33 | this.setContentDisplay(ContentDisplay.TEXT_ONLY); 34 | } 35 | 36 | public SqlTableViewEditableCell(SqlTableView parentTable, SqlConnector sqlConnector) { 37 | this(parentTable); 38 | this.sqlConnector = sqlConnector; 39 | } 40 | 41 | @Override 42 | protected void updateItem(Object item, boolean empty) { 43 | if (item == null || empty) { 44 | setText(null); 45 | } else if (!item.equals(getText())) { 46 | setText(item.toString()); 47 | } 48 | 49 | } 50 | 51 | @Override 52 | public void startEdit() { 53 | TablePosition pos = parentTableView.getSelectionModel().getSelectedCells().get(0); 54 | 55 | if (pos != null && pos.getTableColumn() != null && pos.getTableColumn().getText() != null 56 | && pos.getTableColumn().getText().equals(parentTableView.getPrimaryKey())) { 57 | return; 58 | } 59 | 60 | TextField textField = createTextField(); 61 | setGraphic(textField); 62 | setContentDisplay(ContentDisplay.GRAPHIC_ONLY); 63 | Platform.runLater(() -> { 64 | textField.requestFocus(); 65 | textField.selectAll(); 66 | textField.focusedProperty().addListener((observable, oldValue, newValue) -> cancelEdit()); 67 | }); 68 | 69 | } 70 | 71 | @Override 72 | public void commitEdit(Object newValue) { 73 | Object oldValue = getText(); 74 | if (newValue != null && !newValue.equals(getText())) { 75 | String column = this.getTableColumn().getText(); 76 | parentTableView.getSelectionModel().getSelectedItem().set(column, newValue); 77 | try { 78 | parentTableView.updateSelectedRow(); 79 | DialogFactory.createNotification("Record update", "Successfully updated!"); 80 | } catch (Exception e) { 81 | parentTableView.getSelectionModel().getSelectedItem().set(column, oldValue); 82 | DialogFactory.createErrorNotification(e.getClass().getSimpleName(), "Could not update cell!\n" + e.getMessage(), e); 83 | } 84 | } 85 | setContentDisplay(ContentDisplay.TEXT_ONLY); 86 | parentTableView.requestFocus(); 87 | 88 | } 89 | 90 | @Override 91 | public void cancelEdit() { 92 | setText(getText()); 93 | setContentDisplay(ContentDisplay.TEXT_ONLY); 94 | } 95 | 96 | protected TextField createTextField() { 97 | TableViewCellEditField textField = new TableViewCellEditField(getText(), this); 98 | textField.setEditable(sqlConnector != null); 99 | textField.setStyle("-fx-border-width: 0.0 0.0 0.0 0.0; -fx-padding: 0;"); 100 | return textField; 101 | } 102 | 103 | public SqlTableView getParentTable() { 104 | return parentTableView; 105 | } 106 | 107 | } -------------------------------------------------------------------------------- /src/main/java/gr/sqlbrowserfx/nodes/tableviews/TableViewCellEditArea.java: -------------------------------------------------------------------------------- 1 | package gr.sqlbrowserfx.nodes.tableviews; 2 | 3 | import javafx.scene.control.TableCell; 4 | import javafx.scene.control.TextArea; 5 | import javafx.scene.input.KeyCode; 6 | 7 | public class TableViewCellEditArea extends TextArea { 8 | 9 | public TableViewCellEditArea(String text, TableCell cell) { 10 | super(text); 11 | this.setOnKeyPressed(keyEvent -> { 12 | if (keyEvent.getCode() == KeyCode.ENTER) { 13 | cell.commitEdit(this.getText()); 14 | } else if (keyEvent.getCode() == KeyCode.ESCAPE) { 15 | cell.cancelEdit(); 16 | } else if (keyEvent.isShiftDown() || keyEvent.isControlDown()) { 17 | if (keyEvent.getCode() == KeyCode.A) { 18 | this.selectAll(); 19 | } 20 | else if (keyEvent.getCode() == KeyCode.C && keyEvent.isControlDown()) { 21 | this.copy(); 22 | } 23 | else if (keyEvent.getCode() == KeyCode.V && keyEvent.isControlDown()) { 24 | this.paste(); 25 | } 26 | else if (keyEvent.getCode() == KeyCode.X && keyEvent.isControlDown()) { 27 | this.cut(); 28 | } 29 | else if (keyEvent.getCode() == KeyCode.Z && keyEvent.isShiftDown() && keyEvent.isControlDown()) { 30 | this.redo(); 31 | } 32 | else if (keyEvent.getCode() == KeyCode.Z && keyEvent.isControlDown()) { 33 | this.undo(); 34 | } 35 | else if (keyEvent.getCode() == KeyCode.LEFT && keyEvent.isShiftDown() && keyEvent.isControlDown()) { 36 | this.selectPreviousWord(); 37 | } 38 | else if(keyEvent.getCode() == KeyCode.RIGHT && keyEvent.isShiftDown() && keyEvent.isControlDown()) { 39 | this.selectNextWord(); 40 | } 41 | else if (keyEvent.getCode() == KeyCode.LEFT && keyEvent.isControlDown()) { 42 | this.previousWord(); 43 | } 44 | else if(keyEvent.getCode() == KeyCode.RIGHT && keyEvent.isControlDown()) { 45 | this.nextWord(); 46 | } 47 | else if (keyEvent.getCode() == KeyCode.LEFT && keyEvent.isShiftDown()) { 48 | this.selectBackward(); 49 | } 50 | else if(keyEvent.getCode() == KeyCode.RIGHT && keyEvent.isShiftDown()) { 51 | this.selectForward(); 52 | } 53 | 54 | keyEvent.consume(); 55 | } 56 | }); 57 | // this.focusedProperty().addListener((ChangeListener) (observable, oldValue, newValue) -> { 58 | // if (!newValue) { 59 | // cell.commitEdit(this.getText()); 60 | // } 61 | // }); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/main/java/gr/sqlbrowserfx/nodes/tableviews/TableViewCellEditField.java: -------------------------------------------------------------------------------- 1 | package gr.sqlbrowserfx.nodes.tableviews; 2 | 3 | import javafx.scene.control.TableCell; 4 | import javafx.scene.control.TextField; 5 | import javafx.scene.input.KeyCode; 6 | 7 | public class TableViewCellEditField extends TextField{ 8 | 9 | public TableViewCellEditField(String text, TableCell cell) { 10 | super(text); 11 | this.setOnKeyPressed(keyEvent -> { 12 | if (keyEvent.getCode() == KeyCode.ENTER) { 13 | cell.commitEdit(this.getText()); 14 | } else if (keyEvent.getCode() == KeyCode.ESCAPE) { 15 | cell.cancelEdit(); 16 | } else if (keyEvent.isShiftDown() || keyEvent.isControlDown()) { 17 | keyEvent.consume(); 18 | } 19 | }); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/gr/sqlbrowserfx/nodes/tableviews/filter/DupeCounter.java: -------------------------------------------------------------------------------- 1 | package gr.sqlbrowserfx.nodes.tableviews.filter; 2 | 3 | import java.util.HashMap; 4 | import java.util.Optional; 5 | 6 | 7 | final class DupeCounter { 8 | 9 | private final HashMap counts = new HashMap<>(); 10 | private final boolean enforceFloor; 11 | 12 | public DupeCounter(boolean enforceFloor) { 13 | this.enforceFloor = enforceFloor; 14 | } 15 | public int add(T value) { 16 | Integer prev = counts.get(value); 17 | int newVal; 18 | if (prev == null) { 19 | newVal = 1; 20 | counts.put(value, newVal); 21 | } else { 22 | newVal = prev + 1; 23 | counts.put(value, newVal); 24 | } 25 | return newVal; 26 | } 27 | public int get(T value) { 28 | return Optional.ofNullable(counts.get(value)).orElse(0); 29 | } 30 | public int remove(T value) { 31 | Integer prev = counts.get(value); 32 | if (prev != null && prev > 0) { 33 | int newVal = prev - 1; 34 | if (newVal == 0) { 35 | counts.remove(value); 36 | } else { 37 | counts.put(value, newVal); 38 | } 39 | return newVal; 40 | } 41 | else if (enforceFloor) { 42 | throw new IllegalStateException(); 43 | } 44 | else { 45 | return 0; 46 | } 47 | } 48 | 49 | @Override 50 | public String toString() { 51 | return counts.toString(); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/gr/sqlbrowserfx/nodes/tableviews/filter/FilterValue.java: -------------------------------------------------------------------------------- 1 | package gr.sqlbrowserfx.nodes.tableviews.filter; 2 | 3 | import javafx.beans.InvalidationListener; 4 | import javafx.beans.Observable; 5 | import javafx.beans.WeakInvalidationListener; 6 | import javafx.beans.property.BooleanProperty; 7 | import javafx.beans.property.SimpleBooleanProperty; 8 | import javafx.scene.control.CheckBox; 9 | import javafx.scene.control.Label; 10 | import javafx.scene.layout.HBox; 11 | import javafx.scene.paint.Color; 12 | 13 | import java.util.Optional; 14 | 15 | public final class FilterValue extends HBox implements Comparable> { 16 | 17 | private final R value; 18 | private final BooleanProperty isSelected = new SimpleBooleanProperty(true); 19 | private final BooleanProperty inScope = new SimpleBooleanProperty(true); 20 | private final ColumnFilter columnFilter; 21 | private final InvalidationListener scopeListener; 22 | 23 | 24 | FilterValue(R value, ColumnFilter columnFilter) { 25 | this.value = value; 26 | this.columnFilter = columnFilter; 27 | 28 | final CheckBox checkBox = new CheckBox(); 29 | final Label label = new Label(); 30 | label.setText(Optional.ofNullable(value).map(Object::toString).orElse(null)); 31 | scopeListener = (Observable v) -> label.textFillProperty().set(getInScopeProperty().get() ? Color.BLACK : Color.LIGHTGRAY); 32 | inScope.addListener(new WeakInvalidationListener(scopeListener)); 33 | checkBox.selectedProperty().bindBidirectional(selectedProperty()); 34 | getChildren().addAll(checkBox,label); 35 | } 36 | 37 | /** 38 | * Returns the R value for this given FilterValue 39 | */ 40 | public R getValue() { 41 | return value; 42 | } 43 | 44 | /** 45 | * Property indicating whether this value is selected or not. 46 | */ 47 | public BooleanProperty selectedProperty() { 48 | return isSelected; 49 | } 50 | 51 | /** 52 | * Property indicating whether this value is in scope. 53 | */ 54 | public BooleanProperty getInScopeProperty() { 55 | return inScope; 56 | } 57 | 58 | void refreshScope() { 59 | inScope.setValue(columnFilter.wasLastFiltered() || columnFilter.valueIsVisible(value)); 60 | } 61 | 62 | @Override 63 | public String toString() { 64 | return Optional.ofNullable(value).map(Object::toString).orElse(""); 65 | } 66 | 67 | 68 | @Override 69 | public int compareTo(FilterValue other) { 70 | if (value != null && other.value != null) { 71 | if (value instanceof Comparable && other.value instanceof Comparable) { 72 | try { 73 | return ((Comparable) value).compareTo(((Comparable) other.value)); 74 | } catch (Exception e) { 75 | // ignore 76 | } 77 | } 78 | } 79 | return Optional.ofNullable(value).map(Object::toString).orElse("") 80 | .compareTo(Optional.ofNullable(other).map(Object::toString).orElse("")); 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/main/java/gr/sqlbrowserfx/nodes/tableviews/filter/SqlTableFilter.java: -------------------------------------------------------------------------------- 1 | package gr.sqlbrowserfx.nodes.tableviews.filter; 2 | 3 | import gr.sqlbrowserfx.nodes.tableviews.MapTableViewRow; 4 | import gr.sqlbrowserfx.nodes.tableviews.SqlTableView; 5 | import gr.sqlbrowserfx.utils.JavaFXUtils; 6 | import javafx.scene.Node; 7 | import javafx.scene.control.TableColumn; 8 | import javafx.scene.control.TableView; 9 | import javafx.scene.layout.HBox; 10 | 11 | public class SqlTableFilter extends TableFilter{ 12 | 13 | private static final int MAX_FILTERABLE_VALUES = 50; 14 | 15 | 16 | protected SqlTableFilter(TableView tableView) { 17 | this(tableView, false); 18 | } 19 | 20 | protected SqlTableFilter(TableView tableView, boolean isLazy) { 21 | super(tableView, isLazy); 22 | } 23 | 24 | @Override 25 | protected boolean isColumnFilterable(TableColumn tableColumn) { 26 | ((SqlTableView) tableColumn.getTableView()).resetColumnGraphic(tableColumn); 27 | boolean isFilterable = ((SqlTableView)tableColumn.getTableView()).getUniqueEntriesForColumn(tableColumn.getText()) < MAX_FILTERABLE_VALUES; 28 | if (isFilterable) { 29 | Node graphic = tableColumn.getGraphic() != null ? new HBox(tableColumn.getGraphic(),JavaFXUtils.createIcon("/icons/filter.png")) : JavaFXUtils.createIcon("/icons/filter.png"); 30 | tableColumn.setGraphic(graphic); 31 | } 32 | return isFilterable; 33 | } 34 | 35 | public static void apply(SqlTableView sqlTableView) { 36 | new SqlTableFilter(sqlTableView); 37 | // in order to use controlsfx 11 implementation use line bellow 38 | // org.controlsfx.control.table.TableFilter.forTableView(sqlTableView).apply(); 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/gr/sqlbrowserfx/rest/RESTfulService.java: -------------------------------------------------------------------------------- 1 | package gr.sqlbrowserfx.rest; 2 | 3 | import java.util.ArrayList; 4 | import java.util.HashMap; 5 | import java.util.List; 6 | 7 | import io.javalin.plugin.bundled.CorsPluginConfig; 8 | import org.json.JSONArray; 9 | import org.json.JSONObject; 10 | import org.slf4j.Logger; 11 | import org.slf4j.LoggerFactory; 12 | 13 | import gr.sqlbrowserfx.LoggerConf; 14 | import gr.sqlbrowserfx.conn.SqlConnector; 15 | import gr.sqlbrowserfx.utils.mapper.DTOMapper; 16 | import io.javalin.Javalin; 17 | 18 | public class RESTfulService { 19 | 20 | private static Javalin APP; 21 | private static int PORT; 22 | private static String IP; 23 | static Logger logger = LoggerFactory.getLogger(LoggerConf.LOGGER_NAME); 24 | 25 | 26 | public static void init(SqlConnector sqlConnector) { 27 | APP = Javalin.create(config -> { 28 | config.plugins.enableCors(cors -> cors.add(CorsPluginConfig::anyHost)); 29 | config.plugins.enableDevLogging(); 30 | }); 31 | APP.exception(Exception.class, (e, ctx) -> { 32 | logger.error(e.getMessage()); 33 | ctx.status(500).result("{ \"message\":\"Oops something went wrong!\" }"); 34 | }); 35 | 36 | APP.before(ctx -> { 37 | ctx.res().addHeader("Access-Control-Allow-Methods", "GET,PUT,POST,DELETE,OPTIONS"); 38 | ctx.res().addHeader("Access-Control-Allow-Origin", "*"); 39 | ctx.res().addHeader("Access-Control-Allow-Headers", "*"); 40 | ctx.res().addHeader("Access-Control-Allow-Credentials", "true"); 41 | ctx.res().addHeader("Content-Type", "application/json"); 42 | }); 43 | 44 | 45 | APP.get("/api/tables", ctx-> { 46 | List data = new ArrayList<>(sqlConnector.getTables()); 47 | data.addAll(sqlConnector.getViews()); 48 | ctx.result(new JSONArray(data).toString()); 49 | }); 50 | 51 | 52 | APP.post("/api/save/{table}", (ctx) -> { 53 | JSONObject jsonObject = new JSONObject(ctx.body()); 54 | 55 | String table = ctx.pathParam("table"); 56 | StringBuilder columns = new StringBuilder(); 57 | StringBuilder values = new StringBuilder(); 58 | List params = new ArrayList<>(); 59 | 60 | for (String key : jsonObject.keySet()) { 61 | columns.append(key).append(", "); 62 | values.append("?, "); 63 | params.add(jsonObject.get(key)); 64 | } 65 | 66 | columns = new StringBuilder(columns.substring(0, columns.length() - ", ".length())); 67 | values = new StringBuilder(values.substring(0, values.length() - ", ".length())); 68 | 69 | String query = "insert into " + table + " (" + columns 70 | + ") values (" + values + ")"; 71 | sqlConnector.executeUpdate(query, params); 72 | 73 | ctx.result("{ \"message\": \"Data has been saved\"}"); 74 | }); 75 | 76 | APP.post("/api/delete/{table}", (ctx) -> { 77 | JSONObject jsonObject = new JSONObject(ctx.body()); 78 | 79 | String table = ctx.pathParam("table"); 80 | 81 | List params = new ArrayList<>(); 82 | String primaryKey = sqlConnector.findPrimaryKey(table); 83 | String query = "delete from " + table + " where " + primaryKey + " = ?"; 84 | for (String key : jsonObject.keySet()) { 85 | if (key.equals(primaryKey)) { 86 | params.add(jsonObject.get(key)); 87 | } 88 | } 89 | sqlConnector.executeUpdate(query, params); 90 | ctx.result("{ message: \"Data has been deleted\"}"); 91 | }); 92 | 93 | APP.get("/api/get/{table}", (ctx) -> { 94 | String table = ctx.pathParam("table"); 95 | 96 | StringBuilder whereFilter = new StringBuilder(" where 1=1 "); 97 | List params = new ArrayList<>(); 98 | 99 | ctx.queryParamMap().forEach((actualParam, value1) -> { 100 | String value = value1.get(0); 101 | String actualValue = value; 102 | String operator = "="; 103 | String logic = " and "; 104 | 105 | if (value.startsWith(">=") || value.startsWith("<=")) { 106 | operator = value.substring(0, 2); 107 | actualValue = value.substring(2); 108 | } else if (value.startsWith(">") || value.startsWith("<")) { 109 | operator = value.substring(0, 1); 110 | actualValue = value.substring(1); 111 | } 112 | 113 | if (actualParam.startsWith("|")) { 114 | logic = " or "; 115 | actualParam = actualParam.substring(1); 116 | } 117 | 118 | whereFilter.append(logic).append(actualParam).append(operator).append("?"); 119 | params.add(actualValue); 120 | }); 121 | 122 | List data = new ArrayList<>(); 123 | logger.debug("Executing : select * from " + table + " " + whereFilter + " , " + params); 124 | sqlConnector.executeQuery("select * from " + table + whereFilter, params, rset -> { 125 | HashMap dto = DTOMapper.mapUnsafely(rset); 126 | data.add(dto); 127 | }); 128 | 129 | ctx.result(new JSONArray(data).toString()); 130 | }); 131 | 132 | } 133 | 134 | public static void configure(String ip, int port) { 135 | IP = ip; 136 | PORT = port; 137 | } 138 | 139 | public static void start() { 140 | APP.start(IP,PORT); 141 | } 142 | 143 | public static void stop() { 144 | APP.stop(); 145 | } 146 | } 147 | -------------------------------------------------------------------------------- /src/main/java/gr/sqlbrowserfx/rest/RESTfulServiceConfig.java: -------------------------------------------------------------------------------- 1 | package gr.sqlbrowserfx.rest; 2 | 3 | public class RESTfulServiceConfig { 4 | 5 | private String ip; 6 | private Integer port; 7 | private String database; 8 | 9 | public RESTfulServiceConfig(String ip, Integer port, String database) { 10 | this.ip = ip; 11 | this.port = port; 12 | this.database = database; 13 | } 14 | 15 | public String getIp() { 16 | return ip; 17 | } 18 | public void setIp(String ip) { 19 | this.ip = ip; 20 | } 21 | public Integer getPort() { 22 | return port; 23 | } 24 | public void setPort(Integer port) { 25 | this.port = port; 26 | } 27 | public String getDatabase() { 28 | return database; 29 | } 30 | public void setDatabase(String database) { 31 | this.database = database; 32 | } 33 | 34 | 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/gr/sqlbrowserfx/utils/FilesUtils.java: -------------------------------------------------------------------------------- 1 | package gr.sqlbrowserfx.utils; 2 | 3 | import java.nio.file.Files; 4 | import java.nio.file.Path; 5 | import java.nio.file.Paths; 6 | import java.util.HashSet; 7 | import java.util.Set; 8 | import java.util.stream.Collectors; 9 | 10 | import org.slf4j.LoggerFactory; 11 | 12 | import gr.sqlbrowserfx.LoggerConf; 13 | 14 | public class FilesUtils { 15 | 16 | public static Set walk(String dir, String pattern, int depth) { 17 | try (var stream = Files.walk(Paths.get(dir), depth)) { 18 | return stream 19 | .filter(file -> !Files.isDirectory(file) && file.getFileName().toString().contains(pattern)) 20 | .map(Path::toAbsolutePath) 21 | .map(Path::toString) 22 | .collect(Collectors.toSet()); 23 | } catch(Exception e) { 24 | LoggerFactory.getLogger(LoggerConf.LOGGER_NAME).error("File search failed", e); 25 | return new HashSet<>(); 26 | } 27 | } 28 | 29 | public static Set walk(String dir, String pattern) { 30 | return walk(dir, pattern, 5); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/gr/sqlbrowserfx/utils/HttpClient.java: -------------------------------------------------------------------------------- 1 | package gr.sqlbrowserfx.utils; 2 | 3 | import java.io.IOException; 4 | import java.net.URI; 5 | import java.net.URISyntaxException; 6 | import java.net.http.HttpRequest; 7 | import java.net.http.HttpRequest.BodyPublishers; 8 | import java.net.http.HttpResponse; 9 | import java.net.http.HttpResponse.BodyHandlers; 10 | 11 | import org.json.JSONObject; 12 | 13 | public class HttpClient { 14 | 15 | private static final java.net.http.HttpClient client = java.net.http.HttpClient.newBuilder().build(); 16 | 17 | public static String GET(String url) throws IOException, InterruptedException, URISyntaxException { 18 | var builder = HttpRequest.newBuilder().uri(new URI(url)).GET(); 19 | var req = builder.build(); 20 | var res = client.send(req, BodyHandlers.ofString()); 21 | 22 | checkResSuccess(res); 23 | 24 | return res.body().toString(); 25 | } 26 | 27 | public static String POST(String url, Object body) throws URISyntaxException, IOException, InterruptedException { 28 | var bodyPublisher = BodyPublishers 29 | .ofString(body instanceof JSONObject ? body.toString() : new JSONObject(body).toString()); 30 | var builder = HttpRequest.newBuilder().uri(new URI(url)).POST(bodyPublisher); 31 | var req = builder.build(); 32 | var res = client.send(req, BodyHandlers.ofString()); 33 | 34 | checkResSuccess(res); 35 | 36 | return res.body().toString(); 37 | } 38 | 39 | private static void checkResSuccess(HttpResponse res) throws IOException { 40 | if (res.statusCode() < 200 || res.statusCode() > 300) { 41 | throw new IOException("Status code: " + res.statusCode() + " , " + res.body().toString()); 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/gr/sqlbrowserfx/utils/JavaFXUtils.java: -------------------------------------------------------------------------------- 1 | package gr.sqlbrowserfx.utils; 2 | 3 | import javax.swing.Timer; 4 | 5 | import org.fxmisc.wellbehaved.event.EventPattern; 6 | import org.fxmisc.wellbehaved.event.InputMap; 7 | import org.fxmisc.wellbehaved.event.Nodes; 8 | 9 | import javafx.application.Platform; 10 | import javafx.event.Event; 11 | import javafx.scene.Node; 12 | import javafx.scene.image.Image; 13 | import javafx.scene.image.ImageView; 14 | import javafx.scene.input.KeyCode; 15 | import javafx.scene.input.KeyCombination; 16 | import javafx.scene.input.ScrollEvent; 17 | 18 | public class JavaFXUtils { 19 | 20 | private static String CSS_THEME = "/styles/" + PropertiesLoader.getProperty("sqlbrowserfx.css.theme", String.class, "flat-dark"); 21 | private static double ZOOM = 1.0; 22 | 23 | static { 24 | try { 25 | new ImageView(new Image(CSS_THEME + "/icons/add.png")); 26 | } catch (Exception e) { 27 | CSS_THEME = "/styles/flat-dark"; 28 | } 29 | } 30 | 31 | public static Double getZoomFactorApplied() { 32 | return ZOOM; 33 | } 34 | 35 | public static ImageView createIcon(String url) { 36 | url = CSS_THEME + url; 37 | return new ImageView(new Image(url)); 38 | } 39 | 40 | public static ImageView createImageView(String url, Double width, Double height) { 41 | url = CSS_THEME + url; 42 | return new ImageView(new Image(url, width, height, true, false)); 43 | } 44 | 45 | public static Image createImage(String url) { 46 | url = CSS_THEME + url; 47 | return new Image(url); 48 | } 49 | 50 | public static void addMouseScrolling(Node node) { 51 | node.setOnScroll((ScrollEvent event) -> { 52 | // Adjust the ZOOM factor as per your requirement 53 | if (event.isControlDown()) { 54 | double zoomFactor = 1.05; 55 | double deltaY = event.getDeltaY(); 56 | if (deltaY < 0){ 57 | zoomFactor = 2.0 - zoomFactor; 58 | } 59 | node.setScaleX(node.getScaleX() * zoomFactor); 60 | node.setScaleY(node.getScaleY() * zoomFactor); 61 | event.consume(); 62 | } 63 | }); 64 | } 65 | 66 | public static void zoomToCurrentFactor(Node node) { 67 | // node.setStyle("-fx-font-size: " + ZOOM + "em;"); 68 | } 69 | 70 | public static void addZoomInOutSupport(Node node) { 71 | InputMap zoomIn = InputMap.consume( 72 | EventPattern.keyPressed(KeyCode.EQUALS, KeyCombination.CONTROL_DOWN), 73 | action -> { 74 | if (ZOOM < 2.5) 75 | ZOOM += 0.1; 76 | node.setStyle("-fx-font-size: " + ZOOM + "em;"); 77 | } 78 | ); 79 | InputMap zoomOut = InputMap.consume( 80 | EventPattern.keyPressed(KeyCode.MINUS, KeyCombination.CONTROL_DOWN), 81 | action -> { 82 | if (ZOOM > 0.8) 83 | ZOOM -= 0.1; 84 | node.setStyle("-fx-font-size: " + ZOOM + "em;"); 85 | } 86 | ); 87 | 88 | Nodes.addInputMap(node, zoomIn); 89 | Nodes.addInputMap(node, zoomOut); 90 | 91 | } 92 | 93 | public static void timer(int delay, Runnable action) { 94 | Timer timer = new Timer(delay, event -> Platform.runLater(action)); 95 | timer.setRepeats(false); 96 | timer.start(); 97 | } 98 | 99 | } 100 | -------------------------------------------------------------------------------- /src/main/java/gr/sqlbrowserfx/utils/MemoryGuard.java: -------------------------------------------------------------------------------- 1 | package gr.sqlbrowserfx.utils; 2 | 3 | import java.sql.ResultSet; 4 | import java.sql.SQLException; 5 | import java.sql.Statement; 6 | 7 | import org.slf4j.LoggerFactory; 8 | 9 | import gr.sqlbrowserfx.LoggerConf; 10 | import gr.sqlbrowserfx.factories.DialogFactory; 11 | 12 | public class MemoryGuard { 13 | 14 | private static final int MEMORY_DIVIDER = 10; 15 | public static Integer SQL_MEMORY_ERROR_CODE = 1234; 16 | /** 17 | * A new thread monitors the execution of a query, in 18 | * order to cancel it if memory consumption gets very big, to avoid jvm memory 19 | * crashes. 20 | * 21 | * @param rset 22 | */ 23 | public static void protect(ResultSet rset) { 24 | new Thread(() -> { 25 | try { 26 | long heapMaxSize = Runtime.getRuntime().maxMemory(); 27 | while (rset != null && !rset.isClosed()) { 28 | long currentUsage = (Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory()); 29 | if (currentUsage > heapMaxSize - heapMaxSize / MEMORY_DIVIDER) { 30 | rset.close(); 31 | LoggerFactory.getLogger(LoggerConf.LOGGER_NAME).debug("Query was canceled due to fast growing memory consumption of sql result set"); 32 | System.gc(); 33 | DialogFactory.createErrorNotification(new OutOfMemoryError("Fast growing memory consumption of sql result set")); 34 | return; 35 | } 36 | Thread.sleep(100); 37 | } 38 | } catch (Throwable e) { 39 | LoggerFactory.getLogger(LoggerConf.LOGGER_NAME).error(e.getMessage(), e); 40 | } finally { 41 | try { 42 | rset.close(); 43 | } catch (SQLException e) { 44 | LoggerFactory.getLogger(LoggerConf.LOGGER_NAME).error(e.getMessage(), e); 45 | } 46 | } 47 | }, "memory-guard").start(); 48 | } 49 | 50 | /** 51 | * A new thread monitors the execution of a query, in 52 | * order to cancel it if memory consumption gets very big, to avoid jvm memory 53 | * crashes. 54 | * 55 | * @param statement 56 | */ 57 | public static void protect(Statement statement) { 58 | new Thread(() -> { 59 | try { 60 | long heapMaxSize = Runtime.getRuntime().maxMemory(); 61 | while ((statement != null && !statement.isClosed()) ) { 62 | long currentUsage = (Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory()); 63 | if (currentUsage > heapMaxSize - heapMaxSize / MEMORY_DIVIDER) { 64 | LoggerFactory.getLogger(LoggerConf.LOGGER_NAME).debug("Query was canceled due to fast growing memory consumption of sql statement"); 65 | statement.cancel(); 66 | System.gc(); 67 | DialogFactory.createErrorNotification(new OutOfMemoryError("Fast growing memory consumption of sql statement")); 68 | return; 69 | } 70 | Thread.sleep(100); 71 | } 72 | } catch (Throwable e) { 73 | LoggerFactory.getLogger(LoggerConf.LOGGER_NAME).error(e.getMessage(), e); 74 | } finally { 75 | try { 76 | statement.close(); 77 | } catch (SQLException e) { 78 | LoggerFactory.getLogger(LoggerConf.LOGGER_NAME).error(e.getMessage(), e); 79 | } 80 | } 81 | }, "memory-guard").start(); 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/main/java/gr/sqlbrowserfx/utils/PropertiesLoader.java: -------------------------------------------------------------------------------- 1 | package gr.sqlbrowserfx.utils; 2 | 3 | import java.io.FileInputStream; 4 | import java.io.IOException; 5 | import java.io.InputStream; 6 | import java.lang.reflect.Constructor; 7 | import java.nio.file.Files; 8 | import java.nio.file.Paths; 9 | import java.util.HashMap; 10 | import java.util.Properties; 11 | 12 | import org.slf4j.Logger; 13 | 14 | public class PropertiesLoader { 15 | 16 | private static final HashMap propertiesMap = new HashMap<>(); 17 | private static Logger logger; 18 | private static Boolean IS_ENABLED = true; 19 | static { 20 | if (System.getProperty("load.props") != null) 21 | IS_ENABLED = Boolean.parseBoolean(System.getProperty("load.props", "true")); 22 | if (IS_ENABLED) 23 | loadProperties("./"); 24 | } 25 | 26 | public static void setLogger(Logger logger) { 27 | PropertiesLoader.logger = logger; 28 | } 29 | 30 | public static void loadProperties(String rootPath) { 31 | try(var walk = Files.walk(Paths.get(rootPath))) { 32 | walk 33 | .filter(Files::isRegularFile) 34 | .filter(path -> path.toString().endsWith(".properties")) 35 | .forEach(path -> { 36 | try (InputStream inputStream = new FileInputStream(path.toFile())) { 37 | Properties props = new Properties(); 38 | props.load(inputStream); 39 | propertiesMap.put(path.getFileName().toString(), props); 40 | } catch (IOException e) { 41 | if (logger != null) 42 | logger.error(e.getMessage()); 43 | else 44 | e.printStackTrace(); 45 | } 46 | }); 47 | } catch (IOException e) { 48 | if (logger != null) 49 | logger.debug("Could not read property from file"); 50 | else 51 | System.err.println("Could not read property from file"); 52 | } 53 | } 54 | 55 | @SuppressWarnings("unchecked") 56 | public static T getProperty(String fileKey, String key, Class clazz) { 57 | T value = (T) propertiesMap.get(fileKey).get(key); 58 | try { 59 | Constructor cons = clazz.getConstructor(String.class); 60 | return (T) cons.newInstance(value.toString()); 61 | } catch (Exception e) { 62 | if (logger != null) 63 | logger.debug("Could not read property from file"); 64 | else 65 | System.err.println("Could not read property from file"); 66 | } 67 | return null; 68 | } 69 | 70 | @SuppressWarnings("unchecked") 71 | public static T getProperty(String fileKey, String key, Class clazz, Object defaultValue) { 72 | T value = getProperty(fileKey, key, clazz); 73 | return value != null ? value : (T) defaultValue; 74 | } 75 | 76 | /** 77 | * Returns the first matching key from all loaded properties 78 | * 79 | * @param key 80 | * @param clazz 81 | * @return 82 | */ 83 | @SuppressWarnings("unchecked") 84 | public static T getProperty(String key, Class clazz) { 85 | Object value = null; 86 | if (IS_ENABLED) { 87 | for (Properties props : propertiesMap.values()) { 88 | value = props.get(key); 89 | if (value != null) 90 | break; 91 | } 92 | } 93 | else { 94 | value = System.getProperty(key); 95 | } 96 | try { 97 | Constructor cons = clazz.getConstructor(String.class); 98 | return (T) cons.newInstance(value.toString()); 99 | } catch (Throwable e) { 100 | if (logger != null) 101 | logger.debug("Could not read property from file"); 102 | else 103 | System.err.println("Could not read property from file"); 104 | } 105 | return null; 106 | } 107 | 108 | /** 109 | * Returns the first matching key from all loaded properties 110 | * 111 | * @param key 112 | * @param clazz 113 | * @return 114 | */ 115 | @SuppressWarnings("unchecked") 116 | public static T getProperty(String key, Class clazz, Object defaultValue) { 117 | T value = getProperty(key, clazz); 118 | return value != null ? value : (T) defaultValue; 119 | } 120 | 121 | public static Properties getPropertiesFromFile(String fileNamePart) { 122 | for (String key : propertiesMap.keySet()) { 123 | if (key.contains(fileNamePart)) 124 | return propertiesMap.get(key); 125 | } 126 | return null; 127 | } 128 | 129 | 130 | } 131 | -------------------------------------------------------------------------------- /src/main/java/gr/sqlbrowserfx/utils/Property.java: -------------------------------------------------------------------------------- 1 | package gr.sqlbrowserfx.utils; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | @Retention(RetentionPolicy.RUNTIME) 9 | @Target({ElementType.LOCAL_VARIABLE, ElementType.FIELD}) 10 | public @interface Property { 11 | String file(); 12 | String property(); 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/gr/sqlbrowserfx/utils/mapper/Column.java: -------------------------------------------------------------------------------- 1 | package gr.sqlbrowserfx.utils.mapper; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | @Retention(RetentionPolicy.RUNTIME) 9 | @Target(ElementType.FIELD) 10 | public @interface Column { 11 | 12 | String value() default ""; 13 | 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/gr/sqlbrowserfx/utils/mapper/DTO.java: -------------------------------------------------------------------------------- 1 | package gr.sqlbrowserfx.utils.mapper; 2 | 3 | import java.lang.annotation.Retention; 4 | import java.lang.annotation.RetentionPolicy; 5 | 6 | @Retention(RetentionPolicy.RUNTIME) 7 | public @interface DTO { 8 | String value() default ""; 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/gr/sqlbrowserfx/utils/mapper/DTOMapper.java: -------------------------------------------------------------------------------- 1 | package gr.sqlbrowserfx.utils.mapper; 2 | 3 | import java.lang.annotation.Annotation; 4 | import java.lang.reflect.Field; 5 | import java.sql.ResultSet; 6 | import java.sql.ResultSetMetaData; 7 | import java.util.HashMap; 8 | import java.util.LinkedHashMap; 9 | 10 | 11 | 12 | public class DTOMapper { 13 | 14 | /** 15 | * Maps a row of result set into a HashMap. 16 | * For mapping columns aliases are used. 17 | * 18 | * @param rset 19 | * @return LinkedHashMap 20 | * @throws Exception 21 | */ 22 | public static LinkedHashMap map(ResultSet rset) throws Exception { 23 | 24 | LinkedHashMap dto = new LinkedHashMap<>(); 25 | ResultSetMetaData rsmd = rset.getMetaData(); 26 | 27 | for (int i=1;i<= rsmd.getColumnCount();i++) { 28 | Object value = dto.get(rsmd.getColumnLabel(i)); 29 | if (value != null) 30 | dto.put(rsmd.getTableName(i) + "." + rsmd.getColumnLabel(i), rset.getObject(i)); 31 | else dto.put(rsmd.getColumnLabel(i), rset.getObject(i)); 32 | } 33 | 34 | return dto; 35 | } 36 | 37 | 38 | /** 39 | * Maps a row of result set into a HashMap. 40 | * For mapping columns real names are used. 41 | * 42 | * @param rset 43 | * @return LinkedHashMap 44 | * @throws Exception 45 | */ 46 | public static LinkedHashMap mapUsingRealColumnNames(ResultSet rset) throws Exception { 47 | 48 | LinkedHashMap dto = new LinkedHashMap<>(); 49 | ResultSetMetaData rsmd = rset.getMetaData(); 50 | 51 | for (int i=1;i<= rsmd.getColumnCount();i++) { 52 | Object value = dto.get(rsmd.getColumnName(i)); 53 | if (value != null) 54 | dto.put(rsmd.getTableName(i) + "." + rsmd.getColumnName(i), rset.getObject(i)); 55 | else dto.put(rsmd.getColumnName(i), rset.getObject(i)); 56 | } 57 | 58 | return dto; 59 | } 60 | 61 | /** 62 | * 63 | * @param rset 64 | * @return HashMap 65 | * @throws RuntimeException 66 | */ 67 | public static HashMap mapUnsafely(ResultSet rset) throws RuntimeException { 68 | 69 | LinkedHashMap dto = null; 70 | try { 71 | dto = map(rset); 72 | } catch (Throwable e) { 73 | throw new RuntimeException(e.getMessage(), e); 74 | } 75 | return dto; 76 | } 77 | 78 | public static Object mapu(ResultSet rset, Class clazz) { 79 | Object dto = null; 80 | try { 81 | dto = map(rset, clazz); 82 | } catch (Throwable e) { 83 | throw new RuntimeException(e.getMessage(), e); 84 | } 85 | return dto; 86 | } 87 | /** 88 | * Maps a row of result set in a given class (which has @DTO annotation and its fields have @Column annotation). 89 | * Database's column types and class fields must be type compatible. 90 | * 91 | * @param rset 92 | * @param clazz 93 | * @return 94 | * @throws Exception 95 | */ 96 | public static Object map(ResultSet rset, Class clazz) throws Exception { 97 | 98 | if (clazz.getAnnotation(DTO.class) == null) 99 | throw new IllegalAccessException( 100 | "Class " + clazz.getSimpleName() + " has no annotation " + DTO.class.getName()); 101 | 102 | Object dto = clazz.getDeclaredConstructor().newInstance(); 103 | 104 | for (Field field : clazz.getDeclaredFields()) { 105 | field.setAccessible(true); 106 | Annotation annotation = field.getAnnotation(Column.class); 107 | if (annotation != null) { 108 | // get object from result set and cast it to field's class 109 | Object value = null; 110 | try { 111 | value = rset.getObject(((Column) annotation).value(), field.getType()); 112 | } catch(Exception e) { 113 | // getObject(name, class) may be unsupported in some jdbc drivers (ex sqlite) 114 | value = rset.getObject(((Column) annotation).value()); 115 | } 116 | field.set(dto, value); 117 | } 118 | } 119 | 120 | return dto; 121 | } 122 | } -------------------------------------------------------------------------------- /src/main/java/org/dockfx/DockPos.java: -------------------------------------------------------------------------------- 1 | /** 2 | * @file DockArea.java 3 | * @brief Enumeration of dock area alignment constants. 4 | * 5 | * @section License 6 | * 7 | * This file is a part of the DockFX Library. Copyright (C) 2015 Robert B. Colton 8 | * 9 | * This program is free software: you can redistribute it and/or modify it under the terms 10 | * of the GNU Lesser General Public License as published by the Free Software Foundation, 11 | * either version 3 of the License, or (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, but WITHOUT ANY 14 | * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 15 | * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU Lesser General Public License along with this 18 | * program. If not, see . 19 | **/ 20 | 21 | package org.dockfx; 22 | 23 | /** 24 | * DockPos 25 | * 26 | * @since DockFX 0.1 27 | */ 28 | public enum DockPos { 29 | /** 30 | * Dock to the center by stacking inside a TabPane. This should be considered the equivalent of 31 | * null. 32 | */ 33 | CENTER, 34 | 35 | /** 36 | * Dock to the left using a splitter. 37 | */ 38 | LEFT, 39 | 40 | /** 41 | * Dock to the right using a splitter. 42 | */ 43 | RIGHT, 44 | 45 | /** 46 | * Dock to the top using a splitter. 47 | */ 48 | TOP, 49 | 50 | /** 51 | * Dock to the bottom using a splitter. 52 | */ 53 | BOTTOM; 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/org/dockfx/DockTabPane.java: -------------------------------------------------------------------------------- 1 | package org.dockfx; 2 | 3 | import gr.sqlbrowserfx.nodes.ContextMenuOwner; 4 | import gr.sqlbrowserfx.nodes.sqlpane.DraggingTabPaneSupport; 5 | import javafx.scene.Node; 6 | import javafx.scene.control.ContextMenu; 7 | import javafx.scene.control.Label; 8 | import javafx.scene.control.MenuItem; 9 | import javafx.scene.control.Tab; 10 | import javafx.scene.control.TabPane; 11 | 12 | public class DockTabPane extends TabPane implements ContextMenuOwner, Dockable { 13 | 14 | private DockNode thisDockNode; 15 | 16 | public DockTabPane() { 17 | super(); 18 | this.setContextMenu(createContextMenu()); 19 | new DraggingTabPaneSupport().addSupport(this); 20 | } 21 | 22 | public void addTab(DockNode dockNode) { 23 | Tab tab = new Tab(dockNode.getTitle(), dockNode); 24 | tab.setGraphic(dockNode.getGraphic()); 25 | dockNode.setGraphic(null); 26 | if (dockNode.isClosable()) { 27 | tab.setOnClosed(closeEvent -> { 28 | Runnable closeAction = dockNode.getOnCloseAction(); 29 | if (closeAction != null) 30 | closeAction.run(); 31 | undockIfNeccessary(); 32 | }); 33 | } 34 | tab.setClosable(dockNode.isClosable()); 35 | this.getTabs().add(tab); 36 | this.getSelectionModel().select(tab); 37 | } 38 | 39 | private void undockIfNeccessary() { 40 | if (this.getTabs().size() == 1) { 41 | Tab tab = this.getTabs().get(0); 42 | this.getTabs().remove(tab); 43 | DockNode dockNode = (DockNode) tab.getContent(); 44 | dockNode.dock(dockNode.getDockPane(), DockPos.TOP, thisDockNode, DockWeights.asDoubleArrray(0.5f, 0.5f)); 45 | dockNode.setGraphic(getGraphicFromTab(tab)); 46 | dockNode.showTitleBar(); 47 | dockNode.getDockPane().undock(thisDockNode); 48 | } 49 | // if (this.getTabs().size() == 0) { 50 | // this.asDockNode().close(); 51 | // } 52 | } 53 | 54 | private Node getGraphicFromTab(Tab tab) { 55 | return ((Label)tab.getGraphic()).getGraphic(); 56 | } 57 | 58 | @Override 59 | public ContextMenu createContextMenu() { 60 | 61 | MenuItem menuItemUndock = new MenuItem("Undock Selected"); 62 | menuItemUndock.setOnAction(event -> { 63 | Tab selectedTab = getSelectionModel().getSelectedItem(); 64 | DockNode dockNode = (DockNode) selectedTab.getContent(); 65 | this.getTabs().remove(selectedTab); 66 | dockNode.undock(); 67 | dockNode.setGraphic(getGraphicFromTab(selectedTab)); 68 | dockNode.showTitleBar(); 69 | dockNode.setFloating(true); 70 | 71 | undockIfNeccessary(); 72 | }); 73 | 74 | return new ContextMenu(menuItemUndock); 75 | } 76 | 77 | @Override 78 | public DockNode asDockNode() { 79 | if (thisDockNode == null) { 80 | thisDockNode = new DockNode(this, "Grouped View"); 81 | thisDockNode.setClosable(false); 82 | } 83 | return thisDockNode; 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/main/java/org/dockfx/DockWeights.java: -------------------------------------------------------------------------------- 1 | package org.dockfx; 2 | 3 | public class DockWeights { 4 | 5 | /** 6 | * Method for code readability apply weights to dock nodes in same order. 7 | * 8 | * @param weights 9 | * @return double[] array 10 | */ 11 | public static double[] asDoubleArrray(double... weights) { 12 | return weights; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/org/dockfx/Dockable.java: -------------------------------------------------------------------------------- 1 | package org.dockfx; 2 | 3 | public interface Dockable { 4 | 5 | /** 6 | * Returns Node wrapped in DockNode. 7 | * To use this interface you have to keep a DockNode instance as member of class. 8 | * Then you can dock the node by calling node.asDockNode().dock(...) 9 | * 10 | * @return 11 | */ 12 | public DockNode asDockNode(); 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/res-to-styles.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | for file in $(find . -name "*") 4 | do 5 | if [ -f "$file" ] 6 | then 7 | echo "Fixing file : $file ..." 8 | sed -i "s/res\//\/icons\//g" $file 9 | echo "done" 10 | fi 11 | done -------------------------------------------------------------------------------- /src/main/resources/log4j2.properties: -------------------------------------------------------------------------------- 1 | name = PropertiesConfig 2 | 3 | appender.sqlbrowserfx.type = RollingFile 4 | appender.sqlbrowserfx.name = sqlbrowserfxAppender 5 | appender.sqlbrowserfx.fileName = ./logs/sqlbrowserfx.log 6 | appender.sqlbrowserfx.filePattern = ./logs/sqlbrowserfx.%d{dd-MMM}.log.gz 7 | appender.sqlbrowserfx.layout.type = PatternLayout 8 | appender.sqlbrowserfx.layout.pattern = %d{yyyy-MM-dd HH:mm:ss} [%t] %c{1} %class %-5p %m%n 9 | appender.sqlbrowserfx.policies.type = Policies 10 | appender.sqlbrowserfx.policies.size.type = SizeBasedTriggeringPolicy 11 | appender.sqlbrowserfx.policies.size.size=1MB 12 | appender.sqlbrowserfx.strategy.type = DefaultRolloverStrategy 13 | appender.sqlbrowserfx.strategy.max = 5 14 | 15 | logger.sqlbrowserfx.name = sqlbrowserfx 16 | logger.sqlbrowserfx.level = info 17 | logger.sqlbrowserfx.additivity = false 18 | logger.sqlbrowserfx.appenderRef.sqlbrowserfx.ref = sqlbrowserfxAppender 19 | 20 | #appender.spark.type = RollingFile 21 | #appender.spark.name = sparkAppender 22 | #appender.spark.fileName = ./logs/spark.log 23 | #appender.spark.filePattern = ./logs/spark.%d{dd-MMM}.log.gz 24 | #appender.spark.layout.type = PatternLayout 25 | #appender.spark.layout.pattern = %d{yyyy-MM-dd HH:mm:ss} [%t] %c{1} %class %-5p %m%n 26 | #appender.spark.policies.type = Policies 27 | #appender.spark.policies.size.type = SizeBasedTriggeringPolicy 28 | #appender.spark.policies.size.size=10MB 29 | #appender.spark.strategy.type = DefaultRolloverStrategy 30 | #appender.spark.strategy.max = 5 31 | 32 | logger.spark.name = spark 33 | logger.spark.level = debug 34 | logger.spark.additivity = false 35 | logger.spark.appenderRef.spark.ref = sqlbrowserfxAppender 36 | -------------------------------------------------------------------------------- /src/main/resources/styles/fix-missing-icons.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | source_theme="./flat-dark/icons" 4 | #target_theme="./flat-blue/icons" 5 | target_theme="./$1/icons" 6 | 7 | for file in $(find $source_theme -type f -name "*") 8 | do 9 | if [ $(find $target_theme -type f -name "*" | grep -ic $(basename $file)) -eq 0 ] 10 | then 11 | echo "Copying $(basename $file) ..." 12 | cp $file $target_theme/ 13 | fi 14 | done 15 | -------------------------------------------------------------------------------- /src/main/resources/styles/flat-dark/icons/add.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pariskol/sqlbrowserfx/433976953de44268e2e9bca634e12547cd14a886/src/main/resources/styles/flat-dark/icons/add.png -------------------------------------------------------------------------------- /src/main/resources/styles/flat-dark/icons/blue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pariskol/sqlbrowserfx/433976953de44268e2e9bca634e12547cd14a886/src/main/resources/styles/flat-dark/icons/blue.png -------------------------------------------------------------------------------- /src/main/resources/styles/flat-dark/icons/chart-pie.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pariskol/sqlbrowserfx/433976953de44268e2e9bca634e12547cd14a886/src/main/resources/styles/flat-dark/icons/chart-pie.png -------------------------------------------------------------------------------- /src/main/resources/styles/flat-dark/icons/chart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pariskol/sqlbrowserfx/433976953de44268e2e9bca634e12547cd14a886/src/main/resources/styles/flat-dark/icons/chart.png -------------------------------------------------------------------------------- /src/main/resources/styles/flat-dark/icons/check.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pariskol/sqlbrowserfx/433976953de44268e2e9bca634e12547cd14a886/src/main/resources/styles/flat-dark/icons/check.png -------------------------------------------------------------------------------- /src/main/resources/styles/flat-dark/icons/clear.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pariskol/sqlbrowserfx/433976953de44268e2e9bca634e12547cd14a886/src/main/resources/styles/flat-dark/icons/clear.png -------------------------------------------------------------------------------- /src/main/resources/styles/flat-dark/icons/close-win-w.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pariskol/sqlbrowserfx/433976953de44268e2e9bca634e12547cd14a886/src/main/resources/styles/flat-dark/icons/close-win-w.png -------------------------------------------------------------------------------- /src/main/resources/styles/flat-dark/icons/close-win.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pariskol/sqlbrowserfx/433976953de44268e2e9bca634e12547cd14a886/src/main/resources/styles/flat-dark/icons/close-win.png -------------------------------------------------------------------------------- /src/main/resources/styles/flat-dark/icons/close.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pariskol/sqlbrowserfx/433976953de44268e2e9bca634e12547cd14a886/src/main/resources/styles/flat-dark/icons/close.png -------------------------------------------------------------------------------- /src/main/resources/styles/flat-dark/icons/code-file.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pariskol/sqlbrowserfx/433976953de44268e2e9bca634e12547cd14a886/src/main/resources/styles/flat-dark/icons/code-file.png -------------------------------------------------------------------------------- /src/main/resources/styles/flat-dark/icons/collapse.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pariskol/sqlbrowserfx/433976953de44268e2e9bca634e12547cd14a886/src/main/resources/styles/flat-dark/icons/collapse.png -------------------------------------------------------------------------------- /src/main/resources/styles/flat-dark/icons/columns.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pariskol/sqlbrowserfx/433976953de44268e2e9bca634e12547cd14a886/src/main/resources/styles/flat-dark/icons/columns.png -------------------------------------------------------------------------------- /src/main/resources/styles/flat-dark/icons/compare.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pariskol/sqlbrowserfx/433976953de44268e2e9bca634e12547cd14a886/src/main/resources/styles/flat-dark/icons/compare.png -------------------------------------------------------------------------------- /src/main/resources/styles/flat-dark/icons/console.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pariskol/sqlbrowserfx/433976953de44268e2e9bca634e12547cd14a886/src/main/resources/styles/flat-dark/icons/console.png -------------------------------------------------------------------------------- /src/main/resources/styles/flat-dark/icons/copy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pariskol/sqlbrowserfx/433976953de44268e2e9bca634e12547cd14a886/src/main/resources/styles/flat-dark/icons/copy.png -------------------------------------------------------------------------------- /src/main/resources/styles/flat-dark/icons/csv-import.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pariskol/sqlbrowserfx/433976953de44268e2e9bca634e12547cd14a886/src/main/resources/styles/flat-dark/icons/csv-import.png -------------------------------------------------------------------------------- /src/main/resources/styles/flat-dark/icons/csv.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pariskol/sqlbrowserfx/433976953de44268e2e9bca634e12547cd14a886/src/main/resources/styles/flat-dark/icons/csv.png -------------------------------------------------------------------------------- /src/main/resources/styles/flat-dark/icons/cut.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pariskol/sqlbrowserfx/433976953de44268e2e9bca634e12547cd14a886/src/main/resources/styles/flat-dark/icons/cut.png -------------------------------------------------------------------------------- /src/main/resources/styles/flat-dark/icons/database.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pariskol/sqlbrowserfx/433976953de44268e2e9bca634e12547cd14a886/src/main/resources/styles/flat-dark/icons/database.png -------------------------------------------------------------------------------- /src/main/resources/styles/flat-dark/icons/details.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pariskol/sqlbrowserfx/433976953de44268e2e9bca634e12547cd14a886/src/main/resources/styles/flat-dark/icons/details.png -------------------------------------------------------------------------------- /src/main/resources/styles/flat-dark/icons/diagram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pariskol/sqlbrowserfx/433976953de44268e2e9bca634e12547cd14a886/src/main/resources/styles/flat-dark/icons/diagram.png -------------------------------------------------------------------------------- /src/main/resources/styles/flat-dark/icons/edit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pariskol/sqlbrowserfx/433976953de44268e2e9bca634e12547cd14a886/src/main/resources/styles/flat-dark/icons/edit.png -------------------------------------------------------------------------------- /src/main/resources/styles/flat-dark/icons/filter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pariskol/sqlbrowserfx/433976953de44268e2e9bca634e12547cd14a886/src/main/resources/styles/flat-dark/icons/filter.png -------------------------------------------------------------------------------- /src/main/resources/styles/flat-dark/icons/folder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pariskol/sqlbrowserfx/433976953de44268e2e9bca634e12547cd14a886/src/main/resources/styles/flat-dark/icons/folder.png -------------------------------------------------------------------------------- /src/main/resources/styles/flat-dark/icons/foreign-key.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pariskol/sqlbrowserfx/433976953de44268e2e9bca634e12547cd14a886/src/main/resources/styles/flat-dark/icons/foreign-key.png -------------------------------------------------------------------------------- /src/main/resources/styles/flat-dark/icons/format.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pariskol/sqlbrowserfx/433976953de44268e2e9bca634e12547cd14a886/src/main/resources/styles/flat-dark/icons/format.png -------------------------------------------------------------------------------- /src/main/resources/styles/flat-dark/icons/function.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pariskol/sqlbrowserfx/433976953de44268e2e9bca634e12547cd14a886/src/main/resources/styles/flat-dark/icons/function.png -------------------------------------------------------------------------------- /src/main/resources/styles/flat-dark/icons/green.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pariskol/sqlbrowserfx/433976953de44268e2e9bca634e12547cd14a886/src/main/resources/styles/flat-dark/icons/green.png -------------------------------------------------------------------------------- /src/main/resources/styles/flat-dark/icons/help.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pariskol/sqlbrowserfx/433976953de44268e2e9bca634e12547cd14a886/src/main/resources/styles/flat-dark/icons/help.png -------------------------------------------------------------------------------- /src/main/resources/styles/flat-dark/icons/icons8-pulse-20.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pariskol/sqlbrowserfx/433976953de44268e2e9bca634e12547cd14a886/src/main/resources/styles/flat-dark/icons/icons8-pulse-20.png -------------------------------------------------------------------------------- /src/main/resources/styles/flat-dark/icons/index.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pariskol/sqlbrowserfx/433976953de44268e2e9bca634e12547cd14a886/src/main/resources/styles/flat-dark/icons/index.png -------------------------------------------------------------------------------- /src/main/resources/styles/flat-dark/icons/javalin-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pariskol/sqlbrowserfx/433976953de44268e2e9bca634e12547cd14a886/src/main/resources/styles/flat-dark/icons/javalin-logo.png -------------------------------------------------------------------------------- /src/main/resources/styles/flat-dark/icons/lowercase.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pariskol/sqlbrowserfx/433976953de44268e2e9bca634e12547cd14a886/src/main/resources/styles/flat-dark/icons/lowercase.png -------------------------------------------------------------------------------- /src/main/resources/styles/flat-dark/icons/m-database.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pariskol/sqlbrowserfx/433976953de44268e2e9bca634e12547cd14a886/src/main/resources/styles/flat-dark/icons/m-database.png -------------------------------------------------------------------------------- /src/main/resources/styles/flat-dark/icons/magnify.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pariskol/sqlbrowserfx/433976953de44268e2e9bca634e12547cd14a886/src/main/resources/styles/flat-dark/icons/magnify.png -------------------------------------------------------------------------------- /src/main/resources/styles/flat-dark/icons/mariadb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pariskol/sqlbrowserfx/433976953de44268e2e9bca634e12547cd14a886/src/main/resources/styles/flat-dark/icons/mariadb.png -------------------------------------------------------------------------------- /src/main/resources/styles/flat-dark/icons/maximize-win-w.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pariskol/sqlbrowserfx/433976953de44268e2e9bca634e12547cd14a886/src/main/resources/styles/flat-dark/icons/maximize-win-w.png -------------------------------------------------------------------------------- /src/main/resources/styles/flat-dark/icons/maximize-win.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pariskol/sqlbrowserfx/433976953de44268e2e9bca634e12547cd14a886/src/main/resources/styles/flat-dark/icons/maximize-win.png -------------------------------------------------------------------------------- /src/main/resources/styles/flat-dark/icons/maximize.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pariskol/sqlbrowserfx/433976953de44268e2e9bca634e12547cd14a886/src/main/resources/styles/flat-dark/icons/maximize.png -------------------------------------------------------------------------------- /src/main/resources/styles/flat-dark/icons/menu-edit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pariskol/sqlbrowserfx/433976953de44268e2e9bca634e12547cd14a886/src/main/resources/styles/flat-dark/icons/menu-edit.png -------------------------------------------------------------------------------- /src/main/resources/styles/flat-dark/icons/menu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pariskol/sqlbrowserfx/433976953de44268e2e9bca634e12547cd14a886/src/main/resources/styles/flat-dark/icons/menu.png -------------------------------------------------------------------------------- /src/main/resources/styles/flat-dark/icons/minus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pariskol/sqlbrowserfx/433976953de44268e2e9bca634e12547cd14a886/src/main/resources/styles/flat-dark/icons/minus.png -------------------------------------------------------------------------------- /src/main/resources/styles/flat-dark/icons/monitor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pariskol/sqlbrowserfx/433976953de44268e2e9bca634e12547cd14a886/src/main/resources/styles/flat-dark/icons/monitor.png -------------------------------------------------------------------------------- /src/main/resources/styles/flat-dark/icons/mysql.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pariskol/sqlbrowserfx/433976953de44268e2e9bca634e12547cd14a886/src/main/resources/styles/flat-dark/icons/mysql.png -------------------------------------------------------------------------------- /src/main/resources/styles/flat-dark/icons/next.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pariskol/sqlbrowserfx/433976953de44268e2e9bca634e12547cd14a886/src/main/resources/styles/flat-dark/icons/next.png -------------------------------------------------------------------------------- /src/main/resources/styles/flat-dark/icons/no.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pariskol/sqlbrowserfx/433976953de44268e2e9bca634e12547cd14a886/src/main/resources/styles/flat-dark/icons/no.png -------------------------------------------------------------------------------- /src/main/resources/styles/flat-dark/icons/old/add.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pariskol/sqlbrowserfx/433976953de44268e2e9bca634e12547cd14a886/src/main/resources/styles/flat-dark/icons/old/add.png -------------------------------------------------------------------------------- /src/main/resources/styles/flat-dark/icons/old/check.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pariskol/sqlbrowserfx/433976953de44268e2e9bca634e12547cd14a886/src/main/resources/styles/flat-dark/icons/old/check.png -------------------------------------------------------------------------------- /src/main/resources/styles/flat-dark/icons/old/clear.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pariskol/sqlbrowserfx/433976953de44268e2e9bca634e12547cd14a886/src/main/resources/styles/flat-dark/icons/old/clear.png -------------------------------------------------------------------------------- /src/main/resources/styles/flat-dark/icons/old/code-file.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pariskol/sqlbrowserfx/433976953de44268e2e9bca634e12547cd14a886/src/main/resources/styles/flat-dark/icons/old/code-file.png -------------------------------------------------------------------------------- /src/main/resources/styles/flat-dark/icons/old/collapse.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pariskol/sqlbrowserfx/433976953de44268e2e9bca634e12547cd14a886/src/main/resources/styles/flat-dark/icons/old/collapse.png -------------------------------------------------------------------------------- /src/main/resources/styles/flat-dark/icons/old/columns.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pariskol/sqlbrowserfx/433976953de44268e2e9bca634e12547cd14a886/src/main/resources/styles/flat-dark/icons/old/columns.png -------------------------------------------------------------------------------- /src/main/resources/styles/flat-dark/icons/old/compare.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pariskol/sqlbrowserfx/433976953de44268e2e9bca634e12547cd14a886/src/main/resources/styles/flat-dark/icons/old/compare.png -------------------------------------------------------------------------------- /src/main/resources/styles/flat-dark/icons/old/console.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pariskol/sqlbrowserfx/433976953de44268e2e9bca634e12547cd14a886/src/main/resources/styles/flat-dark/icons/old/console.png -------------------------------------------------------------------------------- /src/main/resources/styles/flat-dark/icons/old/copy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pariskol/sqlbrowserfx/433976953de44268e2e9bca634e12547cd14a886/src/main/resources/styles/flat-dark/icons/old/copy.png -------------------------------------------------------------------------------- /src/main/resources/styles/flat-dark/icons/old/csv-import.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pariskol/sqlbrowserfx/433976953de44268e2e9bca634e12547cd14a886/src/main/resources/styles/flat-dark/icons/old/csv-import.png -------------------------------------------------------------------------------- /src/main/resources/styles/flat-dark/icons/old/csv.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pariskol/sqlbrowserfx/433976953de44268e2e9bca634e12547cd14a886/src/main/resources/styles/flat-dark/icons/old/csv.png -------------------------------------------------------------------------------- /src/main/resources/styles/flat-dark/icons/old/cut.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pariskol/sqlbrowserfx/433976953de44268e2e9bca634e12547cd14a886/src/main/resources/styles/flat-dark/icons/old/cut.png -------------------------------------------------------------------------------- /src/main/resources/styles/flat-dark/icons/old/database.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pariskol/sqlbrowserfx/433976953de44268e2e9bca634e12547cd14a886/src/main/resources/styles/flat-dark/icons/old/database.png -------------------------------------------------------------------------------- /src/main/resources/styles/flat-dark/icons/old/details.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pariskol/sqlbrowserfx/433976953de44268e2e9bca634e12547cd14a886/src/main/resources/styles/flat-dark/icons/old/details.png -------------------------------------------------------------------------------- /src/main/resources/styles/flat-dark/icons/old/edit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pariskol/sqlbrowserfx/433976953de44268e2e9bca634e12547cd14a886/src/main/resources/styles/flat-dark/icons/old/edit.png -------------------------------------------------------------------------------- /src/main/resources/styles/flat-dark/icons/old/filter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pariskol/sqlbrowserfx/433976953de44268e2e9bca634e12547cd14a886/src/main/resources/styles/flat-dark/icons/old/filter.png -------------------------------------------------------------------------------- /src/main/resources/styles/flat-dark/icons/old/foreign-key.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pariskol/sqlbrowserfx/433976953de44268e2e9bca634e12547cd14a886/src/main/resources/styles/flat-dark/icons/old/foreign-key.png -------------------------------------------------------------------------------- /src/main/resources/styles/flat-dark/icons/old/format.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pariskol/sqlbrowserfx/433976953de44268e2e9bca634e12547cd14a886/src/main/resources/styles/flat-dark/icons/old/format.png -------------------------------------------------------------------------------- /src/main/resources/styles/flat-dark/icons/old/function.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pariskol/sqlbrowserfx/433976953de44268e2e9bca634e12547cd14a886/src/main/resources/styles/flat-dark/icons/old/function.png -------------------------------------------------------------------------------- /src/main/resources/styles/flat-dark/icons/old/help.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pariskol/sqlbrowserfx/433976953de44268e2e9bca634e12547cd14a886/src/main/resources/styles/flat-dark/icons/old/help.png -------------------------------------------------------------------------------- /src/main/resources/styles/flat-dark/icons/old/icons8-lightning-bolt-20.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pariskol/sqlbrowserfx/433976953de44268e2e9bca634e12547cd14a886/src/main/resources/styles/flat-dark/icons/old/icons8-lightning-bolt-20.png -------------------------------------------------------------------------------- /src/main/resources/styles/flat-dark/icons/old/index.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pariskol/sqlbrowserfx/433976953de44268e2e9bca634e12547cd14a886/src/main/resources/styles/flat-dark/icons/old/index.png -------------------------------------------------------------------------------- /src/main/resources/styles/flat-dark/icons/old/lowercase.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pariskol/sqlbrowserfx/433976953de44268e2e9bca634e12547cd14a886/src/main/resources/styles/flat-dark/icons/old/lowercase.png -------------------------------------------------------------------------------- /src/main/resources/styles/flat-dark/icons/old/magnify.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pariskol/sqlbrowserfx/433976953de44268e2e9bca634e12547cd14a886/src/main/resources/styles/flat-dark/icons/old/magnify.png -------------------------------------------------------------------------------- /src/main/resources/styles/flat-dark/icons/old/minus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pariskol/sqlbrowserfx/433976953de44268e2e9bca634e12547cd14a886/src/main/resources/styles/flat-dark/icons/old/minus.png -------------------------------------------------------------------------------- /src/main/resources/styles/flat-dark/icons/old/monitor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pariskol/sqlbrowserfx/433976953de44268e2e9bca634e12547cd14a886/src/main/resources/styles/flat-dark/icons/old/monitor.png -------------------------------------------------------------------------------- /src/main/resources/styles/flat-dark/icons/old/next.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pariskol/sqlbrowserfx/433976953de44268e2e9bca634e12547cd14a886/src/main/resources/styles/flat-dark/icons/old/next.png -------------------------------------------------------------------------------- /src/main/resources/styles/flat-dark/icons/old/no.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pariskol/sqlbrowserfx/433976953de44268e2e9bca634e12547cd14a886/src/main/resources/styles/flat-dark/icons/old/no.png -------------------------------------------------------------------------------- /src/main/resources/styles/flat-dark/icons/old/open-view.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pariskol/sqlbrowserfx/433976953de44268e2e9bca634e12547cd14a886/src/main/resources/styles/flat-dark/icons/old/open-view.png -------------------------------------------------------------------------------- /src/main/resources/styles/flat-dark/icons/old/openTab.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pariskol/sqlbrowserfx/433976953de44268e2e9bca634e12547cd14a886/src/main/resources/styles/flat-dark/icons/old/openTab.png -------------------------------------------------------------------------------- /src/main/resources/styles/flat-dark/icons/old/paste.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pariskol/sqlbrowserfx/433976953de44268e2e9bca634e12547cd14a886/src/main/resources/styles/flat-dark/icons/old/paste.png -------------------------------------------------------------------------------- /src/main/resources/styles/flat-dark/icons/old/play.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pariskol/sqlbrowserfx/433976953de44268e2e9bca634e12547cd14a886/src/main/resources/styles/flat-dark/icons/old/play.png -------------------------------------------------------------------------------- /src/main/resources/styles/flat-dark/icons/old/primary-key.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pariskol/sqlbrowserfx/433976953de44268e2e9bca634e12547cd14a886/src/main/resources/styles/flat-dark/icons/old/primary-key.png -------------------------------------------------------------------------------- /src/main/resources/styles/flat-dark/icons/old/procedure.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pariskol/sqlbrowserfx/433976953de44268e2e9bca634e12547cd14a886/src/main/resources/styles/flat-dark/icons/old/procedure.png -------------------------------------------------------------------------------- /src/main/resources/styles/flat-dark/icons/old/refresh.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pariskol/sqlbrowserfx/433976953de44268e2e9bca634e12547cd14a886/src/main/resources/styles/flat-dark/icons/old/refresh.png -------------------------------------------------------------------------------- /src/main/resources/styles/flat-dark/icons/old/replace.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pariskol/sqlbrowserfx/433976953de44268e2e9bca634e12547cd14a886/src/main/resources/styles/flat-dark/icons/old/replace.png -------------------------------------------------------------------------------- /src/main/resources/styles/flat-dark/icons/old/save.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pariskol/sqlbrowserfx/433976953de44268e2e9bca634e12547cd14a886/src/main/resources/styles/flat-dark/icons/old/save.png -------------------------------------------------------------------------------- /src/main/resources/styles/flat-dark/icons/old/script.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pariskol/sqlbrowserfx/433976953de44268e2e9bca634e12547cd14a886/src/main/resources/styles/flat-dark/icons/old/script.png -------------------------------------------------------------------------------- /src/main/resources/styles/flat-dark/icons/old/settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pariskol/sqlbrowserfx/433976953de44268e2e9bca634e12547cd14a886/src/main/resources/styles/flat-dark/icons/old/settings.png -------------------------------------------------------------------------------- /src/main/resources/styles/flat-dark/icons/old/stop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pariskol/sqlbrowserfx/433976953de44268e2e9bca634e12547cd14a886/src/main/resources/styles/flat-dark/icons/old/stop.png -------------------------------------------------------------------------------- /src/main/resources/styles/flat-dark/icons/old/structure.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pariskol/sqlbrowserfx/433976953de44268e2e9bca634e12547cd14a886/src/main/resources/styles/flat-dark/icons/old/structure.png -------------------------------------------------------------------------------- /src/main/resources/styles/flat-dark/icons/old/suggestion.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pariskol/sqlbrowserfx/433976953de44268e2e9bca634e12547cd14a886/src/main/resources/styles/flat-dark/icons/old/suggestion.png -------------------------------------------------------------------------------- /src/main/resources/styles/flat-dark/icons/old/table-e.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pariskol/sqlbrowserfx/433976953de44268e2e9bca634e12547cd14a886/src/main/resources/styles/flat-dark/icons/old/table-e.png -------------------------------------------------------------------------------- /src/main/resources/styles/flat-dark/icons/old/table-settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pariskol/sqlbrowserfx/433976953de44268e2e9bca634e12547cd14a886/src/main/resources/styles/flat-dark/icons/old/table-settings.png -------------------------------------------------------------------------------- /src/main/resources/styles/flat-dark/icons/old/table-y.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pariskol/sqlbrowserfx/433976953de44268e2e9bca634e12547cd14a886/src/main/resources/styles/flat-dark/icons/old/table-y.png -------------------------------------------------------------------------------- /src/main/resources/styles/flat-dark/icons/old/table.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pariskol/sqlbrowserfx/433976953de44268e2e9bca634e12547cd14a886/src/main/resources/styles/flat-dark/icons/old/table.png -------------------------------------------------------------------------------- /src/main/resources/styles/flat-dark/icons/old/thunder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pariskol/sqlbrowserfx/433976953de44268e2e9bca634e12547cd14a886/src/main/resources/styles/flat-dark/icons/old/thunder.png -------------------------------------------------------------------------------- /src/main/resources/styles/flat-dark/icons/old/transaction.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pariskol/sqlbrowserfx/433976953de44268e2e9bca634e12547cd14a886/src/main/resources/styles/flat-dark/icons/old/transaction.png -------------------------------------------------------------------------------- /src/main/resources/styles/flat-dark/icons/old/trigger.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pariskol/sqlbrowserfx/433976953de44268e2e9bca634e12547cd14a886/src/main/resources/styles/flat-dark/icons/old/trigger.png -------------------------------------------------------------------------------- /src/main/resources/styles/flat-dark/icons/old/uppercase.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pariskol/sqlbrowserfx/433976953de44268e2e9bca634e12547cd14a886/src/main/resources/styles/flat-dark/icons/old/uppercase.png -------------------------------------------------------------------------------- /src/main/resources/styles/flat-dark/icons/old/view.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pariskol/sqlbrowserfx/433976953de44268e2e9bca634e12547cd14a886/src/main/resources/styles/flat-dark/icons/old/view.png -------------------------------------------------------------------------------- /src/main/resources/styles/flat-dark/icons/old/web.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pariskol/sqlbrowserfx/433976953de44268e2e9bca634e12547cd14a886/src/main/resources/styles/flat-dark/icons/old/web.png -------------------------------------------------------------------------------- /src/main/resources/styles/flat-dark/icons/old/yes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pariskol/sqlbrowserfx/433976953de44268e2e9bca634e12547cd14a886/src/main/resources/styles/flat-dark/icons/old/yes.png -------------------------------------------------------------------------------- /src/main/resources/styles/flat-dark/icons/old/zoom.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pariskol/sqlbrowserfx/433976953de44268e2e9bca634e12547cd14a886/src/main/resources/styles/flat-dark/icons/old/zoom.png -------------------------------------------------------------------------------- /src/main/resources/styles/flat-dark/icons/open-view.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pariskol/sqlbrowserfx/433976953de44268e2e9bca634e12547cd14a886/src/main/resources/styles/flat-dark/icons/open-view.png -------------------------------------------------------------------------------- /src/main/resources/styles/flat-dark/icons/openTab.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pariskol/sqlbrowserfx/433976953de44268e2e9bca634e12547cd14a886/src/main/resources/styles/flat-dark/icons/openTab.png -------------------------------------------------------------------------------- /src/main/resources/styles/flat-dark/icons/paste.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pariskol/sqlbrowserfx/433976953de44268e2e9bca634e12547cd14a886/src/main/resources/styles/flat-dark/icons/paste.png -------------------------------------------------------------------------------- /src/main/resources/styles/flat-dark/icons/pin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pariskol/sqlbrowserfx/433976953de44268e2e9bca634e12547cd14a886/src/main/resources/styles/flat-dark/icons/pin.png -------------------------------------------------------------------------------- /src/main/resources/styles/flat-dark/icons/play.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pariskol/sqlbrowserfx/433976953de44268e2e9bca634e12547cd14a886/src/main/resources/styles/flat-dark/icons/play.png -------------------------------------------------------------------------------- /src/main/resources/styles/flat-dark/icons/postgre.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pariskol/sqlbrowserfx/433976953de44268e2e9bca634e12547cd14a886/src/main/resources/styles/flat-dark/icons/postgre.png -------------------------------------------------------------------------------- /src/main/resources/styles/flat-dark/icons/primary-key.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pariskol/sqlbrowserfx/433976953de44268e2e9bca634e12547cd14a886/src/main/resources/styles/flat-dark/icons/primary-key.png -------------------------------------------------------------------------------- /src/main/resources/styles/flat-dark/icons/procedure.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pariskol/sqlbrowserfx/433976953de44268e2e9bca634e12547cd14a886/src/main/resources/styles/flat-dark/icons/procedure.png -------------------------------------------------------------------------------- /src/main/resources/styles/flat-dark/icons/red.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pariskol/sqlbrowserfx/433976953de44268e2e9bca634e12547cd14a886/src/main/resources/styles/flat-dark/icons/red.png -------------------------------------------------------------------------------- /src/main/resources/styles/flat-dark/icons/refresh.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pariskol/sqlbrowserfx/433976953de44268e2e9bca634e12547cd14a886/src/main/resources/styles/flat-dark/icons/refresh.png -------------------------------------------------------------------------------- /src/main/resources/styles/flat-dark/icons/replace.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pariskol/sqlbrowserfx/433976953de44268e2e9bca634e12547cd14a886/src/main/resources/styles/flat-dark/icons/replace.png -------------------------------------------------------------------------------- /src/main/resources/styles/flat-dark/icons/restore-win-w.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pariskol/sqlbrowserfx/433976953de44268e2e9bca634e12547cd14a886/src/main/resources/styles/flat-dark/icons/restore-win-w.png -------------------------------------------------------------------------------- /src/main/resources/styles/flat-dark/icons/restore-win.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pariskol/sqlbrowserfx/433976953de44268e2e9bca634e12547cd14a886/src/main/resources/styles/flat-dark/icons/restore-win.png -------------------------------------------------------------------------------- /src/main/resources/styles/flat-dark/icons/restore.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pariskol/sqlbrowserfx/433976953de44268e2e9bca634e12547cd14a886/src/main/resources/styles/flat-dark/icons/restore.png -------------------------------------------------------------------------------- /src/main/resources/styles/flat-dark/icons/save.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pariskol/sqlbrowserfx/433976953de44268e2e9bca634e12547cd14a886/src/main/resources/styles/flat-dark/icons/save.png -------------------------------------------------------------------------------- /src/main/resources/styles/flat-dark/icons/script.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pariskol/sqlbrowserfx/433976953de44268e2e9bca634e12547cd14a886/src/main/resources/styles/flat-dark/icons/script.png -------------------------------------------------------------------------------- /src/main/resources/styles/flat-dark/icons/settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pariskol/sqlbrowserfx/433976953de44268e2e9bca634e12547cd14a886/src/main/resources/styles/flat-dark/icons/settings.png -------------------------------------------------------------------------------- /src/main/resources/styles/flat-dark/icons/spark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pariskol/sqlbrowserfx/433976953de44268e2e9bca634e12547cd14a886/src/main/resources/styles/flat-dark/icons/spark.png -------------------------------------------------------------------------------- /src/main/resources/styles/flat-dark/icons/sqlbrowser-fx.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pariskol/sqlbrowserfx/433976953de44268e2e9bca634e12547cd14a886/src/main/resources/styles/flat-dark/icons/sqlbrowser-fx.png -------------------------------------------------------------------------------- /src/main/resources/styles/flat-dark/icons/sqlite.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pariskol/sqlbrowserfx/433976953de44268e2e9bca634e12547cd14a886/src/main/resources/styles/flat-dark/icons/sqlite.png -------------------------------------------------------------------------------- /src/main/resources/styles/flat-dark/icons/sqlserver.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pariskol/sqlbrowserfx/433976953de44268e2e9bca634e12547cd14a886/src/main/resources/styles/flat-dark/icons/sqlserver.png -------------------------------------------------------------------------------- /src/main/resources/styles/flat-dark/icons/stop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pariskol/sqlbrowserfx/433976953de44268e2e9bca634e12547cd14a886/src/main/resources/styles/flat-dark/icons/stop.png -------------------------------------------------------------------------------- /src/main/resources/styles/flat-dark/icons/structure.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pariskol/sqlbrowserfx/433976953de44268e2e9bca634e12547cd14a886/src/main/resources/styles/flat-dark/icons/structure.png -------------------------------------------------------------------------------- /src/main/resources/styles/flat-dark/icons/suggestion.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pariskol/sqlbrowserfx/433976953de44268e2e9bca634e12547cd14a886/src/main/resources/styles/flat-dark/icons/suggestion.png -------------------------------------------------------------------------------- /src/main/resources/styles/flat-dark/icons/table-e.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pariskol/sqlbrowserfx/433976953de44268e2e9bca634e12547cd14a886/src/main/resources/styles/flat-dark/icons/table-e.png -------------------------------------------------------------------------------- /src/main/resources/styles/flat-dark/icons/table-settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pariskol/sqlbrowserfx/433976953de44268e2e9bca634e12547cd14a886/src/main/resources/styles/flat-dark/icons/table-settings.png -------------------------------------------------------------------------------- /src/main/resources/styles/flat-dark/icons/table-y.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pariskol/sqlbrowserfx/433976953de44268e2e9bca634e12547cd14a886/src/main/resources/styles/flat-dark/icons/table-y.png -------------------------------------------------------------------------------- /src/main/resources/styles/flat-dark/icons/table.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pariskol/sqlbrowserfx/433976953de44268e2e9bca634e12547cd14a886/src/main/resources/styles/flat-dark/icons/table.png -------------------------------------------------------------------------------- /src/main/resources/styles/flat-dark/icons/thunder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pariskol/sqlbrowserfx/433976953de44268e2e9bca634e12547cd14a886/src/main/resources/styles/flat-dark/icons/thunder.png -------------------------------------------------------------------------------- /src/main/resources/styles/flat-dark/icons/transaction.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pariskol/sqlbrowserfx/433976953de44268e2e9bca634e12547cd14a886/src/main/resources/styles/flat-dark/icons/transaction.png -------------------------------------------------------------------------------- /src/main/resources/styles/flat-dark/icons/trigger.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pariskol/sqlbrowserfx/433976953de44268e2e9bca634e12547cd14a886/src/main/resources/styles/flat-dark/icons/trigger.png -------------------------------------------------------------------------------- /src/main/resources/styles/flat-dark/icons/uppercase.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pariskol/sqlbrowserfx/433976953de44268e2e9bca634e12547cd14a886/src/main/resources/styles/flat-dark/icons/uppercase.png -------------------------------------------------------------------------------- /src/main/resources/styles/flat-dark/icons/var.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pariskol/sqlbrowserfx/433976953de44268e2e9bca634e12547cd14a886/src/main/resources/styles/flat-dark/icons/var.png -------------------------------------------------------------------------------- /src/main/resources/styles/flat-dark/icons/view.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pariskol/sqlbrowserfx/433976953de44268e2e9bca634e12547cd14a886/src/main/resources/styles/flat-dark/icons/view.png -------------------------------------------------------------------------------- /src/main/resources/styles/flat-dark/icons/web.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pariskol/sqlbrowserfx/433976953de44268e2e9bca634e12547cd14a886/src/main/resources/styles/flat-dark/icons/web.png -------------------------------------------------------------------------------- /src/main/resources/styles/flat-dark/icons/yes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pariskol/sqlbrowserfx/433976953de44268e2e9bca634e12547cd14a886/src/main/resources/styles/flat-dark/icons/yes.png -------------------------------------------------------------------------------- /src/main/resources/styles/flat-dark/icons/zoom.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pariskol/sqlbrowserfx/433976953de44268e2e9bca634e12547cd14a886/src/main/resources/styles/flat-dark/icons/zoom.png -------------------------------------------------------------------------------- /src/test/java/sqlbrowserfx/FilesTreeViewTestGui.java: -------------------------------------------------------------------------------- 1 | package sqlbrowserfx; 2 | 3 | import java.io.IOException; 4 | 5 | import gr.sqlbrowserfx.nodes.codeareas.java.JavaCodeArea; 6 | import javafx.application.Application; 7 | import javafx.scene.Scene; 8 | import javafx.stage.Stage; 9 | 10 | public class FilesTreeViewTestGui extends Application { 11 | 12 | @Override 13 | public void start(Stage primaryStage) throws IOException { 14 | Scene scene = new Scene(new JavaCodeArea(), 800, 600); 15 | scene.getStylesheets().add("/styles/flat-dark.css"); 16 | primaryStage.setScene(scene); 17 | primaryStage.show(); 18 | } 19 | 20 | public static void main(String[] args) { 21 | launch(args); 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /src/test/java/sqlbrowserfx/GuiTestStarter.java: -------------------------------------------------------------------------------- 1 | package sqlbrowserfx; 2 | 3 | public class GuiTestStarter { 4 | 5 | public static void main(String[] args) { 6 | SqlPaneTestGui.main(args); 7 | } 8 | 9 | } 10 | -------------------------------------------------------------------------------- /src/test/java/sqlbrowserfx/JavaCodeAreaTestGui.java: -------------------------------------------------------------------------------- 1 | package sqlbrowserfx; 2 | 3 | import java.io.IOException; 4 | 5 | import gr.sqlbrowserfx.nodes.codeareas.java.JavaCodeArea; 6 | import javafx.application.Application; 7 | import javafx.scene.Scene; 8 | import javafx.stage.Stage; 9 | 10 | public class JavaCodeAreaTestGui extends Application { 11 | 12 | @Override 13 | public void start(Stage primaryStage) throws IOException { 14 | Scene scene = new Scene(new JavaCodeArea(), 800, 600); 15 | scene.getStylesheets().add("/styles/flat-dark.css"); 16 | primaryStage.setScene(scene); 17 | primaryStage.show(); 18 | } 19 | 20 | public static void main(String[] args) { 21 | launch(args); 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /src/test/java/sqlbrowserfx/JsonTableViewTestGui.java: -------------------------------------------------------------------------------- 1 | package sqlbrowserfx; 2 | 3 | import org.json.JSONArray; 4 | 5 | import gr.sqlbrowserfx.nodes.tableviews.JSONTableView; 6 | import gr.sqlbrowserfx.utils.HttpClient; 7 | import javafx.application.Application; 8 | import javafx.scene.Scene; 9 | import javafx.scene.control.TextField; 10 | import javafx.scene.layout.VBox; 11 | import javafx.stage.Stage; 12 | 13 | public class JsonTableViewTestGui extends Application{ 14 | 15 | public static void main(String[] args) { 16 | launch(args); 17 | } 18 | 19 | @Override 20 | public void start(Stage primaryStage) { 21 | try { 22 | primaryStage.setTitle("SqlBrowser"); 23 | JSONArray jsonArray = new JSONArray(HttpClient.GET("")); 24 | JSONTableView tableView = new JSONTableView(); 25 | tableView.setItemsLater(jsonArray); 26 | primaryStage.setScene(new Scene(new VBox(new TextField(), tableView))); 27 | primaryStage.show(); 28 | } catch (Throwable e) { 29 | e.printStackTrace(); 30 | } 31 | 32 | 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/test/java/sqlbrowserfx/SqlPaneTestGui.java: -------------------------------------------------------------------------------- 1 | package sqlbrowserfx; 2 | 3 | import gr.sqlbrowserfx.conn.SqliteConnector; 4 | import gr.sqlbrowserfx.nodes.sqlpane.SqlPane; 5 | import javafx.application.Application; 6 | import javafx.scene.Scene; 7 | import javafx.stage.Stage; 8 | 9 | public class SqlPaneTestGui extends Application { 10 | 11 | @Override 12 | public void start(Stage primaryStage) throws Exception { 13 | Scene scene = new Scene(new SqlPane(new SqliteConnector("/home/paris/sqlite-dbs/chinook.db")), 800, 600); 14 | scene.getStylesheets().add("/styles/flat-dark.css"); 15 | primaryStage.setScene(scene); 16 | primaryStage.show(); 17 | } 18 | 19 | public static void main(String[] args) { 20 | launch(args); 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /src/test/java/sqlbrowserfx/TableCreationPaneTestGui.java: -------------------------------------------------------------------------------- 1 | package sqlbrowserfx; 2 | 3 | import gr.sqlbrowserfx.conn.SqliteConnector; 4 | import gr.sqlbrowserfx.nodes.TableCreationPane; 5 | import javafx.application.Application; 6 | import javafx.scene.Scene; 7 | import javafx.stage.Stage; 8 | 9 | public class TableCreationPaneTestGui extends Application { 10 | 11 | @Override 12 | public void start(Stage primaryStage) throws Exception { 13 | primaryStage.setScene(new Scene(new TableCreationPane(new SqliteConnector("/home/paris/sqlite-dbs/chinook.db")))); 14 | primaryStage.show(); 15 | } 16 | 17 | public static void main(String[] args) { 18 | launch(args); 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /starters/SqlBrowserFX.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pariskol/sqlbrowserfx/433976953de44268e2e9bca634e12547cd14a886/starters/SqlBrowserFX.exe -------------------------------------------------------------------------------- /starters/sqlbrowserfx.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | cd "$(dirname "$0")" 4 | 5 | main_jar=$(find . -name "sqlbrowser*.jar") 6 | main_class=gr.sqlbrowserfx.GUIStarter 7 | 8 | [ ! -z "$JAVA_HOME" ] && JAVA_HOME=$JAVA_HOME/bin/ 9 | ${JAVA_HOME}java -Xmx512m -Xms128m -XX:+UseG1GC -XX:MaxGCPauseMillis=100 -Dprism.lcdtext=false \ 10 | -cp lib/*:$main_jar $main_class 11 | --------------------------------------------------------------------------------