diff --git a/README.md b/README.md
index 0a9e971..9fff76f 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,12 @@
+
+
+
-Small tool for quick text transformations such as checksums, encoding, decoding and so on. Written in Vala for GNOME desktop in the hope to be useful.
+Small tool for quick sql query, specialized in PostgresSQL. Written in Vala for GNOME desktop in the hope to be useful.
# Features
- Load and save connections.
diff --git a/res/gtk/connection-form.blp b/res/gtk/connection-form.blp
index ca9997d..c38921c 100644
--- a/res/gtk/connection-form.blp
+++ b/res/gtk/connection-form.blp
@@ -13,6 +13,14 @@ template $PsequelConnectionForm : Gtk.Box {
Label {
label: "";
}
+
+ // Dupplicate primary_menu in query-view.blp.
+ // Update both if you change something
+ [end]
+ MenuButton {
+ icon-name: "open-menu-symbolic";
+ menu-model: primary_menu;
+ }
}
Adw.Clamp {
@@ -214,4 +222,23 @@ template $PsequelConnectionForm : Gtk.Box {
}
}
+}
+
+menu primary_menu {
+ section {
+ item {
+ label: _("_Preferences");
+ action: "app.preferences";
+ }
+
+ item {
+ label: _("_Keyboard Shortcuts");
+ // action: "win.show-help-overlay";
+ }
+
+ item {
+ label: _("_About");
+ action: "app.about";
+ }
+ }
}
\ No newline at end of file
diff --git a/res/gtk/icons/text-sql-symbolic.svg b/res/gtk/icons/text-sql-symbolic.svg
new file mode 100644
index 0000000..1075496
--- /dev/null
+++ b/res/gtk/icons/text-sql-symbolic.svg
@@ -0,0 +1,4 @@
+
+
diff --git a/res/gtk/query-view.blp b/res/gtk/query-view.blp
index 7b66d61..37a64de 100644
--- a/res/gtk/query-view.blp
+++ b/res/gtk/query-view.blp
@@ -223,6 +223,12 @@ template $PsequelQueryView : Adw.Bin {
policy: wide;
stack: stack;
}
+
+ [end]
+ MenuButton {
+ icon-name: "open-menu-symbolic";
+ menu-model: primary_menu;
+ }
}
Adw.ViewStack stack {
@@ -259,4 +265,24 @@ template $PsequelQueryView : Adw.Bin {
}
}
}
-}
\ No newline at end of file
+}
+
+
+menu primary_menu {
+ section {
+ item {
+ label: _("_Preferences");
+ action: "app.preferences";
+ }
+
+ item {
+ label: _("_Keyboard Shortcuts");
+ // action: "win.show-help-overlay";
+ }
+
+ item {
+ label: _("_About");
+ action: "app.about";
+ }
+ }
+}
\ No newline at end of file
diff --git a/res/gtk/table-data-view.blp b/res/gtk/table-data-view.blp
index 18be54f..f7e3b7a 100644
--- a/res/gtk/table-data-view.blp
+++ b/res/gtk/table-data-view.blp
@@ -32,13 +32,8 @@ template $PsequelTableData : Gtk.Box {
}
}
- ScrolledWindow {
- ColumnView data_view {
- show-row-separators: true;
- show-column-separators: true;
- styles ["data-table"]
- vexpand: true;
- }
+ $PsequelQueryResults query_results {
+
}
diff --git a/res/psequel.gresource.xml b/res/psequel.gresource.xml
index 4409a06..d6f9868 100644
--- a/res/psequel.gresource.xml
+++ b/res/psequel.gresource.xml
@@ -33,5 +33,6 @@
gtk/icons/category-search-symbolic.svg
gtk/icons/left-large-symbolic.svg
gtk/icons/right-large-symbolic.svg
+ gtk/icons/text-sql-symbolic.svg
diff --git a/src/application.vala b/src/application.vala
index 45f9c4a..35eecf8 100644
--- a/src/application.vala
+++ b/src/application.vala
@@ -30,6 +30,16 @@ namespace Psequel {
Object (application_id: "me.ppvan.psequel", flags: ApplicationFlags.DEFAULT_FLAGS);
}
+ construct {
+ ActionEntry[] action_entries = {
+ { "about", this.on_about_action },
+ { "preferences", this.on_preferences_action },
+ { "quit", this.quit }
+ };
+ this.add_action_entries (action_entries, this);
+ this.set_accels_for_action ("app.quit", {"q"});
+ }
+
public override void activate () {
base.activate ();
var win = this.active_window;
@@ -102,5 +112,31 @@ namespace Psequel {
typeof (Psequel.TableIndexInfo).ensure ();
typeof (Psequel.TableFKInfo).ensure ();
}
+
+ private void on_about_action () {
+ string[] developers = { "ppvan" };
+
+ var about = new Adw.AboutWindow () {
+ transient_for = this.get_active_window (),
+ application_name = Config.APP_NAME,
+ application_icon = Config.APP_ID,
+ developer_name = "Phạm Văn Phúc",
+ version = Config.VERSION,
+ developers = developers,
+ copyright = "© 2023 ppvan",
+ license_type = Gtk.License.GPL_3_0_ONLY,
+ issue_url = "https://github.com/ppvan/psequel/issues",
+
+ developers = {
+ "ppvan https://ppvan.me",
+ },
+ };
+
+ about.present ();
+ }
+
+ private void on_preferences_action () {
+ debug ("Setting");
+ }
}
}
\ No newline at end of file
diff --git a/src/services/query_service.vala b/src/services/query_service.vala
index 938c94d..5eb34a2 100644
--- a/src/services/query_service.vala
+++ b/src/services/query_service.vala
@@ -13,14 +13,9 @@ namespace Psequel {
public async Relation select (string schema, string table_name, int offset = 0, int limit = 500, string where_clause = "") throws PsequelError {
string escape_tbname = active_db.escape_identifier (table_name);
- if (where_clause == "") {
- string stmt = @"SELECT * FROM $escape_tbname LIMIT $limit OFFSET $offset";
- return yield exec_query (stmt);
- } else {
- string stmt = @"SELECT * FROM $escape_tbname WHERE $where_clause LIMIT $limit OFFSET $offset";
- return yield exec_query (stmt);
- }
+ string stmt = @"SELECT * FROM $escape_tbname $where_clause LIMIT $limit OFFSET $offset";
+ return yield exec_query (stmt);
}
public async string db_version () throws PsequelError {
@@ -57,7 +52,7 @@ namespace Psequel {
}
public async Relation exec_query (string query, out int64 exec_ms = null) throws PsequelError {
-
+
int64 begin = GLib.get_real_time ();
var result = yield exec_query_internal (query);
diff --git a/src/ui/query/table_data_view.vala b/src/ui/query/table_data_view.vala
index 3b9b05b..69d7604 100644
--- a/src/ui/query/table_data_view.vala
+++ b/src/ui/query/table_data_view.vala
@@ -9,11 +9,6 @@ namespace Psequel {
private ObservableArrayList model;
- private Gtk.SortListModel sort_model;
- private Gtk.SelectionModel selection_model;
-
- public int64 acc = 0;
-
public int query_limit { get; set; }
public Schema schema { get; set; }
@@ -32,51 +27,29 @@ namespace Psequel {
var setting = ResourceManager.instance ().settings;
setting.bind ("query-limit", this, "query-limit", SettingsBindFlags.DEFAULT);
connect_signal ();
- alloc_columns ();
}
public async void load_data (string schema, string table_name, int page = 0, string where = "") {
- Idle.add (load_data.callback, Priority.DEFAULT_IDLE);
- yield;
-
- var columns = data_view.columns;
- uint n = columns.get_n_items ();
- int offset = page * query_limit;
+ var offset = current_page * query_limit;
try {
- var relation = yield query_service.select (schema, table_name, offset, query_limit, where);
-
- debug ("Begin add rows to views");
- for (int i = 0; i < n; i++) {
- var col = columns.get_item (i) as Gtk.ColumnViewColumn;
- if (i >= relation.cols) {
- col.set_visible (false);
- continue;
- }
- auto_set_sorter (col, relation.get_column_type (i), i);
- col.set_title (relation.get_header (i));
- col.set_visible (true);
- }
+ query_results.show_loading ();
- this.selection_model.unselect_all ();
- model.clear ();
+ var relation = yield query_service.select (schema, table_name, offset, query_limit, where);
- model.batch_add (relation.iterator ());
+ query_results.show_result (relation);
+ update_status_label (relation);
+ update_pagination_btn (relation);
} catch (PsequelError err) {
- create_dialog ("Query Fail", err.message).present ();
+ query_results.show_error (err);
}
-
- this.sort_model.set_sorter (data_view.get_sorter ());
- debug ("Load %u records from %s", model.get_n_items (), table_name);
- update_status_label ();
- update_pagination_btn ();
}
- private void update_pagination_btn () {
- if (model.get_n_items () < (uint) query_limit) {
+ private void update_pagination_btn (Relation relation) {
+ if (relation.rows < query_limit) {
right_page.sensitive = false;
} else {
right_page.sensitive = true;
@@ -89,9 +62,9 @@ namespace Psequel {
}
}
- private void update_status_label () {
+ private void update_status_label (Relation relation) {
uint begin = query_limit * current_page + 1;
- uint end = begin + model.get_n_items () - 1;
+ uint end = begin + relation.rows - 1;
status_label.label = @"Rows $begin - $end";
}
@@ -114,67 +87,16 @@ namespace Psequel {
});
}
- private void alloc_columns () {
- for (int i = 0; i < ResourceManager.MAX_COLUMNS; i++) {
- var factory = new Gtk.SignalListItemFactory ();
- factory.set_data ("index", i);
-
- factory.setup.connect ((_fact, _item) => {
- var label = new Gtk.Label (null);
- label.halign = Gtk.Align.START;
- label.margin_start = 8;
- _item.child = label;
- });
-
- factory.bind.connect ((_fact, _item) => {
- var row = _item.item as Relation.Row;
- var label = _item.child as Gtk.Label;
- int index = _fact.get_data ("index");
- label.label = row[index];
- });
-
- Gtk.ColumnViewColumn column = new Gtk.ColumnViewColumn ("", factory);
- column.set_expand (true);
- // column.fixed_width = 200;
- column.set_visible (false);
-
- data_view.append_column (column);
- }
-
- this.sort_model = new Gtk.SortListModel (model, null);
- this.sort_model.incremental = true;
-
- this.selection_model = new Gtk.SingleSelection (sort_model);
-
- data_view.set_model (this.selection_model);
- }
-
- private void auto_set_sorter (Gtk.ColumnViewColumn col, Type type, int col_index) {
- switch (type) {
- case Type.BOOLEAN, Type.INT64, Type.FLOAT, Type.DOUBLE:
- var constexprs = new Gtk.ConstantExpression (Type.INT, col_index);
- var expresion = new Gtk.CClosureExpression (Type.INT64, null, { constexprs }, (Callback) get_col_by_index_int, null, null);
-
- var sorter = new Gtk.NumericSorter (expresion);
-
- col.set_sorter (sorter);
- break;
-
- default:
- var constexprs = new Gtk.ConstantExpression (Type.INT, col_index);
- var expresion = new Gtk.CClosureExpression (Type.STRING, null, { constexprs }, (Callback) get_col_by_index, null, null);
-
- var sorter = new Gtk.StringSorter (expresion);
-
- col.set_sorter (sorter);
- break;
- }
- }
-
[GtkCallback]
private void filter_query (Gtk.Button btn) {
var where_clause = filter_entry.get_text ();
- load_data.begin (schema.name, tbname, current_page, where_clause);
+
+ if (!where_clause.up ().has_prefix ("WHERE")) {
+ var dialog = create_dialog ("Filter Failed", "WHERE clause should starts with 'WHERE'");
+ dialog.present ();
+ } else {
+ load_data.begin (schema.name, tbname, current_page, where_clause);
+ }
}
[GtkCallback]
@@ -202,7 +124,7 @@ namespace Psequel {
}
[GtkChild]
- private unowned Gtk.ColumnView data_view;
+ private unowned QueryResults query_results;
[GtkChild]
private unowned Gtk.Entry filter_entry;