Spec-Zone .ru
спецификации, руководства, описания, API
|
001/* 002 * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. 003 */ 004package javafx.scene.web; 005 006import com.sun.webkit.BackForwardList; 007import com.sun.webkit.WebPage; 008import com.sun.webkit.event.WCChangeEvent; 009import com.sun.webkit.event.WCChangeListener; 010import java.net.URL; 011import java.util.Date; 012import javafx.beans.property.IntegerProperty; 013import javafx.beans.property.ReadOnlyIntegerProperty; 014import javafx.beans.property.ReadOnlyIntegerWrapper; 015import javafx.beans.property.ReadOnlyObjectProperty; 016import javafx.beans.property.ReadOnlyObjectWrapper; 017import javafx.beans.property.SimpleIntegerProperty; 018import javafx.collections.FXCollections; 019import javafx.collections.ObservableList; 020 021/** 022 * The {@code WebHistory} class represents a session history associated with 023 * a {@link WebEngine} instance. 024 * 025 * A single instance of {@code WebHistory} for a particular web engine can be 026 * obtained through the {@link WebEngine#getHistory()} method. 027 * 028 * The history is basically a list of entries. Each entry represents a visited page 029 * and it provides access to relevant page info, such as URL, title, and the date 030 * the page was last visited. Entries in the list are arranged in the order 031 * in which the corresponding pages were visited from oldest to newest. The list can 032 * be obtained by using the {@link #getEntries()} method. 033 * 034 * The history and the corresponding list of entries change as {@code WebEngine} navigates 035 * across the web. The list may expand or shrink depending on browser actions. These 036 * changes can be listened to by the {@link javafx.collections.ObservableList} 037 * API that the list exposes. 038 * 039 * The index of the history entry associated with the currently visited page 040 * is represented by the {@link #currentIndexProperty}. The current index can be 041 * used to navigate to any entry in the history by using the {@link #go(int)} method. 042 * 043 * The {@link #maxSizeProperty()} sets the maximum history size, which is the size of the 044 * history list. 045 * 046 * @since 2.2 047 */ 048public final class WebHistory { 049 /** 050 * The {@code Entry} class represents a single entry in the session history. 051 * An entry instance is associated with the visited page. 052 * 053 * @since 2.2 054 */ 055 public final class Entry { 056 private final URL url; 057 private final ReadOnlyObjectWrapper<String> title = new ReadOnlyObjectWrapper(this, "title"); 058 private final ReadOnlyObjectWrapper<Date> lastVisitedDate = new ReadOnlyObjectWrapper(this, "lastVisitedDate"); 059 private final BackForwardList.Entry peer; 060 061 private Entry(final BackForwardList.Entry entry) { 062 this.url = entry.getURL(); 063 this.title.set(entry.getTitle()); 064 this.lastVisitedDate.set(entry.getLastVisitedDate()); 065 this.peer = entry; 066 067 entry.addChangeListener(new WCChangeListener() { 068 @Override 069 public void stateChanged(WCChangeEvent e) { 070 String _title = entry.getTitle(); 071 // null title is acceptable 072 if (_title == null || !_title.equals(getTitle())) { 073 title.set(_title); 074 } 075 076 Date _date = entry.getLastVisitedDate(); 077 // null date is not acceptable 078 if (_date != null && !_date.equals(getLastVisitedDate())) { 079 lastVisitedDate.set(_date); 080 } 081 } 082 }); 083 } 084 085 /** 086 * Returns the URL of the page. 087 * 088 * @return the url of the page 089 */ 090 public String getUrl() { 091 assert url != null; 092 return url.toString(); 093 } 094 095 /** 096 * Defines the title of the page. 097 */ 098 public ReadOnlyObjectProperty<String> titleProperty() { 099 return title.getReadOnlyProperty(); 100 } 101 102 public String getTitle() { 103 return title.get(); 104 } 105 106 /** 107 * Defines the {@link java.util.Date} the page was last visited. 108 */ 109 public ReadOnlyObjectProperty<Date> lastVisitedDateProperty() { 110 return lastVisitedDate.getReadOnlyProperty(); 111 } 112 113 public Date getLastVisitedDate() { 114 return lastVisitedDate.get(); 115 } 116 117 boolean isPeer(BackForwardList.Entry entry) { 118 return peer == entry; 119 } 120 121 @Override 122 public String toString() { 123 return "[url: " + getUrl() 124 + ", title: " + getTitle() 125 + ", date: " + getLastVisitedDate() 126 + "]"; 127 } 128 } 129 130 private final BackForwardList bfl; // backend history impl 131 132 private final ObservableList<Entry> list; 133 private final ObservableList<Entry> ulist; // unmodifiable wrapper 134 135 WebHistory(WebPage page) { 136 this.list = FXCollections.<Entry>observableArrayList(); 137 this.ulist = FXCollections.unmodifiableObservableList(list); 138 this.bfl = page.createBackForwardList(); 139 140 setMaxSize(getMaxSize()); // init default 141 142 this.bfl.addChangeListener(new WCChangeListener() { 143 @Override 144 public void stateChanged(WCChangeEvent e) { 145 // 1. Size has increased 146 // - one new entry is appended. 147 // - currentIndex is set to the new entry. 148 if (bfl.size() > list.size()) { 149 assert (bfl.size() == list.size() + 1); 150 list.add(new Entry(bfl.getCurrentEntry())); 151 152 WebHistory.this.setCurrentIndex(list.size() - 1); 153 return; 154 } 155 156 // 2. Size hasn't changed 157 if (bfl.size() == list.size()) { 158 if (list.size() == 0) { 159 return; // no changes 160 } 161 assert (list.size() > 0); 162 BackForwardList.Entry last = bfl.get(list.size() - 1); 163 BackForwardList.Entry first = bfl.get(0); 164 165 // - currentIndex may change 166 if (list.get(list.size() - 1).isPeer(last)) { 167 WebHistory.this.setCurrentIndex(bfl.getCurrentIndex()); 168 return; 169 170 // - first entry is removed. 171 // - one new entry is appended. 172 // - currentIndex is set to the new entry. 173 } else if (!list.get(0).isPeer(first)) { 174 list.remove(0); 175 list.add(new Entry(last)); 176 WebHistory.this.setCurrentIndex(bfl.getCurrentIndex()); 177 return; 178 } 179 } 180 181 // 3. Size has decreased or hasn't changed (due to maxSize or navigation) 182 // - one or more entries are popped. 183 // - one new entry may be appended. 184 // - currentIndex may be set to the new entry. 185 assert (bfl.size() <= list.size()); 186 list.remove(bfl.size(), list.size()); // no-op if equals 187 int lastIndex = list.size() - 1; 188 if (lastIndex >= 0 && !list.get(lastIndex).isPeer(bfl.get(lastIndex))) { 189 list.remove(lastIndex); 190 list.add(new Entry(bfl.get(lastIndex))); 191 } 192 WebHistory.this.setCurrentIndex(bfl.getCurrentIndex()); 193 } 194 }); 195 } 196 197 private final ReadOnlyIntegerWrapper currentIndex = 198 new ReadOnlyIntegerWrapper(this, "currentIndex"); 199 200 /** 201 * Defines the index of the current {@code Entry} in the history. 202 * The current entry is the entry associated with the currently loaded page. 203 * The index belongs to the range of (<tt>index >= 0 && index < getEntries().size()</tt>) 204 */ 205 public ReadOnlyIntegerProperty currentIndexProperty() { 206 return currentIndex.getReadOnlyProperty(); 207 } 208 209 public int getCurrentIndex() { 210 return currentIndexProperty().get(); 211 } 212 213 private void setCurrentIndex(int value) { 214 currentIndex.set(value); 215 } 216 217 private IntegerProperty maxSize; 218 219 /** 220 * Defines the maximum size of the history list. 221 * If the list reaches its maximum and a new entry is added, 222 * the first entry is removed from the history. 223 * <p> 224 * The value specified for this property can not be negative, otherwise 225 * {@code IllegalArgumentException} is thrown. 226 * 227 * @defaultValue 100 228 */ 229 public IntegerProperty maxSizeProperty() { 230 if (maxSize == null) { 231 maxSize = new SimpleIntegerProperty(this, "maxSize", 100) { 232 @Override 233 public void set(int value) { 234 if (value < 0) { 235 throw new IllegalArgumentException("value cannot be negative."); 236 } 237 super.set(value); 238 } 239 }; 240 } 241 return maxSize; 242 } 243 244 public void setMaxSize(int value) { 245 maxSizeProperty().set(value); 246 bfl.setMaximumSize(value); 247 } 248 249 public int getMaxSize() { 250 return maxSizeProperty().get(); 251 } 252 253 /** 254 * Returns an unmodifiable observable list of all entries in the history. 255 * 256 * @return list of all history entries 257 */ 258 public ObservableList<Entry> getEntries() { 259 return ulist; 260 } 261 262 /** 263 * Navigates the web engine to the URL defined by the {@code Entry} object 264 * within the specified position relative to the current entry. A negative 265 * {@code offset} value specifies the position preceding to the current entry, 266 * and a positive {@code offset} value specifies the position following the 267 * current entry. For example, -1 points to the previous entry, and 1 points 268 * to the next entry, corresponding to pressing a web browser's 'back' 269 * and 'forward' buttons, respectively. 270 * 271 * The zero {@code offset} value is silently ignored (no-op). 272 * 273 * The effective entry position should belong to the rage of [0..size-1]. 274 * Otherwise, {@code IndexOutOfBoundsException} is thrown. 275 * 276 * @param offset a negative value specifies a position preceding the 277 * current entry, a positive value specifies a position following 278 * the current entry, zero value causes no effect 279 * @throws IndexOutOfBoundsException if the effective entry position is out 280 * of range 281 */ 282 public void go(int offset) throws IndexOutOfBoundsException { 283 if (offset == 0) 284 return; 285 286 int index = getCurrentIndex() + offset; 287 if (index < 0 || index >= list.size()) { 288 throw new IndexOutOfBoundsException("the effective index " + index 289 + " is out of the range [0.." 290 + (list.size() - 1) + "]"); 291 } 292 bfl.setCurrentIndex(index); 293 } 294}