/** * i-net software provides programming examples for illustration only, without warranty * either expressed or implied, including, but not limited to, the implied warranties * of merchantability and/or fitness for a particular purpose. This programming example * assumes that you are familiar with the programming language being demonstrated and * the tools used to create and debug procedures. i-net software support professionals * can help explain the functionality of a particular procedure, but they will not modify * these examples to provide added functionality or construct procedures to meet your * specific needs. * * Copyright © 1999-2025 i-net software GmbH, Berlin, Germany. **/ package viewer.bookmark; import java.awt.Component; import java.awt.Dimension; import java.awt.GridLayout; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTree; import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.DefaultTreeModel; import javax.swing.tree.TreePath; import javax.swing.tree.TreeSelectionModel; import com.inet.viewer.NavigationTab; import com.inet.viewer.RenderData; import com.inet.viewer.ReportView; /** * This is an implementation of NavigationTab which offers a bookmark navigation for the report. Using "addBookmark", * bookmarks can be added to the view. When a bookmark is double-clicked, the bookmarked page is navigated to. Also, * bookmarks can be deleted by selecting a bookmark and pressing Delete. * @see samples.viewer.ViewerWithBookmarks */ public class BookmarkView extends JPanel implements NavigationTab { private ReportView reportView; public static final String TITLE = "Bookmarks"; /** * Preferred size of this view. The width is the only thing that matters, since our height will be filled as high as * the window allows. */ private static final Dimension PREFERRED_SIZE = new Dimension( 160, 50 ); private RenderData data = null; private JTree bookmarkTree = new JTree() { // We need to subclass this method so we return the bookmark's name as its display text @Override public String convertValueToText( Object value, boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus ) { if( value instanceof DefaultMutableTreeNode ) { Object obj = ((DefaultMutableTreeNode)value).getUserObject(); if( obj instanceof Bookmark ) { Bookmark bookmark = (Bookmark)obj; return bookmark.getName(); } } return super.convertValueToText( value, selected, expanded, leaf, row, hasFocus ); } }; private MouseListener treeMouseListener = new MouseAdapter() { // Check for double clicks on bookmark nodes, and then navigate to this bookmark's page. @Override public void mousePressed( MouseEvent e ) { if( e.getClickCount() == 2 ) { TreePath treePath = bookmarkTree.getPathForLocation( e.getX(), e.getY() ); if( treePath != null ) { Object value = treePath.getLastPathComponent(); if( value instanceof DefaultMutableTreeNode ) { Object obj = ((DefaultMutableTreeNode)value).getUserObject(); if( obj instanceof Bookmark ) { int page = ((Bookmark)obj).getPage(); reportView.goToPage( page ); } } } } } }; private KeyListener treeKeyListener = new KeyAdapter() { // Check for "DELETE" pressed and then delete the selected bookmark @Override public void keyReleased( KeyEvent e ) { if( e.getKeyCode() == KeyEvent.VK_DELETE ) { TreePath path = bookmarkTree.getSelectionPath(); if( path != null ) { Object value = path.getLastPathComponent(); if( value instanceof DefaultMutableTreeNode ) { Object obj = ((DefaultMutableTreeNode)value).getUserObject(); if( obj instanceof Bookmark ) { treeModel.removeNodeFromParent( (DefaultMutableTreeNode)value ); } } } } } }; // Our root node private DefaultMutableTreeNode rootNode = new DefaultMutableTreeNode( "" ); // Our tree's model private DefaultTreeModel treeModel = new DefaultTreeModel( rootNode ); /** * A simple holder for a bookmark, which consists of a name and a page */ private class Bookmark { private String name; private int page; /** * Create a bookmark * @param name the name of the bookmark * @param page the page */ Bookmark( String name, int page ) { this.setName( name ); this.setPage( page ); } /** * {@inheritDoc} */ @Override public boolean equals( Object obj ) { return(obj instanceof Bookmark && ((Bookmark)obj).getPage() == getPage() && ((Bookmark)obj).getName().equals( getName() )); } /** * Set the bookmark name. * @param name the name to set */ void setName( String name ) { this.name = name; } /** * Get the bookmark name. * @return the name */ String getName() { return name; } /** * Set the page of the bookmark. * @param page the page to set */ void setPage( int page ) { this.page = page; } /** * Get the page of the bookmark. * @return the page */ int getPage() { return page; } } /** * Initialization: initializes the GUI and the underlying JTree model. * @param parent ReportView parent to use for navigation */ public BookmarkView( ReportView parent ) { super( new GridLayout( 1, 0 ) ); this.reportView = parent; bookmarkTree.setModel( treeModel ); initGUI(); } /** * Build the GUI */ private void initGUI() { bookmarkTree.addMouseListener( treeMouseListener ); bookmarkTree.addKeyListener( treeKeyListener ); bookmarkTree.getSelectionModel().setSelectionMode( TreeSelectionModel.SINGLE_TREE_SELECTION ); JScrollPane scrollPane = new JScrollPane( bookmarkTree ); add( scrollPane ); setMinimumSize( PREFERRED_SIZE ); setPreferredSize( PREFERRED_SIZE ); } /** * Adds a bookmark with the given name and page to the bookmark list, unless such a bookmark already exists. * @param name Name to use for the bookmark. This name will show up in the list * @param page Page in the report to jump to in case of a double click on the bookmark. */ public void addBookmark( String name, int page ) { Bookmark bookmark = new Bookmark( name, page ); addIfNecessary( bookmark ); bookmarkTree.expandRow( 0 ); } /** * Check whether the bookmark already exists. If so, do nothing. If not, place in the correct spot (ordered by page) * @param bookmark Bookmark to add if necessary */ private void addIfNecessary( Bookmark bookmark ) { int i = 0; for( ; i < rootNode.getChildCount(); i++ ) { DefaultMutableTreeNode node = (DefaultMutableTreeNode)rootNode.getChildAt( i ); Bookmark tmpBookmark = (Bookmark)node.getUserObject(); if( tmpBookmark.equals( bookmark ) ) { return; } if( tmpBookmark.getPage() > bookmark.getPage() ) { break; } } DefaultMutableTreeNode child = new DefaultMutableTreeNode( bookmark ); treeModel.insertNodeInto( child, rootNode, i ); } /** * {@inheritDoc} */ @Override public String getName() { return TITLE; } /** * {@inheritDoc} */ @Override public RenderData getReportData() { return data; } /** * {@inheritDoc} */ @Override public void init( RenderData renderData ) { this.data = renderData; } /** * {@inheritDoc} */ @Override public void reload() { // ignore a reload. This may mean we have invalid bookmarks, but the // user can always delete them himself, and all they'd do is cause the // report to jump to the end, which is fine. } /** * {@inheritDoc} */ @Override public void showError( Throwable th ) { reportView.showError( th ); } /** * {@inheritDoc} */ @Override public Component getComponent() { return this; } }