├── .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 | ![support project](./SNAPSHOTS/donate/paypal.png) 21 | ![support project](./SNAPSHOTS/donate/alipay.png) 22 | ![support project](./SNAPSHOTS/donate/wechat.png) 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 | ![Loading Fail](./SNAPSHOTS/a.png) 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 { 38 | return arrayListOf(clear, openLogDir) 39 | } 40 | 41 | override fun getTitle(): String { 42 | return I18N.getString("tool.bar.log") 43 | } 44 | 45 | override fun close() {} 46 | 47 | fun getOutput(): OutputStream { 48 | return this.output 49 | } 50 | 51 | inner class LogConsole : OutputStream() { 52 | override fun write(b: Int) { 53 | 54 | } 55 | 56 | override fun write(b: ByteArray) { 57 | if (!listenerLog) { 58 | return 59 | } 60 | val logTxt = String(b) 61 | Platform.runLater { 62 | textArea.appendText(logTxt) 63 | } 64 | } 65 | 66 | override fun write(b: ByteArray, off: Int, len: Int) { 67 | super.write(b, off, len) 68 | } 69 | } 70 | 71 | companion object { 72 | val logController: LogController by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) { LogController() } 73 | } 74 | } -------------------------------------------------------------------------------- /app/src/main/kotlin/cn/navigational/dbfx/controller/TerminalController.kt: -------------------------------------------------------------------------------- 1 | package cn.navigational.dbfx.controller 2 | 3 | import cn.navigational.dbfx.config.B_N_TERMINAL_PANE 4 | import cn.navigational.dbfx.controller.BottomNavigationExpandPaneAbstractFxmlController.* 5 | import cn.navigational.dbfx.i18n.I18N 6 | import javafx.scene.control.MenuItem 7 | import javafx.scene.layout.BorderPane 8 | 9 | class TerminalController : ExpandPaneProvider(B_N_TERMINAL_PANE) { 10 | 11 | override fun getSetting(): MutableList { 12 | return arrayListOf() 13 | } 14 | 15 | override fun getTitle(): String { 16 | return I18N.getString("tool.bar.terminal") 17 | } 18 | 19 | override fun close() { 20 | } 21 | } -------------------------------------------------------------------------------- /app/src/main/kotlin/cn/navigational/dbfx/controls/AbstractBaseTab.kt: -------------------------------------------------------------------------------- 1 | package cn.navigational.dbfx.controls 2 | 3 | import cn.navigational.dbfx.handler.MainTabPaneHandler 4 | import cn.navigational.dbfx.tool.svg.SvgImageTranscoder 5 | import javafx.beans.property.BooleanProperty 6 | import javafx.beans.property.SimpleBooleanProperty 7 | import javafx.beans.property.SimpleStringProperty 8 | import javafx.beans.property.StringProperty 9 | import javafx.scene.control.Tab 10 | import kotlinx.coroutines.GlobalScope 11 | import kotlinx.coroutines.launch 12 | 13 | abstract class AbstractBaseTab : Tab { 14 | constructor() : super() { 15 | this.setOnCloseRequest { 16 | it.consume() 17 | GlobalScope.launch { 18 | MainTabPaneHandler.closeTab(getTabPath()) 19 | } 20 | } 21 | } 22 | 23 | constructor(icon: String) : this() { 24 | this.graphic = SvgImageTranscoder.svgToImageView(icon) 25 | } 26 | 27 | /** 28 | * When tab instance after init data call that method 29 | */ 30 | abstract suspend fun init() 31 | 32 | /** 33 | * When current tab request close call that method 34 | */ 35 | open suspend fun close() { 36 | } 37 | 38 | /** 39 | * 40 | * Current Tab load status, if current tab doing load data that property value is true, 41 | * or else that property value is false.

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 | 5 | 6 | 7 | 8 | 10 | -------------------------------------------------------------------------------- /app/src/main/resources/assets/icons/db/mini/folder.svg: -------------------------------------------------------------------------------- 1 | 3 | 5 | 6 | 7 | 8 | 10 | -------------------------------------------------------------------------------- /app/src/main/resources/assets/icons/db/mini/my_collation.svg: -------------------------------------------------------------------------------- 1 | 3 | 5 | 6 | 7 | 8 | 10 | -------------------------------------------------------------------------------- /app/src/main/resources/assets/icons/db/mini/my_user.svg: -------------------------------------------------------------------------------- 1 | 3 | 5 | 6 | 7 | 8 | 10 | -------------------------------------------------------------------------------- /app/src/main/resources/assets/icons/db/mini/mysql.svg: -------------------------------------------------------------------------------- 1 | 3 | 5 | 6 | 7 | 8 | 10 | 12 | -------------------------------------------------------------------------------- /app/src/main/resources/assets/icons/db/mini/open.svg: -------------------------------------------------------------------------------- 1 | 3 | 5 | 6 | 7 | 8 | 10 | 12 | -------------------------------------------------------------------------------- /app/src/main/resources/assets/icons/db/mini/pg_db.svg: -------------------------------------------------------------------------------- 1 | 3 | 5 | 6 | 7 | 8 | 10 | 12 | 14 | -------------------------------------------------------------------------------- /app/src/main/resources/assets/icons/db/mini/pg_role.svg: -------------------------------------------------------------------------------- 1 | 3 | 5 | 6 | 7 | 8 | 10 | -------------------------------------------------------------------------------- /app/src/main/resources/assets/icons/db/mini/remove_db.svg: -------------------------------------------------------------------------------- 1 | 3 | 5 | 6 | 7 | 8 | 10 | -------------------------------------------------------------------------------- /app/src/main/resources/assets/icons/db/mini/scheme.svg: -------------------------------------------------------------------------------- 1 | 3 | 5 | 6 | 7 | 8 | 10 | -------------------------------------------------------------------------------- /app/src/main/resources/assets/icons/db/mysql.svg: -------------------------------------------------------------------------------- 1 | 3 | 5 | 6 | 7 | 8 | 10 | 12 | -------------------------------------------------------------------------------- /app/src/main/resources/assets/icons/dialog/close.svg: -------------------------------------------------------------------------------- 1 | 3 | 5 | 6 | 7 | 8 | 10 | -------------------------------------------------------------------------------- /app/src/main/resources/assets/icons/dialog/info.svg: -------------------------------------------------------------------------------- 1 | 3 | 5 | 6 | 7 | 8 | 10 | -------------------------------------------------------------------------------- /app/src/main/resources/assets/icons/dialog/minimize.svg: -------------------------------------------------------------------------------- 1 | 3 | 5 | 6 | 7 | 8 | 10 | -------------------------------------------------------------------------------- /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 | 5 | 6 | 7 | 8 | 10 | 12 | 14 | 16 | -------------------------------------------------------------------------------- /app/src/main/resources/assets/icons/mini/edit.svg: -------------------------------------------------------------------------------- 1 | 3 | 5 | 6 | 7 | 8 | 9 | 11 | 13 | 15 | 17 | -------------------------------------------------------------------------------- /app/src/main/resources/assets/icons/mini/flush.svg: -------------------------------------------------------------------------------- 1 | 3 | 5 | 6 | 7 | 8 | 10 | -------------------------------------------------------------------------------- /app/src/main/resources/assets/icons/mini/open_con.svg: -------------------------------------------------------------------------------- 1 | 3 | 5 | 6 | 7 | 8 | 10 | -------------------------------------------------------------------------------- /app/src/main/resources/assets/icons/mini/terminal.svg: -------------------------------------------------------------------------------- 1 | 3 | 5 | 6 | 7 | 8 | 10 | -------------------------------------------------------------------------------- /app/src/main/resources/assets/icons/nav/event-log.svg: -------------------------------------------------------------------------------- 1 | 3 | 5 | 6 | 7 | 8 | 10 | -------------------------------------------------------------------------------- /app/src/main/resources/assets/icons/nav/terminal.svg: -------------------------------------------------------------------------------- 1 | 3 | 5 | 6 | 7 | 8 | 10 | -------------------------------------------------------------------------------- /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 | 5 | 6 | 7 | 8 | 10 | -------------------------------------------------------------------------------- /app/src/main/resources/assets/icons/table/add.svg: -------------------------------------------------------------------------------- 1 | 3 | 5 | 6 | 7 | 8 | 10 | -------------------------------------------------------------------------------- /app/src/main/resources/assets/icons/table/asc.svg: -------------------------------------------------------------------------------- 1 | 3 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /app/src/main/resources/assets/icons/table/del.svg: -------------------------------------------------------------------------------- 1 | 3 | 5 | 6 | 7 | 8 | 10 | -------------------------------------------------------------------------------- /app/src/main/resources/assets/icons/table/des.svg: -------------------------------------------------------------------------------- 1 | 3 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /app/src/main/resources/assets/icons/table/field/date_time.svg: -------------------------------------------------------------------------------- 1 | 3 | 5 | 6 | 7 | 8 | 10 | 12 | -------------------------------------------------------------------------------- /app/src/main/resources/assets/icons/table/field/letter.svg: -------------------------------------------------------------------------------- 1 | 3 | 5 | 6 | 7 | 8 | 10 | 12 | 13 | -------------------------------------------------------------------------------- /app/src/main/resources/assets/icons/table/field/number.svg: -------------------------------------------------------------------------------- 1 | 3 | 5 | 6 | 7 | 8 | 10 | -------------------------------------------------------------------------------- /app/src/main/resources/assets/icons/table/field/pri_key_icon.svg: -------------------------------------------------------------------------------- 1 | 3 | 5 | 6 | 7 | 8 | 10 | -------------------------------------------------------------------------------- /app/src/main/resources/assets/icons/table/first_page.svg: -------------------------------------------------------------------------------- 1 | 3 | 5 | 6 | 7 | 8 | 10 | -------------------------------------------------------------------------------- /app/src/main/resources/assets/icons/table/flush.svg: -------------------------------------------------------------------------------- 1 | 3 | 5 | 6 | 7 | 8 | 10 | -------------------------------------------------------------------------------- /app/src/main/resources/assets/icons/table/last.svg: -------------------------------------------------------------------------------- 1 | 3 | 5 | 6 | 7 | 8 | 10 | -------------------------------------------------------------------------------- /app/src/main/resources/assets/icons/table/last_page.svg: -------------------------------------------------------------------------------- 1 | 3 | 5 | 6 | 7 | 8 | 10 | -------------------------------------------------------------------------------- /app/src/main/resources/assets/icons/table/next.svg: -------------------------------------------------------------------------------- 1 | 3 | 5 | 6 | 7 | 8 | 10 | -------------------------------------------------------------------------------- /app/src/main/resources/assets/icons/table/search_icon.svg: -------------------------------------------------------------------------------- 1 | 3 | 5 | 6 | 7 | 8 | 10 | -------------------------------------------------------------------------------- /app/src/main/resources/assets/icons/table/setting.svg: -------------------------------------------------------------------------------- 1 | 3 | 5 | 6 | 7 | 8 | 10 | 12 | -------------------------------------------------------------------------------- /app/src/main/resources/assets/icons/table/sort.svg: -------------------------------------------------------------------------------- 1 | 3 | 5 | 6 | 7 | 8 | 10 | -------------------------------------------------------------------------------- /app/src/main/resources/assets/icons/table/table.svg: -------------------------------------------------------------------------------- 1 | 3 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /app/src/main/resources/assets/icons/table/table_field.svg: -------------------------------------------------------------------------------- 1 | 3 | 5 | 6 | 7 | 8 | 10 | -------------------------------------------------------------------------------- /app/src/main/resources/assets/icons/table/table_view.svg: -------------------------------------------------------------------------------- 1 | 3 | 5 | 6 | 7 | 8 | 10 | 12 | 14 | 16 | -------------------------------------------------------------------------------- /app/src/main/resources/assets/icons/terminal/info.svg: -------------------------------------------------------------------------------- 1 | 3 | 5 | 6 | 7 | 8 | 10 | -------------------------------------------------------------------------------- /app/src/main/resources/assets/icons/terminal/start.svg: -------------------------------------------------------------------------------- 1 | 3 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /app/src/main/resources/assets/icons/w_mini.svg: -------------------------------------------------------------------------------- 1 | 3 | 5 | 6 | 7 | 8 | 10 | -------------------------------------------------------------------------------- /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 | 5 | 6 | 7 | 8 | 10 | 12 | -------------------------------------------------------------------------------- /app/src/main/resources/assets/icons/x16/stop_x16.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/src/main/resources/assets/icons/x16/table_x16.svg: -------------------------------------------------------------------------------- 1 | 3 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /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 | 24 | 25 | 26 | 31 | 32 | 33 |
34 | 35 | 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 | 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 |