All Downloads are FREE. Search and download functionalities are using the official Maven repository.

javafx.scene.web.WebHistory Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
 */
package javafx.scene.web;

import com.sun.webkit.BackForwardList;
import com.sun.webkit.WebPage;
import com.sun.webkit.event.WCChangeEvent;
import com.sun.webkit.event.WCChangeListener;
import java.net.URL;
import java.util.Date;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.ReadOnlyIntegerProperty;
import javafx.beans.property.ReadOnlyIntegerWrapper;
import javafx.beans.property.ReadOnlyObjectProperty;
import javafx.beans.property.ReadOnlyObjectWrapper;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;

/**
 * The {@code WebHistory} class represents a session history associated with
 * a {@link WebEngine} instance.
 * 
 * A single instance of {@code WebHistory} for a particular web engine can be
 * obtained through the {@link WebEngine#getHistory()} method.
 * 
 * The history is basically a list of entries. Each entry represents a visited page
 * and it provides access to relevant page info, such as URL, title, and the date
 * the page was last visited. Entries in the list are arranged in the order
 * in which the corresponding pages were visited from oldest to newest. The list can
 * be obtained by using the {@link #getEntries()} method.
 * 
 * The history and the corresponding list of entries change as {@code WebEngine} navigates
 * across the web. The list may expand or shrink depending on browser actions. These
 * changes can be listened to by the {@link javafx.collections.ObservableList}
 * API that the list exposes.
 * 
 * The index of the history entry associated with the currently visited page 
 * is represented by the {@link #currentIndexProperty}. The current index can be
 * used to navigate to any entry in the history by using the {@link #go(int)} method. 
 * 
 * The {@link #maxSizeProperty()} sets the maximum history size, which is the size of the
 * history list.
 *
 * @since JavaFX 2.2
 */
public final class WebHistory {
    /**
     * The {@code Entry} class represents a single entry in the session history.
     * An entry instance is associated with the visited page.
     *
     * @since JavaFX 2.2
     */
    public final class Entry {
        private final URL url;
        private final ReadOnlyObjectWrapper title = new ReadOnlyObjectWrapper(this, "title");
        private final ReadOnlyObjectWrapper lastVisitedDate = new ReadOnlyObjectWrapper(this, "lastVisitedDate");
        private final BackForwardList.Entry peer;
        
        private Entry(final BackForwardList.Entry entry) {
            this.url = entry.getURL();
            this.title.set(entry.getTitle());
            this.lastVisitedDate.set(entry.getLastVisitedDate());
            this.peer = entry;
            
            entry.addChangeListener(new WCChangeListener() {
                @Override
                public void stateChanged(WCChangeEvent e) {
                    String _title = entry.getTitle();
                    // null title is acceptable
                    if (_title == null || !_title.equals(getTitle())) {
                        title.set(_title);
                    }
                    
                    Date _date = entry.getLastVisitedDate();
                    // null date is not acceptable
                    if (_date != null && !_date.equals(getLastVisitedDate())) {
                        lastVisitedDate.set(_date);
                    }
                }
            });
        }
         
        /** 
         * Returns the URL of the page. 
         * 
         * @return the url of the page 
         */ 
        public String getUrl() {
            assert url != null;
            return url.toString();
        }
         
        /** 
         * Defines the title of the page. 
         */ 
        public ReadOnlyObjectProperty titleProperty() {
            return title.getReadOnlyProperty();
        }
         
        public String getTitle() {
            return title.get();
        }
         
        /** 
         * Defines the {@link java.util.Date} the page was last visited. 
         */ 
        public ReadOnlyObjectProperty lastVisitedDateProperty() {
            return lastVisitedDate.getReadOnlyProperty();
        }
         
        public Date getLastVisitedDate() {
            return lastVisitedDate.get();
        }
        
        boolean isPeer(BackForwardList.Entry entry) {
            return peer == entry;
        }
        
        @Override
        public String toString() {
            return "[url: " + getUrl()
                 + ", title: " + getTitle()
                 + ", date: " + getLastVisitedDate()
                 + "]";
        }
    }
    
    private final BackForwardList bfl; // backend history impl
    
    private final ObservableList list;
    private final ObservableList ulist; // unmodifiable wrapper
    
