Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Dec 30, 2025

Implements clickable hyperlinks and TOC navigation for PDFs. Links are only active when Ctrl/Cmd is pressed to avoid interfering with annotation workflow.

Changes

Table of Contents

  • New TocTab sidebar extracts PDF outline using PDFBox PDDocumentOutline
  • Tree view displays bookmark hierarchy with page navigation on click
  • Auto-loads on document open, shows placeholder when no TOC exists

Hyperlink Overlays

  • HyperlinkOverlayManager extracts and renders link annotations per page
  • Semi-transparent overlays appear only on Ctrl/Cmd keypress (hidden by default)
  • Supports URL (browser), internal page references (scroll), and mailto (email client)
  • Coordinate conversion accounts for PDF coordinate space → JavaFX page dimensions

Integration

  • PageRenderer: Instantiates overlay manager, extracts links on render
  • Document: Manages show/hide across all pages
  • MainWindow: Keyboard event handlers toggle overlay visibility

Example

When user presses Ctrl/Cmd on a PDF with links:

// In MainWindow keyboard handler
scene.setOnKeyPressed(e -> {
    if(e.isControlDown() || e.isMetaDown()) {
        mainScreen.document.showHyperlinks();  // Show overlays on all pages
    }
});

Link click triggers appropriate action:

// In HyperlinkOverlay
switch(hyperlink.getType()) {
    case URL: hostServices.showDocument(url); break;
    case GOTO: navigateToPage(targetPage); break;
    case MAILTO: hostServices.showDocument(mailto); break;
}

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • clojars.org
    • Triggering command: /usr/lib/jvm/temurin-17-jdk-amd64/bin/java /usr/lib/jvm/temurin-17-jdk-amd64/bin/java --add-opens=java.base/java.util=ALL-UNNAMED --add-opens=java.base/java.lang=ALL-UNNAMED --add-opens=java.base/java.lang.invoke=ALL-UNNAMED --add-opens=java.prefs/java.util.prefs=ALL-UNNAMED --add-opens=java.base/java.nio.charset=ALL-UNNAMED --add-opens=java.base/java.net=ALL-UNNAMED --add-opens=java.base/java.util.concurrent.atomic=ALL-UNNAMED -XX:MaxMetaspaceSize=384m -XX:+HeapDumpOnOutOfMemoryError -Xms256m -Xmx512m -Dfile.encoding=UTF-8 -Duser.country -Duser.language=en -Duser.variant -cp /home/REDACTED/.gradle/wrapper/dists/gradle-8.5-bin/5t9huq95ubn472n8rpzujfbqh/gradle-8.5/lib/gradle-launcher-8.5.jar -javaagent:/home/REDACTED/.gradle/wrapper/dists/gradle-8.5-bin/5t9huq95ubn472n8rpzujfbqh/gradle-8.5/lib/agents/gradle-instrumentation-agent-8.5.jar org.gradle.launcher.daemon.bootstrap.GradleDaemon (dns block)
    • Triggering command: /usr/lib/jvm/temurin-21-jdk-amd64/bin/java /usr/lib/jvm/temurin-21-jdk-amd64/bin/java --add-opens=java.base/java.util=ALL-UNNAMED --add-opens=java.base/java.lang=ALL-UNNAMED --add-opens=java.base/java.lang.invoke=ALL-UNNAMED --add-opens=java.prefs/java.util.prefs=ALL-UNNAMED --add-opens=java.base/java.nio.charset=ALL-UNNAMED --add-opens=java.base/java.net=ALL-UNNAMED --add-opens=java.base/java.util.concurrent.atomic=ALL-UNNAMED -XX:MaxMetaspaceSize=384m -XX:+HeapDumpOnOutOfMemoryError -Xms256m -Xmx512m -Dfile.encoding=UTF-8 -Duser.country -Duser.language=en -Duser.variant -cp /home/REDACTED/.gradle/wrapper/dists/gradle-8.5-bin/5t9huq95ubn472n8rpzujfbqh/gradle-8.5/lib/gradle-launcher-8.5.jar -javaagent:/home/REDACTED/.gradle/wrapper/dists/gradle-8.5-bin/5t9huq95ubn472n8rpzujfbqh/gradle-8.5/lib/agents/gradle-instrumentation-agent-8.5.jar org.gradle.launcher.daemon.bootstrap.GradleDaemon (dns block)
  • jitpack.io
    • Triggering command: /usr/lib/jvm/temurin-17-jdk-amd64/bin/java /usr/lib/jvm/temurin-17-jdk-amd64/bin/java --add-opens=java.base/java.util=ALL-UNNAMED --add-opens=java.base/java.lang=ALL-UNNAMED --add-opens=java.base/java.lang.invoke=ALL-UNNAMED --add-opens=java.prefs/java.util.prefs=ALL-UNNAMED --add-opens=java.base/java.nio.charset=ALL-UNNAMED --add-opens=java.base/java.net=ALL-UNNAMED --add-opens=java.base/java.util.concurrent.atomic=ALL-UNNAMED -XX:MaxMetaspaceSize=384m -XX:+HeapDumpOnOutOfMemoryError -Xms256m -Xmx512m -Dfile.encoding=UTF-8 -Duser.country -Duser.language=en -Duser.variant -cp /home/REDACTED/.gradle/wrapper/dists/gradle-8.5-bin/5t9huq95ubn472n8rpzujfbqh/gradle-8.5/lib/gradle-launcher-8.5.jar -javaagent:/home/REDACTED/.gradle/wrapper/dists/gradle-8.5-bin/5t9huq95ubn472n8rpzujfbqh/gradle-8.5/lib/agents/gradle-instrumentation-agent-8.5.jar org.gradle.launcher.daemon.bootstrap.GradleDaemon (dns block)
    • Triggering command: /usr/lib/jvm/temurin-21-jdk-amd64/bin/java /usr/lib/jvm/temurin-21-jdk-amd64/bin/java --add-opens=java.base/java.util=ALL-UNNAMED --add-opens=java.base/java.lang=ALL-UNNAMED --add-opens=java.base/java.lang.invoke=ALL-UNNAMED --add-opens=java.prefs/java.util.prefs=ALL-UNNAMED --add-opens=java.base/java.nio.charset=ALL-UNNAMED --add-opens=java.base/java.net=ALL-UNNAMED --add-opens=java.base/java.util.concurrent.atomic=ALL-UNNAMED -XX:MaxMetaspaceSize=384m -XX:+HeapDumpOnOutOfMemoryError -Xms256m -Xmx512m -Dfile.encoding=UTF-8 -Duser.country -Duser.language=en -Duser.variant -cp /home/REDACTED/.gradle/wrapper/dists/gradle-8.5-bin/5t9huq95ubn472n8rpzujfbqh/gradle-8.5/lib/gradle-launcher-8.5.jar -javaagent:/home/REDACTED/.gradle/wrapper/dists/gradle-8.5-bin/5t9huq95ubn472n8rpzujfbqh/gradle-8.5/lib/agents/gradle-instrumentation-agent-8.5.jar org.gradle.launcher.daemon.bootstrap.GradleDaemon (dns block)

