-
-
Notifications
You must be signed in to change notification settings - Fork 2.6k
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
Fix for issue #10418 - Added the ability to focus on the most viewed entries #12077
base: main
Are you sure you want to change the base?
Changes from 11 commits
07ead47
0fa8663
d7697a1
15547d3
f215a82
f72b644
bce457e
cbf4b27
1f14d65
8c2efa2
8d96cb5
31e22bd
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 |
---|---|---|
|
@@ -7,6 +7,7 @@ | |
import java.util.Objects; | ||
import java.util.Optional; | ||
import java.util.Random; | ||
import java.util.concurrent.locks.ReentrantLock; | ||
import java.util.function.Supplier; | ||
import java.util.stream.Collectors; | ||
|
||
|
@@ -44,6 +45,7 @@ | |
import org.jabref.gui.autosaveandbackup.AutosaveManager; | ||
import org.jabref.gui.autosaveandbackup.BackupManager; | ||
import org.jabref.gui.collab.DatabaseChangeMonitor; | ||
import org.jabref.gui.desktop.os.NativeDesktop; | ||
import org.jabref.gui.dialogs.AutosaveUiManager; | ||
import org.jabref.gui.entryeditor.EntryEditor; | ||
import org.jabref.gui.exporter.SaveDatabaseAction; | ||
|
@@ -55,6 +57,7 @@ | |
import org.jabref.gui.maintable.MainTable; | ||
import org.jabref.gui.maintable.MainTableDataModel; | ||
import org.jabref.gui.preferences.GuiPreferences; | ||
import org.jabref.gui.preferences.entry.EntryTabViewModel; | ||
import org.jabref.gui.undo.CountingUndoManager; | ||
import org.jabref.gui.undo.NamedCompound; | ||
import org.jabref.gui.undo.RedoAction; | ||
|
@@ -94,6 +97,7 @@ | |
import org.jabref.model.entry.field.Field; | ||
import org.jabref.model.entry.field.FieldFactory; | ||
import org.jabref.model.groups.GroupTreeNode; | ||
import org.jabref.model.groups.PopularityGroup; | ||
import org.jabref.model.search.query.SearchQuery; | ||
import org.jabref.model.util.DirectoryMonitor; | ||
import org.jabref.model.util.DirectoryMonitorManager; | ||
|
@@ -105,6 +109,8 @@ | |
import com.tobiasdiez.easybind.Subscription; | ||
import org.controlsfx.control.NotificationPane; | ||
import org.controlsfx.control.action.Action; | ||
import org.h2.mvstore.MVMap; | ||
import org.h2.mvstore.MVStore; | ||
import org.slf4j.Logger; | ||
import org.slf4j.LoggerFactory; | ||
|
||
|
@@ -151,6 +157,10 @@ private enum PanelMode { MAIN_TABLE, MAIN_TABLE_AND_ENTRY_EDITOR } | |
|
||
private SuggestionProviders suggestionProviders; | ||
|
||
// Used to track how many views each attachment has. | ||
private final Path viewStorePath = NativeDesktop.getOtherDataDir().resolve("tracking.mv"); | ||
private final ReentrantLock fileLock = new ReentrantLock(); | ||
|
||
@SuppressWarnings({"FieldCanBeLocal"}) | ||
private Subscription dividerPositionSubscription; | ||
|
||
|
@@ -572,6 +582,8 @@ public EntryEditor getEntryEditor() { | |
* @param entry The entry to edit. | ||
*/ | ||
public void showAndEdit(BibEntry entry) { | ||
incrementViewCount(entry); | ||
|
||
if (!splitPane.getItems().contains(entryEditor)) { | ||
splitPane.getItems().addLast(entryEditor); | ||
mode = PanelMode.MAIN_TABLE_AND_ENTRY_EDITOR; | ||
|
@@ -1197,4 +1209,26 @@ public String toString() { | |
public LibraryTabContainer getLibraryTabContainer() { | ||
return tabContainer; | ||
} | ||
|
||
/** | ||
* Takes an entry and increments the number of times it has been viewed by 1. | ||
*/ | ||
Comment on lines
+1209
to
+1211
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. It does more - there is a kind of if |
||
private void incrementViewCount(BibEntry entry) { | ||
MVStore mvStore = PopularityGroup.getMVStore(); | ||
synchronized (mvStore) { | ||
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. if the maps are opened after load, there is no need for |
||
MVMap<String, Integer> viewCounts = mvStore.openMap("entryViewCounts"); | ||
MVMap<String, Long> lastViewTimestamps = mvStore.openMap("lastViewTimestamps"); | ||
Comment on lines
+1215
to
+1216
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. Nono - the map is a class variable - no need to open the map each time for writing. You need to shut down the mvstore when the tab is closed. The the lifecycle of the AiService or search for examples. |
||
|
||
long currentTime = System.currentTimeMillis(); | ||
String uniqueKey = PopularityGroup.getUniqueKeyForEntry(entry); | ||
long lastViewTime = lastViewTimestamps.getOrDefault(uniqueKey, 0L); | ||
|
||
if (currentTime - lastViewTime >= 3600000 && EntryTabViewModel.trackViewsProperty().get()) { // 3600000 milliseconds in one hour | ||
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. Introduce constant 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. You can also use |
||
int currentCount = viewCounts.getOrDefault(uniqueKey, 0); | ||
viewCounts.put(uniqueKey, currentCount + 1); | ||
lastViewTimestamps.put(uniqueKey, currentTime); | ||
mvStore.commit(); // Save changes | ||
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. AI comment. Delete. |
||
} | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -34,6 +34,7 @@ | |
import org.jabref.model.entry.identifier.Identifier; | ||
|
||
import com.airhacks.afterburner.injection.Injector; | ||
import net.harawata.appdirs.AppDirsFactory; | ||
import org.slf4j.LoggerFactory; | ||
|
||
import static org.jabref.model.entry.field.StandardField.PDF; | ||
|
@@ -386,4 +387,19 @@ public void moveToTrash(Path path) { | |
public boolean moveToTrashSupported() { | ||
return Desktop.getDesktop().isSupported(Desktop.Action.MOVE_TO_TRASH); | ||
} | ||
|
||
public static Path getOtherDataDir() { | ||
Path userDataDir = Path.of(AppDirsFactory.getInstance().getUserDataDir( | ||
OS.APP_DIR_APP_NAME, | ||
"views", | ||
OS.APP_DIR_APP_AUTHOR)); | ||
|
||
try { | ||
Files.createDirectories(userDataDir); | ||
} catch (IOException e) { | ||
// Update this for more elegant error handling | ||
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. AI generated. Pleasemwork on this |
||
} | ||
|
||
return userDataDir; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -23,6 +23,7 @@ | |
<ToggleGroup fx:id="hierarchicalContext"/> | ||
<ToggleGroup fx:id="type"/> | ||
<ToggleGroup fx:id="autoGroupOptions"/> | ||
<ToggleGroup fx:id="popularityOptions"/> | ||
</fx:define> | ||
<VBox spacing="10.0" minWidth="200"> | ||
<padding> | ||
|
@@ -99,6 +100,12 @@ | |
<Tooltip text="%Group containing entries cited in a given TeX file"/> | ||
</tooltip> | ||
</RadioButton> | ||
<RadioButton fx:id="popularityButton" toggleGroup="$type" wrapText="true" | ||
text="%Popularity"> | ||
<tooltip> | ||
<Tooltip text="%Group containing entries cited in a given TeX file"/> | ||
</tooltip> | ||
</RadioButton> | ||
Comment on lines
+103
to
+108
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. This is another functionality. CHANGELOG only talks about view count. Did you work on another issue, too? |
||
</VBox> | ||
<Separator orientation="VERTICAL"/> | ||
<StackPane HBox.hgrow="ALWAYS"> | ||
|
@@ -183,6 +190,12 @@ | |
<Button onAction="#texGroupBrowse" text="%Browse" prefHeight="30.0"/> | ||
</HBox> | ||
</VBox> | ||
<VBox visible="${popularityButton.selected}" spacing="10.0"> | ||
<Label text="%Time Period"/> | ||
<ComboBox fx:id="timePeriodCombo"/> | ||
<Label text="%Maximum Number of Entries"/> | ||
<ComboBox fx:id="maxEntriesCombo"/> | ||
</VBox> | ||
</StackPane> | ||
</HBox> | ||
</VBox> | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -81,6 +81,7 @@ public class GroupDialogView extends BaseDialog<AbstractGroup> { | |
@FXML private RadioButton searchRadioButton; | ||
@FXML private RadioButton autoRadioButton; | ||
@FXML private RadioButton texRadioButton; | ||
@FXML private RadioButton popularityButton; | ||
|
||
// Option Groups | ||
@FXML private TextField keywordGroupSearchTerm; | ||
|
@@ -101,6 +102,9 @@ public class GroupDialogView extends BaseDialog<AbstractGroup> { | |
|
||
@FXML private TextField texGroupFilePath; | ||
|
||
@FXML private ComboBox<String> timePeriodCombo; | ||
@FXML private ComboBox<Integer> maxEntriesCombo; | ||
|
||
private final EnumMap<GroupHierarchyType, String> hierarchyText = new EnumMap<>(GroupHierarchyType.class); | ||
private final EnumMap<GroupHierarchyType, String> hierarchyToolTip = new EnumMap<>(GroupHierarchyType.class); | ||
|
||
|
@@ -201,6 +205,15 @@ public void initialize() { | |
searchRadioButton.selectedProperty().bindBidirectional(viewModel.typeSearchProperty()); | ||
autoRadioButton.selectedProperty().bindBidirectional(viewModel.typeAutoProperty()); | ||
texRadioButton.selectedProperty().bindBidirectional(viewModel.typeTexProperty()); | ||
popularityButton.selectedProperty().bindBidirectional(viewModel.typePopularityProperty()); | ||
popularityButton.disableProperty().bind(viewModel.trackViewsEnabledProperty().not()); | ||
|
||
timePeriodCombo.visibleProperty().bind(popularityButton.selectedProperty()); | ||
maxEntriesCombo.visibleProperty().bind(popularityButton.selectedProperty()); | ||
timePeriodCombo.valueProperty().bindBidirectional(viewModel.timePeriodProperty()); | ||
maxEntriesCombo.valueProperty().bindBidirectional(viewModel.maxEntriesProperty()); | ||
timePeriodCombo.setItems(FXCollections.observableArrayList("Last week", "Last month", "Last year", "All time")); | ||
maxEntriesCombo.setItems(FXCollections.observableArrayList(10, 20, 50, 100, 999)); | ||
Comment on lines
+211
to
+216
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. Please group by button, not by method. Otherwise, it is hard to read. |
||
|
||
keywordGroupSearchTerm.textProperty().bindBidirectional(viewModel.keywordGroupSearchTermProperty()); | ||
keywordGroupSearchField.textProperty().bindBidirectional(viewModel.keywordGroupSearchFieldProperty()); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -54,4 +54,15 @@ | |
<Label styleClass="sectionHeader" text="%Time stamp"/> | ||
<CheckBox fx:id="addCreationDate" text="%Add timestamp to new entries (field "creationdate")"/> | ||
<CheckBox fx:id="addModificationDate" text="%Add timestamp to modified entries (field "modificationdate")"/> | ||
|
||
|
||
|
||
<CheckBox fx:id="enableViewTracking" text="%Enable user behaviour analysis"/> | ||
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.
|
||
<CheckBox fx:id="trackViews" text="%Track entry views" | ||
disable="${!enableViewTracking.selected}"> | ||
<padding> | ||
<Insets left="20.0"/> | ||
</padding> | ||
</CheckBox> | ||
|
||
</fx:root> |
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.
what is this useful for?
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.
Sorry about that, I was having issues with file locks earlier in development and forgot to remove the import and some variables I never used.