Skip to content

Commit 518375f

Browse files
oops-shlokcalixtuskoppor
authored andcommitted
Show a welcome screen if no database is open (JabRef#12461)
* Fix JabRef#12272 - Show a welcome screen if no database is open * Fix JabRef#12272 - Fix missing localisation keys for WelcomePage * Fix JabRef#12272 - Fix missing localisation keys for WelcomePage * Fix JabRef#12272 - Addressed 1st Review Changes * Fix JabRef#12272 - Checkstyle issue fix in ExportCommand file * Reverted csl-styles submodule changes * Reverted abbrv.jabref.org submodule changes * Integrated WelcomePage in WelcomeTab and code changes * Implemented Review Changes 5 * Fix JabRef#12272 - Localization key fix in JabRef_en.properties * Implemented Open Welcome tab in help menu option and open welcome tab if no library is open * Implemented Review Changes 6 * Reverted Interface changes and fixed save as and save for welcome tab * Fixed checkstyle import issue * Simplify and fix casting * Fix casting * Fixed Responsiveness * Undo newlines in MainToolBar.java * Added Footer for Welcome Tab * Fixed Localization issues * Fixed Recents Library issue * Fixed Tragbot review for Footer * Refactored the code as suggested in review comments * Introduced URLs Util * Fixed Localization issues * Fixed Localization issues * Fixed Localization issues * Fixed missing Localization in WelcomeTab * Fixed missing Localization in WelcomeTab * Fixed Review changes * Added Changelog entry * Update src/main/java/org/jabref/gui/frame/JabRefFrame.java * Update src/main/java/org/jabref/gui/WelcomeTab.java * Update src/main/java/org/jabref/gui/frame/JabRefFrame.java * Fixed Localization issue * Fix position of showing welcome tab * Streamline wording * Remove obsolete strings * Fix obsolete code * Fix comment * Fix localization --------- Co-authored-by: Carl Christian Snethlage <[email protected]> Co-authored-by: Oliver Kopp <[email protected]>
1 parent 599fb5f commit 518375f

13 files changed

+451
-34
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ Note that this project **does not** adhere to [Semantic Versioning](https://semv
1111

1212
### Added
1313

14+
- We added a new Welcome tab which shows a welcome screen if no database is open. [#12272](https://github.com/JabRef/jabref/issues/12272)
1415
- We added <kbd>F5</kbd> as a shortcut key for fetching data and <kbd>Alt+F</kbd> as a shortcut for looking up data using DOI. [#11802](https://github.com/JabRef/jabref/issues/11802)
1516
- We added a feature to rename the subgroup, with the keybinding (<kbd>F2</kbd>) for quick access. [#11896](https://github.com/JabRef/jabref/issues/11896)
1617
- We added a new functionality that displays a drop-down list of matching suggestions when typing a citation key pattern. [#12502](https://github.com/JabRef/jabref/issues/12502)

src/main/java/org/jabref/cli/ArgumentProcessor.java

+4
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,10 @@ public void processArguments() {
296296
uiCommands.add(new UiCommand.OpenDatabases(loaded));
297297
}
298298

299+
if (cli.isBlank() && loaded.isEmpty()) {
300+
uiCommands.add(new UiCommand.BlankWorkspace());
301+
}
302+
299303
if (cli.isCheckConsistency()) {
300304
checkConsistency(cliPreferences, entryTypesManager);
301305
}

src/main/java/org/jabref/gui/Base.css

+61
Original file line numberDiff line numberDiff line change
@@ -1730,6 +1730,67 @@ We want to have a look that matches our icons in the tool-bar */
17301730
-fx-effect: dropshadow(three-pass-box, rgba(0, 0, 0, 0.6), 8, 0.0, 0, 0);
17311731
}
17321732

1733+
.welcome-label {
1734+
-fx-font-size: 2.75em;
1735+
-fx-text-fill: -jr-theme-text;
1736+
-fx-font-family: "Arial";
1737+
}
1738+
1739+
.welcome-description-label {
1740+
-fx-font-size: 1.75em;
1741+
-fx-font-family: "Arial";
1742+
}
1743+
1744+
.welcome-header-label {
1745+
-fx-font-size: 1.5em;
1746+
-fx-font-weight: bold;
1747+
-fx-font-family: "Arial";
1748+
}
1749+
1750+
.welcome-no-recent-label {
1751+
-fx-font-size: 1.25em;
1752+
-fx-text-fill: -jr-theme;
1753+
-fx-font-family: "Arial";
1754+
}
1755+
1756+
.welcome-hyperlink {
1757+
-fx-font-size: 1.25em;
1758+
-fx-text-fill: -jr-theme;
1759+
}
1760+
1761+
.welcome-hyperlink:visited {
1762+
-fx-text-fill: -jr-theme;
1763+
}
1764+
1765+
.welcome-footer-container {
1766+
-fx-padding: 15px;
1767+
-fx-alignment: center;
1768+
-fx-spacing: 15px;
1769+
}
1770+
1771+
.welcome-footer-label {
1772+
-fx-font-size: 2.25em;
1773+
-fx-text-fill: -jr-theme-text;
1774+
-fx-font-family: "Arial";
1775+
}
1776+
1777+
.welcome-footer-link {
1778+
-fx-font-size: 1.2em;
1779+
-fx-text-fill: -jr-theme;
1780+
-fx-font-family: "Arial";
1781+
}
1782+
1783+
.welcome-footer-link:hover {
1784+
-fx-underline: true;
1785+
-fx-text-fill: derive(-jr-theme, -20%);
1786+
}
1787+
1788+
.welcome-footer-version {
1789+
-fx-font-size: 1.2em;
1790+
-fx-text-fill: -jr-theme;
1791+
-fx-font-family: "Arial";
1792+
}
1793+
17331794
/* AboutDialog */
17341795
#aboutDialog .about-heading {
17351796
-fx-font-size: 30;

src/main/java/org/jabref/gui/JabRefGUI.java

+9
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,8 @@ private void openWindow() {
260260
LOGGER.debug("frame initialized");
261261

262262
Platform.runLater(() -> mainFrame.handleUiCommands(uiCommands));
263+
264+
// Lifecycle note: after this method, #onShowing will be called
263265
}
264266

265267
public void onShowing(WindowEvent event) {
@@ -270,6 +272,13 @@ public void onShowing(WindowEvent event) {
270272
&& preferences.getWorkspacePreferences().shouldOpenLastEdited()) {
271273
mainFrame.openLastEditedDatabases();
272274
}
275+
276+
Platform.runLater(() -> {
277+
// We need to check at this point, because here, all libraries are loaded (e.g., load previously opened libraries) and all UI commands (e.g., load libraries, blank workspace, ...) are handled.
278+
if (stateManager.getOpenDatabases().isEmpty()) {
279+
mainFrame.showWelcomeTab();
280+
}
281+
});
273282
}
274283

275284
public void onCloseRequest(WindowEvent event) {

src/main/java/org/jabref/gui/LibraryTab.java

+1
Original file line numberDiff line numberDiff line change
@@ -809,6 +809,7 @@ private void onClosed(Event event) {
809809
if (tableModel != null) {
810810
tableModel.unbind();
811811
}
812+
812813
// clean up the groups map
813814
stateManager.clearSelectedGroups(bibDatabaseContext);
814815
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,261 @@
1+
package org.jabref.gui;
2+
3+
import javafx.collections.ListChangeListener;
4+
import javafx.geometry.Insets;
5+
import javafx.geometry.Pos;
6+
import javafx.scene.Node;
7+
import javafx.scene.control.Hyperlink;
8+
import javafx.scene.control.Label;
9+
import javafx.scene.control.MenuItem;
10+
import javafx.scene.control.Tab;
11+
import javafx.scene.layout.BorderPane;
12+
import javafx.scene.layout.HBox;
13+
import javafx.scene.layout.Priority;
14+
import javafx.scene.layout.VBox;
15+
16+
import org.jabref.gui.actions.StandardActions;
17+
import org.jabref.gui.edit.OpenBrowserAction;
18+
import org.jabref.gui.frame.FileHistoryMenu;
19+
import org.jabref.gui.icon.IconTheme;
20+
import org.jabref.gui.importer.NewDatabaseAction;
21+
import org.jabref.gui.importer.actions.OpenDatabaseAction;
22+
import org.jabref.gui.preferences.GuiPreferences;
23+
import org.jabref.gui.undo.CountingUndoManager;
24+
import org.jabref.gui.util.URLs;
25+
import org.jabref.logic.ai.AiService;
26+
import org.jabref.logic.l10n.Localization;
27+
import org.jabref.logic.util.BuildInfo;
28+
import org.jabref.logic.util.TaskExecutor;
29+
import org.jabref.model.entry.BibEntryTypesManager;
30+
import org.jabref.model.util.FileUpdateMonitor;
31+
32+
public class WelcomeTab extends Tab {
33+
34+
private final VBox recentLibrariesBox;
35+
private final LibraryTabContainer tabContainer;
36+
private final GuiPreferences preferences;
37+
private final AiService aiService;
38+
private final DialogService dialogService;
39+
private final StateManager stateManager;
40+
private final FileUpdateMonitor fileUpdateMonitor;
41+
private final BibEntryTypesManager entryTypesManager;
42+
private final CountingUndoManager undoManager;
43+
private final ClipBoardManager clipBoardManager;
44+
private final TaskExecutor taskExecutor;
45+
private final FileHistoryMenu fileHistoryMenu;
46+
private final BuildInfo buildInfo;
47+
48+
public WelcomeTab(LibraryTabContainer tabContainer,
49+
GuiPreferences preferences,
50+
AiService aiService,
51+
DialogService dialogService,
52+
StateManager stateManager,
53+
FileUpdateMonitor fileUpdateMonitor,
54+
BibEntryTypesManager entryTypesManager,
55+
CountingUndoManager undoManager,
56+
ClipBoardManager clipBoardManager,
57+
TaskExecutor taskExecutor,
58+
FileHistoryMenu fileHistoryMenu,
59+
BuildInfo buildInfo) {
60+
61+
super(Localization.lang("Welcome"));
62+
setClosable(true);
63+
64+
this.tabContainer = tabContainer;
65+
this.preferences = preferences;
66+
this.aiService = aiService;
67+
this.dialogService = dialogService;
68+
this.stateManager = stateManager;
69+
this.fileUpdateMonitor = fileUpdateMonitor;
70+
this.entryTypesManager = entryTypesManager;
71+
this.undoManager = undoManager;
72+
this.clipBoardManager = clipBoardManager;
73+
this.taskExecutor = taskExecutor;
74+
this.fileHistoryMenu = fileHistoryMenu;
75+
this.buildInfo = buildInfo;
76+
77+
this.recentLibrariesBox = new VBox(10);
78+
79+
VBox welcomeBox = createWelcomeBox();
80+
VBox startBox = createWelcomeStartBox();
81+
VBox recentBox = createWelcomeRecentBox();
82+
83+
VBox welcomePageContainer = new VBox(10);
84+
welcomePageContainer.setAlignment(Pos.CENTER);
85+
welcomePageContainer.getChildren().addAll(welcomeBox, startBox, recentBox);
86+
87+
HBox welcomeMainContainer = new HBox(10);
88+
welcomeMainContainer.setAlignment(Pos.CENTER);
89+
welcomeMainContainer.setPadding(new Insets(10, 10, 10, 50));
90+
91+
welcomeMainContainer.getChildren().add(welcomePageContainer);
92+
93+
BorderPane rootLayout = new BorderPane();
94+
rootLayout.setCenter(welcomeMainContainer);
95+
rootLayout.setBottom(createFooter());
96+
97+
VBox container = new VBox();
98+
container.getChildren().add(rootLayout);
99+
VBox.setVgrow(rootLayout, Priority.ALWAYS);
100+
setContent(container);
101+
}
102+
103+
private VBox createWelcomeBox() {
104+
Label welcomeLabel = new Label(Localization.lang("Welcome to JabRef"));
105+
welcomeLabel.getStyleClass().add("welcome-label");
106+
107+
Label descriptionLabel = new Label(Localization.lang("Stay on top of your literature"));
108+
descriptionLabel.getStyleClass().add("welcome-description-label");
109+
110+
return createVBoxContainer(welcomeLabel, descriptionLabel);
111+
}
112+
113+
private VBox createWelcomeStartBox() {
114+
Label startLabel = new Label(Localization.lang("Start"));
115+
startLabel.getStyleClass().add("welcome-header-label");
116+
117+
Hyperlink newLibraryLink = new Hyperlink(Localization.lang("New library"));
118+
newLibraryLink.getStyleClass().add("welcome-hyperlink");
119+
newLibraryLink.setOnAction(e -> new NewDatabaseAction(tabContainer, preferences).execute());
120+
121+
Hyperlink openLibraryLink = new Hyperlink(Localization.lang("Open library"));
122+
openLibraryLink.getStyleClass().add("welcome-hyperlink");
123+
openLibraryLink.setOnAction(e -> new OpenDatabaseAction(tabContainer, preferences, aiService, dialogService,
124+
stateManager, fileUpdateMonitor, entryTypesManager, undoManager, clipBoardManager,
125+
taskExecutor).execute());
126+
127+
return createVBoxContainer(startLabel, newLibraryLink, openLibraryLink);
128+
}
129+
130+
private VBox createWelcomeRecentBox() {
131+
Label recentLabel = new Label(Localization.lang("Recent"));
132+
recentLabel.getStyleClass().add("welcome-header-label");
133+
134+
recentLibrariesBox.setAlignment(Pos.TOP_LEFT);
135+
updateWelcomeRecentLibraries();
136+
137+
fileHistoryMenu.getItems().addListener((ListChangeListener<MenuItem>) change -> updateWelcomeRecentLibraries());
138+
139+
return createVBoxContainer(recentLabel, recentLibrariesBox);
140+
}
141+
142+
private void updateWelcomeRecentLibraries() {
143+
if (fileHistoryMenu.getItems().isEmpty()) {
144+
displayNoRecentLibrariesMessage();
145+
return;
146+
}
147+
148+
recentLibrariesBox.getChildren().clear();
149+
fileHistoryMenu.disableProperty().unbind();
150+
fileHistoryMenu.setDisable(false);
151+
152+
for (MenuItem item : fileHistoryMenu.getItems()) {
153+
Hyperlink recentLibraryLink = new Hyperlink(item.getText());
154+
recentLibraryLink.getStyleClass().add("welcome-hyperlink");
155+
recentLibraryLink.setOnAction(item.getOnAction());
156+
recentLibrariesBox.getChildren().add(recentLibraryLink);
157+
}
158+
}
159+
160+
private void displayNoRecentLibrariesMessage() {
161+
recentLibrariesBox.getChildren().clear();
162+
Label noRecentLibrariesLabel = new Label(Localization.lang("No recent libraries"));
163+
noRecentLibrariesLabel.getStyleClass().add("welcome-no-recent-label");
164+
recentLibrariesBox.getChildren().add(noRecentLibrariesLabel);
165+
166+
fileHistoryMenu.disableProperty().unbind();
167+
fileHistoryMenu.setDisable(true);
168+
}
169+
170+
private VBox createVBoxContainer(Node... nodes) {
171+
VBox box = new VBox(10);
172+
box.setAlignment(Pos.TOP_LEFT);
173+
box.getChildren().addAll(nodes);
174+
return box;
175+
}
176+
177+
private VBox createFooter() {
178+
// Heading for the footer area
179+
Label communityLabel = createFooterLabel(Localization.lang("Community"));
180+
181+
HBox iconLinksContainer = createIconLinksContainer();
182+
HBox textLinksContainer = createTextLinksContainer();
183+
HBox versionContainer = createVersionContainer();
184+
185+
VBox footerBox = new VBox(10);
186+
footerBox.setAlignment(Pos.CENTER);
187+
footerBox.getChildren().addAll(communityLabel, iconLinksContainer, textLinksContainer, versionContainer);
188+
footerBox.setPadding(new Insets(10, 0, 10, 0));
189+
footerBox.getStyleClass().add("welcome-footer-container");
190+
191+
return footerBox;
192+
}
193+
194+
private Label createFooterLabel(String text) {
195+
Label label = new Label(text);
196+
label.getStyleClass().add("welcome-footer-label");
197+
return label;
198+
}
199+
200+
private HBox createIconLinksContainer() {
201+
HBox container = new HBox(10);
202+
container.setAlignment(Pos.CENTER);
203+
204+
Hyperlink onlineHelpLink = createFooterLink(Localization.lang("Online help"), StandardActions.HELP, IconTheme.JabRefIcons.HELP);
205+
Hyperlink forumLink = createFooterLink(Localization.lang("Community forum"), StandardActions.OPEN_FORUM, IconTheme.JabRefIcons.FORUM);
206+
Hyperlink mastodonLink = createFooterLink(Localization.lang("Mastodon"), StandardActions.OPEN_MASTODON, IconTheme.JabRefIcons.MASTODON);
207+
Hyperlink linkedInLink = createFooterLink(Localization.lang("LinkedIn"), StandardActions.OPEN_LINKEDIN, IconTheme.JabRefIcons.LINKEDIN);
208+
Hyperlink donationLink = createFooterLink(Localization.lang("Donation"), StandardActions.DONATE, IconTheme.JabRefIcons.DONATE);
209+
210+
container.getChildren().addAll(onlineHelpLink, forumLink, mastodonLink, linkedInLink, donationLink);
211+
return container;
212+
}
213+
214+
private HBox createTextLinksContainer() {
215+
HBox container = new HBox(10);
216+
container.setAlignment(Pos.CENTER);
217+
218+
Hyperlink devVersionLink = createFooterLink(Localization.lang("Download development version"), StandardActions.OPEN_DEV_VERSION_LINK, null);
219+
Hyperlink changelogLink = createFooterLink(Localization.lang("CHANGELOG"), StandardActions.OPEN_CHANGELOG, null);
220+
221+
container.getChildren().addAll(devVersionLink, changelogLink);
222+
return container;
223+
}
224+
225+
private Hyperlink createFooterLink(String text, StandardActions action, IconTheme.JabRefIcons icon) {
226+
Hyperlink link = new Hyperlink(text);
227+
link.getStyleClass().add("welcome-footer-link");
228+
229+
String url = switch (action) {
230+
case HELP -> URLs.HELP_URL;
231+
case OPEN_FORUM -> URLs.FORUM_URL;
232+
case OPEN_MASTODON -> URLs.MASTODON_URL;
233+
case OPEN_LINKEDIN -> URLs.LINKEDIN_URL;
234+
case DONATE -> URLs.DONATE_URL;
235+
case OPEN_DEV_VERSION_LINK -> URLs.DEV_VERSION_LINK_URL;
236+
case OPEN_CHANGELOG -> URLs.CHANGELOG_URL;
237+
default -> null;
238+
};
239+
240+
if (url != null) {
241+
link.setOnAction(e -> new OpenBrowserAction(url, dialogService, preferences.getExternalApplicationsPreferences()).execute());
242+
}
243+
244+
if (icon != null) {
245+
link.setGraphic(icon.getGraphicNode());
246+
}
247+
248+
return link;
249+
}
250+
251+
private HBox createVersionContainer() {
252+
HBox container = new HBox(10);
253+
container.setAlignment(Pos.CENTER);
254+
255+
Label versionLabel = new Label(Localization.lang("Current JabRef version: %0", buildInfo.version));
256+
versionLabel.getStyleClass().add("welcome-footer-version");
257+
258+
container.getChildren().add(versionLabel);
259+
return container;
260+
}
261+
}

src/main/java/org/jabref/gui/actions/StandardActions.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -181,10 +181,11 @@ public enum StandardActions implements Action {
181181
OPEN_CHANGELOG(Localization.lang("View change log"), Localization.lang("See what has been changed in the JabRef versions")),
182182
OPEN_GITHUB("GitHub", Localization.lang("Opens JabRef's GitHub page"), IconTheme.JabRefIcons.GITHUB),
183183
DONATE(Localization.lang("Donate to JabRef"), Localization.lang("Donate to JabRef"), IconTheme.JabRefIcons.DONATE),
184-
OPEN_FORUM(Localization.lang("Online help forum"), Localization.lang("Online help forum"), IconTheme.JabRefIcons.FORUM),
184+
OPEN_FORUM(Localization.lang("Community forum"), Localization.lang("Community forum"), IconTheme.JabRefIcons.FORUM),
185185
ERROR_CONSOLE(Localization.lang("View event log"), Localization.lang("Display all error messages")),
186186
SEARCH_FOR_UPDATES(Localization.lang("Check for updates")),
187187
ABOUT(Localization.lang("About JabRef"), Localization.lang("About JabRef")),
188+
OPEN_WELCOME_TAB(Localization.lang("Open welcome tab")),
188189

189190
EDIT_LIST(Localization.lang("Edit"), IconTheme.JabRefIcons.EDIT),
190191
VIEW_LIST(Localization.lang("View"), IconTheme.JabRefIcons.FILE),

0 commit comments

Comments
 (0)