diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0d66089..dd4e8cc 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -2,6 +2,7 @@ name: CI permissions: contents: write + actions: write on: push: @@ -20,7 +21,7 @@ env: jobs: test: - if: github.event_name == 'pull_request' || (github.event_name == 'push' && github.ref != 'refs/heads/main' && github.ref != 'refs/heads/nightly') + if: github.event_name == 'pull_request' || (github.event_name == 'push' && github.ref != 'refs/heads/main') runs-on: ubuntu-latest steps: @@ -63,6 +64,14 @@ jobs: restore-keys: | pip-${{ runner.os }}-py${{ env.PYTHON_VERSION }}- + - name: Cache uv + uses: actions/cache@v4 + with: + path: ${{ env.UV_CACHE_DIR }} + key: uv-${{ runner.os }}-py${{ env.PYTHON_VERSION }}-${{ hashFiles('**/uv.lock', '**/pyproject.toml') }} + restore-keys: | + uv-${{ runner.os }}-py${{ env.PYTHON_VERSION }}- + - name: Cache wheelhouse uses: actions/cache@v4 with: @@ -82,7 +91,7 @@ jobs: run: | mkdir -p "${WHEEL_CACHE_DIR}" - if ls "${WHEEL_CACHE_DIR}"/wxPython*.whl >/dev/null 2>&1; then + if ls "${WHEEL_CACHE_DIR}"/wxpython-*.whl >/dev/null 2>&1; then echo "wxPython wheel found in cache, skipping wheel build" echo "needs_build=false" >> "$GITHUB_OUTPUT" else @@ -95,10 +104,19 @@ jobs: run: | mkdir -p "${WHEEL_CACHE_DIR}" python -m pip wheel -w "${WHEEL_CACHE_DIR}" -r requirements.lock.txt + find "${PIP_CACHE_DIR}/wheels" -type f -name 'wxpython-*.whl' -exec cp -u {} "${WHEEL_CACHE_DIR}/" \; - name: Upgrade build tooling run: uv pip install -U pip setuptools wheel + - name: Preinstall wxPython from wheelhouse + run: | + if ls "${WHEEL_CACHE_DIR}"/wxpython-*.whl >/dev/null 2>&1; then + uv pip install --no-index --find-links "${WHEEL_CACHE_DIR}" wxpython==4.2.5 + else + echo "No wxPython wheel found in wheelhouse" + fi + - name: Install dependencies from wheelhouse (fallback on build) run: | if uv sync --extra dev --find-links "${WHEEL_CACHE_DIR}" --no-build; then @@ -109,10 +127,10 @@ jobs: fi - name: Run tests (--all) - run: xvfb-run -a ./scripts/runtest.sh --all + run: xvfb-run -a uv run ./scripts/runtest.py --all update: - if: github.event_name == 'push' && github.ref == 'refs/heads/nightly' + if: github.event_name == 'push' && github.ref == 'refs/heads/main' && !contains(github.event.head_commit.message, '[skip ci]') runs-on: ubuntu-latest steps: @@ -155,6 +173,14 @@ jobs: restore-keys: | pip-${{ runner.os }}-py${{ env.PYTHON_VERSION }}- + - name: Cache uv + uses: actions/cache@v4 + with: + path: ${{ env.UV_CACHE_DIR }} + key: uv-${{ runner.os }}-py${{ env.PYTHON_VERSION }}-${{ hashFiles('**/uv.lock', '**/pyproject.toml') }} + restore-keys: | + uv-${{ runner.os }}-py${{ env.PYTHON_VERSION }}- + - name: Cache wheelhouse uses: actions/cache@v4 with: @@ -174,7 +200,7 @@ jobs: run: | mkdir -p "${WHEEL_CACHE_DIR}" - if ls "${WHEEL_CACHE_DIR}"/wxPython*.whl >/dev/null 2>&1; then + if ls "${WHEEL_CACHE_DIR}"/wxpython-*.whl >/dev/null 2>&1; then echo "wxPython wheel found in cache, skipping wheel build" echo "needs_build=false" >> "$GITHUB_OUTPUT" else @@ -187,10 +213,19 @@ jobs: run: | mkdir -p "${WHEEL_CACHE_DIR}" python -m pip wheel -w "${WHEEL_CACHE_DIR}" -r requirements.lock.txt + find "${PIP_CACHE_DIR}/wheels" -type f -name 'wxpython-*.whl' -exec cp -u {} "${WHEEL_CACHE_DIR}/" \; - name: Upgrade build tooling run: uv pip install -U pip setuptools wheel + - name: Preinstall wxPython from wheelhouse + run: | + if ls "${WHEEL_CACHE_DIR}"/wxpython-*.whl >/dev/null 2>&1; then + uv pip install --no-index --find-links "${WHEEL_CACHE_DIR}" wxpython==4.2.5 + else + echo "No wxPython wheel found in wheelhouse" + fi + - name: Install dependencies from wheelhouse (fallback on build) run: | if uv sync --extra dev --find-links "${WHEEL_CACHE_DIR}" --no-build; then @@ -201,7 +236,7 @@ jobs: fi - name: Run tests and update README (--update) - run: xvfb-run -a ./scripts/runtest.sh --update + run: xvfb-run -a uv run ./scripts/runtest.py --update - name: Commit and push updated README run: | @@ -221,7 +256,8 @@ jobs: run: echo "Build scripts are not ready yet." release: - if: github.event_name == 'push' && github.ref == 'refs/heads/main' + # Temporarily disabled: release flow is not ready yet. + if: false runs-on: ubuntu-latest steps: @@ -267,4 +303,4 @@ jobs: echo "Release $tag already exists" else gh release create "$tag" --generate-notes --title "$tag" - fi + fi \ No newline at end of file diff --git a/CODE_STYLE.md b/CODE_STYLE.md index 5189a1f..b6190a5 100644 --- a/CODE_STYLE.md +++ b/CODE_STYLE.md @@ -1,14 +1,65 @@ -# Code Style Guidelines (v1.4) +# Code Style Guidelines (v1.5) These rules define the expected coding style for this project. -They apply to all contributors, including humans, AI-assisted tools, and automated systems. -They are mandatory unless explicitly stated otherwise. + +They apply to all contributors: + +- human developers +- AI-assisted tools +- coding agents +- automated systems + +These rules are **mandatory** unless explicitly stated otherwise. + +If a requested change conflicts with these rules, the change must **stop** and clarification must be requested. + +--- + +## Core Rules (Quick Reference) + +The following rules are the most critical and must always be respected: + +1. All code, comments, documentation, commit messages, and user-facing text MUST be written in English. +2. Python typing rules MUST be respected (PEP 585 generics; `Optional[T]`, not `T | None`). +3. Import ordering and grouping rules MUST be followed exactly. +4. Functions and methods MUST NOT exceed 50 lines. +5. Code changes MUST avoid modifying unrelated code. +6. Naming MUST remain explicit and descriptive (no aggressive abbreviations). +7. Code MUST remain mypy-friendly whenever possible. + +When generating or modifying code, tools and agents MUST consult this file before producing changes. + +--- + +## Mandatory Rules + +The following rules are strict and MUST NOT be violated: + +- English must always be used for code and documentation. +- `typing.Optional[T]` MUST be used instead of `T | None`. +- `from __future__ import annotations` MUST NOT be used. +- Import ordering rules MUST be respected exactly. +- Functions MUST NOT exceed the maximum size limit. + +--- + +## Usage by AI Tools + +AI-assisted tools and coding agents MUST read this file before generating or modifying code. + +If a requested change conflicts with these rules, the tool MUST: + +1. stop the modification +2. explain the conflict +3. request clarification + +Agents MUST prioritize deterministic rules over stylistic interpretation. --- ## Design Principles -#### These principles explain why the rules exist. They protect consistency over time. +These principles explain why the rules exist. They protect consistency over time. - Determinism over preference A rule must always produce the same result. Subjective rules lead to debates and inconsistency. @@ -476,6 +527,8 @@ def get_dialect() -> str: return connection.engine.value.dialect ``` +If exact ordering cannot be determined automatically, prefer consistency with the surrounding file. + --- ## 7. Variable Definition Order @@ -586,8 +639,8 @@ class Example: ## 10. Walrus Operator ( := ) -- Always try to use the walrus operator when it improves clarity and avoids redundant calls. -- Do NOT use it if it reduces readability. +- The walrus operator MAY be used when it improves clarity and avoids redundant calls. +- It MUST NOT be used when it makes the control flow harder to read. #### Good examples diff --git a/PROJECT_STATUS.md b/PROJECT_STATUS.md index c2efc22..7c0e50c 100644 --- a/PROJECT_STATUS.md +++ b/PROJECT_STATUS.md @@ -1,6 +1,6 @@ # PeterSQL — Project Status -> **Last Updated:** 2026-03-07 +> **Last Updated:** 2026-03-10 > **Validation Policy:** new engine features are marked **PARTIAL** until broader integration validation is complete. --- @@ -21,10 +21,14 @@ | Area | Current State | |------|---------------| -| **PostgreSQL Function** | Class + CRUD methods exist, context introspection exists, still considered under validation. | -| **PostgreSQL Procedure** | Class + CRUD methods exist, context introspection exists, still considered under validation. | +| **MySQL Procedure** | Class + CRUD methods exist, context introspection exists, integration tests added, broader validation still ongoing. | +| **MariaDB Procedure** | Class + CRUD methods exist, context introspection exists, integration tests added, broader validation still ongoing. | +| **PostgreSQL Function** | Class + CRUD methods exist, context introspection exists, integration tests now cover create/alter/drop across supported PG versions; broader validation still ongoing. | +| **PostgreSQL Procedure** | Class + CRUD methods exist, context introspection exists, integration tests now cover create/alter/drop across supported PG versions; broader validation still ongoing. | | **Check Constraints (MySQL/MariaDB/PostgreSQL)** | Engine classes and introspection exist, cross-version validation still needed. | | **Connection Reliability Features** | Persistent connection statistics, empty DB password support, and TLS auto-retry are implemented and need longer real-world validation. | +| **SQL Dump / Backup** | `SQLDatabase.dump()` produces object-driven `.sql` dumps (schema + records); restore/import workflow is still missing. | +| **Database Lifecycle (Create/Drop)** | Engine database objects expose lifecycle methods, but context/UI workflow parity is still incomplete. | ### ❌ Missing / Not Implemented @@ -34,7 +38,6 @@ | **Database Create/Drop UI** | No complete create/drop workflow across engines. | | **Schema/Sequence Management** | PostgreSQL schema/sequence CRUD is not available. | | **User/Role/Grants** | Not implemented for any engine. | -| **Import/Export** | Dump/restore and structured data import/export not implemented. | --- @@ -69,8 +72,8 @@ | Table / Column / Index / FK / Record | ✅ | ✅ | ✅ | ✅ | Stable core workflow. | | View / Trigger / Function | ✅ | ✅ | ✅ | ✅ | Implemented in engine layer. | | Check Constraint | 🟡 | 🟡 | 🟡 | 🟡 | Implemented (`MySQLCheck` + `get_checks()`), validation ongoing. | -| Procedure | ❌ | ❌ | ❌ | ❌ | `build_empty_procedure` still not implemented. | -| Database Create/Drop | ❌ | ✅ | ❌ | ❌ | Read-only listing in context. | +| Procedure | 🟡 | 🟡 | 🟡 | 🟡 | Implemented (`MySQLProcedure` + `get_procedures()`), broader validation ongoing. | +| Database Create/Drop | 🟡 | ✅ | 🟡 | 🟡 | Engine object lifecycle methods exist; context/UI wiring still partial. | --- @@ -81,8 +84,8 @@ | Table / Column / Index / FK / Record | ✅ | ✅ | ✅ | ✅ | Stable core workflow. | | View / Trigger / Function | ✅ | ✅ | ✅ | ✅ | Implemented in engine layer. | | Check Constraint | 🟡 | 🟡 | 🟡 | 🟡 | Implemented (`MariaDBCheck` + `get_checks()`), validation ongoing. | -| Procedure | ❌ | ❌ | ❌ | ❌ | `build_empty_procedure` still not implemented. | -| Database Create/Drop | ❌ | ✅ | ❌ | ❌ | Read-only listing in context. | +| Procedure | 🟡 | 🟡 | 🟡 | 🟡 | Implemented (`MariaDBProcedure` + `get_procedures()`), broader validation ongoing. | +| Database Create/Drop | 🟡 | ✅ | 🟡 | 🟡 | Engine object lifecycle methods exist; context/UI wiring still partial. | --- @@ -95,6 +98,7 @@ | Function | 🟡 | 🟡 | 🟡 | 🟡 | `PostgreSQLFunction` implemented, still under validation. | | Procedure | 🟡 | 🟡 | 🟡 | 🟡 | `PostgreSQLProcedure` implemented, still under validation. | | Check Constraint | 🟡 | 🟡 | 🟡 | 🟡 | Implemented (`PostgreSQLCheck` + `get_checks()`), validation ongoing. | +| Database Create/Drop | 🟡 | ✅ | 🟡 | 🟡 | Engine object lifecycle methods exist; context/UI wiring still partial. | | Schema / Sequence | ❌ | 🟡 | ❌ | ❌ | Basic schema visibility exists; no CRUD layer yet. | --- @@ -123,12 +127,16 @@ - Persistent connection statistics in connection model and dialog. - Empty database password accepted in connection validation. - Automatic TLS retry path for MySQL/MariaDB when server requires TLS. +- Unit reliability coverage for MySQL/MariaDB TLS auto-retry and SSH tunnel lifecycle contracts. +- SQL dump/backup pipeline is now object-driven via `SQLDatabase.dump()` + per-object `raw_create()`. - CI workflow split into `test`, `update` (nightly), and `release` jobs. ### Main Remaining Risks -- Newly implemented PostgreSQL Function/Procedure paths need broader integration validation. +- PostgreSQL Function/Procedure now have integration coverage for create/alter/drop, but still need broader long-run/manual validation. - Check constraints across MySQL/MariaDB/PostgreSQL need more cross-version coverage. +- SQL dump/backup still needs broader cross-engine manual restore validation. +- SSH tunnel integration validation with testcontainers remains blocked (existing SSH integration suites are still skipped). - UI parity lags engine parity for Trigger/Function/Procedure editors. --- @@ -137,16 +145,13 @@ ### Priority A — Validate Newly Implemented Features -1. PostgreSQL Function integration validation (all supported PG variants). -2. PostgreSQL Procedure integration validation (all supported PG variants). -3. Check constraints validation matrix for MySQL, MariaDB, PostgreSQL. -4. Connection statistics + TLS auto-retry robustness checks. +1. PostgreSQL Function/Procedure long-run validation (manual workflows + regression suites after integration coverage). +2. Check constraints validation matrix for MySQL, MariaDB, PostgreSQL. +3. Connection statistics + TLS auto-retry robustness checks. ### Priority B — Close Engine Gaps -1. MySQL Procedure implementation. -2. MariaDB Procedure implementation. -3. Database create/drop methods in engine contexts. +1. Complete context/UI wiring for database lifecycle (create/drop) across engines. ### Priority C — UI Completeness @@ -159,7 +164,7 @@ 1. PostgreSQL schema CRUD. 2. PostgreSQL sequence CRUD. 3. User/role/grants management. -4. Import/export workflows. +4. Restore and structured import/export workflows. --- diff --git a/PeterSQL.fbp b/PeterSQL.fbp index 594082d..ec7b972 100755 --- a/PeterSQL.fbp +++ b/PeterSQL.fbp @@ -31,7 +31,7 @@ 1 0 0 - + 0 wxAUI_MGR_DEFAULT @@ -60,16 +60,16 @@ on_close - + bSizer34 wxVERTICAL none - + 5 wxEXPAND 1 - + 1 1 1 @@ -127,8 +127,8 @@ - - + + 1 1 1 @@ -180,7 +180,7 @@ wxTAB_TRAVERSAL - + bSizer35 wxVERTICAL @@ -385,8 +385,8 @@ - - + + 1 1 1 @@ -438,16 +438,16 @@ wxTAB_TRAVERSAL - + bSizer36 wxVERTICAL none - + 5 wxALL|wxEXPAND 1 - + 1 1 1 @@ -3325,11 +3325,11 @@ - + Statistics 0 - + 1 1 1 @@ -3381,16 +3381,16 @@ wxTAB_TRAVERSAL - + bSizer361 wxVERTICAL none - + 5 wxEXPAND 0 - + bSizer37 wxHORIZONTAL @@ -3521,11 +3521,11 @@ - + 5 wxEXPAND 0 - + bSizer371 wxHORIZONTAL @@ -3656,11 +3656,11 @@ - + 5 wxEXPAND 0 - + bSizer3711 wxHORIZONTAL @@ -3791,20 +3791,20 @@ - + 5 wxEXPAND 0 - + bSizer371111 wxHORIZONTAL none - + 5 wxALL 0 - + 1 1 1 @@ -3862,11 +3862,11 @@ -1 - + 5 wxALL 1 - + 1 1 1 @@ -3926,11 +3926,11 @@ - + 5 wxEXPAND 0 - + bSizer37111 wxHORIZONTAL @@ -4061,20 +4061,20 @@ - + 5 wxEXPAND 0 - + bSizer371112 wxHORIZONTAL none - + 5 wxALL 0 - + 1 1 1 @@ -4132,11 +4132,11 @@ -1 - + 5 wxALL 1 - + 1 1 1 @@ -4196,20 +4196,20 @@ - + 5 wxEXPAND 0 - + bSizer3711121 wxHORIZONTAL none - + 5 wxALL 0 - + 1 1 1 @@ -4267,11 +4267,11 @@ -1 - + 5 wxALL 1 - + 1 1 1 @@ -4331,20 +4331,20 @@ - + 5 wxEXPAND 0 - + bSizer37111211 wxHORIZONTAL none - + 5 wxALL 0 - + 1 1 1 @@ -4402,11 +4402,11 @@ -1 - + 5 wxALL 1 - + 1 1 1 @@ -4466,20 +4466,20 @@ - + 5 wxEXPAND 0 - + bSizer371112111 wxHORIZONTAL none - + 5 wxALL 0 - + 1 1 1 @@ -4537,11 +4537,11 @@ -1 - + 5 wxALL 1 - + 1 1 1 @@ -4670,16 +4670,16 @@ - + 0 wxEXPAND 0 - + bSizer28 wxHORIZONTAL none - + 5 wxEXPAND 1 @@ -4761,11 +4761,11 @@ on_create - + MenuCreate m_menu12 protected - + 0 1 @@ -4778,7 +4778,7 @@ - + 0 1 @@ -4957,11 +4957,11 @@ none - + 5 wxEXPAND 0 - + bSizer29 wxHORIZONTAL @@ -5271,7 +5271,7 @@ - + 0 wxAUI_MGR_DEFAULT @@ -5990,7 +5990,7 @@ - + 0 @@ -6020,7 +6020,7 @@ wxTAB_TRAVERSAL 1 do_close - + 1 @@ -6046,8 +6046,22 @@ File m_menu2 protected + + + 0 + 1 + + wxID_ANY + wxITEM_NORMAL + Settings + m_menuItem22 + none + + + on_settings + - + Help m_menu4 protected @@ -6188,16 +6202,16 @@ - + bSizer19 wxVERTICAL none - + 0 wxEXPAND | wxALL 1 - + 1 1 1 @@ -6249,16 +6263,16 @@ wxTAB_TRAVERSAL - + bSizer21 wxVERTICAL none - + 5 wxEXPAND 1 - + 1 1 1 @@ -6316,8 +6330,8 @@ - - + + 1 1 1 @@ -6369,16 +6383,16 @@ wxTAB_TRAVERSAL - + bSizer72 wxVERTICAL none - + 5 wxEXPAND 1 - + 1 1 1 @@ -6606,8 +6620,8 @@ - - + + 1 1 1 @@ -6659,16 +6673,16 @@ wxTAB_TRAVERSAL - + bSizer25 wxVERTICAL none - + 5 wxALL|wxEXPAND 1 - + 1 1 1 @@ -6932,11 +6946,11 @@ - + Load From File; icons/16x16/database.png Database 0 - + 1 1 1 @@ -6988,16 +7002,16 @@ wxTAB_TRAVERSAL - + bSizer27 wxVERTICAL none - + 5 wxEXPAND | wxALL 1 - + 1 1 1 @@ -7051,11 +7065,11 @@ - + - Tables + Options 0 - + 1 1 1 @@ -7107,25 +7121,75 @@ wxTAB_TRAVERSAL - + bSizer80 wxVERTICAL none - + 5 wxEXPAND - 0 - + 1 + + 1 + 1 + 1 + 1 + 0 + + 0 + 0 + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 0 + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + 0 + + 0 - bSizer531 - wxHORIZONTAL - none - - 5 - wxALIGN_CENTER_VERTICAL|wxALL - 0 - + 1 + m_splitter7 + 1 + + + protected + 1 + + Resizable + 0.0 + -1 + -1 + 1 + + wxSPLIT_HORIZONTAL + wxSP_3D + ; ; forward_declare + 0 + + + + + + 1 1 1 @@ -7154,16 +7218,14 @@ 0 0 wxID_ANY - Table: - 0 0 0 - -1,-1 + 1 - m_staticText391 + m_panel54 1 @@ -7173,106 +7235,3275 @@ Resizable 1 - ; ; forward_declare 0 - - -1 - - - - 5 - wxEXPAND - 0 - - 0 - protected - 100 - - - - 2 - wxALL|wxEXPAND - 0 - - 1 - 1 - 1 - 1 - 0 - - 0 - 0 - 0 - - - Load From File; icons/16x16/add.png - - 1 - 0 - 1 - - 1 - - 0 - 0 - - Dock - 0 - Left - 0 - 1 - - 1 - - - 0 - 0 - wxID_ANY - Insert - - 0 - - 0 - - - 0 - - 1 - btn_insert_table - 1 - - - protected - 1 - - - - Resizable - 1 - - wxBORDER_NONE - ; ; forward_declare - 0 - - - wxFILTER_NONE - wxDefaultValidator + wxTAB_TRAVERSAL + + + bSizer158 + wxVERTICAL + none + + 5 + wxEXPAND + 0 + + + bSizer159 + wxHORIZONTAL + none + + 5 + wxALIGN_CENTER|wxALL + 0 + + 1 + 1 + 1 + 1 + 0 + + 0 + 0 + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 0 + 1 + + 1 + + 0 + 0 + wxID_ANY + Name + 0 + + 0 + + + 0 + 150,-1 + 1 + m_staticText90 + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + + + -1 + + + + 5 + wxALL + 1 + + 1 + 1 + 1 + 1 + 0 + + 0 + 0 + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 0 + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + 0 + + 0 + + 1 + database_name + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + 5 + wxEXPAND + 1 + + + bSizer1481111 + wxHORIZONTAL + none + + + + 5 + wxEXPAND + 0 + + + bSizer142 + wxHORIZONTAL + none + + 5 + wxALIGN_CENTER + 1 + + 1 + 1 + 1 + 1 + 0 + + 0 + 0 + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 0 + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + database_character_set_panel + 1 + + + protected + 1 + + Resizable + 1 + + ; ; forward_declare + 0 + + + + wxTAB_TRAVERSAL + + + bSizer139 + wxHORIZONTAL + none + + 5 + wxALIGN_CENTER|wxALL + 0 + + 1 + 1 + 1 + 1 + 0 + + 0 + 0 + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 0 + 1 + + 1 + + 0 + 0 + wxID_ANY + Character set + 0 + + 0 + + + 0 + 150,-1 + 1 + m_staticText70 + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + + + -1 + + + + 5 + wxALL + 1 + + 1 + 1 + 1 + 1 + 0 + + 0 + 0 + + + + 1 + 0 + + 1 + + 1 + 0 + Dock + 0 + Left + 0 + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + database_character_set + 1 + + + protected + 1 + + Resizable + 0 + 1 + + + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + 5 + wxALIGN_CENTER + 1 + + 1 + 1 + 1 + 1 + 0 + + 0 + 0 + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 0 + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + database_collation_panel + 1 + + + protected + 1 + + Resizable + 1 + + ; ; forward_declare + 0 + + + + wxTAB_TRAVERSAL + + + bSizer1392 + wxHORIZONTAL + none + + 5 + wxALIGN_CENTER|wxALL + 0 + + 1 + 1 + 1 + 1 + 0 + + 0 + 0 + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 0 + 1 + + 1 + + 0 + 0 + wxID_ANY + Collation + 0 + + 0 + + + 0 + 150,-1 + 1 + m_staticText702 + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + + + -1 + + + + 5 + wxALL + 1 + + 1 + 1 + 1 + 1 + 0 + + 0 + 0 + + + + 1 + 0 + + 1 + + 1 + 0 + Dock + 0 + Left + 0 + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + database_collation + 1 + + + protected + 1 + + Resizable + 0 + 1 + + + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + 5 + wxEXPAND + 0 + + + bSizer13911 + wxHORIZONTAL + none + + 0 + wxALIGN_CENTER + 1 + + 1 + 1 + 1 + 1 + 0 + + 0 + 0 + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 0 + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + database_encryption_panel + 1 + + + protected + 1 + + Resizable + 1 + + ; ; forward_declare + 0 + + + + wxTAB_TRAVERSAL + + + bSizer1391 + wxHORIZONTAL + none + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + 0 + + 0 + 0 + + + + 1 + 0 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 0 + 1 + + 1 + + 0 + 0 + wxID_ANY + Encryption + + 0 + + + 0 + + 1 + database_encryption + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + 5 + wxEXPAND | wxALL + 1 + + 1 + 1 + 1 + 1 + 0 + + 0 + 0 + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 0 + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + database_read_only_panel + 1 + + + protected + 1 + + Resizable + 1 + + ; ; forward_declare + 0 + + + + wxTAB_TRAVERSAL + + + bSizer148 + wxHORIZONTAL + none + + 5 + wxALIGN_CENTER|wxALL + 0 + + 1 + 1 + 1 + 1 + 0 + + 0 + 0 + + + + 1 + 0 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 0 + 1 + + 1 + + 0 + 0 + wxID_ANY + Read Only + + 0 + + + 0 + + 1 + database_read_only + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + 5 + wxEXPAND + 0 + + + bSizer92 + wxHORIZONTAL + none + + 5 + wxALIGN_CENTER + 1 + + 1 + 1 + 1 + 1 + 0 + + 0 + 0 + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 0 + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + database_tablespace_panel + 1 + + + protected + 1 + + Resizable + 1 + + ; ; forward_declare + 0 + + + + wxTAB_TRAVERSAL + + + bSizer13912 + wxHORIZONTAL + none + + 5 + wxALIGN_CENTER|wxALL + 0 + + 1 + 1 + 1 + 1 + 0 + + 0 + 0 + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 0 + 1 + + 1 + + 0 + 0 + wxID_ANY + Tablespace + 0 + + 0 + + + 0 + 150,-1 + 1 + m_staticText7012 + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + + + -1 + + + + 5 + wxALL + 1 + + 1 + 1 + 1 + 1 + 0 + + 0 + 0 + + + + 1 + 0 + + 1 + + 1 + 0 + Dock + 0 + Left + 0 + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + database_tablespace + 1 + + + protected + 1 + + Resizable + 0 + 1 + + + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + 5 + wxALIGN_CENTER + 1 + + 1 + 1 + 1 + 1 + 0 + + 0 + 0 + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 0 + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + database_connection_limit_panel + 1 + + + protected + 1 + + Resizable + 1 + + ; ; forward_declare + 0 + + + + wxTAB_TRAVERSAL + + + bSizer139111 + wxHORIZONTAL + none + + 5 + wxALIGN_CENTER|wxALL + 0 + + 1 + 1 + 1 + 1 + 0 + + 0 + 0 + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 0 + 1 + + 1 + + 0 + 0 + wxID_ANY + Connection limit + 0 + + 0 + + + 0 + 150,-1 + 1 + m_staticText70111 + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + + + -1 + + + + 5 + wxALL + 1 + + 1 + 1 + 1 + 1 + 0 + + 0 + 0 + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 0 + 1 + + 1 + + 0 + 0 + wxID_ANY + 0 + 0 + + 0 + + 0 + + 0 + + 1 + database_connection_limit + 1 + + + protected + 1 + + Resizable + 1 + + wxSP_ARROW_KEYS + ; ; forward_declare + 0 + + + + + + + + + + + + + + 5 + wxEXPAND + 0 + + + bSizer1481 + wxHORIZONTAL + none + + 5 + wxALIGN_CENTER + 1 + + 1 + 1 + 1 + 1 + 0 + + 0 + 0 + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 0 + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + database_password_panel + 1 + + + protected + 1 + + Resizable + 1 + + ; ; forward_declare + 0 + + + + wxTAB_TRAVERSAL + + + bSizer139121 + wxHORIZONTAL + none + + 5 + wxALIGN_CENTER|wxALL + 0 + + 1 + 1 + 1 + 1 + 0 + + 0 + 0 + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 0 + 1 + + 1 + + 0 + 0 + wxID_ANY + Password + 0 + + 0 + + + 0 + 150,-1 + 1 + m_staticText70121 + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + + + -1 + + + + 5 + wxALL + 1 + + 1 + 1 + 1 + 1 + 0 + + 0 + 0 + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 0 + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + 0 + + 0 + + 1 + m_textCtrl36 + 1 + + + protected + 1 + + Resizable + 1 + + wxTE_PASSWORD + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + 5 + wxALIGN_CENTER + 1 + + 1 + 1 + 1 + 1 + 0 + + 0 + 0 + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 0 + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + database_profile_panel + 1 + + + protected + 1 + + Resizable + 1 + + ; ; forward_declare + 0 + + + + wxTAB_TRAVERSAL + + + bSizer1391111 + wxHORIZONTAL + none + + 5 + wxALIGN_CENTER|wxALL + 0 + + 1 + 1 + 1 + 1 + 0 + + 0 + 0 + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 0 + 1 + + 1 + + 0 + 0 + wxID_ANY + Profile + 0 + + 0 + + + 0 + 150,-1 + 1 + m_staticText701111 + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + + + -1 + + + + 5 + wxALL + 1 + + 1 + 1 + 1 + 1 + 0 + + 0 + 0 + + + + 1 + 0 + + 1 + + 1 + 0 + Dock + 0 + Left + 0 + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + database_profile + 1 + + + protected + 1 + + Resizable + 0 + 1 + + + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + 5 + wxEXPAND + 0 + + + bSizer96 + wxHORIZONTAL + none + + 5 + wxALIGN_CENTER + 1 + + 1 + 1 + 1 + 1 + 0 + + 0 + 0 + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 0 + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + database_default_tablespace_panel + 1 + + + protected + 1 + + Resizable + 1 + + ; ; forward_declare + 0 + + + + wxTAB_TRAVERSAL + + + bSizer1391212 + wxHORIZONTAL + none + + 5 + wxALIGN_CENTER|wxALL + 0 + + 1 + 1 + 1 + 1 + 0 + + 0 + 0 + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 0 + 1 + + 1 + + 0 + 0 + wxID_ANY + Default tablespace + 0 + + 0 + + + 0 + 150,-1 + 1 + m_staticText701212 + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + + + -1 + + + + 5 + wxALL + 1 + + 1 + 1 + 1 + 1 + 0 + + 0 + 0 + + + + 1 + 0 + + 1 + + 1 + 0 + Dock + 0 + Left + 0 + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + database_default_tablespace + 1 + + + protected + 1 + + Resizable + 0 + 1 + + + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + 5 + wxALIGN_CENTER + 1 + + 1 + 1 + 1 + 1 + 0 + + 0 + 0 + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 0 + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + database_temporary_tablespace_panel + 1 + + + protected + 1 + + Resizable + 1 + + ; ; forward_declare + 0 + + + + wxTAB_TRAVERSAL + + + bSizer13912121 + wxHORIZONTAL + none + + 5 + wxALIGN_CENTER|wxALL + 0 + + 1 + 1 + 1 + 1 + 0 + + 0 + 0 + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 0 + 1 + + 1 + + 0 + 0 + wxID_ANY + Temporary tablespace + 0 + + 0 + + + 0 + 150,-1 + 1 + m_staticText7012121 + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + + + -1 + + + + 5 + wxALL + 1 + + 1 + 1 + 1 + 1 + 0 + + 0 + 0 + + + + 1 + 0 + + 1 + + 1 + 0 + Dock + 0 + Left + 0 + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + database_temporary_tablespace + 1 + + + protected + 1 + + Resizable + 0 + 1 + + + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + 5 + wxEXPAND + 0 + + + bSizer14811 + wxHORIZONTAL + none + + 5 + wxALIGN_CENTER + 1 + + 1 + 1 + 1 + 1 + 0 + + 0 + 0 + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 0 + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + database_quota_panel + 1 + + + protected + 1 + + Resizable + 1 + + ; ; forward_declare + 0 + + + + wxTAB_TRAVERSAL + + + bSizer1391211 + wxHORIZONTAL + none + + 5 + wxALIGN_CENTER|wxALL + 0 + + 1 + 1 + 1 + 1 + 0 + + 0 + 0 + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 0 + 1 + + 1 + + 0 + 0 + wxID_ANY + Quota + 0 + + 0 + + + 0 + 150,-1 + 1 + m_staticText701211 + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + + + -1 + + + + 5 + wxALL + 1 + + 1 + 1 + 1 + 1 + 0 + + 0 + 0 + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 0 + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + 0 + + 0 + + 1 + database_quota + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + 5 + wxALIGN_CENTER + 1 + + 1 + 1 + 1 + 1 + 0 + + 0 + 0 + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 0 + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + database_unlimited_quota_panel + 1 + + + protected + 1 + + Resizable + 1 + + ; ; forward_declare + 0 + + + + wxTAB_TRAVERSAL + + + bSizer13911111 + wxHORIZONTAL + none + + 5 + wxALIGN_CENTER|wxALL + 0 + + 1 + 1 + 1 + 1 + 0 + + 0 + 0 + + + + 1 + 0 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 0 + 1 + + 1 + + 0 + 0 + wxID_ANY + Unlimited quota + + 0 + + + 0 + + 1 + database_unlimited_quota + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + 5 + wxEXPAND + 0 + + + bSizer148111 + wxHORIZONTAL + none + + 5 + wxALIGN_CENTER + 1 + + 1 + 1 + 1 + 1 + 0 + + 0 + 0 + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 0 + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + database_account_status_panel + 1 + + + protected + 1 + + Resizable + 1 + + ; ; forward_declare + 0 + + + + wxTAB_TRAVERSAL + + + bSizer13912111 + wxHORIZONTAL + none + + 5 + wxALIGN_CENTER|wxALL + 0 + + 1 + 1 + 1 + 1 + 0 + + 0 + 0 + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 0 + 1 + + 1 + + 0 + 0 + wxID_ANY + Account status + 0 + + 0 + + + 0 + 150,-1 + 1 + m_staticText7012111 + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + + + -1 + + + + 5 + wxALL + 1 + + 1 + 1 + 1 + 1 + 0 + + 0 + 0 + + + + 1 + 0 + + 1 + + 1 + 0 + Dock + 0 + Left + 0 + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + database_account_status + 1 + + + protected + 1 + + Resizable + 0 + 1 + + + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + 5 + wxALIGN_CENTER + 1 + + 1 + 1 + 1 + 1 + 0 + + 0 + 0 + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 0 + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + database_password_expire_panel + 1 + + + protected + 1 + + Resizable + 1 + + ; ; forward_declare + 0 + + + + wxTAB_TRAVERSAL + + + bSizer139111111 + wxHORIZONTAL + none + + 5 + wxALIGN_CENTER|wxALL + 0 + + 1 + 1 + 1 + 1 + 0 + + 0 + 0 + + + + 1 + 0 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 0 + 1 + + 1 + + 0 + 0 + wxID_ANY + Password expire + + 0 + + + 0 + + 1 + database_password_expire + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + 1 + 1 + 1 + 1 + 0 + + 0 + 0 + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 0 + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + m_panel55 + 1 + + + protected + 1 + + Resizable + 1 + + ; ; forward_declare + 0 + + + + wxTAB_TRAVERSAL + + + bSizer154 + wxVERTICAL + none + + 5 + wxEXPAND + 0 + + + bSizer531 + wxHORIZONTAL + none + + 5 + wxALIGN_CENTER_VERTICAL|wxALL + 0 + + 1 + 1 + 1 + 1 + 0 + + 0 + 0 + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 0 + 1 + + 1 + + 0 + 0 + wxID_ANY + Table: + 0 + + 0 + + + 0 + -1,-1 + 1 + m_staticText391 + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + + + -1 + + + + 5 + wxEXPAND + 0 + + 0 + protected + 100 + + + + 2 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + 0 + + 0 + 0 + 0 + + + Load From File; icons/16x16/add.png + + 1 + 0 + 1 + + 1 + + 0 + 0 + + Dock + 0 + Left + 0 + 1 + + 1 + + + 0 + 0 + wxID_ANY + Insert + + 0 + + 0 + + + 0 + + 1 + btn_insert_table + 1 + + + protected + 1 + + + + Resizable + 1 + + wxBORDER_NONE + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + on_insert_table + + + + 5 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + 0 + + 0 + 0 + 0 + + + Load From File; icons/16x16/table_multiple.png + + 1 + 0 + 1 + + 1 + + 0 + 0 + + Dock + 0 + Left + 0 + 0 + + 1 + + + 0 + 0 + wxID_ANY + Clone + + 0 + + 0 + + + 0 + + 1 + btn_clone_table + 1 + + + protected + 1 + + + + Resizable + 1 + + wxBORDER_NONE + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + on_clone_table + + + + 2 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + 0 + + 0 + 0 + 0 + + + Load From File; icons/16x16/delete.png + + 1 + 0 + 1 + + 1 + + 0 + 0 + + Dock + 0 + Left + 0 + 0 + + 1 + + + 0 + 0 + wxID_ANY + Delete + + 0 + + 0 + + + 0 + + 1 + btn_delete_table1 + 1 + + + protected + 1 + + + + Resizable + 1 + + wxBORDER_NONE + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + on_delete_table + + + + 5 + wxEXPAND + 1 + + 0 + protected + 0 + + + + + + 5 + wxEXPAND + 1 + + + bSizer152 + wxVERTICAL + none + + 5 + wxALL|wxEXPAND + 1 + + + + 1 + 0 + 1 + + + 0 + wxID_ANY + + + list_ctrl_database_tables + protected + + + + ; ; forward_declare + + + + + + wxALIGN_LEFT + + wxDATAVIEW_COL_RESIZABLE|wxDATAVIEW_COL_SORTABLE + Name + wxDATAVIEW_CELL_INERT + 0 + m_dataViewColumn12 + protected + Text + -1 + + + wxALIGN_RIGHT + + wxDATAVIEW_COL_RESIZABLE|wxDATAVIEW_COL_SORTABLE + Rows + wxDATAVIEW_CELL_INERT + 1 + m_dataViewColumn13 + protected + Text + -1 + + + wxALIGN_RIGHT + + wxDATAVIEW_COL_RESIZABLE|wxDATAVIEW_COL_SORTABLE + Size + wxDATAVIEW_CELL_INERT + 2 + m_dataViewColumn14 + protected + Text + -1 + + + wxALIGN_LEFT + + wxDATAVIEW_COL_RESIZABLE|wxDATAVIEW_COL_SORTABLE + Created at + wxDATAVIEW_CELL_INERT + 3 + m_dataViewColumn15 + protected + Date + -1 + + + wxALIGN_LEFT + + wxDATAVIEW_COL_RESIZABLE|wxDATAVIEW_COL_SORTABLE + Updated at + wxDATAVIEW_CELL_INERT + 4 + m_dataViewColumn16 + protected + Date + -1 + + + wxALIGN_LEFT + + wxDATAVIEW_COL_RESIZABLE|wxDATAVIEW_COL_SORTABLE + Engine + wxDATAVIEW_CELL_INERT + 5 + m_dataViewColumn17 + protected + Text + -1 + + + wxALIGN_LEFT + + wxDATAVIEW_COL_RESIZABLE|wxDATAVIEW_COL_SORTABLE + Collation + wxDATAVIEW_CELL_INERT + 6 + m_dataViewColumn19 + protected + Text + -1 + + + wxALIGN_LEFT + + wxDATAVIEW_COL_RESIZABLE|wxDATAVIEW_COL_SORTABLE + Comments + wxDATAVIEW_CELL_INERT + 7 + m_dataViewColumn18 + protected + Text + -1 + + + + + + + + + + + + 5 + wxEXPAND + 0 + + + bSizer138 + wxHORIZONTAL + none + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + 0 + + 0 + 0 + 0 + + + + + 1 + 0 + 1 + + 1 + + 0 + 0 + + Dock + 0 + Left + 0 + 1 + + 1 + + + 0 + 0 + wxID_ANY + Cancel + + 0 + + 0 + + + 0 + + 1 + btn_cancel_database + 1 + + + protected + 1 + + + + Resizable + 1 + + + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator - on_insert_table + on_cancel_database - + 5 - wxALL|wxEXPAND + wxALL 0 - + 1 1 1 @@ -7284,7 +10515,7 @@ 0 - Load From File; icons/16x16/table_multiple.png + 1 0 @@ -7299,7 +10530,7 @@ 0 Left 0 - 0 + 1 1 @@ -7307,7 +10538,7 @@ 0 0 wxID_ANY - Clone + Delete 0 @@ -7317,7 +10548,7 @@ 0 1 - btn_clone_table + btn_delete_database 1 @@ -7329,7 +10560,7 @@ Resizable 1 - wxBORDER_NONE + ; ; forward_declare 0 @@ -7340,14 +10571,14 @@ - on_clone_table + on_delete_database - - 2 - wxALL|wxEXPAND + + 5 + wxALL 0 - + 1 1 1 @@ -7359,7 +10590,7 @@ 0 - Load From File; icons/16x16/delete.png + 1 0 @@ -7374,7 +10605,7 @@ 0 Left 0 - 0 + 1 1 @@ -7382,7 +10613,7 @@ 0 0 wxID_ANY - Delete + Apply 0 @@ -7392,7 +10623,7 @@ 0 1 - btn_delete_table + btn_apply_database 1 @@ -7404,7 +10635,7 @@ Resizable 1 - wxBORDER_NONE + ; ; forward_declare 0 @@ -7415,212 +10646,264 @@ - on_delete_table - - - - 5 - wxEXPAND - 1 - - 0 - protected - 0 + on_apply_database - + + + + + + Diagram + 0 + + 1 + 1 + 1 + 1 + 0 + + 0 + 0 + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 0 + 1 + + 1 + + 0 + 1 + wxID_ANY + + 0 + + + 0 + + 1 + m_panel31 + 1 + + + protected + 1 + + Resizable + 1 + + ; ; forward_declare + 0 + + + + wxTAB_TRAVERSAL + + + bSizer82 + wxVERTICAL + none + 5 - wxALL|wxEXPAND - 1 - + wxALL + 0 + + 1 + 1 + 1 + 1 + 0 + + 0 + 0 + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 0 + 1 + + 1 + + 0 + 0 + wxID_ANY + MyLabel + 0 + + 0 + + + 0 + 150,-1 + 1 + m_staticText7011 + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + + + -1 + + + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + 0 + + 0 + 0 + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 0 + 1 + + 1 + + 0 + 0 + wxID_ANY + MyLabel + 0 + + 0 + + + 0 + 150,-1 + 1 + m_staticText7011111 + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + + + -1 + + + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + 0 + + 0 + 0 + + + 1 + 0 + 1 1 + 0 + Dock + 0 + Left 0 1 + 1 + 0 0 wxID_ANY + MyLabel + 0 + + 0 - - list_ctrl_database_tables + + 0 + 150,-1 + 1 + m_staticText70111111 + 1 + + protected + 1 + Resizable + 1 ; ; forward_declare + 0 - - wxALIGN_LEFT - - wxDATAVIEW_COL_RESIZABLE|wxDATAVIEW_COL_SORTABLE - Name - wxDATAVIEW_CELL_INERT - 0 - m_dataViewColumn12 - protected - Text - -1 - - - wxALIGN_RIGHT - - wxDATAVIEW_COL_RESIZABLE|wxDATAVIEW_COL_SORTABLE - Rows - wxDATAVIEW_CELL_INERT - 1 - m_dataViewColumn13 - protected - Text - -1 - - - wxALIGN_RIGHT - - wxDATAVIEW_COL_RESIZABLE|wxDATAVIEW_COL_SORTABLE - Size - wxDATAVIEW_CELL_INERT - 2 - m_dataViewColumn14 - protected - Text - -1 - - - wxALIGN_LEFT - - wxDATAVIEW_COL_RESIZABLE|wxDATAVIEW_COL_SORTABLE - Created at - wxDATAVIEW_CELL_INERT - 3 - m_dataViewColumn15 - protected - Date - -1 - - - wxALIGN_LEFT - - wxDATAVIEW_COL_RESIZABLE|wxDATAVIEW_COL_SORTABLE - Updated at - wxDATAVIEW_CELL_INERT - 4 - m_dataViewColumn16 - protected - Date - -1 - - - wxALIGN_LEFT - - wxDATAVIEW_COL_RESIZABLE|wxDATAVIEW_COL_SORTABLE - Engine - wxDATAVIEW_CELL_INERT - 5 - m_dataViewColumn17 - protected - Text - -1 - - - wxALIGN_LEFT - - wxDATAVIEW_COL_RESIZABLE|wxDATAVIEW_COL_SORTABLE - Collation - wxDATAVIEW_CELL_INERT - 6 - m_dataViewColumn19 - protected - Text - -1 - - - wxALIGN_LEFT - - wxDATAVIEW_COL_RESIZABLE|wxDATAVIEW_COL_SORTABLE - Comments - wxDATAVIEW_CELL_INERT - 7 - m_dataViewColumn18 - protected - Text - -1 - + -1 - - - Diagram - 0 - - 1 - 1 - 1 - 1 - 0 - - 0 - 0 - - - - 1 - 0 - 1 - - 1 - 0 - Dock - 0 - Left - 0 - 1 - - 1 - - 0 - 0 - wxID_ANY - - 0 - - - 0 - - 1 - m_panel31 - 1 - - - protected - 1 - - Resizable - 1 - - ; ; forward_declare - 0 - - - - wxTAB_TRAVERSAL - - - bSizer82 - wxVERTICAL - none - - - @@ -7634,7 +10917,7 @@ Load From File; icons/16x16/table.png Table - 0 + 1 1 1 @@ -12750,7 +16033,7 @@ Load From File; icons/16x16/text_columns.png Data - 1 + 0 1 1 @@ -14505,24 +17788,6 @@ - - MyMenu - m_menu3 - protected - - - 0 - 1 - - wxID_ANY - wxITEM_NORMAL - MyMenuItem - m_menuItem3 - none - - - - @@ -14793,11 +18058,11 @@ bSizer93 wxVERTICAL none - + 5 wxEXPAND | wxALL 1 - + 1 1 1 @@ -14867,11 +18132,11 @@ bSizer129 wxVERTICAL none - + 5 wxALL|wxEXPAND 1 - + 1 1 1 @@ -14932,11 +18197,11 @@ - + 5 wxALL|wxEXPAND 1 - + 1 1 1 @@ -14995,7 +18260,7 @@ - + MyMenu m_menu13 protected @@ -15016,11 +18281,11 @@ - + 5 wxALL|wxEXPAND 1 - + 1 1 1 @@ -15081,11 +18346,11 @@ - + 5 wxALIGN_CENTER|wxALL 0 - + 1 1 1 @@ -15171,11 +18436,11 @@ - + 5 wxALL 0 - + 1 1 1 @@ -15368,7 +18633,7 @@ - + MyMenu m_menu15 protected @@ -15440,13 +18705,78 @@ + + 5 + wxALL + 1 + + 1 + 1 + 1 + 1 + 0 + + 0 + 0 + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 0 + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + 0 + + 0 + + 1 + m_textCtrl361 + 1 + + + protected + 1 + + Resizable + 1 + + wxTE_PASSWORD + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + - + 5 wxEXPAND | wxALL 1 - + 1 1 1 @@ -15503,11 +18833,11 @@ - + 5 wxALIGN_CENTER|wxALL 1 - + 1 1 1 @@ -15568,13 +18898,78 @@ + + 5 + wxALL + 1 + + 1 + 1 + 1 + 1 + 0 + + 0 + 0 + + + + 1 + 0 + + 1 + + 1 + 0 + Dock + 0 + Left + 0 + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + database_encryption_old + 1 + + + protected + 1 + + Resizable + 0 + 1 + + + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + - + 5 wxEXPAND | wxALL 1 - + 1 1 1 @@ -15633,19 +19028,13 @@ - - - bSizer92 - wxVERTICAL - none - - + 5 wxALL|wxEXPAND 1 - + 1 1 1 @@ -15769,7 +19158,7 @@ 5 wxEXPAND | wxALL 1 - + 1 1 1 @@ -15975,11 +19364,11 @@ bSizer51 wxVERTICAL none - + 0 wxEXPAND | wxALL 0 - + 1 1 1 @@ -16031,7 +19420,7 @@ wxTAB_TRAVERSAL - + bSizer48 wxVERTICAL @@ -16097,13 +19486,31 @@ + + MyMenu + m_menu3 + protected + + + 0 + 1 + + wxID_ANY + wxITEM_NORMAL + MyMenuItem + m_menuItem3 + none + + + + - + 0 wxEXPAND | wxALL 0 - + 1 1 1 @@ -16155,16 +19562,16 @@ wxTAB_TRAVERSAL - + bSizer52 wxVERTICAL none - + 0 wxEXPAND 0 - + bSizer1212 wxHORIZONTAL @@ -16366,70 +19773,6 @@ - - 5 - wxEXPAND | wxALL - 1 - - 1 - 1 - 1 - 1 - 0 - - 0 - 0 - - - - 1 - 0 - 1 - - 1 - 0 - Dock - 0 - Left - 0 - 1 - - 1 - - 0 - 0 - wxID_ANY - - 0 - - - 0 - - 1 - m_panel35 - 1 - - - protected - 1 - - Resizable - 1 - - ; ; forward_declare - 0 - - - - wxTAB_TRAVERSAL - - - bSizer96 - wxVERTICAL - none - - - 5 wxALIGN_CENTER|wxALL @@ -17220,11 +20563,11 @@ - + 5 wxALL 0 - + 1 1 1 @@ -17279,11 +20622,11 @@ - + 5 wxALL 0 - + 1 1 1 @@ -17343,11 +20686,11 @@ - + 5 wxEXPAND 1 - + bSizer871 wxHORIZONTAL @@ -17481,11 +20824,11 @@ - + 5 wxEXPAND | wxALL 1 - + 1 1 1 @@ -17544,16 +20887,16 @@ - + bSizer115 wxVERTICAL none - + 5 wxEXPAND | wxALL 1 - + 1 1 1 @@ -17607,11 +20950,11 @@ wxTAB_TRAVERSAL - + 5 wxEXPAND | wxALL 1 - + 1 1 1 @@ -17665,11 +21008,11 @@ wxTAB_TRAVERSAL - + 5 wxEXPAND | wxALL 1 - + 1 1 1 @@ -17726,11 +21069,11 @@ - + 5 wxALL|wxEXPAND 1 - + 1 1 1 @@ -17791,11 +21134,11 @@ - + 5 wxALL|wxEXPAND 1 - + 1 1 1 @@ -17856,11 +21199,11 @@ - + 5 wxALL|wxEXPAND 1 - + 1 1 1 @@ -17938,7 +21281,7 @@ 5 wxEXPAND 1 - + bSizer8712 wxHORIZONTAL @@ -18202,11 +21545,11 @@ - + 5 wxEXPAND 0 - + bSizer12211 wxHORIZONTAL @@ -18215,11 +21558,11 @@ - + 5 wxALL 0 - + 1 1 1 @@ -18289,11 +21632,11 @@ bSizer86 wxHORIZONTAL none - + 5 wxEXPAND | wxALL 1 - + 1 1 1 @@ -18349,11 +21692,11 @@ - + 5 wxALL 0 - + 1 1 1 @@ -18415,6 +21758,133 @@ + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + 0 + + 0 + 0 + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 0 + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + 0 + + 0 + + 1 + m_textCtrl351 + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + 5 + wxALIGN_CENTER|wxALL + 0 + + 1 + 1 + 1 + 1 + 0 + + 0 + 0 + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 0 + 1 + + 1 + + 0 + 0 + wxID_ANY + Encryption + 0 + + 0 + + + 0 + 150,-1 + 1 + m_staticText701 + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + + + -1 + + MyMenu diff --git a/README.md b/README.md index 577a352..b651e06 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,6 @@ ![status: unstable](https://img.shields.io/badge/status-unstable-orange) -![Coverage](https://img.shields.io/badge/coverage-54%25-brightgreen) +![Coverage](https://img.shields.io/badge/coverage-56%25-brightgreen) +![Tests](https://img.shields.io/badge/tests-2495-blue) ![SQLite](https://img.shields.io/badge/SQLite-tested-lightgrey) ![MySQL](https://img.shields.io/badge/MySQL-5.7%20%7C%208.0%20%7C%20latest-lightgrey) @@ -111,13 +112,28 @@ You can change the language in the application settings (Settings → General ## 🧪 Test Coverage -PeterSQL has **comprehensive integration tests** across all supported database engines covering Tables, Records, Columns, Indexes, Foreign Keys, Triggers, Views, and SSH tunnels. +PeterSQL has a structured test suite with both **unit tests** and **integration tests** across supported database engines. - 🏗️ **Granular base class architecture** - zero code duplication - 🐛 **Bug detection** - tests have found multiple API inconsistencies - ✅ **Full CRUD coverage** for core database objects -For detailed test coverage matrix, statistics, architecture, and running instructions, see **[tests/README.md](tests/README.md)**. +For detailed test coverage matrix, statistics, and architecture, see **[tests/README.md](tests/README.md)**. + + +### Suite status (passed / skipped) + +| Suite | Passed | Skipped | +|-------|--------|---------| +| autocomplete | ![passed](https://img.shields.io/badge/passed-1944-brightgreen) | ![skipped](https://img.shields.io/badge/skipped-0-lightgrey) | +| core | ![passed](https://img.shields.io/badge/passed-122-brightgreen) | ![skipped](https://img.shields.io/badge/skipped-0-lightgrey) | +| ui | ![passed](https://img.shields.io/badge/passed-57-brightgreen) | ![skipped](https://img.shields.io/badge/skipped-0-lightgrey) | +| mysql | ![passed](https://img.shields.io/badge/passed-59-brightgreen) | ![skipped](https://img.shields.io/badge/skipped-1-lightgrey) | +| mariadb | ![passed](https://img.shields.io/badge/passed-115-brightgreen) | ![skipped](https://img.shields.io/badge/skipped-3-lightgrey) | +| postgresql | ![passed](https://img.shields.io/badge/passed-132-brightgreen) | ![skipped](https://img.shields.io/badge/skipped-0-lightgrey) | +| sqlite | ![passed](https://img.shields.io/badge/passed-21-brightgreen) | ![skipped](https://img.shields.io/badge/skipped-5-lightgrey) | + + --- @@ -153,10 +169,10 @@ PeterSQL uses [uv](https://github.com/astral-sh/uv) for fast and reliable depend uv sync --extra dev ``` -To run tests: +Run tests with the project runner script: ```bash -uv run pytest +./scripts/runtest.py ``` ### Troubleshooting installation @@ -172,6 +188,30 @@ uv pip install -U --reinstall wxPython==4.2.5 --no-binary wxPython ###### Once the build finishes, rerun `uv sync` so the refreshed environment picks up the manually installed wxPython. +--- + +## 🧪 Running Tests + +- **Unit tests only** (default): + Uses `-m "not integration"`, so integration tests are excluded. + + ```bash + ./scripts/runtest.py + ``` + +- **Unit + integration tests**: + Runs the full suite, including integration tests. + + ```bash + ./scripts/runtest.py --all + ``` + +- **Unit + integration tests + README badge update** (engine badges + coverage badge): + + ```bash + ./scripts/runtest.py --update + ``` + ## 📸 Screenshot

diff --git a/ROADMAP.md b/ROADMAP.md index 2b898e7..9096d56 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -1,6 +1,6 @@ # PeterSQL — Development Roadmap -> **Last Updated:** 2026-03-07 +> **Last Updated:** 2026-03-10 > **Status Rule:** newly implemented features are tracked as **PARTIAL** until validated across supported versions. --- @@ -32,11 +32,13 @@ This roadmap reflects the current project state and separates: - [x] **PostgreSQL Function engine implementation** (PARTIAL) - **Files:** `structures/engines/postgresql/database.py`, `structures/engines/postgresql/context.py` - - **Next:** validate behavior across supported PostgreSQL variants. + - **Status:** integration coverage for create/alter/drop is now in place across supported PostgreSQL variants. + - **Next:** long-run/manual workflow validation + broader regression checks. - [x] **PostgreSQL Procedure engine implementation** (PARTIAL) - **Files:** `structures/engines/postgresql/database.py`, `structures/engines/postgresql/context.py` - - **Next:** validate create/alter/drop and introspection consistency. + - **Status:** integration coverage for create/alter/drop is now in place across supported PostgreSQL variants. + - **Next:** long-run/manual workflow validation + introspection consistency checks. - [x] **Check constraint implementations for MySQL/MariaDB/PostgreSQL** (PARTIAL) - **Files:** @@ -51,22 +53,35 @@ This roadmap reflects the current project state and separates: - `structures/connection.py` - `windows/dialogs/connections/model.py` - `windows/dialogs/connections/view.py` - - **Next:** long-run behavioral validation. + - **Validation status:** unit tests now cover connection statistics updates, MySQL/MariaDB TLS retry behavior, and SSH tunnel context lifecycle contracts. + - **Next:** unblock and run SSH testcontainers integration validation (currently skipped) + long-run behavioral validation. + +- [x] **SQL dump/backup object-driven flow** (PARTIAL) + - **Scope:** `SQLDatabase.dump()` now generates SQL dump files through domain objects (`raw_create()`), with ordered schema + records sections. + - **Files:** + - `structures/engines/database.py` + - `structures/engines/dump.py` + - `structures/engines/mysql/database.py` + - `structures/engines/mariadb/database.py` + - `structures/engines/postgresql/database.py` + - `structures/engines/sqlite/database.py` + - **Validation status:** unit suite is green in serial and xdist runs. + - **Next:** cross-engine manual restore/import verification from produced dumps. --- ## 🟡 P1 - Engine Gaps -- [ ] **MySQL Procedure implementation** - - **Current blocker:** `build_empty_procedure` not implemented in MySQL context. - - **Files:** `structures/engines/mysql/context.py`, `structures/engines/mysql/database.py` +- [x] **MySQL Procedure implementation** (PARTIAL) + - **Status:** Engine CRUD + introspection implemented, integration tests added. + - **Files:** `structures/engines/mysql/context.py`, `structures/engines/mysql/database.py`, `tests/engines/mysql/test_integration_suite.py`, `tests/engines/base_procedure_tests.py` -- [ ] **MariaDB Procedure implementation** - - **Current blocker:** `build_empty_procedure` not implemented in MariaDB context. - - **Files:** `structures/engines/mariadb/context.py`, `structures/engines/mariadb/database.py` +- [x] **MariaDB Procedure implementation** (PARTIAL) + - **Status:** Engine CRUD + introspection implemented, integration tests added. + - **Files:** `structures/engines/mariadb/context.py`, `structures/engines/mariadb/database.py`, `tests/engines/mariadb/test_integration_suite.py`, `tests/engines/base_procedure_tests.py` -- [ ] **Database create/drop API parity** - - **Current state:** list/read available, lifecycle operations missing in contexts. +- [ ] **Database lifecycle parity (context + UI wiring)** + - **Current state:** engine database objects expose create/alter/drop, but context/UI workflow remains read/list oriented. - **Files:** `structures/engines/*/context.py` --- @@ -97,7 +112,7 @@ This roadmap reflects the current project state and separates: - [ ] PostgreSQL sequence CRUD - [ ] User/role management - [ ] Privileges/grants management -- [ ] Import/export workflows (dump/restore + structured data) +- [ ] Restore + structured import/export workflows - [ ] PostgreSQL advanced objects (materialized views, partitioning, extensions) --- @@ -117,16 +132,19 @@ Before moving a PARTIAL item to DONE: ### Current Status -- **P0 implemented (partial):** 4/4 -- **P1 gaps closed:** 0/3 +- **P0 implemented (partial):** 5/5 +- **P1 gaps closed:** 2/3 - **P2 UI tasks complete:** 1/5 - **P3 advanced tasks complete:** 0/6 ### Recent Highlights - PostgreSQL Function and Procedure engine classes added. +- PostgreSQL Function/Procedure integration tests now include ALTER coverage (create/alter/drop). - Check constraint support added for MySQL, MariaDB, PostgreSQL. - Connection statistics and TLS auto-retry behavior added in connection manager. +- SQL dump/backup pipeline refactored to object-driven generation (`SQLDatabase.dump()` + `raw_create()`). +- SSH tunnel unit contract tests added for context lifecycle and process stop behavior. - CI workflow split into test/nightly-update/release lanes. --- diff --git a/helpers/bindings.py b/helpers/bindings.py index e05b25c..9a0a417 100644 --- a/helpers/bindings.py +++ b/helpers/bindings.py @@ -110,7 +110,7 @@ def get(self) -> Any: class BindSelectionControl(AbstractBindControl): - def __init__(self, control: CONTROL_BIND_SELECTION, observable: Observable, initial: Optional[List[str]] = None): + def __init__(self, control: CONTROL_BIND_SELECTION, observable: Observable, initial: Optional[list[str]] = None): super().__init__(control, observable, event=wx.EVT_CHOICE) if initial is not None: self.control.Set(initial) @@ -226,7 +226,7 @@ def __init__(cls, name, bases, attrs): class AbstractModel(metaclass=AbstractMetaModel): - observables: List[Observable] = [] + observables: list[Observable] = [] def bind_control(self, control: CONTROLS, observable: Observable): if isinstance(control, wx.StaticText): @@ -246,7 +246,7 @@ def bind_control(self, control: CONTROLS, observable: Observable): self.observables.append(observable) - def bind_controls(self, **controls: Union[CONTROLS, Tuple[CONTROLS, Dict]]): + def bind_controls(self, **controls: Union[CONTROLS, tuple[CONTROLS, dict]]): for name, ctrl in controls.items(): if hasattr(self, name) and isinstance(getattr(self, name), Observable): observable = getattr(self, name) diff --git a/helpers/dataview.py b/helpers/dataview.py index 67a78a9..a59467c 100644 --- a/helpers/dataview.py +++ b/helpers/dataview.py @@ -34,34 +34,24 @@ def __init__(self, column_count: Optional[int] = None): self._column_count = column_count def load(self, data: list[Any]): - logger.debug(f"{self.__class__.__name__}.load: {data[:50]}") - if data: self._data = data.copy() def filter(self, data: list[Any]): - logger.debug(f"{self.__class__.__name__}.filter: {data[:50]}") - if data: self._data = data.copy() def append(self, data: Any) -> int: - logger.debug(f"{self.__class__.__name__}.append: {data}") - self._data.append(data) return len(self._data) - 1 def insert(self, data: Any, index: int) -> int: - logger.debug(f"{self.__class__.__name__}._insert: {index} {data} ") - self._data.insert(index, data) return index def replace(self, data: Any, index: int) -> int: - logger.debug(f"{self.__class__.__name__}.replace: index={index} {data}") - index = self._data.index(data) self._data.remove(data) @@ -70,15 +60,11 @@ def replace(self, data: Any, index: int) -> int: return index def move(self, data: Any, current: int, future: int) -> (int, int): - logger.debug(f"{self.__class__.__name__}.move: {data} current={current} future={future}") - self._data[current], self._data[future] = self._data[future], self._data[current] return current, future def remove(self, data: Any) -> int: - logger.debug(f"{self.__class__.__name__}.remove: {data}") - index = self._data.index(data) self._data.remove(data) @@ -86,8 +72,6 @@ def remove(self, data: Any) -> int: return index def pop(self, data: Any) -> int: - logger.debug(f"{self.__class__.__name__}.pop: {data}") - index = self._data.index(data) self._data.pop(index) @@ -121,7 +105,7 @@ def __init__(self, column_count: Optional[int] = None): AbstractBaseDataModel.__init__(self, column_count) wx.dataview.PyDataViewModel.__init__(self) - def _load(self, data: List[Any]): + def _load(self, data: list[Any]): self.clear() AbstractBaseDataModel.load(self, data) self.Cleared() diff --git a/helpers/observables.py b/helpers/observables.py index 4fa5d52..5babdf1 100755 --- a/helpers/observables.py +++ b/helpers/observables.py @@ -2,12 +2,11 @@ import enum import inspect import weakref + from threading import Timer from typing import Callable, TypeVar, Generic, Any, SupportsIndex, Union, Optional, cast, Self, Hashable -import wx - from helpers.logger import logger T = TypeVar("T") @@ -365,7 +364,7 @@ def refresh(self) -> Self: class ObservableObject(Observable): - def _get_in_ref(self, ref: Union[Dict, List, Any], key: Union[str, SupportsIndex]): + def _get_in_ref(self, ref: Union[dict, list, Any], key: Union[str, SupportsIndex]): if isinstance(ref, dict): return ref.get(key) elif isinstance(ref, list): @@ -373,7 +372,7 @@ def _get_in_ref(self, ref: Union[Dict, List, Any], key: Union[str, SupportsIndex else: return getattr(ref, str(key), None) - def _set_in_ref(self, ref: Union[Dict, List, Any], key: Union[str, SupportsIndex], value: Any): + def _set_in_ref(self, ref: Union[dict, list, Any], key: Union[str, SupportsIndex], value: Any): if isinstance(ref, dict): ref[key] = value elif isinstance(ref, list): diff --git a/locale/de_DE/LC_MESSAGES/petersql.mo b/locale/de_DE/LC_MESSAGES/petersql.mo index c6aade8..120161d 100644 Binary files a/locale/de_DE/LC_MESSAGES/petersql.mo and b/locale/de_DE/LC_MESSAGES/petersql.mo differ diff --git a/locale/de_DE/LC_MESSAGES/petersql.po b/locale/de_DE/LC_MESSAGES/petersql.po index ae08f55..9ce809a 100644 --- a/locale/de_DE/LC_MESSAGES/petersql.po +++ b/locale/de_DE/LC_MESSAGES/petersql.po @@ -1,492 +1,725 @@ -# German translations for petersql. -# Copyright (C) 2024 -# This file is distributed under the same license as the petersql package. +# Deutsch (de_DE) translations for PeterSQL. +# Copyright (C) 2026 ORGANIZATION +# This file is distributed under the same license as the PeterSQL project. # +#, fuzzy msgid "" msgstr "" -"Language: de\n" -"Content-Type: text/plain; charset=UTF-8\n" +"Project-Id-Version: PeterSQL 0.1.0\n" +"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" +"POT-Creation-Date: 2026-03-10 18:23+0100\n" +"PO-Revision-Date: 2026-03-10 18:21+0000\n" +"Last-Translator: \n" +"Language: de_DE\n" +"Language-Team: de_DE \n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Generated-By: Babel 2.18.0\n" -#: helpers/__init__.py:14 +#: helpers/__init__.py:16 msgctxt "unit" msgid "B" msgstr "B" -#: helpers/__init__.py:15 +#: helpers/__init__.py:17 msgctxt "unit" msgid "KB" msgstr "KB" -#: helpers/__init__.py:16 +#: helpers/__init__.py:18 msgctxt "unit" msgid "MB" msgstr "MB" -#: helpers/__init__.py:17 +#: helpers/__init__.py:19 msgctxt "unit" msgid "GB" msgstr "GB" -#: helpers/__init__.py:18 +#: helpers/__init__.py:20 msgctxt "unit" msgid "TB" msgstr "TB" -#: structures/ssh_tunnel.py:117 +#: structures/ssh_tunnel.py:166 msgid "OpenSSH client not found." msgstr "OpenSSH-Client nicht gefunden." -#: windows/__init__.py:31 windows/main/main_frame.py:224 +#: windows/dialogs/connections/view.py:395 +#: windows/dialogs/connections/view.py:738 windows/main/controller.py:296 +#: windows/views.py:33 msgid "Connection" msgstr "Verbindung" -#: windows/__init__.py:45 windows/__init__.py:83 windows/__init__.py:820 -#: windows/__init__.py:880 windows/__init__.py:1267 windows/__init__.py:1950 -#: windows/__init__.py:1973 windows/__init__.py:1974 windows/__init__.py:1975 -#: windows/__init__.py:1976 windows/__init__.py:1977 windows/__init__.py:1978 -#: windows/__init__.py:1979 windows/__init__.py:1980 windows/__init__.py:1981 -#: windows/__init__.py:1985 windows/__init__.py:2076 windows/__init__.py:2277 #: windows/components/dataview.py:113 windows/components/dataview.py:225 #: windows/components/dataview.py:238 windows/components/dataview.py:253 +#: windows/views.py:47 windows/views.py:97 windows/views.py:956 +#: windows/views.py:1306 windows/views.py:1413 windows/views.py:1796 +#: windows/views.py:2707 windows/views.py:2730 windows/views.py:2731 +#: windows/views.py:2732 windows/views.py:2733 windows/views.py:2734 +#: windows/views.py:2735 windows/views.py:2736 windows/views.py:2737 +#: windows/views.py:2738 windows/views.py:2742 windows/views.py:2936 +#: windows/views.py:3137 msgid "Name" msgstr "Name" -#: windows/__init__.py:46 windows/__init__.py:322 +#: windows/views.py:48 windows/views.py:381 msgid "Last connection" msgstr "Letzte Verbindung" -#: windows/__init__.py:59 windows/connections/manager.py:174 +#: windows/dialogs/connections/view.py:631 windows/views.py:61 msgid "New directory" msgstr "Neues Verzeichnis" -#: windows/__init__.py:62 -msgid "New Session" -msgstr "Neue Sitzung" +#: windows/dialogs/connections/model.py:187 +#: windows/dialogs/connections/view.py:591 windows/views.py:65 +msgid "New connection" +msgstr "Neue Verbindung" + +#: windows/views.py:71 +#, fuzzy +msgid "Rename" +msgstr "Name" -#: windows/__init__.py:67 -msgid "Import" -msgstr "Importieren" +#: windows/views.py:76 +#, fuzzy +msgid "Clone connection" +msgstr "Neue Verbindung" + +#: windows/views.py:81 windows/views.py:556 windows/views.py:1290 +#: windows/views.py:1331 windows/views.py:1706 windows/views.py:1738 +#: windows/views.py:1997 windows/views.py:3273 windows/views.py:3305 +msgid "Delete" +msgstr "Löschen" -#: windows/__init__.py:97 windows/__init__.py:825 windows/__init__.py:935 -#: windows/__init__.py:1990 windows/__init__.py:2332 +#: windows/views.py:111 windows/views.py:1311 windows/views.py:1468 +#: windows/views.py:2747 windows/views.py:3192 msgid "Engine" msgstr "Engine" -#: windows/__init__.py:118 +#: windows/views.py:132 msgid "Host + port" msgstr "Host + Port" -#: windows/__init__.py:134 +#: windows/views.py:148 msgid "Username" msgstr "Benutzername" -#: windows/__init__.py:147 +#: windows/views.py:161 windows/views.py:1100 msgid "Password" msgstr "Passwort" -#: windows/__init__.py:163 +#: windows/views.py:177 +msgid "Use TLS" +msgstr "TLS verwenden" + +#: windows/views.py:180 msgid "Use SSH tunnel" msgstr "SSH-Tunnel verwenden" -#: windows/__init__.py:185 windows/__init__.py:1897 +#: windows/views.py:202 windows/views.py:2668 msgid "Filename" msgstr "Dateiname" -#: windows/__init__.py:190 windows/__init__.py:1902 +#: windows/views.py:207 windows/views.py:324 windows/views.py:2673 +#: windows/views.py:2856 msgid "Select a file" msgstr "Datei auswählen" -#: windows/__init__.py:190 -msgid "*. *" +#: windows/views.py:207 windows/views.py:324 windows/views.py:2856 +#, fuzzy +msgid "*.*" msgstr "*. *" -#: windows/__init__.py:204 windows/__init__.py:827 windows/__init__.py:893 -#: windows/__init__.py:1991 windows/__init__.py:2174 windows/__init__.py:2290 #: windows/components/dataview.py:70 windows/components/dataview.py:92 +#: windows/views.py:221 windows/views.py:1313 windows/views.py:1426 +#: windows/views.py:2748 windows/views.py:3034 windows/views.py:3150 msgid "Comments" msgstr "Kommentare" -#: windows/__init__.py:218 windows/__init__.py:520 +#: windows/main/controller.py:219 windows/views.py:235 windows/views.py:683 +#: windows/views.py:837 msgid "Settings" msgstr "Einstellungen" -#: windows/__init__.py:227 +#: windows/views.py:244 msgid "SSH executable" msgstr "SSH-Executable" -#: windows/__init__.py:232 +#: windows/views.py:249 msgid "ssh" msgstr "ssh" -#: windows/__init__.py:240 +#: windows/views.py:257 msgid "SSH host + port" msgstr "SSH-Host + Port" -#: windows/__init__.py:256 +#: windows/views.py:269 +msgid "SSH host + port (the SSH server that forwards traffic to the DB)" +msgstr "SSH-Host + Port (der SSH-Server, der den Verkehr zur DB weiterleitet)" + +#: windows/views.py:278 msgid "SSH username" msgstr "SSH-Benutzername" -#: windows/__init__.py:269 +#: windows/views.py:291 msgid "SSH password" msgstr "SSH-Passwort" -#: windows/__init__.py:282 +#: windows/views.py:304 msgid "Local port" msgstr "Lokaler Port" -#: windows/__init__.py:288 +#: windows/views.py:310 msgid "if the value is set to 0, the first available port will be used" msgstr "wenn der Wert auf 0 gesetzt ist, wird der erste verfügbare Port verwendet" -#: windows/__init__.py:299 +#: windows/views.py:319 +msgid "Identity file" +msgstr "Identitätsdatei" + +#: windows/views.py:335 +#, fuzzy +msgid "Remote host + port" +msgstr "Host + Port" + +#: windows/views.py:347 +msgid "Remote host/port is the real DB target (defaults to DB Host/Port)." +msgstr "Remote-Host/Port ist das eigentliche DB-Ziel (standardmäßig DB-Host/Port)." + +#: windows/views.py:358 msgid "SSH Tunnel" msgstr "SSH-Tunnel" -#: windows/__init__.py:305 windows/__init__.py:823 windows/__init__.py:1988 +#: windows/views.py:364 windows/views.py:1309 windows/views.py:2745 msgid "Created at" msgstr "Erstellt am" -#: windows/__init__.py:339 +#: windows/views.py:398 msgid "Successful connections" msgstr "Erfolgreiche Verbindungen" -#: windows/__init__.py:356 +#: windows/views.py:415 +#, fuzzy +msgid "Last successful connection" +msgstr "Erfolgreiche Verbindungen" + +#: windows/views.py:432 msgid "Unsuccessful connections" msgstr "Erfolglose Verbindungen" -#: windows/__init__.py:375 +#: windows/views.py:449 +msgid "Last failure reason" +msgstr "" + +#: windows/views.py:466 +#, fuzzy +msgid "Total connection attempts" +msgstr "Letzte Verbindung" + +#: windows/views.py:483 +#, fuzzy +msgid " Average connection time (ms)" +msgstr "Wiederverbindung fehlgeschlagen:" + +#: windows/views.py:500 +#, fuzzy +msgid " Most recent connection duration" +msgstr "Verbindungsmanager öffnen" + +#: windows/views.py:519 msgid "Statistics" msgstr "Statistiken" -#: windows/__init__.py:393 windows/__init__.py:1139 +#: windows/views.py:537 windows/views.py:1672 msgid "Create" msgstr "Erstellen" -#: windows/__init__.py:403 windows/__init__.py:806 windows/__init__.py:1173 -#: windows/__init__.py:1205 windows/__init__.py:1340 windows/__init__.py:2413 -#: windows/__init__.py:2445 -msgid "Delete" -msgstr "Löschen" +#: windows/views.py:541 +#, fuzzy +msgid "Create connection" +msgstr "Letzte Verbindung" -#: windows/__init__.py:420 windows/__init__.py:634 windows/__init__.py:1208 -#: windows/__init__.py:1343 windows/__init__.py:1419 windows/__init__.py:2221 -#: windows/__init__.py:2448 +#: windows/views.py:544 +#, fuzzy +msgid "Create directory" +msgstr "Neues Verzeichnis" + +#: windows/views.py:573 windows/views.py:797 windows/views.py:1328 +#: windows/views.py:1741 windows/views.py:2002 windows/views.py:2078 +#: windows/views.py:3081 windows/views.py:3308 msgid "Cancel" msgstr "Abbrechen" -#: windows/__init__.py:425 windows/__init__.py:1348 windows/__init__.py:2231 -#: windows/__init__.py:2453 +#: windows/views.py:578 windows/views.py:2007 windows/views.py:3091 +#: windows/views.py:3313 msgid "Save" msgstr "Speichern" -#: windows/__init__.py:432 +#: windows/views.py:585 msgid "Test" msgstr "Testen" -#: windows/__init__.py:439 +#: windows/views.py:592 msgid "Connect" msgstr "Verbinden" -#: windows/__init__.py:532 +#: windows/views.py:695 msgid "Language" msgstr "Sprache" -#: windows/__init__.py:537 +#: windows/views.py:700 msgid "English" msgstr "Englisch" -#: windows/__init__.py:537 +#: windows/views.py:700 msgid "Italian" msgstr "Italienisch" -#: windows/__init__.py:537 +#: windows/views.py:700 msgid "French" msgstr "Französisch" -#: windows/__init__.py:549 +#: windows/views.py:712 msgid "Locale" msgstr "Lokale" -#: windows/__init__.py:570 +#: windows/views.py:733 msgid "Edit Value" msgstr "Wert bearbeiten" -#: windows/__init__.py:580 +#: windows/views.py:743 msgid "Syntax" msgstr "Syntax" -#: windows/__init__.py:637 +#: windows/views.py:800 msgid "Ok" msgstr "Ok" -#: windows/__init__.py:668 +#: windows/views.py:831 msgid "PeterSQL" msgstr "PeterSQL" -#: windows/__init__.py:674 +#: windows/views.py:840 msgid "File" msgstr "Datei" -#: windows/__init__.py:677 +#: windows/views.py:843 msgid "About" msgstr "Über" -#: windows/__init__.py:680 +#: windows/views.py:846 msgid "Help" msgstr "Hilfe" -#: windows/__init__.py:685 +#: windows/views.py:851 msgid "Open connection manager" msgstr "Verbindungsmanager öffnen" -#: windows/__init__.py:687 +#: windows/views.py:853 msgid "Disconnect from server" msgstr "Vom Server trennen" -#: windows/__init__.py:691 +#: windows/views.py:857 msgid "tool" msgstr "Werkzeug" -#: windows/__init__.py:691 +#: windows/views.py:857 msgid "Refresh" msgstr "Aktualisieren" -#: windows/__init__.py:695 windows/__init__.py:697 +#: windows/views.py:861 windows/views.py:863 msgid "Add" msgstr "Hinzufügen" -#: windows/__init__.py:731 windows/__init__.py:735 windows/__init__.py:1507 -#: windows/__init__.py:1603 +#: windows/views.py:897 windows/views.py:901 windows/views.py:2166 +#: windows/views.py:2654 msgid "MyMenuItem" msgstr "MeinMenüElement" -#: windows/__init__.py:738 windows/__init__.py:1236 windows/__init__.py:2476 +#: windows/views.py:904 windows/views.py:1769 windows/views.py:3336 msgid "MyMenu" msgstr "MeinMenü" -#: windows/__init__.py:753 +#: windows/views.py:919 windows/views.py:1350 windows/views.py:1357 +#: windows/views.py:1364 msgid "MyLabel" msgstr "MeinLabel" -#: windows/__init__.py:759 +#: windows/views.py:925 msgid "Databases" msgstr "Datenbanken" -#: windows/__init__.py:760 windows/__init__.py:822 windows/__init__.py:1959 -#: windows/__init__.py:1987 +#: windows/views.py:926 windows/views.py:1308 windows/views.py:2716 +#: windows/views.py:2744 msgid "Size" msgstr "Größe" -#: windows/__init__.py:761 +#: windows/views.py:927 msgid "Elements" msgstr "Elemente" -#: windows/__init__.py:762 +#: windows/views.py:928 msgid "Modified at" msgstr "Geändert am" -#: windows/__init__.py:763 windows/__init__.py:834 +#: windows/views.py:929 msgid "Tables" msgstr "Tabellen" -#: windows/__init__.py:770 +#: windows/views.py:936 msgid "System" msgstr "System" -#: windows/__init__.py:786 +#: windows/views.py:979 +#, fuzzy +msgid "Character set" +msgstr "Erstellt am" + +#: windows/components/dataview.py:43 windows/components/dataview.py:67 +#: windows/components/dataview.py:89 windows/views.py:1000 +#: windows/views.py:1312 windows/views.py:2980 +msgid "Collation" +msgstr "Sortierung" + +#: windows/views.py:1026 windows/views.py:2862 +msgid "Encryption" +msgstr "" + +#: windows/views.py:1038 +msgid "Read Only" +msgstr "" + +#: windows/views.py:1055 +#, fuzzy +msgid "Tablespace" +msgstr "Tabellen" + +#: windows/views.py:1076 +#, fuzzy +msgid "Connection limit" +msgstr "Verbindung verloren" + +#: windows/views.py:1119 +#, fuzzy +msgid "Profile" +msgstr "Datei" + +#: windows/views.py:1145 +#, fuzzy +msgid "Default tablespace" +msgstr "Tabelle löschen" + +#: windows/views.py:1166 +#, fuzzy +msgid "Temporary tablespace" +msgstr "Temporär" + +#: windows/views.py:1192 +msgid "Quota" +msgstr "" + +#: windows/views.py:1211 +msgid "Unlimited quota" +msgstr "" + +#: windows/views.py:1228 +msgid "Account status" +msgstr "" + +#: windows/views.py:1249 +#, fuzzy +msgid "Password expire" +msgstr "Passwort" + +#: windows/views.py:1270 msgid "Table:" msgstr "Tabelle:" -#: windows/__init__.py:794 windows/__init__.py:1018 windows/__init__.py:1062 -#: windows/__init__.py:1168 windows/__init__.py:2408 +#: windows/views.py:1278 windows/views.py:1551 windows/views.py:1595 +#: windows/views.py:1701 windows/views.py:3268 msgid "Insert" msgstr "Einfügen" -#: windows/__init__.py:799 +#: windows/views.py:1283 msgid "Clone" msgstr "Klonen" -#: windows/__init__.py:821 +#: windows/views.py:1307 msgid "Rows" msgstr "Zeilen" -#: windows/__init__.py:824 windows/__init__.py:1989 +#: windows/views.py:1310 windows/views.py:2746 msgid "Updated at" msgstr "Aktualisiert am" -#: windows/__init__.py:826 windows/__init__.py:2120 -#: windows/components/dataview.py:43 windows/components/dataview.py:67 -#: windows/components/dataview.py:89 -msgid "Collation" -msgstr "Sortierung" +#: windows/views.py:1334 windows/views.py:1746 windows/views.py:2085 +#: windows/views.py:2140 +msgid "Apply" +msgstr "Anwenden" + +#: windows/views.py:1344 windows/views.py:1503 windows/views.py:1956 +#: windows/views.py:3225 +msgid "Options" +msgstr "Optionen" -#: windows/__init__.py:842 +#: windows/views.py:1375 msgid "Diagram" msgstr "Diagramm" -#: windows/__init__.py:853 windows/__init__.py:1958 +#: windows/views.py:1386 windows/views.py:2715 msgid "Database" msgstr "Datenbank" -#: windows/__init__.py:908 windows/__init__.py:2305 +#: windows/views.py:1441 windows/views.py:3165 msgid "Base" msgstr "Basis" -#: windows/__init__.py:922 windows/__init__.py:2319 +#: windows/views.py:1455 windows/views.py:3179 msgid "Auto Increment" msgstr "Auto Inkrement" -#: windows/__init__.py:950 windows/__init__.py:2347 +#: windows/views.py:1483 windows/views.py:3207 msgid "Default Collation" msgstr "Standard-Sortierung" -#: windows/__init__.py:970 windows/__init__.py:1301 windows/__init__.py:2365 -msgid "Options" -msgstr "Optionen" - -#: windows/__init__.py:982 windows/__init__.py:1023 windows/__init__.py:1067 +#: windows/views.py:1515 windows/views.py:1556 windows/views.py:1600 msgid "Remove" msgstr "Entfernen" -#: windows/__init__.py:989 windows/__init__.py:1030 windows/__init__.py:1074 +#: windows/views.py:1522 windows/views.py:1563 windows/views.py:1607 msgid "Clear" msgstr "Löschen" -#: windows/__init__.py:1004 windows/__init__.py:2379 +#: windows/views.py:1537 windows/views.py:3239 msgid "Indexes" msgstr "Indizes" -#: windows/__init__.py:1048 +#: windows/views.py:1581 msgid "Foreign Keys" msgstr "Fremdschlüssel" -#: windows/__init__.py:1092 +#: windows/views.py:1625 msgid "Checks" msgstr "Prüfungen" -#: windows/__init__.py:1160 windows/__init__.py:2400 +#: windows/views.py:1693 windows/views.py:3260 msgid "Columns:" msgstr "Spalten:" -#: windows/__init__.py:1180 windows/__init__.py:2420 +#: windows/views.py:1713 windows/views.py:3280 msgid "Up" msgstr "Hoch" -#: windows/__init__.py:1187 windows/__init__.py:2427 +#: windows/views.py:1720 windows/views.py:3287 msgid "Down" msgstr "Runter" -#: windows/__init__.py:1213 windows/__init__.py:1426 windows/__init__.py:1481 -msgid "Apply" -msgstr "Anwenden" - -#: windows/__init__.py:1226 windows/__init__.py:1233 windows/__init__.py:2466 -#: windows/__init__.py:2473 +#: windows/views.py:1759 windows/views.py:1766 windows/views.py:3326 +#: windows/views.py:3333 msgid "Add Index" msgstr "Index hinzufügen" -#: windows/__init__.py:1230 windows/__init__.py:2470 +#: windows/views.py:1763 windows/views.py:3330 msgid "Add PrimaryKey" msgstr "Primärschlüssel hinzufügen" -#: windows/__init__.py:1247 +#: windows/views.py:1780 msgid "Table" msgstr "Tabelle" -#: windows/__init__.py:1280 -msgid "Temporary" -msgstr "Temporär" +#: windows/views.py:1816 +#, fuzzy +msgid "Definer" +msgstr "Einfügen" + +#: windows/views.py:1836 +msgid "Schema" +msgstr "" + +#: windows/views.py:1862 +msgid "SQL security" +msgstr "" + +#: windows/views.py:1869 +#, fuzzy +msgid "DEFINER" +msgstr "Einfügen" + +#: windows/views.py:1869 +#, fuzzy +msgid "INVOKER" +msgstr "Einfügen" + +#: windows/views.py:1881 windows/views.py:2558 windows/views.py:2577 +#: windows/views.py:2820 +msgid "Algorithm" +msgstr "" -#: windows/__init__.py:1360 +#: windows/views.py:1883 windows/views.py:2543 windows/views.py:2576 +#: windows/views.py:2825 +#, fuzzy +msgid "UNDEFINED" +msgstr "Ohne Vorzeichen" + +#: windows/views.py:1886 windows/views.py:2546 windows/views.py:2576 +#: windows/views.py:2828 +msgid "MERGE" +msgstr "" + +#: windows/views.py:1889 windows/views.py:2555 windows/views.py:2576 +#: windows/views.py:2831 +#, fuzzy +msgid "TEMPTABLE" +msgstr "Tabelle" + +#: windows/views.py:1899 windows/views.py:2582 +msgid "View constraint" +msgstr "" + +#: windows/views.py:1901 windows/views.py:2581 +#, fuzzy +msgid "None" +msgstr "Klonen" + +#: windows/views.py:1904 windows/views.py:2581 +#, fuzzy +msgid "LOCAL" +msgstr "Lokale" + +#: windows/views.py:1907 +#, fuzzy +msgid "CASCADE" +msgstr "Abbrechen" + +#: windows/views.py:1910 +#, fuzzy +msgid "CHECK ONLY" +msgstr "Prüfen" + +#: windows/views.py:1913 windows/views.py:2581 +msgid "READ ONLY" +msgstr "" + +#: windows/views.py:1925 +msgid "Force" +msgstr "" + +#: windows/views.py:1937 +msgid "Security barrier" +msgstr "" + +#: windows/views.py:2019 msgid "Views" msgstr "Ansichten" -#: windows/__init__.py:1368 +#: windows/views.py:2027 msgid "Triggers" msgstr "Trigger" -#: windows/__init__.py:1380 +#: windows/views.py:2039 #, python-format msgid "Table `%(database_name)s`.`%(table_name)s`: %(total_rows) rows total" -msgstr "Tabelle `%(database_name)s`.`%(table_name)s`: %(total_rows) Zeilen insgesamt" +msgstr "" +"Tabelle `%(database_name)s`.`%(table_name)s`: %(total_rows) Zeilen " +"insgesamt" -#: windows/__init__.py:1390 +#: windows/views.py:2049 msgid "Insert record" msgstr "Datensatz einfügen" -#: windows/__init__.py:1395 +#: windows/views.py:2054 msgid "Duplicate record" msgstr "Datensatz duplizieren" -#: windows/__init__.py:1402 +#: windows/views.py:2061 msgid "Delete record" msgstr "Datensatz löschen" -#: windows/__init__.py:1412 +#: windows/views.py:2071 msgid "Apply changes automatically" msgstr "Änderungen automatisch anwenden" -#: windows/__init__.py:1414 windows/__init__.py:1415 +#: windows/views.py:2073 windows/views.py:2074 msgid "" "If enabled, table edits are applied immediately without pressing Apply or" " Cancel" msgstr "" -"Wenn aktiviert, werden Tabellenbearbeitungen sofort angewendet, ohne auf Anwenden oder Abbrechen zu drücken" -"" +"Wenn aktiviert, werden Tabellenbearbeitungen sofort angewendet, ohne auf " +"Anwenden oder Abbrechen zu drücken" -#: windows/__init__.py:1436 +#: windows/views.py:2095 msgid "Next" msgstr "Weiter" -#: windows/__init__.py:1444 +#: windows/views.py:2103 msgid "Filters" msgstr "Filter" -#: windows/__init__.py:1484 +#: windows/views.py:2143 msgid "CTRL+ENTER" msgstr "CTRL+ENTER" -#: windows/__init__.py:1504 +#: windows/views.py:2163 msgid "Insert row" msgstr "Zeile einfügen" -#: windows/__init__.py:1512 +#: windows/views.py:2171 msgid "Data" msgstr "Daten" -#: windows/__init__.py:1561 +#: windows/views.py:2225 windows/views.py:2275 +msgid "New" +msgstr "Neu" + +#: windows/views.py:2252 msgid "Query" msgstr "Abfrage" -#: windows/__init__.py:1581 +#: windows/views.py:2272 msgid "Close" msgstr "Schließen" -#: windows/__init__.py:1584 windows/__init__.py:2019 -msgid "New" -msgstr "Neu" - -#: windows/__init__.py:1594 +#: windows/views.py:2285 msgid "Query #2" msgstr "Abfrage #2" -#: windows/__init__.py:1835 +#: windows/views.py:2537 msgid "Column5" msgstr "Spalte5" -#: windows/__init__.py:1842 +#: windows/views.py:2548 +msgid "Import" +msgstr "Importieren" + +#: windows/views.py:2573 +msgid "Read only" +msgstr "" + +#: windows/views.py:2581 +msgid "CASCADED" +msgstr "" + +#: windows/views.py:2581 +#, fuzzy +msgid "CHECK OPTION" +msgstr "Verbindung" + +#: windows/views.py:2613 msgid "collapsible" msgstr "zusammenklappbar" -#: windows/__init__.py:1864 +#: windows/views.py:2629 msgid "Column3" msgstr "Spalte3" -#: windows/__init__.py:1865 +#: windows/views.py:2630 msgid "Column4" msgstr "Spalte4" -#: windows/__init__.py:1902 +#: windows/views.py:2673 msgid "" "Database " "(*.db;*.db3;*.sdb;*.s3db;*.sqlite;*.sqlite3)|*.db;*.db3;*.sdb;*.s3db;*.sqlite;*.sqlite3" @@ -494,65 +727,78 @@ msgstr "" "Database " "(*.db;*.db3;*.sdb;*.s3db;*.sqlite;*.sqlite3)|*.db;*.db3;*.sdb;*.s3db;*.sqlite;*.sqlite3" -#: windows/__init__.py:1934 +#: windows/views.py:2685 msgid "Port" msgstr "Port" -#: windows/__init__.py:1951 +#: windows/views.py:2708 msgid "Usage" msgstr "Verwendung" -#: windows/__init__.py:1962 +#: windows/views.py:2719 #, python-format msgid "%(total_rows)s" msgstr "%(total_rows)s" -#: windows/__init__.py:1967 +#: windows/views.py:2724 msgid "rows total" msgstr "Zeilen insgesamt" -#: windows/__init__.py:1986 +#: windows/views.py:2743 msgid "Lines" msgstr "Zeilen" -#: windows/__init__.py:2068 +#: windows/views.py:2775 +msgid "Temporary" +msgstr "Temporär" + +#: windows/views.py:2786 +#, fuzzy +msgid "Engine options" +msgstr "Optionen" + +#: windows/views.py:2845 +msgid "RadioBtn" +msgstr "" + +#: windows/views.py:2928 msgid "Edit Column" msgstr "Spalte bearbeiten" -#: windows/__init__.py:2084 +#: windows/views.py:2944 msgid "Datatype" msgstr "Datentyp" -#: windows/__init__.py:2099 windows/components/dataview.py:121 +#: windows/components/dataview.py:121 windows/views.py:2959 msgid "Length/Set" msgstr "Länge/Menge" -#: windows/__init__.py:2138 windows/components/dataview.py:51 +#: windows/components/dataview.py:51 windows/views.py:2998 msgid "Unsigned" msgstr "Ohne Vorzeichen" -#: windows/__init__.py:2144 windows/components/dataview.py:25 -#: windows/components/dataview.py:52 windows/components/dataview.py:75 +#: windows/components/dataview.py:25 windows/components/dataview.py:52 +#: windows/components/dataview.py:75 windows/views.py:3004 msgid "Allow NULL" msgstr "NULL erlauben" -#: windows/__init__.py:2150 +#: windows/views.py:3010 msgid "Zero Fill" msgstr "Nullfüllung" -#: windows/__init__.py:2161 windows/components/dataview.py:32 -#: windows/components/dataview.py:56 windows/components/dataview.py:78 +#: windows/components/dataview.py:32 windows/components/dataview.py:56 +#: windows/components/dataview.py:78 windows/views.py:3021 msgid "Default" msgstr "Standard" -#: windows/__init__.py:2187 windows/components/dataview.py:36 -#: windows/components/dataview.py:60 windows/components/dataview.py:82 +#: windows/components/dataview.py:36 windows/components/dataview.py:60 +#: windows/components/dataview.py:82 windows/views.py:3047 msgid "Virtuality" msgstr "Virtualität" -#: windows/__init__.py:2202 windows/components/dataview.py:39 -#: windows/components/dataview.py:63 windows/components/dataview.py:85 -#: windows/components/dataview.py:241 +#: windows/components/dataview.py:39 windows/components/dataview.py:63 +#: windows/components/dataview.py:85 windows/components/dataview.py:241 +#: windows/views.py:3062 msgid "Expression" msgstr "Ausdruck" @@ -632,103 +878,232 @@ msgstr "Fremdschlüssel hinzufügen" msgid "Remove foreign key" msgstr "Fremdschlüssel entfernen" -#: windows/components/popup.py:24 +#: windows/components/popup.py:26 msgid "No default value" msgstr "Kein Standardwert" -#: windows/components/popup.py:29 +#: windows/components/popup.py:31 msgid "NULL" msgstr "NULL" -#: windows/components/popup.py:33 +#: windows/components/popup.py:35 msgid "AUTO INCREMENT" msgstr "AUTO INCREMENT" -#: windows/components/popup.py:37 +#: windows/components/popup.py:39 msgid "Text/Expression" msgstr "Text/Ausdruck" -#: windows/connections/manager.py:125 +#: windows/dialogs/connections/view.py:119 windows/main/tabs/query.py:376 +msgid "Unknown error" +msgstr "" + +#: windows/dialogs/connections/view.py:394 +msgid "Connection established successfully" +msgstr "" + +#: windows/dialogs/connections/view.py:407 msgid "Confirm save" msgstr "Speichern bestätigen" -#: windows/connections/manager.py:193 +#: windows/dialogs/connections/view.py:459 +msgid "You have unsaved changes. Do you want to save them before continuing?" +msgstr "" + +#: windows/dialogs/connections/view.py:461 +msgid "Unsaved changes" +msgstr "" + +#: windows/dialogs/connections/view.py:736 +msgid "" +"This connection cannot work without TLS. TLS has been enabled " +"automatically." +msgstr "" + +#: windows/dialogs/connections/view.py:762 msgid "Connection error" msgstr "Verbindungsfehler" -#: windows/connections/manager.py:214 -msgid "connection" -msgstr "Verbindung" - -#: windows/connections/manager.py:215 windows/connections/manager.py:230 +#: windows/dialogs/connections/view.py:788 +#: windows/dialogs/connections/view.py:803 msgid "Confirm delete" msgstr "Löschen bestätigen" -#: windows/connections/manager.py:229 -msgid "directory" -msgstr "Verzeichnis" - -#: windows/connections/model.py:101 -msgid "New connection" -msgstr "Neue Verbindung" - -#: windows/main/database.py:70 -msgid "The connection to the database was lost." -msgstr "Die Verbindung zur Datenbank wurde verloren." - -#: windows/main/database.py:72 -msgid "Do you want to reconnect?" -msgstr "Möchten Sie erneut verbinden?" - -#: windows/main/database.py:74 -msgid "Connection lost" -msgstr "Verbindung verloren" - -#: windows/main/database.py:83 -msgid "Reconnection failed:" -msgstr "Wiederverbindung fehlgeschlagen:" - -#: windows/main/database.py:84 -msgid "Error" -msgstr "Fehler" - -#: windows/main/main_frame.py:124 +#: windows/main/controller.py:172 msgid "days" msgstr "Tage" -#: windows/main/main_frame.py:125 +#: windows/main/controller.py:173 msgid "hours" msgstr "Stunden" -#: windows/main/main_frame.py:126 +#: windows/main/controller.py:174 msgid "minutes" msgstr "Minuten" -#: windows/main/main_frame.py:127 +#: windows/main/controller.py:175 msgid "seconds" msgstr "Sekunden" -#: windows/main/main_frame.py:135 +#: windows/main/controller.py:183 #, python-brace-format msgid "Memory used: {used} ({percentage:.2%})" msgstr "Verwendeter Speicher: {used} ({percentage:.2%})" -#: windows/main/main_frame.py:226 +#: windows/main/controller.py:219 +msgid "Settings saved successfully" +msgstr "" + +#: windows/main/controller.py:298 msgid "Version" msgstr "Version" -#: windows/main/main_frame.py:228 +#: windows/main/controller.py:300 msgid "Uptime" msgstr "Betriebszeit" -#: windows/main/main_frame.py:431 +#: windows/main/controller.py:399 +#, python-brace-format +msgid "" +"Do you want to create a dump before dropping database '{database_name}'?\n" +"\n" +"Dump is not implemented yet.\n" +"- Yes: open dump flow (coming soon, no drop).\n" +"- No: drop the database now." +msgstr "" + +#: windows/main/controller.py:404 windows/main/controller.py:425 +#, fuzzy +msgid "Delete database" +msgstr "Tabelle löschen" + +#: windows/main/controller.py:410 +msgid "Dump is not implemented yet. No action has been performed." +msgstr "" + +#: windows/main/controller.py:411 +msgid "Dump not available" +msgstr "" + +#: windows/main/controller.py:424 +msgid "Database deletion is not supported by this engine." +msgstr "" + +#: windows/main/controller.py:439 +msgid "Database deleted successfully" +msgstr "" + +#: windows/main/controller.py:440 windows/main/tabs/view.py:253 +#: windows/main/tabs/view.py:279 +msgid "Success" +msgstr "" + +#: windows/main/controller.py:582 msgid "Delete table" msgstr "Tabelle löschen" -#: windows/main/main_frame.py:586 +#: windows/main/controller.py:699 msgid "Do you want delete the records?" msgstr "Möchten Sie die Datensätze löschen?" +#: windows/main/tabs/database.py:71 +msgid "The connection to the database was lost." +msgstr "Die Verbindung zur Datenbank wurde verloren." + +#: windows/main/tabs/database.py:73 +msgid "Do you want to reconnect?" +msgstr "Möchten Sie erneut verbinden?" + +#: windows/main/tabs/database.py:75 +msgid "Connection lost" +msgstr "Verbindung verloren" + +#: windows/main/tabs/database.py:85 +msgid "Reconnection failed:" +msgstr "Wiederverbindung fehlgeschlagen:" + +#: windows/main/tabs/database.py:86 windows/main/tabs/query.py:450 +#: windows/main/tabs/view.py:256 windows/main/tabs/view.py:282 +msgid "Error" +msgstr "Fehler" + +#: windows/main/tabs/query.py:305 +#, python-brace-format +msgid "{} rows affected" +msgstr "" + +#: windows/main/tabs/query.py:309 windows/main/tabs/query.py:331 +#, fuzzy, python-brace-format +msgid "Query {}" +msgstr "Abfrage" + +#: windows/main/tabs/query.py:314 +#, python-brace-format +msgid "Query {} (Error)" +msgstr "" + +#: windows/main/tabs/query.py:326 +#, python-brace-format +msgid "Query {} ({} rows × {} cols)" +msgstr "" + +#: windows/main/tabs/query.py:353 +#, fuzzy, python-brace-format +msgid "{} rows" +msgstr "Zeilen" + +#: windows/main/tabs/query.py:355 +#, python-brace-format +msgid "{:.1f} ms" +msgstr "" + +#: windows/main/tabs/query.py:358 +#, python-brace-format +msgid "{} warnings" +msgstr "" + +#: windows/main/tabs/query.py:370 +#, fuzzy +msgid "Error:" +msgstr "Fehler" + +#: windows/main/tabs/query.py:449 +#, fuzzy +msgid "No active database connection" +msgstr "Neue Verbindung" + +#: windows/main/tabs/view.py:252 +msgid "View created successfully" +msgstr "" + +#: windows/main/tabs/view.py:252 +msgid "View updated successfully" +msgstr "" + +#: windows/main/tabs/view.py:256 +#, python-brace-format +msgid "Error saving view: {}" +msgstr "" + +#: windows/main/tabs/view.py:269 +#, python-brace-format +msgid "Are you sure you want to delete view '{}'?" +msgstr "" + +#: windows/main/tabs/view.py:270 +#, fuzzy +msgid "Confirm Delete" +msgstr "Löschen bestätigen" + +#: windows/main/tabs/view.py:279 +msgid "View deleted successfully" +msgstr "" + +#: windows/main/tabs/view.py:282 +#, python-brace-format +msgid "Error deleting view: {}" +msgstr "" + #~ msgid "Created at:" #~ msgstr "" @@ -759,3 +1134,9 @@ msgstr "Möchten Sie die Datensätze löschen?" #~ msgid "Foreign Key" #~ msgstr "" +#~ msgid "New Session" +#~ msgstr "Neue Sitzung" + +#~ msgid "directory" +#~ msgstr "Verzeichnis" + diff --git a/locale/en_US/LC_MESSAGES/petersql.mo b/locale/en_US/LC_MESSAGES/petersql.mo new file mode 100644 index 0000000..7e69f11 Binary files /dev/null and b/locale/en_US/LC_MESSAGES/petersql.mo differ diff --git a/locale/en_US/LC_MESSAGES/petersql.po b/locale/en_US/LC_MESSAGES/petersql.po index c910513..89d304b 100644 --- a/locale/en_US/LC_MESSAGES/petersql.po +++ b/locale/en_US/LC_MESSAGES/petersql.po @@ -1,545 +1,770 @@ -#: helpers/__init__.py:14 +# English (en_US) translations for PeterSQL. +# Copyright (C) 2026 ORGANIZATION +# This file is distributed under the same license as the PeterSQL project. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PeterSQL 0.1.0\n" +"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" +"POT-Creation-Date: 2026-03-10 18:23+0100\n" +"PO-Revision-Date: 2026-03-10 18:21+0000\n" +"Last-Translator: \n" +"Language: en_US\n" +"Language-Team: en_US \n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Generated-By: Babel 2.18.0\n" + +#: helpers/__init__.py:16 msgctxt "unit" msgid "B" -msgstr "" +msgstr "B" -#: helpers/__init__.py:15 +#: helpers/__init__.py:17 msgctxt "unit" msgid "KB" -msgstr "" +msgstr "KB" -#: helpers/__init__.py:16 +#: helpers/__init__.py:18 msgctxt "unit" msgid "MB" -msgstr "" +msgstr "MB" -#: helpers/__init__.py:17 +#: helpers/__init__.py:19 msgctxt "unit" msgid "GB" -msgstr "" +msgstr "GB" -#: helpers/__init__.py:18 +#: helpers/__init__.py:20 msgctxt "unit" msgid "TB" -msgstr "" +msgstr "TB" -#: structures/ssh_tunnel.py:117 +#: structures/ssh_tunnel.py:166 msgid "OpenSSH client not found." -msgstr "" +msgstr "OpenSSH client not found." -#: windows/__init__.py:31 windows/main/main_frame.py:224 +#: windows/dialogs/connections/view.py:395 +#: windows/dialogs/connections/view.py:738 windows/main/controller.py:296 +#: windows/views.py:33 msgid "Connection" -msgstr "" +msgstr "Connection" -#: windows/__init__.py:45 windows/__init__.py:83 windows/__init__.py:820 -#: windows/__init__.py:880 windows/__init__.py:1267 windows/__init__.py:1950 -#: windows/__init__.py:1973 windows/__init__.py:1974 windows/__init__.py:1975 -#: windows/__init__.py:1976 windows/__init__.py:1977 windows/__init__.py:1978 -#: windows/__init__.py:1979 windows/__init__.py:1980 windows/__init__.py:1981 -#: windows/__init__.py:1985 windows/__init__.py:2076 windows/__init__.py:2277 #: windows/components/dataview.py:113 windows/components/dataview.py:225 #: windows/components/dataview.py:238 windows/components/dataview.py:253 +#: windows/views.py:47 windows/views.py:97 windows/views.py:956 +#: windows/views.py:1306 windows/views.py:1413 windows/views.py:1796 +#: windows/views.py:2707 windows/views.py:2730 windows/views.py:2731 +#: windows/views.py:2732 windows/views.py:2733 windows/views.py:2734 +#: windows/views.py:2735 windows/views.py:2736 windows/views.py:2737 +#: windows/views.py:2738 windows/views.py:2742 windows/views.py:2936 +#: windows/views.py:3137 msgid "Name" -msgstr "" +msgstr "Name" -#: windows/__init__.py:46 windows/__init__.py:322 +#: windows/views.py:48 windows/views.py:381 msgid "Last connection" -msgstr "" +msgstr "Last connection" -#: windows/__init__.py:59 windows/connections/manager.py:174 +#: windows/dialogs/connections/view.py:631 windows/views.py:61 msgid "New directory" -msgstr "" +msgstr "New directory" -#: windows/__init__.py:62 -msgid "New Session" -msgstr "" +#: windows/dialogs/connections/model.py:187 +#: windows/dialogs/connections/view.py:591 windows/views.py:65 +msgid "New connection" +msgstr "New connection" -#: windows/__init__.py:67 -msgid "Import" -msgstr "" +#: windows/views.py:71 +msgid "Rename" +msgstr "Rename" + +#: windows/views.py:76 +msgid "Clone connection" +msgstr "Clone connection" -#: windows/__init__.py:97 windows/__init__.py:825 windows/__init__.py:935 -#: windows/__init__.py:1990 windows/__init__.py:2332 +#: windows/views.py:81 windows/views.py:556 windows/views.py:1290 +#: windows/views.py:1331 windows/views.py:1706 windows/views.py:1738 +#: windows/views.py:1997 windows/views.py:3273 windows/views.py:3305 +msgid "Delete" +msgstr "Delete" + +#: windows/views.py:111 windows/views.py:1311 windows/views.py:1468 +#: windows/views.py:2747 windows/views.py:3192 msgid "Engine" -msgstr "" +msgstr "Engine" -#: windows/__init__.py:118 +#: windows/views.py:132 msgid "Host + port" -msgstr "" +msgstr "Host + port" -#: windows/__init__.py:134 +#: windows/views.py:148 msgid "Username" -msgstr "" +msgstr "Username" -#: windows/__init__.py:147 +#: windows/views.py:161 windows/views.py:1100 msgid "Password" -msgstr "" +msgstr "Password" -#: windows/__init__.py:163 +#: windows/views.py:177 +msgid "Use TLS" +msgstr "Use TLS" + +#: windows/views.py:180 msgid "Use SSH tunnel" -msgstr "" +msgstr "Use SSH tunnel" -#: windows/__init__.py:185 windows/__init__.py:1897 +#: windows/views.py:202 windows/views.py:2668 msgid "Filename" -msgstr "" +msgstr "Filename" -#: windows/__init__.py:190 windows/__init__.py:1902 +#: windows/views.py:207 windows/views.py:324 windows/views.py:2673 +#: windows/views.py:2856 msgid "Select a file" -msgstr "" +msgstr "Select a file" -#: windows/__init__.py:190 +#: windows/views.py:207 windows/views.py:324 windows/views.py:2856 msgid "*.*" -msgstr "" +msgstr "*.*" -#: windows/__init__.py:204 windows/__init__.py:827 windows/__init__.py:893 -#: windows/__init__.py:1991 windows/__init__.py:2174 windows/__init__.py:2290 #: windows/components/dataview.py:70 windows/components/dataview.py:92 +#: windows/views.py:221 windows/views.py:1313 windows/views.py:1426 +#: windows/views.py:2748 windows/views.py:3034 windows/views.py:3150 msgid "Comments" -msgstr "" +msgstr "Comments" -#: windows/__init__.py:218 windows/__init__.py:520 +#: windows/main/controller.py:219 windows/views.py:235 windows/views.py:683 +#: windows/views.py:837 msgid "Settings" -msgstr "" +msgstr "Settings" -#: windows/__init__.py:227 +#: windows/views.py:244 msgid "SSH executable" -msgstr "" +msgstr "SSH executable" -#: windows/__init__.py:232 +#: windows/views.py:249 msgid "ssh" -msgstr "" +msgstr "ssh" -#: windows/__init__.py:240 +#: windows/views.py:257 msgid "SSH host + port" -msgstr "" +msgstr "SSH host + port" -#: windows/__init__.py:256 +#: windows/views.py:269 +msgid "SSH host + port (the SSH server that forwards traffic to the DB)" +msgstr "SSH host + port (the SSH server that forwards traffic to the DB)" + +#: windows/views.py:278 msgid "SSH username" -msgstr "" +msgstr "SSH username" -#: windows/__init__.py:269 +#: windows/views.py:291 msgid "SSH password" -msgstr "" +msgstr "SSH password" -#: windows/__init__.py:282 +#: windows/views.py:304 msgid "Local port" -msgstr "" +msgstr "Local port" -#: windows/__init__.py:288 +#: windows/views.py:310 msgid "if the value is set to 0, the first available port will be used" -msgstr "" +msgstr "if the value is set to 0, the first available port will be used" + +#: windows/views.py:319 +msgid "Identity file" +msgstr "Identity file" + +#: windows/views.py:335 +msgid "Remote host + port" +msgstr "Remote host + port" + +#: windows/views.py:347 +msgid "Remote host/port is the real DB target (defaults to DB Host/Port)." +msgstr "Remote host/port is the real DB target (defaults to DB Host/Port)." -#: windows/__init__.py:299 +#: windows/views.py:358 msgid "SSH Tunnel" -msgstr "" +msgstr "SSH Tunnel" -#: windows/__init__.py:305 windows/__init__.py:823 windows/__init__.py:1988 +#: windows/views.py:364 windows/views.py:1309 windows/views.py:2745 msgid "Created at" -msgstr "" +msgstr "Created at" -#: windows/__init__.py:339 +#: windows/views.py:398 msgid "Successful connections" msgstr "" -#: windows/__init__.py:356 +#: windows/views.py:415 +msgid "Last successful connection" +msgstr "" + +#: windows/views.py:432 msgid "Unsuccessful connections" msgstr "" -#: windows/__init__.py:375 +#: windows/views.py:449 +msgid "Last failure reason" +msgstr "" + +#: windows/views.py:466 +msgid "Total connection attempts" +msgstr "" + +#: windows/views.py:483 +msgid " Average connection time (ms)" +msgstr "" + +#: windows/views.py:500 +msgid " Most recent connection duration" +msgstr "" + +#: windows/views.py:519 msgid "Statistics" msgstr "" -#: windows/__init__.py:393 windows/__init__.py:1139 +#: windows/views.py:537 windows/views.py:1672 msgid "Create" msgstr "" -#: windows/__init__.py:403 windows/__init__.py:806 windows/__init__.py:1173 -#: windows/__init__.py:1205 windows/__init__.py:1340 windows/__init__.py:2413 -#: windows/__init__.py:2445 -msgid "Delete" +#: windows/views.py:541 +msgid "Create connection" +msgstr "" + +#: windows/views.py:544 +msgid "Create directory" msgstr "" -#: windows/__init__.py:420 windows/__init__.py:634 windows/__init__.py:1208 -#: windows/__init__.py:1343 windows/__init__.py:1419 windows/__init__.py:2221 -#: windows/__init__.py:2448 +#: windows/views.py:573 windows/views.py:797 windows/views.py:1328 +#: windows/views.py:1741 windows/views.py:2002 windows/views.py:2078 +#: windows/views.py:3081 windows/views.py:3308 msgid "Cancel" msgstr "" -#: windows/__init__.py:425 windows/__init__.py:1348 windows/__init__.py:2231 -#: windows/__init__.py:2453 +#: windows/views.py:578 windows/views.py:2007 windows/views.py:3091 +#: windows/views.py:3313 msgid "Save" msgstr "" -#: windows/__init__.py:432 +#: windows/views.py:585 msgid "Test" msgstr "" -#: windows/__init__.py:439 +#: windows/views.py:592 msgid "Connect" msgstr "" -#: windows/__init__.py:532 +#: windows/views.py:695 msgid "Language" msgstr "" -#: windows/__init__.py:537 +#: windows/views.py:700 msgid "English" msgstr "" -#: windows/__init__.py:537 +#: windows/views.py:700 msgid "Italian" msgstr "" -#: windows/__init__.py:537 +#: windows/views.py:700 msgid "French" msgstr "" -#: windows/__init__.py:549 +#: windows/views.py:712 msgid "Locale" msgstr "" -#: windows/__init__.py:570 +#: windows/views.py:733 msgid "Edit Value" msgstr "" -#: windows/__init__.py:580 +#: windows/views.py:743 msgid "Syntax" msgstr "" -#: windows/__init__.py:637 +#: windows/views.py:800 msgid "Ok" msgstr "" -#: windows/__init__.py:668 +#: windows/views.py:831 msgid "PeterSQL" msgstr "" -#: windows/__init__.py:674 +#: windows/views.py:840 msgid "File" msgstr "" -#: windows/__init__.py:677 +#: windows/views.py:843 msgid "About" msgstr "" -#: windows/__init__.py:680 +#: windows/views.py:846 msgid "Help" msgstr "" -#: windows/__init__.py:685 +#: windows/views.py:851 msgid "Open connection manager" msgstr "" -#: windows/__init__.py:687 +#: windows/views.py:853 msgid "Disconnect from server" msgstr "" -#: windows/__init__.py:691 +#: windows/views.py:857 msgid "tool" msgstr "" -#: windows/__init__.py:691 +#: windows/views.py:857 msgid "Refresh" msgstr "" -#: windows/__init__.py:695 windows/__init__.py:697 +#: windows/views.py:861 windows/views.py:863 msgid "Add" msgstr "" -#: windows/__init__.py:731 windows/__init__.py:735 windows/__init__.py:1507 -#: windows/__init__.py:1603 +#: windows/views.py:897 windows/views.py:901 windows/views.py:2166 +#: windows/views.py:2654 msgid "MyMenuItem" msgstr "" -#: windows/__init__.py:738 windows/__init__.py:1236 windows/__init__.py:2476 +#: windows/views.py:904 windows/views.py:1769 windows/views.py:3336 msgid "MyMenu" msgstr "" -#: windows/__init__.py:753 +#: windows/views.py:919 windows/views.py:1350 windows/views.py:1357 +#: windows/views.py:1364 msgid "MyLabel" msgstr "" -#: windows/__init__.py:759 +#: windows/views.py:925 msgid "Databases" msgstr "" -#: windows/__init__.py:760 windows/__init__.py:822 windows/__init__.py:1959 -#: windows/__init__.py:1987 +#: windows/views.py:926 windows/views.py:1308 windows/views.py:2716 +#: windows/views.py:2744 msgid "Size" msgstr "" -#: windows/__init__.py:761 +#: windows/views.py:927 msgid "Elements" msgstr "" -#: windows/__init__.py:762 +#: windows/views.py:928 msgid "Modified at" msgstr "" -#: windows/__init__.py:763 windows/__init__.py:834 +#: windows/views.py:929 msgid "Tables" msgstr "" -#: windows/__init__.py:770 +#: windows/views.py:936 msgid "System" msgstr "" -#: windows/__init__.py:786 +#: windows/views.py:979 +msgid "Character set" +msgstr "" + +#: windows/components/dataview.py:43 windows/components/dataview.py:67 +#: windows/components/dataview.py:89 windows/views.py:1000 +#: windows/views.py:1312 windows/views.py:2980 +msgid "Collation" +msgstr "" + +#: windows/views.py:1026 windows/views.py:2862 +msgid "Encryption" +msgstr "" + +#: windows/views.py:1038 +msgid "Read Only" +msgstr "" + +#: windows/views.py:1055 +msgid "Tablespace" +msgstr "" + +#: windows/views.py:1076 +msgid "Connection limit" +msgstr "" + +#: windows/views.py:1119 +msgid "Profile" +msgstr "" + +#: windows/views.py:1145 +msgid "Default tablespace" +msgstr "" + +#: windows/views.py:1166 +msgid "Temporary tablespace" +msgstr "" + +#: windows/views.py:1192 +msgid "Quota" +msgstr "" + +#: windows/views.py:1211 +msgid "Unlimited quota" +msgstr "" + +#: windows/views.py:1228 +msgid "Account status" +msgstr "" + +#: windows/views.py:1249 +msgid "Password expire" +msgstr "" + +#: windows/views.py:1270 msgid "Table:" msgstr "" -#: windows/__init__.py:794 windows/__init__.py:1018 windows/__init__.py:1062 -#: windows/__init__.py:1168 windows/__init__.py:2408 +#: windows/views.py:1278 windows/views.py:1551 windows/views.py:1595 +#: windows/views.py:1701 windows/views.py:3268 msgid "Insert" msgstr "" -#: windows/__init__.py:799 +#: windows/views.py:1283 msgid "Clone" msgstr "" -#: windows/__init__.py:821 +#: windows/views.py:1307 msgid "Rows" msgstr "" -#: windows/__init__.py:824 windows/__init__.py:1989 +#: windows/views.py:1310 windows/views.py:2746 msgid "Updated at" msgstr "" -#: windows/__init__.py:826 windows/__init__.py:2120 -#: windows/components/dataview.py:43 windows/components/dataview.py:67 -#: windows/components/dataview.py:89 -msgid "Collation" +#: windows/views.py:1334 windows/views.py:1746 windows/views.py:2085 +#: windows/views.py:2140 +msgid "Apply" msgstr "" -#: windows/__init__.py:842 +#: windows/views.py:1344 windows/views.py:1503 windows/views.py:1956 +#: windows/views.py:3225 +msgid "Options" +msgstr "" + +#: windows/views.py:1375 msgid "Diagram" msgstr "" -#: windows/__init__.py:853 windows/__init__.py:1958 +#: windows/views.py:1386 windows/views.py:2715 msgid "Database" msgstr "" -#: windows/__init__.py:908 windows/__init__.py:2305 +#: windows/views.py:1441 windows/views.py:3165 msgid "Base" msgstr "" -#: windows/__init__.py:922 windows/__init__.py:2319 +#: windows/views.py:1455 windows/views.py:3179 msgid "Auto Increment" msgstr "" -#: windows/__init__.py:950 windows/__init__.py:2347 +#: windows/views.py:1483 windows/views.py:3207 msgid "Default Collation" msgstr "" -#: windows/__init__.py:970 windows/__init__.py:1301 windows/__init__.py:2365 -msgid "Options" -msgstr "" - -#: windows/__init__.py:982 windows/__init__.py:1023 windows/__init__.py:1067 +#: windows/views.py:1515 windows/views.py:1556 windows/views.py:1600 msgid "Remove" msgstr "" -#: windows/__init__.py:989 windows/__init__.py:1030 windows/__init__.py:1074 +#: windows/views.py:1522 windows/views.py:1563 windows/views.py:1607 msgid "Clear" msgstr "" -#: windows/__init__.py:1004 windows/__init__.py:2379 +#: windows/views.py:1537 windows/views.py:3239 msgid "Indexes" msgstr "" -#: windows/__init__.py:1048 +#: windows/views.py:1581 msgid "Foreign Keys" msgstr "" -#: windows/__init__.py:1092 +#: windows/views.py:1625 msgid "Checks" msgstr "" -#: windows/__init__.py:1160 windows/__init__.py:2400 +#: windows/views.py:1693 windows/views.py:3260 msgid "Columns:" msgstr "" -#: windows/__init__.py:1180 windows/__init__.py:2420 +#: windows/views.py:1713 windows/views.py:3280 msgid "Up" msgstr "" -#: windows/__init__.py:1187 windows/__init__.py:2427 +#: windows/views.py:1720 windows/views.py:3287 msgid "Down" msgstr "" -#: windows/__init__.py:1213 windows/__init__.py:1426 windows/__init__.py:1481 -msgid "Apply" -msgstr "" - -#: windows/__init__.py:1226 windows/__init__.py:1233 windows/__init__.py:2466 -#: windows/__init__.py:2473 +#: windows/views.py:1759 windows/views.py:1766 windows/views.py:3326 +#: windows/views.py:3333 msgid "Add Index" msgstr "" -#: windows/__init__.py:1230 windows/__init__.py:2470 +#: windows/views.py:1763 windows/views.py:3330 msgid "Add PrimaryKey" msgstr "" -#: windows/__init__.py:1247 +#: windows/views.py:1780 msgid "Table" msgstr "" -#: windows/__init__.py:1280 -msgid "Temporary" +#: windows/views.py:1816 +msgid "Definer" +msgstr "" + +#: windows/views.py:1836 +msgid "Schema" +msgstr "" + +#: windows/views.py:1862 +msgid "SQL security" +msgstr "" + +#: windows/views.py:1869 +msgid "DEFINER" +msgstr "" + +#: windows/views.py:1869 +msgid "INVOKER" +msgstr "" + +#: windows/views.py:1881 windows/views.py:2558 windows/views.py:2577 +#: windows/views.py:2820 +msgid "Algorithm" +msgstr "" + +#: windows/views.py:1883 windows/views.py:2543 windows/views.py:2576 +#: windows/views.py:2825 +msgid "UNDEFINED" +msgstr "" + +#: windows/views.py:1886 windows/views.py:2546 windows/views.py:2576 +#: windows/views.py:2828 +msgid "MERGE" +msgstr "" + +#: windows/views.py:1889 windows/views.py:2555 windows/views.py:2576 +#: windows/views.py:2831 +msgid "TEMPTABLE" +msgstr "" + +#: windows/views.py:1899 windows/views.py:2582 +msgid "View constraint" +msgstr "" + +#: windows/views.py:1901 windows/views.py:2581 +msgid "None" +msgstr "" + +#: windows/views.py:1904 windows/views.py:2581 +msgid "LOCAL" +msgstr "" + +#: windows/views.py:1907 +msgid "CASCADE" +msgstr "" + +#: windows/views.py:1910 +msgid "CHECK ONLY" +msgstr "" + +#: windows/views.py:1913 windows/views.py:2581 +msgid "READ ONLY" +msgstr "" + +#: windows/views.py:1925 +msgid "Force" +msgstr "" + +#: windows/views.py:1937 +msgid "Security barrier" msgstr "" -#: windows/__init__.py:1360 +#: windows/views.py:2019 msgid "Views" msgstr "" -#: windows/__init__.py:1368 +#: windows/views.py:2027 msgid "Triggers" msgstr "" -#: windows/__init__.py:1380 +#: windows/views.py:2039 #, python-format msgid "Table `%(database_name)s`.`%(table_name)s`: %(total_rows) rows total" msgstr "" -#: windows/__init__.py:1390 +#: windows/views.py:2049 msgid "Insert record" msgstr "" -#: windows/__init__.py:1395 +#: windows/views.py:2054 msgid "Duplicate record" msgstr "" -#: windows/__init__.py:1402 +#: windows/views.py:2061 msgid "Delete record" msgstr "" -#: windows/__init__.py:1412 +#: windows/views.py:2071 msgid "Apply changes automatically" msgstr "" -#: windows/__init__.py:1414 windows/__init__.py:1415 +#: windows/views.py:2073 windows/views.py:2074 msgid "" "If enabled, table edits are applied immediately without pressing Apply or" " Cancel" msgstr "" -#: windows/__init__.py:1436 +#: windows/views.py:2095 msgid "Next" msgstr "" -#: windows/__init__.py:1444 +#: windows/views.py:2103 msgid "Filters" msgstr "" -#: windows/__init__.py:1484 +#: windows/views.py:2143 msgid "CTRL+ENTER" msgstr "" -#: windows/__init__.py:1504 +#: windows/views.py:2163 msgid "Insert row" msgstr "" -#: windows/__init__.py:1512 +#: windows/views.py:2171 msgid "Data" msgstr "" -#: windows/__init__.py:1561 -msgid "Query" +#: windows/views.py:2225 windows/views.py:2275 +msgid "New" msgstr "" -#: windows/__init__.py:1581 -msgid "Close" +#: windows/views.py:2252 +msgid "Query" msgstr "" -#: windows/__init__.py:1584 windows/__init__.py:2019 -msgid "New" +#: windows/views.py:2272 +msgid "Close" msgstr "" -#: windows/__init__.py:1594 +#: windows/views.py:2285 msgid "Query #2" msgstr "" -#: windows/__init__.py:1835 +#: windows/views.py:2537 msgid "Column5" msgstr "" -#: windows/__init__.py:1842 +#: windows/views.py:2548 +msgid "Import" +msgstr "" + +#: windows/views.py:2573 +msgid "Read only" +msgstr "" + +#: windows/views.py:2581 +msgid "CASCADED" +msgstr "" + +#: windows/views.py:2581 +msgid "CHECK OPTION" +msgstr "" + +#: windows/views.py:2613 msgid "collapsible" msgstr "" -#: windows/__init__.py:1864 +#: windows/views.py:2629 msgid "Column3" msgstr "" -#: windows/__init__.py:1865 +#: windows/views.py:2630 msgid "Column4" msgstr "" -#: windows/__init__.py:1902 +#: windows/views.py:2673 msgid "" "Database " "(*.db;*.db3;*.sdb;*.s3db;*.sqlite;*.sqlite3)|*.db;*.db3;*.sdb;*.s3db;*.sqlite;*.sqlite3" msgstr "" -#: windows/__init__.py:1934 +#: windows/views.py:2685 msgid "Port" msgstr "" -#: windows/__init__.py:1951 +#: windows/views.py:2708 msgid "Usage" msgstr "" -#: windows/__init__.py:1962 +#: windows/views.py:2719 #, python-format msgid "%(total_rows)s" msgstr "" -#: windows/__init__.py:1967 +#: windows/views.py:2724 msgid "rows total" msgstr "" -#: windows/__init__.py:1986 +#: windows/views.py:2743 msgid "Lines" msgstr "" -#: windows/__init__.py:2068 +#: windows/views.py:2775 +msgid "Temporary" +msgstr "" + +#: windows/views.py:2786 +msgid "Engine options" +msgstr "" + +#: windows/views.py:2845 +msgid "RadioBtn" +msgstr "" + +#: windows/views.py:2928 msgid "Edit Column" msgstr "" -#: windows/__init__.py:2084 +#: windows/views.py:2944 msgid "Datatype" msgstr "" -#: windows/__init__.py:2099 windows/components/dataview.py:121 +#: windows/components/dataview.py:121 windows/views.py:2959 msgid "Length/Set" msgstr "" -#: windows/__init__.py:2138 windows/components/dataview.py:51 +#: windows/components/dataview.py:51 windows/views.py:2998 msgid "Unsigned" msgstr "" -#: windows/__init__.py:2144 windows/components/dataview.py:25 -#: windows/components/dataview.py:52 windows/components/dataview.py:75 +#: windows/components/dataview.py:25 windows/components/dataview.py:52 +#: windows/components/dataview.py:75 windows/views.py:3004 msgid "Allow NULL" msgstr "" -#: windows/__init__.py:2150 +#: windows/views.py:3010 msgid "Zero Fill" msgstr "" -#: windows/__init__.py:2161 windows/components/dataview.py:32 -#: windows/components/dataview.py:56 windows/components/dataview.py:78 +#: windows/components/dataview.py:32 windows/components/dataview.py:56 +#: windows/components/dataview.py:78 windows/views.py:3021 msgid "Default" msgstr "" -#: windows/__init__.py:2187 windows/components/dataview.py:36 -#: windows/components/dataview.py:60 windows/components/dataview.py:82 +#: windows/components/dataview.py:36 windows/components/dataview.py:60 +#: windows/components/dataview.py:82 windows/views.py:3047 msgid "Virtuality" msgstr "" -#: windows/__init__.py:2202 windows/components/dataview.py:39 -#: windows/components/dataview.py:63 windows/components/dataview.py:85 -#: windows/components/dataview.py:241 +#: windows/components/dataview.py:39 windows/components/dataview.py:63 +#: windows/components/dataview.py:85 windows/components/dataview.py:241 +#: windows/views.py:3062 msgid "Expression" msgstr "" @@ -619,101 +844,226 @@ msgstr "" msgid "Remove foreign key" msgstr "" -#: windows/components/popup.py:24 +#: windows/components/popup.py:26 msgid "No default value" msgstr "" -#: windows/components/popup.py:29 +#: windows/components/popup.py:31 msgid "NULL" msgstr "" -#: windows/components/popup.py:33 +#: windows/components/popup.py:35 msgid "AUTO INCREMENT" msgstr "" -#: windows/components/popup.py:37 +#: windows/components/popup.py:39 msgid "Text/Expression" msgstr "" -#: windows/connections/manager.py:125 +#: windows/dialogs/connections/view.py:119 windows/main/tabs/query.py:376 +msgid "Unknown error" +msgstr "" + +#: windows/dialogs/connections/view.py:394 +msgid "Connection established successfully" +msgstr "" + +#: windows/dialogs/connections/view.py:407 msgid "Confirm save" msgstr "" -#: windows/connections/manager.py:193 -msgid "Connection error" +#: windows/dialogs/connections/view.py:459 +msgid "You have unsaved changes. Do you want to save them before continuing?" +msgstr "" + +#: windows/dialogs/connections/view.py:461 +msgid "Unsaved changes" msgstr "" -#: windows/connections/manager.py:214 -msgid "connection" +#: windows/dialogs/connections/view.py:736 +msgid "" +"This connection cannot work without TLS. TLS has been enabled " +"automatically." +msgstr "" + +#: windows/dialogs/connections/view.py:762 +msgid "Connection error" msgstr "" -#: windows/connections/manager.py:215 windows/connections/manager.py:230 +#: windows/dialogs/connections/view.py:788 +#: windows/dialogs/connections/view.py:803 msgid "Confirm delete" msgstr "" -#: windows/connections/manager.py:229 -msgid "directory" +#: windows/main/controller.py:172 +msgid "days" msgstr "" -#: windows/connections/model.py:101 -msgid "New connection" +#: windows/main/controller.py:173 +msgid "hours" msgstr "" -#: windows/main/database.py:70 +#: windows/main/controller.py:174 +msgid "minutes" +msgstr "" + +#: windows/main/controller.py:175 +msgid "seconds" +msgstr "" + +#: windows/main/controller.py:183 +#, python-brace-format +msgid "Memory used: {used} ({percentage:.2%})" +msgstr "" + +#: windows/main/controller.py:219 +msgid "Settings saved successfully" +msgstr "" + +#: windows/main/controller.py:298 +msgid "Version" +msgstr "" + +#: windows/main/controller.py:300 +msgid "Uptime" +msgstr "" + +#: windows/main/controller.py:399 +#, python-brace-format +msgid "" +"Do you want to create a dump before dropping database '{database_name}'?\n" +"\n" +"Dump is not implemented yet.\n" +"- Yes: open dump flow (coming soon, no drop).\n" +"- No: drop the database now." +msgstr "" + +#: windows/main/controller.py:404 windows/main/controller.py:425 +msgid "Delete database" +msgstr "" + +#: windows/main/controller.py:410 +msgid "Dump is not implemented yet. No action has been performed." +msgstr "" + +#: windows/main/controller.py:411 +msgid "Dump not available" +msgstr "" + +#: windows/main/controller.py:424 +msgid "Database deletion is not supported by this engine." +msgstr "" + +#: windows/main/controller.py:439 +msgid "Database deleted successfully" +msgstr "" + +#: windows/main/controller.py:440 windows/main/tabs/view.py:253 +#: windows/main/tabs/view.py:279 +msgid "Success" +msgstr "" + +#: windows/main/controller.py:582 +msgid "Delete table" +msgstr "" + +#: windows/main/controller.py:699 +msgid "Do you want delete the records?" +msgstr "" + +#: windows/main/tabs/database.py:71 msgid "The connection to the database was lost." msgstr "" -#: windows/main/database.py:72 +#: windows/main/tabs/database.py:73 msgid "Do you want to reconnect?" msgstr "" -#: windows/main/database.py:74 +#: windows/main/tabs/database.py:75 msgid "Connection lost" msgstr "" -#: windows/main/database.py:83 +#: windows/main/tabs/database.py:85 msgid "Reconnection failed:" msgstr "" -#: windows/main/database.py:84 +#: windows/main/tabs/database.py:86 windows/main/tabs/query.py:450 +#: windows/main/tabs/view.py:256 windows/main/tabs/view.py:282 msgid "Error" msgstr "" -#: windows/main/main_frame.py:124 -msgid "days" +#: windows/main/tabs/query.py:305 +#, python-brace-format +msgid "{} rows affected" msgstr "" -#: windows/main/main_frame.py:125 -msgid "hours" +#: windows/main/tabs/query.py:309 windows/main/tabs/query.py:331 +#, python-brace-format +msgid "Query {}" msgstr "" -#: windows/main/main_frame.py:126 -msgid "minutes" +#: windows/main/tabs/query.py:314 +#, python-brace-format +msgid "Query {} (Error)" msgstr "" -#: windows/main/main_frame.py:127 -msgid "seconds" +#: windows/main/tabs/query.py:326 +#, python-brace-format +msgid "Query {} ({} rows × {} cols)" msgstr "" -#: windows/main/main_frame.py:135 +#: windows/main/tabs/query.py:353 #, python-brace-format -msgid "Memory used: {used} ({percentage:.2%})" +msgid "{} rows" msgstr "" -#: windows/main/main_frame.py:226 -msgid "Version" +#: windows/main/tabs/query.py:355 +#, python-brace-format +msgid "{:.1f} ms" msgstr "" -#: windows/main/main_frame.py:228 -msgid "Uptime" +#: windows/main/tabs/query.py:358 +#, python-brace-format +msgid "{} warnings" msgstr "" -#: windows/main/main_frame.py:431 -msgid "Delete table" +#: windows/main/tabs/query.py:370 +msgid "Error:" msgstr "" -#: windows/main/main_frame.py:586 -msgid "Do you want delete the records?" +#: windows/main/tabs/query.py:449 +msgid "No active database connection" +msgstr "" + +#: windows/main/tabs/view.py:252 +msgid "View created successfully" +msgstr "" + +#: windows/main/tabs/view.py:252 +msgid "View updated successfully" +msgstr "" + +#: windows/main/tabs/view.py:256 +#, python-brace-format +msgid "Error saving view: {}" +msgstr "" + +#: windows/main/tabs/view.py:269 +#, python-brace-format +msgid "Are you sure you want to delete view '{}'?" +msgstr "" + +#: windows/main/tabs/view.py:270 +msgid "Confirm Delete" +msgstr "" + +#: windows/main/tabs/view.py:279 +msgid "View deleted successfully" +msgstr "" + +#: windows/main/tabs/view.py:282 +#, python-brace-format +msgid "Error deleting view: {}" msgstr "" #~ msgid "Created at:" @@ -746,3 +1096,12 @@ msgstr "" #~ msgid "Foreign Key" #~ msgstr "" +#~ msgid "New Session" +#~ msgstr "" + +#~ msgid "connection" +#~ msgstr "" + +#~ msgid "directory" +#~ msgstr "" + diff --git a/locale/es_ES/LC_MESSAGES/petersql.mo b/locale/es_ES/LC_MESSAGES/petersql.mo index 0913f7b..eca2649 100644 Binary files a/locale/es_ES/LC_MESSAGES/petersql.mo and b/locale/es_ES/LC_MESSAGES/petersql.mo differ diff --git a/locale/es_ES/LC_MESSAGES/petersql.po b/locale/es_ES/LC_MESSAGES/petersql.po index 2eb83b6..9cf4c67 100644 --- a/locale/es_ES/LC_MESSAGES/petersql.po +++ b/locale/es_ES/LC_MESSAGES/petersql.po @@ -1,492 +1,723 @@ -# Spanish translations for petersql. -# Copyright (C) 2024 -# This file is distributed under the same license as the petersql package. +# Español (es_ES) translations for PeterSQL. +# Copyright (C) 2026 ORGANIZATION +# This file is distributed under the same license as the PeterSQL project. # +#, fuzzy msgid "" msgstr "" -"Language: es\n" -"Content-Type: text/plain; charset=UTF-8\n" +"Project-Id-Version: PeterSQL 0.1.0\n" +"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" +"POT-Creation-Date: 2026-03-10 18:23+0100\n" +"PO-Revision-Date: 2026-03-10 18:21+0000\n" +"Last-Translator: \n" +"Language: es_ES\n" +"Language-Team: es_ES \n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Generated-By: Babel 2.18.0\n" -#: helpers/__init__.py:14 +#: helpers/__init__.py:16 msgctxt "unit" msgid "B" msgstr "B" -#: helpers/__init__.py:15 +#: helpers/__init__.py:17 msgctxt "unit" msgid "KB" msgstr "KB" -#: helpers/__init__.py:16 +#: helpers/__init__.py:18 msgctxt "unit" msgid "MB" msgstr "MB" -#: helpers/__init__.py:17 +#: helpers/__init__.py:19 msgctxt "unit" msgid "GB" msgstr "GB" -#: helpers/__init__.py:18 +#: helpers/__init__.py:20 msgctxt "unit" msgid "TB" msgstr "TB" -#: structures/ssh_tunnel.py:117 +#: structures/ssh_tunnel.py:166 msgid "OpenSSH client not found." msgstr "Cliente OpenSSH no encontrado." -#: windows/__init__.py:31 windows/main/main_frame.py:224 +#: windows/dialogs/connections/view.py:395 +#: windows/dialogs/connections/view.py:738 windows/main/controller.py:296 +#: windows/views.py:33 msgid "Connection" msgstr "Conexión" -#: windows/__init__.py:45 windows/__init__.py:83 windows/__init__.py:820 -#: windows/__init__.py:880 windows/__init__.py:1267 windows/__init__.py:1950 -#: windows/__init__.py:1973 windows/__init__.py:1974 windows/__init__.py:1975 -#: windows/__init__.py:1976 windows/__init__.py:1977 windows/__init__.py:1978 -#: windows/__init__.py:1979 windows/__init__.py:1980 windows/__init__.py:1981 -#: windows/__init__.py:1985 windows/__init__.py:2076 windows/__init__.py:2277 #: windows/components/dataview.py:113 windows/components/dataview.py:225 #: windows/components/dataview.py:238 windows/components/dataview.py:253 +#: windows/views.py:47 windows/views.py:97 windows/views.py:956 +#: windows/views.py:1306 windows/views.py:1413 windows/views.py:1796 +#: windows/views.py:2707 windows/views.py:2730 windows/views.py:2731 +#: windows/views.py:2732 windows/views.py:2733 windows/views.py:2734 +#: windows/views.py:2735 windows/views.py:2736 windows/views.py:2737 +#: windows/views.py:2738 windows/views.py:2742 windows/views.py:2936 +#: windows/views.py:3137 msgid "Name" msgstr "Nombre" -#: windows/__init__.py:46 windows/__init__.py:322 +#: windows/views.py:48 windows/views.py:381 msgid "Last connection" msgstr "Última conexión" -#: windows/__init__.py:59 windows/connections/manager.py:174 +#: windows/dialogs/connections/view.py:631 windows/views.py:61 msgid "New directory" msgstr "Nuevo directorio" -#: windows/__init__.py:62 -msgid "New Session" -msgstr "Nueva sesión" +#: windows/dialogs/connections/model.py:187 +#: windows/dialogs/connections/view.py:591 windows/views.py:65 +msgid "New connection" +msgstr "Nueva conexión" + +#: windows/views.py:71 +#, fuzzy +msgid "Rename" +msgstr "Nombre" -#: windows/__init__.py:67 -msgid "Import" -msgstr "Importar" +#: windows/views.py:76 +#, fuzzy +msgid "Clone connection" +msgstr "Nueva conexión" + +#: windows/views.py:81 windows/views.py:556 windows/views.py:1290 +#: windows/views.py:1331 windows/views.py:1706 windows/views.py:1738 +#: windows/views.py:1997 windows/views.py:3273 windows/views.py:3305 +msgid "Delete" +msgstr "Eliminar" -#: windows/__init__.py:97 windows/__init__.py:825 windows/__init__.py:935 -#: windows/__init__.py:1990 windows/__init__.py:2332 +#: windows/views.py:111 windows/views.py:1311 windows/views.py:1468 +#: windows/views.py:2747 windows/views.py:3192 msgid "Engine" msgstr "Motor" -#: windows/__init__.py:118 +#: windows/views.py:132 msgid "Host + port" msgstr "Host + puerto" -#: windows/__init__.py:134 +#: windows/views.py:148 msgid "Username" msgstr "Nombre de usuario" -#: windows/__init__.py:147 +#: windows/views.py:161 windows/views.py:1100 msgid "Password" msgstr "Contraseña" -#: windows/__init__.py:163 +#: windows/views.py:177 +msgid "Use TLS" +msgstr "Usar TLS" + +#: windows/views.py:180 msgid "Use SSH tunnel" msgstr "Usar túnel SSH" -#: windows/__init__.py:185 windows/__init__.py:1897 +#: windows/views.py:202 windows/views.py:2668 msgid "Filename" msgstr "Nombre de archivo" -#: windows/__init__.py:190 windows/__init__.py:1902 +#: windows/views.py:207 windows/views.py:324 windows/views.py:2673 +#: windows/views.py:2856 msgid "Select a file" msgstr "Seleccionar un archivo" -#: windows/__init__.py:190 -msgid "*. *" +#: windows/views.py:207 windows/views.py:324 windows/views.py:2856 +#, fuzzy +msgid "*.*" msgstr "*. *" -#: windows/__init__.py:204 windows/__init__.py:827 windows/__init__.py:893 -#: windows/__init__.py:1991 windows/__init__.py:2174 windows/__init__.py:2290 #: windows/components/dataview.py:70 windows/components/dataview.py:92 +#: windows/views.py:221 windows/views.py:1313 windows/views.py:1426 +#: windows/views.py:2748 windows/views.py:3034 windows/views.py:3150 msgid "Comments" msgstr "Comentarios" -#: windows/__init__.py:218 windows/__init__.py:520 +#: windows/main/controller.py:219 windows/views.py:235 windows/views.py:683 +#: windows/views.py:837 msgid "Settings" msgstr "Configuraciones" -#: windows/__init__.py:227 +#: windows/views.py:244 msgid "SSH executable" msgstr "Ejecutable SSH" -#: windows/__init__.py:232 +#: windows/views.py:249 msgid "ssh" msgstr "ssh" -#: windows/__init__.py:240 +#: windows/views.py:257 msgid "SSH host + port" msgstr "Host SSH + puerto" -#: windows/__init__.py:256 +#: windows/views.py:269 +msgid "SSH host + port (the SSH server that forwards traffic to the DB)" +msgstr "Host SSH + puerto (el servidor SSH que reenvía el tráfico a la BD)" + +#: windows/views.py:278 msgid "SSH username" msgstr "Nombre de usuario SSH" -#: windows/__init__.py:269 +#: windows/views.py:291 msgid "SSH password" msgstr "Contraseña SSH" -#: windows/__init__.py:282 +#: windows/views.py:304 msgid "Local port" msgstr "Puerto local" -#: windows/__init__.py:288 +#: windows/views.py:310 msgid "if the value is set to 0, the first available port will be used" msgstr "si el valor se establece en 0, se utilizará el primer puerto disponible" -#: windows/__init__.py:299 +#: windows/views.py:319 +msgid "Identity file" +msgstr "Archivo de identidad" + +#: windows/views.py:335 +#, fuzzy +msgid "Remote host + port" +msgstr "Host + puerto" + +#: windows/views.py:347 +msgid "Remote host/port is the real DB target (defaults to DB Host/Port)." +msgstr "Host/puerto remoto es el objetivo real de la BD (por defecto Host/Puerto BD)." + +#: windows/views.py:358 msgid "SSH Tunnel" msgstr "Túnel SSH" -#: windows/__init__.py:305 windows/__init__.py:823 windows/__init__.py:1988 +#: windows/views.py:364 windows/views.py:1309 windows/views.py:2745 msgid "Created at" msgstr "Creado en" -#: windows/__init__.py:339 +#: windows/views.py:398 msgid "Successful connections" msgstr "Conexiones exitosas" -#: windows/__init__.py:356 +#: windows/views.py:415 +#, fuzzy +msgid "Last successful connection" +msgstr "Conexiones exitosas" + +#: windows/views.py:432 msgid "Unsuccessful connections" msgstr "Conexiones fallidas" -#: windows/__init__.py:375 +#: windows/views.py:449 +msgid "Last failure reason" +msgstr "" + +#: windows/views.py:466 +#, fuzzy +msgid "Total connection attempts" +msgstr "Última conexión" + +#: windows/views.py:483 +#, fuzzy +msgid " Average connection time (ms)" +msgstr "Reconexión fallida:" + +#: windows/views.py:500 +#, fuzzy +msgid " Most recent connection duration" +msgstr "Abrir administrador de conexiones" + +#: windows/views.py:519 msgid "Statistics" msgstr "Estadísticas" -#: windows/__init__.py:393 windows/__init__.py:1139 +#: windows/views.py:537 windows/views.py:1672 msgid "Create" msgstr "Crear" -#: windows/__init__.py:403 windows/__init__.py:806 windows/__init__.py:1173 -#: windows/__init__.py:1205 windows/__init__.py:1340 windows/__init__.py:2413 -#: windows/__init__.py:2445 -msgid "Delete" -msgstr "Eliminar" +#: windows/views.py:541 +#, fuzzy +msgid "Create connection" +msgstr "Última conexión" -#: windows/__init__.py:420 windows/__init__.py:634 windows/__init__.py:1208 -#: windows/__init__.py:1343 windows/__init__.py:1419 windows/__init__.py:2221 -#: windows/__init__.py:2448 +#: windows/views.py:544 +#, fuzzy +msgid "Create directory" +msgstr "Nuevo directorio" + +#: windows/views.py:573 windows/views.py:797 windows/views.py:1328 +#: windows/views.py:1741 windows/views.py:2002 windows/views.py:2078 +#: windows/views.py:3081 windows/views.py:3308 msgid "Cancel" msgstr "Cancelar" -#: windows/__init__.py:425 windows/__init__.py:1348 windows/__init__.py:2231 -#: windows/__init__.py:2453 +#: windows/views.py:578 windows/views.py:2007 windows/views.py:3091 +#: windows/views.py:3313 msgid "Save" msgstr "Guardar" -#: windows/__init__.py:432 +#: windows/views.py:585 msgid "Test" msgstr "Probar" -#: windows/__init__.py:439 +#: windows/views.py:592 msgid "Connect" msgstr "Conectar" -#: windows/__init__.py:532 +#: windows/views.py:695 msgid "Language" msgstr "Idioma" -#: windows/__init__.py:537 +#: windows/views.py:700 msgid "English" msgstr "Inglés" -#: windows/__init__.py:537 +#: windows/views.py:700 msgid "Italian" msgstr "Italiano" -#: windows/__init__.py:537 +#: windows/views.py:700 msgid "French" msgstr "Francés" -#: windows/__init__.py:549 +#: windows/views.py:712 msgid "Locale" msgstr "Localización" -#: windows/__init__.py:570 +#: windows/views.py:733 msgid "Edit Value" msgstr "Editar valor" -#: windows/__init__.py:580 +#: windows/views.py:743 msgid "Syntax" msgstr "Sintaxis" -#: windows/__init__.py:637 +#: windows/views.py:800 msgid "Ok" msgstr "Ok" -#: windows/__init__.py:668 +#: windows/views.py:831 msgid "PeterSQL" msgstr "PeterSQL" -#: windows/__init__.py:674 +#: windows/views.py:840 msgid "File" msgstr "Archivo" -#: windows/__init__.py:677 +#: windows/views.py:843 msgid "About" msgstr "Acerca de" -#: windows/__init__.py:680 +#: windows/views.py:846 msgid "Help" msgstr "Ayuda" -#: windows/__init__.py:685 +#: windows/views.py:851 msgid "Open connection manager" msgstr "Abrir administrador de conexiones" -#: windows/__init__.py:687 +#: windows/views.py:853 msgid "Disconnect from server" msgstr "Desconectar del servidor" -#: windows/__init__.py:691 +#: windows/views.py:857 msgid "tool" msgstr "herramienta" -#: windows/__init__.py:691 +#: windows/views.py:857 msgid "Refresh" msgstr "Actualizar" -#: windows/__init__.py:695 windows/__init__.py:697 +#: windows/views.py:861 windows/views.py:863 msgid "Add" msgstr "Agregar" -#: windows/__init__.py:731 windows/__init__.py:735 windows/__init__.py:1507 -#: windows/__init__.py:1603 +#: windows/views.py:897 windows/views.py:901 windows/views.py:2166 +#: windows/views.py:2654 msgid "MyMenuItem" msgstr "MiElementoMenu" -#: windows/__init__.py:738 windows/__init__.py:1236 windows/__init__.py:2476 +#: windows/views.py:904 windows/views.py:1769 windows/views.py:3336 msgid "MyMenu" msgstr "MiMenu" -#: windows/__init__.py:753 +#: windows/views.py:919 windows/views.py:1350 windows/views.py:1357 +#: windows/views.py:1364 msgid "MyLabel" msgstr "MiEtiqueta" -#: windows/__init__.py:759 +#: windows/views.py:925 msgid "Databases" msgstr "Bases de datos" -#: windows/__init__.py:760 windows/__init__.py:822 windows/__init__.py:1959 -#: windows/__init__.py:1987 +#: windows/views.py:926 windows/views.py:1308 windows/views.py:2716 +#: windows/views.py:2744 msgid "Size" msgstr "Tamaño" -#: windows/__init__.py:761 +#: windows/views.py:927 msgid "Elements" msgstr "Elementos" -#: windows/__init__.py:762 +#: windows/views.py:928 msgid "Modified at" msgstr "Modificado en" -#: windows/__init__.py:763 windows/__init__.py:834 +#: windows/views.py:929 msgid "Tables" msgstr "Tablas" -#: windows/__init__.py:770 +#: windows/views.py:936 msgid "System" msgstr "Sistema" -#: windows/__init__.py:786 +#: windows/views.py:979 +#, fuzzy +msgid "Character set" +msgstr "Creado en" + +#: windows/components/dataview.py:43 windows/components/dataview.py:67 +#: windows/components/dataview.py:89 windows/views.py:1000 +#: windows/views.py:1312 windows/views.py:2980 +msgid "Collation" +msgstr "Intercalación" + +#: windows/views.py:1026 windows/views.py:2862 +msgid "Encryption" +msgstr "" + +#: windows/views.py:1038 +msgid "Read Only" +msgstr "" + +#: windows/views.py:1055 +#, fuzzy +msgid "Tablespace" +msgstr "Tablas" + +#: windows/views.py:1076 +#, fuzzy +msgid "Connection limit" +msgstr "Conexión perdida" + +#: windows/views.py:1119 +#, fuzzy +msgid "Profile" +msgstr "Archivo" + +#: windows/views.py:1145 +#, fuzzy +msgid "Default tablespace" +msgstr "Eliminar tabla" + +#: windows/views.py:1166 +#, fuzzy +msgid "Temporary tablespace" +msgstr "Temporal" + +#: windows/views.py:1192 +msgid "Quota" +msgstr "" + +#: windows/views.py:1211 +msgid "Unlimited quota" +msgstr "" + +#: windows/views.py:1228 +msgid "Account status" +msgstr "" + +#: windows/views.py:1249 +#, fuzzy +msgid "Password expire" +msgstr "Contraseña" + +#: windows/views.py:1270 msgid "Table:" msgstr "Tabla:" -#: windows/__init__.py:794 windows/__init__.py:1018 windows/__init__.py:1062 -#: windows/__init__.py:1168 windows/__init__.py:2408 +#: windows/views.py:1278 windows/views.py:1551 windows/views.py:1595 +#: windows/views.py:1701 windows/views.py:3268 msgid "Insert" msgstr "Insertar" -#: windows/__init__.py:799 +#: windows/views.py:1283 msgid "Clone" msgstr "Clonar" -#: windows/__init__.py:821 +#: windows/views.py:1307 msgid "Rows" msgstr "Filas" -#: windows/__init__.py:824 windows/__init__.py:1989 +#: windows/views.py:1310 windows/views.py:2746 msgid "Updated at" msgstr "Actualizado en" -#: windows/__init__.py:826 windows/__init__.py:2120 -#: windows/components/dataview.py:43 windows/components/dataview.py:67 -#: windows/components/dataview.py:89 -msgid "Collation" -msgstr "Intercalación" +#: windows/views.py:1334 windows/views.py:1746 windows/views.py:2085 +#: windows/views.py:2140 +msgid "Apply" +msgstr "Aplicar" + +#: windows/views.py:1344 windows/views.py:1503 windows/views.py:1956 +#: windows/views.py:3225 +msgid "Options" +msgstr "Opciones" -#: windows/__init__.py:842 +#: windows/views.py:1375 msgid "Diagram" msgstr "Diagrama" -#: windows/__init__.py:853 windows/__init__.py:1958 +#: windows/views.py:1386 windows/views.py:2715 msgid "Database" msgstr "Base de datos" -#: windows/__init__.py:908 windows/__init__.py:2305 +#: windows/views.py:1441 windows/views.py:3165 msgid "Base" msgstr "Base" -#: windows/__init__.py:922 windows/__init__.py:2319 +#: windows/views.py:1455 windows/views.py:3179 msgid "Auto Increment" msgstr "Auto incremento" -#: windows/__init__.py:950 windows/__init__.py:2347 +#: windows/views.py:1483 windows/views.py:3207 msgid "Default Collation" msgstr "Intercalación predeterminada" -#: windows/__init__.py:970 windows/__init__.py:1301 windows/__init__.py:2365 -msgid "Options" -msgstr "Opciones" - -#: windows/__init__.py:982 windows/__init__.py:1023 windows/__init__.py:1067 +#: windows/views.py:1515 windows/views.py:1556 windows/views.py:1600 msgid "Remove" msgstr "Eliminar" -#: windows/__init__.py:989 windows/__init__.py:1030 windows/__init__.py:1074 +#: windows/views.py:1522 windows/views.py:1563 windows/views.py:1607 msgid "Clear" msgstr "Limpiar" -#: windows/__init__.py:1004 windows/__init__.py:2379 +#: windows/views.py:1537 windows/views.py:3239 msgid "Indexes" msgstr "Índices" -#: windows/__init__.py:1048 +#: windows/views.py:1581 msgid "Foreign Keys" msgstr "Claves foráneas" -#: windows/__init__.py:1092 +#: windows/views.py:1625 msgid "Checks" msgstr "Comprobaciones" -#: windows/__init__.py:1160 windows/__init__.py:2400 +#: windows/views.py:1693 windows/views.py:3260 msgid "Columns:" msgstr "Columnas:" -#: windows/__init__.py:1180 windows/__init__.py:2420 +#: windows/views.py:1713 windows/views.py:3280 msgid "Up" msgstr "Arriba" -#: windows/__init__.py:1187 windows/__init__.py:2427 +#: windows/views.py:1720 windows/views.py:3287 msgid "Down" msgstr "Abajo" -#: windows/__init__.py:1213 windows/__init__.py:1426 windows/__init__.py:1481 -msgid "Apply" -msgstr "Aplicar" - -#: windows/__init__.py:1226 windows/__init__.py:1233 windows/__init__.py:2466 -#: windows/__init__.py:2473 +#: windows/views.py:1759 windows/views.py:1766 windows/views.py:3326 +#: windows/views.py:3333 msgid "Add Index" msgstr "Agregar índice" -#: windows/__init__.py:1230 windows/__init__.py:2470 +#: windows/views.py:1763 windows/views.py:3330 msgid "Add PrimaryKey" msgstr "Agregar clave primaria" -#: windows/__init__.py:1247 +#: windows/views.py:1780 msgid "Table" msgstr "Tabla" -#: windows/__init__.py:1280 -msgid "Temporary" -msgstr "Temporal" +#: windows/views.py:1816 +#, fuzzy +msgid "Definer" +msgstr "Insertar" + +#: windows/views.py:1836 +msgid "Schema" +msgstr "" + +#: windows/views.py:1862 +msgid "SQL security" +msgstr "" + +#: windows/views.py:1869 +#, fuzzy +msgid "DEFINER" +msgstr "Insertar" + +#: windows/views.py:1869 +#, fuzzy +msgid "INVOKER" +msgstr "Insertar" + +#: windows/views.py:1881 windows/views.py:2558 windows/views.py:2577 +#: windows/views.py:2820 +msgid "Algorithm" +msgstr "" -#: windows/__init__.py:1360 +#: windows/views.py:1883 windows/views.py:2543 windows/views.py:2576 +#: windows/views.py:2825 +#, fuzzy +msgid "UNDEFINED" +msgstr "Sin signo" + +#: windows/views.py:1886 windows/views.py:2546 windows/views.py:2576 +#: windows/views.py:2828 +msgid "MERGE" +msgstr "" + +#: windows/views.py:1889 windows/views.py:2555 windows/views.py:2576 +#: windows/views.py:2831 +#, fuzzy +msgid "TEMPTABLE" +msgstr "Tabla" + +#: windows/views.py:1899 windows/views.py:2582 +msgid "View constraint" +msgstr "" + +#: windows/views.py:1901 windows/views.py:2581 +#, fuzzy +msgid "None" +msgstr "Clonar" + +#: windows/views.py:1904 windows/views.py:2581 +#, fuzzy +msgid "LOCAL" +msgstr "Localización" + +#: windows/views.py:1907 +#, fuzzy +msgid "CASCADE" +msgstr "Cancelar" + +#: windows/views.py:1910 +#, fuzzy +msgid "CHECK ONLY" +msgstr "Verificar" + +#: windows/views.py:1913 windows/views.py:2581 +msgid "READ ONLY" +msgstr "" + +#: windows/views.py:1925 +msgid "Force" +msgstr "" + +#: windows/views.py:1937 +msgid "Security barrier" +msgstr "" + +#: windows/views.py:2019 msgid "Views" msgstr "Vistas" -#: windows/__init__.py:1368 +#: windows/views.py:2027 msgid "Triggers" msgstr "Disparadores" -#: windows/__init__.py:1380 +#: windows/views.py:2039 #, python-format msgid "Table `%(database_name)s`.`%(table_name)s`: %(total_rows) rows total" msgstr "Tabla `%(database_name)s`.`%(table_name)s`: %(total_rows) filas en total" -#: windows/__init__.py:1390 +#: windows/views.py:2049 msgid "Insert record" msgstr "Insertar registro" -#: windows/__init__.py:1395 +#: windows/views.py:2054 msgid "Duplicate record" msgstr "Duplicar registro" -#: windows/__init__.py:1402 +#: windows/views.py:2061 msgid "Delete record" msgstr "Eliminar registro" -#: windows/__init__.py:1412 +#: windows/views.py:2071 msgid "Apply changes automatically" msgstr "Aplicar cambios automáticamente" -#: windows/__init__.py:1414 windows/__init__.py:1415 +#: windows/views.py:2073 windows/views.py:2074 msgid "" "If enabled, table edits are applied immediately without pressing Apply or" " Cancel" msgstr "" -"Si está habilitado, las ediciones de la tabla se aplican inmediatamente sin presionar Aplicar o" -" Cancelar" +"Si está habilitado, las ediciones de la tabla se aplican inmediatamente " +"sin presionar Aplicar o Cancelar" -#: windows/__init__.py:1436 +#: windows/views.py:2095 msgid "Next" msgstr "Siguiente" -#: windows/__init__.py:1444 +#: windows/views.py:2103 msgid "Filters" msgstr "Filtros" -#: windows/__init__.py:1484 +#: windows/views.py:2143 msgid "CTRL+ENTER" msgstr "CTRL+ENTER" -#: windows/__init__.py:1504 +#: windows/views.py:2163 msgid "Insert row" msgstr "Insertar fila" -#: windows/__init__.py:1512 +#: windows/views.py:2171 msgid "Data" msgstr "Datos" -#: windows/__init__.py:1561 +#: windows/views.py:2225 windows/views.py:2275 +msgid "New" +msgstr "Nuevo" + +#: windows/views.py:2252 msgid "Query" msgstr "Consulta" -#: windows/__init__.py:1581 +#: windows/views.py:2272 msgid "Close" msgstr "Cerrar" -#: windows/__init__.py:1584 windows/__init__.py:2019 -msgid "New" -msgstr "Nuevo" - -#: windows/__init__.py:1594 +#: windows/views.py:2285 msgid "Query #2" msgstr "Consulta #2" -#: windows/__init__.py:1835 +#: windows/views.py:2537 msgid "Column5" msgstr "Columna5" -#: windows/__init__.py:1842 +#: windows/views.py:2548 +msgid "Import" +msgstr "Importar" + +#: windows/views.py:2573 +msgid "Read only" +msgstr "" + +#: windows/views.py:2581 +msgid "CASCADED" +msgstr "" + +#: windows/views.py:2581 +#, fuzzy +msgid "CHECK OPTION" +msgstr "conexión" + +#: windows/views.py:2613 msgid "collapsible" msgstr "colapsable" -#: windows/__init__.py:1864 +#: windows/views.py:2629 msgid "Column3" msgstr "Columna3" -#: windows/__init__.py:1865 +#: windows/views.py:2630 msgid "Column4" msgstr "Columna4" -#: windows/__init__.py:1902 +#: windows/views.py:2673 msgid "" "Database " "(*.db;*.db3;*.sdb;*.s3db;*.sqlite;*.sqlite3)|*.db;*.db3;*.sdb;*.s3db;*.sqlite;*.sqlite3" @@ -494,65 +725,78 @@ msgstr "" "Database " "(*.db;*.db3;*.sdb;*.s3db;*.sqlite;*.sqlite3)|*.db;*.db3;*.sdb;*.s3db;*.sqlite;*.sqlite3" -#: windows/__init__.py:1934 +#: windows/views.py:2685 msgid "Port" msgstr "Puerto" -#: windows/__init__.py:1951 +#: windows/views.py:2708 msgid "Usage" msgstr "Uso" -#: windows/__init__.py:1962 +#: windows/views.py:2719 #, python-format msgid "%(total_rows)s" msgstr "%(total_rows)s" -#: windows/__init__.py:1967 +#: windows/views.py:2724 msgid "rows total" msgstr "filas en total" -#: windows/__init__.py:1986 +#: windows/views.py:2743 msgid "Lines" msgstr "Líneas" -#: windows/__init__.py:2068 +#: windows/views.py:2775 +msgid "Temporary" +msgstr "Temporal" + +#: windows/views.py:2786 +#, fuzzy +msgid "Engine options" +msgstr "Opciones" + +#: windows/views.py:2845 +msgid "RadioBtn" +msgstr "" + +#: windows/views.py:2928 msgid "Edit Column" msgstr "Editar columna" -#: windows/__init__.py:2084 +#: windows/views.py:2944 msgid "Datatype" msgstr "Tipo de datos" -#: windows/__init__.py:2099 windows/components/dataview.py:121 +#: windows/components/dataview.py:121 windows/views.py:2959 msgid "Length/Set" msgstr "Longitud/Conjunto" -#: windows/__init__.py:2138 windows/components/dataview.py:51 +#: windows/components/dataview.py:51 windows/views.py:2998 msgid "Unsigned" msgstr "Sin signo" -#: windows/__init__.py:2144 windows/components/dataview.py:25 -#: windows/components/dataview.py:52 windows/components/dataview.py:75 +#: windows/components/dataview.py:25 windows/components/dataview.py:52 +#: windows/components/dataview.py:75 windows/views.py:3004 msgid "Allow NULL" msgstr "Permitir NULL" -#: windows/__init__.py:2150 +#: windows/views.py:3010 msgid "Zero Fill" msgstr "Relleno cero" -#: windows/__init__.py:2161 windows/components/dataview.py:32 -#: windows/components/dataview.py:56 windows/components/dataview.py:78 +#: windows/components/dataview.py:32 windows/components/dataview.py:56 +#: windows/components/dataview.py:78 windows/views.py:3021 msgid "Default" msgstr "Predeterminado" -#: windows/__init__.py:2187 windows/components/dataview.py:36 -#: windows/components/dataview.py:60 windows/components/dataview.py:82 +#: windows/components/dataview.py:36 windows/components/dataview.py:60 +#: windows/components/dataview.py:82 windows/views.py:3047 msgid "Virtuality" msgstr "Virtualidad" -#: windows/__init__.py:2202 windows/components/dataview.py:39 -#: windows/components/dataview.py:63 windows/components/dataview.py:85 -#: windows/components/dataview.py:241 +#: windows/components/dataview.py:39 windows/components/dataview.py:63 +#: windows/components/dataview.py:85 windows/components/dataview.py:241 +#: windows/views.py:3062 msgid "Expression" msgstr "Expresión" @@ -632,103 +876,232 @@ msgstr "Agregar clave foránea" msgid "Remove foreign key" msgstr "Eliminar clave foránea" -#: windows/components/popup.py:24 +#: windows/components/popup.py:26 msgid "No default value" msgstr "Sin valor predeterminado" -#: windows/components/popup.py:29 +#: windows/components/popup.py:31 msgid "NULL" msgstr "NULL" -#: windows/components/popup.py:33 +#: windows/components/popup.py:35 msgid "AUTO INCREMENT" msgstr "AUTO INCREMENTO" -#: windows/components/popup.py:37 +#: windows/components/popup.py:39 msgid "Text/Expression" msgstr "Texto/Expresión" -#: windows/connections/manager.py:125 +#: windows/dialogs/connections/view.py:119 windows/main/tabs/query.py:376 +msgid "Unknown error" +msgstr "" + +#: windows/dialogs/connections/view.py:394 +msgid "Connection established successfully" +msgstr "" + +#: windows/dialogs/connections/view.py:407 msgid "Confirm save" msgstr "Confirmar guardar" -#: windows/connections/manager.py:193 +#: windows/dialogs/connections/view.py:459 +msgid "You have unsaved changes. Do you want to save them before continuing?" +msgstr "" + +#: windows/dialogs/connections/view.py:461 +msgid "Unsaved changes" +msgstr "" + +#: windows/dialogs/connections/view.py:736 +msgid "" +"This connection cannot work without TLS. TLS has been enabled " +"automatically." +msgstr "" + +#: windows/dialogs/connections/view.py:762 msgid "Connection error" msgstr "Error de conexión" -#: windows/connections/manager.py:214 -msgid "connection" -msgstr "conexión" - -#: windows/connections/manager.py:215 windows/connections/manager.py:230 +#: windows/dialogs/connections/view.py:788 +#: windows/dialogs/connections/view.py:803 msgid "Confirm delete" msgstr "Confirmar eliminar" -#: windows/connections/manager.py:229 -msgid "directory" -msgstr "directorio" - -#: windows/connections/model.py:101 -msgid "New connection" -msgstr "Nueva conexión" - -#: windows/main/database.py:70 -msgid "The connection to the database was lost." -msgstr "Se perdió la conexión a la base de datos." - -#: windows/main/database.py:72 -msgid "Do you want to reconnect?" -msgstr "¿Quieres reconectar?" - -#: windows/main/database.py:74 -msgid "Connection lost" -msgstr "Conexión perdida" - -#: windows/main/database.py:83 -msgid "Reconnection failed:" -msgstr "Reconexión fallida:" - -#: windows/main/database.py:84 -msgid "Error" -msgstr "Error" - -#: windows/main/main_frame.py:124 +#: windows/main/controller.py:172 msgid "days" msgstr "días" -#: windows/main/main_frame.py:125 +#: windows/main/controller.py:173 msgid "hours" msgstr "horas" -#: windows/main/main_frame.py:126 +#: windows/main/controller.py:174 msgid "minutes" msgstr "minutos" -#: windows/main/main_frame.py:127 +#: windows/main/controller.py:175 msgid "seconds" msgstr "segundos" -#: windows/main/main_frame.py:135 +#: windows/main/controller.py:183 #, python-brace-format msgid "Memory used: {used} ({percentage:.2%})" msgstr "Memoria utilizada: {used} ({percentage:.2%})" -#: windows/main/main_frame.py:226 +#: windows/main/controller.py:219 +msgid "Settings saved successfully" +msgstr "" + +#: windows/main/controller.py:298 msgid "Version" msgstr "Versión" -#: windows/main/main_frame.py:228 +#: windows/main/controller.py:300 msgid "Uptime" msgstr "Tiempo de actividad" -#: windows/main/main_frame.py:431 +#: windows/main/controller.py:399 +#, python-brace-format +msgid "" +"Do you want to create a dump before dropping database '{database_name}'?\n" +"\n" +"Dump is not implemented yet.\n" +"- Yes: open dump flow (coming soon, no drop).\n" +"- No: drop the database now." +msgstr "" + +#: windows/main/controller.py:404 windows/main/controller.py:425 +#, fuzzy +msgid "Delete database" +msgstr "Eliminar tabla" + +#: windows/main/controller.py:410 +msgid "Dump is not implemented yet. No action has been performed." +msgstr "" + +#: windows/main/controller.py:411 +msgid "Dump not available" +msgstr "" + +#: windows/main/controller.py:424 +msgid "Database deletion is not supported by this engine." +msgstr "" + +#: windows/main/controller.py:439 +msgid "Database deleted successfully" +msgstr "" + +#: windows/main/controller.py:440 windows/main/tabs/view.py:253 +#: windows/main/tabs/view.py:279 +msgid "Success" +msgstr "" + +#: windows/main/controller.py:582 msgid "Delete table" msgstr "Eliminar tabla" -#: windows/main/main_frame.py:586 +#: windows/main/controller.py:699 msgid "Do you want delete the records?" msgstr "¿Quieres eliminar los registros?" +#: windows/main/tabs/database.py:71 +msgid "The connection to the database was lost." +msgstr "Se perdió la conexión a la base de datos." + +#: windows/main/tabs/database.py:73 +msgid "Do you want to reconnect?" +msgstr "¿Quieres reconectar?" + +#: windows/main/tabs/database.py:75 +msgid "Connection lost" +msgstr "Conexión perdida" + +#: windows/main/tabs/database.py:85 +msgid "Reconnection failed:" +msgstr "Reconexión fallida:" + +#: windows/main/tabs/database.py:86 windows/main/tabs/query.py:450 +#: windows/main/tabs/view.py:256 windows/main/tabs/view.py:282 +msgid "Error" +msgstr "Error" + +#: windows/main/tabs/query.py:305 +#, python-brace-format +msgid "{} rows affected" +msgstr "" + +#: windows/main/tabs/query.py:309 windows/main/tabs/query.py:331 +#, fuzzy, python-brace-format +msgid "Query {}" +msgstr "Consulta" + +#: windows/main/tabs/query.py:314 +#, python-brace-format +msgid "Query {} (Error)" +msgstr "" + +#: windows/main/tabs/query.py:326 +#, python-brace-format +msgid "Query {} ({} rows × {} cols)" +msgstr "" + +#: windows/main/tabs/query.py:353 +#, fuzzy, python-brace-format +msgid "{} rows" +msgstr "Filas" + +#: windows/main/tabs/query.py:355 +#, python-brace-format +msgid "{:.1f} ms" +msgstr "" + +#: windows/main/tabs/query.py:358 +#, python-brace-format +msgid "{} warnings" +msgstr "" + +#: windows/main/tabs/query.py:370 +#, fuzzy +msgid "Error:" +msgstr "Error" + +#: windows/main/tabs/query.py:449 +#, fuzzy +msgid "No active database connection" +msgstr "Nueva conexión" + +#: windows/main/tabs/view.py:252 +msgid "View created successfully" +msgstr "" + +#: windows/main/tabs/view.py:252 +msgid "View updated successfully" +msgstr "" + +#: windows/main/tabs/view.py:256 +#, python-brace-format +msgid "Error saving view: {}" +msgstr "" + +#: windows/main/tabs/view.py:269 +#, python-brace-format +msgid "Are you sure you want to delete view '{}'?" +msgstr "" + +#: windows/main/tabs/view.py:270 +#, fuzzy +msgid "Confirm Delete" +msgstr "Confirmar eliminar" + +#: windows/main/tabs/view.py:279 +msgid "View deleted successfully" +msgstr "" + +#: windows/main/tabs/view.py:282 +#, python-brace-format +msgid "Error deleting view: {}" +msgstr "" + #~ msgid "Created at:" #~ msgstr "" @@ -759,3 +1132,9 @@ msgstr "¿Quieres eliminar los registros?" #~ msgid "Foreign Key" #~ msgstr "" +#~ msgid "New Session" +#~ msgstr "Nueva sesión" + +#~ msgid "directory" +#~ msgstr "directorio" + diff --git a/locale/fr_FR/LC_MESSAGES/petersql.mo b/locale/fr_FR/LC_MESSAGES/petersql.mo index 16435e8..13d3905 100644 Binary files a/locale/fr_FR/LC_MESSAGES/petersql.mo and b/locale/fr_FR/LC_MESSAGES/petersql.mo differ diff --git a/locale/fr_FR/LC_MESSAGES/petersql.po b/locale/fr_FR/LC_MESSAGES/petersql.po index 4e7c519..028bb82 100644 --- a/locale/fr_FR/LC_MESSAGES/petersql.po +++ b/locale/fr_FR/LC_MESSAGES/petersql.po @@ -1,492 +1,723 @@ -# French translations for petersql. -# Copyright (C) 2024 -# This file is distributed under the same license as the petersql package. +# Français (fr_FR) translations for PeterSQL. +# Copyright (C) 2026 ORGANIZATION +# This file is distributed under the same license as the PeterSQL project. # +#, fuzzy msgid "" msgstr "" -"Language: fr\n" -"Content-Type: text/plain; charset=UTF-8\n" +"Project-Id-Version: PeterSQL 0.1.0\n" +"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" +"POT-Creation-Date: 2026-03-10 18:23+0100\n" +"PO-Revision-Date: 2026-03-10 18:21+0000\n" +"Last-Translator: \n" +"Language: fr_FR\n" +"Language-Team: fr_FR \n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Generated-By: Babel 2.18.0\n" -#: helpers/__init__.py:14 +#: helpers/__init__.py:16 msgctxt "unit" msgid "B" msgstr "o" -#: helpers/__init__.py:15 +#: helpers/__init__.py:17 msgctxt "unit" msgid "KB" msgstr "Ko" -#: helpers/__init__.py:16 +#: helpers/__init__.py:18 msgctxt "unit" msgid "MB" msgstr "Mo" -#: helpers/__init__.py:17 +#: helpers/__init__.py:19 msgctxt "unit" msgid "GB" msgstr "Go" -#: helpers/__init__.py:18 +#: helpers/__init__.py:20 msgctxt "unit" msgid "TB" msgstr "To" -#: structures/ssh_tunnel.py:117 +#: structures/ssh_tunnel.py:166 msgid "OpenSSH client not found." msgstr "Client OpenSSH introuvable." -#: windows/__init__.py:31 windows/main/main_frame.py:224 +#: windows/dialogs/connections/view.py:395 +#: windows/dialogs/connections/view.py:738 windows/main/controller.py:296 +#: windows/views.py:33 msgid "Connection" msgstr "Connexion" -#: windows/__init__.py:45 windows/__init__.py:83 windows/__init__.py:820 -#: windows/__init__.py:880 windows/__init__.py:1267 windows/__init__.py:1950 -#: windows/__init__.py:1973 windows/__init__.py:1974 windows/__init__.py:1975 -#: windows/__init__.py:1976 windows/__init__.py:1977 windows/__init__.py:1978 -#: windows/__init__.py:1979 windows/__init__.py:1980 windows/__init__.py:1981 -#: windows/__init__.py:1985 windows/__init__.py:2076 windows/__init__.py:2277 #: windows/components/dataview.py:113 windows/components/dataview.py:225 #: windows/components/dataview.py:238 windows/components/dataview.py:253 +#: windows/views.py:47 windows/views.py:97 windows/views.py:956 +#: windows/views.py:1306 windows/views.py:1413 windows/views.py:1796 +#: windows/views.py:2707 windows/views.py:2730 windows/views.py:2731 +#: windows/views.py:2732 windows/views.py:2733 windows/views.py:2734 +#: windows/views.py:2735 windows/views.py:2736 windows/views.py:2737 +#: windows/views.py:2738 windows/views.py:2742 windows/views.py:2936 +#: windows/views.py:3137 msgid "Name" msgstr "Nom" -#: windows/__init__.py:46 windows/__init__.py:322 +#: windows/views.py:48 windows/views.py:381 msgid "Last connection" msgstr "Dernière connexion" -#: windows/__init__.py:59 windows/connections/manager.py:174 +#: windows/dialogs/connections/view.py:631 windows/views.py:61 msgid "New directory" msgstr "Nouveau répertoire" -#: windows/__init__.py:62 -msgid "New Session" -msgstr "Nouvelle session" +#: windows/dialogs/connections/model.py:187 +#: windows/dialogs/connections/view.py:591 windows/views.py:65 +msgid "New connection" +msgstr "Nouvelle connexion" + +#: windows/views.py:71 +#, fuzzy +msgid "Rename" +msgstr "Nom" -#: windows/__init__.py:67 -msgid "Import" -msgstr "Importer" +#: windows/views.py:76 +#, fuzzy +msgid "Clone connection" +msgstr "Nouvelle connexion" + +#: windows/views.py:81 windows/views.py:556 windows/views.py:1290 +#: windows/views.py:1331 windows/views.py:1706 windows/views.py:1738 +#: windows/views.py:1997 windows/views.py:3273 windows/views.py:3305 +msgid "Delete" +msgstr "Supprimer" -#: windows/__init__.py:97 windows/__init__.py:825 windows/__init__.py:935 -#: windows/__init__.py:1990 windows/__init__.py:2332 +#: windows/views.py:111 windows/views.py:1311 windows/views.py:1468 +#: windows/views.py:2747 windows/views.py:3192 msgid "Engine" msgstr "Moteur" -#: windows/__init__.py:118 +#: windows/views.py:132 msgid "Host + port" msgstr "Hôte + port" -#: windows/__init__.py:134 +#: windows/views.py:148 msgid "Username" msgstr "Nom d'utilisateur" -#: windows/__init__.py:147 +#: windows/views.py:161 windows/views.py:1100 msgid "Password" msgstr "Mot de passe" -#: windows/__init__.py:163 +#: windows/views.py:177 +msgid "Use TLS" +msgstr "" + +#: windows/views.py:180 msgid "Use SSH tunnel" msgstr "Utiliser un tunnel SSH" -#: windows/__init__.py:185 windows/__init__.py:1897 +#: windows/views.py:202 windows/views.py:2668 msgid "Filename" msgstr "Nom de fichier" -#: windows/__init__.py:190 windows/__init__.py:1902 +#: windows/views.py:207 windows/views.py:324 windows/views.py:2673 +#: windows/views.py:2856 msgid "Select a file" msgstr "Sélectionner un fichier" -#: windows/__init__.py:190 -msgid "*. *" +#: windows/views.py:207 windows/views.py:324 windows/views.py:2856 +#, fuzzy +msgid "*.*" msgstr "*. *" -#: windows/__init__.py:204 windows/__init__.py:827 windows/__init__.py:893 -#: windows/__init__.py:1991 windows/__init__.py:2174 windows/__init__.py:2290 #: windows/components/dataview.py:70 windows/components/dataview.py:92 +#: windows/views.py:221 windows/views.py:1313 windows/views.py:1426 +#: windows/views.py:2748 windows/views.py:3034 windows/views.py:3150 msgid "Comments" msgstr "Commentaires" -#: windows/__init__.py:218 windows/__init__.py:520 +#: windows/main/controller.py:219 windows/views.py:235 windows/views.py:683 +#: windows/views.py:837 msgid "Settings" msgstr "Paramètres" -#: windows/__init__.py:227 +#: windows/views.py:244 msgid "SSH executable" msgstr "Exécutable SSH" -#: windows/__init__.py:232 +#: windows/views.py:249 msgid "ssh" msgstr "ssh" -#: windows/__init__.py:240 +#: windows/views.py:257 msgid "SSH host + port" msgstr "Hôte SSH + port" -#: windows/__init__.py:256 +#: windows/views.py:269 +msgid "SSH host + port (the SSH server that forwards traffic to the DB)" +msgstr "" + +#: windows/views.py:278 msgid "SSH username" msgstr "Nom d'utilisateur SSH" -#: windows/__init__.py:269 +#: windows/views.py:291 msgid "SSH password" msgstr "Mot de passe SSH" -#: windows/__init__.py:282 +#: windows/views.py:304 msgid "Local port" msgstr "Port local" -#: windows/__init__.py:288 +#: windows/views.py:310 msgid "if the value is set to 0, the first available port will be used" msgstr "si la valeur est définie à 0, le premier port disponible sera utilisé" -#: windows/__init__.py:299 +#: windows/views.py:319 +msgid "Identity file" +msgstr "" + +#: windows/views.py:335 +#, fuzzy +msgid "Remote host + port" +msgstr "Hôte + port" + +#: windows/views.py:347 +msgid "Remote host/port is the real DB target (defaults to DB Host/Port)." +msgstr "" + +#: windows/views.py:358 msgid "SSH Tunnel" msgstr "Tunnel SSH" -#: windows/__init__.py:305 windows/__init__.py:823 windows/__init__.py:1988 +#: windows/views.py:364 windows/views.py:1309 windows/views.py:2745 msgid "Created at" msgstr "Créé le" -#: windows/__init__.py:339 +#: windows/views.py:398 msgid "Successful connections" msgstr "Connexions réussies" -#: windows/__init__.py:356 +#: windows/views.py:415 +#, fuzzy +msgid "Last successful connection" +msgstr "Connexions réussies" + +#: windows/views.py:432 msgid "Unsuccessful connections" msgstr "Connexions échouées" -#: windows/__init__.py:375 +#: windows/views.py:449 +msgid "Last failure reason" +msgstr "" + +#: windows/views.py:466 +#, fuzzy +msgid "Total connection attempts" +msgstr "Dernière connexion" + +#: windows/views.py:483 +#, fuzzy +msgid " Average connection time (ms)" +msgstr "Échec de la reconnexion :" + +#: windows/views.py:500 +#, fuzzy +msgid " Most recent connection duration" +msgstr "Ouvrir le gestionnaire de connexions" + +#: windows/views.py:519 msgid "Statistics" msgstr "Statistiques" -#: windows/__init__.py:393 windows/__init__.py:1139 +#: windows/views.py:537 windows/views.py:1672 msgid "Create" msgstr "Créer" -#: windows/__init__.py:403 windows/__init__.py:806 windows/__init__.py:1173 -#: windows/__init__.py:1205 windows/__init__.py:1340 windows/__init__.py:2413 -#: windows/__init__.py:2445 -msgid "Delete" -msgstr "Supprimer" +#: windows/views.py:541 +#, fuzzy +msgid "Create connection" +msgstr "Dernière connexion" -#: windows/__init__.py:420 windows/__init__.py:634 windows/__init__.py:1208 -#: windows/__init__.py:1343 windows/__init__.py:1419 windows/__init__.py:2221 -#: windows/__init__.py:2448 +#: windows/views.py:544 +#, fuzzy +msgid "Create directory" +msgstr "Nouveau répertoire" + +#: windows/views.py:573 windows/views.py:797 windows/views.py:1328 +#: windows/views.py:1741 windows/views.py:2002 windows/views.py:2078 +#: windows/views.py:3081 windows/views.py:3308 msgid "Cancel" msgstr "Annuler" -#: windows/__init__.py:425 windows/__init__.py:1348 windows/__init__.py:2231 -#: windows/__init__.py:2453 +#: windows/views.py:578 windows/views.py:2007 windows/views.py:3091 +#: windows/views.py:3313 msgid "Save" msgstr "Enregistrer" -#: windows/__init__.py:432 +#: windows/views.py:585 msgid "Test" msgstr "Tester" -#: windows/__init__.py:439 +#: windows/views.py:592 msgid "Connect" msgstr "Connecter" -#: windows/__init__.py:532 +#: windows/views.py:695 msgid "Language" msgstr "Langue" -#: windows/__init__.py:537 +#: windows/views.py:700 msgid "English" msgstr "Anglais" -#: windows/__init__.py:537 +#: windows/views.py:700 msgid "Italian" msgstr "Italien" -#: windows/__init__.py:537 +#: windows/views.py:700 msgid "French" msgstr "Français" -#: windows/__init__.py:549 +#: windows/views.py:712 msgid "Locale" msgstr "Localisation" -#: windows/__init__.py:570 +#: windows/views.py:733 msgid "Edit Value" msgstr "Modifier la valeur" -#: windows/__init__.py:580 +#: windows/views.py:743 msgid "Syntax" msgstr "Syntaxe" -#: windows/__init__.py:637 +#: windows/views.py:800 msgid "Ok" msgstr "Ok" -#: windows/__init__.py:668 +#: windows/views.py:831 msgid "PeterSQL" msgstr "PeterSQL" -#: windows/__init__.py:674 +#: windows/views.py:840 msgid "File" msgstr "Fichier" -#: windows/__init__.py:677 +#: windows/views.py:843 msgid "About" msgstr "À propos" -#: windows/__init__.py:680 +#: windows/views.py:846 msgid "Help" msgstr "Aide" -#: windows/__init__.py:685 +#: windows/views.py:851 msgid "Open connection manager" msgstr "Ouvrir le gestionnaire de connexions" -#: windows/__init__.py:687 +#: windows/views.py:853 msgid "Disconnect from server" msgstr "Se déconnecter du serveur" -#: windows/__init__.py:691 +#: windows/views.py:857 msgid "tool" msgstr "outil" -#: windows/__init__.py:691 +#: windows/views.py:857 msgid "Refresh" msgstr "Actualiser" -#: windows/__init__.py:695 windows/__init__.py:697 +#: windows/views.py:861 windows/views.py:863 msgid "Add" msgstr "Ajouter" -#: windows/__init__.py:731 windows/__init__.py:735 windows/__init__.py:1507 -#: windows/__init__.py:1603 +#: windows/views.py:897 windows/views.py:901 windows/views.py:2166 +#: windows/views.py:2654 msgid "MyMenuItem" msgstr "MonÉlémentMenu" -#: windows/__init__.py:738 windows/__init__.py:1236 windows/__init__.py:2476 +#: windows/views.py:904 windows/views.py:1769 windows/views.py:3336 msgid "MyMenu" msgstr "MonMenu" -#: windows/__init__.py:753 +#: windows/views.py:919 windows/views.py:1350 windows/views.py:1357 +#: windows/views.py:1364 msgid "MyLabel" msgstr "MonÉtiquette" -#: windows/__init__.py:759 +#: windows/views.py:925 msgid "Databases" msgstr "Bases de données" -#: windows/__init__.py:760 windows/__init__.py:822 windows/__init__.py:1959 -#: windows/__init__.py:1987 +#: windows/views.py:926 windows/views.py:1308 windows/views.py:2716 +#: windows/views.py:2744 msgid "Size" msgstr "Taille" -#: windows/__init__.py:761 +#: windows/views.py:927 msgid "Elements" msgstr "Éléments" -#: windows/__init__.py:762 +#: windows/views.py:928 msgid "Modified at" msgstr "Modifié le" -#: windows/__init__.py:763 windows/__init__.py:834 +#: windows/views.py:929 msgid "Tables" msgstr "Tables" -#: windows/__init__.py:770 +#: windows/views.py:936 msgid "System" msgstr "Système" -#: windows/__init__.py:786 +#: windows/views.py:979 +#, fuzzy +msgid "Character set" +msgstr "Créé le" + +#: windows/components/dataview.py:43 windows/components/dataview.py:67 +#: windows/components/dataview.py:89 windows/views.py:1000 +#: windows/views.py:1312 windows/views.py:2980 +msgid "Collation" +msgstr "Classement" + +#: windows/views.py:1026 windows/views.py:2862 +msgid "Encryption" +msgstr "" + +#: windows/views.py:1038 +msgid "Read Only" +msgstr "" + +#: windows/views.py:1055 +#, fuzzy +msgid "Tablespace" +msgstr "Tables" + +#: windows/views.py:1076 +#, fuzzy +msgid "Connection limit" +msgstr "Connexion perdue" + +#: windows/views.py:1119 +#, fuzzy +msgid "Profile" +msgstr "Fichier" + +#: windows/views.py:1145 +#, fuzzy +msgid "Default tablespace" +msgstr "Supprimer la table" + +#: windows/views.py:1166 +#, fuzzy +msgid "Temporary tablespace" +msgstr "Temporaire" + +#: windows/views.py:1192 +msgid "Quota" +msgstr "" + +#: windows/views.py:1211 +msgid "Unlimited quota" +msgstr "" + +#: windows/views.py:1228 +msgid "Account status" +msgstr "" + +#: windows/views.py:1249 +#, fuzzy +msgid "Password expire" +msgstr "Mot de passe" + +#: windows/views.py:1270 msgid "Table:" msgstr "Table :" -#: windows/__init__.py:794 windows/__init__.py:1018 windows/__init__.py:1062 -#: windows/__init__.py:1168 windows/__init__.py:2408 +#: windows/views.py:1278 windows/views.py:1551 windows/views.py:1595 +#: windows/views.py:1701 windows/views.py:3268 msgid "Insert" msgstr "Insérer" -#: windows/__init__.py:799 +#: windows/views.py:1283 msgid "Clone" msgstr "Cloner" -#: windows/__init__.py:821 +#: windows/views.py:1307 msgid "Rows" msgstr "Lignes" -#: windows/__init__.py:824 windows/__init__.py:1989 +#: windows/views.py:1310 windows/views.py:2746 msgid "Updated at" msgstr "Mis à jour le" -#: windows/__init__.py:826 windows/__init__.py:2120 -#: windows/components/dataview.py:43 windows/components/dataview.py:67 -#: windows/components/dataview.py:89 -msgid "Collation" -msgstr "Classement" +#: windows/views.py:1334 windows/views.py:1746 windows/views.py:2085 +#: windows/views.py:2140 +msgid "Apply" +msgstr "Appliquer" -#: windows/__init__.py:842 +#: windows/views.py:1344 windows/views.py:1503 windows/views.py:1956 +#: windows/views.py:3225 +msgid "Options" +msgstr "Options" + +#: windows/views.py:1375 msgid "Diagram" msgstr "Diagramme" -#: windows/__init__.py:853 windows/__init__.py:1958 +#: windows/views.py:1386 windows/views.py:2715 msgid "Database" msgstr "Base de données" -#: windows/__init__.py:908 windows/__init__.py:2305 +#: windows/views.py:1441 windows/views.py:3165 msgid "Base" msgstr "Base" -#: windows/__init__.py:922 windows/__init__.py:2319 +#: windows/views.py:1455 windows/views.py:3179 msgid "Auto Increment" msgstr "Auto incrément" -#: windows/__init__.py:950 windows/__init__.py:2347 +#: windows/views.py:1483 windows/views.py:3207 msgid "Default Collation" msgstr "Classement par défaut" -#: windows/__init__.py:970 windows/__init__.py:1301 windows/__init__.py:2365 -msgid "Options" -msgstr "Options" - -#: windows/__init__.py:982 windows/__init__.py:1023 windows/__init__.py:1067 +#: windows/views.py:1515 windows/views.py:1556 windows/views.py:1600 msgid "Remove" msgstr "Supprimer" -#: windows/__init__.py:989 windows/__init__.py:1030 windows/__init__.py:1074 +#: windows/views.py:1522 windows/views.py:1563 windows/views.py:1607 msgid "Clear" msgstr "Effacer" -#: windows/__init__.py:1004 windows/__init__.py:2379 +#: windows/views.py:1537 windows/views.py:3239 msgid "Indexes" msgstr "Index" -#: windows/__init__.py:1048 +#: windows/views.py:1581 msgid "Foreign Keys" msgstr "Clés étrangères" -#: windows/__init__.py:1092 +#: windows/views.py:1625 msgid "Checks" msgstr "Contrôles" -#: windows/__init__.py:1160 windows/__init__.py:2400 +#: windows/views.py:1693 windows/views.py:3260 msgid "Columns:" msgstr "Colonnes :" -#: windows/__init__.py:1180 windows/__init__.py:2420 +#: windows/views.py:1713 windows/views.py:3280 msgid "Up" msgstr "Haut" -#: windows/__init__.py:1187 windows/__init__.py:2427 +#: windows/views.py:1720 windows/views.py:3287 msgid "Down" msgstr "Bas" -#: windows/__init__.py:1213 windows/__init__.py:1426 windows/__init__.py:1481 -msgid "Apply" -msgstr "Appliquer" - -#: windows/__init__.py:1226 windows/__init__.py:1233 windows/__init__.py:2466 -#: windows/__init__.py:2473 +#: windows/views.py:1759 windows/views.py:1766 windows/views.py:3326 +#: windows/views.py:3333 msgid "Add Index" msgstr "Ajouter un index" -#: windows/__init__.py:1230 windows/__init__.py:2470 +#: windows/views.py:1763 windows/views.py:3330 msgid "Add PrimaryKey" msgstr "Ajouter une clé primaire" -#: windows/__init__.py:1247 +#: windows/views.py:1780 msgid "Table" msgstr "Table" -#: windows/__init__.py:1280 -msgid "Temporary" -msgstr "Temporaire" +#: windows/views.py:1816 +#, fuzzy +msgid "Definer" +msgstr "Insérer" + +#: windows/views.py:1836 +msgid "Schema" +msgstr "" + +#: windows/views.py:1862 +msgid "SQL security" +msgstr "" + +#: windows/views.py:1869 +#, fuzzy +msgid "DEFINER" +msgstr "Insérer" + +#: windows/views.py:1869 +#, fuzzy +msgid "INVOKER" +msgstr "Insérer" + +#: windows/views.py:1881 windows/views.py:2558 windows/views.py:2577 +#: windows/views.py:2820 +msgid "Algorithm" +msgstr "" + +#: windows/views.py:1883 windows/views.py:2543 windows/views.py:2576 +#: windows/views.py:2825 +#, fuzzy +msgid "UNDEFINED" +msgstr "Non signé" + +#: windows/views.py:1886 windows/views.py:2546 windows/views.py:2576 +#: windows/views.py:2828 +msgid "MERGE" +msgstr "" + +#: windows/views.py:1889 windows/views.py:2555 windows/views.py:2576 +#: windows/views.py:2831 +#, fuzzy +msgid "TEMPTABLE" +msgstr "Table" + +#: windows/views.py:1899 windows/views.py:2582 +msgid "View constraint" +msgstr "" + +#: windows/views.py:1901 windows/views.py:2581 +#, fuzzy +msgid "None" +msgstr "Cloner" + +#: windows/views.py:1904 windows/views.py:2581 +#, fuzzy +msgid "LOCAL" +msgstr "Localisation" -#: windows/__init__.py:1360 +#: windows/views.py:1907 +#, fuzzy +msgid "CASCADE" +msgstr "Annuler" + +#: windows/views.py:1910 +#, fuzzy +msgid "CHECK ONLY" +msgstr "Vérifier" + +#: windows/views.py:1913 windows/views.py:2581 +msgid "READ ONLY" +msgstr "" + +#: windows/views.py:1925 +msgid "Force" +msgstr "" + +#: windows/views.py:1937 +msgid "Security barrier" +msgstr "" + +#: windows/views.py:2019 msgid "Views" msgstr "Vues" -#: windows/__init__.py:1368 +#: windows/views.py:2027 msgid "Triggers" msgstr "Déclencheurs" -#: windows/__init__.py:1380 +#: windows/views.py:2039 #, python-format msgid "Table `%(database_name)s`.`%(table_name)s`: %(total_rows) rows total" msgstr "Table `%(database_name)s`.`%(table_name)s` : %(total_rows) lignes au total" -#: windows/__init__.py:1390 +#: windows/views.py:2049 msgid "Insert record" msgstr "Insérer un enregistrement" -#: windows/__init__.py:1395 +#: windows/views.py:2054 msgid "Duplicate record" msgstr "Dupliquer un enregistrement" -#: windows/__init__.py:1402 +#: windows/views.py:2061 msgid "Delete record" msgstr "Supprimer un enregistrement" -#: windows/__init__.py:1412 +#: windows/views.py:2071 msgid "Apply changes automatically" msgstr "Appliquer les modifications automatiquement" -#: windows/__init__.py:1414 windows/__init__.py:1415 +#: windows/views.py:2073 windows/views.py:2074 msgid "" "If enabled, table edits are applied immediately without pressing Apply or" " Cancel" msgstr "" -"Si activé, les modifications de la table sont appliquées immédiatement sans appuyer sur Appliquer ou" -" Annuler" +"Si activé, les modifications de la table sont appliquées immédiatement " +"sans appuyer sur Appliquer ou Annuler" -#: windows/__init__.py:1436 +#: windows/views.py:2095 msgid "Next" msgstr "Suivant" -#: windows/__init__.py:1444 +#: windows/views.py:2103 msgid "Filters" msgstr "Filtres" -#: windows/__init__.py:1484 +#: windows/views.py:2143 msgid "CTRL+ENTER" msgstr "CTRL+ENTER" -#: windows/__init__.py:1504 +#: windows/views.py:2163 msgid "Insert row" msgstr "Insérer une ligne" -#: windows/__init__.py:1512 +#: windows/views.py:2171 msgid "Data" msgstr "Données" -#: windows/__init__.py:1561 +#: windows/views.py:2225 windows/views.py:2275 +msgid "New" +msgstr "Nouveau" + +#: windows/views.py:2252 msgid "Query" msgstr "Requête" -#: windows/__init__.py:1581 +#: windows/views.py:2272 msgid "Close" msgstr "Fermer" -#: windows/__init__.py:1584 windows/__init__.py:2019 -msgid "New" -msgstr "Nouveau" - -#: windows/__init__.py:1594 +#: windows/views.py:2285 msgid "Query #2" msgstr "Requête #2" -#: windows/__init__.py:1835 +#: windows/views.py:2537 msgid "Column5" msgstr "Colonne5" -#: windows/__init__.py:1842 +#: windows/views.py:2548 +msgid "Import" +msgstr "Importer" + +#: windows/views.py:2573 +msgid "Read only" +msgstr "" + +#: windows/views.py:2581 +msgid "CASCADED" +msgstr "" + +#: windows/views.py:2581 +#, fuzzy +msgid "CHECK OPTION" +msgstr "connexion" + +#: windows/views.py:2613 msgid "collapsible" msgstr "rétractable" -#: windows/__init__.py:1864 +#: windows/views.py:2629 msgid "Column3" msgstr "Colonne3" -#: windows/__init__.py:1865 +#: windows/views.py:2630 msgid "Column4" msgstr "Colonne4" -#: windows/__init__.py:1902 +#: windows/views.py:2673 msgid "" "Database " "(*.db;*.db3;*.sdb;*.s3db;*.sqlite;*.sqlite3)|*.db;*.db3;*.sdb;*.s3db;*.sqlite;*.sqlite3" @@ -494,65 +725,78 @@ msgstr "" "Database " "(*.db;*.db3;*.sdb;*.s3db;*.sqlite;*.sqlite3)|*.db;*.db3;*.sdb;*.s3db;*.sqlite;*.sqlite3" -#: windows/__init__.py:1934 +#: windows/views.py:2685 msgid "Port" msgstr "Port" -#: windows/__init__.py:1951 +#: windows/views.py:2708 msgid "Usage" msgstr "Utilisation" -#: windows/__init__.py:1962 +#: windows/views.py:2719 #, python-format msgid "%(total_rows)s" msgstr "%(total_rows)s" -#: windows/__init__.py:1967 +#: windows/views.py:2724 msgid "rows total" msgstr "lignes au total" -#: windows/__init__.py:1986 +#: windows/views.py:2743 msgid "Lines" msgstr "Lignes" -#: windows/__init__.py:2068 +#: windows/views.py:2775 +msgid "Temporary" +msgstr "Temporaire" + +#: windows/views.py:2786 +#, fuzzy +msgid "Engine options" +msgstr "Options" + +#: windows/views.py:2845 +msgid "RadioBtn" +msgstr "" + +#: windows/views.py:2928 msgid "Edit Column" msgstr "Modifier la colonne" -#: windows/__init__.py:2084 +#: windows/views.py:2944 msgid "Datatype" msgstr "Type de données" -#: windows/__init__.py:2099 windows/components/dataview.py:121 +#: windows/components/dataview.py:121 windows/views.py:2959 msgid "Length/Set" msgstr "Longueur/Ensemble" -#: windows/__init__.py:2138 windows/components/dataview.py:51 +#: windows/components/dataview.py:51 windows/views.py:2998 msgid "Unsigned" msgstr "Non signé" -#: windows/__init__.py:2144 windows/components/dataview.py:25 -#: windows/components/dataview.py:52 windows/components/dataview.py:75 +#: windows/components/dataview.py:25 windows/components/dataview.py:52 +#: windows/components/dataview.py:75 windows/views.py:3004 msgid "Allow NULL" msgstr "Autoriser NULL" -#: windows/__init__.py:2150 +#: windows/views.py:3010 msgid "Zero Fill" msgstr "Remplissage zéro" -#: windows/__init__.py:2161 windows/components/dataview.py:32 -#: windows/components/dataview.py:56 windows/components/dataview.py:78 +#: windows/components/dataview.py:32 windows/components/dataview.py:56 +#: windows/components/dataview.py:78 windows/views.py:3021 msgid "Default" msgstr "Par défaut" -#: windows/__init__.py:2187 windows/components/dataview.py:36 -#: windows/components/dataview.py:60 windows/components/dataview.py:82 +#: windows/components/dataview.py:36 windows/components/dataview.py:60 +#: windows/components/dataview.py:82 windows/views.py:3047 msgid "Virtuality" msgstr "Virtualité" -#: windows/__init__.py:2202 windows/components/dataview.py:39 -#: windows/components/dataview.py:63 windows/components/dataview.py:85 -#: windows/components/dataview.py:241 +#: windows/components/dataview.py:39 windows/components/dataview.py:63 +#: windows/components/dataview.py:85 windows/components/dataview.py:241 +#: windows/views.py:3062 msgid "Expression" msgstr "Expression" @@ -632,103 +876,232 @@ msgstr "Ajouter une clé étrangère" msgid "Remove foreign key" msgstr "Supprimer une clé étrangère" -#: windows/components/popup.py:24 +#: windows/components/popup.py:26 msgid "No default value" msgstr "Aucune valeur par défaut" -#: windows/components/popup.py:29 +#: windows/components/popup.py:31 msgid "NULL" msgstr "NULL" -#: windows/components/popup.py:33 +#: windows/components/popup.py:35 msgid "AUTO INCREMENT" msgstr "AUTO INCREMENT" -#: windows/components/popup.py:37 +#: windows/components/popup.py:39 msgid "Text/Expression" msgstr "Texte/Expression" -#: windows/connections/manager.py:125 +#: windows/dialogs/connections/view.py:119 windows/main/tabs/query.py:376 +msgid "Unknown error" +msgstr "" + +#: windows/dialogs/connections/view.py:394 +msgid "Connection established successfully" +msgstr "" + +#: windows/dialogs/connections/view.py:407 msgid "Confirm save" msgstr "Confirmer la sauvegarde" -#: windows/connections/manager.py:193 +#: windows/dialogs/connections/view.py:459 +msgid "You have unsaved changes. Do you want to save them before continuing?" +msgstr "" + +#: windows/dialogs/connections/view.py:461 +msgid "Unsaved changes" +msgstr "" + +#: windows/dialogs/connections/view.py:736 +msgid "" +"This connection cannot work without TLS. TLS has been enabled " +"automatically." +msgstr "" + +#: windows/dialogs/connections/view.py:762 msgid "Connection error" msgstr "Erreur de connexion" -#: windows/connections/manager.py:214 -msgid "connection" -msgstr "connexion" - -#: windows/connections/manager.py:215 windows/connections/manager.py:230 +#: windows/dialogs/connections/view.py:788 +#: windows/dialogs/connections/view.py:803 msgid "Confirm delete" msgstr "Confirmer la suppression" -#: windows/connections/manager.py:229 -msgid "directory" -msgstr "répertoire" - -#: windows/connections/model.py:101 -msgid "New connection" -msgstr "Nouvelle connexion" - -#: windows/main/database.py:70 -msgid "The connection to the database was lost." -msgstr "La connexion à la base de données a été perdue." - -#: windows/main/database.py:72 -msgid "Do you want to reconnect?" -msgstr "Voulez-vous vous reconnecter ?" - -#: windows/main/database.py:74 -msgid "Connection lost" -msgstr "Connexion perdue" - -#: windows/main/database.py:83 -msgid "Reconnection failed:" -msgstr "Échec de la reconnexion :" - -#: windows/main/database.py:84 -msgid "Error" -msgstr "Erreur" - -#: windows/main/main_frame.py:124 +#: windows/main/controller.py:172 msgid "days" msgstr "jours" -#: windows/main/main_frame.py:125 +#: windows/main/controller.py:173 msgid "hours" msgstr "heures" -#: windows/main/main_frame.py:126 +#: windows/main/controller.py:174 msgid "minutes" msgstr "minutes" -#: windows/main/main_frame.py:127 +#: windows/main/controller.py:175 msgid "seconds" msgstr "secondes" -#: windows/main/main_frame.py:135 +#: windows/main/controller.py:183 #, python-brace-format msgid "Memory used: {used} ({percentage:.2%})" msgstr "Mémoire utilisée : {used} ({percentage:.2%})" -#: windows/main/main_frame.py:226 +#: windows/main/controller.py:219 +msgid "Settings saved successfully" +msgstr "" + +#: windows/main/controller.py:298 msgid "Version" msgstr "Version" -#: windows/main/main_frame.py:228 +#: windows/main/controller.py:300 msgid "Uptime" msgstr "Temps de fonctionnement" -#: windows/main/main_frame.py:431 +#: windows/main/controller.py:399 +#, python-brace-format +msgid "" +"Do you want to create a dump before dropping database '{database_name}'?\n" +"\n" +"Dump is not implemented yet.\n" +"- Yes: open dump flow (coming soon, no drop).\n" +"- No: drop the database now." +msgstr "" + +#: windows/main/controller.py:404 windows/main/controller.py:425 +#, fuzzy +msgid "Delete database" +msgstr "Supprimer la table" + +#: windows/main/controller.py:410 +msgid "Dump is not implemented yet. No action has been performed." +msgstr "" + +#: windows/main/controller.py:411 +msgid "Dump not available" +msgstr "" + +#: windows/main/controller.py:424 +msgid "Database deletion is not supported by this engine." +msgstr "" + +#: windows/main/controller.py:439 +msgid "Database deleted successfully" +msgstr "" + +#: windows/main/controller.py:440 windows/main/tabs/view.py:253 +#: windows/main/tabs/view.py:279 +msgid "Success" +msgstr "" + +#: windows/main/controller.py:582 msgid "Delete table" msgstr "Supprimer la table" -#: windows/main/main_frame.py:586 +#: windows/main/controller.py:699 msgid "Do you want delete the records?" msgstr "Voulez-vous supprimer les enregistrements ?" +#: windows/main/tabs/database.py:71 +msgid "The connection to the database was lost." +msgstr "La connexion à la base de données a été perdue." + +#: windows/main/tabs/database.py:73 +msgid "Do you want to reconnect?" +msgstr "Voulez-vous vous reconnecter ?" + +#: windows/main/tabs/database.py:75 +msgid "Connection lost" +msgstr "Connexion perdue" + +#: windows/main/tabs/database.py:85 +msgid "Reconnection failed:" +msgstr "Échec de la reconnexion :" + +#: windows/main/tabs/database.py:86 windows/main/tabs/query.py:450 +#: windows/main/tabs/view.py:256 windows/main/tabs/view.py:282 +msgid "Error" +msgstr "Erreur" + +#: windows/main/tabs/query.py:305 +#, python-brace-format +msgid "{} rows affected" +msgstr "" + +#: windows/main/tabs/query.py:309 windows/main/tabs/query.py:331 +#, fuzzy, python-brace-format +msgid "Query {}" +msgstr "Requête" + +#: windows/main/tabs/query.py:314 +#, python-brace-format +msgid "Query {} (Error)" +msgstr "" + +#: windows/main/tabs/query.py:326 +#, python-brace-format +msgid "Query {} ({} rows × {} cols)" +msgstr "" + +#: windows/main/tabs/query.py:353 +#, fuzzy, python-brace-format +msgid "{} rows" +msgstr "Lignes" + +#: windows/main/tabs/query.py:355 +#, python-brace-format +msgid "{:.1f} ms" +msgstr "" + +#: windows/main/tabs/query.py:358 +#, python-brace-format +msgid "{} warnings" +msgstr "" + +#: windows/main/tabs/query.py:370 +#, fuzzy +msgid "Error:" +msgstr "Erreur" + +#: windows/main/tabs/query.py:449 +#, fuzzy +msgid "No active database connection" +msgstr "Nouvelle connexion" + +#: windows/main/tabs/view.py:252 +msgid "View created successfully" +msgstr "" + +#: windows/main/tabs/view.py:252 +msgid "View updated successfully" +msgstr "" + +#: windows/main/tabs/view.py:256 +#, python-brace-format +msgid "Error saving view: {}" +msgstr "" + +#: windows/main/tabs/view.py:269 +#, python-brace-format +msgid "Are you sure you want to delete view '{}'?" +msgstr "" + +#: windows/main/tabs/view.py:270 +#, fuzzy +msgid "Confirm Delete" +msgstr "Confirmer la suppression" + +#: windows/main/tabs/view.py:279 +msgid "View deleted successfully" +msgstr "" + +#: windows/main/tabs/view.py:282 +#, python-brace-format +msgid "Error deleting view: {}" +msgstr "" + #~ msgid "Created at:" #~ msgstr "" @@ -759,3 +1132,9 @@ msgstr "Voulez-vous supprimer les enregistrements ?" #~ msgid "Foreign Key" #~ msgstr "" +#~ msgid "New Session" +#~ msgstr "Nouvelle session" + +#~ msgid "directory" +#~ msgstr "répertoire" + diff --git a/locale/it_IT/LC_MESSAGES/petersql.mo b/locale/it_IT/LC_MESSAGES/petersql.mo index c9e6904..2efb70e 100644 Binary files a/locale/it_IT/LC_MESSAGES/petersql.mo and b/locale/it_IT/LC_MESSAGES/petersql.mo differ diff --git a/locale/it_IT/LC_MESSAGES/petersql.po b/locale/it_IT/LC_MESSAGES/petersql.po index 3cb91f5..94bfe10 100644 --- a/locale/it_IT/LC_MESSAGES/petersql.po +++ b/locale/it_IT/LC_MESSAGES/petersql.po @@ -1,432 +1,645 @@ -# Italian translations for petersql. -# Copyright (C) 2024 -# This file is distributed under the same license as the petersql package. +# Italiano (it_IT) translations for PeterSQL. +# Copyright (C) 2026 ORGANIZATION +# This file is distributed under the same license as the PeterSQL project. # +#, fuzzy msgid "" msgstr "" -"Language: it\n" -"Content-Type: text/plain; charset=UTF-8\n" +"Project-Id-Version: PeterSQL 0.1.0\n" +"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" +"POT-Creation-Date: 2026-03-10 18:23+0100\n" +"PO-Revision-Date: 2026-03-10 18:21+0000\n" +"Last-Translator: \n" +"Language: it_IT\n" +"Language-Team: it_IT \n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Generated-By: Babel 2.18.0\n" -#: helpers/__init__.py:14 +#: helpers/__init__.py:16 msgctxt "unit" msgid "B" msgstr "B" -#: helpers/__init__.py:15 +#: helpers/__init__.py:17 msgctxt "unit" msgid "KB" msgstr "KB" -#: helpers/__init__.py:16 +#: helpers/__init__.py:18 msgctxt "unit" msgid "MB" msgstr "MB" -#: helpers/__init__.py:17 +#: helpers/__init__.py:19 msgctxt "unit" msgid "GB" msgstr "GB" -#: helpers/__init__.py:18 +#: helpers/__init__.py:20 msgctxt "unit" msgid "TB" msgstr "TB" -#: structures/ssh_tunnel.py:117 +#: structures/ssh_tunnel.py:166 msgid "OpenSSH client not found." msgstr "Client OpenSSH non trovato." -#: windows/__init__.py:31 windows/main/main_frame.py:224 +#: windows/dialogs/connections/view.py:395 +#: windows/dialogs/connections/view.py:738 windows/main/controller.py:296 +#: windows/views.py:33 msgid "Connection" msgstr "Connessione" -#: windows/__init__.py:45 windows/__init__.py:83 windows/__init__.py:820 -#: windows/__init__.py:880 windows/__init__.py:1267 windows/__init__.py:1950 -#: windows/__init__.py:1973 windows/__init__.py:1974 windows/__init__.py:1975 -#: windows/__init__.py:1976 windows/__init__.py:1977 windows/__init__.py:1978 -#: windows/__init__.py:1979 windows/__init__.py:1980 windows/__init__.py:1981 -#: windows/__init__.py:1985 windows/__init__.py:2076 windows/__init__.py:2277 #: windows/components/dataview.py:113 windows/components/dataview.py:225 #: windows/components/dataview.py:238 windows/components/dataview.py:253 +#: windows/views.py:47 windows/views.py:97 windows/views.py:956 +#: windows/views.py:1306 windows/views.py:1413 windows/views.py:1796 +#: windows/views.py:2707 windows/views.py:2730 windows/views.py:2731 +#: windows/views.py:2732 windows/views.py:2733 windows/views.py:2734 +#: windows/views.py:2735 windows/views.py:2736 windows/views.py:2737 +#: windows/views.py:2738 windows/views.py:2742 windows/views.py:2936 +#: windows/views.py:3137 msgid "Name" msgstr "Nome" -#: windows/__init__.py:46 windows/__init__.py:322 +#: windows/views.py:48 windows/views.py:381 msgid "Last connection" msgstr "Ultima connessione" -#: windows/__init__.py:59 windows/connections/manager.py:174 +#: windows/dialogs/connections/view.py:631 windows/views.py:61 msgid "New directory" msgstr "Nuova directory" -#: windows/__init__.py:62 -msgid "New Session" -msgstr "Nuova sessione" +#: windows/dialogs/connections/model.py:187 +#: windows/dialogs/connections/view.py:591 windows/views.py:65 +msgid "New connection" +msgstr "Nuova connessione" + +#: windows/views.py:71 +#, fuzzy +msgid "Rename" +msgstr "Nome" -#: windows/__init__.py:67 -msgid "Import" -msgstr "Importa" +#: windows/views.py:76 +#, fuzzy +msgid "Clone connection" +msgstr "Nuova connessione" + +#: windows/views.py:81 windows/views.py:556 windows/views.py:1290 +#: windows/views.py:1331 windows/views.py:1706 windows/views.py:1738 +#: windows/views.py:1997 windows/views.py:3273 windows/views.py:3305 +msgid "Delete" +msgstr "Elimina" -#: windows/__init__.py:97 windows/__init__.py:825 windows/__init__.py:935 -#: windows/__init__.py:1990 windows/__init__.py:2332 +#: windows/views.py:111 windows/views.py:1311 windows/views.py:1468 +#: windows/views.py:2747 windows/views.py:3192 msgid "Engine" msgstr "Motore" -#: windows/__init__.py:118 +#: windows/views.py:132 msgid "Host + port" msgstr "Host + porta" -#: windows/__init__.py:134 +#: windows/views.py:148 msgid "Username" msgstr "Nome utente" -#: windows/__init__.py:147 +#: windows/views.py:161 windows/views.py:1100 msgid "Password" msgstr "Password" -#: windows/__init__.py:163 +#: windows/views.py:177 +msgid "Use TLS" +msgstr "" + +#: windows/views.py:180 msgid "Use SSH tunnel" msgstr "Usa tunnel SSH" -#: windows/__init__.py:185 windows/__init__.py:1897 +#: windows/views.py:202 windows/views.py:2668 msgid "Filename" msgstr "Nome file" -#: windows/__init__.py:190 windows/__init__.py:1902 +#: windows/views.py:207 windows/views.py:324 windows/views.py:2673 +#: windows/views.py:2856 msgid "Select a file" msgstr "Seleziona un file" -#: windows/__init__.py:190 +#: windows/views.py:207 windows/views.py:324 windows/views.py:2856 msgid "*.*" msgstr "*.*" -#: windows/__init__.py:204 windows/__init__.py:827 windows/__init__.py:893 -#: windows/__init__.py:1991 windows/__init__.py:2174 windows/__init__.py:2290 #: windows/components/dataview.py:70 windows/components/dataview.py:92 +#: windows/views.py:221 windows/views.py:1313 windows/views.py:1426 +#: windows/views.py:2748 windows/views.py:3034 windows/views.py:3150 msgid "Comments" msgstr "Commenti" -#: windows/__init__.py:218 windows/__init__.py:520 +#: windows/main/controller.py:219 windows/views.py:235 windows/views.py:683 +#: windows/views.py:837 msgid "Settings" msgstr "Impostazioni" -#: windows/__init__.py:227 +#: windows/views.py:244 msgid "SSH executable" msgstr "Eseguibile SSH" -#: windows/__init__.py:232 +#: windows/views.py:249 msgid "ssh" msgstr "ssh" -#: windows/__init__.py:240 +#: windows/views.py:257 msgid "SSH host + port" msgstr "Host SSH + porta" -#: windows/__init__.py:256 +#: windows/views.py:269 +msgid "SSH host + port (the SSH server that forwards traffic to the DB)" +msgstr "" + +#: windows/views.py:278 msgid "SSH username" msgstr "Nome utente SSH" -#: windows/__init__.py:269 +#: windows/views.py:291 msgid "SSH password" msgstr "Password SSH" -#: windows/__init__.py:282 +#: windows/views.py:304 msgid "Local port" msgstr "Porta locale" -#: windows/__init__.py:288 +#: windows/views.py:310 msgid "if the value is set to 0, the first available port will be used" msgstr "se il valore è impostato a 0, verrà utilizzata la prima porta disponibile" -#: windows/__init__.py:299 +#: windows/views.py:319 +msgid "Identity file" +msgstr "" + +#: windows/views.py:335 +#, fuzzy +msgid "Remote host + port" +msgstr "Host + porta" + +#: windows/views.py:347 +msgid "Remote host/port is the real DB target (defaults to DB Host/Port)." +msgstr "" + +#: windows/views.py:358 msgid "SSH Tunnel" msgstr "Tunnel SSH" -#: windows/__init__.py:305 windows/__init__.py:823 windows/__init__.py:1988 +#: windows/views.py:364 windows/views.py:1309 windows/views.py:2745 msgid "Created at" msgstr "Creato il" -#: windows/__init__.py:339 +#: windows/views.py:398 msgid "Successful connections" msgstr "Connessioni riuscite" -#: windows/__init__.py:356 +#: windows/views.py:415 +#, fuzzy +msgid "Last successful connection" +msgstr "Connessioni riuscite" + +#: windows/views.py:432 msgid "Unsuccessful connections" msgstr "Connessioni non riuscite" -#: windows/__init__.py:375 +#: windows/views.py:449 +msgid "Last failure reason" +msgstr "" + +#: windows/views.py:466 +#, fuzzy +msgid "Total connection attempts" +msgstr "Ultima connessione" + +#: windows/views.py:483 +#, fuzzy +msgid " Average connection time (ms)" +msgstr "Riconnessione fallita:" + +#: windows/views.py:500 +#, fuzzy +msgid " Most recent connection duration" +msgstr "Apri gestore connessioni" + +#: windows/views.py:519 msgid "Statistics" msgstr "Statistiche" -#: windows/__init__.py:393 windows/__init__.py:1139 +#: windows/views.py:537 windows/views.py:1672 msgid "Create" msgstr "Crea" -#: windows/__init__.py:403 windows/__init__.py:806 windows/__init__.py:1173 -#: windows/__init__.py:1205 windows/__init__.py:1340 windows/__init__.py:2413 -#: windows/__init__.py:2445 -msgid "Delete" -msgstr "Elimina" +#: windows/views.py:541 +#, fuzzy +msgid "Create connection" +msgstr "Ultima connessione" -#: windows/__init__.py:420 windows/__init__.py:634 windows/__init__.py:1208 -#: windows/__init__.py:1343 windows/__init__.py:1419 windows/__init__.py:2221 -#: windows/__init__.py:2448 +#: windows/views.py:544 +#, fuzzy +msgid "Create directory" +msgstr "Nuova directory" + +#: windows/views.py:573 windows/views.py:797 windows/views.py:1328 +#: windows/views.py:1741 windows/views.py:2002 windows/views.py:2078 +#: windows/views.py:3081 windows/views.py:3308 msgid "Cancel" msgstr "Annulla" -#: windows/__init__.py:425 windows/__init__.py:1348 windows/__init__.py:2231 -#: windows/__init__.py:2453 +#: windows/views.py:578 windows/views.py:2007 windows/views.py:3091 +#: windows/views.py:3313 msgid "Save" msgstr "Salva" -#: windows/__init__.py:432 +#: windows/views.py:585 msgid "Test" msgstr "Testa" -#: windows/__init__.py:439 +#: windows/views.py:592 msgid "Connect" msgstr "Connetti" -#: windows/__init__.py:532 +#: windows/views.py:695 msgid "Language" msgstr "Lingua" -#: windows/__init__.py:537 +#: windows/views.py:700 msgid "English" msgstr "Inglese" -#: windows/__init__.py:537 +#: windows/views.py:700 msgid "Italian" msgstr "Italiano" -#: windows/__init__.py:537 +#: windows/views.py:700 msgid "French" msgstr "Francese" -#: windows/__init__.py:549 +#: windows/views.py:712 msgid "Locale" msgstr "Localizzazione" -#: windows/__init__.py:570 +#: windows/views.py:733 msgid "Edit Value" msgstr "Modifica valore" -#: windows/__init__.py:580 +#: windows/views.py:743 msgid "Syntax" msgstr "Sintassi" -#: windows/__init__.py:637 +#: windows/views.py:800 msgid "Ok" msgstr "Ok" -#: windows/__init__.py:668 +#: windows/views.py:831 msgid "PeterSQL" msgstr "PeterSQL" -#: windows/__init__.py:674 +#: windows/views.py:840 msgid "File" msgstr "File" -#: windows/__init__.py:677 +#: windows/views.py:843 msgid "About" msgstr "Informazioni" -#: windows/__init__.py:680 +#: windows/views.py:846 msgid "Help" msgstr "Aiuto" -#: windows/__init__.py:685 +#: windows/views.py:851 msgid "Open connection manager" msgstr "Apri gestore connessioni" -#: windows/__init__.py:687 +#: windows/views.py:853 msgid "Disconnect from server" msgstr "Disconnetti dal server" -#: windows/__init__.py:691 +#: windows/views.py:857 msgid "tool" msgstr "strumento" -#: windows/__init__.py:691 +#: windows/views.py:857 msgid "Refresh" msgstr "Aggiorna" -#: windows/__init__.py:695 windows/__init__.py:697 +#: windows/views.py:861 windows/views.py:863 msgid "Add" msgstr "Aggiungi" -#: windows/__init__.py:731 windows/__init__.py:735 windows/__init__.py:1507 -#: windows/__init__.py:1603 +#: windows/views.py:897 windows/views.py:901 windows/views.py:2166 +#: windows/views.py:2654 msgid "MyMenuItem" msgstr "IlMioElementoMenu" -#: windows/__init__.py:738 windows/__init__.py:1236 windows/__init__.py:2476 +#: windows/views.py:904 windows/views.py:1769 windows/views.py:3336 msgid "MyMenu" msgstr "IlMioMenu" -#: windows/__init__.py:753 +#: windows/views.py:919 windows/views.py:1350 windows/views.py:1357 +#: windows/views.py:1364 msgid "MyLabel" msgstr "LaMiaEtichetta" -#: windows/__init__.py:759 +#: windows/views.py:925 msgid "Databases" msgstr "Database" -#: windows/__init__.py:760 windows/__init__.py:822 windows/__init__.py:1959 -#: windows/__init__.py:1987 +#: windows/views.py:926 windows/views.py:1308 windows/views.py:2716 +#: windows/views.py:2744 msgid "Size" msgstr "Dimensione" -#: windows/__init__.py:761 +#: windows/views.py:927 msgid "Elements" msgstr "Elementi" -#: windows/__init__.py:762 +#: windows/views.py:928 msgid "Modified at" msgstr "Modificato il" -#: windows/__init__.py:763 windows/__init__.py:834 +#: windows/views.py:929 msgid "Tables" msgstr "Tabelle" -#: windows/__init__.py:770 +#: windows/views.py:936 msgid "System" msgstr "Sistema" -#: windows/__init__.py:786 +#: windows/views.py:979 +#, fuzzy +msgid "Character set" +msgstr "Creato il" + +#: windows/components/dataview.py:43 windows/components/dataview.py:67 +#: windows/components/dataview.py:89 windows/views.py:1000 +#: windows/views.py:1312 windows/views.py:2980 +msgid "Collation" +msgstr "Ordinamento" + +#: windows/views.py:1026 windows/views.py:2862 +msgid "Encryption" +msgstr "" + +#: windows/views.py:1038 +msgid "Read Only" +msgstr "" + +#: windows/views.py:1055 +#, fuzzy +msgid "Tablespace" +msgstr "Tabelle" + +#: windows/views.py:1076 +#, fuzzy +msgid "Connection limit" +msgstr "Connessione persa" + +#: windows/views.py:1119 +#, fuzzy +msgid "Profile" +msgstr "File" + +#: windows/views.py:1145 +#, fuzzy +msgid "Default tablespace" +msgstr "Elimina tabella" + +#: windows/views.py:1166 +#, fuzzy +msgid "Temporary tablespace" +msgstr "Temporaneo" + +#: windows/views.py:1192 +msgid "Quota" +msgstr "" + +#: windows/views.py:1211 +msgid "Unlimited quota" +msgstr "" + +#: windows/views.py:1228 +msgid "Account status" +msgstr "" + +#: windows/views.py:1249 +#, fuzzy +msgid "Password expire" +msgstr "Password" + +#: windows/views.py:1270 msgid "Table:" msgstr "Tabella:" -#: windows/__init__.py:794 windows/__init__.py:1018 windows/__init__.py:1062 -#: windows/__init__.py:1168 windows/__init__.py:2408 +#: windows/views.py:1278 windows/views.py:1551 windows/views.py:1595 +#: windows/views.py:1701 windows/views.py:3268 msgid "Insert" msgstr "Inserisci" -#: windows/__init__.py:799 +#: windows/views.py:1283 msgid "Clone" msgstr "Clona" -#: windows/__init__.py:821 +#: windows/views.py:1307 msgid "Rows" msgstr "Righe" -#: windows/__init__.py:824 windows/__init__.py:1989 +#: windows/views.py:1310 windows/views.py:2746 msgid "Updated at" msgstr "Aggiornato il" -#: windows/__init__.py:826 windows/__init__.py:2120 -#: windows/components/dataview.py:43 windows/components/dataview.py:67 -#: windows/components/dataview.py:89 -msgid "Collation" -msgstr "Ordinamento" +#: windows/views.py:1334 windows/views.py:1746 windows/views.py:2085 +#: windows/views.py:2140 +msgid "Apply" +msgstr "Applica" -#: windows/__init__.py:842 +#: windows/views.py:1344 windows/views.py:1503 windows/views.py:1956 +#: windows/views.py:3225 +msgid "Options" +msgstr "Opzioni" + +#: windows/views.py:1375 msgid "Diagram" msgstr "Diagramma" -#: windows/__init__.py:853 windows/__init__.py:1958 +#: windows/views.py:1386 windows/views.py:2715 msgid "Database" msgstr "Database" -#: windows/__init__.py:908 windows/__init__.py:2305 +#: windows/views.py:1441 windows/views.py:3165 msgid "Base" msgstr "Base" -#: windows/__init__.py:922 windows/__init__.py:2319 +#: windows/views.py:1455 windows/views.py:3179 msgid "Auto Increment" msgstr "Auto incremento" -#: windows/__init__.py:950 windows/__init__.py:2347 +#: windows/views.py:1483 windows/views.py:3207 msgid "Default Collation" msgstr "Ordinamento predefinito" -#: windows/__init__.py:970 windows/__init__.py:1301 windows/__init__.py:2365 -msgid "Options" -msgstr "Opzioni" - -#: windows/__init__.py:982 windows/__init__.py:1023 windows/__init__.py:1067 +#: windows/views.py:1515 windows/views.py:1556 windows/views.py:1600 msgid "Remove" msgstr "Rimuovi" -#: windows/__init__.py:989 windows/__init__.py:1030 windows/__init__.py:1074 +#: windows/views.py:1522 windows/views.py:1563 windows/views.py:1607 msgid "Clear" msgstr "Pulisci" -#: windows/__init__.py:1004 windows/__init__.py:2379 +#: windows/views.py:1537 windows/views.py:3239 msgid "Indexes" msgstr "Indici" -#: windows/__init__.py:1048 +#: windows/views.py:1581 msgid "Foreign Keys" msgstr "Chiavi esterne" -#: windows/__init__.py:1092 +#: windows/views.py:1625 msgid "Checks" msgstr "Vincoli" -#: windows/__init__.py:1160 windows/__init__.py:2400 +#: windows/views.py:1693 windows/views.py:3260 msgid "Columns:" msgstr "Colonne:" -#: windows/__init__.py:1180 windows/__init__.py:2420 +#: windows/views.py:1713 windows/views.py:3280 msgid "Up" msgstr "Su" -#: windows/__init__.py:1187 windows/__init__.py:2427 +#: windows/views.py:1720 windows/views.py:3287 msgid "Down" msgstr "Giù" -#: windows/__init__.py:1213 windows/__init__.py:1426 windows/__init__.py:1481 -msgid "Apply" -msgstr "Applica" - -#: windows/__init__.py:1226 windows/__init__.py:1233 windows/__init__.py:2466 -#: windows/__init__.py:2473 +#: windows/views.py:1759 windows/views.py:1766 windows/views.py:3326 +#: windows/views.py:3333 msgid "Add Index" msgstr "Aggiungi indice" -#: windows/__init__.py:1230 windows/__init__.py:2470 +#: windows/views.py:1763 windows/views.py:3330 msgid "Add PrimaryKey" msgstr "Aggiungi chiave primaria" -#: windows/__init__.py:1247 +#: windows/views.py:1780 msgid "Table" msgstr "Tabella" -#: windows/__init__.py:1280 -msgid "Temporary" -msgstr "Temporaneo" +#: windows/views.py:1816 +#, fuzzy +msgid "Definer" +msgstr "Inserisci" + +#: windows/views.py:1836 +msgid "Schema" +msgstr "" + +#: windows/views.py:1862 +msgid "SQL security" +msgstr "" + +#: windows/views.py:1869 +#, fuzzy +msgid "DEFINER" +msgstr "Inserisci" + +#: windows/views.py:1869 +#, fuzzy +msgid "INVOKER" +msgstr "Inserisci" + +#: windows/views.py:1881 windows/views.py:2558 windows/views.py:2577 +#: windows/views.py:2820 +msgid "Algorithm" +msgstr "" + +#: windows/views.py:1883 windows/views.py:2543 windows/views.py:2576 +#: windows/views.py:2825 +#, fuzzy +msgid "UNDEFINED" +msgstr "Senza segno" + +#: windows/views.py:1886 windows/views.py:2546 windows/views.py:2576 +#: windows/views.py:2828 +msgid "MERGE" +msgstr "" + +#: windows/views.py:1889 windows/views.py:2555 windows/views.py:2576 +#: windows/views.py:2831 +#, fuzzy +msgid "TEMPTABLE" +msgstr "Tabella" + +#: windows/views.py:1899 windows/views.py:2582 +msgid "View constraint" +msgstr "" + +#: windows/views.py:1901 windows/views.py:2581 +#, fuzzy +msgid "None" +msgstr "Clona" + +#: windows/views.py:1904 windows/views.py:2581 +#, fuzzy +msgid "LOCAL" +msgstr "Localizzazione" -#: windows/__init__.py:1360 +#: windows/views.py:1907 +#, fuzzy +msgid "CASCADE" +msgstr "Annulla" + +#: windows/views.py:1910 +#, fuzzy +msgid "CHECK ONLY" +msgstr "Verifica" + +#: windows/views.py:1913 windows/views.py:2581 +msgid "READ ONLY" +msgstr "" + +#: windows/views.py:1925 +msgid "Force" +msgstr "" + +#: windows/views.py:1937 +msgid "Security barrier" +msgstr "" + +#: windows/views.py:2019 msgid "Views" msgstr "Viste" -#: windows/__init__.py:1368 +#: windows/views.py:2027 msgid "Triggers" msgstr "Trigger" -#: windows/__init__.py:1380 +#: windows/views.py:2039 #, python-format msgid "Table `%(database_name)s`.`%(table_name)s`: %(total_rows) rows total" msgstr "Tabella `%(database_name)s`.`%(table_name)s`: %(total_rows) righe totali" -#: windows/__init__.py:1390 +#: windows/views.py:2049 msgid "Insert record" msgstr "Inserisci record" -#: windows/__init__.py:1395 +#: windows/views.py:2054 msgid "Duplicate record" msgstr "Duplica record" -#: windows/__init__.py:1402 +#: windows/views.py:2061 msgid "Delete record" msgstr "Elimina record" -#: windows/__init__.py:1412 +#: windows/views.py:2071 msgid "Apply changes automatically" msgstr "Applica modifiche automaticamente" -#: windows/__init__.py:1414 windows/__init__.py:1415 +#: windows/views.py:2073 windows/views.py:2074 msgid "" "If enabled, table edits are applied immediately without pressing Apply or" " Cancel" @@ -434,59 +647,76 @@ msgstr "" "Se abilitato, le modifiche alla tabella vengono applicate immediatamente " "senza premere Applica o Annulla" -#: windows/__init__.py:1436 +#: windows/views.py:2095 msgid "Next" msgstr "Avanti" -#: windows/__init__.py:1444 +#: windows/views.py:2103 msgid "Filters" msgstr "Filtri" -#: windows/__init__.py:1484 +#: windows/views.py:2143 msgid "CTRL+ENTER" msgstr "CTRL+ENTER" -#: windows/__init__.py:1504 +#: windows/views.py:2163 msgid "Insert row" msgstr "Inserisci riga" -#: windows/__init__.py:1512 +#: windows/views.py:2171 msgid "Data" msgstr "Dati" -#: windows/__init__.py:1561 +#: windows/views.py:2225 windows/views.py:2275 +msgid "New" +msgstr "Nuovo" + +#: windows/views.py:2252 msgid "Query" msgstr "Query" -#: windows/__init__.py:1581 +#: windows/views.py:2272 msgid "Close" msgstr "Chiudi" -#: windows/__init__.py:1584 windows/__init__.py:2019 -msgid "New" -msgstr "Nuovo" - -#: windows/__init__.py:1594 +#: windows/views.py:2285 msgid "Query #2" msgstr "Query #2" -#: windows/__init__.py:1835 +#: windows/views.py:2537 msgid "Column5" msgstr "Colonna5" -#: windows/__init__.py:1842 +#: windows/views.py:2548 +msgid "Import" +msgstr "Importa" + +#: windows/views.py:2573 +msgid "Read only" +msgstr "" + +#: windows/views.py:2581 +msgid "CASCADED" +msgstr "" + +#: windows/views.py:2581 +#, fuzzy +msgid "CHECK OPTION" +msgstr "connessione" + +#: windows/views.py:2613 msgid "collapsible" msgstr "collassabile" -#: windows/__init__.py:1864 +#: windows/views.py:2629 msgid "Column3" msgstr "Colonna3" -#: windows/__init__.py:1865 +#: windows/views.py:2630 msgid "Column4" msgstr "Colonna4" -#: windows/__init__.py:1902 +#: windows/views.py:2673 msgid "" "Database " "(*.db;*.db3;*.sdb;*.s3db;*.sqlite;*.sqlite3)|*.db;*.db3;*.sdb;*.s3db;*.sqlite;*.sqlite3" @@ -494,65 +724,78 @@ msgstr "" "Database " "(*.db;*.db3;*.sdb;*.s3db;*.sqlite;*.sqlite3)|*.db;*.db3;*.sdb;*.s3db;*.sqlite;*.sqlite3" -#: windows/__init__.py:1934 +#: windows/views.py:2685 msgid "Port" msgstr "Porta" -#: windows/__init__.py:1951 +#: windows/views.py:2708 msgid "Usage" msgstr "Utilizzo" -#: windows/__init__.py:1962 +#: windows/views.py:2719 #, python-format msgid "%(total_rows)s" msgstr "%(total_rows)s" -#: windows/__init__.py:1967 +#: windows/views.py:2724 msgid "rows total" msgstr "righe totali" -#: windows/__init__.py:1986 +#: windows/views.py:2743 msgid "Lines" msgstr "Righe" -#: windows/__init__.py:2068 +#: windows/views.py:2775 +msgid "Temporary" +msgstr "Temporaneo" + +#: windows/views.py:2786 +#, fuzzy +msgid "Engine options" +msgstr "Opzioni" + +#: windows/views.py:2845 +msgid "RadioBtn" +msgstr "" + +#: windows/views.py:2928 msgid "Edit Column" msgstr "Modifica colonna" -#: windows/__init__.py:2084 +#: windows/views.py:2944 msgid "Datatype" msgstr "Tipo di dati" -#: windows/__init__.py:2099 windows/components/dataview.py:121 +#: windows/components/dataview.py:121 windows/views.py:2959 msgid "Length/Set" msgstr "Lunghezza/Insieme" -#: windows/__init__.py:2138 windows/components/dataview.py:51 +#: windows/components/dataview.py:51 windows/views.py:2998 msgid "Unsigned" msgstr "Senza segno" -#: windows/__init__.py:2144 windows/components/dataview.py:25 -#: windows/components/dataview.py:52 windows/components/dataview.py:75 +#: windows/components/dataview.py:25 windows/components/dataview.py:52 +#: windows/components/dataview.py:75 windows/views.py:3004 msgid "Allow NULL" msgstr "Consenti NULL" -#: windows/__init__.py:2150 +#: windows/views.py:3010 msgid "Zero Fill" msgstr "Riempimento zero" -#: windows/__init__.py:2161 windows/components/dataview.py:32 -#: windows/components/dataview.py:56 windows/components/dataview.py:78 +#: windows/components/dataview.py:32 windows/components/dataview.py:56 +#: windows/components/dataview.py:78 windows/views.py:3021 msgid "Default" msgstr "Predefinito" -#: windows/__init__.py:2187 windows/components/dataview.py:36 -#: windows/components/dataview.py:60 windows/components/dataview.py:82 +#: windows/components/dataview.py:36 windows/components/dataview.py:60 +#: windows/components/dataview.py:82 windows/views.py:3047 msgid "Virtuality" msgstr "Virtualità" -#: windows/__init__.py:2202 windows/components/dataview.py:39 -#: windows/components/dataview.py:63 windows/components/dataview.py:85 -#: windows/components/dataview.py:241 +#: windows/components/dataview.py:39 windows/components/dataview.py:63 +#: windows/components/dataview.py:85 windows/components/dataview.py:241 +#: windows/views.py:3062 msgid "Expression" msgstr "Espressione" @@ -632,103 +875,232 @@ msgstr "Aggiungi chiave esterna" msgid "Remove foreign key" msgstr "Rimuovi chiave esterna" -#: windows/components/popup.py:24 +#: windows/components/popup.py:26 msgid "No default value" msgstr "Nessun valore predefinito" -#: windows/components/popup.py:29 +#: windows/components/popup.py:31 msgid "NULL" msgstr "NULL" -#: windows/components/popup.py:33 +#: windows/components/popup.py:35 msgid "AUTO INCREMENT" msgstr "AUTO INCREMENTO" -#: windows/components/popup.py:37 +#: windows/components/popup.py:39 msgid "Text/Expression" msgstr "Testo/Espressione" -#: windows/connections/manager.py:125 +#: windows/dialogs/connections/view.py:119 windows/main/tabs/query.py:376 +msgid "Unknown error" +msgstr "" + +#: windows/dialogs/connections/view.py:394 +msgid "Connection established successfully" +msgstr "" + +#: windows/dialogs/connections/view.py:407 msgid "Confirm save" msgstr "Conferma salvataggio" -#: windows/connections/manager.py:193 +#: windows/dialogs/connections/view.py:459 +msgid "You have unsaved changes. Do you want to save them before continuing?" +msgstr "" + +#: windows/dialogs/connections/view.py:461 +msgid "Unsaved changes" +msgstr "" + +#: windows/dialogs/connections/view.py:736 +msgid "" +"This connection cannot work without TLS. TLS has been enabled " +"automatically." +msgstr "" + +#: windows/dialogs/connections/view.py:762 msgid "Connection error" msgstr "Errore di connessione" -#: windows/connections/manager.py:214 -msgid "connection" -msgstr "connessione" - -#: windows/connections/manager.py:215 windows/connections/manager.py:230 +#: windows/dialogs/connections/view.py:788 +#: windows/dialogs/connections/view.py:803 msgid "Confirm delete" msgstr "Conferma eliminazione" -#: windows/connections/manager.py:229 -msgid "directory" -msgstr "directory" - -#: windows/connections/model.py:101 -msgid "New connection" -msgstr "Nuova connessione" - -#: windows/main/database.py:70 -msgid "The connection to the database was lost." -msgstr "La connessione al database è stata persa." - -#: windows/main/database.py:72 -msgid "Do you want to reconnect?" -msgstr "Vuoi riconnetterti?" - -#: windows/main/database.py:74 -msgid "Connection lost" -msgstr "Connessione persa" - -#: windows/main/database.py:83 -msgid "Reconnection failed:" -msgstr "Riconnessione fallita:" - -#: windows/main/database.py:84 -msgid "Error" -msgstr "Errore" - -#: windows/main/main_frame.py:124 +#: windows/main/controller.py:172 msgid "days" msgstr "giorni" -#: windows/main/main_frame.py:125 +#: windows/main/controller.py:173 msgid "hours" msgstr "ore" -#: windows/main/main_frame.py:126 +#: windows/main/controller.py:174 msgid "minutes" msgstr "minuti" -#: windows/main/main_frame.py:127 +#: windows/main/controller.py:175 msgid "seconds" msgstr "secondi" -#: windows/main/main_frame.py:135 +#: windows/main/controller.py:183 #, python-brace-format msgid "Memory used: {used} ({percentage:.2%})" msgstr "Memoria utilizzata: {used} ({percentage:.2%})" -#: windows/main/main_frame.py:226 +#: windows/main/controller.py:219 +msgid "Settings saved successfully" +msgstr "" + +#: windows/main/controller.py:298 msgid "Version" msgstr "Versione" -#: windows/main/main_frame.py:228 +#: windows/main/controller.py:300 msgid "Uptime" msgstr "Tempo di attività" -#: windows/main/main_frame.py:431 +#: windows/main/controller.py:399 +#, python-brace-format +msgid "" +"Do you want to create a dump before dropping database '{database_name}'?\n" +"\n" +"Dump is not implemented yet.\n" +"- Yes: open dump flow (coming soon, no drop).\n" +"- No: drop the database now." +msgstr "" + +#: windows/main/controller.py:404 windows/main/controller.py:425 +#, fuzzy +msgid "Delete database" +msgstr "Elimina tabella" + +#: windows/main/controller.py:410 +msgid "Dump is not implemented yet. No action has been performed." +msgstr "" + +#: windows/main/controller.py:411 +msgid "Dump not available" +msgstr "" + +#: windows/main/controller.py:424 +msgid "Database deletion is not supported by this engine." +msgstr "" + +#: windows/main/controller.py:439 +msgid "Database deleted successfully" +msgstr "" + +#: windows/main/controller.py:440 windows/main/tabs/view.py:253 +#: windows/main/tabs/view.py:279 +msgid "Success" +msgstr "" + +#: windows/main/controller.py:582 msgid "Delete table" msgstr "Elimina tabella" -#: windows/main/main_frame.py:586 +#: windows/main/controller.py:699 msgid "Do you want delete the records?" msgstr "Vuoi eliminare i record?" +#: windows/main/tabs/database.py:71 +msgid "The connection to the database was lost." +msgstr "La connessione al database è stata persa." + +#: windows/main/tabs/database.py:73 +msgid "Do you want to reconnect?" +msgstr "Vuoi riconnetterti?" + +#: windows/main/tabs/database.py:75 +msgid "Connection lost" +msgstr "Connessione persa" + +#: windows/main/tabs/database.py:85 +msgid "Reconnection failed:" +msgstr "Riconnessione fallita:" + +#: windows/main/tabs/database.py:86 windows/main/tabs/query.py:450 +#: windows/main/tabs/view.py:256 windows/main/tabs/view.py:282 +msgid "Error" +msgstr "Errore" + +#: windows/main/tabs/query.py:305 +#, python-brace-format +msgid "{} rows affected" +msgstr "" + +#: windows/main/tabs/query.py:309 windows/main/tabs/query.py:331 +#, fuzzy, python-brace-format +msgid "Query {}" +msgstr "Query" + +#: windows/main/tabs/query.py:314 +#, python-brace-format +msgid "Query {} (Error)" +msgstr "" + +#: windows/main/tabs/query.py:326 +#, python-brace-format +msgid "Query {} ({} rows × {} cols)" +msgstr "" + +#: windows/main/tabs/query.py:353 +#, fuzzy, python-brace-format +msgid "{} rows" +msgstr "Righe" + +#: windows/main/tabs/query.py:355 +#, python-brace-format +msgid "{:.1f} ms" +msgstr "" + +#: windows/main/tabs/query.py:358 +#, python-brace-format +msgid "{} warnings" +msgstr "" + +#: windows/main/tabs/query.py:370 +#, fuzzy +msgid "Error:" +msgstr "Errore" + +#: windows/main/tabs/query.py:449 +#, fuzzy +msgid "No active database connection" +msgstr "Nuova connessione" + +#: windows/main/tabs/view.py:252 +msgid "View created successfully" +msgstr "" + +#: windows/main/tabs/view.py:252 +msgid "View updated successfully" +msgstr "" + +#: windows/main/tabs/view.py:256 +#, python-brace-format +msgid "Error saving view: {}" +msgstr "" + +#: windows/main/tabs/view.py:269 +#, python-brace-format +msgid "Are you sure you want to delete view '{}'?" +msgstr "" + +#: windows/main/tabs/view.py:270 +#, fuzzy +msgid "Confirm Delete" +msgstr "Conferma eliminazione" + +#: windows/main/tabs/view.py:279 +msgid "View deleted successfully" +msgstr "" + +#: windows/main/tabs/view.py:282 +#, python-brace-format +msgid "Error deleting view: {}" +msgstr "" + #~ msgid "Created at:" #~ msgstr "" @@ -753,3 +1125,9 @@ msgstr "Vuoi eliminare i record?" #~ msgid "Foreign Key" #~ msgstr "" +#~ msgid "New Session" +#~ msgstr "Nuova sessione" + +#~ msgid "directory" +#~ msgstr "directory" + diff --git a/locale/petersql.pot b/locale/petersql.pot index 4b90a0e..da6114d 100644 --- a/locale/petersql.pot +++ b/locale/petersql.pot @@ -1,545 +1,750 @@ -#: helpers/__init__.py:14 +#: helpers/__init__.py:16 msgctxt "unit" msgid "B" msgstr "" -#: helpers/__init__.py:15 +#: helpers/__init__.py:17 msgctxt "unit" msgid "KB" msgstr "" -#: helpers/__init__.py:16 +#: helpers/__init__.py:18 msgctxt "unit" msgid "MB" msgstr "" -#: helpers/__init__.py:17 +#: helpers/__init__.py:19 msgctxt "unit" msgid "GB" msgstr "" -#: helpers/__init__.py:18 +#: helpers/__init__.py:20 msgctxt "unit" msgid "TB" msgstr "" -#: structures/ssh_tunnel.py:117 +#: structures/ssh_tunnel.py:166 msgid "OpenSSH client not found." msgstr "" -#: windows/__init__.py:31 windows/main/main_frame.py:224 +#: windows/dialogs/connections/view.py:395 +#: windows/dialogs/connections/view.py:738 windows/main/controller.py:296 +#: windows/views.py:33 msgid "Connection" msgstr "" -#: windows/__init__.py:45 windows/__init__.py:83 windows/__init__.py:820 -#: windows/__init__.py:880 windows/__init__.py:1267 windows/__init__.py:1950 -#: windows/__init__.py:1973 windows/__init__.py:1974 windows/__init__.py:1975 -#: windows/__init__.py:1976 windows/__init__.py:1977 windows/__init__.py:1978 -#: windows/__init__.py:1979 windows/__init__.py:1980 windows/__init__.py:1981 -#: windows/__init__.py:1985 windows/__init__.py:2076 windows/__init__.py:2277 #: windows/components/dataview.py:113 windows/components/dataview.py:225 #: windows/components/dataview.py:238 windows/components/dataview.py:253 +#: windows/views.py:47 windows/views.py:97 windows/views.py:956 +#: windows/views.py:1306 windows/views.py:1413 windows/views.py:1796 +#: windows/views.py:2707 windows/views.py:2730 windows/views.py:2731 +#: windows/views.py:2732 windows/views.py:2733 windows/views.py:2734 +#: windows/views.py:2735 windows/views.py:2736 windows/views.py:2737 +#: windows/views.py:2738 windows/views.py:2742 windows/views.py:2936 +#: windows/views.py:3137 msgid "Name" msgstr "" -#: windows/__init__.py:46 windows/__init__.py:322 +#: windows/views.py:48 windows/views.py:381 msgid "Last connection" msgstr "" -#: windows/__init__.py:59 windows/connections/manager.py:174 +#: windows/dialogs/connections/view.py:631 windows/views.py:61 msgid "New directory" msgstr "" -#: windows/__init__.py:62 -msgid "New Session" +#: windows/dialogs/connections/model.py:187 +#: windows/dialogs/connections/view.py:591 windows/views.py:65 +msgid "New connection" +msgstr "" + +#: windows/views.py:71 +msgid "Rename" msgstr "" -#: windows/__init__.py:67 -msgid "Import" +#: windows/views.py:76 +msgid "Clone connection" msgstr "" -#: windows/__init__.py:97 windows/__init__.py:825 windows/__init__.py:935 -#: windows/__init__.py:1990 windows/__init__.py:2332 +#: windows/views.py:81 windows/views.py:556 windows/views.py:1290 +#: windows/views.py:1331 windows/views.py:1706 windows/views.py:1738 +#: windows/views.py:1997 windows/views.py:3273 windows/views.py:3305 +msgid "Delete" +msgstr "" + +#: windows/views.py:111 windows/views.py:1311 windows/views.py:1468 +#: windows/views.py:2747 windows/views.py:3192 msgid "Engine" msgstr "" -#: windows/__init__.py:118 +#: windows/views.py:132 msgid "Host + port" msgstr "" -#: windows/__init__.py:134 +#: windows/views.py:148 msgid "Username" msgstr "" -#: windows/__init__.py:147 +#: windows/views.py:161 windows/views.py:1100 msgid "Password" msgstr "" -#: windows/__init__.py:163 +#: windows/views.py:177 +msgid "Use TLS" +msgstr "" + +#: windows/views.py:180 msgid "Use SSH tunnel" msgstr "" -#: windows/__init__.py:185 windows/__init__.py:1897 +#: windows/views.py:202 windows/views.py:2668 msgid "Filename" msgstr "" -#: windows/__init__.py:190 windows/__init__.py:1902 +#: windows/views.py:207 windows/views.py:324 windows/views.py:2673 +#: windows/views.py:2856 msgid "Select a file" msgstr "" -#: windows/__init__.py:190 +#: windows/views.py:207 windows/views.py:324 windows/views.py:2856 msgid "*.*" msgstr "" -#: windows/__init__.py:204 windows/__init__.py:827 windows/__init__.py:893 -#: windows/__init__.py:1991 windows/__init__.py:2174 windows/__init__.py:2290 #: windows/components/dataview.py:70 windows/components/dataview.py:92 +#: windows/views.py:221 windows/views.py:1313 windows/views.py:1426 +#: windows/views.py:2748 windows/views.py:3034 windows/views.py:3150 msgid "Comments" msgstr "" -#: windows/__init__.py:218 windows/__init__.py:520 +#: windows/main/controller.py:219 windows/views.py:235 windows/views.py:683 +#: windows/views.py:837 msgid "Settings" msgstr "" -#: windows/__init__.py:227 +#: windows/views.py:244 msgid "SSH executable" msgstr "" -#: windows/__init__.py:232 +#: windows/views.py:249 msgid "ssh" msgstr "" -#: windows/__init__.py:240 +#: windows/views.py:257 msgid "SSH host + port" msgstr "" -#: windows/__init__.py:256 +#: windows/views.py:269 +msgid "SSH host + port (the SSH server that forwards traffic to the DB)" +msgstr "" + +#: windows/views.py:278 msgid "SSH username" msgstr "" -#: windows/__init__.py:269 +#: windows/views.py:291 msgid "SSH password" msgstr "" -#: windows/__init__.py:282 +#: windows/views.py:304 msgid "Local port" msgstr "" -#: windows/__init__.py:288 +#: windows/views.py:310 msgid "if the value is set to 0, the first available port will be used" msgstr "" -#: windows/__init__.py:299 +#: windows/views.py:319 +msgid "Identity file" +msgstr "" + +#: windows/views.py:335 +msgid "Remote host + port" +msgstr "" + +#: windows/views.py:347 +msgid "Remote host/port is the real DB target (defaults to DB Host/Port)." +msgstr "" + +#: windows/views.py:358 msgid "SSH Tunnel" msgstr "" -#: windows/__init__.py:305 windows/__init__.py:823 windows/__init__.py:1988 +#: windows/views.py:364 windows/views.py:1309 windows/views.py:2745 msgid "Created at" msgstr "" -#: windows/__init__.py:339 +#: windows/views.py:398 msgid "Successful connections" msgstr "" -#: windows/__init__.py:356 +#: windows/views.py:415 +msgid "Last successful connection" +msgstr "" + +#: windows/views.py:432 msgid "Unsuccessful connections" msgstr "" -#: windows/__init__.py:375 +#: windows/views.py:449 +msgid "Last failure reason" +msgstr "" + +#: windows/views.py:466 +msgid "Total connection attempts" +msgstr "" + +#: windows/views.py:483 +msgid " Average connection time (ms)" +msgstr "" + +#: windows/views.py:500 +msgid " Most recent connection duration" +msgstr "" + +#: windows/views.py:519 msgid "Statistics" msgstr "" -#: windows/__init__.py:393 windows/__init__.py:1139 +#: windows/views.py:537 windows/views.py:1672 msgid "Create" msgstr "" -#: windows/__init__.py:403 windows/__init__.py:806 windows/__init__.py:1173 -#: windows/__init__.py:1205 windows/__init__.py:1340 windows/__init__.py:2413 -#: windows/__init__.py:2445 -msgid "Delete" +#: windows/views.py:541 +msgid "Create connection" +msgstr "" + +#: windows/views.py:544 +msgid "Create directory" msgstr "" -#: windows/__init__.py:420 windows/__init__.py:634 windows/__init__.py:1208 -#: windows/__init__.py:1343 windows/__init__.py:1419 windows/__init__.py:2221 -#: windows/__init__.py:2448 +#: windows/views.py:573 windows/views.py:797 windows/views.py:1328 +#: windows/views.py:1741 windows/views.py:2002 windows/views.py:2078 +#: windows/views.py:3081 windows/views.py:3308 msgid "Cancel" msgstr "" -#: windows/__init__.py:425 windows/__init__.py:1348 windows/__init__.py:2231 -#: windows/__init__.py:2453 +#: windows/views.py:578 windows/views.py:2007 windows/views.py:3091 +#: windows/views.py:3313 msgid "Save" msgstr "" -#: windows/__init__.py:432 +#: windows/views.py:585 msgid "Test" msgstr "" -#: windows/__init__.py:439 +#: windows/views.py:592 msgid "Connect" msgstr "" -#: windows/__init__.py:532 +#: windows/views.py:695 msgid "Language" msgstr "" -#: windows/__init__.py:537 +#: windows/views.py:700 msgid "English" msgstr "" -#: windows/__init__.py:537 +#: windows/views.py:700 msgid "Italian" msgstr "" -#: windows/__init__.py:537 +#: windows/views.py:700 msgid "French" msgstr "" -#: windows/__init__.py:549 +#: windows/views.py:712 msgid "Locale" msgstr "" -#: windows/__init__.py:570 +#: windows/views.py:733 msgid "Edit Value" msgstr "" -#: windows/__init__.py:580 +#: windows/views.py:743 msgid "Syntax" msgstr "" -#: windows/__init__.py:637 +#: windows/views.py:800 msgid "Ok" msgstr "" -#: windows/__init__.py:668 +#: windows/views.py:831 msgid "PeterSQL" msgstr "" -#: windows/__init__.py:674 +#: windows/views.py:840 msgid "File" msgstr "" -#: windows/__init__.py:677 +#: windows/views.py:843 msgid "About" msgstr "" -#: windows/__init__.py:680 +#: windows/views.py:846 msgid "Help" msgstr "" -#: windows/__init__.py:685 +#: windows/views.py:851 msgid "Open connection manager" msgstr "" -#: windows/__init__.py:687 +#: windows/views.py:853 msgid "Disconnect from server" msgstr "" -#: windows/__init__.py:691 +#: windows/views.py:857 msgid "tool" msgstr "" -#: windows/__init__.py:691 +#: windows/views.py:857 msgid "Refresh" msgstr "" -#: windows/__init__.py:695 windows/__init__.py:697 +#: windows/views.py:861 windows/views.py:863 msgid "Add" msgstr "" -#: windows/__init__.py:731 windows/__init__.py:735 windows/__init__.py:1507 -#: windows/__init__.py:1603 +#: windows/views.py:897 windows/views.py:901 windows/views.py:2166 +#: windows/views.py:2654 msgid "MyMenuItem" msgstr "" -#: windows/__init__.py:738 windows/__init__.py:1236 windows/__init__.py:2476 +#: windows/views.py:904 windows/views.py:1769 windows/views.py:3336 msgid "MyMenu" msgstr "" -#: windows/__init__.py:753 +#: windows/views.py:919 windows/views.py:1350 windows/views.py:1357 +#: windows/views.py:1364 msgid "MyLabel" msgstr "" -#: windows/__init__.py:759 +#: windows/views.py:925 msgid "Databases" msgstr "" -#: windows/__init__.py:760 windows/__init__.py:822 windows/__init__.py:1959 -#: windows/__init__.py:1987 +#: windows/views.py:926 windows/views.py:1308 windows/views.py:2716 +#: windows/views.py:2744 msgid "Size" msgstr "" -#: windows/__init__.py:761 +#: windows/views.py:927 msgid "Elements" msgstr "" -#: windows/__init__.py:762 +#: windows/views.py:928 msgid "Modified at" msgstr "" -#: windows/__init__.py:763 windows/__init__.py:834 +#: windows/views.py:929 msgid "Tables" msgstr "" -#: windows/__init__.py:770 +#: windows/views.py:936 msgid "System" msgstr "" -#: windows/__init__.py:786 +#: windows/views.py:979 +msgid "Character set" +msgstr "" + +#: windows/components/dataview.py:43 windows/components/dataview.py:67 +#: windows/components/dataview.py:89 windows/views.py:1000 +#: windows/views.py:1312 windows/views.py:2980 +msgid "Collation" +msgstr "" + +#: windows/views.py:1026 windows/views.py:2862 +msgid "Encryption" +msgstr "" + +#: windows/views.py:1038 +msgid "Read Only" +msgstr "" + +#: windows/views.py:1055 +msgid "Tablespace" +msgstr "" + +#: windows/views.py:1076 +msgid "Connection limit" +msgstr "" + +#: windows/views.py:1119 +msgid "Profile" +msgstr "" + +#: windows/views.py:1145 +msgid "Default tablespace" +msgstr "" + +#: windows/views.py:1166 +msgid "Temporary tablespace" +msgstr "" + +#: windows/views.py:1192 +msgid "Quota" +msgstr "" + +#: windows/views.py:1211 +msgid "Unlimited quota" +msgstr "" + +#: windows/views.py:1228 +msgid "Account status" +msgstr "" + +#: windows/views.py:1249 +msgid "Password expire" +msgstr "" + +#: windows/views.py:1270 msgid "Table:" msgstr "" -#: windows/__init__.py:794 windows/__init__.py:1018 windows/__init__.py:1062 -#: windows/__init__.py:1168 windows/__init__.py:2408 +#: windows/views.py:1278 windows/views.py:1551 windows/views.py:1595 +#: windows/views.py:1701 windows/views.py:3268 msgid "Insert" msgstr "" -#: windows/__init__.py:799 +#: windows/views.py:1283 msgid "Clone" msgstr "" -#: windows/__init__.py:821 +#: windows/views.py:1307 msgid "Rows" msgstr "" -#: windows/__init__.py:824 windows/__init__.py:1989 +#: windows/views.py:1310 windows/views.py:2746 msgid "Updated at" msgstr "" -#: windows/__init__.py:826 windows/__init__.py:2120 -#: windows/components/dataview.py:43 windows/components/dataview.py:67 -#: windows/components/dataview.py:89 -msgid "Collation" +#: windows/views.py:1334 windows/views.py:1746 windows/views.py:2085 +#: windows/views.py:2140 +msgid "Apply" msgstr "" -#: windows/__init__.py:842 +#: windows/views.py:1344 windows/views.py:1503 windows/views.py:1956 +#: windows/views.py:3225 +msgid "Options" +msgstr "" + +#: windows/views.py:1375 msgid "Diagram" msgstr "" -#: windows/__init__.py:853 windows/__init__.py:1958 +#: windows/views.py:1386 windows/views.py:2715 msgid "Database" msgstr "" -#: windows/__init__.py:908 windows/__init__.py:2305 +#: windows/views.py:1441 windows/views.py:3165 msgid "Base" msgstr "" -#: windows/__init__.py:922 windows/__init__.py:2319 +#: windows/views.py:1455 windows/views.py:3179 msgid "Auto Increment" msgstr "" -#: windows/__init__.py:950 windows/__init__.py:2347 +#: windows/views.py:1483 windows/views.py:3207 msgid "Default Collation" msgstr "" -#: windows/__init__.py:970 windows/__init__.py:1301 windows/__init__.py:2365 -msgid "Options" -msgstr "" - -#: windows/__init__.py:982 windows/__init__.py:1023 windows/__init__.py:1067 +#: windows/views.py:1515 windows/views.py:1556 windows/views.py:1600 msgid "Remove" msgstr "" -#: windows/__init__.py:989 windows/__init__.py:1030 windows/__init__.py:1074 +#: windows/views.py:1522 windows/views.py:1563 windows/views.py:1607 msgid "Clear" msgstr "" -#: windows/__init__.py:1004 windows/__init__.py:2379 +#: windows/views.py:1537 windows/views.py:3239 msgid "Indexes" msgstr "" -#: windows/__init__.py:1048 +#: windows/views.py:1581 msgid "Foreign Keys" msgstr "" -#: windows/__init__.py:1092 +#: windows/views.py:1625 msgid "Checks" msgstr "" -#: windows/__init__.py:1160 windows/__init__.py:2400 +#: windows/views.py:1693 windows/views.py:3260 msgid "Columns:" msgstr "" -#: windows/__init__.py:1180 windows/__init__.py:2420 +#: windows/views.py:1713 windows/views.py:3280 msgid "Up" msgstr "" -#: windows/__init__.py:1187 windows/__init__.py:2427 +#: windows/views.py:1720 windows/views.py:3287 msgid "Down" msgstr "" -#: windows/__init__.py:1213 windows/__init__.py:1426 windows/__init__.py:1481 -msgid "Apply" -msgstr "" - -#: windows/__init__.py:1226 windows/__init__.py:1233 windows/__init__.py:2466 -#: windows/__init__.py:2473 +#: windows/views.py:1759 windows/views.py:1766 windows/views.py:3326 +#: windows/views.py:3333 msgid "Add Index" msgstr "" -#: windows/__init__.py:1230 windows/__init__.py:2470 +#: windows/views.py:1763 windows/views.py:3330 msgid "Add PrimaryKey" msgstr "" -#: windows/__init__.py:1247 +#: windows/views.py:1780 msgid "Table" msgstr "" -#: windows/__init__.py:1280 -msgid "Temporary" +#: windows/views.py:1816 +msgid "Definer" +msgstr "" + +#: windows/views.py:1836 +msgid "Schema" +msgstr "" + +#: windows/views.py:1862 +msgid "SQL security" +msgstr "" + +#: windows/views.py:1869 +msgid "DEFINER" +msgstr "" + +#: windows/views.py:1869 +msgid "INVOKER" +msgstr "" + +#: windows/views.py:1881 windows/views.py:2558 windows/views.py:2577 +#: windows/views.py:2820 +msgid "Algorithm" +msgstr "" + +#: windows/views.py:1883 windows/views.py:2543 windows/views.py:2576 +#: windows/views.py:2825 +msgid "UNDEFINED" +msgstr "" + +#: windows/views.py:1886 windows/views.py:2546 windows/views.py:2576 +#: windows/views.py:2828 +msgid "MERGE" +msgstr "" + +#: windows/views.py:1889 windows/views.py:2555 windows/views.py:2576 +#: windows/views.py:2831 +msgid "TEMPTABLE" +msgstr "" + +#: windows/views.py:1899 windows/views.py:2582 +msgid "View constraint" +msgstr "" + +#: windows/views.py:1901 windows/views.py:2581 +msgid "None" +msgstr "" + +#: windows/views.py:1904 windows/views.py:2581 +msgid "LOCAL" +msgstr "" + +#: windows/views.py:1907 +msgid "CASCADE" +msgstr "" + +#: windows/views.py:1910 +msgid "CHECK ONLY" +msgstr "" + +#: windows/views.py:1913 windows/views.py:2581 +msgid "READ ONLY" +msgstr "" + +#: windows/views.py:1925 +msgid "Force" +msgstr "" + +#: windows/views.py:1937 +msgid "Security barrier" msgstr "" -#: windows/__init__.py:1360 +#: windows/views.py:2019 msgid "Views" msgstr "" -#: windows/__init__.py:1368 +#: windows/views.py:2027 msgid "Triggers" msgstr "" -#: windows/__init__.py:1380 +#: windows/views.py:2039 #, python-format msgid "Table `%(database_name)s`.`%(table_name)s`: %(total_rows) rows total" msgstr "" -#: windows/__init__.py:1390 +#: windows/views.py:2049 msgid "Insert record" msgstr "" -#: windows/__init__.py:1395 +#: windows/views.py:2054 msgid "Duplicate record" msgstr "" -#: windows/__init__.py:1402 +#: windows/views.py:2061 msgid "Delete record" msgstr "" -#: windows/__init__.py:1412 +#: windows/views.py:2071 msgid "Apply changes automatically" msgstr "" -#: windows/__init__.py:1414 windows/__init__.py:1415 +#: windows/views.py:2073 windows/views.py:2074 msgid "" "If enabled, table edits are applied immediately without pressing Apply or" " Cancel" msgstr "" -#: windows/__init__.py:1436 +#: windows/views.py:2095 msgid "Next" msgstr "" -#: windows/__init__.py:1444 +#: windows/views.py:2103 msgid "Filters" msgstr "" -#: windows/__init__.py:1484 +#: windows/views.py:2143 msgid "CTRL+ENTER" msgstr "" -#: windows/__init__.py:1504 +#: windows/views.py:2163 msgid "Insert row" msgstr "" -#: windows/__init__.py:1512 +#: windows/views.py:2171 msgid "Data" msgstr "" -#: windows/__init__.py:1561 -msgid "Query" +#: windows/views.py:2225 windows/views.py:2275 +msgid "New" msgstr "" -#: windows/__init__.py:1581 -msgid "Close" +#: windows/views.py:2252 +msgid "Query" msgstr "" -#: windows/__init__.py:1584 windows/__init__.py:2019 -msgid "New" +#: windows/views.py:2272 +msgid "Close" msgstr "" -#: windows/__init__.py:1594 +#: windows/views.py:2285 msgid "Query #2" msgstr "" -#: windows/__init__.py:1835 +#: windows/views.py:2537 msgid "Column5" msgstr "" -#: windows/__init__.py:1842 +#: windows/views.py:2548 +msgid "Import" +msgstr "" + +#: windows/views.py:2573 +msgid "Read only" +msgstr "" + +#: windows/views.py:2581 +msgid "CASCADED" +msgstr "" + +#: windows/views.py:2581 +msgid "CHECK OPTION" +msgstr "" + +#: windows/views.py:2613 msgid "collapsible" msgstr "" -#: windows/__init__.py:1864 +#: windows/views.py:2629 msgid "Column3" msgstr "" -#: windows/__init__.py:1865 +#: windows/views.py:2630 msgid "Column4" msgstr "" -#: windows/__init__.py:1902 +#: windows/views.py:2673 msgid "" "Database " "(*.db;*.db3;*.sdb;*.s3db;*.sqlite;*.sqlite3)|*.db;*.db3;*.sdb;*.s3db;*.sqlite;*.sqlite3" msgstr "" -#: windows/__init__.py:1934 +#: windows/views.py:2685 msgid "Port" msgstr "" -#: windows/__init__.py:1951 +#: windows/views.py:2708 msgid "Usage" msgstr "" -#: windows/__init__.py:1962 +#: windows/views.py:2719 #, python-format msgid "%(total_rows)s" msgstr "" -#: windows/__init__.py:1967 +#: windows/views.py:2724 msgid "rows total" msgstr "" -#: windows/__init__.py:1986 +#: windows/views.py:2743 msgid "Lines" msgstr "" -#: windows/__init__.py:2068 +#: windows/views.py:2775 +msgid "Temporary" +msgstr "" + +#: windows/views.py:2786 +msgid "Engine options" +msgstr "" + +#: windows/views.py:2845 +msgid "RadioBtn" +msgstr "" + +#: windows/views.py:2928 msgid "Edit Column" msgstr "" -#: windows/__init__.py:2084 +#: windows/views.py:2944 msgid "Datatype" msgstr "" -#: windows/__init__.py:2099 windows/components/dataview.py:121 +#: windows/components/dataview.py:121 windows/views.py:2959 msgid "Length/Set" msgstr "" -#: windows/__init__.py:2138 windows/components/dataview.py:51 +#: windows/components/dataview.py:51 windows/views.py:2998 msgid "Unsigned" msgstr "" -#: windows/__init__.py:2144 windows/components/dataview.py:25 -#: windows/components/dataview.py:52 windows/components/dataview.py:75 +#: windows/components/dataview.py:25 windows/components/dataview.py:52 +#: windows/components/dataview.py:75 windows/views.py:3004 msgid "Allow NULL" msgstr "" -#: windows/__init__.py:2150 +#: windows/views.py:3010 msgid "Zero Fill" msgstr "" -#: windows/__init__.py:2161 windows/components/dataview.py:32 -#: windows/components/dataview.py:56 windows/components/dataview.py:78 +#: windows/components/dataview.py:32 windows/components/dataview.py:56 +#: windows/components/dataview.py:78 windows/views.py:3021 msgid "Default" msgstr "" -#: windows/__init__.py:2187 windows/components/dataview.py:36 -#: windows/components/dataview.py:60 windows/components/dataview.py:82 +#: windows/components/dataview.py:36 windows/components/dataview.py:60 +#: windows/components/dataview.py:82 windows/views.py:3047 msgid "Virtuality" msgstr "" -#: windows/__init__.py:2202 windows/components/dataview.py:39 -#: windows/components/dataview.py:63 windows/components/dataview.py:85 -#: windows/components/dataview.py:241 +#: windows/components/dataview.py:39 windows/components/dataview.py:63 +#: windows/components/dataview.py:85 windows/components/dataview.py:241 +#: windows/views.py:3062 msgid "Expression" msgstr "" @@ -619,100 +824,225 @@ msgstr "" msgid "Remove foreign key" msgstr "" -#: windows/components/popup.py:24 +#: windows/components/popup.py:26 msgid "No default value" msgstr "" -#: windows/components/popup.py:29 +#: windows/components/popup.py:31 msgid "NULL" msgstr "" -#: windows/components/popup.py:33 +#: windows/components/popup.py:35 msgid "AUTO INCREMENT" msgstr "" -#: windows/components/popup.py:37 +#: windows/components/popup.py:39 msgid "Text/Expression" msgstr "" -#: windows/connections/manager.py:125 +#: windows/dialogs/connections/view.py:119 windows/main/tabs/query.py:376 +msgid "Unknown error" +msgstr "" + +#: windows/dialogs/connections/view.py:394 +msgid "Connection established successfully" +msgstr "" + +#: windows/dialogs/connections/view.py:407 msgid "Confirm save" msgstr "" -#: windows/connections/manager.py:193 -msgid "Connection error" +#: windows/dialogs/connections/view.py:459 +msgid "You have unsaved changes. Do you want to save them before continuing?" msgstr "" -#: windows/connections/manager.py:214 -msgid "connection" +#: windows/dialogs/connections/view.py:461 +msgid "Unsaved changes" msgstr "" -#: windows/connections/manager.py:215 windows/connections/manager.py:230 +#: windows/dialogs/connections/view.py:736 +msgid "" +"This connection cannot work without TLS. TLS has been enabled " +"automatically." +msgstr "" + +#: windows/dialogs/connections/view.py:762 +msgid "Connection error" +msgstr "" + +#: windows/dialogs/connections/view.py:788 +#: windows/dialogs/connections/view.py:803 msgid "Confirm delete" msgstr "" -#: windows/connections/manager.py:229 -msgid "directory" +#: windows/main/controller.py:172 +msgid "days" +msgstr "" + +#: windows/main/controller.py:173 +msgid "hours" msgstr "" -#: windows/connections/model.py:101 -msgid "New connection" +#: windows/main/controller.py:174 +msgid "minutes" +msgstr "" + +#: windows/main/controller.py:175 +msgid "seconds" +msgstr "" + +#: windows/main/controller.py:183 +#, python-brace-format +msgid "Memory used: {used} ({percentage:.2%})" +msgstr "" + +#: windows/main/controller.py:219 +msgid "Settings saved successfully" +msgstr "" + +#: windows/main/controller.py:298 +msgid "Version" +msgstr "" + +#: windows/main/controller.py:300 +msgid "Uptime" msgstr "" -#: windows/main/database.py:70 +#: windows/main/controller.py:399 +#, python-brace-format +msgid "" +"Do you want to create a dump before dropping database '{database_name}'?\n" +"\n" +"Dump is not implemented yet.\n" +"- Yes: open dump flow (coming soon, no drop).\n" +"- No: drop the database now." +msgstr "" + +#: windows/main/controller.py:404 windows/main/controller.py:425 +msgid "Delete database" +msgstr "" + +#: windows/main/controller.py:410 +msgid "Dump is not implemented yet. No action has been performed." +msgstr "" + +#: windows/main/controller.py:411 +msgid "Dump not available" +msgstr "" + +#: windows/main/controller.py:424 +msgid "Database deletion is not supported by this engine." +msgstr "" + +#: windows/main/controller.py:439 +msgid "Database deleted successfully" +msgstr "" + +#: windows/main/controller.py:440 windows/main/tabs/view.py:253 +#: windows/main/tabs/view.py:279 +msgid "Success" +msgstr "" + +#: windows/main/controller.py:582 +msgid "Delete table" +msgstr "" + +#: windows/main/controller.py:699 +msgid "Do you want delete the records?" +msgstr "" + +#: windows/main/tabs/database.py:71 msgid "The connection to the database was lost." msgstr "" -#: windows/main/database.py:72 +#: windows/main/tabs/database.py:73 msgid "Do you want to reconnect?" msgstr "" -#: windows/main/database.py:74 +#: windows/main/tabs/database.py:75 msgid "Connection lost" msgstr "" -#: windows/main/database.py:83 +#: windows/main/tabs/database.py:85 msgid "Reconnection failed:" msgstr "" -#: windows/main/database.py:84 +#: windows/main/tabs/database.py:86 windows/main/tabs/query.py:450 +#: windows/main/tabs/view.py:256 windows/main/tabs/view.py:282 msgid "Error" msgstr "" -#: windows/main/main_frame.py:124 -msgid "days" +#: windows/main/tabs/query.py:305 +#, python-brace-format +msgid "{} rows affected" msgstr "" -#: windows/main/main_frame.py:125 -msgid "hours" +#: windows/main/tabs/query.py:309 windows/main/tabs/query.py:331 +#, python-brace-format +msgid "Query {}" msgstr "" -#: windows/main/main_frame.py:126 -msgid "minutes" +#: windows/main/tabs/query.py:314 +#, python-brace-format +msgid "Query {} (Error)" msgstr "" -#: windows/main/main_frame.py:127 -msgid "seconds" +#: windows/main/tabs/query.py:326 +#, python-brace-format +msgid "Query {} ({} rows × {} cols)" msgstr "" -#: windows/main/main_frame.py:135 +#: windows/main/tabs/query.py:353 #, python-brace-format -msgid "Memory used: {used} ({percentage:.2%})" +msgid "{} rows" msgstr "" -#: windows/main/main_frame.py:226 -msgid "Version" +#: windows/main/tabs/query.py:355 +#, python-brace-format +msgid "{:.1f} ms" msgstr "" -#: windows/main/main_frame.py:228 -msgid "Uptime" +#: windows/main/tabs/query.py:358 +#, python-brace-format +msgid "{} warnings" msgstr "" -#: windows/main/main_frame.py:431 -msgid "Delete table" +#: windows/main/tabs/query.py:370 +msgid "Error:" msgstr "" -#: windows/main/main_frame.py:586 -msgid "Do you want delete the records?" +#: windows/main/tabs/query.py:449 +msgid "No active database connection" +msgstr "" + +#: windows/main/tabs/view.py:252 +msgid "View created successfully" +msgstr "" + +#: windows/main/tabs/view.py:252 +msgid "View updated successfully" +msgstr "" + +#: windows/main/tabs/view.py:256 +#, python-brace-format +msgid "Error saving view: {}" +msgstr "" + +#: windows/main/tabs/view.py:269 +#, python-brace-format +msgid "Are you sure you want to delete view '{}'?" +msgstr "" + +#: windows/main/tabs/view.py:270 +msgid "Confirm Delete" +msgstr "" + +#: windows/main/tabs/view.py:279 +msgid "View deleted successfully" +msgstr "" + +#: windows/main/tabs/view.py:282 +#, python-brace-format +msgid "Error deleting view: {}" msgstr "" diff --git a/pyproject.toml b/pyproject.toml index d1d0475..e252424 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,5 @@ [project] -name = "petersql" +name = "PeterSQL" version = "0.1.0" description = "graphical client for database management" readme = "README.md" @@ -24,6 +24,7 @@ dev = [ "pytest-mock>=3.15.1", "pytest-xdist>=3.8.0", "testcontainers>=4.14.1", + "toml>=0.10.2", "types-pymysql>=1.1.0.20251220", "types-pyyaml>=6.0.12.20250915", "types-wxpython>=0.9.7", diff --git a/scripts/locale/de_DE/LC_MESSAGES/petersql.po b/scripts/locale/de_DE/LC_MESSAGES/petersql.po deleted file mode 100644 index 4370e80..0000000 --- a/scripts/locale/de_DE/LC_MESSAGES/petersql.po +++ /dev/null @@ -1,952 +0,0 @@ -#: helpers/__init__.py:16 -msgctxt "unit" -msgid "B" -msgstr "" - -#: helpers/__init__.py:17 -msgctxt "unit" -msgid "KB" -msgstr "" - -#: helpers/__init__.py:18 -msgctxt "unit" -msgid "MB" -msgstr "" - -#: helpers/__init__.py:19 -msgctxt "unit" -msgid "GB" -msgstr "" - -#: helpers/__init__.py:20 -msgctxt "unit" -msgid "TB" -msgstr "" - -#: structures/ssh_tunnel.py:166 -msgid "OpenSSH client not found." -msgstr "" - -#: windows/dialogs/connections/view.py:259 -#: windows/dialogs/connections/view.py:547 windows/main/controller.py:294 -#: windows/views.py:33 -msgid "Connection" -msgstr "" - -#: windows/components/dataview.py:113 windows/components/dataview.py:225 -#: windows/components/dataview.py:238 windows/components/dataview.py:253 -#: windows/views.py:47 windows/views.py:97 windows/views.py:898 -#: windows/views.py:958 windows/views.py:1341 windows/views.py:2246 -#: windows/views.py:2269 windows/views.py:2270 windows/views.py:2271 -#: windows/views.py:2272 windows/views.py:2273 windows/views.py:2274 -#: windows/views.py:2275 windows/views.py:2276 windows/views.py:2277 -#: windows/views.py:2281 windows/views.py:2462 windows/views.py:2663 -msgid "Name" -msgstr "" - -#: windows/views.py:48 windows/views.py:381 -msgid "Last connection" -msgstr "" - -#: windows/dialogs/connections/view.py:452 windows/views.py:61 -msgid "New directory" -msgstr "" - -#: windows/dialogs/connections/model.py:142 -#: windows/dialogs/connections/view.py:384 windows/views.py:65 -msgid "New connection" -msgstr "" - -#: windows/views.py:71 -msgid "Rename" -msgstr "" - -#: windows/views.py:76 -msgid "Clone connection" -msgstr "" - -#: windows/views.py:81 windows/views.py:471 windows/views.py:884 -#: windows/views.py:1251 windows/views.py:1283 windows/views.py:1542 -#: windows/views.py:2799 windows/views.py:2831 -msgid "Delete" -msgstr "" - -#: windows/views.py:111 windows/views.py:903 windows/views.py:1013 -#: windows/views.py:2286 windows/views.py:2718 -msgid "Engine" -msgstr "" - -#: windows/views.py:132 -msgid "Host + port" -msgstr "" - -#: windows/views.py:148 -msgid "Username" -msgstr "" - -#: windows/views.py:161 -msgid "Password" -msgstr "" - -#: windows/views.py:177 -msgid "Use TLS" -msgstr "" - -#: windows/views.py:180 -msgid "Use SSH tunnel" -msgstr "" - -#: windows/views.py:202 windows/views.py:2198 -msgid "Filename" -msgstr "" - -#: windows/views.py:207 windows/views.py:324 windows/views.py:2203 -#: windows/views.py:2395 -msgid "Select a file" -msgstr "" - -#: windows/views.py:207 windows/views.py:324 windows/views.py:2395 -msgid "*.*" -msgstr "" - -#: windows/components/dataview.py:70 windows/components/dataview.py:92 -#: windows/views.py:221 windows/views.py:905 windows/views.py:971 -#: windows/views.py:2287 windows/views.py:2560 windows/views.py:2676 -msgid "Comments" -msgstr "" - -#: windows/main/controller.py:217 windows/views.py:235 windows/views.py:598 -msgid "Settings" -msgstr "" - -#: windows/views.py:244 -msgid "SSH executable" -msgstr "" - -#: windows/views.py:249 -msgid "ssh" -msgstr "" - -#: windows/views.py:257 -msgid "SSH host + port" -msgstr "" - -#: windows/views.py:269 -msgid "SSH host + port (the SSH server that forwards traffic to the DB)" -msgstr "" - -#: windows/views.py:278 -msgid "SSH username" -msgstr "" - -#: windows/views.py:291 -msgid "SSH password" -msgstr "" - -#: windows/views.py:304 -msgid "Local port" -msgstr "" - -#: windows/views.py:310 -msgid "if the value is set to 0, the first available port will be used" -msgstr "" - -#: windows/views.py:319 -msgid "Identity file" -msgstr "" - -#: windows/views.py:335 -msgid "Remote host + port" -msgstr "" - -#: windows/views.py:347 -msgid "Remote host/port is the real DB target (defaults to DB Host/Port)." -msgstr "" - -#: windows/views.py:358 -msgid "SSH Tunnel" -msgstr "" - -#: windows/views.py:364 windows/views.py:901 windows/views.py:2284 -msgid "Created at" -msgstr "" - -#: windows/views.py:398 -msgid "Successful connections" -msgstr "" - -#: windows/views.py:415 -msgid "Unsuccessful connections" -msgstr "" - -#: windows/views.py:434 -msgid "Statistics" -msgstr "" - -#: windows/views.py:452 windows/views.py:1217 -msgid "Create" -msgstr "" - -#: windows/views.py:456 -msgid "Create connection" -msgstr "" - -#: windows/views.py:459 -msgid "Create directory" -msgstr "" - -#: windows/views.py:488 windows/views.py:712 windows/views.py:1286 -#: windows/views.py:1547 windows/views.py:1623 windows/views.py:2607 -#: windows/views.py:2834 -msgid "Cancel" -msgstr "" - -#: windows/views.py:493 windows/views.py:1552 windows/views.py:2617 -#: windows/views.py:2839 -msgid "Save" -msgstr "" - -#: windows/views.py:500 -msgid "Test" -msgstr "" - -#: windows/views.py:507 -msgid "Connect" -msgstr "" - -#: windows/views.py:610 -msgid "Language" -msgstr "" - -#: windows/views.py:615 -msgid "English" -msgstr "" - -#: windows/views.py:615 -msgid "Italian" -msgstr "" - -#: windows/views.py:615 -msgid "French" -msgstr "" - -#: windows/views.py:627 -msgid "Locale" -msgstr "" - -#: windows/views.py:648 -msgid "Edit Value" -msgstr "" - -#: windows/views.py:658 -msgid "Syntax" -msgstr "" - -#: windows/views.py:715 -msgid "Ok" -msgstr "" - -#: windows/views.py:746 -msgid "PeterSQL" -msgstr "" - -#: windows/views.py:752 -msgid "File" -msgstr "" - -#: windows/views.py:755 -msgid "About" -msgstr "" - -#: windows/views.py:758 -msgid "Help" -msgstr "" - -#: windows/views.py:763 -msgid "Open connection manager" -msgstr "" - -#: windows/views.py:765 -msgid "Disconnect from server" -msgstr "" - -#: windows/views.py:769 -msgid "tool" -msgstr "" - -#: windows/views.py:769 -msgid "Refresh" -msgstr "" - -#: windows/views.py:773 windows/views.py:775 -msgid "Add" -msgstr "" - -#: windows/views.py:809 windows/views.py:813 windows/views.py:1711 -#: windows/views.py:1839 -msgid "MyMenuItem" -msgstr "" - -#: windows/views.py:816 windows/views.py:1314 windows/views.py:2862 -msgid "MyMenu" -msgstr "" - -#: windows/views.py:831 -msgid "MyLabel" -msgstr "" - -#: windows/views.py:837 -msgid "Databases" -msgstr "" - -#: windows/views.py:838 windows/views.py:900 windows/views.py:2255 -#: windows/views.py:2283 -msgid "Size" -msgstr "" - -#: windows/views.py:839 -msgid "Elements" -msgstr "" - -#: windows/views.py:840 -msgid "Modified at" -msgstr "" - -#: windows/views.py:841 windows/views.py:912 -msgid "Tables" -msgstr "" - -#: windows/views.py:848 -msgid "System" -msgstr "" - -#: windows/views.py:864 -msgid "Table:" -msgstr "" - -#: windows/views.py:872 windows/views.py:1096 windows/views.py:1140 -#: windows/views.py:1246 windows/views.py:2794 -msgid "Insert" -msgstr "" - -#: windows/views.py:877 -msgid "Clone" -msgstr "" - -#: windows/views.py:899 -msgid "Rows" -msgstr "" - -#: windows/views.py:902 windows/views.py:2285 -msgid "Updated at" -msgstr "" - -#: windows/components/dataview.py:43 windows/components/dataview.py:67 -#: windows/components/dataview.py:89 windows/views.py:904 windows/views.py:2506 -msgid "Collation" -msgstr "" - -#: windows/views.py:920 -msgid "Diagram" -msgstr "" - -#: windows/views.py:931 windows/views.py:2254 -msgid "Database" -msgstr "" - -#: windows/views.py:986 windows/views.py:2691 -msgid "Base" -msgstr "" - -#: windows/views.py:1000 windows/views.py:2705 -msgid "Auto Increment" -msgstr "" - -#: windows/views.py:1028 windows/views.py:2733 -msgid "Default Collation" -msgstr "" - -#: windows/views.py:1048 windows/views.py:1501 windows/views.py:2751 -msgid "Options" -msgstr "" - -#: windows/views.py:1060 windows/views.py:1101 windows/views.py:1145 -msgid "Remove" -msgstr "" - -#: windows/views.py:1067 windows/views.py:1108 windows/views.py:1152 -msgid "Clear" -msgstr "" - -#: windows/views.py:1082 windows/views.py:2765 -msgid "Indexes" -msgstr "" - -#: windows/views.py:1126 -msgid "Foreign Keys" -msgstr "" - -#: windows/views.py:1170 -msgid "Checks" -msgstr "" - -#: windows/views.py:1238 windows/views.py:2786 -msgid "Columns:" -msgstr "" - -#: windows/views.py:1258 windows/views.py:2806 -msgid "Up" -msgstr "" - -#: windows/views.py:1265 windows/views.py:2813 -msgid "Down" -msgstr "" - -#: windows/views.py:1291 windows/views.py:1630 windows/views.py:1685 -msgid "Apply" -msgstr "" - -#: windows/views.py:1304 windows/views.py:1311 windows/views.py:2852 -#: windows/views.py:2859 -msgid "Add Index" -msgstr "" - -#: windows/views.py:1308 windows/views.py:2856 -msgid "Add PrimaryKey" -msgstr "" - -#: windows/views.py:1325 -msgid "Table" -msgstr "" - -#: windows/views.py:1361 -msgid "Definer" -msgstr "" - -#: windows/views.py:1381 -msgid "Schema" -msgstr "" - -#: windows/views.py:1407 -msgid "SQL security" -msgstr "" - -#: windows/views.py:1414 -msgid "DEFINER" -msgstr "" - -#: windows/views.py:1414 -msgid "INVOKER" -msgstr "" - -#: windows/views.py:1426 windows/views.py:2096 windows/views.py:2115 -#: windows/views.py:2359 -msgid "Algorithm" -msgstr "" - -#: windows/views.py:1428 windows/views.py:2081 windows/views.py:2114 -#: windows/views.py:2364 -msgid "UNDEFINED" -msgstr "" - -#: windows/views.py:1431 windows/views.py:2084 windows/views.py:2114 -#: windows/views.py:2367 -msgid "MERGE" -msgstr "" - -#: windows/views.py:1434 windows/views.py:2093 windows/views.py:2114 -#: windows/views.py:2370 -msgid "TEMPTABLE" -msgstr "" - -#: windows/views.py:1444 windows/views.py:2120 -msgid "View constraint" -msgstr "" - -#: windows/views.py:1446 windows/views.py:2119 -msgid "None" -msgstr "" - -#: windows/views.py:1449 windows/views.py:2119 -msgid "LOCAL" -msgstr "" - -#: windows/views.py:1452 -msgid "CASCADE" -msgstr "" - -#: windows/views.py:1455 -msgid "CHECK ONLY" -msgstr "" - -#: windows/views.py:1458 windows/views.py:2119 -msgid "READ ONLY" -msgstr "" - -#: windows/views.py:1470 -msgid "Force" -msgstr "" - -#: windows/views.py:1482 -msgid "Security barrier" -msgstr "" - -#: windows/views.py:1564 -msgid "Views" -msgstr "" - -#: windows/views.py:1572 -msgid "Triggers" -msgstr "" - -#: windows/views.py:1584 -#, python-format -msgid "Table `%(database_name)s`.`%(table_name)s`: %(total_rows) rows total" -msgstr "" - -#: windows/views.py:1594 -msgid "Insert record" -msgstr "" - -#: windows/views.py:1599 -msgid "Duplicate record" -msgstr "" - -#: windows/views.py:1606 -msgid "Delete record" -msgstr "" - -#: windows/views.py:1616 -msgid "Apply changes automatically" -msgstr "" - -#: windows/views.py:1618 windows/views.py:1619 -msgid "" -"If enabled, table edits are applied immediately without pressing Apply or" -" Cancel" -msgstr "" - -#: windows/views.py:1640 -msgid "Next" -msgstr "" - -#: windows/views.py:1648 -msgid "Filters" -msgstr "" - -#: windows/views.py:1688 -msgid "CTRL+ENTER" -msgstr "" - -#: windows/views.py:1708 -msgid "Insert row" -msgstr "" - -#: windows/views.py:1716 -msgid "Data" -msgstr "" - -#: windows/views.py:1770 windows/views.py:1820 -msgid "New" -msgstr "" - -#: windows/views.py:1797 -msgid "Query" -msgstr "" - -#: windows/views.py:1817 -msgid "Close" -msgstr "" - -#: windows/views.py:1830 -msgid "Query #2" -msgstr "" - -#: windows/views.py:2075 -msgid "Column5" -msgstr "" - -#: windows/views.py:2086 -msgid "Import" -msgstr "" - -#: windows/views.py:2111 -msgid "Read only" -msgstr "" - -#: windows/views.py:2119 -msgid "CASCADED" -msgstr "" - -#: windows/views.py:2119 -msgid "CHECK OPTION" -msgstr "" - -#: windows/views.py:2143 -msgid "collapsible" -msgstr "" - -#: windows/views.py:2165 -msgid "Column3" -msgstr "" - -#: windows/views.py:2166 -msgid "Column4" -msgstr "" - -#: windows/views.py:2203 -msgid "" -"Database " -"(*.db;*.db3;*.sdb;*.s3db;*.sqlite;*.sqlite3)|*.db;*.db3;*.sdb;*.s3db;*.sqlite;*.sqlite3" -msgstr "" - -#: windows/views.py:2215 -msgid "Port" -msgstr "" - -#: windows/views.py:2247 -msgid "Usage" -msgstr "" - -#: windows/views.py:2258 -#, python-format -msgid "%(total_rows)s" -msgstr "" - -#: windows/views.py:2263 -msgid "rows total" -msgstr "" - -#: windows/views.py:2282 -msgid "Lines" -msgstr "" - -#: windows/views.py:2314 -msgid "Temporary" -msgstr "" - -#: windows/views.py:2325 -msgid "Engine options" -msgstr "" - -#: windows/views.py:2384 -msgid "RadioBtn" -msgstr "" - -#: windows/views.py:2454 -msgid "Edit Column" -msgstr "" - -#: windows/views.py:2470 -msgid "Datatype" -msgstr "" - -#: windows/components/dataview.py:121 windows/views.py:2485 -msgid "Length/Set" -msgstr "" - -#: windows/components/dataview.py:51 windows/views.py:2524 -msgid "Unsigned" -msgstr "" - -#: windows/components/dataview.py:25 windows/components/dataview.py:52 -#: windows/components/dataview.py:75 windows/views.py:2530 -msgid "Allow NULL" -msgstr "" - -#: windows/views.py:2536 -msgid "Zero Fill" -msgstr "" - -#: windows/components/dataview.py:32 windows/components/dataview.py:56 -#: windows/components/dataview.py:78 windows/views.py:2547 -msgid "Default" -msgstr "" - -#: windows/components/dataview.py:36 windows/components/dataview.py:60 -#: windows/components/dataview.py:82 windows/views.py:2573 -msgid "Virtuality" -msgstr "" - -#: windows/components/dataview.py:39 windows/components/dataview.py:63 -#: windows/components/dataview.py:85 windows/components/dataview.py:241 -#: windows/views.py:2588 -msgid "Expression" -msgstr "" - -#: windows/components/dataview.py:28 -msgid "Check" -msgstr "" - -#: windows/components/dataview.py:53 -msgid "Zerofill" -msgstr "" - -#: windows/components/dataview.py:109 -msgid "#" -msgstr "" - -#: windows/components/dataview.py:117 -msgid "Data type" -msgstr "" - -#: windows/components/dataview.py:155 -msgid "Add column\tCTRL+INS" -msgstr "" - -#: windows/components/dataview.py:161 -msgid "Remove column\tCTRL+DEL" -msgstr "" - -#: windows/components/dataview.py:169 -msgid "Move up\tCTRL+UP" -msgstr "" - -#: windows/components/dataview.py:176 -msgid "Move down\tCTRL+D" -msgstr "" - -#: windows/components/dataview.py:199 -msgid "Create new index" -msgstr "" - -#: windows/components/dataview.py:214 -msgid "Append to index" -msgstr "" - -#: windows/components/dataview.py:228 -msgid "Column(s)/Expression" -msgstr "" - -#: windows/components/dataview.py:229 -msgid "Condition" -msgstr "" - -#: windows/components/dataview.py:259 -msgid "Column(s)" -msgstr "" - -#: windows/components/dataview.py:265 -msgid "Reference table" -msgstr "" - -#: windows/components/dataview.py:271 -msgid "Reference column(s)" -msgstr "" - -#: windows/components/dataview.py:277 -msgid "On UPDATE" -msgstr "" - -#: windows/components/dataview.py:283 -msgid "On DELETE" -msgstr "" - -#: windows/components/dataview.py:299 -msgid "Add foreign key" -msgstr "" - -#: windows/components/dataview.py:305 -msgid "Remove foreign key" -msgstr "" - -#: windows/components/popup.py:26 -msgid "No default value" -msgstr "" - -#: windows/components/popup.py:31 -msgid "NULL" -msgstr "" - -#: windows/components/popup.py:35 -msgid "AUTO INCREMENT" -msgstr "" - -#: windows/components/popup.py:39 -msgid "Text/Expression" -msgstr "" - -#: windows/dialogs/connections/view.py:258 -msgid "Connection established successfully" -msgstr "" - -#: windows/dialogs/connections/view.py:271 -msgid "Confirm save" -msgstr "" - -#: windows/dialogs/connections/view.py:314 -msgid "You have unsaved changes. Do you want to save them before continuing?" -msgstr "" - -#: windows/dialogs/connections/view.py:316 -msgid "Unsaved changes" -msgstr "" - -#: windows/dialogs/connections/view.py:545 -msgid "" -"This connection cannot work without TLS. TLS has been enabled " -"automatically." -msgstr "" - -#: windows/dialogs/connections/view.py:554 -msgid "Connection error" -msgstr "" - -#: windows/dialogs/connections/view.py:580 -#: windows/dialogs/connections/view.py:595 -msgid "Confirm delete" -msgstr "" - -#: windows/main/controller.py:170 -msgid "days" -msgstr "" - -#: windows/main/controller.py:171 -msgid "hours" -msgstr "" - -#: windows/main/controller.py:172 -msgid "minutes" -msgstr "" - -#: windows/main/controller.py:173 -msgid "seconds" -msgstr "" - -#: windows/main/controller.py:181 -#, python-brace-format -msgid "Memory used: {used} ({percentage:.2%})" -msgstr "" - -#: windows/main/controller.py:217 -msgid "Settings saved successfully" -msgstr "" - -#: windows/main/controller.py:296 -msgid "Version" -msgstr "" - -#: windows/main/controller.py:298 -msgid "Uptime" -msgstr "" - -#: windows/main/controller.py:467 -msgid "Delete table" -msgstr "" - -#: windows/main/controller.py:584 -msgid "Do you want delete the records?" -msgstr "" - -#: windows/main/tabs/database.py:71 -msgid "The connection to the database was lost." -msgstr "" - -#: windows/main/tabs/database.py:73 -msgid "Do you want to reconnect?" -msgstr "" - -#: windows/main/tabs/database.py:75 -msgid "Connection lost" -msgstr "" - -#: windows/main/tabs/database.py:85 -msgid "Reconnection failed:" -msgstr "" - -#: windows/main/tabs/database.py:86 windows/main/tabs/query.py:450 -#: windows/main/tabs/view.py:256 windows/main/tabs/view.py:282 -msgid "Error" -msgstr "" - -#: windows/main/tabs/query.py:305 -#, python-brace-format -msgid "{} rows affected" -msgstr "" - -#: windows/main/tabs/query.py:309 windows/main/tabs/query.py:331 -#, python-brace-format -msgid "Query {}" -msgstr "" - -#: windows/main/tabs/query.py:314 -#, python-brace-format -msgid "Query {} (Error)" -msgstr "" - -#: windows/main/tabs/query.py:326 -#, python-brace-format -msgid "Query {} ({} rows × {} cols)" -msgstr "" - -#: windows/main/tabs/query.py:353 -#, python-brace-format -msgid "{} rows" -msgstr "" - -#: windows/main/tabs/query.py:355 -#, python-brace-format -msgid "{:.1f} ms" -msgstr "" - -#: windows/main/tabs/query.py:358 -#, python-brace-format -msgid "{} warnings" -msgstr "" - -#: windows/main/tabs/query.py:370 -msgid "Error:" -msgstr "" - -#: windows/main/tabs/query.py:376 -msgid "Unknown error" -msgstr "" - -#: windows/main/tabs/query.py:449 -msgid "No active database connection" -msgstr "" - -#: windows/main/tabs/view.py:252 -msgid "View created successfully" -msgstr "" - -#: windows/main/tabs/view.py:252 -msgid "View updated successfully" -msgstr "" - -#: windows/main/tabs/view.py:253 windows/main/tabs/view.py:279 -msgid "Success" -msgstr "" - -#: windows/main/tabs/view.py:256 -#, python-brace-format -msgid "Error saving view: {}" -msgstr "" - -#: windows/main/tabs/view.py:269 -#, python-brace-format -msgid "Are you sure you want to delete view '{}'?" -msgstr "" - -#: windows/main/tabs/view.py:270 -msgid "Confirm Delete" -msgstr "" - -#: windows/main/tabs/view.py:279 -msgid "View deleted successfully" -msgstr "" - -#: windows/main/tabs/view.py:282 -#, python-brace-format -msgid "Error deleting view: {}" -msgstr "" - -#~ msgid "New Session" -#~ msgstr "" - -#~ msgid "connection" -#~ msgstr "" - -#~ msgid "directory" -#~ msgstr "" - diff --git a/scripts/locale/en_US/LC_MESSAGES/petersql.po b/scripts/locale/en_US/LC_MESSAGES/petersql.po deleted file mode 100644 index 4370e80..0000000 --- a/scripts/locale/en_US/LC_MESSAGES/petersql.po +++ /dev/null @@ -1,952 +0,0 @@ -#: helpers/__init__.py:16 -msgctxt "unit" -msgid "B" -msgstr "" - -#: helpers/__init__.py:17 -msgctxt "unit" -msgid "KB" -msgstr "" - -#: helpers/__init__.py:18 -msgctxt "unit" -msgid "MB" -msgstr "" - -#: helpers/__init__.py:19 -msgctxt "unit" -msgid "GB" -msgstr "" - -#: helpers/__init__.py:20 -msgctxt "unit" -msgid "TB" -msgstr "" - -#: structures/ssh_tunnel.py:166 -msgid "OpenSSH client not found." -msgstr "" - -#: windows/dialogs/connections/view.py:259 -#: windows/dialogs/connections/view.py:547 windows/main/controller.py:294 -#: windows/views.py:33 -msgid "Connection" -msgstr "" - -#: windows/components/dataview.py:113 windows/components/dataview.py:225 -#: windows/components/dataview.py:238 windows/components/dataview.py:253 -#: windows/views.py:47 windows/views.py:97 windows/views.py:898 -#: windows/views.py:958 windows/views.py:1341 windows/views.py:2246 -#: windows/views.py:2269 windows/views.py:2270 windows/views.py:2271 -#: windows/views.py:2272 windows/views.py:2273 windows/views.py:2274 -#: windows/views.py:2275 windows/views.py:2276 windows/views.py:2277 -#: windows/views.py:2281 windows/views.py:2462 windows/views.py:2663 -msgid "Name" -msgstr "" - -#: windows/views.py:48 windows/views.py:381 -msgid "Last connection" -msgstr "" - -#: windows/dialogs/connections/view.py:452 windows/views.py:61 -msgid "New directory" -msgstr "" - -#: windows/dialogs/connections/model.py:142 -#: windows/dialogs/connections/view.py:384 windows/views.py:65 -msgid "New connection" -msgstr "" - -#: windows/views.py:71 -msgid "Rename" -msgstr "" - -#: windows/views.py:76 -msgid "Clone connection" -msgstr "" - -#: windows/views.py:81 windows/views.py:471 windows/views.py:884 -#: windows/views.py:1251 windows/views.py:1283 windows/views.py:1542 -#: windows/views.py:2799 windows/views.py:2831 -msgid "Delete" -msgstr "" - -#: windows/views.py:111 windows/views.py:903 windows/views.py:1013 -#: windows/views.py:2286 windows/views.py:2718 -msgid "Engine" -msgstr "" - -#: windows/views.py:132 -msgid "Host + port" -msgstr "" - -#: windows/views.py:148 -msgid "Username" -msgstr "" - -#: windows/views.py:161 -msgid "Password" -msgstr "" - -#: windows/views.py:177 -msgid "Use TLS" -msgstr "" - -#: windows/views.py:180 -msgid "Use SSH tunnel" -msgstr "" - -#: windows/views.py:202 windows/views.py:2198 -msgid "Filename" -msgstr "" - -#: windows/views.py:207 windows/views.py:324 windows/views.py:2203 -#: windows/views.py:2395 -msgid "Select a file" -msgstr "" - -#: windows/views.py:207 windows/views.py:324 windows/views.py:2395 -msgid "*.*" -msgstr "" - -#: windows/components/dataview.py:70 windows/components/dataview.py:92 -#: windows/views.py:221 windows/views.py:905 windows/views.py:971 -#: windows/views.py:2287 windows/views.py:2560 windows/views.py:2676 -msgid "Comments" -msgstr "" - -#: windows/main/controller.py:217 windows/views.py:235 windows/views.py:598 -msgid "Settings" -msgstr "" - -#: windows/views.py:244 -msgid "SSH executable" -msgstr "" - -#: windows/views.py:249 -msgid "ssh" -msgstr "" - -#: windows/views.py:257 -msgid "SSH host + port" -msgstr "" - -#: windows/views.py:269 -msgid "SSH host + port (the SSH server that forwards traffic to the DB)" -msgstr "" - -#: windows/views.py:278 -msgid "SSH username" -msgstr "" - -#: windows/views.py:291 -msgid "SSH password" -msgstr "" - -#: windows/views.py:304 -msgid "Local port" -msgstr "" - -#: windows/views.py:310 -msgid "if the value is set to 0, the first available port will be used" -msgstr "" - -#: windows/views.py:319 -msgid "Identity file" -msgstr "" - -#: windows/views.py:335 -msgid "Remote host + port" -msgstr "" - -#: windows/views.py:347 -msgid "Remote host/port is the real DB target (defaults to DB Host/Port)." -msgstr "" - -#: windows/views.py:358 -msgid "SSH Tunnel" -msgstr "" - -#: windows/views.py:364 windows/views.py:901 windows/views.py:2284 -msgid "Created at" -msgstr "" - -#: windows/views.py:398 -msgid "Successful connections" -msgstr "" - -#: windows/views.py:415 -msgid "Unsuccessful connections" -msgstr "" - -#: windows/views.py:434 -msgid "Statistics" -msgstr "" - -#: windows/views.py:452 windows/views.py:1217 -msgid "Create" -msgstr "" - -#: windows/views.py:456 -msgid "Create connection" -msgstr "" - -#: windows/views.py:459 -msgid "Create directory" -msgstr "" - -#: windows/views.py:488 windows/views.py:712 windows/views.py:1286 -#: windows/views.py:1547 windows/views.py:1623 windows/views.py:2607 -#: windows/views.py:2834 -msgid "Cancel" -msgstr "" - -#: windows/views.py:493 windows/views.py:1552 windows/views.py:2617 -#: windows/views.py:2839 -msgid "Save" -msgstr "" - -#: windows/views.py:500 -msgid "Test" -msgstr "" - -#: windows/views.py:507 -msgid "Connect" -msgstr "" - -#: windows/views.py:610 -msgid "Language" -msgstr "" - -#: windows/views.py:615 -msgid "English" -msgstr "" - -#: windows/views.py:615 -msgid "Italian" -msgstr "" - -#: windows/views.py:615 -msgid "French" -msgstr "" - -#: windows/views.py:627 -msgid "Locale" -msgstr "" - -#: windows/views.py:648 -msgid "Edit Value" -msgstr "" - -#: windows/views.py:658 -msgid "Syntax" -msgstr "" - -#: windows/views.py:715 -msgid "Ok" -msgstr "" - -#: windows/views.py:746 -msgid "PeterSQL" -msgstr "" - -#: windows/views.py:752 -msgid "File" -msgstr "" - -#: windows/views.py:755 -msgid "About" -msgstr "" - -#: windows/views.py:758 -msgid "Help" -msgstr "" - -#: windows/views.py:763 -msgid "Open connection manager" -msgstr "" - -#: windows/views.py:765 -msgid "Disconnect from server" -msgstr "" - -#: windows/views.py:769 -msgid "tool" -msgstr "" - -#: windows/views.py:769 -msgid "Refresh" -msgstr "" - -#: windows/views.py:773 windows/views.py:775 -msgid "Add" -msgstr "" - -#: windows/views.py:809 windows/views.py:813 windows/views.py:1711 -#: windows/views.py:1839 -msgid "MyMenuItem" -msgstr "" - -#: windows/views.py:816 windows/views.py:1314 windows/views.py:2862 -msgid "MyMenu" -msgstr "" - -#: windows/views.py:831 -msgid "MyLabel" -msgstr "" - -#: windows/views.py:837 -msgid "Databases" -msgstr "" - -#: windows/views.py:838 windows/views.py:900 windows/views.py:2255 -#: windows/views.py:2283 -msgid "Size" -msgstr "" - -#: windows/views.py:839 -msgid "Elements" -msgstr "" - -#: windows/views.py:840 -msgid "Modified at" -msgstr "" - -#: windows/views.py:841 windows/views.py:912 -msgid "Tables" -msgstr "" - -#: windows/views.py:848 -msgid "System" -msgstr "" - -#: windows/views.py:864 -msgid "Table:" -msgstr "" - -#: windows/views.py:872 windows/views.py:1096 windows/views.py:1140 -#: windows/views.py:1246 windows/views.py:2794 -msgid "Insert" -msgstr "" - -#: windows/views.py:877 -msgid "Clone" -msgstr "" - -#: windows/views.py:899 -msgid "Rows" -msgstr "" - -#: windows/views.py:902 windows/views.py:2285 -msgid "Updated at" -msgstr "" - -#: windows/components/dataview.py:43 windows/components/dataview.py:67 -#: windows/components/dataview.py:89 windows/views.py:904 windows/views.py:2506 -msgid "Collation" -msgstr "" - -#: windows/views.py:920 -msgid "Diagram" -msgstr "" - -#: windows/views.py:931 windows/views.py:2254 -msgid "Database" -msgstr "" - -#: windows/views.py:986 windows/views.py:2691 -msgid "Base" -msgstr "" - -#: windows/views.py:1000 windows/views.py:2705 -msgid "Auto Increment" -msgstr "" - -#: windows/views.py:1028 windows/views.py:2733 -msgid "Default Collation" -msgstr "" - -#: windows/views.py:1048 windows/views.py:1501 windows/views.py:2751 -msgid "Options" -msgstr "" - -#: windows/views.py:1060 windows/views.py:1101 windows/views.py:1145 -msgid "Remove" -msgstr "" - -#: windows/views.py:1067 windows/views.py:1108 windows/views.py:1152 -msgid "Clear" -msgstr "" - -#: windows/views.py:1082 windows/views.py:2765 -msgid "Indexes" -msgstr "" - -#: windows/views.py:1126 -msgid "Foreign Keys" -msgstr "" - -#: windows/views.py:1170 -msgid "Checks" -msgstr "" - -#: windows/views.py:1238 windows/views.py:2786 -msgid "Columns:" -msgstr "" - -#: windows/views.py:1258 windows/views.py:2806 -msgid "Up" -msgstr "" - -#: windows/views.py:1265 windows/views.py:2813 -msgid "Down" -msgstr "" - -#: windows/views.py:1291 windows/views.py:1630 windows/views.py:1685 -msgid "Apply" -msgstr "" - -#: windows/views.py:1304 windows/views.py:1311 windows/views.py:2852 -#: windows/views.py:2859 -msgid "Add Index" -msgstr "" - -#: windows/views.py:1308 windows/views.py:2856 -msgid "Add PrimaryKey" -msgstr "" - -#: windows/views.py:1325 -msgid "Table" -msgstr "" - -#: windows/views.py:1361 -msgid "Definer" -msgstr "" - -#: windows/views.py:1381 -msgid "Schema" -msgstr "" - -#: windows/views.py:1407 -msgid "SQL security" -msgstr "" - -#: windows/views.py:1414 -msgid "DEFINER" -msgstr "" - -#: windows/views.py:1414 -msgid "INVOKER" -msgstr "" - -#: windows/views.py:1426 windows/views.py:2096 windows/views.py:2115 -#: windows/views.py:2359 -msgid "Algorithm" -msgstr "" - -#: windows/views.py:1428 windows/views.py:2081 windows/views.py:2114 -#: windows/views.py:2364 -msgid "UNDEFINED" -msgstr "" - -#: windows/views.py:1431 windows/views.py:2084 windows/views.py:2114 -#: windows/views.py:2367 -msgid "MERGE" -msgstr "" - -#: windows/views.py:1434 windows/views.py:2093 windows/views.py:2114 -#: windows/views.py:2370 -msgid "TEMPTABLE" -msgstr "" - -#: windows/views.py:1444 windows/views.py:2120 -msgid "View constraint" -msgstr "" - -#: windows/views.py:1446 windows/views.py:2119 -msgid "None" -msgstr "" - -#: windows/views.py:1449 windows/views.py:2119 -msgid "LOCAL" -msgstr "" - -#: windows/views.py:1452 -msgid "CASCADE" -msgstr "" - -#: windows/views.py:1455 -msgid "CHECK ONLY" -msgstr "" - -#: windows/views.py:1458 windows/views.py:2119 -msgid "READ ONLY" -msgstr "" - -#: windows/views.py:1470 -msgid "Force" -msgstr "" - -#: windows/views.py:1482 -msgid "Security barrier" -msgstr "" - -#: windows/views.py:1564 -msgid "Views" -msgstr "" - -#: windows/views.py:1572 -msgid "Triggers" -msgstr "" - -#: windows/views.py:1584 -#, python-format -msgid "Table `%(database_name)s`.`%(table_name)s`: %(total_rows) rows total" -msgstr "" - -#: windows/views.py:1594 -msgid "Insert record" -msgstr "" - -#: windows/views.py:1599 -msgid "Duplicate record" -msgstr "" - -#: windows/views.py:1606 -msgid "Delete record" -msgstr "" - -#: windows/views.py:1616 -msgid "Apply changes automatically" -msgstr "" - -#: windows/views.py:1618 windows/views.py:1619 -msgid "" -"If enabled, table edits are applied immediately without pressing Apply or" -" Cancel" -msgstr "" - -#: windows/views.py:1640 -msgid "Next" -msgstr "" - -#: windows/views.py:1648 -msgid "Filters" -msgstr "" - -#: windows/views.py:1688 -msgid "CTRL+ENTER" -msgstr "" - -#: windows/views.py:1708 -msgid "Insert row" -msgstr "" - -#: windows/views.py:1716 -msgid "Data" -msgstr "" - -#: windows/views.py:1770 windows/views.py:1820 -msgid "New" -msgstr "" - -#: windows/views.py:1797 -msgid "Query" -msgstr "" - -#: windows/views.py:1817 -msgid "Close" -msgstr "" - -#: windows/views.py:1830 -msgid "Query #2" -msgstr "" - -#: windows/views.py:2075 -msgid "Column5" -msgstr "" - -#: windows/views.py:2086 -msgid "Import" -msgstr "" - -#: windows/views.py:2111 -msgid "Read only" -msgstr "" - -#: windows/views.py:2119 -msgid "CASCADED" -msgstr "" - -#: windows/views.py:2119 -msgid "CHECK OPTION" -msgstr "" - -#: windows/views.py:2143 -msgid "collapsible" -msgstr "" - -#: windows/views.py:2165 -msgid "Column3" -msgstr "" - -#: windows/views.py:2166 -msgid "Column4" -msgstr "" - -#: windows/views.py:2203 -msgid "" -"Database " -"(*.db;*.db3;*.sdb;*.s3db;*.sqlite;*.sqlite3)|*.db;*.db3;*.sdb;*.s3db;*.sqlite;*.sqlite3" -msgstr "" - -#: windows/views.py:2215 -msgid "Port" -msgstr "" - -#: windows/views.py:2247 -msgid "Usage" -msgstr "" - -#: windows/views.py:2258 -#, python-format -msgid "%(total_rows)s" -msgstr "" - -#: windows/views.py:2263 -msgid "rows total" -msgstr "" - -#: windows/views.py:2282 -msgid "Lines" -msgstr "" - -#: windows/views.py:2314 -msgid "Temporary" -msgstr "" - -#: windows/views.py:2325 -msgid "Engine options" -msgstr "" - -#: windows/views.py:2384 -msgid "RadioBtn" -msgstr "" - -#: windows/views.py:2454 -msgid "Edit Column" -msgstr "" - -#: windows/views.py:2470 -msgid "Datatype" -msgstr "" - -#: windows/components/dataview.py:121 windows/views.py:2485 -msgid "Length/Set" -msgstr "" - -#: windows/components/dataview.py:51 windows/views.py:2524 -msgid "Unsigned" -msgstr "" - -#: windows/components/dataview.py:25 windows/components/dataview.py:52 -#: windows/components/dataview.py:75 windows/views.py:2530 -msgid "Allow NULL" -msgstr "" - -#: windows/views.py:2536 -msgid "Zero Fill" -msgstr "" - -#: windows/components/dataview.py:32 windows/components/dataview.py:56 -#: windows/components/dataview.py:78 windows/views.py:2547 -msgid "Default" -msgstr "" - -#: windows/components/dataview.py:36 windows/components/dataview.py:60 -#: windows/components/dataview.py:82 windows/views.py:2573 -msgid "Virtuality" -msgstr "" - -#: windows/components/dataview.py:39 windows/components/dataview.py:63 -#: windows/components/dataview.py:85 windows/components/dataview.py:241 -#: windows/views.py:2588 -msgid "Expression" -msgstr "" - -#: windows/components/dataview.py:28 -msgid "Check" -msgstr "" - -#: windows/components/dataview.py:53 -msgid "Zerofill" -msgstr "" - -#: windows/components/dataview.py:109 -msgid "#" -msgstr "" - -#: windows/components/dataview.py:117 -msgid "Data type" -msgstr "" - -#: windows/components/dataview.py:155 -msgid "Add column\tCTRL+INS" -msgstr "" - -#: windows/components/dataview.py:161 -msgid "Remove column\tCTRL+DEL" -msgstr "" - -#: windows/components/dataview.py:169 -msgid "Move up\tCTRL+UP" -msgstr "" - -#: windows/components/dataview.py:176 -msgid "Move down\tCTRL+D" -msgstr "" - -#: windows/components/dataview.py:199 -msgid "Create new index" -msgstr "" - -#: windows/components/dataview.py:214 -msgid "Append to index" -msgstr "" - -#: windows/components/dataview.py:228 -msgid "Column(s)/Expression" -msgstr "" - -#: windows/components/dataview.py:229 -msgid "Condition" -msgstr "" - -#: windows/components/dataview.py:259 -msgid "Column(s)" -msgstr "" - -#: windows/components/dataview.py:265 -msgid "Reference table" -msgstr "" - -#: windows/components/dataview.py:271 -msgid "Reference column(s)" -msgstr "" - -#: windows/components/dataview.py:277 -msgid "On UPDATE" -msgstr "" - -#: windows/components/dataview.py:283 -msgid "On DELETE" -msgstr "" - -#: windows/components/dataview.py:299 -msgid "Add foreign key" -msgstr "" - -#: windows/components/dataview.py:305 -msgid "Remove foreign key" -msgstr "" - -#: windows/components/popup.py:26 -msgid "No default value" -msgstr "" - -#: windows/components/popup.py:31 -msgid "NULL" -msgstr "" - -#: windows/components/popup.py:35 -msgid "AUTO INCREMENT" -msgstr "" - -#: windows/components/popup.py:39 -msgid "Text/Expression" -msgstr "" - -#: windows/dialogs/connections/view.py:258 -msgid "Connection established successfully" -msgstr "" - -#: windows/dialogs/connections/view.py:271 -msgid "Confirm save" -msgstr "" - -#: windows/dialogs/connections/view.py:314 -msgid "You have unsaved changes. Do you want to save them before continuing?" -msgstr "" - -#: windows/dialogs/connections/view.py:316 -msgid "Unsaved changes" -msgstr "" - -#: windows/dialogs/connections/view.py:545 -msgid "" -"This connection cannot work without TLS. TLS has been enabled " -"automatically." -msgstr "" - -#: windows/dialogs/connections/view.py:554 -msgid "Connection error" -msgstr "" - -#: windows/dialogs/connections/view.py:580 -#: windows/dialogs/connections/view.py:595 -msgid "Confirm delete" -msgstr "" - -#: windows/main/controller.py:170 -msgid "days" -msgstr "" - -#: windows/main/controller.py:171 -msgid "hours" -msgstr "" - -#: windows/main/controller.py:172 -msgid "minutes" -msgstr "" - -#: windows/main/controller.py:173 -msgid "seconds" -msgstr "" - -#: windows/main/controller.py:181 -#, python-brace-format -msgid "Memory used: {used} ({percentage:.2%})" -msgstr "" - -#: windows/main/controller.py:217 -msgid "Settings saved successfully" -msgstr "" - -#: windows/main/controller.py:296 -msgid "Version" -msgstr "" - -#: windows/main/controller.py:298 -msgid "Uptime" -msgstr "" - -#: windows/main/controller.py:467 -msgid "Delete table" -msgstr "" - -#: windows/main/controller.py:584 -msgid "Do you want delete the records?" -msgstr "" - -#: windows/main/tabs/database.py:71 -msgid "The connection to the database was lost." -msgstr "" - -#: windows/main/tabs/database.py:73 -msgid "Do you want to reconnect?" -msgstr "" - -#: windows/main/tabs/database.py:75 -msgid "Connection lost" -msgstr "" - -#: windows/main/tabs/database.py:85 -msgid "Reconnection failed:" -msgstr "" - -#: windows/main/tabs/database.py:86 windows/main/tabs/query.py:450 -#: windows/main/tabs/view.py:256 windows/main/tabs/view.py:282 -msgid "Error" -msgstr "" - -#: windows/main/tabs/query.py:305 -#, python-brace-format -msgid "{} rows affected" -msgstr "" - -#: windows/main/tabs/query.py:309 windows/main/tabs/query.py:331 -#, python-brace-format -msgid "Query {}" -msgstr "" - -#: windows/main/tabs/query.py:314 -#, python-brace-format -msgid "Query {} (Error)" -msgstr "" - -#: windows/main/tabs/query.py:326 -#, python-brace-format -msgid "Query {} ({} rows × {} cols)" -msgstr "" - -#: windows/main/tabs/query.py:353 -#, python-brace-format -msgid "{} rows" -msgstr "" - -#: windows/main/tabs/query.py:355 -#, python-brace-format -msgid "{:.1f} ms" -msgstr "" - -#: windows/main/tabs/query.py:358 -#, python-brace-format -msgid "{} warnings" -msgstr "" - -#: windows/main/tabs/query.py:370 -msgid "Error:" -msgstr "" - -#: windows/main/tabs/query.py:376 -msgid "Unknown error" -msgstr "" - -#: windows/main/tabs/query.py:449 -msgid "No active database connection" -msgstr "" - -#: windows/main/tabs/view.py:252 -msgid "View created successfully" -msgstr "" - -#: windows/main/tabs/view.py:252 -msgid "View updated successfully" -msgstr "" - -#: windows/main/tabs/view.py:253 windows/main/tabs/view.py:279 -msgid "Success" -msgstr "" - -#: windows/main/tabs/view.py:256 -#, python-brace-format -msgid "Error saving view: {}" -msgstr "" - -#: windows/main/tabs/view.py:269 -#, python-brace-format -msgid "Are you sure you want to delete view '{}'?" -msgstr "" - -#: windows/main/tabs/view.py:270 -msgid "Confirm Delete" -msgstr "" - -#: windows/main/tabs/view.py:279 -msgid "View deleted successfully" -msgstr "" - -#: windows/main/tabs/view.py:282 -#, python-brace-format -msgid "Error deleting view: {}" -msgstr "" - -#~ msgid "New Session" -#~ msgstr "" - -#~ msgid "connection" -#~ msgstr "" - -#~ msgid "directory" -#~ msgstr "" - diff --git a/scripts/locale/es_ES/LC_MESSAGES/petersql.po b/scripts/locale/es_ES/LC_MESSAGES/petersql.po deleted file mode 100644 index 4370e80..0000000 --- a/scripts/locale/es_ES/LC_MESSAGES/petersql.po +++ /dev/null @@ -1,952 +0,0 @@ -#: helpers/__init__.py:16 -msgctxt "unit" -msgid "B" -msgstr "" - -#: helpers/__init__.py:17 -msgctxt "unit" -msgid "KB" -msgstr "" - -#: helpers/__init__.py:18 -msgctxt "unit" -msgid "MB" -msgstr "" - -#: helpers/__init__.py:19 -msgctxt "unit" -msgid "GB" -msgstr "" - -#: helpers/__init__.py:20 -msgctxt "unit" -msgid "TB" -msgstr "" - -#: structures/ssh_tunnel.py:166 -msgid "OpenSSH client not found." -msgstr "" - -#: windows/dialogs/connections/view.py:259 -#: windows/dialogs/connections/view.py:547 windows/main/controller.py:294 -#: windows/views.py:33 -msgid "Connection" -msgstr "" - -#: windows/components/dataview.py:113 windows/components/dataview.py:225 -#: windows/components/dataview.py:238 windows/components/dataview.py:253 -#: windows/views.py:47 windows/views.py:97 windows/views.py:898 -#: windows/views.py:958 windows/views.py:1341 windows/views.py:2246 -#: windows/views.py:2269 windows/views.py:2270 windows/views.py:2271 -#: windows/views.py:2272 windows/views.py:2273 windows/views.py:2274 -#: windows/views.py:2275 windows/views.py:2276 windows/views.py:2277 -#: windows/views.py:2281 windows/views.py:2462 windows/views.py:2663 -msgid "Name" -msgstr "" - -#: windows/views.py:48 windows/views.py:381 -msgid "Last connection" -msgstr "" - -#: windows/dialogs/connections/view.py:452 windows/views.py:61 -msgid "New directory" -msgstr "" - -#: windows/dialogs/connections/model.py:142 -#: windows/dialogs/connections/view.py:384 windows/views.py:65 -msgid "New connection" -msgstr "" - -#: windows/views.py:71 -msgid "Rename" -msgstr "" - -#: windows/views.py:76 -msgid "Clone connection" -msgstr "" - -#: windows/views.py:81 windows/views.py:471 windows/views.py:884 -#: windows/views.py:1251 windows/views.py:1283 windows/views.py:1542 -#: windows/views.py:2799 windows/views.py:2831 -msgid "Delete" -msgstr "" - -#: windows/views.py:111 windows/views.py:903 windows/views.py:1013 -#: windows/views.py:2286 windows/views.py:2718 -msgid "Engine" -msgstr "" - -#: windows/views.py:132 -msgid "Host + port" -msgstr "" - -#: windows/views.py:148 -msgid "Username" -msgstr "" - -#: windows/views.py:161 -msgid "Password" -msgstr "" - -#: windows/views.py:177 -msgid "Use TLS" -msgstr "" - -#: windows/views.py:180 -msgid "Use SSH tunnel" -msgstr "" - -#: windows/views.py:202 windows/views.py:2198 -msgid "Filename" -msgstr "" - -#: windows/views.py:207 windows/views.py:324 windows/views.py:2203 -#: windows/views.py:2395 -msgid "Select a file" -msgstr "" - -#: windows/views.py:207 windows/views.py:324 windows/views.py:2395 -msgid "*.*" -msgstr "" - -#: windows/components/dataview.py:70 windows/components/dataview.py:92 -#: windows/views.py:221 windows/views.py:905 windows/views.py:971 -#: windows/views.py:2287 windows/views.py:2560 windows/views.py:2676 -msgid "Comments" -msgstr "" - -#: windows/main/controller.py:217 windows/views.py:235 windows/views.py:598 -msgid "Settings" -msgstr "" - -#: windows/views.py:244 -msgid "SSH executable" -msgstr "" - -#: windows/views.py:249 -msgid "ssh" -msgstr "" - -#: windows/views.py:257 -msgid "SSH host + port" -msgstr "" - -#: windows/views.py:269 -msgid "SSH host + port (the SSH server that forwards traffic to the DB)" -msgstr "" - -#: windows/views.py:278 -msgid "SSH username" -msgstr "" - -#: windows/views.py:291 -msgid "SSH password" -msgstr "" - -#: windows/views.py:304 -msgid "Local port" -msgstr "" - -#: windows/views.py:310 -msgid "if the value is set to 0, the first available port will be used" -msgstr "" - -#: windows/views.py:319 -msgid "Identity file" -msgstr "" - -#: windows/views.py:335 -msgid "Remote host + port" -msgstr "" - -#: windows/views.py:347 -msgid "Remote host/port is the real DB target (defaults to DB Host/Port)." -msgstr "" - -#: windows/views.py:358 -msgid "SSH Tunnel" -msgstr "" - -#: windows/views.py:364 windows/views.py:901 windows/views.py:2284 -msgid "Created at" -msgstr "" - -#: windows/views.py:398 -msgid "Successful connections" -msgstr "" - -#: windows/views.py:415 -msgid "Unsuccessful connections" -msgstr "" - -#: windows/views.py:434 -msgid "Statistics" -msgstr "" - -#: windows/views.py:452 windows/views.py:1217 -msgid "Create" -msgstr "" - -#: windows/views.py:456 -msgid "Create connection" -msgstr "" - -#: windows/views.py:459 -msgid "Create directory" -msgstr "" - -#: windows/views.py:488 windows/views.py:712 windows/views.py:1286 -#: windows/views.py:1547 windows/views.py:1623 windows/views.py:2607 -#: windows/views.py:2834 -msgid "Cancel" -msgstr "" - -#: windows/views.py:493 windows/views.py:1552 windows/views.py:2617 -#: windows/views.py:2839 -msgid "Save" -msgstr "" - -#: windows/views.py:500 -msgid "Test" -msgstr "" - -#: windows/views.py:507 -msgid "Connect" -msgstr "" - -#: windows/views.py:610 -msgid "Language" -msgstr "" - -#: windows/views.py:615 -msgid "English" -msgstr "" - -#: windows/views.py:615 -msgid "Italian" -msgstr "" - -#: windows/views.py:615 -msgid "French" -msgstr "" - -#: windows/views.py:627 -msgid "Locale" -msgstr "" - -#: windows/views.py:648 -msgid "Edit Value" -msgstr "" - -#: windows/views.py:658 -msgid "Syntax" -msgstr "" - -#: windows/views.py:715 -msgid "Ok" -msgstr "" - -#: windows/views.py:746 -msgid "PeterSQL" -msgstr "" - -#: windows/views.py:752 -msgid "File" -msgstr "" - -#: windows/views.py:755 -msgid "About" -msgstr "" - -#: windows/views.py:758 -msgid "Help" -msgstr "" - -#: windows/views.py:763 -msgid "Open connection manager" -msgstr "" - -#: windows/views.py:765 -msgid "Disconnect from server" -msgstr "" - -#: windows/views.py:769 -msgid "tool" -msgstr "" - -#: windows/views.py:769 -msgid "Refresh" -msgstr "" - -#: windows/views.py:773 windows/views.py:775 -msgid "Add" -msgstr "" - -#: windows/views.py:809 windows/views.py:813 windows/views.py:1711 -#: windows/views.py:1839 -msgid "MyMenuItem" -msgstr "" - -#: windows/views.py:816 windows/views.py:1314 windows/views.py:2862 -msgid "MyMenu" -msgstr "" - -#: windows/views.py:831 -msgid "MyLabel" -msgstr "" - -#: windows/views.py:837 -msgid "Databases" -msgstr "" - -#: windows/views.py:838 windows/views.py:900 windows/views.py:2255 -#: windows/views.py:2283 -msgid "Size" -msgstr "" - -#: windows/views.py:839 -msgid "Elements" -msgstr "" - -#: windows/views.py:840 -msgid "Modified at" -msgstr "" - -#: windows/views.py:841 windows/views.py:912 -msgid "Tables" -msgstr "" - -#: windows/views.py:848 -msgid "System" -msgstr "" - -#: windows/views.py:864 -msgid "Table:" -msgstr "" - -#: windows/views.py:872 windows/views.py:1096 windows/views.py:1140 -#: windows/views.py:1246 windows/views.py:2794 -msgid "Insert" -msgstr "" - -#: windows/views.py:877 -msgid "Clone" -msgstr "" - -#: windows/views.py:899 -msgid "Rows" -msgstr "" - -#: windows/views.py:902 windows/views.py:2285 -msgid "Updated at" -msgstr "" - -#: windows/components/dataview.py:43 windows/components/dataview.py:67 -#: windows/components/dataview.py:89 windows/views.py:904 windows/views.py:2506 -msgid "Collation" -msgstr "" - -#: windows/views.py:920 -msgid "Diagram" -msgstr "" - -#: windows/views.py:931 windows/views.py:2254 -msgid "Database" -msgstr "" - -#: windows/views.py:986 windows/views.py:2691 -msgid "Base" -msgstr "" - -#: windows/views.py:1000 windows/views.py:2705 -msgid "Auto Increment" -msgstr "" - -#: windows/views.py:1028 windows/views.py:2733 -msgid "Default Collation" -msgstr "" - -#: windows/views.py:1048 windows/views.py:1501 windows/views.py:2751 -msgid "Options" -msgstr "" - -#: windows/views.py:1060 windows/views.py:1101 windows/views.py:1145 -msgid "Remove" -msgstr "" - -#: windows/views.py:1067 windows/views.py:1108 windows/views.py:1152 -msgid "Clear" -msgstr "" - -#: windows/views.py:1082 windows/views.py:2765 -msgid "Indexes" -msgstr "" - -#: windows/views.py:1126 -msgid "Foreign Keys" -msgstr "" - -#: windows/views.py:1170 -msgid "Checks" -msgstr "" - -#: windows/views.py:1238 windows/views.py:2786 -msgid "Columns:" -msgstr "" - -#: windows/views.py:1258 windows/views.py:2806 -msgid "Up" -msgstr "" - -#: windows/views.py:1265 windows/views.py:2813 -msgid "Down" -msgstr "" - -#: windows/views.py:1291 windows/views.py:1630 windows/views.py:1685 -msgid "Apply" -msgstr "" - -#: windows/views.py:1304 windows/views.py:1311 windows/views.py:2852 -#: windows/views.py:2859 -msgid "Add Index" -msgstr "" - -#: windows/views.py:1308 windows/views.py:2856 -msgid "Add PrimaryKey" -msgstr "" - -#: windows/views.py:1325 -msgid "Table" -msgstr "" - -#: windows/views.py:1361 -msgid "Definer" -msgstr "" - -#: windows/views.py:1381 -msgid "Schema" -msgstr "" - -#: windows/views.py:1407 -msgid "SQL security" -msgstr "" - -#: windows/views.py:1414 -msgid "DEFINER" -msgstr "" - -#: windows/views.py:1414 -msgid "INVOKER" -msgstr "" - -#: windows/views.py:1426 windows/views.py:2096 windows/views.py:2115 -#: windows/views.py:2359 -msgid "Algorithm" -msgstr "" - -#: windows/views.py:1428 windows/views.py:2081 windows/views.py:2114 -#: windows/views.py:2364 -msgid "UNDEFINED" -msgstr "" - -#: windows/views.py:1431 windows/views.py:2084 windows/views.py:2114 -#: windows/views.py:2367 -msgid "MERGE" -msgstr "" - -#: windows/views.py:1434 windows/views.py:2093 windows/views.py:2114 -#: windows/views.py:2370 -msgid "TEMPTABLE" -msgstr "" - -#: windows/views.py:1444 windows/views.py:2120 -msgid "View constraint" -msgstr "" - -#: windows/views.py:1446 windows/views.py:2119 -msgid "None" -msgstr "" - -#: windows/views.py:1449 windows/views.py:2119 -msgid "LOCAL" -msgstr "" - -#: windows/views.py:1452 -msgid "CASCADE" -msgstr "" - -#: windows/views.py:1455 -msgid "CHECK ONLY" -msgstr "" - -#: windows/views.py:1458 windows/views.py:2119 -msgid "READ ONLY" -msgstr "" - -#: windows/views.py:1470 -msgid "Force" -msgstr "" - -#: windows/views.py:1482 -msgid "Security barrier" -msgstr "" - -#: windows/views.py:1564 -msgid "Views" -msgstr "" - -#: windows/views.py:1572 -msgid "Triggers" -msgstr "" - -#: windows/views.py:1584 -#, python-format -msgid "Table `%(database_name)s`.`%(table_name)s`: %(total_rows) rows total" -msgstr "" - -#: windows/views.py:1594 -msgid "Insert record" -msgstr "" - -#: windows/views.py:1599 -msgid "Duplicate record" -msgstr "" - -#: windows/views.py:1606 -msgid "Delete record" -msgstr "" - -#: windows/views.py:1616 -msgid "Apply changes automatically" -msgstr "" - -#: windows/views.py:1618 windows/views.py:1619 -msgid "" -"If enabled, table edits are applied immediately without pressing Apply or" -" Cancel" -msgstr "" - -#: windows/views.py:1640 -msgid "Next" -msgstr "" - -#: windows/views.py:1648 -msgid "Filters" -msgstr "" - -#: windows/views.py:1688 -msgid "CTRL+ENTER" -msgstr "" - -#: windows/views.py:1708 -msgid "Insert row" -msgstr "" - -#: windows/views.py:1716 -msgid "Data" -msgstr "" - -#: windows/views.py:1770 windows/views.py:1820 -msgid "New" -msgstr "" - -#: windows/views.py:1797 -msgid "Query" -msgstr "" - -#: windows/views.py:1817 -msgid "Close" -msgstr "" - -#: windows/views.py:1830 -msgid "Query #2" -msgstr "" - -#: windows/views.py:2075 -msgid "Column5" -msgstr "" - -#: windows/views.py:2086 -msgid "Import" -msgstr "" - -#: windows/views.py:2111 -msgid "Read only" -msgstr "" - -#: windows/views.py:2119 -msgid "CASCADED" -msgstr "" - -#: windows/views.py:2119 -msgid "CHECK OPTION" -msgstr "" - -#: windows/views.py:2143 -msgid "collapsible" -msgstr "" - -#: windows/views.py:2165 -msgid "Column3" -msgstr "" - -#: windows/views.py:2166 -msgid "Column4" -msgstr "" - -#: windows/views.py:2203 -msgid "" -"Database " -"(*.db;*.db3;*.sdb;*.s3db;*.sqlite;*.sqlite3)|*.db;*.db3;*.sdb;*.s3db;*.sqlite;*.sqlite3" -msgstr "" - -#: windows/views.py:2215 -msgid "Port" -msgstr "" - -#: windows/views.py:2247 -msgid "Usage" -msgstr "" - -#: windows/views.py:2258 -#, python-format -msgid "%(total_rows)s" -msgstr "" - -#: windows/views.py:2263 -msgid "rows total" -msgstr "" - -#: windows/views.py:2282 -msgid "Lines" -msgstr "" - -#: windows/views.py:2314 -msgid "Temporary" -msgstr "" - -#: windows/views.py:2325 -msgid "Engine options" -msgstr "" - -#: windows/views.py:2384 -msgid "RadioBtn" -msgstr "" - -#: windows/views.py:2454 -msgid "Edit Column" -msgstr "" - -#: windows/views.py:2470 -msgid "Datatype" -msgstr "" - -#: windows/components/dataview.py:121 windows/views.py:2485 -msgid "Length/Set" -msgstr "" - -#: windows/components/dataview.py:51 windows/views.py:2524 -msgid "Unsigned" -msgstr "" - -#: windows/components/dataview.py:25 windows/components/dataview.py:52 -#: windows/components/dataview.py:75 windows/views.py:2530 -msgid "Allow NULL" -msgstr "" - -#: windows/views.py:2536 -msgid "Zero Fill" -msgstr "" - -#: windows/components/dataview.py:32 windows/components/dataview.py:56 -#: windows/components/dataview.py:78 windows/views.py:2547 -msgid "Default" -msgstr "" - -#: windows/components/dataview.py:36 windows/components/dataview.py:60 -#: windows/components/dataview.py:82 windows/views.py:2573 -msgid "Virtuality" -msgstr "" - -#: windows/components/dataview.py:39 windows/components/dataview.py:63 -#: windows/components/dataview.py:85 windows/components/dataview.py:241 -#: windows/views.py:2588 -msgid "Expression" -msgstr "" - -#: windows/components/dataview.py:28 -msgid "Check" -msgstr "" - -#: windows/components/dataview.py:53 -msgid "Zerofill" -msgstr "" - -#: windows/components/dataview.py:109 -msgid "#" -msgstr "" - -#: windows/components/dataview.py:117 -msgid "Data type" -msgstr "" - -#: windows/components/dataview.py:155 -msgid "Add column\tCTRL+INS" -msgstr "" - -#: windows/components/dataview.py:161 -msgid "Remove column\tCTRL+DEL" -msgstr "" - -#: windows/components/dataview.py:169 -msgid "Move up\tCTRL+UP" -msgstr "" - -#: windows/components/dataview.py:176 -msgid "Move down\tCTRL+D" -msgstr "" - -#: windows/components/dataview.py:199 -msgid "Create new index" -msgstr "" - -#: windows/components/dataview.py:214 -msgid "Append to index" -msgstr "" - -#: windows/components/dataview.py:228 -msgid "Column(s)/Expression" -msgstr "" - -#: windows/components/dataview.py:229 -msgid "Condition" -msgstr "" - -#: windows/components/dataview.py:259 -msgid "Column(s)" -msgstr "" - -#: windows/components/dataview.py:265 -msgid "Reference table" -msgstr "" - -#: windows/components/dataview.py:271 -msgid "Reference column(s)" -msgstr "" - -#: windows/components/dataview.py:277 -msgid "On UPDATE" -msgstr "" - -#: windows/components/dataview.py:283 -msgid "On DELETE" -msgstr "" - -#: windows/components/dataview.py:299 -msgid "Add foreign key" -msgstr "" - -#: windows/components/dataview.py:305 -msgid "Remove foreign key" -msgstr "" - -#: windows/components/popup.py:26 -msgid "No default value" -msgstr "" - -#: windows/components/popup.py:31 -msgid "NULL" -msgstr "" - -#: windows/components/popup.py:35 -msgid "AUTO INCREMENT" -msgstr "" - -#: windows/components/popup.py:39 -msgid "Text/Expression" -msgstr "" - -#: windows/dialogs/connections/view.py:258 -msgid "Connection established successfully" -msgstr "" - -#: windows/dialogs/connections/view.py:271 -msgid "Confirm save" -msgstr "" - -#: windows/dialogs/connections/view.py:314 -msgid "You have unsaved changes. Do you want to save them before continuing?" -msgstr "" - -#: windows/dialogs/connections/view.py:316 -msgid "Unsaved changes" -msgstr "" - -#: windows/dialogs/connections/view.py:545 -msgid "" -"This connection cannot work without TLS. TLS has been enabled " -"automatically." -msgstr "" - -#: windows/dialogs/connections/view.py:554 -msgid "Connection error" -msgstr "" - -#: windows/dialogs/connections/view.py:580 -#: windows/dialogs/connections/view.py:595 -msgid "Confirm delete" -msgstr "" - -#: windows/main/controller.py:170 -msgid "days" -msgstr "" - -#: windows/main/controller.py:171 -msgid "hours" -msgstr "" - -#: windows/main/controller.py:172 -msgid "minutes" -msgstr "" - -#: windows/main/controller.py:173 -msgid "seconds" -msgstr "" - -#: windows/main/controller.py:181 -#, python-brace-format -msgid "Memory used: {used} ({percentage:.2%})" -msgstr "" - -#: windows/main/controller.py:217 -msgid "Settings saved successfully" -msgstr "" - -#: windows/main/controller.py:296 -msgid "Version" -msgstr "" - -#: windows/main/controller.py:298 -msgid "Uptime" -msgstr "" - -#: windows/main/controller.py:467 -msgid "Delete table" -msgstr "" - -#: windows/main/controller.py:584 -msgid "Do you want delete the records?" -msgstr "" - -#: windows/main/tabs/database.py:71 -msgid "The connection to the database was lost." -msgstr "" - -#: windows/main/tabs/database.py:73 -msgid "Do you want to reconnect?" -msgstr "" - -#: windows/main/tabs/database.py:75 -msgid "Connection lost" -msgstr "" - -#: windows/main/tabs/database.py:85 -msgid "Reconnection failed:" -msgstr "" - -#: windows/main/tabs/database.py:86 windows/main/tabs/query.py:450 -#: windows/main/tabs/view.py:256 windows/main/tabs/view.py:282 -msgid "Error" -msgstr "" - -#: windows/main/tabs/query.py:305 -#, python-brace-format -msgid "{} rows affected" -msgstr "" - -#: windows/main/tabs/query.py:309 windows/main/tabs/query.py:331 -#, python-brace-format -msgid "Query {}" -msgstr "" - -#: windows/main/tabs/query.py:314 -#, python-brace-format -msgid "Query {} (Error)" -msgstr "" - -#: windows/main/tabs/query.py:326 -#, python-brace-format -msgid "Query {} ({} rows × {} cols)" -msgstr "" - -#: windows/main/tabs/query.py:353 -#, python-brace-format -msgid "{} rows" -msgstr "" - -#: windows/main/tabs/query.py:355 -#, python-brace-format -msgid "{:.1f} ms" -msgstr "" - -#: windows/main/tabs/query.py:358 -#, python-brace-format -msgid "{} warnings" -msgstr "" - -#: windows/main/tabs/query.py:370 -msgid "Error:" -msgstr "" - -#: windows/main/tabs/query.py:376 -msgid "Unknown error" -msgstr "" - -#: windows/main/tabs/query.py:449 -msgid "No active database connection" -msgstr "" - -#: windows/main/tabs/view.py:252 -msgid "View created successfully" -msgstr "" - -#: windows/main/tabs/view.py:252 -msgid "View updated successfully" -msgstr "" - -#: windows/main/tabs/view.py:253 windows/main/tabs/view.py:279 -msgid "Success" -msgstr "" - -#: windows/main/tabs/view.py:256 -#, python-brace-format -msgid "Error saving view: {}" -msgstr "" - -#: windows/main/tabs/view.py:269 -#, python-brace-format -msgid "Are you sure you want to delete view '{}'?" -msgstr "" - -#: windows/main/tabs/view.py:270 -msgid "Confirm Delete" -msgstr "" - -#: windows/main/tabs/view.py:279 -msgid "View deleted successfully" -msgstr "" - -#: windows/main/tabs/view.py:282 -#, python-brace-format -msgid "Error deleting view: {}" -msgstr "" - -#~ msgid "New Session" -#~ msgstr "" - -#~ msgid "connection" -#~ msgstr "" - -#~ msgid "directory" -#~ msgstr "" - diff --git a/scripts/locale/fr_FR/LC_MESSAGES/petersql.po b/scripts/locale/fr_FR/LC_MESSAGES/petersql.po deleted file mode 100644 index 4370e80..0000000 --- a/scripts/locale/fr_FR/LC_MESSAGES/petersql.po +++ /dev/null @@ -1,952 +0,0 @@ -#: helpers/__init__.py:16 -msgctxt "unit" -msgid "B" -msgstr "" - -#: helpers/__init__.py:17 -msgctxt "unit" -msgid "KB" -msgstr "" - -#: helpers/__init__.py:18 -msgctxt "unit" -msgid "MB" -msgstr "" - -#: helpers/__init__.py:19 -msgctxt "unit" -msgid "GB" -msgstr "" - -#: helpers/__init__.py:20 -msgctxt "unit" -msgid "TB" -msgstr "" - -#: structures/ssh_tunnel.py:166 -msgid "OpenSSH client not found." -msgstr "" - -#: windows/dialogs/connections/view.py:259 -#: windows/dialogs/connections/view.py:547 windows/main/controller.py:294 -#: windows/views.py:33 -msgid "Connection" -msgstr "" - -#: windows/components/dataview.py:113 windows/components/dataview.py:225 -#: windows/components/dataview.py:238 windows/components/dataview.py:253 -#: windows/views.py:47 windows/views.py:97 windows/views.py:898 -#: windows/views.py:958 windows/views.py:1341 windows/views.py:2246 -#: windows/views.py:2269 windows/views.py:2270 windows/views.py:2271 -#: windows/views.py:2272 windows/views.py:2273 windows/views.py:2274 -#: windows/views.py:2275 windows/views.py:2276 windows/views.py:2277 -#: windows/views.py:2281 windows/views.py:2462 windows/views.py:2663 -msgid "Name" -msgstr "" - -#: windows/views.py:48 windows/views.py:381 -msgid "Last connection" -msgstr "" - -#: windows/dialogs/connections/view.py:452 windows/views.py:61 -msgid "New directory" -msgstr "" - -#: windows/dialogs/connections/model.py:142 -#: windows/dialogs/connections/view.py:384 windows/views.py:65 -msgid "New connection" -msgstr "" - -#: windows/views.py:71 -msgid "Rename" -msgstr "" - -#: windows/views.py:76 -msgid "Clone connection" -msgstr "" - -#: windows/views.py:81 windows/views.py:471 windows/views.py:884 -#: windows/views.py:1251 windows/views.py:1283 windows/views.py:1542 -#: windows/views.py:2799 windows/views.py:2831 -msgid "Delete" -msgstr "" - -#: windows/views.py:111 windows/views.py:903 windows/views.py:1013 -#: windows/views.py:2286 windows/views.py:2718 -msgid "Engine" -msgstr "" - -#: windows/views.py:132 -msgid "Host + port" -msgstr "" - -#: windows/views.py:148 -msgid "Username" -msgstr "" - -#: windows/views.py:161 -msgid "Password" -msgstr "" - -#: windows/views.py:177 -msgid "Use TLS" -msgstr "" - -#: windows/views.py:180 -msgid "Use SSH tunnel" -msgstr "" - -#: windows/views.py:202 windows/views.py:2198 -msgid "Filename" -msgstr "" - -#: windows/views.py:207 windows/views.py:324 windows/views.py:2203 -#: windows/views.py:2395 -msgid "Select a file" -msgstr "" - -#: windows/views.py:207 windows/views.py:324 windows/views.py:2395 -msgid "*.*" -msgstr "" - -#: windows/components/dataview.py:70 windows/components/dataview.py:92 -#: windows/views.py:221 windows/views.py:905 windows/views.py:971 -#: windows/views.py:2287 windows/views.py:2560 windows/views.py:2676 -msgid "Comments" -msgstr "" - -#: windows/main/controller.py:217 windows/views.py:235 windows/views.py:598 -msgid "Settings" -msgstr "" - -#: windows/views.py:244 -msgid "SSH executable" -msgstr "" - -#: windows/views.py:249 -msgid "ssh" -msgstr "" - -#: windows/views.py:257 -msgid "SSH host + port" -msgstr "" - -#: windows/views.py:269 -msgid "SSH host + port (the SSH server that forwards traffic to the DB)" -msgstr "" - -#: windows/views.py:278 -msgid "SSH username" -msgstr "" - -#: windows/views.py:291 -msgid "SSH password" -msgstr "" - -#: windows/views.py:304 -msgid "Local port" -msgstr "" - -#: windows/views.py:310 -msgid "if the value is set to 0, the first available port will be used" -msgstr "" - -#: windows/views.py:319 -msgid "Identity file" -msgstr "" - -#: windows/views.py:335 -msgid "Remote host + port" -msgstr "" - -#: windows/views.py:347 -msgid "Remote host/port is the real DB target (defaults to DB Host/Port)." -msgstr "" - -#: windows/views.py:358 -msgid "SSH Tunnel" -msgstr "" - -#: windows/views.py:364 windows/views.py:901 windows/views.py:2284 -msgid "Created at" -msgstr "" - -#: windows/views.py:398 -msgid "Successful connections" -msgstr "" - -#: windows/views.py:415 -msgid "Unsuccessful connections" -msgstr "" - -#: windows/views.py:434 -msgid "Statistics" -msgstr "" - -#: windows/views.py:452 windows/views.py:1217 -msgid "Create" -msgstr "" - -#: windows/views.py:456 -msgid "Create connection" -msgstr "" - -#: windows/views.py:459 -msgid "Create directory" -msgstr "" - -#: windows/views.py:488 windows/views.py:712 windows/views.py:1286 -#: windows/views.py:1547 windows/views.py:1623 windows/views.py:2607 -#: windows/views.py:2834 -msgid "Cancel" -msgstr "" - -#: windows/views.py:493 windows/views.py:1552 windows/views.py:2617 -#: windows/views.py:2839 -msgid "Save" -msgstr "" - -#: windows/views.py:500 -msgid "Test" -msgstr "" - -#: windows/views.py:507 -msgid "Connect" -msgstr "" - -#: windows/views.py:610 -msgid "Language" -msgstr "" - -#: windows/views.py:615 -msgid "English" -msgstr "" - -#: windows/views.py:615 -msgid "Italian" -msgstr "" - -#: windows/views.py:615 -msgid "French" -msgstr "" - -#: windows/views.py:627 -msgid "Locale" -msgstr "" - -#: windows/views.py:648 -msgid "Edit Value" -msgstr "" - -#: windows/views.py:658 -msgid "Syntax" -msgstr "" - -#: windows/views.py:715 -msgid "Ok" -msgstr "" - -#: windows/views.py:746 -msgid "PeterSQL" -msgstr "" - -#: windows/views.py:752 -msgid "File" -msgstr "" - -#: windows/views.py:755 -msgid "About" -msgstr "" - -#: windows/views.py:758 -msgid "Help" -msgstr "" - -#: windows/views.py:763 -msgid "Open connection manager" -msgstr "" - -#: windows/views.py:765 -msgid "Disconnect from server" -msgstr "" - -#: windows/views.py:769 -msgid "tool" -msgstr "" - -#: windows/views.py:769 -msgid "Refresh" -msgstr "" - -#: windows/views.py:773 windows/views.py:775 -msgid "Add" -msgstr "" - -#: windows/views.py:809 windows/views.py:813 windows/views.py:1711 -#: windows/views.py:1839 -msgid "MyMenuItem" -msgstr "" - -#: windows/views.py:816 windows/views.py:1314 windows/views.py:2862 -msgid "MyMenu" -msgstr "" - -#: windows/views.py:831 -msgid "MyLabel" -msgstr "" - -#: windows/views.py:837 -msgid "Databases" -msgstr "" - -#: windows/views.py:838 windows/views.py:900 windows/views.py:2255 -#: windows/views.py:2283 -msgid "Size" -msgstr "" - -#: windows/views.py:839 -msgid "Elements" -msgstr "" - -#: windows/views.py:840 -msgid "Modified at" -msgstr "" - -#: windows/views.py:841 windows/views.py:912 -msgid "Tables" -msgstr "" - -#: windows/views.py:848 -msgid "System" -msgstr "" - -#: windows/views.py:864 -msgid "Table:" -msgstr "" - -#: windows/views.py:872 windows/views.py:1096 windows/views.py:1140 -#: windows/views.py:1246 windows/views.py:2794 -msgid "Insert" -msgstr "" - -#: windows/views.py:877 -msgid "Clone" -msgstr "" - -#: windows/views.py:899 -msgid "Rows" -msgstr "" - -#: windows/views.py:902 windows/views.py:2285 -msgid "Updated at" -msgstr "" - -#: windows/components/dataview.py:43 windows/components/dataview.py:67 -#: windows/components/dataview.py:89 windows/views.py:904 windows/views.py:2506 -msgid "Collation" -msgstr "" - -#: windows/views.py:920 -msgid "Diagram" -msgstr "" - -#: windows/views.py:931 windows/views.py:2254 -msgid "Database" -msgstr "" - -#: windows/views.py:986 windows/views.py:2691 -msgid "Base" -msgstr "" - -#: windows/views.py:1000 windows/views.py:2705 -msgid "Auto Increment" -msgstr "" - -#: windows/views.py:1028 windows/views.py:2733 -msgid "Default Collation" -msgstr "" - -#: windows/views.py:1048 windows/views.py:1501 windows/views.py:2751 -msgid "Options" -msgstr "" - -#: windows/views.py:1060 windows/views.py:1101 windows/views.py:1145 -msgid "Remove" -msgstr "" - -#: windows/views.py:1067 windows/views.py:1108 windows/views.py:1152 -msgid "Clear" -msgstr "" - -#: windows/views.py:1082 windows/views.py:2765 -msgid "Indexes" -msgstr "" - -#: windows/views.py:1126 -msgid "Foreign Keys" -msgstr "" - -#: windows/views.py:1170 -msgid "Checks" -msgstr "" - -#: windows/views.py:1238 windows/views.py:2786 -msgid "Columns:" -msgstr "" - -#: windows/views.py:1258 windows/views.py:2806 -msgid "Up" -msgstr "" - -#: windows/views.py:1265 windows/views.py:2813 -msgid "Down" -msgstr "" - -#: windows/views.py:1291 windows/views.py:1630 windows/views.py:1685 -msgid "Apply" -msgstr "" - -#: windows/views.py:1304 windows/views.py:1311 windows/views.py:2852 -#: windows/views.py:2859 -msgid "Add Index" -msgstr "" - -#: windows/views.py:1308 windows/views.py:2856 -msgid "Add PrimaryKey" -msgstr "" - -#: windows/views.py:1325 -msgid "Table" -msgstr "" - -#: windows/views.py:1361 -msgid "Definer" -msgstr "" - -#: windows/views.py:1381 -msgid "Schema" -msgstr "" - -#: windows/views.py:1407 -msgid "SQL security" -msgstr "" - -#: windows/views.py:1414 -msgid "DEFINER" -msgstr "" - -#: windows/views.py:1414 -msgid "INVOKER" -msgstr "" - -#: windows/views.py:1426 windows/views.py:2096 windows/views.py:2115 -#: windows/views.py:2359 -msgid "Algorithm" -msgstr "" - -#: windows/views.py:1428 windows/views.py:2081 windows/views.py:2114 -#: windows/views.py:2364 -msgid "UNDEFINED" -msgstr "" - -#: windows/views.py:1431 windows/views.py:2084 windows/views.py:2114 -#: windows/views.py:2367 -msgid "MERGE" -msgstr "" - -#: windows/views.py:1434 windows/views.py:2093 windows/views.py:2114 -#: windows/views.py:2370 -msgid "TEMPTABLE" -msgstr "" - -#: windows/views.py:1444 windows/views.py:2120 -msgid "View constraint" -msgstr "" - -#: windows/views.py:1446 windows/views.py:2119 -msgid "None" -msgstr "" - -#: windows/views.py:1449 windows/views.py:2119 -msgid "LOCAL" -msgstr "" - -#: windows/views.py:1452 -msgid "CASCADE" -msgstr "" - -#: windows/views.py:1455 -msgid "CHECK ONLY" -msgstr "" - -#: windows/views.py:1458 windows/views.py:2119 -msgid "READ ONLY" -msgstr "" - -#: windows/views.py:1470 -msgid "Force" -msgstr "" - -#: windows/views.py:1482 -msgid "Security barrier" -msgstr "" - -#: windows/views.py:1564 -msgid "Views" -msgstr "" - -#: windows/views.py:1572 -msgid "Triggers" -msgstr "" - -#: windows/views.py:1584 -#, python-format -msgid "Table `%(database_name)s`.`%(table_name)s`: %(total_rows) rows total" -msgstr "" - -#: windows/views.py:1594 -msgid "Insert record" -msgstr "" - -#: windows/views.py:1599 -msgid "Duplicate record" -msgstr "" - -#: windows/views.py:1606 -msgid "Delete record" -msgstr "" - -#: windows/views.py:1616 -msgid "Apply changes automatically" -msgstr "" - -#: windows/views.py:1618 windows/views.py:1619 -msgid "" -"If enabled, table edits are applied immediately without pressing Apply or" -" Cancel" -msgstr "" - -#: windows/views.py:1640 -msgid "Next" -msgstr "" - -#: windows/views.py:1648 -msgid "Filters" -msgstr "" - -#: windows/views.py:1688 -msgid "CTRL+ENTER" -msgstr "" - -#: windows/views.py:1708 -msgid "Insert row" -msgstr "" - -#: windows/views.py:1716 -msgid "Data" -msgstr "" - -#: windows/views.py:1770 windows/views.py:1820 -msgid "New" -msgstr "" - -#: windows/views.py:1797 -msgid "Query" -msgstr "" - -#: windows/views.py:1817 -msgid "Close" -msgstr "" - -#: windows/views.py:1830 -msgid "Query #2" -msgstr "" - -#: windows/views.py:2075 -msgid "Column5" -msgstr "" - -#: windows/views.py:2086 -msgid "Import" -msgstr "" - -#: windows/views.py:2111 -msgid "Read only" -msgstr "" - -#: windows/views.py:2119 -msgid "CASCADED" -msgstr "" - -#: windows/views.py:2119 -msgid "CHECK OPTION" -msgstr "" - -#: windows/views.py:2143 -msgid "collapsible" -msgstr "" - -#: windows/views.py:2165 -msgid "Column3" -msgstr "" - -#: windows/views.py:2166 -msgid "Column4" -msgstr "" - -#: windows/views.py:2203 -msgid "" -"Database " -"(*.db;*.db3;*.sdb;*.s3db;*.sqlite;*.sqlite3)|*.db;*.db3;*.sdb;*.s3db;*.sqlite;*.sqlite3" -msgstr "" - -#: windows/views.py:2215 -msgid "Port" -msgstr "" - -#: windows/views.py:2247 -msgid "Usage" -msgstr "" - -#: windows/views.py:2258 -#, python-format -msgid "%(total_rows)s" -msgstr "" - -#: windows/views.py:2263 -msgid "rows total" -msgstr "" - -#: windows/views.py:2282 -msgid "Lines" -msgstr "" - -#: windows/views.py:2314 -msgid "Temporary" -msgstr "" - -#: windows/views.py:2325 -msgid "Engine options" -msgstr "" - -#: windows/views.py:2384 -msgid "RadioBtn" -msgstr "" - -#: windows/views.py:2454 -msgid "Edit Column" -msgstr "" - -#: windows/views.py:2470 -msgid "Datatype" -msgstr "" - -#: windows/components/dataview.py:121 windows/views.py:2485 -msgid "Length/Set" -msgstr "" - -#: windows/components/dataview.py:51 windows/views.py:2524 -msgid "Unsigned" -msgstr "" - -#: windows/components/dataview.py:25 windows/components/dataview.py:52 -#: windows/components/dataview.py:75 windows/views.py:2530 -msgid "Allow NULL" -msgstr "" - -#: windows/views.py:2536 -msgid "Zero Fill" -msgstr "" - -#: windows/components/dataview.py:32 windows/components/dataview.py:56 -#: windows/components/dataview.py:78 windows/views.py:2547 -msgid "Default" -msgstr "" - -#: windows/components/dataview.py:36 windows/components/dataview.py:60 -#: windows/components/dataview.py:82 windows/views.py:2573 -msgid "Virtuality" -msgstr "" - -#: windows/components/dataview.py:39 windows/components/dataview.py:63 -#: windows/components/dataview.py:85 windows/components/dataview.py:241 -#: windows/views.py:2588 -msgid "Expression" -msgstr "" - -#: windows/components/dataview.py:28 -msgid "Check" -msgstr "" - -#: windows/components/dataview.py:53 -msgid "Zerofill" -msgstr "" - -#: windows/components/dataview.py:109 -msgid "#" -msgstr "" - -#: windows/components/dataview.py:117 -msgid "Data type" -msgstr "" - -#: windows/components/dataview.py:155 -msgid "Add column\tCTRL+INS" -msgstr "" - -#: windows/components/dataview.py:161 -msgid "Remove column\tCTRL+DEL" -msgstr "" - -#: windows/components/dataview.py:169 -msgid "Move up\tCTRL+UP" -msgstr "" - -#: windows/components/dataview.py:176 -msgid "Move down\tCTRL+D" -msgstr "" - -#: windows/components/dataview.py:199 -msgid "Create new index" -msgstr "" - -#: windows/components/dataview.py:214 -msgid "Append to index" -msgstr "" - -#: windows/components/dataview.py:228 -msgid "Column(s)/Expression" -msgstr "" - -#: windows/components/dataview.py:229 -msgid "Condition" -msgstr "" - -#: windows/components/dataview.py:259 -msgid "Column(s)" -msgstr "" - -#: windows/components/dataview.py:265 -msgid "Reference table" -msgstr "" - -#: windows/components/dataview.py:271 -msgid "Reference column(s)" -msgstr "" - -#: windows/components/dataview.py:277 -msgid "On UPDATE" -msgstr "" - -#: windows/components/dataview.py:283 -msgid "On DELETE" -msgstr "" - -#: windows/components/dataview.py:299 -msgid "Add foreign key" -msgstr "" - -#: windows/components/dataview.py:305 -msgid "Remove foreign key" -msgstr "" - -#: windows/components/popup.py:26 -msgid "No default value" -msgstr "" - -#: windows/components/popup.py:31 -msgid "NULL" -msgstr "" - -#: windows/components/popup.py:35 -msgid "AUTO INCREMENT" -msgstr "" - -#: windows/components/popup.py:39 -msgid "Text/Expression" -msgstr "" - -#: windows/dialogs/connections/view.py:258 -msgid "Connection established successfully" -msgstr "" - -#: windows/dialogs/connections/view.py:271 -msgid "Confirm save" -msgstr "" - -#: windows/dialogs/connections/view.py:314 -msgid "You have unsaved changes. Do you want to save them before continuing?" -msgstr "" - -#: windows/dialogs/connections/view.py:316 -msgid "Unsaved changes" -msgstr "" - -#: windows/dialogs/connections/view.py:545 -msgid "" -"This connection cannot work without TLS. TLS has been enabled " -"automatically." -msgstr "" - -#: windows/dialogs/connections/view.py:554 -msgid "Connection error" -msgstr "" - -#: windows/dialogs/connections/view.py:580 -#: windows/dialogs/connections/view.py:595 -msgid "Confirm delete" -msgstr "" - -#: windows/main/controller.py:170 -msgid "days" -msgstr "" - -#: windows/main/controller.py:171 -msgid "hours" -msgstr "" - -#: windows/main/controller.py:172 -msgid "minutes" -msgstr "" - -#: windows/main/controller.py:173 -msgid "seconds" -msgstr "" - -#: windows/main/controller.py:181 -#, python-brace-format -msgid "Memory used: {used} ({percentage:.2%})" -msgstr "" - -#: windows/main/controller.py:217 -msgid "Settings saved successfully" -msgstr "" - -#: windows/main/controller.py:296 -msgid "Version" -msgstr "" - -#: windows/main/controller.py:298 -msgid "Uptime" -msgstr "" - -#: windows/main/controller.py:467 -msgid "Delete table" -msgstr "" - -#: windows/main/controller.py:584 -msgid "Do you want delete the records?" -msgstr "" - -#: windows/main/tabs/database.py:71 -msgid "The connection to the database was lost." -msgstr "" - -#: windows/main/tabs/database.py:73 -msgid "Do you want to reconnect?" -msgstr "" - -#: windows/main/tabs/database.py:75 -msgid "Connection lost" -msgstr "" - -#: windows/main/tabs/database.py:85 -msgid "Reconnection failed:" -msgstr "" - -#: windows/main/tabs/database.py:86 windows/main/tabs/query.py:450 -#: windows/main/tabs/view.py:256 windows/main/tabs/view.py:282 -msgid "Error" -msgstr "" - -#: windows/main/tabs/query.py:305 -#, python-brace-format -msgid "{} rows affected" -msgstr "" - -#: windows/main/tabs/query.py:309 windows/main/tabs/query.py:331 -#, python-brace-format -msgid "Query {}" -msgstr "" - -#: windows/main/tabs/query.py:314 -#, python-brace-format -msgid "Query {} (Error)" -msgstr "" - -#: windows/main/tabs/query.py:326 -#, python-brace-format -msgid "Query {} ({} rows × {} cols)" -msgstr "" - -#: windows/main/tabs/query.py:353 -#, python-brace-format -msgid "{} rows" -msgstr "" - -#: windows/main/tabs/query.py:355 -#, python-brace-format -msgid "{:.1f} ms" -msgstr "" - -#: windows/main/tabs/query.py:358 -#, python-brace-format -msgid "{} warnings" -msgstr "" - -#: windows/main/tabs/query.py:370 -msgid "Error:" -msgstr "" - -#: windows/main/tabs/query.py:376 -msgid "Unknown error" -msgstr "" - -#: windows/main/tabs/query.py:449 -msgid "No active database connection" -msgstr "" - -#: windows/main/tabs/view.py:252 -msgid "View created successfully" -msgstr "" - -#: windows/main/tabs/view.py:252 -msgid "View updated successfully" -msgstr "" - -#: windows/main/tabs/view.py:253 windows/main/tabs/view.py:279 -msgid "Success" -msgstr "" - -#: windows/main/tabs/view.py:256 -#, python-brace-format -msgid "Error saving view: {}" -msgstr "" - -#: windows/main/tabs/view.py:269 -#, python-brace-format -msgid "Are you sure you want to delete view '{}'?" -msgstr "" - -#: windows/main/tabs/view.py:270 -msgid "Confirm Delete" -msgstr "" - -#: windows/main/tabs/view.py:279 -msgid "View deleted successfully" -msgstr "" - -#: windows/main/tabs/view.py:282 -#, python-brace-format -msgid "Error deleting view: {}" -msgstr "" - -#~ msgid "New Session" -#~ msgstr "" - -#~ msgid "connection" -#~ msgstr "" - -#~ msgid "directory" -#~ msgstr "" - diff --git a/scripts/locale/it_IT/LC_MESSAGES/petersql.po b/scripts/locale/it_IT/LC_MESSAGES/petersql.po deleted file mode 100644 index 4370e80..0000000 --- a/scripts/locale/it_IT/LC_MESSAGES/petersql.po +++ /dev/null @@ -1,952 +0,0 @@ -#: helpers/__init__.py:16 -msgctxt "unit" -msgid "B" -msgstr "" - -#: helpers/__init__.py:17 -msgctxt "unit" -msgid "KB" -msgstr "" - -#: helpers/__init__.py:18 -msgctxt "unit" -msgid "MB" -msgstr "" - -#: helpers/__init__.py:19 -msgctxt "unit" -msgid "GB" -msgstr "" - -#: helpers/__init__.py:20 -msgctxt "unit" -msgid "TB" -msgstr "" - -#: structures/ssh_tunnel.py:166 -msgid "OpenSSH client not found." -msgstr "" - -#: windows/dialogs/connections/view.py:259 -#: windows/dialogs/connections/view.py:547 windows/main/controller.py:294 -#: windows/views.py:33 -msgid "Connection" -msgstr "" - -#: windows/components/dataview.py:113 windows/components/dataview.py:225 -#: windows/components/dataview.py:238 windows/components/dataview.py:253 -#: windows/views.py:47 windows/views.py:97 windows/views.py:898 -#: windows/views.py:958 windows/views.py:1341 windows/views.py:2246 -#: windows/views.py:2269 windows/views.py:2270 windows/views.py:2271 -#: windows/views.py:2272 windows/views.py:2273 windows/views.py:2274 -#: windows/views.py:2275 windows/views.py:2276 windows/views.py:2277 -#: windows/views.py:2281 windows/views.py:2462 windows/views.py:2663 -msgid "Name" -msgstr "" - -#: windows/views.py:48 windows/views.py:381 -msgid "Last connection" -msgstr "" - -#: windows/dialogs/connections/view.py:452 windows/views.py:61 -msgid "New directory" -msgstr "" - -#: windows/dialogs/connections/model.py:142 -#: windows/dialogs/connections/view.py:384 windows/views.py:65 -msgid "New connection" -msgstr "" - -#: windows/views.py:71 -msgid "Rename" -msgstr "" - -#: windows/views.py:76 -msgid "Clone connection" -msgstr "" - -#: windows/views.py:81 windows/views.py:471 windows/views.py:884 -#: windows/views.py:1251 windows/views.py:1283 windows/views.py:1542 -#: windows/views.py:2799 windows/views.py:2831 -msgid "Delete" -msgstr "" - -#: windows/views.py:111 windows/views.py:903 windows/views.py:1013 -#: windows/views.py:2286 windows/views.py:2718 -msgid "Engine" -msgstr "" - -#: windows/views.py:132 -msgid "Host + port" -msgstr "" - -#: windows/views.py:148 -msgid "Username" -msgstr "" - -#: windows/views.py:161 -msgid "Password" -msgstr "" - -#: windows/views.py:177 -msgid "Use TLS" -msgstr "" - -#: windows/views.py:180 -msgid "Use SSH tunnel" -msgstr "" - -#: windows/views.py:202 windows/views.py:2198 -msgid "Filename" -msgstr "" - -#: windows/views.py:207 windows/views.py:324 windows/views.py:2203 -#: windows/views.py:2395 -msgid "Select a file" -msgstr "" - -#: windows/views.py:207 windows/views.py:324 windows/views.py:2395 -msgid "*.*" -msgstr "" - -#: windows/components/dataview.py:70 windows/components/dataview.py:92 -#: windows/views.py:221 windows/views.py:905 windows/views.py:971 -#: windows/views.py:2287 windows/views.py:2560 windows/views.py:2676 -msgid "Comments" -msgstr "" - -#: windows/main/controller.py:217 windows/views.py:235 windows/views.py:598 -msgid "Settings" -msgstr "" - -#: windows/views.py:244 -msgid "SSH executable" -msgstr "" - -#: windows/views.py:249 -msgid "ssh" -msgstr "" - -#: windows/views.py:257 -msgid "SSH host + port" -msgstr "" - -#: windows/views.py:269 -msgid "SSH host + port (the SSH server that forwards traffic to the DB)" -msgstr "" - -#: windows/views.py:278 -msgid "SSH username" -msgstr "" - -#: windows/views.py:291 -msgid "SSH password" -msgstr "" - -#: windows/views.py:304 -msgid "Local port" -msgstr "" - -#: windows/views.py:310 -msgid "if the value is set to 0, the first available port will be used" -msgstr "" - -#: windows/views.py:319 -msgid "Identity file" -msgstr "" - -#: windows/views.py:335 -msgid "Remote host + port" -msgstr "" - -#: windows/views.py:347 -msgid "Remote host/port is the real DB target (defaults to DB Host/Port)." -msgstr "" - -#: windows/views.py:358 -msgid "SSH Tunnel" -msgstr "" - -#: windows/views.py:364 windows/views.py:901 windows/views.py:2284 -msgid "Created at" -msgstr "" - -#: windows/views.py:398 -msgid "Successful connections" -msgstr "" - -#: windows/views.py:415 -msgid "Unsuccessful connections" -msgstr "" - -#: windows/views.py:434 -msgid "Statistics" -msgstr "" - -#: windows/views.py:452 windows/views.py:1217 -msgid "Create" -msgstr "" - -#: windows/views.py:456 -msgid "Create connection" -msgstr "" - -#: windows/views.py:459 -msgid "Create directory" -msgstr "" - -#: windows/views.py:488 windows/views.py:712 windows/views.py:1286 -#: windows/views.py:1547 windows/views.py:1623 windows/views.py:2607 -#: windows/views.py:2834 -msgid "Cancel" -msgstr "" - -#: windows/views.py:493 windows/views.py:1552 windows/views.py:2617 -#: windows/views.py:2839 -msgid "Save" -msgstr "" - -#: windows/views.py:500 -msgid "Test" -msgstr "" - -#: windows/views.py:507 -msgid "Connect" -msgstr "" - -#: windows/views.py:610 -msgid "Language" -msgstr "" - -#: windows/views.py:615 -msgid "English" -msgstr "" - -#: windows/views.py:615 -msgid "Italian" -msgstr "" - -#: windows/views.py:615 -msgid "French" -msgstr "" - -#: windows/views.py:627 -msgid "Locale" -msgstr "" - -#: windows/views.py:648 -msgid "Edit Value" -msgstr "" - -#: windows/views.py:658 -msgid "Syntax" -msgstr "" - -#: windows/views.py:715 -msgid "Ok" -msgstr "" - -#: windows/views.py:746 -msgid "PeterSQL" -msgstr "" - -#: windows/views.py:752 -msgid "File" -msgstr "" - -#: windows/views.py:755 -msgid "About" -msgstr "" - -#: windows/views.py:758 -msgid "Help" -msgstr "" - -#: windows/views.py:763 -msgid "Open connection manager" -msgstr "" - -#: windows/views.py:765 -msgid "Disconnect from server" -msgstr "" - -#: windows/views.py:769 -msgid "tool" -msgstr "" - -#: windows/views.py:769 -msgid "Refresh" -msgstr "" - -#: windows/views.py:773 windows/views.py:775 -msgid "Add" -msgstr "" - -#: windows/views.py:809 windows/views.py:813 windows/views.py:1711 -#: windows/views.py:1839 -msgid "MyMenuItem" -msgstr "" - -#: windows/views.py:816 windows/views.py:1314 windows/views.py:2862 -msgid "MyMenu" -msgstr "" - -#: windows/views.py:831 -msgid "MyLabel" -msgstr "" - -#: windows/views.py:837 -msgid "Databases" -msgstr "" - -#: windows/views.py:838 windows/views.py:900 windows/views.py:2255 -#: windows/views.py:2283 -msgid "Size" -msgstr "" - -#: windows/views.py:839 -msgid "Elements" -msgstr "" - -#: windows/views.py:840 -msgid "Modified at" -msgstr "" - -#: windows/views.py:841 windows/views.py:912 -msgid "Tables" -msgstr "" - -#: windows/views.py:848 -msgid "System" -msgstr "" - -#: windows/views.py:864 -msgid "Table:" -msgstr "" - -#: windows/views.py:872 windows/views.py:1096 windows/views.py:1140 -#: windows/views.py:1246 windows/views.py:2794 -msgid "Insert" -msgstr "" - -#: windows/views.py:877 -msgid "Clone" -msgstr "" - -#: windows/views.py:899 -msgid "Rows" -msgstr "" - -#: windows/views.py:902 windows/views.py:2285 -msgid "Updated at" -msgstr "" - -#: windows/components/dataview.py:43 windows/components/dataview.py:67 -#: windows/components/dataview.py:89 windows/views.py:904 windows/views.py:2506 -msgid "Collation" -msgstr "" - -#: windows/views.py:920 -msgid "Diagram" -msgstr "" - -#: windows/views.py:931 windows/views.py:2254 -msgid "Database" -msgstr "" - -#: windows/views.py:986 windows/views.py:2691 -msgid "Base" -msgstr "" - -#: windows/views.py:1000 windows/views.py:2705 -msgid "Auto Increment" -msgstr "" - -#: windows/views.py:1028 windows/views.py:2733 -msgid "Default Collation" -msgstr "" - -#: windows/views.py:1048 windows/views.py:1501 windows/views.py:2751 -msgid "Options" -msgstr "" - -#: windows/views.py:1060 windows/views.py:1101 windows/views.py:1145 -msgid "Remove" -msgstr "" - -#: windows/views.py:1067 windows/views.py:1108 windows/views.py:1152 -msgid "Clear" -msgstr "" - -#: windows/views.py:1082 windows/views.py:2765 -msgid "Indexes" -msgstr "" - -#: windows/views.py:1126 -msgid "Foreign Keys" -msgstr "" - -#: windows/views.py:1170 -msgid "Checks" -msgstr "" - -#: windows/views.py:1238 windows/views.py:2786 -msgid "Columns:" -msgstr "" - -#: windows/views.py:1258 windows/views.py:2806 -msgid "Up" -msgstr "" - -#: windows/views.py:1265 windows/views.py:2813 -msgid "Down" -msgstr "" - -#: windows/views.py:1291 windows/views.py:1630 windows/views.py:1685 -msgid "Apply" -msgstr "" - -#: windows/views.py:1304 windows/views.py:1311 windows/views.py:2852 -#: windows/views.py:2859 -msgid "Add Index" -msgstr "" - -#: windows/views.py:1308 windows/views.py:2856 -msgid "Add PrimaryKey" -msgstr "" - -#: windows/views.py:1325 -msgid "Table" -msgstr "" - -#: windows/views.py:1361 -msgid "Definer" -msgstr "" - -#: windows/views.py:1381 -msgid "Schema" -msgstr "" - -#: windows/views.py:1407 -msgid "SQL security" -msgstr "" - -#: windows/views.py:1414 -msgid "DEFINER" -msgstr "" - -#: windows/views.py:1414 -msgid "INVOKER" -msgstr "" - -#: windows/views.py:1426 windows/views.py:2096 windows/views.py:2115 -#: windows/views.py:2359 -msgid "Algorithm" -msgstr "" - -#: windows/views.py:1428 windows/views.py:2081 windows/views.py:2114 -#: windows/views.py:2364 -msgid "UNDEFINED" -msgstr "" - -#: windows/views.py:1431 windows/views.py:2084 windows/views.py:2114 -#: windows/views.py:2367 -msgid "MERGE" -msgstr "" - -#: windows/views.py:1434 windows/views.py:2093 windows/views.py:2114 -#: windows/views.py:2370 -msgid "TEMPTABLE" -msgstr "" - -#: windows/views.py:1444 windows/views.py:2120 -msgid "View constraint" -msgstr "" - -#: windows/views.py:1446 windows/views.py:2119 -msgid "None" -msgstr "" - -#: windows/views.py:1449 windows/views.py:2119 -msgid "LOCAL" -msgstr "" - -#: windows/views.py:1452 -msgid "CASCADE" -msgstr "" - -#: windows/views.py:1455 -msgid "CHECK ONLY" -msgstr "" - -#: windows/views.py:1458 windows/views.py:2119 -msgid "READ ONLY" -msgstr "" - -#: windows/views.py:1470 -msgid "Force" -msgstr "" - -#: windows/views.py:1482 -msgid "Security barrier" -msgstr "" - -#: windows/views.py:1564 -msgid "Views" -msgstr "" - -#: windows/views.py:1572 -msgid "Triggers" -msgstr "" - -#: windows/views.py:1584 -#, python-format -msgid "Table `%(database_name)s`.`%(table_name)s`: %(total_rows) rows total" -msgstr "" - -#: windows/views.py:1594 -msgid "Insert record" -msgstr "" - -#: windows/views.py:1599 -msgid "Duplicate record" -msgstr "" - -#: windows/views.py:1606 -msgid "Delete record" -msgstr "" - -#: windows/views.py:1616 -msgid "Apply changes automatically" -msgstr "" - -#: windows/views.py:1618 windows/views.py:1619 -msgid "" -"If enabled, table edits are applied immediately without pressing Apply or" -" Cancel" -msgstr "" - -#: windows/views.py:1640 -msgid "Next" -msgstr "" - -#: windows/views.py:1648 -msgid "Filters" -msgstr "" - -#: windows/views.py:1688 -msgid "CTRL+ENTER" -msgstr "" - -#: windows/views.py:1708 -msgid "Insert row" -msgstr "" - -#: windows/views.py:1716 -msgid "Data" -msgstr "" - -#: windows/views.py:1770 windows/views.py:1820 -msgid "New" -msgstr "" - -#: windows/views.py:1797 -msgid "Query" -msgstr "" - -#: windows/views.py:1817 -msgid "Close" -msgstr "" - -#: windows/views.py:1830 -msgid "Query #2" -msgstr "" - -#: windows/views.py:2075 -msgid "Column5" -msgstr "" - -#: windows/views.py:2086 -msgid "Import" -msgstr "" - -#: windows/views.py:2111 -msgid "Read only" -msgstr "" - -#: windows/views.py:2119 -msgid "CASCADED" -msgstr "" - -#: windows/views.py:2119 -msgid "CHECK OPTION" -msgstr "" - -#: windows/views.py:2143 -msgid "collapsible" -msgstr "" - -#: windows/views.py:2165 -msgid "Column3" -msgstr "" - -#: windows/views.py:2166 -msgid "Column4" -msgstr "" - -#: windows/views.py:2203 -msgid "" -"Database " -"(*.db;*.db3;*.sdb;*.s3db;*.sqlite;*.sqlite3)|*.db;*.db3;*.sdb;*.s3db;*.sqlite;*.sqlite3" -msgstr "" - -#: windows/views.py:2215 -msgid "Port" -msgstr "" - -#: windows/views.py:2247 -msgid "Usage" -msgstr "" - -#: windows/views.py:2258 -#, python-format -msgid "%(total_rows)s" -msgstr "" - -#: windows/views.py:2263 -msgid "rows total" -msgstr "" - -#: windows/views.py:2282 -msgid "Lines" -msgstr "" - -#: windows/views.py:2314 -msgid "Temporary" -msgstr "" - -#: windows/views.py:2325 -msgid "Engine options" -msgstr "" - -#: windows/views.py:2384 -msgid "RadioBtn" -msgstr "" - -#: windows/views.py:2454 -msgid "Edit Column" -msgstr "" - -#: windows/views.py:2470 -msgid "Datatype" -msgstr "" - -#: windows/components/dataview.py:121 windows/views.py:2485 -msgid "Length/Set" -msgstr "" - -#: windows/components/dataview.py:51 windows/views.py:2524 -msgid "Unsigned" -msgstr "" - -#: windows/components/dataview.py:25 windows/components/dataview.py:52 -#: windows/components/dataview.py:75 windows/views.py:2530 -msgid "Allow NULL" -msgstr "" - -#: windows/views.py:2536 -msgid "Zero Fill" -msgstr "" - -#: windows/components/dataview.py:32 windows/components/dataview.py:56 -#: windows/components/dataview.py:78 windows/views.py:2547 -msgid "Default" -msgstr "" - -#: windows/components/dataview.py:36 windows/components/dataview.py:60 -#: windows/components/dataview.py:82 windows/views.py:2573 -msgid "Virtuality" -msgstr "" - -#: windows/components/dataview.py:39 windows/components/dataview.py:63 -#: windows/components/dataview.py:85 windows/components/dataview.py:241 -#: windows/views.py:2588 -msgid "Expression" -msgstr "" - -#: windows/components/dataview.py:28 -msgid "Check" -msgstr "" - -#: windows/components/dataview.py:53 -msgid "Zerofill" -msgstr "" - -#: windows/components/dataview.py:109 -msgid "#" -msgstr "" - -#: windows/components/dataview.py:117 -msgid "Data type" -msgstr "" - -#: windows/components/dataview.py:155 -msgid "Add column\tCTRL+INS" -msgstr "" - -#: windows/components/dataview.py:161 -msgid "Remove column\tCTRL+DEL" -msgstr "" - -#: windows/components/dataview.py:169 -msgid "Move up\tCTRL+UP" -msgstr "" - -#: windows/components/dataview.py:176 -msgid "Move down\tCTRL+D" -msgstr "" - -#: windows/components/dataview.py:199 -msgid "Create new index" -msgstr "" - -#: windows/components/dataview.py:214 -msgid "Append to index" -msgstr "" - -#: windows/components/dataview.py:228 -msgid "Column(s)/Expression" -msgstr "" - -#: windows/components/dataview.py:229 -msgid "Condition" -msgstr "" - -#: windows/components/dataview.py:259 -msgid "Column(s)" -msgstr "" - -#: windows/components/dataview.py:265 -msgid "Reference table" -msgstr "" - -#: windows/components/dataview.py:271 -msgid "Reference column(s)" -msgstr "" - -#: windows/components/dataview.py:277 -msgid "On UPDATE" -msgstr "" - -#: windows/components/dataview.py:283 -msgid "On DELETE" -msgstr "" - -#: windows/components/dataview.py:299 -msgid "Add foreign key" -msgstr "" - -#: windows/components/dataview.py:305 -msgid "Remove foreign key" -msgstr "" - -#: windows/components/popup.py:26 -msgid "No default value" -msgstr "" - -#: windows/components/popup.py:31 -msgid "NULL" -msgstr "" - -#: windows/components/popup.py:35 -msgid "AUTO INCREMENT" -msgstr "" - -#: windows/components/popup.py:39 -msgid "Text/Expression" -msgstr "" - -#: windows/dialogs/connections/view.py:258 -msgid "Connection established successfully" -msgstr "" - -#: windows/dialogs/connections/view.py:271 -msgid "Confirm save" -msgstr "" - -#: windows/dialogs/connections/view.py:314 -msgid "You have unsaved changes. Do you want to save them before continuing?" -msgstr "" - -#: windows/dialogs/connections/view.py:316 -msgid "Unsaved changes" -msgstr "" - -#: windows/dialogs/connections/view.py:545 -msgid "" -"This connection cannot work without TLS. TLS has been enabled " -"automatically." -msgstr "" - -#: windows/dialogs/connections/view.py:554 -msgid "Connection error" -msgstr "" - -#: windows/dialogs/connections/view.py:580 -#: windows/dialogs/connections/view.py:595 -msgid "Confirm delete" -msgstr "" - -#: windows/main/controller.py:170 -msgid "days" -msgstr "" - -#: windows/main/controller.py:171 -msgid "hours" -msgstr "" - -#: windows/main/controller.py:172 -msgid "minutes" -msgstr "" - -#: windows/main/controller.py:173 -msgid "seconds" -msgstr "" - -#: windows/main/controller.py:181 -#, python-brace-format -msgid "Memory used: {used} ({percentage:.2%})" -msgstr "" - -#: windows/main/controller.py:217 -msgid "Settings saved successfully" -msgstr "" - -#: windows/main/controller.py:296 -msgid "Version" -msgstr "" - -#: windows/main/controller.py:298 -msgid "Uptime" -msgstr "" - -#: windows/main/controller.py:467 -msgid "Delete table" -msgstr "" - -#: windows/main/controller.py:584 -msgid "Do you want delete the records?" -msgstr "" - -#: windows/main/tabs/database.py:71 -msgid "The connection to the database was lost." -msgstr "" - -#: windows/main/tabs/database.py:73 -msgid "Do you want to reconnect?" -msgstr "" - -#: windows/main/tabs/database.py:75 -msgid "Connection lost" -msgstr "" - -#: windows/main/tabs/database.py:85 -msgid "Reconnection failed:" -msgstr "" - -#: windows/main/tabs/database.py:86 windows/main/tabs/query.py:450 -#: windows/main/tabs/view.py:256 windows/main/tabs/view.py:282 -msgid "Error" -msgstr "" - -#: windows/main/tabs/query.py:305 -#, python-brace-format -msgid "{} rows affected" -msgstr "" - -#: windows/main/tabs/query.py:309 windows/main/tabs/query.py:331 -#, python-brace-format -msgid "Query {}" -msgstr "" - -#: windows/main/tabs/query.py:314 -#, python-brace-format -msgid "Query {} (Error)" -msgstr "" - -#: windows/main/tabs/query.py:326 -#, python-brace-format -msgid "Query {} ({} rows × {} cols)" -msgstr "" - -#: windows/main/tabs/query.py:353 -#, python-brace-format -msgid "{} rows" -msgstr "" - -#: windows/main/tabs/query.py:355 -#, python-brace-format -msgid "{:.1f} ms" -msgstr "" - -#: windows/main/tabs/query.py:358 -#, python-brace-format -msgid "{} warnings" -msgstr "" - -#: windows/main/tabs/query.py:370 -msgid "Error:" -msgstr "" - -#: windows/main/tabs/query.py:376 -msgid "Unknown error" -msgstr "" - -#: windows/main/tabs/query.py:449 -msgid "No active database connection" -msgstr "" - -#: windows/main/tabs/view.py:252 -msgid "View created successfully" -msgstr "" - -#: windows/main/tabs/view.py:252 -msgid "View updated successfully" -msgstr "" - -#: windows/main/tabs/view.py:253 windows/main/tabs/view.py:279 -msgid "Success" -msgstr "" - -#: windows/main/tabs/view.py:256 -#, python-brace-format -msgid "Error saving view: {}" -msgstr "" - -#: windows/main/tabs/view.py:269 -#, python-brace-format -msgid "Are you sure you want to delete view '{}'?" -msgstr "" - -#: windows/main/tabs/view.py:270 -msgid "Confirm Delete" -msgstr "" - -#: windows/main/tabs/view.py:279 -msgid "View deleted successfully" -msgstr "" - -#: windows/main/tabs/view.py:282 -#, python-brace-format -msgid "Error deleting view: {}" -msgstr "" - -#~ msgid "New Session" -#~ msgstr "" - -#~ msgid "connection" -#~ msgstr "" - -#~ msgid "directory" -#~ msgstr "" - diff --git a/scripts/locale/petersql.pot b/scripts/locale/petersql.pot deleted file mode 100644 index 9cb1378..0000000 --- a/scripts/locale/petersql.pot +++ /dev/null @@ -1,943 +0,0 @@ -#: helpers/__init__.py:16 -msgctxt "unit" -msgid "B" -msgstr "" - -#: helpers/__init__.py:17 -msgctxt "unit" -msgid "KB" -msgstr "" - -#: helpers/__init__.py:18 -msgctxt "unit" -msgid "MB" -msgstr "" - -#: helpers/__init__.py:19 -msgctxt "unit" -msgid "GB" -msgstr "" - -#: helpers/__init__.py:20 -msgctxt "unit" -msgid "TB" -msgstr "" - -#: structures/ssh_tunnel.py:166 -msgid "OpenSSH client not found." -msgstr "" - -#: windows/dialogs/connections/view.py:259 -#: windows/dialogs/connections/view.py:547 windows/main/controller.py:294 -#: windows/views.py:33 -msgid "Connection" -msgstr "" - -#: windows/components/dataview.py:113 windows/components/dataview.py:225 -#: windows/components/dataview.py:238 windows/components/dataview.py:253 -#: windows/views.py:47 windows/views.py:97 windows/views.py:898 -#: windows/views.py:958 windows/views.py:1341 windows/views.py:2246 -#: windows/views.py:2269 windows/views.py:2270 windows/views.py:2271 -#: windows/views.py:2272 windows/views.py:2273 windows/views.py:2274 -#: windows/views.py:2275 windows/views.py:2276 windows/views.py:2277 -#: windows/views.py:2281 windows/views.py:2462 windows/views.py:2663 -msgid "Name" -msgstr "" - -#: windows/views.py:48 windows/views.py:381 -msgid "Last connection" -msgstr "" - -#: windows/dialogs/connections/view.py:452 windows/views.py:61 -msgid "New directory" -msgstr "" - -#: windows/dialogs/connections/model.py:142 -#: windows/dialogs/connections/view.py:384 windows/views.py:65 -msgid "New connection" -msgstr "" - -#: windows/views.py:71 -msgid "Rename" -msgstr "" - -#: windows/views.py:76 -msgid "Clone connection" -msgstr "" - -#: windows/views.py:81 windows/views.py:471 windows/views.py:884 -#: windows/views.py:1251 windows/views.py:1283 windows/views.py:1542 -#: windows/views.py:2799 windows/views.py:2831 -msgid "Delete" -msgstr "" - -#: windows/views.py:111 windows/views.py:903 windows/views.py:1013 -#: windows/views.py:2286 windows/views.py:2718 -msgid "Engine" -msgstr "" - -#: windows/views.py:132 -msgid "Host + port" -msgstr "" - -#: windows/views.py:148 -msgid "Username" -msgstr "" - -#: windows/views.py:161 -msgid "Password" -msgstr "" - -#: windows/views.py:177 -msgid "Use TLS" -msgstr "" - -#: windows/views.py:180 -msgid "Use SSH tunnel" -msgstr "" - -#: windows/views.py:202 windows/views.py:2198 -msgid "Filename" -msgstr "" - -#: windows/views.py:207 windows/views.py:324 windows/views.py:2203 -#: windows/views.py:2395 -msgid "Select a file" -msgstr "" - -#: windows/views.py:207 windows/views.py:324 windows/views.py:2395 -msgid "*.*" -msgstr "" - -#: windows/components/dataview.py:70 windows/components/dataview.py:92 -#: windows/views.py:221 windows/views.py:905 windows/views.py:971 -#: windows/views.py:2287 windows/views.py:2560 windows/views.py:2676 -msgid "Comments" -msgstr "" - -#: windows/main/controller.py:217 windows/views.py:235 windows/views.py:598 -msgid "Settings" -msgstr "" - -#: windows/views.py:244 -msgid "SSH executable" -msgstr "" - -#: windows/views.py:249 -msgid "ssh" -msgstr "" - -#: windows/views.py:257 -msgid "SSH host + port" -msgstr "" - -#: windows/views.py:269 -msgid "SSH host + port (the SSH server that forwards traffic to the DB)" -msgstr "" - -#: windows/views.py:278 -msgid "SSH username" -msgstr "" - -#: windows/views.py:291 -msgid "SSH password" -msgstr "" - -#: windows/views.py:304 -msgid "Local port" -msgstr "" - -#: windows/views.py:310 -msgid "if the value is set to 0, the first available port will be used" -msgstr "" - -#: windows/views.py:319 -msgid "Identity file" -msgstr "" - -#: windows/views.py:335 -msgid "Remote host + port" -msgstr "" - -#: windows/views.py:347 -msgid "Remote host/port is the real DB target (defaults to DB Host/Port)." -msgstr "" - -#: windows/views.py:358 -msgid "SSH Tunnel" -msgstr "" - -#: windows/views.py:364 windows/views.py:901 windows/views.py:2284 -msgid "Created at" -msgstr "" - -#: windows/views.py:398 -msgid "Successful connections" -msgstr "" - -#: windows/views.py:415 -msgid "Unsuccessful connections" -msgstr "" - -#: windows/views.py:434 -msgid "Statistics" -msgstr "" - -#: windows/views.py:452 windows/views.py:1217 -msgid "Create" -msgstr "" - -#: windows/views.py:456 -msgid "Create connection" -msgstr "" - -#: windows/views.py:459 -msgid "Create directory" -msgstr "" - -#: windows/views.py:488 windows/views.py:712 windows/views.py:1286 -#: windows/views.py:1547 windows/views.py:1623 windows/views.py:2607 -#: windows/views.py:2834 -msgid "Cancel" -msgstr "" - -#: windows/views.py:493 windows/views.py:1552 windows/views.py:2617 -#: windows/views.py:2839 -msgid "Save" -msgstr "" - -#: windows/views.py:500 -msgid "Test" -msgstr "" - -#: windows/views.py:507 -msgid "Connect" -msgstr "" - -#: windows/views.py:610 -msgid "Language" -msgstr "" - -#: windows/views.py:615 -msgid "English" -msgstr "" - -#: windows/views.py:615 -msgid "Italian" -msgstr "" - -#: windows/views.py:615 -msgid "French" -msgstr "" - -#: windows/views.py:627 -msgid "Locale" -msgstr "" - -#: windows/views.py:648 -msgid "Edit Value" -msgstr "" - -#: windows/views.py:658 -msgid "Syntax" -msgstr "" - -#: windows/views.py:715 -msgid "Ok" -msgstr "" - -#: windows/views.py:746 -msgid "PeterSQL" -msgstr "" - -#: windows/views.py:752 -msgid "File" -msgstr "" - -#: windows/views.py:755 -msgid "About" -msgstr "" - -#: windows/views.py:758 -msgid "Help" -msgstr "" - -#: windows/views.py:763 -msgid "Open connection manager" -msgstr "" - -#: windows/views.py:765 -msgid "Disconnect from server" -msgstr "" - -#: windows/views.py:769 -msgid "tool" -msgstr "" - -#: windows/views.py:769 -msgid "Refresh" -msgstr "" - -#: windows/views.py:773 windows/views.py:775 -msgid "Add" -msgstr "" - -#: windows/views.py:809 windows/views.py:813 windows/views.py:1711 -#: windows/views.py:1839 -msgid "MyMenuItem" -msgstr "" - -#: windows/views.py:816 windows/views.py:1314 windows/views.py:2862 -msgid "MyMenu" -msgstr "" - -#: windows/views.py:831 -msgid "MyLabel" -msgstr "" - -#: windows/views.py:837 -msgid "Databases" -msgstr "" - -#: windows/views.py:838 windows/views.py:900 windows/views.py:2255 -#: windows/views.py:2283 -msgid "Size" -msgstr "" - -#: windows/views.py:839 -msgid "Elements" -msgstr "" - -#: windows/views.py:840 -msgid "Modified at" -msgstr "" - -#: windows/views.py:841 windows/views.py:912 -msgid "Tables" -msgstr "" - -#: windows/views.py:848 -msgid "System" -msgstr "" - -#: windows/views.py:864 -msgid "Table:" -msgstr "" - -#: windows/views.py:872 windows/views.py:1096 windows/views.py:1140 -#: windows/views.py:1246 windows/views.py:2794 -msgid "Insert" -msgstr "" - -#: windows/views.py:877 -msgid "Clone" -msgstr "" - -#: windows/views.py:899 -msgid "Rows" -msgstr "" - -#: windows/views.py:902 windows/views.py:2285 -msgid "Updated at" -msgstr "" - -#: windows/components/dataview.py:43 windows/components/dataview.py:67 -#: windows/components/dataview.py:89 windows/views.py:904 windows/views.py:2506 -msgid "Collation" -msgstr "" - -#: windows/views.py:920 -msgid "Diagram" -msgstr "" - -#: windows/views.py:931 windows/views.py:2254 -msgid "Database" -msgstr "" - -#: windows/views.py:986 windows/views.py:2691 -msgid "Base" -msgstr "" - -#: windows/views.py:1000 windows/views.py:2705 -msgid "Auto Increment" -msgstr "" - -#: windows/views.py:1028 windows/views.py:2733 -msgid "Default Collation" -msgstr "" - -#: windows/views.py:1048 windows/views.py:1501 windows/views.py:2751 -msgid "Options" -msgstr "" - -#: windows/views.py:1060 windows/views.py:1101 windows/views.py:1145 -msgid "Remove" -msgstr "" - -#: windows/views.py:1067 windows/views.py:1108 windows/views.py:1152 -msgid "Clear" -msgstr "" - -#: windows/views.py:1082 windows/views.py:2765 -msgid "Indexes" -msgstr "" - -#: windows/views.py:1126 -msgid "Foreign Keys" -msgstr "" - -#: windows/views.py:1170 -msgid "Checks" -msgstr "" - -#: windows/views.py:1238 windows/views.py:2786 -msgid "Columns:" -msgstr "" - -#: windows/views.py:1258 windows/views.py:2806 -msgid "Up" -msgstr "" - -#: windows/views.py:1265 windows/views.py:2813 -msgid "Down" -msgstr "" - -#: windows/views.py:1291 windows/views.py:1630 windows/views.py:1685 -msgid "Apply" -msgstr "" - -#: windows/views.py:1304 windows/views.py:1311 windows/views.py:2852 -#: windows/views.py:2859 -msgid "Add Index" -msgstr "" - -#: windows/views.py:1308 windows/views.py:2856 -msgid "Add PrimaryKey" -msgstr "" - -#: windows/views.py:1325 -msgid "Table" -msgstr "" - -#: windows/views.py:1361 -msgid "Definer" -msgstr "" - -#: windows/views.py:1381 -msgid "Schema" -msgstr "" - -#: windows/views.py:1407 -msgid "SQL security" -msgstr "" - -#: windows/views.py:1414 -msgid "DEFINER" -msgstr "" - -#: windows/views.py:1414 -msgid "INVOKER" -msgstr "" - -#: windows/views.py:1426 windows/views.py:2096 windows/views.py:2115 -#: windows/views.py:2359 -msgid "Algorithm" -msgstr "" - -#: windows/views.py:1428 windows/views.py:2081 windows/views.py:2114 -#: windows/views.py:2364 -msgid "UNDEFINED" -msgstr "" - -#: windows/views.py:1431 windows/views.py:2084 windows/views.py:2114 -#: windows/views.py:2367 -msgid "MERGE" -msgstr "" - -#: windows/views.py:1434 windows/views.py:2093 windows/views.py:2114 -#: windows/views.py:2370 -msgid "TEMPTABLE" -msgstr "" - -#: windows/views.py:1444 windows/views.py:2120 -msgid "View constraint" -msgstr "" - -#: windows/views.py:1446 windows/views.py:2119 -msgid "None" -msgstr "" - -#: windows/views.py:1449 windows/views.py:2119 -msgid "LOCAL" -msgstr "" - -#: windows/views.py:1452 -msgid "CASCADE" -msgstr "" - -#: windows/views.py:1455 -msgid "CHECK ONLY" -msgstr "" - -#: windows/views.py:1458 windows/views.py:2119 -msgid "READ ONLY" -msgstr "" - -#: windows/views.py:1470 -msgid "Force" -msgstr "" - -#: windows/views.py:1482 -msgid "Security barrier" -msgstr "" - -#: windows/views.py:1564 -msgid "Views" -msgstr "" - -#: windows/views.py:1572 -msgid "Triggers" -msgstr "" - -#: windows/views.py:1584 -#, python-format -msgid "Table `%(database_name)s`.`%(table_name)s`: %(total_rows) rows total" -msgstr "" - -#: windows/views.py:1594 -msgid "Insert record" -msgstr "" - -#: windows/views.py:1599 -msgid "Duplicate record" -msgstr "" - -#: windows/views.py:1606 -msgid "Delete record" -msgstr "" - -#: windows/views.py:1616 -msgid "Apply changes automatically" -msgstr "" - -#: windows/views.py:1618 windows/views.py:1619 -msgid "" -"If enabled, table edits are applied immediately without pressing Apply or" -" Cancel" -msgstr "" - -#: windows/views.py:1640 -msgid "Next" -msgstr "" - -#: windows/views.py:1648 -msgid "Filters" -msgstr "" - -#: windows/views.py:1688 -msgid "CTRL+ENTER" -msgstr "" - -#: windows/views.py:1708 -msgid "Insert row" -msgstr "" - -#: windows/views.py:1716 -msgid "Data" -msgstr "" - -#: windows/views.py:1770 windows/views.py:1820 -msgid "New" -msgstr "" - -#: windows/views.py:1797 -msgid "Query" -msgstr "" - -#: windows/views.py:1817 -msgid "Close" -msgstr "" - -#: windows/views.py:1830 -msgid "Query #2" -msgstr "" - -#: windows/views.py:2075 -msgid "Column5" -msgstr "" - -#: windows/views.py:2086 -msgid "Import" -msgstr "" - -#: windows/views.py:2111 -msgid "Read only" -msgstr "" - -#: windows/views.py:2119 -msgid "CASCADED" -msgstr "" - -#: windows/views.py:2119 -msgid "CHECK OPTION" -msgstr "" - -#: windows/views.py:2143 -msgid "collapsible" -msgstr "" - -#: windows/views.py:2165 -msgid "Column3" -msgstr "" - -#: windows/views.py:2166 -msgid "Column4" -msgstr "" - -#: windows/views.py:2203 -msgid "" -"Database " -"(*.db;*.db3;*.sdb;*.s3db;*.sqlite;*.sqlite3)|*.db;*.db3;*.sdb;*.s3db;*.sqlite;*.sqlite3" -msgstr "" - -#: windows/views.py:2215 -msgid "Port" -msgstr "" - -#: windows/views.py:2247 -msgid "Usage" -msgstr "" - -#: windows/views.py:2258 -#, python-format -msgid "%(total_rows)s" -msgstr "" - -#: windows/views.py:2263 -msgid "rows total" -msgstr "" - -#: windows/views.py:2282 -msgid "Lines" -msgstr "" - -#: windows/views.py:2314 -msgid "Temporary" -msgstr "" - -#: windows/views.py:2325 -msgid "Engine options" -msgstr "" - -#: windows/views.py:2384 -msgid "RadioBtn" -msgstr "" - -#: windows/views.py:2454 -msgid "Edit Column" -msgstr "" - -#: windows/views.py:2470 -msgid "Datatype" -msgstr "" - -#: windows/components/dataview.py:121 windows/views.py:2485 -msgid "Length/Set" -msgstr "" - -#: windows/components/dataview.py:51 windows/views.py:2524 -msgid "Unsigned" -msgstr "" - -#: windows/components/dataview.py:25 windows/components/dataview.py:52 -#: windows/components/dataview.py:75 windows/views.py:2530 -msgid "Allow NULL" -msgstr "" - -#: windows/views.py:2536 -msgid "Zero Fill" -msgstr "" - -#: windows/components/dataview.py:32 windows/components/dataview.py:56 -#: windows/components/dataview.py:78 windows/views.py:2547 -msgid "Default" -msgstr "" - -#: windows/components/dataview.py:36 windows/components/dataview.py:60 -#: windows/components/dataview.py:82 windows/views.py:2573 -msgid "Virtuality" -msgstr "" - -#: windows/components/dataview.py:39 windows/components/dataview.py:63 -#: windows/components/dataview.py:85 windows/components/dataview.py:241 -#: windows/views.py:2588 -msgid "Expression" -msgstr "" - -#: windows/components/dataview.py:28 -msgid "Check" -msgstr "" - -#: windows/components/dataview.py:53 -msgid "Zerofill" -msgstr "" - -#: windows/components/dataview.py:109 -msgid "#" -msgstr "" - -#: windows/components/dataview.py:117 -msgid "Data type" -msgstr "" - -#: windows/components/dataview.py:155 -msgid "Add column\tCTRL+INS" -msgstr "" - -#: windows/components/dataview.py:161 -msgid "Remove column\tCTRL+DEL" -msgstr "" - -#: windows/components/dataview.py:169 -msgid "Move up\tCTRL+UP" -msgstr "" - -#: windows/components/dataview.py:176 -msgid "Move down\tCTRL+D" -msgstr "" - -#: windows/components/dataview.py:199 -msgid "Create new index" -msgstr "" - -#: windows/components/dataview.py:214 -msgid "Append to index" -msgstr "" - -#: windows/components/dataview.py:228 -msgid "Column(s)/Expression" -msgstr "" - -#: windows/components/dataview.py:229 -msgid "Condition" -msgstr "" - -#: windows/components/dataview.py:259 -msgid "Column(s)" -msgstr "" - -#: windows/components/dataview.py:265 -msgid "Reference table" -msgstr "" - -#: windows/components/dataview.py:271 -msgid "Reference column(s)" -msgstr "" - -#: windows/components/dataview.py:277 -msgid "On UPDATE" -msgstr "" - -#: windows/components/dataview.py:283 -msgid "On DELETE" -msgstr "" - -#: windows/components/dataview.py:299 -msgid "Add foreign key" -msgstr "" - -#: windows/components/dataview.py:305 -msgid "Remove foreign key" -msgstr "" - -#: windows/components/popup.py:26 -msgid "No default value" -msgstr "" - -#: windows/components/popup.py:31 -msgid "NULL" -msgstr "" - -#: windows/components/popup.py:35 -msgid "AUTO INCREMENT" -msgstr "" - -#: windows/components/popup.py:39 -msgid "Text/Expression" -msgstr "" - -#: windows/dialogs/connections/view.py:258 -msgid "Connection established successfully" -msgstr "" - -#: windows/dialogs/connections/view.py:271 -msgid "Confirm save" -msgstr "" - -#: windows/dialogs/connections/view.py:314 -msgid "You have unsaved changes. Do you want to save them before continuing?" -msgstr "" - -#: windows/dialogs/connections/view.py:316 -msgid "Unsaved changes" -msgstr "" - -#: windows/dialogs/connections/view.py:545 -msgid "" -"This connection cannot work without TLS. TLS has been enabled " -"automatically." -msgstr "" - -#: windows/dialogs/connections/view.py:554 -msgid "Connection error" -msgstr "" - -#: windows/dialogs/connections/view.py:580 -#: windows/dialogs/connections/view.py:595 -msgid "Confirm delete" -msgstr "" - -#: windows/main/controller.py:170 -msgid "days" -msgstr "" - -#: windows/main/controller.py:171 -msgid "hours" -msgstr "" - -#: windows/main/controller.py:172 -msgid "minutes" -msgstr "" - -#: windows/main/controller.py:173 -msgid "seconds" -msgstr "" - -#: windows/main/controller.py:181 -#, python-brace-format -msgid "Memory used: {used} ({percentage:.2%})" -msgstr "" - -#: windows/main/controller.py:217 -msgid "Settings saved successfully" -msgstr "" - -#: windows/main/controller.py:296 -msgid "Version" -msgstr "" - -#: windows/main/controller.py:298 -msgid "Uptime" -msgstr "" - -#: windows/main/controller.py:467 -msgid "Delete table" -msgstr "" - -#: windows/main/controller.py:584 -msgid "Do you want delete the records?" -msgstr "" - -#: windows/main/tabs/database.py:71 -msgid "The connection to the database was lost." -msgstr "" - -#: windows/main/tabs/database.py:73 -msgid "Do you want to reconnect?" -msgstr "" - -#: windows/main/tabs/database.py:75 -msgid "Connection lost" -msgstr "" - -#: windows/main/tabs/database.py:85 -msgid "Reconnection failed:" -msgstr "" - -#: windows/main/tabs/database.py:86 windows/main/tabs/query.py:450 -#: windows/main/tabs/view.py:256 windows/main/tabs/view.py:282 -msgid "Error" -msgstr "" - -#: windows/main/tabs/query.py:305 -#, python-brace-format -msgid "{} rows affected" -msgstr "" - -#: windows/main/tabs/query.py:309 windows/main/tabs/query.py:331 -#, python-brace-format -msgid "Query {}" -msgstr "" - -#: windows/main/tabs/query.py:314 -#, python-brace-format -msgid "Query {} (Error)" -msgstr "" - -#: windows/main/tabs/query.py:326 -#, python-brace-format -msgid "Query {} ({} rows × {} cols)" -msgstr "" - -#: windows/main/tabs/query.py:353 -#, python-brace-format -msgid "{} rows" -msgstr "" - -#: windows/main/tabs/query.py:355 -#, python-brace-format -msgid "{:.1f} ms" -msgstr "" - -#: windows/main/tabs/query.py:358 -#, python-brace-format -msgid "{} warnings" -msgstr "" - -#: windows/main/tabs/query.py:370 -msgid "Error:" -msgstr "" - -#: windows/main/tabs/query.py:376 -msgid "Unknown error" -msgstr "" - -#: windows/main/tabs/query.py:449 -msgid "No active database connection" -msgstr "" - -#: windows/main/tabs/view.py:252 -msgid "View created successfully" -msgstr "" - -#: windows/main/tabs/view.py:252 -msgid "View updated successfully" -msgstr "" - -#: windows/main/tabs/view.py:253 windows/main/tabs/view.py:279 -msgid "Success" -msgstr "" - -#: windows/main/tabs/view.py:256 -#, python-brace-format -msgid "Error saving view: {}" -msgstr "" - -#: windows/main/tabs/view.py:269 -#, python-brace-format -msgid "Are you sure you want to delete view '{}'?" -msgstr "" - -#: windows/main/tabs/view.py:270 -msgid "Confirm Delete" -msgstr "" - -#: windows/main/tabs/view.py:279 -msgid "View deleted successfully" -msgstr "" - -#: windows/main/tabs/view.py:282 -#, python-brace-format -msgid "Error deleting view: {}" -msgstr "" - diff --git a/scripts/locales.py b/scripts/locales.py index f8a6d24..8dd3d49 100755 --- a/scripts/locales.py +++ b/scripts/locales.py @@ -4,23 +4,65 @@ import shutil import subprocess import sys +import toml +from datetime import datetime from pathlib import Path sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) -from constants import Language +from constants import WORKDIR, Language APP_NAME = "petersql" LANGUAGES = Language.get_codes() -BASE_DIR = Path(__file__).parent -LOCALE_DIR = BASE_DIR.joinpath("locale") +LOCALE_DIR = WORKDIR.joinpath("locale") POT_FILE = LOCALE_DIR.joinpath(f"{APP_NAME}.pot") +PYPROJECT_FILE = WORKDIR.joinpath("pyproject.toml") + + +def get_project_info(): + """Read project information from pyproject.toml""" + try: + with open(PYPROJECT_FILE, 'r', encoding='utf-8') as f: + data = toml.load(f) + project = data.get('project', {}) + return { + 'name': project.get('name'), + 'version': project.get('version') + } + except Exception: + return {'name': 'PeterSQL', 'version': '0.1.0'} def run(cmd): subprocess.run(cmd, shell=True, check=True) +def generate_header(lang): + """Generate proper header for .po files based on language""" + project_info = get_project_info() + current_date = datetime.now().strftime("%Y-%m-%d %H:%M%z") + + language = Language.from_code(lang) + lang_name = f"{language.label} ({lang})" + + return f'''# {lang_name} translations for {project_info['name']}. +# Copyright (C) 2026 {project_info['name']} +# This file is distributed under the same license as the {project_info['name']} project. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: {project_info['name']} {project_info['version']}\\n" +"POT-Creation-Date: {current_date}\\n" +"PO-Revision-Date: {current_date}\\n" +"Language: {lang}\\n" +"MIME-Version: 1.0\\n" +"Content-Type: text/plain; charset=utf-8\\n" +"Content-Transfer-Encoding: 8bit\\n" + +''' + + def extract(): LOCALE_DIR.mkdir(parents=True, exist_ok=True) @@ -41,15 +83,32 @@ def update(): po_file = message_dir.joinpath(f"{APP_NAME}.po") if not po_file.exists(): - shutil.copy(POT_FILE, po_file) - + # Create new .po file with proper header + with open(po_file, 'w', encoding='utf-8') as f: + f.write(generate_header(lang)) + + # Then update with babel to add translations + run( + f"pybabel update " + f"-i {POT_FILE} " + f"-o {po_file} " + f"-l {lang} " + ) else: + # Always prepend header for existing files (one-time patch) + with open(po_file, 'r', encoding='utf-8') as f: + existing_content = f.read() + + with open(po_file, 'w', encoding='utf-8') as f: + f.write(generate_header(lang)) + f.write(existing_content) + + # Update with babel run( f"pybabel update " f"-i {POT_FILE} " f"-o {po_file} " f"-l {lang} " - f"--omit-header" ) diff --git a/scripts/runtest.py b/scripts/runtest.py index 79ceca3..35f862a 100755 --- a/scripts/runtest.py +++ b/scripts/runtest.py @@ -7,10 +7,11 @@ """ import argparse -import subprocess import os import re +import subprocess import sys +import xml.etree.ElementTree as ET # Add project root to Python path for imports sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) @@ -20,6 +21,111 @@ README = "README.md" TESTS_DIR = "tests/engines" RESULTS_FILE = "/tmp/pytest_results.txt" +JUNIT_FILE = "/tmp/pytest_results.xml" + +SUITE_BADGES_START = "" +SUITE_BADGES_END = "" + +SUITE_ORDER = [ + "autocomplete", + "core", + "ui", + "mysql", + "mariadb", + "postgresql", + "sqlite", +] + + +def _build_suite_badges_table(suite_stats: dict[str, dict[str, int]]) -> str: + lines = [ + SUITE_BADGES_START, + "### Suite status (passed / skipped)", + "", + "| Suite | Passed | Skipped |", + "|-------|--------|---------|", + ] + + for suite_name in SUITE_ORDER: + passed = suite_stats[suite_name]["passed"] + skipped = suite_stats[suite_name]["skipped"] + passed_badge = f"![passed](https://img.shields.io/badge/passed-{passed}-brightgreen)" + skipped_badge = f"![skipped](https://img.shields.io/badge/skipped-{skipped}-lightgrey)" + lines.append(f"| {suite_name} | {passed_badge} | {skipped_badge} |") + + lines += ["", SUITE_BADGES_END] + return "\n".join(lines) + + +def _extract_suite_name(case_node: ET.Element) -> str: + file_path = case_node.attrib.get("file", "") + class_name = case_node.attrib.get("classname", "") + source = file_path or class_name.replace(".", "/") + + mapping = [ + ("tests/autocomplete/", "autocomplete"), + ("tests/core/", "core"), + ("tests/ui/", "ui"), + ("tests/engines/mysql/", "mysql"), + ("tests/engines/mariadb/", "mariadb"), + ("tests/engines/postgresql/", "postgresql"), + ("tests/engines/sqlite/", "sqlite"), + ] + + for prefix, suite_name in mapping: + if source.startswith(prefix): + return suite_name + + return "" + + +def _load_suite_stats(junit_file: str) -> dict[str, dict[str, int]]: + stats = { + suite_name: {"passed": 0, "skipped": 0} + for suite_name in SUITE_ORDER + } + + if not os.path.exists(junit_file): + return stats + + try: + tree = ET.parse(junit_file) + except ET.ParseError: + return stats + + root = tree.getroot() + for case in root.findall(".//testcase"): + suite_name = _extract_suite_name(case) + if not suite_name: + continue + + if case.find("skipped") is not None: + stats[suite_name]["skipped"] += 1 + continue + + if case.find("failure") is not None or case.find("error") is not None: + continue + + stats[suite_name]["passed"] += 1 + + return stats + + +def _update_suite_badges_block(content: str, suite_stats: dict[str, dict[str, int]]) -> str: + replacement = _build_suite_badges_table(suite_stats) + block_pattern = re.compile( + rf"{re.escape(SUITE_BADGES_START)}.*?{re.escape(SUITE_BADGES_END)}", + re.DOTALL, + ) + + if block_pattern.search(content): + return block_pattern.sub(replacement, content) + + anchor = "For detailed test coverage matrix, statistics, and architecture, see **[tests/README.md](tests/README.md)**." + if anchor in content: + return content.replace(anchor, f"{anchor}\n\n{replacement}") + + return f"{content}\n\n{replacement}\n" def get_engine_color(engine, results_content): @@ -95,6 +201,10 @@ def update_badges(): match = re.search(r'TOTAL\s+\d+\s+\d+\s+(\d+)%', results_content) coverage = match.group(1) if match else "0" + tests_total_match = re.search(r'\[(\d+)\s+items\]', results_content) + tests_total = tests_total_match.group(1) if tests_total_match else "unknown" + suite_stats = _load_suite_stats(JUNIT_FILE) + print(f"\nCoverage: {coverage}%") print("\nAnalyzing results for badge updates...") @@ -114,6 +224,26 @@ def update_badges(): content = re.sub(r'coverage-\d+%', f'coverage-{coverage}%', content) print(f" Coverage badge updated: {coverage}%") + # Update total tests badge + content = re.sub( + r'!\[Tests\]\(https://img\.shields\.io/badge/tests-[^\)]*\)', + f'![Tests](https://img.shields.io/badge/tests-{tests_total}-blue)', + content, + ) + + if "![Tests](https://img.shields.io/badge/tests-" not in content: + content = re.sub( + r'(!\[Coverage\]\(https://img\.shields\.io/badge/coverage-[^\)]*\))', + rf'\1\n![Tests](https://img.shields.io/badge/tests-{tests_total}-blue)', + content, + count=1, + ) + + print(f" Tests badge updated: {tests_total}") + + content = _update_suite_badges_block(content, suite_stats) + print(" Suite matrix badges updated") + # Update engine badges for engine, color in colors.items(): @@ -138,6 +268,11 @@ def update_badges(): except OSError: pass + try: + os.remove(JUNIT_FILE) + except OSError: + pass + def main(): parser = argparse.ArgumentParser(description='Unified test runner') @@ -160,7 +295,15 @@ def main(): try: with open(RESULTS_FILE, 'w') as f: process = subprocess.Popen( - ['uv', 'run', 'pytest', 'tests/', '--tb=no'], + [ + 'uv', + 'run', + 'pytest', + 'tests/', + '--tb=no', + '--junitxml', + JUNIT_FILE, + ], stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True diff --git a/structures/connection.py b/structures/connection.py index ab1c10e..2fcc64f 100755 --- a/structures/connection.py +++ b/structures/connection.py @@ -150,3 +150,28 @@ def is_new(self): def has_enabled_tunnel(self) -> bool: return bool(self.ssh_tunnel and self.ssh_tunnel.is_enabled) + + def record_connection_attempt( + self, + timestamp: str, + success: bool, + duration_ms: int, + failure_reason: Optional[str] = None, + ) -> None: + self.total_connection_attempts += 1 + self.last_connection_at = timestamp + self.most_recent_connection_duration_ms = duration_ms + + if success: + self.successful_connections += 1 + self.last_successful_connection_at = timestamp + self.last_failure_reason = None + else: + self.unsuccessful_connections += 1 + self.last_failure_reason = failure_reason + + previous_average = self.average_connection_time_ms or 0 + total_attempts = self.total_connection_attempts + self.average_connection_time_ms = int( + ((previous_average * (total_attempts - 1)) + duration_ms) / total_attempts + ) diff --git a/structures/engines/context.py b/structures/engines/context.py index a0f965d..1728107 100755 --- a/structures/engines/context.py +++ b/structures/engines/context.py @@ -55,7 +55,8 @@ def __init__(self, connection: Connection): self.databases = ObservableLazyList(self.get_databases) def __del__(self): - self.disconnect() + with contextlib.suppress(Exception): + self.disconnect() def before_connect(self, *args, **kwargs): # SSH tunnel support via connection configuration @@ -509,11 +510,15 @@ def disconnect(self) -> None: self.before_disconnect() if self._cursor is not None: - self._cursor.close() + close_cursor = getattr(self._cursor, "close", None) + if callable(close_cursor): + close_cursor() self._cursor = None if self._connection is not None: - self._connection.close() + close_connection = getattr(self._connection, "close", None) + if callable(close_connection): + close_connection() self._connection = None @contextlib.contextmanager diff --git a/structures/engines/database.py b/structures/engines/database.py index 58dc527..70802dc 100755 --- a/structures/engines/database.py +++ b/structures/engines/database.py @@ -13,6 +13,7 @@ from structures.engines.datatype import SQLDataType from structures.engines.indextype import SQLIndexType +from structures.engines.dump import create_database_dump from structures.engines.sqlite.indextype import SQLiteIndexType @@ -76,6 +77,41 @@ def refresh(self): if getattr(self, observable_lazy_list_name, None) != (observable_lazy_list := getattr(original_database, observable_lazy_list_name, None)): observable_lazy_list.refresh() + @property + def is_new(self) -> bool: + return self.id <= -1 + + def save(self) -> bool: + if self.is_new: + return self.create() + + return self.alter() + + @abc.abstractmethod + def create(self) -> bool: + raise NotImplementedError + + @abc.abstractmethod + def alter(self) -> bool: + raise NotImplementedError + + @abc.abstractmethod + def drop(self) -> bool: + raise NotImplementedError + + def dump( + self, + /, + *, + include_schema: bool = True, + include_records: bool = True, + ) -> str: + return create_database_dump( + self, + include_schema=include_schema, + include_records=include_records, + ) + @dataclasses.dataclass(eq=False) class SQLTable(abc.ABC): @@ -195,9 +231,8 @@ def is_new(self): def generate_uuid(length: int = 8) -> str: return str(uuid.uuid4())[::-1][:length] - @abc.abstractmethod def raw_create(self) -> str: - raise NotImplementedError + raise NotImplementedError(f"{self.__class__.__name__}.raw_create() is not implemented") def get_identifier_indexes(self) -> list['SQLIndex']: identifier_indexes = [] @@ -472,6 +507,9 @@ def copy(self): field_values = {f.name: getattr(self, f.name) for f in dataclasses.fields(cls)} return cls(**field_values) + def raw_create(self) -> str: + raise NotImplementedError(f"{self.__class__.__name__}.raw_create() is not implemented") + @dataclasses.dataclass(eq=False) class SQLForeignKey(abc.ABC): @@ -677,6 +715,10 @@ def drop(self) -> bool: def alter(self) -> bool: raise NotImplementedError + @abc.abstractmethod + def raw_create(self) -> str: + raise NotImplementedError + @dataclasses.dataclass(eq=False) class SQLTrigger(abc.ABC): @@ -726,6 +768,10 @@ def drop(self) -> bool: def alter(self) -> bool: raise NotImplementedError + @abc.abstractmethod + def raw_create(self) -> str: + raise NotImplementedError + @dataclasses.dataclass(eq=False) class SQLProcedure(abc.ABC): @@ -772,6 +818,10 @@ def drop(self) -> bool: def alter(self) -> bool: raise NotImplementedError + @abc.abstractmethod + def raw_create(self) -> str: + raise NotImplementedError + @dataclasses.dataclass(eq=False) class SQLFunction(abc.ABC): @@ -818,6 +868,10 @@ def drop(self) -> bool: def alter(self) -> bool: raise NotImplementedError + @abc.abstractmethod + def raw_create(self) -> str: + raise NotImplementedError + @dataclasses.dataclass(eq=False) class SQLEvent(abc.ABC): diff --git a/structures/engines/datatype.py b/structures/engines/datatype.py index c52c98c..25b34b4 100755 --- a/structures/engines/datatype.py +++ b/structures/engines/datatype.py @@ -36,12 +36,12 @@ class SQLDataType: name: str category: DataTypeCategory - alias: List[str] = dataclasses.field(default_factory=list) + alias: list[str] = dataclasses.field(default_factory=list) max_size: Optional[int] = None format: Optional[DataTypeFormat] = dataclasses.field(default=None) - default_set: List[str] = dataclasses.field(default_factory=list) + default_set: list[str] = dataclasses.field(default_factory=list) default_length: int = 50 # for the text default_precision: int = 10 # for the integer/boolean default_scale: int = 5 # for the real @@ -56,7 +56,7 @@ class SQLDataType: has_zerofill: bool = dataclasses.field(default=False) # for the integer and real has_unsigned: bool = dataclasses.field(default=False) # for the integer and real - set: List[str] = dataclasses.field(default_factory=list) + set: list[str] = dataclasses.field(default_factory=list) def __post_init__(self): if self.has_set is None: @@ -105,7 +105,7 @@ class StandardDataType(): @classmethod @functools.lru_cache(maxsize=1) - def get_all(cls) -> List[SQLDataType]: + def get_all(cls) -> list[SQLDataType]: types = [ getattr(cls, name) for name in dir(cls) diff --git a/structures/engines/dump.py b/structures/engines/dump.py new file mode 100644 index 0000000..cca3645 --- /dev/null +++ b/structures/engines/dump.py @@ -0,0 +1,275 @@ +import datetime +import decimal +import json +import pathlib + +from typing import Any + + +def create_database_dump( + database: Any, + /, + *, + include_schema: bool = True, + include_records: bool = True, +) -> str: + database.context.set_database(database) + dump_path = _build_dump_path(database.name) + with dump_path.open("w", encoding="utf-8") as handle: + _write_header(handle) + if include_schema: + _write_schema(handle, database) + if include_records: + _write_records(handle, database) + + return str(dump_path) + + +def _build_dump_path(database_name: str) -> pathlib.Path: + now = datetime.datetime.now() + safe_name = "".join(char if char.isalnum() or char == "_" else "_" for char in database_name) + suffix = now.strftime("%Y%m%d_%H%M%S_%f") + filename = f"petersql_backup_{safe_name}_{suffix}.sql" + return pathlib.Path.cwd() / filename + + +def _write_header(handle): + now = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S") + handle.write(f"-- This backup was created by PeterSQL on {now}\n\n") + + +def _write_records(handle, database: Any): + _write_section_title(handle, "Insert records") + statements = _collect_record_statements(database) + _write_statements(handle, statements) + + +def _write_schema(handle, database: Any): + _write_section_title(handle, "Create database") + _write_statements(handle, _collect_database_statements(database)) + + _write_section_title(handle, "Create tables") + _write_statements(handle, _collect_table_statements(database)) + + _write_section_title(handle, "Create indexes/triggers/views/procedures/functions") + _write_statements(handle, _collect_secondary_statements(database)) + + +def _write_section_title(handle, title: str): + handle.write(f"-- {title}\n") + handle.write("-- ----------------------------------------\n") + + +def _write_statements(handle, statements: list[str]): + if not statements: + handle.write("-- No statements\n\n") + return + + for statement in statements: + if not statement: + continue + handle.write(statement.rstrip()) + handle.write("\n\n") + + +def _collect_database_statements(database: Any) -> list[str]: + context = database.context + context_name = context.__class__.__name__.lower() + if "sqlite" in context_name: + return ["-- SQLite does not support CREATE DATABASE statements"] + + database_name = context.quote_identifier(database.name) + create_statement = f"CREATE DATABASE {database_name};" + if "postgresql" in context_name: + return [create_statement, f"\\connect {database.name}"] + + return [create_statement, f"USE {database_name};"] + + +def _collect_table_statements(database: Any) -> list[str]: + statements = [] + tables = sorted(list(database.tables), key=lambda table: table.name) + for table in tables: + statements.append(_normalize_statement(table.raw_create())) + + return [statement for statement in statements if statement] + + +def _collect_secondary_statements(database: Any) -> list[str]: + statements = [] + statements.extend(_collect_index_statements(database)) + statements.extend(_collect_trigger_statements(database)) + statements.extend(_collect_view_statements(database)) + statements.extend(_collect_procedure_statements(database)) + statements.extend(_collect_function_statements(database)) + return [statement for statement in statements if statement] + + +def _collect_index_statements(database: Any) -> list[str]: + statements = [] + context_name = database.context.__class__.__name__.lower() + tables = sorted(list(database.tables), key=lambda table: table.name) + for table in tables: + indexes = sorted(list(table.indexes), key=lambda index: index.name) + for index in indexes: + if not _is_dumpable_index(index, context_name): + continue + + statements.append(_normalize_statement(index.raw_create())) + + return [statement for statement in statements if statement] + + +def _collect_record_statements(database: Any) -> list[str]: + statements = [] + tables = sorted(list(database.tables), key=lambda table: table.name) + for table in tables: + statements.extend(_table_record_statements(table)) + + return statements + + +def _collect_trigger_statements(database: Any) -> list[str]: + context_name = database.context.__class__.__name__.lower() + triggers = sorted(list(getattr(database, "triggers", [])), key=lambda trigger: trigger.name) + if "mysql" in context_name or "mariadb" in context_name: + return [_mysql_block_statement(trigger.raw_create()) for trigger in triggers] + + return [_normalize_statement(trigger.raw_create()) for trigger in triggers] + + +def _collect_view_statements(database: Any) -> list[str]: + views = sorted(list(getattr(database, "views", [])), key=lambda view: view.name) + return [_normalize_statement(view.raw_create()) for view in views] + + +def _collect_function_statements(database: Any) -> list[str]: + context_name = database.context.__class__.__name__.lower() + functions = sorted(list(getattr(database, "functions", [])), key=lambda function: function.name) + if "mysql" in context_name or "mariadb" in context_name: + return [_mysql_block_statement(function.raw_create()) for function in functions] + + return [_normalize_statement(function.raw_create()) for function in functions] + + +def _collect_procedure_statements(database: Any) -> list[str]: + context_name = database.context.__class__.__name__.lower() + procedures = sorted(list(getattr(database, "procedures", [])), key=lambda procedure: procedure.name) + if "mysql" in context_name or "mariadb" in context_name: + return [_mysql_block_statement(procedure.raw_create()) for procedure in procedures] + + return [_normalize_statement(procedure.raw_create()) for procedure in procedures] + + +def _is_dumpable_index(index: Any, context_name: str) -> bool: + if index.type.name == "PRIMARY": + return False + + if "sqlite" in context_name and index.name.startswith("sqlite_autoindex_"): + return False + + return True + + +def _mysql_block_statement(statement: str) -> str: + statement = statement.strip().rstrip(";") + return f"DELIMITER $$\n{statement}$$\nDELIMITER ;" + + +def _normalize_statement(statement: str) -> str: + statement = statement.strip().rstrip(";") + if not statement: + return "" + return f"{statement};" + + +def _render_literal(value: Any, table: Any) -> str: + if value is None: + return "NULL" + if isinstance(value, bool): + return _render_boolean(value, table) + if isinstance(value, (int, float, decimal.Decimal)): + return str(value) + if isinstance(value, datetime.datetime): + return _quote_literal(value.isoformat(sep=" ")) + if isinstance(value, (datetime.date, datetime.time)): + return _quote_literal(value.isoformat()) + if isinstance(value, (bytes, bytearray, memoryview)): + return _quote_literal(bytes(value).hex()) + if isinstance(value, (dict, list, tuple, set)): + return _quote_literal(json.dumps(value, ensure_ascii=False)) + + return _quote_literal(str(value)) + + +def _render_boolean(value: bool, table: Any) -> str: + context_name = table.database.context.__class__.__name__.lower() + if "postgresql" in context_name: + return "TRUE" if value else "FALSE" + return "1" if value else "0" + + +def _table_record_statements(table: Any) -> list[str]: + context = table.database.context + columns = [column for column in table.columns if getattr(column, "virtuality", None) is None] + if not columns: + return [] + + table_name = _table_reference(table) + column_names = ", ".join(context.quote_identifier(column.name) for column in columns) + ordering = ", ".join(context.quote_identifier(column.name) for column in columns) + return _table_record_pages(table, table_name, column_names, columns, ordering) + + +def _table_record_pages( + table: Any, + table_name: str, + column_names: str, + columns: list[Any], + ordering: str, +) -> list[str]: + offset = 0 + limit = 1000 + statements = [] + while True: + records = table.database.context.get_records(table, limit=limit, offset=offset, orders=ordering) + if not records: + break + + statements.extend(_table_record_page(table, table_name, column_names, columns, records)) + if len(records) < limit: + break + + offset += limit + + return statements + + +def _table_record_page( + table: Any, + table_name: str, + column_names: str, + columns: list[Any], + records: list[Any], +) -> list[str]: + statements = [] + for record in records: + values = [_render_literal(record.values.get(column.name), table) for column in columns] + values_sql = ", ".join(values) + statements.append(f"INSERT INTO {table_name} ({column_names}) VALUES ({values_sql});") + + return statements + + +def _table_reference(table: Any) -> str: + context = table.database.context + context_name = context.__class__.__name__.lower() + if "sqlite" in context_name: + return context.quote_identifier(table.name) + + return table.fully_qualified_name + + +def _quote_literal(value: str) -> str: + escaped = value.replace("'", "''") + return f"'{escaped}'" \ No newline at end of file diff --git a/structures/engines/indextype.py b/structures/engines/indextype.py index 3198f23..d271caa 100755 --- a/structures/engines/indextype.py +++ b/structures/engines/indextype.py @@ -38,7 +38,7 @@ class StandardIndexType(): @classmethod @functools.lru_cache() - def get_all(cls) -> List[SQLIndexType]: + def get_all(cls) -> list[SQLIndexType]: types = [] for base in reversed(cls.__mro__): for key, value in base.__dict__.items(): diff --git a/structures/engines/mariadb/context.py b/structures/engines/mariadb/context.py index 14238b8..af4284b 100755 --- a/structures/engines/mariadb/context.py +++ b/structures/engines/mariadb/context.py @@ -25,6 +25,7 @@ MariaDBColumn, MariaDBIndex, MariaDBForeignKey, + MariaDBProcedure, MariaDBRecord, MariaDBView, MariaDBTrigger, @@ -197,7 +198,8 @@ def connect(self, **connect_kwargs) -> None: except Exception as e: logger.error(f"Failed to connect to MariaDB: {e}", exc_info=True) raise - else: + + if self._cursor is not None: self.after_connect() def disconnect(self) -> None: @@ -258,12 +260,36 @@ def get_databases(self) -> list[SQLDatabase]: total_bytes=float(row["total_bytes"]), context=self, get_tables_handler=self.get_tables, + get_procedures_handler=self.get_procedures, get_views_handler=self.get_views, get_triggers_handler=self.get_triggers, ) ) return results + def get_procedures(self, database: SQLDatabase) -> list[MariaDBProcedure]: + results: list[MariaDBProcedure] = [] + self.execute( + f""" + SELECT ROUTINE_NAME + FROM INFORMATION_SCHEMA.ROUTINES + WHERE ROUTINE_SCHEMA = '{database.name}' AND ROUTINE_TYPE = 'PROCEDURE' + ORDER BY ROUTINE_NAME + """ + ) + for i, result in enumerate(self.fetchall()): + results.append( + MariaDBProcedure( + id=i, + name=result["ROUTINE_NAME"], + database=database, + parameters="", + statement="", + ) + ) + + return results + def get_views(self, database: SQLDatabase): results: list[MariaDBView] = [] self.execute( @@ -442,7 +468,7 @@ def get_indexes(self, table: SQLTable) -> list[SQLIndex]: return results - def get_checks(self, table: MariaDBTable) -> list[MariaDBCheck]: + def get_checks(self, table: MariaDBTable) -> list["MariaDBCheck"]: from structures.engines.mariadb.database import MariaDBCheck if table is None or table.is_new: @@ -612,7 +638,7 @@ def build_empty_check( name: Optional[str] = None, expression: Optional[str] = None, **default_values, - ) -> MariaDBCheck: + ) -> "MariaDBCheck": from structures.engines.mariadb.database import MariaDBCheck id = MariaDBContext.get_temporary_id(table.checks) @@ -697,8 +723,19 @@ def build_empty_function( def build_empty_procedure( self, database: SQLDatabase, /, name: Optional[str] = None, **default_values - ): - raise NotImplementedError("MariaDB Procedure not implemented yet") + ) -> MariaDBProcedure: + id = MariaDBContext.get_temporary_id(database.procedures) + + if name is None: + name = f"procedure_{id}" + + return MariaDBProcedure( + id=id, + name=name, + database=database, + parameters=default_values.get("parameters", ""), + statement=default_values.get("statement", ""), + ) def build_empty_trigger( self, database: SQLDatabase, /, name: Optional[str] = None, **default_values diff --git a/structures/engines/mariadb/database.py b/structures/engines/mariadb/database.py index 2a0f2de..d383b8a 100644 --- a/structures/engines/mariadb/database.py +++ b/structures/engines/mariadb/database.py @@ -5,7 +5,7 @@ from structures.helpers import merge_original_current from structures.engines.context import QUERY_LOGS -from structures.engines.database import SQLTable, SQLColumn, SQLIndex, SQLForeignKey, SQLRecord, SQLView, SQLTrigger, SQLFunction, SQLDatabase, SQLCheck +from structures.engines.database import SQLTable, SQLCheck, SQLColumn, SQLIndex, SQLView, SQLRecord, SQLTrigger, SQLFunction, SQLDatabase, SQLForeignKey, SQLProcedure from structures.engines.mariadb.indextype import MariaDBIndexType from structures.engines.mariadb.builder import MariaDBColumnBuilder, MariaDBIndexBuilder @@ -14,6 +14,45 @@ @dataclasses.dataclass class MariaDBDatabase(SQLDatabase): default_collation: str = None + character_set: Optional[str] = None + encryption: Optional[str] = None + + def _build_database_clauses(self) -> list[str]: + clauses: list[str] = [] + + if self.character_set: + clauses.append(f"CHARACTER SET {self.context.quote_identifier(self.character_set)}") + + if self.default_collation: + clauses.append(f"COLLATE {self.context.quote_identifier(self.default_collation)}") + + if self.encryption: + clauses.append(f"ENCRYPTION = '{str(self.encryption).upper()}'") + + return clauses + + def create(self) -> bool: + clauses = self._build_database_clauses() + query = f"CREATE DATABASE {self.context.quote_identifier(self.name)}" + if clauses: + query += f" {' '.join(clauses)}" + + return self.context.execute(query) + + def alter(self) -> bool: + clauses = self._build_database_clauses() + + if not clauses: + return False + + self.context.execute( + f"ALTER DATABASE {self.context.quote_identifier(self.name)} {' '.join(clauses)}" + ) + return True + + def drop(self) -> bool: + query = f"DROP DATABASE {self.context.quote_identifier(self.name)}" + return self.context.execute(query) @dataclasses.dataclass(eq=False) @@ -199,6 +238,9 @@ def drop(self) -> bool: @dataclasses.dataclass(eq=False) class MariaDBIndex(SQLIndex): + def raw_create(self) -> str: + return str(MariaDBIndexBuilder(self)) + def create(self) -> bool: if self.type == MariaDBIndexType.PRIMARY: return self.table.database.context.execute(f"""ALTER TABLE {self.table.fully_qualified_name} ADD PRIMARY KEY ({", ".join(self.columns)})""") @@ -331,9 +373,12 @@ def delete(self) -> bool: class MariaDBView(SQLView): + def raw_create(self) -> str: + return f"CREATE VIEW {self.fully_qualified_name} AS {self.statement}" + def create(self) -> bool: self.database.context.set_database(self.database) - return self.database.context.execute(f"CREATE VIEW {self.fully_qualified_name} AS {self.statement}") + return self.database.context.execute(self.raw_create()) def drop(self) -> bool: self.database.context.set_database(self.database) @@ -345,8 +390,20 @@ def alter(self) -> bool: class MariaDBTrigger(SQLTrigger): + def _show_create_trigger(self) -> str: + context = self.database.context + context.execute(f"SHOW CREATE TRIGGER {self.quoted_name}") + row = context.fetchone() + return row.get("SQL Original Statement", "") if row else "" + + def raw_create(self) -> str: + if self.statement.strip().upper().startswith(("BEFORE", "AFTER")): + return f"CREATE TRIGGER {self.fully_qualified_name} {self.statement}" + + return self._show_create_trigger() + def create(self) -> bool: - return self.database.context.execute(f"CREATE TRIGGER {self.fully_qualified_name} {self.statement}") + return self.database.context.execute(self.raw_create()) def drop(self) -> bool: return self.database.context.execute(f"DROP TRIGGER IF EXISTS {self.fully_qualified_name}") @@ -363,9 +420,21 @@ class MariaDBFunction(SQLFunction): deterministic: bool = False statement: str = "" + def _show_create_function(self) -> str: + context = self.database.context + context.execute(f"SHOW CREATE FUNCTION {self.fully_qualified_name}") + row = context.fetchone() + return row.get("Create Function", "") if row else "" + def create(self) -> bool: + return self.database.context.execute(self.raw_create()) + + def raw_create(self) -> str: + if not self.statement.strip() or not self.returns.strip(): + return self._show_create_function() + deterministic = "DETERMINISTIC" if self.deterministic else "NOT DETERMINISTIC" - query = f""" + return f""" CREATE FUNCTION {self.fully_qualified_name}({self.parameters}) RETURNS {self.returns} {deterministic} @@ -373,7 +442,6 @@ def create(self) -> bool: {self.statement}; END """ - return self.database.context.execute(query) def drop(self) -> bool: return self.database.context.execute(f"DROP FUNCTION IF EXISTS {self.fully_qualified_name}") @@ -381,3 +449,49 @@ def drop(self) -> bool: def alter(self) -> bool: self.drop() return self.create() + + +@dataclasses.dataclass(eq=False) +class MariaDBProcedure(SQLProcedure): + parameters: str = "" + statement: str = "" + + @staticmethod + def _render_body(statement: str) -> str: + body = statement.strip() + if body.endswith(";"): + return body + + return f"{body};" + + def _show_create_procedure(self) -> str: + context = self.database.context + context.execute(f"SHOW CREATE PROCEDURE {self.fully_qualified_name}") + row = context.fetchone() + return row.get("Create Procedure", "") if row else "" + + def create(self) -> bool: + self.database.context.set_database(self.database) + return self.database.context.execute(self.raw_create()) + + def raw_create(self) -> str: + if not self.statement.strip(): + return self._show_create_procedure() + + body = self._render_body(self.statement) + return f""" + CREATE PROCEDURE {self.fully_qualified_name}({self.parameters}) + BEGIN + {body} + END + """ + + def drop(self) -> bool: + self.database.context.set_database(self.database) + return self.database.context.execute( + f"DROP PROCEDURE IF EXISTS {self.fully_qualified_name}" + ) + + def alter(self) -> bool: + self.drop() + return self.create() diff --git a/structures/engines/mysql/builder.py b/structures/engines/mysql/builder.py index fbe014c..dd361c2 100644 --- a/structures/engines/mysql/builder.py +++ b/structures/engines/mysql/builder.py @@ -7,7 +7,7 @@ class MySQLColumnBuilder(AbstractColumnBuilder): TEMPLATE = ["%(name)s", "%(datatype)s", "%(unsigned)s", "%(zerofill)s", "%(collate)s", "%(nullable)s", "%(default)s", "%(auto_increment)s", - "%(unique)s", "%(primary_key)s", "%(comment)s", "%(check)s", + "%(unique)s", "%(comment)s", "%(check)s", # TODO: COLUMN_FORMAT {FIXED|DYNAMIC|DEFAULT} - STORAGE {DISK|MEMORY}] # "%(format)s","%(storage)s", "%(generated)s"] @@ -51,7 +51,7 @@ def generated(self): class MySQLIndexBuilder(AbstractIndexBuilder): TEMPLATE = ["%(type)s", "%(name)s", "(%(columns)s)"] - def __init__(self, index: 'MariaDBIndex', exclude: Optional[List[str]] = None): + def __init__(self, index: 'MariaDBIndex', exclude: Optional[list[str]] = None): super().__init__(index, exclude) @property diff --git a/structures/engines/mysql/context.py b/structures/engines/mysql/context.py index 65a2aee..ffd1012 100644 --- a/structures/engines/mysql/context.py +++ b/structures/engines/mysql/context.py @@ -25,6 +25,7 @@ MySQLDatabase, MySQLForeignKey, MySQLIndex, + MySQLProcedure, MySQLRecord, MySQLTable, MySQLTrigger, @@ -182,7 +183,8 @@ def connect(self, **connect_kwargs) -> None: except Exception as e: logger.error(f"Failed to connect to MySQL: {e}") raise - else: + + if self._cursor is not None: self.after_connect() def set_database(self, database: SQLDatabase) -> None: @@ -228,12 +230,36 @@ def get_databases(self) -> list[SQLDatabase]: total_bytes=float(row["total_bytes"]), context=self, get_tables_handler=self.get_tables, + get_procedures_handler=self.get_procedures, get_views_handler=self.get_views, get_triggers_handler=self.get_triggers, ) ) return results + def get_procedures(self, database: SQLDatabase) -> list[MySQLProcedure]: + results: list[MySQLProcedure] = [] + self.execute( + f""" + SELECT ROUTINE_NAME + FROM INFORMATION_SCHEMA.ROUTINES + WHERE ROUTINE_SCHEMA = '{database.name}' AND ROUTINE_TYPE = 'PROCEDURE' + ORDER BY ROUTINE_NAME + """ + ) + for i, result in enumerate(self.fetchall()): + results.append( + MySQLProcedure( + id=i, + name=result["ROUTINE_NAME"], + database=database, + parameters="", + statement="", + ) + ) + + return results + def get_views(self, database: SQLDatabase): results: list[MySQLView] = [] self.execute( @@ -412,7 +438,7 @@ def get_indexes(self, table: SQLTable) -> list[SQLIndex]: return results - def get_checks(self, table: MySQLTable) -> list[MySQLCheck]: + def get_checks(self, table: MySQLTable) -> list["MySQLCheck"]: from structures.engines.mysql.database import MySQLCheck if table is None or table.is_new: @@ -583,7 +609,7 @@ def build_empty_check( name: Optional[str] = None, expression: Optional[str] = None, **default_values, - ) -> MySQLCheck: + ) -> "MySQLCheck": from structures.engines.mysql.database import MySQLCheck id = MySQLContext.get_temporary_id(table.checks) @@ -666,8 +692,19 @@ def build_empty_function( def build_empty_procedure( self, database: SQLDatabase, /, name: Optional[str] = None, **default_values - ): - raise NotImplementedError("MySQL Procedure not implemented yet") + ) -> MySQLProcedure: + id = MySQLContext.get_temporary_id(database.procedures) + + if name is None: + name = f"procedure_{id}" + + return MySQLProcedure( + id=id, + name=name, + database=database, + parameters=default_values.get("parameters", ""), + statement=default_values.get("statement", ""), + ) def build_empty_trigger( self, database: SQLDatabase, /, name: Optional[str] = None, **default_values diff --git a/structures/engines/mysql/database.py b/structures/engines/mysql/database.py index e84de88..fd2694d 100644 --- a/structures/engines/mysql/database.py +++ b/structures/engines/mysql/database.py @@ -12,6 +12,7 @@ SQLForeignKey, SQLFunction, SQLIndex, + SQLProcedure, SQLRecord, SQLTable, SQLTrigger, @@ -24,6 +25,45 @@ @dataclasses.dataclass class MySQLDatabase(SQLDatabase): default_collation: str = None + character_set: Optional[str] = None + encryption: Optional[str] = None + + def _build_database_clauses(self) -> list[str]: + clauses: list[str] = [] + + if self.character_set: + clauses.append(f"CHARACTER SET {self.context.quote_identifier(self.character_set)}") + + if self.default_collation: + clauses.append(f"COLLATE {self.context.quote_identifier(self.default_collation)}") + + if self.encryption: + clauses.append(f"ENCRYPTION = '{str(self.encryption).upper()}'") + + return clauses + + def create(self) -> bool: + clauses = self._build_database_clauses() + query = f"CREATE DATABASE {self.context.quote_identifier(self.name)}" + if clauses: + query += f" {' '.join(clauses)}" + + return self.context.execute(query) + + def alter(self) -> bool: + clauses = self._build_database_clauses() + + if not clauses: + return False + + self.context.execute( + f"ALTER DATABASE {self.context.quote_identifier(self.name)} {' '.join(clauses)}" + ) + return True + + def drop(self) -> bool: + query = f"DROP DATABASE {self.context.quote_identifier(self.name)}" + return self.context.execute(query) @@ -196,6 +236,9 @@ def drop(self) -> bool: @dataclasses.dataclass(eq=False) class MySQLIndex(SQLIndex): + def raw_create(self) -> str: + return str(MySQLIndexBuilder(self)) + def create(self) -> bool: if self.type == MySQLIndexType.PRIMARY: return self.table.database.context.execute(f"""ALTER TABLE `{self.table.database.name}`.`{self.table.name}` ADD PRIMARY KEY ({", ".join(self.columns)})""") @@ -328,9 +371,12 @@ def delete(self) -> bool: class MySQLView(SQLView): + def raw_create(self) -> str: + return f"CREATE VIEW {self.fully_qualified_name} AS {self.statement}" + def create(self) -> bool: self.database.context.set_database(self.database) - return self.database.context.execute(f"CREATE VIEW {self.fully_qualified_name} AS {self.statement}") + return self.database.context.execute(self.raw_create()) def drop(self) -> bool: self.database.context.set_database(self.database) @@ -342,8 +388,20 @@ def alter(self) -> bool: class MySQLTrigger(SQLTrigger): + def _show_create_trigger(self) -> str: + context = self.database.context + context.execute(f"SHOW CREATE TRIGGER {self.quoted_name}") + row = context.fetchone() + return row.get("SQL Original Statement", "") if row else "" + + def raw_create(self) -> str: + if self.statement.strip().upper().startswith(("BEFORE", "AFTER")): + return f"CREATE TRIGGER {self.fully_qualified_name} {self.statement}" + + return self._show_create_trigger() + def create(self) -> bool: - return self.database.context.execute(f"CREATE TRIGGER {self.fully_qualified_name} {self.statement}") + return self.database.context.execute(self.raw_create()) def drop(self) -> bool: return self.database.context.execute(f"DROP TRIGGER IF EXISTS {self.fully_qualified_name}") @@ -360,9 +418,21 @@ class MySQLFunction(SQLFunction): deterministic: bool = False sql: str = "" + def _show_create_function(self) -> str: + context = self.database.context + context.execute(f"SHOW CREATE FUNCTION {self.fully_qualified_name}") + row = context.fetchone() + return row.get("Create Function", "") if row else "" + def create(self) -> bool: + return self.database.context.execute(self.raw_create()) + + def raw_create(self) -> str: + if not self.sql.strip() or not self.returns.strip(): + return self._show_create_function() + deterministic = "DETERMINISTIC" if self.deterministic else "NOT DETERMINISTIC" - query = f""" + return f""" CREATE FUNCTION {self.fully_qualified_name}({self.parameters}) RETURNS {self.returns} {deterministic} @@ -370,7 +440,6 @@ def create(self) -> bool: {self.sql}; END """ - return self.database.context.execute(query) def drop(self) -> bool: return self.database.context.execute(f"DROP FUNCTION IF EXISTS {self.fully_qualified_name}") @@ -378,3 +447,49 @@ def drop(self) -> bool: def alter(self) -> bool: self.drop() return self.create() + + +@dataclasses.dataclass(eq=False) +class MySQLProcedure(SQLProcedure): + parameters: str = "" + statement: str = "" + + @staticmethod + def _render_body(statement: str) -> str: + body = statement.strip() + if body.endswith(";"): + return body + + return f"{body};" + + def _show_create_procedure(self) -> str: + context = self.database.context + context.execute(f"SHOW CREATE PROCEDURE {self.fully_qualified_name}") + row = context.fetchone() + return row.get("Create Procedure", "") if row else "" + + def create(self) -> bool: + self.database.context.set_database(self.database) + return self.database.context.execute(self.raw_create()) + + def raw_create(self) -> str: + if not self.statement.strip(): + return self._show_create_procedure() + + body = self._render_body(self.statement) + return f""" + CREATE PROCEDURE {self.fully_qualified_name}({self.parameters}) + BEGIN + {body} + END + """ + + def drop(self) -> bool: + self.database.context.set_database(self.database) + return self.database.context.execute( + f"DROP PROCEDURE IF EXISTS {self.fully_qualified_name}" + ) + + def alter(self) -> bool: + self.drop() + return self.create() diff --git a/structures/engines/postgresql/database.py b/structures/engines/postgresql/database.py index c320356..57be67d 100644 --- a/structures/engines/postgresql/database.py +++ b/structures/engines/postgresql/database.py @@ -13,7 +13,52 @@ @dataclasses.dataclass class PostgreSQLDatabase(SQLDatabase): - pass + tablespace: Optional[str] = None + connection_limit: Optional[int] = None + + def _build_create_database_clauses(self) -> list[str]: + clauses: list[str] = [] + + if self.tablespace: + clauses.append(f"TABLESPACE {self.context.quote_identifier(self.tablespace)}") + + if self.connection_limit is not None: + clauses.append(f"CONNECTION LIMIT {int(self.connection_limit)}") + + return clauses + + def create(self) -> bool: + clauses = self._build_create_database_clauses() + query = f"CREATE DATABASE {self.context.quote_identifier(self.name)}" + if clauses: + query += f" {' '.join(clauses)}" + + return self.context.execute(query) + + def alter(self) -> bool: + statements: list[str] = [] + + if self.tablespace: + statements.append( + f"ALTER DATABASE {self.context.quote_identifier(self.name)} SET TABLESPACE {self.context.quote_identifier(self.tablespace)}" + ) + + if self.connection_limit is not None: + statements.append( + f"ALTER DATABASE {self.context.quote_identifier(self.name)} CONNECTION LIMIT {int(self.connection_limit)}" + ) + + if not statements: + return False + + for statement in statements: + self.context.execute(statement) + + return True + + def drop(self) -> bool: + query = f"DROP DATABASE {self.context.quote_identifier(self.name)}" + return self.context.execute(query) @dataclasses.dataclass(eq=False) @@ -217,8 +262,17 @@ def modify(self, current: Self): @dataclasses.dataclass(eq=False) class PostgreSQLIndex(SQLIndex): + def raw_create(self) -> str: + if self.type.name == "PRIMARY": + return "" + + return str(PostgreSQLIndexBuilder(self, inline=False)) + def create(self) -> bool: - statement = str(PostgreSQLIndexBuilder(self, inline=False)) + statement = self.raw_create() + if not statement: + return True + return self.table.database.context.execute(statement) def drop(self) -> bool: @@ -348,9 +402,11 @@ class PostgreSQLView(SQLView): def fully_qualified_name(self): return self.database.context.qualify('public', self.name) + def raw_create(self) -> str: + return f'CREATE VIEW {self.fully_qualified_name} AS {self.statement};' + def create(self) -> bool: - statement = f'CREATE VIEW {self.fully_qualified_name} AS {self.statement};' - return self.database.context.execute(statement) + return self.database.context.execute(self.raw_create()) def drop(self) -> bool: statement = f'DROP VIEW IF EXISTS {self.fully_qualified_name};' @@ -373,8 +429,8 @@ class PostgreSQLFunction(SQLFunction): def fully_qualified_name(self): return self.database.context.qualify('public', self.name) - def create(self) -> bool: - create_statement = f""" + def raw_create(self) -> str: + return f""" CREATE OR REPLACE FUNCTION {self.fully_qualified_name}({self.parameters}) RETURNS {self.returns} LANGUAGE {self.language} @@ -385,7 +441,9 @@ def create(self) -> bool: END; $$; """ - return self.database.context.execute(create_statement) + + def create(self) -> bool: + return self.database.context.execute(self.raw_create()) def drop(self) -> bool: statement = f'DROP FUNCTION IF EXISTS {self.fully_qualified_name}({self.parameters});' @@ -406,8 +464,8 @@ class PostgreSQLProcedure(SQLProcedure): def fully_qualified_name(self): return self.database.context.qualify('public', self.name) - def create(self) -> bool: - create_statement = f""" + def raw_create(self) -> str: + return f""" CREATE OR REPLACE PROCEDURE {self.fully_qualified_name}({self.parameters}) LANGUAGE {self.language} AS $$ @@ -416,7 +474,9 @@ def create(self) -> bool: END; $$; """ - return self.database.context.execute(create_statement) + + def create(self) -> bool: + return self.database.context.execute(self.raw_create()) def drop(self) -> bool: statement = f'DROP PROCEDURE IF EXISTS {self.fully_qualified_name}({self.parameters});' @@ -429,8 +489,11 @@ def alter(self) -> bool: @dataclasses.dataclass class PostgreSQLTrigger(SQLTrigger): + def raw_create(self) -> str: + return self.statement + def create(self) -> bool: - return self.database.context.execute(self.statement) + return self.database.context.execute(self.raw_create()) def alter(self) -> bool: self.drop() diff --git a/structures/engines/sqlite/database.py b/structures/engines/sqlite/database.py index f31cb0e..de82eb6 100644 --- a/structures/engines/sqlite/database.py +++ b/structures/engines/sqlite/database.py @@ -1,6 +1,6 @@ import re import dataclasses -from typing import Self, Optional, Dict +from typing import Self, Optional from helpers.logger import logger @@ -15,7 +15,14 @@ @dataclasses.dataclass class SQLiteDatabase(SQLDatabase): - pass + def create(self) -> bool: + return False + + def alter(self) -> bool: + return False + + def drop(self) -> bool: + return False @dataclasses.dataclass(eq=False) @@ -94,7 +101,7 @@ def raw_create(self) -> str: constraints = [] primary_keys = [] unique_indexes = [] - columns_definitions: Dict[str, str] = {} + columns_definitions: dict[str, str] = {} for index in self.indexes: if index.type == SQLiteIndexType.PRIMARY: @@ -326,25 +333,27 @@ class SQLiteIndex(SQLIndex): def fully_qualified_name(self): return self.table.database.context.qualify(self.table.database.name, self.name) - def create(self) -> bool: + def raw_create(self) -> str: if self.type == SQLiteIndexType.PRIMARY: - return False # PRIMARY is handled in table creation + return "" if self.type == SQLiteIndexType.UNIQUE and self.name.startswith("sqlite_autoindex_"): - return False # CONSTRAINT UNIQUE is handled in table creation + return "" unique_index = "UNIQUE INDEX" if self.type == SQLiteIndexType.UNIQUE else "INDEX" - quote_identifier = self.table.database.context.quote_identifier - columns_clause = ", ".join([quote_identifier(column) for column in self.columns]) where_clause = f" WHERE {self.condition}" if self.condition else "" - - statement = ( + return ( f"CREATE {unique_index} IF NOT EXISTS {self.fully_qualified_name} " - f"ON {self.table.name}({columns_clause}){where_clause} " + f"ON {self.table.name}({columns_clause}){where_clause}" ) + def create(self) -> bool: + statement = self.raw_create() + if not statement: + return False + return self.table.database.context.execute(statement) def drop(self) -> bool: @@ -470,8 +479,11 @@ def __init__(self, /, id: int, name: str, database: SQLDatabase, statement: str) super().__init__(id=id, name=name, database=database, statement=statement) + def raw_create(self) -> str: + return f"CREATE VIEW IF NOT EXISTS {self.fully_qualified_name} AS {self.statement}" + def create(self) -> bool: - return self.database.context.execute(f"CREATE VIEW IF NOT EXISTS {self.fully_qualified_name} AS {self.statement}") + return self.database.context.execute(self.raw_create()) def drop(self) -> bool: return self.database.context.execute(f"DROP VIEW IF EXISTS {self.fully_qualified_name}") @@ -481,8 +493,11 @@ def alter(self) -> bool: class SQLiteTrigger(SQLTrigger): + def raw_create(self) -> str: + return f"CREATE TRIGGER IF NOT EXISTS {self.fully_qualified_name} {self.statement}" + def create(self) -> bool: - return self.database.context.execute(f"CREATE TRIGGER IF NOT EXISTS {self.fully_qualified_name} {self.statement}") + return self.database.context.execute(self.raw_create()) def drop(self) -> bool: return self.database.context.execute(f"DROP TRIGGER IF EXISTS {self.fully_qualified_name}") diff --git a/tests/core/test_connection.py b/tests/core/test_connection.py index e2d6b6e..7030712 100644 --- a/tests/core/test_connection.py +++ b/tests/core/test_connection.py @@ -1,5 +1,3 @@ -import pytest - from structures.connection import Connection, ConnectionEngine from structures.configurations import ( CredentialsConfiguration, @@ -9,111 +7,102 @@ class TestConnection: - """Tests for Connection dataclass.""" - def test_connection_mysql(self): - """Test MySQL connection creation.""" config = CredentialsConfiguration( hostname="localhost", username="root", password="secret", port=3306, ) - conn = Connection( + connection = Connection( id=1, name="MySQL Test", engine=ConnectionEngine.MYSQL, configuration=config, ) - assert conn.id == 1 - assert conn.name == "MySQL Test" - assert conn.engine == ConnectionEngine.MYSQL - assert conn.configuration.hostname == "localhost" - assert conn.configuration.port == 3306 + assert connection.id == 1 + assert connection.name == "MySQL Test" + assert connection.engine == ConnectionEngine.MYSQL + assert connection.configuration.hostname == "localhost" + assert connection.configuration.port == 3306 def test_connection_sqlite(self): - """Test SQLite connection creation.""" config = SourceConfiguration(filename=":memory:") - conn = Connection( + connection = Connection( id=2, name="SQLite Test", engine=ConnectionEngine.SQLITE, configuration=config, ) - assert conn.engine == ConnectionEngine.SQLITE - assert conn.configuration.filename == ":memory:" + assert connection.engine == ConnectionEngine.SQLITE + assert connection.configuration.filename == ":memory:" def test_connection_is_new(self): - """Test is_new property.""" config = SourceConfiguration(filename=":memory:") - conn = Connection( + connection = Connection( id=-1, name="New", engine=ConnectionEngine.SQLITE, configuration=config, ) - assert conn.is_new is True + assert connection.is_new is True def test_connection_is_not_new(self): - """Test is_new property when id >= 0.""" config = SourceConfiguration(filename=":memory:") - conn = Connection( + connection = Connection( id=0, name="Existing", engine=ConnectionEngine.SQLITE, configuration=config, ) - assert conn.is_new is False + assert connection.is_new is False def test_connection_copy(self): - """Test connection copy.""" config = CredentialsConfiguration( hostname="localhost", username="root", password="", port=3306, ) - conn = Connection( + connection = Connection( id=1, name="Original", engine=ConnectionEngine.MYSQL, configuration=config, ) - copy = conn.copy() + copy = connection.copy() - assert copy.id == conn.id - assert copy.name == conn.name - assert copy is not conn + assert copy.id == connection.id + assert copy.name == connection.name + assert copy is not connection def test_connection_to_dict(self): - """Test connection serialization to dict.""" config = CredentialsConfiguration( hostname="localhost", username="root", password="secret", port=3306, ) - conn = Connection( + connection = Connection( id=1, name="Test", engine=ConnectionEngine.MYSQL, configuration=config, ) - d = conn.to_dict() + data = connection.to_dict() - assert d["id"] == 1 - assert d["name"] == "Test" - assert d["engine"] == "MySQL" - assert d["configuration"]["hostname"] == "localhost" + assert data["id"] == 1 + assert data["name"] == "Test" + assert data["engine"] == "MySQL" + assert data["configuration"]["hostname"] == "localhost" def test_connection_with_ssh_tunnel(self): - """Test connection with SSH tunnel.""" config = CredentialsConfiguration( hostname="localhost", username="root", @@ -129,7 +118,7 @@ def test_connection_with_ssh_tunnel(self): password="sshpass", local_port=3307, ) - conn = Connection( + connection = Connection( id=1, name="With SSH", engine=ConnectionEngine.MYSQL, @@ -137,9 +126,9 @@ def test_connection_with_ssh_tunnel(self): ssh_tunnel=ssh, ) - assert conn.ssh_tunnel is not None - assert conn.ssh_tunnel.enabled is True - assert conn.ssh_tunnel.hostname == "bastion.example.com" + assert connection.ssh_tunnel is not None + assert connection.ssh_tunnel.enabled is True + assert connection.ssh_tunnel.hostname == "bastion.example.com" def test_connection_is_valid_with_empty_password(self): config = CredentialsConfiguration( @@ -148,60 +137,110 @@ def test_connection_is_valid_with_empty_password(self): password="", port=3306, ) - conn = Connection( + connection = Connection( id=1, name="Local", engine=ConnectionEngine.MYSQL, configuration=config, ) - assert conn.is_valid is True + assert connection.is_valid is True + def test_record_connection_attempt_success_updates_statistics(self): + config = CredentialsConfiguration( + hostname="localhost", + username="root", + password="", + port=3306, + ) + connection = Connection( + id=1, + name="Stats Success", + engine=ConnectionEngine.MYSQL, + configuration=config, + ) -class TestConnectionEngine: - """Tests for ConnectionEngine enum.""" + connection.record_connection_attempt( + timestamp="2026-03-07 17:00:00", + success=True, + duration_ms=120, + ) + + assert connection.total_connection_attempts == 1 + assert connection.successful_connections == 1 + assert connection.unsuccessful_connections == 0 + assert connection.last_connection_at == "2026-03-07 17:00:00" + assert connection.last_successful_connection_at == "2026-03-07 17:00:00" + assert connection.last_failure_reason is None + assert connection.most_recent_connection_duration_ms == 120 + assert connection.average_connection_time_ms == 120 + def test_record_connection_attempt_failure_updates_statistics(self): + config = CredentialsConfiguration( + hostname="localhost", + username="root", + password="", + port=3306, + ) + connection = Connection( + id=1, + name="Stats Failure", + engine=ConnectionEngine.MYSQL, + configuration=config, + average_connection_time_ms=100, + total_connection_attempts=1, + successful_connections=1, + ) + + connection.record_connection_attempt( + timestamp="2026-03-07 17:01:00", + success=False, + duration_ms=300, + failure_reason="Authentication failed", + ) + + assert connection.total_connection_attempts == 2 + assert connection.successful_connections == 1 + assert connection.unsuccessful_connections == 1 + assert connection.last_connection_at == "2026-03-07 17:01:00" + assert connection.last_successful_connection_at is None + assert connection.last_failure_reason == "Authentication failed" + assert connection.most_recent_connection_duration_ms == 300 + assert connection.average_connection_time_ms == 200 + + +class TestConnectionEngine: def test_engine_mysql(self): - """Test MySQL engine.""" engine = ConnectionEngine.MYSQL assert engine.value.name == "MySQL" def test_engine_mariadb(self): - """Test MariaDB engine.""" engine = ConnectionEngine.MARIADB assert engine.value.name == "MariaDB" def test_engine_sqlite(self): - """Test SQLite engine.""" engine = ConnectionEngine.SQLITE assert engine.value.name == "SQLite" def test_engine_postgresql(self): - """Test PostgreSQL engine.""" engine = ConnectionEngine.POSTGRESQL assert engine.value.name == "PostgreSQL" def test_engine_from_name_mysql(self): - """Test from_name with MySQL.""" engine = ConnectionEngine.from_name("MySQL") assert engine == ConnectionEngine.MYSQL def test_engine_from_name_sqlite(self): - """Test from_name with SQLite.""" engine = ConnectionEngine.from_name("SQLite") assert engine == ConnectionEngine.SQLITE def test_engine_from_name_case_insensitive(self): - """Test from_name is case sensitive.""" engine = ConnectionEngine.from_name("MariaDB") assert engine == ConnectionEngine.MARIADB class TestCredentialsConfiguration: - """Tests for CredentialsConfiguration.""" - def test_credentials_config(self): - """Test credentials configuration.""" config = CredentialsConfiguration( hostname="db.example.com", username="admin", @@ -216,16 +255,12 @@ def test_credentials_config(self): class TestSourceConfiguration: - """Tests for SourceConfiguration.""" - def test_source_config(self): - """Test source configuration.""" config = SourceConfiguration(filename="/path/to/database.db") assert config.filename == "/path/to/database.db" def test_source_config_memory(self): - """Test source configuration with memory.""" config = SourceConfiguration(filename=":memory:") assert config.filename == ":memory:" diff --git a/tests/core/test_ssh_tunnel_contract.py b/tests/core/test_ssh_tunnel_contract.py new file mode 100644 index 0000000..5ec1146 --- /dev/null +++ b/tests/core/test_ssh_tunnel_contract.py @@ -0,0 +1,145 @@ +import signal + +from structures.connection import Connection, ConnectionEngine +from structures.ssh_tunnel import SSHTunnel +from structures.configurations import CredentialsConfiguration, SSHTunnelConfiguration +from structures.engines.mysql.context import MySQLContext +from structures.engines.mariadb.context import MariaDBContext + + +class _FakeTunnel: + def __init__(self, *args, **kwargs): + self.local_port = kwargs["local_bind_address"][1] or 4406 + self.call_log: list[str] = kwargs["extra_args"] + + def start(self): + self.call_log.append("start") + + def stop(self): + self.call_log.append("stop") + + +class _FakeProcess: + def __init__(self): + self.pid = 999 + + def poll(self): + return None + + def wait(self, timeout=None): + return 0 + + def terminate(self): + return None + + +class TestSSHTunnelContextContract: + def test_mariadb_context_manages_tunnel_lifecycle(self, monkeypatch): + call_log: list[str] = [] + configuration = CredentialsConfiguration("db.internal", "root", "secret", 3306) + ssh_tunnel = SSHTunnelConfiguration( + True, + "ssh", + "bastion.internal", + 22, + "sshuser", + "sshpass", + 0, + extra_args=call_log, + ) + connection = Connection( + 1, + "mariadb_tunnel", + ConnectionEngine.MARIADB, + configuration, + ssh_tunnel=ssh_tunnel, + ) + context = MariaDBContext(connection) + monkeypatch.setattr("structures.engines.context.SSHTunnel", _FakeTunnel) + + context.before_connect() + assert context.host == "127.0.0.1" + assert context.port == 4406 + assert call_log == ["start"] + + context.before_disconnect() + assert context.host == "db.internal" + assert context.port == 3306 + assert call_log == ["start", "stop"] + + def test_mysql_context_manages_tunnel_lifecycle(self, monkeypatch): + call_log: list[str] = [] + configuration = CredentialsConfiguration("db.internal", "root", "secret", 3306) + ssh_tunnel = SSHTunnelConfiguration( + True, + "ssh", + "bastion.internal", + 22, + "sshuser", + "sshpass", + 4407, + extra_args=call_log, + ) + connection = Connection( + 2, + "mysql_tunnel", + ConnectionEngine.MYSQL, + configuration, + ssh_tunnel=ssh_tunnel, + ) + context = MySQLContext(connection) + monkeypatch.setattr("structures.engines.context.SSHTunnel", _FakeTunnel) + + context.before_connect() + assert context.host == "127.0.0.1" + assert context.port == 4407 + assert call_log == ["start"] + + context.before_disconnect() + assert context.host == "db.internal" + assert context.port == 3306 + assert call_log == ["start", "stop"] + + +class TestSSHTunnelStopContract: + def test_mariadb_disconnect_stops_active_tunnel(self): + call_log: list[str] = [] + configuration = CredentialsConfiguration("db.internal", "root", "secret", 3306) + connection = Connection( + 3, + "mariadb_disconnect", + ConnectionEngine.MARIADB, + configuration, + ) + context = MariaDBContext(connection) + + class FakeActiveTunnel: + def stop(self): + call_log.append("stop") + + context._ssh_tunnel = FakeActiveTunnel() + context.disconnect() + + assert call_log == ["stop"] + assert context._ssh_tunnel is None + + def test_ssh_tunnel_stop_terminates_posix_process_group(self, monkeypatch): + kill_calls: list[tuple[int, int]] = [] + tunnel = SSHTunnel("bastion.internal") + tunnel._process = _FakeProcess() + + monkeypatch.setattr("os.killpg", lambda pid, sig: kill_calls.append((pid, sig))) + monkeypatch.setattr("os.name", "posix", raising=False) + + tunnel.stop() + + assert kill_calls == [(999, signal.SIGTERM)] + assert tunnel._process is None + + def test_ssh_tunnel_stop_returns_when_process_is_missing(self): + tunnel = SSHTunnel("bastion.internal") + tunnel._process = None + + tunnel.stop() + + assert tunnel._process is None \ No newline at end of file diff --git a/tests/engines/base_check_tests.py b/tests/engines/base_check_tests.py index ae30832..691a677 100644 --- a/tests/engines/base_check_tests.py +++ b/tests/engines/base_check_tests.py @@ -96,4 +96,8 @@ def test_check_alter(self, session, database, create_users_table, datatype_class check.expression = "age >= 18" assert check.alter() is True + table.checks.refresh() + checks = table.checks.get_value() + assert any(c.name == "age_check" for c in checks) + table.drop() diff --git a/tests/engines/base_database_tests.py b/tests/engines/base_database_tests.py new file mode 100644 index 0000000..a703367 --- /dev/null +++ b/tests/engines/base_database_tests.py @@ -0,0 +1,119 @@ +import uuid + + +class BaseDatabaseCreateAlterTests: + + def _build_new_database(self, database, session, name: str): + database_class = database.__class__ + new_database = database_class(id=-1, name=name, context=session.context) + + for key, value in self.get_create_options().items(): + if hasattr(new_database, key): + setattr(new_database, key, value) + + return new_database + + @staticmethod + def _find_database_by_name(session, name: str): + session.context.databases.refresh() + return next((db for db in session.context.databases.get_value() if db.name == name), None) + + def _execute_database_operation(self, session, operation): + if not self.requires_autocommit_for_database_ddl(): + operation() + return + + connection = getattr(session.context, "_connection", None) + if connection is None or not hasattr(connection, "autocommit"): + operation() + return + + connection.commit() + + previous_autocommit = connection.autocommit + connection.autocommit = True + try: + operation() + finally: + connection.autocommit = previous_autocommit + + def _drop_database(self, session, database) -> bool: + result = False + + def operation() -> None: + nonlocal result + result = database.drop() + + self._execute_database_operation(session, operation) + return result + + def _create_database(self, database) -> bool: + if not self.requires_autocommit_for_database_ddl(): + return database.create() + + connection = getattr(database.context, "_connection", None) + if connection is None or not hasattr(connection, "autocommit"): + return database.create() + + connection.commit() + + previous_autocommit = connection.autocommit + connection.autocommit = True + try: + return database.create() + finally: + connection.autocommit = previous_autocommit + + @staticmethod + def _build_unique_database_name() -> str: + unique_name = str(uuid.uuid4()).replace("-", "")[:12] + return f"db_{unique_name}" + + def test_database_create_and_drop(self, session, database): + name = self._build_unique_database_name() + created_database = self._build_new_database(database, session, name) + + assert self._create_database(created_database) is True + + loaded_database = self._find_database_by_name(session, name) + assert loaded_database is not None + + assert self._drop_database(session, loaded_database) is True + + def test_database_alter(self, database): + for key, value in self.get_alter_options().items(): + if hasattr(database, key): + setattr(database, key, value) + + assert database.alter() is True + + def get_create_options(self) -> dict[str, str]: + return {} + + def get_alter_options(self) -> dict[str, str]: + return {} + + def requires_autocommit_for_database_ddl(self) -> bool: + return False + + +class BaseDatabaseUnsupportedTests: + + @staticmethod + def _build_new_database(database, session, name: str): + database_class = database.__class__ + return database_class(id=-1, name=name, context=session.context) + + @staticmethod + def _build_unique_database_name() -> str: + unique_name = str(uuid.uuid4()).replace("-", "")[:12] + return f"db_{unique_name}" + + def test_database_create_returns_false(self, session, database): + name = self._build_unique_database_name() + new_database = self._build_new_database(database, session, name) + + assert new_database.create() is False + + def test_database_alter_returns_false(self, database): + assert database.alter() is False \ No newline at end of file diff --git a/tests/engines/base_function_tests.py b/tests/engines/base_function_tests.py index e4ebb55..9eefeb5 100644 --- a/tests/engines/base_function_tests.py +++ b/tests/engines/base_function_tests.py @@ -14,6 +14,9 @@ def get_function_parameters(self) -> str: def get_function_returns(self) -> str: return "integer" + + def get_updated_function_statement(self) -> str: + return self.get_function_statement() def test_function_create_and_drop(self, session: Session, database: SQLDatabase): function = session.context.build_empty_function( @@ -39,3 +42,31 @@ def test_function_create_and_drop(self, session: Session, database: SQLDatabase) database.functions.refresh() found = any(f.name == "test_function" for f in database.functions.get_value()) assert found is False + + def test_function_alter(self, session: Session, database: SQLDatabase): + function = session.context.build_empty_function( + database, + name="test_function_alter", + parameters=self.get_function_parameters(), + returns=self.get_function_returns(), + statement=self.get_function_statement(), + ) + + assert function.create() is True + + database.functions.refresh() + found = any( + f.name == "test_function_alter" for f in database.functions.get_value() + ) + assert found is True + + function.statement = self.get_updated_function_statement() + assert function.alter() is True + + database.functions.refresh() + found = any( + f.name == "test_function_alter" for f in database.functions.get_value() + ) + assert found is True + + assert function.drop() is True diff --git a/tests/engines/base_procedure_tests.py b/tests/engines/base_procedure_tests.py index 075566f..b838afa 100644 --- a/tests/engines/base_procedure_tests.py +++ b/tests/engines/base_procedure_tests.py @@ -11,6 +11,9 @@ def get_procedure_statement(self) -> str: def get_procedure_parameters(self) -> str: return "" + + def get_updated_procedure_statement(self) -> str: + return self.get_procedure_statement() def test_procedure_create_and_drop(self, session: Session, database: SQLDatabase): procedure = session.context.build_empty_procedure( @@ -35,3 +38,30 @@ def test_procedure_create_and_drop(self, session: Session, database: SQLDatabase database.procedures.refresh() found = any(p.name == "test_procedure" for p in database.procedures.get_value()) assert found is False + + def test_procedure_alter(self, session: Session, database: SQLDatabase): + procedure = session.context.build_empty_procedure( + database, + name="test_procedure_alter", + parameters=self.get_procedure_parameters(), + statement=self.get_procedure_statement() + ) + + assert procedure.create() is True + + database.procedures.refresh() + found = any( + p.name == "test_procedure_alter" for p in database.procedures.get_value() + ) + assert found is True + + procedure.statement = self.get_updated_procedure_statement() + assert procedure.alter() is True + + database.procedures.refresh() + found = any( + p.name == "test_procedure_alter" for p in database.procedures.get_value() + ) + assert found is True + + assert procedure.drop() is True diff --git a/tests/engines/mariadb/conftest.py b/tests/engines/mariadb/conftest.py index 990ddb3..ff173db 100644 --- a/tests/engines/mariadb/conftest.py +++ b/tests/engines/mariadb/conftest.py @@ -1,6 +1,5 @@ import pytest - from testcontainers.mysql import MySqlContainer from structures.session import Session @@ -64,13 +63,15 @@ def pytest_generate_tests(metafunc): @pytest.fixture(scope="module") def mariadb_container(mariadb_version, worker_id): - container = MySqlContainer(mariadb_version, name=f"petersql_test_{worker_id}_{mariadb_version.replace(":", "_")}", - mem_limit="768m", - memswap_limit="1g", - nano_cpus=1_000_000_000, - shm_size="256m", - ) - + container = MySqlContainer( + mariadb_version, + name=f"petersql_test_{worker_id}_{mariadb_version.replace(':', '_')}", + mem_limit="768m", + memswap_limit="1g", + nano_cpus=1_000_000_000, + shm_size="256m", + ) + with container: yield container diff --git a/tests/engines/mariadb/test_context.py b/tests/engines/mariadb/test_context.py index eb7514f..fcdd160 100644 --- a/tests/engines/mariadb/test_context.py +++ b/tests/engines/mariadb/test_context.py @@ -1,48 +1,83 @@ +import pymysql import pytest +from structures.connection import Connection, ConnectionEngine +from structures.configurations import CredentialsConfiguration +from structures.engines.mariadb.context import MariaDBContext + + +class TestMariaDBContextReliability: + def test_connect_retries_with_tls_on_auth_error(self, monkeypatch): + config = CredentialsConfiguration( + hostname="localhost", + username="root", + password="secret", + port=3306, + ) + connection = Connection( + id=1, + name="mariadb_tls_retry", + engine=ConnectionEngine.MARIADB, + configuration=config, + ) + context = MariaDBContext(connection) + monkeypatch.setattr(context, "before_connect", lambda *args, **kwargs: None) + monkeypatch.setattr(context, "after_connect", lambda *args, **kwargs: None) + + calls = [] + + class FakeConnection: + def cursor(self): + return object() + + def fake_connect(**kwargs): + calls.append(kwargs) + if len(calls) == 1: + raise pymysql.err.OperationalError(1045, "Access denied") + return FakeConnection() + + monkeypatch.setattr(pymysql, "connect", fake_connect) + + context.connect(connect_timeout=1) + + assert len(calls) == 2 + assert "ssl" not in calls[0] + assert "ssl" in calls[1] + assert connection.configuration.use_tls_enabled is True + @pytest.mark.integration @pytest.mark.xdist_group("mariadb") class TestMariaDBContext: - """Tests for MariaDB context methods.""" - def test_context_connection(self, mariadb_session): - """Test context is connected.""" ctx = mariadb_session.context assert ctx.is_connected is True def test_context_execute_query(self, mariadb_session): - """Test executing a query.""" ctx = mariadb_session.context ctx.execute("SELECT 1 as test") result = ctx.fetchone() assert result["test"] == 1 def test_context_fetchall(self, mariadb_session): - """Test fetchall method.""" ctx = mariadb_session.context ctx.execute("SELECT 1 as val UNION SELECT 2 UNION SELECT 3") results = ctx.fetchall() assert len(results) == 3 def test_context_get_server_version(self, mariadb_session): - """Test getting server version.""" version = mariadb_session.context.get_server_version() assert version is not None assert len(version) > 0 def test_context_quote_identifier(self, mariadb_session): - """Test building SQL safe names uses IDENTIFIER_QUOTE_CHAR.""" ctx = mariadb_session.context quote = ctx.IDENTIFIER_QUOTE_CHAR - # Simple names don't need quoting assert ctx.quote_identifier("normal") == "normal" - # Names with spaces are quoted using IDENTIFIER_QUOTE_CHAR assert ctx.quote_identifier("with space") == f'{quote}with space{quote}' def test_context_transaction(self, mariadb_session, mariadb_database): - """Test transaction context manager.""" ctx = mariadb_session.context db_name = mariadb_database.name @@ -57,10 +92,8 @@ def test_context_transaction(self, mariadb_session, mariadb_database): ctx.execute(f"DROP TABLE {db_name}.test_tx") def test_context_databases_list(self, mariadb_session): - """Test getting databases list.""" ctx = mariadb_session.context databases = ctx.databases.get_value() assert len(databases) > 0 - # Should have at least information_schema db_names = [db.name for db in databases] assert "information_schema" in db_names diff --git a/tests/engines/mariadb/test_integration_suite.py b/tests/engines/mariadb/test_integration_suite.py index b025c09..92da41b 100644 --- a/tests/engines/mariadb/test_integration_suite.py +++ b/tests/engines/mariadb/test_integration_suite.py @@ -2,12 +2,14 @@ from structures.engines.mariadb.datatype import MariaDBDataType from structures.engines.mariadb.indextype import MariaDBIndexType +from tests.engines.base_database_tests import BaseDatabaseCreateAlterTests from tests.engines.base_table_tests import BaseTableTests from tests.engines.base_record_tests import BaseRecordTests from tests.engines.base_column_tests import BaseColumnTests from tests.engines.base_index_tests import BaseIndexTests from tests.engines.base_foreignkey_tests import BaseForeignKeyTests from tests.engines.base_check_tests import BaseCheckTests +from tests.engines.base_procedure_tests import BaseProcedureTests from tests.engines.base_trigger_tests import BaseTriggerTests from tests.engines.base_view_tests import BaseViewSaveTests, BaseViewIsNewTests, BaseViewDefinerTests @@ -56,6 +58,17 @@ class TestMariaDBCheck(BaseCheckTests): pass +@pytest.mark.integration +@pytest.mark.xdist_group("mariadb") +class TestMariaDBProcedure(BaseProcedureTests): + + def get_procedure_statement(self) -> str: + return "SELECT 1" + + def get_updated_procedure_statement(self) -> str: + return "SELECT 2" + + @pytest.mark.integration @pytest.mark.xdist_group("mariadb") class TestMariaDBTrigger(BaseTriggerTests): @@ -90,3 +103,20 @@ def get_simple_view_statement(self) -> str: @pytest.mark.xdist_group("mariadb") class TestMariaDBViewDefiner(BaseViewDefinerTests): pass + + +@pytest.mark.integration +@pytest.mark.xdist_group("mariadb") +class TestMariaDBDatabase(BaseDatabaseCreateAlterTests): + + def get_create_options(self) -> dict[str, str]: + return { + "character_set": "utf8mb4", + "default_collation": "utf8mb4_general_ci", + } + + def get_alter_options(self) -> dict[str, str]: + return { + "character_set": "utf8mb4", + "default_collation": "utf8mb4_general_ci", + } diff --git a/tests/engines/mysql/test_context.py b/tests/engines/mysql/test_context.py index 13817a0..523e7e2 100644 --- a/tests/engines/mysql/test_context.py +++ b/tests/engines/mysql/test_context.py @@ -1,48 +1,83 @@ +import pymysql import pytest +from structures.connection import Connection, ConnectionEngine +from structures.configurations import CredentialsConfiguration +from structures.engines.mysql.context import MySQLContext + + +class TestMySQLContextReliability: + def test_connect_retries_with_tls_on_auth_error(self, monkeypatch): + config = CredentialsConfiguration( + hostname="localhost", + username="root", + password="secret", + port=3306, + ) + connection = Connection( + id=1, + name="mysql_tls_retry", + engine=ConnectionEngine.MYSQL, + configuration=config, + ) + context = MySQLContext(connection) + monkeypatch.setattr(context, "before_connect", lambda *args, **kwargs: None) + monkeypatch.setattr(context, "after_connect", lambda *args, **kwargs: None) + + calls = [] + + class FakeConnection: + def cursor(self): + return object() + + def fake_connect(**kwargs): + calls.append(kwargs) + if len(calls) == 1: + raise pymysql.err.OperationalError(1045, "Access denied") + return FakeConnection() + + monkeypatch.setattr(pymysql, "connect", fake_connect) + + context.connect(connect_timeout=1) + + assert len(calls) == 2 + assert "ssl" not in calls[0] + assert "ssl" in calls[1] + assert connection.configuration.use_tls_enabled is True + @pytest.mark.integration @pytest.mark.xdist_group("mysql") class TestMySQLContext: - """Tests for MySQL context methods.""" - def test_context_connection(self, mysql_session): - """Test context is connected.""" ctx = mysql_session.context assert ctx.is_connected is True def test_context_execute_query(self, mysql_session): - """Test executing a query.""" ctx = mysql_session.context ctx.execute("SELECT 1 as test") result = ctx.fetchone() assert result["test"] == 1 def test_context_fetchall(self, mysql_session): - """Test fetchall method.""" ctx = mysql_session.context ctx.execute("SELECT 1 as val UNION SELECT 2 UNION SELECT 3") results = ctx.fetchall() assert len(results) == 3 def test_context_get_server_version(self, mysql_session): - """Test getting server version.""" version = mysql_session.context.get_server_version() assert version is not None assert len(version) > 0 def test_context_quote_identifier(self, mysql_session): - """Test building SQL safe names uses IDENTIFIER_QUOTE_CHAR.""" ctx = mysql_session.context quote = ctx.IDENTIFIER_QUOTE_CHAR - # Simple names don't need quoting assert ctx.quote_identifier("normal") == "normal" - # Names with spaces are quoted using IDENTIFIER_QUOTE_CHAR assert ctx.quote_identifier("with space") == f'{quote}with space{quote}' def test_context_transaction(self, mysql_session, mysql_database): - """Test transaction context manager.""" ctx = mysql_session.context db_name = mysql_database.name @@ -57,10 +92,8 @@ def test_context_transaction(self, mysql_session, mysql_database): ctx.execute(f"DROP TABLE {db_name}.test_tx") def test_context_databases_list(self, mysql_session): - """Test getting databases list.""" ctx = mysql_session.context databases = ctx.databases.get_value() assert len(databases) > 0 - # Should have at least information_schema db_names = [db.name for db in databases] assert "information_schema" in db_names diff --git a/tests/engines/mysql/test_integration_suite.py b/tests/engines/mysql/test_integration_suite.py index 953e72d..e0a54c6 100644 --- a/tests/engines/mysql/test_integration_suite.py +++ b/tests/engines/mysql/test_integration_suite.py @@ -2,12 +2,14 @@ from structures.engines.mysql.datatype import MySQLDataType from structures.engines.mysql.indextype import MySQLIndexType +from tests.engines.base_database_tests import BaseDatabaseCreateAlterTests from tests.engines.base_table_tests import BaseTableTests from tests.engines.base_record_tests import BaseRecordTests from tests.engines.base_column_tests import BaseColumnTests from tests.engines.base_index_tests import BaseIndexTests from tests.engines.base_foreignkey_tests import BaseForeignKeyTests from tests.engines.base_check_tests import BaseCheckTests +from tests.engines.base_procedure_tests import BaseProcedureTests from tests.engines.base_trigger_tests import BaseTriggerTests from tests.engines.base_view_tests import BaseViewSaveTests, BaseViewIsNewTests, BaseViewDefinerTests @@ -56,6 +58,17 @@ class TestMySQLCheck(BaseCheckTests): pass +@pytest.mark.integration +@pytest.mark.xdist_group("mysql") +class TestMySQLProcedure(BaseProcedureTests): + + def get_procedure_statement(self) -> str: + return "SELECT 1" + + def get_updated_procedure_statement(self) -> str: + return "SELECT 2" + + @pytest.mark.integration @pytest.mark.xdist_group("mysql") class TestMySQLTrigger(BaseTriggerTests): @@ -90,3 +103,20 @@ def get_simple_view_statement(self) -> str: @pytest.mark.xdist_group("mysql") class TestMySQLViewDefiner(BaseViewDefinerTests): pass + + +@pytest.mark.integration +@pytest.mark.xdist_group("mysql") +class TestMySQLDatabase(BaseDatabaseCreateAlterTests): + + def get_create_options(self) -> dict[str, str]: + return { + "character_set": "utf8mb4", + "default_collation": "utf8mb4_general_ci", + } + + def get_alter_options(self) -> dict[str, str]: + return { + "character_set": "utf8mb4", + "default_collation": "utf8mb4_general_ci", + } diff --git a/tests/engines/postgresql/test_integration_suite.py b/tests/engines/postgresql/test_integration_suite.py index e218e9b..b016e9c 100644 --- a/tests/engines/postgresql/test_integration_suite.py +++ b/tests/engines/postgresql/test_integration_suite.py @@ -11,6 +11,7 @@ from structures.engines.postgresql.datatype import PostgreSQLDataType from structures.engines.postgresql.indextype import PostgreSQLIndexType +from tests.engines.base_database_tests import BaseDatabaseCreateAlterTests from tests.engines.base_table_tests import BaseTableTests from tests.engines.base_record_tests import BaseRecordTests from tests.engines.base_column_tests import BaseColumnTests @@ -112,6 +113,9 @@ def get_function_parameters(self) -> str: def get_function_returns(self) -> str: return "integer" + def get_updated_function_statement(self) -> str: + return "RETURN x + 2;" + @pytest.mark.integration @pytest.mark.xdist_group("postgresql") @@ -123,6 +127,9 @@ def get_procedure_statement(self) -> str: def get_procedure_parameters(self) -> str: return "" + def get_updated_procedure_statement(self) -> str: + return "RAISE NOTICE 'Updated from procedure';" + @pytest.mark.integration @pytest.mark.xdist_group("postgresql") @@ -130,3 +137,16 @@ class TestPostgreSQLViewIsNew(BaseViewIsNewTests): def get_simple_view_statement(self) -> str: return "SELECT 1 as id" + + +@pytest.mark.integration +@pytest.mark.xdist_group("postgresql") +class TestPostgreSQLDatabase(BaseDatabaseCreateAlterTests): + + def get_alter_options(self) -> dict[str, int]: + return { + "connection_limit": 50, + } + + def requires_autocommit_for_database_ddl(self) -> bool: + return True diff --git a/tests/engines/sqlite/test_context.py b/tests/engines/sqlite/test_context.py index 8e6a38d..a5460b8 100644 --- a/tests/engines/sqlite/test_context.py +++ b/tests/engines/sqlite/test_context.py @@ -1,3 +1,5 @@ +import pathlib + from structures.session import Session from structures.connection import Connection, ConnectionEngine from structures.configurations import SourceConfiguration @@ -105,3 +107,24 @@ def test_context_quote_identifier(self, sqlite_session): assert ctx.quote_identifier("normal") == "normal" # Names with spaces are quoted using IDENTIFIER_QUOTE_CHAR assert ctx.quote_identifier("with space") == f'{quote}with space{quote}' + + def test_database_dump(self, sqlite_session): + ctx = sqlite_session.context + database = ctx.get_databases()[0] + + with ctx.transaction() as transaction: + transaction.execute("CREATE TABLE dump_users (id INTEGER PRIMARY KEY, name TEXT NOT NULL)") + transaction.execute("INSERT INTO dump_users (id, name) VALUES (1, 'Alice')") + + dump_path = pathlib.Path(database.dump()) + content = dump_path.read_text(encoding="utf-8") + + assert dump_path.exists() + assert "This backup was created by PeterSQL" in content + assert "-- Create database" in content + assert "-- Create tables" in content + assert "-- Insert records" in content + assert "CREATE TABLE" in content + assert "INSERT INTO" in content + + dump_path.unlink(missing_ok=True) diff --git a/tests/engines/sqlite/test_integration_suite.py b/tests/engines/sqlite/test_integration_suite.py index f5cdaad..bd4b6d5 100644 --- a/tests/engines/sqlite/test_integration_suite.py +++ b/tests/engines/sqlite/test_integration_suite.py @@ -2,6 +2,7 @@ from structures.engines.sqlite.datatype import SQLiteDataType from structures.engines.sqlite.indextype import SQLiteIndexType +from tests.engines.base_database_tests import BaseDatabaseUnsupportedTests from tests.engines.base_table_tests import BaseTableTests from tests.engines.base_record_tests import BaseRecordTests from tests.engines.base_column_tests import BaseColumnTests @@ -76,3 +77,8 @@ class TestSQLiteViewIsNew(BaseViewIsNewTests): def get_simple_view_statement(self) -> str: return "SELECT * FROM users" + + +@pytest.mark.integration +class TestSQLiteDatabase(BaseDatabaseUnsupportedTests): + pass diff --git a/uv.lock b/uv.lock index d077a7b..6ed37a4 100644 --- a/uv.lock +++ b/uv.lock @@ -388,6 +388,7 @@ dev = [ { name = "pytest-mock" }, { name = "pytest-xdist" }, { name = "testcontainers" }, + { name = "toml" }, { name = "types-pymysql" }, { name = "types-pyyaml" }, { name = "types-wxpython" }, @@ -409,6 +410,7 @@ requires-dist = [ { name = "pyyaml", specifier = ">=6.0.3" }, { name = "sqlglot", specifier = ">=29.0.1" }, { name = "testcontainers", marker = "extra == 'dev'", specifier = ">=4.14.1" }, + { name = "toml", marker = "extra == 'dev'", specifier = ">=0.10.2" }, { name = "types-pymysql", marker = "extra == 'dev'", specifier = ">=1.1.0.20251220" }, { name = "types-pyyaml", marker = "extra == 'dev'", specifier = ">=6.0.12.20250915" }, { name = "types-wxpython", marker = "extra == 'dev'", specifier = ">=0.9.7" }, @@ -671,6 +673,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/c8/31/5e7b23f9e43ff7fd46d243808d70c5e8daf3bc08ecf5a7fb84d5e38f7603/testcontainers-4.14.1-py3-none-any.whl", hash = "sha256:03dfef4797b31c82e7b762a454b6afec61a2a512ad54af47ab41e4fa5415f891", size = 125640, upload-time = "2026-01-31T23:13:45.464Z" }, ] +[[package]] +name = "toml" +version = "0.10.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/be/ba/1f744cdc819428fc6b5084ec34d9b30660f6f9daaf70eead706e3203ec3c/toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f", size = 22253, upload-time = "2020-11-01T01:40:22.204Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/44/6f/7120676b6d73228c96e17f1f794d8ab046fc910d781c8d151120c3f1569e/toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b", size = 16588, upload-time = "2020-11-01T01:40:20.672Z" }, +] + [[package]] name = "types-pymysql" version = "1.1.0.20251220" diff --git a/windows/dialogs/connections/view.py b/windows/dialogs/connections/view.py index f15ea6d..94b4417 100644 --- a/windows/dialogs/connections/view.py +++ b/windows/dialogs/connections/view.py @@ -31,6 +31,9 @@ class ConnectionsManager(ConnectionsDialog): + _SETTINGS_SECTION = "connections_dialog" + _SETTINGS_EXPANDED_DIRECTORIES = "expanded_directories" + def __init__(self, parent): super().__init__(parent) self._app = wx.GetApp() @@ -83,6 +86,7 @@ def __init__(self, parent): self._pending_parent_directory_id = None self._setup_event_handlers() self._update_tree_menu_state() + wx.CallAfter(self._restore_expanded_directory_paths_from_settings) def _update_tree_menu_state(self): selected_connection = CURRENT_CONNECTION() @@ -112,24 +116,13 @@ def _record_connection_attempt( duration_ms: int, failure_reason: Optional[str] = None, ) -> None: - connection.total_connection_attempts += 1 - connection.last_connection_at = self._current_timestamp() - connection.most_recent_connection_duration_ms = duration_ms - - if success: - connection.successful_connections += 1 - connection.last_successful_connection_at = connection.last_connection_at - connection.last_failure_reason = None - else: - connection.unsuccessful_connections += 1 - connection.last_failure_reason = failure_reason or _("Unknown error") - - if connection.total_connection_attempts > 0: - previous_total = connection.average_connection_time_ms or 0 - attempt_count = connection.total_connection_attempts - connection.average_connection_time_ms = int( - ((previous_total * (attempt_count - 1)) + duration_ms) / attempt_count - ) + reason = failure_reason if success else failure_reason or _("Unknown error") + connection.record_connection_attempt( + timestamp=self._current_timestamp(), + success=success, + duration_ms=duration_ms, + failure_reason=reason, + ) if not connection.is_new: self._repository.save_connection(connection) @@ -240,11 +233,75 @@ def _setup_event_handlers(self): wx.dataview.EVT_DATAVIEW_ITEM_CONTEXT_MENU, self._on_tree_item_context_menu, ) + self.connections_tree_ctrl.Bind( + wx.dataview.EVT_DATAVIEW_ITEM_EXPANDED, + self._on_tree_expansion_changed, + ) + self.connections_tree_ctrl.Bind( + wx.dataview.EVT_DATAVIEW_ITEM_COLLAPSED, + self._on_tree_expansion_changed, + ) CURRENT_DIRECTORY.subscribe(self._on_current_directory) CURRENT_CONNECTION.subscribe(self._on_current_connection) PENDING_CONNECTION.subscribe(self._on_pending_connection) + @staticmethod + def _serialize_expanded_directory_paths(paths) -> list[list[int]]: + serialized_paths = [] + for path in sorted(paths): + if not path: + continue + + if not all(isinstance(node_id, int) for node_id in path): + continue + + serialized_paths.append([int(node_id) for node_id in path]) + + return serialized_paths + + @staticmethod + def _deserialize_expanded_directory_paths(raw_paths) -> set[tuple[int, ...]]: + if not isinstance(raw_paths, list): + return set() + + deserialized_paths = set() + for raw_path in raw_paths: + if not isinstance(raw_path, list) or not raw_path: + continue + + if not all(isinstance(node_id, int) for node_id in raw_path): + continue + + deserialized_paths.add(tuple(int(node_id) for node_id in raw_path)) + + return deserialized_paths + + def _save_expanded_directory_paths_to_settings(self) -> None: + expanded_paths = self._capture_expanded_directory_paths() + serialized_paths = self._serialize_expanded_directory_paths(expanded_paths) + + if self._app.settings.get_value(self._SETTINGS_SECTION) is None: + self._app.settings.set_value(self._SETTINGS_SECTION, value={}) + + self._app.settings.set_value( + self._SETTINGS_SECTION, + self._SETTINGS_EXPANDED_DIRECTORIES, + value=serialized_paths, + ) + + def _restore_expanded_directory_paths_from_settings(self) -> None: + raw_paths = self._app.settings.get_value( + self._SETTINGS_SECTION, + self._SETTINGS_EXPANDED_DIRECTORIES, + ) + expanded_paths = self._deserialize_expanded_directory_paths(raw_paths) + self._restore_expanded_directory_paths(expanded_paths) + + def _on_tree_expansion_changed(self, event) -> None: + self._save_expanded_directory_paths_to_settings() + event.Skip() + def _on_tree_item_context_menu(self, event): position = event.GetPosition() if position == wx.DefaultPosition: @@ -771,6 +828,8 @@ def on_delete(self, *args): wx.CallAfter(self._restore_expanded_directory_paths, expanded_paths) def on_exit(self, event): + self._save_expanded_directory_paths_to_settings() + if not self._app.main_frame: self._app.do_exit(event) else: diff --git a/windows/main/controller.py b/windows/main/controller.py index 78a58da..214169e 100755 --- a/windows/main/controller.py +++ b/windows/main/controller.py @@ -36,6 +36,7 @@ from windows.main.tabs.column import TableColumnsController from windows.main.tabs.records import TableRecordsController from windows.main.tabs.database import ListDatabaseTable +from windows.main.tabs.database_options import DatabaseOptionsController from windows.main.tabs.explorer import TreeExplorerController from windows.main.tabs.foreign_key import TableForeignKeyController from windows.main.tabs.view import ViewEditorController @@ -59,6 +60,7 @@ def __init__(self): ) self.list_database_tables = ListDatabaseTable(self.list_ctrl_database_tables) + self.controller_database_options = DatabaseOptionsController(self) self.controller_tree_connections = TreeExplorerController(self.tree_ctrl_explorer) self.controller_tree_connections.on_cancel_table = self.on_cancel_table @@ -280,10 +282,10 @@ def toggle_panel(self, current: Optional[Union[SQLDatabase, SQLTable, SQLView, S def on_page_chaged(self, event): if int(event.Selection) == 5: - if table := CURRENT_TABLE(): + if table := CURRENT_TABLE.get_value(): table.load_records() - self.controller_list_table_records.load_model() + # self.controller_list_table_records.load_model() def _on_current_session(self, session: Session): from structures.session import Session @@ -330,6 +332,119 @@ def _on_current_database(self, database: SQLDatabase): if (session := CURRENT_SESSION.get_value()) and session.engine in [ConnectionEngine.SQLITE]: self.table_collation.Enable(False) + def on_apply_database(self, event: wx.Event): + database = CURRENT_DATABASE.get_value() + session = CURRENT_SESSION.get_value() + + if database is None or session is None: + return + + try: + database.save() + session.context.databases.refresh() + + database = next( + (d for d in session.context.databases.get_value() if d.id == database.id), + None, + ) + + if database is not None: + CURRENT_DATABASE.set_value(None).set_value(database) + session.context.set_database(database) + + except Exception as ex: + logger.error(str(ex), exc_info=True) + wx.MessageDialog(None, str(ex), "Error", wx.OK | wx.ICON_ERROR).ShowModal() + + def on_cancel_database(self, event: wx.Event): + database = CURRENT_DATABASE.get_value() + session = CURRENT_SESSION.get_value() + + if database is None or session is None: + return + + if wx.MessageDialog( + None, + message=_(f"Do you want discard the change to {database.name}?"), + style=wx.YES_NO | wx.YES_DEFAULT | wx.ICON_QUESTION, + ).ShowModal() != wx.ID_YES: + return + + try: + session.context.databases.refresh() + + database = next( + (d for d in session.context.databases.get_value() if d.id == database.id), + None, + ) + + if database is not None: + CURRENT_DATABASE.set_value(None).set_value(database) + session.context.set_database(database) + + except Exception as ex: + logger.error(str(ex), exc_info=True) + wx.MessageDialog(None, str(ex), "Error", wx.OK | wx.ICON_ERROR).ShowModal() + + def on_delete_database(self, event: wx.Event): + database = CURRENT_DATABASE.get_value() + session = CURRENT_SESSION.get_value() + + if database is None or session is None: + return + + choice = wx.MessageDialog( + None, + message=_( + "Do you want to create a dump before dropping database '{database_name}'?\n\n" + "Dump is not implemented yet.\n" + "- Yes: open dump flow (coming soon, no drop).\n" + "- No: drop the database now." + ).format(database_name=database.name), + caption=_("Delete database"), + style=wx.YES_NO | wx.CANCEL | wx.CANCEL_DEFAULT | wx.ICON_WARNING, + ).ShowModal() + + if choice == wx.ID_YES: + wx.MessageBox( + _("Dump is not implemented yet. No action has been performed."), + _("Dump not available"), + wx.OK | wx.ICON_INFORMATION, + ) + return + + if choice != wx.ID_NO: + return + + try: + dropped = database.drop() + + if not dropped: + wx.MessageBox( + _("Database deletion is not supported by this engine."), + _("Delete database"), + wx.OK | wx.ICON_WARNING, + ) + return + + session.context.databases.refresh() + + CURRENT_DATABASE.set_value(None) + next_database = next(iter(session.context.databases.get_value()), None) + if next_database is not None: + CURRENT_DATABASE.set_value(next_database) + session.context.set_database(next_database) + + wx.MessageBox( + _("Database deleted successfully"), + _("Success"), + wx.OK | wx.ICON_INFORMATION, + ) + + except Exception as ex: + logger.error(str(ex), exc_info=True) + wx.MessageDialog(None, str(ex), "Error", wx.OK | wx.ICON_ERROR).ShowModal() + # VIEW def _on_current_view(self, current: SQLView): self.toggle_panel(current) @@ -595,7 +710,7 @@ def on_apply_filters(self, event): filters = (self.sql_query_filters.GetSelectedText() or self.sql_query_filters.GetText()).strip() table.load_records(filters) - self.controller_list_table_records.load_model() + # self.controller_list_table_records.load_model() # def on_clear_record(self, event): # self.controller_list_table_records.on_row_clear() diff --git a/windows/main/tabs/database_options.py b/windows/main/tabs/database_options.py new file mode 100644 index 0000000..034161e --- /dev/null +++ b/windows/main/tabs/database_options.py @@ -0,0 +1,366 @@ +from typing import Optional + +import wx + +from helpers.bindings import AbstractModel +from helpers.observables import Observable, debounce + +from structures.connection import ConnectionEngine + +from windows.main import CURRENT_DATABASE, CURRENT_SESSION + + +class EditDatabaseOptionsModel(AbstractModel): + def __init__(self): + self.database_name = Observable() + self.database_character_set = Observable() + self.database_collation = Observable() + self.database_encryption = Observable(False) + self.database_read_only = Observable(False) + self.database_tablespace = Observable() + self.database_connection_limit = Observable(0) + self.database_password = Observable() + self.database_profile = Observable() + self.database_default_tablespace = Observable() + self.database_temporary_tablespace = Observable() + self.database_quota = Observable() + self.database_unlimited_quota = Observable(False) + self.database_account_status = Observable() + self.database_password_expire = Observable(False) + + debounce( + self.database_name, + self.database_character_set, + self.database_collation, + self.database_encryption, + self.database_read_only, + self.database_tablespace, + self.database_connection_limit, + self.database_password, + self.database_profile, + self.database_default_tablespace, + self.database_temporary_tablespace, + self.database_quota, + self.database_unlimited_quota, + self.database_account_status, + self.database_password_expire, + callback=self._update_database, + ) + + CURRENT_DATABASE.subscribe(self._load_database) + + @staticmethod + def _first_attr(source, names: list[str], default=None): + if source is None: + return default + + for name in names: + if hasattr(source, name): + value = getattr(source, name) + if value is not None: + return value + + return default + + @staticmethod + def _encryption_to_bool(value) -> bool: + if isinstance(value, bool): + return value + + if value is None: + return False + + return str(value).strip().upper() in ["Y", "YES", "TRUE", "1", "ON"] + + def _load_database(self, database) -> None: + self.database_name.set_initial(self._first_attr(database, ["name"], "")) + self.database_collation.set_initial( + self._first_attr(database, ["default_collation", "collation", "collation_name"], "") + ) + + context = database.context if database else None + charset = None + if context and self.database_collation.get_value() and getattr(context, "COLLATIONS", None): + charset = context.COLLATIONS.get(self.database_collation.get_value()) + + self.database_character_set.set_initial( + charset or self._first_attr(database, ["character_set", "charset"], "") + ) + + self.database_encryption.set_initial( + self._encryption_to_bool(self._first_attr(database, ["encryption"], None)) + ) + self.database_read_only.set_initial(bool(self._first_attr(database, ["read_only", "is_read_only"], False))) + self.database_tablespace.set_initial(self._first_attr(database, ["tablespace", "default_tablespace"], "")) + self.database_connection_limit.set_initial(int(self._first_attr(database, ["connection_limit"], 0) or 0)) + self.database_password.set_initial(self._first_attr(database, ["password"], "")) + self.database_profile.set_initial(self._first_attr(database, ["profile"], "")) + self.database_default_tablespace.set_initial(self._first_attr(database, ["default_tablespace"], "")) + self.database_temporary_tablespace.set_initial(self._first_attr(database, ["temporary_tablespace"], "")) + self.database_quota.set_initial(self._first_attr(database, ["quota"], "")) + self.database_unlimited_quota.set_initial(bool(self._first_attr(database, ["unlimited_quota"], False))) + self.database_account_status.set_initial(self._first_attr(database, ["account_status"], "")) + self.database_password_expire.set_initial(bool(self._first_attr(database, ["password_expire"], False))) + + def _update_database(self, *args) -> None: + if not any(arg is not None for arg in args): + return + + database = CURRENT_DATABASE.get_value() + if database is None: + return + + session = CURRENT_SESSION.get_value() + engine = session.engine if session else None + + encryption_value = self.database_encryption.get_value() + if engine in [ConnectionEngine.MYSQL, ConnectionEngine.MARIADB]: + encryption_value = "Y" if bool(encryption_value) else "N" + + if hasattr(database, "name"): + database.name = self.database_name.get_value() + + mapping = { + "character_set": self.database_character_set.get_value(), + "charset": self.database_character_set.get_value(), + "default_collation": self.database_collation.get_value(), + "collation": self.database_collation.get_value(), + "collation_name": self.database_collation.get_value(), + "encryption": encryption_value, + "read_only": self.database_read_only.get_value(), + "is_read_only": self.database_read_only.get_value(), + "tablespace": self.database_tablespace.get_value(), + "default_tablespace": self.database_default_tablespace.get_value(), + "temporary_tablespace": self.database_temporary_tablespace.get_value(), + "connection_limit": self.database_connection_limit.get_value(), + "password": self.database_password.get_value(), + "profile": self.database_profile.get_value(), + "quota": self.database_quota.get_value(), + "unlimited_quota": self.database_unlimited_quota.get_value(), + "account_status": self.database_account_status.get_value(), + "password_expire": self.database_password_expire.get_value(), + } + + for attr, value in mapping.items(): + if hasattr(database, attr): + setattr(database, attr, value) + + +class DatabaseOptionsController: + def __init__(self, parent): + self.parent = parent + self.model = EditDatabaseOptionsModel() + self._panel_by_name = self._build_panel_by_name() + self._panels_all = list(self._panel_by_name.values()) + self._controls_all = self._build_controls_all() + + self._bind_controls() + + CURRENT_SESSION.subscribe(self._on_current_session) + CURRENT_DATABASE.subscribe(self._on_current_database) + + self.apply_for_current_state() + + @staticmethod + def _first_attr(source, names: list[str], default=None): + if source is None: + return default + + for name in names: + if hasattr(source, name): + value = getattr(source, name) + if value is not None: + return value + + return default + + def _apply_choice(self, choice: wx.Choice, items: list[str], selected: Optional[str]) -> None: + normalized = [str(item) for item in items if item is not None and str(item)] + + if selected is not None and str(selected) and str(selected) not in normalized: + normalized.append(str(selected)) + + choice.SetItems(normalized) + + if not normalized: + return + + if selected and choice.SetStringSelection(str(selected)): + return + + choice.SetSelection(0) + + def _apply_engine(self, engine: Optional[ConnectionEngine]) -> None: + panel_names = self._get_panel_names_for_engine(engine) + visible_panels = [self._panel_by_name[name] for name in panel_names] + + self._batch_show_hide(show=visible_panels, hide=self._panels_all) + self._apply_readonly_rules(engine) + self._layout_database_options() + + def _apply_readonly_rules(self, engine: Optional[ConnectionEngine]) -> None: + is_sqlite = engine == ConnectionEngine.SQLITE + + self.parent.database_name.Enable(True) + self.parent.database_name.SetEditable(not is_sqlite) + self._set_controls_enabled(enabled=not is_sqlite) + + def _batch_show_hide(self, show: list[wx.Window], hide: list[wx.Window]) -> None: + show_set = set(show) + for panel in hide: + panel.Show(panel in show_set) + + def _bind_controls(self) -> None: + self.model.bind_controls( + database_name=self.parent.database_name, + database_character_set=self.parent.database_character_set, + database_collation=self.parent.database_collation, + database_encryption=self.parent.database_encryption, + database_read_only=self.parent.database_read_only, + database_tablespace=self.parent.database_tablespace, + database_connection_limit=self.parent.database_connection_limit, + database_password=self.parent.m_textCtrl36, + database_profile=self.parent.database_profile, + database_default_tablespace=self.parent.database_default_tablespace, + database_temporary_tablespace=self.parent.database_temporary_tablespace, + database_quota=self.parent.database_quota, + database_unlimited_quota=self.parent.database_unlimited_quota, + database_account_status=self.parent.database_account_status, + database_password_expire=self.parent.database_password_expire, + ) + + def _build_controls_all(self) -> list[wx.Window]: + return [ + self.parent.database_character_set, + self.parent.database_collation, + self.parent.database_encryption, + self.parent.database_read_only, + self.parent.database_tablespace, + self.parent.database_connection_limit, + self.parent.m_textCtrl36, + self.parent.database_profile, + self.parent.database_default_tablespace, + self.parent.database_temporary_tablespace, + self.parent.database_quota, + self.parent.database_unlimited_quota, + self.parent.database_account_status, + self.parent.database_password_expire, + ] + + def _build_panel_by_name(self) -> dict[str, wx.Window]: + return { + "database_character_set_panel": self.parent.database_character_set_panel, + "database_collation_panel": self.parent.database_collation_panel, + "database_encryption_panel": self.parent.database_encryption_panel, + "database_read_only_panel": self.parent.database_read_only_panel, + "database_tablespace_panel": self.parent.database_tablespace_panel, + "database_connection_limit_panel": self.parent.database_connection_limit_panel, + "database_password_panel": self.parent.database_password_panel, + "database_profile_panel": self.parent.database_profile_panel, + "database_default_tablespace_panel": self.parent.database_default_tablespace_panel, + "database_temporary_tablespace_panel": self.parent.database_temporary_tablespace_panel, + "database_quota_panel": self.parent.database_quota_panel, + "database_unlimited_quota_panel": self.parent.database_unlimited_quota_panel, + "database_account_status_panel": self.parent.database_account_status_panel, + "database_password_expire_panel": self.parent.database_password_expire_panel, + } + + def _get_panel_names_for_engine(self, engine: Optional[ConnectionEngine]) -> list[str]: + if engine in [ConnectionEngine.MYSQL, ConnectionEngine.MARIADB]: + return [ + "database_character_set_panel", + "database_collation_panel", + "database_encryption_panel", + ] + + if engine == ConnectionEngine.POSTGRESQL: + return [ + "database_collation_panel", + "database_tablespace_panel", + "database_connection_limit_panel", + ] + + if engine == ConnectionEngine.ORACLE: + return [ + "database_password_panel", + "database_profile_panel", + "database_default_tablespace_panel", + "database_temporary_tablespace_panel", + "database_quota_panel", + "database_unlimited_quota_panel", + "database_account_status_panel", + "database_password_expire_panel", + ] + + return [] + + def _layout_database_options(self) -> None: + self.parent.m_panel54.Layout() + if parent := self.parent.m_panel54.GetParent(): + parent.Layout() + + def _on_current_database(self, database) -> None: + self.apply_for_current_state() + + def _on_current_session(self, session) -> None: + self.apply_for_current_state() + + def _populate_choices(self, database) -> None: + context = database.context if database else None + + collations = [] + if context and getattr(context, "COLLATIONS", None): + collations = sorted(context.COLLATIONS.keys()) + + charsets = [] + if context and getattr(context, "COLLATIONS", None): + charsets = sorted(set(context.COLLATIONS.values())) + + self._apply_choice( + self.parent.database_character_set, + charsets, + self.model.database_character_set.get_value(), + ) + self._apply_choice( + self.parent.database_collation, + collations, + self.model.database_collation.get_value(), + ) + + self._apply_choice( + self.parent.database_tablespace, + [self._first_attr(database, ["tablespace", "default_tablespace"])], + self.model.database_tablespace.get_value(), + ) + self._apply_choice( + self.parent.database_profile, + [self._first_attr(database, ["profile"])], + self.model.database_profile.get_value(), + ) + self._apply_choice( + self.parent.database_default_tablespace, + [self._first_attr(database, ["default_tablespace"])], + self.model.database_default_tablespace.get_value(), + ) + self._apply_choice( + self.parent.database_temporary_tablespace, + [self._first_attr(database, ["temporary_tablespace"])], + self.model.database_temporary_tablespace.get_value(), + ) + self._apply_choice( + self.parent.database_account_status, + [self._first_attr(database, ["account_status"])], + self.model.database_account_status.get_value(), + ) + + def _set_controls_enabled(self, enabled: bool) -> None: + for control in self._controls_all: + control.Enable(enabled) + + def apply_for_current_state(self) -> None: + session = CURRENT_SESSION.get_value() + database = CURRENT_DATABASE.get_value() + engine = session.engine if session else None + + self._populate_choices(database) + self._apply_engine(engine) diff --git a/windows/views.py b/windows/views.py index 3d49225..eb525bd 100755 --- a/windows/views.py +++ b/windows/views.py @@ -834,6 +834,9 @@ def __init__( self, parent ): self.m_menubar2 = wx.MenuBar( 0 ) self.m_menu2 = wx.Menu() + self.m_menuItem22 = wx.MenuItem( self.m_menu2, wx.ID_ANY, _(u"Settings"), wx.EmptyString, wx.ITEM_NORMAL ) + self.m_menu2.Append( self.m_menuItem22 ) + self.m_menubar2.Append( self.m_menu2, _(u"File") ) self.m_menu4 = wx.Menu() @@ -944,9 +947,327 @@ def __init__( self, parent ): self.m_panel30 = wx.Panel( self.m_notebook6, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.TAB_TRAVERSAL ) bSizer80 = wx.BoxSizer( wx.VERTICAL ) + self.m_splitter7 = wx.SplitterWindow( self.m_panel30, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.SP_3D ) + self.m_panel54 = wx.Panel( self.m_splitter7, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.TAB_TRAVERSAL ) + bSizer158 = wx.BoxSizer( wx.VERTICAL ) + + bSizer159 = wx.BoxSizer( wx.HORIZONTAL ) + + self.m_staticText90 = wx.StaticText( self.m_panel54, wx.ID_ANY, _(u"Name"), wx.DefaultPosition, wx.DefaultSize, 0 ) + self.m_staticText90.Wrap( -1 ) + + self.m_staticText90.SetMinSize( wx.Size( 150,-1 ) ) + + bSizer159.Add( self.m_staticText90, 0, wx.ALIGN_CENTER|wx.ALL, 5 ) + + self.database_name = wx.TextCtrl( self.m_panel54, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0 ) + bSizer159.Add( self.database_name, 1, wx.ALL, 5 ) + + + bSizer158.Add( bSizer159, 0, wx.EXPAND, 5 ) + + bSizer1481111 = wx.BoxSizer( wx.HORIZONTAL ) + + + bSizer158.Add( bSizer1481111, 1, wx.EXPAND, 5 ) + + bSizer142 = wx.BoxSizer( wx.HORIZONTAL ) + + self.database_character_set_panel = wx.Panel( self.m_panel54, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.TAB_TRAVERSAL ) + bSizer139 = wx.BoxSizer( wx.HORIZONTAL ) + + self.m_staticText70 = wx.StaticText( self.database_character_set_panel, wx.ID_ANY, _(u"Character set"), wx.DefaultPosition, wx.DefaultSize, 0 ) + self.m_staticText70.Wrap( -1 ) + + self.m_staticText70.SetMinSize( wx.Size( 150,-1 ) ) + + bSizer139.Add( self.m_staticText70, 0, wx.ALIGN_CENTER|wx.ALL, 5 ) + + database_character_setChoices = [] + self.database_character_set = wx.Choice( self.database_character_set_panel, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, database_character_setChoices, 0 ) + self.database_character_set.SetSelection( 0 ) + bSizer139.Add( self.database_character_set, 1, wx.ALL, 5 ) + + + self.database_character_set_panel.SetSizer( bSizer139 ) + self.database_character_set_panel.Layout() + bSizer139.Fit( self.database_character_set_panel ) + bSizer142.Add( self.database_character_set_panel, 1, wx.ALIGN_CENTER, 5 ) + + self.database_collation_panel = wx.Panel( self.m_panel54, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.TAB_TRAVERSAL ) + bSizer1392 = wx.BoxSizer( wx.HORIZONTAL ) + + self.m_staticText702 = wx.StaticText( self.database_collation_panel, wx.ID_ANY, _(u"Collation"), wx.DefaultPosition, wx.DefaultSize, 0 ) + self.m_staticText702.Wrap( -1 ) + + self.m_staticText702.SetMinSize( wx.Size( 150,-1 ) ) + + bSizer1392.Add( self.m_staticText702, 0, wx.ALIGN_CENTER|wx.ALL, 5 ) + + database_collationChoices = [] + self.database_collation = wx.Choice( self.database_collation_panel, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, database_collationChoices, 0 ) + self.database_collation.SetSelection( 0 ) + bSizer1392.Add( self.database_collation, 1, wx.ALL, 5 ) + + + self.database_collation_panel.SetSizer( bSizer1392 ) + self.database_collation_panel.Layout() + bSizer1392.Fit( self.database_collation_panel ) + bSizer142.Add( self.database_collation_panel, 1, wx.ALIGN_CENTER, 5 ) + + + bSizer158.Add( bSizer142, 0, wx.EXPAND, 5 ) + + bSizer13911 = wx.BoxSizer( wx.HORIZONTAL ) + + self.database_encryption_panel = wx.Panel( self.m_panel54, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.TAB_TRAVERSAL ) + bSizer1391 = wx.BoxSizer( wx.HORIZONTAL ) + + self.database_encryption = wx.CheckBox( self.database_encryption_panel, wx.ID_ANY, _(u"Encryption"), wx.DefaultPosition, wx.DefaultSize, 0 ) + bSizer1391.Add( self.database_encryption, 0, wx.ALL, 5 ) + + + self.database_encryption_panel.SetSizer( bSizer1391 ) + self.database_encryption_panel.Layout() + bSizer1391.Fit( self.database_encryption_panel ) + bSizer13911.Add( self.database_encryption_panel, 1, wx.ALIGN_CENTER, 0 ) + + self.database_read_only_panel = wx.Panel( self.m_panel54, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.TAB_TRAVERSAL ) + bSizer148 = wx.BoxSizer( wx.HORIZONTAL ) + + self.database_read_only = wx.CheckBox( self.database_read_only_panel, wx.ID_ANY, _(u"Read Only"), wx.DefaultPosition, wx.DefaultSize, 0 ) + bSizer148.Add( self.database_read_only, 0, wx.ALIGN_CENTER|wx.ALL, 5 ) + + + self.database_read_only_panel.SetSizer( bSizer148 ) + self.database_read_only_panel.Layout() + bSizer148.Fit( self.database_read_only_panel ) + bSizer13911.Add( self.database_read_only_panel, 1, wx.EXPAND | wx.ALL, 5 ) + + + bSizer158.Add( bSizer13911, 0, wx.EXPAND, 5 ) + + bSizer92 = wx.BoxSizer( wx.HORIZONTAL ) + + self.database_tablespace_panel = wx.Panel( self.m_panel54, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.TAB_TRAVERSAL ) + bSizer13912 = wx.BoxSizer( wx.HORIZONTAL ) + + self.m_staticText7012 = wx.StaticText( self.database_tablespace_panel, wx.ID_ANY, _(u"Tablespace"), wx.DefaultPosition, wx.DefaultSize, 0 ) + self.m_staticText7012.Wrap( -1 ) + + self.m_staticText7012.SetMinSize( wx.Size( 150,-1 ) ) + + bSizer13912.Add( self.m_staticText7012, 0, wx.ALIGN_CENTER|wx.ALL, 5 ) + + database_tablespaceChoices = [] + self.database_tablespace = wx.Choice( self.database_tablespace_panel, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, database_tablespaceChoices, 0 ) + self.database_tablespace.SetSelection( 0 ) + bSizer13912.Add( self.database_tablespace, 1, wx.ALL, 5 ) + + + self.database_tablespace_panel.SetSizer( bSizer13912 ) + self.database_tablespace_panel.Layout() + bSizer13912.Fit( self.database_tablespace_panel ) + bSizer92.Add( self.database_tablespace_panel, 1, wx.ALIGN_CENTER, 5 ) + + self.database_connection_limit_panel = wx.Panel( self.m_panel54, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.TAB_TRAVERSAL ) + bSizer139111 = wx.BoxSizer( wx.HORIZONTAL ) + + self.m_staticText70111 = wx.StaticText( self.database_connection_limit_panel, wx.ID_ANY, _(u"Connection limit"), wx.DefaultPosition, wx.DefaultSize, 0 ) + self.m_staticText70111.Wrap( -1 ) + + self.m_staticText70111.SetMinSize( wx.Size( 150,-1 ) ) + + bSizer139111.Add( self.m_staticText70111, 0, wx.ALIGN_CENTER|wx.ALL, 5 ) + + self.database_connection_limit = wx.SpinCtrl( self.database_connection_limit_panel, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, wx.SP_ARROW_KEYS, 0, 0, 0 ) + bSizer139111.Add( self.database_connection_limit, 1, wx.ALL, 5 ) + + + self.database_connection_limit_panel.SetSizer( bSizer139111 ) + self.database_connection_limit_panel.Layout() + bSizer139111.Fit( self.database_connection_limit_panel ) + bSizer92.Add( self.database_connection_limit_panel, 1, wx.ALIGN_CENTER, 5 ) + + + bSizer158.Add( bSizer92, 0, wx.EXPAND, 5 ) + + bSizer1481 = wx.BoxSizer( wx.HORIZONTAL ) + + self.database_password_panel = wx.Panel( self.m_panel54, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.TAB_TRAVERSAL ) + bSizer139121 = wx.BoxSizer( wx.HORIZONTAL ) + + self.m_staticText70121 = wx.StaticText( self.database_password_panel, wx.ID_ANY, _(u"Password"), wx.DefaultPosition, wx.DefaultSize, 0 ) + self.m_staticText70121.Wrap( -1 ) + + self.m_staticText70121.SetMinSize( wx.Size( 150,-1 ) ) + + bSizer139121.Add( self.m_staticText70121, 0, wx.ALIGN_CENTER|wx.ALL, 5 ) + + self.m_textCtrl36 = wx.TextCtrl( self.database_password_panel, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, wx.TE_PASSWORD ) + bSizer139121.Add( self.m_textCtrl36, 1, wx.ALL, 5 ) + + + self.database_password_panel.SetSizer( bSizer139121 ) + self.database_password_panel.Layout() + bSizer139121.Fit( self.database_password_panel ) + bSizer1481.Add( self.database_password_panel, 1, wx.ALIGN_CENTER, 5 ) + + self.database_profile_panel = wx.Panel( self.m_panel54, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.TAB_TRAVERSAL ) + bSizer1391111 = wx.BoxSizer( wx.HORIZONTAL ) + + self.m_staticText701111 = wx.StaticText( self.database_profile_panel, wx.ID_ANY, _(u"Profile"), wx.DefaultPosition, wx.DefaultSize, 0 ) + self.m_staticText701111.Wrap( -1 ) + + self.m_staticText701111.SetMinSize( wx.Size( 150,-1 ) ) + + bSizer1391111.Add( self.m_staticText701111, 0, wx.ALIGN_CENTER|wx.ALL, 5 ) + + database_profileChoices = [] + self.database_profile = wx.Choice( self.database_profile_panel, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, database_profileChoices, 0 ) + self.database_profile.SetSelection( 0 ) + bSizer1391111.Add( self.database_profile, 1, wx.ALL, 5 ) + + + self.database_profile_panel.SetSizer( bSizer1391111 ) + self.database_profile_panel.Layout() + bSizer1391111.Fit( self.database_profile_panel ) + bSizer1481.Add( self.database_profile_panel, 1, wx.ALIGN_CENTER, 5 ) + + + bSizer158.Add( bSizer1481, 0, wx.EXPAND, 5 ) + + bSizer96 = wx.BoxSizer( wx.HORIZONTAL ) + + self.database_default_tablespace_panel = wx.Panel( self.m_panel54, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.TAB_TRAVERSAL ) + bSizer1391212 = wx.BoxSizer( wx.HORIZONTAL ) + + self.m_staticText701212 = wx.StaticText( self.database_default_tablespace_panel, wx.ID_ANY, _(u"Default tablespace"), wx.DefaultPosition, wx.DefaultSize, 0 ) + self.m_staticText701212.Wrap( -1 ) + + self.m_staticText701212.SetMinSize( wx.Size( 150,-1 ) ) + + bSizer1391212.Add( self.m_staticText701212, 0, wx.ALIGN_CENTER|wx.ALL, 5 ) + + database_default_tablespaceChoices = [] + self.database_default_tablespace = wx.Choice( self.database_default_tablespace_panel, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, database_default_tablespaceChoices, 0 ) + self.database_default_tablespace.SetSelection( 0 ) + bSizer1391212.Add( self.database_default_tablespace, 1, wx.ALL, 5 ) + + + self.database_default_tablespace_panel.SetSizer( bSizer1391212 ) + self.database_default_tablespace_panel.Layout() + bSizer1391212.Fit( self.database_default_tablespace_panel ) + bSizer96.Add( self.database_default_tablespace_panel, 1, wx.ALIGN_CENTER, 5 ) + + self.database_temporary_tablespace_panel = wx.Panel( self.m_panel54, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.TAB_TRAVERSAL ) + bSizer13912121 = wx.BoxSizer( wx.HORIZONTAL ) + + self.m_staticText7012121 = wx.StaticText( self.database_temporary_tablespace_panel, wx.ID_ANY, _(u"Temporary tablespace"), wx.DefaultPosition, wx.DefaultSize, 0 ) + self.m_staticText7012121.Wrap( -1 ) + + self.m_staticText7012121.SetMinSize( wx.Size( 150,-1 ) ) + + bSizer13912121.Add( self.m_staticText7012121, 0, wx.ALIGN_CENTER|wx.ALL, 5 ) + + database_temporary_tablespaceChoices = [] + self.database_temporary_tablespace = wx.Choice( self.database_temporary_tablespace_panel, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, database_temporary_tablespaceChoices, 0 ) + self.database_temporary_tablespace.SetSelection( 0 ) + bSizer13912121.Add( self.database_temporary_tablespace, 1, wx.ALL, 5 ) + + + self.database_temporary_tablespace_panel.SetSizer( bSizer13912121 ) + self.database_temporary_tablespace_panel.Layout() + bSizer13912121.Fit( self.database_temporary_tablespace_panel ) + bSizer96.Add( self.database_temporary_tablespace_panel, 1, wx.ALIGN_CENTER, 5 ) + + + bSizer158.Add( bSizer96, 0, wx.EXPAND, 5 ) + + bSizer14811 = wx.BoxSizer( wx.HORIZONTAL ) + + self.database_quota_panel = wx.Panel( self.m_panel54, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.TAB_TRAVERSAL ) + bSizer1391211 = wx.BoxSizer( wx.HORIZONTAL ) + + self.m_staticText701211 = wx.StaticText( self.database_quota_panel, wx.ID_ANY, _(u"Quota"), wx.DefaultPosition, wx.DefaultSize, 0 ) + self.m_staticText701211.Wrap( -1 ) + + self.m_staticText701211.SetMinSize( wx.Size( 150,-1 ) ) + + bSizer1391211.Add( self.m_staticText701211, 0, wx.ALIGN_CENTER|wx.ALL, 5 ) + + self.database_quota = wx.TextCtrl( self.database_quota_panel, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0 ) + bSizer1391211.Add( self.database_quota, 1, wx.ALL, 5 ) + + + self.database_quota_panel.SetSizer( bSizer1391211 ) + self.database_quota_panel.Layout() + bSizer1391211.Fit( self.database_quota_panel ) + bSizer14811.Add( self.database_quota_panel, 1, wx.ALIGN_CENTER, 5 ) + + self.database_unlimited_quota_panel = wx.Panel( self.m_panel54, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.TAB_TRAVERSAL ) + bSizer13911111 = wx.BoxSizer( wx.HORIZONTAL ) + + self.database_unlimited_quota = wx.CheckBox( self.database_unlimited_quota_panel, wx.ID_ANY, _(u"Unlimited quota"), wx.DefaultPosition, wx.DefaultSize, 0 ) + bSizer13911111.Add( self.database_unlimited_quota, 0, wx.ALIGN_CENTER|wx.ALL, 5 ) + + + self.database_unlimited_quota_panel.SetSizer( bSizer13911111 ) + self.database_unlimited_quota_panel.Layout() + bSizer13911111.Fit( self.database_unlimited_quota_panel ) + bSizer14811.Add( self.database_unlimited_quota_panel, 1, wx.ALIGN_CENTER, 5 ) + + + bSizer158.Add( bSizer14811, 0, wx.EXPAND, 5 ) + + bSizer148111 = wx.BoxSizer( wx.HORIZONTAL ) + + self.database_account_status_panel = wx.Panel( self.m_panel54, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.TAB_TRAVERSAL ) + bSizer13912111 = wx.BoxSizer( wx.HORIZONTAL ) + + self.m_staticText7012111 = wx.StaticText( self.database_account_status_panel, wx.ID_ANY, _(u"Account status"), wx.DefaultPosition, wx.DefaultSize, 0 ) + self.m_staticText7012111.Wrap( -1 ) + + self.m_staticText7012111.SetMinSize( wx.Size( 150,-1 ) ) + + bSizer13912111.Add( self.m_staticText7012111, 0, wx.ALIGN_CENTER|wx.ALL, 5 ) + + database_account_statusChoices = [] + self.database_account_status = wx.Choice( self.database_account_status_panel, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, database_account_statusChoices, 0 ) + self.database_account_status.SetSelection( 0 ) + bSizer13912111.Add( self.database_account_status, 1, wx.ALL, 5 ) + + + self.database_account_status_panel.SetSizer( bSizer13912111 ) + self.database_account_status_panel.Layout() + bSizer13912111.Fit( self.database_account_status_panel ) + bSizer148111.Add( self.database_account_status_panel, 1, wx.ALIGN_CENTER, 5 ) + + self.database_password_expire_panel = wx.Panel( self.m_panel54, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.TAB_TRAVERSAL ) + bSizer139111111 = wx.BoxSizer( wx.HORIZONTAL ) + + self.database_password_expire = wx.CheckBox( self.database_password_expire_panel, wx.ID_ANY, _(u"Password expire"), wx.DefaultPosition, wx.DefaultSize, 0 ) + bSizer139111111.Add( self.database_password_expire, 0, wx.ALIGN_CENTER|wx.ALL, 5 ) + + + self.database_password_expire_panel.SetSizer( bSizer139111111 ) + self.database_password_expire_panel.Layout() + bSizer139111111.Fit( self.database_password_expire_panel ) + bSizer148111.Add( self.database_password_expire_panel, 1, wx.ALIGN_CENTER, 5 ) + + + bSizer158.Add( bSizer148111, 0, wx.EXPAND, 5 ) + + + self.m_panel54.SetSizer( bSizer158 ) + self.m_panel54.Layout() + bSizer158.Fit( self.m_panel54 ) + self.m_panel55 = wx.Panel( self.m_splitter7, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.TAB_TRAVERSAL ) + bSizer154 = wx.BoxSizer( wx.VERTICAL ) + bSizer531 = wx.BoxSizer( wx.HORIZONTAL ) - self.m_staticText391 = wx.StaticText( self.m_panel30, wx.ID_ANY, _(u"Table:"), wx.DefaultPosition, wx.DefaultSize, 0 ) + self.m_staticText391 = wx.StaticText( self.m_panel55, wx.ID_ANY, _(u"Table:"), wx.DefaultPosition, wx.DefaultSize, 0 ) self.m_staticText391.Wrap( -1 ) bSizer531.Add( self.m_staticText391, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5 ) @@ -954,32 +1275,34 @@ def __init__( self, parent ): bSizer531.Add( ( 100, 0), 0, wx.EXPAND, 5 ) - self.btn_insert_table = wx.Button( self.m_panel30, wx.ID_ANY, _(u"Insert"), wx.DefaultPosition, wx.DefaultSize, wx.BORDER_NONE ) + self.btn_insert_table = wx.Button( self.m_panel55, wx.ID_ANY, _(u"Insert"), wx.DefaultPosition, wx.DefaultSize, wx.BORDER_NONE ) self.btn_insert_table.SetBitmap( wx.Bitmap( u"icons/16x16/add.png", wx.BITMAP_TYPE_ANY ) ) bSizer531.Add( self.btn_insert_table, 0, wx.ALL|wx.EXPAND, 2 ) - self.btn_clone_table = wx.Button( self.m_panel30, wx.ID_ANY, _(u"Clone"), wx.DefaultPosition, wx.DefaultSize, wx.BORDER_NONE ) + self.btn_clone_table = wx.Button( self.m_panel55, wx.ID_ANY, _(u"Clone"), wx.DefaultPosition, wx.DefaultSize, wx.BORDER_NONE ) self.btn_clone_table.SetBitmap( wx.Bitmap( u"icons/16x16/table_multiple.png", wx.BITMAP_TYPE_ANY ) ) self.btn_clone_table.Enable( False ) bSizer531.Add( self.btn_clone_table, 0, wx.ALL|wx.EXPAND, 5 ) - self.btn_delete_table = wx.Button( self.m_panel30, wx.ID_ANY, _(u"Delete"), wx.DefaultPosition, wx.DefaultSize, wx.BORDER_NONE ) + self.btn_delete_table1 = wx.Button( self.m_panel55, wx.ID_ANY, _(u"Delete"), wx.DefaultPosition, wx.DefaultSize, wx.BORDER_NONE ) - self.btn_delete_table.SetBitmap( wx.Bitmap( u"icons/16x16/delete.png", wx.BITMAP_TYPE_ANY ) ) - self.btn_delete_table.Enable( False ) + self.btn_delete_table1.SetBitmap( wx.Bitmap( u"icons/16x16/delete.png", wx.BITMAP_TYPE_ANY ) ) + self.btn_delete_table1.Enable( False ) - bSizer531.Add( self.btn_delete_table, 0, wx.ALL|wx.EXPAND, 2 ) + bSizer531.Add( self.btn_delete_table1, 0, wx.ALL|wx.EXPAND, 2 ) bSizer531.Add( ( 0, 0), 1, wx.EXPAND, 5 ) - bSizer80.Add( bSizer531, 0, wx.EXPAND, 5 ) + bSizer154.Add( bSizer531, 0, wx.EXPAND, 5 ) + + bSizer152 = wx.BoxSizer( wx.VERTICAL ) - self.list_ctrl_database_tables = wx.dataview.DataViewCtrl( self.m_panel30, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, 0 ) + self.list_ctrl_database_tables = wx.dataview.DataViewCtrl( self.m_panel55, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, 0 ) self.m_dataViewColumn12 = self.list_ctrl_database_tables.AppendTextColumn( _(u"Name"), 0, wx.dataview.DATAVIEW_CELL_INERT, -1, wx.ALIGN_LEFT, wx.dataview.DATAVIEW_COL_RESIZABLE|wx.dataview.DATAVIEW_COL_SORTABLE ) self.m_dataViewColumn13 = self.list_ctrl_database_tables.AppendTextColumn( _(u"Rows"), 1, wx.dataview.DATAVIEW_CELL_INERT, -1, wx.ALIGN_RIGHT, wx.dataview.DATAVIEW_COL_RESIZABLE|wx.dataview.DATAVIEW_COL_SORTABLE ) self.m_dataViewColumn14 = self.list_ctrl_database_tables.AppendTextColumn( _(u"Size"), 2, wx.dataview.DATAVIEW_CELL_INERT, -1, wx.ALIGN_RIGHT, wx.dataview.DATAVIEW_COL_RESIZABLE|wx.dataview.DATAVIEW_COL_SORTABLE ) @@ -988,16 +1311,63 @@ def __init__( self, parent ): self.m_dataViewColumn17 = self.list_ctrl_database_tables.AppendTextColumn( _(u"Engine"), 5, wx.dataview.DATAVIEW_CELL_INERT, -1, wx.ALIGN_LEFT, wx.dataview.DATAVIEW_COL_RESIZABLE|wx.dataview.DATAVIEW_COL_SORTABLE ) self.m_dataViewColumn19 = self.list_ctrl_database_tables.AppendTextColumn( _(u"Collation"), 6, wx.dataview.DATAVIEW_CELL_INERT, -1, wx.ALIGN_LEFT, wx.dataview.DATAVIEW_COL_RESIZABLE|wx.dataview.DATAVIEW_COL_SORTABLE ) self.m_dataViewColumn18 = self.list_ctrl_database_tables.AppendTextColumn( _(u"Comments"), 7, wx.dataview.DATAVIEW_CELL_INERT, -1, wx.ALIGN_LEFT, wx.dataview.DATAVIEW_COL_RESIZABLE|wx.dataview.DATAVIEW_COL_SORTABLE ) - bSizer80.Add( self.list_ctrl_database_tables, 1, wx.ALL|wx.EXPAND, 5 ) + bSizer152.Add( self.list_ctrl_database_tables, 1, wx.ALL|wx.EXPAND, 5 ) + + + bSizer154.Add( bSizer152, 1, wx.EXPAND, 5 ) + + + self.m_panel55.SetSizer( bSizer154 ) + self.m_panel55.Layout() + bSizer154.Fit( self.m_panel55 ) + self.m_splitter7.SplitHorizontally( self.m_panel54, self.m_panel55, -1 ) + bSizer80.Add( self.m_splitter7, 1, wx.EXPAND, 5 ) + + bSizer138 = wx.BoxSizer( wx.HORIZONTAL ) + + self.btn_cancel_database = wx.Button( self.m_panel30, wx.ID_ANY, _(u"Cancel"), wx.DefaultPosition, wx.DefaultSize, 0 ) + bSizer138.Add( self.btn_cancel_database, 0, wx.ALL, 5 ) + + self.btn_delete_database = wx.Button( self.m_panel30, wx.ID_ANY, _(u"Delete"), wx.DefaultPosition, wx.DefaultSize, 0 ) + bSizer138.Add( self.btn_delete_database, 0, wx.ALL, 5 ) + + self.btn_apply_database = wx.Button( self.m_panel30, wx.ID_ANY, _(u"Apply"), wx.DefaultPosition, wx.DefaultSize, 0 ) + bSizer138.Add( self.btn_apply_database, 0, wx.ALL, 5 ) + + + bSizer80.Add( bSizer138, 0, wx.EXPAND, 5 ) self.m_panel30.SetSizer( bSizer80 ) self.m_panel30.Layout() bSizer80.Fit( self.m_panel30 ) - self.m_notebook6.AddPage( self.m_panel30, _(u"Tables"), False ) + self.m_notebook6.AddPage( self.m_panel30, _(u"Options"), False ) self.m_panel31 = wx.Panel( self.m_notebook6, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.TAB_TRAVERSAL ) + self.m_panel31.Hide() + bSizer82 = wx.BoxSizer( wx.VERTICAL ) + self.m_staticText7011 = wx.StaticText( self.m_panel31, wx.ID_ANY, _(u"MyLabel"), wx.DefaultPosition, wx.DefaultSize, 0 ) + self.m_staticText7011.Wrap( -1 ) + + self.m_staticText7011.SetMinSize( wx.Size( 150,-1 ) ) + + bSizer82.Add( self.m_staticText7011, 0, wx.ALL, 5 ) + + self.m_staticText7011111 = wx.StaticText( self.m_panel31, wx.ID_ANY, _(u"MyLabel"), wx.DefaultPosition, wx.DefaultSize, 0 ) + self.m_staticText7011111.Wrap( -1 ) + + self.m_staticText7011111.SetMinSize( wx.Size( 150,-1 ) ) + + bSizer82.Add( self.m_staticText7011111, 0, wx.ALL, 5 ) + + self.m_staticText70111111 = wx.StaticText( self.m_panel31, wx.ID_ANY, _(u"MyLabel"), wx.DefaultPosition, wx.DefaultSize, 0 ) + self.m_staticText70111111.Wrap( -1 ) + + self.m_staticText70111111.SetMinSize( wx.Size( 150,-1 ) ) + + bSizer82.Add( self.m_staticText70111111, 0, wx.ALL, 5 ) + self.m_panel31.SetSizer( bSizer82 ) self.m_panel31.Layout() @@ -1407,7 +1777,7 @@ def __init__( self, parent ): self.panel_table.SetSizer( bSizer251 ) self.panel_table.Layout() bSizer251.Fit( self.panel_table ) - self.MainFrameNotebook.AddPage( self.panel_table, _(u"Table"), False ) + self.MainFrameNotebook.AddPage( self.panel_table, _(u"Table"), True ) MainFrameNotebookBitmap = wx.Bitmap( u"icons/16x16/table.png", wx.BITMAP_TYPE_ANY ) if ( MainFrameNotebookBitmap.IsOk() ): MainFrameNotebookImages.Add( MainFrameNotebookBitmap ) @@ -1798,7 +2168,7 @@ def __init__( self, parent ): self.panel_records.Bind( wx.EVT_RIGHT_DOWN, self.panel_recordsOnContextMenu ) - self.MainFrameNotebook.AddPage( self.panel_records, _(u"Data"), True ) + self.MainFrameNotebook.AddPage( self.panel_records, _(u"Data"), False ) MainFrameNotebookBitmap = wx.Bitmap( u"icons/16x16/text_columns.png", wx.BITMAP_TYPE_ANY ) if ( MainFrameNotebookBitmap.IsOk() ): MainFrameNotebookImages.Add( MainFrameNotebookBitmap ) @@ -1920,12 +2290,6 @@ def __init__( self, parent ): self.m_panel15.SetSizer( bSizer25 ) self.m_panel15.Layout() bSizer25.Fit( self.m_panel15 ) - self.m_menu3 = wx.Menu() - self.m_menuItem3 = wx.MenuItem( self.m_menu3, wx.ID_ANY, _(u"MyMenuItem"), wx.EmptyString, wx.ITEM_NORMAL ) - self.m_menu3.Append( self.m_menuItem3 ) - - self.m_panel15.Bind( wx.EVT_RIGHT_DOWN, self.m_panel15OnContextMenu ) - self.m_splitter4.SplitVertically( self.m_panel14, self.m_panel15, 320 ) bSizer72.Add( self.m_splitter4, 1, wx.EXPAND, 5 ) @@ -1991,13 +2355,17 @@ def __init__( self, parent ): # Connect Events self.Bind( wx.EVT_CLOSE, self.do_close ) + self.Bind( wx.EVT_MENU, self.on_settings, id = self.m_menuItem22.GetId() ) self.Bind( wx.EVT_MENU, self.on_menu_about, id = self.m_menuItem15.GetId() ) self.Bind( wx.EVT_TOOL, self.do_open_connection_manager, id = self.m_tool5.GetId() ) self.Bind( wx.EVT_TOOL, self.do_disconnect, id = self.m_tool4.GetId() ) self.MainFrameNotebook.Bind( wx.EVT_NOTEBOOK_PAGE_CHANGED, self.on_page_chaged ) self.btn_insert_table.Bind( wx.EVT_BUTTON, self.on_insert_table ) self.btn_clone_table.Bind( wx.EVT_BUTTON, self.on_clone_table ) - self.btn_delete_table.Bind( wx.EVT_BUTTON, self.on_delete_table ) + self.btn_delete_table1.Bind( wx.EVT_BUTTON, self.on_delete_table ) + self.btn_cancel_database.Bind( wx.EVT_BUTTON, self.on_cancel_database ) + self.btn_delete_database.Bind( wx.EVT_BUTTON, self.on_delete_database ) + self.btn_apply_database.Bind( wx.EVT_BUTTON, self.on_apply_database ) self.btn_delete_index.Bind( wx.EVT_BUTTON, self.on_delete_index ) self.btn_clear_index.Bind( wx.EVT_BUTTON, self.on_clear_index ) self.btn_insert_foreign_key.Bind( wx.EVT_BUTTON, self.on_insert_foreign_key ) @@ -2029,6 +2397,9 @@ def __del__( self ): def do_close( self, event ): event.Skip() + def on_settings( self, event ): + event.Skip() + def on_menu_about( self, event ): event.Skip() @@ -2050,6 +2421,15 @@ def on_clone_table( self, event ): def on_delete_table( self, event ): event.Skip() + def on_cancel_database( self, event ): + event.Skip() + + def on_delete_database( self, event ): + event.Skip() + + def on_apply_database( self, event ): + event.Skip() + def on_delete_index( self, event ): event.Skip() @@ -2136,9 +2516,6 @@ def m_splitter6OnIdle( self, event ): self.m_splitter6.SetSashPosition( -300 ) self.m_splitter6.Unbind( wx.EVT_IDLE ) - def m_panel15OnContextMenu( self, event ): - self.m_panel15.PopupMenu( self.m_menu3, event.GetPosition() ) - ########################################################################### ## Class Trash @@ -2212,6 +2589,9 @@ def __init__( self, parent, id = wx.ID_ANY, pos = wx.DefaultPosition, size = wx. self.m_textCtrl10 = wx.TextCtrl( self, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, wx.TE_MULTILINE|wx.TE_RICH|wx.TE_RICH2 ) bSizer129.Add( self.m_textCtrl10, 1, wx.ALL|wx.EXPAND, 5 ) + self.m_textCtrl361 = wx.TextCtrl( self, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, wx.TE_PASSWORD ) + bSizer129.Add( self.m_textCtrl361, 1, wx.ALL, 5 ) + bSizer93.Add( bSizer129, 1, wx.EXPAND, 5 ) @@ -2222,18 +2602,17 @@ def __init__( self, parent, id = wx.ID_ANY, pos = wx.DefaultPosition, size = wx. self.ssh_tunnel_password1 = wx.TextCtrl( self, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, wx.TE_PASSWORD ) bSizer93.Add( self.ssh_tunnel_password1, 1, wx.ALIGN_CENTER|wx.ALL, 5 ) + database_encryption_oldChoices = [] + self.database_encryption_old = wx.Choice( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, database_encryption_oldChoices, 0 ) + self.database_encryption_old.SetSelection( 0 ) + bSizer93.Add( self.database_encryption_old, 1, wx.ALL, 5 ) + bSizer90.Add( bSizer93, 1, wx.EXPAND, 5 ) self.m_collapsiblePane2 = wx.CollapsiblePane( self, wx.ID_ANY, _(u"collapsible"), wx.DefaultPosition, wx.DefaultSize, wx.CP_DEFAULT_STYLE ) self.m_collapsiblePane2.Collapse( False ) - bSizer92 = wx.BoxSizer( wx.VERTICAL ) - - - self.m_collapsiblePane2.GetPane().SetSizer( bSizer92 ) - self.m_collapsiblePane2.GetPane().Layout() - bSizer92.Fit( self.m_collapsiblePane2.GetPane() ) bSizer90.Add( self.m_collapsiblePane2, 1, wx.EXPAND | wx.ALL, 5 ) self.tree_ctrl_sessions = wx.TreeCtrl( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.TR_DEFAULT_STYLE|wx.TR_FULL_ROW_HIGHLIGHT|wx.TR_HAS_BUTTONS|wx.TR_HIDE_ROOT|wx.TR_TWIST_BUTTONS ) @@ -2271,6 +2650,12 @@ def __init__( self, parent, id = wx.ID_ANY, pos = wx.DefaultPosition, size = wx. self.panel_credentials.SetSizer( bSizer48 ) self.panel_credentials.Layout() bSizer48.Fit( self.panel_credentials ) + self.m_menu3 = wx.Menu() + self.m_menuItem3 = wx.MenuItem( self.m_menu3, wx.ID_ANY, _(u"MyMenuItem"), wx.EmptyString, wx.ITEM_NORMAL ) + self.m_menu3.Append( self.m_menuItem3 ) + + self.panel_credentials.Bind( wx.EVT_RIGHT_DOWN, self.panel_credentialsOnContextMenu ) + bSizer51.Add( self.panel_credentials, 0, wx.EXPAND | wx.ALL, 0 ) self.panel_source = wx.Panel( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.TAB_TRAVERSAL ) @@ -2305,15 +2690,6 @@ def __init__( self, parent, id = wx.ID_ANY, pos = wx.DefaultPosition, size = wx. bSizer90.Add( bSizer51, 0, wx.EXPAND, 0 ) - self.m_panel35 = wx.Panel( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.TAB_TRAVERSAL ) - bSizer96 = wx.BoxSizer( wx.VERTICAL ) - - - self.m_panel35.SetSizer( bSizer96 ) - self.m_panel35.Layout() - bSizer96.Fit( self.m_panel35 ) - bSizer90.Add( self.m_panel35, 1, wx.EXPAND | wx.ALL, 5 ) - self.ssh_tunnel_port = wx.TextCtrl( self, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0 ) bSizer90.Add( self.ssh_tunnel_port, 0, wx.ALIGN_CENTER|wx.ALL, 5 ) @@ -2480,6 +2856,16 @@ def __init__( self, parent, id = wx.ID_ANY, pos = wx.DefaultPosition, size = wx. self.filename1 = wx.FilePickerCtrl( self, wx.ID_ANY, wx.EmptyString, _(u"Select a file"), _(u"*.*"), wx.DefaultPosition, wx.DefaultSize, wx.FLP_CHANGE_DIR|wx.FLP_DEFAULT_STYLE|wx.FLP_FILE_MUST_EXIST ) bSizer90.Add( self.filename1, 0, wx.ALL, 5 ) + self.m_textCtrl351 = wx.TextCtrl( self, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0 ) + bSizer90.Add( self.m_textCtrl351, 0, wx.ALL, 5 ) + + self.m_staticText701 = wx.StaticText( self, wx.ID_ANY, _(u"Encryption"), wx.DefaultPosition, wx.DefaultSize, 0 ) + self.m_staticText701.Wrap( -1 ) + + self.m_staticText701.SetMinSize( wx.Size( 150,-1 ) ) + + bSizer90.Add( self.m_staticText701, 0, wx.ALIGN_CENTER|wx.ALL, 5 ) + self.SetSizer( bSizer90 ) self.Layout() @@ -2511,6 +2897,9 @@ def rad_view_constraintOnContextMenu( self, event ): def tree_ctrl_sessionsOnContextMenu( self, event ): self.tree_ctrl_sessions.PopupMenu( self.m_menu12, event.GetPosition() ) + def panel_credentialsOnContextMenu( self, event ): + self.panel_credentials.PopupMenu( self.m_menu3, event.GetPosition() ) + def TrashOnContextMenu( self, event ): self.PopupMenu( self.m_menu11, event.GetPosition() )