    WebHistory(WebPage page) {
        this.list = FXCollections.observableArrayList();
        this.ulist = FXCollections.unmodifiableObservableList(list);
        this.bfl = page.createBackForwardList();
        
        setMaxSize(getMaxSize()); // init default
        
        this.bfl.addChangeListener(new WCChangeListener() {
            @Override
            public void stateChanged(WCChangeEvent e) {
                // 1. Size has increased
                //    - one new entry is appended.
                //    - currentIndex is set to the new entry.
                if (bfl.size() > list.size()) {
                    assert (bfl.size() == list.size() + 1);
                    list.add(new Entry(bfl.getCurrentEntry()));
                    
                    WebHistory.this.setCurrentIndex(list.size() - 1);
                    return;
                }
                
                // 2. Size hasn't changed
                if (bfl.size() == list.size()) {
                    if (list.size() == 0) {
                        return; // no changes
                    }                    
                    assert (list.size() > 0);
                    BackForwardList.Entry last = bfl.get(list.size() - 1);
                    BackForwardList.Entry first = bfl.get(0);
                    
                    // - currentIndex may change
                    if (list.get(list.size() - 1).isPeer(last)) {
                        WebHistory.this.setCurrentIndex(bfl.getCurrentIndex());
                        return;
                    
                    // - first entry is removed.
                    // - one new entry is appended.
                    // - currentIndex is set to the new entry.
                    } else if (!list.get(0).isPeer(first)) {
                        list.remove(0);
                        list.add(new Entry(last));
                        WebHistory.this.setCurrentIndex(bfl.getCurrentIndex());                        
                        return;
                    }
                }
                                
                // 3. Size has decreased or hasn't changed (due to maxSize or navigation)
                //    - one or more entries are popped.
                //    - one new entry may be appended.
                //    - currentIndex may be set to the new entry.
                assert (bfl.size() <= list.size());                
                list.remove(bfl.size(), list.size()); // no-op if equals
                int lastIndex = list.size() - 1;
                if (lastIndex >= 0 && !list.get(lastIndex).isPeer(bfl.get(lastIndex))) {
                    list.remove(lastIndex);
                    list.add(new Entry(bfl.get(lastIndex)));
                }
                WebHistory.this.setCurrentIndex(bfl.getCurrentIndex());
            }
        });
    }
    
    private final ReadOnlyIntegerWrapper currentIndex =
            new ReadOnlyIntegerWrapper(this, "currentIndex");

    /**
     * Defines the index of the current {@code Entry} in the history.
     * The current entry is the entry associated with the currently loaded page.
     * The index belongs to the range of (index >= 0 && index < getEntries().size())
     */
    public ReadOnlyIntegerProperty currentIndexProperty() {
        return currentIndex.getReadOnlyProperty();
    }
     
    public int getCurrentIndex() {
        return currentIndexProperty().get();
    }
    
    private void setCurrentIndex(int value) {
        currentIndex.set(value);
    }
    
    private IntegerProperty maxSize;
     
    /**
     * Defines the maximum size of the history list.
     * If the list reaches its maximum and a new entry is added,
     * the first entry is removed from the history.
     * 

* The value specified for this property can not be negative, otherwise * {@code IllegalArgumentException} is thrown. * * @defaultValue 100 */ public IntegerProperty maxSizeProperty() { if (maxSize == null) { maxSize = new SimpleIntegerProperty(this, "maxSize", 100) { @Override public void set(int value) { if (value < 0) { throw new IllegalArgumentException("value cannot be negative."); } super.set(value); } }; } return maxSize; } public void setMaxSize(int value) { maxSizeProperty().set(value); bfl.setMaximumSize(value); } public int getMaxSize() { return maxSizeProperty().get(); } /** * Returns an unmodifiable observable list of all entries in the history. * * @return list of all history entries */ public ObservableList getEntries() { return ulist; } /** * Navigates the web engine to the URL defined by the {@code Entry} object * within the specified position relative to the current entry. A negative * {@code offset} value specifies the position preceding to the current entry, * and a positive {@code offset} value specifies the position following the * current entry. For example, -1 points to the previous entry, and 1 points * to the next entry, corresponding to pressing a web browser's 'back' * and 'forward' buttons, respectively. * * The zero {@code offset} value is silently ignored (no-op). * * The effective entry position should belong to the rage of [0..size-1]. * Otherwise, {@code IndexOutOfBoundsException} is thrown. * * @param offset a negative value specifies a position preceding the * current entry, a positive value specifies a position following * the current entry, zero value causes no effect * @throws IndexOutOfBoundsException if the effective entry position is out * of range */ public void go(int offset) throws IndexOutOfBoundsException { if (offset == 0) return; int index = getCurrentIndex() + offset; if (index < 0 || index >= list.size()) { throw new IndexOutOfBoundsException("the effective index " + index + " is out of the range [0.." + (list.size() - 1) + "]"); } bfl.setCurrentIndex(index); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy