-
-
Notifications
You must be signed in to change notification settings - Fork 2.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Show a welcome screen if no database is open #12461
Changes from 56 commits
08ec5d8
684f7df
3759e24
9fc595d
4e576e9
52409bd
f130244
2559f22
0d240c9
cb05ec7
0489da1
669083d
cf3188e
e5a4840
d4332c6
c11ca80
5c0b6ee
f97be18
cdc1977
7db3b81
4de4651
815ba53
c401e67
dea3f05
40c4ca3
a8ee2c8
f048c4b
0e5ed41
76b1aba
970d7e8
fbf3405
5e199c4
e373b34
fc78dc5
66ccb58
1e24223
8efa826
5196593
afa8b54
d920d6c
5aa63d2
fcc5be3
a6d50e2
2f9811f
8885b4d
721a77f
6744ec2
22347f8
a8ac3e5
cc78bbe
cd11463
efc4767
c0a4696
8aed6f7
7ba378d
95a93eb
0e786cc
f6a5587
ba1ad6f
23891b6
4bc74b6
0076919
a71d9fb
3c14ba8
c94fb15
c695f5b
5115579
f7c0c3b
5d84d89
37e24d2
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,274 @@ | ||
package org.jabref.gui; | ||
|
||
import javafx.collections.ListChangeListener; | ||
import javafx.geometry.Insets; | ||
import javafx.geometry.Pos; | ||
import javafx.scene.Node; | ||
import javafx.scene.control.Hyperlink; | ||
import javafx.scene.control.Label; | ||
import javafx.scene.control.MenuItem; | ||
import javafx.scene.control.ScrollPane; | ||
import javafx.scene.control.Tab; | ||
import javafx.scene.layout.BorderPane; | ||
import javafx.scene.layout.HBox; | ||
import javafx.scene.layout.Priority; | ||
import javafx.scene.layout.StackPane; | ||
import javafx.scene.layout.VBox; | ||
|
||
import org.jabref.gui.actions.StandardActions; | ||
import org.jabref.gui.edit.OpenBrowserAction; | ||
import org.jabref.gui.frame.FileHistoryMenu; | ||
import org.jabref.gui.icon.IconTheme; | ||
import org.jabref.gui.importer.NewDatabaseAction; | ||
import org.jabref.gui.importer.actions.OpenDatabaseAction; | ||
import org.jabref.gui.preferences.GuiPreferences; | ||
import org.jabref.gui.undo.CountingUndoManager; | ||
import org.jabref.gui.util.URLs; | ||
import org.jabref.logic.ai.AiService; | ||
import org.jabref.logic.l10n.Localization; | ||
import org.jabref.logic.util.BuildInfo; | ||
import org.jabref.logic.util.TaskExecutor; | ||
import org.jabref.model.entry.BibEntryTypesManager; | ||
import org.jabref.model.util.FileUpdateMonitor; | ||
|
||
public class WelcomeTab extends Tab { | ||
|
||
private final VBox recentLibrariesBox; | ||
private final LibraryTabContainer tabContainer; | ||
private final GuiPreferences preferences; | ||
private final AiService aiService; | ||
private final DialogService dialogService; | ||
private final StateManager stateManager; | ||
private final FileUpdateMonitor fileUpdateMonitor; | ||
private final BibEntryTypesManager entryTypesManager; | ||
private final CountingUndoManager undoManager; | ||
private final ClipBoardManager clipBoardManager; | ||
private final TaskExecutor taskExecutor; | ||
private final FileHistoryMenu fileHistoryMenu; | ||
private final BuildInfo buildInfo; | ||
|
||
public WelcomeTab(LibraryTabContainer tabContainer, | ||
GuiPreferences preferences, | ||
AiService aiService, | ||
DialogService dialogService, | ||
StateManager stateManager, | ||
FileUpdateMonitor fileUpdateMonitor, | ||
BibEntryTypesManager entryTypesManager, | ||
CountingUndoManager undoManager, | ||
ClipBoardManager clipBoardManager, | ||
TaskExecutor taskExecutor, | ||
FileHistoryMenu fileHistoryMenu, | ||
BuildInfo buildInfo) { | ||
|
||
super(Localization.lang("Welcome")); | ||
setClosable(true); | ||
|
||
this.tabContainer = tabContainer; | ||
this.preferences = preferences; | ||
this.aiService = aiService; | ||
this.dialogService = dialogService; | ||
this.stateManager = stateManager; | ||
this.fileUpdateMonitor = fileUpdateMonitor; | ||
this.entryTypesManager = entryTypesManager; | ||
this.undoManager = undoManager; | ||
this.clipBoardManager = clipBoardManager; | ||
this.taskExecutor = taskExecutor; | ||
this.fileHistoryMenu = fileHistoryMenu; | ||
this.buildInfo = buildInfo; | ||
|
||
this.recentLibrariesBox = new VBox(5); | ||
|
||
VBox welcomePageContainer = new VBox(20); | ||
welcomePageContainer.setAlignment(Pos.CENTER); | ||
|
||
HBox welcomeMainContainer = new HBox(20); | ||
welcomeMainContainer.setAlignment(Pos.CENTER); | ||
|
||
welcomeMainContainer.setPadding(new Insets(10, 10, 10, 50)); | ||
|
||
ScrollPane scrollPane = new ScrollPane(welcomeMainContainer); | ||
scrollPane.setFitToWidth(true); | ||
scrollPane.setFitToHeight(true); | ||
|
||
scrollPane.widthProperty().addListener((_, _, newWidth) -> { | ||
double dynamicPadding = Math.max(20, newWidth.doubleValue() * 0.05); | ||
welcomeMainContainer.setPadding(new Insets(10, 10, 10, dynamicPadding)); | ||
}); | ||
|
||
setContent(new StackPane(scrollPane)); | ||
|
||
VBox welcomeBox = createWelcomeBox(); | ||
VBox startBox = createWelcomeStartBox(); | ||
VBox recentBox = createWelcomeRecentBox(); | ||
|
||
welcomePageContainer.getChildren().addAll(welcomeBox, startBox, recentBox); | ||
welcomeMainContainer.getChildren().add(welcomePageContainer); | ||
|
||
BorderPane rootLayout = new BorderPane(); | ||
rootLayout.setCenter(welcomeMainContainer); | ||
rootLayout.setBottom(createFooter()); | ||
|
||
VBox container = new VBox(); | ||
container.getChildren().add(rootLayout); | ||
VBox.setVgrow(rootLayout, Priority.ALWAYS); | ||
setContent(container); | ||
} | ||
|
||
private VBox createWelcomeBox() { | ||
Label welcomeLabel = new Label(Localization.lang("Welcome to JabRef")); | ||
welcomeLabel.getStyleClass().add("welcome-label"); | ||
|
||
Label descriptionLabel = new Label(Localization.lang("Stay on top of your literature")); | ||
descriptionLabel.getStyleClass().add("welcome-description-label"); | ||
|
||
return createVBoxContainer(welcomeLabel, descriptionLabel); | ||
} | ||
|
||
private VBox createWelcomeStartBox() { | ||
Label startLabel = new Label(Localization.lang("Start")); | ||
startLabel.getStyleClass().add("welcome-header-label"); | ||
|
||
Hyperlink newLibraryLink = new Hyperlink(Localization.lang("New library")); | ||
newLibraryLink.getStyleClass().add("welcome-hyperlink"); | ||
newLibraryLink.setOnAction(e -> new NewDatabaseAction(tabContainer, preferences).execute()); | ||
|
||
Hyperlink openLibraryLink = new Hyperlink(Localization.lang("Open library")); | ||
openLibraryLink.getStyleClass().add("welcome-hyperlink"); | ||
openLibraryLink.setOnAction(e -> new OpenDatabaseAction(tabContainer, preferences, aiService, dialogService, | ||
stateManager, fileUpdateMonitor, entryTypesManager, undoManager, clipBoardManager, | ||
taskExecutor).execute()); | ||
|
||
return createVBoxContainer(startLabel, newLibraryLink, openLibraryLink); | ||
} | ||
|
||
private VBox createWelcomeRecentBox() { | ||
Label recentLabel = new Label(Localization.lang("Recent")); | ||
recentLabel.getStyleClass().add("welcome-header-label"); | ||
|
||
recentLibrariesBox.setAlignment(Pos.TOP_LEFT); | ||
updateWelcomeRecentLibraries(); | ||
|
||
fileHistoryMenu.getItems().addListener((ListChangeListener<MenuItem>) change -> updateWelcomeRecentLibraries()); | ||
|
||
return createVBoxContainer(recentLabel, recentLibrariesBox); | ||
} | ||
|
||
private void updateWelcomeRecentLibraries() { | ||
if (fileHistoryMenu.getItems().isEmpty()) { | ||
displayNoRecentLibrariesMessage(); | ||
return; | ||
} | ||
|
||
recentLibrariesBox.getChildren().clear(); | ||
fileHistoryMenu.disableProperty().unbind(); | ||
fileHistoryMenu.setDisable(false); | ||
|
||
for (MenuItem item : fileHistoryMenu.getItems()) { | ||
Hyperlink recentLibraryLink = new Hyperlink(item.getText()); | ||
recentLibraryLink.getStyleClass().add("welcome-hyperlink"); | ||
recentLibraryLink.setOnAction(item.getOnAction()); | ||
recentLibrariesBox.getChildren().add(recentLibraryLink); | ||
} | ||
} | ||
|
||
private void displayNoRecentLibrariesMessage() { | ||
recentLibrariesBox.getChildren().clear(); | ||
Label noRecentLibrariesLabel = new Label(Localization.lang("No recent libraries")); | ||
noRecentLibrariesLabel.getStyleClass().add("welcome-no-recent-label"); | ||
recentLibrariesBox.getChildren().add(noRecentLibrariesLabel); | ||
|
||
fileHistoryMenu.disableProperty().unbind(); | ||
fileHistoryMenu.setDisable(true); | ||
} | ||
|
||
private VBox createVBoxContainer(Node... nodes) { | ||
VBox box = new VBox(5); | ||
box.setAlignment(Pos.TOP_LEFT); | ||
box.getChildren().addAll(nodes); | ||
return box; | ||
} | ||
|
||
private VBox createFooter() { | ||
Label communityLabel = createFooterLabel(Localization.lang("Community")); | ||
|
||
HBox iconLinksContainer = createIconLinksContainer(); | ||
HBox textLinksContainer = createTextLinksContainer(); | ||
HBox versionContainer = createVersionContainer(); | ||
|
||
VBox footerBox = new VBox(10); | ||
footerBox.setAlignment(Pos.CENTER); | ||
footerBox.getChildren().addAll(communityLabel, iconLinksContainer, textLinksContainer, versionContainer); | ||
footerBox.setPadding(new Insets(10, 0, 10, 0)); | ||
footerBox.getStyleClass().add("welcome-footer-container"); | ||
|
||
return footerBox; | ||
} | ||
|
||
private Label createFooterLabel(String text) { | ||
Label label = new Label(text); | ||
label.getStyleClass().add("welcome-footer-label"); | ||
return label; | ||
} | ||
|
||
private HBox createIconLinksContainer() { | ||
HBox container = new HBox(15); | ||
container.setAlignment(Pos.CENTER); | ||
|
||
Hyperlink onlineHelpLink = createFooterLink(Localization.lang("Online help"), StandardActions.HELP, IconTheme.JabRefIcons.HELP); | ||
Hyperlink forumLink = createFooterLink(Localization.lang("Forum for support"), StandardActions.OPEN_FORUM, IconTheme.JabRefIcons.FORUM); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @koppor Forum is used not only for support. Also for feature requests, introductions. What about changing to just "Forum"? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Changed to "Community forum" by me
koppor marked this conversation as resolved.
Show resolved
Hide resolved
|
||
Hyperlink mastodonLink = createFooterLink(Localization.lang("Mastodon"), StandardActions.OPEN_MASTODON, IconTheme.JabRefIcons.MASTODON); | ||
Hyperlink linkedInLink = createFooterLink(Localization.lang("LinkedIn"), StandardActions.OPEN_LINKEDIN, IconTheme.JabRefIcons.LINKEDIN); | ||
Hyperlink donationLink = createFooterLink(Localization.lang("Donation"), StandardActions.DONATE, IconTheme.JabRefIcons.DONATE); | ||
|
||
container.getChildren().addAll(onlineHelpLink, forumLink, mastodonLink, linkedInLink, donationLink); | ||
return container; | ||
} | ||
|
||
private HBox createTextLinksContainer() { | ||
HBox container = new HBox(15); | ||
container.setAlignment(Pos.CENTER); | ||
|
||
Hyperlink devVersionLink = createFooterLink(Localization.lang("Download development version"), StandardActions.OPEN_DEV_VERSION_LINK, null); | ||
Hyperlink changelogLink = createFooterLink(Localization.lang("CHANGELOG"), StandardActions.OPEN_CHANGELOG, null); | ||
|
||
container.getChildren().addAll(devVersionLink, changelogLink); | ||
return container; | ||
} | ||
|
||
private Hyperlink createFooterLink(String text, StandardActions action, IconTheme.JabRefIcons icon) { | ||
Hyperlink link = new Hyperlink(text); | ||
link.getStyleClass().add("welcome-footer-link"); | ||
|
||
String url = switch (action) { | ||
case HELP -> URLs.HELP_URL; | ||
case OPEN_FORUM -> URLs.FORUM_URL; | ||
case OPEN_MASTODON -> URLs.MASTODON_URL; | ||
case OPEN_LINKEDIN -> URLs.LINKEDIN_URL; | ||
case DONATE -> URLs.DONATE_URL; | ||
case OPEN_DEV_VERSION_LINK -> URLs.DEV_VERSION_LINK_URL; | ||
case OPEN_CHANGELOG -> URLs.CHANGELOG_URL; | ||
default -> null; | ||
}; | ||
|
||
if (url != null) { | ||
link.setOnAction(e -> new OpenBrowserAction(url, dialogService, preferences.getExternalApplicationsPreferences()).execute()); | ||
} | ||
|
||
if (icon != null) { | ||
link.setGraphic(icon.getGraphicNode()); | ||
} | ||
|
||
return link; | ||
} | ||
|
||
private HBox createVersionContainer() { | ||
HBox container = new HBox(15); | ||
container.setAlignment(Pos.CENTER); | ||
|
||
Label versionLabel = new Label(Localization.lang("Current JabRef version") + ": " + buildInfo.version); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sorry again GOOD: Localization.lang("Current JabRef version: %0", buildInfo.version); Use parameters. Reason: even the |
||
versionLabel.getStyleClass().add("welcome-footer-version"); | ||
|
||
container.getChildren().add(versionLabel); | ||
return container; | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All over JabRef we often use 10 as spacing for
VBox
es andHBox
es.What if you could use it everywhere? How would it look?
I'm just feared of constant values
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just like here: https://github.com/JabRef/jabref/pull/12461/files#diff-83814543084e1de08c7978d3361eb0889b4c77aad0e1365a8a0d53b4484f2b75R87
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure! Will try it out and if it looks fine, will update it to 10.