Desktop Client Shell
Module: suredms-desktop-client
Source root: SC/suredms-desktop-client/src/main/java/com/sureclinical/suredms/
This module is the primary entry point and UI shell for the Java desktop application. It owns the application lifecycle, Swing frame, login flow, ribbon navigation, all named views, the gadget docking framework, the wizard framework, 30+ ribbon actions, and all desktop dialogs.
Purpose
The shell acts as the host process. It initializes the JVM environment, creates the DesktopClient application singleton, mounts views into the docked frame, and coordinates module transitions via NavigationHelper. All feature-specific behavior — quality review, signing, document navigation — is delegated to gadgets and views within this shell or to the quality/signing modules.
Package Structure
| Package | Contents |
|---|---|
com.sureclinical.suredms | BaseLauncher, BaseEntryPoint — startup entry points |
com.sureclinical.suredms.ui | DesktopClient, NavigationHelper, LoginType, SharedResources, UiExceptionHelper |
com.sureclinical.suredms.ui.views | Named views: HomeView, ViewView, AcquireView, ShareView |
com.sureclinical.suredms.ui.ribbon | RibbonMenu, RibbonPanel, TaskBar, ribbon button types |
com.sureclinical.suredms.ui.gadgets | BaseGadget, GadgetPane, GadgetDocNav, GadgetMetadata, GadgetDocQueue, stream gadgets, charts |
com.sureclinical.suredms.ui.wizard | WizardBuilder, WizardDialog, WizardStep, upload/sign/compliance/imaging wizard implementations |
com.sureclinical.suredms.ui.actions | 30+ BaseAction subclasses wired to ribbon menu items |
com.sureclinical.suredms.ui.dialogs | 40+ dialogs for documents, users, organizations, study, system settings |
com.sureclinical.suredms.permissions | DocumentPermissionsHelper, FolderPermissionsHelper |
com.sureclinical.suredms.security | DigitalIdVerificationDialog, license dialogs, VerificationServiceImpl |
com.sureclinical.suredms.services.job | JobManager, UiThreadPool, JobFactory |
com.sureclinical.suredms.ui.search | SearchEngineWrapper, quick-find support |
Startup Sequence
BaseLauncher
SC/suredms-desktop-client/src/main/java/com/sureclinical/suredms/BaseLauncher.java
Two static initializers run before the constructor:
PreferencesUtils.initFolders()— creates working directories; must run first to enablelog4j.DeploymentUtils.applyAllWorkarounds()— applies platform rendering workarounds; on macOS, sets the dock icon viacom.apple.eawt.Applicationreflection.
The constructor then:
- Installs a global
UncaughtExceptionHandler(suppressesThreadDeathin pool workers). - Logs JVM version, heap size, and runtime arguments via
RuntimeMXBean. - Reads command-line arguments into a parameter map.
- Uses JFreeChart's
ChartFactorywith an emptyXYSeriesCollectionto pre-warm chart rendering. - Creates a
BaseEntryPointand hands control to theApplicationframework.
BaseEntryPoint
SC/suredms-desktop-client/src/main/java/com/sureclinical/suredms/BaseEntryPoint.java
Extends JApplet — the desktop client still uses the applet lifecycle model for parameter passing. It is a singleton:
getInstance()returns the current entry-point instance; in test mode returns an anonymous stub.getParameter(String key)first checks the command-line parameter map, then falls back to hardcoded defaults:serviceHost = http://127.0.0.1:8080,servicePath = /nuxeo/site/automation-ext.getCodeBase()returns afile:/URL pointing to the current working directory.destroy()callsDesktopClient.getInstance().exit()and clears the singleton.
DesktopClient
SC/suredms-desktop-client/src/main/java/com/sureclinical/suredms/ui/DesktopClient.java
Extends org.jdesktop.application.Application. The central singleton.
Key constants and fields:
| Field | Value / Type | Purpose |
|---|---|---|
MAX_NUMBER_OF_ACTIVE_ARCHIVES | 5 | Hard cap on concurrently open archives |
isOnline | boolean | Live connection state |
isLocked | volatile boolean | Lock-screen state |
user | User | Authenticated desktop user |
ribbonMenu | RibbonMenu | Top navigation ribbon |
enabledModules | Set<String> | Feature-flag module keys |
loginAs | SharedLoginRecord | Support for shared login |
bookmarkFile | File | Bookmark opened on startup (-open) |
Lifecycle events use an EventListenerList of DesktopClientEventListener. On login the client:
- Starts an
AutoLogoutThreadand aUserNotificationMonitorThread. - Installs a
KeyEventDispatcherthat intercepts Ctrl+G to openGettingStartedDialog.
On logout the client tears down both background threads via interrupt() and calls afterLogout().
Feature gating is implemented via isFeatureEnabled(String featureKey), checked by RibbonMenu.hasPermission(featureKey).
Views
All views extend BaseView, which extends GadgetPanel and implements DesktopClientEventListener. Each view:
- Has a static
IDconstant used byAbstractDesktopClientContentPanel.setSelectedView(id). - Registers for login/logout events and calls
destroy()on logout (nulling all gadget references). - Persists gadget layout per user via
PreferencesUtilsunderuser.custom.ui.<loginName>.<viewName>.<gadgetName>. - Uses
CGridfrom Bibliothek DockingFrames to position gadgets.
HomeView
SC/suredms-desktop-client/src/main/java/com/sureclinical/suredms/ui/views/HomeView.java
The application dashboard after login. Hosts:
| Gadget | Type | Purpose |
|---|---|---|
gadgetAnnouncements | GadgetArticleViewer | System announcements |
gadgetEvents | GadgetArticleViewer | Upcoming events |
gadgetArticles | GadgetArticleViewer | News/articles |
gadgetDocumentsOverTime | GadgetChartDocumentsOverTime | Document volume trend chart |
gadgetDocumentsByStudy | GadgetChartDocumentsByStudy | Per-study document count chart |
gadgetStreamGeneratedReports | GadgetStreamGeneratedReports | Recent generated reports |
gadgetStreamModifiedDocuments | GadgetStreamModifiedDocuments | Recently modified documents |
gadgetStreamModifiedWorkflows | GadgetStreamModifiedWorkflows | Active workflow changes |
gadgetStreamOverdueWorkflows | GadgetStreamOverdueWorkflows | Overdue workflow items |
gadgetRequiredDocuments | GadgetRequiredDocuments | Required document compliance |
gadgetExpiredDocuments | GadgetExpiredDocuments | Expiring/expired documents |
gadgetDocumentsByMilestone | GadgetDocumentsByMilestone | Milestone-based document view |
gadgetStreamUserAuditTrail | GadgetStreamUserAuditTrail | Recent user audit trail |
gadgetWorkflowStatusCharts | GadgetWorkflowStatusCharts | Workflow status summary charts |
ViewView
SC/suredms-desktop-client/src/main/java/com/sureclinical/suredms/ui/views/ViewView.java
The primary document browsing view. Hosts:
| Gadget | Purpose |
|---|---|
GadgetDocNav | Document navigator tree/table with multiple view modes |
GadgetMetadata (viewer mode) | Read-only metadata panel |
GadgetMetadata (editor mode) | Editable metadata panel |
GadgetDocumentWorkflows | Workflow status and actions for the selected document |
GadgetStack | Stacked viewer area |
GadgetIcePDFViewer | In-process PDF renderer |
GadgetThumbnailsView | Page thumbnail strip |
GadgetDocDiscrepancyView | Inline discrepancy display for the selected document |
NavigationHelper (SC/suredms-desktop-client/src/main/java/com/sureclinical/suredms/ui/NavigationHelper.java) is a static utility class that provides all programmatic navigation within the desktop shell. All calls are dispatched via SwingUtilities.invokeLater (except displayInAcquireView, which is synchronous).
| Method | Description |
|---|---|
switchToViewView() | Sets the selected view to ViewView.ID |
switchToViewViewByCategory() | Switches to ViewView and activates DocNavViewMode.BY_CATEGORY |
switchToViewViewByReports() | Switches to ViewView and activates DocNavViewMode.BY_REPORTS |
displayInViewView(DocSearchFilter) | Navigates to ViewView and applies the given search filter |
displayInViewView(Bookmark) | Navigates to ViewView and calls displayBookmark |
displayInViewView(BaseEntity) | Navigates to ViewView (BY_CATEGORY) and calls displayEntity |
displayInViewView(Document) | Navigates to ViewView; uses BY_REPORTS for report documents, BY_CATEGORY otherwise |
displayInViewView(ContentType) | Navigates to ViewView (BY_CATEGORY) and displays the content type |
switchToWorkflowView() | Switches to "WorkflowPlatformView" or "WorkflowView" based on the WorkflowGlobalParameters.WORKFLOW_PLATFORM_ENABLED feature flag |
displayInWorkflowView(Object) | Switches to the workflow view and calls baseView.activateObject(object) |
displayInAcquireView(Document) | Switches to "AcquireView" and calls AcquireView.getInstance().displayDocument(document); returns boolean success |
A static VIEW_REPORT_CALLBACK field holds a ReportCallback that calls displayInViewView(report) — used by report generation to auto-navigate on completion.
AcquireView
SC/suredms-desktop-client/src/main/java/com/sureclinical/suredms/ui/views/AcquireView.java
The acquire queue view. A singleton (AcquireView.getInstance()). Hosts:
| Gadget | Purpose |
|---|---|
GadgetDocQueue | Document acquire queue with popup menu handler |
GadgetDocNav | Document navigator with popup menu handler |
GadgetIcePDFViewer | PDF viewer for selected queue item |
GadgetMetadata | Metadata panel for selected document |
ShareView
SC/suredms-desktop-client/src/main/java/com/sureclinical/suredms/ui/views/ShareView.java
The share/collaboration view. Hosts GadgetShareNavigation and GadgetSharePreview.
Ribbon and Actions
RibbonMenu is an abstract class that extends AbstractAction. Concrete subclasses define the dropdown menus for each ribbon button group.
Key design points:
hasPermission(featureKey)delegates toDesktopClient.getInstance().isFeatureEnabled(featureKey).onArchiveOpened(Archive)andonArchiveClosed(Archive)let each menu react to archive lifecycle changes.- Menu items are created lazily:
initMenu()runs once on first click;refreshMenu()runs on every open to update enabled state.
Action classes in com.sureclinical.suredms.ui.actions (all extend BaseAction):
| Action | Description |
|---|---|
ActionOpenArchiveFromNetwork | Opens a remote Nuxeo archive |
ActionOpenArchiveFromFile | Opens a local XML archive file |
ActionSaveArchiveToFile / ActionSaveSureDriveToFile | Exports archive to file |
ActionDeleteArchive / ActionDeleteSureDrive | Deletes the active archive |
ActionLockArchive / ActionLockSureDrive | Locks archive |
ActionExportStudyContentModel / ActionExportSureDriveContentModel | Exports CME |
ActionArchiveSetup / ActionSureDriveSetup | Opens properties/setup dialogs |
ActionQualityAssurance | Opens quality assurance setup dialog |
ActionPublish | Publishes documents |
ActionPdfTool | Opens PDF tools |
ActionMedicalImageUpload / ActionMedicalImageEditor | Imaging workflows |
ActionUserAccount / ActionUserProfile / ActionUserSettings | User management |
ActionSendAlertToUsers / ActionSendMessageToUsers | Messaging |
ActionShowArticles / ActionShowDrafts | Article/draft browsing |
ActionHelp / ActionAbout / ActionExit | Application actions |
Wizard Framework
Base class: SC/suredms-desktop-client/src/main/java/com/sureclinical/suredms/ui/wizard/WizardBuilder.java
WizardBuilder provides:
- Configurable dialog title, header, and description via
initDialogHeader(resourceKey). - Step sequencing via
createWizardSteps()→List<WizardStep>. - Forward/back navigation with per-step validation.
- Escape-key cancellation, confirmation dialog via
cancelQuestion. earlyFinishSupportedflag for wizards that allow skipping remaining steps.DialogResultListenercallback set called afterperformWizardAction().- Dependency injection via
Injector.inject(this). - Leak detection via
LeakDetector.getInstance().watch(this).
Wizard implementations:
| Wizard | Steps | Trigger |
|---|---|---|
UploadWizardBuilder | Select files → Confirm upload | Ribbon upload action |
SignLocalFileWizardBuilder | Select file → Sign → Download signed file | Sign local file action |
AuditWizardBuilder | Select study → Select content → Sample size → Create list | Quality ribbon |
RequiredDocumentWizardBuilder | Select milestone → Required document | Compliance workflow |
Permissions
DocumentPermissionsHelper and FolderPermissionsHelper (in com.sureclinical.suredms.permissions) implement permission checks at the document and folder level. Both are consulted by ribbon actions and popup menus to determine which operations to enable.
Background Services
JobManager (SC/suredms-desktop-client-connector/src/main/java/com/sureclinical/suredms/services/job/JobManager.java) is a singleton thread-pool based job queue in the connector module. It schedules and tracks AbstractJob and AbstractProgressJob instances:
- All long-running operations (uploads, exports, syncs) run as jobs.
UiThreadPooldispatches results back to the Swing EDT.JobFactory(suredms-desktop-client/services/job/JobFactory.java) creates typed job instances — it is separate fromJobManagerand lives in the shell module.JobManagerListener(connector) andJobManagerEventsubscribe to and describe job completion events.
JobManager is retrieved via ServiceProvider.getService(JobManager.class) — it does not have a traditional static singleton getInstance() pattern.
The AutoLogoutThread watches for inactivity and calls the logout flow. UserNotificationMonitorThread polls the server for pending notifications and fires UI events when new items arrive.
Service Registry — ServiceProvider
ServiceProvider (in suredms-common) is a thin wrapper around Java ServiceLoader that discovers and returns IService implementations registered in META-INF/services files:
FeatureManager featureManager = ServiceProvider.getService(FeatureManager.class);
List<SomeSvc> all = ServiceProvider.getServices(SomeSvc.class);
Services are sorted by getServicePriority() descending; the highest-priority instance is returned by getService(). Client-side implementations use ServiceType.ST_CLIENT; server-side use ST_SERVER. For full API details see Data Access Layer.
Feature Flags — FeatureManager
FeatureManager (in suredms-desktop-client-connector) controls which features are available at runtime. FeatureManagerImpl selects between NuxeoFeatureManager (online mode) and SaveFeatureManager (offline mode) at construction time:
boolean hasPdf = featureManager.isFeatureEnabled("FEATURE_PDF_VIEWER");
boolean canView = featureManager.isFeatureEnabled("FEATURE_IMAGE_VIEW", currentUser);
Feature state is snapshotted via FeatureSnapshot. Admins can create named snapshots, list them, inspect details, and roll back to a prior snapshot via restoreSnapshot(id). For the full interface see Data Access Layer.
IcePDF Viewer Gadget
Source: SC/suredms-desktop-client/src/main/java/com/sureclinical/suredms/ui/gadgets/icepdf/
The GadgetIcePDFViewer gadget hosts an in-process IcePDF panel for rendering PDF documents without launching an external viewer.
Library: org.icepdf.os:icepdf-pro version 6.2.5-java6 (with icepdf-pro-intl for international font support). jbig2-imageio is included as a JBIG2 decoder plugin.
Rendering runs on a dedicated IcePDF worker thread and results are painted via Java2D. The default icepdf.pro.version property is stub; builds for specific clients override this to enable the full Pro font engine.
Key Classes
| Class | Role |
|---|---|
GadgetIcePDFViewer | Top-level gadget; hosts the IcePDF panel inside a GadgetPanel container |
CustomSwingController | Extends SwingController; adds page-navigation buttons, IcePDFViewerListener list, and JBIG2 page tracking |
SureDocumentViewController | Extends DocumentViewControllerImpl; overrides setDocument() to swap in SureDocumentViewModel without restarting the viewer |
SureDocumentViewModel | Custom IcePDF document view model |
SurePageViewComponent | Custom page component with SureDMS-specific rendering hooks |
IcePDFToolBar | Custom toolbar with navigation, zoom, rotate, and selection controls |
IcePDFSearchDialog | In-viewer full-text search dialog |
SaveController | Handles save-with-annotations flow |
DocumentBlobPromise | Async document blob fetcher that resolves to a FileBlob before loading |
DownloadPromiseJob | Background AbstractJob that executes a DocumentBlobPromise |
CustomAnnotationCallback | Receives IcePDF annotation events for SureDMS-specific handling |
SignatureEvent / SignatureListener | Signature field detection events |
SelectedPagesDocumentView | View mode that shows only a specified subset of pages |
GadgetIcePdfViewerIntegrationTest in suredms-web-start validates PDF rendering in the test environment.
Application Configuration
Source: SC/suredms-desktop-client/src/main/java/com/sureclinical/suredms/configuration/
ApplicationConfigurationHelper (com.sureclinical.suredms.configuration) implements server-side application configuration snapshot — export and import of FeatureSnapshot and ArchiveAclRule sets.
Operations
| Method | Description |
|---|---|
getVisibility() | Returns the current List<ArchiveAclRule> from ArchiveVisibilityHelper.getInstance().getRules() |
getExportConfigurationToFileJob() | Returns an async AbstractProgressJob that invokes SureOperations.OP_APPLICATION_CONFIGURATION_EXPORT on the server and returns a ByteArrayBlob (Excel) for download |
importConfigurationFromFile() | Opens a file chooser (.xls filter), parses the selected file via ApplicationConfigurationParser, then shows ApplicationConfigurationImportDialog |
importViewVisibility(Map<String, Boolean>) | Disables auto-save, applies each view-visibility flag to ArchiveVisibilityHelper and DocNavViewMode, then re-enables auto-save |
Import Dialog
ApplicationConfigurationImportDialog (same package) shows a summary of the imported configuration — feature snapshot state and ACL rule counts — and lets the admin confirm before applying.
Move Document Wizard (GAP-12)
MoveDocumentWizardBuilder extends WizardBuilder and provides a two-step wizard for renaming and moving documents. Entry points:
MoveDocumentWizardBuilder.showWizard(List<Document> documents);
MoveDocumentWizardBuilder.showWizard(List<Document> documents, DocNavTreeNode treeNode);
Dialog dimensions: 1200 × 800, resizable.
Steps
| Step | Purpose |
|---|---|
DocumentNameStep (wizard.move.step1) | Edit document name metadata and form fields |
ConfirmationStep (wizard.move.step2) | Review selected names and confirm |
Context
MoveDocumentWizardContext carries:
List<Document> documents— source documents to movenameDocumentcounterparts — renamed versionsMap<Document, List<FormField>> docFieldsMap— metadata fields per document- (optional)
DocNavTreeNode treeNode— pre-set target folder
Action
On confirm, the wizard builds parallel lists of originals, name-docs, and fields and calls:
DocNavTreeModel2.getInstance().renameDocuments(originals, nameDocs, fields, /*move=*/true);
For batches ≥ 25 documents, a ConfirmationDialog is shown before proceeding.
Look and Feel / Theme System (GAP-15)
Source: SC/suredms-desktop-client/src/main/java/com/sureclinical/suredms/ui/laf/LookAndFeelManager.java
LookAndFeelManager (package com.sureclinical.suredms.ui.laf) manages Swing look-and-feel and zoom state for the desktop application. It uses the Substance look-and-feel library (Office 2007 Silver skin) via PushingPixels.
Font Management
| Method | Description |
|---|---|
setDefaultFont(String fontName) | Sets and persists the default font |
setDefaultFont(String fontName, boolean savePreferences) | As above; conditionally saves |
getDefaultFont() | Returns the current default Font |
getDefaultFontSmall() | Returns the default font at 11pt |
getDefaultFontBold() | Returns the bold variant of the default font |
getFontNames() | Returns all system font names |
Platform fonts: DEFAULT_FONT_LINUX, DEFAULT_FONT_WINDOWS, DEFAULT_FONT_MAC.
Zoom
| Method | Description |
|---|---|
changeZoom(int zoomDelta) | Adjusts all font sizes by zoomDelta points |
resetZoom() | Reverts to the platform default font size |
LAF Reload and Listeners
| Method | Description |
|---|---|
reloadLookAndFeel() | Re-applies the current Substance skin and updates all open windows |
setRibbonMode(RibbonMode) | Switches ribbon display mode |
addLookAndFeelChangeListener(LookAndFeelChangeListener) | Subscribes to theme-change events |
addZoomChangeListener(ZoomChangeListener) | Subscribes to zoom-change events |
Share Tab (GAP-18)
The ShareView (already noted in the Views section above) contains two gadgets:
| Gadget | Class | Role |
|---|---|---|
| Share navigator | GadgetShareNavigation | Navigation tree for shared document context |
| Share preview | GadgetSharePreview | Preview panel for the selected shared item |
The Share tab is visible only when FEATURE_SHARE_VIEW or FEATURE_SHARE_VIEW_WITH_DELETION is enabled (checked in StudyDashboardController.canModifyTeam). In the web client, the same feature flag governs the Share tab visibility.
Additional detail panels used within the share context:
PersonDetailsPanel— person-specific share detailOrganizationDetailsPanel— organisation-specific share detailStudySubjectDetailsPanel— study subject share detail
Desktop Content Model Editor (GAP-20)
Source: SC/suredms-desktop-client/src/main/java/com/sureclinical/suredms/tempdata/ContentModelEditor.java
ContentModelEditor (package com.sureclinical.suredms.tempdata) is a singleton helper that provides CRUD operations on content model entities (categories, content types, metadata terms) from the desktop shell. Equivalent to the web client's Content Model Editor feature.
ContentModelEditor editor = ContentModelEditor.getInstance();
API
| Method | Description |
|---|---|
addCategory(Category) | Saves category and parent; reloads; fires entity-data update event |
updateCategory(Category) | Updates existing category |
addContentType(ContentType) | Adds a new content type to the repository |
updateContentType(ContentType) | Updates an existing content type |
reserveCategory(Category) | Marks a category as reserved (prevents user deletion) |
unReserveCategory(Category) | Clears the reserved flag |
reserveContentType(ContentType) | Marks a content type as reserved |
unReserveContentType(ContentType) | Clears the reserved flag |
addOrUpdateMetadataTerm(DataPropertyDef) | Persists a metadata term definition via NuxeoClientPool remote operation |
updateEntities(Collection<? extends BaseEntity>) | Batch-updates multiple entities |
canReserve(ContentType) | Returns !contentType.isReserved() |
canReserve(Category) | Recursively checks children for reservable state |
canDelete(ContentType) | Returns false if documents use this type |
canDelete(Category) | Returns false if documents use this category |
containDocuments(ContentType / Category / Person) | Checks for document use |
getAnnotations(Archive) | Returns List<AnnotationDef> for an archive |
getDataProperties(Archive) | Returns List<DataPropertyDef> for an archive |
Associated UI: LinkMetadataTermDialog (links metadata terms to content types), AssociationAction (ribbon action to open the linking dialog).
Dependencies
| Module | Role |
|---|---|
suredms-desktop-client-connector | Endpoint selection and all remote/local data operations |
suredms-desktop-client-data | Entity model for session, archives, documents, users |
suredms-desktop-client-quality | QualityView mounted by the shell |
suredms-desktop-client-signing | ESignServiceProxy accessed from wizard and ribbon actions |
Constraints and Notes
MAX_NUMBER_OF_ACTIVE_ARCHIVES = 5is enforced byDesktopClient; opening a sixth archive fails.- All Swing UI construction and updates must run on the EDT. Background work uses
JobManager/UiThreadPool. isLockedisvolatile; modified byLockScreenDialogfrom any thread.BaseEntryPointdefaults tohttp://127.0.0.1:8080if the parameter map does not containserviceHost.- The
KeyEventDispatcherfor Ctrl+G is registered once and remains for the application lifetime. - Gadget layout positions are stored normalized (0–100 range) relative to the view size and restored on next login.