├── .editorconfig ├── .github ├── FUNDING.yml └── workflows │ ├── ci.yml │ └── lint.yml ├── .gitignore ├── AUTHORS ├── LICENSE ├── README.md ├── build-aux ├── com.github.alecaddd.sequeler.json └── meson_post_install.py ├── com.github.alecaddd.sequeler.json ├── data ├── assets.gresource.xml ├── assets │ ├── icons │ │ ├── 128x128 │ │ │ ├── com.github.alecaddd.sequeler.svg │ │ │ └── com.github.alecaddd.sequelerDevel.svg │ │ ├── 16x16 │ │ │ ├── com.github.alecaddd.sequeler.svg │ │ │ └── com.github.alecaddd.sequelerDevel.svg │ │ ├── 24x24 │ │ │ ├── com.github.alecaddd.sequeler.svg │ │ │ └── com.github.alecaddd.sequelerDevel.svg │ │ ├── 32x32 │ │ │ ├── com.github.alecaddd.sequeler.svg │ │ │ └── com.github.alecaddd.sequelerDevel.svg │ │ ├── 48x48 │ │ │ ├── com.github.alecaddd.sequeler.svg │ │ │ └── com.github.alecaddd.sequelerDevel.svg │ │ ├── 64x64 │ │ │ ├── com.github.alecaddd.sequeler.svg │ │ │ └── com.github.alecaddd.sequelerDevel.svg │ │ ├── actions │ │ │ ├── application-logout.svg │ │ │ ├── office-database-edit.svg │ │ │ ├── office-database-new.svg │ │ │ └── office-database-remove.svg │ │ └── status │ │ │ ├── table-empty.svg │ │ │ └── table.svg │ ├── screenshots │ │ ├── sequeler-screenshot.png │ │ ├── sequeler-screenshot1.png │ │ └── sequeler-screenshot2.png │ ├── sequeler-logo-transparent.png │ └── sequeler.png ├── com.github.alecaddd.sequeler.appdata.xml.in.in ├── com.github.alecaddd.sequeler.desktop.in.in ├── meson.build └── stylesheet.css ├── meson.build ├── meson_options.txt ├── po ├── LINGUAS ├── POTFILES ├── ar_EG.po ├── ars.po ├── ca.po ├── com.github.alecaddd.sequeler.pot ├── cs.po ├── de.po ├── es.po ├── et.po ├── extra │ ├── LINGUAS │ ├── POTFILES │ ├── de.po │ ├── et.po │ ├── extra.pot │ ├── fr.po │ ├── ja.po │ ├── lt.po │ └── meson.build ├── fr.po ├── hi.po ├── id.po ├── it.po ├── ja.po ├── lg.po ├── lt.po ├── meson.build ├── pl.po ├── pt.po ├── pt_BR.po ├── ru.po ├── ta.po ├── tr.po ├── uk.po ├── zh_Hans.po └── zh_Hant.po ├── schemas ├── com.github.alecaddd.sequeler.gschema.xml.in └── meson.build ├── src ├── Application.vala ├── Layouts │ ├── DataBaseSchema.vala │ ├── DataBaseView.vala │ ├── HeaderBar.vala │ ├── Library.vala │ ├── Main.vala │ ├── Views │ │ ├── Content.vala │ │ ├── Query.vala │ │ ├── Relations.vala │ │ └── Structure.vala │ └── Welcome.vala ├── Main.vala ├── Partials │ ├── ButtonType.vala │ ├── DataBasePanel.vala │ ├── DatabaseTable.vala │ ├── Helpers.vala │ ├── LibraryItem.vala │ └── TreeBuilder.vala ├── Services │ ├── ActionManager.vala │ ├── ConnectionManager.vala │ ├── DataManager.vala │ ├── PasswordManager.vala │ ├── Settings.vala │ ├── Types │ │ ├── DataBaseType.vala │ │ ├── MySQL.vala │ │ ├── PostgreSQL.vala │ │ └── SQLite.vala │ └── UpgradeManager.vala ├── Widgets │ ├── ConnectionDialog.vala │ └── QueryParamsDialog.vala ├── Window.vala ├── config.vala.in └── meson.build └── vapi ├── libgda-5.0.deps ├── libgda-5.0.vapi ├── libsecret-1.vapi ├── libssh2.vapi └── linux.vapi /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | [*] 3 | indent_style = space 4 | trim_trailing_whitespace = true 5 | insert_final_newline = true 6 | charset = utf-8 7 | 8 | [*.{build,json,xml*}] 9 | indent_size = 2 10 | 11 | [*.vala] 12 | indent_size = 4 13 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: [alecaddd] 4 | patreon: alecaddd 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: Alecaddd 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 13 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | on: 2 | pull_request: 3 | types: 4 | - opened 5 | - reopened 6 | - synchronize 7 | name: CI 8 | jobs: 9 | flatpak-builder: 10 | name: "Flatpak Builder" 11 | runs-on: ubuntu-latest 12 | container: 13 | image: ghcr.io/flathub-infra/flatpak-github-actions:gnome-48 14 | options: --privileged 15 | steps: 16 | - uses: actions/checkout@v4 17 | - uses: bilelmoussaoui/flatpak-github-actions/flatpak-builder@master 18 | with: 19 | bundle: "sequeler-nightly.flatpak" 20 | manifest-path: "build-aux/com.github.alecaddd.sequeler.json" 21 | run-tests: true 22 | cache-key: "flatpak-builder-${{ github.sha }}" 23 | -------------------------------------------------------------------------------- /.github/workflows/lint.yml: -------------------------------------------------------------------------------- 1 | name: "CI: Lint" 2 | 3 | on: 4 | pull_request: 5 | types: 6 | - opened 7 | - reopened 8 | - synchronize 9 | 10 | jobs: 11 | lint: 12 | 13 | runs-on: ubuntu-latest 14 | 15 | container: 16 | image: valalang/lint 17 | 18 | steps: 19 | - uses: actions/checkout@v4 20 | - name: Lint 21 | run: io.elementary.vala-lint -d . 22 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .snapcraft 2 | .vscode 3 | src/config.vala 4 | build/ 5 | _build/ 6 | parts/ 7 | prime/ 8 | stage/ 9 | builddir/ 10 | .flatpak-builder/ 11 | *~ 12 | *.snap -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | Alessandro "Alecaddd" Castellani 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ![Sequeler](data/assets/sequeler-logo-transparent.png) 2 | > Friendly SQL Client 3 | 4 | [![Build Status](https://github.com/ellie-commons/sequeler/actions/workflows/ci.yml/badge.svg)](https://github.com/ellie-commons/sequeler/actions/workflows/ci.yml) 5 | [![Translation status](https://hosted.weblate.org/widgets/sequeler/-/svg-badge.svg)](https://hosted.weblate.org/engage/sequeler/?utm_source=widget) 6 | 7 | Sequeler is a native Linux SQL client built in Vala and Gtk. It allows you to connect to your local and remote databases, write SQL in a handy text editor with language recognition, and visualize SELECT results in a Gtk.Grid Widget. 8 | 9 | ![](data/assets/screenshots/sequeler-screenshot.png) 10 | 11 | ## Supported Databases 12 | - PostgreSQL 13 | - MariaDB/MySQL 14 | - SQLite 15 | 16 | ## Get it from the elementary OS AppCenter! 17 | Sequeler, is primarily available from the AppCenter of elementary OS. Download it from there! 18 | 19 | [![Get it on AppCenter](https://appcenter.elementary.io/badge.svg)](https://appcenter.elementary.io/com.github.alecaddd.sequeler) 20 | 21 | ## Get it from Flathub! 22 | You can get Sequeler form Flathub no matter what distribution you're using. Download it or follow the instructions to install it from here! 23 | 24 | Get it from Flathub! 25 | 26 | ## Support the Project 27 | If you like Sequeler and you want to support its development, consider donating via [PayPal](https://www.paypal.me/alecaddd) or pledge on [Patreon](https://www.patreon.com/alecaddd). 28 | 29 | Become a Patron Donate on PayPal 30 | 31 | ## Install it from source 32 | You can install Sequeler by compiling from source, here's the list of dependencies required: 33 | - `gtk+-3.0>=3.22.29` 34 | - `granite>=5.3` 35 | - `glib-2.0` 36 | - `gee-0.8` 37 | - `gobject-2.0` 38 | - `libxml-2.0` 39 | - `libgda-5.0` 40 | - `gtksourceview-4` 41 | - `libsecret-1` 42 | - `libssh2` 43 | - `meson` 44 | 45 | ## Building 46 | ``` 47 | meson build --prefix=/usr 48 | sudo ninja -C build install 49 | ``` 50 | 51 | ## Building development version 52 | The development version allows you to keep the stable version perfectly working while hacking on Sequeler. 53 | ``` 54 | meson build --prefix=/usr -Dprofile=development 55 | sudo ninja -C build install 56 | ``` 57 | 58 | You can run the application from terminal using 59 | ``` 60 | com.github.alecaddd.sequelerDevel 61 | ``` 62 | 63 | ### Help with the translation 64 | [![Translation status](https://hosted.weblate.org/widgets/sequeler/-/287x66-grey.png)](https://hosted.weblate.org/engage/sequeler/?utm_source=widget) 65 | 66 | ### Contributors 67 | - Alberto Fanjul - [Github](https://github.com/albfan) 68 | - Bilal Elmoussaoui - [Github](https://github.com/bilelmoussaoui) - [Paypal](https://www.paypal.me/BilalELMoussaoui) 69 | 70 | -------------------------------------------------------------------------------- /build-aux/com.github.alecaddd.sequeler.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "com.github.alecaddd.sequeler", 3 | "runtime": "org.gnome.Platform", 4 | "runtime-version": "48", 5 | "sdk": "org.gnome.Sdk", 6 | "base": "io.elementary.BaseApp", 7 | "base-version": "circe-24.08", 8 | "command": "com.github.alecaddd.sequeler", 9 | "finish-args": [ 10 | "--share=ipc", 11 | "--socket=fallback-x11", 12 | "--socket=wayland", 13 | "--talk-name=org.freedesktop.secrets", 14 | "--metadata=X-DConf=migrate-path=/com/github/alecaddd/sequeler/", 15 | "--share=network", 16 | "--filesystem=~/.ssh/:ro", 17 | "--socket=ssh-auth" 18 | ], 19 | "cleanup": [ 20 | "/include", 21 | "/lib/pkgconfig", 22 | "/lib/debug", 23 | "/share/vala", 24 | "/man", 25 | "*.a", 26 | "*.la" 27 | ], 28 | "build-options": { 29 | "libdir": "/app/lib" 30 | }, 31 | "modules": [ 32 | { 33 | "name": "gtksourceview", 34 | "buildsystem": "meson", 35 | "build-options": { 36 | "config-opts": [ 37 | "-Dgtk_doc=false" 38 | ] 39 | }, 40 | "sources": [ 41 | { 42 | "type": "archive", 43 | "url": "https://download.gnome.org/sources/gtksourceview/4.8/gtksourceview-4.8.4.tar.xz", 44 | "sha256": "7ec9d18fb283d1f84a3a3eff3b7a72b09a10c9c006597b3fbabbb5958420a87d" 45 | } 46 | ] 47 | }, 48 | { 49 | "name": "libgda", 50 | "build-options": { 51 | "config-opts": [ 52 | "--with-java=no", 53 | "--with-jni=no", 54 | "--with-oracle=no" 55 | ], 56 | "cflags": "-Wno-error=incompatible-pointer-types -Wno-error=implicit-function-declaration" 57 | }, 58 | "sources": [ 59 | { 60 | "type": "archive", 61 | "url": "https://download.gnome.org/sources/libgda/5.2/libgda-5.2.9.tar.xz", 62 | "sha256": "59caed8ca72b1ac6437c9844f0677f8a296d52cfd1c0049116026abfb1d87d9b" 63 | } 64 | ], 65 | "modules": [ 66 | { 67 | "name": "postgresql-libs", 68 | "build-options": { 69 | "config-opts": [ 70 | "--with-python=no", 71 | "--with-perl=no", 72 | "--with-libxml", 73 | "--with-openssl" 74 | ], 75 | "cflags": "-Wno-error=incompatible-pointer-types" 76 | }, 77 | "sources": [ 78 | { 79 | "type": "archive", 80 | "url": "https://ftp.postgresql.org/pub/source/v13.2/postgresql-13.2.tar.gz", 81 | "sha256": "3386a40736332aceb055c7c9012ecc665188536d874d967fcc5a33e7992f8080" 82 | } 83 | ] 84 | }, 85 | { 86 | "name": "jemalloc", 87 | "cleanup": [ 88 | "/bin/", 89 | "/share" 90 | ], 91 | "sources": [ 92 | { 93 | "type": "archive", 94 | "url": "https://github.com/jemalloc/jemalloc/releases/download/5.2.1/jemalloc-5.2.1.tar.bz2", 95 | "sha256": "34330e5ce276099e2e8950d9335db5a875689a4c6a56751ef3b1d8c537f887f6" 96 | } 97 | ] 98 | }, 99 | { 100 | "name": "libaio", 101 | "buildsystem": "simple", 102 | "build-options": { 103 | "arch": { 104 | "i386": { 105 | "cflags": "-march=x86-64 -mtune=generic -O2 -pipe -fno-stack-protector -fno-plt" 106 | } 107 | } 108 | }, 109 | "build-commands": [ 110 | "make", 111 | "make prefix=/app install" 112 | ], 113 | "sources": [ 114 | { 115 | "type": "archive", 116 | "url": "https://ftp.debian.org/debian/pool/main/liba/libaio/libaio_0.3.113.orig.tar.gz", 117 | "sha256": "2c44d1c5fd0d43752287c9ae1eb9c023f04ef848ea8d4aafa46e9aedb678200b" 118 | } 119 | ] 120 | }, 121 | { 122 | "name": "libfmt", 123 | "buildsystem": "cmake-ninja", 124 | "sources": [ 125 | { 126 | "type": "git", 127 | "url": "https://github.com/fmtlib/fmt.git", 128 | "tag": "8.1.1", 129 | "commit": "b6f4ceaed0a0a24ccf575fab6c56dd50ccf6f1a9" 130 | } 131 | ] 132 | }, 133 | { 134 | "name": "mariadb", 135 | "buildsystem": "cmake-ninja", 136 | "config-opts": [ 137 | "-DCMAKE_BUILD_TYPE=Release", 138 | "-DBUILD_CONFIG=mysql_release", 139 | "-DWITH_INNOBASE_STORAGE_ENGINE=1", 140 | "-DWITH_PCRE=system", 141 | "-DWITH_LIBFMT=system", 142 | "-DWITHOUT_ARCHIVE_STORAGE_ENGINE=1", 143 | "-DWITHOUT_BLACKHOLE_STORAGE_ENGINE=1", 144 | "-DWITHOUT_PARTITION_STORAGE_ENGINE=1", 145 | "-DWITHOUT_TOKUDB=1", 146 | "-DWITHOUT_EXAMPLE_STORAGE_ENGINE=1", 147 | "-DWITHOUT_FEDERATED_STORAGE_ENGINE=1", 148 | "-DWITHOUT_PBXT_STORAGE_ENGINE=1", 149 | "-DWITHOUT_SERVER=ON", 150 | "-DPLUGIN_AUTH_PAM=NO" 151 | ], 152 | "cleanup": [ 153 | "/bin/" 154 | ], 155 | "sources": [ 156 | { 157 | "type": "git", 158 | "url": "https://github.com/MariaDB/server.git", 159 | "tag": "mariadb-10.11.7", 160 | "commit": "87e13722a95af5d9378d990caf48cb6874439347" 161 | } 162 | ] 163 | }, 164 | { 165 | "name": "intltool", 166 | "cleanup": [ "*" ], 167 | "sources": [ 168 | { 169 | "type": "archive", 170 | "url": "https://launchpad.net/intltool/trunk/0.51.0/+download/intltool-0.51.0.tar.gz", 171 | "sha256": "67c74d94196b153b774ab9f89b2fa6c6ba79352407037c8c14d5aeb334e959cd" 172 | } 173 | ] 174 | } 175 | ] 176 | }, 177 | { 178 | "name": "libssh2", 179 | "sources": [ 180 | { 181 | "type": "archive", 182 | "url": "https://www.libssh2.org/download/libssh2-1.9.0.tar.gz", 183 | "sha256": "d5fb8bd563305fd1074dda90bd053fb2d29fc4bce048d182f96eaa466dfadafd" 184 | } 185 | ] 186 | }, 187 | { 188 | "name": "libfiposix", 189 | "sources": [ 190 | { 191 | "type": "archive", 192 | "url": "https://github.com/sionescu/libfixposix/archive/v0.4.3.tar.gz", 193 | "sha256": "78fe8bcebf496520ac29b5b65049f5ec1977c6bd956640bdc6d1da6ea04d8504" 194 | }, 195 | { 196 | "type": "script", 197 | "dest-filename": "autogen.sh", 198 | "commands": [ 199 | "autoreconf -vfi" 200 | ] 201 | } 202 | ] 203 | }, 204 | { 205 | "name": "sequeler", 206 | "buildsystem": "meson", 207 | "sources": [ 208 | { 209 | "type": "dir", 210 | "path": "../" 211 | } 212 | ] 213 | } 214 | ] 215 | } 216 | -------------------------------------------------------------------------------- /build-aux/meson_post_install.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import os 4 | import subprocess 5 | 6 | install_prefix = os.environ['MESON_INSTALL_PREFIX'] 7 | schemadir = os.path.join(install_prefix, 'share/glib-2.0/schemas') 8 | 9 | if not os.environ.get('DESTDIR'): 10 | print('Compiling gsettings schemas...') 11 | subprocess.call(['glib-compile-schemas', schemadir]) 12 | 13 | print('Updating icon cache...') 14 | icon_cache_dir = os.path.join(install_prefix, 'share/icons/hicolor') 15 | subprocess.call(['gtk-update-icon-cache', '-qtf', icon_cache_dir]) 16 | 17 | print('Updating desktop database...') 18 | desktop_database_dir = os.path.join(install_prefix, 'share/applications') 19 | subprocess.call(['update-desktop-database', '-q', desktop_database_dir]) 20 | -------------------------------------------------------------------------------- /com.github.alecaddd.sequeler.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "com.github.alecaddd.sequeler", 3 | "runtime": "io.elementary.Platform", 4 | "runtime-version": "8.1", 5 | "sdk": "io.elementary.Sdk", 6 | "command": "com.github.alecaddd.sequeler", 7 | "finish-args": [ 8 | "--share=ipc", 9 | "--socket=fallback-x11", 10 | "--socket=wayland", 11 | "--share=network", 12 | "--filesystem=~/.ssh/:ro", 13 | "--socket=ssh-auth" 14 | ], 15 | "cleanup": [ 16 | "/include", 17 | "/lib/pkgconfig", 18 | "/lib/debug", 19 | "/share/vala", 20 | "/man", 21 | "*.a", 22 | "*.la" 23 | ], 24 | "build-options": { 25 | "libdir": "/app/lib" 26 | }, 27 | "modules": [ 28 | { 29 | "name": "gtksourceview", 30 | "buildsystem": "meson", 31 | "build-options": { 32 | "config-opts": [ 33 | "-Dgtk_doc=false" 34 | ] 35 | }, 36 | "sources": [ 37 | { 38 | "type": "archive", 39 | "url": "https://download.gnome.org/sources/gtksourceview/4.8/gtksourceview-4.8.4.tar.xz", 40 | "sha256": "7ec9d18fb283d1f84a3a3eff3b7a72b09a10c9c006597b3fbabbb5958420a87d" 41 | } 42 | ] 43 | }, 44 | { 45 | "name": "libgda", 46 | "build-options": { 47 | "config-opts": [ 48 | "--with-java=no", 49 | "--with-jni=no", 50 | "--with-oracle=no" 51 | ], 52 | "cflags": "-Wno-error=incompatible-pointer-types -Wno-error=implicit-function-declaration" 53 | }, 54 | "sources": [ 55 | { 56 | "type": "archive", 57 | "url": "https://download.gnome.org/sources/libgda/5.2/libgda-5.2.9.tar.xz", 58 | "sha256": "59caed8ca72b1ac6437c9844f0677f8a296d52cfd1c0049116026abfb1d87d9b" 59 | } 60 | ], 61 | "modules": [ 62 | { 63 | "name": "postgresql-libs", 64 | "build-options": { 65 | "config-opts": [ 66 | "--with-python=no", 67 | "--with-perl=no", 68 | "--with-libxml", 69 | "--with-openssl" 70 | ], 71 | "cflags": "-Wno-error=incompatible-pointer-types" 72 | }, 73 | "sources": [ 74 | { 75 | "type": "archive", 76 | "url": "https://ftp.postgresql.org/pub/source/v13.2/postgresql-13.2.tar.gz", 77 | "sha256": "3386a40736332aceb055c7c9012ecc665188536d874d967fcc5a33e7992f8080" 78 | } 79 | ] 80 | }, 81 | { 82 | "name": "jemalloc", 83 | "cleanup": [ 84 | "/bin/", 85 | "/share" 86 | ], 87 | "sources": [ 88 | { 89 | "type": "archive", 90 | "url": "https://github.com/jemalloc/jemalloc/releases/download/5.2.1/jemalloc-5.2.1.tar.bz2", 91 | "sha256": "34330e5ce276099e2e8950d9335db5a875689a4c6a56751ef3b1d8c537f887f6" 92 | } 93 | ] 94 | }, 95 | { 96 | "name": "libaio", 97 | "buildsystem": "simple", 98 | "build-options": { 99 | "arch": { 100 | "i386": { 101 | "cflags": "-march=x86-64 -mtune=generic -O2 -pipe -fno-stack-protector -fno-plt" 102 | } 103 | } 104 | }, 105 | "build-commands": [ 106 | "make", 107 | "make prefix=/app install" 108 | ], 109 | "sources": [ 110 | { 111 | "type": "archive", 112 | "url": "https://ftp.debian.org/debian/pool/main/liba/libaio/libaio_0.3.113.orig.tar.gz", 113 | "sha256": "2c44d1c5fd0d43752287c9ae1eb9c023f04ef848ea8d4aafa46e9aedb678200b" 114 | } 115 | ] 116 | }, 117 | { 118 | "name": "libfmt", 119 | "buildsystem": "cmake-ninja", 120 | "sources": [ 121 | { 122 | "type": "git", 123 | "url": "https://github.com/fmtlib/fmt.git", 124 | "tag": "8.1.1", 125 | "commit": "b6f4ceaed0a0a24ccf575fab6c56dd50ccf6f1a9" 126 | } 127 | ] 128 | }, 129 | { 130 | "name": "mariadb", 131 | "buildsystem": "cmake-ninja", 132 | "config-opts": [ 133 | "-DCMAKE_BUILD_TYPE=Release", 134 | "-DBUILD_CONFIG=mysql_release", 135 | "-DWITH_INNOBASE_STORAGE_ENGINE=1", 136 | "-DWITH_PCRE=system", 137 | "-DWITH_LIBFMT=system", 138 | "-DWITHOUT_ARCHIVE_STORAGE_ENGINE=1", 139 | "-DWITHOUT_BLACKHOLE_STORAGE_ENGINE=1", 140 | "-DWITHOUT_PARTITION_STORAGE_ENGINE=1", 141 | "-DWITHOUT_TOKUDB=1", 142 | "-DWITHOUT_EXAMPLE_STORAGE_ENGINE=1", 143 | "-DWITHOUT_FEDERATED_STORAGE_ENGINE=1", 144 | "-DWITHOUT_PBXT_STORAGE_ENGINE=1", 145 | "-DWITHOUT_SERVER=ON", 146 | "-DPLUGIN_AUTH_PAM=NO" 147 | ], 148 | "cleanup": [ 149 | "/bin/" 150 | ], 151 | "sources": [ 152 | { 153 | "type": "git", 154 | "url": "https://github.com/MariaDB/server.git", 155 | "tag": "mariadb-10.11.7", 156 | "commit": "87e13722a95af5d9378d990caf48cb6874439347" 157 | } 158 | ] 159 | }, 160 | { 161 | "name": "intltool", 162 | "cleanup": [ "*" ], 163 | "sources": [ 164 | { 165 | "type": "archive", 166 | "url": "https://launchpad.net/intltool/trunk/0.51.0/+download/intltool-0.51.0.tar.gz", 167 | "sha256": "67c74d94196b153b774ab9f89b2fa6c6ba79352407037c8c14d5aeb334e959cd" 168 | } 169 | ] 170 | } 171 | ] 172 | }, 173 | { 174 | "name": "libssh2", 175 | "sources": [ 176 | { 177 | "type": "archive", 178 | "url": "https://www.libssh2.org/download/libssh2-1.9.0.tar.gz", 179 | "sha256": "d5fb8bd563305fd1074dda90bd053fb2d29fc4bce048d182f96eaa466dfadafd" 180 | } 181 | ] 182 | }, 183 | { 184 | "name": "libfiposix", 185 | "sources": [ 186 | { 187 | "type": "archive", 188 | "url": "https://github.com/sionescu/libfixposix/archive/v0.4.3.tar.gz", 189 | "sha256": "78fe8bcebf496520ac29b5b65049f5ec1977c6bd956640bdc6d1da6ea04d8504" 190 | }, 191 | { 192 | "type": "script", 193 | "dest-filename": "autogen.sh", 194 | "commands": [ 195 | "autoreconf -vfi" 196 | ] 197 | } 198 | ] 199 | }, 200 | { 201 | "name": "sequeler", 202 | "buildsystem": "meson", 203 | "sources": [ 204 | { 205 | "type": "dir", 206 | "path": "." 207 | } 208 | ] 209 | } 210 | ] 211 | } 212 | -------------------------------------------------------------------------------- /data/assets.gresource.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | stylesheet.css 5 | 6 | 7 | -------------------------------------------------------------------------------- /data/assets/screenshots/sequeler-screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ellie-commons/sequeler/0b964cbd6cad18787a6e8cbe57a77b6784b7f39d/data/assets/screenshots/sequeler-screenshot.png -------------------------------------------------------------------------------- /data/assets/screenshots/sequeler-screenshot1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ellie-commons/sequeler/0b964cbd6cad18787a6e8cbe57a77b6784b7f39d/data/assets/screenshots/sequeler-screenshot1.png -------------------------------------------------------------------------------- /data/assets/screenshots/sequeler-screenshot2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ellie-commons/sequeler/0b964cbd6cad18787a6e8cbe57a77b6784b7f39d/data/assets/screenshots/sequeler-screenshot2.png -------------------------------------------------------------------------------- /data/assets/sequeler-logo-transparent.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ellie-commons/sequeler/0b964cbd6cad18787a6e8cbe57a77b6784b7f39d/data/assets/sequeler-logo-transparent.png -------------------------------------------------------------------------------- /data/assets/sequeler.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ellie-commons/sequeler/0b964cbd6cad18787a6e8cbe57a77b6784b7f39d/data/assets/sequeler.png -------------------------------------------------------------------------------- /data/com.github.alecaddd.sequeler.desktop.in.in: -------------------------------------------------------------------------------- 1 | [Desktop Entry] 2 | Name=Sequeler 3 | GenericName=Sequeler App 4 | Comment=Friendly SQL Client 5 | Categories=Utility;Development; 6 | TryExec=@binary@ 7 | Exec=@binary@ %U 8 | Icon=@icon@ 9 | Terminal=false 10 | Type=Application 11 | Keywords=SQL;MySql;Database;MariaDB;S3;PostgreSQL; 12 | MimeType=application/x-sqlite3;application/vnd.sqlite3; 13 | StartupWMClass=Sequeler 14 | -------------------------------------------------------------------------------- /data/meson.build: -------------------------------------------------------------------------------- 1 | icon_sizes = ['16', '24', '32', '48', '64', '128'] 2 | 3 | icons_dir = join_paths(get_option('datadir'), 'icons', 'hicolor') 4 | foreach size : icon_sizes 5 | asset = join_paths('assets', 'icons', '@0@x@0@'.format(size), '@0@.svg'.format(meson.project_name())) 6 | install_data( 7 | asset, 8 | install_dir: join_paths(icons_dir, '@0@x@0@'.format(size), 'apps'), 9 | rename: '@0@.svg'.format(application_id) 10 | ) 11 | install_data( 12 | asset, 13 | install_dir: join_paths(icons_dir, '@0@x@0@@2'.format(size), 'apps'), 14 | rename: '@0@.svg'.format(application_id) 15 | ) 16 | endforeach 17 | 18 | install_data( 19 | join_paths('assets', 'icons', '128x128', '@0@.svg'.format(meson.project_name())), 20 | install_dir: join_paths(icons_dir , 'scalable', 'apps'), 21 | rename: '@0@.svg'.format(application_id) 22 | ) 23 | 24 | install_data( 25 | join_paths('assets', 'icons', 'status', 'table.svg'), 26 | install_dir: join_paths(icons_dir , '16x16', 'status'), 27 | ) 28 | 29 | install_data( 30 | join_paths('assets', 'icons', 'status', 'table-empty.svg'), 31 | install_dir: join_paths(icons_dir , '16x16', 'status'), 32 | ) 33 | 34 | install_data( 35 | join_paths('assets', 'icons', 'actions', 'office-database-new.svg'), 36 | install_dir: join_paths(icons_dir , '24x24', 'actions'), 37 | ) 38 | 39 | install_data( 40 | join_paths('assets', 'icons', 'actions', 'office-database-remove.svg'), 41 | install_dir: join_paths(icons_dir , '24x24', 'actions'), 42 | ) 43 | 44 | install_data( 45 | join_paths('assets', 'icons', 'actions', 'office-database-edit.svg'), 46 | install_dir: join_paths(icons_dir , '24x24', 'actions'), 47 | ) 48 | 49 | install_data( 50 | join_paths('assets', 'icons', 'actions', 'application-logout.svg'), 51 | install_dir: join_paths(icons_dir , '24x24', 'actions'), 52 | ) 53 | 54 | # Install the Desktop file 55 | desktop_conf = configuration_data() 56 | desktop_conf.set('icon', application_id) 57 | desktop_conf.set('binary', application_id) 58 | 59 | desktop_file = i18n.merge_file( 60 | input: configure_file( 61 | input: '@0@.desktop.in.in'.format(meson.project_name()), 62 | output: '@0@.desktop.in'.format(application_id), 63 | configuration: desktop_conf 64 | ), 65 | output:'@0@.desktop'.format(application_id), 66 | po_dir: join_paths(meson.source_root(), 'po', 'extra'), 67 | type: 'desktop', 68 | install: true, 69 | install_dir: join_paths(get_option('datadir'), 'applications') 70 | ) 71 | 72 | # Validate desktop file 73 | desktop_file_validate = find_program('desktop-file-validate', required: false) 74 | if desktop_file_validate.found() 75 | test( 76 | 'validate-desktop', 77 | desktop_file_validate, 78 | args: [ 79 | desktop_file.full_path() 80 | ] 81 | ) 82 | endif 83 | 84 | # Install the AppData file 85 | appdata_conf = configuration_data() 86 | appdata_conf.set('appid', application_id) 87 | 88 | appdata_file = i18n.merge_file( 89 | input: configure_file( 90 | input: '@0@.appdata.xml.in.in'.format(meson.project_name()), 91 | output: '@0@.appdata.xml.in'.format(application_id), 92 | configuration: appdata_conf 93 | ), 94 | output: '@0@.appdata.xml'.format(application_id), 95 | po_dir: join_paths(meson.source_root(), 'po'), 96 | install: true, 97 | install_dir: join_paths(get_option('datadir'), 'metainfo') 98 | ) 99 | 100 | # Validate AppData file 101 | appstream_util = find_program('appstream-util', required: false) 102 | if appstream_util.found() 103 | test( 104 | 'validate-appdata', appstream_util, 105 | args: [ 106 | 'validate-relax', appdata_file.full_path() 107 | ] 108 | ) 109 | endif 110 | -------------------------------------------------------------------------------- /data/stylesheet.css: -------------------------------------------------------------------------------- 1 | .text-bold { 2 | font-weight: 600; 3 | } 4 | 5 | .library-box { 6 | background-color: transparent; 7 | } 8 | 9 | .library-box:selected .library-btn { 10 | background-color: transparent; 11 | } 12 | 13 | .library-box:selected .library-btn image { 14 | color: @fg_color; 15 | } 16 | 17 | .library-inner-box { 18 | background: transparent; 19 | transition: background 320ms ease; 20 | color: @fg_color; 21 | } 22 | 23 | .library-inner-box .library-btn { 24 | opacity: 0; 25 | } 26 | 27 | .library-inner-box:hover { 28 | background: shade (@bg_color, 0.9); 29 | } 30 | 31 | .library-inner-box:hover .library-btn { 32 | opacity: 1; 33 | } 34 | 35 | .library-btn:active, 36 | .library-btn:focus { 37 | background-color: transparent; 38 | } 39 | 40 | .grid-motion { 41 | background-color: alpha (#3689e6, 0.25); 42 | border-radius: 4px; 43 | } 44 | 45 | .library-titlebar { 46 | border-bottom: 1px solid shade (@bg_color, 0.9); 47 | background: shade (@bg_color, 0.95); 48 | } 49 | 50 | .library-toolbar { 51 | background: shade (@bg_color, 0.95); 52 | border-top: 1px solid shade (@bg_color, 0.9); 53 | } 54 | 55 | .library-colorbox { 56 | border-radius: 12px; 57 | box-shadow: inset 0px 0px 0px 1px rgba(0, 0, 0, 0.2); 58 | } 59 | 60 | .toolbar-btn { 61 | background: transparent; 62 | border: none; 63 | box-shadow: none; 64 | } 65 | 66 | .toolbar-btn.active { 67 | background: shade (@bg_color, 0.9); 68 | opacity: 1; 69 | } 70 | 71 | .headerbar-separator { 72 | margin-right: 3px; 73 | margin-left: 3px; 74 | } 75 | 76 | infobar.inline revealer > box { 77 | box-shadow: inset 0 -1px 0 0 alpha (#fff, 0.4); 78 | border-width: 1px; 79 | border-radius: 4px; 80 | } 81 | 82 | .color-button radio, 83 | .color-button radio:checked { 84 | border-color: alpha (#000, 0.3); 85 | box-shadow: 86 | inset 0 1px 0 0 alpha (@inset_dark_color, 0.7), 87 | inset 0 0 0 1px alpha (@inset_dark_color, 0.3), 88 | 0 1px 0 0 alpha (@bg_highlight_color, 0.3); 89 | padding: 10px; 90 | -gtk-icon-shadow: none; 91 | } 92 | 93 | .color-button radio:focus { 94 | border-color: @colorAccent; 95 | box-shadow: 96 | inset 0 1px 0 0 alpha (@inset_dark_color, 0.7), 97 | inset 0 0 0 1px alpha (@inset_dark_color, 0.3), 98 | inset 0 0 0 1px alpha (@bg_highlight_color, 0.05), 99 | 0 1px 0 0 alpha (@bg_highlight_color, 0.3), 100 | 0 0 0 1px alpha (@colorAccent, 0.25); 101 | } 102 | 103 | .color-dark radio { 104 | background: #252E32; 105 | border-color: #151B1C; 106 | color: #fff; 107 | } 108 | 109 | .color-light radio { 110 | background: #fdf6e3; 111 | color: #4d4d4d; 112 | } 113 | 114 | .color-white radio { 115 | background: #fff; 116 | color: #000; 117 | } 118 | 119 | .query-error { 120 | background-color: alpha (@STRAWBERRY_300, 0.2); 121 | border: 1px solid @STRAWBERRY_500; 122 | border-radius: 4px; 123 | } 124 | 125 | button.notebook-temp-fix image { 126 | color: @selected_fg_color; 127 | } 128 | 129 | .database-panel-overlay { 130 | background-color: alpha (#000, 0.3); 131 | } 132 | 133 | .database-panel { 134 | border-radius: 3px; 135 | border: 1px solid alpha (#000, 0.3); 136 | box-shadow: 0 3px 1px -2px rgba(0,0,0,.2), 137 | 0 2px 2px 0 rgba(0,0,0,.14), 138 | 0 1px 5px 0 rgba(0,0,0,.12); 139 | text-shadow: none; 140 | background-color: shade (@base_color, 1.15); 141 | } 142 | 143 | .database-panel-bottom { 144 | background-color: alpha (#000, 0.1); 145 | box-shadow: inset 0 5px 5px -10px #000 146 | } 147 | -------------------------------------------------------------------------------- /meson.build: -------------------------------------------------------------------------------- 1 | # project name and programming language 2 | project('com.github.alecaddd.sequeler', 'vala', 'c', 3 | version: '0.8.2') 4 | 5 | cc = meson.get_compiler('c') 6 | m_dep = cc.find_library('m', required: true) 7 | 8 | vala_args = ['--pkg', 'posix'] 9 | 10 | add_project_arguments( 11 | ['--vapidir', join_paths(meson.current_source_dir(), 'vapi')], 12 | language: 'vala' 13 | ) 14 | 15 | if get_option('profile') == 'development' 16 | application_id = '@0@Devel'.format(meson.project_name()) 17 | vala_args += ['-D', 'IS_DEVEL'] 18 | else 19 | application_id = meson.project_name() 20 | endif 21 | 22 | linux_dep = meson.get_compiler('vala').find_library('linux') 23 | 24 | # Include the translations module 25 | i18n = import('i18n') 26 | 27 | # Include the gnome module 28 | gnome = import('gnome') 29 | asresources = gnome.compile_resources( 30 | 'as-resources', 'data/assets.gresource.xml', 31 | source_dir: 'data', 32 | c_name: 'as' 33 | ) 34 | 35 | # Set our translation domain 36 | add_global_arguments('-DGETTEXT_PACKAGE="@0@"'.format (meson.project_name()), language: 'c') 37 | 38 | vala_lint = find_program('io.elementary.vala-lint', required : false) 39 | if vala_lint.found() 40 | test ( 41 | 'Vala lint', 42 | vala_lint, 43 | args: ['-d', join_paths(meson.source_root(), 'src')] 44 | ) 45 | endif 46 | 47 | subdir('src') 48 | subdir('data') 49 | subdir('po') 50 | subdir('schemas') 51 | 52 | meson.add_install_script('build-aux/meson_post_install.py') 53 | -------------------------------------------------------------------------------- /meson_options.txt: -------------------------------------------------------------------------------- 1 | option( 2 | 'profile', 3 | type: 'combo', 4 | choices: [ 5 | 'default', 6 | 'development' 7 | ], 8 | value: 'default' 9 | ) 10 | -------------------------------------------------------------------------------- /po/LINGUAS: -------------------------------------------------------------------------------- 1 | ca 2 | de 3 | es 4 | fr 5 | id 6 | it 7 | lg 8 | lt 9 | pt_BR 10 | ru 11 | tr 12 | ja 13 | zh_Hans 14 | ar_EG 15 | pt 16 | uk 17 | cs 18 | zh_Hant 19 | ars 20 | pl 21 | hi 22 | ta 23 | et 24 | -------------------------------------------------------------------------------- /po/POTFILES: -------------------------------------------------------------------------------- 1 | src/Main.vala 2 | src/Application.vala 3 | src/Window.vala 4 | 5 | src/Layouts/HeaderBar.vala 6 | src/Layouts/Main.vala 7 | src/Layouts/Library.vala 8 | src/Layouts/Welcome.vala 9 | src/Layouts/DataBaseSchema.vala 10 | src/Layouts/DataBaseView.vala 11 | src/Layouts/Views/Structure.vala 12 | src/Layouts/Views/Content.vala 13 | src/Layouts/Views/Relations.vala 14 | src/Layouts/Views/Query.vala 15 | 16 | src/Partials/ButtonType.vala 17 | src/Partials/Helpers.vala 18 | src/Partials/LibraryItem.vala 19 | src/Partials/TreeBuilder.vala 20 | 21 | src/Services/Settings.vala 22 | src/Services/ActionManager.vala 23 | src/Services/DataManager.vala 24 | src/Services/ConnectionManager.vala 25 | src/Services/Types/DataBaseType.vala 26 | src/Services/Types/MySQL.vala 27 | src/Services/Types/PostgreSQL.vala 28 | src/Services/Types/SQLite.vala 29 | 30 | src/Widgets/ConnectionDialog.vala 31 | -------------------------------------------------------------------------------- /po/com.github.alecaddd.sequeler.pot: -------------------------------------------------------------------------------- 1 | # SOME DESCRIPTIVE TITLE. 2 | # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER 3 | # This file is distributed under the same license as the com.github.alecaddd.sequeler package. 4 | # FIRST AUTHOR , YEAR. 5 | # 6 | #, fuzzy 7 | msgid "" 8 | msgstr "" 9 | "Project-Id-Version: com.github.alecaddd.sequeler\n" 10 | "Report-Msgid-Bugs-To: \n" 11 | "POT-Creation-Date: 2025-06-03 22:03+0900\n" 12 | "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" 13 | "Last-Translator: FULL NAME \n" 14 | "Language-Team: LANGUAGE \n" 15 | "Language: \n" 16 | "MIME-Version: 1.0\n" 17 | "Content-Type: text/plain; charset=UTF-8\n" 18 | "Content-Transfer-Encoding: 8bit\n" 19 | 20 | #: src/Application.vala:67 21 | msgid "Directories are not supported" 22 | msgstr "" 23 | 24 | #: src/Application.vala:73 25 | msgid "Don't know what to do" 26 | msgstr "" 27 | 28 | #: src/Application.vala:85 29 | msgid "Something completely unexpected happened" 30 | msgstr "" 31 | 32 | #: src/Layouts/HeaderBar.vala:52 33 | msgid "Logout" 34 | msgstr "" 35 | 36 | #: src/Layouts/HeaderBar.vala:57 37 | msgid "Create a new database" 38 | msgstr "" 39 | 40 | #: src/Layouts/HeaderBar.vala:66 41 | msgid "Delete database" 42 | msgstr "" 43 | 44 | #: src/Layouts/HeaderBar.vala:75 45 | msgid "Database properties" 46 | msgstr "" 47 | 48 | #: src/Layouts/HeaderBar.vala:89 49 | msgid "Light background" 50 | msgstr "" 51 | 52 | #: src/Layouts/HeaderBar.vala:90 53 | msgid "Dark background" 54 | msgstr "" 55 | 56 | #: src/Layouts/HeaderBar.vala:101 src/Layouts/Welcome.vala:39 57 | msgid "New Window" 58 | msgstr "" 59 | 60 | #: src/Layouts/HeaderBar.vala:104 src/Widgets/ConnectionDialog.vala:135 61 | #: src/Widgets/ConnectionDialog.vala:170 62 | msgid "New Connection" 63 | msgstr "" 64 | 65 | #: src/Layouts/HeaderBar.vala:107 66 | msgid "Quit" 67 | msgstr "" 68 | 69 | #: src/Layouts/HeaderBar.vala:127 70 | msgid "Menu" 71 | msgstr "" 72 | 73 | #: src/Layouts/Main.vala:77 74 | #, c-format 75 | msgid "Connected to %s" 76 | msgstr "" 77 | 78 | #: src/Layouts/Library.vala:65 79 | msgid "SAVED CONNECTIONS" 80 | msgstr "" 81 | 82 | #: src/Layouts/Library.vala:74 83 | msgid "Delete All" 84 | msgstr "" 85 | 86 | #: src/Layouts/Library.vala:81 87 | msgid "Reload Library" 88 | msgstr "" 89 | 90 | #: src/Layouts/Library.vala:84 91 | msgid "Export Library" 92 | msgstr "" 93 | 94 | #: src/Layouts/Library.vala:215 src/Layouts/Library.vala:233 95 | msgid "Are you sure you want to proceed?" 96 | msgstr "" 97 | 98 | #: src/Layouts/Library.vala:215 99 | msgid "By deleting this connection you won’t be able to recover this data." 100 | msgstr "" 101 | 102 | #: src/Layouts/Library.vala:218 src/Services/ActionManager.vala:257 103 | msgid "Yes, Delete!" 104 | msgstr "" 105 | 106 | #: src/Layouts/Library.vala:233 107 | msgid "All the data will be deleted and you won’t be able to recover it." 108 | msgstr "" 109 | 110 | #: src/Layouts/Library.vala:236 111 | msgid "Yes, Delete All!" 112 | msgstr "" 113 | 114 | #: src/Layouts/Library.vala:335 src/Widgets/ConnectionDialog.vala:602 115 | #: src/Widgets/ConnectionDialog.vala:623 116 | msgid "A username is required in order to connect!" 117 | msgstr "" 118 | 119 | #: src/Layouts/Library.vala:409 src/Layouts/Views/Query.vala:555 120 | msgid "Pick a file" 121 | msgstr "" 122 | 123 | #: src/Layouts/Library.vala:412 src/Layouts/Views/Query.vala:558 124 | msgid "_Save" 125 | msgstr "" 126 | 127 | #: src/Layouts/Library.vala:413 src/Layouts/Welcome.vala:62 128 | #: src/Layouts/Views/Query.vala:559 129 | msgid "_Cancel" 130 | msgstr "" 131 | 132 | #: src/Layouts/Library.vala:472 133 | #, c-format 134 | msgid "Unable to Connect to %s" 135 | msgstr "" 136 | 137 | #: src/Layouts/Library.vala:485 138 | msgid "Unable to Export Library " 139 | msgstr "" 140 | 141 | #: src/Layouts/Welcome.vala:28 142 | msgid "Welcome to Sequeler" 143 | msgstr "" 144 | 145 | #: src/Layouts/Welcome.vala:29 146 | msgid "Connect to Any Local or Remote Database." 147 | msgstr "" 148 | 149 | #: src/Layouts/Welcome.vala:38 150 | msgid "Add a New Database" 151 | msgstr "" 152 | 153 | #: src/Layouts/Welcome.vala:38 154 | msgid "Connect to a Database and Save It in Your Library" 155 | msgstr "" 156 | 157 | #: src/Layouts/Welcome.vala:39 158 | msgid "Open a New Sequeler Window" 159 | msgstr "" 160 | 161 | #: src/Layouts/Welcome.vala:40 162 | msgid "Import Connections" 163 | msgstr "" 164 | 165 | #: src/Layouts/Welcome.vala:40 166 | msgid "Import Previously Exported Sequeler Connections" 167 | msgstr "" 168 | 169 | #: src/Layouts/Welcome.vala:58 170 | msgid "Select a file" 171 | msgstr "" 172 | 173 | #: src/Layouts/Welcome.vala:61 174 | msgid "_Open" 175 | msgstr "" 176 | 177 | #: src/Layouts/Welcome.vala:107 178 | msgid "Unable to Import Library " 179 | msgstr "" 180 | 181 | #: src/Layouts/DataBaseSchema.vala:80 182 | msgid "Search Tables" 183 | msgstr "" 184 | 185 | #: src/Layouts/DataBaseSchema.vala:92 186 | msgid "Search Tables…" 187 | msgstr "" 188 | 189 | #: src/Layouts/DataBaseSchema.vala:114 190 | msgid "Reload Tables" 191 | msgstr "" 192 | 193 | #: src/Layouts/DataBaseSchema.vala:119 194 | msgid "Add Table" 195 | msgstr "" 196 | 197 | #: src/Layouts/DataBaseSchema.vala:176 198 | msgid "- Select Database -" 199 | msgstr "" 200 | 201 | #: src/Layouts/DataBaseSchema.vala:298 202 | msgid "TABLES" 203 | msgstr "" 204 | 205 | #: src/Layouts/DataBaseView.vala:49 206 | msgid "Structure" 207 | msgstr "" 208 | 209 | #: src/Layouts/DataBaseView.vala:50 210 | msgid "Content" 211 | msgstr "" 212 | 213 | #: src/Layouts/DataBaseView.vala:51 214 | msgid "Relations" 215 | msgstr "" 216 | 217 | #: src/Layouts/DataBaseView.vala:52 src/Layouts/DataBaseView.vala:228 218 | #: src/Layouts/DataBaseView.vala:256 219 | msgid "Query" 220 | msgstr "" 221 | 222 | #: src/Layouts/DataBaseView.vala:100 223 | msgid "Zoom Out" 224 | msgstr "" 225 | 226 | #: src/Layouts/DataBaseView.vala:106 227 | msgid "Zoom 1:1" 228 | msgstr "" 229 | 230 | #: src/Layouts/DataBaseView.vala:110 231 | msgid "Zoom In" 232 | msgstr "" 233 | 234 | #: src/Layouts/DataBaseView.vala:123 235 | msgid "High Contrast" 236 | msgstr "" 237 | 238 | #: src/Layouts/DataBaseView.vala:131 239 | msgid "Solarized Light" 240 | msgstr "" 241 | 242 | #: src/Layouts/DataBaseView.vala:139 243 | msgid "Solarized Dark" 244 | msgstr "" 245 | 246 | #: src/Layouts/DataBaseView.vala:162 247 | msgid "Change Text Style" 248 | msgstr "" 249 | 250 | #: src/Layouts/DataBaseView.vala:221 251 | msgid "Create a new Query Tab" 252 | msgstr "" 253 | 254 | #: src/Layouts/DataBaseView.vala:241 255 | #, c-format 256 | msgid "Query %i" 257 | msgstr "" 258 | 259 | #: src/Layouts/Views/Structure.vala:78 src/Layouts/Views/Content.vala:89 260 | #: src/Layouts/Views/Relations.vala:77 261 | msgid "Select Table" 262 | msgstr "" 263 | 264 | #: src/Layouts/Views/Structure.vala:78 src/Layouts/Views/Content.vala:89 265 | #: src/Layouts/Views/Relations.vala:77 266 | msgid "Select a table from the left sidebar to activate this view." 267 | msgstr "" 268 | 269 | #: src/Layouts/Views/Structure.vala:108 src/Layouts/Views/Structure.vala:146 270 | #: src/Layouts/Views/Content.vala:180 src/Layouts/Views/Content.vala:219 271 | #: src/Layouts/Views/Relations.vala:107 src/Layouts/Views/Relations.vala:145 272 | #: src/Layouts/Views/Query.vala:317 273 | msgid "No Results Available" 274 | msgstr "" 275 | 276 | #: src/Layouts/Views/Structure.vala:119 src/Layouts/Views/Content.vala:192 277 | #: src/Layouts/Views/Relations.vala:118 278 | msgid "Reload Results" 279 | msgstr "" 280 | 281 | #: src/Layouts/Views/Structure.vala:198 282 | msgid " Fields" 283 | msgstr "" 284 | 285 | #: src/Layouts/Views/Content.vala:122 286 | msgid "Previous Page" 287 | msgstr "" 288 | 289 | #: src/Layouts/Views/Content.vala:127 290 | msgid "Next Page" 291 | msgstr "" 292 | 293 | #: src/Layouts/Views/Content.vala:132 294 | #, c-format 295 | msgid "%d Pages" 296 | msgstr "" 297 | 298 | #: src/Layouts/Views/Content.vala:135 299 | msgid "Jump to page…" 300 | msgstr "" 301 | 302 | #: src/Layouts/Views/Content.vala:166 303 | msgid "1 Page" 304 | msgstr "" 305 | 306 | #: src/Layouts/Views/Content.vala:172 307 | #, c-format 308 | msgid "%d of %d Pages" 309 | msgstr "" 310 | 311 | #: src/Layouts/Views/Content.vala:276 312 | #, c-format 313 | msgid "%d Entries" 314 | msgstr "" 315 | 316 | #: src/Layouts/Views/Relations.vala:198 317 | msgid " Constraints" 318 | msgstr "" 319 | 320 | #: src/Layouts/Views/Query.vala:280 321 | msgid "Running Query…" 322 | msgstr "" 323 | 324 | #: src/Layouts/Views/Query.vala:350 325 | msgid "Export Results" 326 | msgstr "" 327 | 328 | #: src/Layouts/Views/Query.vala:363 329 | msgid "Export as CSV" 330 | msgstr "" 331 | 332 | #: src/Layouts/Views/Query.vala:371 333 | msgid "Export as Text" 334 | msgstr "" 335 | 336 | #: src/Layouts/Views/Query.vala:463 src/Layouts/Views/Query.vala:509 337 | msgid "Unable to process Query!" 338 | msgstr "" 339 | 340 | #: src/Layouts/Views/Query.vala:484 341 | #, c-format 342 | msgid "%d Total Results" 343 | msgstr "" 344 | 345 | #: src/Layouts/Views/Query.vala:519 346 | #, c-format 347 | msgid "Query Successfully Executed! Rows Affected: %s" 348 | msgstr "" 349 | 350 | #: src/Layouts/Views/Query.vala:522 351 | msgid "Query Executed!" 352 | msgstr "" 353 | 354 | #: src/Partials/Helpers.vala:130 src/Partials/Helpers.vala:136 355 | msgid "Run Query" 356 | msgstr "" 357 | 358 | #: src/Partials/LibraryItem.vala:107 src/Widgets/ConnectionDialog.vala:443 359 | msgid "Connect" 360 | msgstr "" 361 | 362 | #: src/Partials/LibraryItem.vala:110 363 | msgid "Edit Connection" 364 | msgstr "" 365 | 366 | #: src/Partials/LibraryItem.vala:113 367 | msgid "Duplicate Connection" 368 | msgstr "" 369 | 370 | #: src/Partials/LibraryItem.vala:116 371 | msgid "Delete Connection" 372 | msgstr "" 373 | 374 | #: src/Partials/LibraryItem.vala:126 375 | msgid "Options" 376 | msgstr "" 377 | 378 | #: src/Partials/TreeBuilder.vala:132 379 | msgid "Error" 380 | msgstr "" 381 | 382 | #: src/Partials/TreeBuilder.vala:132 383 | msgid "on Column" 384 | msgstr "" 385 | 386 | #: src/Partials/TreeBuilder.vala:173 387 | #, c-format 388 | msgid "Copy %s" 389 | msgstr "" 390 | 391 | #: src/Services/Settings.vala:103 392 | #, c-format 393 | msgid "%s (copy)" 394 | msgstr "" 395 | 396 | #: src/Services/ActionManager.vala:254 397 | msgid "Are you sure you want to delete this Database?" 398 | msgstr "" 399 | 400 | #: src/Services/ActionManager.vala:254 401 | msgid "" 402 | "All the tables and data will be deleted and you won’t be able to recover it." 403 | msgstr "" 404 | 405 | #: src/Services/ConnectionManager.vala:193 406 | #, c-format 407 | msgid "Libssh2 initialization failed (%d)" 408 | msgstr "" 409 | 410 | #: src/Services/ConnectionManager.vala:202 411 | msgid "Failed to open socket" 412 | msgstr "" 413 | 414 | #: src/Services/ConnectionManager.vala:211 415 | msgid "Failed to connect!" 416 | msgstr "" 417 | 418 | #: src/Services/ConnectionManager.vala:223 419 | #, c-format 420 | msgid "Error when starting up SSH session: %d" 421 | msgstr "" 422 | 423 | #: src/Services/ConnectionManager.vala:242 424 | msgid "Authentication by password failed!" 425 | msgstr "" 426 | 427 | #: src/Services/ConnectionManager.vala:252 428 | msgid "Authentication by public key failed!" 429 | msgstr "" 430 | 431 | #: src/Services/ConnectionManager.vala:259 432 | msgid "No supported authentication methods found!" 433 | msgstr "" 434 | 435 | #: src/Services/ConnectionManager.vala:266 436 | msgid "Failed to open listen socket" 437 | msgstr "" 438 | 439 | #: src/Services/ConnectionManager.vala:281 440 | msgid "Failed to bind. Your Database Port may be wrong!" 441 | msgstr "" 442 | 443 | #: src/Services/ConnectionManager.vala:287 444 | msgid "Failed to listen!" 445 | msgstr "" 446 | 447 | #: src/Services/ConnectionManager.vala:314 448 | msgid "Failed to accept remote connection!" 449 | msgstr "" 450 | 451 | #: src/Services/ConnectionManager.vala:323 452 | msgid "" 453 | "Could not open the direct-tcpip channel! (Note that this can be a problem at " 454 | "the server! Please review the server logs.)" 455 | msgstr "" 456 | 457 | #: src/Services/ConnectionManager.vala:578 458 | msgid "Error!" 459 | msgstr "" 460 | 461 | #: src/Widgets/ConnectionDialog.vala:35 462 | msgid "Missing SSH Key file!" 463 | msgstr "" 464 | 465 | #: src/Widgets/ConnectionDialog.vala:36 466 | msgid "Missing SSH public key!" 467 | msgstr "" 468 | 469 | #: src/Widgets/ConnectionDialog.vala:94 src/Widgets/ConnectionDialog.vala:369 470 | msgid "Connection" 471 | msgstr "" 472 | 473 | #: src/Widgets/ConnectionDialog.vala:146 474 | msgid "Select connection color" 475 | msgstr "" 476 | 477 | #: src/Widgets/ConnectionDialog.vala:169 478 | msgid "Connection Name:" 479 | msgstr "" 480 | 481 | #: src/Widgets/ConnectionDialog.vala:170 482 | msgid "Connection's name" 483 | msgstr "" 484 | 485 | #: src/Widgets/ConnectionDialog.vala:177 486 | msgid "Database Type:" 487 | msgstr "" 488 | 489 | #: src/Widgets/ConnectionDialog.vala:199 490 | msgid "Host:" 491 | msgstr "" 492 | 493 | #: src/Widgets/ConnectionDialog.vala:205 494 | msgid "Database Name:" 495 | msgstr "" 496 | 497 | #: src/Widgets/ConnectionDialog.vala:212 498 | msgid "Username:" 499 | msgstr "" 500 | 501 | #: src/Widgets/ConnectionDialog.vala:218 502 | msgid "Password:" 503 | msgstr "" 504 | 505 | #: src/Widgets/ConnectionDialog.vala:222 src/Widgets/ConnectionDialog.vala:232 506 | #: src/Widgets/ConnectionDialog.vala:299 src/Widgets/ConnectionDialog.vala:309 507 | msgid "Show password" 508 | msgstr "" 509 | 510 | #: src/Widgets/ConnectionDialog.vala:229 src/Widgets/ConnectionDialog.vala:306 511 | msgid "Hide password" 512 | msgstr "" 513 | 514 | #: src/Widgets/ConnectionDialog.vala:239 515 | msgid "Port:" 516 | msgstr "" 517 | 518 | #: src/Widgets/ConnectionDialog.vala:245 519 | msgid "Use SSL:" 520 | msgstr "" 521 | 522 | #: src/Widgets/ConnectionDialog.vala:254 523 | msgid "File Path:" 524 | msgstr "" 525 | 526 | #: src/Widgets/ConnectionDialog.vala:255 527 | msgid "Select Your SQLite File…" 528 | msgstr "" 529 | 530 | #: src/Widgets/ConnectionDialog.vala:275 531 | msgid "Connect via SSH Tunnel:" 532 | msgstr "" 533 | 534 | #: src/Widgets/ConnectionDialog.vala:285 535 | msgid "SSH Host:" 536 | msgstr "" 537 | 538 | #: src/Widgets/ConnectionDialog.vala:290 539 | msgid "SSH Username:" 540 | msgstr "" 541 | 542 | #: src/Widgets/ConnectionDialog.vala:295 543 | msgid "SSH Password:" 544 | msgstr "" 545 | 546 | #: src/Widgets/ConnectionDialog.vala:315 547 | msgid "SSH Port:" 548 | msgstr "" 549 | 550 | #: src/Widgets/ConnectionDialog.vala:316 551 | msgid "Optional" 552 | msgstr "" 553 | 554 | #: src/Widgets/ConnectionDialog.vala:320 555 | msgid "SSH Identity" 556 | msgstr "" 557 | 558 | #: src/Widgets/ConnectionDialog.vala:322 559 | msgid "Select Your Identity File…" 560 | msgstr "" 561 | 562 | #: src/Widgets/ConnectionDialog.vala:338 563 | msgid "Generate SSH Key" 564 | msgstr "" 565 | 566 | #: src/Widgets/ConnectionDialog.vala:370 567 | msgid "SSH Tunnel" 568 | msgstr "" 569 | 570 | #: src/Widgets/ConnectionDialog.vala:440 571 | msgid "Close" 572 | msgstr "" 573 | 574 | #: src/Widgets/ConnectionDialog.vala:441 575 | msgid "Save Connection" 576 | msgstr "" 577 | 578 | #: src/Widgets/ConnectionDialog.vala:442 579 | msgid "Test Connection" 580 | msgstr "" 581 | 582 | #: src/Widgets/ConnectionDialog.vala:647 583 | msgid "Opening SSH Tunnel…" 584 | msgstr "" 585 | 586 | #: src/Widgets/ConnectionDialog.vala:683 587 | msgid "Testing Connection…" 588 | msgstr "" 589 | 590 | #: src/Widgets/ConnectionDialog.vala:705 591 | msgid "Successfully Connected!" 592 | msgstr "" 593 | 594 | #: src/Widgets/ConnectionDialog.vala:714 595 | msgid "Saving Connection…" 596 | msgstr "" 597 | 598 | #: src/Widgets/ConnectionDialog.vala:719 599 | msgid "Connection Saved!" 600 | msgstr "" 601 | 602 | #: src/Widgets/ConnectionDialog.vala:727 603 | msgid "Connecting…" 604 | msgstr "" 605 | -------------------------------------------------------------------------------- /po/extra/LINGUAS: -------------------------------------------------------------------------------- 1 | de 2 | fr 3 | lt 4 | ja 5 | et 6 | -------------------------------------------------------------------------------- /po/extra/POTFILES: -------------------------------------------------------------------------------- 1 | data/com.github.alecaddd.sequeler.desktop.in.in 2 | data/com.github.alecaddd.sequeler.appdata.xml.in.in 3 | -------------------------------------------------------------------------------- /po/extra/meson.build: -------------------------------------------------------------------------------- 1 | i18n.gettext('extra', 2 | args: [ 3 | '--directory=' + meson.source_root(), 4 | '--from-code=UTF-8' 5 | ], 6 | install: false 7 | ) 8 | -------------------------------------------------------------------------------- /po/meson.build: -------------------------------------------------------------------------------- 1 | i18n.gettext(meson.project_name(), 2 | args: [ 3 | '--directory=' + meson.source_root(), 4 | '--from-code=UTF-8' 5 | ] 6 | ) 7 | 8 | subdir('extra') 9 | -------------------------------------------------------------------------------- /schemas/com.github.alecaddd.sequeler.gschema.xml.in: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 360 5 | The saved horizontal position of the window. 6 | The saved horizontal position of the window. 7 | 8 | 9 | 10 | 360 11 | The vertical position width of the window. 12 | The saved vertical position of the window. 13 | 14 | 15 | 16 | 900 17 | The saved width of the window. 18 | The saved width of the window. Must be greater than 750, or it will not take effect. 19 | 20 | 21 | 22 | 600 23 | The saved height of the window. 24 | The saved height of the window. Must be greater than 500, or it will not take effect. 25 | 26 | 27 | 28 | 260 29 | The saved width of the sidebar pane. 30 | The saved width of the sidebar pane containing the connections library and database schema. 31 | 32 | 33 | 34 | 0 35 | Total amount of saved connections. 36 | Increase the amount at every new connection, set a unique ID for every connection. 37 | 38 | 39 | 40 | 1000 41 | Max rows to show in Content tab. 42 | Split results based on max amount, helps generate the pagination. 43 | 44 | 45 | 46 | [] 47 | The saved configured conenctions 48 | All the configured connections you saved are here 49 | 50 | 51 | 52 | true 53 | Save Quick Connections 54 | Automatically Save a Quick Connections into the Database Library. 55 | 56 | 57 | 58 | false 59 | Use dark theme 60 | Switch between Light and Dark theme. 61 | 62 | 63 | 64 | "" 65 | Current Version 66 | Check current App version for upgrades on startup. 67 | 68 | 69 | 70 | true 71 | Use system font 72 | Whether Sequeler should use the default system font 73 | 74 | 75 | 76 | 'Droid Sans Mono 12' 77 | Preferred Font 78 | Set the preferred font. 79 | 80 | 81 | 82 | 'solarized-light' 83 | Preferred Style Scheme 84 | Set the preferred style scheme. 85 | 86 | 87 | 88 | 200 89 | Query tab height. 90 | Controls the height of the Query tab. 91 | 92 | 93 | 94 | -------------------------------------------------------------------------------- /schemas/meson.build: -------------------------------------------------------------------------------- 1 | schema_path = '/com/github/alecaddd/sequeler/' 2 | if get_option('profile') == 'development' 3 | schema_path += 'Devel/' 4 | endif 5 | 6 | schema_conf = configuration_data() 7 | schema_conf.set('appid', application_id) 8 | schema_conf.set('schema-path', schema_path) 9 | 10 | configure_file( 11 | input: '@0@.gschema.xml.in'.format(meson.project_name()), 12 | output: '@0@.gschema.xml'.format(application_id), 13 | install: true, 14 | install_dir: join_paths(get_option('datadir'), 'glib-2.0', 'schemas'), 15 | configuration:schema_conf 16 | ) 17 | -------------------------------------------------------------------------------- /src/Application.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2011-2018 Alecaddd (http://alecaddd.com) 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 2 of the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public 15 | * License along with this program; if not, write to the 16 | * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 17 | * Boston, MA 02110-1301 USA 18 | * 19 | * Authored by: Alessandro "Alecaddd" Castellani 20 | */ 21 | 22 | namespace Sequeler { 23 | public Sequeler.Services.Settings settings; 24 | public Sequeler.Services.PasswordManager password_mngr; 25 | public Sequeler.Services.UpgradeManager upgrade_mngr; 26 | public Secret.Schema schema; 27 | } 28 | 29 | public class Sequeler.Application : Gtk.Application { 30 | public GLib.List windows; 31 | 32 | construct { 33 | application_id = Constants.PROJECT_NAME; 34 | flags |= ApplicationFlags.HANDLES_OPEN; 35 | 36 | GLib.Intl.setlocale (LocaleCategory.ALL, ""); 37 | GLib.Intl.bindtextdomain (Constants.GETTEXT_PACKAGE, Constants.LOCALEDIR); 38 | GLib.Intl.bind_textdomain_codeset (Constants.GETTEXT_PACKAGE, "UTF-8"); 39 | GLib.Intl.textdomain (Constants.GETTEXT_PACKAGE); 40 | 41 | schema = new Secret.Schema (Constants.PROJECT_NAME, Secret.SchemaFlags.NONE, 42 | "id", Secret.SchemaAttributeType.INTEGER, 43 | "schema", Secret.SchemaAttributeType.STRING); 44 | 45 | settings = new Sequeler.Services.Settings (); 46 | password_mngr = new Sequeler.Services.PasswordManager (); 47 | upgrade_mngr = new Sequeler.Services.UpgradeManager (); 48 | 49 | windows = new GLib.List (); 50 | } 51 | 52 | public void new_window () { 53 | new Sequeler.Window (this).present (); 54 | } 55 | 56 | public override void window_added (Gtk.Window window) { 57 | windows.append (window as Window); 58 | base.window_added (window); 59 | } 60 | 61 | protected override void open (File[] files, string hint) { 62 | foreach (var file in files) { 63 | var type = file.query_file_type (FileQueryInfoFlags.NONE); 64 | 65 | switch (type) { 66 | case FileType.DIRECTORY: // File handle represents a directory. 67 | critical (_("Directories are not supported")); 68 | continue; 69 | 70 | case FileType.UNKNOWN: // File's type is unknown 71 | case FileType.SPECIAL: // File is a "special" file, such as a socket, fifo, block device, or character device. 72 | case FileType.MOUNTABLE: // File is a mountable location. 73 | critical (_("Don't know what to do")); 74 | continue; 75 | 76 | case FileType.REGULAR: // File handle represents a regular file. 77 | case FileType.SYMBOLIC_LINK: // File handle represents a symbolic link (Unix systems). 78 | case FileType.SHORTCUT: // File is a shortcut (Windows systems). 79 | var window = this.add_new_window (); 80 | 81 | window.main.library.check_open_sqlite_file (file.get_uri (), file.get_basename ()); 82 | break; 83 | 84 | default: 85 | error (_("Something completely unexpected happened")); 86 | } 87 | } 88 | } 89 | 90 | public override void window_removed (Gtk.Window window) { 91 | windows.remove (window as Window); 92 | base.window_removed (window); 93 | } 94 | 95 | private Sequeler.Window add_new_window () { 96 | var window = new Sequeler.Window (this); 97 | this.add_window (window); 98 | 99 | return window; 100 | } 101 | 102 | protected override void activate () { 103 | this.add_new_window (); 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /src/Layouts/DataBaseView.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2011-2018 Alecaddd (http://alecaddd.com) 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 2 of the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public 15 | * License along with this program; if not, write to the 16 | * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 17 | * Boston, MA 02110-1301 USA 18 | * 19 | * Authored by: Alessandro "Alecaddd" Castellani 20 | */ 21 | 22 | public class Sequeler.Layouts.DataBaseView : Gtk.Grid { 23 | public weak Sequeler.Window window { get; construct; } 24 | 25 | public Granite.Widgets.ModeButton tabs; 26 | public Gtk.Stack stack; 27 | public Sequeler.Layouts.Views.Structure structure; 28 | public Sequeler.Layouts.Views.Content content; 29 | public Sequeler.Layouts.Views.Relations relations; 30 | public Granite.Widgets.DynamicNotebook query; 31 | 32 | private Sequeler.Layouts.Views.Query tab_to_restore; 33 | 34 | public Gtk.MenuButton font_style; 35 | 36 | public DataBaseView (Sequeler.Window main_window) { 37 | Object ( 38 | orientation: Gtk.Orientation.VERTICAL, 39 | window: main_window, 40 | column_homogeneous: true 41 | ); 42 | } 43 | 44 | construct { 45 | var toolbar = new Gtk.Grid (); 46 | toolbar.get_style_context ().add_class ("library-titlebar"); 47 | 48 | tabs = new Granite.Widgets.ModeButton (); 49 | tabs.append (new Sequeler.Partials.ToolBarButton ("x-office-spreadsheet-template", "Structure", _("Structure"))); 50 | tabs.append (new Sequeler.Partials.ToolBarButton ("x-office-document", "Content", _("Content"))); 51 | tabs.append (new Sequeler.Partials.ToolBarButton ("preferences-system-windows", "Relations", _("Relations"))); 52 | tabs.append (new Sequeler.Partials.ToolBarButton ("accessories-text-editor", "Query", _("Query"))); 53 | tabs.set_active (0); 54 | tabs.margin = 9; 55 | 56 | tabs.mode_changed.connect ((tab) => { 57 | stack.set_visible_child_name (tab.name); 58 | 59 | if (tab.name == "Query") { 60 | font_style.visible = true; 61 | font_style.no_show_all = false; 62 | } else { 63 | font_style.visible = false; 64 | font_style.no_show_all = true; 65 | } 66 | 67 | if (window.main.database_schema.source_list == null) { 68 | return; 69 | } 70 | 71 | var item_selected = window.main.database_schema.source_list.selected; 72 | 73 | if (item_selected == null) { 74 | return; 75 | } 76 | 77 | if (tab.name == "Structure") { 78 | window.main.database_view.structure.fill (item_selected.name, window.main.database_view.structure.database); 79 | } 80 | 81 | if (tab.name == "Content") { 82 | window.main.database_view.content.fill (item_selected.name, window.main.database_view.content.database, item_selected.badge); 83 | } 84 | 85 | if (tab.name == "Relations") { 86 | window.main.database_view.relations.fill (item_selected.name, window.main.database_view.relations.database); 87 | } 88 | }); 89 | 90 | toolbar.attach (tabs, 0, 0, 1, 1); 91 | 92 | var view_options = new Gtk.Grid (); 93 | view_options.hexpand = true; 94 | view_options.halign = Gtk.Align.END; 95 | view_options.valign = Gtk.Align.CENTER; 96 | 97 | // Query View buttons 98 | var zoom_out_button = new Gtk.Button.from_icon_name ("zoom-out-symbolic", Gtk.IconSize.MENU); 99 | zoom_out_button.action_name = Sequeler.Services.ActionManager.ACTION_PREFIX + Sequeler.Services.ActionManager.ACTION_ZOOM_OUT; 100 | zoom_out_button.tooltip_markup = Granite.markup_accel_tooltip ({"minus"}, _("Zoom Out")); 101 | 102 | var zoom_default_button = new Gtk.Button.with_label ( 103 | "%.0f%%".printf (window.action_manager.get_current_font_size () * 10) 104 | ); 105 | zoom_default_button.action_name = Sequeler.Services.ActionManager.ACTION_PREFIX + Sequeler.Services.ActionManager.ACTION_ZOOM_DEFAULT; 106 | zoom_default_button.tooltip_markup = Granite.markup_accel_tooltip ({"0"}, _("Zoom 1:1")); 107 | 108 | var zoom_in_button = new Gtk.Button.from_icon_name ("zoom-in-symbolic", Gtk.IconSize.MENU); 109 | zoom_in_button.action_name = Sequeler.Services.ActionManager.ACTION_PREFIX + Sequeler.Services.ActionManager.ACTION_ZOOM_IN; 110 | zoom_in_button.tooltip_markup = Granite.markup_accel_tooltip ({"plus"}, _("Zoom In")); 111 | 112 | var font_size_grid = new Gtk.Grid (); 113 | font_size_grid.column_homogeneous = true; 114 | font_size_grid.hexpand = true; 115 | font_size_grid.margin = 12; 116 | font_size_grid.get_style_context ().add_class (Gtk.STYLE_CLASS_LINKED); 117 | font_size_grid.add (zoom_out_button); 118 | font_size_grid.add (zoom_default_button); 119 | font_size_grid.add (zoom_in_button); 120 | 121 | var color_button_white = new Gtk.RadioButton (null); 122 | color_button_white.halign = Gtk.Align.CENTER; 123 | color_button_white.tooltip_text = _("High Contrast"); 124 | 125 | var color_button_white_context = color_button_white.get_style_context (); 126 | color_button_white_context.add_class ("color-button"); 127 | color_button_white_context.add_class ("color-white"); 128 | 129 | var color_button_light = new Gtk.RadioButton.from_widget (color_button_white); 130 | color_button_light.halign = Gtk.Align.CENTER; 131 | color_button_light.tooltip_text = _("Solarized Light"); 132 | 133 | var color_button_light_context = color_button_light.get_style_context (); 134 | color_button_light_context.add_class ("color-button"); 135 | color_button_light_context.add_class ("color-light"); 136 | 137 | var color_button_dark = new Gtk.RadioButton.from_widget (color_button_white); 138 | color_button_dark.halign = Gtk.Align.CENTER; 139 | color_button_dark.tooltip_text = _("Solarized Dark"); 140 | 141 | var color_button_dark_context = color_button_dark.get_style_context (); 142 | color_button_dark_context.add_class ("color-button"); 143 | color_button_dark_context.add_class ("color-dark"); 144 | 145 | var menu_grid = new Gtk.Grid (); 146 | menu_grid.margin_bottom = 12; 147 | menu_grid.orientation = Gtk.Orientation.VERTICAL; 148 | menu_grid.width_request = 200; 149 | menu_grid.attach (font_size_grid, 0, 0, 3, 1); 150 | menu_grid.attach (color_button_white, 0, 1, 1, 1); 151 | menu_grid.attach (color_button_light, 1, 1, 1, 1); 152 | menu_grid.attach (color_button_dark, 2, 1, 1, 1); 153 | menu_grid.show_all (); 154 | 155 | var menu = new Gtk.Popover (null); 156 | menu.add (menu_grid); 157 | 158 | font_style = new Gtk.MenuButton (); 159 | font_style.margin_end = 9; 160 | font_style.get_style_context ().add_class (Gtk.STYLE_CLASS_FLAT); 161 | font_style.set_image (new Gtk.Image.from_icon_name ("font-select-symbolic", Gtk.IconSize.LARGE_TOOLBAR)); 162 | font_style.tooltip_text = _("Change Text Style"); 163 | font_style.popover = menu; 164 | font_style.can_focus = false; 165 | font_style.visible = false; 166 | font_style.no_show_all = true; 167 | 168 | view_options.add (font_style); 169 | 170 | toolbar.attach (view_options, 1, 0, 1, 1); 171 | 172 | stack = new Gtk.Stack (); 173 | structure = new Sequeler.Layouts.Views.Structure (window); 174 | content = new Sequeler.Layouts.Views.Content (window); 175 | relations = new Sequeler.Layouts.Views.Relations (window); 176 | query = get_query_notebook (); 177 | 178 | stack.add_named (structure, "Structure"); 179 | stack.add_named (content, "Content"); 180 | stack.add_named (relations, "Relations"); 181 | stack.add_named (query, "Query"); 182 | stack.expand = true; 183 | 184 | attach (toolbar, 0, 0, 1, 1); 185 | attach (stack, 0, 1, 1, 1); 186 | 187 | settings.changed.connect (() => { 188 | zoom_default_button.label = "%.0f%%".printf (window.action_manager.get_current_font_size () * 10); 189 | }); 190 | 191 | switch (Sequeler.settings.style_scheme) { 192 | case "high-contrast": 193 | color_button_white.active = true; 194 | break; 195 | case "solarized-light": 196 | color_button_light.active = true; 197 | break; 198 | case "solarized-dark": 199 | color_button_dark.active = true; 200 | break; 201 | } 202 | 203 | color_button_dark.clicked.connect (() => { 204 | Sequeler.settings.style_scheme = "solarized-dark"; 205 | (query.current.page as Layouts.Views.Query).update_color_style (); 206 | }); 207 | 208 | color_button_light.clicked.connect (() => { 209 | Sequeler.settings.style_scheme = "solarized-light"; 210 | (query.current.page as Layouts.Views.Query).update_color_style (); 211 | }); 212 | 213 | color_button_white.clicked.connect (() => { 214 | Sequeler.settings.style_scheme = "classic"; 215 | (query.current.page as Layouts.Views.Query).update_color_style (); 216 | }); 217 | } 218 | 219 | private Granite.Widgets.DynamicNotebook get_query_notebook () { 220 | var notebook = new Granite.Widgets.DynamicNotebook (); 221 | notebook.add_button_tooltip = _("Create a new Query Tab"); 222 | notebook.expand = true; 223 | notebook.allow_restoring = true; 224 | notebook.max_restorable_tabs = 1; 225 | 226 | var first_page = new Sequeler.Layouts.Views.Query (window); 227 | var first_tab = new Granite.Widgets.Tab ( 228 | _("Query"), null, first_page 229 | ); 230 | first_page.update_tab_indicator.connect ((status) => { 231 | var icon = status 232 | ? new ThemedIcon ("process-completed") 233 | : new ThemedIcon ("process-stop"); 234 | first_tab.icon = icon; 235 | }); 236 | notebook.insert_tab (first_tab, 0); 237 | 238 | notebook.new_tab_requested.connect (() => { 239 | var new_page = new Sequeler.Layouts.Views.Query (window); 240 | var new_tab = new Granite.Widgets.Tab ( 241 | _("Query %i").printf (notebook.n_tabs), null, new_page 242 | ); 243 | new_page.update_tab_indicator.connect ((status) => { 244 | var icon = status 245 | ? new ThemedIcon ("process-completed") 246 | : new ThemedIcon ("process-stop"); 247 | new_tab.icon = icon; 248 | }); 249 | notebook.insert_tab (new_tab, notebook.n_tabs - 1); 250 | }); 251 | 252 | notebook.close_tab_requested.connect ((tab) => { 253 | if (notebook.n_tabs == 1) { 254 | var new_page = new Sequeler.Layouts.Views.Query (window); 255 | var new_tab = new Granite.Widgets.Tab ( 256 | _("Query"), null, new_page 257 | ); 258 | notebook.insert_tab (new_tab, notebook.n_tabs - 1); 259 | } 260 | tab_to_restore = tab.page as Sequeler.Layouts.Views.Query; 261 | tab.restore_data = tab.label; 262 | return true; 263 | }); 264 | 265 | notebook.tab_restored.connect ((label, data, icon) => { 266 | var tab = new Granite.Widgets.Tab (label, icon, tab_to_restore); 267 | tab_to_restore.update_tab_indicator.connect ((status) => { 268 | var update_icon = status 269 | ? new ThemedIcon ("process-completed") 270 | : new ThemedIcon ("process-stop"); 271 | tab.icon = update_icon; 272 | }); 273 | notebook.insert_tab (tab, notebook.n_tabs - 1); 274 | }); 275 | 276 | return notebook; 277 | } 278 | } 279 | -------------------------------------------------------------------------------- /src/Layouts/HeaderBar.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2020 Alecaddd (https://alecaddd.com) 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 2 of the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public 15 | * License along with this program; if not, write to the 16 | * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 17 | * Boston, MA 02110-1301 USA 18 | * 19 | * Authored by: Alessandro "Alecaddd" Castellani 20 | */ 21 | 22 | public class Sequeler.Layouts.HeaderBar : Gtk.HeaderBar { 23 | public weak Sequeler.Window window { get; construct; } 24 | 25 | private Gtk.Button logout_button; 26 | private Gtk.Button new_db_button; 27 | private Gtk.Button delete_db_button; 28 | private Gtk.Button edit_db_button; 29 | private Granite.ModeSwitch mode_switch; 30 | private Gtk.Popover menu_popover; 31 | 32 | public bool logged_out { get; set; } 33 | 34 | public HeaderBar (Sequeler.Window main_window) { 35 | Object ( 36 | window: main_window, 37 | logged_out: true 38 | ); 39 | 40 | set_title (APP_NAME); 41 | set_show_close_button (true); 42 | 43 | build_ui (); 44 | toggle_logout.begin (); 45 | } 46 | 47 | private void build_ui () { 48 | logout_button = header_button ("application-logout"); 49 | logout_button.action_name = 50 | Sequeler.Services.ActionManager.ACTION_PREFIX 51 | + Sequeler.Services.ActionManager.ACTION_LOGOUT; 52 | logout_button.tooltip_markup = Granite.markup_accel_tooltip ({"Escape"}, _("Logout")); 53 | 54 | new_db_button = header_button ("office-database-new"); 55 | new_db_button.tooltip_markup = Granite.markup_accel_tooltip ( 56 | {"N"}, 57 | _("Create a new database") 58 | ); 59 | new_db_button.action_name = 60 | Sequeler.Services.ActionManager.ACTION_PREFIX 61 | + Sequeler.Services.ActionManager.ACTION_NEW_DB; 62 | 63 | delete_db_button = header_button ("office-database-remove"); 64 | delete_db_button.tooltip_markup = Granite.markup_accel_tooltip ( 65 | {"D"}, 66 | _("Delete database") 67 | ); 68 | delete_db_button.action_name = 69 | Sequeler.Services.ActionManager.ACTION_PREFIX 70 | + Sequeler.Services.ActionManager.ACTION_DELETE_DB; 71 | 72 | edit_db_button = header_button ("office-database-edit"); 73 | edit_db_button.tooltip_markup = Granite.markup_accel_tooltip ( 74 | {"P"}, 75 | _("Database properties") 76 | ); 77 | edit_db_button.action_name = 78 | Sequeler.Services.ActionManager.ACTION_PREFIX 79 | + Sequeler.Services.ActionManager.ACTION_EDIT_DB; 80 | 81 | new_db_button.visible = false; 82 | new_db_button.no_show_all = true; 83 | edit_db_button.visible = false; 84 | edit_db_button.no_show_all = true; 85 | delete_db_button.visible = false; 86 | delete_db_button.no_show_all = true; 87 | 88 | mode_switch = new Granite.ModeSwitch.from_icon_name ("display-brightness-symbolic", "weather-clear-night-symbolic"); 89 | mode_switch.primary_icon_tooltip_text = _("Light background"); 90 | mode_switch.secondary_icon_tooltip_text = _("Dark background"); 91 | mode_switch.valign = Gtk.Align.CENTER; 92 | mode_switch.bind_property ("active", settings, "dark-theme"); 93 | mode_switch.notify.connect (() => { 94 | Gtk.Settings.get_default ().gtk_application_prefer_dark_theme = settings.dark_theme; 95 | }); 96 | 97 | if (settings.dark_theme) { 98 | mode_switch.active = true; 99 | } 100 | 101 | var new_window_item = new_menuitem (_("New Window"), "n"); 102 | new_window_item.action_name = Sequeler.Services.ActionManager.ACTION_PREFIX + Sequeler.Services.ActionManager.ACTION_NEW_WINDOW; 103 | 104 | var new_connection_item = new_menuitem (_("New Connection"), "n"); 105 | new_connection_item.action_name = Sequeler.Services.ActionManager.ACTION_PREFIX + Sequeler.Services.ActionManager.ACTION_NEW_CONNECTION; 106 | 107 | var quit_item = new_menuitem (_("Quit"), "q"); 108 | quit_item.action_name = Sequeler.Services.ActionManager.ACTION_PREFIX + Sequeler.Services.ActionManager.ACTION_QUIT; 109 | 110 | var menu_separator = new Gtk.Separator (Gtk.Orientation.HORIZONTAL); 111 | menu_separator.margin_top = 6; 112 | menu_separator.margin_bottom = 6; 113 | 114 | var menu_grid = new Gtk.Grid (); 115 | menu_grid.expand = true; 116 | menu_grid.margin_top = menu_grid.margin_bottom = 6; 117 | menu_grid.orientation = Gtk.Orientation.VERTICAL; 118 | 119 | menu_grid.attach (new_window_item, 0, 1, 1, 1); 120 | menu_grid.attach (new_connection_item, 0, 2, 1, 1); 121 | menu_grid.attach (menu_separator, 0, 3, 1, 1); 122 | menu_grid.attach (quit_item, 0, 4, 1, 1); 123 | menu_grid.show_all (); 124 | 125 | var open_menu = new Gtk.MenuButton (); 126 | open_menu.set_image (new Gtk.Image.from_icon_name ("open-menu", Gtk.IconSize.LARGE_TOOLBAR)); 127 | open_menu.tooltip_text = _("Menu"); 128 | 129 | menu_popover = new Gtk.Popover (open_menu); 130 | menu_popover.add (menu_grid); 131 | 132 | open_menu.popover = menu_popover; 133 | open_menu.valign = Gtk.Align.CENTER; 134 | 135 | pack_start (logout_button); 136 | pack_start (headerbar_separator ()); 137 | pack_start (new_db_button); 138 | pack_start (edit_db_button); 139 | pack_start (headerbar_separator ()); 140 | pack_start (delete_db_button); 141 | 142 | pack_end (open_menu); 143 | pack_end (headerbar_separator ()); 144 | pack_end (mode_switch); 145 | } 146 | 147 | private Gtk.ModelButton new_menuitem (string label, string accels) { 148 | var button = new Gtk.ModelButton (); 149 | button.get_child ().destroy (); 150 | button.add (new Granite.AccelLabel (label, accels)); 151 | 152 | return button; 153 | } 154 | 155 | private Gtk.Button header_button (string image) { 156 | var button = new Gtk.Button.from_icon_name (image, Gtk.IconSize.LARGE_TOOLBAR); 157 | button.get_style_context ().add_class (Gtk.STYLE_CLASS_FLAT); 158 | button.valign = Gtk.Align.CENTER; 159 | button.can_focus = false; 160 | 161 | return button; 162 | } 163 | 164 | private Gtk.Separator headerbar_separator () { 165 | var separator = new Gtk.Separator (Gtk.Orientation.VERTICAL); 166 | separator.get_style_context ().add_class ("headerbar-separator"); 167 | 168 | return separator; 169 | } 170 | 171 | public async void toggle_logout () { 172 | logged_out = !logged_out; 173 | 174 | logout_button.visible = logged_out; 175 | logout_button.no_show_all = !logged_out; 176 | 177 | if ( 178 | window.data_manager != null && 179 | ( 180 | window.data_manager.data["type"] == "MySQL" 181 | || window.data_manager.data["type"] == "MariaDB" 182 | ) 183 | ) { 184 | new_db_button.visible = logged_out; 185 | new_db_button.no_show_all = !logged_out; 186 | edit_db_button.visible = logged_out; 187 | edit_db_button.no_show_all = !logged_out; 188 | delete_db_button.visible = logged_out; 189 | delete_db_button.no_show_all = !logged_out; 190 | } 191 | } 192 | } 193 | -------------------------------------------------------------------------------- /src/Layouts/Main.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2011-2018 Alecaddd (http://alecaddd.com) 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 2 of the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public 15 | * License along with this program; if not, write to the 16 | * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 17 | * Boston, MA 02110-1301 USA 18 | * 19 | * Authored by: Alessandro "Alecaddd" Castellani 20 | */ 21 | 22 | public class Sequeler.Layouts.Main : Gtk.Paned { 23 | public weak Sequeler.Window window { get; construct; } 24 | public Sequeler.Services.ConnectionManager? connection_manager { get; set; default = null; } 25 | 26 | public Sequeler.Layouts.Library library; 27 | public Sequeler.Layouts.DataBaseSchema database_schema; 28 | public Sequeler.Layouts.Welcome welcome; 29 | public Sequeler.Layouts.DataBaseView database_view; 30 | 31 | public Gtk.Stack sidebar_stack; 32 | public Gtk.Stack main_stack; 33 | 34 | public Main (Sequeler.Window main_window) { 35 | Object ( 36 | orientation: Gtk.Orientation.HORIZONTAL, 37 | window: main_window 38 | ); 39 | } 40 | 41 | construct { 42 | position = settings.sidebar_width; 43 | 44 | sidebar_stack = new Gtk.Stack (); 45 | library = new Sequeler.Layouts.Library (window); 46 | database_schema = new Sequeler.Layouts.DataBaseSchema (window); 47 | sidebar_stack.add_named (library, "library"); 48 | sidebar_stack.add_named (database_schema, "database_schema"); 49 | 50 | main_stack = new Gtk.Stack (); 51 | welcome = new Sequeler.Layouts.Welcome (window); 52 | database_view = new Sequeler.Layouts.DataBaseView (window); 53 | main_stack.add_named (welcome, "welcome"); 54 | main_stack.add_named (database_view, "database_view"); 55 | 56 | build_sidebar (); 57 | build_main (); 58 | } 59 | 60 | public void build_sidebar () { 61 | pack1 (sidebar_stack, false, false); 62 | } 63 | 64 | public void build_main () { 65 | pack2 (main_stack, true, false); 66 | } 67 | 68 | public async void connection_opened (Sequeler.Services.ConnectionManager? cnn_manager) { 69 | debug ("connection opened"); 70 | connection_manager = cnn_manager; 71 | var host = cnn_manager.data["host"] != "" ? cnn_manager.data["host"] : "127.0.0.1"; 72 | 73 | window.headerbar.toggle_logout.begin (); 74 | sidebar_stack.set_visible_child_full ("database_schema", Gtk.StackTransitionType.CROSSFADE); 75 | main_stack.set_visible_child_full ("database_view", Gtk.StackTransitionType.SLIDE_LEFT); 76 | 77 | window.headerbar.title = _("Connected to %s").printf (cnn_manager.data["title"]); 78 | window.headerbar.subtitle = cnn_manager.data["username"] + "@" + host; 79 | 80 | database_schema.reload_schema.begin (); 81 | } 82 | 83 | public void connection_closed () { 84 | if (connection_manager.data["has_ssh"] == "true") { 85 | debug ("connection manager %p", connection_manager); 86 | connection_manager.ssh_tunnel_close (Log.FILE + ":" + Log.LINE.to_string ()); 87 | } 88 | 89 | if (connection_manager.connection != null && connection_manager.connection.is_opened ()) { 90 | connection_manager.connection.clear_events_list (); 91 | connection_manager.connection.close (); 92 | connection_manager.connection = null; 93 | } 94 | 95 | connection_manager = null; 96 | sidebar_stack.set_visible_child_full ("library", Gtk.StackTransitionType.CROSSFADE); 97 | main_stack.set_visible_child_full ("welcome", Gtk.StackTransitionType.UNDER_RIGHT); 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /src/Layouts/Views/Content.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2020 Alecaddd (https://alecaddd.com) 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 2 of the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public 15 | * License along with this program; if not, write to the 16 | * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 17 | * Boston, MA 02110-1301 USA 18 | * 19 | * Authored by: Alessandro "Alecaddd" Castellani 20 | */ 21 | 22 | public class Sequeler.Layouts.Views.Content : Gtk.Grid { 23 | public weak Sequeler.Window window { get; construct; } 24 | 25 | public Gtk.Stack stack; 26 | private Gda.DataModel? table_content; 27 | public Gtk.Grid scroll_grid; 28 | public Gtk.ScrolledWindow scroll; 29 | public Gtk.Label result_message; 30 | private Gtk.Spinner spinner; 31 | 32 | private Gtk.Button pages_button; 33 | private Gtk.SpinButton pages_entry; 34 | private Sequeler.Partials.HeaderBarButton page_prev_btn; 35 | private Sequeler.Partials.HeaderBarButton page_next_btn; 36 | private int tot_pages { get; set; default = 0; } 37 | private int current_page { get; set; default = 1; } 38 | private bool reloading { get; set; default = false; } 39 | 40 | private string _table_name = ""; 41 | 42 | public string table_name { 43 | get { return _table_name; } 44 | set { _table_name = value; } 45 | } 46 | 47 | private string _database = ""; 48 | 49 | public string database { 50 | get { return _database; } 51 | set { _database = value; } 52 | } 53 | 54 | public int table_count = 0; 55 | 56 | private string? sortby = null; 57 | private string sort = "ASC"; 58 | 59 | public Content (Sequeler.Window main_window) { 60 | Object ( 61 | orientation: Gtk.Orientation.VERTICAL, 62 | window: main_window 63 | ); 64 | } 65 | 66 | construct { 67 | scroll_grid = new Gtk.Grid (); 68 | scroll_grid.expand = true; 69 | 70 | scroll = new Gtk.ScrolledWindow (null, null); 71 | scroll.hscrollbar_policy = Gtk.PolicyType.AUTOMATIC; 72 | scroll.vscrollbar_policy = Gtk.PolicyType.AUTOMATIC; 73 | scroll.expand = true; 74 | scroll_grid.add (scroll); 75 | 76 | var info_bar = new Gtk.Grid (); 77 | info_bar.get_style_context ().add_class ("library-toolbar"); 78 | info_bar.attach (build_pagination (), 0, 0, 1, 1); 79 | info_bar.attach (new Gtk.Separator (Gtk.Orientation.VERTICAL), 1, 0, 1, 1); 80 | info_bar.attach (build_results_msg (), 2, 0, 1, 1); 81 | info_bar.attach (build_reload_btn (), 3, 0, 1, 1); 82 | 83 | spinner = new Gtk.Spinner (); 84 | spinner.hexpand = true; 85 | spinner.vexpand = true; 86 | spinner.halign = Gtk.Align.CENTER; 87 | spinner.valign = Gtk.Align.CENTER; 88 | 89 | var welcome = new Granite.Widgets.Welcome (_("Select Table"), _("Select a table from the left sidebar to activate this view.")); 90 | 91 | stack = new Gtk.Stack (); 92 | stack.hexpand = true; 93 | stack.vexpand = true; 94 | stack.add_named (welcome, "welcome"); 95 | stack.add_named (spinner, "spinner"); 96 | stack.add_named (scroll_grid, "list"); 97 | 98 | attach (stack, 0, 0, 1, 1); 99 | attach (info_bar, 0, 1, 1, 1); 100 | 101 | placeholder (); 102 | } 103 | 104 | public void placeholder () { 105 | stack.visible_child_name = "welcome"; 106 | } 107 | 108 | public void start_spinner () { 109 | spinner.start (); 110 | stack.visible_child_name = "spinner"; 111 | } 112 | 113 | public void stop_spinner () { 114 | spinner.stop (); 115 | stack.visible_child_name = "list"; 116 | } 117 | 118 | public Gtk.Grid build_pagination () { 119 | var page_grid = new Gtk.Grid (); 120 | page_grid.valign = Gtk.Align.CENTER; 121 | 122 | page_prev_btn = new Sequeler.Partials.HeaderBarButton ("go-previous-symbolic", _("Previous Page")); 123 | page_prev_btn.clicked.connect (go_prev_page); 124 | page_prev_btn.halign = Gtk.Align.START; 125 | page_prev_btn.sensitive = false; 126 | 127 | page_next_btn = new Sequeler.Partials.HeaderBarButton ("go-next-symbolic", _("Next Page")); 128 | page_next_btn.clicked.connect (go_next_page); 129 | page_next_btn.halign = Gtk.Align.END; 130 | page_next_btn.sensitive = false; 131 | 132 | pages_button = new Gtk.Button.with_label (_("%d Pages").printf (tot_pages)); 133 | pages_button.can_focus = false; 134 | pages_button.get_style_context ().add_class (Gtk.STYLE_CLASS_FLAT); 135 | pages_button.set_tooltip_text (_("Jump to page…")); 136 | 137 | pages_entry = new Gtk.SpinButton.with_range (0, 0, 1); 138 | pages_entry.margin = 3; 139 | pages_entry.value_changed.connect (() => { 140 | if (pages_entry.get_value_as_int () > tot_pages) { 141 | return; 142 | } 143 | current_page = pages_entry.get_value_as_int (); 144 | reload_results (); 145 | }); 146 | 147 | var pages_popover = new Gtk.Popover (pages_button); 148 | pages_popover.add (pages_entry); 149 | 150 | pages_button.clicked.connect (() => { 151 | pages_popover.popup (); 152 | pages_popover.show_all (); 153 | }); 154 | 155 | page_grid.attach (page_prev_btn, 0, 0, 1, 1); 156 | page_grid.attach (new Gtk.Separator (Gtk.Orientation.VERTICAL), 1, 0, 1, 1); 157 | page_grid.attach (pages_button, 2, 0, 1, 1); 158 | page_grid.attach (new Gtk.Separator (Gtk.Orientation.VERTICAL), 3, 0, 1, 1); 159 | page_grid.attach (page_next_btn, 4, 0, 1, 1); 160 | 161 | return page_grid; 162 | } 163 | 164 | private void update_pagination () { 165 | if (table_count <= settings.limit_results) { 166 | pages_button.label = _("1 Page"); 167 | pages_entry.set_range (1, 1); 168 | return; 169 | } 170 | 171 | tot_pages = (int) Math.ceilf (((float) table_count) / settings.limit_results); 172 | pages_button.label = _("%d of %d Pages").printf (current_page, tot_pages); 173 | 174 | page_prev_btn.sensitive = (current_page > 1); 175 | page_next_btn.sensitive = (current_page < tot_pages); 176 | pages_entry.set_range (1, tot_pages); 177 | } 178 | 179 | public Gtk.Label build_results_msg () { 180 | result_message = new Gtk.Label (_("No Results Available")); 181 | result_message.halign = Gtk.Align.START; 182 | result_message.margin_top = result_message.margin_bottom = 3; 183 | result_message.margin_start = result_message.margin_end = 9; 184 | result_message.ellipsize = Pango.EllipsizeMode.END; 185 | result_message.hexpand = true; 186 | result_message.wrap = true; 187 | 188 | return result_message; 189 | } 190 | 191 | private Gtk.Button build_reload_btn () { 192 | var reload_btn = new Sequeler.Partials.HeaderBarButton ("view-refresh-symbolic", _("Reload Results")); 193 | reload_btn.clicked.connect (reload_results); 194 | reload_btn.halign = Gtk.Align.END; 195 | 196 | return reload_btn; 197 | } 198 | 199 | public async void clear () { 200 | if (scroll == null) { 201 | return; 202 | } 203 | 204 | scroll.destroy (); 205 | 206 | scroll = new Gtk.ScrolledWindow (null, null); 207 | scroll.hscrollbar_policy = Gtk.PolicyType.AUTOMATIC; 208 | scroll.vscrollbar_policy = Gtk.PolicyType.AUTOMATIC; 209 | scroll.expand = true; 210 | 211 | scroll_grid.add (scroll); 212 | } 213 | 214 | public async void reset () { 215 | if (scroll.get_child () != null) { 216 | scroll.remove (scroll.get_child ()); 217 | } 218 | 219 | result_message.label = _("No Results Available"); 220 | table_name = ""; 221 | database = ""; 222 | placeholder (); 223 | } 224 | 225 | public void fill (string? table, string? db_name = null, string? count = null) { 226 | if (table == null) { 227 | return; 228 | } 229 | 230 | if (table == _table_name && db_name == _database) { 231 | return; 232 | } 233 | 234 | // Reset sorting attributes. 235 | sortby = null; 236 | sort = "ASC"; 237 | 238 | table_name = table; 239 | database = db_name; 240 | table_count = count != null ? int.parse (count) : 0; 241 | 242 | tot_pages = 0; 243 | current_page = 1; 244 | 245 | get_content_and_fill.begin (); 246 | } 247 | 248 | public void reload_results () { 249 | if (table_name == "") { 250 | return; 251 | } 252 | 253 | get_content_and_fill.begin (); 254 | } 255 | 256 | public async void get_content_and_fill () { 257 | if (reloading) { 258 | debug ("still loading"); 259 | return; 260 | } 261 | 262 | start_spinner (); 263 | var query = (window.main.connection_manager.db_type as DataBaseType) 264 | .show_table_content (table_name, table_count, current_page, sortby, sort); 265 | reloading = true; 266 | 267 | table_content = yield get_table_content (query); 268 | 269 | if (table_content == null) { 270 | return; 271 | } 272 | 273 | var result_data = new Sequeler.Partials.TreeBuilder ( 274 | table_content, window, settings.limit_results, current_page, sortby, sort); 275 | build_signals (result_data); 276 | result_message.label = _("%d Entries").printf (table_count); 277 | 278 | yield clear (); 279 | update_pagination (); 280 | 281 | scroll.add (result_data); 282 | scroll.show_all (); 283 | reloading = false; 284 | 285 | stop_spinner (); 286 | } 287 | 288 | private async Gda.DataModel? get_table_content (string query) { 289 | Gda.DataModel? result = null; 290 | 291 | result = yield window.main.connection_manager.init_select_query (query); 292 | 293 | if (result == null) { 294 | reloading = false; 295 | yield reset (); 296 | } 297 | 298 | return result; 299 | } 300 | 301 | private void build_signals (Sequeler.Partials.TreeBuilder tree) { 302 | tree.sortby_column.connect ((column, direction) => { 303 | sortby = column; 304 | sort = direction; 305 | reload_results (); 306 | }); 307 | } 308 | 309 | public void go_prev_page () { 310 | page_prev_btn.sensitive = false; 311 | current_page--; 312 | get_content_and_fill.begin (); 313 | } 314 | 315 | public void go_next_page () { 316 | page_next_btn.sensitive = false; 317 | current_page++; 318 | get_content_and_fill.begin (); 319 | } 320 | } 321 | -------------------------------------------------------------------------------- /src/Layouts/Views/Relations.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2020 Alecaddd (https://alecaddd.com) 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 2 of the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public 15 | * License along with this program; if not, write to the 16 | * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 17 | * Boston, MA 02110-1301 USA 18 | * 19 | * Authored by: Alessandro "Alecaddd" Castellani 20 | */ 21 | 22 | public class Sequeler.Layouts.Views.Relations : Gtk.Grid { 23 | public weak Sequeler.Window window { get; construct; } 24 | 25 | public Gtk.Stack stack; 26 | public Gtk.Grid scroll_grid; 27 | public Gtk.ScrolledWindow scroll; 28 | public Gtk.Label result_message; 29 | private Gtk.Spinner spinner; 30 | 31 | private bool reloading { get; set; default = false; } 32 | 33 | private string _table_name = ""; 34 | 35 | public string table_name { 36 | get { return _table_name; } 37 | set { _table_name = value; } 38 | } 39 | 40 | private string _database = ""; 41 | 42 | public string database { 43 | get { return _database; } 44 | set { _database = value; } 45 | } 46 | 47 | private string? sortby = null; 48 | private string sort = "ASC"; 49 | 50 | public Relations (Sequeler.Window main_window) { 51 | Object ( 52 | orientation: Gtk.Orientation.VERTICAL, 53 | window: main_window 54 | ); 55 | } 56 | 57 | construct { 58 | scroll_grid = new Gtk.Grid (); 59 | scroll_grid.expand = true; 60 | 61 | scroll = new Gtk.ScrolledWindow (null, null); 62 | scroll.hscrollbar_policy = Gtk.PolicyType.AUTOMATIC; 63 | scroll.vscrollbar_policy = Gtk.PolicyType.AUTOMATIC; 64 | scroll.expand = true; 65 | 66 | var info_bar = new Gtk.Grid (); 67 | info_bar.get_style_context ().add_class ("library-toolbar"); 68 | info_bar.attach (build_results_msg (), 0, 0, 1, 1); 69 | info_bar.attach (build_reload_btn (), 1, 0, 1, 1); 70 | 71 | spinner = new Gtk.Spinner (); 72 | spinner.hexpand = true; 73 | spinner.vexpand = true; 74 | spinner.halign = Gtk.Align.CENTER; 75 | spinner.valign = Gtk.Align.CENTER; 76 | 77 | var welcome = new Granite.Widgets.Welcome (_("Select Table"), _("Select a table from the left sidebar to activate this view.")); 78 | 79 | stack = new Gtk.Stack (); 80 | stack.hexpand = true; 81 | stack.vexpand = true; 82 | stack.add_named (welcome, "welcome"); 83 | stack.add_named (spinner, "spinner"); 84 | stack.add_named (scroll_grid, "list"); 85 | 86 | attach (stack, 0, 0, 1, 1); 87 | attach (info_bar, 0, 1, 1, 1); 88 | 89 | placeholder (); 90 | } 91 | 92 | public void placeholder () { 93 | stack.visible_child_name = "welcome"; 94 | } 95 | 96 | public void start_spinner () { 97 | spinner.start (); 98 | stack.visible_child_name = "spinner"; 99 | } 100 | 101 | public void stop_spinner () { 102 | spinner.stop (); 103 | stack.visible_child_name = "list"; 104 | } 105 | 106 | public Gtk.Label build_results_msg () { 107 | result_message = new Gtk.Label (_("No Results Available")); 108 | result_message.halign = Gtk.Align.START; 109 | result_message.margin = 7; 110 | result_message.margin_top = 6; 111 | result_message.hexpand = true; 112 | result_message.wrap = true; 113 | 114 | return result_message; 115 | } 116 | 117 | private Gtk.Button build_reload_btn () { 118 | var reload_btn = new Sequeler.Partials.HeaderBarButton ("view-refresh-symbolic", _("Reload Results")); 119 | reload_btn.clicked.connect (reload_results); 120 | reload_btn.halign = Gtk.Align.END; 121 | 122 | return reload_btn; 123 | } 124 | 125 | public async void clear () { 126 | if (scroll == null) { 127 | return; 128 | } 129 | 130 | scroll.destroy (); 131 | 132 | scroll = new Gtk.ScrolledWindow (null, null); 133 | scroll.hscrollbar_policy = Gtk.PolicyType.AUTOMATIC; 134 | scroll.vscrollbar_policy = Gtk.PolicyType.AUTOMATIC; 135 | scroll.expand = true; 136 | 137 | scroll_grid.add (scroll); 138 | } 139 | 140 | public async void reset () { 141 | if (scroll.get_child () != null) { 142 | scroll.remove (scroll.get_child ()); 143 | } 144 | 145 | result_message.label = _("No Results Available"); 146 | table_name = ""; 147 | database = ""; 148 | placeholder (); 149 | } 150 | 151 | public void fill (string? table, string? db_name = null) { 152 | if (table == null) { 153 | return; 154 | } 155 | 156 | if (table == _table_name && db_name == _database) { 157 | return; 158 | } 159 | 160 | // Reset sorting attributes. 161 | sortby = null; 162 | sort = "ASC"; 163 | 164 | table_name = table; 165 | database = db_name; 166 | 167 | get_content_and_fill.begin (); 168 | } 169 | 170 | public void reload_results () { 171 | if (table_name == "") { 172 | return; 173 | } 174 | 175 | get_content_and_fill.begin (); 176 | } 177 | 178 | public async void get_content_and_fill () { 179 | if (reloading) { 180 | debug ("still loading"); 181 | return; 182 | } 183 | 184 | start_spinner (); 185 | var query = (window.main.connection_manager.db_type as DataBaseType) 186 | .show_table_relations (table_name, database, sortby, sort); 187 | reloading = true; 188 | 189 | var table_relations = yield get_table_relations (query); 190 | 191 | if (table_relations == null) { 192 | return; 193 | } 194 | 195 | var result_data = new Sequeler.Partials.TreeBuilder ( 196 | table_relations, window, 0, 0, sortby, sort); 197 | build_signals (result_data); 198 | result_message.label = table_relations.get_n_rows ().to_string () + _(" Constraints"); 199 | 200 | yield clear (); 201 | 202 | scroll.add (result_data); 203 | scroll.show_all (); 204 | reloading = false; 205 | 206 | stop_spinner (); 207 | } 208 | 209 | private async Gda.DataModel? get_table_relations (string query) { 210 | Gda.DataModel? result = null; 211 | 212 | result = yield window.main.connection_manager.init_select_query (query); 213 | 214 | if (result == null) { 215 | reloading = false; 216 | yield reset (); 217 | } 218 | 219 | return result; 220 | } 221 | 222 | private void build_signals (Sequeler.Partials.TreeBuilder tree) { 223 | tree.sortby_column.connect ((column, direction) => { 224 | sortby = column; 225 | sort = direction; 226 | reload_results (); 227 | }); 228 | } 229 | } 230 | -------------------------------------------------------------------------------- /src/Layouts/Views/Structure.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2011-2019 Alecaddd (http://alecaddd.com) 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 2 of the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public 15 | * License along with this program; if not, write to the 16 | * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 17 | * Boston, MA 02110-1301 USA 18 | * 19 | * Authored by: Alessandro "Alecaddd" Castellani 20 | */ 21 | 22 | public class Sequeler.Layouts.Views.Structure : Gtk.Grid { 23 | public weak Sequeler.Window window { get; construct; } 24 | 25 | public Gtk.Stack stack; 26 | public Gtk.Grid scroll_grid; 27 | public Gtk.ScrolledWindow scroll; 28 | public Gtk.Label result_message; 29 | private Gtk.Spinner spinner; 30 | 31 | private bool reloading { get; set; default = false; } 32 | 33 | private string _table_name = ""; 34 | 35 | public string table_name { 36 | get { return _table_name; } 37 | set { _table_name = value; } 38 | } 39 | 40 | private string _database = ""; 41 | 42 | public string database { 43 | get { return _database; } 44 | set { _database = value; } 45 | } 46 | 47 | private string? sortby = null; 48 | private string sort = "ASC"; 49 | 50 | public Structure (Sequeler.Window main_window) { 51 | Object ( 52 | orientation: Gtk.Orientation.VERTICAL, 53 | window: main_window 54 | ); 55 | } 56 | 57 | construct { 58 | scroll_grid = new Gtk.Grid (); 59 | scroll_grid.expand = true; 60 | 61 | scroll = new Gtk.ScrolledWindow (null, null); 62 | scroll.hscrollbar_policy = Gtk.PolicyType.AUTOMATIC; 63 | scroll.vscrollbar_policy = Gtk.PolicyType.AUTOMATIC; 64 | scroll.expand = true; 65 | scroll_grid.add (scroll); 66 | 67 | var info_bar = new Gtk.Grid (); 68 | info_bar.get_style_context ().add_class ("library-toolbar"); 69 | info_bar.attach (build_results_msg (), 0, 0, 1, 1); 70 | info_bar.attach (build_reload_btn (), 1, 0, 1, 1); 71 | 72 | spinner = new Gtk.Spinner (); 73 | spinner.hexpand = true; 74 | spinner.vexpand = true; 75 | spinner.halign = Gtk.Align.CENTER; 76 | spinner.valign = Gtk.Align.CENTER; 77 | 78 | var welcome = new Granite.Widgets.Welcome (_("Select Table"), _("Select a table from the left sidebar to activate this view.")); 79 | 80 | stack = new Gtk.Stack (); 81 | stack.hexpand = true; 82 | stack.vexpand = true; 83 | stack.add_named (welcome, "welcome"); 84 | stack.add_named (spinner, "spinner"); 85 | stack.add_named (scroll_grid, "list"); 86 | 87 | attach (stack, 0, 0, 1, 1); 88 | attach (info_bar, 0, 1, 1, 1); 89 | 90 | placeholder (); 91 | } 92 | 93 | public void placeholder () { 94 | stack.visible_child_name = "welcome"; 95 | } 96 | 97 | public void start_spinner () { 98 | spinner.start (); 99 | stack.visible_child_name = "spinner"; 100 | } 101 | 102 | public void stop_spinner () { 103 | spinner.stop (); 104 | stack.visible_child_name = "list"; 105 | } 106 | 107 | public Gtk.Label build_results_msg () { 108 | result_message = new Gtk.Label (_("No Results Available")); 109 | result_message.halign = Gtk.Align.START; 110 | result_message.margin = 7; 111 | result_message.margin_top = 6; 112 | result_message.hexpand = true; 113 | result_message.wrap = true; 114 | 115 | return result_message; 116 | } 117 | 118 | private Gtk.Button build_reload_btn () { 119 | var reload_btn = new Sequeler.Partials.HeaderBarButton ("view-refresh-symbolic", _("Reload Results")); 120 | reload_btn.clicked.connect (reload_results); 121 | reload_btn.halign = Gtk.Align.END; 122 | 123 | return reload_btn; 124 | } 125 | 126 | public async void clear () { 127 | if (scroll == null) { 128 | return; 129 | } 130 | 131 | scroll.destroy (); 132 | 133 | scroll = new Gtk.ScrolledWindow (null, null); 134 | scroll.hscrollbar_policy = Gtk.PolicyType.AUTOMATIC; 135 | scroll.vscrollbar_policy = Gtk.PolicyType.AUTOMATIC; 136 | scroll.expand = true; 137 | 138 | scroll_grid.add (scroll); 139 | } 140 | 141 | public async void reset () { 142 | if (scroll.get_child () != null) { 143 | scroll.remove (scroll.get_child ()); 144 | } 145 | 146 | result_message.label = _("No Results Available"); 147 | table_name = ""; 148 | database = ""; 149 | placeholder (); 150 | } 151 | 152 | public void fill (string? table, string? db_name = null) { 153 | if (table == null) { 154 | return; 155 | } 156 | 157 | if (table == _table_name && db_name == _database) { 158 | return; 159 | } 160 | 161 | // Reset sorting attributes. 162 | sortby = null; 163 | sort = "ASC"; 164 | 165 | table_name = table; 166 | database = db_name; 167 | 168 | get_content_and_fill.begin (); 169 | } 170 | 171 | public void reload_results () { 172 | if (table_name == "") { 173 | return; 174 | } 175 | 176 | get_content_and_fill.begin (); 177 | } 178 | 179 | public async void get_content_and_fill () { 180 | if (reloading) { 181 | debug ("still loading"); 182 | return; 183 | } 184 | 185 | start_spinner (); 186 | var query = (window.main.connection_manager.db_type as DataBaseType) 187 | .show_table_structure (table_name, sortby, sort); 188 | reloading = true; 189 | 190 | var table_schema = yield get_table_schema (query); 191 | 192 | if (table_schema == null) { 193 | return; 194 | } 195 | 196 | var result_data = new Sequeler.Partials.TreeBuilder (table_schema, window, 0, 0, sortby, sort); 197 | build_signals (result_data); 198 | result_message.label = table_schema.get_n_rows ().to_string () + _(" Fields"); 199 | 200 | yield clear (); 201 | 202 | scroll.add (result_data); 203 | scroll.show_all (); 204 | reloading = false; 205 | 206 | stop_spinner (); 207 | } 208 | 209 | private async Gda.DataModel? get_table_schema (string query) { 210 | Gda.DataModel? result = null; 211 | 212 | result = yield window.main.connection_manager.init_select_query (query); 213 | 214 | if (result == null) { 215 | reloading = false; 216 | yield reset (); 217 | } 218 | 219 | return result; 220 | } 221 | 222 | private void build_signals (Sequeler.Partials.TreeBuilder tree) { 223 | tree.sortby_column.connect ((column, direction) => { 224 | sortby = column; 225 | sort = direction; 226 | reload_results (); 227 | }); 228 | } 229 | } 230 | -------------------------------------------------------------------------------- /src/Layouts/Welcome.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2011-2018 Alecaddd (http://alecaddd.com) 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 2 of the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public 15 | * License along with this program; if not, write to the 16 | * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 17 | * Boston, MA 02110-1301 USA 18 | * 19 | * Authored by: Alessandro "Alecaddd" Castellani 20 | */ 21 | 22 | public class Sequeler.Layouts.Welcome : Granite.Widgets.Welcome { 23 | public unowned Sequeler.Window window { get; construct; } 24 | 25 | public Welcome (Sequeler.Window main_window) { 26 | Object ( 27 | window: main_window, 28 | title: _("Welcome to Sequeler"), 29 | subtitle: _("Connect to Any Local or Remote Database.") 30 | ); 31 | } 32 | 33 | construct { 34 | valign = Gtk.Align.FILL; 35 | halign = Gtk.Align.FILL; 36 | vexpand = true; 37 | 38 | append ("bookmark-new", _("Add a New Database"), _("Connect to a Database and Save It in Your Library")); 39 | append ("window-new", _("New Window"), _("Open a New Sequeler Window")); 40 | append ("folder-download", _("Import Connections"), _("Import Previously Exported Sequeler Connections")); 41 | 42 | activated.connect ( index => { 43 | switch (index) { 44 | case 0: 45 | Sequeler.Services.ActionManager.action_from_group (Sequeler.Services.ActionManager.ACTION_NEW_CONNECTION, window.get_action_group ("win")); 46 | break; 47 | case 1: 48 | Sequeler.Services.ActionManager.action_from_group (Sequeler.Services.ActionManager.ACTION_NEW_WINDOW, window.get_action_group ("win")); 49 | break; 50 | case 2: 51 | import_file (); 52 | break; 53 | } 54 | }); 55 | } 56 | 57 | private void import_file () { 58 | var open_dialog = new Gtk.FileChooserNative (_("Select a file"), 59 | window, 60 | Gtk.FileChooserAction.OPEN, 61 | _("_Open"), 62 | _("_Cancel")); 63 | 64 | open_dialog.local_only = true; 65 | open_dialog.modal = true; 66 | open_dialog.response.connect (open_file); 67 | open_dialog.run (); 68 | } 69 | 70 | private void open_file (Gtk.NativeDialog dialog, int response_id) { 71 | var open_dialog = dialog as Gtk.FileChooserNative; 72 | 73 | switch (response_id) { 74 | case Gtk.ResponseType.ACCEPT: 75 | var file = open_dialog.get_file (); 76 | uint8[] file_contents; 77 | 78 | try { 79 | file.load_contents (null, out file_contents, null); 80 | } 81 | catch (GLib.Error err) { 82 | import_warning (err.message); 83 | } 84 | var imported_connections = (string) file_contents; 85 | var data = imported_connections.split ("---\n"); 86 | foreach (var import in data) { 87 | if (import == "") { 88 | continue; 89 | } 90 | var array = settings.arraify_data (import); 91 | array["id"] = settings.tot_connections.to_string (); 92 | settings.add_connection (array); 93 | } 94 | 95 | window.main.library.reload_library.begin (); 96 | 97 | break; 98 | 99 | case Gtk.ResponseType.CANCEL: 100 | break; 101 | } 102 | 103 | open_dialog.destroy (); 104 | } 105 | 106 | private void import_warning (string message) { 107 | var message_dialog = new Granite.MessageDialog.with_image_from_icon_name (_("Unable to Import Library "), message, "dialog-error", Gtk.ButtonsType.NONE); 108 | message_dialog.transient_for = window; 109 | 110 | var suggested_button = new Gtk.Button.with_label ("Close"); 111 | message_dialog.add_action_widget (suggested_button, Gtk.ResponseType.ACCEPT); 112 | 113 | message_dialog.show_all (); 114 | if (message_dialog.run () == Gtk.ResponseType.ACCEPT) {} 115 | 116 | message_dialog.destroy (); 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /src/Main.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2011-2018 Alecaddd (http://alecaddd.com) 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 2 of the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public 15 | * License along with this program; if not, write to the 16 | * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 17 | * Boston, MA 02110-1301 USA 18 | * 19 | * Authored by: Alessandro "Alecaddd" Castellani 20 | */ 21 | 22 | #if IS_DEVEL 23 | public const string APP_NAME = "(Development) Sequeler"; 24 | #else 25 | public const string APP_NAME = "Sequeler"; 26 | #endif 27 | public const string TERMINAL_NAME = "sequeler"; 28 | 29 | public static int main (string[] args) { 30 | Environment.set_application_name ("Sequeler"); 31 | Environment.set_prgname ("Sequeler"); 32 | 33 | var application = new Sequeler.Application (); 34 | 35 | return application.run (args); 36 | } 37 | -------------------------------------------------------------------------------- /src/Partials/ButtonType.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2011-2018 Alecaddd (http://alecaddd.com) 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 2 of the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public 15 | * License along with this program; if not, write to the 16 | * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 17 | * Boston, MA 02110-1301 USA 18 | * 19 | * Authored by: Alessandro "Alecaddd" Castellani 20 | */ 21 | 22 | namespace Sequeler.Partials { 23 | public class HeaderBarButton : Gtk.Button { 24 | public HeaderBarButton (string icon_name, string tooltip) { 25 | can_focus = false; 26 | 27 | Gtk.Image image; 28 | 29 | if (icon_name.contains ("/")) { 30 | image = new Gtk.Image.from_resource (icon_name); 31 | } else { 32 | image = new Gtk.Image.from_icon_name (icon_name, Gtk.IconSize.BUTTON); 33 | } 34 | 35 | image.margin = 3; 36 | 37 | get_style_context ().add_class (Gtk.STYLE_CLASS_FLAT); 38 | set_tooltip_text (tooltip); 39 | add (image); 40 | } 41 | } 42 | 43 | public class ToolBarButton : Gtk.Grid { 44 | public ToolBarButton (string icon_name, string tooltip, string label) { 45 | name = tooltip; 46 | halign = Gtk.Align.CENTER; 47 | 48 | Gtk.Image icon; 49 | var title = new Gtk.Label (label); 50 | 51 | if (icon_name.contains ("/")) { 52 | icon = new Gtk.Image.from_resource (icon_name); 53 | } else { 54 | icon = new Gtk.Image.from_icon_name (icon_name, Gtk.IconSize.BUTTON); 55 | } 56 | 57 | icon.margin = 2; 58 | 59 | attach (icon, 0, 0, 1, 1); 60 | attach (title, 1, 0, 1, 1); 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/Partials/DataBasePanel.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 Alecaddd (https://alecaddd.com) 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 2 of the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public 15 | * License along with this program; if not, write to the 16 | * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 17 | * Boston, MA 02110-1301 USA 18 | * 19 | * Authored by: Alessandro "Alecaddd" Castellani 20 | */ 21 | 22 | public class Sequeler.Partials.DataBasePanel : Gtk.Revealer { 23 | public weak Sequeler.Window window { get; construct; } 24 | 25 | private Gtk.Label title; 26 | private Sequeler.Partials.Entry db_entry; 27 | private Gtk.Stack button_stack; 28 | private Gtk.Button button_save; 29 | private Gtk.Button button_edit; 30 | private Gtk.Button button_cancel; 31 | private Gtk.Spinner spinner; 32 | 33 | public bool reveal { 34 | get { 35 | return reveal_child; 36 | } 37 | set { 38 | reveal_child = value; 39 | spinner.stop (); 40 | button_cancel.sensitive = true; 41 | } 42 | } 43 | 44 | public DataBasePanel (Sequeler.Window main_window) { 45 | Object ( 46 | window: main_window 47 | ); 48 | } 49 | 50 | construct { 51 | valign = Gtk.Align.START; 52 | hexpand = true; 53 | transition_type = Gtk.RevealerTransitionType.SLIDE_DOWN; 54 | reveal_child = false; 55 | 56 | var panel = new Gtk.Grid (); 57 | panel.margin = 9; 58 | panel.get_style_context ().add_class ("database-panel"); 59 | 60 | // Title area. 61 | title = new Gtk.Label (""); 62 | title.get_style_context ().add_class ("h4"); 63 | title.margin_start = title.margin_end = 3; 64 | title.margin_top = 6; 65 | title.ellipsize = Pango.EllipsizeMode.END; 66 | 67 | // Body area. 68 | var body = new Gtk.Grid (); 69 | body.margin = 3; 70 | 71 | db_entry = new Sequeler.Partials.Entry (_("Database name"), null); 72 | db_entry.margin = 6; 73 | db_entry.changed.connect (change_sensitivity); 74 | 75 | body.add (db_entry); 76 | 77 | // Action buttons area. 78 | var buttons_area = new Gtk.Grid (); 79 | buttons_area.hexpand = true; 80 | buttons_area.get_style_context ().add_class ("database-panel-bottom"); 81 | 82 | button_cancel = new Gtk.Button.with_label (_("Cancel")); 83 | button_cancel.clicked.connect (() => { 84 | window.main.database_schema.hide_database_panel (); 85 | }); 86 | button_cancel.margin = 9; 87 | 88 | button_save = new Gtk.Button.with_label (_("Save")); 89 | button_save.get_style_context ().add_class (Gtk.STYLE_CLASS_SUGGESTED_ACTION); 90 | button_save.margin = 9; 91 | button_save.sensitive = false; 92 | button_save.clicked.connect (() => { 93 | window.main.database_schema.create_database.begin (db_entry.text); 94 | }); 95 | 96 | button_edit = new Gtk.Button.with_label (_("Edit")); 97 | button_edit.get_style_context ().add_class (Gtk.STYLE_CLASS_SUGGESTED_ACTION); 98 | button_edit.margin = 9; 99 | button_edit.sensitive = false; 100 | button_edit.clicked.connect (() => { 101 | var dialog = new Granite.MessageDialog.with_image_from_icon_name (_("Are you sure you want to edit this Database?"), _("This is a dangerous operation and it might cause data loss, a backup before proceeding is recommended."), "dialog-warning", Gtk.ButtonsType.CANCEL); 102 | dialog.transient_for = window; 103 | 104 | var suggested_button = new Gtk.Button.with_label (_("Yes, proceed!")); 105 | suggested_button.get_style_context ().add_class (Gtk.STYLE_CLASS_DESTRUCTIVE_ACTION); 106 | dialog.add_action_widget (suggested_button, Gtk.ResponseType.ACCEPT); 107 | 108 | dialog.show_all (); 109 | if (dialog.run () == Gtk.ResponseType.ACCEPT) { 110 | button_cancel.sensitive = false; 111 | spinner.start (); 112 | button_stack.visible_child_name = "spinner"; 113 | window.main.database_schema.edit_database.begin (db_entry.text); 114 | } 115 | 116 | dialog.destroy (); 117 | }); 118 | 119 | spinner = new Gtk.Spinner (); 120 | spinner.hexpand = true; 121 | spinner.vexpand = true; 122 | spinner.halign = Gtk.Align.CENTER; 123 | spinner.valign = Gtk.Align.CENTER; 124 | 125 | button_stack = new Gtk.Stack (); 126 | button_stack.expand = false; 127 | button_stack.add_named (button_save, "new"); 128 | button_stack.add_named (button_edit, "edit"); 129 | button_stack.add_named (spinner, "spinner"); 130 | 131 | var separator = new Gtk.Separator (Gtk.Orientation.HORIZONTAL); 132 | separator.expand = true; 133 | separator.halign = Gtk.Align.CENTER; 134 | 135 | buttons_area.attach (button_cancel, 0, 0); 136 | buttons_area.attach (separator, 1, 0); 137 | buttons_area.attach (button_stack, 2, 0); 138 | 139 | panel.attach (title, 0, 0); 140 | panel.attach (body, 0, 1); 141 | panel.attach (buttons_area, 0, 2); 142 | 143 | add (panel); 144 | } 145 | 146 | private void change_sensitivity () { 147 | button_save.sensitive = db_entry.text != ""; 148 | button_edit.sensitive = db_entry.text != ""; 149 | } 150 | 151 | public void new_database () { 152 | spinner.stop (); 153 | button_cancel.sensitive = true; 154 | title.label = _("Create a new Database"); 155 | db_entry.text = ""; 156 | button_stack.visible_child_name = "new"; 157 | } 158 | 159 | public void edit_database (string name) { 160 | spinner.stop (); 161 | button_cancel.sensitive = true; 162 | title.label = _("Edit Database"); 163 | db_entry.text = name; 164 | button_stack.visible_child_name = "edit"; 165 | } 166 | } 167 | -------------------------------------------------------------------------------- /src/Partials/DatabaseTable.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2020 Alecaddd (https://alecaddd.com) 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 2 of the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public 15 | * License along with this program; if not, write to the 16 | * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 17 | * Boston, MA 02110-1301 USA 18 | * 19 | * Authored by: Alessandro "Alecaddd" Castellani 20 | */ 21 | 22 | public class Sequeler.Partials.DataBaseTable : Granite.Widgets.SourceList.Item { 23 | private Gtk.Menu menu; 24 | private Granite.Widgets.SourceList source_list; 25 | 26 | public DataBaseTable (string table_name = "", Granite.Widgets.SourceList list) { 27 | name = table_name; 28 | source_list = list; 29 | editable = true; 30 | build_context_menu (); 31 | } 32 | 33 | public override Gtk.Menu? get_context_menu () { 34 | return menu; 35 | } 36 | 37 | private void build_context_menu () { 38 | menu = new Gtk.Menu (); 39 | Gtk.MenuItem copy_item = new Gtk.MenuItem.with_label (_("Copy table name")); 40 | Gtk.MenuItem edit_item = new Gtk.MenuItem.with_label (_("Edit table name")); 41 | 42 | copy_item.activate.connect (() => { 43 | Gdk.Display display = Gdk.Display.get_default (); 44 | Gtk.Clipboard clipboard = Gtk.Clipboard.get_default (display); 45 | 46 | clipboard.set_text (name, -1); 47 | }); 48 | copy_item.show (); 49 | 50 | edit_item.activate.connect (() => { 51 | source_list.start_editing_item (this); 52 | }); 53 | edit_item.show (); 54 | 55 | menu.append (copy_item); 56 | menu.append (edit_item); 57 | 58 | /* Wayland complains if not set */ 59 | menu.realize.connect (() => { 60 | Gdk.Window child = menu.get_window (); 61 | child.set_type_hint (Gdk.WindowTypeHint.POPUP_MENU); 62 | }); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/Partials/Helpers.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2011-2018 Alecaddd (http://alecaddd.com) 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 2 of the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public 15 | * License along with this program; if not, write to the 16 | * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 17 | * Boston, MA 02110-1301 USA 18 | * 19 | * Authored by: Alessandro "Alecaddd" Castellani 20 | */ 21 | 22 | namespace Sequeler.Partials { 23 | public class TitleBar : Gtk.Grid { 24 | public TitleBar (string text) { 25 | get_style_context ().add_class ("library-titlebar"); 26 | 27 | var title = new Gtk.Label (text); 28 | title.get_style_context ().add_class ("h4"); 29 | title.halign = Gtk.Align.CENTER; 30 | title.margin = 4; 31 | title.hexpand = true; 32 | 33 | this.add (title); 34 | } 35 | } 36 | 37 | public class ResponseMessage : Gtk.Label { 38 | public ResponseMessage () { 39 | get_style_context ().add_class ("h4"); 40 | halign = Gtk.Align.CENTER; 41 | valign = Gtk.Align.CENTER; 42 | justify = Gtk.Justification.CENTER; 43 | set_line_wrap (true); 44 | margin_bottom = 10; 45 | } 46 | } 47 | 48 | public class Entry : Gtk.Entry { 49 | public Entry (string? placeholder, string? val) { 50 | hexpand = true; 51 | 52 | if (placeholder != null) { 53 | placeholder_text = placeholder; 54 | } 55 | 56 | if (val != null) { 57 | text = val; 58 | } 59 | } 60 | } 61 | 62 | public class ButtonClass : Gtk.Button { 63 | public ButtonClass (string text, string* class) { 64 | label = text; 65 | 66 | if (class != null) { 67 | var style_context = this.get_style_context (); 68 | style_context.add_class (class); 69 | } 70 | } 71 | } 72 | 73 | public class TableRow : Gtk.Grid { 74 | public TableRow (string text, int type) { 75 | if (type % 2 == 0) { 76 | get_style_context ().add_class ("row-odd"); 77 | } else { 78 | get_style_context ().add_class ("row-even"); 79 | } 80 | 81 | var title = new Gtk.Label (text); 82 | title.get_style_context ().add_class ("h4"); 83 | title.halign = Gtk.Align.START; 84 | title.margin_start = 6; 85 | title.margin_end = 6; 86 | title.hexpand = true; 87 | 88 | this.add (title); 89 | } 90 | } 91 | 92 | public class LabelForm : Gtk.Label { 93 | public LabelForm (string text) { 94 | label = text; 95 | halign = Gtk.Align.END; 96 | } 97 | } 98 | 99 | class UrlButton : Gtk.Button { 100 | public UrlButton (string label, string uri, string icon_name) { 101 | get_style_context ().add_class (Granite.STYLE_CLASS_ACCENT); 102 | get_style_context ().add_class (Gtk.STYLE_CLASS_FLAT); 103 | tooltip_text = uri; 104 | 105 | var icon = new Gtk.Image.from_icon_name (icon_name, Gtk.IconSize.SMALL_TOOLBAR); 106 | icon.valign = Gtk.Align.CENTER; 107 | 108 | var title = new Gtk.Label (label); 109 | title.ellipsize = Pango.EllipsizeMode.END; 110 | 111 | var grid = new Gtk.Grid (); 112 | grid.column_spacing = 6; 113 | grid.add (icon); 114 | grid.add (title); 115 | 116 | add (grid); 117 | 118 | clicked.connect (() => { 119 | try { 120 | AppInfo.launch_default_for_uri (uri, null); 121 | } catch (Error e) { 122 | warning ("%s\n", e.message); 123 | } 124 | }); 125 | } 126 | } 127 | 128 | public class RunQueryButton : Gtk.Button { 129 | public RunQueryButton () { 130 | set_label (_("Run Query")); 131 | get_style_context ().add_class ("suggested-action"); 132 | get_style_context ().add_class ("notebook-temp-fix"); 133 | always_show_image = true; 134 | image = new Gtk.Image.from_icon_name ("media-playback-start-symbolic", Gtk.IconSize.BUTTON); 135 | image.valign = Gtk.Align.CENTER; 136 | tooltip_markup = Granite.markup_accel_tooltip ({"Return"}, _("Run Query")); 137 | } 138 | } 139 | 140 | public class ParamEntry : Gtk.Entry { 141 | public ParamEntry (Widgets.QueryParamsDialog dialog, Gtk.InputPurpose? purpose = null) { 142 | hexpand = true; 143 | 144 | if (purpose != null) { 145 | set_input_purpose (purpose); 146 | } 147 | 148 | activate.connect (() => { 149 | dialog.run_query (); 150 | }); 151 | } 152 | } 153 | } 154 | -------------------------------------------------------------------------------- /src/Partials/LibraryItem.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2020 Alecaddd (https://alecaddd.com) 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 2 of the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public 15 | * License along with this program; if not, write to the 16 | * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 17 | * Boston, MA 02110-1301 USA 18 | * 19 | * Authored by: Alessandro "Alecaddd" Castellani 20 | */ 21 | 22 | public class Sequeler.Partials.LibraryItem : Gtk.ListBoxRow { 23 | public Gee.HashMap data { get; set; } 24 | public Gtk.Label title; 25 | public Gdk.RGBA color; 26 | 27 | public Gtk.Revealer main_revealer; 28 | private Gtk.Revealer motion_revealer; 29 | public Gtk.ModelButton connect_button; 30 | public Gtk.Spinner spinner; 31 | 32 | public Gtk.ScrolledWindow scrolled { get; set; } 33 | private bool scroll_up = false; 34 | private bool scrolling = false; 35 | private bool should_scroll = false; 36 | public Gtk.Adjustment vadjustment; 37 | 38 | private const int SCROLL_STEP_SIZE = 5; 39 | private const int SCROLL_DISTANCE = 30; 40 | private const int SCROLL_DELAY = 50; 41 | 42 | public signal void edit_dialog (Gee.HashMap data); 43 | public signal void duplicate_connection (Gee.HashMap data); 44 | public signal void confirm_delete ( 45 | Gtk.ListBoxRow item, 46 | Gee.HashMap data 47 | ); 48 | public signal void connect_to ( 49 | Gee.HashMap data, 50 | Gtk.Spinner spinner, 51 | Gtk.ModelButton button 52 | ); 53 | 54 | // Datatype restrictions on DnD (Gtk.TargetFlags). 55 | const Gtk.TargetEntry[] TARGET_ENTRIES_LABEL = { 56 | { "LIBRARYITEM", Gtk.TargetFlags.SAME_APP, 0 } 57 | }; 58 | 59 | public LibraryItem (Gee.HashMap data) { 60 | Object ( 61 | data: data 62 | ); 63 | 64 | get_style_context ().add_class ("library-box"); 65 | expand = true; 66 | 67 | var box = new Gtk.Grid (); 68 | box.get_style_context ().add_class ("library-inner-box"); 69 | box.margin = 3; 70 | 71 | var color_box = new Gtk.Grid (); 72 | color_box.get_style_context ().add_class ("library-colorbox"); 73 | color_box.set_size_request (12, 12); 74 | color_box.margin = 9; 75 | 76 | color = Gdk.RGBA (); 77 | color.parse (data["color"]); 78 | try { 79 | var style = new Gtk.CssProvider (); 80 | style.load_from_data ( 81 | "* {background-color: %s;}".printf (color.to_string ()), 82 | -1 83 | ); 84 | color_box.get_style_context ().add_provider ( 85 | style, 86 | Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION 87 | ); 88 | } catch (Error e) { 89 | debug ( 90 | "Internal error loading session chooser style: %s", 91 | e.message 92 | ); 93 | } 94 | 95 | title = new Gtk.Label (data["title"]); 96 | title.get_style_context ().add_class ("text-bold"); 97 | title.halign = Gtk.Align.START; 98 | title.ellipsize = Pango.EllipsizeMode.END; 99 | title.margin_end = 9; 100 | title.set_line_wrap (true); 101 | title.hexpand = true; 102 | 103 | box.attach (color_box, 0, 0, 1, 1); 104 | box.attach (title, 1, 0, 1, 1); 105 | 106 | connect_button = new Gtk.ModelButton (); 107 | connect_button.text = _("Connect"); 108 | 109 | var edit_button = new Gtk.ModelButton (); 110 | edit_button.text = _("Edit Connection"); 111 | 112 | var duplicate_button = new Gtk.ModelButton (); 113 | duplicate_button.text = _("Duplicate Connection"); 114 | 115 | var delete_button = new Gtk.ModelButton (); 116 | delete_button.text = _("Delete Connection"); 117 | 118 | var open_menu = new Gtk.MenuButton (); 119 | open_menu.set_image ( 120 | new Gtk.Image.from_icon_name ( 121 | "view-more-symbolic", 122 | Gtk.IconSize.SMALL_TOOLBAR 123 | ) 124 | ); 125 | open_menu.get_style_context ().add_class ("library-btn"); 126 | open_menu.tooltip_text = _("Options"); 127 | 128 | var menu_separator = new Gtk.Separator (Gtk.Orientation.HORIZONTAL); 129 | menu_separator.margin_top = 6; 130 | menu_separator.margin_bottom = 6; 131 | 132 | var menu_grid = new Gtk.Grid (); 133 | menu_grid.expand = true; 134 | menu_grid.margin_top = 3; 135 | menu_grid.margin_bottom = 3; 136 | menu_grid.orientation = Gtk.Orientation.VERTICAL; 137 | 138 | menu_grid.attach (connect_button, 0, 1, 1, 1); 139 | menu_grid.attach (edit_button, 0, 2, 1, 1); 140 | menu_grid.attach (duplicate_button, 0, 3, 1, 1); 141 | menu_grid.attach (menu_separator, 0, 4, 1, 1); 142 | menu_grid.attach (delete_button, 0, 5, 1, 1); 143 | menu_grid.show_all (); 144 | 145 | var menu_popover = new Gtk.Popover (null); 146 | menu_popover.add (menu_grid); 147 | 148 | open_menu.popover = menu_popover; 149 | open_menu.relief = Gtk.ReliefStyle.NONE; 150 | open_menu.valign = Gtk.Align.CENTER; 151 | 152 | spinner = new Gtk.Spinner (); 153 | 154 | box.attach (spinner, 2, 0, 1, 1); 155 | box.attach (open_menu, 3, 0, 1, 1); 156 | 157 | var motion_grid = new Gtk.Grid (); 158 | motion_grid.margin = 6; 159 | motion_grid.get_style_context ().add_class ("grid-motion"); 160 | motion_grid.height_request = 18; 161 | 162 | motion_revealer = new Gtk.Revealer (); 163 | motion_revealer.transition_type = Gtk.RevealerTransitionType.SLIDE_DOWN; 164 | motion_revealer.add (motion_grid); 165 | 166 | box.attach (motion_revealer, 0, 1, 4, 1); 167 | 168 | var event_box = new Gtk.EventBox (); 169 | event_box.add (box); 170 | 171 | main_revealer = new Gtk.Revealer (); 172 | main_revealer.reveal_child = true; 173 | main_revealer.transition_type = Gtk.RevealerTransitionType.SLIDE_DOWN; 174 | main_revealer.add (event_box); 175 | 176 | add (main_revealer); 177 | 178 | delete_button.clicked.connect (() => { 179 | confirm_delete (this, data); 180 | }); 181 | 182 | edit_button.clicked.connect (() => { 183 | edit_dialog (data); 184 | }); 185 | 186 | duplicate_button.clicked.connect (() => { 187 | duplicate_connection (data); 188 | }); 189 | 190 | connect_button.clicked.connect (() => { 191 | spinner.start (); 192 | connect_button.sensitive = false; 193 | connect_to (data, spinner, connect_button); 194 | }); 195 | 196 | event_box.enter_notify_event.connect (event => { 197 | box.set_state_flags (Gtk.StateFlags.PRELIGHT, true); 198 | return false; 199 | }); 200 | 201 | event_box.leave_notify_event.connect (event => { 202 | if (event.detail != Gdk.NotifyType.INFERIOR) { 203 | box.set_state_flags (Gtk.StateFlags.NORMAL, true); 204 | } 205 | return false; 206 | }); 207 | 208 | open_menu.clicked.connect (event => { 209 | box.set_state_flags (Gtk.StateFlags.PRELIGHT, true); 210 | }); 211 | 212 | menu_popover.closed.connect (event => { 213 | box.set_state_flags (Gtk.StateFlags.NORMAL, true); 214 | }); 215 | 216 | build_drag_and_drop (); 217 | } 218 | 219 | private void build_drag_and_drop () { 220 | // Make this a draggable widget 221 | Gtk.drag_source_set ( 222 | this, 223 | Gdk.ModifierType.BUTTON1_MASK, 224 | TARGET_ENTRIES_LABEL, 225 | Gdk.DragAction.MOVE 226 | ); 227 | 228 | drag_begin.connect (on_drag_begin); 229 | drag_data_get.connect (on_drag_data_get); 230 | 231 | // Make this widget a DnD destination. 232 | Gtk.drag_dest_set ( 233 | this, 234 | Gtk.DestDefaults.MOTION, 235 | TARGET_ENTRIES_LABEL, 236 | Gdk.DragAction.MOVE 237 | ); 238 | 239 | drag_motion.connect (on_drag_motion); 240 | drag_leave.connect (on_drag_leave); 241 | drag_end.connect (clear_indicator); 242 | } 243 | 244 | private void on_drag_begin (Gtk.Widget widget, Gdk.DragContext context) { 245 | var row = (Partials.LibraryItem) widget; 246 | 247 | Gtk.Allocation alloc; 248 | row.get_allocation (out alloc); 249 | 250 | var surface = new Cairo.ImageSurface (Cairo.Format.ARGB32, alloc.width, alloc.height); 251 | var cr = new Cairo.Context (surface); 252 | cr.set_source_rgba (0, 0, 0, 0.3); 253 | cr.set_line_width (1); 254 | 255 | cr.move_to (0, 0); 256 | cr.line_to (alloc.width, 0); 257 | cr.line_to (alloc.width, alloc.height); 258 | cr.line_to (0, alloc.height); 259 | cr.line_to (0, 0); 260 | cr.stroke (); 261 | 262 | cr.set_source_rgba (255, 255, 255, 0.5); 263 | cr.rectangle (0, 0, alloc.width, alloc.height); 264 | cr.fill (); 265 | 266 | row.draw (cr); 267 | Gtk.drag_set_icon_surface (context, surface); 268 | main_revealer.reveal_child = false; 269 | } 270 | 271 | private void on_drag_data_get (Gtk.Widget widget, Gdk.DragContext context, 272 | Gtk.SelectionData selection_data, uint target_type, uint time) { 273 | uchar[] data = new uchar[(sizeof (Partials.LibraryItem))]; 274 | ((Gtk.Widget[])data)[0] = widget; 275 | 276 | selection_data.set ( 277 | Gdk.Atom.intern_static_string ("LIBRARYITEM"), 32, data 278 | ); 279 | } 280 | 281 | public void clear_indicator (Gdk.DragContext context) { 282 | main_revealer.reveal_child = true; 283 | } 284 | 285 | public bool on_drag_motion (Gdk.DragContext context, int x, int y, uint time) { 286 | motion_revealer.reveal_child = true; 287 | 288 | int index = get_index (); 289 | Gtk.Allocation alloc; 290 | get_allocation (out alloc); 291 | 292 | int real_y = (index * alloc.height) - alloc.height + y; 293 | check_scroll (real_y); 294 | 295 | if (should_scroll && !scrolling) { 296 | scrolling = true; 297 | Timeout.add (SCROLL_DELAY, scroll); 298 | } 299 | 300 | return true; 301 | } 302 | 303 | private void check_scroll (int y) { 304 | vadjustment = scrolled.vadjustment; 305 | 306 | if (vadjustment == null) { 307 | return; 308 | } 309 | 310 | double vadjustment_min = vadjustment.value; 311 | double vadjustment_max = vadjustment.page_size + vadjustment_min; 312 | double show_min = double.max (0, y - SCROLL_DISTANCE); 313 | double show_max = double.min (vadjustment.upper, y + SCROLL_DISTANCE); 314 | 315 | if (vadjustment_min > show_min) { 316 | should_scroll = true; 317 | scroll_up = true; 318 | } else if (vadjustment_max < show_max) { 319 | should_scroll = true; 320 | scroll_up = false; 321 | } else { 322 | should_scroll = false; 323 | } 324 | } 325 | 326 | private bool scroll () { 327 | if (should_scroll) { 328 | if (scroll_up) { 329 | vadjustment.value -= SCROLL_STEP_SIZE; 330 | } else { 331 | vadjustment.value += SCROLL_STEP_SIZE; 332 | } 333 | } else { 334 | scrolling = false; 335 | } 336 | 337 | return should_scroll; 338 | } 339 | 340 | public void on_drag_leave (Gdk.DragContext context, uint time) { 341 | motion_revealer.reveal_child = false; 342 | should_scroll = false; 343 | } 344 | } 345 | -------------------------------------------------------------------------------- /src/Partials/TreeBuilder.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2011-2019 Alecaddd (http://alecaddd.com) 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 2 of the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public 15 | * License along with this program; if not, write to the 16 | * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 17 | * Boston, MA 02110-1301 USA 18 | * 19 | * Authored by: Alessandro "Alecaddd" Castellani 20 | */ 21 | 22 | public class Sequeler.Partials.TreeBuilder : Gtk.TreeView { 23 | public weak Sequeler.Window window { get; construct; } 24 | public Gda.DataModel data { get; construct; } 25 | public int per_page { get; construct; } 26 | public int current_page { get; construct; } 27 | public string? sortby { get; set construct; } 28 | public string sort { get; set construct; } 29 | 30 | public Gtk.ListStore store; 31 | public string? error_message { get; set; default = null; } 32 | public string background; 33 | public int tot_columns; 34 | 35 | private string bg_light = "rgba(255,255,255,0.05)"; 36 | private string bg_dark = "rgba(0,0,0,0.05)"; 37 | 38 | public signal void sortby_column (string column, string direction); 39 | 40 | public TreeBuilder ( 41 | Gda.DataModel response, Sequeler.Window main_window, int per_page = 0, int current_page = 0, 42 | string? sortby = null, string sort = "ASC" 43 | ) { 44 | Object ( 45 | window: main_window, 46 | data: response, 47 | per_page: per_page, 48 | current_page: current_page, 49 | sortby: sortby, 50 | sort: sort 51 | ); 52 | } 53 | 54 | construct { 55 | Gtk.TreeViewColumn column; 56 | var renderer = new Gtk.CellRendererText (); 57 | renderer.single_paragraph_mode = true; 58 | 59 | tot_columns = data.get_n_columns (); 60 | 61 | var the_types = new GLib.Type [tot_columns + 1]; 62 | for (int col = 0; col < tot_columns; col++) { 63 | the_types[col] = data.describe_column (col).get_g_type (); 64 | 65 | var title = data.get_column_title (col).replace ("_", "__"); 66 | column = new Gtk.TreeViewColumn.with_attributes (title, renderer, "text", col, "background", tot_columns, null); 67 | column.clickable = true; 68 | column.resizable = true; 69 | column.expand = true; 70 | column.set_data ("model_column_id", col); 71 | 72 | if (col > 0) { 73 | column.sizing = Gtk.TreeViewColumnSizing.FIXED; 74 | column.fixed_width = 150; 75 | } 76 | 77 | if (sortby != null && sortby.replace ("_", "__") == title) { 78 | column.sort_indicator = true; 79 | column.sort_order = sort == "ASC" ? Gtk.SortType.ASCENDING : Gtk.SortType.DESCENDING; 80 | } 81 | 82 | column.clicked.connect (init_sortby_column); 83 | append_column (column); 84 | } 85 | 86 | the_types[tot_columns] = typeof (string); 87 | 88 | store = new Gtk.ListStore.newv (the_types); 89 | Gda.DataModelIter _iter = data.create_iter (); 90 | Gtk.TreeIter iter; 91 | 92 | if (per_page != 0 && data.get_n_rows () > per_page) { 93 | int counter = 1; 94 | int offset = (per_page * (current_page - 1)); 95 | 96 | if (current_page != 0 && offset != 0) { 97 | _iter.move_to_row ((offset - 1)); 98 | } 99 | 100 | while (counter <= per_page && _iter.move_next ()) { 101 | append_value (_iter, iter); 102 | counter++; 103 | } 104 | } else { 105 | while (_iter.move_next ()) { 106 | append_value (_iter, iter); 107 | } 108 | } 109 | 110 | if (error_message != null) { 111 | window.main.connection_manager.query_warning (error_message); 112 | error_message = null; 113 | } 114 | 115 | set_model (store); 116 | } 117 | 118 | private void append_value (Gda.DataModelIter _iter, Gtk.TreeIter iter) { 119 | background = _iter.get_row () % 2 == 0 ? bg_light : bg_dark; 120 | store.append (out iter); 121 | 122 | for (int i = 0; i < tot_columns; i++) { 123 | var placeholder_type = data.describe_column (i).get_g_type (); 124 | 125 | try { 126 | var raw_value = _iter.get_value_at_e (i); 127 | var sanitized_value = raw_value.strdup_contents () != "NULL" ? 128 | raw_value : GLib.Value (placeholder_type); 129 | 130 | store.set_value (iter, i, sanitized_value); 131 | } catch (Error e) { 132 | error_message = "%s %s %s %s: %s".printf (_("Error"), e.code.to_string (), _("on Column"), data.get_column_title (i), e.message.to_string ()); 133 | } 134 | } 135 | store.set_value (iter, tot_columns, background); 136 | } 137 | 138 | public void init_sortby_column (Gtk.TreeViewColumn column) { 139 | // Detect sort order. 140 | sort = "ASC"; 141 | if (column.sort_order == Gtk.SortType.ASCENDING) { 142 | sort = "DESC"; 143 | } 144 | 145 | sortby_column (column.title.replace ("__", "_"), sort); 146 | } 147 | 148 | private void copy_column_data (Gdk.EventButton event, Gtk.TreePath path, Gtk.TreeViewColumn column) { 149 | if (path == null || column == null) { 150 | return; 151 | } 152 | 153 | Value val; 154 | Gtk.TreeIter iter; 155 | 156 | Gdk.Display display = Gdk.Display.get_default (); 157 | Gtk.Clipboard clipboard = Gtk.Clipboard.get_default (display); 158 | model.get_iter (out iter, path); 159 | model.get_value (iter, column.get_data ("model_column_id"), out val); 160 | 161 | Gda.DataHandler handler = Gda.DataHandler.get_default (val.type ()); 162 | string? column_data = handler.get_str_from_value (val); 163 | 164 | if (column_data == null) { 165 | column_data = ""; 166 | } 167 | 168 | clipboard.set_text (column_data, -1); 169 | } 170 | 171 | private Gtk.Menu create_context_menu (Gdk.EventButton event, Gtk.TreePath path, Gtk.TreeViewColumn column) { 172 | Gtk.Menu menu = new Gtk.Menu (); 173 | Gtk.MenuItem item = new Gtk.MenuItem.with_label (_("Copy %s").printf (column.get_title ())); 174 | item.activate.connect (() => { copy_column_data (event, path, column); }); 175 | item.show (); 176 | menu.append (item); 177 | 178 | /* Wayland complains if not set */ 179 | menu.realize.connect (() => { 180 | Gdk.Window child = menu.get_window (); 181 | child.set_type_hint (Gdk.WindowTypeHint.POPUP_MENU); 182 | }); 183 | 184 | return menu; 185 | } 186 | 187 | public override bool button_press_event (Gdk.EventButton event) { 188 | if (event.triggers_context_menu () && event.type == Gdk.EventType.BUTTON_PRESS) { 189 | Gtk.TreePath path; 190 | Gtk.TreeViewColumn column; 191 | get_path_at_pos ((int) event.x, (int) event.y, out path, out column, null, null); 192 | 193 | if (path != null) { 194 | var menu = create_context_menu (event, path, column); 195 | menu.popup_at_pointer (event); 196 | 197 | return true; 198 | } 199 | } 200 | 201 | return base.button_press_event (event); 202 | } 203 | } 204 | -------------------------------------------------------------------------------- /src/Services/ActionManager.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2011-2018 Alecaddd (http://alecaddd.com) 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 2 of the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public 15 | * License along with this program; if not, write to the 16 | * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 17 | * Boston, MA 02110-1301 USA 18 | * 19 | * Authored by: Alessandro "Alecaddd" Castellani 20 | */ 21 | 22 | public class Sequeler.Services.ActionManager : Object { 23 | public const int FONT_SIZE_MAX = 72; 24 | public const int FONT_SIZE_MIN = 7; 25 | 26 | public weak Sequeler.Application app { get; construct; } 27 | public weak Sequeler.Window window { get; construct; } 28 | 29 | public SimpleActionGroup actions { get; construct; } 30 | 31 | public const string ACTION_PREFIX = "win."; 32 | public const string ACTION_NEW_WINDOW = "action_new_window"; 33 | public const string ACTION_NEW_CONNECTION = "action_new_connection"; 34 | public const string ACTION_RUN_QUERY = "action_run_query"; 35 | public const string ACTION_LOGOUT = "action_logout"; 36 | public const string ACTION_QUIT = "action_quit"; 37 | public const string ACTION_ZOOM_DEFAULT = "action_zoom_default"; 38 | public const string ACTION_ZOOM_IN = "action_zoom_in"; 39 | public const string ACTION_ZOOM_OUT = "action_zoom_out"; 40 | public const string ACTION_NEW_DB = "action_new_db"; 41 | public const string ACTION_EDIT_DB = "action_edit_db"; 42 | public const string ACTION_DELETE_DB = "action_delete_db"; 43 | 44 | public static Gee.MultiMap action_accelerators = new Gee.HashMultiMap (); 45 | 46 | private const ActionEntry[] ACTION_ENTRIES = { 47 | { ACTION_NEW_WINDOW, action_new_window }, 48 | { ACTION_NEW_CONNECTION, action_new_connection }, 49 | { ACTION_RUN_QUERY, action_run_query }, 50 | { ACTION_LOGOUT, action_logout }, 51 | { ACTION_QUIT, action_quit }, 52 | { ACTION_ZOOM_DEFAULT, action_set_default_zoom }, 53 | { ACTION_ZOOM_IN, action_zoom_in }, 54 | { ACTION_ZOOM_OUT, action_zoom_out}, 55 | { ACTION_NEW_DB, action_new_db}, 56 | { ACTION_EDIT_DB, action_edit_db}, 57 | { ACTION_DELETE_DB, action_delete_db} 58 | }; 59 | 60 | public ActionManager (Sequeler.Application sequeler_app, Sequeler.Window main_window) { 61 | Object ( 62 | app: sequeler_app, 63 | window: main_window 64 | ); 65 | } 66 | 67 | static construct { 68 | action_accelerators.set (ACTION_NEW_WINDOW, "n"); 69 | action_accelerators.set (ACTION_NEW_CONNECTION, "n"); 70 | action_accelerators.set (ACTION_RUN_QUERY, "Return"); 71 | action_accelerators.set (ACTION_LOGOUT, "Escape"); 72 | action_accelerators.set (ACTION_QUIT, "q"); 73 | action_accelerators.set (ACTION_ZOOM_DEFAULT, "0"); 74 | action_accelerators.set (ACTION_ZOOM_DEFAULT, "KP_0"); 75 | action_accelerators.set (ACTION_ZOOM_IN, "plus"); 76 | action_accelerators.set (ACTION_ZOOM_IN, "equal"); 77 | action_accelerators.set (ACTION_ZOOM_IN, "KP_Add"); 78 | action_accelerators.set (ACTION_ZOOM_OUT, "minus"); 79 | action_accelerators.set (ACTION_ZOOM_OUT, "KP_Subtract"); 80 | action_accelerators.set (ACTION_NEW_DB, "N"); 81 | action_accelerators.set (ACTION_EDIT_DB, "P"); 82 | action_accelerators.set (ACTION_DELETE_DB, "D"); 83 | } 84 | 85 | construct { 86 | actions = new SimpleActionGroup (); 87 | actions.add_action_entries (ACTION_ENTRIES, this); 88 | window.insert_action_group ("win", actions); 89 | 90 | foreach (var action in action_accelerators.get_keys ()) { 91 | var accels_array = action_accelerators[action].to_array (); 92 | accels_array += null; 93 | 94 | app.set_accels_for_action (ACTION_PREFIX + action, accels_array); 95 | } 96 | } 97 | 98 | private void action_quit () { 99 | window.before_destroy (); 100 | } 101 | 102 | private void action_logout () { 103 | window.headerbar.toggle_logout.begin (); 104 | window.headerbar.title = APP_NAME; 105 | window.headerbar.subtitle = null; 106 | 107 | if (window.main.database_schema.scroll.get_child () != null) { 108 | window.main.database_schema.scroll.remove (window.main.database_schema.scroll.get_child ()); 109 | } 110 | 111 | if (window.main.database_view.query.n_tabs > 0) { 112 | (window.main.database_view.query.current.page as Layouts.Views.Query).buffer.text = ""; 113 | (window.main.database_view.query.current.page as Layouts.Views.Query).export_button.sensitive = false; 114 | } 115 | 116 | window.main.database_view.structure.reset.begin (); 117 | window.main.database_view.structure.table_name = ""; 118 | 119 | window.main.database_view.content.reset.begin (); 120 | window.main.database_view.content.table_name = ""; 121 | 122 | window.main.database_view.relations.reset.begin (); 123 | window.main.database_view.relations.table_name = ""; 124 | 125 | window.main.connection_closed (); 126 | window.data_manager.data = null; 127 | window.main.database_schema.hide_database_panel (); 128 | } 129 | 130 | private void action_new_window () { 131 | app.new_window (); 132 | } 133 | 134 | private void action_new_connection () { 135 | if (window.main.connection_manager != null) { 136 | return; 137 | } 138 | 139 | window.data_manager.data = null; 140 | 141 | if (window.connection_dialog == null) { 142 | window.connection_dialog = new Sequeler.Widgets.ConnectionDialog (window); 143 | window.connection_dialog.show_all (); 144 | 145 | window.connection_dialog.destroy.connect (() => { 146 | window.connection_dialog = null; 147 | }); 148 | } 149 | 150 | window.connection_dialog.present (); 151 | } 152 | 153 | private void action_run_query () { 154 | if (window.main.connection_manager == null) { 155 | return; 156 | } 157 | 158 | var page = (window.main.database_view.query.current.page as Layouts.Views.Query); 159 | var query = page.get_text ().strip (); 160 | 161 | if (query == "") { 162 | return; 163 | } 164 | 165 | page.run_query (query); 166 | } 167 | 168 | public static void action_from_group (string action_name, ActionGroup? action_group) { 169 | action_group.activate_action (action_name, null); 170 | } 171 | 172 | public void set_default_zoom () { 173 | Sequeler.settings.font = get_current_font () + " " + get_default_font_size ().to_string (); 174 | (window.main.database_view.query.current.page as Layouts.Views.Query).update_font_style (); 175 | } 176 | 177 | // Ctrl + scroll 178 | public void action_zoom_in () { 179 | zooming (Gdk.ScrollDirection.UP); 180 | } 181 | 182 | // Ctrl + scroll 183 | public void action_zoom_out () { 184 | zooming (Gdk.ScrollDirection.DOWN); 185 | } 186 | 187 | private void zooming (Gdk.ScrollDirection direction) { 188 | string font = get_current_font (); 189 | int font_size = (int) get_current_font_size (); 190 | if (Sequeler.settings.use_system_font) { 191 | Sequeler.settings.use_system_font = false; 192 | font = get_default_font (); 193 | font_size = (int) get_default_font_size (); 194 | } 195 | 196 | if (direction == Gdk.ScrollDirection.DOWN) { 197 | font_size --; 198 | if (font_size < FONT_SIZE_MIN) { 199 | return; 200 | } 201 | } else if (direction == Gdk.ScrollDirection.UP) { 202 | font_size ++; 203 | if (font_size > FONT_SIZE_MAX) { 204 | return; 205 | } 206 | } 207 | 208 | string new_font = font + " " + font_size.to_string (); 209 | Sequeler.settings.font = new_font; 210 | (window.main.database_view.query.current.page as Layouts.Views.Query).update_font_style (); 211 | } 212 | 213 | public string get_current_font () { 214 | string font = Sequeler.settings.font; 215 | string font_family = font.substring (0, font.last_index_of (" ")); 216 | return font_family; 217 | } 218 | 219 | public double get_current_font_size () { 220 | string font = Sequeler.settings.font; 221 | string font_size = font.substring (font.last_index_of (" ") + 1); 222 | return double.parse (font_size); 223 | } 224 | 225 | public string get_default_font () { 226 | string font = (window.main.database_view.query.current.page as Layouts.Views.Query).default_font; 227 | string font_family = font.substring (0, font.last_index_of (" ")); 228 | return font_family; 229 | } 230 | 231 | public double get_default_font_size () { 232 | string font = (window.main.database_view.query.current.page as Layouts.Views.Query).default_font; 233 | string font_size = font.substring (font.last_index_of (" ") + 1); 234 | return double.parse (font_size); 235 | } 236 | 237 | // Actions functions 238 | private void action_set_default_zoom () { 239 | set_default_zoom (); 240 | } 241 | 242 | // Show the Database Panel. 243 | private void action_new_db () { 244 | window.main.database_schema.show_database_panel (); 245 | } 246 | 247 | // Show the Database Panel to edit the currently selected database. 248 | private void action_edit_db () { 249 | window.main.database_schema.edit_database_name (); 250 | } 251 | 252 | // Ask confirmation to the user before deleting the database. 253 | private void action_delete_db () { 254 | var dialog = new Granite.MessageDialog.with_image_from_icon_name (_("Are you sure you want to delete this Database?"), _("All the tables and data will be deleted and you won’t be able to recover it."), "dialog-warning", Gtk.ButtonsType.CANCEL); 255 | dialog.transient_for = window; 256 | 257 | var suggested_button = new Gtk.Button.with_label (_("Yes, Delete!")); 258 | suggested_button.get_style_context ().add_class (Gtk.STYLE_CLASS_DESTRUCTIVE_ACTION); 259 | dialog.add_action_widget (suggested_button, Gtk.ResponseType.ACCEPT); 260 | 261 | dialog.show_all (); 262 | if (dialog.run () == Gtk.ResponseType.ACCEPT) { 263 | window.main.database_schema.delete_database.begin (); 264 | } 265 | 266 | dialog.destroy (); 267 | } 268 | } 269 | -------------------------------------------------------------------------------- /src/Services/DataManager.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2011-2018 Alecaddd (http://alecaddd.com) 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 2 of the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public 15 | * License along with this program; if not, write to the 16 | * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 17 | * Boston, MA 02110-1301 USA 18 | * 19 | * Authored by: Alessandro "Alecaddd" Castellani 20 | */ 21 | 22 | public class Sequeler.Services.DataManager : Object { 23 | private Gee.HashMap? _data = null; 24 | 25 | public Gee.HashMap? data { 26 | get { return _data; } 27 | set { _data = value; } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/Services/PasswordManager.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2011-2018 Alecaddd (http://alecaddd.com) 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 2 of the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public 15 | * License along with this program; if not, write to the 16 | * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 17 | * Boston, MA 02110-1301 USA 18 | * 19 | * Authored by: Alessandro "Alecaddd" Castellani 20 | */ 21 | 22 | public class Sequeler.Services.PasswordManager : Object { 23 | 24 | // Store Password Async 25 | public async void store_password_async (string id, string password) throws Error { 26 | var attributes = new GLib.HashTable (str_hash, str_equal); 27 | attributes["id"] = id; 28 | attributes["schema"] = Constants.PROJECT_NAME; 29 | 30 | var key_name = Constants.PROJECT_NAME + "." + id; 31 | 32 | bool result = yield Secret.password_storev (schema, attributes, Secret.COLLECTION_DEFAULT, key_name, password, null); 33 | 34 | if (! result) { 35 | debug ("Unable to store password for \"%s\" in libsecret keyring", key_name); 36 | } 37 | } 38 | 39 | // Get Password Async 40 | public async string? get_password_async (string id) throws Error { 41 | var attributes = new GLib.HashTable (str_hash, str_equal); 42 | attributes["id"] = id; 43 | attributes["schema"] = Constants.PROJECT_NAME; 44 | 45 | var key_name = Constants.PROJECT_NAME + "." + id; 46 | 47 | string? password = yield Secret.password_lookupv (schema, attributes, null); 48 | 49 | if (password == null) { 50 | debug ("Unable to fetch password in libsecret keyring for %s", key_name); 51 | } 52 | 53 | return password; 54 | } 55 | 56 | // Delete Password Async 57 | public async void clear_password_async (string id) throws Error { 58 | var attributes = new GLib.HashTable (str_hash, str_equal); 59 | attributes["id"] = id; 60 | attributes["schema"] = Constants.PROJECT_NAME; 61 | 62 | var key_name = Constants.PROJECT_NAME + "." + id; 63 | 64 | bool removed = yield Secret.password_clearv (schema, attributes, null); 65 | 66 | if (! removed) { 67 | debug ("Unable to clear password in libsecret keyring for %s", key_name); 68 | } 69 | } 70 | 71 | // Delete All Passwords 72 | public async void clear_all_passwords_async () throws Error { 73 | var attributes = new GLib.HashTable (str_hash, str_equal); 74 | attributes["schema"] = Constants.PROJECT_NAME; 75 | 76 | bool removed = yield Secret.password_clearv (schema, attributes, null); 77 | 78 | if (! removed) { 79 | debug ("Unable to clear all passwords in libsecret"); 80 | } 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/Services/Settings.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2020 Alecaddd (https://alecaddd.com) 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 2 of the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public 15 | * License along with this program; if not, write to the 16 | * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 17 | * Boston, MA 02110-1301 USA 18 | * 19 | * Authored by: Alessandro "Alecaddd" Castellani 20 | */ 21 | 22 | public class Sequeler.Services.Settings : GLib.Settings { 23 | public int pos_x { 24 | get { return get_int ("pos-x"); } 25 | set { set_int ("pos-x", value); } 26 | } 27 | public int pos_y { 28 | get { return get_int ("pos-y"); } 29 | set { set_int ("pos-y", value); } 30 | } 31 | public int window_width { 32 | get { return get_int ("window-width"); } 33 | set { set_int ("window-width", value); } 34 | } 35 | public int window_height { 36 | get { return get_int ("window-height"); } 37 | set { set_int ("window-height", value); } 38 | } 39 | public int sidebar_width { 40 | get { return get_int ("sidebar-width"); } 41 | set { set_int ("sidebar-width", value); } 42 | } 43 | public string[] saved_connections { 44 | owned get { return get_strv ("saved-connections"); } 45 | set { set_strv ("saved-connections", value); } 46 | } 47 | public int tot_connections { 48 | get { return get_int ("tot-connections"); } 49 | set { set_int ("tot-connections", value); } 50 | } 51 | public int limit_results { 52 | get { return get_int ("limit-results"); } 53 | set { set_int ("limit-results", value); } 54 | } 55 | public bool dark_theme { 56 | get { return get_boolean ("dark-theme"); } 57 | set { set_boolean ("dark-theme", value); } 58 | } 59 | public bool save_quick { 60 | get { return get_boolean ("save-quick"); } 61 | set { set_boolean ("save-quick", value); } 62 | } 63 | public string version { 64 | owned get { return get_string ("version"); } 65 | set { set_string ("version", value); } 66 | } 67 | public bool use_system_font { 68 | get { return get_boolean ("use-system-font"); } 69 | set { set_boolean ("use-system-font", value); } 70 | } 71 | public string font { 72 | owned get { return get_string ("font"); } 73 | set { set_string ("font", value); } 74 | } 75 | public string style_scheme { 76 | owned get { return get_string ("style-scheme"); } 77 | set { set_string ("style-scheme", value); } 78 | } 79 | public int query_area { 80 | get { return get_int ("query-area"); } 81 | set { set_int ("query-area", value); } 82 | } 83 | 84 | public Settings () { 85 | Object (schema_id: Constants.PROJECT_NAME); 86 | } 87 | 88 | public void add_connection (Gee.HashMap data) { 89 | if (data["type"] != "SQLite") { 90 | update_password.begin (data); 91 | data.unset ("password"); 92 | data.unset ("ssh_password"); 93 | } 94 | 95 | var conns = get_strv ("saved-connections"); 96 | conns += stringify_data (data); 97 | set_strv ("saved-connections", conns); 98 | tot_connections = tot_connections + 1; 99 | } 100 | 101 | public async void duplicate_connection (Gee.HashMap data) { 102 | data["id"] = tot_connections.to_string (); 103 | data["title"] = _("%s (copy)").printf (data["title"]); 104 | add_connection (data); 105 | } 106 | 107 | public void edit_connection (Gee.HashMap new_data, string old_data) { 108 | var position = 0; 109 | Gee.List existing_connections = new Gee.ArrayList (); 110 | existing_connections.add_all_array (saved_connections); 111 | 112 | if (existing_connections.contains (old_data)) { 113 | position = existing_connections.index_of (old_data); 114 | existing_connections.remove (old_data); 115 | } 116 | 117 | if (new_data["type"] != "SQLite") { 118 | update_password.begin (new_data); 119 | new_data.unset ("password"); 120 | 121 | if (new_data["has_ssh"] == "true" && new_data["ssh_password"] != null) { 122 | update_ssh_password.begin (new_data); 123 | new_data.unset ("ssh_password"); 124 | } 125 | } 126 | 127 | existing_connections.insert (position, stringify_data (new_data)); 128 | 129 | string[] new_conns = {}; 130 | foreach (var conn in existing_connections.to_array ()) { 131 | new_conns += conn; 132 | } 133 | 134 | set_strv ("saved-connections", new_conns); 135 | } 136 | 137 | public void delete_connection (Gee.HashMap data) { 138 | string[] new_conns = {}; 139 | var conns = get_strv ("saved-connections"); 140 | 141 | if (data["type"] != "SQLite") { 142 | delete_password.begin (data); 143 | } 144 | 145 | foreach (var conn in conns) { 146 | var check = arraify_data (conn); 147 | if (check["id"] == data["id"]) { 148 | continue; 149 | } 150 | new_conns += conn; 151 | } 152 | 153 | set_strv ("saved-connections", new_conns); 154 | } 155 | 156 | public void clear_connections () { 157 | string[] empty = {}; 158 | set_strv ("saved-connections", empty); 159 | tot_connections = 0; 160 | 161 | delete_all_passwords.begin (); 162 | } 163 | 164 | public void reorder_connection (Gee.HashMap source, int position) { 165 | Gee.ArrayList existing_connections = new Gee.ArrayList (); 166 | existing_connections.add_all_array (saved_connections); 167 | 168 | foreach (var conn in saved_connections) { 169 | var check = arraify_data (conn); 170 | if (check["id"] == source["id"]) { 171 | existing_connections.remove (conn); 172 | } 173 | } 174 | 175 | existing_connections.insert (position, stringify_data (source)); 176 | 177 | string[] new_conns = {}; 178 | foreach (var conn in existing_connections.to_array ()) { 179 | new_conns += conn; 180 | } 181 | 182 | set_strv ("saved-connections", new_conns); 183 | } 184 | 185 | public string stringify_data (Gee.HashMap data) { 186 | string result = ""; 187 | 188 | foreach (var entry in data.entries) { 189 | string values = "%s=%s\n".printf (entry.key, entry.value); 190 | result = result + values; 191 | } 192 | 193 | return result; 194 | } 195 | 196 | public Gee.HashMap arraify_data (string connection) { 197 | var array = new Gee.HashMap (); 198 | var data = connection.split ("\n"); 199 | 200 | foreach (var d in data) { 201 | var d2 = d.split ("=", 2); 202 | 203 | if (d2[0] == null) { 204 | continue; 205 | } 206 | 207 | array.set (d2[0], d2[1]); 208 | } 209 | 210 | return array; 211 | } 212 | 213 | public async void update_password (Gee.HashMap data) throws Error { 214 | yield password_mngr.store_password_async (data["id"], data["password"]); 215 | } 216 | 217 | public async void update_ssh_password (Gee.HashMap data) throws Error { 218 | yield password_mngr.store_password_async (data["id"] + "9999", data["ssh_password"]); 219 | } 220 | 221 | public async void delete_password (Gee.HashMap data) throws Error { 222 | yield password_mngr.clear_password_async (data["id"]); 223 | 224 | if (data["has_ssh"] == "true" && data["ssh_password"] != null) { 225 | yield password_mngr.clear_password_async (data["id"] + "9999"); 226 | } 227 | } 228 | 229 | public async void delete_all_passwords () throws Error { 230 | yield password_mngr.clear_all_passwords_async (); 231 | } 232 | } 233 | -------------------------------------------------------------------------------- /src/Services/Types/DataBaseType.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2011-2018 Alecaddd (http://alecaddd.com) 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 2 of the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public 15 | * License along with this program; if not, write to the 16 | * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 17 | * Boston, MA 02110-1301 USA 18 | * 19 | * Authored by: Alessandro "Alecaddd" Castellani 20 | */ 21 | 22 | public interface DataBaseType : Object { 23 | /* 24 | * Connect to the database 25 | */ 26 | public abstract string connection_string (Gee.HashMap data); 27 | 28 | /* 29 | * Populate dropdown database selection 30 | */ 31 | public abstract string show_schema (); 32 | 33 | /* 34 | * Populate sidebar with table list 35 | */ 36 | public abstract string show_table_list (string name); 37 | 38 | /* 39 | * Update table name 40 | */ 41 | public abstract string edit_table_name (string old_table, string new_table); 42 | 43 | /* 44 | * Transfer a table from a Database to another 45 | */ 46 | public abstract string transfer_table (string old_database, string table, string new_database); 47 | 48 | /* 49 | * Show table structure 50 | */ 51 | public abstract string show_table_structure (string table, string? sortby = null, string sort = "ASC"); 52 | 53 | /* 54 | * Show table content 55 | */ 56 | public abstract string show_table_content ( 57 | string table, int? count = null, int? page = null, 58 | string? sortby = null, string sort = "ASC" 59 | ); 60 | 61 | /* 62 | * Show table relations 63 | */ 64 | public abstract string show_table_relations ( 65 | string table, string? database, 66 | string? sortby = null, string sort = "ASC" 67 | ); 68 | 69 | /* 70 | * Create database 71 | */ 72 | public abstract string create_database (string name); 73 | 74 | /* 75 | * Delete database 76 | */ 77 | public abstract string delete_database (string name); 78 | } 79 | -------------------------------------------------------------------------------- /src/Services/Types/MySQL.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2011-2019 Alecaddd (https://alecaddd.com) 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 2 of the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public 15 | * License along with this program; if not, write to the 16 | * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 17 | * Boston, MA 02110-1301 USA 18 | * 19 | * Authored by: Alessandro "Alecaddd" Castellani 20 | */ 21 | 22 | public class Sequeler.Services.Types.MySQL : Object, DataBaseType { 23 | public string port { set; get; default = "3306"; } 24 | public string host { set; get; default = "127.0.0.1"; } 25 | 26 | public string connection_string (Gee.HashMap data) { 27 | var username = Gda.rfc1738_encode (data["username"]); 28 | var password = Gda.rfc1738_encode (data["password"]); 29 | var use_ssl = Gda.rfc1738_encode (data["use_ssl"] ?? "false"); 30 | var name = Gda.rfc1738_encode (data["name"]); 31 | if (data["has_ssh"] == "true") { 32 | port = "9000"; 33 | host = "127.0.0.1"; 34 | } else { 35 | port = data["port"] != "" ? data["port"] : port; 36 | host = data["host"] != "" ? Gda.rfc1738_encode (data["host"]) : host; 37 | } 38 | 39 | return "MySQL://" + username + ":" + password + "@DB_NAME=" + name + ";HOST=" + host + ";PORT=" + port + ";USE_SSL=" + use_ssl; 40 | } 41 | 42 | public string show_schema () { 43 | return "SHOW SCHEMAS"; 44 | } 45 | 46 | public string show_table_list (string name) { 47 | return "SELECT table_name, table_rows FROM information_schema.TABLES WHERE TABLE_SCHEMA = '%s' ORDER BY table_name ASC".printf (name); 48 | } 49 | 50 | public string edit_table_name (string old_table, string new_table) { 51 | return "RENAME TABLE %s TO %s".printf (old_table, new_table); 52 | } 53 | 54 | public string transfer_table (string old_database, string table, string new_database) { 55 | return "RENAME TABLE %s.%s TO %s.%s".printf (old_database, table, new_database, table); 56 | } 57 | 58 | public string show_table_structure (string table, string? sortby = null, string sort = "ASC") { 59 | var output = "SELECT COLUMN_NAME, ORDINAL_POSITION, COLUMN_DEFAULT, IS_NULLABLE, CHARACTER_SET_NAME, COLLATION_NAME, COLUMN_TYPE, COLUMN_KEY, EXTRA, COLUMN_COMMENT FROM information_schema.COLUMNS WHERE table_name = '%s' AND table_schema = DATABASE()".printf (table); 60 | 61 | if (sortby != null) { 62 | output += " ORDER BY %s %s".printf (sortby, sort); 63 | } 64 | 65 | return output; 66 | } 67 | 68 | public string show_table_content ( 69 | string table, int? count = null, int? page = null, 70 | string? sortby = null, string sort = "ASC" 71 | ) { 72 | var output = "SELECT * FROM %s".printf (table); 73 | 74 | if (sortby != null) { 75 | output += " ORDER BY %s %s".printf (sortby, sort); 76 | } 77 | 78 | if (count != null && count > settings.limit_results) { 79 | output += " LIMIT %i".printf (settings.limit_results); 80 | } 81 | 82 | if (page != null && page > 1) { 83 | output += " OFFSET %i".printf (settings.limit_results * (page - 1)); 84 | } 85 | 86 | return output; 87 | } 88 | 89 | public string show_table_relations ( 90 | string table, string? database, 91 | string? sortby = null, string sort = "ASC" 92 | ) { 93 | var output = "SELECT COLUMN_NAME, CONSTRAINT_NAME, REFERENCED_COLUMN_NAME, REFERENCED_TABLE_NAME FROM information_schema.KEY_COLUMN_USAGE WHERE TABLE_NAME = '%s' AND TABLE_SCHEMA = '%s'".printf (table, database); 94 | 95 | if (sortby != null) { 96 | output += " ORDER BY %s %s".printf (sortby, sort); 97 | } 98 | 99 | return output; 100 | } 101 | 102 | public string create_database (string name) { 103 | return "CREATE DATABASE %s".printf (name); 104 | } 105 | 106 | public string delete_database (string name) { 107 | return "DROP DATABASE %s".printf (name); 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /src/Services/Types/PostgreSQL.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2011-2019 Alecaddd (https://alecaddd.com) 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 2 of the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public 15 | * License along with this program; if not, write to the 16 | * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 17 | * Boston, MA 02110-1301 USA 18 | * 19 | * Authored by: Alessandro "Alecaddd" Castellani 20 | */ 21 | 22 | public class Sequeler.Services.Types.PostgreSQL : Object, DataBaseType { 23 | public string port { set; get; default = "5432"; } 24 | public string host { set; get; default = "127.0.0.1"; } 25 | 26 | public string connection_string (Gee.HashMap data) { 27 | var username = Gda.rfc1738_encode (data["username"]); 28 | var password = Gda.rfc1738_encode (data["password"]); 29 | var use_ssl = Gda.rfc1738_encode (data["use_ssl"] ?? "false"); 30 | var name = Gda.rfc1738_encode (data["name"]); 31 | host = data["host"] != "" ? Gda.rfc1738_encode (data["host"]) : host; 32 | if (data["has_ssh"] == "true") { 33 | port = "9000"; 34 | } else { 35 | port = data["port"] != "" ? data["port"] : port; 36 | } 37 | 38 | return "PostgreSQL://" + username + ":" + password + "@DB_NAME=" + name + ";HOST=" + host + ";PORT=" + port + ";USE_SSL=" + use_ssl; 39 | } 40 | 41 | public string show_schema () { 42 | return "SELECT schema_name FROM information_schema.schemata"; 43 | } 44 | 45 | public string show_table_list (string name) { 46 | return "SELECT relname, reltuples FROM pg_class C LEFT JOIN pg_namespace N ON (N.oid = C.relnamespace) WHERE nspname NOT IN ('pg_catalog', 'information_schema') AND relkind='r' ORDER BY relname ASC;"; 47 | } 48 | 49 | public string edit_table_name (string old_table, string new_table) { 50 | return "ALTER TABLE \"%s\" RENAME TO \"%s\"".printf (old_table, new_table); 51 | } 52 | 53 | public string transfer_table (string old_database, string table, string new_database) { 54 | return ""; 55 | } 56 | 57 | public string show_table_structure (string table, string? sortby = null, string sort = "ASC") { 58 | var output = "SELECT * FROM information_schema.COLUMNS WHERE table_name='%s'".printf (table); 59 | 60 | if (sortby != null) { 61 | output += " ORDER BY %s %s".printf (sortby, sort); 62 | } 63 | 64 | return output; 65 | } 66 | 67 | public string show_table_content ( 68 | string table, int? count = null, int? page = null, 69 | string? sortby = null, string sort = "ASC" 70 | ) { 71 | var output = "SELECT * FROM \"%s\"".printf (table); 72 | 73 | if (sortby != null) { 74 | output += " ORDER BY \"%s\" %s".printf (sortby, sort); 75 | } 76 | 77 | if (count != null && count > settings.limit_results) { 78 | output += " LIMIT %i".printf (settings.limit_results); 79 | } 80 | 81 | if (page != null && page > 1) { 82 | output += " OFFSET %i".printf (settings.limit_results * (page - 1)); 83 | } 84 | 85 | return output; 86 | } 87 | 88 | public string show_table_relations ( 89 | string table, string? database, 90 | string? sortby = null, string sort = "ASC" 91 | ) { 92 | var output = "SELECT ccu.column_name as \"COLUMN_NAME\", tc.constraint_name as \"CONSTRAINT_NAME\", kcu.column_name as \"REFERENCED_COLUMN_NAME\", tc.table_name as \"REFERENCED_TABLE\" FROM information_schema.table_constraints tc JOIN information_schema.key_column_usage kcu ON tc.constraint_name = kcu.constraint_name JOIN information_schema.constraint_column_usage ccu ON ccu.constraint_name = tc.constraint_name WHERE constraint_type = 'FOREIGN KEY' AND ccu.table_name='%s' AND ccu.table_schema = '%s'".printf (table, database); 93 | 94 | if (sortby != null) { 95 | output += " ORDER BY \"%s\" %s".printf (sortby, sort); 96 | } 97 | 98 | return output; 99 | } 100 | 101 | public string create_database (string name) { 102 | // Temporary placeholder methods. No current support for database 103 | // operations in PostgreSQL. 104 | return ""; 105 | } 106 | 107 | public string delete_database (string name) { 108 | // Temporary placeholder methods. No current support for database 109 | // operations in PostgreSQL. 110 | return ""; 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /src/Services/Types/SQLite.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2011-2019 Alecaddd (https://alecaddd.com) 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 2 of the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public 15 | * License along with this program; if not, write to the 16 | * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 17 | * Boston, MA 02110-1301 USA 18 | * 19 | * Authored by: Alessandro "Alecaddd" Castellani 20 | */ 21 | 22 | public class Sequeler.Services.Types.SQLite : Object, DataBaseType { 23 | 24 | public string connection_string (Gee.HashMap data) { 25 | var file_path = data["file_path"].replace ("file://", ""); 26 | var last_slash = file_path.last_index_of ("/", 0) + 1; 27 | 28 | var dir = Gda.rfc1738_encode (file_path.substring (0, last_slash)); 29 | var name = Gda.rfc1738_encode (file_path.substring (last_slash, -1)); 30 | 31 | return "SQLite://DB_DIR=" + dir + ";DB_NAME=" + name; 32 | } 33 | 34 | public string show_schema () { 35 | return "SELECT name FROM sqlite_master WHERE type='table' ORDER BY name;"; 36 | } 37 | 38 | public string show_table_list (string name) { 39 | return "SELECT COUNT(*) FROM %s".printf (name); 40 | } 41 | 42 | public string edit_table_name (string old_table, string new_table) { 43 | return "ALTER TABLE %s RENAME TO %s".printf (old_table, new_table); 44 | } 45 | 46 | public string transfer_table (string old_database, string table, string new_database) { 47 | // Temporary placeholder methods. No current support for database 48 | // operations in SQLite. 49 | return ""; 50 | } 51 | 52 | public string show_table_structure (string table, string? sortby = null, string sort = "ASC") { 53 | return "PRAGMA table_info('%s')".printf (table); 54 | } 55 | 56 | public string show_table_content ( 57 | string table, int? count = null, int? page = null, 58 | string? sortby = null, string sort = "ASC" 59 | ) { 60 | var output = "SELECT * FROM %s".printf (table); 61 | 62 | if (sortby != null) { 63 | output += " ORDER BY `%s` %s".printf (sortby, sort); 64 | } 65 | 66 | if (count != null && count > settings.limit_results) { 67 | output += " LIMIT %i".printf (settings.limit_results); 68 | } 69 | 70 | if (page != null && page > 1) { 71 | output += " OFFSET %i".printf (settings.limit_results * (page - 1)); 72 | } 73 | 74 | return output; 75 | } 76 | 77 | public string show_table_relations ( 78 | string table, string? database, 79 | string? sortby = null, string sort = "ASC" 80 | ) { 81 | return "PRAGMA foreign_key_list('%s')".printf (table); 82 | } 83 | 84 | public string create_database (string name) { 85 | // Temporary placeholder methods. No current support for database 86 | // operations in SQLite. 87 | return ""; 88 | } 89 | 90 | public string delete_database (string name) { 91 | // Temporary placeholder methods. No current support for database 92 | // operations in SQLite. 93 | return ""; 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /src/Services/UpgradeManager.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2011-2018 Alecaddd (http://alecaddd.com) 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 2 of the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public 15 | * License along with this program; if not, write to the 16 | * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 17 | * Boston, MA 02110-1301 USA 18 | * 19 | * Authored by: Alessandro "Alecaddd" Castellani 20 | */ 21 | 22 | public class Sequeler.Services.UpgradeManager : Object { 23 | construct { 24 | string version = settings.version; 25 | 26 | switch (version) { 27 | case "": 28 | upgrade_passwords_to_libsecret.begin (); 29 | case Constants.VERSION: 30 | debug ("Current Version"); 31 | } 32 | 33 | settings.version = Constants.VERSION; 34 | } 35 | 36 | public virtual async void upgrade_passwords_to_libsecret () throws Error { 37 | var current_connections = settings.saved_connections; 38 | 39 | Gee.List existing_connections = new Gee.ArrayList (); 40 | existing_connections.add_all_array (current_connections); 41 | 42 | foreach (var conn in settings.saved_connections) { 43 | var check = settings.arraify_data (conn); 44 | 45 | if (check["type"] != "SQLite" && check.has_key ("password")) { 46 | settings.update_password.begin (check); 47 | check.unset ("password"); 48 | 49 | existing_connections.remove (conn); 50 | existing_connections.insert (0, settings.stringify_data (check)); 51 | } 52 | } 53 | 54 | settings.saved_connections = existing_connections.to_array (); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/Widgets/QueryParamsDialog.vala: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2017-2020 Alecaddd (https://alecaddd.com) 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 2 of the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public 15 | * License along with this program; if not, write to the 16 | * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 17 | * Boston, MA 02110-1301 USA 18 | * 19 | * Authored by: Francisco Altoe 20 | * Authored by: Alessandro "Alecaddd" Castellani 21 | */ 22 | 23 | /** 24 | * Dialog subclass used to prompt the user to provide the required query parameters 25 | */ 26 | public class Sequeler.Widgets.QueryParamsDialog : Gtk.Dialog { 27 | public weak Sequeler.Window window { get; construct; } 28 | 29 | public Sequeler.Layouts.Views.Query parent_view { get; construct; } 30 | public string query { get; construct; } 31 | public Gda.Statement statement { get; construct; } 32 | public Gda.Set params { get; construct; } 33 | private Gee.ArrayList entries; 34 | 35 | private Sequeler.Partials.ResponseMessage response_msg; 36 | 37 | enum Action { 38 | RUN_QUERY, 39 | CANCEL 40 | } 41 | 42 | public QueryParamsDialog ( 43 | Sequeler.Window? parent, 44 | Sequeler.Layouts.Views.Query view, 45 | string query, 46 | Gda.Statement statement, 47 | Gda.Set? @params 48 | ) { 49 | Object ( 50 | border_width: 6, 51 | deletable: false, 52 | resizable: true, 53 | title: _("Query parameters"), 54 | transient_for: parent, 55 | window: parent, 56 | parent_view: view, 57 | query: query, 58 | statement: statement, 59 | params: @params 60 | ); 61 | } 62 | 63 | construct { 64 | build_content (); 65 | response.connect (on_response); 66 | } 67 | 68 | private void build_content () { 69 | default_width = 500; 70 | var content = get_content_area (); 71 | 72 | var form_grid = new Gtk.Grid (); 73 | form_grid.margin = 6; 74 | form_grid.row_spacing = 12; 75 | form_grid.column_spacing = 12; 76 | 77 | entries = new Gee.ArrayList (); 78 | 79 | for (int i = 0; ; i++) { 80 | Gda.Holder? holder = params.get_nth_holder (i); 81 | if (holder == null) { 82 | break; 83 | } 84 | var holder_id = holder.get_id (); 85 | 86 | var label = new Gtk.Label (holder_id + ":"); 87 | form_grid.attach (label, 0, i, 1, 1); 88 | var entry = entry_for_holder (holder); 89 | form_grid.attach (entry, 1, i, 1, 1); 90 | entries.add (entry); 91 | } 92 | 93 | var scrolled_window = new Gtk.ScrolledWindow (null, null); 94 | scrolled_window.add (form_grid); 95 | 96 | int main_window_width, main_window_height; 97 | parent_view.window.get_size (out main_window_width, out main_window_height); 98 | 99 | // Prevent the scrolled window from growing bigger than the main window itself. 100 | scrolled_window.set_max_content_height (main_window_height / 2); 101 | scrolled_window.set_max_content_width (main_window_width); 102 | scrolled_window.set_propagate_natural_width (true); 103 | scrolled_window.set_propagate_natural_height (true); 104 | 105 | response_msg = new Sequeler.Partials.ResponseMessage (); 106 | 107 | content.add (scrolled_window); 108 | content.add (response_msg); 109 | 110 | var cancel_button = new Gtk.Button.with_label (_("Cancel")); 111 | add_action_widget (cancel_button, Action.CANCEL); 112 | 113 | var run_button = new Sequeler.Partials.RunQueryButton (); 114 | add_action_widget (run_button, Action.RUN_QUERY); 115 | } 116 | 117 | private Gtk.Widget entry_for_holder (Gda.Holder holder) { 118 | Type holder_g_type = holder.get_g_type (); 119 | switch (holder_g_type) { 120 | case Type.BOOLEAN: 121 | return new Gtk.Switch (); 122 | case Type.INT: 123 | case Type.UINT: 124 | var widget = new Partials.ParamEntry (this, Gtk.InputPurpose.DIGITS); 125 | return widget; 126 | case Type.FLOAT: 127 | case Type.DOUBLE: 128 | var widget = new Partials.ParamEntry (this, Gtk.InputPurpose.NUMBER); 129 | return widget; 130 | default: 131 | return new Partials.ParamEntry (this); 132 | } 133 | } 134 | 135 | /** 136 | * Takes the parse result and update the widgets style and the holder value. 137 | */ 138 | private bool store_parsed_value ( 139 | bool parse_result, 140 | Value parsed_value, 141 | Gda.Holder holder, 142 | Gtk.Entry entry 143 | ) { 144 | entry.get_style_context ().remove_class ("error"); 145 | 146 | if (!parse_result) { 147 | entry.get_style_context ().add_class ("error"); 148 | return false; 149 | } 150 | 151 | try { 152 | holder.set_value (parsed_value); 153 | } catch (Error e) { 154 | write_response (e.message); 155 | entry.get_style_context ().add_class ("error"); 156 | return false; 157 | } 158 | 159 | return true; 160 | } 161 | 162 | private bool set_value_for_holder (Gda.Holder holder, Gtk.Widget widget) { 163 | Type holder_g_type = holder.get_g_type (); 164 | if (holder_g_type == Type.BOOLEAN) { 165 | Gtk.Switch switch = widget as Gtk.Switch; 166 | if (switch == null) { 167 | return false; 168 | } 169 | 170 | try { 171 | holder.set_value (switch.get_active ()); 172 | } catch (Error ex) { 173 | return false; 174 | } 175 | 176 | return true; 177 | } else { 178 | Gtk.Entry entry = widget as Gtk.Entry; 179 | string text = entry.get_text (); 180 | 181 | bool parse_result = true; 182 | Value parsed_value; 183 | 184 | if (holder_g_type == Type.INT) { 185 | // TODO: replace this with the following once we upgrade to a newer valac 186 | // parse_result = int.try_parse (text, out parsed_value); 187 | parsed_value = int.parse (text); 188 | } else if (holder_g_type == Type.UINT) { 189 | // TODO: replace this with the following once we upgrade to a newer valac 190 | // parse_result = uint.try_parse (text, out parsed_value); 191 | parsed_value = int.parse (text); 192 | } else if (holder_g_type == Type.FLOAT) { 193 | // TODO: replace this with the following once we upgrade to a newer valac 194 | // parse_result = float.try_parse (text, out parsed_value); 195 | parsed_value = double.parse (text); 196 | } else if (holder_g_type == Type.DOUBLE) { 197 | // TODO: replace this with the following once we upgrade to a newer valac 198 | // parse_result = double.try_parse (text, out parsed_value); 199 | parsed_value = double.parse (text); 200 | } else { 201 | parsed_value = text; 202 | } 203 | 204 | return store_parsed_value (parse_result, parsed_value, holder, entry); 205 | } 206 | } 207 | 208 | private bool get_param_values () { 209 | bool validation_result = true; 210 | for (int i = 0; ; i++) { 211 | Gda.Holder? holder = params.get_nth_holder (i); 212 | if (holder == null) { 213 | break; 214 | } 215 | validation_result &= set_value_for_holder (holder, entries[i]); 216 | } 217 | 218 | return validation_result; 219 | } 220 | 221 | private void on_response (Gtk.Dialog source, int response_id) { 222 | switch (response_id) { 223 | case Action.RUN_QUERY: 224 | run_query (); 225 | break; 226 | case Action.CANCEL: 227 | destroy (); 228 | break; 229 | } 230 | } 231 | 232 | public void run_query () { 233 | if (!get_param_values ()) { 234 | return; 235 | } 236 | 237 | parent_view.run_query_statement (query, statement, params); 238 | destroy (); 239 | } 240 | 241 | private void write_response (string? response_text) { 242 | response_msg.label = response_text; 243 | } 244 | } 245 | -------------------------------------------------------------------------------- /src/Window.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2020 Alecaddd (https://alecaddd.com) 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 2 of the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public 15 | * License along with this program; if not, write to the 16 | * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 17 | * Boston, MA 02110-1301 USA 18 | * 19 | * Authored by: Alessandro "Alecaddd" Castellani 20 | */ 21 | 22 | public class Sequeler.Window : Gtk.ApplicationWindow { 23 | public weak Sequeler.Application app { get; construct; } 24 | 25 | public Sequeler.Layouts.Main main; 26 | public Sequeler.Layouts.HeaderBar headerbar; 27 | public Sequeler.Services.ActionManager action_manager; 28 | public Sequeler.Services.DataManager data_manager; 29 | public Sequeler.Widgets.ConnectionDialog? connection_dialog = null; 30 | 31 | public Gtk.AccelGroup accel_group { get; construct; } 32 | 33 | public Window (Sequeler.Application sequeler_app) { 34 | Object ( 35 | application: sequeler_app, 36 | app: sequeler_app, 37 | icon_name: Constants.PROJECT_NAME 38 | ); 39 | } 40 | 41 | construct { 42 | accel_group = new Gtk.AccelGroup (); 43 | add_accel_group (accel_group); 44 | 45 | action_manager = new Sequeler.Services.ActionManager (app, this); 46 | main = new Sequeler.Layouts.Main (this); 47 | headerbar = new Sequeler.Layouts.HeaderBar (this); 48 | data_manager = new Sequeler.Services.DataManager (); 49 | 50 | build_ui (); 51 | 52 | move (settings.pos_x, settings.pos_y); 53 | resize (settings.window_width, settings.window_height); 54 | 55 | show_app (); 56 | } 57 | 58 | public Sequeler.Window get_instance () { 59 | return this; 60 | } 61 | 62 | private void build_ui () { 63 | Gtk.Settings.get_default ().gtk_application_prefer_dark_theme = settings.dark_theme; 64 | 65 | var css_provider = new Gtk.CssProvider (); 66 | css_provider.load_from_resource ("/com/github/alecaddd/sequeler/stylesheet.css"); 67 | 68 | Gtk.StyleContext.add_provider_for_screen ( 69 | Gdk.Screen.get_default (), css_provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION 70 | ); 71 | 72 | set_titlebar (headerbar); 73 | set_border_width (0); 74 | 75 | delete_event.connect (before_destroy); 76 | 77 | add (main); 78 | } 79 | 80 | public bool before_destroy () { 81 | update_status (); 82 | app.get_active_window ().destroy (); 83 | return true; 84 | } 85 | 86 | private void update_status () { 87 | int width, height, x, y; 88 | 89 | get_size (out width, out height); 90 | get_position (out x, out y); 91 | 92 | settings.pos_x = x; 93 | settings.pos_y = y; 94 | settings.window_width = width; 95 | settings.window_height = height; 96 | settings.sidebar_width = main.get_position (); 97 | if (main.database_view.query.n_tabs > 0) { 98 | settings.query_area = 99 | (main.database_view.query.current.page as Layouts.Views.Query) 100 | .panels.get_position (); 101 | } 102 | } 103 | 104 | public void show_app () { 105 | show_all (); 106 | show (); 107 | present (); 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /src/config.vala.in: -------------------------------------------------------------------------------- 1 | namespace Constants { 2 | public const string PROJECT_NAME = "@PROJECT_NAME@"; 3 | public const string GETTEXT_PACKAGE = "@GETTEXT_PACKAGE@"; 4 | public const string LOCALEDIR = "@LOCALEDIR@"; 5 | public const string VERSION = "@VERSION@"; 6 | } 7 | -------------------------------------------------------------------------------- /src/meson.build: -------------------------------------------------------------------------------- 1 | conf_data = configuration_data() 2 | conf_data.set('PROJECT_NAME', application_id) 3 | conf_data.set('GETTEXT_PACKAGE', meson.project_name()) 4 | conf_data.set('LOCALEDIR', join_paths(get_option('prefix'), get_option('localedir'))) 5 | conf_data.set('VERSION', meson.project_version()) 6 | 7 | config_header = configure_file( 8 | input: 'config.vala.in', 9 | output: 'config.vala', 10 | configuration: conf_data 11 | ) 12 | 13 | 14 | # Create a new executable, list the files we want to compile, list the dependencies we need, and install 15 | executable( 16 | application_id, 17 | 'Main.vala', 18 | 'Application.vala', 19 | 'Window.vala', 20 | 21 | 'Layouts/HeaderBar.vala', 22 | 'Layouts/Main.vala', 23 | 'Layouts/Library.vala', 24 | 'Layouts/Welcome.vala', 25 | 'Layouts/DataBaseSchema.vala', 26 | 'Layouts/DataBaseView.vala', 27 | 28 | 'Layouts/Views/Structure.vala', 29 | 'Layouts/Views/Content.vala', 30 | 'Layouts/Views/Relations.vala', 31 | 'Layouts/Views/Query.vala', 32 | 33 | 'Partials/ButtonType.vala', 34 | 'Partials/DataBasePanel.vala', 35 | 'Partials/DatabaseTable.vala', 36 | 'Partials/Helpers.vala', 37 | 'Partials/LibraryItem.vala', 38 | 'Partials/TreeBuilder.vala', 39 | 40 | 'Services/Settings.vala', 41 | 'Services/ActionManager.vala', 42 | 'Services/DataManager.vala', 43 | 'Services/ConnectionManager.vala', 44 | 'Services/PasswordManager.vala', 45 | 'Services/UpgradeManager.vala', 46 | 47 | 'Services/Types/DataBaseType.vala', 48 | 'Services/Types/MySQL.vala', 49 | 'Services/Types/PostgreSQL.vala', 50 | 'Services/Types/SQLite.vala', 51 | 52 | 'Widgets/ConnectionDialog.vala', 53 | 'Widgets/QueryParamsDialog.vala', 54 | 55 | asresources, 56 | config_header, 57 | dependencies: [ 58 | dependency('gtk+-3.0'), 59 | dependency('granite', version: '>= 5.3.0'), 60 | dependency('glib-2.0'), 61 | dependency('gee-0.8'), 62 | dependency('gobject-2.0'), 63 | dependency('libxml-2.0'), 64 | dependency('libgda-5.0'), 65 | dependency('libssh2'), 66 | dependency('libsecret-1'), 67 | dependency('gtksourceview-4'), 68 | m_dep, 69 | linux_dep 70 | ], 71 | vala_args: vala_args, 72 | install: true 73 | ) 74 | -------------------------------------------------------------------------------- /vapi/libgda-5.0.deps: -------------------------------------------------------------------------------- 1 | glib-2.0 2 | gobject-2.0 3 | libxml-2.0 -------------------------------------------------------------------------------- /vapi/libsecret-1.vapi: -------------------------------------------------------------------------------- 1 | /* libsecret-1.vapi generated by vapigen-0.18 and hand-edited to add SCHEMA_COMPAT_NETWORK */ 2 | 3 | [CCode (cprefix = "Secret", gir_namespace = "Secret", gir_version = "1", lower_case_cprefix = "secret_")] 4 | namespace Secret { 5 | [CCode (cheader_filename = "libsecret/secret.h", cname = "SECRET_SCHEMA_COMPAT_NETWORK")] 6 | public Secret.Schema SCHEMA_COMPAT_NETWORK; 7 | 8 | [CCode (cheader_filename = "libsecret/secret.h", copy_function = "g_boxed_copy", free_function = "g_boxed_free", type_id = "secret_schema_get_type ()")] 9 | [Compact] 10 | public class Schema { 11 | [CCode (array_length = false, array_null_terminated = true)] 12 | public weak Secret.SchemaAttribute[] attributes; 13 | public Secret.SchemaFlags flags; 14 | public weak string name; 15 | [CCode (has_construct_function = false)] 16 | public Schema (string name, Secret.SchemaFlags flags, ...); 17 | [CCode (cname = "secret_schema_newv", has_construct_function = false)] 18 | public Schema.newv (string name, Secret.SchemaFlags flags, GLib.HashTable attribute_names_and_types); 19 | public Secret.Schema @ref (); 20 | public void unref (); 21 | } 22 | [CCode (cheader_filename = "libsecret/secret.h", copy_function = "g_boxed_copy", free_function = "g_boxed_free", type_id = "secret_schema_attribute_get_type ()")] 23 | [Compact] 24 | public class SchemaAttribute { 25 | public weak string name; 26 | public Secret.SchemaAttributeType type; 27 | } 28 | [CCode (cheader_filename = "libsecret/secret.h", cprefix = "SECRET_ERROR_", has_type_id = false)] 29 | public enum Error { 30 | PROTOCOL, 31 | IS_LOCKED, 32 | NO_SUCH_OBJECT, 33 | ALREADY_EXISTS; 34 | public static GLib.Quark get_quark (); 35 | } 36 | [CCode (cheader_filename = "libsecret/secret.h", cprefix = "SECRET_SCHEMA_ATTRIBUTE_", has_type_id = false)] 37 | public enum SchemaAttributeType { 38 | STRING, 39 | INTEGER, 40 | BOOLEAN 41 | } 42 | [CCode (cheader_filename = "libsecret/secret.h", cprefix = "SECRET_SCHEMA_", has_type_id = false)] 43 | [Flags] 44 | public enum SchemaFlags { 45 | NONE, 46 | DONT_MATCH_NAME 47 | } 48 | [CCode (cheader_filename = "libsecret/secret.h", cname = "SECRET_COLLECTION_DEFAULT")] 49 | public const string COLLECTION_DEFAULT; 50 | [CCode (cheader_filename = "libsecret/secret.h", cname = "SECRET_COLLECTION_SESSION")] 51 | public const string COLLECTION_SESSION; 52 | [CCode (cheader_filename = "libsecret/secret.h")] 53 | public static GLib.HashTable attributes_build (Secret.Schema schema, ...); 54 | [CCode (cheader_filename = "libsecret/secret.h")] 55 | public static GLib.HashTable attributes_buildv (Secret.Schema schema, va_list va); 56 | [CCode (cheader_filename = "libsecret/secret.h")] 57 | public static async bool password_clear (Secret.Schema schema, GLib.Cancellable? cancellable, ...) throws GLib.Error; 58 | [CCode (cheader_filename = "libsecret/secret.h")] 59 | public static bool password_clear_sync (Secret.Schema schema, GLib.Cancellable? cancellable = null, ...) throws GLib.Error; 60 | [CCode (cheader_filename = "libsecret/secret.h", finish_name = "secret_password_clear_finish")] 61 | public static async bool password_clearv (Secret.Schema schema, GLib.HashTable attributes, GLib.Cancellable? cancellable) throws GLib.Error; 62 | [CCode (cheader_filename = "libsecret/secret.h")] 63 | public static bool password_clearv_sync (Secret.Schema schema, GLib.HashTable attributes, GLib.Cancellable? cancellable = null) throws GLib.Error; 64 | [CCode (cheader_filename = "libsecret/secret.h")] 65 | public static async string password_lookup (Secret.Schema schema, GLib.Cancellable? cancellable, ...) throws GLib.Error; 66 | [CCode (cheader_filename = "libsecret/secret.h")] 67 | public static string password_lookup_sync (Secret.Schema schema, GLib.Cancellable? cancellable = null, ...) throws GLib.Error; 68 | [CCode (cheader_filename = "libsecret/secret.h", finish_name = "secret_password_lookup_finish")] 69 | public static async string password_lookupv (Secret.Schema schema, GLib.HashTable attributes, GLib.Cancellable? cancellable) throws GLib.Error; 70 | [CCode (cheader_filename = "libsecret/secret.h")] 71 | public static string password_lookupv_sync (Secret.Schema schema, GLib.HashTable attributes, GLib.Cancellable? cancellable = null) throws GLib.Error; 72 | [CCode (cheader_filename = "libsecret/secret.h")] 73 | public static async bool password_store (Secret.Schema schema, string? collection, string label, string password, GLib.Cancellable? cancellable, ...) throws GLib.Error; 74 | [CCode (cheader_filename = "libsecret/secret.h")] 75 | public static bool password_store_sync (Secret.Schema schema, string? collection, string label, string password, GLib.Cancellable? cancellable = null, ...) throws GLib.Error; 76 | [CCode (cheader_filename = "libsecret/secret.h", finish_name = "secret_password_store_finish")] 77 | public static async bool password_storev (Secret.Schema schema, GLib.HashTable attributes, string? collection, string label, string password, GLib.Cancellable? cancellable) throws GLib.Error; 78 | [CCode (cheader_filename = "libsecret/secret.h")] 79 | public static bool password_storev_sync (Secret.Schema schema, GLib.HashTable attributes, string? collection, string label, string password, GLib.Cancellable? cancellable = null) throws GLib.Error; 80 | [CCode (cheader_filename = "libsecret/secret.h")] 81 | public static void password_wipe (string? password); 82 | } 83 | --------------------------------------------------------------------------------