If you need me to access, download, or install something from one of these locations, you can either:

Original prompt

This section details on the original issue you should resolve

<issue_title>utiliser les liens hypertextes</issue_title>
<issue_description>### Prerequisite

  • I checked this feature was not already requested here

Is your feature request related to a problem? Please describe.

Bonjour,
il semble que les liens hypertextes ne puissent être cliqués dans pdf4teachers.
Tous les pdfs contenants des liens (internes ou externes ou mailto:) que j'ai ouvert ne me permettaient pas de les utiliser.
Alors, certes, pdf4teachers est là pour annoter une copie, mais dans un mémoire quand on demande expressément aux étudiants de produire des sommaires interactifs et des bas de pages avec des liens pour naviguer facilement et que on a l'impression qu'ils ne l'ont pas fait... c'est troublant.

Describe the solution you'd like

Pouvoir cliquer sur les liens hypertextes et que les applications externes s'ouvrent et les liens internes changent l'affichage du doucment en le positionnant à la bonne place.

Describe alternatives you've considered

Je suppose que cela pose des problèmes en termes d'UX pour différencier les objets (annotations, notes, dessins) que pdf4teachers permet d'ajouter et les objets sous-jacents du pdf.
Peut-être que :

  • on peut considérer les objets ajoutés comme systématiquement au dessus des liens natifs pour leur donner la priorité.
  • on pourrait éventuellement si çà simplifie qqch se limiter uniquement aux liens internes au document ?
  • on pourrait avoir un interrupteur sur l'interface des documents (au niveau des menus, à droite ?) pour activer/désactiver la fonctionnalité à volonté si vraiment çà semble compliqué en termes d'UX ?

Merci pour ce formidable outil !

Additional context

No response</issue_description>

<agent_instructions>- Read the table of contents from PDDocument at the loading of a document. Then, add a sidebar item that displays the table of contents and allow to go to a reference.

  • On each PageRenderer, add clickable elements for each hyperlink (urls or inner references). These elements should be on the foreground only when pressing the shortcut key (disable them by default and make them visible only when the shortcut key is pressed).</agent_instructions>

Comments on the Issue (you are @copilot in this section)

@ClementGre En effet, ce serait un bel ajout à PDF4Teachers !

L’application pourrait aussi intégrer un onglet table des matières pour une navigation plus rapide via les signets du PDF.</comment_new>


💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.

Copilot AI and others added 4 commits December 30, 2025 12:18
Co-authored-by: ClementGre <51322714+ClementGre@users.noreply.github.com>
Co-authored-by: ClementGre <51322714+ClementGre@users.noreply.github.com>
Co-authored-by: ClementGre <51322714+ClementGre@users.noreply.github.com>
… by zero risks

Co-authored-by: ClementGre <51322714+ClementGre@users.noreply.github.com>
Copilot AI changed the title [WIP] Add functionality to enable hyperlink clicking in PDFs Add PDF hyperlink navigation and table of contents sidebar Dec 30, 2025
Copilot AI requested a review from ClementGre December 30, 2025 12:28
@ClementGre ClementGre marked this pull request as ready for review December 30, 2025 17:08
@ClementGre ClementGre merged commit 409646c into master Dec 30, 2025
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

utiliser les liens hypertextes

2 participants