{"id":28580931,"url":"https://github.com/techsenger/tabshell","last_synced_at":"2025-06-26T16:09:32.722Z","repository":{"id":296624499,"uuid":"936262459","full_name":"techsenger/tabshell","owner":"techsenger","description":"Techsenger TabShell is a lightweight platform for building tab-based applications in JavaFX using the MVVM pattern.","archived":false,"fork":false,"pushed_at":"2025-06-11T20:58:16.000Z","size":6748,"stargazers_count":20,"open_issues_count":0,"forks_count":2,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-06-20T05:14:03.200Z","etag":null,"topics":["javafx","javafx-application","javafx-component","javafx-components","javafx-desktop-app","javafx-desktop-apps","javafx-gui","javafx-library","javafx-project","mvvm","mvvm-architecture","mvvm-pattern"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/techsenger.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null},"funding":{"github":"techsenger"}},"created_at":"2025-02-20T19:43:04.000Z","updated_at":"2025-06-11T20:58:19.000Z","dependencies_parsed_at":"2025-06-01T10:49:35.376Z","dependency_job_id":"f627ce27-a6c5-4fd8-939d-222d00def65b","html_url":"https://github.com/techsenger/tabshell","commit_stats":null,"previous_names":["techsenger/tabshell"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/techsenger/tabshell","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/techsenger%2Ftabshell","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/techsenger%2Ftabshell/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/techsenger%2Ftabshell/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/techsenger%2Ftabshell/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/techsenger","download_url":"https://codeload.github.com/techsenger/tabshell/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/techsenger%2Ftabshell/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":262099716,"owners_count":23258668,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["javafx","javafx-application","javafx-component","javafx-components","javafx-desktop-app","javafx-desktop-apps","javafx-gui","javafx-library","javafx-project","mvvm","mvvm-architecture","mvvm-pattern"],"created_at":"2025-06-11T04:14:27.575Z","updated_at":"2025-06-26T16:09:32.676Z","avatar_url":"https://github.com/techsenger.png","language":"Java","funding_links":["https://github.com/sponsors/techsenger"],"categories":["Frameworks"],"sub_categories":[],"readme":"# Techsenger TabShell\n\n| Support the Project! |\n|:-------------|\n| This project is open-source and free to use, both commercially and non-commercially, which is why we need your help in its development. If you like it, please give it a star ⭐ on GitHub — it helps others discover the project and increases its visibility. You can also contribute, for example, by fixing bugs 🐛 or suggesting improvements 💡, see [Contributing](#contributing). If you can, financial support 💰 is always appreciated, see [Support Us](#support-us). Thank you! |\n\n## Table of Contents\n* [Overview](#overview)\n* [Demo](#demo)\n    * [Text Editor](#demo-text-editor)\n    * [Hex Editor](#demo-hex-editor)\n    * [Terminal](#demo-terminal)\n    * [Dialogs](#demo-dialogs)\n* [Features](#features)\n* [Requirements](#requirements)\n* [Modules](#modules)\n* [Dependencies](#dependencies)\n* [Usage](#usage)\n    * [Quick Start](#usage-quick-start)\n    * [Component](#usage-component)\n    * [Shell](#usage-shell)\n    * [Tab](#usage-tab)\n    * [Dialog](#usage-dialog)\n* [Code building](#code-building)\n* [Running Demos](#running-demos)\n    * [Core Demo](#running-core-demo)\n    * [Full Demo](#running-full-demo)\n* [License](#license)\n* [Contributing](#contributing)\n* [👉 Support Us](#support-us)\n\n## Overview \u003ca name=\"overview\"\u003e\u003c/a\u003e\n\nTechsenger TabShell is a lightweight platform for building tab-based applications in JavaFX using the MVVM pattern.\n\nThe platform consists of two parts: the core and ready-made components. The core includes the core shell and classes\nfor creating components. Ready-made components are used as needed and significantly reduce the development time of the\nfinal application.\n\n## Demo \u003ca name=\"demo\"\u003e\u003c/a\u003e\n\n### Text Editor \u003ca name=\"demo-text-editor\"\u003e\u003c/a\u003e\n\n![TabShell Text Editor](https://github.com/user-attachments/assets/42b61472-3ce6-4309-91fe-8ecd188f494f)\n\n### Hex Editor (In Progress) \u003ca name=\"demo-hex-editor\"\u003e\u003c/a\u003e\n\n![Screenshot from 2025-06-11 23-30-02](https://github.com/user-attachments/assets/13fd4345-db82-40d1-b79a-b71341c90a09)\n\n### Terminal \u003ca name=\"demo-terminal\"\u003e\u003c/a\u003e\n\n![Screenshot from 2025-06-11 23-53-30](https://github.com/user-attachments/assets/d7be0f9f-38ba-4e0f-aa75-23ed830c7f60)\n\n### Dialogs \u003ca name=\"demo-dialogs\"\u003e\u003c/a\u003e\n\n![TabShell Dialogs](https://github.com/user-attachments/assets/83be533a-08fb-437a-aeb7-38b48ebe2291)\n\n## Features \u003ca name=\"features\"\u003e\u003c/a\u003e\n\nKey features of TabShell include:\n\n* Abstract classes to simplify component development.\n* Dynamically configurable menu.\n* Ability to preserve component history.\n* Support for dialogs with two scopes — shell and tab.\n* Window styling that matches the theme.\n* Support for 7 themes (4 dark and 3 light).\n* Styling with CSS.\n\nCurrently, TabShell contains the following ready-made components:\n\n* Terminal.\n* Text Viewer/Editor.\n* Dialogs.\n\n## Requirements \u003ca name=\"requirements\"\u003e\u003c/a\u003e\n\nThe library requires Java 17 or later. Due to some bugs, use JavaFX versions 19–20, or a version of JavaFX after\n24-ea+19 (see JDK-8344372).\n\n## Modules\u003ca name=\"modules\"\u003e\u003c/a\u003e\n\nThe platform consists of the following modules:\n\n* Material — provides UI elements (menus, text areas, etc.) and supporting classes.\n* Core — includes the shell itself, base classes for component development, settings, and core utility classes.\nIf you don't plan to use ready-made components, just two modules (material and core) are sufficient to run TabShell\nand develop custom components. See [Core Demo](#running-core-demo) for details.\n* Tabs — offers abstract components for creating tabs with various layouts.\n* Storage — contains classes to interact with storage systems that are not natively recognized by the operating system\n(such as Google Drive, Dropbox, FTP, and similar). At the same time, the module only includes implementations for\nworking with the OS's default storage systems.\n* Dialogs — provides ready-to-use dialogs: alert, file chooser, confirmation etc.\n* Text — contains text viewer and editor components.\n* Hex — contains hex editor.\n* Terminal — includes a terminal emulator component.\n* Registrars — provides default registrars (for menu items, etc.).\n* Icons — contains the Material Design Icons font and module-specific stylesheets that utilize these icons. To use\ncustom icons instead, simply create your own stylesheets and add them to Shell.\n* Core Demo — showcases TabShell's core functionality and provides examples for building custom components. This demo\nonly requires the material and core modules.\n* Full Demo — showcases the complete platform with all components. This comprehensive demo uses all modules.\n\n## Dependencies \u003ca name=\"dependencies\"\u003e\u003c/a\u003e\n\nThis project is available on Maven Central.\n\n## Usage \u003ca name=\"usage\"\u003e\u003c/a\u003e\n\n### Quick Start \u003ca name=\"usage-quick-start\"\u003e\u003c/a\u003e\nTo get started with TabShell, it is recommended to follow these steps:\n\n1. Familiarize yourself with the [mvvm4fx](https://github.com/techsenger/mvvm4fx) framework and its sampler.\n2. Explore and run core demo. See [Core Demo](#running-core-demo) for details.\n3. Explore and run full demo. See [Full Demo](#running-full-demo) for details.\n\n### Component \u003ca name=\"usage-component\"\u003e\u003c/a\u003e\n\nThe component is the main building block for creating an application using this platform. There are the following\ntypes of components:\n\n* [Shell](#usage-shell) component.\n* [Tab](#usage-tab) component.\n* [Dialog](#usage-dialog) component.\n* Page component, which represents a titled component that can be selected.\n* Pane component, which represents a rectangular area.\n* Node component, which is used for the simplest and smallest elements.\n\nWhen working with components, there are a few key points to remember:\n\n1. A component is initialized manually (by calling the `initialize()` method) and deinitialized automatically (by\ncalling the `deinitialize()` method). This is because the developer may need to perform certain actions with the\ncomponent after initialization but before passing it to the parent component.\n\n2. The following components can be closed: `Shell`, `ShellTab`, `Tab`, `Dialog`. Each of these components has\na `requestClose()` method in its `ViewModel` and a `close()` method in its `View`. In all components, when the\n`ViewModel#requestClose()` method is called, it triggers the `View#close()` method via a listener.\n\n### Shell \u003ca name=\"usage-shell\"\u003e\u003c/a\u003e\n\n`Shell` is the main component and it is responsible for the following tasks:\n\n* Window management.\n* Dynamic menu management.\n* Shell tab management.\n* Shell-scoped dialog management.\n* Theme management.\n\n`Shell` core doesn't have any business logic. It is only a shell for tabs that contain logic.\n\nWorking with the main menu of the `Shell` is carried out in two directions:\n\n1. Configuring menu elements\n2. Managing the state of elements and responding to user actions\n\nThe configuration of menu elements is performed dynamically and in any order, with the final result being unknown in\nadvance. This feature is crucial in cases where plugins/extensions are used, as they can be added/removed dynamically by\nthe user. Each plugin may introduce its own menu items and interact with existing menus. Therefore, it is impossible\nto predict the final structure of the menu that the user will work with.\n\nThe implementation of this feature is structured as follows. There are three key elements: the menu, the group, and the\nitem. Each element has its own key, which is used for identification. A menu consists of groups separated by a\nseparator. Items are added to groups, and empty groups are ignored. All three elements are registered/unregistered in\nthe `ControlRegistry`. When the menu needs to be updated, this `ControlRegistry` is used by `Shell` to construct\nthe final menu.\n\nThe `MenuManager` is responsible for managing the state of menu elements and responding to their actions. It interacts\nwith a component that implements the `MenuAware` interface. This interface is implemented by `Shell`, `ShellTab`,\n`Tab` and `TabManager`. If all tabs are closed, `MenuManager` interacts with `Shell`. When tabs are present,\n`MenuManager` interacts with the currently selected tab.\n\nIt is also important to remember that the `MenuManager` also interacts with MenuAware when the user uses accelerators.\n\nTo gain a complete understanding of working with the menu, it is recommended to familiarize yourself with the\n`MenuAware` interface, experiment with the menu in the demo, and pay attention to log messages at the debug level.\n\nRegarding `Shell` closure, it should be noted that as the top-level component (i.e., having no parent component),\n`Shell` is unique in self-managing its own closure process (whereas all other components are closed by their\nparent components).\n\n### Tab \u003ca name=\"usage-tab\"\u003e\u003c/a\u003e\n\nThere are two types of tabs: `ShellTab` and `Tab`. A `ShellTab` component can be opened through the `Shell`, so\n`ShellTab` components are second-level components under the `Shell`. `ShellTab` manages tab-scoped dialogs.\n\nA `Tab` component cannot be opened directly through the `Shell`, so it always resides inside a `ShellTab`.\n\nThe `ShellTab` a `Tab` components are closed in the following way. When the `View#close()` method is called, control is\ntransferred to their parent component (e.g., `Shell`, `TabManager`), which is responsible for their actual closure.\nThus, these tabs can also be closed directly through their parent if a reference to the tab is available.\n\nThe tab closing procedure is largely determined by the asynchronous nature of dialogs in the TabShell project and\nconsists of the following steps:\n\n1. The parent component calls the tab's `boolean View#doOnCloseAttempt(CloseScope, Runnable)` method.\n2. By default, this method calls two ViewModel methods: `ViewModel#isReadyToClose()` and\n`ViewModel#prepareForClose(CloseScope, Runnable)`:\n\n```\nboolean onCloseAttempt(CloseScope scope, Runnable retryCallback) {\n    if (getViewModel().isReadyToClose()) {\n        return true;\n    } else {\n        getViewModel().prepareForClose(scope, retryCallback);\n        return false;\n    }\n}\n```\n3. If `ViewModel#prepareForClose(CloseScope, Runnable)` successfully prepares the component for closure, it invokes\nthe provided callback to restart the closing process. If preparation fails, the closing process is silently aborted.\n\n### Dialog \u003ca name=\"usage-dialog\"\u003e\u003c/a\u003e\n\nAll dialogs in TabShell are `inline`, `asynchronous` and have a `scope` that affects what will be blocked when the\ndialog is open.\n\nInline dialogs are UI elements that appear embedded within the current application window, typically overlaid on top\nof the existing content with a semi-transparent backdrop to focus attention. They are contextually tied to a specific\nsection (e.g., a tab or component) and do not create a separate OS-level window. In contrast, [modal] window dialogs\n(or native dialogs) open as standalone OS-managed windows with their own frames and system controls, completely\nindependent of the parent UI.\n\nAsynchronous dialogs allow the program to continue running while the dialog is open, relying on callbacks, promises,\nor event listeners. These avoid UI freezes and enable background tasks but require handling user responses indirectly,\noften via lambda functions or observable states. Synchronous dialogs, conversely, block the application's execution\nflow until the user responds, pausing all other interactions (e.g., showAndWait() in JavaFX). They simplify code logic\nby enforcing a linear sequence but risk freezing the UI during operation. The key distinction lies in control flow:\nasynchronous dialogs prioritize responsiveness, deferring action until the user completes the interaction, while\nsynchronous ones enforce immediate resolution. Modern UI design increasingly favors async approaches for scalability\nand user experience.\n\nThere are two types of scope: `Shell` and `Tab`. If a dialog has a `Shell` scope, the user will not be able to do\nanything in `Shell` while this dialog is displayed until it is closed. If a dialog has a `Tab` scope, only the\ntab that triggered the dialog will be blocked when it is displayed. All other tabs, the main menu, etc., will be\navailable to the user.\n\nDialogs are invoked from the `ViewModel` using `ComponentHelper`.\n\nThe `Dialog` component is closed in the following way. When the `View#close()` method is called on a `Dialog`, control\nis delegated to the `DialogManager`, which handles its actual closure. Therefore, a `Dialog` can also be closed\ndirectly through the `DialogManager` when holding a reference to the dialog instance.\n\n## Code Building \u003ca name=\"code-building\"\u003e\u003c/a\u003e\n\nTo build the library use standard Git and Maven commands:\n\n    git clone https://github.com/techsenger/tabshell\n    cd tabshell\n    mvn clean install\n\n## Running Demos \u003ca name=\"running-demos\"\u003e\u003c/a\u003e\n\nThe project provides two demo applications:\n\n* Core Demo — showcases TabShell basics (material and core modules) including shell operation and custom component\ndevelopment.\n* Full Demo — demonstrates the complete platform with all components, featuring pre-built tabs, dialogs, text editor,\nterminal emulator, and other ready-to-use components.\n\n### Core Demo \u003ca name=\"running-core-demo\"\u003e\u003c/a\u003e\n\nTo run the demo, execute the following commands in the project root:\n\n    cd tabshell-demos/tabshell-demos-core\n    mvn javafx:run\n\nPlease note, that debugger settings are in `pom.xml` file.\n\n### Full Demo \u003ca name=\"running-full-demo\"\u003e\u003c/a\u003e\n\nTo run the demo, execute the following commands in the project root:\n\n    cd tabshell-demos/tabshell-demos-full\n    mvn javafx:run\n\nPlease note, that debugger settings are in `pom.xml` file.\n\n## License \u003ca name=\"license\"\u003e\u003c/a\u003e\n\nTechsenger TabShell is licensed under the Apache License, Version 2.0.\n\n## Contributing \u003ca name=\"contributing\"\u003e\u003c/a\u003e\n\nWe welcome all contributions. You can help by reporting bugs, suggesting improvements, or submitting pull requests\nwith fixes and new features. If you have any questions, feel free to reach out — we’ll be happy to assist you.\n\n## 👉 Support Us \u003ca name=\"support-us\"\u003e\u003c/a\u003e\n\nYou can support us financially through [GitHub Sponsors](https://github.com/sponsors/techsenger). Your\ncontribution directly helps us keep our open-source projects active, improve their features, and offer ongoing support.\nBesides, we offer multiple sponsorship tiers, with different rewards.\n\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftechsenger%2Ftabshell","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftechsenger%2Ftabshell","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftechsenger%2Ftabshell/lists"}