Skip to content

Commit

Permalink
Logic for counting views is now working correctly (JabRef#10418)
Browse files Browse the repository at this point in the history
  • Loading branch information
ExrosZ-Alt committed Oct 17, 2024
1 parent 5367b87 commit 707e3c0
Show file tree
Hide file tree
Showing 3 changed files with 140 additions and 0 deletions.
32 changes: 32 additions & 0 deletions src/main/java/org/jabref/gui/LibraryTab.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@
import java.io.IOException;
import java.nio.file.Path;
import java.util.Collections;
import java.util.Hashtable;
import java.util.List;
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;

Expand Down Expand Up @@ -44,6 +46,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;
Expand Down Expand Up @@ -95,6 +98,7 @@
import org.jabref.model.entry.field.FieldFactory;
import org.jabref.model.entry.field.StandardField;
import org.jabref.model.groups.GroupTreeNode;
import org.jabref.model.groups.PopularityGroup;
import org.jabref.model.search.SearchQuery;
import org.jabref.model.util.DirectoryMonitor;
import org.jabref.model.util.DirectoryMonitorManager;
Expand All @@ -106,6 +110,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;

Expand Down Expand Up @@ -152,6 +158,11 @@ private enum PanelMode { MAIN_TABLE, MAIN_TABLE_AND_ENTRY_EDITOR }

private SuggestionProviders suggestionProviders;

// Used to track how many views each attachment has.
private Hashtable<BibEntry, Integer> viewCountTable = new Hashtable<>();
private final Path viewStorePath = NativeDesktop.getOtherDataDir().resolve("tracking.mv");
private static final ReentrantLock fileLock = new ReentrantLock();

@SuppressWarnings({"FieldCanBeLocal"})
private Subscription dividerPositionSubscription;

Expand Down Expand Up @@ -573,6 +584,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;
Expand Down Expand Up @@ -1198,4 +1211,23 @@ public String toString() {
public LibraryTabContainer getLibraryTabContainer() {
return tabContainer;
}

private void incrementViewCount(BibEntry entry) {
MVStore mvStore = PopularityGroup.getMVStore();
synchronized (mvStore) {
MVMap<String, Integer> viewCounts = mvStore.openMap("entryViewCounts");
MVMap<String, Long> lastViewTimestamps = mvStore.openMap("lastViewTimestamps");

long currentTime = System.currentTimeMillis();
String uniqueKey = PopularityGroup.getUniqueKeyForEntry(entry);
long lastViewTime = lastViewTimestamps.getOrDefault(uniqueKey, 0L);

if (currentTime - lastViewTime >= 3600000) { // 3600000 milliseconds in one hour
int currentCount = viewCounts.getOrDefault(uniqueKey, 0);
viewCounts.put(uniqueKey, currentCount + 1);
lastViewTimestamps.put(uniqueKey, currentTime);
mvStore.commit(); // Save changes
}
}
}
}
16 changes: 16 additions & 0 deletions src/main/java/org/jabref/gui/desktop/os/NativeDesktop.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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
}

return userDataDir;
}
}
92 changes: 92 additions & 0 deletions src/main/java/org/jabref/model/groups/PopularityGroup.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
package org.jabref.model.groups;

import java.nio.file.Path;
import java.util.Objects;

import org.jabref.model.entry.BibEntry;
import org.jabref.model.entry.field.StandardField;

import org.h2.mvstore.MVMap;
import org.h2.mvstore.MVStore;

import static org.jabref.gui.desktop.os.NativeDesktop.getOtherDataDir;

/**
* This group contains entries that have been viewed more than once.
* {@link StandardField#GROUPS}.
*/
public class PopularityGroup extends AbstractGroup {
private static MVStore mvStore;

public PopularityGroup(String name, GroupHierarchyType context) {
super(name, context);
mvStore = getMVStore();
}

public boolean contains(BibEntry entry) {
int viewCount = getEntryViewCount(entry);
return viewCount > 0;
}

@Override
public AbstractGroup deepCopy() {
// Create a copy of this popularity group with the same tracker and context
return new PopularityGroup(getName(), getHierarchicalContext());
}

@Override
public boolean isDynamic() {
// This group is dynamic since it changes based on view count
return true;
}

@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof PopularityGroup other)) {
return false;
}
return Objects.equals(getName(), other.getName())
&& Objects.equals(getHierarchicalContext(), other.getHierarchicalContext());
}

@Override
public int hashCode() {
return Objects.hash(getName(), getHierarchicalContext());
}

/**
* Retrieves the view count for a given BibEntry.
*
* @param entry The BibEntry whose view count is to be fetched.
* @return The number of views for the BibEntry, or 0 if not found.
*/
public static int getEntryViewCount(BibEntry entry) {
MVMap<String, Integer> viewCounts = mvStore.openMap("entryViewCounts");
String uniqueKey = getUniqueKeyForEntry(entry);

// Log the entry and unique key
System.out.println("BibEntry: " + entry);
System.out.println("UniqueKey: " + uniqueKey);

return viewCounts.getOrDefault(uniqueKey, 0);
}

public static String getUniqueKeyForEntry(BibEntry entry) {
return entry.getField(StandardField.DOI).orElse(
entry.getField(StandardField.KEY).orElse(
String.valueOf(entry.hashCode())
)
);
}

public static synchronized MVStore getMVStore() {
if (mvStore == null) {
Path mvStorePath = getOtherDataDir().resolve("tracking.mv");
mvStore = new MVStore.Builder().fileName(mvStorePath.toString()).open();
}
return mvStore;
}
}

0 comments on commit 707e3c0

Please sign in to comment.