001package votorola.a.web.wic; // Copyright 2008-2009, 2012, Michael Allan. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Votorola Software"), to deal in the Votorola Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicence, and/or sell copies of the Votorola Software, and to permit persons to whom the Votorola Software is furnished to do so, subject to the following conditions: The preceding copyright notice and this permission notice shall be included in all copies or substantial portions of the Votorola Software. THE VOTOROLA SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE VOTOROLA SOFTWARE OR THE USE OR OTHER DEALINGS IN THE VOTOROLA SOFTWARE. 002 003import java.util.*; 004import java.util.concurrent.*; 005import org.apache.wicket.Page; 006import votorola.g.lang.*; 007import votorola.g.web.wic.*; 008 009 010/** A navigation bar containing a series of tabs. 011 */ 012public abstract @ThreadSafe class NavBar 013{ 014 015 // - N a v - B a r -------------------------------------------------------------------- 016 017 018 /** The index of the default tab. The implementation of this method in class NavBar 019 * returns zero, which corresponds to the left-hand tab. 020 */ 021 public int defaultTabIndex() { return 0; } 022 023 024 025 /** The hash key for this bar's session scope. 026 */ 027 HashKey hashKey() { return hashKey; } 028 029 030 private final HashKey hashKey = new HashKey(); 031 032 033 034 // /** The runner for the last page viewed beneath this bar; or, if none was viewed, the 035 // * runner of the default tab. 036 // * 037 // * @see #defaultTabIndex() 038 // */ 039 // public final RequestCycleRunner lastRunner( VRequestCycle cycle ) 040 // { 041 // final SessionScope sessionScope = VSession.get().scopeNavBar(); 042 // final int lastIndexOnPath; 043 // { 044 // Integer i = sessionScope.getLastIndexOnPath( hashKey ); 045 // lastIndexOnPath = i == null? defaultTabIndex(): i; 046 // } 047 // final NavTab lastTabOnPath = tabList().get( lastIndexOnPath ); 048 // if( lastTabOnPath instanceof SuperTab ) 049 // { 050 // return ((SuperTab)lastTabOnPath).subBar().lastRunner( cycle ); 051 // } 052 // else return lastTabOnPath.runner( cycle ); 053 // } 054 ///// runners removed on migration to stateless pages 055 056 057 058 /** The tab that controls the visibility of this bar. 059 * 060 * @return the super-tab; or null, if this bar is always visible 061 */ 062 public abstract SuperTab superTab(); 063 064 065 066 /** A list of the navigation tabs contained within this bar. 067 */ 068 public abstract List<NavTab> tabList(); 069 070 071 072 // /** Returns the first tab for a particular page type, within this bar. 073 // * 074 // * @throws IllegalStateException if this bar contains no tab for the specified page type 075 // */ 076 // public final NavTab tabForPageType( Class pageClass, VRequestCycle cycle ) 077 // { 078 // for( NavTab tab: tabList() ) 079 // { 080 // if( !tab.bookmark(cycle).pageClass().equals( pageClass )) continue; 081 // 082 // return tab; 083 // } 084 // throw new IllegalStateException(); 085 // } 086 087 088 089 /** Returns the first tab of a particular tab type, within this bar. 090 * 091 * @throws IllegalStateException if this bar contains no tab of the specified type 092 */ 093 public final NavTab tabOfType( Class<? extends Page> pageClass, VRequestCycle cycle ) 094 { 095 for( NavTab tab: tabList() ) 096 { 097 if( !pageClass.isInstance( tab )) continue; 098 099 return tab; 100 } 101 throw new IllegalStateException(); 102 } 103 104 105 106 // ==================================================================================== 107 108 109 /** Session scope for instances of NavBar. 110 * 111 * @see VSession#scopeNavBar() 112 */ 113 static @ThreadSafe class SessionScope implements java.io.Serializable 114 { 115 116 private static final long serialVersionUID = 0L; 117 118 119 120 /** Constructs a SessionScope. 121 */ 122 SessionScope( VSession session ) { this.session = session; } 123 124 125 126 private final VSession session; 127 128 129 130 // -------------------------------------------------------------------------------- 131 132 133 /** @see #putLastIndexOnPath(NavBar.HashKey,Integer) 134 */ 135 Integer getLastIndexOnPath( HashKey key ) { return lastIndexOnPathMap.get( key ); } 136 137 138 private final ConcurrentHashMap<HashKey,Integer> lastIndexOnPathMap = 139 new ConcurrentHashMap<HashKey,Integer>( /*initial capacity*/32, 140 /*load factor*/0.75f, /*concurrency*/1 ); // only one writer (or reader) typically 141 142 143 144 /** @see #getLastIndexOnPath(NavBar.HashKey) 145 * @see #removeLastIndexOnPath(NavBar.HashKey) 146 */ 147 Integer putLastIndexOnPath( HashKey key, Integer index ) 148 { 149 try{ return lastIndexOnPathMap.put( key, index ); } 150 finally{ session.dirty(); } // per Session API 151 } 152 153 154 155 /** @see #putLastIndexOnPath(NavBar.HashKey,Integer) 156 */ 157 Integer removeLastIndexOnPath( HashKey key ) 158 { 159 try{ return lastIndexOnPathMap.remove( key ); } 160 finally{ session.dirty(); } // per Session API 161 } 162 163 164 165 } 166 167 168 169//// P r i v a t e /////////////////////////////////////////////////////////////////////// 170 171 172 /** A serializeable hash key for instances of NavBar. 173 */ 174 private static @ThreadSafe final class HashKey implements java.io.Serializable {} 175 176 177 178}