您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

Table.java 69KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574
  1. /* *************************************************************************
  2. IT Mill Toolkit
  3. Development of Browser User Interfaces Made Easy
  4. Copyright (C) 2000-2006 IT Mill Ltd
  5. *************************************************************************
  6. This product is distributed under commercial license that can be found
  7. from the product package on license.pdf. Use of this product might
  8. require purchasing a commercial license from IT Mill Ltd. For guidelines
  9. on usage, see licensing-guidelines.html
  10. *************************************************************************
  11. For more information, contact:
  12. IT Mill Ltd phone: +358 2 4802 7180
  13. Ruukinkatu 2-4 fax: +358 2 4802 7181
  14. 20540, Turku email: info@itmill.com
  15. Finland company www: www.itmill.com
  16. Primary source for information and releases: www.itmill.com
  17. ********************************************************************** */
  18. package com.itmill.toolkit.ui;
  19. import java.util.ArrayList;
  20. import java.util.Collection;
  21. import java.util.HashMap;
  22. import java.util.HashSet;
  23. import java.util.Iterator;
  24. import java.util.LinkedHashSet;
  25. import java.util.LinkedList;
  26. import java.util.Map;
  27. import java.util.Set;
  28. import java.util.StringTokenizer;
  29. import com.itmill.toolkit.data.Container;
  30. import com.itmill.toolkit.data.Item;
  31. import com.itmill.toolkit.data.Property;
  32. import com.itmill.toolkit.data.util.ContainerOrderedWrapper;
  33. import com.itmill.toolkit.data.util.IndexedContainer;
  34. import com.itmill.toolkit.event.Action;
  35. import com.itmill.toolkit.terminal.KeyMapper;
  36. import com.itmill.toolkit.terminal.PaintException;
  37. import com.itmill.toolkit.terminal.PaintTarget;
  38. import com.itmill.toolkit.terminal.Resource;
  39. import com.itmill.toolkit.terminal.Sizeable;
  40. /**
  41. * <code>TableComponent</code> is used for representing data or components in
  42. * pageable and selectable table.
  43. *
  44. * @author IT Mill Ltd.
  45. * @version
  46. * @VERSION@
  47. * @since 3.0
  48. */
  49. public class Table extends AbstractSelect implements Action.Container,
  50. Container.Ordered, Container.Sortable, Sizeable {
  51. private static final int CELL_KEY = 0;
  52. private static final int CELL_HEADER = 1;
  53. private static final int CELL_ICON = 2;
  54. private static final int CELL_ITEMID = 3;
  55. private static final int CELL_FIRSTCOL = 4;
  56. /**
  57. * Width of the table or -1 if unspecified.
  58. */
  59. private int width = -1;
  60. /**
  61. * Height of the table or -1 if unspecified.
  62. */
  63. private int height = -1;
  64. /**
  65. * Width unit.
  66. */
  67. private int widthUnit = Sizeable.UNITS_PIXELS;
  68. /**
  69. * Height unit.
  70. */
  71. private int heightUnit = Sizeable.UNITS_PIXELS;
  72. /**
  73. * Left column alignment. <b>This is the default behaviour. </b>
  74. */
  75. public static final String ALIGN_LEFT = "b";
  76. /**
  77. * Center column alignment.
  78. */
  79. public static final String ALIGN_CENTER = "c";
  80. /**
  81. * Right column alignment.
  82. */
  83. public static final String ALIGN_RIGHT = "e";
  84. /**
  85. * Column header mode: Column headers are hidden. <b>This is the default
  86. * behaviour. </b>
  87. */
  88. public static final int COLUMN_HEADER_MODE_HIDDEN = -1;
  89. /**
  90. * Column header mode: Property ID:s are used as column headers.
  91. */
  92. public static final int COLUMN_HEADER_MODE_ID = 0;
  93. /**
  94. * Column header mode: Column headers are explicitly specified with
  95. * <code>setColumnHeaders</code>.
  96. */
  97. public static final int COLUMN_HEADER_MODE_EXPLICIT = 1;
  98. /**
  99. * Column header mode: Column headers are explicitly specified with
  100. * <code>setColumnHeaders</code>
  101. */
  102. public static final int COLUMN_HEADER_MODE_EXPLICIT_DEFAULTS_ID = 2;
  103. /**
  104. * Row caption mode: The row headers are hidden. <b>This is the default
  105. * mode. </b>
  106. */
  107. public static final int ROW_HEADER_MODE_HIDDEN = -1;
  108. /**
  109. * Row caption mode: Items Id-objects toString is used as row caption.
  110. */
  111. public static final int ROW_HEADER_MODE_ID = Select.ITEM_CAPTION_MODE_ID;
  112. /**
  113. * Row caption mode: Item-objects toString is used as row caption.
  114. */
  115. public static final int ROW_HEADER_MODE_ITEM = Select.ITEM_CAPTION_MODE_ITEM;
  116. /**
  117. * Row caption mode: Index of the item is used as item caption. The index
  118. * mode can only be used with the containers implementing Container.Indexed
  119. * interface.
  120. */
  121. public static final int ROW_HEADER_MODE_INDEX = Select.ITEM_CAPTION_MODE_INDEX;
  122. /**
  123. * Row caption mode: Item captions are explicitly specified.
  124. */
  125. public static final int ROW_HEADER_MODE_EXPLICIT = Select.ITEM_CAPTION_MODE_EXPLICIT;
  126. /**
  127. * Row caption mode: Item captions are read from property specified with
  128. * <code>setItemCaptionPropertyId</code>.
  129. */
  130. public static final int ROW_HEADER_MODE_PROPERTY = Select.ITEM_CAPTION_MODE_PROPERTY;
  131. /**
  132. * Row caption mode: Only icons are shown, the captions are hidden.
  133. */
  134. public static final int ROW_HEADER_MODE_ICON_ONLY = Select.ITEM_CAPTION_MODE_ICON_ONLY;
  135. /**
  136. * Row caption mode: Item captions are explicitly specified, but if the
  137. * caption is missing, the item id objects <code>toString()</code> is used
  138. * instead.
  139. */
  140. public static final int ROW_HEADER_MODE_EXPLICIT_DEFAULTS_ID = Select.ITEM_CAPTION_MODE_EXPLICIT_DEFAULTS_ID;
  141. /* Private table extensions to Select *********************************** */
  142. /**
  143. * True if column collapsing is allowed.
  144. */
  145. private boolean columnCollapsingAllowed = false;
  146. /**
  147. * True if reordering of columns is allowed on the client side.
  148. */
  149. private boolean columnReorderingAllowed = false;
  150. /**
  151. * Keymapper for column ids.
  152. */
  153. private final KeyMapper columnIdMap = new KeyMapper();
  154. /**
  155. * Holds visible column propertyIds - in order.
  156. */
  157. private LinkedList visibleColumns = new LinkedList();
  158. /**
  159. * Holds propertyIds of currently collapsed columns.
  160. */
  161. private final HashSet collapsedColumns = new HashSet();
  162. /**
  163. * Holds headers for visible columns (by propertyId).
  164. */
  165. private final HashMap columnHeaders = new HashMap();
  166. /**
  167. * Holds icons for visible columns (by propertyId).
  168. */
  169. private final HashMap columnIcons = new HashMap();
  170. /**
  171. * Holds alignments for visible columns (by propertyId).
  172. */
  173. private HashMap columnAlignments = new HashMap();
  174. /**
  175. * Holds column widths in pixels for visible columns (by propertyId).
  176. */
  177. private final HashMap columnWidths = new HashMap();
  178. /**
  179. * Holds value of property pageLength. 0 disables paging.
  180. */
  181. private int pageLength = 15;
  182. /**
  183. * Id the first item on the current page.
  184. */
  185. private Object currentPageFirstItemId = null;
  186. /**
  187. * Index of the first item on the current page.
  188. */
  189. private int currentPageFirstItemIndex = 0;
  190. /**
  191. * Holds value of property pageBuffering.
  192. */
  193. private boolean pageBuffering = false;
  194. /**
  195. * Holds value of property selectable.
  196. */
  197. private boolean selectable = false;
  198. /**
  199. * Holds value of property columnHeaderMode.
  200. */
  201. private int columnHeaderMode = COLUMN_HEADER_MODE_EXPLICIT_DEFAULTS_ID;
  202. /**
  203. * True iff the row captions are hidden.
  204. */
  205. private boolean rowCaptionsAreHidden = true;
  206. /**
  207. * Page contents buffer used in buffered mode.
  208. */
  209. private Object[][] pageBuffer = null;
  210. /**
  211. * List of properties listened - the list is kept to release the listeners
  212. * later.
  213. */
  214. private LinkedList listenedProperties = null;
  215. /**
  216. * List of visible components - the is used for needsRepaint calculation.
  217. */
  218. private LinkedList visibleComponents = null;
  219. /**
  220. * List of action handlers.
  221. */
  222. private LinkedList actionHandlers = null;
  223. /**
  224. * Action mapper.
  225. */
  226. private KeyMapper actionMapper = null;
  227. /**
  228. * Table cell editor factory.
  229. */
  230. private FieldFactory fieldFactory = new BaseFieldFactory();
  231. /**
  232. * Is table editable.
  233. */
  234. private boolean editable = false;
  235. /**
  236. * Current sorting direction.
  237. */
  238. private boolean sortAscending = true;
  239. /**
  240. * Currently table is sorted on this propertyId.
  241. */
  242. private Object sortContainerPropertyId = null;
  243. /**
  244. * Is table sorting disabled alltogether; even if some of the properties
  245. * would be sortable.
  246. */
  247. private boolean sortDisabled = false;
  248. /**
  249. * Number of rows explicitly requested by the client to be painted on next
  250. * paint. This is -1 if no request by the client is made. Painting the
  251. * component will automatically reset this to -1.
  252. */
  253. private int reqRowsToPaint = -1;
  254. /**
  255. * Index of the first rows explicitly requested by the client to be painted.
  256. * This is -1 if no request by the client is made. Painting the component
  257. * will automatically reset this to -1.
  258. */
  259. private int reqFirstRowToPaint = -1;
  260. /* Table constructors *************************************************** */
  261. /**
  262. * Creates a new empty table.
  263. */
  264. public Table() {
  265. setRowHeaderMode(ROW_HEADER_MODE_HIDDEN);
  266. }
  267. /**
  268. * Creates a new empty table with caption.
  269. *
  270. * @param caption
  271. */
  272. public Table(String caption) {
  273. this();
  274. setCaption(caption);
  275. }
  276. /**
  277. * Creates a new table with caption and connect it to a Container.
  278. *
  279. * @param caption
  280. * @param dataSource
  281. */
  282. public Table(String caption, Container dataSource) {
  283. this();
  284. setCaption(caption);
  285. setContainerDataSource(dataSource);
  286. }
  287. /* Table functionality ************************************************** */
  288. /**
  289. * Gets the array of visible column property id:s.
  290. *
  291. * <p>
  292. * The columns are show in the order of their appearance in this array.
  293. * </p>
  294. *
  295. * @return the Value of property availableColumns.
  296. */
  297. public Object[] getVisibleColumns() {
  298. if (this.visibleColumns == null) {
  299. return null;
  300. }
  301. return this.visibleColumns.toArray();
  302. }
  303. /**
  304. * Sets the array of visible column property id:s.
  305. *
  306. * <p>
  307. * The columns are show in the order of their appearance in this array.
  308. * </p>
  309. *
  310. * @param visibleColumns
  311. * the Array of shown property id:s.
  312. */
  313. public void setVisibleColumns(Object[] visibleColumns) {
  314. // Visible columns must exist
  315. if (visibleColumns == null) {
  316. throw new NullPointerException(
  317. "Can not set visible columns to null value");
  318. }
  319. // Checks that the new visible columns contains no nulls and properties
  320. // exist
  321. Collection properties = getContainerPropertyIds();
  322. for (int i = 0; i < visibleColumns.length; i++) {
  323. if (visibleColumns[i] == null) {
  324. throw new NullPointerException("Properties must be non-nulls");
  325. } else if (!properties.contains(visibleColumns[i])) {
  326. throw new IllegalArgumentException(
  327. "Properties must exist in the Container, missing property: "
  328. + visibleColumns[i]);
  329. }
  330. }
  331. // If this is called befor the constructor is finished, it might be
  332. // uninitialized
  333. LinkedList newVC = new LinkedList();
  334. for (int i = 0; i < visibleColumns.length; i++) {
  335. newVC.add(visibleColumns[i]);
  336. }
  337. // Removes alignments, icons and headers from hidden columns
  338. if (this.visibleColumns != null) {
  339. for (Iterator i = this.visibleColumns.iterator(); i.hasNext();) {
  340. Object col = i.next();
  341. if (!newVC.contains(col)) {
  342. setColumnHeader(col, null);
  343. setColumnAlignment(col, null);
  344. setColumnIcon(col, null);
  345. }
  346. }
  347. }
  348. this.visibleColumns = newVC;
  349. // Assures visual refresh
  350. refreshCurrentPage();
  351. }
  352. /**
  353. * Gets the headers of the columns.
  354. *
  355. * <p>
  356. * The headers match the property id:s given my the set visible column
  357. * headers. The table must be set in either
  358. * <code>ROW_HEADER_MODE_EXPLICIT</code> or
  359. * <code>ROW_HEADER_MODE_EXPLICIT_DEFAULTS_ID</code> mode to show the
  360. * headers. In the defaults mode any nulls in the headers array are replaced
  361. * with id.toString() outputs when rendering.
  362. * </p>
  363. *
  364. * @return the Array of column headers.
  365. */
  366. public String[] getColumnHeaders() {
  367. if (this.columnHeaders == null) {
  368. return null;
  369. }
  370. String[] headers = new String[this.visibleColumns.size()];
  371. int i = 0;
  372. for (Iterator it = this.visibleColumns.iterator(); it.hasNext(); i++) {
  373. headers[i] = (String) this.columnHeaders.get(it.next());
  374. }
  375. return headers;
  376. }
  377. /**
  378. * Sets the headers of the columns.
  379. *
  380. * <p>
  381. * The headers match the property id:s given my the set visible column
  382. * headers. The table must be set in either
  383. * <code>ROW_HEADER_MODE_EXPLICIT</code> or
  384. * <code>ROW_HEADER_MODE_EXPLICIT_DEFAULTS_ID</code> mode to show the
  385. * headers. In the defaults mode any nulls in the headers array are replaced
  386. * with id.toString() outputs when rendering.
  387. * </p>
  388. *
  389. * @param columnHeaders
  390. * the Array of column headers that match the
  391. * <code>getVisibleColumns</code> method.
  392. */
  393. public void setColumnHeaders(String[] columnHeaders) {
  394. if (columnHeaders.length != this.visibleColumns.size()) {
  395. throw new IllegalArgumentException(
  396. "The length of the headers array must match the number of visible columns");
  397. }
  398. this.columnHeaders.clear();
  399. int i = 0;
  400. for (Iterator it = this.visibleColumns.iterator(); it.hasNext()
  401. && i < columnHeaders.length; i++) {
  402. this.columnHeaders.put(it.next(), columnHeaders[i]);
  403. }
  404. // Assures the visual refresh
  405. refreshCurrentPage();
  406. }
  407. /**
  408. * Gets the icons of the columns.
  409. *
  410. * <p>
  411. * The icons in headers match the property id:s given my the set visible
  412. * column headers. The table must be set in either
  413. * <code>ROW_HEADER_MODE_EXPLICIT</code> or
  414. * <code>ROW_HEADER_MODE_EXPLICIT_DEFAULTS_ID</code> mode to show the
  415. * headers with icons.
  416. * </p>
  417. *
  418. * @return the Array of icons that match the <code>getVisibleColumns</code>.
  419. */
  420. public Resource[] getColumnIcons() {
  421. if (this.columnIcons == null) {
  422. return null;
  423. }
  424. Resource[] icons = new Resource[this.visibleColumns.size()];
  425. int i = 0;
  426. for (Iterator it = this.visibleColumns.iterator(); it.hasNext(); i++) {
  427. icons[i] = (Resource) this.columnIcons.get(it.next());
  428. }
  429. return icons;
  430. }
  431. /**
  432. * Sets the icons of the columns.
  433. *
  434. * <p>
  435. * The icons in headers match the property id:s given my the set visible
  436. * column headers. The table must be set in either
  437. * <code>ROW_HEADER_MODE_EXPLICIT</code> or
  438. * <code>ROW_HEADER_MODE_EXPLICIT_DEFAULTS_ID</code> mode to show the
  439. * headers with icons.
  440. * </p>
  441. *
  442. * @param columnIcons
  443. * the Array of icons that match the
  444. * <code>getVisibleColumns</code>.
  445. */
  446. public void setColumnIcons(Resource[] columnIcons) {
  447. if (columnIcons.length != this.visibleColumns.size()) {
  448. throw new IllegalArgumentException(
  449. "The length of the icons array must match the number of visible columns");
  450. }
  451. this.columnIcons.clear();
  452. int i = 0;
  453. for (Iterator it = this.visibleColumns.iterator(); it.hasNext()
  454. && i < columnIcons.length; i++) {
  455. this.columnIcons.put(it.next(), columnIcons[i]);
  456. }
  457. // Assure visual refresh
  458. refreshCurrentPage();
  459. }
  460. /**
  461. * Gets the array of column alignments.
  462. *
  463. * <p>
  464. * The items in the array must match the properties identified by
  465. * <code>getVisibleColumns()</code>. The possible values for the
  466. * alignments include:
  467. * <ul>
  468. * <li><code>ALIGN_LEFT</code>: Left alignment</li>
  469. * <li><code>ALIGN_CENTER</code>: Centered</li>
  470. * <li><code>ALIGN_RIGHT</code>: Right alignment</li>
  471. * </ul>
  472. * The alignments default to <code>ALIGN_LEFT</code>: any null values are
  473. * rendered as align lefts.
  474. * </p>
  475. *
  476. * @return the Column alignments array.
  477. */
  478. public String[] getColumnAlignments() {
  479. if (this.columnAlignments == null) {
  480. return null;
  481. }
  482. String[] alignments = new String[this.visibleColumns.size()];
  483. int i = 0;
  484. for (Iterator it = this.visibleColumns.iterator(); it.hasNext(); i++) {
  485. alignments[i++] = getColumnAlignment(it.next());
  486. }
  487. return alignments;
  488. }
  489. /**
  490. * Sets the column alignments.
  491. *
  492. * <p>
  493. * The items in the array must match the properties identified by
  494. * <code>getVisibleColumns()</code>. The possible values for the
  495. * alignments include:
  496. * <ul>
  497. * <li><code>ALIGN_LEFT</code>: Left alignment</li>
  498. * <li><code>ALIGN_CENTER</code>: Centered</li>
  499. * <li><code>ALIGN_RIGHT</code>: Right alignment</li>
  500. * </ul>
  501. * The alignments default to <code>ALIGN_LEFT</code>
  502. * </p>
  503. *
  504. * @param columnAlignments
  505. * the Column alignments array.
  506. */
  507. public void setColumnAlignments(String[] columnAlignments) {
  508. if (columnAlignments.length != this.visibleColumns.size()) {
  509. throw new IllegalArgumentException(
  510. "The length of the alignments array must match the number of visible columns");
  511. }
  512. // Checks all alignments
  513. for (int i = 0; i < columnAlignments.length; i++) {
  514. String a = columnAlignments[i];
  515. if (a != null && !a.equals(ALIGN_LEFT) && !a.equals(ALIGN_CENTER)
  516. && !a.equals(ALIGN_RIGHT)) {
  517. throw new IllegalArgumentException("Column " + i
  518. + " aligment '" + a + "' is invalid");
  519. }
  520. }
  521. // Resets the alignments
  522. HashMap newCA = new HashMap();
  523. int i = 0;
  524. for (Iterator it = this.visibleColumns.iterator(); it.hasNext()
  525. && i < columnAlignments.length; i++) {
  526. newCA.put(it.next(), columnAlignments[i]);
  527. }
  528. this.columnAlignments = newCA;
  529. // Assures the visual refresh
  530. refreshCurrentPage();
  531. }
  532. /**
  533. * Sets columns width (in pixels). Theme may not necessary respect very
  534. * small or very big values. Setting width to -1 (default) means that theme
  535. * will make decision of width.
  536. *
  537. * @param columnId
  538. * colunmns property id
  539. * @param width
  540. * width to be reserved for colunmns content
  541. * @since 4.0.3
  542. */
  543. public void setColumnWidth(Object columnId, int width) {
  544. this.columnWidths.put(columnId, new Integer(width));
  545. }
  546. /**
  547. * Gets the width of column
  548. *
  549. * @param propertyId
  550. * @return width of colun or -1 when value not set
  551. */
  552. public int getColumnWidth(Object propertyId) {
  553. Integer value = (Integer) this.columnWidths.get(propertyId);
  554. if (value == null) {
  555. return -1;
  556. }
  557. return value.intValue();
  558. }
  559. /**
  560. * Gets the page length.
  561. *
  562. * <p>
  563. * Setting page length 0 disables paging.
  564. * </p>
  565. *
  566. * @return the Length of one page.
  567. */
  568. public int getPageLength() {
  569. return this.pageLength;
  570. }
  571. /**
  572. * Sets the page length.
  573. *
  574. * <p>
  575. * Setting page length 0 disables paging. The page length defaults to 15.
  576. * </p>
  577. *
  578. * @param pageLength
  579. * the Length of one page.
  580. */
  581. public void setPageLength(int pageLength) {
  582. if (pageLength >= 0 && this.pageLength != pageLength) {
  583. this.pageLength = pageLength;
  584. // "scroll" to first row
  585. setCurrentPageFirstItemIndex(0);
  586. // Assures the visual refresh
  587. refreshCurrentPage();
  588. }
  589. }
  590. /**
  591. * Getter for property currentPageFirstItem.
  592. *
  593. * @return the Value of property currentPageFirstItem.
  594. */
  595. public Object getCurrentPageFirstItemId() {
  596. // Priorise index over id if indexes are supported
  597. if (this.items instanceof Container.Indexed) {
  598. int index = getCurrentPageFirstItemIndex();
  599. Object id = null;
  600. if (index >= 0 && index < size()) {
  601. id = ((Container.Indexed) this.items).getIdByIndex(index);
  602. }
  603. if (id != null && !id.equals(this.currentPageFirstItemId)) {
  604. this.currentPageFirstItemId = id;
  605. }
  606. }
  607. // If there is no item id at all, use the first one
  608. if (this.currentPageFirstItemId == null) {
  609. this.currentPageFirstItemId = ((Container.Ordered) this.items)
  610. .firstItemId();
  611. }
  612. return this.currentPageFirstItemId;
  613. }
  614. /**
  615. * Setter for property currentPageFirstItemId.
  616. *
  617. * @param currentPageFirstItemId
  618. * the New value of property currentPageFirstItemId.
  619. */
  620. public void setCurrentPageFirstItemId(Object currentPageFirstItemId) {
  621. // Gets the corresponding index
  622. int index = -1;
  623. try {
  624. index = ((Container.Indexed) this.items)
  625. .indexOfId(currentPageFirstItemId);
  626. } catch (ClassCastException e) {
  627. // If the table item container does not have index, we have to
  628. // calculates the index by hand
  629. Object id = ((Container.Ordered) this.items).firstItemId();
  630. while (id != null && !id.equals(currentPageFirstItemId)) {
  631. index++;
  632. id = ((Container.Ordered) this.items).nextItemId(id);
  633. }
  634. if (id == null) {
  635. index = -1;
  636. }
  637. }
  638. // If the search for item index was successfull
  639. if (index >= 0) {
  640. this.currentPageFirstItemId = currentPageFirstItemId;
  641. this.currentPageFirstItemIndex = index;
  642. }
  643. // Assures the visual refresh
  644. refreshCurrentPage();
  645. }
  646. /**
  647. * Gets the icon Resource for the specified column.
  648. *
  649. * @param propertyId
  650. * the propertyId indentifying the column.
  651. * @return the icon for the specified column; null if the column has no icon
  652. * set, or if the column is not visible.
  653. */
  654. public Resource getColumnIcon(Object propertyId) {
  655. return (Resource) this.columnIcons.get(propertyId);
  656. }
  657. /**
  658. * Sets the icon Resource for the specified column.
  659. * <p>
  660. * Throws IllegalArgumentException if the specified column is not visible.
  661. * </p>
  662. *
  663. * @param propertyId
  664. * the propertyId identifying the column.
  665. * @param icon
  666. * the icon Resource to set.
  667. */
  668. public void setColumnIcon(Object propertyId, Resource icon) {
  669. if (icon == null) {
  670. this.columnIcons.remove(propertyId);
  671. } else {
  672. this.columnIcons.put(propertyId, icon);
  673. }
  674. // Assures the visual refresh
  675. refreshCurrentPage();
  676. }
  677. /**
  678. * Gets the header for the specified column.
  679. *
  680. * @param propertyId
  681. * the propertyId indentifying the column.
  682. * @return the header for the specifed column if it has one.
  683. */
  684. public String getColumnHeader(Object propertyId) {
  685. if (getColumnHeaderMode() == COLUMN_HEADER_MODE_HIDDEN) {
  686. return null;
  687. }
  688. String header = (String) this.columnHeaders.get(propertyId);
  689. if ((header == null && getColumnHeaderMode() == COLUMN_HEADER_MODE_EXPLICIT_DEFAULTS_ID)
  690. || getColumnHeaderMode() == COLUMN_HEADER_MODE_ID) {
  691. header = propertyId.toString();
  692. }
  693. return header;
  694. }
  695. /**
  696. * Sets the column header for the specified column;
  697. *
  698. * @param propertyId
  699. * the propertyId indentifying the column.
  700. * @param header
  701. * the header to set.
  702. */
  703. public void setColumnHeader(Object propertyId, String header) {
  704. if (header == null) {
  705. this.columnHeaders.remove(propertyId);
  706. return;
  707. }
  708. this.columnHeaders.put(propertyId, header);
  709. // Assures the visual refresh
  710. refreshCurrentPage();
  711. }
  712. /**
  713. * Gets the specified column's alignment.
  714. *
  715. * @param propertyId
  716. * the propertyID identifying the column.
  717. * @return the specified column's alignment if it as one; null otherwise.
  718. */
  719. public String getColumnAlignment(Object propertyId) {
  720. String a = (String) this.columnAlignments.get(propertyId);
  721. return a == null ? ALIGN_LEFT : a;
  722. }
  723. /**
  724. * Sets the specified column's alignment.
  725. *
  726. * <p>
  727. * Throws IllegalArgumentException if the alignment is not one of the
  728. * following: ALIGN_LEFT, ALIGN_CENTER or ALIGN_RIGHT
  729. * </p>
  730. *
  731. * @param propertyId
  732. * the propertyID identifying the column.
  733. * @param alignment
  734. * the desired alignment.
  735. */
  736. public void setColumnAlignment(Object propertyId, String alignment) {
  737. // Checks for valid alignments
  738. if (alignment != null && !alignment.equals(ALIGN_LEFT)
  739. && !alignment.equals(ALIGN_CENTER)
  740. && !alignment.equals(ALIGN_RIGHT)) {
  741. throw new IllegalArgumentException("Column alignment '" + alignment
  742. + "' is not supported.");
  743. }
  744. if (alignment == null || alignment.equals(ALIGN_LEFT)) {
  745. this.columnAlignments.remove(propertyId);
  746. return;
  747. }
  748. this.columnAlignments.put(propertyId, alignment);
  749. // Assures the visual refresh
  750. refreshCurrentPage();
  751. }
  752. /**
  753. * Checks if the specified column is collapsed.
  754. *
  755. * @param propertyId
  756. * the propertyID identifying the column.
  757. * @return true if the column is collapsed; false otherwise;
  758. */
  759. public boolean isColumnCollapsed(Object propertyId) {
  760. return this.collapsedColumns != null
  761. && this.collapsedColumns.contains(propertyId);
  762. }
  763. /**
  764. * Sets whether the specified column is collapsed or not.
  765. *
  766. *
  767. * @param propertyId
  768. * the propertyID identifying the column.
  769. * @param collapsed
  770. * the desired collapsedness.
  771. * @throws IllegalAccessException
  772. */
  773. public void setColumnCollapsed(Object propertyId, boolean collapsed)
  774. throws IllegalAccessException {
  775. if (!isColumnCollapsingAllowed()) {
  776. throw new IllegalAccessException("Column collapsing not allowed!");
  777. }
  778. if (collapsed) {
  779. this.collapsedColumns.add(propertyId);
  780. } else {
  781. this.collapsedColumns.remove(propertyId);
  782. }
  783. // Assures the visual refresh
  784. refreshCurrentPage();
  785. }
  786. /**
  787. * Checks if column collapsing is allowed.
  788. *
  789. * @return true if columns can be collapsed; false otherwise.
  790. */
  791. public boolean isColumnCollapsingAllowed() {
  792. return this.columnCollapsingAllowed;
  793. }
  794. /**
  795. * Sets whether column collapsing is allowed or not.
  796. *
  797. * @param collapsingAllowed
  798. * specifies whether column collapsing is allowed.
  799. */
  800. public void setColumnCollapsingAllowed(boolean collapsingAllowed) {
  801. this.columnCollapsingAllowed = collapsingAllowed;
  802. if (!collapsingAllowed) {
  803. this.collapsedColumns.clear();
  804. }
  805. // Assures the visual refresh
  806. refreshCurrentPage();
  807. }
  808. /**
  809. * Checks if column reordering is allowed.
  810. *
  811. * @return true if columns can be reordered; false otherwise.
  812. */
  813. public boolean isColumnReorderingAllowed() {
  814. return this.columnReorderingAllowed;
  815. }
  816. /**
  817. * Sets whether column reordering is allowed or not.
  818. *
  819. * @param reorderingAllowed
  820. * specifies whether column reordering is allowed.
  821. */
  822. public void setColumnReorderingAllowed(boolean reorderingAllowed) {
  823. this.columnReorderingAllowed = reorderingAllowed;
  824. // Assures the visual refresh
  825. refreshCurrentPage();
  826. }
  827. /*
  828. * Arranges visible columns according to given columnOrder. Silently ignores
  829. * colimnId:s that are not visible columns, and keeps the internal order of
  830. * visible columns left out of the ordering (trailing). Silently does
  831. * nothing if columnReordering is not allowed.
  832. */
  833. private void setColumnOrder(Object[] columnOrder) {
  834. if (columnOrder == null || !isColumnReorderingAllowed()) {
  835. return;
  836. }
  837. LinkedList newOrder = new LinkedList();
  838. for (int i = 0; i < columnOrder.length; i++) {
  839. if (columnOrder[i] != null
  840. && this.visibleColumns.contains(columnOrder[i])) {
  841. this.visibleColumns.remove(columnOrder[i]);
  842. newOrder.add(columnOrder[i]);
  843. }
  844. }
  845. for (Iterator it = this.visibleColumns.iterator(); it.hasNext();) {
  846. Object columnId = it.next();
  847. if (!newOrder.contains(columnId)) {
  848. newOrder.add(columnId);
  849. }
  850. }
  851. this.visibleColumns = newOrder;
  852. // Assure visual refresh
  853. refreshCurrentPage();
  854. }
  855. /**
  856. * Getter for property currentPageFirstItem.
  857. *
  858. * @return the Value of property currentPageFirstItem.
  859. */
  860. public int getCurrentPageFirstItemIndex() {
  861. return this.currentPageFirstItemIndex;
  862. }
  863. /**
  864. * Setter for property currentPageFirstItem.
  865. *
  866. * @param newIndex
  867. * the New value of property currentPageFirstItem.
  868. */
  869. public void setCurrentPageFirstItemIndex(int newIndex) {
  870. // Ensures that the new value is valid
  871. if (newIndex < 0) {
  872. newIndex = 0;
  873. }
  874. if (newIndex >= size()) {
  875. newIndex = size() - 1;
  876. }
  877. // Refresh first item id
  878. if (this.items instanceof Container.Indexed) {
  879. try {
  880. this.currentPageFirstItemId = ((Container.Indexed) this.items)
  881. .getIdByIndex(newIndex);
  882. } catch (IndexOutOfBoundsException e) {
  883. this.currentPageFirstItemId = null;
  884. }
  885. this.currentPageFirstItemIndex = newIndex;
  886. } else {
  887. // For containers not supporting indexes, we must iterate the
  888. // container forwards / backwards
  889. // next available item forward or backward
  890. this.currentPageFirstItemId = ((Container.Ordered) this.items)
  891. .firstItemId();
  892. // Go forwards in the middle of the list (respect borders)
  893. while (this.currentPageFirstItemIndex < newIndex
  894. && !((Container.Ordered) this.items)
  895. .isLastId(this.currentPageFirstItemId)) {
  896. this.currentPageFirstItemIndex++;
  897. this.currentPageFirstItemId = ((Container.Ordered) this.items)
  898. .nextItemId(this.currentPageFirstItemId);
  899. }
  900. // If we did hit the border
  901. if (((Container.Ordered) this.items)
  902. .isLastId(this.currentPageFirstItemId)) {
  903. this.currentPageFirstItemIndex = size() - 1;
  904. }
  905. // Go backwards in the middle of the list (respect borders)
  906. while (this.currentPageFirstItemIndex > newIndex
  907. && !((Container.Ordered) this.items)
  908. .isFirstId(this.currentPageFirstItemId)) {
  909. this.currentPageFirstItemIndex--;
  910. this.currentPageFirstItemId = ((Container.Ordered) this.items)
  911. .prevItemId(this.currentPageFirstItemId);
  912. }
  913. // If we did hit the border
  914. if (((Container.Ordered) this.items)
  915. .isFirstId(this.currentPageFirstItemId)) {
  916. this.currentPageFirstItemIndex = 0;
  917. }
  918. // Go forwards once more
  919. while (this.currentPageFirstItemIndex < newIndex
  920. && !((Container.Ordered) this.items)
  921. .isLastId(this.currentPageFirstItemId)) {
  922. this.currentPageFirstItemIndex++;
  923. this.currentPageFirstItemId = ((Container.Ordered) this.items)
  924. .nextItemId(this.currentPageFirstItemId);
  925. }
  926. // If for some reason we do hit border again, override
  927. // the user index request
  928. if (((Container.Ordered) this.items)
  929. .isLastId(this.currentPageFirstItemId)) {
  930. newIndex = this.currentPageFirstItemIndex = size() - 1;
  931. }
  932. }
  933. // Assures the visual refresh
  934. refreshCurrentPage();
  935. }
  936. /**
  937. * Getter for property pageBuffering.
  938. *
  939. * @return the Value of property pageBuffering.
  940. */
  941. public boolean isPageBufferingEnabled() {
  942. return this.pageBuffering;
  943. }
  944. /**
  945. * Setter for property pageBuffering.
  946. *
  947. * @param pageBuffering
  948. * the New value of property pageBuffering.
  949. */
  950. public void setPageBufferingEnabled(boolean pageBuffering) {
  951. this.pageBuffering = pageBuffering;
  952. // If page buffering is disabled, clear the buffer
  953. if (!pageBuffering) {
  954. this.pageBuffer = null;
  955. }
  956. }
  957. /**
  958. * Getter for property selectable.
  959. *
  960. * <p>
  961. * The table is not selectable by default.
  962. * </p>
  963. *
  964. * @return the Value of property selectable.
  965. */
  966. public boolean isSelectable() {
  967. return this.selectable;
  968. }
  969. /**
  970. * Setter for property selectable.
  971. *
  972. * <p>
  973. * The table is not selectable by default.
  974. * </p>
  975. *
  976. * @param selectable
  977. * the New value of property selectable.
  978. */
  979. public void setSelectable(boolean selectable) {
  980. if (this.selectable != selectable) {
  981. this.selectable = selectable;
  982. requestRepaint();
  983. }
  984. }
  985. /**
  986. * Getter for property columnHeaderMode.
  987. *
  988. * @return the Value of property columnHeaderMode.
  989. */
  990. public int getColumnHeaderMode() {
  991. return this.columnHeaderMode;
  992. }
  993. /**
  994. * Setter for property columnHeaderMode.
  995. *
  996. * @param columnHeaderMode
  997. * the New value of property columnHeaderMode.
  998. */
  999. public void setColumnHeaderMode(int columnHeaderMode) {
  1000. if (columnHeaderMode >= COLUMN_HEADER_MODE_HIDDEN
  1001. && columnHeaderMode <= COLUMN_HEADER_MODE_EXPLICIT_DEFAULTS_ID) {
  1002. this.columnHeaderMode = columnHeaderMode;
  1003. }
  1004. // Assures the visual refresh
  1005. refreshCurrentPage();
  1006. }
  1007. /**
  1008. * Refreshes the current page contents. If the page buffering is turned off,
  1009. * it is not necessary to call this explicitely.
  1010. */
  1011. public void refreshCurrentPage() {
  1012. // Clear page buffer and notify about the change
  1013. this.pageBuffer = null;
  1014. requestRepaint();
  1015. }
  1016. /**
  1017. * Sets the row header mode.
  1018. * <p>
  1019. * The mode can be one of the following ones:
  1020. * <ul>
  1021. * <li><code>ROW_HEADER_MODE_HIDDEN</code>: The row captions are hidden.
  1022. * </li>
  1023. * <li><code>ROW_HEADER_MODE_ID</code>: Items Id-objects
  1024. * <code>toString()</code> is used as row caption.
  1025. * <li><code>ROW_HEADER_MODE_ITEM</code>: Item-objects
  1026. * <code>toString()</code> is used as row caption.
  1027. * <li><code>ROW_HEADER_MODE_PROPERTY</code>: Property set with
  1028. * <code>setItemCaptionPropertyId()</code> is used as row header.
  1029. * <li><code>ROW_HEADER_MODE_EXPLICIT_DEFAULTS_ID</code>: Items
  1030. * Id-objects <code>toString()</code> is used as row header. If caption is
  1031. * explicitly specified, it overrides the id-caption.
  1032. * <li><code>ROW_HEADER_MODE_EXPLICIT</code>: The row headers must be
  1033. * explicitly specified.</li>
  1034. * <li><code>ROW_HEADER_MODE_INDEX</code>: The index of the item is used
  1035. * as row caption. The index mode can only be used with the containers
  1036. * implementing <code>Container.Indexed</code> interface.</li>
  1037. * </ul>
  1038. * The default value is <code>ROW_HEADER_MODE_HIDDEN</code>
  1039. * </p>
  1040. *
  1041. * @param mode
  1042. * the One of the modes listed above.
  1043. */
  1044. public void setRowHeaderMode(int mode) {
  1045. if (ROW_HEADER_MODE_HIDDEN == mode) {
  1046. this.rowCaptionsAreHidden = true;
  1047. } else {
  1048. this.rowCaptionsAreHidden = false;
  1049. setItemCaptionMode(mode);
  1050. }
  1051. // Assure visual refresh
  1052. refreshCurrentPage();
  1053. }
  1054. /**
  1055. * Gets the row header mode.
  1056. *
  1057. * @return the Row header mode.
  1058. * @see #setRowHeaderMode(int)
  1059. */
  1060. public int getRowHeaderMode() {
  1061. return this.rowCaptionsAreHidden ? ROW_HEADER_MODE_HIDDEN
  1062. : getItemCaptionMode();
  1063. }
  1064. /**
  1065. * Adds the new row to table and fill the visible cells with given values.
  1066. *
  1067. * @param cells
  1068. * the Object array that is used for filling the visible cells
  1069. * new row. The types must be settable to visible column property
  1070. * types.
  1071. * @param itemId
  1072. * the Id the new row. If null, a new id is automatically
  1073. * assigned. If given, the table cant already have a item with
  1074. * given id.
  1075. * @return Returns item id for the new row. Returns null if operation fails.
  1076. */
  1077. public Object addItem(Object[] cells, Object itemId)
  1078. throws UnsupportedOperationException {
  1079. Object[] cols = getVisibleColumns();
  1080. // Checks that a correct number of cells are given
  1081. if (cells.length != cols.length) {
  1082. return null;
  1083. }
  1084. // Creates new item
  1085. Item item;
  1086. if (itemId == null) {
  1087. itemId = this.items.addItem();
  1088. if (itemId == null) {
  1089. return null;
  1090. }
  1091. item = this.items.getItem(itemId);
  1092. } else {
  1093. item = this.items.addItem(itemId);
  1094. }
  1095. if (item == null) {
  1096. return null;
  1097. }
  1098. // Fills the item properties
  1099. for (int i = 0; i < cols.length; i++) {
  1100. item.getItemProperty(cols[i]).setValue(cells[i]);
  1101. }
  1102. return itemId;
  1103. }
  1104. /* Overriding select behavior******************************************** */
  1105. /**
  1106. * Sets the Container that serves as the data source of the viewer.
  1107. *
  1108. * @see com.itmill.toolkit.data.Container.Viewer#setContainerDataSource(Container)
  1109. */
  1110. public void setContainerDataSource(Container newDataSource) {
  1111. if (newDataSource == null) {
  1112. newDataSource = new IndexedContainer();
  1113. }
  1114. // Assures that the data source is ordered by making unordered
  1115. // containers ordered by wrapping them
  1116. if (newDataSource instanceof Container.Ordered) {
  1117. super.setContainerDataSource(newDataSource);
  1118. } else {
  1119. super.setContainerDataSource(new ContainerOrderedWrapper(
  1120. newDataSource));
  1121. }
  1122. // Resets page position
  1123. this.currentPageFirstItemId = null;
  1124. this.currentPageFirstItemIndex = 0;
  1125. // Resets column properties
  1126. if (this.collapsedColumns != null) {
  1127. this.collapsedColumns.clear();
  1128. }
  1129. setVisibleColumns(getContainerPropertyIds().toArray());
  1130. // Assure visual refresh
  1131. refreshCurrentPage();
  1132. }
  1133. /* Component basics ***************************************************** */
  1134. /**
  1135. * Invoked when the value of a variable has changed.
  1136. *
  1137. * @see com.itmill.toolkit.ui.Select#changeVariables(java.lang.Object,
  1138. * java.util.Map)
  1139. */
  1140. public void changeVariables(Object source, Map variables) {
  1141. super.changeVariables(source, variables);
  1142. // Page start index
  1143. if (variables.containsKey("firstvisible")) {
  1144. Integer value = (Integer) variables.get("firstvisible");
  1145. if (value != null) {
  1146. setCurrentPageFirstItemIndex(value.intValue());
  1147. }
  1148. }
  1149. // Sets requested firstrow and rows for the next paint
  1150. if (variables.containsKey("reqfirstrow")
  1151. || variables.containsKey("reqrows")) {
  1152. Integer value = (Integer) variables.get("reqfirstrow");
  1153. if (value != null) {
  1154. this.reqFirstRowToPaint = value.intValue();
  1155. }
  1156. value = (Integer) variables.get("reqrows");
  1157. if (value != null) {
  1158. this.reqRowsToPaint = value.intValue();
  1159. }
  1160. this.pageBuffer = null;
  1161. requestRepaint();
  1162. }
  1163. // Actions
  1164. if (variables.containsKey("action")) {
  1165. StringTokenizer st = new StringTokenizer((String) variables
  1166. .get("action"), ",");
  1167. if (st.countTokens() == 2) {
  1168. Object itemId = this.itemIdMapper.get(st.nextToken());
  1169. Action action = (Action) this.actionMapper.get(st.nextToken());
  1170. if (action != null && containsId(itemId)
  1171. && this.actionHandlers != null) {
  1172. for (Iterator i = this.actionHandlers.iterator(); i
  1173. .hasNext();) {
  1174. ((Action.Handler) i.next()).handleAction(action, this,
  1175. itemId);
  1176. }
  1177. }
  1178. }
  1179. }
  1180. // Sorting
  1181. boolean doSort = false;
  1182. if (!this.sortDisabled) {
  1183. if (variables.containsKey("sortcolumn")) {
  1184. String colId = (String) variables.get("sortcolumn");
  1185. if (colId != null && !"".equals(colId) && !"null".equals(colId)) {
  1186. Object id = this.columnIdMap.get(colId);
  1187. setSortContainerPropertyId(id);
  1188. doSort = true;
  1189. }
  1190. }
  1191. if (variables.containsKey("sortascending")) {
  1192. boolean state = ((Boolean) variables.get("sortascending"))
  1193. .booleanValue();
  1194. if (state != this.sortAscending) {
  1195. setSortAscending(state);
  1196. doSort = true;
  1197. }
  1198. }
  1199. }
  1200. if (doSort) {
  1201. this.sort();
  1202. }
  1203. // Dynamic column hide/show and order
  1204. // Update visible columns
  1205. if (isColumnCollapsingAllowed()) {
  1206. if (variables.containsKey("collapsedcolumns")) {
  1207. try {
  1208. Object[] ids = (Object[]) variables.get("collapsedcolumns");
  1209. for (Iterator it = this.visibleColumns.iterator(); it
  1210. .hasNext();) {
  1211. setColumnCollapsed(it.next(), false);
  1212. }
  1213. for (int i = 0; i < ids.length; i++) {
  1214. setColumnCollapsed(this.columnIdMap.get(ids[i]
  1215. .toString()), true);
  1216. }
  1217. } catch (Exception ignored) {
  1218. }
  1219. }
  1220. }
  1221. if (isColumnReorderingAllowed()) {
  1222. if (variables.containsKey("columnorder")) {
  1223. try {
  1224. Object[] ids = (Object[]) variables.get("columnorder");
  1225. for (int i = 0; i < ids.length; i++) {
  1226. ids[i] = this.columnIdMap.get(ids[i].toString());
  1227. }
  1228. setColumnOrder(ids);
  1229. } catch (Exception ignored) {
  1230. }
  1231. }
  1232. }
  1233. }
  1234. /**
  1235. * Paints the content of this component.
  1236. *
  1237. * @param target
  1238. * the Paint target.
  1239. * @throws PaintException
  1240. * if the paint operation failed.
  1241. */
  1242. public void paintContent(PaintTarget target) throws PaintException {
  1243. // Focus control id
  1244. if (getFocusableId() > 0) {
  1245. target.addAttribute("focusid", getFocusableId());
  1246. }
  1247. // The tab ordering number
  1248. if (getTabIndex() > 0) {
  1249. target.addAttribute("tabindex", getTabIndex());
  1250. }
  1251. // Size
  1252. if (getHeight() >= 0) {
  1253. target.addAttribute("height", "" + getHeight()
  1254. + Sizeable.UNIT_SYMBOLS[getHeightUnits()]);
  1255. }
  1256. if (getWidth() >= 0) {
  1257. target.addAttribute("width", "" + getWidth()
  1258. + Sizeable.UNIT_SYMBOLS[getWidthUnits()]);
  1259. }
  1260. // Initialize temps
  1261. Object[] colids = getVisibleColumns();
  1262. int cols = colids.length;
  1263. int first = getCurrentPageFirstItemIndex();
  1264. int total = size();
  1265. int pagelen = getPageLength();
  1266. int colHeadMode = getColumnHeaderMode();
  1267. boolean colheads = colHeadMode != COLUMN_HEADER_MODE_HIDDEN;
  1268. boolean rowheads = getRowHeaderMode() != ROW_HEADER_MODE_HIDDEN;
  1269. Object[][] cells = getVisibleCells();
  1270. boolean iseditable = isEditable();
  1271. // selection support
  1272. String[] selectedKeys;
  1273. if (isMultiSelect()) {
  1274. selectedKeys = new String[((Set) getValue()).size()];
  1275. } else {
  1276. selectedKeys = new String[(getValue() == null
  1277. && getNullSelectionItemId() == null ? 0 : 1)];
  1278. }
  1279. int keyIndex = 0;
  1280. // Table attributes
  1281. if (isSelectable()) {
  1282. target.addAttribute("selectmode", (isMultiSelect() ? "multi"
  1283. : "single"));
  1284. } else {
  1285. target.addAttribute("selectmode", "none");
  1286. }
  1287. target.addAttribute("cols", cols);
  1288. target.addAttribute("rows", cells[0].length);
  1289. target
  1290. .addAttribute("firstrow",
  1291. (this.reqFirstRowToPaint >= 0 ? this.reqFirstRowToPaint
  1292. : first));
  1293. target.addAttribute("totalrows", total);
  1294. if (pagelen != 0) {
  1295. target.addAttribute("pagelength", pagelen);
  1296. }
  1297. if (colheads) {
  1298. target.addAttribute("colheaders", true);
  1299. }
  1300. if (rowheads) {
  1301. target.addAttribute("rowheaders", true);
  1302. }
  1303. // Visible column order
  1304. Collection sortables = getSortableContainerPropertyIds();
  1305. ArrayList visibleColOrder = new ArrayList();
  1306. for (Iterator it = this.visibleColumns.iterator(); it.hasNext();) {
  1307. Object columnId = it.next();
  1308. if (!isColumnCollapsed(columnId)) {
  1309. visibleColOrder.add(this.columnIdMap.key(columnId));
  1310. }
  1311. }
  1312. target.addAttribute("vcolorder", visibleColOrder.toArray());
  1313. // Rows
  1314. Set actionSet = new LinkedHashSet();
  1315. boolean selectable = isSelectable();
  1316. boolean[] iscomponent = new boolean[this.visibleColumns.size()];
  1317. int iscomponentIndex = 0;
  1318. for (Iterator it = this.visibleColumns.iterator(); it.hasNext()
  1319. && iscomponentIndex < iscomponent.length;) {
  1320. Object columnId = it.next();
  1321. Class colType = getType(columnId);
  1322. iscomponent[iscomponentIndex++] = colType != null
  1323. && Component.class.isAssignableFrom(colType);
  1324. }
  1325. target.startTag("rows");
  1326. for (int i = 0; i < cells[0].length; i++) {
  1327. target.startTag("tr");
  1328. Object itemId = cells[CELL_ITEMID][i];
  1329. // tr attributes
  1330. if (rowheads) {
  1331. if (cells[CELL_ICON][i] != null) {
  1332. target.addAttribute("icon", (Resource) cells[CELL_ICON][i]);
  1333. }
  1334. if (cells[CELL_HEADER][i] != null) {
  1335. target.addAttribute("caption",
  1336. (String) cells[CELL_HEADER][i]);
  1337. }
  1338. }
  1339. target.addAttribute("key", Integer.parseInt(cells[CELL_KEY][i]
  1340. .toString()));
  1341. if (this.actionHandlers != null || isSelectable()) {
  1342. if (isSelected(itemId) && keyIndex < selectedKeys.length) {
  1343. target.addAttribute("selected", true);
  1344. selectedKeys[keyIndex++] = (String) cells[CELL_KEY][i];
  1345. }
  1346. }
  1347. // Actions
  1348. if (this.actionHandlers != null) {
  1349. ArrayList keys = new ArrayList();
  1350. for (Iterator ahi = this.actionHandlers.iterator(); ahi
  1351. .hasNext();) {
  1352. Action[] aa = ((Action.Handler) ahi.next()).getActions(
  1353. itemId, this);
  1354. if (aa != null) {
  1355. for (int ai = 0; ai < aa.length; ai++) {
  1356. String key = this.actionMapper.key(aa[ai]);
  1357. actionSet.add(aa[ai]);
  1358. keys.add(key);
  1359. }
  1360. }
  1361. }
  1362. target.addAttribute("al", keys.toArray());
  1363. }
  1364. // cells
  1365. int currentColumn = 0;
  1366. for (Iterator it = this.visibleColumns.iterator(); it.hasNext(); currentColumn++) {
  1367. Object columnId = it.next();
  1368. if (columnId == null || isColumnCollapsed(columnId)) {
  1369. continue;
  1370. }
  1371. if ((iscomponent[currentColumn] || iseditable)
  1372. && Component.class.isInstance(cells[CELL_FIRSTCOL
  1373. + currentColumn][i])) {
  1374. Component c = (Component) cells[CELL_FIRSTCOL
  1375. + currentColumn][i];
  1376. if (c == null) {
  1377. target.addText("");
  1378. } else {
  1379. c.paint(target);
  1380. }
  1381. } else {
  1382. target
  1383. .addText((String) cells[CELL_FIRSTCOL
  1384. + currentColumn][i]);
  1385. }
  1386. }
  1387. target.endTag("tr");
  1388. }
  1389. target.endTag("rows");
  1390. // The select variable is only enabled if selectable
  1391. if (selectable) {
  1392. target.addVariable(this, "selected", selectedKeys);
  1393. }
  1394. // The cursors are only shown on pageable table
  1395. if (first != 0 || getPageLength() > 0) {
  1396. target.addVariable(this, "firstvisible", first);
  1397. }
  1398. // Sorting
  1399. if (getContainerDataSource() instanceof Container.Sortable) {
  1400. target.addVariable(this, "sortcolumn", this.columnIdMap
  1401. .key(this.sortContainerPropertyId));
  1402. target.addVariable(this, "sortascending", this.sortAscending);
  1403. }
  1404. // Resets and paints "to be painted next" variables. Also reset
  1405. // pageBuffer
  1406. this.reqFirstRowToPaint = -1;
  1407. this.reqRowsToPaint = -1;
  1408. this.pageBuffer = null;
  1409. target.addVariable(this, "reqrows", this.reqRowsToPaint);
  1410. target.addVariable(this, "reqfirstrow", this.reqFirstRowToPaint);
  1411. // Actions
  1412. if (!actionSet.isEmpty()) {
  1413. target.addVariable(this, "action", "");
  1414. target.startTag("actions");
  1415. for (Iterator it = actionSet.iterator(); it.hasNext();) {
  1416. Action a = (Action) it.next();
  1417. target.startTag("action");
  1418. if (a.getCaption() != null) {
  1419. target.addAttribute("caption", a.getCaption());
  1420. }
  1421. if (a.getIcon() != null) {
  1422. target.addAttribute("icon", a.getIcon());
  1423. }
  1424. target.addAttribute("key", this.actionMapper.key(a));
  1425. target.endTag("action");
  1426. }
  1427. target.endTag("actions");
  1428. }
  1429. if (this.columnReorderingAllowed) {
  1430. String[] colorder = new String[this.visibleColumns.size()];
  1431. int i = 0;
  1432. for (Iterator it = this.visibleColumns.iterator(); it.hasNext()
  1433. && i < colorder.length;) {
  1434. colorder[i++] = this.columnIdMap.key(it.next());
  1435. }
  1436. target.addVariable(this, "columnorder", colorder);
  1437. }
  1438. // Available columns
  1439. if (this.columnCollapsingAllowed) {
  1440. HashSet ccs = new HashSet();
  1441. for (Iterator i = this.visibleColumns.iterator(); i.hasNext();) {
  1442. Object o = i.next();
  1443. if (isColumnCollapsed(o)) {
  1444. ccs.add(o);
  1445. }
  1446. }
  1447. String[] collapsedkeys = new String[ccs.size()];
  1448. int nextColumn = 0;
  1449. for (Iterator it = this.visibleColumns.iterator(); it.hasNext()
  1450. && nextColumn < collapsedkeys.length;) {
  1451. Object columnId = it.next();
  1452. if (isColumnCollapsed(columnId)) {
  1453. collapsedkeys[nextColumn++] = this.columnIdMap
  1454. .key(columnId);
  1455. }
  1456. }
  1457. target.addVariable(this, "collapsedcolumns", collapsedkeys);
  1458. }
  1459. target.startTag("visiblecolumns");
  1460. int i = 0;
  1461. for (Iterator it = this.visibleColumns.iterator(); it.hasNext(); i++) {
  1462. Object columnId = it.next();
  1463. if (columnId != null) {
  1464. target.startTag("column");
  1465. target.addAttribute("cid", this.columnIdMap.key(columnId));
  1466. String head = getColumnHeader(columnId);
  1467. target.addAttribute("caption", (head != null ? head : ""));
  1468. if (isColumnCollapsed(columnId)) {
  1469. target.addAttribute("collapsed", true);
  1470. }
  1471. if (colheads) {
  1472. if (getColumnIcon(columnId) != null) {
  1473. target.addAttribute("icon", getColumnIcon(columnId));
  1474. }
  1475. if (sortables.contains(columnId)) {
  1476. target.addAttribute("sortable", true);
  1477. }
  1478. }
  1479. if (!ALIGN_LEFT.equals(getColumnAlignment(columnId))) {
  1480. target.addAttribute("align", getColumnAlignment(columnId));
  1481. }
  1482. if (getColumnWidth(columnId) > -1) {
  1483. target.addAttribute("width", String
  1484. .valueOf(getColumnWidth(columnId)));
  1485. }
  1486. target.endTag("column");
  1487. }
  1488. }
  1489. target.endTag("visiblecolumns");
  1490. }
  1491. /**
  1492. * Gets the UIDL tag corresponding to component.
  1493. *
  1494. * @return the UIDL tag as string.
  1495. */
  1496. public String getTag() {
  1497. return "table";
  1498. }
  1499. /**
  1500. * Gets the cached visible table contents.
  1501. *
  1502. * @return the cahced visible table conetents.
  1503. */
  1504. private Object[][] getVisibleCells() {
  1505. // Returns a buffered value if possible
  1506. if (this.pageBuffer != null && isPageBufferingEnabled()) {
  1507. return this.pageBuffer;
  1508. }
  1509. // Stops listening the old properties and initialise the list
  1510. if (this.listenedProperties == null) {
  1511. this.listenedProperties = new LinkedList();
  1512. } else {
  1513. for (Iterator i = this.listenedProperties.iterator(); i.hasNext();) {
  1514. ((Property.ValueChangeNotifier) i.next()).removeListener(this);
  1515. }
  1516. }
  1517. // Detach old visible component from the table
  1518. if (this.visibleComponents == null) {
  1519. this.visibleComponents = new LinkedList();
  1520. } else {
  1521. for (Iterator i = this.visibleComponents.iterator(); i.hasNext();) {
  1522. ((Component) i.next()).setParent(null);
  1523. }
  1524. this.visibleComponents.clear();
  1525. }
  1526. // Collects the basic facts about the table page
  1527. Object[] colids = getVisibleColumns();
  1528. int cols = colids.length;
  1529. int pagelen = getPageLength();
  1530. int firstIndex = getCurrentPageFirstItemIndex();
  1531. int rows = size();
  1532. if (rows > 0 && firstIndex >= 0) {
  1533. rows -= firstIndex;
  1534. }
  1535. if (pagelen > 0 && pagelen < rows) {
  1536. rows = pagelen;
  1537. }
  1538. // If "to be painted next" variables are set, use them
  1539. if (this.reqRowsToPaint >= 0) {
  1540. rows = this.reqRowsToPaint;
  1541. }
  1542. Object id;
  1543. if (this.reqFirstRowToPaint >= 0 && this.reqFirstRowToPaint < size()) {
  1544. firstIndex = this.reqFirstRowToPaint;
  1545. }
  1546. if (size() > 0) {
  1547. if (rows + firstIndex > size()) {
  1548. rows = size() - firstIndex;
  1549. }
  1550. } else {
  1551. rows = 0;
  1552. }
  1553. Object[][] cells = new Object[cols + CELL_FIRSTCOL][rows];
  1554. if (rows == 0) {
  1555. return cells;
  1556. }
  1557. // Gets the first item id
  1558. if (this.items instanceof Container.Indexed) {
  1559. id = ((Container.Indexed) this.items).getIdByIndex(firstIndex);
  1560. } else {
  1561. id = ((Container.Ordered) this.items).firstItemId();
  1562. for (int i = 0; i < firstIndex; i++) {
  1563. id = ((Container.Ordered) this.items).nextItemId(id);
  1564. }
  1565. }
  1566. int headmode = getRowHeaderMode();
  1567. boolean[] iscomponent = new boolean[cols];
  1568. for (int i = 0; i < cols; i++) {
  1569. iscomponent[i] = Component.class
  1570. .isAssignableFrom(getType(colids[i]));
  1571. }
  1572. // Creates the page contents
  1573. int filledRows = 0;
  1574. for (int i = 0; i < rows && id != null; i++) {
  1575. cells[CELL_ITEMID][i] = id;
  1576. cells[CELL_KEY][i] = this.itemIdMapper.key(id);
  1577. if (headmode != ROW_HEADER_MODE_HIDDEN) {
  1578. switch (headmode) {
  1579. case ROW_HEADER_MODE_INDEX:
  1580. cells[CELL_HEADER][i] = String.valueOf(i + firstIndex + 1);
  1581. break;
  1582. default:
  1583. cells[CELL_HEADER][i] = getItemCaption(id);
  1584. }
  1585. cells[CELL_ICON][i] = getItemIcon(id);
  1586. }
  1587. if (cols > 0) {
  1588. for (int j = 0; j < cols; j++) {
  1589. Object value = null;
  1590. Property p = getContainerProperty(id, colids[j]);
  1591. if (p != null) {
  1592. if (p instanceof Property.ValueChangeNotifier) {
  1593. ((Property.ValueChangeNotifier) p)
  1594. .addListener(this);
  1595. this.listenedProperties.add(p);
  1596. }
  1597. if (iscomponent[j]) {
  1598. value = p.getValue();
  1599. } else if (p != null) {
  1600. value = getPropertyValue(id, colids[j], p);
  1601. } else {
  1602. value = getPropertyValue(id, colids[j], null);
  1603. }
  1604. } else {
  1605. value = "";
  1606. }
  1607. if (value instanceof Component) {
  1608. ((Component) value).setParent(this);
  1609. this.visibleComponents.add(value);
  1610. }
  1611. cells[CELL_FIRSTCOL + j][i] = value;
  1612. }
  1613. }
  1614. id = ((Container.Ordered) this.items).nextItemId(id);
  1615. filledRows++;
  1616. }
  1617. // Assures that all the rows of the cell-buffer are valid
  1618. if (filledRows != cells[0].length) {
  1619. Object[][] temp = new Object[cells.length][filledRows];
  1620. for (int i = 0; i < cells.length; i++) {
  1621. for (int j = 0; j < filledRows; j++) {
  1622. temp[i][j] = cells[i][j];
  1623. }
  1624. }
  1625. cells = temp;
  1626. }
  1627. // Saves the results to internal buffer iff in buffering mode
  1628. // to possible conserve memory from large non-buffered pages
  1629. if (isPageBufferingEnabled()) {
  1630. this.pageBuffer = cells;
  1631. }
  1632. return cells;
  1633. }
  1634. /**
  1635. * Gets the value of property.
  1636. *
  1637. * By default if the table is editable the fieldFactory is used to create
  1638. * editors for table cells. Otherwise formatPropertyValue is used to format
  1639. * the value representation.
  1640. *
  1641. * @param rowId
  1642. * the Id of the row (same as item Id).
  1643. * @param colId
  1644. * the Id of the column.
  1645. * @param property
  1646. * the Property to be presented.
  1647. * @return Object Either formatted value or Component for field.
  1648. * @see #setFieldFactory(FieldFactory)
  1649. */
  1650. protected Object getPropertyValue(Object rowId, Object colId,
  1651. Property property) {
  1652. if (isEditable() && this.fieldFactory != null) {
  1653. Field f = this.fieldFactory.createField(getContainerDataSource(),
  1654. rowId, colId, this);
  1655. if (f != null) {
  1656. f.setPropertyDataSource(property);
  1657. return f;
  1658. }
  1659. }
  1660. return formatPropertyValue(rowId, colId, property);
  1661. }
  1662. /**
  1663. * Formats table cell property values. By default the property.toString()
  1664. * and return a empty string for null properties.
  1665. *
  1666. * @param rowId
  1667. * the Id of the row (same as item Id).
  1668. * @param colId
  1669. * the Id of the column.
  1670. * @param property
  1671. * the Property to be formatted.
  1672. * @return the String representation of property and its value.
  1673. * @since 3.1
  1674. */
  1675. protected String formatPropertyValue(Object rowId, Object colId,
  1676. Property property) {
  1677. if (property == null) {
  1678. return "";
  1679. }
  1680. return property.toString();
  1681. }
  1682. /* Action container *************************************************** */
  1683. /**
  1684. * Registers a new action handler for this container
  1685. *
  1686. * @see com.itmill.toolkit.event.Action.Container#addActionHandler(Action.Handler)
  1687. */
  1688. public void addActionHandler(Action.Handler actionHandler) {
  1689. if (actionHandler != null) {
  1690. if (this.actionHandlers == null) {
  1691. this.actionHandlers = new LinkedList();
  1692. this.actionMapper = new KeyMapper();
  1693. }
  1694. if (!this.actionHandlers.contains(actionHandler)) {
  1695. this.actionHandlers.add(actionHandler);
  1696. requestRepaint();
  1697. }
  1698. }
  1699. }
  1700. /**
  1701. * Removes a previously registered action handler for the contents of this
  1702. * container.
  1703. *
  1704. * @see com.itmill.toolkit.event.Action.Container#removeActionHandler(Action.Handler)
  1705. */
  1706. public void removeActionHandler(Action.Handler actionHandler) {
  1707. if (this.actionHandlers != null
  1708. && this.actionHandlers.contains(actionHandler)) {
  1709. this.actionHandlers.remove(actionHandler);
  1710. if (this.actionHandlers.isEmpty()) {
  1711. this.actionHandlers = null;
  1712. this.actionMapper = null;
  1713. }
  1714. requestRepaint();
  1715. }
  1716. }
  1717. /* Property value change listening support **************************** */
  1718. /**
  1719. * Notifies this listener that the Property's value has changed.
  1720. *
  1721. * @see com.itmill.toolkit.data.Property.ValueChangeListener#valueChange(Property.ValueChangeEvent)
  1722. */
  1723. public void valueChange(Property.ValueChangeEvent event) {
  1724. super.valueChange(event);
  1725. requestRepaint();
  1726. }
  1727. /**
  1728. * Notifies the component that it is connected to an application.
  1729. *
  1730. * @see com.itmill.toolkit.ui.Component#attach()
  1731. */
  1732. public void attach() {
  1733. super.attach();
  1734. if (this.visibleComponents != null) {
  1735. for (Iterator i = this.visibleComponents.iterator(); i.hasNext();) {
  1736. ((Component) i.next()).attach();
  1737. }
  1738. }
  1739. }
  1740. /**
  1741. * Notifies the component that it is detached from the application
  1742. *
  1743. * @see com.itmill.toolkit.ui.Component#detach()
  1744. */
  1745. public void detach() {
  1746. super.detach();
  1747. if (this.visibleComponents != null) {
  1748. for (Iterator i = this.visibleComponents.iterator(); i.hasNext();) {
  1749. ((Component) i.next()).detach();
  1750. }
  1751. }
  1752. }
  1753. /**
  1754. * Removes all Items from the Container.
  1755. *
  1756. * @see com.itmill.toolkit.data.Container#removeAllItems()
  1757. */
  1758. public boolean removeAllItems() {
  1759. this.currentPageFirstItemId = null;
  1760. this.currentPageFirstItemIndex = 0;
  1761. return super.removeAllItems();
  1762. }
  1763. /**
  1764. * Removes the Item identified by <code>ItemId</code> from the Container.
  1765. *
  1766. * @see com.itmill.toolkit.data.Container#removeItem(Object)
  1767. */
  1768. public boolean removeItem(Object itemId) {
  1769. Object nextItemId = ((Container.Ordered) this.items).nextItemId(itemId);
  1770. boolean ret = super.removeItem(itemId);
  1771. if (ret && (itemId != null)
  1772. && (itemId.equals(this.currentPageFirstItemId))) {
  1773. this.currentPageFirstItemId = nextItemId;
  1774. }
  1775. return ret;
  1776. }
  1777. /**
  1778. * Removes a Property specified by the given Property ID from the Container.
  1779. *
  1780. * @see com.itmill.toolkit.data.Container#removeContainerProperty(Object)
  1781. */
  1782. public boolean removeContainerProperty(Object propertyId)
  1783. throws UnsupportedOperationException {
  1784. // If a visible property is removed, remove the corresponding column
  1785. this.visibleColumns.remove(propertyId);
  1786. this.columnAlignments.remove(propertyId);
  1787. this.columnIcons.remove(propertyId);
  1788. this.columnHeaders.remove(propertyId);
  1789. return super.removeContainerProperty(propertyId);
  1790. }
  1791. /**
  1792. * Adds a new property to the table and show it as a visible column.
  1793. *
  1794. * @param propertyId
  1795. * the Id of the proprty.
  1796. * @param type
  1797. * the class of the property.
  1798. * @param defaultValue
  1799. * the default value given for all existing items.
  1800. * @see com.itmill.toolkit.data.Container#addContainerProperty(Object,
  1801. * Class, Object)
  1802. */
  1803. public boolean addContainerProperty(Object propertyId, Class type,
  1804. Object defaultValue) throws UnsupportedOperationException {
  1805. if (!super.addContainerProperty(propertyId, type, defaultValue)) {
  1806. return false;
  1807. }
  1808. if (!this.visibleColumns.contains(propertyId)) {
  1809. this.visibleColumns.add(propertyId);
  1810. }
  1811. return true;
  1812. }
  1813. /**
  1814. * Adds a new property to the table and show it as a visible column.
  1815. *
  1816. * @param propertyId
  1817. * the Id of the proprty
  1818. * @param type
  1819. * the class of the property
  1820. * @param defaultValue
  1821. * the default value given for all existing items
  1822. * @param columnHeader
  1823. * the Explicit header of the column. If explicit header is not
  1824. * needed, this should be set null.
  1825. * @param columnIcon
  1826. * the Icon of the column. If icon is not needed, this should be
  1827. * set null.
  1828. * @param columnAlignment
  1829. * the Alignment of the column. Null implies align left.
  1830. * @throws UnsupportedOperationException
  1831. * if the operation is not supported.
  1832. * @see com.itmill.toolkit.data.Container#addContainerProperty(Object,
  1833. * Class, Object)
  1834. */
  1835. public boolean addContainerProperty(Object propertyId, Class type,
  1836. Object defaultValue, String columnHeader, Resource columnIcon,
  1837. String columnAlignment) throws UnsupportedOperationException {
  1838. if (!this.addContainerProperty(propertyId, type, defaultValue)) {
  1839. return false;
  1840. }
  1841. setColumnAlignment(propertyId, columnAlignment);
  1842. setColumnHeader(propertyId, columnHeader);
  1843. setColumnIcon(propertyId, columnIcon);
  1844. return true;
  1845. }
  1846. /**
  1847. * Returns the list of items on the current page
  1848. *
  1849. * @see com.itmill.toolkit.ui.Select#getVisibleItemIds()
  1850. */
  1851. public Collection getVisibleItemIds() {
  1852. LinkedList visible = new LinkedList();
  1853. Object[][] cells = getVisibleCells();
  1854. for (int i = 0; i < cells[CELL_ITEMID].length; i++) {
  1855. visible.add(cells[CELL_ITEMID][i]);
  1856. }
  1857. return visible;
  1858. }
  1859. /**
  1860. * Container datasource item set change. Table must flush its buffers on
  1861. * change.
  1862. *
  1863. * @see com.itmill.toolkit.data.Container.ItemSetChangeListener#containerItemSetChange(com.itmill.toolkit.data.Container.ItemSetChangeEvent)
  1864. */
  1865. public void containerItemSetChange(Container.ItemSetChangeEvent event) {
  1866. this.pageBuffer = null;
  1867. super.containerItemSetChange(event);
  1868. setCurrentPageFirstItemIndex(getCurrentPageFirstItemIndex());
  1869. }
  1870. /**
  1871. * Container datasource property set change. Table must flush its buffers on
  1872. * change.
  1873. *
  1874. * @see com.itmill.toolkit.data.Container.PropertySetChangeListener#containerPropertySetChange(com.itmill.toolkit.data.Container.PropertySetChangeEvent)
  1875. */
  1876. public void containerPropertySetChange(
  1877. Container.PropertySetChangeEvent event) {
  1878. this.pageBuffer = null;
  1879. super.containerPropertySetChange(event);
  1880. }
  1881. /**
  1882. * Adding new items is not supported.
  1883. *
  1884. * @throws UnsupportedOperationException
  1885. * if set to true.
  1886. * @see com.itmill.toolkit.ui.Select#setNewItemsAllowed(boolean)
  1887. */
  1888. public void setNewItemsAllowed(boolean allowNewOptions)
  1889. throws UnsupportedOperationException {
  1890. if (allowNewOptions) {
  1891. throw new UnsupportedOperationException();
  1892. }
  1893. }
  1894. /**
  1895. * Focusing to this component is not supported.
  1896. *
  1897. * @throws UnsupportedOperationException
  1898. * if invoked.
  1899. * @see com.itmill.toolkit.ui.AbstractField#focus()
  1900. */
  1901. public void focus() throws UnsupportedOperationException {
  1902. throw new UnsupportedOperationException();
  1903. }
  1904. /**
  1905. * Gets the ID of the Item following the Item that corresponds to itemId.
  1906. *
  1907. * @see com.itmill.toolkit.data.Container.Ordered#nextItemId(java.lang.Object)
  1908. */
  1909. public Object nextItemId(Object itemId) {
  1910. return ((Container.Ordered) this.items).nextItemId(itemId);
  1911. }
  1912. /**
  1913. * Gets the ID of the Item preceding the Item that corresponds to the
  1914. * itemId.
  1915. *
  1916. * @see com.itmill.toolkit.data.Container.Ordered#prevItemId(java.lang.Object)
  1917. */
  1918. public Object prevItemId(Object itemId) {
  1919. return ((Container.Ordered) this.items).prevItemId(itemId);
  1920. }
  1921. /**
  1922. * Gets the ID of the first Item in the Container.
  1923. *
  1924. * @see com.itmill.toolkit.data.Container.Ordered#firstItemId()
  1925. */
  1926. public Object firstItemId() {
  1927. return ((Container.Ordered) this.items).firstItemId();
  1928. }
  1929. /**
  1930. * Gets the ID of the last Item in the Container.
  1931. *
  1932. * @see com.itmill.toolkit.data.Container.Ordered#lastItemId()
  1933. */
  1934. public Object lastItemId() {
  1935. return ((Container.Ordered) this.items).lastItemId();
  1936. }
  1937. /**
  1938. * Tests if the Item corresponding to the given Item ID is the first Item in
  1939. * the Container.
  1940. *
  1941. * @see com.itmill.toolkit.data.Container.Ordered#isFirstId(java.lang.Object)
  1942. */
  1943. public boolean isFirstId(Object itemId) {
  1944. return ((Container.Ordered) this.items).isFirstId(itemId);
  1945. }
  1946. /**
  1947. * Tests if the Item corresponding to the given Item ID is the last Item in
  1948. * the Container.
  1949. *
  1950. * @see com.itmill.toolkit.data.Container.Ordered#isLastId(java.lang.Object)
  1951. */
  1952. public boolean isLastId(Object itemId) {
  1953. return ((Container.Ordered) this.items).isLastId(itemId);
  1954. }
  1955. /**
  1956. * Adds new item after the given item.
  1957. *
  1958. * @see com.itmill.toolkit.data.Container.Ordered#addItemAfter(java.lang.Object)
  1959. */
  1960. public Object addItemAfter(Object previousItemId)
  1961. throws UnsupportedOperationException {
  1962. return ((Container.Ordered) this.items).addItemAfter(previousItemId);
  1963. }
  1964. /**
  1965. * Adds new item after the given item.
  1966. *
  1967. * @see com.itmill.toolkit.data.Container.Ordered#addItemAfter(java.lang.Object,
  1968. * java.lang.Object)
  1969. */
  1970. public Item addItemAfter(Object previousItemId, Object newItemId)
  1971. throws UnsupportedOperationException {
  1972. return ((Container.Ordered) this.items).addItemAfter(previousItemId,
  1973. newItemId);
  1974. }
  1975. /**
  1976. * Gets the FieldFactory that is used to create editor for table cells.
  1977. *
  1978. * The FieldFactory is only used if the Table is editable.
  1979. *
  1980. * @return FieldFactory used to create the Field instances.
  1981. * @see #isEditable
  1982. */
  1983. public FieldFactory getFieldFactory() {
  1984. return this.fieldFactory;
  1985. }
  1986. /**
  1987. * Sets the FieldFactory that is used to create editor for table cells.
  1988. *
  1989. * The FieldFactory is only used if the Table is editable. By default the
  1990. * BaseFieldFactory is used.
  1991. *
  1992. * @param fieldFactory
  1993. * the field factory to set.
  1994. * @see #isEditable
  1995. * @see BaseFieldFactory
  1996. *
  1997. */
  1998. public void setFieldFactory(FieldFactory fieldFactory) {
  1999. this.fieldFactory = fieldFactory;
  2000. // Assure visual refresh
  2001. refreshCurrentPage();
  2002. }
  2003. /**
  2004. * Is table editable.
  2005. *
  2006. * If table is editable a editor of type Field is created for each table
  2007. * cell. The assigned FieldFactory is used to create the instances.
  2008. *
  2009. * To provide custom editors for table cells create a class implementins the
  2010. * FieldFactory interface, and assign it to table, and set the editable
  2011. * property to true.
  2012. *
  2013. * @return true if table is editable, false oterwise.
  2014. * @see Field
  2015. * @see FieldFactory
  2016. *
  2017. */
  2018. public boolean isEditable() {
  2019. return this.editable;
  2020. }
  2021. /**
  2022. * Sets the editable property.
  2023. *
  2024. * If table is editable a editor of type Field is created for each table
  2025. * cell. The assigned FieldFactory is used to create the instances.
  2026. *
  2027. * To provide custom editors for table cells create a class implementins the
  2028. * FieldFactory interface, and assign it to table, and set the editable
  2029. * property to true.
  2030. *
  2031. * @param editable
  2032. * true if table should be editable by user.
  2033. * @see Field
  2034. * @see FieldFactory
  2035. *
  2036. */
  2037. public void setEditable(boolean editable) {
  2038. this.editable = editable;
  2039. // Assure visual refresh
  2040. refreshCurrentPage();
  2041. }
  2042. /**
  2043. * Sorts the table.
  2044. *
  2045. * @throws UnsupportedOperationException
  2046. * if the container data source does not implement
  2047. * Container.Sortable
  2048. * @see com.itmill.toolkit.data.Container.Sortable#sort(java.lang.Object[],
  2049. * boolean[])
  2050. *
  2051. */
  2052. public void sort(Object[] propertyId, boolean[] ascending)
  2053. throws UnsupportedOperationException {
  2054. Container c = getContainerDataSource();
  2055. if (c instanceof Container.Sortable) {
  2056. int pageIndex = getCurrentPageFirstItemIndex();
  2057. ((Container.Sortable) c).sort(propertyId, ascending);
  2058. setCurrentPageFirstItemIndex(pageIndex);
  2059. } else if (c != null) {
  2060. throw new UnsupportedOperationException(
  2061. "Underlying Data does not allow sorting");
  2062. }
  2063. }
  2064. /**
  2065. * Sorts the table by currently selected sorting column.
  2066. *
  2067. * @throws UnsupportedOperationException
  2068. * if the container data source does not implement
  2069. * Container.Sortable
  2070. */
  2071. public void sort() {
  2072. if (getSortContainerPropertyId() == null) {
  2073. return;
  2074. }
  2075. sort(new Object[] { this.sortContainerPropertyId },
  2076. new boolean[] { this.sortAscending });
  2077. }
  2078. /**
  2079. * Gets the container property IDs, which can be used to sort the item.
  2080. *
  2081. * @see com.itmill.toolkit.data.Container.Sortable#getSortableContainerPropertyIds()
  2082. */
  2083. public Collection getSortableContainerPropertyIds() {
  2084. Container c = getContainerDataSource();
  2085. if (c instanceof Container.Sortable && !isSortDisabled()) {
  2086. return ((Container.Sortable) c).getSortableContainerPropertyIds();
  2087. } else {
  2088. return new LinkedList();
  2089. }
  2090. }
  2091. /**
  2092. * Gets the currently sorted column property ID.
  2093. *
  2094. * @return the Container property id of the currently sorted column.
  2095. */
  2096. public Object getSortContainerPropertyId() {
  2097. return this.sortContainerPropertyId;
  2098. }
  2099. /**
  2100. * Sets the currently sorted column property id.
  2101. *
  2102. * @param propertyId
  2103. * the Container property id of the currently sorted column.
  2104. */
  2105. public void setSortContainerPropertyId(Object propertyId) {
  2106. if ((this.sortContainerPropertyId != null && !this.sortContainerPropertyId
  2107. .equals(propertyId))
  2108. || (this.sortContainerPropertyId == null && propertyId != null)) {
  2109. this.sortContainerPropertyId = propertyId;
  2110. sort();
  2111. }
  2112. // Assures the visual refresh
  2113. refreshCurrentPage();
  2114. }
  2115. /**
  2116. * Is the table currently sorted in ascending order.
  2117. *
  2118. * @return <code>true</code> if ascending, <code>false</code> if
  2119. * descending.
  2120. */
  2121. public boolean isSortAscending() {
  2122. return this.sortAscending;
  2123. }
  2124. /**
  2125. * Sets the table in ascending order.
  2126. *
  2127. * @param ascending
  2128. * <code>true</code> if ascending, <code>false</code> if
  2129. * descending.
  2130. */
  2131. public void setSortAscending(boolean ascending) {
  2132. if (this.sortAscending != ascending) {
  2133. this.sortAscending = ascending;
  2134. sort();
  2135. }
  2136. // Assures the visual refresh
  2137. refreshCurrentPage();
  2138. }
  2139. /**
  2140. * Is sorting disabled altogether.
  2141. *
  2142. * True iff no sortable columns are given even in the case where data source
  2143. * would support this.
  2144. *
  2145. * @return True iff sorting is disabled.
  2146. */
  2147. public boolean isSortDisabled() {
  2148. return this.sortDisabled;
  2149. }
  2150. /**
  2151. * Disables the sorting altogether.
  2152. *
  2153. * To disable sorting altogether, set to true. In this case no sortable
  2154. * columns are given even in the case where datasource would support this.
  2155. *
  2156. * @param sortDisabled
  2157. * True iff sorting is disabled.
  2158. */
  2159. public void setSortDisabled(boolean sortDisabled) {
  2160. if (this.sortDisabled != sortDisabled) {
  2161. this.sortDisabled = sortDisabled;
  2162. refreshCurrentPage();
  2163. }
  2164. }
  2165. /**
  2166. * Gets height property unit.
  2167. *
  2168. * @see com.itmill.toolkit.terminal.Sizeable#getHeightUnits()
  2169. */
  2170. public int getHeightUnits() {
  2171. return this.heightUnit;
  2172. }
  2173. /**
  2174. * Gets width property unit.
  2175. *
  2176. * @see com.itmill.toolkit.terminal.Sizeable#getWidthUnits()
  2177. */
  2178. public int getWidthUnits() {
  2179. return this.widthUnit;
  2180. }
  2181. /**
  2182. * Sets height units.
  2183. *
  2184. * @see com.itmill.toolkit.terminal.Sizeable#setHeightUnits(int)
  2185. */
  2186. public void setHeightUnits(int units) {
  2187. this.heightUnit = units;
  2188. }
  2189. /**
  2190. * Sets width units. Table supports only Sizeable.UNITS_PIXELS and
  2191. * Sizeable.UNITS_PERCENTAGE. Setting to any other throws
  2192. * IllegalArgumentException.
  2193. *
  2194. * @see com.itmill.toolkit.terminal.Sizeable#setWidthUnits(int)
  2195. */
  2196. public void setWidthUnits(int units) {
  2197. if (units != Sizeable.UNITS_PIXELS
  2198. && units != Sizeable.UNITS_PERCENTAGE) {
  2199. throw new IllegalArgumentException();
  2200. }
  2201. this.widthUnit = units;
  2202. }
  2203. /**
  2204. * Gets height.
  2205. *
  2206. * @return height value as a positive integer or negative value if not
  2207. * assigned.
  2208. * @see com.itmill.toolkit.terminal.Sizeable#getHeight()
  2209. */
  2210. public int getHeight() {
  2211. return this.height;
  2212. }
  2213. /**
  2214. * Gets width.
  2215. *
  2216. * @return width value as positive integer or negative value if not
  2217. * assigned.
  2218. * @see com.itmill.toolkit.terminal.Sizeable#getWidth()
  2219. */
  2220. public int getWidth() {
  2221. return this.width;
  2222. }
  2223. /**
  2224. * Sets height. Use negative value to let the client decide the height.
  2225. *
  2226. * @param height
  2227. * the height to set.
  2228. */
  2229. public void setHeight(int height) {
  2230. this.height = height;
  2231. requestRepaint();
  2232. }
  2233. /**
  2234. * Sets width. Use negative value to allow the client decide the width.
  2235. *
  2236. * @param width
  2237. * the width to set.
  2238. */
  2239. public void setWidth(int width) {
  2240. this.width = width;
  2241. requestRepaint();
  2242. }
  2243. /**
  2244. * Table does not support lazy options loading mode. Setting this true will
  2245. * throw UnsupportedOperationException.
  2246. *
  2247. * @see com.itmill.toolkit.ui.Select#setLazyLoading(boolean)
  2248. */
  2249. public void setLazyLoading(boolean useLazyLoading) {
  2250. if (useLazyLoading) {
  2251. throw new UnsupportedOperationException(
  2252. "Lazy options loading is not supported by Table.");
  2253. }
  2254. }
  2255. /*
  2256. * (non-Javadoc)
  2257. *
  2258. * @see com.itmill.toolkit.terminal.Sizeable#setSizeFull()
  2259. */
  2260. public void setSizeFull() {
  2261. setWidth(100);
  2262. setHeight(100);
  2263. setWidthUnits(UNITS_PERCENTAGE);
  2264. setHeightUnits(UNITS_PERCENTAGE);
  2265. }
  2266. /*
  2267. * (non-Javadoc)
  2268. *
  2269. * @see com.itmill.toolkit.terminal.Sizeable#setSizeUndefined()
  2270. */
  2271. public void setSizeUndefined() {
  2272. setWidth(-1);
  2273. setHeight(-1);
  2274. setWidthUnits(UNITS_PIXELS);
  2275. setHeightUnits(UNITS_PIXELS);
  2276. }
  2277. }