├── .gitattributes
├── LICENSE
├── README.md
├── SNAPSHOTS
├── a.png
├── b.png
├── c.png
├── d.png
├── donate
│ ├── alipay.png
│ ├── paypal.png
│ └── wechat.png
├── e.png
├── f.png
└── g.png
├── app
├── build.gradle
└── src
│ └── main
│ ├── java
│ └── cn
│ │ └── navigational
│ │ └── dbfx
│ │ ├── AbstractFxmlController.java
│ │ ├── AppPlatform.java
│ │ ├── DatabaseFxApp.java
│ │ ├── FXMLHelper.java
│ │ ├── Launcher.java
│ │ ├── ViewController.java
│ │ ├── controller
│ │ ├── BottomNavigationExpandPaneAbstractFxmlController.java
│ │ └── NavigatorToolBarController.java
│ │ ├── controls
│ │ ├── editor
│ │ │ └── SQLAutoCompletePopup.java
│ │ ├── table
│ │ │ ├── CustomTableColumn.java
│ │ │ ├── CustomTableView.java
│ │ │ ├── DataTableCell.java
│ │ │ └── IndexTableCell.java
│ │ └── tree
│ │ │ ├── AbstractBaseTreeItem.java
│ │ │ ├── CustomTreeView.java
│ │ │ ├── TreeItemMenuHandler.java
│ │ │ └── impl
│ │ │ └── ProgressTreeItem.java
│ │ ├── convert
│ │ └── RowSetConvert.java
│ │ ├── dialog
│ │ ├── SimpleConfirmDialog.java
│ │ └── UnDecoratedDialog.java
│ │ ├── editor
│ │ └── EditorPlatform.java
│ │ ├── handler
│ │ └── DataTableCellEditHandler.java
│ │ ├── i18n
│ │ ├── I18N.java
│ │ └── I18NControl.java
│ │ ├── model
│ │ ├── DatabaseMeta.java
│ │ ├── DbInfo.java
│ │ ├── Manifest.java
│ │ ├── SQLClient.java
│ │ └── TableSetting.java
│ │ ├── security
│ │ └── AseAlgorithm.java
│ │ ├── tool
│ │ ├── export
│ │ │ └── DataExportFactory.java
│ │ └── svg
│ │ │ └── SvgImageTranscoder.java
│ │ ├── utils
│ │ ├── AlertUtils.java
│ │ ├── AppSettings.java
│ │ ├── DateUtils.java
│ │ ├── FileMutex.java
│ │ ├── MessageBox.java
│ │ ├── SqlConsoleAppender.java
│ │ └── TableColumnUtils.java
│ │ └── view
│ │ └── AboutViewController.java
│ ├── kotlin
│ └── cn
│ │ └── navigational
│ │ └── dbfx
│ │ ├── DatabaseMetaManager.kt
│ │ ├── SQLClientManager.kt
│ │ ├── config
│ │ ├── AppConstants.kt
│ │ ├── ControllerPath.kt
│ │ └── ViewPath.kt
│ │ ├── controller
│ │ ├── ConInfoPaneController.kt
│ │ ├── LogController.kt
│ │ ├── SQLTerminalController.kt
│ │ ├── TableViewController.kt
│ │ └── TerminalController.kt
│ │ ├── controls
│ │ ├── AbstractBaseTab.kt
│ │ ├── tab
│ │ │ ├── SQLTerminalTab.kt
│ │ │ └── TableTab.kt
│ │ └── tree
│ │ │ ├── DatabaseTreeItem.kt
│ │ │ ├── RoleItem.kt
│ │ │ ├── cell
│ │ │ └── NTreeCell.kt
│ │ │ ├── folder
│ │ │ ├── RoleFolder.kt
│ │ │ ├── SchemeFolder.kt
│ │ │ ├── TableFolder.kt
│ │ │ └── ViewFolder.kt
│ │ │ ├── scheme
│ │ │ ├── PgSchemeItem.kt
│ │ │ └── SchemeItem.kt
│ │ │ └── table
│ │ │ ├── TableFieldItem.kt
│ │ │ └── TableTreeItem.kt
│ │ ├── dialog
│ │ ├── ProgressDialog.kt
│ │ └── TableSettingDialog.kt
│ │ ├── handler
│ │ ├── AppExitHandler.kt
│ │ └── MainTabPaneHandler.kt
│ │ ├── io
│ │ ├── DbFxIO.kt
│ │ └── LogIO.kt
│ │ └── view
│ │ ├── CreateConViewController.kt
│ │ ├── EditConViewController.kt
│ │ ├── ExportViewController.kt
│ │ ├── HomeViewController.kt
│ │ └── SplashViewController.kt
│ └── resources
│ ├── assets
│ ├── icons
│ │ ├── db
│ │ │ ├── db2.svg
│ │ │ ├── mini
│ │ │ │ ├── field.svg
│ │ │ │ ├── folder.svg
│ │ │ │ ├── my_collation.svg
│ │ │ │ ├── my_user.svg
│ │ │ │ ├── mysql.svg
│ │ │ │ ├── open.svg
│ │ │ │ ├── pg_db.svg
│ │ │ │ ├── pg_role.svg
│ │ │ │ ├── postgres.svg
│ │ │ │ ├── remove_db.svg
│ │ │ │ └── scheme.svg
│ │ │ ├── mysql.svg
│ │ │ ├── postgres.svg
│ │ │ └── sql_server.svg
│ │ ├── dialog
│ │ │ ├── close.svg
│ │ │ ├── info.svg
│ │ │ └── minimize.svg
│ │ ├── home
│ │ │ ├── break_off_icon.png
│ │ │ ├── con_icon.png
│ │ │ ├── recon-icon.png
│ │ │ └── sql_edit_icon.png
│ │ ├── icon.png
│ │ ├── icon.svg
│ │ ├── last.png
│ │ ├── mini
│ │ │ ├── dis_con.svg
│ │ │ ├── edit.svg
│ │ │ ├── flush.svg
│ │ │ ├── open_con.svg
│ │ │ └── terminal.svg
│ │ ├── nav
│ │ │ ├── event-log.svg
│ │ │ └── terminal.svg
│ │ ├── next.png
│ │ ├── setting.svg
│ │ ├── table
│ │ │ ├── add.svg
│ │ │ ├── asc.svg
│ │ │ ├── del.svg
│ │ │ ├── des.svg
│ │ │ ├── field
│ │ │ │ ├── date_time.svg
│ │ │ │ ├── letter.svg
│ │ │ │ ├── number.svg
│ │ │ │ └── pri_key_icon.svg
│ │ │ ├── first_page.svg
│ │ │ ├── flush.svg
│ │ │ ├── last.svg
│ │ │ ├── last_page.svg
│ │ │ ├── next.svg
│ │ │ ├── search_icon.svg
│ │ │ ├── setting.svg
│ │ │ ├── sort.svg
│ │ │ ├── table.svg
│ │ │ ├── table_field.svg
│ │ │ └── table_view.svg
│ │ ├── terminal
│ │ │ ├── exe_result.svg
│ │ │ ├── info.svg
│ │ │ └── start.svg
│ │ ├── w_mini.svg
│ │ └── x16
│ │ │ ├── add_x16.svg
│ │ │ ├── db_config_x16.svg
│ │ │ ├── duplicate_x16.svg
│ │ │ ├── flush_x16.svg
│ │ │ ├── folder_x16.svg
│ │ │ ├── stop_x16.svg
│ │ │ ├── table_x16.svg
│ │ │ └── terminal_x16.svg
│ └── imgs
│ │ └── splash.png
│ ├── banner.txt
│ ├── config
│ ├── s_db.json
│ └── ui_preferences.json
│ ├── css
│ ├── about_style.css
│ ├── app_style.css
│ ├── controller
│ │ ├── b_expand_pane_style.css
│ │ ├── con_info_style.css
│ │ ├── log_pane_style.css
│ │ ├── progress_dialog_pane_style.css
│ │ ├── sql_terminal_style.css
│ │ └── table_view_style.css
│ ├── create_con_style.css
│ ├── dialog
│ │ └── table_setting_dialog_style.css
│ ├── edit_con_style.css
│ ├── export_style.css
│ ├── home_style.css
│ └── splash_style.css
│ ├── fxml
│ ├── about_view.fxml
│ ├── controller
│ │ ├── b_expand_pane.fxml
│ │ ├── con_info_pane.fxml
│ │ ├── log_pane.fxml
│ │ ├── n_top_bar.fxml
│ │ ├── sql_terminal.fxml
│ │ ├── table_view.fxml
│ │ └── terminal_pane.fxml
│ ├── create_con_view.fxml
│ ├── dialog
│ │ ├── progress_dialog_pane.fxml
│ │ └── table_setting_dialog_pane.fxml
│ ├── edit_con_view.fxml
│ ├── export_view.fxml
│ ├── home_view.fxml
│ └── splash_view.fxml
│ ├── i18n
│ ├── dbfx.properties
│ └── dbfx_zh_CN.properties
│ └── logback.xml
├── build.gradle
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── kit
├── build.gradle
└── src
│ ├── main
│ ├── java
│ │ └── cn
│ │ │ └── navigational
│ │ │ └── dbfx
│ │ │ └── kit
│ │ │ ├── KeywordHelper.java
│ │ │ ├── SqlClientFactory.java
│ │ │ ├── enums
│ │ │ ├── Clients.java
│ │ │ └── DataType.java
│ │ │ ├── ex
│ │ │ └── NotSupportException.java
│ │ │ ├── model
│ │ │ └── TableColumnMeta.java
│ │ │ └── utils
│ │ │ ├── NumberUtils.java
│ │ │ ├── OssUtils.java
│ │ │ ├── StringUtils.java
│ │ │ └── VertxUtils.java
│ ├── kotlin
│ │ └── cn
│ │ │ └── navigational
│ │ │ └── dbfx
│ │ │ └── kit
│ │ │ ├── SQLExecutor.kt
│ │ │ ├── SQLQuery.kt
│ │ │ ├── config
│ │ │ └── Constants.kt
│ │ │ ├── mysql
│ │ │ ├── MyDataTypeHelper.kt
│ │ │ ├── MysqlHelper.kt
│ │ │ ├── MysqlPageHelper.kt
│ │ │ └── MysqlQuery.kt
│ │ │ └── postgres
│ │ │ ├── PgQuery.kt
│ │ │ └── PgSQLHelper.kt
│ └── resources
│ │ └── config
│ │ └── keyword
│ │ └── support_key.json
│ └── test
│ └── kotlin
│ └── cn
│ └── navigational
│ └── dbfx
│ └── kit
│ └── test
│ ├── BaseTest.kt
│ ├── DB2BaseTest.kt
│ ├── MSSqlBaseTest.kt
│ ├── MySqlTestBase.kt
│ ├── PostgresqlBaseTest.kt
│ └── impl
│ ├── MySqlClientTest.kt
│ └── PostgresqlClientTest.kt
├── native
└── linux-gl-menu
│ ├── CMakeLists.txt
│ ├── linux_global_menu_wrapper.c
│ ├── linux_global_menu_wrapper.h
│ └── test.c
└── settings.gradle
/.gitattributes:
--------------------------------------------------------------------------------
1 | *.c,*.h linguist-language=c
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # dbfx
2 |
3 | This is a free, cross platform, open source database management tool based on JavaFX and vertx SQL client.
4 |
5 | ## Build
6 | To build DatabaseFX, execute the following command:
7 | ```
8 | gradlew build
9 | ```
10 | To run the product, execute the following command:
11 | ```
12 | gradlew run
13 | ```
14 | NOTE : DatabaseFX requires Java 15 and above.
15 |
16 | ## Support and sponsorship projects
17 | If you think that the Dbfx database management tool is useful and willing to support its continuous enrichment functions,
18 | you can support and sponsor projects through the following ways (click link or scan code through PayPal / WeChat support / Alipay payment).
19 |
20 | 
21 | 
22 | 
23 |
24 | ## Supported database systems
25 | Database support capability level: __Planned__ / __Part__ / __support(:100:)__
26 |
27 | | Database | Version | SQL Query | Data Edit | Design Table | Export | Import | Smart Tips | Modeling | Data synchronization |
28 | |-------------|---------|--------------|------------|----------|---------|--------|---------------|-------|---------|
29 | | MySQL | 5.7 + | support:100: | Planned | Planned | Planned | Planned | Part | Planned | Planned |
30 | | MariaDB | 10.0 + | support:100: | Planned| Planned | Planned | Planned | Part | Planned | Planned |
31 | | PostgreSQL | 9.0 + | support:100: | Planned | Planned | Planned | Planned | Planned | Planned | Planned |
32 | | Redis | | Planned | Planned | Planned | Planned | Planned | Planned | Planned | Planned |
33 | | DB2 | | | | | | | | | |
34 | | SQL Server | | | | | | | | | |
35 |
36 | ## Snapshots
37 |
38 | 
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/SNAPSHOTS/a.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/databasefx/dbfx/4e47738a27c6e0deb2514d4c5891ccfb59635284/SNAPSHOTS/a.png
--------------------------------------------------------------------------------
/SNAPSHOTS/b.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/databasefx/dbfx/4e47738a27c6e0deb2514d4c5891ccfb59635284/SNAPSHOTS/b.png
--------------------------------------------------------------------------------
/SNAPSHOTS/c.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/databasefx/dbfx/4e47738a27c6e0deb2514d4c5891ccfb59635284/SNAPSHOTS/c.png
--------------------------------------------------------------------------------
/SNAPSHOTS/d.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/databasefx/dbfx/4e47738a27c6e0deb2514d4c5891ccfb59635284/SNAPSHOTS/d.png
--------------------------------------------------------------------------------
/SNAPSHOTS/donate/alipay.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/databasefx/dbfx/4e47738a27c6e0deb2514d4c5891ccfb59635284/SNAPSHOTS/donate/alipay.png
--------------------------------------------------------------------------------
/SNAPSHOTS/donate/paypal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/databasefx/dbfx/4e47738a27c6e0deb2514d4c5891ccfb59635284/SNAPSHOTS/donate/paypal.png
--------------------------------------------------------------------------------
/SNAPSHOTS/donate/wechat.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/databasefx/dbfx/4e47738a27c6e0deb2514d4c5891ccfb59635284/SNAPSHOTS/donate/wechat.png
--------------------------------------------------------------------------------
/SNAPSHOTS/e.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/databasefx/dbfx/4e47738a27c6e0deb2514d4c5891ccfb59635284/SNAPSHOTS/e.png
--------------------------------------------------------------------------------
/SNAPSHOTS/f.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/databasefx/dbfx/4e47738a27c6e0deb2514d4c5891ccfb59635284/SNAPSHOTS/f.png
--------------------------------------------------------------------------------
/SNAPSHOTS/g.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/databasefx/dbfx/4e47738a27c6e0deb2514d4c5891ccfb59635284/SNAPSHOTS/g.png
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | import java.text.SimpleDateFormat
2 |
3 | plugins {
4 | id 'application'
5 | id 'org.openjfx.javafxplugin' version '0.0.9'
6 | }
7 |
8 | mainClassName = 'cn.navigational.dbfx.Launcher'
9 |
10 | //jvm args
11 | applicationDefaultJvmArgs = ['-Dsun.java2d.opengl=true', '-XX:+UseZGC', '-Xms512M', '-Xmx1024M']
12 | if (javafx.platform.classifier == 'linux') applicationDefaultJvmArgs.add("-Djdk.gtk.version=2")
13 |
14 | javafx {
15 | version = "15"
16 | modules = ['javafx.controls', 'javafx.fxml', 'javafx.base', 'javafx.graphics', 'javafx.swing']
17 | }
18 |
19 |
20 | jar {
21 | from {
22 | configurations.runtime.collect {
23 | if (!it.name.startsWith("javafx")) {
24 | zipTree(it)
25 | }
26 | }
27 | }
28 | archiveFileName = "dbfx.jar"
29 | manifest {
30 | attributes 'Multi-Release': true
31 | attributes 'Main-Class': mainClassName
32 | attributes 'App-Name': rootProject.name
33 | attributes "App-Version": project.version
34 | attributes 'App-Author': '752544765@qq.com'
35 | attributes 'App-Website': 'http://navigational.cn'
36 | attributes 'Build-Time': new SimpleDateFormat().format(new Date())
37 | attributes 'Copyright': 'Copyright © 2019-2020 navigational.cn'
38 | }
39 | }
40 |
41 | dependencies {
42 | compile project(":kit")
43 | compile group: 'commons-codec', name: 'commons-codec', version: '1.14'
44 | compile group: 'org.controlsfx', name: 'controlsfx', version: '11.0.2'
45 | compile group: 'org.fxmisc.richtext', name: 'richtextfx', version: '0.10.5'
46 | compile group: 'org.apache.xmlgraphics', name: 'batik-transcoder', version: '1.13'
47 | }
48 |
49 |
--------------------------------------------------------------------------------
/app/src/main/java/cn/navigational/dbfx/AbstractFxmlController.java:
--------------------------------------------------------------------------------
1 | package cn.navigational.dbfx;
2 |
3 |
4 | /**
5 | * FXML controller base class
6 | *
7 | * @param
Current fxml root node
8 | * @author yangkui
9 | * @since 1.0
10 | */
11 | public class AbstractFxmlController
{
12 | private final P root;
13 |
14 | public AbstractFxmlController(String path) {
15 | this.root = FXMLHelper.loadFxml(path, this);
16 | }
17 |
18 | public P getParent() {
19 | return root;
20 | }
21 |
22 | /**
23 | * This method is called to release resources when the current view dies
24 | */
25 | public void dispose() {
26 |
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/app/src/main/java/cn/navigational/dbfx/DatabaseFxApp.java:
--------------------------------------------------------------------------------
1 | package cn.navigational.dbfx;
2 |
3 | import cn.navigational.dbfx.i18n.I18N;
4 | import cn.navigational.dbfx.kit.utils.VertxUtils;
5 | import cn.navigational.dbfx.view.SplashViewController;
6 | import javafx.application.Application;
7 | import javafx.application.Platform;
8 | import javafx.stage.Stage;
9 | import org.controlsfx.dialog.ExceptionDialog;
10 | import org.slf4j.Logger;
11 | import org.slf4j.LoggerFactory;
12 |
13 | import java.util.List;
14 |
15 | /**
16 | * Javafx application class
17 | *
18 | * @author yangkui
19 | * @since 1.0
20 | */
21 | public class DatabaseFxApp extends Application implements AppPlatform.AppNotificationHandler {
22 | private final static Logger LOG = LoggerFactory.getLogger(Launcher.class);
23 |
24 | private static void setApplicationUncaughtExceptionHandler() {
25 | if (Thread.getDefaultUncaughtExceptionHandler() == null) {
26 | // Register a Default Uncaught Exception Handler for the application
27 | Thread.setDefaultUncaughtExceptionHandler(new DbFxUncaughtExceptionHandler());
28 | }
29 | }
30 |
31 | @Override
32 | public void start(Stage primaryStage) {
33 | //Global catch javafx UI thread un-caught exception
34 | setApplicationUncaughtExceptionHandler();
35 | try {
36 | if (!AppPlatform.requestStart(this, getParameters())) {
37 | Platform.exit();
38 | }
39 | } catch (Exception e) {
40 | var error = new ExceptionDialog(e);
41 | error.setTitle(I18N.getString("alert.title.start"));
42 | error.setHeaderText(I18N.getString("alert.start.failure.message"));
43 | error.showAndWait();
44 | Platform.exit();
45 | }
46 | }
47 |
48 | @Override
49 | public void stop() throws Exception {
50 | LOG.debug("Stop current application.");
51 | VertxUtils.close();
52 | }
53 |
54 | private static class DbFxUncaughtExceptionHandler implements Thread.UncaughtExceptionHandler {
55 |
56 | private static final Logger LOGGER = LoggerFactory.getLogger(DbFxUncaughtExceptionHandler.class);
57 |
58 | @Override
59 | public void uncaughtException(Thread t, Throwable e) {
60 | // Print the details of the exception in dbfx log file
61 | LOGGER.error("An exception was thrown:", e);
62 | }
63 | }
64 |
65 | @Override
66 | public void handleLaunch(List files) {
67 | new SplashViewController();
68 | }
69 |
70 | @Override
71 | public void handleOpenFilesAction(List files) {
72 |
73 | }
74 |
75 | @Override
76 | public void handleMessageBoxFailure(Exception x) {
77 |
78 | }
79 |
80 | @Override
81 | public void handleQuitAction() {
82 |
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/app/src/main/java/cn/navigational/dbfx/FXMLHelper.java:
--------------------------------------------------------------------------------
1 | package cn.navigational.dbfx;
2 |
3 | import cn.navigational.dbfx.i18n.I18N;
4 | import javafx.fxml.FXMLLoader;
5 | import org.slf4j.Logger;
6 | import org.slf4j.LoggerFactory;
7 |
8 | import java.io.IOException;
9 |
10 | /**
11 | * FXML helper
12 | *
13 | * @author yangkui
14 | * @since 1.0
15 | */
16 | public class FXMLHelper {
17 |
18 | private static final Logger LOG = LoggerFactory.getLogger(FXMLHelper.class);
19 |
20 | /**
21 | * Load fxml view
22 | *
23 | * @param path FXML view path
24 | */
25 | public static P loadFxml(final String path, Object controller) {
26 | var fxLoader = new FXMLLoader();
27 | fxLoader.setResources(I18N.getBundle());
28 | fxLoader.setController(controller);
29 | final P root;
30 | try {
31 | root = fxLoader.load(ClassLoader.getSystemResourceAsStream(path));
32 | } catch (IOException e) {
33 | LOG.debug("Load fxml view happen error.", e);
34 | throw new RuntimeException("Load fxml view failed path=[" + path + "].");
35 | }
36 | return root;
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/app/src/main/java/cn/navigational/dbfx/Launcher.java:
--------------------------------------------------------------------------------
1 | package cn.navigational.dbfx;
2 |
3 | /**
4 | * Java progress start class
5 | *
6 | * @author yangkui
7 | * @since 1.0
8 | */
9 | public class Launcher {
10 | public static void main(String[] args) {
11 | DatabaseFxApp.launch(DatabaseFxApp.class, args);
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/app/src/main/java/cn/navigational/dbfx/ViewController.java:
--------------------------------------------------------------------------------
1 | package cn.navigational.dbfx;
2 |
3 | import cn.navigational.dbfx.tool.svg.SvgImageTranscoder;
4 | import javafx.scene.Parent;
5 | import javafx.scene.Scene;
6 | import javafx.scene.image.Image;
7 | import javafx.stage.Screen;
8 | import javafx.stage.Stage;
9 | import javafx.stage.WindowEvent;
10 |
11 | import static cn.navigational.dbfx.config.AppConstantsKt.APP_ICON;
12 |
13 |
14 | /**
15 | * This class encapsulates stage, which encapsulates some event monitoring,
16 | * such as display event monitoring, window minimization listening,
17 | * window closing event listening, etc
18 | *
19 | * @param
20 | * @author yangkui
21 | * @since 1.0
22 | */
23 | public class ViewController extends AbstractFxmlController {
24 | /**
25 | * Current stage scene
26 | */
27 | private final Scene scene;
28 | /**
29 | * Current stage instance object
30 | */
31 | private final Stage stage = new Stage();
32 | /**
33 | * Default stage icon
34 | */
35 | private static final Image ICON_IMAGE = SvgImageTranscoder.svgToImage(APP_ICON);
36 |
37 | public ViewController(String path) {
38 | super(path);
39 | this.scene = new Scene(getParent());
40 | this.stage.setScene(scene);
41 | this.stage.getIcons().add(ICON_IMAGE);
42 | this.stage.setOnCloseRequest(this::onCloseRequest);
43 | this.scene.getStylesheets().add("css/app_style.css");
44 | }
45 |
46 |
47 | /**
48 | * This method is called when the window is closed
49 | *
50 | * @param event Event source
51 | */
52 | protected void onCloseRequest(WindowEvent event) {
53 | }
54 |
55 | public void showStage() {
56 | this.stage.show();
57 | }
58 |
59 | public Scene getScene() {
60 | return scene;
61 | }
62 |
63 | public Stage getStage() {
64 | return stage;
65 | }
66 |
67 | /**
68 | * Setting the current stage size has set the current screen size as
69 | * the base according to the given proportion.
70 | *
71 | * @param wProp width proportion
72 | * @param hProp height proportion
73 | */
74 | protected void setSizeWithScreen(double wProp, double hProp) {
75 | var rect = Screen.getPrimary().getBounds();
76 | var width = rect.getWidth() * wProp;
77 | var height = rect.getHeight() * hProp;
78 | this.stage.setWidth(width);
79 | this.stage.setHeight(height);
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/app/src/main/java/cn/navigational/dbfx/controls/table/DataTableCell.java:
--------------------------------------------------------------------------------
1 | package cn.navigational.dbfx.controls.table;
2 |
3 | import javafx.beans.property.StringProperty;
4 | import javafx.collections.ObservableList;
5 | import javafx.scene.control.TableCell;
6 | import javafx.scene.input.MouseEvent;
7 |
8 | import static cn.navigational.dbfx.kit.config.ConstantsKt.NULL_TAG;
9 |
10 | /**
11 | * Table data cell
12 | *
13 | * @author yangkui
14 | * @since 1.0
15 | */
16 | public class DataTableCell extends TableCell, String> {
17 | public static final String NULL_STYLE = "null-style";
18 |
19 | DataTableCell() {
20 | setWrapText(false);
21 | addEventFilter(MouseEvent.MOUSE_CLICKED, event -> {
22 | if (isEmpty() || getTableColumn() == null || getTableRow() == null) {
23 | return;
24 | }
25 | var selectModel = getTableView().getSelectionModel();
26 | selectModel.setCellSelectionEnabled(true);
27 | var rowIndex = getTableRow().getIndex();
28 | selectModel.select(rowIndex, getTableColumn());
29 | });
30 | }
31 |
32 | @Override
33 | public void updateItem(String item, boolean empty) {
34 | super.updateItem(item, empty);
35 | var status = (empty || getTableColumn() == null || getTableRow() == null);
36 | if (status) {
37 | setText(null);
38 | return;
39 | }
40 | var value = item;
41 | var table = (CustomTableView) getTableView();
42 | var styleClass = getStyleClass();
43 | if (item.equals(NULL_TAG)) {
44 | value = table.getTableSetting().getNulValue();
45 | if (!styleClass.contains(NULL_STYLE)) {
46 | styleClass.add(NULL_STYLE);
47 | }
48 | } else {
49 | styleClass.remove(NULL_STYLE);
50 | }
51 | setText(value);
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/app/src/main/java/cn/navigational/dbfx/controls/table/IndexTableCell.java:
--------------------------------------------------------------------------------
1 | package cn.navigational.dbfx.controls.table;
2 |
3 | import javafx.beans.property.StringProperty;
4 | import javafx.collections.ObservableList;
5 | import javafx.scene.control.TableCell;
6 | import javafx.scene.input.MouseEvent;
7 |
8 | /**
9 | * Index table cell
10 | *
11 | * @author yangkui
12 | * @since 1.0
13 | */
14 | public class IndexTableCell extends TableCell, String> {
15 | public IndexTableCell() {
16 | addEventHandler(MouseEvent.MOUSE_CLICKED, event -> {
17 | if (isEmpty() || getTableRow() == null) {
18 | return;
19 | }
20 | var selectionModel = getTableView().getSelectionModel();
21 | selectionModel.setCellSelectionEnabled(false);
22 | selectionModel.select(getTableRow().getIndex());
23 | });
24 | }
25 |
26 | @Override
27 | protected void updateItem(String item, boolean empty) {
28 | super.updateItem(item, empty);
29 | if (empty || getTableRow() == null) {
30 | setText(null);
31 | return;
32 | }
33 | setText(String.valueOf(getTableRow().getIndex() + 1));
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/app/src/main/java/cn/navigational/dbfx/controls/tree/TreeItemMenuHandler.java:
--------------------------------------------------------------------------------
1 | package cn.navigational.dbfx.controls.tree;
2 |
3 | /**
4 | * {@link AbstractBaseTreeItem} menu handler
5 | *
6 | * @author yangkui
7 | * @since 1.0
8 | */
9 | public interface TreeItemMenuHandler {
10 | /**
11 | * {@link javafx.scene.control.TreeItem} current support menu
12 | */
13 | enum MenuAction {
14 | /**
15 | * FLUSH
16 | */
17 | FLUSH,
18 | /**
19 | * Open terminal
20 | */
21 | OPEN_TERMINAL,
22 | /**
23 | * Edit connect
24 | */
25 | EDIT_CONNECT,
26 | /**
27 | * Open connection
28 | */
29 | OPEN_CONNECT,
30 | /**
31 | * Delete a connect
32 | */
33 | DELETE_CONNECT,
34 | /**
35 | * Discount connect
36 | */
37 | DISCOUNT_CONNECT,
38 | /**
39 | * Create copy
40 | */
41 | CREATE_COPY,
42 | /**
43 | * Edit table
44 | */
45 | EDIT_TABLE,
46 | /**
47 | * Export data
48 | */
49 | EXPORT_DATA_TO_FILE
50 | }
51 |
52 | /**
53 | * When any {@link javafx.scene.control.MenuItem} has clicked callback that method.
54 | *
55 | * @param action Some action
56 | */
57 | void onAction(MenuAction action);
58 | }
59 |
--------------------------------------------------------------------------------
/app/src/main/java/cn/navigational/dbfx/controls/tree/impl/ProgressTreeItem.java:
--------------------------------------------------------------------------------
1 | package cn.navigational.dbfx.controls.tree.impl;
2 |
3 | import cn.navigational.dbfx.controls.tree.AbstractBaseTreeItem;
4 | import javafx.application.Platform;
5 | import javafx.beans.property.BooleanProperty;
6 | import javafx.beans.property.SimpleBooleanProperty;
7 | import javafx.beans.value.ChangeListener;
8 | import javafx.scene.Node;
9 | import javafx.scene.control.ProgressIndicator;
10 |
11 |
12 | /**
13 | * Progress TreeItem
14 | *
15 | * @author yangkui
16 | * @since 1.0
17 | */
18 | public abstract class ProgressTreeItem extends AbstractBaseTreeItem {
19 | /**
20 | * Load status
21 | */
22 | protected final BooleanProperty loadStatus;
23 | /**
24 | * Load status show suffix graphic
25 | */
26 | private final ProgressIndicator indicator;
27 | /**
28 | * Load status change listener
29 | */
30 | private final ChangeListener statusListener;
31 | /**
32 | * Prefix graphic
33 | */
34 | private final Node prefixGra;
35 |
36 | public ProgressTreeItem(Node prefixGra) {
37 | this.prefixGra = prefixGra;
38 | this.setPrefixGra(prefixGra);
39 | this.statusListener = statusChange();
40 | this.indicator = new ProgressIndicator();
41 | this.loadStatus = new SimpleBooleanProperty(null, "loadStatus", false);
42 | this.loadStatus.addListener(this.statusListener);
43 | }
44 |
45 | /**
46 | * Load status change callback that method
47 | *
48 | * @return {@link ChangeListener}
49 | */
50 | private ChangeListener statusChange() {
51 | return ((observable, oldValue, newValue) -> {
52 | final Node node;
53 | if (newValue) {
54 | node = indicator;
55 | } else {
56 | node = prefixGra;
57 | }
58 | Platform.runLater(() -> setPrefixGra(node));
59 | });
60 | }
61 |
62 | @Override
63 | public void dispose() {
64 | super.dispose();
65 | this.loadStatus.removeListener(this.statusListener);
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/app/src/main/java/cn/navigational/dbfx/dialog/SimpleConfirmDialog.java:
--------------------------------------------------------------------------------
1 | package cn.navigational.dbfx.dialog;
2 |
3 | import cn.navigational.dbfx.tool.svg.SvgImageTranscoder;
4 | import javafx.scene.control.*;
5 | import javafx.scene.image.Image;
6 | import javafx.scene.image.ImageView;
7 | import javafx.scene.layout.HBox;
8 |
9 | import static cn.navigational.dbfx.config.AppConstantsKt.APP_STYLE;
10 | import static cn.navigational.dbfx.config.AppConstantsKt.INFO_ICON;
11 |
12 | /**
13 | * Show a confirm dialog
14 | *
15 | * @author yangkui
16 | * @since 1.0
17 | */
18 | public class SimpleConfirmDialog extends Alert {
19 | /**
20 | * Info icon
21 | */
22 | private static final Image INFO_IMAGE = SvgImageTranscoder.svgToImage(INFO_ICON);
23 | /**
24 | * Default css class name
25 | */
26 | private static final String DEFAULT_STYLE_CSS = "confirm-alert";
27 |
28 | public SimpleConfirmDialog(String content) {
29 | super(AlertType.CONFIRMATION);
30 |
31 | this.setGraphic(null);
32 | this.setHeaderText(null);
33 | this.setContentText(null);
34 |
35 | var hBox = new HBox();
36 | var label = new Label(content);
37 | var icon = new ImageView(INFO_IMAGE);
38 |
39 | getDialogPane().setContent(hBox);
40 | hBox.getChildren().addAll(icon, label);
41 | getDialogPane().getStylesheets().add(APP_STYLE);
42 | getDialogPane().getStyleClass().add(DEFAULT_STYLE_CSS);
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/app/src/main/java/cn/navigational/dbfx/editor/EditorPlatform.java:
--------------------------------------------------------------------------------
1 | package cn.navigational.dbfx.editor;
2 |
3 | import cn.navigational.dbfx.kit.utils.OssUtils;
4 |
5 | import java.io.File;
6 | import java.util.Locale;
7 |
8 | public class EditorPlatform {
9 | /**
10 | * Application name
11 | */
12 | public static final String APP_NAME = "dbfx";
13 | /**
14 | * Current os name
15 | */
16 | private static final String OS_NAME = OssUtils.getOsName().toLowerCase(Locale.ROOT);
17 | /**
18 | * True if current platform is running Linux.
19 | */
20 | public static final boolean IS_LINUX = OS_NAME.contains("linux");
21 |
22 | /**
23 | * True if current platform is running Mac OS X.
24 | */
25 | public static final boolean IS_MAC = OS_NAME.contains("mac");
26 |
27 | /**
28 | * True if current platform is running Windows.
29 | */
30 | public static final boolean IS_WINDOWS = OS_NAME.contains("windows");
31 | /**
32 | * Application log file direction
33 | */
34 | public static final String APP_LOG_PATH = OssUtils.getUserHome() + File.separator + APP_NAME + File.separator + "logs" + File.separator;
35 |
36 | /**
37 | * Returns true if the jvm is running with assertions enabled.
38 | *
39 | * @return true if the jvm is running with assertions enabled.
40 | */
41 | public static boolean isAssertionEnabled() {
42 | return EditorPlatform.class.desiredAssertionStatus();
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/app/src/main/java/cn/navigational/dbfx/handler/DataTableCellEditHandler.java:
--------------------------------------------------------------------------------
1 | package cn.navigational.dbfx.handler;
2 |
3 | import cn.navigational.dbfx.kit.enums.DataType;
4 | import javafx.scene.Node;
5 | import javafx.scene.control.TextField;
6 |
7 | /**
8 | * Data table cell editor handler
9 | *
10 | * @author yangkui
11 | * @since 1.0
12 | */
13 | public class DataTableCellEditHandler {
14 | private final Node graphics;
15 | private final DataType dataType;
16 |
17 | private DataTableCellEditHandler(DataType dataType) {
18 | this.dataType = dataType;
19 | this.graphics = new TextField();
20 | }
21 |
22 | public Node getEditor() {
23 | return graphics;
24 | }
25 |
26 | public static DataTableCellEditHandler getEditorHandler(DataType type) {
27 | return new DataTableCellEditHandler(type);
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/app/src/main/java/cn/navigational/dbfx/i18n/I18N.java:
--------------------------------------------------------------------------------
1 | package cn.navigational.dbfx.i18n;
2 |
3 |
4 | import java.text.MessageFormat;
5 | import java.util.ResourceBundle;
6 |
7 | public class I18N {
8 |
9 | private static ResourceBundle bundle;
10 |
11 | private static final String PACKAGE_NAME = "i18n";
12 |
13 | private static final ResourceBundle.Control UTF_ENCODING_CONTROL = new I18NControl();
14 |
15 | public static String getString(String key) {
16 | return getBundle().getString(key);
17 | }
18 |
19 | public static String getString(String key, Object... arguments) {
20 | final String pattern = getString(key);
21 | return MessageFormat.format(pattern, arguments);
22 | }
23 |
24 | public static synchronized ResourceBundle getBundle() {
25 | if (bundle == null) {
26 | bundle = ResourceBundle.getBundle(PACKAGE_NAME + ".dbfx", UTF_ENCODING_CONTROL);
27 | }
28 | return bundle;
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/app/src/main/java/cn/navigational/dbfx/i18n/I18NControl.java:
--------------------------------------------------------------------------------
1 | package cn.navigational.dbfx.i18n;
2 |
3 | import org.slf4j.Logger;
4 | import org.slf4j.LoggerFactory;
5 |
6 | import java.io.BufferedReader;
7 | import java.io.IOException;
8 | import java.io.InputStreamReader;
9 | import java.nio.charset.StandardCharsets;
10 | import java.util.Locale;
11 | import java.util.PropertyResourceBundle;
12 | import java.util.ResourceBundle;
13 |
14 | public class I18NControl extends ResourceBundle.Control {
15 | @Override
16 | public ResourceBundle newBundle(String baseName, Locale locale, String format, ClassLoader loader, boolean reload) {
17 | var bundleName = toBundleName(baseName, locale);
18 | var resourceName = toResourceName(bundleName, "properties");
19 | try (var is = loader.getResourceAsStream(resourceName)) {
20 | try (var isr = new InputStreamReader(is, StandardCharsets.UTF_8);
21 | var reader = new BufferedReader(isr)) {
22 | return new PropertyResourceBundle(reader);
23 | }
24 | } catch (IOException ex) {
25 | return null;
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/app/src/main/java/cn/navigational/dbfx/model/DatabaseMeta.java:
--------------------------------------------------------------------------------
1 | package cn.navigational.dbfx.model;
2 |
3 | /**
4 | * Database meta data
5 | *
6 | * @author yangkui
7 | * @since 1.0
8 | */
9 | public class DatabaseMeta {
10 | /**
11 | * DB Name
12 | */
13 | private String name;
14 | /**
15 | * Current is support
16 | */
17 | private Boolean support;
18 | /**
19 | * DB icon
20 | */
21 | private String icon;
22 | /**
23 | * DB default port
24 | */
25 | private Integer port;
26 | /**
27 | * Default select database
28 | */
29 | private String database;
30 | /**
31 | * Default username
32 | */
33 | private String username;
34 |
35 | public String getName() {
36 | return name;
37 | }
38 |
39 | public void setName(String name) {
40 | this.name = name;
41 | }
42 |
43 | public Boolean getSupport() {
44 | return support;
45 | }
46 |
47 | public void setSupport(Boolean support) {
48 | this.support = support;
49 | }
50 |
51 | public String getIcon() {
52 | return icon;
53 | }
54 |
55 | public void setIcon(String icon) {
56 | this.icon = icon;
57 | }
58 |
59 | public Integer getPort() {
60 | return port;
61 | }
62 |
63 | public void setPort(Integer port) {
64 | this.port = port;
65 | }
66 |
67 | public String getDatabase() {
68 | return database;
69 | }
70 |
71 | public void setDatabase(String database) {
72 | this.database = database;
73 | }
74 |
75 | public String getUsername() {
76 | return username;
77 | }
78 |
79 | public void setUsername(String username) {
80 | this.username = username;
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/app/src/main/java/cn/navigational/dbfx/model/Manifest.java:
--------------------------------------------------------------------------------
1 | package cn.navigational.dbfx.model;
2 |
3 | public class Manifest {
4 | private String name;
5 | private String version;
6 | private String author;
7 | private String website;
8 | private String buildTime;
9 | private String copyright;
10 |
11 | public String getName() {
12 | return name;
13 | }
14 |
15 | public void setName(String name) {
16 | this.name = name;
17 | }
18 |
19 | public String getVersion() {
20 | return version;
21 | }
22 |
23 | public void setVersion(String version) {
24 | this.version = version;
25 | }
26 |
27 | public String getAuthor() {
28 | return author;
29 | }
30 |
31 | public void setAuthor(String author) {
32 | this.author = author;
33 | }
34 |
35 | public String getWebsite() {
36 | return website;
37 | }
38 |
39 | public void setWebsite(String website) {
40 | this.website = website;
41 | }
42 |
43 | public String getBuildTime() {
44 | return buildTime;
45 | }
46 |
47 | public void setBuildTime(String buildTime) {
48 | this.buildTime = buildTime;
49 | }
50 |
51 | public String getCopyright() {
52 | return copyright;
53 | }
54 |
55 | public void setCopyright(String copyright) {
56 | this.copyright = copyright;
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/app/src/main/java/cn/navigational/dbfx/model/SQLClient.java:
--------------------------------------------------------------------------------
1 | package cn.navigational.dbfx.model;
2 |
3 | import cn.navigational.dbfx.kit.enums.Clients;
4 | import io.vertx.sqlclient.Pool;
5 |
6 | import java.net.FileNameMap;
7 |
8 | import static cn.navigational.dbfx.config.AppConstantsKt.MYSQL_ICON;
9 | import static cn.navigational.dbfx.config.AppConstantsKt.PG_ICON;
10 |
11 | /**
12 | * For running sql client package
13 | *
14 | * @author yangkui
15 | * @since 1.0
16 | */
17 | public class SQLClient {
18 | /**
19 | * Current client id
20 | */
21 | private String uuid;
22 | /**
23 | * Current database info
24 | */
25 | private DbInfo dbInfo;
26 | /**
27 | * Sql client info
28 | */
29 | private Pool client;
30 | /**
31 | * Current database version
32 | */
33 | private String version;
34 | /**
35 | * {@link Clients}
36 | */
37 | private Clients cl;
38 |
39 | public String getUuid() {
40 | return uuid;
41 | }
42 |
43 | public void setUuid(String uuid) {
44 | this.uuid = uuid;
45 | }
46 |
47 | public DbInfo getDbInfo() {
48 | return dbInfo;
49 | }
50 |
51 | public void setDbInfo(DbInfo dbInfo) {
52 | this.dbInfo = dbInfo;
53 | }
54 |
55 | public Pool getClient() {
56 | return client;
57 | }
58 |
59 | public void setClient(Pool client) {
60 | this.client = client;
61 | }
62 |
63 | public String getVersion() {
64 | return version;
65 | }
66 |
67 | public void setVersion(String version) {
68 | this.version = version;
69 | }
70 |
71 | public Clients getCl() {
72 | return cl;
73 | }
74 |
75 | public void setCl(Clients cl) {
76 | this.cl = cl;
77 | }
78 |
79 | public static String getMiniIcon(Clients cl) {
80 | final String mini;
81 | if (cl == Clients.MYSQL) {
82 | mini = MYSQL_ICON;
83 | } else {
84 | mini = PG_ICON;
85 | }
86 | return mini;
87 | }
88 | }
89 |
--------------------------------------------------------------------------------
/app/src/main/java/cn/navigational/dbfx/model/TableSetting.java:
--------------------------------------------------------------------------------
1 | package cn.navigational.dbfx.model;
2 |
3 | import static cn.navigational.dbfx.kit.config.ConstantsKt.NULL_VALUE;
4 |
5 | /**
6 | * Table setting
7 | *
8 | * @author yangkui
9 | * @since 1.0
10 | */
11 | public class TableSetting {
12 | /**
13 | * Global save?
14 | */
15 | private boolean global = false;
16 | /**
17 | * Default value show value
18 | */
19 | private String nulValue = NULL_VALUE;
20 | /**
21 | * Default date time format pattern
22 | */
23 | private String dtFormat = "yyyy-MM-dd HH:mm:ss";
24 |
25 | public String getDtFormat() {
26 | return dtFormat;
27 | }
28 |
29 | public void setDtFormat(String dtFormat) {
30 | this.dtFormat = dtFormat;
31 | }
32 |
33 | public String getNulValue() {
34 | return nulValue;
35 | }
36 |
37 | public void setNulValue(String nulValue) {
38 | this.nulValue = nulValue;
39 | }
40 |
41 | public boolean isGlobal() {
42 | return global;
43 | }
44 |
45 | public void setGlobal(boolean global) {
46 | this.global = global;
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/app/src/main/java/cn/navigational/dbfx/security/AseAlgorithm.java:
--------------------------------------------------------------------------------
1 | package cn.navigational.dbfx.security;
2 |
3 | import org.apache.commons.codec.binary.Base64;
4 |
5 | import javax.crypto.*;
6 | import javax.crypto.spec.SecretKeySpec;
7 | import java.nio.charset.StandardCharsets;
8 | import java.security.NoSuchAlgorithmException;
9 | import java.security.SecureRandom;
10 |
11 | /**
12 | * Ase algorithm encode or decode
13 | *
14 | * @author yangkui
15 | * @since 1.0
16 | */
17 | public class AseAlgorithm {
18 | private static final String KEY_ALGORITHM = "AES";
19 | /**
20 | * 默认的加密算法
21 | */
22 | private static final String DEFAULT_CIPHER_ALGORITHM = "AES/ECB/PKCS5Padding";
23 |
24 | /**
25 | * AES 加密操作
26 | *
27 | * @param content 待加密内容
28 | * @param key 密钥
29 | * @return 返回Base64转码后的加密数据
30 | */
31 | public static String encrypt(String content, String key) throws Exception {
32 | var cipher = Cipher.getInstance(DEFAULT_CIPHER_ALGORITHM);
33 | var byteContent = content.getBytes(StandardCharsets.UTF_8);
34 | cipher.init(Cipher.ENCRYPT_MODE, getSecretKey(key));
35 | var result = cipher.doFinal(byteContent);
36 | return Base64.encodeBase64String(result);
37 | }
38 |
39 | /**
40 | * AES 解密操作
41 | *
42 | * @param content 待解密内容
43 | * @param key 密钥
44 | * @throws Exception {@inheritDoc}
45 | */
46 | public static String decrypt(String content, String key) throws Exception {
47 | var cipher = Cipher.getInstance(DEFAULT_CIPHER_ALGORITHM);
48 | cipher.init(Cipher.DECRYPT_MODE, getSecretKey(key));
49 | var result = cipher.doFinal(Base64.decodeBase64(content));
50 | return new String(result, StandardCharsets.UTF_8);
51 |
52 | }
53 |
54 | /**
55 | * 生成加密秘钥
56 | *
57 | * @return {@link SecretKeySpec}
58 | * @throws NoSuchAlgorithmException {@inheritDoc}
59 | */
60 | private static SecretKeySpec getSecretKey(final String key) throws NoSuchAlgorithmException {
61 | var kg = KeyGenerator.getInstance(KEY_ALGORITHM);
62 | var secureRandom = SecureRandom.getInstance("SHA1PRNG");
63 | secureRandom.setSeed(key.getBytes());
64 | kg.init(128, secureRandom);
65 | var secretKey = kg.generateKey();
66 | return new SecretKeySpec(secretKey.getEncoded(), KEY_ALGORITHM);
67 | }
68 |
69 | }
70 |
--------------------------------------------------------------------------------
/app/src/main/java/cn/navigational/dbfx/tool/export/DataExportFactory.java:
--------------------------------------------------------------------------------
1 | package cn.navigational.dbfx.tool.export;
2 |
3 | /**
4 | * Data export factory
5 | *
6 | * @author yangkui
7 | * @since 1.0
8 | */
9 | public class DataExportFactory {
10 | public enum ExportFormat {
11 | /**
12 | * Json file
13 | */
14 | JSON("JSON", "json"),
15 | /**
16 | * Excel file
17 | */
18 | EXCEL("Excel", "xlsx"),
19 | /**
20 | * XML file
21 | */
22 | XML("XML", "xml"),
23 | /**
24 | * CSV file
25 | */
26 | CSV("CSV", "csv"),
27 | /**
28 | * Sql inserts file
29 | */
30 | SQL_INSERT("SQL Inserts", "sql"),
31 | /**
32 | * Sql update file
33 | */
34 | SQL_UPDATE("SQL Updates", "sql");
35 | /**
36 | * Format name
37 | */
38 | private final String name;
39 | /**
40 | * File suffix format
41 | */
42 | private final String format;
43 |
44 | ExportFormat(String name, String format) {
45 | this.name = name;
46 | this.format = format;
47 | }
48 |
49 | public String getName() {
50 | return name;
51 | }
52 |
53 | public String getFormat() {
54 | return format;
55 | }
56 | }
57 |
58 | public static ExportFormat getExFormat(String f) {
59 | ExportFormat format = null;
60 | for (ExportFormat value : ExportFormat.values()) {
61 | if (f.equals(value.name)) {
62 | format = value;
63 | break;
64 | }
65 | }
66 | return format;
67 | }
68 |
69 | public static String getFormat(String f) {
70 | var ex = getExFormat(f);
71 | return ex.format;
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/app/src/main/java/cn/navigational/dbfx/tool/svg/SvgImageTranscoder.java:
--------------------------------------------------------------------------------
1 | package cn.navigational.dbfx.tool.svg;
2 |
3 | import javafx.embed.swing.SwingFXUtils;
4 | import javafx.scene.image.Image;
5 | import javafx.scene.image.ImageView;
6 | import org.apache.batik.transcoder.TranscoderException;
7 | import org.apache.batik.transcoder.TranscoderInput;
8 | import org.apache.batik.transcoder.TranscoderOutput;
9 | import org.apache.batik.transcoder.image.ImageTranscoder;
10 |
11 | import java.awt.image.BufferedImage;
12 |
13 | /**
14 | * A tool for svg transform to Javafx image
15 | *
16 | * @author yangkui
17 | * @since 1.0
18 | */
19 | public class SvgImageTranscoder extends ImageTranscoder {
20 | private BufferedImage img = null;
21 |
22 | @Override
23 | public BufferedImage createImage(int width, int height) {
24 | return new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
25 | }
26 |
27 | @Override
28 | public void writeImage(BufferedImage img, TranscoderOutput output) {
29 | this.img = img;
30 | }
31 |
32 | public BufferedImage getImg() {
33 | return img;
34 | }
35 |
36 | /**
37 | * Svg picture transform to Javafx Image object
38 | *
39 | * @param url Target path
40 | * @return {@link Image} Javafx Image object
41 | */
42 | public static Image svgToImage(String url) {
43 | var transcoder = new SvgImageTranscoder();
44 | var in = ClassLoader.getSystemResourceAsStream(url);
45 | var transIn = new TranscoderInput(in);
46 | try {
47 | transcoder.transcode(transIn, null);
48 | } catch (TranscoderException e) {
49 | throw new RuntimeException(e);
50 | }
51 | return SwingFXUtils.toFXImage(transcoder.getImg(), null);
52 | }
53 |
54 | /**
55 | * Svg picture transform to Javafx ImageView
56 | *
57 | * @param url Target path
58 | * @return {@link ImageView}
59 | */
60 | public static ImageView svgToImageView(String url) {
61 | var image = svgToImage(url);
62 | return new ImageView(image);
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/app/src/main/java/cn/navigational/dbfx/utils/AppSettings.java:
--------------------------------------------------------------------------------
1 | package cn.navigational.dbfx.utils;
2 |
3 | import cn.navigational.dbfx.model.Manifest;
4 | import cn.navigational.dbfx.model.TableSetting;
5 |
6 | /**
7 | * dbfx app setting
8 | *
9 | * @author yangkui
10 | * @since 1.0
11 | */
12 | public class AppSettings {
13 | /**
14 | * MANIFEST.MF file
15 | */
16 | private Manifest manifest;
17 | /**
18 | * Application table data setting
19 | */
20 | private TableSetting tableSetting;
21 |
22 | private static AppSettings appSettings = new AppSettings();
23 |
24 | public TableSetting getTableSetting() {
25 | return tableSetting;
26 | }
27 |
28 | public void setTableSetting(TableSetting tableSetting) {
29 | this.tableSetting = tableSetting;
30 | }
31 |
32 | public Manifest getManifest() {
33 | return manifest;
34 | }
35 |
36 | public void setManifest(Manifest manifest) {
37 | this.manifest = manifest;
38 | }
39 |
40 | public static AppSettings getAppSettings() {
41 | return appSettings;
42 | }
43 |
44 | public static synchronized void setAppSettings(AppSettings settings) {
45 | AppSettings.appSettings = settings;
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/app/src/main/java/cn/navigational/dbfx/utils/DateUtils.java:
--------------------------------------------------------------------------------
1 | package cn.navigational.dbfx.utils;
2 |
3 | import java.time.LocalDateTime;
4 | import java.time.format.DateTimeFormatter;
5 | import java.util.Objects;
6 |
7 | public class DateUtils {
8 | /**
9 | * Format local time according by fix format
10 | *
11 | * @param localDateTime Target localDateTime
12 | * @param format Format str
13 | * @return Format after local time str
14 | */
15 | public static String formatLocalTime(LocalDateTime localDateTime, String format) {
16 | Objects.requireNonNull(format);
17 | Objects.requireNonNull(localDateTime);
18 | var formatter = DateTimeFormatter.ofPattern(format);
19 | return localDateTime.format(formatter);
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/app/src/main/java/cn/navigational/dbfx/utils/FileMutex.java:
--------------------------------------------------------------------------------
1 | package cn.navigational.dbfx.utils;
2 |
3 | import java.io.IOException;
4 | import java.io.RandomAccessFile;
5 | import java.nio.channels.FileLock;
6 | import java.nio.file.FileAlreadyExistsException;
7 | import java.nio.file.Files;
8 | import java.nio.file.Path;
9 | import java.util.Timer;
10 | import java.util.TimerTask;
11 |
12 | /**
13 | * This class implements a mutex using FileLock.
14 | * Two processes which want to be in mutual exclusion should:
15 | * 1) create an instance of FileMutex using the same file
16 | * 2) call FileMutex.lock() or FileMutex.tryLock()
17 | */
18 | class FileMutex {
19 |
20 | private final Path lockFile;
21 | private RandomAccessFile lockRAF;
22 | private FileLock lock;
23 |
24 | public FileMutex(Path lockFile) {
25 | assert lockFile != null;
26 | this.lockFile = lockFile;
27 | }
28 |
29 | public Path getLockFile() {
30 | return lockFile;
31 | }
32 |
33 | public void lock(long timeout) throws IOException {
34 | assert lockRAF == null;
35 | assert lock == null;
36 |
37 | createFileChannel();
38 | assert lockRAF != null;
39 | final Timer timer = new Timer();
40 | timer.schedule(new InterruptTask(), timeout);
41 | lock = lockRAF.getChannel().lock();
42 | timer.cancel();
43 | assert lock != null;
44 | }
45 |
46 | public boolean tryLock() throws IOException {
47 | assert lockRAF == null;
48 | assert lock == null;
49 |
50 | createFileChannel();
51 | assert lockRAF != null;
52 | lock = lockRAF.getChannel().tryLock();
53 | if (lock == null) {
54 | lockRAF.close();
55 | lockRAF = null;
56 | }
57 |
58 | return lock != null;
59 | }
60 |
61 | public void unlock() throws IOException {
62 | assert lockRAF != null;
63 | assert lock != null;
64 | assert lock.channel() == lockRAF.getChannel();
65 |
66 | lock.release();
67 | lock = null;
68 | lockRAF.close();
69 | lockRAF = null;
70 | }
71 |
72 | public boolean isLocked() {
73 | return lock != null;
74 | }
75 |
76 |
77 | /*
78 | * Private
79 | */
80 |
81 | private void createFileChannel() throws IOException {
82 | try {
83 | Files.createFile(lockFile);
84 | } catch (FileAlreadyExistsException x) {
85 | // Someone else already created it
86 | }
87 | lockRAF = new RandomAccessFile(lockFile.toFile(), "rw");
88 | }
89 |
90 | private static class InterruptTask extends TimerTask {
91 | @Override
92 | public void run() {
93 | Thread.currentThread().interrupt();
94 | }
95 | }
96 | }
--------------------------------------------------------------------------------
/app/src/main/java/cn/navigational/dbfx/utils/SqlConsoleAppender.java:
--------------------------------------------------------------------------------
1 | package cn.navigational.dbfx.utils;
2 |
3 | import ch.qos.logback.core.OutputStreamAppender;
4 | import cn.navigational.dbfx.controller.LogController;
5 |
6 |
7 | /**
8 | * Custom log output target
9 | *
10 | * @param
11 | * @author yangkui
12 | * @since 1.0
13 | */
14 | public class SqlConsoleAppender extends OutputStreamAppender {
15 |
16 | private final LogController target = LogController.Companion.getLogController();
17 |
18 | @Override
19 | public void start() {
20 | var stream = target.getOutput();
21 | if (target.getListenerLog()) {
22 | setOutputStream(stream);
23 | }
24 | super.start();
25 | }
26 |
27 |
28 | /**
29 | * Returns the current value of the target property. The default value
30 | * of the option is {@link LogController}.
31 | *
32 | */
33 | public String getTarget() {
34 | return target.getClass().getName();
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/app/src/main/java/cn/navigational/dbfx/utils/TableColumnUtils.java:
--------------------------------------------------------------------------------
1 | package cn.navigational.dbfx.utils;
2 |
3 | import cn.navigational.dbfx.controls.table.CustomTableColumn;
4 | import cn.navigational.dbfx.controls.table.CustomTableView;
5 | import cn.navigational.dbfx.kit.enums.DataType;
6 | import cn.navigational.dbfx.kit.model.TableColumnMeta;
7 | import javafx.application.Platform;
8 |
9 | import java.util.ArrayList;
10 | import java.util.List;
11 | import java.util.stream.Collectors;
12 |
13 | /**
14 | * TableColumn utils
15 | *
16 | * @author yangkui
17 | * @since 1.0
18 | */
19 | public class TableColumnUtils {
20 | /**
21 | * Create table data column
22 | *
23 | * @param metas database table column meta data
24 | * @return return {@link CustomTableColumn} list
25 | */
26 | public static List createTableDataColumn(List metas) {
27 | var columns = new ArrayList();
28 | for (TableColumnMeta meta : metas) {
29 | var column = createTableDataColumn(meta);
30 | columns.add(column);
31 | }
32 | return columns;
33 | }
34 |
35 | /**
36 | * Create single {@link CustomTableColumn} instance object
37 | *
38 | * @param meta Table meta data
39 | * @return {@link CustomTableColumn}
40 | */
41 | public static CustomTableColumn createTableDataColumn(TableColumnMeta meta) {
42 | var column = new CustomTableColumn(meta);
43 | column.setCellValueFactory(cellDataFeatures -> {
44 | var tableView = cellDataFeatures.getTableView();
45 | var tableColumn = cellDataFeatures.getTableColumn();
46 | var columnIndex = tableView.getColumns().indexOf(tableColumn);
47 | return cellDataFeatures.getValue().get(columnIndex - 1);
48 | });
49 | return column;
50 | }
51 |
52 | public static void createTableColumns(CustomTableView tableView, List columnNames) {
53 | var metas = TableColumnMeta.createDefaultTableColumnMeta(columnNames);
54 | Platform.runLater(() -> {
55 | var columns = tableView.getColumns();
56 | var length = columns.size();
57 | if (length > 1) {
58 | tableView.getColumns().remove(1, length);
59 | }
60 | columns.addAll(createTableDataColumn(metas));
61 | });
62 | }
63 | }
--------------------------------------------------------------------------------
/app/src/main/java/cn/navigational/dbfx/view/AboutViewController.java:
--------------------------------------------------------------------------------
1 | package cn.navigational.dbfx.view;
2 |
3 | import cn.navigational.dbfx.ViewController;
4 |
5 | import cn.navigational.dbfx.i18n.I18N;
6 | import cn.navigational.dbfx.tool.svg.SvgImageTranscoder;
7 | import cn.navigational.dbfx.utils.AppSettings;
8 | import javafx.fxml.FXML;
9 | import javafx.scene.control.Button;
10 | import javafx.scene.control.Label;
11 | import javafx.scene.image.ImageView;
12 | import javafx.scene.layout.BorderPane;
13 | import javafx.stage.Modality;
14 | import javafx.stage.StageStyle;
15 |
16 | import java.lang.management.ManagementFactory;
17 | import java.lang.management.RuntimeMXBean;
18 |
19 | import static cn.navigational.dbfx.config.AppConstantsKt.APP_ICON;
20 | import static cn.navigational.dbfx.config.AppConstantsKt.DIALOG_CLOSE_ICON;
21 | import static cn.navigational.dbfx.config.ViewPathKt.ABOUT_PAGE;
22 |
23 | /**
24 | * Application about view
25 | *
26 | * @author yangkui
27 | * @since 1.0
28 | */
29 | public class AboutViewController extends ViewController {
30 | @FXML
31 | private Label vm;
32 | @FXML
33 | private Label bTime;
34 | @FXML
35 | private Button close;
36 | @FXML
37 | private Label version;
38 | @FXML
39 | private Label runtime;
40 | @FXML
41 | private ImageView icon;
42 | @FXML
43 | private Label copyright;
44 |
45 | private static final RuntimeMXBean RUNTIME = ManagementFactory.getRuntimeMXBean();
46 |
47 |
48 | public AboutViewController() {
49 | super(ABOUT_PAGE);
50 | this.getStage().setAlwaysOnTop(true);
51 | this.getStage().initStyle(StageStyle.UNDECORATED);
52 | this.getStage().initModality(Modality.APPLICATION_MODAL);
53 | this.close.setOnAction(event -> this.getStage().close());
54 | this.runtime.setText(I18N.getString("about.options.runtime.version", RUNTIME.getVmVersion()));
55 | this.vm.setText("VM: " + RUNTIME.getVmName() + " by " + RUNTIME.getVmVendor());
56 | this.icon.setImage(SvgImageTranscoder.svgToImage(APP_ICON));
57 | this.close.setGraphic(SvgImageTranscoder.svgToImageView(DIALOG_CLOSE_ICON));
58 | }
59 |
60 | /**
61 | * Load MANIFEST.MF file content render some applicarion info
62 | */
63 | private void initLocalInfo() {
64 | var manifest = AppSettings.getAppSettings().getManifest();
65 | this.version.setText("V " + manifest.getVersion());
66 | this.copyright.setText(manifest.getCopyright());
67 | this.bTime.setText(I18N.getString("about.options.build.time", manifest.getBuildTime()));
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/app/src/main/kotlin/cn/navigational/dbfx/DatabaseMetaManager.kt:
--------------------------------------------------------------------------------
1 | package cn.navigational.dbfx
2 |
3 | import cn.navigational.dbfx.kit.enums.Clients
4 | import cn.navigational.dbfx.model.DatabaseMeta
5 |
6 | /**
7 | *
8 | *Current support sql client meta data manager
9 | *
10 | * @author yangkui
11 | * @since 1.0
12 | */
13 | class DatabaseMetaManager {
14 | companion object {
15 | private val metas: ArrayList = arrayListOf()
16 |
17 | /**
18 | *
19 | * Get origin database meta
20 | * @param client Current client
21 | */
22 | fun getDbMeta(client: Clients): DatabaseMeta {
23 | for (meta in metas) {
24 | val cl = Clients.getClient(meta.name)
25 | if (cl == client) {
26 | return meta
27 | }
28 | }
29 | throw RuntimeException("Not found $client database meta!")
30 | }
31 |
32 | fun addDbMeta(ms: ArrayList) {
33 | this.metas.addAll(ms)
34 | }
35 |
36 | fun getMetas(): List {
37 | return this.metas
38 | }
39 | }
40 | }
--------------------------------------------------------------------------------
/app/src/main/kotlin/cn/navigational/dbfx/config/ControllerPath.kt:
--------------------------------------------------------------------------------
1 | package cn.navigational.dbfx.config
2 |
3 | const val TABLE_VIEW = "fxml/controller/table_view.fxml"
4 | const val SQL_TERMINAL_PAGE = "fxml/controller/sql_terminal.fxml"
5 | const val CON_INFO_PANE = "fxml/controller/con_info_pane.fxml"
6 | const val TABLE_SETTING_PAGE = "fxml/dialog/table_setting_dialog_pane.fxml"
7 | const val PROGRESS_DIALOG_PANE = "fxml/dialog/progress_dialog_pane.fxml"
8 | const val B_N_EXPAND_PANE_PANE = "fxml/controller/b_expand_pane.fxml"
9 | const val B_N_TERMINAL_PANE = "fxml/controller/terminal_pane.fxml"
10 | const val B_N_LOG_PANE = "fxml/controller/log_pane.fxml"
11 | const val N_TOP_BAR = "fxml/controller/n_top_bar.fxml"
12 |
--------------------------------------------------------------------------------
/app/src/main/kotlin/cn/navigational/dbfx/config/ViewPath.kt:
--------------------------------------------------------------------------------
1 | package cn.navigational.dbfx.config
2 |
3 | const val HOME_PAGE = "fxml/home_view.fxml"
4 | const val ABOUT_PAGE= "fxml/about_view.fxml"
5 | const val SPLASH_PAGE = "fxml/splash_view.fxml"
6 | const val EXPORT_PAGE = "fxml/export_view.fxml"
7 | const val EDIT_CON_PAGE = "fxml/edit_con_view.fxml"
8 | const val CREATE_CON_PAGE = "fxml/create_con_view.fxml"
9 |
--------------------------------------------------------------------------------
/app/src/main/kotlin/cn/navigational/dbfx/controller/LogController.kt:
--------------------------------------------------------------------------------
1 | package cn.navigational.dbfx.controller
2 |
3 | import cn.navigational.dbfx.config.B_N_LOG_PANE
4 | import cn.navigational.dbfx.editor.EditorPlatform.APP_LOG_PATH
5 | import cn.navigational.dbfx.i18n.I18N
6 | import cn.navigational.dbfx.kit.utils.OssUtils
7 | import javafx.application.Platform
8 | import javafx.fxml.FXML
9 | import javafx.scene.control.MenuItem
10 | import javafx.scene.control.TextArea
11 | import javafx.scene.layout.BorderPane
12 | import java.awt.Desktop
13 | import java.io.File
14 | import java.io.OutputStream
15 | import javax.swing.SwingUtilities
16 |
17 | class LogController private constructor() : BottomNavigationExpandPaneAbstractFxmlController.ExpandPaneProvider(B_N_LOG_PANE) {
18 | //whether listener listener log output stream
19 | var listenerLog: Boolean = true
20 | private val output: OutputStream = LogConsole()
21 | private val clear: MenuItem = MenuItem(I18N.getString("expand.pane.setting.action.clear"))
22 | private val openLogDir: MenuItem = MenuItem(I18N.getString("expand.pane.setting.action.open.log.dir"))
23 |
24 | @FXML
25 | private lateinit var textArea: TextArea
26 |
27 |
28 | init {
29 | this.clear.setOnAction {
30 | this.textArea.clear()
31 | }
32 | this.openLogDir.setOnAction {
33 | OssUtils.openDirOrFileUseFileSystem(APP_LOG_PATH)
34 | }
35 | }
36 |
37 | override fun getSetting(): MutableList
42 | *
43 | */
44 | private val loadStatus: BooleanProperty = SimpleBooleanProperty(false, "loadingStatus")
45 |
46 | fun getLoadStatus(): Boolean {
47 | return loadStatus.get()
48 | }
49 |
50 | fun getLoadStatusProperty(): BooleanProperty {
51 | return loadStatus
52 | }
53 |
54 | fun setLoadStatus(status: Boolean) {
55 | this.loadStatus.set(status)
56 | }
57 |
58 | /**
59 | *
60 | * Note that the path must be unique and cannot be repeated,
61 | * because the system will take the current path as a unique identifier.
62 | * For any tab, for example, each time you open a tab,
63 | * the system will detect whether the current path exists.
64 | * If it does, the current current tab will be displayed.If not, a new tab with the
65 | * current path as the key will be put into the system cache and the tab will be displayed
66 | *
67 | */
68 | private val tabPath: StringProperty = SimpleStringProperty(null, "tabPath")
69 |
70 | fun setTabPath(tabPath: String) {
71 | this.tabPath.set(tabPath)
72 | }
73 |
74 | private fun getTabPath(): String {
75 | return tabPath.get()
76 | }
77 |
78 | fun getTabPathProperty(): StringProperty {
79 | return tabPath
80 | }
81 | }
--------------------------------------------------------------------------------
/app/src/main/kotlin/cn/navigational/dbfx/controls/tab/SQLTerminalTab.kt:
--------------------------------------------------------------------------------
1 | package cn.navigational.dbfx.controls.tab
2 |
3 | import cn.navigational.dbfx.SQLClientManager
4 | import cn.navigational.dbfx.controller.SQLTerminalController
5 | import cn.navigational.dbfx.controls.AbstractBaseTab
6 | import cn.navigational.dbfx.model.SQLClient
7 | import javafx.application.Platform
8 |
9 | class SQLTerminalTab(private val uuid: String, private val scheme: String = "") : AbstractBaseTab(SQLClient.getMiniIcon(SQLClientManager.getDbInfo(uuid).client)) {
10 |
11 | private lateinit var controller: SQLTerminalController
12 |
13 | override suspend fun init() {
14 | this.controller = SQLTerminalController(uuid, scheme)
15 | val info = SQLClientManager.getDbInfo(uuid)
16 | Platform.runLater {
17 | this.content = controller.parent
18 | this.text = "console [${scheme}@${info.host}"
19 | }
20 | }
21 |
22 | override suspend fun close() {
23 | this.controller.dispose()
24 | }
25 | }
--------------------------------------------------------------------------------
/app/src/main/kotlin/cn/navigational/dbfx/controls/tab/TableTab.kt:
--------------------------------------------------------------------------------
1 | package cn.navigational.dbfx.controls.tab
2 |
3 | import cn.navigational.dbfx.convert.RowSetConvert
4 | import cn.navigational.dbfx.config.TABLE_ICON
5 | import cn.navigational.dbfx.config.TABLE_VIEW_ICON
6 | import cn.navigational.dbfx.controller.TableViewController
7 | import cn.navigational.dbfx.controls.AbstractBaseTab
8 | import cn.navigational.dbfx.controls.tree.table.TableTreeItem
9 | import cn.navigational.dbfx.model.SQLClient
10 | import cn.navigational.dbfx.tool.svg.SvgImageTranscoder
11 | import cn.navigational.dbfx.kit.SQLQuery
12 | import cn.navigational.dbfx.kit.model.TableColumnMeta
13 | import cn.navigational.dbfx.model.TableSetting
14 | import javafx.beans.property.StringProperty
15 | import javafx.collections.ObservableList
16 |
17 |
18 | class TableTab(
19 | private val table: String,
20 | private val category: String,
21 | private val client: SQLClient, tableType: TableTreeItem.TableType) : AbstractBaseTab(), TableViewController.TableDataProvider {
22 |
23 | private val controller: TableViewController = TableViewController(this)
24 |
25 | init {
26 | val host = client.dbInfo.host
27 | this.controller.load()
28 | this.text = "$table[$host]"
29 | this.content = controller.parent
30 | this.graphic = if (tableType == TableTreeItem.TableType.BASE_TABLE) {
31 | SvgImageTranscoder.svgToImageView(TABLE_ICON)
32 | } else {
33 | SvgImageTranscoder.svgToImageView(TABLE_VIEW_ICON)
34 | }
35 | }
36 |
37 | override suspend fun init() {}
38 |
39 |
40 | override suspend fun close() {
41 | super.close()
42 | this.controller.dispose()
43 | }
44 |
45 | override suspend fun getDataTotal(): Long {
46 | return SQLQuery.getClQuery(client.cl).queryTableTotal(category, table, client.client)
47 |
48 | }
49 |
50 | override suspend fun getColumnMeta(): List {
51 | return SQLQuery.getClQuery(client.cl).showTableField(category, table, client.client)
52 | }
53 |
54 | override suspend fun getItems(pageIndex: Int, pageSize: Int, setting: TableSetting): List> {
55 | val sqlQuery = SQLQuery.getClQuery(client.cl)
56 | val list = sqlQuery.pageQuery(category, table, pageIndex, pageSize, client.client)
57 | return RowSetConvert.rowSetConvert(list, setting)
58 | }
59 | }
--------------------------------------------------------------------------------
/app/src/main/kotlin/cn/navigational/dbfx/controls/tree/RoleItem.kt:
--------------------------------------------------------------------------------
1 | package cn.navigational.dbfx.controls.tree
2 |
3 | import cn.navigational.dbfx.config.MYSQL_USER_ICON
4 | import cn.navigational.dbfx.config.PG_ROLE_ICON
5 | import cn.navigational.dbfx.kit.enums.Clients
6 | import cn.navigational.dbfx.tool.svg.SvgImageTranscoder
7 | import javafx.event.ActionEvent
8 |
9 | class RoleItem(uuid: String, name: String) : AbstractBaseTreeItem() {
10 | init {
11 | this.text = name
12 | getSqlClient(uuid).ifPresent {
13 | val str = if (it.cl == Clients.POSTGRESQL) {
14 | PG_ROLE_ICON
15 | } else {
16 | MYSQL_USER_ICON
17 | }
18 | this.prefixGra = SvgImageTranscoder.svgToImageView(str)
19 | }
20 | }
21 |
22 | override fun onAction(action: TreeItemMenuHandler.MenuAction?) {
23 | }
24 | }
--------------------------------------------------------------------------------
/app/src/main/kotlin/cn/navigational/dbfx/controls/tree/cell/NTreeCell.kt:
--------------------------------------------------------------------------------
1 | package cn.navigational.dbfx.controls.tree.cell
2 |
3 | import javafx.scene.control.ContextMenu
4 | import javafx.scene.control.TreeCell
5 |
6 | /**
7 | *
8 | * Customer {@link TreeCell}
9 | *
10 | * @author yangkui
11 | * @since 1.0
12 | */
13 | class NTreeCell : TreeCell() {
14 | override fun updateItem(item: String?, empty: Boolean) {
15 | if (empty || treeItem == null) {
16 | this.text = null
17 | this.graphic = null
18 | } else {
19 | graphic = treeItem.graphic
20 | }
21 | super.updateItem(item, empty)
22 | }
23 | }
--------------------------------------------------------------------------------
/app/src/main/kotlin/cn/navigational/dbfx/controls/tree/folder/RoleFolder.kt:
--------------------------------------------------------------------------------
1 | package cn.navigational.dbfx.controls.tree.folder
2 |
3 | import cn.navigational.dbfx.config.FOLDER_ICON
4 | import cn.navigational.dbfx.controls.tree.RoleItem
5 | import cn.navigational.dbfx.controls.tree.TreeItemMenuHandler
6 | import cn.navigational.dbfx.controls.tree.impl.ProgressTreeItem
7 | import cn.navigational.dbfx.i18n.I18N
8 | import cn.navigational.dbfx.kit.SQLQuery
9 | import cn.navigational.dbfx.kit.enums.Clients
10 | import cn.navigational.dbfx.model.DbInfo
11 | import cn.navigational.dbfx.model.SQLClient
12 | import cn.navigational.dbfx.tool.svg.SvgImageTranscoder
13 | import javafx.event.ActionEvent
14 | import kotlinx.coroutines.GlobalScope
15 | import kotlinx.coroutines.launch
16 |
17 | class RoleFolder(uuid: String, category: String? = null) : ProgressTreeItem(SvgImageTranscoder.svgToImageView(FOLDER_ICON)) {
18 | init {
19 | this.reListListener()
20 | getSqlClient(uuid).ifPresent {
21 | updateRoleInfo(it.dbInfo)
22 | initRole(it)
23 | }
24 | }
25 |
26 | private fun updateRoleInfo(info: DbInfo) {
27 | val txt = if (info.client == Clients.MYSQL) {
28 | "label.user"
29 | } else {
30 | "label.role"
31 | }
32 | this.text = I18N.getString(txt)
33 | }
34 |
35 | private fun initRole(client: SQLClient) {
36 | val query = SQLQuery.getClQuery(client.cl)
37 | GlobalScope.launch {
38 | loadStatus.set(true)
39 | try {
40 | val list = query.queryDbUser(client.client)
41 | val items = list.map { RoleItem(client.uuid, it) }.toList()
42 | addChildren(items)
43 | } finally {
44 | loadStatus.set(false)
45 | }
46 | }
47 | }
48 |
49 | override fun onAction(action: TreeItemMenuHandler.MenuAction?) {
50 |
51 | }
52 | }
--------------------------------------------------------------------------------
/app/src/main/kotlin/cn/navigational/dbfx/controls/tree/folder/SchemeFolder.kt:
--------------------------------------------------------------------------------
1 | package cn.navigational.dbfx.controls.tree.folder
2 |
3 | import cn.navigational.dbfx.config.FOLDER_ICON
4 | import cn.navigational.dbfx.controls.tree.TreeItemMenuHandler
5 | import cn.navigational.dbfx.controls.tree.scheme.SchemeItem
6 | import cn.navigational.dbfx.controls.tree.impl.ProgressTreeItem
7 | import cn.navigational.dbfx.controls.tree.scheme.PgSchemeItem
8 | import cn.navigational.dbfx.i18n.I18N
9 | import cn.navigational.dbfx.kit.SQLQuery
10 | import cn.navigational.dbfx.kit.enums.Clients
11 | import cn.navigational.dbfx.kit.postgres.PgQuery
12 | import cn.navigational.dbfx.model.SQLClient
13 | import cn.navigational.dbfx.tool.svg.SvgImageTranscoder
14 | import javafx.event.ActionEvent
15 | import kotlinx.coroutines.GlobalScope
16 | import kotlinx.coroutines.launch
17 |
18 | class SchemeFolder() : ProgressTreeItem(SvgImageTranscoder.svgToImageView(FOLDER_ICON)) {
19 |
20 | constructor(uuid: String, scheme: String? = null) : this() {
21 | this.reListListener()
22 | text = I18N.getString("label.database")
23 | this.getSqlClient(uuid).ifPresent { this.initScheme(it, scheme) }
24 | }
25 |
26 | private fun initScheme(client: SQLClient, scheme: String?) {
27 | GlobalScope.launch {
28 | loadStatus.set(true)
29 | try {
30 | if (client.cl == Clients.MYSQL) {
31 | initMyScheme(client)
32 | } else if (client.cl == Clients.POSTGRESQL) {
33 | initPgScheme(client, scheme!!)
34 | }
35 | } finally {
36 | loadStatus.set(false)
37 | }
38 | }
39 | }
40 |
41 | private suspend fun initMyScheme(client: SQLClient) {
42 | val query = SQLQuery.getClQuery(Clients.MYSQL)
43 | val list = query.showDatabase(client.client)
44 | this.addChildren(list.map { SchemeItem(it, client.uuid) }.toList())
45 | }
46 |
47 | private suspend fun initPgScheme(client: SQLClient, scheme: String) {
48 | this.text = I18N.getString("label.scheme")
49 | val query = SQLQuery.getClQuery(Clients.POSTGRESQL) as PgQuery
50 | val list = query.queryDbScheme(scheme, client.client).map {
51 | PgSchemeItem(client.uuid, it, scheme)
52 | }
53 | this.addChildren(list)
54 | }
55 |
56 | override fun onAction(action: TreeItemMenuHandler.MenuAction?) {
57 |
58 | }
59 | }
--------------------------------------------------------------------------------
/app/src/main/kotlin/cn/navigational/dbfx/controls/tree/folder/TableFolder.kt:
--------------------------------------------------------------------------------
1 | package cn.navigational.dbfx.controls.tree.folder
2 |
3 | import cn.navigational.dbfx.config.FOLDER_ICON
4 | import cn.navigational.dbfx.controls.tree.TreeItemMenuHandler
5 | import cn.navigational.dbfx.controls.tree.table.TableTreeItem
6 | import cn.navigational.dbfx.controls.tree.impl.ProgressTreeItem
7 | import cn.navigational.dbfx.i18n.I18N
8 | import cn.navigational.dbfx.kit.SQLQuery
9 | import cn.navigational.dbfx.tool.svg.SvgImageTranscoder
10 | import kotlinx.coroutines.GlobalScope
11 | import kotlinx.coroutines.launch
12 |
13 | class TableFolder(private val category: String, uuid: String) : ProgressTreeItem(SvgImageTranscoder.svgToImageView(FOLDER_ICON)) {
14 | init {
15 | text = I18N.getString("label.table")
16 | this.reListListener()
17 | this.initTable(uuid)
18 | }
19 |
20 | private fun initTable(uuid: String) {
21 | val optional = getSqlClient(uuid)
22 | if (optional.isEmpty) {
23 | return
24 | }
25 | val client = optional.get()
26 | val query = SQLQuery.getClQuery(client.cl)
27 | GlobalScope.launch {
28 | loadStatus.set(true)
29 | try {
30 | val list = query.showTable(category, client.client)
31 | addChildren(list.map { TableTreeItem(uuid, it, category) }.toList())
32 | } finally {
33 | loadStatus.set(false)
34 | }
35 | }
36 | }
37 |
38 | override fun onAction(action: TreeItemMenuHandler.MenuAction) {
39 |
40 | }
41 | }
--------------------------------------------------------------------------------
/app/src/main/kotlin/cn/navigational/dbfx/controls/tree/folder/ViewFolder.kt:
--------------------------------------------------------------------------------
1 | package cn.navigational.dbfx.controls.tree.folder
2 |
3 | import cn.navigational.dbfx.config.FOLDER_ICON
4 | import cn.navigational.dbfx.controls.tree.TreeItemMenuHandler
5 | import cn.navigational.dbfx.controls.tree.table.TableTreeItem
6 | import cn.navigational.dbfx.controls.tree.impl.ProgressTreeItem
7 | import cn.navigational.dbfx.i18n.I18N
8 | import cn.navigational.dbfx.kit.SQLQuery
9 | import cn.navigational.dbfx.tool.svg.SvgImageTranscoder
10 | import javafx.event.ActionEvent
11 | import kotlinx.coroutines.GlobalScope
12 | import kotlinx.coroutines.launch
13 |
14 | class ViewFolder(private val uuid: String, private val category: String) : ProgressTreeItem(SvgImageTranscoder.svgToImageView(FOLDER_ICON)) {
15 | init {
16 | text = I18N.getString("label.view")
17 | this.reListListener()
18 | this.initView()
19 | }
20 |
21 | private fun initView() {
22 | val optional = getSqlClient(uuid)
23 | if (optional.isEmpty) {
24 | return
25 | }
26 | val client = optional.get()
27 | val query = SQLQuery.getClQuery(client.cl)
28 | GlobalScope.launch {
29 | loadStatus.set(true)
30 | try {
31 | val views = query.showView(category, client.client)
32 | val list = views.map {
33 | TableTreeItem(uuid, it, category, tableType = TableTreeItem.TableType.VIEW)
34 | }.toList()
35 | addChildren(list)
36 | } finally {
37 | loadStatus.set(false)
38 | }
39 | }
40 | }
41 |
42 | override fun onAction(action: TreeItemMenuHandler.MenuAction) {
43 | }
44 | }
--------------------------------------------------------------------------------
/app/src/main/kotlin/cn/navigational/dbfx/controls/tree/scheme/PgSchemeItem.kt:
--------------------------------------------------------------------------------
1 | package cn.navigational.dbfx.controls.tree.scheme
2 |
3 | import cn.navigational.dbfx.config.PG_DB_ICON
4 | import cn.navigational.dbfx.controls.tree.TreeItemMenuHandler
5 | import cn.navigational.dbfx.controls.tree.folder.TableFolder
6 | import cn.navigational.dbfx.controls.tree.folder.ViewFolder
7 | import cn.navigational.dbfx.controls.tree.impl.ProgressTreeItem
8 | import cn.navigational.dbfx.tool.svg.SvgImageTranscoder
9 | import javafx.event.ActionEvent
10 | import javafx.scene.input.MouseEvent
11 |
12 | class PgSchemeItem(private val uuid: String, private val scheme: String, private val category: String) : ProgressTreeItem( SvgImageTranscoder.svgToImageView(PG_DB_ICON)) {
13 | init {
14 | this.text = scheme
15 | }
16 |
17 | private fun initScheme() {
18 | val s = "$category.$scheme"
19 | val tableFolder = TableFolder(s, uuid)
20 | val viewFolder = ViewFolder(uuid, s)
21 | this.addChildren(tableFolder, viewFolder)
22 | }
23 |
24 | override fun onMouseClicked(event: MouseEvent) {
25 | if (event.clickCount > 1 && this.treeItem.children.isEmpty()) {
26 | initScheme()
27 | }
28 | }
29 |
30 | override fun onAction(action: TreeItemMenuHandler.MenuAction) {
31 | }
32 | }
--------------------------------------------------------------------------------
/app/src/main/kotlin/cn/navigational/dbfx/controls/tree/scheme/SchemeItem.kt:
--------------------------------------------------------------------------------
1 | package cn.navigational.dbfx.controls.tree.scheme
2 |
3 | import cn.navigational.dbfx.SQLClientManager
4 | import cn.navigational.dbfx.config.SCHEME_ICON
5 | import cn.navigational.dbfx.view.ExportViewController
6 | import cn.navigational.dbfx.controls.tab.SQLTerminalTab
7 | import cn.navigational.dbfx.controls.tree.TreeItemMenuHandler
8 | import cn.navigational.dbfx.controls.tree.folder.RoleFolder
9 | import cn.navigational.dbfx.controls.tree.folder.SchemeFolder
10 | import cn.navigational.dbfx.controls.tree.folder.TableFolder
11 | import cn.navigational.dbfx.controls.tree.folder.ViewFolder
12 | import cn.navigational.dbfx.controls.tree.impl.ProgressTreeItem
13 | import cn.navigational.dbfx.handler.MainTabPaneHandler
14 | import cn.navigational.dbfx.i18n.I18N
15 | import cn.navigational.dbfx.kit.enums.Clients
16 | import cn.navigational.dbfx.tool.svg.SvgImageTranscoder
17 | import javafx.scene.input.MouseEvent
18 | import kotlinx.coroutines.GlobalScope
19 | import kotlinx.coroutines.launch
20 |
21 | class SchemeItem(private val scheme: String, private val uuid: String) : ProgressTreeItem(SvgImageTranscoder.svgToImageView(SCHEME_ICON)) {
22 | init {
23 | this.text = scheme
24 | val info = SQLClientManager.getDbInfo(uuid)
25 | if (info.database == scheme) {
26 | this.setSuffixTx(I18N.getString("label.current"))
27 | }
28 | this.contextMenu.updateItem(ContextMenuAction.ADD,
29 | TreeItemMenuHandler.MenuAction.OPEN_TERMINAL,
30 | TreeItemMenuHandler.MenuAction.EXPORT_DATA_TO_FILE)
31 | }
32 |
33 | private fun initScheme() {
34 | val info = SQLClientManager.getDbInfo(uuid)
35 | if (info.client == Clients.MYSQL) {
36 | val viewFolder = ViewFolder(uuid, scheme)
37 | val tableFolder = TableFolder(scheme, uuid)
38 | this.treeItem.children.addAll(tableFolder.treeItem, viewFolder.treeItem)
39 | }
40 | if (info.client == Clients.POSTGRESQL) {
41 | val schemeFolder = SchemeFolder(uuid, scheme)
42 | val roleFolder = RoleFolder(uuid, category = scheme)
43 | this.addChildren(schemeFolder, roleFolder)
44 | }
45 | }
46 |
47 | override fun onMouseClicked(event: MouseEvent) {
48 | if (event.clickCount > 1 && this.treeItem.children.isEmpty()) {
49 | initScheme()
50 | }
51 | }
52 |
53 | override fun onAction(action: TreeItemMenuHandler.MenuAction) {
54 | if (action == TreeItemMenuHandler.MenuAction.OPEN_TERMINAL) {
55 | GlobalScope.launch {
56 | MainTabPaneHandler.addTabToPane(SQLTerminalTab(uuid, scheme), fullPath)
57 | }
58 | }
59 | if (action == TreeItemMenuHandler.MenuAction.EXPORT_DATA_TO_FILE) {
60 | ExportViewController(uuid, scheme, ExportViewController.ExportTarget.SCHEME).showStage()
61 | }
62 | }
63 | }
--------------------------------------------------------------------------------
/app/src/main/kotlin/cn/navigational/dbfx/controls/tree/table/TableFieldItem.kt:
--------------------------------------------------------------------------------
1 | package cn.navigational.dbfx.controls.tree.table
2 |
3 | import cn.navigational.dbfx.controls.table.CustomTableColumn
4 | import cn.navigational.dbfx.controls.tree.AbstractBaseTreeItem
5 | import cn.navigational.dbfx.controls.tree.TreeItemMenuHandler
6 | import cn.navigational.dbfx.kit.model.TableColumnMeta
7 | import javafx.event.ActionEvent
8 | import javafx.scene.image.ImageView
9 |
10 | class TableFieldItem(tableColumnMeta: TableColumnMeta) : AbstractBaseTreeItem() {
11 | init {
12 | this.text = tableColumnMeta.colName
13 | this.setSuffixTx(tableColumnMeta.type)
14 | this.prefixGra = ImageView(CustomTableColumn.getFieldImage(tableColumnMeta))
15 | }
16 |
17 | override fun onAction(action: TreeItemMenuHandler.MenuAction) {
18 | }
19 | }
--------------------------------------------------------------------------------
/app/src/main/kotlin/cn/navigational/dbfx/dialog/ProgressDialog.kt:
--------------------------------------------------------------------------------
1 | package cn.navigational.dbfx.dialog
2 |
3 | import cn.navigational.dbfx.config.PROGRESS_DIALOG_PANE
4 | import javafx.application.Platform
5 | import javafx.fxml.FXML
6 | import javafx.scene.control.*
7 |
8 | class ProgressDialog : UnDecoratedDialog("Background Tasks", false, PROGRESS_DIALOG_PANE) {
9 | @FXML
10 | private lateinit var tip: Label
11 |
12 | @FXML
13 | private lateinit var des: Label
14 |
15 | @FXML
16 | private lateinit var bar: ProgressBar
17 |
18 | override fun closeDialog() {
19 | //Fix dialog can't close issue
20 | Platform.runLater {
21 | this.result = ButtonType.OK
22 | this.close()
23 | }
24 | }
25 |
26 | /**
27 | * Update {@link TextType} update text info
28 | *
29 | * @param type Update type
30 | * @param text Update text info
31 | */
32 | fun updateText(type: TextType, text: String) {
33 | Platform.runLater {
34 | if (type == TextType.TIP) {
35 | this.tip.text = text
36 | } else {
37 | this.des.text = text
38 | }
39 | }
40 | }
41 |
42 | /**
43 | *
44 | * Text type
45 | *
46 | */
47 | enum class TextType {
48 | TIP,
49 | DES
50 | }
51 | }
--------------------------------------------------------------------------------
/app/src/main/kotlin/cn/navigational/dbfx/dialog/TableSettingDialog.kt:
--------------------------------------------------------------------------------
1 | package cn.navigational.dbfx.dialog
2 |
3 | import cn.navigational.dbfx.config.TABLE_SETTING_PAGE
4 | import cn.navigational.dbfx.model.TableSetting
5 | import javafx.fxml.FXML
6 | import javafx.scene.control.ButtonType
7 | import javafx.scene.control.CheckBox
8 | import javafx.scene.control.ChoiceBox
9 | import javafx.scene.control.TextField
10 |
11 | /**
12 | *
13 | *
14 | *Table data setting dialog box.
15 | * The dialog box will use the setting object imported from outside as the benchmark for various settings.
16 | * If the object returned by the dialog box and the input object input the same object,
17 | * the parameters in the dialog box do not change;
18 | * otherwise, the setting parameters of the dialog box will change
19 | * @author yangkui
20 | * @since 1.0
21 | */
22 | class TableSettingDialog(private val setting: TableSetting) : UnDecoratedDialog("表设置", TABLE_SETTING_PAGE) {
23 | @FXML
24 | private lateinit var global: CheckBox
25 |
26 | @FXML
27 | private lateinit var nulValue: TextField
28 |
29 | @FXML
30 | private lateinit var dfFormatChoice: ChoiceBox
31 |
32 | init {
33 | this.result = setting
34 | nulValue.text = setting.nulValue
35 | global.isSelected = setting.isGlobal
36 | dfFormatChoice.selectionModel.select(setting.dtFormat)
37 | dfFormatChoice.items.addAll("yyyy-MM-dd HH:mm:ss", "yyyyMMdd HH:mm:ss")
38 | this.dialogPane.buttonTypes.add(ButtonType.OK)
39 | this.setResultConverter {
40 | return@setResultConverter if (it == ButtonType.OK) {
41 | val temp = TableSetting()
42 | temp.dtFormat = dfFormatChoice.value
43 | temp.isGlobal = global.isSelected
44 | temp.nulValue = nulValue.text
45 | temp
46 | } else {
47 | this.setting
48 | }
49 | }
50 | }
51 |
52 | override fun closeDialog() {
53 | this.close()
54 | }
55 | }
--------------------------------------------------------------------------------
/app/src/main/kotlin/cn/navigational/dbfx/handler/AppExitHandler.kt:
--------------------------------------------------------------------------------
1 | package cn.navigational.dbfx.handler
2 |
3 | import cn.navigational.dbfx.SQLClientManager
4 | import cn.navigational.dbfx.dialog.ProgressDialog
5 | import javafx.application.Platform
6 | import kotlinx.coroutines.GlobalScope
7 | import kotlinx.coroutines.launch
8 | import org.slf4j.LoggerFactory
9 | import java.lang.Exception
10 | import kotlin.math.log
11 |
12 | /**
13 | *
14 | *
15 | * Close app occur Resource
16 | *
17 | */
18 | private val logger = LoggerFactory.getLogger("AppExitHandler")
19 |
20 | fun closeAppOccurResource() {
21 | val dialog = ProgressDialog()
22 | dialog.show()
23 | dialog.updateText(ProgressDialog.TextType.TIP, "释放资源")
24 | GlobalScope.launch {
25 | try {
26 | dialog.updateText(ProgressDialog.TextType.DES, "正在关闭所Tab...")
27 | MainTabPaneHandler.closeAllTab()
28 | dialog.updateText(ProgressDialog.TextType.DES, "正在关闭所有连接...")
29 | SQLClientManager.closeAllClient()
30 | } catch (e: Exception) {
31 | logger.debug("App exit close resource failed cause:[${e.message}]")
32 | logger.error("Close resource happen error.", e)
33 | }
34 | dialog.closeDialog()
35 | //Exit program
36 | Platform.exit()
37 | }
38 | }
--------------------------------------------------------------------------------
/app/src/main/kotlin/cn/navigational/dbfx/io/LogIO.kt:
--------------------------------------------------------------------------------
1 | //package cn.navigational.dbfx.io
2 | //
3 | //import cn.navigational.dbfx.kit.utils.OssUtils
4 | //import java.io.File
5 | //import java.io.FileReader
6 | //import java.io.LineNumberReader
7 | //import java.lang.StringBuilder
8 | //
9 | //
10 | //
11 | //fun countLogLineNumber(path: String): Int {
12 | // val file = File(path)
13 | // if (!file.exists()) {
14 | // return -1
15 | // }
16 | // val lines: Int
17 | // var lineNumberReader: LineNumberReader? = null
18 | // val length = file.length()
19 | // try {
20 | // lineNumberReader = LineNumberReader(FileReader(file))
21 | // lineNumberReader.skip(length)
22 | // lines = lineNumberReader.lineNumber
23 | // } finally {
24 | // lineNumberReader?.close()
25 | // }
26 | // return lines
27 | //}
28 | //
29 | //fun readFixLineLog(path: String, start: Int, end: Int): String {
30 | // val file = File(path)
31 | // val fileReader = FileReader(file)
32 | // val reader = LineNumberReader(fileReader)
33 | // var str: String?
34 | // var lines = 0
35 | // val sb = StringBuilder()
36 | // while (true) {
37 | // lines++
38 | // str = reader.readLine()
39 | // if (str == null) {
40 | // break
41 | // }
42 | // if (lines in start..end) {
43 | // sb.append(str)
44 | // sb.append("\r\n")
45 | // }
46 | // }
47 | // return sb.toString();
48 | //}
--------------------------------------------------------------------------------
/app/src/main/kotlin/cn/navigational/dbfx/view/EditConViewController.kt:
--------------------------------------------------------------------------------
1 | package cn.navigational.dbfx.view
2 |
3 | import cn.navigational.dbfx.DatabaseMetaManager
4 | import cn.navigational.dbfx.SQLClientManager
5 | import cn.navigational.dbfx.ViewController
6 | import cn.navigational.dbfx.config.APP_STYLE
7 | import cn.navigational.dbfx.config.EDIT_CON_PAGE
8 | import cn.navigational.dbfx.controller.ConInfoPaneController
9 | import cn.navigational.dbfx.controls.tree.CustomTreeView
10 | import cn.navigational.dbfx.i18n.I18N
11 | import cn.navigational.dbfx.model.DatabaseMeta
12 | import cn.navigational.dbfx.model.DbInfo
13 | import javafx.fxml.FXML
14 | import javafx.scene.control.ScrollPane
15 | import javafx.scene.layout.BorderPane
16 | import javafx.stage.Modality
17 |
18 | class EditConViewController(private val info: DbInfo) : ViewController(EDIT_CON_PAGE) {
19 |
20 | private val dbMeta: DatabaseMeta
21 |
22 | private val controller: ConInfoPaneController = ConInfoPaneController()
23 |
24 | init {
25 | controller.initEdit(info)
26 | this.setSizeWithScreen(0.5, 0.7)
27 | this.scene.stylesheets.add(APP_STYLE)
28 | this.stage.initModality(Modality.WINDOW_MODAL)
29 | this.dbMeta = DatabaseMetaManager.getDbMeta(info.client)
30 | (this.parent.content as BorderPane).center = controller.parent
31 | this.stage.title = I18N.getString("stage.edit.connection")
32 | }
33 |
34 | @FXML
35 | fun cancel() {
36 | this.stage.close()
37 | }
38 |
39 | @FXML
40 | fun saveEdit() {
41 | val info = controller.getDbInfo(dbMeta)
42 | info.uuid = this.info.uuid
43 | //Update local cached
44 | SQLClientManager.updateDbInfo(info)
45 | //Require use select whether restart connection.
46 | CustomTreeView.getNavigator().updateConnection(info)
47 | this.stage.close()
48 | }
49 | }
--------------------------------------------------------------------------------
/app/src/main/kotlin/cn/navigational/dbfx/view/HomeViewController.kt:
--------------------------------------------------------------------------------
1 | package cn.navigational.dbfx.view
2 |
3 | import cn.navigational.dbfx.ViewController
4 | import cn.navigational.dbfx.config.*
5 | import cn.navigational.dbfx.controller.NavigatorToolBarController
6 | import cn.navigational.dbfx.controls.tree.CustomTreeView
7 | import cn.navigational.dbfx.handler.MainTabPaneHandler
8 | import cn.navigational.dbfx.handler.closeAppOccurResource
9 | import cn.navigational.dbfx.i18n.I18N
10 | import cn.navigational.dbfx.utils.AlertUtils
11 | import javafx.fxml.FXML
12 | import javafx.scene.control.SplitPane
13 | import javafx.scene.layout.BorderPane
14 | import javafx.scene.layout.Priority
15 | import javafx.scene.layout.VBox
16 | import javafx.stage.WindowEvent
17 |
18 | class HomeViewController private constructor() : ViewController(HOME_PAGE) {
19 |
20 | @FXML
21 | private lateinit var splitPane: SplitPane
22 |
23 | @FXML
24 | private lateinit var leftBox: VBox
25 |
26 | private val navigator: CustomTreeView = CustomTreeView.getNavigator()
27 |
28 | init {
29 | VBox.setVgrow(this.navigator, Priority.ALWAYS)
30 | this.leftBox.children.addAll(this.navigator.controlBar, this.navigator)
31 | this.splitPane.items.add(MainTabPaneHandler.getTabPane())
32 |
33 | //Listener whether bottom expand pane should show
34 |
35 | this.setSizeWithScreen(0.8, 0.9)
36 | this.stage.title = I18N.getString("stage.home")
37 | }
38 |
39 | @FXML
40 | fun about() {
41 | AboutViewController().showStage()
42 | }
43 |
44 |
45 | @FXML
46 | fun exit() {
47 | onCloseRequest(null)
48 | }
49 |
50 |
51 | override fun onCloseRequest(event: WindowEvent?) {
52 | val result = AlertUtils.showSimpleConfirmDialog(I18N.getString("alert.application.exit.tips"))
53 | if (!result) {
54 | event?.consume()
55 | return
56 | }
57 | closeAppOccurResource()
58 | }
59 |
60 | companion object {
61 | val home: HomeViewController by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) { HomeViewController() }
62 | }
63 | }
--------------------------------------------------------------------------------
/app/src/main/kotlin/cn/navigational/dbfx/view/SplashViewController.kt:
--------------------------------------------------------------------------------
1 | package cn.navigational.dbfx.view
2 |
3 |
4 | import cn.navigational.dbfx.ViewController
5 | import cn.navigational.dbfx.config.SPLASH_PAGE
6 |
7 | import javafx.application.Platform
8 | import javafx.scene.layout.BorderPane
9 | import javafx.stage.StageStyle
10 | import kotlinx.coroutines.GlobalScope
11 | import kotlinx.coroutines.launch
12 |
13 | class SplashViewController : ViewController(SPLASH_PAGE) {
14 | init {
15 | this.stage.initStyle(StageStyle.UNDECORATED)
16 | this.showStage()
17 | GlobalScope.launch {
18 | cn.navigational.dbfx.io.init()
19 | Platform.runLater {
20 | stage.close()
21 | HomeViewController.home.showStage()
22 | }
23 | }
24 | }
25 | }
--------------------------------------------------------------------------------
/app/src/main/resources/assets/icons/db/mini/field.svg:
--------------------------------------------------------------------------------
1 |
3 |
--------------------------------------------------------------------------------
/app/src/main/resources/assets/icons/db/mini/folder.svg:
--------------------------------------------------------------------------------
1 |
3 |
--------------------------------------------------------------------------------
/app/src/main/resources/assets/icons/db/mini/my_collation.svg:
--------------------------------------------------------------------------------
1 |
3 |
--------------------------------------------------------------------------------
/app/src/main/resources/assets/icons/db/mini/my_user.svg:
--------------------------------------------------------------------------------
1 |
3 |
--------------------------------------------------------------------------------
/app/src/main/resources/assets/icons/db/mini/mysql.svg:
--------------------------------------------------------------------------------
1 |
3 |
--------------------------------------------------------------------------------
/app/src/main/resources/assets/icons/db/mini/open.svg:
--------------------------------------------------------------------------------
1 |
3 |
--------------------------------------------------------------------------------
/app/src/main/resources/assets/icons/db/mini/pg_db.svg:
--------------------------------------------------------------------------------
1 |
3 |
--------------------------------------------------------------------------------
/app/src/main/resources/assets/icons/db/mini/pg_role.svg:
--------------------------------------------------------------------------------
1 |
3 |
--------------------------------------------------------------------------------
/app/src/main/resources/assets/icons/db/mini/remove_db.svg:
--------------------------------------------------------------------------------
1 |
3 |
--------------------------------------------------------------------------------
/app/src/main/resources/assets/icons/db/mini/scheme.svg:
--------------------------------------------------------------------------------
1 |
3 |
--------------------------------------------------------------------------------
/app/src/main/resources/assets/icons/db/mysql.svg:
--------------------------------------------------------------------------------
1 |
3 |
--------------------------------------------------------------------------------
/app/src/main/resources/assets/icons/dialog/close.svg:
--------------------------------------------------------------------------------
1 |
3 |
--------------------------------------------------------------------------------
/app/src/main/resources/assets/icons/dialog/info.svg:
--------------------------------------------------------------------------------
1 |
3 |
--------------------------------------------------------------------------------
/app/src/main/resources/assets/icons/dialog/minimize.svg:
--------------------------------------------------------------------------------
1 |
3 |
--------------------------------------------------------------------------------
/app/src/main/resources/assets/icons/home/break_off_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/databasefx/dbfx/4e47738a27c6e0deb2514d4c5891ccfb59635284/app/src/main/resources/assets/icons/home/break_off_icon.png
--------------------------------------------------------------------------------
/app/src/main/resources/assets/icons/home/con_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/databasefx/dbfx/4e47738a27c6e0deb2514d4c5891ccfb59635284/app/src/main/resources/assets/icons/home/con_icon.png
--------------------------------------------------------------------------------
/app/src/main/resources/assets/icons/home/recon-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/databasefx/dbfx/4e47738a27c6e0deb2514d4c5891ccfb59635284/app/src/main/resources/assets/icons/home/recon-icon.png
--------------------------------------------------------------------------------
/app/src/main/resources/assets/icons/home/sql_edit_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/databasefx/dbfx/4e47738a27c6e0deb2514d4c5891ccfb59635284/app/src/main/resources/assets/icons/home/sql_edit_icon.png
--------------------------------------------------------------------------------
/app/src/main/resources/assets/icons/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/databasefx/dbfx/4e47738a27c6e0deb2514d4c5891ccfb59635284/app/src/main/resources/assets/icons/icon.png
--------------------------------------------------------------------------------
/app/src/main/resources/assets/icons/last.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/databasefx/dbfx/4e47738a27c6e0deb2514d4c5891ccfb59635284/app/src/main/resources/assets/icons/last.png
--------------------------------------------------------------------------------
/app/src/main/resources/assets/icons/mini/dis_con.svg:
--------------------------------------------------------------------------------
1 |
3 |
--------------------------------------------------------------------------------
/app/src/main/resources/assets/icons/mini/edit.svg:
--------------------------------------------------------------------------------
1 |
3 |
--------------------------------------------------------------------------------
/app/src/main/resources/assets/icons/mini/flush.svg:
--------------------------------------------------------------------------------
1 |
3 |
--------------------------------------------------------------------------------
/app/src/main/resources/assets/icons/mini/open_con.svg:
--------------------------------------------------------------------------------
1 |
3 |
--------------------------------------------------------------------------------
/app/src/main/resources/assets/icons/mini/terminal.svg:
--------------------------------------------------------------------------------
1 |
3 |
--------------------------------------------------------------------------------
/app/src/main/resources/assets/icons/nav/event-log.svg:
--------------------------------------------------------------------------------
1 |
3 |
--------------------------------------------------------------------------------
/app/src/main/resources/assets/icons/nav/terminal.svg:
--------------------------------------------------------------------------------
1 |
3 |
--------------------------------------------------------------------------------
/app/src/main/resources/assets/icons/next.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/databasefx/dbfx/4e47738a27c6e0deb2514d4c5891ccfb59635284/app/src/main/resources/assets/icons/next.png
--------------------------------------------------------------------------------
/app/src/main/resources/assets/icons/setting.svg:
--------------------------------------------------------------------------------
1 |
3 |
--------------------------------------------------------------------------------
/app/src/main/resources/assets/icons/table/add.svg:
--------------------------------------------------------------------------------
1 |
3 |
--------------------------------------------------------------------------------
/app/src/main/resources/assets/icons/table/asc.svg:
--------------------------------------------------------------------------------
1 |
3 |
--------------------------------------------------------------------------------
/app/src/main/resources/assets/icons/table/del.svg:
--------------------------------------------------------------------------------
1 |
3 |
--------------------------------------------------------------------------------
/app/src/main/resources/assets/icons/table/des.svg:
--------------------------------------------------------------------------------
1 |
3 |
--------------------------------------------------------------------------------
/app/src/main/resources/assets/icons/table/field/date_time.svg:
--------------------------------------------------------------------------------
1 |
3 |
--------------------------------------------------------------------------------
/app/src/main/resources/assets/icons/table/field/letter.svg:
--------------------------------------------------------------------------------
1 |
3 |
--------------------------------------------------------------------------------
/app/src/main/resources/assets/icons/table/field/number.svg:
--------------------------------------------------------------------------------
1 |
3 |
--------------------------------------------------------------------------------
/app/src/main/resources/assets/icons/table/field/pri_key_icon.svg:
--------------------------------------------------------------------------------
1 |
3 |
--------------------------------------------------------------------------------
/app/src/main/resources/assets/icons/table/first_page.svg:
--------------------------------------------------------------------------------
1 |
3 |
--------------------------------------------------------------------------------
/app/src/main/resources/assets/icons/table/flush.svg:
--------------------------------------------------------------------------------
1 |
3 |
--------------------------------------------------------------------------------
/app/src/main/resources/assets/icons/table/last.svg:
--------------------------------------------------------------------------------
1 |
3 |
--------------------------------------------------------------------------------
/app/src/main/resources/assets/icons/table/last_page.svg:
--------------------------------------------------------------------------------
1 |
3 |
--------------------------------------------------------------------------------
/app/src/main/resources/assets/icons/table/next.svg:
--------------------------------------------------------------------------------
1 |
3 |
--------------------------------------------------------------------------------
/app/src/main/resources/assets/icons/table/search_icon.svg:
--------------------------------------------------------------------------------
1 |
3 |
--------------------------------------------------------------------------------
/app/src/main/resources/assets/icons/table/setting.svg:
--------------------------------------------------------------------------------
1 |
3 |
--------------------------------------------------------------------------------
/app/src/main/resources/assets/icons/table/sort.svg:
--------------------------------------------------------------------------------
1 |
3 |
--------------------------------------------------------------------------------
/app/src/main/resources/assets/icons/table/table.svg:
--------------------------------------------------------------------------------
1 |
3 |
--------------------------------------------------------------------------------
/app/src/main/resources/assets/icons/table/table_field.svg:
--------------------------------------------------------------------------------
1 |
3 |
--------------------------------------------------------------------------------
/app/src/main/resources/assets/icons/table/table_view.svg:
--------------------------------------------------------------------------------
1 |
3 |
--------------------------------------------------------------------------------
/app/src/main/resources/assets/icons/terminal/info.svg:
--------------------------------------------------------------------------------
1 |
3 |
--------------------------------------------------------------------------------
/app/src/main/resources/assets/icons/terminal/start.svg:
--------------------------------------------------------------------------------
1 |
3 |
--------------------------------------------------------------------------------
/app/src/main/resources/assets/icons/w_mini.svg:
--------------------------------------------------------------------------------
1 |
3 |
--------------------------------------------------------------------------------
/app/src/main/resources/assets/icons/x16/add_x16.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/src/main/resources/assets/icons/x16/duplicate_x16.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/src/main/resources/assets/icons/x16/flush_x16.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/src/main/resources/assets/icons/x16/folder_x16.svg:
--------------------------------------------------------------------------------
1 |
3 |
--------------------------------------------------------------------------------
/app/src/main/resources/assets/icons/x16/stop_x16.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/src/main/resources/assets/icons/x16/table_x16.svg:
--------------------------------------------------------------------------------
1 |
3 |
--------------------------------------------------------------------------------
/app/src/main/resources/assets/icons/x16/terminal_x16.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/src/main/resources/assets/imgs/splash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/databasefx/dbfx/4e47738a27c6e0deb2514d4c5891ccfb59635284/app/src/main/resources/assets/imgs/splash.png
--------------------------------------------------------------------------------
/app/src/main/resources/banner.txt:
--------------------------------------------------------------------------------
1 |
2 | _____ ____ ______ __ __
3 | | __ \ | _ \ | ____| \ \ / /
4 | | | | | | |_) | | |__ \ V /
5 | | | | | | _ < | __| > <
6 | | |__| | | |_) | | | / . \
7 | |_____/ |____/ |_| /_/ \_\
8 |
9 | To learn more about dbfx dynamics, visit: https://github.com/databasefx/dbfx
10 |
--------------------------------------------------------------------------------
/app/src/main/resources/config/s_db.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "name": "MySQL",
4 | "support": true,
5 | "icon": "assets/icons/db/mysql.svg",
6 | "port": 3306,
7 | "database": "",
8 | "username": "root"
9 | },
10 | {
11 | "name": "PostgreSQL",
12 | "support": true,
13 | "icon": "assets/icons/db/postgres.svg",
14 | "port": 5432,
15 | "database": "postgres",
16 | "username": "postgres"
17 | },
18 | {
19 | "name": "SqlServer",
20 | "support": false,
21 | "icon": "assets/icons/db/sql_server.svg",
22 | "port": 1432,
23 | "database": "",
24 | "username": ""
25 | },
26 | {
27 | "name": "DB2",
28 | "support": false,
29 | "icon": "assets/icons/db/db2.svg",
30 | "port": 5000,
31 | "database": "",
32 | "username": ""
33 | }
34 | ]
--------------------------------------------------------------------------------
/app/src/main/resources/config/ui_preferences.json:
--------------------------------------------------------------------------------
1 | {
2 | "tableSetting": {
3 | "global": true,
4 | "nulValue": "",
5 | "dtFormat": "yyyy-MM-dd HH:mm:ss"
6 | }
7 | }
--------------------------------------------------------------------------------
/app/src/main/resources/css/about_style.css:
--------------------------------------------------------------------------------
1 | .root {
2 | -fx-background-color: #2b2b2b;
3 | }
4 |
5 | .top-box *, .grid-pane, .grid-pane * {
6 | -fx-background-color: transparent;
7 | }
8 |
9 | .top-box {
10 | -fx-padding: 0.1em;
11 | -fx-background-color: linear-gradient(to right, #0717AB 0%, #9C000B 50%, #1C0657 100%);
12 | }
13 |
14 | .top-box HBox {
15 | -fx-alignment: center;
16 | }
17 |
18 | .version, .app-name {
19 | -fx-font-weight: bold;
20 | }
21 |
22 | .app-name {
23 | -fx-font-size: 40em;
24 | -fx-text-fill: #ffffff;
25 | -fx-effect: dropshadow(gaussian, rgba(255, 255, 255, 0.5), 0, 0, 0, 1);
26 | }
27 |
28 | .grid-pane {
29 | -fx-hgap: 1em;
30 | -fx-vgap: 1em;
31 | -fx-padding: 1em;
32 | -fx-alignment: center;
33 | }
34 |
35 | .mark-text {
36 | -fx-text-fill: #3448c2;
37 | -fx-cursor: hand;
38 | }
39 |
40 | #close {
41 | -fx-border-width: 0;
42 | }
43 |
--------------------------------------------------------------------------------
/app/src/main/resources/css/controller/b_expand_pane_style.css:
--------------------------------------------------------------------------------
1 | .top-box {
2 | -fx-background-color: #3c3f41;
3 | -fx-border-width: 0 0 0.1em 0;
4 | -fx-border-color: #323232;
5 | -fx-padding: 0 0.3em;
6 | }
--------------------------------------------------------------------------------
/app/src/main/resources/css/controller/con_info_style.css:
--------------------------------------------------------------------------------
1 | .grid-pane {
2 | -fx-vgap: 2em;
3 | -fx-hgap: 1em;
4 | }
5 |
6 | .top-grid {
7 | -fx-padding: 1em;
8 | }
9 |
10 | .grid-pane .label {
11 | -fx-pref-width: 5em;
12 | }
13 |
14 | .center-box {
15 | -fx-spacing: 1em;
16 | -fx-alignment: center-top;
17 | }
18 |
19 | .top-box {
20 | -fx-pref-height: 10em;
21 | -fx-end-margin: 0.5em;
22 | -fx-background-color: #4b4b4b;
23 | -fx-alignment: center;
24 | -fx-spacing: 1em;
25 | }
26 |
27 | .db-title {
28 | -fx-font-size: 2em;
29 | -fx-text-fill: #FEFFFF;
30 | -fx-background-color: transparent;
31 | }
32 |
33 | HBox {
34 | -fx-alignment: center-left;
35 | }
--------------------------------------------------------------------------------
/app/src/main/resources/css/controller/log_pane_style.css:
--------------------------------------------------------------------------------
1 | .text-area {
2 | -fx-border-width: 0;
3 | }
4 |
5 | .text-area .content {
6 | -fx-background-color: #2b2b2b;
7 | }
--------------------------------------------------------------------------------
/app/src/main/resources/css/controller/progress_dialog_pane_style.css:
--------------------------------------------------------------------------------
1 | .progress-bar {
2 | -fx-pref-width: 30em;
3 | -fx-background-insets: 0;
4 | }
5 |
6 | .center-box {
7 | -fx-spacing: 1em;
8 | -fx-padding: 0.5em;
9 | }
--------------------------------------------------------------------------------
/app/src/main/resources/css/controller/sql_terminal_style.css:
--------------------------------------------------------------------------------
1 | .tool-bar {
2 | -fx-border-width: 0 0 0.1em 0;
3 | -fx-background-color: #3C3F41;
4 | }
5 |
6 | .button:hover {
7 | -fx-background-color: #4C5052;
8 | }
9 |
10 | .code-area {
11 | -fx-background-color: #2b2b2b;
12 | }
13 |
14 | .code-area .text {
15 | -fx-fill: #A8B5B4;
16 | -fx-font-size: 1.6em;
17 | }
18 |
19 | .styled-text-area .line-highlighter {
20 | -fx-fill: #323232;
21 | }
22 |
23 | .lineno {
24 | -fx-background-color: #313335;
25 | -fx-font-size: 1em;
26 | -fx-font-weight: bolder;
27 | }
28 |
29 | .exe-info {
30 | -fx-spacing: 0.2em;
31 | -fx-padding: 0.3em;
32 | }
33 |
34 | .split-pane .split-pane-divider {
35 | -fx-pref-width: 0.1em;
36 | }
37 |
38 | .keyword {
39 | -fx-fill: #c77032 !important;
40 | }
41 |
42 | .text-area {
43 | -fx-background-insets: 0;
44 | }
45 |
46 | .text-area, .text-area .content {
47 | -fx-border-width: 0;
48 | -fx-background-color: #2b2b2b;
49 | }
--------------------------------------------------------------------------------
/app/src/main/resources/css/controller/table_view_style.css:
--------------------------------------------------------------------------------
1 | .page-box {
2 | -fx-min-width: 5em;
3 | }
4 |
5 | .search-box {
6 | -fx-alignment: center-left;
7 | -fx-padding: 0 0.1em;
8 | }
9 |
10 | .search-box, .search-box * {
11 | -fx-background-color: #2B2B2B;
12 | }
13 |
14 | .search-box .text-field {
15 | -fx-border-width: 0;
16 | -fx-pref-height: 3em;
17 | }
18 |
19 | .button:hover {
20 | -fx-background-color: #4C5052;
21 | }
22 | .table-view .table-column .tooltip{
23 | -fx-font-size: 0.7em;
24 | }
--------------------------------------------------------------------------------
/app/src/main/resources/css/create_con_style.css:
--------------------------------------------------------------------------------
1 | .pagination-control {
2 | visibility: false;
3 | }
4 |
5 | .bottom-box {
6 | -fx-padding: 0.5em 0.2em;
7 | -fx-alignment: center;
8 | }
9 |
10 | .l-box .button, .r-box .button {
11 | -fx-min-width: 8em;
12 | }
13 |
14 | .l-box {
15 | -fx-alignment: center-left;
16 | }
17 |
18 | .r-box {
19 | -fx-spacing: 1em;
20 | -fx-alignment: center-right;
21 | }
22 |
23 | .first-pane {
24 | -fx-padding: 1em;
25 | -fx-vgap: 1em;
26 | -fx-hgap: 1em;
27 | }
28 |
29 | .flow-item {
30 | -fx-padding: 0.3em;
31 | -fx-border-width: 0.1em;
32 | -fx-border-color: #4C708C;
33 | -fx-alignment: center;
34 | }
35 |
36 | .flow-item .label {
37 | -fx-background-color: transparent;
38 | }
39 |
40 | .first-pane .active {
41 | -fx-background-color: #00BCD4;
42 | }
--------------------------------------------------------------------------------
/app/src/main/resources/css/dialog/table_setting_dialog_style.css:
--------------------------------------------------------------------------------
1 | .root {
2 | -fx-pref-width: 50em;
3 | -fx-padding: 1em 0.5em;
4 | }
5 |
6 | .choice-box, .text-field {
7 | -fx-pref-width: 40em;
8 | }
9 |
10 | .grid-pane {
11 | -fx-hgap: 1em;
12 | -fx-vgap: 1em;
13 | -fx-alignment: center;
14 | }
15 |
16 | .action-box {
17 | -fx-alignment: center-right;
18 | }
--------------------------------------------------------------------------------
/app/src/main/resources/css/edit_con_style.css:
--------------------------------------------------------------------------------
1 | .bottom-box {
2 | -fx-spacing: 1em;
3 | -fx-padding: 1em;
4 | -fx-alignment: center-right;
5 | }
--------------------------------------------------------------------------------
/app/src/main/resources/css/export_style.css:
--------------------------------------------------------------------------------
1 | .options {
2 | -fx-spacing: 1em;
3 | -fx-padding: 0.2em 0.5em;
4 | }
5 |
6 | .options VBox {
7 | -fx-spacing: 0.5em;
8 | }
9 |
10 | .list-view {
11 | -fx-border-color: #323232;
12 | -fx-pref-height: 10em;
13 | -fx-border-width: 0.1em;
14 | }
15 |
16 | .choice-box {
17 | -fx-pref-width: 18em;
18 | }
19 |
20 | .file-selector {
21 | -fx-border-width: 0.1em;
22 | -fx-border-color: #646464;
23 | }
24 |
25 | .file-selector .button, .file-selector .text-field {
26 | -fx-border-width: 0;
27 | }
28 |
29 | .file-selector, .file-selector * {
30 | -fx-background-color: #45494A;
31 | }
32 |
33 |
34 | .bottom-box {
35 | -fx-padding: 0.5em;
36 | -fx-spacing: 0.5em;
37 | -fx-alignment: CENTER-RIGHT;
38 | }
39 |
40 | .bottom-box .cancel {
41 | -fx-background-color: #4c5052;
42 | }
--------------------------------------------------------------------------------
/app/src/main/resources/css/home_style.css:
--------------------------------------------------------------------------------
1 | .root {
2 | background-color: bisque;
3 | }
4 |
5 | .button {
6 | -fx-border-width: 0;
7 | -fx-background-color: transparent;
8 | }
9 |
10 | .menu-bar {
11 | -fx-border-width: 0 0 0.1em 0;
12 | -fx-border-color: #323232;
13 | }
14 |
15 | .tool-bar {
16 | -fx-border-width: 0 0 0.1em 0;
17 | }
18 |
19 | .tool-bar .menu-button:hover, .tool-bar .button:hover {
20 | -fx-background-color: #4c5052;
21 | }
--------------------------------------------------------------------------------
/app/src/main/resources/css/splash_style.css:
--------------------------------------------------------------------------------
1 | .root {
2 | -fx-background-image: url(../assets/imgs/splash.png);
3 | -fx-background-repeat: no-repeat;
4 | -fx-background-size: cover;
5 | }
6 |
7 | .bottom-box {
8 | -fx-spacing: 0.5em;
9 | -fx-padding: 0.5em;
10 | -fx-background-color: transparent;
11 | }
12 |
13 | .bottom-box .label {
14 | -fx-text-fill: white;
15 | }
--------------------------------------------------------------------------------
/app/src/main/resources/fxml/about_view.fxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
--------------------------------------------------------------------------------
/app/src/main/resources/fxml/controller/b_expand_pane.fxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
29 |
30 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/app/src/main/resources/fxml/controller/log_pane.fxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/app/src/main/resources/fxml/controller/n_top_bar.fxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
8 |
9 |
10 |
11 |
12 |
13 |
18 |
19 |
24 |
29 |
34 |
35 |
40 |
45 |
46 |
--------------------------------------------------------------------------------
/app/src/main/resources/fxml/controller/sql_terminal.fxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
18 |
19 |
20 |
21 |
22 |
23 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/app/src/main/resources/fxml/controller/table_view.fxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
22 |
27 |
28 |
29 |
34 |
39 |
40 |
45 |
46 |
51 |
56 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
--------------------------------------------------------------------------------
/app/src/main/resources/fxml/controller/terminal_pane.fxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/resources/fxml/create_con_view.fxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/app/src/main/resources/fxml/dialog/progress_dialog_pane.fxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/app/src/main/resources/fxml/dialog/table_setting_dialog_pane.fxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/app/src/main/resources/fxml/edit_con_view.fxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/app/src/main/resources/fxml/export_view.fxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/app/src/main/resources/fxml/home_view.fxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
10 |
11 |
12 |
13 |
14 |
15 |
18 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/app/src/main/resources/fxml/splash_view.fxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/app/src/main/resources/logback.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n
7 |
8 |
9 |
10 |
11 |
12 |
13 | %magenta(%d{yyyy-MM-dd HH:mm:ss.SSS}) %yellow([%thread]) %highlight(%-5level) %cyan(%logger{50}) -
14 | %green(%msg%n)
15 |
16 |
17 |
18 |
19 |
20 |
21 | %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n
22 | utf-8
23 |
24 | ${user.home}/dbfx/logs/dbfx.log
25 |
26 | ${user.home}/dbfx/logs/dbfx.log.%i
27 | 6
28 | true
29 |
30 |
31 | 1MB
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | buildscript {
2 | ext.kotlin_version = '1.4.10'
3 | ext.vertx_version = '4.0.0'
4 | repositories {
5 | maven {
6 | url "https://maven.aliyun.com/repository/google"
7 | }
8 | maven {
9 | url "https://maven.aliyun.com/nexus/content/repositories/central"
10 | }
11 | maven {
12 | url "https://maven.aliyun.com/nexus/content/groups/public/"
13 | }
14 | maven {
15 | url "https://nexus.gluonhq.com/nexus/content/repositories/releases"
16 | }
17 | maven {
18 | url "https://plugins.gradle.org/m2/"
19 | }
20 | jcenter()
21 | mavenCentral()
22 | }
23 | dependencies {
24 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
25 | }
26 | }
27 | allprojects {
28 | apply plugin: 'java'
29 | apply plugin: 'kotlin'
30 | apply plugin: 'org.jetbrains.kotlin.jvm'
31 |
32 | group 'cn.dbfx'
33 | version '0.0.1-SNAPSHOT'
34 |
35 |
36 | sourceCompatibility = 15
37 | targetCompatibility = 15
38 |
39 | sourceSets {
40 | main {
41 | java {
42 | srcDirs = ['src/main/java', 'src/main/kotlin']
43 | }
44 | resources {
45 | srcDirs = ['src/main/resources']
46 | }
47 | }
48 | }
49 |
50 | tasks.withType(JavaCompile) {
51 | options.encoding = "UTF-8"
52 | }
53 |
54 | tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).all {
55 | kotlinOptions {
56 | jvmTarget = "11"
57 | }
58 | }
59 |
60 | compileTestKotlin {
61 | kotlinOptions {
62 | jvmTarget = "11"
63 | }
64 | }
65 |
66 | repositories {
67 | maven { url "https://maven.aliyun.com/repository/google" }
68 | maven { url "http://maven.aliyun.com/nexus/content/groups/public/" }
69 | mavenCentral()
70 | }
71 | dependencies {
72 | implementation "org.jetbrains.kotlin:kotlin-stdlib"
73 | compile group: 'org.slf4j', name: 'slf4j-api', version: '2.0.0-alpha1'
74 | compile group: 'ch.qos.logback', name: 'logback-core', version: '1.3.0-alpha5'
75 | compile group: 'ch.qos.logback', name: 'logback-classic', version: '1.3.0-alpha5'
76 | compile group: 'io.vertx', name: 'vertx-core', version: vertx_version
77 | compile group: 'io.vertx', name: 'vertx-lang-kotlin-coroutines', version: vertx_version
78 | compile group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: '2.11.2'
79 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
80 | testImplementation 'junit:junit:4.12'
81 | testImplementation "io.vertx:vertx-unit:$vertx_version"
82 |
83 | }
84 | }
85 |
86 |
87 |
88 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/databasefx/dbfx/4e47738a27c6e0deb2514d4c5891ccfb59635284/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | zipStoreBase=GRADLE_USER_HOME
4 | zipStorePath=wrapper/dists
5 | distributionUrl=https\://downloads.gradle-dn.com/distributions/gradle-6.7.1-bin.zip
6 |
--------------------------------------------------------------------------------
/kit/build.gradle:
--------------------------------------------------------------------------------
1 | dependencies {
2 | compile group: 'io.vertx', name: 'vertx-pg-client', version: vertx_version
3 | compile group: 'io.vertx', name: 'vertx-mysql-client', version: vertx_version
4 | compile group: 'io.vertx', name: 'vertx-db2-client', version: vertx_version
5 | compile group: 'io.vertx', name: 'vertx-sql-client', version: vertx_version
6 | compile group: 'com.github.jsqlparser', name: 'jsqlparser', version: '3.2'
7 |
8 | }
--------------------------------------------------------------------------------
/kit/src/main/java/cn/navigational/dbfx/kit/KeywordHelper.java:
--------------------------------------------------------------------------------
1 | package cn.navigational.dbfx.kit;
2 |
3 | import cn.navigational.dbfx.kit.enums.Clients;
4 | import cn.navigational.dbfx.kit.utils.VertxUtils;
5 | import io.vertx.core.Future;
6 | import io.vertx.core.file.FileSystem;
7 | import io.vertx.core.json.JsonArray;
8 |
9 | import java.util.ArrayList;
10 | import java.util.List;
11 | import java.util.stream.Collectors;
12 |
13 | /**
14 | * SQL Statement keyword helper
15 | *
16 | * @author yangkui
17 | * @since 1.0
18 | */
19 | public class KeywordHelper {
20 | private static final String K_PATH = "config/keyword/";
21 | private static final List SUPPORT_KEYWORD = new ArrayList<>();
22 |
23 | static {
24 | final String supportPath = K_PATH + "support_key.json";
25 | final FileSystem fs = VertxUtils.getFileSystem();
26 | final JsonArray array = fs.readFileBlocking(supportPath).toJsonArray();
27 | SUPPORT_KEYWORD.addAll(array.stream().map(Object::toString).collect(Collectors.toList()));
28 | }
29 |
30 | public static List getKeyWordSyn(Clients cl) {
31 | return SUPPORT_KEYWORD;
32 | }
33 |
34 | public static Future> getKeyWordAsync(Clients cl) {
35 | return Future.succeededFuture(SUPPORT_KEYWORD);
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/kit/src/main/java/cn/navigational/dbfx/kit/enums/Clients.java:
--------------------------------------------------------------------------------
1 | package cn.navigational.dbfx.kit.enums;
2 |
3 | /**
4 | * Enum current support database type
5 | *
6 | * @author yangkui
7 | * @since 1.0
8 | */
9 | public enum Clients {
10 | /**
11 | * Mysql client
12 | */
13 | MYSQL("MySQL"),
14 | /**
15 | * Postgresql client
16 | */
17 | POSTGRESQL("PostgreSQL"),
18 | /**
19 | * Microsoft SQL Serve
20 | */
21 | MS_SQL("SqlServer"),
22 | /**
23 | * Db2 client
24 | */
25 | DB2("DB2");
26 |
27 | private final String client;
28 |
29 | Clients(String client) {
30 | this.client = client;
31 | }
32 |
33 | public String getClient() {
34 | return client;
35 | }
36 |
37 | public static Clients getClient(String value) {
38 | final Clients client;
39 | if (value.equals(MS_SQL.client)) {
40 | client = MS_SQL;
41 | } else if (value.equals(MYSQL.client)) {
42 | client = MYSQL;
43 | } else if (value.equals(POSTGRESQL.client)) {
44 | client = POSTGRESQL;
45 | } else {
46 | client = DB2;
47 | }
48 | return client;
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/kit/src/main/java/cn/navigational/dbfx/kit/enums/DataType.java:
--------------------------------------------------------------------------------
1 | package cn.navigational.dbfx.kit.enums;
2 |
3 | /**
4 | * Database data type
5 | *
6 | * @author yangkui
7 | * @since 1.0
8 | */
9 | public enum DataType {
10 | /**
11 | * string
12 | */
13 | STRING,
14 | /**
15 | * number
16 | */
17 | NUMBER,
18 | /**
19 | * date
20 | */
21 | DATE,
22 | /**
23 | * Unknown data type
24 | */
25 | UNKNOWN
26 | }
27 |
--------------------------------------------------------------------------------
/kit/src/main/java/cn/navigational/dbfx/kit/ex/NotSupportException.java:
--------------------------------------------------------------------------------
1 | package cn.navigational.dbfx.kit.ex;
2 |
3 | /**
4 | * Some functions are not implemented.
5 | * If these functions are called, the exception will be thrown.
6 | *
7 | * @author yangkui
8 | * @since 1.0
9 | */
10 | public class NotSupportException extends RuntimeException {
11 | public NotSupportException() {
12 | }
13 |
14 | public NotSupportException(String message) {
15 | super(message);
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/kit/src/main/java/cn/navigational/dbfx/kit/utils/NumberUtils.java:
--------------------------------------------------------------------------------
1 | package cn.navigational.dbfx.kit.utils;
2 |
3 | import java.util.regex.Pattern;
4 |
5 | /**
6 | * Number utils
7 | *
8 | * @author yangkui
9 | * @since 1.0
10 | */
11 | public class NumberUtils {
12 | private static final Pattern NUMBER_PATTERN = Pattern.compile("^[-\\+]?[\\d]*$");
13 |
14 | /**
15 | * Give str is number?
16 | *
17 | * @param str target str
18 | * @return true or false
19 | */
20 | public static boolean isInteger(String str) {
21 | return NUMBER_PATTERN.matcher(str).matches();
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/kit/src/main/java/cn/navigational/dbfx/kit/utils/OssUtils.java:
--------------------------------------------------------------------------------
1 | package cn.navigational.dbfx.kit.utils;
2 |
3 | import org.slf4j.Logger;
4 | import org.slf4j.LoggerFactory;
5 |
6 | import javax.swing.*;
7 | import java.awt.*;
8 | import java.awt.datatransfer.StringSelection;
9 | import java.io.File;
10 | import java.io.IOException;
11 |
12 | /**
13 | * Oss relative operation utils
14 | *
15 | * @author yangkui
16 | * @since 1.0
17 | */
18 | public class OssUtils {
19 | private static final Logger LOG = LoggerFactory.getLogger(OssUtils.class);
20 |
21 | /**
22 | * Get current user home
23 | *
24 | * @return User home dir
25 | */
26 | public static String getUserHome() {
27 | return System.getProperty("user.home");
28 | }
29 |
30 | /**
31 | * Get current os name
32 | *
33 | * @return Os name
34 | */
35 | public static String getOsName() {
36 | return System.getProperty("os.name");
37 | }
38 |
39 | /**
40 | * Call {@link Desktop#open(File)} open a file or direction.
41 | *
42 | * Awt relation api must call in {@link SwingUtilities#invokeLater(Runnable)},otherwise
43 | * javafx application probably crash
44 | *
45 | *
46 | * @param path File or direction path
47 | * @throws Exception Execute error
48 | */
49 | public static void openDirOrFileUseFileSystem(String path) throws Exception {
50 | assert path != null;
51 | var file = new File(path);
52 | assert file.exists();
53 | SwingUtilities.invokeAndWait(() -> {
54 | var desktop = Desktop.getDesktop();
55 | assert desktop.isSupported(Desktop.Action.OPEN);
56 | try {
57 | desktop.open(file);
58 | } catch (IOException e) {
59 | LOG.error("Open direction or file happen error!", e);
60 | throw new RuntimeException(e);
61 | }
62 | });
63 | }
64 |
65 | /**
66 | * Copy the target string to the system clipboard
67 | *
68 | * @param str Target string
69 | */
70 | public static void addStrToClipboard(String str) {
71 | var toolkit = Toolkit.getDefaultToolkit();
72 | var clipboard = toolkit.getSystemClipboard();
73 | clipboard.setContents(new StringSelection(str), null);
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/kit/src/main/java/cn/navigational/dbfx/kit/utils/StringUtils.java:
--------------------------------------------------------------------------------
1 | package cn.navigational.dbfx.kit.utils;
2 |
3 | import java.util.UUID;
4 |
5 | /**
6 | * String utils
7 | *
8 | * @author yangkui
9 | * @since 1.0
10 | */
11 | public class StringUtils {
12 | /**
13 | * Target str is empty.
14 | *
15 | * @param str target str
16 | * @return str is empty
17 | */
18 | public static boolean isEmpty(String str) {
19 | return str == null || "".equals(str.trim());
20 | }
21 |
22 | /**
23 | * Target str string is not empty
24 | *
25 | * @param str Target str string
26 | * @return str is not empty
27 | */
28 | public static boolean isNotEmpty(String str) {
29 | return !isEmpty(str);
30 | }
31 |
32 | /**
33 | * Generate a UUID string
34 | *
35 | * @return uuid string
36 | */
37 | public static String uuid() {
38 | return UUID.randomUUID().toString();
39 | }
40 |
41 | /**
42 | * If target is empty return defaultVal otherwise return target
43 | *
44 | * @param target target str
45 | * @param defaultVal default value
46 | * @return str
47 | */
48 | public static String getValueIfEmpty(String target, String defaultVal) {
49 | return isEmpty(target) ? defaultVal : target;
50 | }
51 |
52 | final protected static char[] hexArray = "0123456789ABCDEF".toCharArray();
53 |
54 | public static String bytesToHex(byte[] bytes) {
55 | StringBuilder sb = new StringBuilder();
56 | for (int j = 0; j < bytes.length; j++) {
57 | int v = bytes[j] & 0xFF;
58 | char x = hexArray[v >>> 4];
59 | char y = hexArray[v & 0x0F];
60 | sb.append(x).append(y);
61 | if (j!=bytes.length-1){
62 | sb.append(" ");
63 | }
64 | }
65 | return sb.toString();
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/kit/src/main/kotlin/cn/navigational/dbfx/kit/SQLQuery.kt:
--------------------------------------------------------------------------------
1 | package cn.navigational.dbfx.kit
2 |
3 | import cn.navigational.dbfx.kit.enums.Clients
4 | import cn.navigational.dbfx.kit.model.TableColumnMeta
5 | import cn.navigational.dbfx.kit.mysql.MysqlQuery
6 | import cn.navigational.dbfx.kit.postgres.PgQuery
7 | import io.vertx.sqlclient.Row
8 | import io.vertx.sqlclient.RowSet
9 | import io.vertx.sqlclient.SqlClient
10 |
11 | interface SQLQuery {
12 | companion object {
13 | fun getClQuery(cl: Clients): SQLQuery {
14 | return when (cl) {
15 | Clients.MYSQL -> MysqlQuery()
16 | else -> PgQuery()
17 | }
18 | }
19 | }
20 |
21 | /**
22 | * Show current client for database info
23 | */
24 | suspend fun showDbInfo(client: SqlClient): RowSet
25 |
26 | /**
27 | *
28 | * Show current client version
29 | *
30 | */
31 | suspend fun showDbVersion(client: SqlClient): String
32 |
33 | /**
34 | * Query current client all database
35 | */
36 | suspend fun showDatabase(client: SqlClient): List
37 |
38 | /**
39 | * Query current client all collation
40 | */
41 | suspend fun showCollations(client: SqlClient): List
42 |
43 | /**
44 | * Query current client user list
45 | */
46 | suspend fun queryDbUser(client: SqlClient): List
47 |
48 | /**
49 | * Query table list from fix category
50 | */
51 | suspend fun showTable(category: String, client: SqlClient): List
52 |
53 | /**
54 | * Query view list from fix category
55 | */
56 | suspend fun showView(category: String, client: SqlClient): List
57 |
58 | /**
59 | * Query a table all field
60 | */
61 | suspend fun showTableField(category: String, table: String, client: SqlClient): List
62 |
63 | /**
64 | * Paging query table data
65 | */
66 | suspend fun pageQuery(category: String, table: String, pageIndex: Int, pageSize: Int, client: SqlClient): RowSet
67 |
68 | /**
69 | * Get target table data total
70 | */
71 | suspend fun queryTableTotal(category: String, table: String, client: SqlClient): Long
72 | }
--------------------------------------------------------------------------------
/kit/src/main/kotlin/cn/navigational/dbfx/kit/config/Constants.kt:
--------------------------------------------------------------------------------
1 | package cn.navigational.dbfx.kit.config
2 |
3 | const val FILE = "file"
4 | const val PASSWORD = "password"
5 | const val NULL_TAG = "-/-/"
6 | const val NULL_VALUE = ""
--------------------------------------------------------------------------------
/kit/src/main/kotlin/cn/navigational/dbfx/kit/mysql/MyDataTypeHelper.kt:
--------------------------------------------------------------------------------
1 | package cn.navigational.dbfx.kit.mysql
2 |
3 | import cn.navigational.dbfx.kit.enums.DataType
4 |
5 | private val number: Array = arrayOf(
6 | "TINYINT", "SMALLINT", "MEDIUMINT", "INT", "INTEGER", "BIGINT", "FLOAT", "DOUBLE", "DECIMAL")
7 | private val dateTime: Array = arrayOf("DATE", "TIME", "YEAR", "DATETIME", "TIMESTAMP")
8 | //private val string: Array = arrayOf("CHAR", "VARCHAR", "TINYBLOB", "TINYTEXT", "BLOB",
9 | // "TEXT", "MEDIUMBLOB", "MEDIUMTEXT", "LONGBLOB", "LONGTEXT")
10 |
11 | fun getMyDataType(type: String): DataType {
12 | val temp = type.toUpperCase()
13 | return when {
14 | number.contains(temp) -> {
15 | DataType.NUMBER
16 | }
17 | dateTime.contains(temp) -> {
18 | DataType.DATE
19 | }
20 | else -> {
21 | DataType.STRING
22 | }
23 | }
24 | }
--------------------------------------------------------------------------------
/kit/src/main/kotlin/cn/navigational/dbfx/kit/mysql/MysqlHelper.kt:
--------------------------------------------------------------------------------
1 | package cn.navigational.dbfx.kit.mysql
2 |
3 | import cn.navigational.dbfx.kit.model.TableColumnMeta
4 | import cn.navigational.dbfx.kit.model.TableColumnMeta.TableColumnExtraAttr
5 | import io.vertx.sqlclient.Row
6 | import io.vertx.sqlclient.RowSet
7 |
8 | class MysqlHelper {
9 | companion object {
10 | fun getMysqlVersion(rowSet: RowSet): String {
11 | var version = ""
12 | for (row in rowSet) {
13 | val des = row.getString(0)
14 | if (des == "version") {
15 | version = row.getString(1)
16 | break
17 | }
18 | }
19 | return version
20 | }
21 |
22 | fun transTableName(category: String, table: String): String {
23 | return "`$category`.`$table`"
24 | }
25 |
26 | /**
27 | *
28 | * Get mysql table column constrain type
29 | *
30 | */
31 | fun getTableConstrain(colKey: String?): Array {
32 | return arrayOf(when (colKey) {
33 | "PRI" -> TableColumnMeta.ConstrainType.PRIMARY_KEY
34 | "UNI" -> TableColumnMeta.ConstrainType.UNIQUE_KEY
35 | else -> TableColumnMeta.ConstrainType.NONE
36 | })
37 | }
38 |
39 | /**
40 | * Get mysql table column extra attr
41 | */
42 | fun getExtraAttr(str: String?): Array {
43 | return arrayOf(when (str) {
44 | "AUTO_INCREMENT" -> TableColumnExtraAttr.AUTO_INCREMENT
45 | "ON UPDATE CURRENT_TIMESTAMP" -> TableColumnExtraAttr.ON_UPDATE_CURRENT_TIMESTAMP
46 | else -> TableColumnExtraAttr.NONE
47 | })
48 | }
49 | }
50 | }
--------------------------------------------------------------------------------
/kit/src/main/kotlin/cn/navigational/dbfx/kit/mysql/MysqlPageHelper.kt:
--------------------------------------------------------------------------------
1 | package cn.navigational.dbfx.kit.mysql
2 |
3 | class MysqlPageHelper {
4 | companion object {
5 | /**
6 | * Get paging start offset
7 | * @param pageIndex Paging start index
8 | * @param pageSize Paging size
9 | */
10 | fun getStartNum(pageIndex: Int, pageSize: Int): Int {
11 | return (pageIndex - 1) * pageSize
12 | }
13 | }
14 | }
--------------------------------------------------------------------------------
/kit/src/main/kotlin/cn/navigational/dbfx/kit/postgres/PgSQLHelper.kt:
--------------------------------------------------------------------------------
1 | package cn.navigational.dbfx.kit.postgres
2 |
3 | import cn.navigational.dbfx.kit.model.TableColumnMeta
4 |
5 | class PgSQLHelper {
6 | companion object {
7 | /**
8 | *
9 | * Get mysql table column constrain type
10 | *
11 | */
12 | fun getTableConstrain(colKey: String?): Array {
13 | return arrayOf(when (colKey) {
14 | "PRIMARY KEY" -> TableColumnMeta.ConstrainType.PRIMARY_KEY
15 | "UNIQUE" -> TableColumnMeta.ConstrainType.UNIQUE_KEY
16 | "FOREIGN KEY" -> TableColumnMeta.ConstrainType.FOREIGN_KEY
17 | else -> TableColumnMeta.ConstrainType.NONE
18 | })
19 | }
20 | }
21 | }
--------------------------------------------------------------------------------
/kit/src/main/resources/config/keyword/support_key.json:
--------------------------------------------------------------------------------
1 | [
2 | "SELECT",
3 | "FROM",
4 | "WHERE",
5 | "LEFT JOIN",
6 | "RIGHT JOIN",
7 | "INNER JOIN",
8 | "ON",
9 | "INSERT",
10 | "DELETE",
11 | "UPDATE",
12 | "CREATE TABLE",
13 | "DROP TABLE",
14 | "ALERT TABLE",
15 | "CREATE VIEW",
16 | "DROP VIEW",
17 | "CREATE INDEX",
18 | "DROP INDEX",
19 | "CREATE PROCEDURE",
20 | "DROP PROCEDURE",
21 | "CREATE TRIGGER",
22 | "DROP TRIGGER",
23 | "CREATE SCHEMA",
24 | "DROP SCHEMA",
25 | "CREATE DOMAIN",
26 | "ALTER DOMAIN",
27 | "DROP DOMAIN"
28 | ]
--------------------------------------------------------------------------------
/kit/src/test/kotlin/cn/navigational/dbfx/kit/test/BaseTest.kt:
--------------------------------------------------------------------------------
1 | package cn.navigational.dbfx.kit.test
2 |
3 | import io.vertx.core.Vertx
4 | import io.vertx.ext.unit.TestContext
5 | import io.vertx.kotlin.coroutines.await
6 | import io.vertx.sqlclient.Pool
7 | import io.vertx.sqlclient.PoolOptions
8 | import io.vertx.sqlclient.SqlConnectOptions
9 | import kotlinx.coroutines.GlobalScope
10 | import kotlinx.coroutines.launch
11 | import org.junit.After
12 |
13 | open class BaseTest {
14 | protected lateinit var vertx: Vertx
15 | protected lateinit var client: Pool
16 | protected lateinit var poolOptions: PoolOptions
17 | protected lateinit var connectionOptions: SqlConnectOptions
18 |
19 |
20 | @After
21 | fun testAfter(context: TestContext) {
22 | val async = context.async()
23 | GlobalScope.launch {
24 | client.close().await()
25 | vertx.close().await()
26 | async.complete()
27 | }
28 | }
29 |
30 | }
--------------------------------------------------------------------------------
/kit/src/test/kotlin/cn/navigational/dbfx/kit/test/DB2BaseTest.kt:
--------------------------------------------------------------------------------
1 | package cn.navigational.dbfx.kit.test
2 |
3 | class DB2BaseTest {
4 | }
--------------------------------------------------------------------------------
/kit/src/test/kotlin/cn/navigational/dbfx/kit/test/MSSqlBaseTest.kt:
--------------------------------------------------------------------------------
1 | package cn.navigational.dbfx.kit.test
2 |
3 | class MSSqlBaseTest {
4 | }
--------------------------------------------------------------------------------
/kit/src/test/kotlin/cn/navigational/dbfx/kit/test/MySqlTestBase.kt:
--------------------------------------------------------------------------------
1 | package cn.navigational.dbfx.kit.test
2 |
3 | import io.vertx.core.Vertx
4 | import io.vertx.ext.unit.TestContext
5 | import io.vertx.mysqlclient.MySQLConnectOptions
6 | import io.vertx.mysqlclient.MySQLPool
7 | import io.vertx.sqlclient.PoolOptions
8 | import kotlinx.coroutines.GlobalScope
9 | import kotlinx.coroutines.launch
10 | import org.junit.Before
11 |
12 | open class MySqlTestBase : BaseTest() {
13 |
14 | @Before
15 | fun testBefore(context: TestContext) {
16 | this.connectionOptions = MySQLConnectOptions()
17 | .setUser("root")
18 | .setPassword("root")
19 | .setCharset("utf8")
20 | this.poolOptions = PoolOptions().setMaxSize(10).setMaxWaitQueueSize(100)
21 | this.vertx = Vertx.vertx()
22 | val async = context.async()
23 | GlobalScope.launch {
24 | client = MySQLPool.pool(vertx, connectionOptions as MySQLConnectOptions, poolOptions)
25 | async.complete()
26 | }
27 | }
28 | }
--------------------------------------------------------------------------------
/kit/src/test/kotlin/cn/navigational/dbfx/kit/test/PostgresqlBaseTest.kt:
--------------------------------------------------------------------------------
1 | package cn.navigational.dbfx.kit.test
2 |
3 | import io.vertx.core.Vertx
4 | import io.vertx.ext.unit.TestContext
5 | import io.vertx.pgclient.PgConnectOptions
6 | import io.vertx.pgclient.PgPool
7 | import io.vertx.sqlclient.PoolOptions
8 | import org.junit.Before
9 |
10 | open class PostgresqlBaseTest : BaseTest() {
11 | @Before
12 | fun testBefore(context: TestContext) {
13 | this.vertx = Vertx.vertx()
14 | this.connectionOptions = PgConnectOptions()
15 | .setUser("postgres")
16 | .setPassword("postgres")
17 | .setDatabase("postgres")
18 | .setHost("localhost")
19 | this.poolOptions = PoolOptions().setMaxSize(10).setMaxWaitQueueSize(100)
20 |
21 | client = PgPool.pool(vertx, connectionOptions as PgConnectOptions, poolOptions)
22 | }
23 |
24 | }
--------------------------------------------------------------------------------
/kit/src/test/kotlin/cn/navigational/dbfx/kit/test/impl/MySqlClientTest.kt:
--------------------------------------------------------------------------------
1 | package cn.navigational.dbfx.kit.test.impl
2 |
3 | import cn.navigational.dbfx.kit.SQLQuery
4 | import cn.navigational.dbfx.kit.enums.Clients
5 | import cn.navigational.dbfx.kit.test.MySqlTestBase
6 | import io.vertx.ext.unit.TestContext
7 | import io.vertx.ext.unit.junit.VertxUnitRunner
8 | import kotlinx.coroutines.GlobalScope
9 | import kotlinx.coroutines.launch
10 | import org.junit.Test
11 | import org.junit.runner.RunWith
12 |
13 | @RunWith(VertxUnitRunner::class)
14 | class MySqlClientTest : MySqlTestBase() {
15 |
16 | @Test
17 | fun `test connection`(context: TestContext) {
18 | val async = context.async()
19 | GlobalScope.launch {
20 | val rs = SQLQuery.getClQuery(Clients.MYSQL).showDbInfo(client)
21 | context.assertTrue(rs.size() > 0)
22 | async.complete()
23 | }
24 | }
25 | }
--------------------------------------------------------------------------------
/kit/src/test/kotlin/cn/navigational/dbfx/kit/test/impl/PostgresqlClientTest.kt:
--------------------------------------------------------------------------------
1 | package cn.navigational.dbfx.kit.test.impl
2 |
3 |
4 | import cn.navigational.dbfx.kit.SQLQuery
5 | import cn.navigational.dbfx.kit.enums.Clients
6 | import cn.navigational.dbfx.kit.test.PostgresqlBaseTest
7 | import io.vertx.ext.unit.TestContext
8 | import io.vertx.ext.unit.junit.VertxUnitRunner
9 | import io.vertx.kotlin.coroutines.await
10 | import io.vertx.kotlin.coroutines.dispatcher
11 | import kotlinx.coroutines.GlobalScope
12 | import kotlinx.coroutines.launch
13 | import org.junit.Test
14 | import org.junit.runner.RunWith
15 |
16 |
17 | @RunWith(VertxUnitRunner::class)
18 | class PostgresqlClientTest : PostgresqlBaseTest() {
19 | @Test
20 | fun `test connection`(context: TestContext) {
21 | val async = context.async()
22 | GlobalScope.launch {
23 | val res = SQLQuery.getClQuery(Clients.POSTGRESQL).showDbInfo(client)
24 | context.assertTrue(res.size() > 0)
25 | async.complete()
26 | }
27 | }
28 |
29 | @Test(timeout = 1000)
30 | fun `test delete role`(context: TestContext) {
31 | val async = context.async()
32 | GlobalScope.launch(vertx.dispatcher()) {
33 | val sql = "DROP ROLE IF EXISTS vertx_pg_user"
34 | val res = client.query(sql).execute().await()
35 | context.assertTrue(res.rowCount() > 0)
36 | async.complete()
37 | }
38 | }
39 |
40 | /**
41 | *
42 | *This test method is used to reproduce the problem that vertx PG client cannot correctly
43 | *resolve some specified values of PG database time and date,Relation pg document please visit:
44 | *
45 | *
46 | *
47 | */
48 | @Test(timeout = 2000)
49 | fun `test create user`(context: TestContext) {
50 | val async = context.async()
51 | GlobalScope.launch(vertx.dispatcher()) {
52 | val sql = "CREATE ROLE vertx_pg_user LOGIN PASSWORD 'test' VALID UNTIL 'infinity'"
53 | val res = client.query(sql).execute().await()
54 | context.assertTrue(res.rowCount() > 0)
55 | val qSql = "SELECT * FROM pg_roles r WHERE r.rolname='vertx_pg_user'"
56 | val res1 = client.query(qSql).execute().await()
57 | context.assertTrue(res1.size() == 1)
58 | async.complete()
59 | }
60 | }
61 |
62 | }
--------------------------------------------------------------------------------
/native/linux-gl-menu/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 3.17)
2 | project(dbm)
3 |
4 | find_package(PkgConfig REQUIRED)
5 | pkg_check_modules(GTK3 REQUIRED gtk+-3.0)
6 | include_directories(${GTK3_INCLUDE_DIRS})
7 | link_directories(${GTK3_LIBRARY_DIRS})
8 | list(APPEND FC_DEP_LIBS ${GTK3_LIBRARIES})
9 |
10 | add_executable(dbmexec test.c)
11 | target_link_libraries(dbmexec ${FC_DEP_LIBS})
12 |
--------------------------------------------------------------------------------
/native/linux-gl-menu/linux_global_menu_wrapper.c:
--------------------------------------------------------------------------------
1 | //
2 | // Created by yangkui on 2020/10/17.
3 | //
4 |
5 | #include
6 | #include "linux_global_menu_wrapper.h"
7 |
--------------------------------------------------------------------------------
/native/linux-gl-menu/linux_global_menu_wrapper.h:
--------------------------------------------------------------------------------
1 | //
2 | // Created by yangkui on 2020/10/17.
3 | //
4 |
5 | #ifndef DBM_LINUX_GLOBAL_MENU_WRAPPER_H
6 | #define DBM_LINUX_GLOBAL_MENU_WRAPPER_H
7 |
8 | #include
9 |
10 | #endif //DBM_LINUX_GLOBAL_MENU_WRAPPER_H
11 |
--------------------------------------------------------------------------------
/native/linux-gl-menu/test.c:
--------------------------------------------------------------------------------
1 | //
2 | // Created by yangkui on 2020/10/19.
3 | //
4 | #include
5 | #include
6 |
7 |
8 | static void activate(GtkApplication *app, gpointer user_data) {
9 | GtkWidget *window;
10 | window = gtk_application_window_new(app);
11 | gtk_window_set_title(GTK_WINDOW (window), "Gtk Application");
12 | gtk_window_set_default_size(GTK_WINDOW (window), 500, 600);
13 | GtkWidget *hbox;
14 | GtkWidget *menubar;
15 | GtkWidget *fileMenu, *helpMenu;
16 | GtkWidget *fileMi, *helpMi;
17 | GtkWidget *quitMi;
18 | menubar = gtk_menu_bar_new();
19 | fileMenu = gtk_menu_new();
20 | helpMenu = gtk_menu_new();
21 |
22 | hbox = gtk_box_new(TRUE, 0);
23 | gtk_container_add(GTK_CONTAINER(window), hbox);
24 |
25 | fileMi = gtk_menu_item_new_with_label("File");
26 | helpMi = gtk_menu_item_new_with_label("Help");
27 | quitMi = gtk_menu_item_new_with_label("Quit");
28 |
29 | gtk_menu_item_set_submenu(GTK_MENU_ITEM(fileMi), fileMenu);
30 | gtk_menu_item_set_submenu(GTK_MENU_ITEM(helpMi), helpMenu);
31 | gtk_menu_shell_append(GTK_MENU_SHELL(fileMenu), quitMi);
32 | gtk_menu_shell_append(GTK_MENU_SHELL(menubar), fileMi);
33 | gtk_menu_shell_append(GTK_MENU_SHELL(menubar), helpMi);
34 | gtk_box_pack_start(GTK_BOX(hbox), menubar, FALSE, FALSE, 0);
35 | gtk_widget_show_all(window);
36 | gtk_main();
37 | }
38 |
39 | int main(int arg, char **argc) {
40 | GtkApplication *app;
41 | int status;
42 | app = gtk_application_new("cn.navigation.dbfx", G_APPLICATION_FLAGS_NONE);
43 | g_signal_connect (app, "activate", G_CALLBACK(activate), NULL);
44 | status = g_application_run(G_APPLICATION (app), arg, argc);
45 | g_object_unref(app);
46 | return status;
47 | }
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | pluginManagement {
2 | repositories {
3 | maven {
4 | url "https://nexus.gluonhq.com/nexus/content/repositories/releases"
5 | }
6 |
7 | gradlePluginPortal()
8 | }
9 | }
10 | rootProject.name = 'dbfx'
11 | include 'kit'
12 | include 'app'
13 |
--------------------------------------------------------------------------------