Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

Migrate 7.7.5 branch patches to v8. (#7969) * Prevent adding several scrollbar handlers (#19189). Change-Id: Ib0cc6c6835aab6d263f153362a328bcf2be7bc5c * Prevent adding several scrollbar handlers (#19189). * Keep expand ratio for last row/column when reducing grid layout size (#20297) Change-Id: Iff53a803596f4fc1eae8e4bfa307b9c1f4df961a * Fixed drag and drop failure when message dragged from email client (#20451) When dragging message form email client on Windows, item.webkitGetAsEntry() might return null creating NPE on the client side. Added additional checks for this situation. Change-Id: I569f7e6d0d7b137f24be53d1fbce384695ae8c73 * Change expected pre-release version number pattern in publish report Change-Id: Icdacecc490d2490ea9e262f5c5736c1dece2a89d * Mark TextField/TextArea as busy when a text change event is pending (#20469) Change-Id: I404985ae0be1e7dc65171b610032f8649e700f50 # Conflicts: # client/src/main/java/com/vaadin/client/ui/VTextField.java # uitest/src/main/java/com/vaadin/tests/components/textfield/TextChangeEvents.java * Fixed touch scrolling issue in Surface and WP devices (#18737) Fixed by using pointerevents instead of touchevents when the browser is IE11, or Edge. Also added touch-action: none; css rules into escalator.css to prevent default touch behaviour on IE11 and Edge. Does not affect IE8 to IE10 browsers, behaviour on those will stay the same as before the fix. No new unit tests since we do not have automatic touch testing possibilities yet. Please test manually with Surface: IE11 and Edge, use for example uitest: com.vaadin.tests.components.grid.basics.GridBasicsomponents.grid.basics.GridBasics Change-Id: Iddbf1852e6ffafc855f749d6f4ebb235ed0f5703 * Add lazy/simple resize mode to Grid (#20108) Change-Id: I47427efc28c350382dba8c1f50fd332a3f4585e4 # Conflicts: # client/src/main/java/com/vaadin/client/connectors/GridConnector.java # client/src/main/java/com/vaadin/client/widgets/Grid.java # server/src/main/java/com/vaadin/ui/Grid.java # shared/src/main/java/com/vaadin/shared/ui/grid/GridState.java # themes/src/main/themes/VAADIN/themes/base/grid/grid.scss # uitest/src/main/java/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java Change-Id: Ieca56121875198ed559a41c143b28926e2695433 * Fix NPE in case some items don't contain all properties of Grid. This could occur in when parent is a different entity than its children in hierarchical data. Change-Id: Icd53b5b5e5544a3680d0cd99702ab78224b2dc08 # Conflicts: # server/src/main/java/com/vaadin/data/fieldgroup/FieldGroup.java # server/src/main/java/com/vaadin/ui/Grid.java * Mark TextField/TextArea as busy when a text change event is pending (#20469) Change-Id: I404985ae0be1e7dc65171b610032f8649e700f50 # Conflicts: # client/src/main/java/com/vaadin/client/ui/VTextField.java # uitest/src/test/java/com/vaadin/tests/components/textfield/TextChangeEventsTest.java * Add lazy/simple resize mode to Grid (#20108) Change-Id: I47427efc28c350382dba8c1f50fd332a3f4585e4 * Removed V8 VTextField unused import, forgotten @RunLocally. * Don't rely on selenium "sendKeys" behavior. * Revert "Change expected pre-release version number pattern in publish report" This reverts commit 8df27b952dddb691aead6a633c5b3724c98bf343. * Migrate TextField/TextArea patch from 7.7 to master (modern components) Mark TextField/TextArea as busy when a text change event is pending (#20469) Change-Id: I404985ae0be1e7dc65171b610032f8649e700f50
7 роки тому
7 роки тому
7 роки тому
7 роки тому
7 роки тому
7 роки тому
5 роки тому
Migrate 7.7.5 branch patches to v8. (#7969) * Prevent adding several scrollbar handlers (#19189). Change-Id: Ib0cc6c6835aab6d263f153362a328bcf2be7bc5c * Prevent adding several scrollbar handlers (#19189). * Keep expand ratio for last row/column when reducing grid layout size (#20297) Change-Id: Iff53a803596f4fc1eae8e4bfa307b9c1f4df961a * Fixed drag and drop failure when message dragged from email client (#20451) When dragging message form email client on Windows, item.webkitGetAsEntry() might return null creating NPE on the client side. Added additional checks for this situation. Change-Id: I569f7e6d0d7b137f24be53d1fbce384695ae8c73 * Change expected pre-release version number pattern in publish report Change-Id: Icdacecc490d2490ea9e262f5c5736c1dece2a89d * Mark TextField/TextArea as busy when a text change event is pending (#20469) Change-Id: I404985ae0be1e7dc65171b610032f8649e700f50 # Conflicts: # client/src/main/java/com/vaadin/client/ui/VTextField.java # uitest/src/main/java/com/vaadin/tests/components/textfield/TextChangeEvents.java * Fixed touch scrolling issue in Surface and WP devices (#18737) Fixed by using pointerevents instead of touchevents when the browser is IE11, or Edge. Also added touch-action: none; css rules into escalator.css to prevent default touch behaviour on IE11 and Edge. Does not affect IE8 to IE10 browsers, behaviour on those will stay the same as before the fix. No new unit tests since we do not have automatic touch testing possibilities yet. Please test manually with Surface: IE11 and Edge, use for example uitest: com.vaadin.tests.components.grid.basics.GridBasicsomponents.grid.basics.GridBasics Change-Id: Iddbf1852e6ffafc855f749d6f4ebb235ed0f5703 * Add lazy/simple resize mode to Grid (#20108) Change-Id: I47427efc28c350382dba8c1f50fd332a3f4585e4 # Conflicts: # client/src/main/java/com/vaadin/client/connectors/GridConnector.java # client/src/main/java/com/vaadin/client/widgets/Grid.java # server/src/main/java/com/vaadin/ui/Grid.java # shared/src/main/java/com/vaadin/shared/ui/grid/GridState.java # themes/src/main/themes/VAADIN/themes/base/grid/grid.scss # uitest/src/main/java/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java Change-Id: Ieca56121875198ed559a41c143b28926e2695433 * Fix NPE in case some items don't contain all properties of Grid. This could occur in when parent is a different entity than its children in hierarchical data. Change-Id: Icd53b5b5e5544a3680d0cd99702ab78224b2dc08 # Conflicts: # server/src/main/java/com/vaadin/data/fieldgroup/FieldGroup.java # server/src/main/java/com/vaadin/ui/Grid.java * Mark TextField/TextArea as busy when a text change event is pending (#20469) Change-Id: I404985ae0be1e7dc65171b610032f8649e700f50 # Conflicts: # client/src/main/java/com/vaadin/client/ui/VTextField.java # uitest/src/test/java/com/vaadin/tests/components/textfield/TextChangeEventsTest.java * Add lazy/simple resize mode to Grid (#20108) Change-Id: I47427efc28c350382dba8c1f50fd332a3f4585e4 * Removed V8 VTextField unused import, forgotten @RunLocally. * Don't rely on selenium "sendKeys" behavior. * Revert "Change expected pre-release version number pattern in publish report" This reverts commit 8df27b952dddb691aead6a633c5b3724c98bf343. * Migrate TextField/TextArea patch from 7.7 to master (modern components) Mark TextField/TextArea as busy when a text change event is pending (#20469) Change-Id: I404985ae0be1e7dc65171b610032f8649e700f50
7 роки тому
Migrate 7.7.5 branch patches to v8. (#7969) * Prevent adding several scrollbar handlers (#19189). Change-Id: Ib0cc6c6835aab6d263f153362a328bcf2be7bc5c * Prevent adding several scrollbar handlers (#19189). * Keep expand ratio for last row/column when reducing grid layout size (#20297) Change-Id: Iff53a803596f4fc1eae8e4bfa307b9c1f4df961a * Fixed drag and drop failure when message dragged from email client (#20451) When dragging message form email client on Windows, item.webkitGetAsEntry() might return null creating NPE on the client side. Added additional checks for this situation. Change-Id: I569f7e6d0d7b137f24be53d1fbce384695ae8c73 * Change expected pre-release version number pattern in publish report Change-Id: Icdacecc490d2490ea9e262f5c5736c1dece2a89d * Mark TextField/TextArea as busy when a text change event is pending (#20469) Change-Id: I404985ae0be1e7dc65171b610032f8649e700f50 # Conflicts: # client/src/main/java/com/vaadin/client/ui/VTextField.java # uitest/src/main/java/com/vaadin/tests/components/textfield/TextChangeEvents.java * Fixed touch scrolling issue in Surface and WP devices (#18737) Fixed by using pointerevents instead of touchevents when the browser is IE11, or Edge. Also added touch-action: none; css rules into escalator.css to prevent default touch behaviour on IE11 and Edge. Does not affect IE8 to IE10 browsers, behaviour on those will stay the same as before the fix. No new unit tests since we do not have automatic touch testing possibilities yet. Please test manually with Surface: IE11 and Edge, use for example uitest: com.vaadin.tests.components.grid.basics.GridBasicsomponents.grid.basics.GridBasics Change-Id: Iddbf1852e6ffafc855f749d6f4ebb235ed0f5703 * Add lazy/simple resize mode to Grid (#20108) Change-Id: I47427efc28c350382dba8c1f50fd332a3f4585e4 # Conflicts: # client/src/main/java/com/vaadin/client/connectors/GridConnector.java # client/src/main/java/com/vaadin/client/widgets/Grid.java # server/src/main/java/com/vaadin/ui/Grid.java # shared/src/main/java/com/vaadin/shared/ui/grid/GridState.java # themes/src/main/themes/VAADIN/themes/base/grid/grid.scss # uitest/src/main/java/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java Change-Id: Ieca56121875198ed559a41c143b28926e2695433 * Fix NPE in case some items don't contain all properties of Grid. This could occur in when parent is a different entity than its children in hierarchical data. Change-Id: Icd53b5b5e5544a3680d0cd99702ab78224b2dc08 # Conflicts: # server/src/main/java/com/vaadin/data/fieldgroup/FieldGroup.java # server/src/main/java/com/vaadin/ui/Grid.java * Mark TextField/TextArea as busy when a text change event is pending (#20469) Change-Id: I404985ae0be1e7dc65171b610032f8649e700f50 # Conflicts: # client/src/main/java/com/vaadin/client/ui/VTextField.java # uitest/src/test/java/com/vaadin/tests/components/textfield/TextChangeEventsTest.java * Add lazy/simple resize mode to Grid (#20108) Change-Id: I47427efc28c350382dba8c1f50fd332a3f4585e4 * Removed V8 VTextField unused import, forgotten @RunLocally. * Don't rely on selenium "sendKeys" behavior. * Revert "Change expected pre-release version number pattern in publish report" This reverts commit 8df27b952dddb691aead6a633c5b3724c98bf343. * Migrate TextField/TextArea patch from 7.7 to master (modern components) Mark TextField/TextArea as busy when a text change event is pending (#20469) Change-Id: I404985ae0be1e7dc65171b610032f8649e700f50
7 роки тому
Migrate 7.7.5 branch patches to v8. (#7969) * Prevent adding several scrollbar handlers (#19189). Change-Id: Ib0cc6c6835aab6d263f153362a328bcf2be7bc5c * Prevent adding several scrollbar handlers (#19189). * Keep expand ratio for last row/column when reducing grid layout size (#20297) Change-Id: Iff53a803596f4fc1eae8e4bfa307b9c1f4df961a * Fixed drag and drop failure when message dragged from email client (#20451) When dragging message form email client on Windows, item.webkitGetAsEntry() might return null creating NPE on the client side. Added additional checks for this situation. Change-Id: I569f7e6d0d7b137f24be53d1fbce384695ae8c73 * Change expected pre-release version number pattern in publish report Change-Id: Icdacecc490d2490ea9e262f5c5736c1dece2a89d * Mark TextField/TextArea as busy when a text change event is pending (#20469) Change-Id: I404985ae0be1e7dc65171b610032f8649e700f50 # Conflicts: # client/src/main/java/com/vaadin/client/ui/VTextField.java # uitest/src/main/java/com/vaadin/tests/components/textfield/TextChangeEvents.java * Fixed touch scrolling issue in Surface and WP devices (#18737) Fixed by using pointerevents instead of touchevents when the browser is IE11, or Edge. Also added touch-action: none; css rules into escalator.css to prevent default touch behaviour on IE11 and Edge. Does not affect IE8 to IE10 browsers, behaviour on those will stay the same as before the fix. No new unit tests since we do not have automatic touch testing possibilities yet. Please test manually with Surface: IE11 and Edge, use for example uitest: com.vaadin.tests.components.grid.basics.GridBasicsomponents.grid.basics.GridBasics Change-Id: Iddbf1852e6ffafc855f749d6f4ebb235ed0f5703 * Add lazy/simple resize mode to Grid (#20108) Change-Id: I47427efc28c350382dba8c1f50fd332a3f4585e4 # Conflicts: # client/src/main/java/com/vaadin/client/connectors/GridConnector.java # client/src/main/java/com/vaadin/client/widgets/Grid.java # server/src/main/java/com/vaadin/ui/Grid.java # shared/src/main/java/com/vaadin/shared/ui/grid/GridState.java # themes/src/main/themes/VAADIN/themes/base/grid/grid.scss # uitest/src/main/java/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java Change-Id: Ieca56121875198ed559a41c143b28926e2695433 * Fix NPE in case some items don't contain all properties of Grid. This could occur in when parent is a different entity than its children in hierarchical data. Change-Id: Icd53b5b5e5544a3680d0cd99702ab78224b2dc08 # Conflicts: # server/src/main/java/com/vaadin/data/fieldgroup/FieldGroup.java # server/src/main/java/com/vaadin/ui/Grid.java * Mark TextField/TextArea as busy when a text change event is pending (#20469) Change-Id: I404985ae0be1e7dc65171b610032f8649e700f50 # Conflicts: # client/src/main/java/com/vaadin/client/ui/VTextField.java # uitest/src/test/java/com/vaadin/tests/components/textfield/TextChangeEventsTest.java * Add lazy/simple resize mode to Grid (#20108) Change-Id: I47427efc28c350382dba8c1f50fd332a3f4585e4 * Removed V8 VTextField unused import, forgotten @RunLocally. * Don't rely on selenium "sendKeys" behavior. * Revert "Change expected pre-release version number pattern in publish report" This reverts commit 8df27b952dddb691aead6a633c5b3724c98bf343. * Migrate TextField/TextArea patch from 7.7 to master (modern components) Mark TextField/TextArea as busy when a text change event is pending (#20469) Change-Id: I404985ae0be1e7dc65171b610032f8649e700f50
7 роки тому
7 роки тому
7 роки тому
7 роки тому
7 роки тому
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015
  1. /*
  2. * Copyright 2000-2021 Vaadin Ltd.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License"); you may not
  5. * use this file except in compliance with the License. You may obtain a copy of
  6. * the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  12. * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  13. * License for the specific language governing permissions and limitations under
  14. * the License.
  15. */
  16. package com.vaadin.ui;
  17. import java.io.Serializable;
  18. import java.lang.reflect.Method;
  19. import java.lang.reflect.Type;
  20. import java.util.ArrayList;
  21. import java.util.Arrays;
  22. import java.util.Collection;
  23. import java.util.Collections;
  24. import java.util.Comparator;
  25. import java.util.HashMap;
  26. import java.util.HashSet;
  27. import java.util.Iterator;
  28. import java.util.LinkedHashSet;
  29. import java.util.List;
  30. import java.util.Map;
  31. import java.util.Objects;
  32. import java.util.Optional;
  33. import java.util.Set;
  34. import java.util.UUID;
  35. import java.util.function.BinaryOperator;
  36. import java.util.function.Function;
  37. import java.util.stream.Collectors;
  38. import java.util.stream.Stream;
  39. import org.jsoup.Jsoup;
  40. import org.jsoup.nodes.Attributes;
  41. import org.jsoup.nodes.Element;
  42. import org.jsoup.select.Elements;
  43. import com.vaadin.data.BeanPropertySet;
  44. import com.vaadin.data.Binder;
  45. import com.vaadin.data.Binder.Binding;
  46. import com.vaadin.data.HasDataProvider;
  47. import com.vaadin.data.HasValue;
  48. import com.vaadin.data.PropertyDefinition;
  49. import com.vaadin.data.PropertySet;
  50. import com.vaadin.data.ValueProvider;
  51. import com.vaadin.data.provider.CallbackDataProvider;
  52. import com.vaadin.data.provider.DataCommunicator;
  53. import com.vaadin.data.provider.DataGenerator;
  54. import com.vaadin.data.provider.DataProvider;
  55. import com.vaadin.data.provider.GridSortOrder;
  56. import com.vaadin.data.provider.GridSortOrderBuilder;
  57. import com.vaadin.data.provider.InMemoryDataProvider;
  58. import com.vaadin.data.provider.Query;
  59. import com.vaadin.data.provider.QuerySortOrder;
  60. import com.vaadin.event.ConnectorEvent;
  61. import com.vaadin.event.ContextClickEvent;
  62. import com.vaadin.event.HasUserOriginated;
  63. import com.vaadin.event.SortEvent;
  64. import com.vaadin.event.SortEvent.SortListener;
  65. import com.vaadin.event.SortEvent.SortNotifier;
  66. import com.vaadin.event.selection.MultiSelectionListener;
  67. import com.vaadin.event.selection.SelectionListener;
  68. import com.vaadin.event.selection.SingleSelectionListener;
  69. import com.vaadin.server.AbstractExtension;
  70. import com.vaadin.server.EncodeResult;
  71. import com.vaadin.server.Extension;
  72. import com.vaadin.server.JsonCodec;
  73. import com.vaadin.server.SerializableComparator;
  74. import com.vaadin.server.SerializableSupplier;
  75. import com.vaadin.server.Setter;
  76. import com.vaadin.server.VaadinServiceClassLoaderUtil;
  77. import com.vaadin.shared.Connector;
  78. import com.vaadin.shared.MouseEventDetails;
  79. import com.vaadin.shared.Registration;
  80. import com.vaadin.shared.data.DataCommunicatorConstants;
  81. import com.vaadin.shared.data.sort.SortDirection;
  82. import com.vaadin.shared.ui.ContentMode;
  83. import com.vaadin.shared.ui.grid.AbstractGridExtensionState;
  84. import com.vaadin.shared.ui.grid.ColumnResizeMode;
  85. import com.vaadin.shared.ui.grid.ColumnState;
  86. import com.vaadin.shared.ui.grid.DetailsManagerState;
  87. import com.vaadin.shared.ui.grid.GridClientRpc;
  88. import com.vaadin.shared.ui.grid.GridConstants;
  89. import com.vaadin.shared.ui.grid.GridConstants.Section;
  90. import com.vaadin.shared.ui.grid.GridServerRpc;
  91. import com.vaadin.shared.ui.grid.GridState;
  92. import com.vaadin.shared.ui.grid.GridStaticCellType;
  93. import com.vaadin.shared.ui.grid.HeightMode;
  94. import com.vaadin.shared.ui.grid.ScrollDestination;
  95. import com.vaadin.shared.ui.grid.SectionState;
  96. import com.vaadin.ui.components.grid.ColumnReorderListener;
  97. import com.vaadin.ui.components.grid.ColumnResizeListener;
  98. import com.vaadin.ui.components.grid.ColumnVisibilityChangeListener;
  99. import com.vaadin.ui.components.grid.DetailsGenerator;
  100. import com.vaadin.ui.components.grid.Editor;
  101. import com.vaadin.ui.components.grid.EditorImpl;
  102. import com.vaadin.ui.components.grid.Footer;
  103. import com.vaadin.ui.components.grid.FooterRow;
  104. import com.vaadin.ui.components.grid.GridMultiSelect;
  105. import com.vaadin.ui.components.grid.GridSelectionModel;
  106. import com.vaadin.ui.components.grid.GridSingleSelect;
  107. import com.vaadin.ui.components.grid.Header;
  108. import com.vaadin.ui.components.grid.Header.Row;
  109. import com.vaadin.ui.components.grid.HeaderCell;
  110. import com.vaadin.ui.components.grid.HeaderRow;
  111. import com.vaadin.ui.components.grid.ItemClickListener;
  112. import com.vaadin.ui.components.grid.MultiSelectionModel;
  113. import com.vaadin.ui.components.grid.MultiSelectionModelImpl;
  114. import com.vaadin.ui.components.grid.NoSelectionModel;
  115. import com.vaadin.ui.components.grid.SingleSelectionModel;
  116. import com.vaadin.ui.components.grid.SingleSelectionModelImpl;
  117. import com.vaadin.ui.components.grid.SortOrderProvider;
  118. import com.vaadin.ui.declarative.DesignAttributeHandler;
  119. import com.vaadin.ui.declarative.DesignContext;
  120. import com.vaadin.ui.declarative.DesignException;
  121. import com.vaadin.ui.declarative.DesignFormatter;
  122. import com.vaadin.ui.renderers.AbstractRenderer;
  123. import com.vaadin.ui.renderers.ComponentRenderer;
  124. import com.vaadin.ui.renderers.HtmlRenderer;
  125. import com.vaadin.ui.renderers.Renderer;
  126. import com.vaadin.ui.renderers.TextRenderer;
  127. import com.vaadin.util.ReflectTools;
  128. import elemental.json.Json;
  129. import elemental.json.JsonObject;
  130. import elemental.json.JsonValue;
  131. /**
  132. * A grid component for displaying tabular data.
  133. *
  134. * @author Vaadin Ltd
  135. * @since 8.0
  136. *
  137. * @param <T>
  138. * the grid bean type
  139. */
  140. public class Grid<T> extends AbstractListing<T> implements HasComponents,
  141. HasDataProvider<T>, SortNotifier<GridSortOrder<T>> {
  142. private static final String DECLARATIVE_DATA_ITEM_TYPE = "data-item-type";
  143. /**
  144. * A callback method for fetching items. The callback is provided with a
  145. * list of sort orders, offset index and limit.
  146. *
  147. * @param <T>
  148. * the grid bean type
  149. */
  150. @FunctionalInterface
  151. public interface FetchItemsCallback<T> extends Serializable {
  152. /**
  153. * Returns a stream of items ordered by given sort orders, limiting the
  154. * results with given offset and limit.
  155. * <p>
  156. * This method is called after the size of the data set is asked from a
  157. * related size callback. The offset and limit are promised to be within
  158. * the size of the data set.
  159. *
  160. * @param sortOrder
  161. * a list of sort orders
  162. * @param offset
  163. * the first index to fetch
  164. * @param limit
  165. * the fetched item count
  166. * @return stream of items
  167. */
  168. public Stream<T> fetchItems(List<QuerySortOrder> sortOrder, int offset,
  169. int limit);
  170. }
  171. @Deprecated
  172. private static final Method COLUMN_REORDER_METHOD = ReflectTools.findMethod(
  173. ColumnReorderListener.class, "columnReorder",
  174. ColumnReorderEvent.class);
  175. private static final Method SORT_ORDER_CHANGE_METHOD = ReflectTools
  176. .findMethod(SortListener.class, "sort", SortEvent.class);
  177. @Deprecated
  178. private static final Method COLUMN_RESIZE_METHOD = ReflectTools.findMethod(
  179. ColumnResizeListener.class, "columnResize",
  180. ColumnResizeEvent.class);
  181. @Deprecated
  182. private static final Method ITEM_CLICK_METHOD = ReflectTools
  183. .findMethod(ItemClickListener.class, "itemClick", ItemClick.class);
  184. @Deprecated
  185. private static final Method COLUMN_VISIBILITY_METHOD = ReflectTools
  186. .findMethod(ColumnVisibilityChangeListener.class,
  187. "columnVisibilityChanged",
  188. ColumnVisibilityChangeEvent.class);
  189. /**
  190. * Selection mode representing the built-in selection models in grid.
  191. * <p>
  192. * These enums can be used in {@link Grid#setSelectionMode(SelectionMode)}
  193. * to easily switch between the build-in selection models.
  194. *
  195. * @see Grid#setSelectionMode(SelectionMode)
  196. * @see Grid#setSelectionModel(GridSelectionModel)
  197. */
  198. public enum SelectionMode {
  199. /**
  200. * Single selection mode that maps to build-in
  201. * {@link SingleSelectionModel}.
  202. *
  203. * @see SingleSelectionModelImpl
  204. */
  205. SINGLE {
  206. @Override
  207. protected <T> GridSelectionModel<T> createModel() {
  208. return new SingleSelectionModelImpl<>();
  209. }
  210. },
  211. /**
  212. * Multiselection mode that maps to build-in {@link MultiSelectionModel}
  213. * .
  214. *
  215. * @see MultiSelectionModelImpl
  216. */
  217. MULTI {
  218. @Override
  219. protected <T> GridSelectionModel<T> createModel() {
  220. return new MultiSelectionModelImpl<>();
  221. }
  222. },
  223. /**
  224. * Selection model that doesn't allow selection.
  225. *
  226. * @see NoSelectionModel
  227. */
  228. NONE {
  229. @Override
  230. protected <T> GridSelectionModel<T> createModel() {
  231. return new NoSelectionModel<>();
  232. }
  233. };
  234. /**
  235. * Creates the selection model to use with this enum.
  236. *
  237. * @param <T>
  238. * the type of items in the grid
  239. * @return the selection model
  240. */
  241. protected abstract <T> GridSelectionModel<T> createModel();
  242. }
  243. /**
  244. * An event that is fired when the columns are reordered.
  245. */
  246. public static class ColumnReorderEvent extends Component.Event
  247. implements HasUserOriginated {
  248. private final boolean userOriginated;
  249. /**
  250. *
  251. * @param source
  252. * the grid where the event originated from
  253. * @param userOriginated
  254. * <code>true</code> if event is a result of user
  255. * interaction, <code>false</code> if from API call
  256. */
  257. public ColumnReorderEvent(Grid source, boolean userOriginated) {
  258. super(source);
  259. this.userOriginated = userOriginated;
  260. }
  261. /**
  262. * Returns <code>true</code> if the column reorder was done by the user,
  263. * <code>false</code> if not and it was triggered by server side code.
  264. *
  265. * @return <code>true</code> if event is a result of user interaction
  266. */
  267. @Override
  268. public boolean isUserOriginated() {
  269. return userOriginated;
  270. }
  271. }
  272. /**
  273. * An event that is fired when a column is resized, either programmatically
  274. * or by the user.
  275. */
  276. public static class ColumnResizeEvent extends Component.Event
  277. implements HasUserOriginated {
  278. private final Column<?, ?> column;
  279. private final boolean userOriginated;
  280. /**
  281. *
  282. * @param source
  283. * the grid where the event originated from
  284. * @param userOriginated
  285. * <code>true</code> if event is a result of user
  286. * interaction, <code>false</code> if from API call
  287. */
  288. public ColumnResizeEvent(Grid<?> source, Column<?, ?> column,
  289. boolean userOriginated) {
  290. super(source);
  291. this.column = column;
  292. this.userOriginated = userOriginated;
  293. }
  294. /**
  295. * Returns the column that was resized.
  296. *
  297. * @return the resized column.
  298. */
  299. public Column<?, ?> getColumn() {
  300. return column;
  301. }
  302. /**
  303. * Returns <code>true</code> if the column resize was done by the user,
  304. * <code>false</code> if not and it was triggered by server side code.
  305. *
  306. * @return <code>true</code> if event is a result of user interaction
  307. */
  308. @Override
  309. public boolean isUserOriginated() {
  310. return userOriginated;
  311. }
  312. }
  313. /**
  314. * An event fired when an item in the Grid has been clicked.
  315. *
  316. * @param <T>
  317. * the grid bean type
  318. */
  319. public static class ItemClick<T> extends ConnectorEvent {
  320. private final T item;
  321. private final Column<T, ?> column;
  322. private final MouseEventDetails mouseEventDetails;
  323. private final int rowIndex;
  324. /**
  325. * Creates a new {@code ItemClick} event containing the given item and
  326. * Column originating from the given Grid.
  327. *
  328. */
  329. public ItemClick(Grid<T> source, Column<T, ?> column, T item,
  330. MouseEventDetails mouseEventDetails, int rowIndex) {
  331. super(source);
  332. this.column = column;
  333. this.item = item;
  334. this.mouseEventDetails = mouseEventDetails;
  335. this.rowIndex = rowIndex;
  336. }
  337. /**
  338. * Returns the clicked item.
  339. *
  340. * @return the clicked item
  341. */
  342. public T getItem() {
  343. return item;
  344. }
  345. /**
  346. * Returns the clicked column.
  347. *
  348. * @return the clicked column
  349. */
  350. public Column<T, ?> getColumn() {
  351. return column;
  352. }
  353. /**
  354. * Returns the source Grid.
  355. *
  356. * @return the grid
  357. */
  358. @Override
  359. public Grid<T> getSource() {
  360. return (Grid<T>) super.getSource();
  361. }
  362. /**
  363. * Returns the mouse event details.
  364. *
  365. * @return the mouse event details
  366. */
  367. public MouseEventDetails getMouseEventDetails() {
  368. return mouseEventDetails;
  369. }
  370. /**
  371. * Returns the clicked rowIndex.
  372. *
  373. * @return the clicked rowIndex
  374. * @since 8.4
  375. */
  376. public int getRowIndex() {
  377. return rowIndex;
  378. }
  379. }
  380. /**
  381. * ContextClickEvent for the Grid Component.
  382. *
  383. * <p>
  384. * Usage:
  385. *
  386. * <pre>
  387. * grid.addContextClickListener(event -&gt; Notification.show(
  388. * ((GridContextClickEvent&lt;Person&gt;) event).getItem() + " Clicked"));
  389. * </pre>
  390. *
  391. * @param <T>
  392. * the grid bean type
  393. */
  394. public static class GridContextClickEvent<T> extends ContextClickEvent {
  395. private final T item;
  396. private final int rowIndex;
  397. private final Column<T, ?> column;
  398. private final Section section;
  399. /**
  400. * Creates a new context click event.
  401. *
  402. * @param source
  403. * the grid where the context click occurred
  404. * @param mouseEventDetails
  405. * details about mouse position
  406. * @param section
  407. * the section of the grid which was clicked
  408. * @param rowIndex
  409. * the index of the row which was clicked
  410. * @param item
  411. * the item which was clicked
  412. * @param column
  413. * the column which was clicked
  414. */
  415. public GridContextClickEvent(Grid<T> source,
  416. MouseEventDetails mouseEventDetails, Section section,
  417. int rowIndex, T item, Column<T, ?> column) {
  418. super(source, mouseEventDetails);
  419. this.item = item;
  420. this.section = section;
  421. this.column = column;
  422. this.rowIndex = rowIndex;
  423. }
  424. /**
  425. * Returns the item of context clicked row.
  426. *
  427. * @return item of clicked row; <code>null</code> if header or footer
  428. */
  429. public T getItem() {
  430. return item;
  431. }
  432. /**
  433. * Returns the clicked column.
  434. *
  435. * @return the clicked column
  436. */
  437. public Column<T, ?> getColumn() {
  438. return column;
  439. }
  440. /**
  441. * Return the clicked section of Grid.
  442. *
  443. * @return section of grid
  444. */
  445. public Section getSection() {
  446. return section;
  447. }
  448. /**
  449. * Returns the clicked row index.
  450. * <p>
  451. * Header and Footer rows for index can be fetched with
  452. * {@link Grid#getHeaderRow(int)} and {@link Grid#getFooterRow(int)}.
  453. *
  454. * @return row index in section
  455. */
  456. public int getRowIndex() {
  457. return rowIndex;
  458. }
  459. @Override
  460. public Grid<T> getComponent() {
  461. return (Grid<T>) super.getComponent();
  462. }
  463. }
  464. /**
  465. * An event that is fired when a column's visibility changes.
  466. *
  467. * @since 7.5.0
  468. */
  469. public static class ColumnVisibilityChangeEvent extends Component.Event
  470. implements HasUserOriginated {
  471. private final Column<?, ?> column;
  472. private final boolean userOriginated;
  473. private final boolean hidden;
  474. /**
  475. * Constructor for a column visibility change event.
  476. *
  477. * @param source
  478. * the grid from which this event originates
  479. * @param column
  480. * the column that changed its visibility
  481. * @param hidden
  482. * <code>true</code> if the column was hidden,
  483. * <code>false</code> if it became visible
  484. * @param isUserOriginated
  485. * <code>true</code> if the event was triggered by an UI
  486. * interaction
  487. */
  488. public ColumnVisibilityChangeEvent(Grid<?> source, Column<?, ?> column,
  489. boolean hidden, boolean isUserOriginated) {
  490. super(source);
  491. this.column = column;
  492. this.hidden = hidden;
  493. userOriginated = isUserOriginated;
  494. }
  495. /**
  496. * Gets the column that became hidden or visible.
  497. *
  498. * @return the column that became hidden or visible.
  499. * @see Column#isHidden()
  500. */
  501. public Column<?, ?> getColumn() {
  502. return column;
  503. }
  504. /**
  505. * Was the column set hidden or visible.
  506. *
  507. * @return <code>true</code> if the column was hidden <code>false</code>
  508. * if it was set visible
  509. */
  510. public boolean isHidden() {
  511. return hidden;
  512. }
  513. @Override
  514. public boolean isUserOriginated() {
  515. return userOriginated;
  516. }
  517. }
  518. /**
  519. * A helper base class for creating extensions for the Grid component.
  520. *
  521. * @param <T>
  522. */
  523. public abstract static class AbstractGridExtension<T>
  524. extends AbstractListingExtension<T> {
  525. @Override
  526. public void extend(AbstractListing<T> grid) {
  527. if (!(grid instanceof Grid)) {
  528. throw new IllegalArgumentException(
  529. getClass().getSimpleName() + " can only extend Grid");
  530. }
  531. super.extend(grid);
  532. }
  533. /**
  534. * Adds given component to the connector hierarchy of Grid.
  535. *
  536. * @param c
  537. * the component to add
  538. */
  539. protected void addComponentToGrid(Component c) {
  540. getParent().addExtensionComponent(c);
  541. }
  542. /**
  543. * Removes given component from the connector hierarchy of Grid.
  544. *
  545. * @param c
  546. * the component to remove
  547. */
  548. protected void removeComponentFromGrid(Component c) {
  549. getParent().removeExtensionComponent(c);
  550. }
  551. @Override
  552. public Grid<T> getParent() {
  553. return (Grid<T>) super.getParent();
  554. }
  555. @Override
  556. protected AbstractGridExtensionState getState() {
  557. return (AbstractGridExtensionState) super.getState();
  558. }
  559. @Override
  560. protected AbstractGridExtensionState getState(boolean markAsDirty) {
  561. return (AbstractGridExtensionState) super.getState(markAsDirty);
  562. }
  563. protected String getInternalIdForColumn(Column<T, ?> column) {
  564. return getParent().getInternalIdForColumn(column);
  565. }
  566. }
  567. private final class GridServerRpcImpl implements GridServerRpc {
  568. @Override
  569. public void sort(String[] columnInternalIds, SortDirection[] directions,
  570. boolean isUserOriginated) {
  571. assert columnInternalIds.length == directions.length : "Column and sort direction counts don't match.";
  572. List<GridSortOrder<T>> list = new ArrayList<>(directions.length);
  573. for (int i = 0; i < columnInternalIds.length; ++i) {
  574. Column<T, ?> column = columnKeys.get(columnInternalIds[i]);
  575. list.add(new GridSortOrder<>(column, directions[i]));
  576. }
  577. setSortOrder(list, isUserOriginated);
  578. }
  579. @Override
  580. public void itemClick(String rowKey, String columnInternalId,
  581. MouseEventDetails details, int rowIndex) {
  582. Column<T, ?> column = getColumnByInternalId(columnInternalId);
  583. T item = getDataCommunicator().getKeyMapper().get(rowKey);
  584. fireEvent(new ItemClick<>(Grid.this, column, item, details,
  585. rowIndex));
  586. }
  587. @Override
  588. public void contextClick(int rowIndex, String rowKey,
  589. String columnInternalId, Section section,
  590. MouseEventDetails details) {
  591. T item = null;
  592. if (rowKey != null) {
  593. item = getDataCommunicator().getKeyMapper().get(rowKey);
  594. }
  595. fireEvent(new GridContextClickEvent<>(Grid.this, details, section,
  596. rowIndex, item, getColumnByInternalId(columnInternalId)));
  597. }
  598. @Override
  599. public void columnsReordered(List<String> newColumnOrder,
  600. List<String> oldColumnOrder) {
  601. final String diffStateKey = "columnOrder";
  602. ConnectorTracker connectorTracker = getUI().getConnectorTracker();
  603. JsonObject diffState = connectorTracker.getDiffState(Grid.this);
  604. // discard the change if the columns have been reordered from
  605. // the server side, as the server side is always right
  606. if (getState(false).columnOrder.equals(oldColumnOrder)) {
  607. // Don't mark as dirty since client has the state already
  608. getState(false).columnOrder = newColumnOrder;
  609. // write changes to diffState so that possible reverting the
  610. // column order is sent to client
  611. assert diffState
  612. .hasKey(diffStateKey) : "Field name has changed";
  613. Type type = null;
  614. try {
  615. type = getState(false).getClass().getField(diffStateKey)
  616. .getGenericType();
  617. } catch (NoSuchFieldException | SecurityException e) {
  618. e.printStackTrace();
  619. }
  620. EncodeResult encodeResult = JsonCodec.encode(
  621. getState(false).columnOrder, diffState, type,
  622. connectorTracker);
  623. diffState.put(diffStateKey, encodeResult.getEncodedValue());
  624. fireColumnReorderEvent(true);
  625. } else {
  626. // make sure the client is reverted to the order that the
  627. // server thinks it is
  628. diffState.remove(diffStateKey);
  629. markAsDirty();
  630. }
  631. }
  632. @Override
  633. public void columnVisibilityChanged(String internalId, boolean hidden) {
  634. Column<T, ?> column = getColumnByInternalId(internalId);
  635. column.checkColumnIsAttached();
  636. if (column.isHidden() != hidden) {
  637. column.getState().hidden = hidden;
  638. fireColumnVisibilityChangeEvent(column, hidden, true);
  639. }
  640. }
  641. @Override
  642. public void columnResized(String internalId, double pixels) {
  643. final Column<T, ?> column = getColumnByInternalId(internalId);
  644. if (column != null && column.isResizable()) {
  645. column.getState().width = pixels;
  646. fireColumnResizeEvent(column, true);
  647. }
  648. }
  649. }
  650. /**
  651. * Class for managing visible details rows.
  652. *
  653. * @param <T>
  654. * the grid bean type
  655. */
  656. public static class DetailsManager<T> extends AbstractGridExtension<T> {
  657. private final Set<T> visibleDetails = new HashSet<>();
  658. private final Map<T, Component> components = new HashMap<>();
  659. private DetailsGenerator<T> generator;
  660. /**
  661. * Sets the details component generator.
  662. *
  663. * @param generator
  664. * the generator for details components
  665. */
  666. public void setDetailsGenerator(DetailsGenerator<T> generator) {
  667. if (this.generator != generator) {
  668. removeAllComponents();
  669. }
  670. getState().hasDetailsGenerator = generator != null;
  671. this.generator = generator;
  672. visibleDetails.forEach(this::refresh);
  673. }
  674. @Override
  675. public void remove() {
  676. removeAllComponents();
  677. super.remove();
  678. }
  679. private void removeAllComponents() {
  680. // Clean up old components
  681. components.values().forEach(this::removeComponentFromGrid);
  682. components.clear();
  683. }
  684. @Override
  685. public void generateData(T item, JsonObject jsonObject) {
  686. if (generator == null || !visibleDetails.contains(item)) {
  687. return;
  688. }
  689. if (!components.containsKey(item)) {
  690. Component detailsComponent = generator.apply(item);
  691. Objects.requireNonNull(detailsComponent,
  692. "Details generator can't create null components");
  693. if (detailsComponent.getParent() != null) {
  694. throw new IllegalStateException(
  695. "Details component was already attached");
  696. }
  697. addComponentToGrid(detailsComponent);
  698. components.put(item, detailsComponent);
  699. }
  700. jsonObject.put(GridState.JSONKEY_DETAILS_VISIBLE,
  701. components.get(item).getConnectorId());
  702. }
  703. @Override
  704. public void destroyData(T item) {
  705. // No clean up needed. Components are removed when hiding details
  706. // and/or changing details generator
  707. }
  708. /**
  709. * Sets the visibility of details component for given item.
  710. *
  711. * @param item
  712. * the item to show details for
  713. * @param visible
  714. * {@code true} if details component should be visible;
  715. * {@code false} if it should be hidden
  716. */
  717. public void setDetailsVisible(T item, boolean visible) {
  718. boolean refresh = false;
  719. if (!visible) {
  720. refresh = visibleDetails.remove(item);
  721. if (components.containsKey(item)) {
  722. removeComponentFromGrid(components.remove(item));
  723. }
  724. } else {
  725. refresh = visibleDetails.add(item);
  726. }
  727. if (refresh) {
  728. refresh(item);
  729. }
  730. }
  731. /**
  732. * Returns the visibility of details component for given item.
  733. *
  734. * @param item
  735. * the item to show details for
  736. *
  737. * @return {@code true} if details component should be visible;
  738. * {@code false} if it should be hidden
  739. */
  740. public boolean isDetailsVisible(T item) {
  741. return visibleDetails.contains(item);
  742. }
  743. @Override
  744. public Grid<T> getParent() {
  745. return super.getParent();
  746. }
  747. @Override
  748. protected DetailsManagerState getState() {
  749. return (DetailsManagerState) super.getState();
  750. }
  751. @Override
  752. protected DetailsManagerState getState(boolean markAsDirty) {
  753. return (DetailsManagerState) super.getState(markAsDirty);
  754. }
  755. }
  756. /**
  757. * This extension manages the configuration and data communication for a
  758. * Column inside of a Grid component.
  759. *
  760. * @param <T>
  761. * the grid bean type
  762. * @param <V>
  763. * the column value type
  764. */
  765. public static class Column<T, V> extends AbstractExtension {
  766. /**
  767. * behavior when parsing nested properties which may contain
  768. * <code>null</code> values in the property chain
  769. */
  770. public enum NestedNullBehavior {
  771. /**
  772. * throw a NullPointerException if there is a nested
  773. * <code>null</code> value
  774. */
  775. THROW,
  776. /**
  777. * silently ignore any exceptions caused by nested <code>null</code>
  778. * values
  779. */
  780. ALLOW_NULLS
  781. }
  782. private final ValueProvider<T, V> valueProvider;
  783. private ValueProvider<V, ?> presentationProvider;
  784. private SortOrderProvider sortOrderProvider = direction -> {
  785. String id = getId();
  786. if (id == null) {
  787. return Stream.empty();
  788. }
  789. return Stream.of(new QuerySortOrder(id, direction));
  790. };
  791. private NestedNullBehavior nestedNullBehavior = NestedNullBehavior.THROW;
  792. private boolean sortable = true;
  793. private SerializableComparator<T> comparator;
  794. private StyleGenerator<T> styleGenerator = item -> null;
  795. private DescriptionGenerator<T> descriptionGenerator;
  796. private DataGenerator<T> dataGenerator = new DataGenerator<T>() {
  797. @Override
  798. public void generateData(T item, JsonObject jsonObject) {
  799. ColumnState state = getState(false);
  800. String communicationId = getConnectorId();
  801. assert communicationId != null : "No communication ID set for column "
  802. + state.caption;
  803. JsonObject obj = getDataObject(jsonObject,
  804. DataCommunicatorConstants.DATA);
  805. obj.put(communicationId, generateRendererValue(item,
  806. presentationProvider, state.renderer));
  807. String style = styleGenerator.apply(item);
  808. if (style != null && !style.isEmpty()) {
  809. JsonObject styleObj = getDataObject(jsonObject,
  810. GridState.JSONKEY_CELLSTYLES);
  811. styleObj.put(communicationId, style);
  812. }
  813. if (descriptionGenerator != null) {
  814. String description = descriptionGenerator.apply(item);
  815. if (description != null && !description.isEmpty()) {
  816. JsonObject descriptionObj = getDataObject(jsonObject,
  817. GridState.JSONKEY_CELLDESCRIPTION);
  818. descriptionObj.put(communicationId, description);
  819. }
  820. }
  821. }
  822. @Override
  823. public void destroyData(T item) {
  824. removeComponent(getGrid().getDataProvider().getId(item));
  825. }
  826. @Override
  827. public void destroyAllData() {
  828. // Make a defensive copy of keys, as the map gets cleared when
  829. // removing components.
  830. new HashSet<>(activeComponents.keySet())
  831. .forEach(component -> removeComponent(component));
  832. }
  833. };
  834. private Binding<T, ?> editorBinding;
  835. private Map<Object, Component> activeComponents = new HashMap<>();
  836. private String userId;
  837. /**
  838. * Constructs a new Column configuration with given renderer and value
  839. * provider.
  840. *
  841. * @param valueProvider
  842. * the function to get values from items, not
  843. * <code>null</code>
  844. * @param renderer
  845. * the value renderer, not <code>null</code>
  846. */
  847. protected Column(ValueProvider<T, V> valueProvider,
  848. Renderer<? super V> renderer) {
  849. this(valueProvider, ValueProvider.identity(), renderer);
  850. }
  851. /**
  852. * Constructs a new Column configuration with given renderer and value
  853. * provider.
  854. * <p>
  855. * For a more complete explanation on presentation provider, see
  856. * {@link #setRenderer(ValueProvider, Renderer)}.
  857. *
  858. * @param valueProvider
  859. * the function to get values from items, not
  860. * <code>null</code>
  861. * @param presentationProvider
  862. * the function to get presentations from the value of this
  863. * column, not <code>null</code>. For more details, see
  864. * {@link #setRenderer(ValueProvider, Renderer)}
  865. * @param renderer
  866. * the presentation renderer, not <code>null</code>
  867. * @param <P>
  868. * the presentation type
  869. *
  870. * @since 8.1
  871. */
  872. protected <P> Column(ValueProvider<T, V> valueProvider,
  873. ValueProvider<V, P> presentationProvider,
  874. Renderer<? super P> renderer) {
  875. Objects.requireNonNull(valueProvider,
  876. "Value provider can't be null");
  877. Objects.requireNonNull(presentationProvider,
  878. "Presentation provider can't be null");
  879. Objects.requireNonNull(renderer, "Renderer can't be null");
  880. ColumnState state = getState();
  881. this.valueProvider = valueProvider;
  882. this.presentationProvider = presentationProvider;
  883. state.renderer = renderer;
  884. state.caption = "";
  885. // Add the renderer as a child extension of this extension, thus
  886. // ensuring the renderer will be unregistered when this column is
  887. // removed
  888. addExtension(renderer);
  889. Class<? super P> valueType = renderer.getPresentationType();
  890. if (Comparable.class.isAssignableFrom(valueType)) {
  891. comparator = (a, b) -> compareComparables(
  892. valueProvider.apply(a), valueProvider.apply(b));
  893. } else if (Number.class.isAssignableFrom(valueType)) {
  894. /*
  895. * Value type will be Number whenever using NumberRenderer.
  896. * Provide explicit comparison support in this case even though
  897. * Number itself isn't Comparable.
  898. */
  899. comparator = (a, b) -> compareNumbers(
  900. (Number) valueProvider.apply(a),
  901. (Number) valueProvider.apply(b));
  902. } else {
  903. comparator = (a, b) -> compareMaybeComparables(
  904. valueProvider.apply(a), valueProvider.apply(b));
  905. }
  906. }
  907. /**
  908. * Constructs a new Column configuration with given renderer and value
  909. * provider.
  910. * <p>
  911. * For a more complete explanation on presentation provider, see
  912. * {@link #setRenderer(ValueProvider, Renderer)}.
  913. *
  914. * @param valueProvider
  915. * the function to get values from items, not
  916. * <code>null</code>
  917. * @param presentationProvider
  918. * the function to get presentations from the value of this
  919. * column, not <code>null</code>. For more details, see
  920. * {@link #setRenderer(ValueProvider, Renderer)}
  921. * @param nestedNullBehavior
  922. * behavior on encountering nested <code>null</code> values
  923. * when reading the value from the bean
  924. * @param renderer
  925. * the presentation renderer, not <code>null</code>
  926. * @param <P>
  927. * the presentation type
  928. *
  929. * @since 8.8
  930. */
  931. protected <P> Column(ValueProvider<T, V> valueProvider,
  932. ValueProvider<V, P> presentationProvider,
  933. Renderer<? super P> renderer,
  934. NestedNullBehavior nestedNullBehavior) {
  935. this(valueProvider, presentationProvider, renderer);
  936. this.nestedNullBehavior = nestedNullBehavior;
  937. }
  938. private static int compareMaybeComparables(Object a, Object b) {
  939. if (hasCommonComparableBaseType(a, b)) {
  940. return compareComparables(a, b);
  941. }
  942. return compareComparables(Objects.toString(a, ""),
  943. Objects.toString(b, ""));
  944. }
  945. private static boolean hasCommonComparableBaseType(Object a, Object b) {
  946. if (a instanceof Comparable<?> && b instanceof Comparable<?>) {
  947. Class<?> aClass = a.getClass();
  948. Class<?> bClass = b.getClass();
  949. if (aClass == bClass) {
  950. return true;
  951. }
  952. Class<?> baseType = ReflectTools.findCommonBaseType(aClass,
  953. bClass);
  954. if (Comparable.class.isAssignableFrom(baseType)) {
  955. return true;
  956. }
  957. }
  958. if ((a == null && b instanceof Comparable<?>)
  959. || (b == null && a instanceof Comparable<?>)) {
  960. return true;
  961. }
  962. return false;
  963. }
  964. @SuppressWarnings({ "unchecked", "rawtypes" })
  965. private static int compareComparables(Object a, Object b) {
  966. return ((Comparator) Comparator
  967. .nullsLast(Comparator.naturalOrder())).compare(a, b);
  968. }
  969. @SuppressWarnings("unchecked")
  970. private static int compareNumbers(Number a, Number b) {
  971. Number valueA = a != null ? a : Double.POSITIVE_INFINITY;
  972. Number valueB = b != null ? b : Double.POSITIVE_INFINITY;
  973. // Most Number implementations are Comparable
  974. if (valueA instanceof Comparable
  975. && valueA.getClass().isInstance(valueB)) {
  976. return ((Comparable<Number>) valueA).compareTo(valueB);
  977. }
  978. if (valueA.equals(valueB)) {
  979. return 0;
  980. }
  981. // Fall back to comparing based on potentially truncated values
  982. int compare = Long.compare(valueA.longValue(), valueB.longValue());
  983. if (compare == 0) {
  984. // This might still produce 0 even though the values are not
  985. // equals, but there's nothing more we can do about that
  986. compare = Double.compare(valueA.doubleValue(),
  987. valueB.doubleValue());
  988. }
  989. return compare;
  990. }
  991. @SuppressWarnings("unchecked")
  992. private <P> JsonValue generateRendererValue(T item,
  993. ValueProvider<V, P> presentationProvider, Connector renderer) {
  994. V value;
  995. try {
  996. value = valueProvider.apply(item);
  997. } catch (NullPointerException npe) {
  998. value = null;
  999. if (NestedNullBehavior.THROW == nestedNullBehavior) {
  1000. throw npe;
  1001. }
  1002. }
  1003. P presentationValue = presentationProvider.apply(value);
  1004. // Make Grid track components.
  1005. if (renderer instanceof ComponentRenderer
  1006. && presentationValue instanceof Component) {
  1007. addComponent(getGrid().getDataProvider().getId(item),
  1008. (Component) presentationValue);
  1009. }
  1010. return ((Renderer<P>) renderer).encode(presentationValue);
  1011. }
  1012. private void addComponent(Object item, Component component) {
  1013. if (activeComponents.containsKey(item)) {
  1014. if (activeComponents.get(item).equals(component)) {
  1015. // Reusing old component
  1016. return;
  1017. }
  1018. removeComponent(item);
  1019. }
  1020. activeComponents.put(item, component);
  1021. getGrid().addExtensionComponent(component);
  1022. }
  1023. private void removeComponent(Object item) {
  1024. Component component = activeComponents.remove(item);
  1025. if (component != null) {
  1026. getGrid().removeExtensionComponent(component);
  1027. }
  1028. }
  1029. /**
  1030. * Gets a data object with the given key from the given JsonObject. If
  1031. * there is no object with the key, this method creates a new
  1032. * JsonObject.
  1033. *
  1034. * @param jsonObject
  1035. * the json object
  1036. * @param key
  1037. * the key where the desired data object is stored
  1038. * @return data object for the given key
  1039. */
  1040. private JsonObject getDataObject(JsonObject jsonObject, String key) {
  1041. if (!jsonObject.hasKey(key)) {
  1042. jsonObject.put(key, Json.createObject());
  1043. }
  1044. return jsonObject.getObject(key);
  1045. }
  1046. @Override
  1047. protected ColumnState getState() {
  1048. return getState(true);
  1049. }
  1050. @Override
  1051. protected ColumnState getState(boolean markAsDirty) {
  1052. return (ColumnState) super.getState(markAsDirty);
  1053. }
  1054. /**
  1055. * This method extends the given Grid with this Column.
  1056. *
  1057. * @param grid
  1058. * the grid to extend
  1059. */
  1060. private void extend(Grid<T> grid) {
  1061. super.extend(grid);
  1062. }
  1063. /**
  1064. * Returns the identifier used with this Column in communication.
  1065. *
  1066. * @return the identifier string
  1067. */
  1068. private String getInternalId() {
  1069. return getState(false).internalId;
  1070. }
  1071. /**
  1072. * Sets the identifier to use with this Column in communication.
  1073. *
  1074. * @param id
  1075. * the identifier string
  1076. */
  1077. private void setInternalId(String id) {
  1078. Objects.requireNonNull(id, "Communication ID can't be null");
  1079. getState().internalId = id;
  1080. }
  1081. /**
  1082. * Returns the user-defined identifier for this column.
  1083. *
  1084. * @return the identifier string
  1085. */
  1086. public String getId() {
  1087. return userId;
  1088. }
  1089. /**
  1090. * Sets the user-defined identifier to map this column. The identifier
  1091. * can be used for example in {@link Grid#getColumn(String)}.
  1092. * <p>
  1093. * The id is also used as the {@link #setSortProperty(String...) backend
  1094. * sort property} for this column if no sort property or sort order
  1095. * provider has been set for this column.
  1096. *
  1097. * @see #setSortProperty(String...)
  1098. * @see #setSortOrderProvider(SortOrderProvider)
  1099. *
  1100. * @param id
  1101. * the identifier string
  1102. * @return this column
  1103. */
  1104. public Column<T, V> setId(String id) {
  1105. Objects.requireNonNull(id, "Column identifier cannot be null");
  1106. if (userId != null) {
  1107. throw new IllegalStateException(
  1108. "Column identifier cannot be changed");
  1109. }
  1110. userId = id;
  1111. getGrid().setColumnId(id, this);
  1112. updateSortable();
  1113. return this;
  1114. }
  1115. private void updateSortable() {
  1116. boolean inMemory = getGrid().getDataProvider().isInMemory();
  1117. boolean hasSortOrder = getSortOrder(SortDirection.ASCENDING)
  1118. .count() != 0;
  1119. getState().sortable = this.sortable && (inMemory || hasSortOrder);
  1120. }
  1121. /**
  1122. * Gets the function used to produce the value for data in this column
  1123. * based on the row item.
  1124. *
  1125. * @return the value provider function
  1126. *
  1127. * @since 8.0.3
  1128. */
  1129. public ValueProvider<T, V> getValueProvider() {
  1130. return valueProvider;
  1131. }
  1132. /**
  1133. * Gets the function to get presentations from the value of data in this
  1134. * column, based on the row item.
  1135. *
  1136. * @return the presentation provider function
  1137. *
  1138. * @since 8.13
  1139. */
  1140. public ValueProvider<V, ?> getPresentationProvider() {
  1141. return presentationProvider;
  1142. }
  1143. /**
  1144. * Sets whether the user can sort this column or not. Whether the column
  1145. * is actually sortable after {@code setSortable(true)} depends on the
  1146. * {@link DataProvider} and the defined sort order for this column. When
  1147. * using an {@link InMemoryDataProvider} sorting can be automatic.
  1148. *
  1149. * @param sortable
  1150. * {@code true} to enable sorting for this column;
  1151. * {@code false} to disable it
  1152. * @return this column
  1153. */
  1154. public Column<T, V> setSortable(boolean sortable) {
  1155. if (this.sortable != sortable) {
  1156. this.sortable = sortable;
  1157. updateSortable();
  1158. }
  1159. return this;
  1160. }
  1161. /**
  1162. * Gets whether sorting is enabled for this column.
  1163. *
  1164. * @return {@code true} if the sorting is enabled for this column;
  1165. * {@code false} if not
  1166. */
  1167. public boolean isSortable() {
  1168. return sortable;
  1169. }
  1170. /**
  1171. * Gets whether the user can actually sort this column.
  1172. *
  1173. * @return {@code true} if the column can be sorted by the user;
  1174. * {@code false} if not
  1175. *
  1176. * @since 8.3.2
  1177. */
  1178. public boolean isSortableByUser() {
  1179. return getState(false).sortable;
  1180. }
  1181. /**
  1182. * Sets the header aria-label for this column.
  1183. *
  1184. * @param caption
  1185. * the header aria-label, null removes the aria-label from
  1186. * this column
  1187. *
  1188. * @return this column
  1189. *
  1190. * @since 8.2
  1191. */
  1192. public Column<T, V> setAssistiveCaption(String caption) {
  1193. if (Objects.equals(caption, getAssistiveCaption())) {
  1194. return this;
  1195. }
  1196. getState().assistiveCaption = caption;
  1197. return this;
  1198. }
  1199. /**
  1200. * Gets the header caption for this column.
  1201. *
  1202. * @return header caption
  1203. *
  1204. * @since 8.2
  1205. */
  1206. public String getAssistiveCaption() {
  1207. return getState(false).assistiveCaption;
  1208. }
  1209. /**
  1210. * Sets the header caption for this column.
  1211. *
  1212. * @param caption
  1213. * the header caption, not null
  1214. *
  1215. * @return this column
  1216. */
  1217. public Column<T, V> setCaption(String caption) {
  1218. Objects.requireNonNull(caption, "Header caption can't be null");
  1219. caption = Jsoup.parse(caption).text();
  1220. if (caption.equals(getState(false).caption)) {
  1221. return this;
  1222. }
  1223. getState().caption = caption;
  1224. HeaderRow row = getGrid().getDefaultHeaderRow();
  1225. if (row != null) {
  1226. row.getCell(this).setText(caption);
  1227. }
  1228. return this;
  1229. }
  1230. /**
  1231. * Gets the header caption for this column.
  1232. *
  1233. * @return header caption
  1234. */
  1235. public String getCaption() {
  1236. return getState(false).caption;
  1237. }
  1238. /**
  1239. * Sets a comparator to use with in-memory sorting with this column.
  1240. * Sorting with a back-end is done using
  1241. * {@link Column#setSortProperty(String...)}.
  1242. *
  1243. * @param comparator
  1244. * the comparator to use when sorting data in this column
  1245. * @return this column
  1246. */
  1247. public Column<T, V> setComparator(
  1248. SerializableComparator<T> comparator) {
  1249. Objects.requireNonNull(comparator, "Comparator can't be null");
  1250. this.comparator = comparator;
  1251. return this;
  1252. }
  1253. /**
  1254. * Gets the comparator to use with in-memory sorting for this column
  1255. * when sorting in the given direction.
  1256. *
  1257. * @param sortDirection
  1258. * the direction this column is sorted by
  1259. * @return comparator for this column
  1260. */
  1261. public SerializableComparator<T> getComparator(
  1262. SortDirection sortDirection) {
  1263. Objects.requireNonNull(comparator,
  1264. "No comparator defined for sorted column.");
  1265. boolean reverse = sortDirection != SortDirection.ASCENDING;
  1266. return reverse ? (t1, t2) -> comparator.reversed().compare(t1, t2)
  1267. : comparator;
  1268. }
  1269. /**
  1270. * Sets strings describing back end properties to be used when sorting
  1271. * this column.
  1272. * <p>
  1273. * By default, the {@link #setId(String) column id} will be used as the
  1274. * sort property.
  1275. *
  1276. * @param properties
  1277. * the array of strings describing backend properties
  1278. * @return this column
  1279. */
  1280. public Column<T, V> setSortProperty(String... properties) {
  1281. Objects.requireNonNull(properties, "Sort properties can't be null");
  1282. return setSortOrderProvider(dir -> Arrays.stream(properties)
  1283. .map(s -> new QuerySortOrder(s, dir)));
  1284. }
  1285. /**
  1286. * Sets the sort orders when sorting this column. The sort order
  1287. * provider is a function which provides {@link QuerySortOrder} objects
  1288. * to describe how to sort by this column.
  1289. * <p>
  1290. * By default, the {@link #setId(String) column id} will be used as the
  1291. * sort property.
  1292. *
  1293. * @param provider
  1294. * the function to use when generating sort orders with the
  1295. * given direction
  1296. * @return this column
  1297. */
  1298. public Column<T, V> setSortOrderProvider(SortOrderProvider provider) {
  1299. Objects.requireNonNull(provider,
  1300. "Sort order provider can't be null");
  1301. sortOrderProvider = provider;
  1302. // Update state
  1303. updateSortable();
  1304. return this;
  1305. }
  1306. /**
  1307. * Gets the sort orders to use with back-end sorting for this column
  1308. * when sorting in the given direction.
  1309. *
  1310. * @see #setSortProperty(String...)
  1311. * @see #setId(String)
  1312. * @see #setSortOrderProvider(SortOrderProvider)
  1313. *
  1314. * @param direction
  1315. * the sorting direction
  1316. * @return stream of sort orders
  1317. */
  1318. public Stream<QuerySortOrder> getSortOrder(SortDirection direction) {
  1319. return sortOrderProvider.apply(direction);
  1320. }
  1321. /**
  1322. * Sets the style generator that is used for generating class names for
  1323. * cells in this column. Returning null from the generator results in no
  1324. * custom style name being set.
  1325. *
  1326. * Note: The style generator is applied only to the body cells, not to
  1327. * the Editor.
  1328. *
  1329. * @param cellStyleGenerator
  1330. * the cell style generator to set, not null
  1331. * @return this column
  1332. * @throws NullPointerException
  1333. * if {@code cellStyleGenerator} is {@code null}
  1334. */
  1335. public Column<T, V> setStyleGenerator(
  1336. StyleGenerator<T> cellStyleGenerator) {
  1337. Objects.requireNonNull(cellStyleGenerator,
  1338. "Cell style generator must not be null");
  1339. this.styleGenerator = cellStyleGenerator;
  1340. getGrid().getDataCommunicator().reset();
  1341. return this;
  1342. }
  1343. /**
  1344. * Gets the style generator that is used for generating styles for
  1345. * cells.
  1346. *
  1347. * @return the cell style generator
  1348. */
  1349. public StyleGenerator<T> getStyleGenerator() {
  1350. return styleGenerator;
  1351. }
  1352. /**
  1353. * Sets the description generator that is used for generating
  1354. * descriptions for cells in this column. This method uses the
  1355. * {@link ContentMode#PREFORMATTED} content mode.
  1356. *
  1357. * @see #setDescriptionGenerator(DescriptionGenerator, ContentMode)
  1358. *
  1359. * @param cellDescriptionGenerator
  1360. * the cell description generator to set, or {@code null} to
  1361. * remove a previously set generator
  1362. * @return this column
  1363. */
  1364. public Column<T, V> setDescriptionGenerator(
  1365. DescriptionGenerator<T> cellDescriptionGenerator) {
  1366. return setDescriptionGenerator(cellDescriptionGenerator,
  1367. ContentMode.PREFORMATTED);
  1368. }
  1369. /**
  1370. * Sets the description generator that is used for generating
  1371. * descriptions for cells in this column. This method uses the given
  1372. * content mode.
  1373. *
  1374. * @see #setDescriptionGenerator(DescriptionGenerator)
  1375. *
  1376. * @param cellDescriptionGenerator
  1377. * the cell description generator to set, or {@code null} to
  1378. * remove a previously set generator
  1379. * @param tooltipContentMode
  1380. * the content mode for tooltips
  1381. * @return this column
  1382. *
  1383. * @since 8.2
  1384. */
  1385. public Column<T, V> setDescriptionGenerator(
  1386. DescriptionGenerator<T> cellDescriptionGenerator,
  1387. ContentMode tooltipContentMode) {
  1388. this.descriptionGenerator = cellDescriptionGenerator;
  1389. getState().tooltipContentMode = tooltipContentMode;
  1390. getGrid().getDataCommunicator().reset();
  1391. return this;
  1392. }
  1393. /**
  1394. * Gets the description generator that is used for generating
  1395. * descriptions for cells.
  1396. *
  1397. * @return the cell description generator, or <code>null</code> if no
  1398. * generator is set
  1399. */
  1400. public DescriptionGenerator<T> getDescriptionGenerator() {
  1401. return descriptionGenerator;
  1402. }
  1403. /**
  1404. * Sets the ratio with which the column expands.
  1405. * <p>
  1406. * By default, all columns expand equally (treated as if all of them had
  1407. * an expand ratio of 1). Once at least one column gets a defined expand
  1408. * ratio, the implicit expand ratio is removed, and only the defined
  1409. * expand ratios are taken into account.
  1410. * <p>
  1411. * If a column has a defined width ({@link #setWidth(double)}), it
  1412. * overrides this method's effects.
  1413. * <p>
  1414. * <em>Example:</em> A grid with three columns, with expand ratios 0, 1
  1415. * and 2, respectively. The column with a <strong>ratio of 0 is exactly
  1416. * as wide as its contents requires</strong>. The column with a ratio of
  1417. * 1 is as wide as it needs, <strong>plus a third of any excess
  1418. * space</strong>, because we have 3 parts total, and this column
  1419. * reserves only one of those. The column with a ratio of 2, is as wide
  1420. * as it needs to be, <strong>plus two thirds</strong> of the excess
  1421. * width.
  1422. *
  1423. * @param expandRatio
  1424. * the expand ratio of this column. {@code 0} to not have it
  1425. * expand at all. A negative number to clear the expand
  1426. * value.
  1427. * @throws IllegalStateException
  1428. * if the column is no longer attached to any grid
  1429. * @see #setWidth(double)
  1430. */
  1431. public Column<T, V> setExpandRatio(int expandRatio)
  1432. throws IllegalStateException {
  1433. checkColumnIsAttached();
  1434. if (expandRatio != getExpandRatio()) {
  1435. getState().expandRatio = expandRatio;
  1436. getGrid().markAsDirty();
  1437. }
  1438. return this;
  1439. }
  1440. /**
  1441. * Returns the column's expand ratio.
  1442. *
  1443. * @return the column's expand ratio
  1444. * @see #setExpandRatio(int)
  1445. */
  1446. public int getExpandRatio() {
  1447. return getState(false).expandRatio;
  1448. }
  1449. /**
  1450. * Clears the expand ratio for this column.
  1451. * <p>
  1452. * Equal to calling {@link #setExpandRatio(int) setExpandRatio(-1)}
  1453. *
  1454. * @throws IllegalStateException
  1455. * if the column is no longer attached to any grid
  1456. */
  1457. public Column<T, V> clearExpandRatio() throws IllegalStateException {
  1458. return setExpandRatio(-1);
  1459. }
  1460. /**
  1461. * Returns the width (in pixels). By default a column width is
  1462. * {@value com.vaadin.shared.ui.grid.GridConstants#DEFAULT_COLUMN_WIDTH_PX}
  1463. * (undefined).
  1464. *
  1465. * @return the width in pixels of the column
  1466. * @throws IllegalStateException
  1467. * if the column is no longer attached to any grid
  1468. */
  1469. public double getWidth() throws IllegalStateException {
  1470. checkColumnIsAttached();
  1471. return getState(false).width;
  1472. }
  1473. /**
  1474. * Sets the width (in pixels).
  1475. * <p>
  1476. * This overrides any configuration set by any of
  1477. * {@link #setExpandRatio(int)}, {@link #setMinimumWidth(double)} or
  1478. * {@link #setMaximumWidth(double)}.
  1479. *
  1480. * @param pixelWidth
  1481. * the new pixel width of the column
  1482. * @return the column itself
  1483. *
  1484. * @throws IllegalStateException
  1485. * if the column is no longer attached to any grid
  1486. * @throws IllegalArgumentException
  1487. * thrown if pixel width is less than zero
  1488. */
  1489. public Column<T, V> setWidth(double pixelWidth)
  1490. throws IllegalStateException, IllegalArgumentException {
  1491. checkColumnIsAttached();
  1492. if (pixelWidth < 0) {
  1493. throw new IllegalArgumentException(
  1494. "Pixel width should be greated than 0 (in " + toString()
  1495. + ")");
  1496. }
  1497. if (pixelWidth != getWidth()) {
  1498. getState().width = pixelWidth;
  1499. getGrid().markAsDirty();
  1500. getGrid().fireColumnResizeEvent(this, false);
  1501. }
  1502. return this;
  1503. }
  1504. /**
  1505. * Returns whether this column has an undefined width.
  1506. *
  1507. * @since 7.6
  1508. * @return whether the width is undefined
  1509. * @throws IllegalStateException
  1510. * if the column is no longer attached to any grid
  1511. */
  1512. public boolean isWidthUndefined() {
  1513. checkColumnIsAttached();
  1514. return getState(false).width < 0;
  1515. }
  1516. /**
  1517. * Marks the column width as undefined. An undefined width means the
  1518. * grid is free to resize the column based on the cell contents and
  1519. * available space in the grid.
  1520. *
  1521. * @return the column itself
  1522. */
  1523. public Column<T, V> setWidthUndefined() {
  1524. checkColumnIsAttached();
  1525. if (!isWidthUndefined()) {
  1526. getState().width = -1;
  1527. getGrid().markAsDirty();
  1528. getGrid().fireColumnResizeEvent(this, false);
  1529. }
  1530. return this;
  1531. }
  1532. /**
  1533. * Sets the minimum width for this column.
  1534. * <p>
  1535. * This defines the minimum guaranteed pixel width of the column
  1536. * <em>when it is set to expand</em>.
  1537. *
  1538. * Note: Value -1 is not accepted, use {@link #setWidthUndefined()}
  1539. * instead.
  1540. *
  1541. * @param pixels
  1542. * the minimum width for the column
  1543. * @throws IllegalStateException
  1544. * if the column is no longer attached to any grid
  1545. * @see #setExpandRatio(int)
  1546. * @return the column itself
  1547. */
  1548. public Column<T, V> setMinimumWidth(double pixels)
  1549. throws IllegalStateException {
  1550. checkColumnIsAttached();
  1551. final double maxwidth = getMaximumWidth();
  1552. if (pixels >= 0 && pixels > maxwidth && maxwidth >= 0) {
  1553. throw new IllegalArgumentException("New minimum width ("
  1554. + pixels + ") was greater than maximum width ("
  1555. + maxwidth + ")");
  1556. }
  1557. getState().minWidth = pixels;
  1558. getGrid().markAsDirty();
  1559. return this;
  1560. }
  1561. /**
  1562. * Return the minimum width for this column.
  1563. *
  1564. * @return the minimum width for this column
  1565. * @see #setMinimumWidth(double)
  1566. */
  1567. public double getMinimumWidth() {
  1568. return getState(false).minWidth;
  1569. }
  1570. /**
  1571. * Sets whether the width of the contents in the column should be
  1572. * considered minimum width for this column.
  1573. * <p>
  1574. * If this is set to <code>true</code> (default for backwards
  1575. * compatibility), then a column will not shrink to smaller than the
  1576. * width required to show the contents available when calculating the
  1577. * widths (only the widths of the initially rendered rows are
  1578. * considered).
  1579. * <p>
  1580. * If this is set to <code>false</code> and the column has been set to
  1581. * expand using #setExpandRatio(int), then the contents of the column
  1582. * will be ignored when calculating the width, and the column will thus
  1583. * shrink down to the minimum width defined by #setMinimumWidth(double)
  1584. * if necessary.
  1585. *
  1586. * @param minimumWidthFromContent
  1587. * <code>true</code> to reserve space for all contents,
  1588. * <code>false</code> to allow the column to shrink smaller
  1589. * than the contents
  1590. * @return the column itself
  1591. * @throws IllegalStateException
  1592. * if the column is no longer attached to any grid
  1593. * @see #setMinimumWidth(double)
  1594. * @since 8.1
  1595. */
  1596. public Column<T, V> setMinimumWidthFromContent(
  1597. boolean minimumWidthFromContent) throws IllegalStateException {
  1598. checkColumnIsAttached();
  1599. if (isMinimumWidthFromContent() != minimumWidthFromContent) {
  1600. getState().minimumWidthFromContent = minimumWidthFromContent;
  1601. getGrid().markAsDirty();
  1602. }
  1603. return this;
  1604. }
  1605. /**
  1606. * Gets whether the width of the contents in the column should be
  1607. * considered minimum width for this column.
  1608. *
  1609. * @return <code>true</code> to reserve space for all contents,
  1610. * <code>false</code> to allow the column to shrink smaller than
  1611. * the contents
  1612. * @see #setMinimumWidthFromContent(boolean)
  1613. * @since 8.1
  1614. */
  1615. public boolean isMinimumWidthFromContent() {
  1616. return getState(false).minimumWidthFromContent;
  1617. }
  1618. /**
  1619. * Sets the maximum width for this column.
  1620. * <p>
  1621. * This defines the maximum allowed pixel width of the column <em>when
  1622. * it is set to expand</em>.
  1623. *
  1624. * @param pixels
  1625. * the maximum width
  1626. * @throws IllegalStateException
  1627. * if the column is no longer attached to any grid
  1628. * @see #setExpandRatio(int)
  1629. */
  1630. public Column<T, V> setMaximumWidth(double pixels) {
  1631. checkColumnIsAttached();
  1632. final double minwidth = getMinimumWidth();
  1633. if (pixels >= 0 && pixels < minwidth && minwidth >= 0) {
  1634. throw new IllegalArgumentException("New maximum width ("
  1635. + pixels + ") was less than minimum width (" + minwidth
  1636. + ")");
  1637. }
  1638. getState().maxWidth = pixels;
  1639. getGrid().markAsDirty();
  1640. return this;
  1641. }
  1642. /**
  1643. * Returns the maximum width for this column.
  1644. *
  1645. * @return the maximum width for this column
  1646. * @see #setMaximumWidth(double)
  1647. */
  1648. public double getMaximumWidth() {
  1649. return getState(false).maxWidth;
  1650. }
  1651. /**
  1652. * Sets whether this column can be resized by the user.
  1653. *
  1654. * @since 7.6
  1655. * @param resizable
  1656. * {@code true} if this column should be resizable,
  1657. * {@code false} otherwise
  1658. * @throws IllegalStateException
  1659. * if the column is no longer attached to any grid
  1660. */
  1661. public Column<T, V> setResizable(boolean resizable) {
  1662. checkColumnIsAttached();
  1663. if (resizable != isResizable()) {
  1664. getState().resizable = resizable;
  1665. getGrid().markAsDirty();
  1666. }
  1667. return this;
  1668. }
  1669. /**
  1670. * Gets the caption of the hiding toggle for this column.
  1671. *
  1672. * @since 7.5.0
  1673. * @see #setHidingToggleCaption(String)
  1674. * @return the caption for the hiding toggle for this column
  1675. */
  1676. public String getHidingToggleCaption() {
  1677. return getState(false).hidingToggleCaption;
  1678. }
  1679. /**
  1680. * Sets the caption of the hiding toggle for this column. Shown in the
  1681. * toggle for this column in the grid's sidebar when the column is
  1682. * {@link #isHidable() hidable}.
  1683. * <p>
  1684. * The default value is <code>null</code>, and in that case the column's
  1685. * {@link #getCaption() header caption} is used.
  1686. * <p>
  1687. * <em>NOTE:</em> setting this to empty string might cause the hiding
  1688. * toggle to not render correctly.
  1689. *
  1690. * @since 7.5.0
  1691. * @param hidingToggleCaption
  1692. * the text to show in the column hiding toggle
  1693. * @return the column itself
  1694. */
  1695. public Column<T, V> setHidingToggleCaption(String hidingToggleCaption) {
  1696. if (hidingToggleCaption != getHidingToggleCaption()) {
  1697. getState().hidingToggleCaption = hidingToggleCaption;
  1698. }
  1699. return this;
  1700. }
  1701. /**
  1702. * Hides or shows the column. By default columns are visible before
  1703. * explicitly hiding them.
  1704. *
  1705. * @since 7.5.0
  1706. * @param hidden
  1707. * <code>true</code> to hide the column, <code>false</code>
  1708. * to show
  1709. * @return this column
  1710. * @throws IllegalStateException
  1711. * if the column is no longer attached to any grid
  1712. */
  1713. public Column<T, V> setHidden(boolean hidden) {
  1714. checkColumnIsAttached();
  1715. if (hidden != isHidden()) {
  1716. getState().hidden = hidden;
  1717. getGrid().fireColumnVisibilityChangeEvent(this, hidden, false);
  1718. }
  1719. return this;
  1720. }
  1721. /**
  1722. * Returns whether this column is hidden. Default is {@code false}.
  1723. *
  1724. * @since 7.5.0
  1725. * @return <code>true</code> if the column is currently hidden,
  1726. * <code>false</code> otherwise
  1727. */
  1728. public boolean isHidden() {
  1729. return getState(false).hidden;
  1730. }
  1731. /**
  1732. * Sets whether this column can be hidden by the user. Hidable columns
  1733. * can be hidden and shown via the sidebar menu.
  1734. *
  1735. * @since 7.5.0
  1736. * @param hidable
  1737. * <code>true</code> if the column may be hidable by the user
  1738. * via UI interaction
  1739. * @return this column
  1740. */
  1741. public Column<T, V> setHidable(boolean hidable) {
  1742. if (hidable != isHidable()) {
  1743. getState().hidable = hidable;
  1744. }
  1745. return this;
  1746. }
  1747. /**
  1748. * Returns whether this column can be hidden by the user. Default is
  1749. * {@code false}.
  1750. * <p>
  1751. * <em>Note:</em> the column can be programmatically hidden using
  1752. * {@link #setHidden(boolean)} regardless of the returned value.
  1753. *
  1754. * @since 7.5.0
  1755. * @return <code>true</code> if the user can hide the column,
  1756. * <code>false</code> if not
  1757. */
  1758. public boolean isHidable() {
  1759. return getState(false).hidable;
  1760. }
  1761. /**
  1762. * Returns whether this column can be resized by the user. Default is
  1763. * {@code true}.
  1764. * <p>
  1765. * <em>Note:</em> the column can be programmatically resized using
  1766. * {@link #setWidth(double)} and {@link #setWidthUndefined()} regardless
  1767. * of the returned value.
  1768. *
  1769. * @since 7.6
  1770. * @return {@code true} if this column is resizable, {@code false}
  1771. * otherwise
  1772. */
  1773. public boolean isResizable() {
  1774. return getState(false).resizable;
  1775. }
  1776. /**
  1777. * Sets whether this Column has a component displayed in Editor or not.
  1778. * A column can only be editable if an editor component or binding has
  1779. * been set.
  1780. *
  1781. * @param editable
  1782. * {@code true} if column is editable; {@code false} if not
  1783. * @return this column
  1784. * @throws IllegalStateException
  1785. * if editable is true and column has no editor binding or
  1786. * component defined
  1787. *
  1788. * @see #setEditorComponent(HasValue, Setter)
  1789. * @see #setEditorBinding(Binding)
  1790. */
  1791. public Column<T, V> setEditable(boolean editable)
  1792. throws IllegalStateException {
  1793. if (editable && editorBinding == null) {
  1794. throw new IllegalStateException(
  1795. "Column has no editor binding or component defined");
  1796. }
  1797. getState().editable = editable;
  1798. return this;
  1799. }
  1800. /**
  1801. * Gets whether this Column has a component displayed in Editor or not.
  1802. *
  1803. * @return {@code true} if the column displays an editor component;
  1804. * {@code false} if not
  1805. */
  1806. public boolean isEditable() {
  1807. return getState(false).editable;
  1808. }
  1809. /**
  1810. * Sets an editor binding for this column. The {@link Binding} is used
  1811. * when a row is in editor mode to define how to populate an editor
  1812. * component based on the edited row and how to update an item based on
  1813. * the value in the editor component.
  1814. * <p>
  1815. * To create a binding to use with a column, define a binding for the
  1816. * editor binder (<code>grid.getEditor().getBinder()</code>) using e.g.
  1817. * {@link Binder#forField(HasValue)}. You can also use
  1818. * {@link #setEditorComponent(HasValue, Setter)} if no validator or
  1819. * converter is needed for the binding.
  1820. * <p>
  1821. * The {@link HasValue} that the binding is defined to use must be a
  1822. * {@link Component}.
  1823. *
  1824. * @param binding
  1825. * the binding to use for this column
  1826. * @return this column
  1827. *
  1828. * @see #setEditorComponent(HasValue, Setter)
  1829. * @see Binding
  1830. * @see Grid#getEditor()
  1831. * @see Editor#getBinder()
  1832. */
  1833. public Column<T, V> setEditorBinding(Binding<T, ?> binding) {
  1834. Objects.requireNonNull(binding, "null is not a valid editor field");
  1835. if (!(binding.getField() instanceof Component)) {
  1836. throw new IllegalArgumentException(
  1837. "Binding target must be a component.");
  1838. }
  1839. this.editorBinding = binding;
  1840. return setEditable(true);
  1841. }
  1842. /**
  1843. * Gets the binder binding that is currently used for this column.
  1844. *
  1845. * @return the used binder binding, or <code>null</code> if no binding
  1846. * is configured
  1847. *
  1848. * @see #setEditorBinding(Binding)
  1849. */
  1850. public Binding<T, ?> getEditorBinding() {
  1851. return editorBinding;
  1852. }
  1853. /**
  1854. * Sets a component and setter to use for editing values of this column
  1855. * in the editor row. This is a shorthand for use in simple cases where
  1856. * no validator or converter is needed. Use
  1857. * {@link #setEditorBinding(Binding)} to support more complex cases.
  1858. * <p>
  1859. * <strong>Note:</strong> The same component cannot be used for multiple
  1860. * columns.
  1861. *
  1862. * @param editorComponent
  1863. * the editor component
  1864. * @param setter
  1865. * a setter that stores the component value in the row item
  1866. * @return this column
  1867. *
  1868. * @see #setEditorBinding(Binding)
  1869. * @see Grid#getEditor()
  1870. * @see Binder#bind(HasValue, ValueProvider, Setter)
  1871. */
  1872. public <C extends HasValue<V> & Component> Column<T, V> setEditorComponent(
  1873. C editorComponent, Setter<T, V> setter) {
  1874. Objects.requireNonNull(editorComponent,
  1875. "Editor component cannot be null");
  1876. Objects.requireNonNull(setter, "Setter cannot be null");
  1877. Binding<T, V> binding = getGrid().getEditor().getBinder()
  1878. .bind(editorComponent, valueProvider::apply, setter);
  1879. return setEditorBinding(binding);
  1880. }
  1881. /**
  1882. * Sets a component to use for editing values of this columns in the
  1883. * editor row. This method can only be used if the column has an
  1884. * {@link #setId(String) id} and the {@link Grid} has been created using
  1885. * {@link Grid#Grid(Class)} or some other way that allows finding
  1886. * properties based on property names.
  1887. * <p>
  1888. * This is a shorthand for use in simple cases where no validator or
  1889. * converter is needed. Use {@link #setEditorBinding(Binding)} to
  1890. * support more complex cases.
  1891. * <p>
  1892. * <strong>Note:</strong> The same component cannot be used for multiple
  1893. * columns.
  1894. *
  1895. * @param editorComponent
  1896. * the editor component
  1897. * @return this column
  1898. *
  1899. * @see #setEditorBinding(Binding)
  1900. * @see Grid#getEditor()
  1901. * @see Binder#bind(HasValue, String)
  1902. * @see Grid#Grid(Class)
  1903. */
  1904. public <F, C extends HasValue<F> & Component> Column<T, V> setEditorComponent(
  1905. C editorComponent) {
  1906. Objects.requireNonNull(editorComponent,
  1907. "Editor component cannot be null");
  1908. String propertyName = getId();
  1909. if (propertyName == null) {
  1910. throw new IllegalStateException(
  1911. "setEditorComponent without a setter can only be used if the column has an id. "
  1912. + "Use another setEditorComponent(Component, Setter) or setEditorBinding(Binding) instead.");
  1913. }
  1914. Binding<T, F> binding = getGrid().getEditor().getBinder()
  1915. .bind(editorComponent, propertyName);
  1916. return setEditorBinding(binding);
  1917. }
  1918. /**
  1919. * Sets the Renderer for this Column. Setting the renderer will cause
  1920. * all currently available row data to be recreated and sent to the
  1921. * client.
  1922. *
  1923. * Note: Setting a new renderer will reset presentation provider if
  1924. * it exists.
  1925. *
  1926. * @param renderer
  1927. * the new renderer
  1928. * @return this column
  1929. *
  1930. * @since 8.0.3
  1931. */
  1932. public Column<T, V> setRenderer(Renderer<? super V> renderer) {
  1933. return setRenderer(ValueProvider.identity(), renderer);
  1934. }
  1935. /**
  1936. * Sets the Renderer for this Column. Setting the renderer will cause
  1937. * all currently available row data to be recreated and sent to the
  1938. * client.
  1939. * <p>
  1940. * The presentation provider is a method that takes the value of this
  1941. * column on a single row, and maps that to a value that the renderer
  1942. * accepts. This feature can be used for storing a complex value in a
  1943. * column for editing, but providing a simplified presentation for the
  1944. * user when not editing.
  1945. *
  1946. * @param presentationProvider
  1947. * the function to get presentations from the value of this
  1948. * column, not {@code null}
  1949. * @param renderer
  1950. * the new renderer, not {@code null}
  1951. *
  1952. * @param <P>
  1953. * the presentation type
  1954. *
  1955. * @return this column
  1956. *
  1957. * @since 8.1
  1958. */
  1959. public <P> Column<T, V> setRenderer(
  1960. ValueProvider<V, P> presentationProvider,
  1961. Renderer<? super P> renderer) {
  1962. Objects.requireNonNull(renderer, "Renderer can not be null");
  1963. Objects.requireNonNull(presentationProvider,
  1964. "Presentation provider can not be null");
  1965. // Remove old renderer
  1966. Connector oldRenderer = getState().renderer;
  1967. if (oldRenderer instanceof Extension) {
  1968. removeExtension((Extension) oldRenderer);
  1969. }
  1970. // Set new renderer
  1971. getState().renderer = renderer;
  1972. addExtension(renderer);
  1973. this.presentationProvider = presentationProvider;
  1974. // Trigger redraw
  1975. getGrid().getDataCommunicator().reset();
  1976. return this;
  1977. }
  1978. /**
  1979. * Gets the Renderer for this Column.
  1980. *
  1981. * @return the renderer
  1982. * @since 8.1
  1983. */
  1984. public Renderer<?> getRenderer() {
  1985. return (Renderer<?>) getState().renderer;
  1986. }
  1987. /**
  1988. * Sets whether Grid should handle events in this Column from Components
  1989. * and Widgets rendered by certain Renderers. By default the events are
  1990. * not handled.
  1991. * <p>
  1992. * <strong>Note:</strong> Enabling this feature will for example select
  1993. * a row when a component is clicked. For example in the case of a
  1994. * {@link ComboBox} or {@link TextField} it might be problematic as the
  1995. * component gets re-rendered and might lose focus.
  1996. *
  1997. * @param handleWidgetEvents
  1998. * {@code true} to handle events; {@code false} to not
  1999. * @return this column
  2000. * @since 8.3
  2001. */
  2002. public Column<T, V> setHandleWidgetEvents(boolean handleWidgetEvents) {
  2003. getState().handleWidgetEvents = handleWidgetEvents;
  2004. return this;
  2005. }
  2006. /**
  2007. * Gets whether Grid is handling the events in this Column from
  2008. * Component and Widgets.
  2009. *
  2010. * @see #setHandleWidgetEvents(boolean)
  2011. *
  2012. * @return {@code true} if handling events; {@code false} if not
  2013. * @since 8.3
  2014. */
  2015. public boolean isHandleWidgetEvents() {
  2016. return getState(false).handleWidgetEvents;
  2017. }
  2018. /**
  2019. * Gets the grid that this column belongs to.
  2020. *
  2021. * @return the grid that this column belongs to, or <code>null</code> if
  2022. * this column has not yet been associated with any grid
  2023. */
  2024. @SuppressWarnings("unchecked")
  2025. protected Grid<T> getGrid() {
  2026. return (Grid<T>) getParent();
  2027. }
  2028. /**
  2029. * Checks if column is attached and throws an
  2030. * {@link IllegalStateException} if it is not.
  2031. *
  2032. * @throws IllegalStateException
  2033. * if the column is no longer attached to any grid
  2034. */
  2035. protected void checkColumnIsAttached() throws IllegalStateException {
  2036. if (getGrid() == null) {
  2037. throw new IllegalStateException(
  2038. "Column is no longer attached to a grid.");
  2039. }
  2040. }
  2041. /**
  2042. * Writes the design attributes for this column into given element.
  2043. *
  2044. * @since 7.5.0
  2045. *
  2046. * @param element
  2047. * Element to write attributes into
  2048. *
  2049. * @param designContext
  2050. * the design context
  2051. */
  2052. protected void writeDesign(Element element,
  2053. DesignContext designContext) {
  2054. Attributes attributes = element.attributes();
  2055. ColumnState defaultState = new ColumnState();
  2056. if (getId() == null) {
  2057. setId("column" + getGrid().getColumns().indexOf(this));
  2058. }
  2059. DesignAttributeHandler.writeAttribute("column-id", attributes,
  2060. getId(), null, String.class, designContext);
  2061. // Sortable is a special attribute that depends on the data
  2062. // provider.
  2063. DesignAttributeHandler.writeAttribute("sortable", attributes,
  2064. isSortable(), null, boolean.class, designContext);
  2065. DesignAttributeHandler.writeAttribute("editable", attributes,
  2066. isEditable(), defaultState.editable, boolean.class,
  2067. designContext);
  2068. DesignAttributeHandler.writeAttribute("resizable", attributes,
  2069. isResizable(), defaultState.resizable, boolean.class,
  2070. designContext);
  2071. DesignAttributeHandler.writeAttribute("hidable", attributes,
  2072. isHidable(), defaultState.hidable, boolean.class,
  2073. designContext);
  2074. DesignAttributeHandler.writeAttribute("hidden", attributes,
  2075. isHidden(), defaultState.hidden, boolean.class,
  2076. designContext);
  2077. DesignAttributeHandler.writeAttribute("hiding-toggle-caption",
  2078. attributes, getHidingToggleCaption(),
  2079. defaultState.hidingToggleCaption, String.class,
  2080. designContext);
  2081. DesignAttributeHandler.writeAttribute("width", attributes,
  2082. getWidth(), defaultState.width, Double.class,
  2083. designContext);
  2084. DesignAttributeHandler.writeAttribute("min-width", attributes,
  2085. getMinimumWidth(), defaultState.minWidth, Double.class,
  2086. designContext);
  2087. DesignAttributeHandler.writeAttribute("max-width", attributes,
  2088. getMaximumWidth(), defaultState.maxWidth, Double.class,
  2089. designContext);
  2090. DesignAttributeHandler.writeAttribute("expand", attributes,
  2091. getExpandRatio(), defaultState.expandRatio, Integer.class,
  2092. designContext);
  2093. }
  2094. /**
  2095. * Reads the design attributes for this column from given element.
  2096. *
  2097. * @since 7.5.0
  2098. * @param design
  2099. * Element to read attributes from
  2100. * @param designContext
  2101. * the design context
  2102. */
  2103. @SuppressWarnings("unchecked")
  2104. protected void readDesign(Element design, DesignContext designContext) {
  2105. Attributes attributes = design.attributes();
  2106. if (design.hasAttr("sortable")) {
  2107. setSortable(DesignAttributeHandler.readAttribute("sortable",
  2108. attributes, boolean.class));
  2109. } else {
  2110. setSortable(false);
  2111. }
  2112. if (design.hasAttr("editable")) {
  2113. /**
  2114. * This is a fake editor just to have something (otherwise
  2115. * "setEditable" throws an exception.
  2116. *
  2117. * Let's use TextField here because we support only Strings as
  2118. * inline data type. It will work incorrectly for other types
  2119. * but we don't support them anyway.
  2120. */
  2121. setEditorComponent((HasValue<V> & Component) new TextField(),
  2122. (item, value) -> {
  2123. // Ignore user value since we don't know the setter
  2124. });
  2125. setEditable(DesignAttributeHandler.readAttribute("editable",
  2126. attributes, boolean.class));
  2127. }
  2128. if (design.hasAttr("resizable")) {
  2129. setResizable(DesignAttributeHandler.readAttribute("resizable",
  2130. attributes, boolean.class));
  2131. }
  2132. if (design.hasAttr("hidable")) {
  2133. setHidable(DesignAttributeHandler.readAttribute("hidable",
  2134. attributes, boolean.class));
  2135. }
  2136. if (design.hasAttr("hidden")) {
  2137. setHidden(DesignAttributeHandler.readAttribute("hidden",
  2138. attributes, boolean.class));
  2139. }
  2140. if (design.hasAttr("hiding-toggle-caption")) {
  2141. setHidingToggleCaption(DesignAttributeHandler.readAttribute(
  2142. "hiding-toggle-caption", attributes, String.class));
  2143. }
  2144. if (design.hasAttr("assistive-caption")) {
  2145. setAssistiveCaption(DesignAttributeHandler.readAttribute(
  2146. "assistive-caption", attributes, String.class));
  2147. }
  2148. // Read size info where necessary.
  2149. if (design.hasAttr("width")) {
  2150. setWidth(DesignAttributeHandler.readAttribute("width",
  2151. attributes, Double.class));
  2152. }
  2153. if (design.hasAttr("min-width")) {
  2154. setMinimumWidth(DesignAttributeHandler
  2155. .readAttribute("min-width", attributes, Double.class));
  2156. }
  2157. if (design.hasAttr("max-width")) {
  2158. setMaximumWidth(DesignAttributeHandler
  2159. .readAttribute("max-width", attributes, Double.class));
  2160. }
  2161. if (design.hasAttr("expand")) {
  2162. if (design.attr("expand").isEmpty()) {
  2163. setExpandRatio(1);
  2164. } else {
  2165. setExpandRatio(DesignAttributeHandler.readAttribute(
  2166. "expand", attributes, Integer.class));
  2167. }
  2168. }
  2169. }
  2170. /**
  2171. * Gets the DataGenerator for this Column.
  2172. *
  2173. * @return data generator
  2174. */
  2175. private DataGenerator<T> getDataGenerator() {
  2176. return dataGenerator;
  2177. }
  2178. }
  2179. private class HeaderImpl extends Header {
  2180. @Override
  2181. protected Grid<T> getGrid() {
  2182. return Grid.this;
  2183. }
  2184. @Override
  2185. protected SectionState getState(boolean markAsDirty) {
  2186. return Grid.this.getState(markAsDirty).header;
  2187. }
  2188. @Override
  2189. protected Column<?, ?> getColumnByInternalId(String internalId) {
  2190. return getGrid().getColumnByInternalId(internalId);
  2191. }
  2192. @Override
  2193. @SuppressWarnings("unchecked")
  2194. protected String getInternalIdForColumn(Column<?, ?> column) {
  2195. return getGrid().getInternalIdForColumn((Column<T, ?>) column);
  2196. }
  2197. };
  2198. private class FooterImpl extends Footer {
  2199. @Override
  2200. protected Grid<T> getGrid() {
  2201. return Grid.this;
  2202. }
  2203. @Override
  2204. protected SectionState getState(boolean markAsDirty) {
  2205. return Grid.this.getState(markAsDirty).footer;
  2206. }
  2207. @Override
  2208. protected Column<?, ?> getColumnByInternalId(String internalId) {
  2209. return getGrid().getColumnByInternalId(internalId);
  2210. }
  2211. @Override
  2212. @SuppressWarnings("unchecked")
  2213. protected String getInternalIdForColumn(Column<?, ?> column) {
  2214. return getGrid().getInternalIdForColumn((Column<T, ?>) column);
  2215. }
  2216. };
  2217. private final Set<Column<T, ?>> columnSet = new LinkedHashSet<>();
  2218. private final Map<String, Column<T, ?>> columnKeys = new HashMap<>();
  2219. private final Map<String, Column<T, ?>> columnIds = new HashMap<>();
  2220. private final List<GridSortOrder<T>> sortOrder = new ArrayList<>();
  2221. private final DetailsManager<T> detailsManager;
  2222. private final Set<Component> extensionComponents = new HashSet<>();
  2223. private StyleGenerator<T> styleGenerator = item -> null;
  2224. private DescriptionGenerator<T> descriptionGenerator;
  2225. private final Header header = new HeaderImpl();
  2226. private final Footer footer = new FooterImpl();
  2227. private int counter = 0;
  2228. private GridSelectionModel<T> selectionModel;
  2229. private Editor<T> editor;
  2230. private PropertySet<T> propertySet;
  2231. private Class<T> beanType = null;
  2232. /**
  2233. * Creates a new grid without support for creating columns based on property
  2234. * names. Use an alternative constructor, such as {@link Grid#Grid(Class)},
  2235. * to create a grid that automatically sets up columns based on the type of
  2236. * presented data.
  2237. *
  2238. * @see #Grid(Class)
  2239. * @see #withPropertySet(PropertySet)
  2240. */
  2241. public Grid() {
  2242. this(new DataCommunicator<>());
  2243. }
  2244. /**
  2245. * Creates a new grid that uses reflection based on the provided bean type
  2246. * to automatically set up an initial set of columns. All columns will be
  2247. * configured using the same {@link Object#toString()} renderer that is used
  2248. * by {@link #addColumn(ValueProvider)}.
  2249. *
  2250. * @param beanType
  2251. * the bean type to use, not <code>null</code>
  2252. * @see #Grid()
  2253. * @see #withPropertySet(PropertySet)
  2254. */
  2255. public Grid(Class<T> beanType) {
  2256. this(beanType, new DataCommunicator<>());
  2257. }
  2258. /**
  2259. * Creates a new grid that uses custom data communicator and provided bean
  2260. * type
  2261. *
  2262. * It uses reflection of the provided bean type to automatically set up an
  2263. * initial set of columns. All columns will be configured using the same
  2264. * {@link Object#toString()} renderer that is used by
  2265. * {@link #addColumn(ValueProvider)}.
  2266. *
  2267. * @param beanType
  2268. * the bean type to use, not <code>null</code>
  2269. * @param dataCommunicator
  2270. * the data communicator to use, not<code>null</code>
  2271. * @since 8.0.7
  2272. */
  2273. protected Grid(Class<T> beanType, DataCommunicator<T> dataCommunicator) {
  2274. this(BeanPropertySet.get(beanType), dataCommunicator);
  2275. this.beanType = beanType;
  2276. }
  2277. /**
  2278. * Creates a new grid with the given data communicator and without support
  2279. * for creating columns based on property names.
  2280. *
  2281. * @param dataCommunicator
  2282. * the custom data communicator to set
  2283. * @see #Grid()
  2284. * @see #Grid(PropertySet, DataCommunicator)
  2285. * @since 8.0.7
  2286. */
  2287. protected Grid(DataCommunicator<T> dataCommunicator) {
  2288. this(new PropertySet<T>() {
  2289. @Override
  2290. public Stream<PropertyDefinition<T, ?>> getProperties() {
  2291. // No columns configured by default
  2292. return Stream.empty();
  2293. }
  2294. @Override
  2295. public Optional<PropertyDefinition<T, ?>> getProperty(String name) {
  2296. throw new IllegalStateException(
  2297. "A Grid created without a bean type class literal or a custom property set"
  2298. + " doesn't support finding properties by name.");
  2299. }
  2300. }, dataCommunicator);
  2301. }
  2302. /**
  2303. * Creates a grid using a custom {@link PropertySet} implementation for
  2304. * configuring the initial columns and resolving property names for
  2305. * {@link #addColumn(String)} and
  2306. * {@link Column#setEditorComponent(HasValue)}.
  2307. *
  2308. * @see #withPropertySet(PropertySet)
  2309. *
  2310. * @param propertySet
  2311. * the property set implementation to use, not <code>null</code>.
  2312. */
  2313. protected Grid(PropertySet<T> propertySet) {
  2314. this(propertySet, new DataCommunicator<>());
  2315. }
  2316. /**
  2317. * Creates a grid using a custom {@link PropertySet} implementation and
  2318. * custom data communicator.
  2319. * <p>
  2320. * Property set is used for configuring the initial columns and resolving
  2321. * property names for {@link #addColumn(String)} and
  2322. * {@link Column#setEditorComponent(HasValue)}.
  2323. *
  2324. * @see #withPropertySet(PropertySet)
  2325. *
  2326. * @param propertySet
  2327. * the property set implementation to use, not <code>null</code>.
  2328. * @param dataCommunicator
  2329. * the data communicator to use, not<code>null</code>
  2330. * @since 8.0.7
  2331. */
  2332. protected Grid(PropertySet<T> propertySet,
  2333. DataCommunicator<T> dataCommunicator) {
  2334. super(dataCommunicator);
  2335. registerRpc(new GridServerRpcImpl());
  2336. setDefaultHeaderRow(appendHeaderRow());
  2337. setSelectionModel(new SingleSelectionModelImpl<>());
  2338. detailsManager = new DetailsManager<>();
  2339. addExtension(detailsManager);
  2340. addDataGenerator(detailsManager);
  2341. addDataGenerator((item, json) -> {
  2342. String styleName = styleGenerator.apply(item);
  2343. if (styleName != null && !styleName.isEmpty()) {
  2344. json.put(GridState.JSONKEY_ROWSTYLE, styleName);
  2345. }
  2346. if (descriptionGenerator != null) {
  2347. String description = descriptionGenerator.apply(item);
  2348. if (description != null && !description.isEmpty()) {
  2349. json.put(GridState.JSONKEY_ROWDESCRIPTION, description);
  2350. }
  2351. }
  2352. });
  2353. setPropertySet(propertySet);
  2354. // Automatically add columns for all available properties
  2355. propertySet.getProperties().map(PropertyDefinition::getName)
  2356. .forEach(this::addColumn);
  2357. }
  2358. @Override
  2359. public void beforeClientResponse(boolean initial) {
  2360. super.beforeClientResponse(initial);
  2361. if (initial && editor.isOpen()) {
  2362. // Re-attaching grid. Any old editor should be closed.
  2363. editor.cancel();
  2364. }
  2365. }
  2366. /**
  2367. * Sets the property set to use for this grid. Does not create or update
  2368. * columns in any way but will delete and re-create the editor.
  2369. * <p>
  2370. * This is only meant to be called from constructors and readDesign, at a
  2371. * stage where it does not matter if you throw away the editor.
  2372. *
  2373. * @param propertySet
  2374. * the property set to use
  2375. *
  2376. * @since 8.0.3
  2377. */
  2378. protected void setPropertySet(PropertySet<T> propertySet) {
  2379. Objects.requireNonNull(propertySet, "propertySet cannot be null");
  2380. this.propertySet = propertySet;
  2381. if (editor instanceof Extension) {
  2382. removeExtension((Extension) editor);
  2383. }
  2384. editor = createEditor();
  2385. if (editor instanceof Extension) {
  2386. addExtension((Extension) editor);
  2387. }
  2388. }
  2389. /**
  2390. * Returns the property set used by this grid.
  2391. *
  2392. * @return propertySet the property set to return
  2393. * @since 8.4
  2394. */
  2395. protected PropertySet<T> getPropertySet() {
  2396. return propertySet;
  2397. }
  2398. /**
  2399. * Creates a grid using a custom {@link PropertySet} implementation for
  2400. * creating a default set of columns and for resolving property names with
  2401. * {@link #addColumn(String)} and
  2402. * {@link Column#setEditorComponent(HasValue)}.
  2403. * <p>
  2404. * This functionality is provided as static method instead of as a public
  2405. * constructor in order to make it possible to use a custom property set
  2406. * without creating a subclass while still leaving the public constructors
  2407. * focused on the common use cases.
  2408. *
  2409. * @see Grid#Grid()
  2410. * @see Grid#Grid(Class)
  2411. *
  2412. * @param propertySet
  2413. * the property set implementation to use, not <code>null</code>.
  2414. * @return a new grid using the provided property set, not <code>null</code>
  2415. */
  2416. public static <BEAN> Grid<BEAN> withPropertySet(
  2417. PropertySet<BEAN> propertySet) {
  2418. return new Grid<>(propertySet);
  2419. }
  2420. /**
  2421. * Creates a new {@code Grid} using the given caption.
  2422. *
  2423. * @param caption
  2424. * the caption of the grid
  2425. */
  2426. public Grid(String caption) {
  2427. this();
  2428. setCaption(caption);
  2429. }
  2430. /**
  2431. * Creates a new {@code Grid} using the given caption and
  2432. * {@code DataProvider}.
  2433. *
  2434. * @param caption
  2435. * the caption of the grid
  2436. * @param dataProvider
  2437. * the data provider, not {@code null}
  2438. */
  2439. public Grid(String caption, DataProvider<T, ?> dataProvider) {
  2440. this(caption);
  2441. setDataProvider(dataProvider);
  2442. }
  2443. /**
  2444. * Creates a new {@code Grid} using the given {@code DataProvider}.
  2445. *
  2446. * @param dataProvider
  2447. * the data provider, not {@code null}
  2448. */
  2449. public Grid(DataProvider<T, ?> dataProvider) {
  2450. this();
  2451. setDataProvider(dataProvider);
  2452. }
  2453. /**
  2454. * Creates a new {@code Grid} using the given caption and collection of
  2455. * items.
  2456. *
  2457. * @param caption
  2458. * the caption of the grid
  2459. * @param items
  2460. * the data items to use, not {@çode null}
  2461. */
  2462. public Grid(String caption, Collection<T> items) {
  2463. this(caption, DataProvider.ofCollection(items));
  2464. }
  2465. /**
  2466. * Gets the bean type used by this grid.
  2467. * <p>
  2468. * The bean type is used to automatically set up a column added using a
  2469. * property name.
  2470. *
  2471. * @return the used bean type or <code>null</code> if no bean type has been
  2472. * defined
  2473. *
  2474. * @since 8.0.3
  2475. */
  2476. public Class<T> getBeanType() {
  2477. return beanType;
  2478. }
  2479. public <V> void fireColumnVisibilityChangeEvent(Column<T, V> column,
  2480. boolean hidden, boolean userOriginated) {
  2481. fireEvent(new ColumnVisibilityChangeEvent(this, column, hidden,
  2482. userOriginated));
  2483. }
  2484. /**
  2485. * Adds a new column with the given property name. The column will use a
  2486. * {@link TextRenderer}. The value is converted to a String using
  2487. * {@link Object#toString()}. The property name will be used as the
  2488. * {@link Column#getId() column id} and the {@link Column#getCaption()
  2489. * column caption} will be set based on the property definition.
  2490. * <p>
  2491. * This method can only be used for a <code>Grid</code> created using
  2492. * {@link Grid#Grid(Class)} or {@link #withPropertySet(PropertySet)}.
  2493. * <p>
  2494. * You can add columns for nested properties with dot notation, eg.
  2495. * <code>"property.nestedProperty"</code>
  2496. *
  2497. * @param propertyName
  2498. * the property name of the new column, not <code>null</code>
  2499. * @return the newly added column, not <code>null</code>
  2500. */
  2501. public Column<T, ?> addColumn(String propertyName) {
  2502. return addColumn(propertyName, new TextRenderer());
  2503. }
  2504. /**
  2505. * Adds a new column with the given property name and renderer. The property
  2506. * name will be used as the {@link Column#getId() column id} and the
  2507. * {@link Column#getCaption() column caption} will be set based on the
  2508. * property definition.
  2509. * <p>
  2510. * This method can only be used for a <code>Grid</code> created using
  2511. * {@link Grid#Grid(Class)} or {@link #withPropertySet(PropertySet)}.
  2512. * <p>
  2513. * You can add columns for nested properties with dot notation, eg.
  2514. * <code>"property.nestedProperty"</code>
  2515. *
  2516. *
  2517. * @param propertyName
  2518. * the property name of the new column, not <code>null</code>
  2519. * @param renderer
  2520. * the renderer to use, not <code>null</code>
  2521. * @return the newly added column, not <code>null</code>
  2522. */
  2523. public Column<T, ?> addColumn(String propertyName,
  2524. AbstractRenderer<? super T, ?> renderer) {
  2525. Objects.requireNonNull(propertyName, "Property name cannot be null");
  2526. Objects.requireNonNull(renderer, "Renderer cannot be null");
  2527. if (getColumn(propertyName) != null) {
  2528. throw new IllegalStateException(
  2529. "There is already a column for " + propertyName);
  2530. }
  2531. PropertyDefinition<T, ?> definition = propertySet
  2532. .getProperty(propertyName)
  2533. .orElseThrow(() -> new IllegalArgumentException(
  2534. "Could not resolve property name " + propertyName
  2535. + " from " + propertySet));
  2536. if (!renderer.getPresentationType()
  2537. .isAssignableFrom(definition.getType())) {
  2538. throw new IllegalArgumentException(
  2539. renderer + " cannot be used with a property of type "
  2540. + definition.getType().getName());
  2541. }
  2542. @SuppressWarnings({ "unchecked", "rawtypes" })
  2543. Column<T, ?> column = addColumn(definition.getGetter(),
  2544. (AbstractRenderer) renderer).setId(definition.getName())
  2545. .setCaption(definition.getCaption());
  2546. return column;
  2547. }
  2548. /**
  2549. * Adds a new column with the given property name and renderer. The property
  2550. * name will be used as the {@link Column#getId() column id} and the
  2551. * {@link Column#getCaption() column caption} will be set based on the
  2552. * property definition.
  2553. * <p>
  2554. * This method can only be used for a <code>Grid</code> created using
  2555. * {@link Grid#Grid(Class)} or {@link #withPropertySet(PropertySet)}.
  2556. * <p>
  2557. * You can add columns for nested properties with dot notation, eg.
  2558. * <code>"property.nestedProperty"</code>
  2559. *
  2560. * @param propertyName
  2561. * the property name of the new column, not <code>null</code>
  2562. * @param renderer
  2563. * the renderer to use, not <code>null</code>
  2564. * @param nestedNullBehavior
  2565. * the behavior when
  2566. * @return the newly added column, not <code>null</code>
  2567. *
  2568. * @since 8.8
  2569. */
  2570. public Column<T, ?> addColumn(String propertyName,
  2571. AbstractRenderer<? super T, ?> renderer,
  2572. Column.NestedNullBehavior nestedNullBehavior) {
  2573. Objects.requireNonNull(propertyName, "Property name cannot be null");
  2574. Objects.requireNonNull(renderer, "Renderer cannot be null");
  2575. if (getColumn(propertyName) != null) {
  2576. throw new IllegalStateException(
  2577. "There is already a column for " + propertyName);
  2578. }
  2579. PropertyDefinition<T, ?> definition = propertySet
  2580. .getProperty(propertyName)
  2581. .orElseThrow(() -> new IllegalArgumentException(
  2582. "Could not resolve property name " + propertyName
  2583. + " from " + propertySet));
  2584. if (!renderer.getPresentationType()
  2585. .isAssignableFrom(definition.getType())) {
  2586. throw new IllegalArgumentException(
  2587. renderer + " cannot be used with a property of type "
  2588. + definition.getType().getName());
  2589. }
  2590. @SuppressWarnings({ "unchecked", "rawtypes" })
  2591. Column<T, ?> column = createColumn(definition.getGetter(),
  2592. ValueProvider.identity(), (AbstractRenderer) renderer,
  2593. nestedNullBehavior);
  2594. String generatedIdentifier = getGeneratedIdentifier();
  2595. addColumn(generatedIdentifier, column);
  2596. column.setId(definition.getName()).setCaption(definition.getCaption());
  2597. return column;
  2598. }
  2599. /**
  2600. * Adds a new text column to this {@link Grid} with a value provider. The
  2601. * column will use a {@link TextRenderer}. The value is converted to a
  2602. * String using {@link Object#toString()}. In-memory sorting will use the
  2603. * natural ordering of elements if they are mutually comparable and
  2604. * otherwise fall back to comparing the string representations of the
  2605. * values.
  2606. *
  2607. * @param valueProvider
  2608. * the value provider
  2609. *
  2610. * @return the new column
  2611. */
  2612. public <V> Column<T, V> addColumn(ValueProvider<T, V> valueProvider) {
  2613. return addColumn(valueProvider, new TextRenderer());
  2614. }
  2615. /**
  2616. * Adds a new column to this {@link Grid} with typed renderer and value
  2617. * provider.
  2618. *
  2619. * @param valueProvider
  2620. * the value provider
  2621. * @param renderer
  2622. * the column value renderer
  2623. * @param <V>
  2624. * the column value type
  2625. *
  2626. * @return the new column
  2627. *
  2628. * @see AbstractRenderer
  2629. */
  2630. public <V> Column<T, V> addColumn(ValueProvider<T, V> valueProvider,
  2631. AbstractRenderer<? super T, ? super V> renderer) {
  2632. return addColumn(valueProvider, ValueProvider.identity(), renderer);
  2633. }
  2634. /**
  2635. * Adds a new column to this {@link Grid} with value provider and
  2636. * presentation provider.
  2637. * <p>
  2638. * <strong>Note:</strong> The presentation type for this method is set to be
  2639. * String. To use any custom renderer with the presentation provider, use
  2640. * {@link #addColumn(ValueProvider, ValueProvider, AbstractRenderer)}.
  2641. *
  2642. * @param valueProvider
  2643. * the value provider
  2644. * @param presentationProvider
  2645. * the value presentation provider
  2646. * @param <V>
  2647. * the column value type
  2648. *
  2649. * @see #addColumn(ValueProvider, ValueProvider, AbstractRenderer)
  2650. *
  2651. * @return the new column
  2652. * @since 8.1
  2653. */
  2654. public <V> Column<T, V> addColumn(ValueProvider<T, V> valueProvider,
  2655. ValueProvider<V, String> presentationProvider) {
  2656. return addColumn(valueProvider, presentationProvider,
  2657. new TextRenderer());
  2658. }
  2659. /**
  2660. * Adds a new column to this {@link Grid} with value provider, presentation
  2661. * provider and typed renderer.
  2662. *
  2663. * <p>
  2664. * The presentation provider is a method that takes the value from the value
  2665. * provider, and maps that to a value that the renderer accepts. This
  2666. * feature can be used for storing a complex value in a column for editing,
  2667. * but providing a simplified presentation for the user when not editing.
  2668. *
  2669. * @param valueProvider
  2670. * the value provider
  2671. * @param presentationProvider
  2672. * the value presentation provider
  2673. * @param renderer
  2674. * the column value renderer
  2675. * @param <V>
  2676. * the column value type
  2677. * @param <P>
  2678. * the column presentation type
  2679. *
  2680. * @return the new column
  2681. *
  2682. * @see AbstractRenderer
  2683. * @since 8.1
  2684. */
  2685. public <V, P> Column<T, V> addColumn(ValueProvider<T, V> valueProvider,
  2686. ValueProvider<V, P> presentationProvider,
  2687. AbstractRenderer<? super T, ? super P> renderer) {
  2688. String generatedIdentifier = getGeneratedIdentifier();
  2689. Column<T, V> column = createColumn(valueProvider, presentationProvider,
  2690. renderer);
  2691. addColumn(generatedIdentifier, column);
  2692. return column;
  2693. }
  2694. /**
  2695. * Adds a column that shows components.
  2696. * <p>
  2697. * This is a shorthand for {@link #addColumn()} with a
  2698. * {@link ComponentRenderer}.
  2699. *
  2700. * @param componentProvider
  2701. * a value provider that will return a component for the given
  2702. * item
  2703. * @return the new column
  2704. * @param <V>
  2705. * the column value type, extends component
  2706. * @since 8.1
  2707. */
  2708. public <V extends Component> Column<T, V> addComponentColumn(
  2709. ValueProvider<T, V> componentProvider) {
  2710. return addColumn(componentProvider, new ComponentRenderer());
  2711. }
  2712. /**
  2713. * Creates a column instance from a value provider, presentation provider
  2714. * and a renderer.
  2715. *
  2716. * @param valueProvider
  2717. * the value provider
  2718. * @param presentationProvider
  2719. * the presentation provider
  2720. * @param renderer
  2721. * the renderer
  2722. * @return a new column instance
  2723. * @param <V>
  2724. * the column value type
  2725. * @param <P>
  2726. * the column presentation type
  2727. *
  2728. * @since 8.1
  2729. */
  2730. protected <V, P> Column<T, V> createColumn(
  2731. ValueProvider<T, V> valueProvider,
  2732. ValueProvider<V, P> presentationProvider,
  2733. AbstractRenderer<? super T, ? super P> renderer) {
  2734. return new Column<>(valueProvider, presentationProvider, renderer);
  2735. }
  2736. /**
  2737. * Creates a column instance from a value provider, presentation provider
  2738. * and a renderer.
  2739. *
  2740. * @param valueProvider
  2741. * the value provider
  2742. * @param presentationProvider
  2743. * the presentation provider
  2744. * @param renderer
  2745. * the renderer
  2746. * @param nestedNullBehavior
  2747. * the behavior when facing nested <code>null</code> values
  2748. * @return a new column instance
  2749. * @param <V>
  2750. * the column value type
  2751. * @param <P>
  2752. * the column presentation type
  2753. *
  2754. * @since 8.8
  2755. */
  2756. private <V, P> Column<T, V> createColumn(ValueProvider<T, V> valueProvider,
  2757. ValueProvider<V, P> presentationProvider,
  2758. AbstractRenderer<? super T, ? super P> renderer,
  2759. Column.NestedNullBehavior nestedNullBehavior) {
  2760. return new Column<>(valueProvider, presentationProvider, renderer,
  2761. nestedNullBehavior);
  2762. }
  2763. private void addColumn(String identifier, Column<T, ?> column) {
  2764. if (getColumns().contains(column)) {
  2765. return;
  2766. }
  2767. column.extend(this);
  2768. columnSet.add(column);
  2769. columnKeys.put(identifier, column);
  2770. column.setInternalId(identifier);
  2771. addDataGenerator(column.getDataGenerator());
  2772. getState().columnOrder.add(identifier);
  2773. getHeader().addColumn(identifier);
  2774. getFooter().addColumn(identifier);
  2775. if (getDefaultHeaderRow() != null) {
  2776. getDefaultHeaderRow().getCell(column).setText(column.getCaption());
  2777. }
  2778. column.updateSortable();
  2779. }
  2780. /**
  2781. * Removes the given column from this {@link Grid}.
  2782. *
  2783. * Note: If you have Editor with binding in this Grid to this property, you need to remove that
  2784. * using removeBinding method provided by Binder.
  2785. *
  2786. * @param column
  2787. * the column to remove
  2788. *
  2789. * @throws IllegalArgumentException
  2790. * if the column is not a valid one
  2791. */
  2792. public void removeColumn(Column<T, ?> column) {
  2793. if (columnSet.remove(column)) {
  2794. String columnId = column.getInternalId();
  2795. int displayIndex = getState(false).columnOrder.indexOf(columnId);
  2796. assert displayIndex != -1 : "Tried to remove a column which is not included in columnOrder. This should not be possible as all columns should be in columnOrder.";
  2797. columnKeys.remove(columnId);
  2798. columnIds.remove(column.getId());
  2799. column.remove();
  2800. removeDataGenerator(column.getDataGenerator());
  2801. getHeader().removeColumn(columnId);
  2802. getFooter().removeColumn(columnId);
  2803. getState(true).columnOrder.remove(columnId);
  2804. // Remove column from sorted columns.
  2805. List<GridSortOrder<T>> filteredSortOrder = sortOrder.stream()
  2806. .filter(order -> !order.getSorted().equals(column))
  2807. .collect(Collectors.toList());
  2808. if (filteredSortOrder.size() < sortOrder.size()) {
  2809. setSortOrder(filteredSortOrder);
  2810. }
  2811. if (displayIndex < getFrozenColumnCount()) {
  2812. setFrozenColumnCount(getFrozenColumnCount() - 1);
  2813. }
  2814. } else {
  2815. throw new IllegalArgumentException("Column with id "
  2816. + column.getId() + " cannot be removed from the grid");
  2817. }
  2818. }
  2819. /**
  2820. * Removes the column with the given column id.
  2821. *
  2822. * @see #removeColumn(Column)
  2823. * @see Column#setId(String)
  2824. *
  2825. * @param columnId
  2826. * the id of the column to remove, not <code>null</code>
  2827. */
  2828. public void removeColumn(String columnId) {
  2829. removeColumn(getColumnOrThrow(columnId));
  2830. }
  2831. /**
  2832. * Removes all columns from this Grid.
  2833. *
  2834. * @since 8.0.2
  2835. */
  2836. public void removeAllColumns() {
  2837. for (Column<T, ?> column : getColumns()) {
  2838. removeColumn(column);
  2839. }
  2840. }
  2841. /**
  2842. * Requests that the column widths should be recalculated.
  2843. * <p>
  2844. * In most cases Grid will know when column widths need to be recalculated
  2845. * but this method can be used to force recalculation in situations when
  2846. * grid does not recalculate automatically.
  2847. *
  2848. * @since 8.1.1
  2849. */
  2850. public void recalculateColumnWidths() {
  2851. getRpcProxy(GridClientRpc.class).recalculateColumnWidths();
  2852. }
  2853. /**
  2854. * Sets the details component generator.
  2855. *
  2856. * @param generator
  2857. * the generator for details components
  2858. */
  2859. public void setDetailsGenerator(DetailsGenerator<T> generator) {
  2860. this.detailsManager.setDetailsGenerator(generator);
  2861. }
  2862. /**
  2863. * Sets the visibility of details component for given item.
  2864. *
  2865. * @param item
  2866. * the item to show details for
  2867. * @param visible
  2868. * {@code true} if details component should be visible;
  2869. * {@code false} if it should be hidden
  2870. */
  2871. public void setDetailsVisible(T item, boolean visible) {
  2872. detailsManager.setDetailsVisible(item, visible);
  2873. }
  2874. /**
  2875. * Returns the visibility of details component for given item.
  2876. *
  2877. * @param item
  2878. * the item to show details for
  2879. *
  2880. * @return {@code true} if details component should be visible;
  2881. * {@code false} if it should be hidden
  2882. */
  2883. public boolean isDetailsVisible(T item) {
  2884. return detailsManager.isDetailsVisible(item);
  2885. }
  2886. /**
  2887. * Gets an unmodifiable collection of all columns currently in this
  2888. * {@link Grid}.
  2889. *
  2890. * @return unmodifiable collection of columns
  2891. */
  2892. public List<Column<T, ?>> getColumns() {
  2893. return Collections.unmodifiableList(getState(false).columnOrder.stream()
  2894. .map(columnKeys::get).collect(Collectors.toList()));
  2895. }
  2896. /**
  2897. * Gets a {@link Column} of this grid by its identifying string.
  2898. *
  2899. * When you use the Grid constructor with bean class, the columns are
  2900. * initialised with columnId being the property name.
  2901. *
  2902. * @see Column#setId(String)
  2903. *
  2904. * @param columnId
  2905. * the identifier of the column to get
  2906. * @return the column corresponding to the given column identifier, or
  2907. * <code>null</code> if there is no such column
  2908. */
  2909. public Column<T, ?> getColumn(String columnId) {
  2910. return columnIds.get(columnId);
  2911. }
  2912. private Column<T, ?> getColumnOrThrow(String columnId) {
  2913. Objects.requireNonNull(columnId, "Column id cannot be null");
  2914. Column<T, ?> column = getColumn(columnId);
  2915. if (column == null) {
  2916. throw new IllegalStateException(
  2917. "There is no column with the id " + columnId);
  2918. }
  2919. return column;
  2920. }
  2921. /**
  2922. * {@inheritDoc}
  2923. * <p>
  2924. * Note that the order of the returned components it not specified.
  2925. */
  2926. @Override
  2927. public Iterator<Component> iterator() {
  2928. Set<Component> componentSet = new LinkedHashSet<>(extensionComponents);
  2929. Header header = getHeader();
  2930. for (int i = 0; i < header.getRowCount(); ++i) {
  2931. HeaderRow row = header.getRow(i);
  2932. componentSet.addAll(row.getComponents());
  2933. }
  2934. Footer footer = getFooter();
  2935. for (int i = 0; i < footer.getRowCount(); ++i) {
  2936. FooterRow row = footer.getRow(i);
  2937. componentSet.addAll(row.getComponents());
  2938. }
  2939. return Collections.unmodifiableSet(componentSet).iterator();
  2940. }
  2941. /**
  2942. * Sets the number of frozen columns in this grid. Setting the count to 0
  2943. * means that no data columns will be frozen, but the built-in selection
  2944. * checkbox column will still be frozen if it's in use. Setting the count to
  2945. * -1 will also disable the selection column.
  2946. * <p>
  2947. * <em>NOTE:</em> this count includes {@link Column#isHidden() hidden
  2948. * columns} in the count.
  2949. * <p>
  2950. * The default value is 0.
  2951. *
  2952. * @param numberOfColumns
  2953. * the number of columns that should be frozen
  2954. *
  2955. * @throws IllegalArgumentException
  2956. * if the column count is less than -1 or greater than the
  2957. * number of visible columns
  2958. */
  2959. public void setFrozenColumnCount(int numberOfColumns) {
  2960. if (numberOfColumns < -1 || numberOfColumns > columnSet.size()) {
  2961. throw new IllegalArgumentException(
  2962. "count must be between -1 and the current number of columns ("
  2963. + columnSet.size() + "): " + numberOfColumns);
  2964. }
  2965. int currentFrozenColumnState = getState(false).frozenColumnCount;
  2966. /*
  2967. * we remove the current value from the state so that setting frozen
  2968. * columns will always happen after this call. This is so that the value
  2969. * will be set also in the widget even if it happens to seem to be the
  2970. * same as this current value we're setting.
  2971. */
  2972. if (currentFrozenColumnState != numberOfColumns) {
  2973. final String diffStateKey = "frozenColumnCount";
  2974. UI ui = getUI();
  2975. if (ui != null) {
  2976. JsonObject diffState = ui.getConnectorTracker()
  2977. .getDiffState(Grid.this);
  2978. // if diffState is not present, there's nothing for us to clean
  2979. if (diffState != null) {
  2980. diffState.remove(diffStateKey);
  2981. }
  2982. }
  2983. }
  2984. getState().frozenColumnCount = numberOfColumns;
  2985. }
  2986. /**
  2987. * Gets the number of frozen columns in this grid. 0 means that no data
  2988. * columns will be frozen, but the built-in selection checkbox column will
  2989. * still be frozen if it's in use. -1 means that not even the selection
  2990. * column is frozen.
  2991. * <p>
  2992. * <em>NOTE:</em> this count includes {@link Column#isHidden() hidden
  2993. * columns} in the count.
  2994. *
  2995. * @see #setFrozenColumnCount(int)
  2996. *
  2997. * @return the number of frozen columns
  2998. */
  2999. public int getFrozenColumnCount() {
  3000. return getState(false).frozenColumnCount;
  3001. }
  3002. /**
  3003. * Sets the number of rows that should be visible in Grid's body. This
  3004. * method will set the height mode to be {@link HeightMode#ROW}.
  3005. *
  3006. * @param rows
  3007. * The height in terms of number of rows displayed in Grid's
  3008. * body. If Grid doesn't contain enough rows, white space is
  3009. * displayed instead.
  3010. * @throws IllegalArgumentException
  3011. * if {@code rows} is zero or less
  3012. * @throws IllegalArgumentException
  3013. * if {@code rows} is {@link Double#isInfinite(double) infinite}
  3014. * @throws IllegalArgumentException
  3015. * if {@code rows} is {@link Double#isNaN(double) NaN}
  3016. */
  3017. public void setHeightByRows(double rows) {
  3018. if (rows <= 0.0d) {
  3019. throw new IllegalArgumentException(
  3020. "More than zero rows must be shown.");
  3021. }
  3022. if (Double.isInfinite(rows)) {
  3023. throw new IllegalArgumentException(
  3024. "Grid doesn't support infinite heights");
  3025. }
  3026. if (Double.isNaN(rows)) {
  3027. throw new IllegalArgumentException("NaN is not a valid row count");
  3028. }
  3029. getState().heightMode = HeightMode.ROW;
  3030. getState().heightByRows = rows;
  3031. }
  3032. /**
  3033. * Gets the amount of rows in Grid's body that are shown, while
  3034. * {@link #getHeightMode()} is {@link HeightMode#ROW}.
  3035. *
  3036. * @return the amount of rows that are being shown in Grid's body
  3037. * @see #setHeightByRows(double)
  3038. */
  3039. public double getHeightByRows() {
  3040. return getState(false).heightByRows;
  3041. }
  3042. /**
  3043. * {@inheritDoc}
  3044. * <p>
  3045. * <em>Note:</em> This method will set the height mode to be
  3046. * {@link HeightMode#CSS}.
  3047. *
  3048. * @see #setHeightMode(HeightMode)
  3049. */
  3050. @Override
  3051. public void setHeight(float height, Unit unit) {
  3052. getState().heightMode = HeightMode.CSS;
  3053. super.setHeight(height, unit);
  3054. }
  3055. /**
  3056. * Defines the mode in which the Grid widget's height is calculated.
  3057. * <p>
  3058. * If {@link HeightMode#CSS} is given, Grid will respect the values given
  3059. * via a {@code setHeight}-method, and behave as a traditional Component.
  3060. * <p>
  3061. * If {@link HeightMode#ROW} is given, Grid will make sure that the body
  3062. * will display as many rows as {@link #getHeightByRows()} defines.
  3063. * <em>Note:</em> If headers/footers are inserted or removed, the widget
  3064. * will resize itself to still display the required amount of rows in its
  3065. * body. It also takes the horizontal scrollbar into account.
  3066. *
  3067. * @param heightMode
  3068. * the mode in to which Grid should be set
  3069. */
  3070. public void setHeightMode(HeightMode heightMode) {
  3071. /**
  3072. * This method is a workaround for the fact that Vaadin re-applies
  3073. * widget dimensions (height/width) on each state change event. The
  3074. * original design was to have setHeight and setHeightByRow be equals,
  3075. * and whichever was called the latest was considered in effect.
  3076. *
  3077. * But, because of Vaadin always calling setHeight on the widget, this
  3078. * approach doesn't work.
  3079. */
  3080. getState().heightMode = heightMode;
  3081. }
  3082. /**
  3083. * Returns the current {@link HeightMode} the Grid is in.
  3084. * <p>
  3085. * Defaults to {@link HeightMode#CSS}.
  3086. *
  3087. * @return the current HeightMode
  3088. */
  3089. public HeightMode getHeightMode() {
  3090. return getState(false).heightMode;
  3091. }
  3092. /**
  3093. * Sets the height of body, header and footer rows. If -1 (default), the row
  3094. * height is calculated based on the theme for an empty row before the Grid
  3095. * is displayed.
  3096. * <p>
  3097. * Note that all header, body and footer rows get the same height if
  3098. * explicitly set. In automatic mode, each section is calculated separately
  3099. * based on an empty row of that type.
  3100. *
  3101. * @see #setBodyRowHeight(double)
  3102. * @see #setHeaderRowHeight(double)
  3103. * @see #setFooterRowHeight(double)
  3104. *
  3105. * @param rowHeight
  3106. * The height of a row in pixels or -1 for automatic calculation
  3107. */
  3108. public void setRowHeight(double rowHeight) {
  3109. setBodyRowHeight(rowHeight);
  3110. setHeaderRowHeight(rowHeight);
  3111. setFooterRowHeight(rowHeight);
  3112. }
  3113. /**
  3114. * Sets the height of a body row. If -1 (default), the row height is
  3115. * calculated based on the theme for an empty row before the Grid is
  3116. * displayed.
  3117. *
  3118. * @param rowHeight
  3119. * The height of a row in pixels or -1 for automatic calculation
  3120. * @since 8.2
  3121. */
  3122. public void setBodyRowHeight(double rowHeight) {
  3123. getState().bodyRowHeight = rowHeight;
  3124. }
  3125. /**
  3126. * Sets the height of a header row. If -1 (default), the row height is
  3127. * calculated based on the theme for an empty row before the Grid is
  3128. * displayed.
  3129. *
  3130. * @param rowHeight
  3131. * The height of a row in pixels or -1 for automatic calculation
  3132. * @since 8.2
  3133. */
  3134. public void setHeaderRowHeight(double rowHeight) {
  3135. getState().headerRowHeight = rowHeight;
  3136. }
  3137. /**
  3138. * Sets the height of a footer row. If -1 (default), the row height is
  3139. * calculated based on the theme for an empty row before the Grid is
  3140. * displayed.
  3141. *
  3142. * @param rowHeight
  3143. * The height of a row in pixels or -1 for automatic calculation
  3144. * @since 8.2
  3145. */
  3146. public void setFooterRowHeight(double rowHeight) {
  3147. getState().footerRowHeight = rowHeight;
  3148. }
  3149. /**
  3150. * Returns the current body row height.-1 if row height is in automatic
  3151. * calculation mode.
  3152. *
  3153. * @see #getBodyRowHeight()
  3154. * @see #getHeaderRowHeight()
  3155. * @see #getFooterRowHeight()
  3156. *
  3157. * @return body row height
  3158. * @deprecated replaced by three separate row height controls
  3159. */
  3160. @Deprecated
  3161. public double getRowHeight() {
  3162. return getBodyRowHeight();
  3163. }
  3164. /**
  3165. * Returns the current body row height. -1 if row height is in automatic
  3166. * calculation mode.
  3167. *
  3168. * @return body row height
  3169. * @since 8.2
  3170. */
  3171. public double getBodyRowHeight() {
  3172. return getState(false).bodyRowHeight;
  3173. }
  3174. /**
  3175. * Returns the current header row height. -1 if row height is in automatic
  3176. * calculation mode.
  3177. *
  3178. * @return header row height
  3179. * @since 8.2
  3180. */
  3181. public double getHeaderRowHeight() {
  3182. return getState(false).headerRowHeight;
  3183. }
  3184. /**
  3185. * Returns the current footer row height. -1 if row height is in automatic
  3186. * calculation mode.
  3187. *
  3188. * @return footer row height
  3189. * @since 8.2
  3190. */
  3191. public double getFooterRowHeight() {
  3192. return getState(false).footerRowHeight;
  3193. }
  3194. /**
  3195. * Sets the style generator that is used for generating class names for rows
  3196. * in this grid. Returning null from the generator results in no custom
  3197. * style name being set.
  3198. *
  3199. * Note: The style generator is applied only to the body cells, not to the
  3200. * Editor.
  3201. *
  3202. * @see StyleGenerator
  3203. *
  3204. * @param styleGenerator
  3205. * the row style generator to set, not null
  3206. * @throws NullPointerException
  3207. * if {@code styleGenerator} is {@code null}
  3208. */
  3209. public void setStyleGenerator(StyleGenerator<T> styleGenerator) {
  3210. Objects.requireNonNull(styleGenerator,
  3211. "Style generator must not be null");
  3212. this.styleGenerator = styleGenerator;
  3213. getDataCommunicator().reset();
  3214. }
  3215. /**
  3216. * Gets the style generator that is used for generating class names for
  3217. * rows.
  3218. *
  3219. * @see StyleGenerator
  3220. *
  3221. * @return the row style generator
  3222. */
  3223. public StyleGenerator<T> getStyleGenerator() {
  3224. return styleGenerator;
  3225. }
  3226. /**
  3227. * Sets the description generator that is used for generating descriptions
  3228. * for rows. This method uses the {@link ContentMode#PREFORMATTED} content
  3229. * mode.
  3230. *
  3231. * @see #setDescriptionGenerator(DescriptionGenerator, ContentMode)
  3232. *
  3233. * @param descriptionGenerator
  3234. * the row description generator to set, or <code>null</code> to
  3235. * remove a previously set generator
  3236. */
  3237. public void setDescriptionGenerator(
  3238. DescriptionGenerator<T> descriptionGenerator) {
  3239. setDescriptionGenerator(descriptionGenerator, ContentMode.PREFORMATTED);
  3240. }
  3241. /**
  3242. * Sets the description generator that is used for generating descriptions
  3243. * for rows. This method uses the given content mode.
  3244. *
  3245. * @see #setDescriptionGenerator(DescriptionGenerator)
  3246. *
  3247. * @param descriptionGenerator
  3248. * the row description generator to set, or {@code null} to
  3249. * remove a previously set generator
  3250. * @param contentMode
  3251. * the content mode for row tooltips
  3252. *
  3253. * @since 8.2
  3254. */
  3255. public void setDescriptionGenerator(
  3256. DescriptionGenerator<T> descriptionGenerator,
  3257. ContentMode contentMode) {
  3258. Objects.requireNonNull(contentMode, "contentMode cannot be null");
  3259. this.descriptionGenerator = descriptionGenerator;
  3260. getState().rowDescriptionContentMode = contentMode;
  3261. getDataCommunicator().reset();
  3262. }
  3263. /**
  3264. * Gets the description generator that is used for generating descriptions
  3265. * for rows.
  3266. *
  3267. * @return the row description generator, or <code>null</code> if no
  3268. * generator is set
  3269. */
  3270. public DescriptionGenerator<T> getDescriptionGenerator() {
  3271. return descriptionGenerator;
  3272. }
  3273. //
  3274. // HEADER AND FOOTER
  3275. //
  3276. /**
  3277. * Returns the header row at the given index.
  3278. *
  3279. * @param index
  3280. * the index of the row, where the topmost row has index zero
  3281. * @return the header row at the index
  3282. * @throws IndexOutOfBoundsException
  3283. * if {@code rowIndex < 0 || rowIndex >= getHeaderRowCount()}
  3284. */
  3285. public HeaderRow getHeaderRow(int index) {
  3286. return getHeader().getRow(index);
  3287. }
  3288. /**
  3289. * Gets the number of rows in the header section.
  3290. *
  3291. * @return the number of header rows
  3292. */
  3293. public int getHeaderRowCount() {
  3294. return header.getRowCount();
  3295. }
  3296. /**
  3297. * Inserts a new row at the given position to the header section. Shifts the
  3298. * row currently at that position and any subsequent rows down (adds one to
  3299. * their indices). Inserting at {@link #getHeaderRowCount()} appends the row
  3300. * at the bottom of the header.
  3301. *
  3302. * @param index
  3303. * the index at which to insert the row, where the topmost row
  3304. * has index zero
  3305. * @return the inserted header row
  3306. *
  3307. * @throws IndexOutOfBoundsException
  3308. * if {@code rowIndex < 0 || rowIndex > getHeaderRowCount()}
  3309. *
  3310. * @see #appendHeaderRow()
  3311. * @see #prependHeaderRow()
  3312. * @see #removeHeaderRow(HeaderRow)
  3313. * @see #removeHeaderRow(int)
  3314. */
  3315. public HeaderRow addHeaderRowAt(int index) {
  3316. return getHeader().addRowAt(index);
  3317. }
  3318. /**
  3319. * Adds a new row at the bottom of the header section.
  3320. *
  3321. * @return the appended header row
  3322. *
  3323. * @see #prependHeaderRow()
  3324. * @see #addHeaderRowAt(int)
  3325. * @see #removeHeaderRow(HeaderRow)
  3326. * @see #removeHeaderRow(int)
  3327. */
  3328. public HeaderRow appendHeaderRow() {
  3329. return addHeaderRowAt(getHeaderRowCount());
  3330. }
  3331. /**
  3332. * Adds a new row at the top of the header section.
  3333. *
  3334. * @return the prepended header row
  3335. *
  3336. * @see #appendHeaderRow()
  3337. * @see #addHeaderRowAt(int)
  3338. * @see #removeHeaderRow(HeaderRow)
  3339. * @see #removeHeaderRow(int)
  3340. */
  3341. public HeaderRow prependHeaderRow() {
  3342. return addHeaderRowAt(0);
  3343. }
  3344. /**
  3345. * Removes the given row from the header section. Removing a default row
  3346. * sets the Grid to have no default row.
  3347. *
  3348. * @param row
  3349. * the header row to be removed, not null
  3350. *
  3351. * @throws IllegalArgumentException
  3352. * if the header does not contain the row
  3353. *
  3354. * @see #removeHeaderRow(int)
  3355. * @see #addHeaderRowAt(int)
  3356. * @see #appendHeaderRow()
  3357. * @see #prependHeaderRow()
  3358. */
  3359. public void removeHeaderRow(HeaderRow row) {
  3360. getHeader().removeRow(row);
  3361. }
  3362. /**
  3363. * Removes the row at the given position from the header section.
  3364. *
  3365. * @param index
  3366. * the index of the row to remove, where the topmost row has
  3367. * index zero
  3368. *
  3369. * @throws IndexOutOfBoundsException
  3370. * if {@code index < 0 || index >= getHeaderRowCount()}
  3371. *
  3372. * @see #removeHeaderRow(HeaderRow)
  3373. * @see #addHeaderRowAt(int)
  3374. * @see #appendHeaderRow()
  3375. * @see #prependHeaderRow()
  3376. */
  3377. public void removeHeaderRow(int index) {
  3378. getHeader().removeRow(index);
  3379. }
  3380. /**
  3381. * Sets the visibility of the Header in this Grid.
  3382. *
  3383. * @param headerVisible
  3384. * {@code true} if visible; {@code false} if not
  3385. *
  3386. * @since 8.1.1
  3387. */
  3388. public void setHeaderVisible(boolean headerVisible) {
  3389. getHeader().setVisible(headerVisible);
  3390. }
  3391. /**
  3392. * Gets the visibility of the Header in this Grid.
  3393. *
  3394. * @return {@code true} if visible; {@code false} if not
  3395. *
  3396. * @since 8.1.1
  3397. */
  3398. public boolean isHeaderVisible() {
  3399. return getHeader().isVisible();
  3400. }
  3401. /**
  3402. * Returns the current default row of the header.
  3403. *
  3404. * @return the default row or null if no default row set
  3405. *
  3406. * @see #setDefaultHeaderRow(HeaderRow)
  3407. */
  3408. public HeaderRow getDefaultHeaderRow() {
  3409. return header.getDefaultRow();
  3410. }
  3411. /**
  3412. * Sets the default row of the header. The default row is a special header
  3413. * row that displays column captions and sort indicators. By default Grid
  3414. * has a single row which is also the default row. When a header row is set
  3415. * as the default row, any existing cell content is replaced by the column
  3416. * captions.
  3417. *
  3418. * @param row
  3419. * the new default row, or null for no default row
  3420. *
  3421. * @throws IllegalArgumentException
  3422. * if the header does not contain the row
  3423. */
  3424. public void setDefaultHeaderRow(HeaderRow row) {
  3425. header.setDefaultRow((Row) row);
  3426. }
  3427. /**
  3428. * Returns the header section of this grid. The default header contains a
  3429. * single row, set as the {@linkplain #setDefaultHeaderRow(HeaderRow)
  3430. * default row}.
  3431. *
  3432. * @return the header section
  3433. */
  3434. protected Header getHeader() {
  3435. return header;
  3436. }
  3437. /**
  3438. * Returns the footer row at the given index.
  3439. *
  3440. * @param index
  3441. * the index of the row, where the topmost row has index zero
  3442. * @return the footer row at the index
  3443. * @throws IndexOutOfBoundsException
  3444. * if {@code rowIndex < 0 || rowIndex >= getFooterRowCount()}
  3445. */
  3446. public FooterRow getFooterRow(int index) {
  3447. return getFooter().getRow(index);
  3448. }
  3449. /**
  3450. * Gets the number of rows in the footer section.
  3451. *
  3452. * @return the number of footer rows
  3453. */
  3454. public int getFooterRowCount() {
  3455. return getFooter().getRowCount();
  3456. }
  3457. /**
  3458. * Inserts a new row at the given position to the footer section. Shifts the
  3459. * row currently at that position and any subsequent rows down (adds one to
  3460. * their indices). Inserting at {@link #getFooterRowCount()} appends the row
  3461. * at the bottom of the footer.
  3462. *
  3463. * @param index
  3464. * the index at which to insert the row, where the topmost row
  3465. * has index zero
  3466. * @return the inserted footer row
  3467. *
  3468. * @throws IndexOutOfBoundsException
  3469. * if {@code rowIndex < 0 || rowIndex > getFooterRowCount()}
  3470. *
  3471. * @see #appendFooterRow()
  3472. * @see #prependFooterRow()
  3473. * @see #removeFooterRow(FooterRow)
  3474. * @see #removeFooterRow(int)
  3475. */
  3476. public FooterRow addFooterRowAt(int index) {
  3477. return getFooter().addRowAt(index);
  3478. }
  3479. /**
  3480. * Adds a new row at the bottom of the footer section.
  3481. *
  3482. * @return the appended footer row
  3483. *
  3484. * @see #prependFooterRow()
  3485. * @see #addFooterRowAt(int)
  3486. * @see #removeFooterRow(FooterRow)
  3487. * @see #removeFooterRow(int)
  3488. */
  3489. public FooterRow appendFooterRow() {
  3490. return addFooterRowAt(getFooterRowCount());
  3491. }
  3492. /**
  3493. * Adds a new row at the top of the footer section.
  3494. *
  3495. * @return the prepended footer row
  3496. *
  3497. * @see #appendFooterRow()
  3498. * @see #addFooterRowAt(int)
  3499. * @see #removeFooterRow(FooterRow)
  3500. * @see #removeFooterRow(int)
  3501. */
  3502. public FooterRow prependFooterRow() {
  3503. return addFooterRowAt(0);
  3504. }
  3505. /**
  3506. * Removes the given row from the footer section. Removing a default row
  3507. * sets the Grid to have no default row.
  3508. *
  3509. * @param row
  3510. * the footer row to be removed, not null
  3511. *
  3512. * @throws IllegalArgumentException
  3513. * if the footer does not contain the row
  3514. *
  3515. * @see #removeFooterRow(int)
  3516. * @see #addFooterRowAt(int)
  3517. * @see #appendFooterRow()
  3518. * @see #prependFooterRow()
  3519. */
  3520. public void removeFooterRow(FooterRow row) {
  3521. getFooter().removeRow(row);
  3522. }
  3523. /**
  3524. * Removes the row at the given position from the footer section.
  3525. *
  3526. * @param index
  3527. * the index of the row to remove, where the topmost row has
  3528. * index zero
  3529. *
  3530. * @throws IndexOutOfBoundsException
  3531. * if {@code index < 0 || index >= getFooterRowCount()}
  3532. *
  3533. * @see #removeFooterRow(FooterRow)
  3534. * @see #addFooterRowAt(int)
  3535. * @see #appendFooterRow()
  3536. * @see #prependFooterRow()
  3537. */
  3538. public void removeFooterRow(int index) {
  3539. getFooter().removeRow(index);
  3540. }
  3541. /**
  3542. * Sets the visibility of the Footer in this Grid.
  3543. *
  3544. * @param footerVisible
  3545. * {@code true} if visible; {@code false} if not
  3546. *
  3547. * @since 8.1.1
  3548. */
  3549. public void setFooterVisible(boolean footerVisible) {
  3550. getFooter().setVisible(footerVisible);
  3551. }
  3552. /**
  3553. * Gets the visibility of the Footer in this Grid.
  3554. *
  3555. * @return {@code true} if visible; {@code false} if not
  3556. *
  3557. * @since 8.1.1
  3558. */
  3559. public boolean isFooterVisible() {
  3560. return getFooter().isVisible();
  3561. }
  3562. /**
  3563. * Returns the footer section of this grid.
  3564. *
  3565. * @return the footer section
  3566. */
  3567. protected Footer getFooter() {
  3568. return footer;
  3569. }
  3570. /**
  3571. * Registers a new column reorder listener.
  3572. *
  3573. * @param listener
  3574. * the listener to register, not null
  3575. * @return a registration for the listener
  3576. */
  3577. public Registration addColumnReorderListener(
  3578. ColumnReorderListener listener) {
  3579. return addListener(ColumnReorderEvent.class, listener,
  3580. COLUMN_REORDER_METHOD);
  3581. }
  3582. /**
  3583. * Registers a new column resize listener.
  3584. *
  3585. * @param listener
  3586. * the listener to register, not null
  3587. * @return a registration for the listener
  3588. */
  3589. public Registration addColumnResizeListener(ColumnResizeListener listener) {
  3590. return addListener(ColumnResizeEvent.class, listener,
  3591. COLUMN_RESIZE_METHOD);
  3592. }
  3593. /**
  3594. * Adds an item click listener. The listener is called when an item of this
  3595. * {@code Grid} is clicked.
  3596. *
  3597. * @param listener
  3598. * the item click listener, not null
  3599. * @return a registration for the listener
  3600. * @see #addContextClickListener
  3601. */
  3602. public Registration addItemClickListener(
  3603. ItemClickListener<? super T> listener) {
  3604. return addListener(GridConstants.ITEM_CLICK_EVENT_ID, ItemClick.class,
  3605. listener, ITEM_CLICK_METHOD);
  3606. }
  3607. /**
  3608. * Adds a context click listener that gets notified when a context click
  3609. * happens.
  3610. *
  3611. * @param listener
  3612. * the context click listener to add, not null actual event
  3613. * provided to the listener is {@link GridContextClickEvent}
  3614. * @return a registration object for removing the listener
  3615. *
  3616. * @since 8.1
  3617. * @see #addItemClickListener
  3618. * @see Registration
  3619. */
  3620. @Override
  3621. public Registration addContextClickListener(
  3622. ContextClickEvent.ContextClickListener listener) {
  3623. return super.addContextClickListener(listener);
  3624. }
  3625. /**
  3626. * Registers a new column visibility change listener.
  3627. *
  3628. * @param listener
  3629. * the listener to register, not null
  3630. * @return a registration for the listener
  3631. */
  3632. public Registration addColumnVisibilityChangeListener(
  3633. ColumnVisibilityChangeListener listener) {
  3634. return addListener(ColumnVisibilityChangeEvent.class, listener,
  3635. COLUMN_VISIBILITY_METHOD);
  3636. }
  3637. /**
  3638. * Returns whether column reordering is allowed. Default value is
  3639. * <code>false</code>.
  3640. *
  3641. * @return true if reordering is allowed
  3642. */
  3643. public boolean isColumnReorderingAllowed() {
  3644. return getState(false).columnReorderingAllowed;
  3645. }
  3646. /**
  3647. * Sets whether or not column reordering is allowed. Default value is
  3648. * <code>false</code>.
  3649. *
  3650. * @param columnReorderingAllowed
  3651. * specifies whether column reordering is allowed
  3652. */
  3653. public void setColumnReorderingAllowed(boolean columnReorderingAllowed) {
  3654. if (isColumnReorderingAllowed() != columnReorderingAllowed) {
  3655. getState().columnReorderingAllowed = columnReorderingAllowed;
  3656. }
  3657. }
  3658. /**
  3659. * Sets the columns and their order based on their column ids. Columns
  3660. * currently in this grid that are not present in the list of column ids are
  3661. * removed. This includes any column that has no id. Similarly, any new
  3662. * column in columns will be added to this grid. New columns can only be
  3663. * added for a <code>Grid</code> created using {@link Grid#Grid(Class)} or
  3664. * {@link #withPropertySet(PropertySet)}.
  3665. *
  3666. *
  3667. * @param columnIds
  3668. * the column ids to set
  3669. *
  3670. * @see Column#setId(String)
  3671. */
  3672. public void setColumns(String... columnIds) {
  3673. // Must extract to an explicitly typed variable because otherwise javac
  3674. // cannot determine which overload of setColumnOrder to use
  3675. Column<T, ?>[] newColumnOrder = Stream.of(columnIds)
  3676. .map((Function<String, Column<T, ?>>) id -> {
  3677. Column<T, ?> column = getColumn(id);
  3678. if (column == null) {
  3679. column = addColumn(id);
  3680. }
  3681. return column;
  3682. }).toArray(Column[]::new);
  3683. setColumnOrder(newColumnOrder);
  3684. // The columns to remove are now at the end of the column list
  3685. getColumns().stream().skip(columnIds.length)
  3686. .forEach(this::removeColumn);
  3687. }
  3688. /**
  3689. * Sets the columns and their order based on their column ids provided that
  3690. * collection supports preserving of the order. Columns currently in this
  3691. * grid that are not present in the collection of column ids are removed.
  3692. * This includes any column that has no id. Similarly, any new column in
  3693. * columns will be added to this grid. New columns can only be added for a
  3694. * <code>Grid</code> created using {@link Grid#Grid(Class)} or
  3695. * {@link #withPropertySet(PropertySet)}.
  3696. *
  3697. *
  3698. * @param columnIds
  3699. * the column ids to set
  3700. *
  3701. * @see Column#setId(String)
  3702. * @see #setColumns(String...)
  3703. */
  3704. public void setColumns(Collection<String> columnIds) {
  3705. Objects.requireNonNull(columnIds, "columnIds can't be null");
  3706. String[] columns = columnIds.toArray(new String[columnIds.size()]);
  3707. setColumns(columns);
  3708. }
  3709. private String getGeneratedIdentifier() {
  3710. String columnId = "" + counter;
  3711. counter++;
  3712. return columnId;
  3713. }
  3714. /**
  3715. * Sets a new column order for the grid. All columns which are not ordered
  3716. * here will remain in the order they were before as the last columns of
  3717. * grid.
  3718. *
  3719. * @param columns
  3720. * the columns in the order they should be
  3721. */
  3722. public void setColumnOrder(Column<T, ?>... columns) {
  3723. setColumnOrder(Stream.of(columns));
  3724. }
  3725. private void setColumnOrder(Stream<Column<T, ?>> columns) {
  3726. List<String> columnOrder = new ArrayList<>();
  3727. columns.forEach(column -> {
  3728. if (columnSet.contains(column)) {
  3729. columnOrder.add(column.getInternalId());
  3730. } else {
  3731. throw new IllegalStateException(
  3732. "setColumnOrder should not be called "
  3733. + "with columns that are not in the grid.");
  3734. }
  3735. });
  3736. List<String> stateColumnOrder = getState().columnOrder;
  3737. if (stateColumnOrder.size() != columnOrder.size()) {
  3738. stateColumnOrder.removeAll(columnOrder);
  3739. columnOrder.addAll(stateColumnOrder);
  3740. }
  3741. getState().columnOrder = columnOrder;
  3742. fireColumnReorderEvent(false);
  3743. }
  3744. /**
  3745. * Sets a new column order for the grid based on their column ids. All
  3746. * columns which are not ordered here will remain in the order they were
  3747. * before as the last columns of grid.
  3748. *
  3749. * @param columnIds
  3750. * the column ids in the order they should be
  3751. *
  3752. * @see Column#setId(String)
  3753. */
  3754. public void setColumnOrder(String... columnIds) {
  3755. setColumnOrder(Stream.of(columnIds).map(this::getColumnOrThrow));
  3756. }
  3757. /**
  3758. * Returns the selection model for this grid.
  3759. *
  3760. * @return the selection model, not null
  3761. */
  3762. public GridSelectionModel<T> getSelectionModel() {
  3763. assert selectionModel != null : "No selection model set by "
  3764. + getClass().getName() + " constructor";
  3765. return selectionModel;
  3766. }
  3767. /**
  3768. * Use this grid as a single select in {@link Binder}.
  3769. * <p>
  3770. * Throws {@link IllegalStateException} if the grid is not using a
  3771. * {@link SingleSelectionModel}.
  3772. *
  3773. * @return the single select wrapper that can be used in binder
  3774. * @throws IllegalStateException
  3775. * if not using a single selection model
  3776. */
  3777. public GridSingleSelect<T> asSingleSelect() {
  3778. return new GridSingleSelect<>(this);
  3779. }
  3780. public Editor<T> getEditor() {
  3781. return editor;
  3782. }
  3783. /**
  3784. * User this grid as a multiselect in {@link Binder}.
  3785. * <p>
  3786. * Throws {@link IllegalStateException} if the grid is not using a
  3787. * {@link MultiSelectionModel}.
  3788. *
  3789. * @return the multiselect wrapper that can be used in binder
  3790. * @throws IllegalStateException
  3791. * if not using a multiselection model
  3792. */
  3793. public GridMultiSelect<T> asMultiSelect() {
  3794. return new GridMultiSelect<>(this);
  3795. }
  3796. /**
  3797. * Sets the selection model for the grid.
  3798. * <p>
  3799. * This method is for setting a custom selection model, and is
  3800. * {@code protected} because {@link #setSelectionMode(SelectionMode)} should
  3801. * be used for easy switching between built-in selection models.
  3802. * <p>
  3803. * The default selection model is {@link SingleSelectionModelImpl}.
  3804. * <p>
  3805. * To use a custom selection model, you can e.g. extend the grid call this
  3806. * method with your custom selection model.
  3807. *
  3808. * @param model
  3809. * the selection model to use, not {@code null}
  3810. *
  3811. * @see #setSelectionMode(SelectionMode)
  3812. */
  3813. @SuppressWarnings("unchecked")
  3814. protected void setSelectionModel(GridSelectionModel<T> model) {
  3815. Objects.requireNonNull(model, "selection model cannot be null");
  3816. if (selectionModel != null) { // null when called from constructor
  3817. selectionModel.remove();
  3818. }
  3819. selectionModel = model;
  3820. if (selectionModel instanceof AbstractListingExtension) {
  3821. ((AbstractListingExtension<T>) selectionModel).extend(this);
  3822. } else {
  3823. addExtension(selectionModel);
  3824. }
  3825. }
  3826. /**
  3827. * Sets the grid's selection mode.
  3828. * <p>
  3829. * The built-in selection models are:
  3830. * <ul>
  3831. * <li>{@link SelectionMode#SINGLE} -> {@link SingleSelectionModelImpl},
  3832. * <b>the default model</b></li>
  3833. * <li>{@link SelectionMode#MULTI} -> {@link MultiSelectionModelImpl}, with
  3834. * checkboxes in the first column for selection</li>
  3835. * <li>{@link SelectionMode#NONE} -> {@link NoSelectionModel}, preventing
  3836. * selection</li>
  3837. * </ul>
  3838. * <p>
  3839. * To use your custom selection model, you can use
  3840. * {@link #setSelectionModel(GridSelectionModel)}, see existing selection
  3841. * model implementations for example.
  3842. *
  3843. * @param selectionMode
  3844. * the selection mode to switch to, not {@code null}
  3845. * @return the used selection model
  3846. *
  3847. * @see SelectionMode
  3848. * @see GridSelectionModel
  3849. * @see #setSelectionModel(GridSelectionModel)
  3850. */
  3851. public GridSelectionModel<T> setSelectionMode(SelectionMode selectionMode) {
  3852. Objects.requireNonNull(selectionMode, "Selection mode cannot be null.");
  3853. GridSelectionModel<T> model = selectionMode.createModel();
  3854. setSelectionModel(model);
  3855. return model;
  3856. }
  3857. /**
  3858. * This method is a shorthand that delegates to the currently set selection
  3859. * model.
  3860. *
  3861. * @see #getSelectionModel()
  3862. * @see GridSelectionModel
  3863. */
  3864. public Set<T> getSelectedItems() {
  3865. return getSelectionModel().getSelectedItems();
  3866. }
  3867. /**
  3868. * This method is a shorthand that delegates to the currently set selection
  3869. * model.
  3870. *
  3871. * @see #getSelectionModel()
  3872. * @see GridSelectionModel
  3873. */
  3874. public void select(T item) {
  3875. getSelectionModel().select(item);
  3876. }
  3877. /**
  3878. * This method is a shorthand that delegates to the currently set selection
  3879. * model.
  3880. *
  3881. * @see #getSelectionModel()
  3882. * @see GridSelectionModel
  3883. */
  3884. public void deselect(T item) {
  3885. getSelectionModel().deselect(item);
  3886. }
  3887. /**
  3888. * This method is a shorthand that delegates to the currently set selection
  3889. * model.
  3890. *
  3891. * @see #getSelectionModel()
  3892. * @see GridSelectionModel
  3893. */
  3894. public void deselectAll() {
  3895. getSelectionModel().deselectAll();
  3896. }
  3897. /**
  3898. * Adds a selection listener to the current selection model.
  3899. * <p>
  3900. * <em>NOTE:</em> If selection mode is switched with
  3901. * {@link #setSelectionMode(SelectionMode)}, then this listener is not
  3902. * triggered anymore when selection changes!
  3903. * <p>
  3904. * This is a shorthand for
  3905. * {@code grid.getSelectionModel().addSelectionListener()}. To get more
  3906. * detailed selection events, use {@link #getSelectionModel()} and either
  3907. * {@link SingleSelectionModel#addSingleSelectionListener(SingleSelectionListener)}
  3908. * or
  3909. * {@link MultiSelectionModel#addMultiSelectionListener(MultiSelectionListener)}
  3910. * depending on the used selection mode.
  3911. *
  3912. * @param listener
  3913. * the listener to add
  3914. * @return a registration handle to remove the listener
  3915. * @throws UnsupportedOperationException
  3916. * if selection has been disabled with
  3917. * {@link SelectionMode#NONE}
  3918. */
  3919. public Registration addSelectionListener(SelectionListener<T> listener)
  3920. throws UnsupportedOperationException {
  3921. return getSelectionModel().addSelectionListener(listener);
  3922. }
  3923. /**
  3924. * Sort this Grid in ascending order by a specified column.
  3925. *
  3926. * @param column
  3927. * a column to sort against
  3928. *
  3929. */
  3930. public void sort(Column<T, ?> column) {
  3931. sort(column, SortDirection.ASCENDING);
  3932. }
  3933. /**
  3934. * Sort this Grid in user-specified direction by a column.
  3935. *
  3936. * @param column
  3937. * a column to sort against
  3938. * @param direction
  3939. * a sort order value (ascending/descending)
  3940. *
  3941. */
  3942. public void sort(Column<T, ?> column, SortDirection direction) {
  3943. setSortOrder(Collections
  3944. .singletonList(new GridSortOrder<>(column, direction)));
  3945. }
  3946. /**
  3947. * Sort this Grid in ascending order by a specified column defined by id.
  3948. *
  3949. * @param columnId
  3950. * the id of the column to sort against
  3951. *
  3952. * @see Column#setId(String)
  3953. */
  3954. public void sort(String columnId) {
  3955. sort(columnId, SortDirection.ASCENDING);
  3956. }
  3957. /**
  3958. * Sort this Grid in a user-specified direction by a column defined by id.
  3959. *
  3960. * @param columnId
  3961. * the id of the column to sort against
  3962. * @param direction
  3963. * a sort order value (ascending/descending)
  3964. *
  3965. * @see Column#setId(String)
  3966. */
  3967. public void sort(String columnId, SortDirection direction) {
  3968. sort(getColumnOrThrow(columnId), direction);
  3969. }
  3970. /**
  3971. * Clear the current sort order, and re-sort the grid.
  3972. */
  3973. public void clearSortOrder() {
  3974. setSortOrder(Collections.emptyList());
  3975. }
  3976. /**
  3977. * Sets the sort order to use.
  3978. *
  3979. * @param order
  3980. * a sort order list.
  3981. *
  3982. * @throws IllegalArgumentException
  3983. * if order is null
  3984. */
  3985. public void setSortOrder(List<GridSortOrder<T>> order) {
  3986. setSortOrder(order, false);
  3987. }
  3988. /**
  3989. * Sets the sort order to use, given a {@link GridSortOrderBuilder}.
  3990. * Shorthand for {@code setSortOrder(builder.build())}.
  3991. *
  3992. * @see GridSortOrderBuilder
  3993. *
  3994. * @param builder
  3995. * the sort builder to retrieve the sort order from
  3996. * @throws NullPointerException
  3997. * if builder is null
  3998. */
  3999. public void setSortOrder(GridSortOrderBuilder<T> builder) {
  4000. Objects.requireNonNull(builder, "Sort builder cannot be null");
  4001. setSortOrder(builder.build());
  4002. }
  4003. /**
  4004. * Adds a sort order change listener that gets notified when the sort order
  4005. * changes.
  4006. *
  4007. * @param listener
  4008. * the sort order change listener to add
  4009. */
  4010. @Override
  4011. public Registration addSortListener(
  4012. SortListener<GridSortOrder<T>> listener) {
  4013. return addListener(SortEvent.class, listener, SORT_ORDER_CHANGE_METHOD);
  4014. }
  4015. /**
  4016. * Get the current sort order list.
  4017. *
  4018. * @return a sort order list
  4019. */
  4020. public List<GridSortOrder<T>> getSortOrder() {
  4021. return Collections.unmodifiableList(sortOrder);
  4022. }
  4023. /**
  4024. * Scrolls to a certain item, using {@link ScrollDestination#ANY}.
  4025. * <p>
  4026. * If the item has an open details row, its size will also be taken into
  4027. * account.
  4028. *
  4029. * @param row
  4030. * zero based index of the item to scroll to in the current view.
  4031. * @throws IllegalArgumentException
  4032. * if the provided row is outside the item range
  4033. */
  4034. public void scrollTo(int row) throws IllegalArgumentException {
  4035. scrollTo(row, ScrollDestination.ANY);
  4036. }
  4037. /**
  4038. * Scrolls to a certain item, using user-specified scroll destination.
  4039. * <p>
  4040. * If the item has an open details row, its size will also be taken into
  4041. * account.
  4042. *
  4043. * @param row
  4044. * zero based index of the item to scroll to in the current view.
  4045. * @param destination
  4046. * value specifying desired position of scrolled-to row, not
  4047. * {@code null}
  4048. * @throws IllegalArgumentException
  4049. * if the provided row is outside the item range
  4050. */
  4051. public void scrollTo(int row, ScrollDestination destination) {
  4052. Objects.requireNonNull(destination,
  4053. "ScrollDestination can not be null");
  4054. if (row >= getDataCommunicator().getDataProviderSize()) {
  4055. throw new IllegalArgumentException("Row outside dataProvider size");
  4056. }
  4057. getRpcProxy(GridClientRpc.class).scrollToRow(row, destination);
  4058. }
  4059. /**
  4060. * Scrolls to the beginning of the first data row.
  4061. */
  4062. public void scrollToStart() {
  4063. getRpcProxy(GridClientRpc.class).scrollToStart();
  4064. }
  4065. /**
  4066. * Scrolls to the end of the last data row.
  4067. */
  4068. public void scrollToEnd() {
  4069. getRpcProxy(GridClientRpc.class).scrollToEnd();
  4070. }
  4071. @Override
  4072. protected GridState getState() {
  4073. return getState(true);
  4074. }
  4075. @Override
  4076. protected GridState getState(boolean markAsDirty) {
  4077. return (GridState) super.getState(markAsDirty);
  4078. }
  4079. /**
  4080. * Sets the column resize mode to use. The default mode is
  4081. * {@link ColumnResizeMode#ANIMATED}.
  4082. *
  4083. * @param mode
  4084. * a ColumnResizeMode value
  4085. * @since 7.7.5
  4086. */
  4087. public void setColumnResizeMode(ColumnResizeMode mode) {
  4088. getState().columnResizeMode = mode;
  4089. }
  4090. /**
  4091. * Returns the current column resize mode. The default mode is
  4092. * {@link ColumnResizeMode#ANIMATED}.
  4093. *
  4094. * @return a ColumnResizeMode value
  4095. * @since 7.7.5
  4096. */
  4097. public ColumnResizeMode getColumnResizeMode() {
  4098. return getState(false).columnResizeMode;
  4099. }
  4100. /**
  4101. * Creates a new Editor instance. Can be overridden to create a custom
  4102. * Editor. If the Editor is a {@link AbstractGridExtension}, it will be
  4103. * automatically added to {@link DataCommunicator}.
  4104. *
  4105. * @return editor
  4106. */
  4107. protected Editor<T> createEditor() {
  4108. return new EditorImpl<>(propertySet);
  4109. }
  4110. private void addExtensionComponent(Component c) {
  4111. if (extensionComponents.add(c)) {
  4112. c.setParent(this);
  4113. markAsDirty();
  4114. }
  4115. }
  4116. private void removeExtensionComponent(Component c) {
  4117. if (extensionComponents.remove(c)) {
  4118. c.setParent(null);
  4119. markAsDirty();
  4120. }
  4121. }
  4122. private void fireColumnReorderEvent(boolean userOriginated) {
  4123. fireEvent(new ColumnReorderEvent(this, userOriginated));
  4124. }
  4125. private void fireColumnResizeEvent(Column<?, ?> column,
  4126. boolean userOriginated) {
  4127. fireEvent(new ColumnResizeEvent(this, column, userOriginated));
  4128. }
  4129. @Override
  4130. protected void readItems(Element design, DesignContext context) {
  4131. // Grid handles reading of items in Grid#readData
  4132. }
  4133. @Override
  4134. public DataProvider<T, ?> getDataProvider() {
  4135. return internalGetDataProvider();
  4136. }
  4137. @Override
  4138. public void setDataProvider(DataProvider<T, ?> dataProvider) {
  4139. internalSetDataProvider(dataProvider);
  4140. }
  4141. /**
  4142. * Sets a CallbackDataProvider using the given fetch items callback and a
  4143. * size callback.
  4144. * <p>
  4145. * This method is a shorthand for making a {@link CallbackDataProvider} that
  4146. * handles a partial {@link Query} object.
  4147. *
  4148. * @param fetchItems
  4149. * a callback for fetching items
  4150. * @param sizeCallback
  4151. * a callback for getting the count of items
  4152. *
  4153. * @see CallbackDataProvider
  4154. * @see #setDataProvider(DataProvider)
  4155. */
  4156. public void setDataProvider(FetchItemsCallback<T> fetchItems,
  4157. SerializableSupplier<Integer> sizeCallback) {
  4158. internalSetDataProvider(
  4159. new CallbackDataProvider<>(
  4160. q -> fetchItems.fetchItems(q.getSortOrders(),
  4161. q.getOffset(), q.getLimit()),
  4162. q -> sizeCallback.get()));
  4163. }
  4164. @Override
  4165. protected void doReadDesign(Element design, DesignContext context) {
  4166. Attributes attrs = design.attributes();
  4167. if (design.hasAttr(DECLARATIVE_DATA_ITEM_TYPE)) {
  4168. String itemType = design.attr(DECLARATIVE_DATA_ITEM_TYPE);
  4169. setBeanType(itemType);
  4170. }
  4171. if (attrs.hasKey("selection-mode")) {
  4172. setSelectionMode(DesignAttributeHandler.readAttribute(
  4173. "selection-mode", attrs, SelectionMode.class));
  4174. }
  4175. Attributes attr = design.attributes();
  4176. if (attr.hasKey("selection-allowed")) {
  4177. setReadOnly(DesignAttributeHandler
  4178. .readAttribute("selection-allowed", attr, Boolean.class));
  4179. }
  4180. if (attrs.hasKey("rows")) {
  4181. setHeightByRows(DesignAttributeHandler.readAttribute("rows", attrs,
  4182. double.class));
  4183. }
  4184. readStructure(design, context);
  4185. // Read frozen columns after columns are read.
  4186. if (attrs.hasKey("frozen-columns")) {
  4187. setFrozenColumnCount(DesignAttributeHandler
  4188. .readAttribute("frozen-columns", attrs, int.class));
  4189. }
  4190. }
  4191. /**
  4192. * Sets the bean type to use for property mapping.
  4193. * <p>
  4194. * This method is responsible also for setting or updating the property set
  4195. * so that it matches the given bean type.
  4196. * <p>
  4197. * Protected mostly for Designer needs, typically should not be overridden
  4198. * or even called.
  4199. *
  4200. * @param beanTypeClassName
  4201. * the fully qualified class name of the bean type
  4202. *
  4203. * @since 8.0.3
  4204. */
  4205. @SuppressWarnings("unchecked")
  4206. protected void setBeanType(String beanTypeClassName) {
  4207. setBeanType((Class<T>) resolveClass(beanTypeClassName));
  4208. }
  4209. /**
  4210. * Sets the bean type to use for property mapping.
  4211. * <p>
  4212. * This method is responsible also for setting or updating the property set
  4213. * so that it matches the given bean type.
  4214. * <p>
  4215. * Protected mostly for Designer needs, typically should not be overridden
  4216. * or even called.
  4217. *
  4218. * @param beanType
  4219. * the bean type class
  4220. *
  4221. * @since 8.0.3
  4222. */
  4223. protected void setBeanType(Class<T> beanType) {
  4224. this.beanType = beanType;
  4225. setPropertySet(BeanPropertySet.get(beanType));
  4226. }
  4227. private Class<?> resolveClass(String qualifiedClassName) {
  4228. try {
  4229. Class<?> resolvedClass = Class.forName(qualifiedClassName, true,
  4230. VaadinServiceClassLoaderUtil.findDefaultClassLoader());
  4231. return resolvedClass;
  4232. } catch (ClassNotFoundException | SecurityException e) {
  4233. throw new IllegalArgumentException(
  4234. "Unable to find class " + qualifiedClassName, e);
  4235. }
  4236. }
  4237. @Override
  4238. protected void doWriteDesign(Element design, DesignContext designContext) {
  4239. Attributes attr = design.attributes();
  4240. if (this.beanType != null) {
  4241. design.attr(DECLARATIVE_DATA_ITEM_TYPE,
  4242. this.beanType.getCanonicalName());
  4243. }
  4244. DesignAttributeHandler.writeAttribute("selection-allowed", attr,
  4245. isReadOnly(), false, Boolean.class, designContext);
  4246. Attributes attrs = design.attributes();
  4247. Grid<?> defaultInstance = designContext.getDefaultInstance(this);
  4248. DesignAttributeHandler.writeAttribute("frozen-columns", attrs,
  4249. getFrozenColumnCount(), defaultInstance.getFrozenColumnCount(),
  4250. int.class, designContext);
  4251. if (HeightMode.ROW.equals(getHeightMode())) {
  4252. DesignAttributeHandler.writeAttribute("rows", attrs,
  4253. getHeightByRows(), defaultInstance.getHeightByRows(),
  4254. double.class, designContext);
  4255. }
  4256. SelectionMode mode = getSelectionMode();
  4257. if (mode != null) {
  4258. DesignAttributeHandler.writeAttribute("selection-mode", attrs, mode,
  4259. SelectionMode.SINGLE, SelectionMode.class, designContext);
  4260. }
  4261. writeStructure(design, designContext);
  4262. }
  4263. @Override
  4264. protected T deserializeDeclarativeRepresentation(String item) {
  4265. if (item == null) {
  4266. return super.deserializeDeclarativeRepresentation(
  4267. UUID.randomUUID().toString());
  4268. }
  4269. return super.deserializeDeclarativeRepresentation(new String(item));
  4270. }
  4271. @Override
  4272. protected boolean isReadOnly() {
  4273. SelectionMode selectionMode = getSelectionMode();
  4274. if (SelectionMode.SINGLE.equals(selectionMode)) {
  4275. return asSingleSelect().isReadOnly();
  4276. }
  4277. if (SelectionMode.MULTI.equals(selectionMode)) {
  4278. return asMultiSelect().isReadOnly();
  4279. }
  4280. return false;
  4281. }
  4282. @Override
  4283. protected void setReadOnly(boolean readOnly) {
  4284. SelectionMode selectionMode = getSelectionMode();
  4285. if (SelectionMode.SINGLE.equals(selectionMode)) {
  4286. asSingleSelect().setReadOnly(readOnly);
  4287. } else if (SelectionMode.MULTI.equals(selectionMode)) {
  4288. asMultiSelect().setReadOnly(readOnly);
  4289. }
  4290. }
  4291. private void readStructure(Element design, DesignContext context) {
  4292. if (design.children().isEmpty()) {
  4293. return;
  4294. }
  4295. if (design.children().size() > 1
  4296. || !design.child(0).tagName().equals("table")) {
  4297. throw new DesignException(
  4298. "Grid needs to have a table element as its only child");
  4299. }
  4300. Element table = design.child(0);
  4301. Elements colgroups = table.getElementsByTag("colgroup");
  4302. if (colgroups.size() != 1) {
  4303. throw new DesignException(
  4304. "Table element in declarative Grid needs to have a"
  4305. + " colgroup defining the columns used in Grid");
  4306. }
  4307. List<DeclarativeValueProvider<T>> providers = new ArrayList<>();
  4308. for (Element col : colgroups.get(0).getElementsByTag("col")) {
  4309. String id = DesignAttributeHandler.readAttribute("column-id",
  4310. col.attributes(), null, String.class);
  4311. // If there is a property with a matching name available,
  4312. // map to that
  4313. Optional<PropertyDefinition<T, ?>> property = propertySet
  4314. .getProperties().filter(p -> p.getName().equals(id))
  4315. .findFirst();
  4316. Column<T, ?> column;
  4317. if (property.isPresent()) {
  4318. column = addColumn(id);
  4319. } else {
  4320. DeclarativeValueProvider<T> provider = new DeclarativeValueProvider<>();
  4321. column = createColumn(provider, ValueProvider.identity(),
  4322. new HtmlRenderer());
  4323. addColumn(getGeneratedIdentifier(), column);
  4324. if (id != null) {
  4325. column.setId(id);
  4326. }
  4327. providers.add(provider);
  4328. }
  4329. column.readDesign(col, context);
  4330. }
  4331. for (Element child : table.children()) {
  4332. if (child.tagName().equals("thead")) {
  4333. getHeader().readDesign(child, context);
  4334. } else if (child.tagName().equals("tbody")) {
  4335. readData(child, providers);
  4336. } else if (child.tagName().equals("tfoot")) {
  4337. getFooter().readDesign(child, context);
  4338. }
  4339. }
  4340. // Sync default header captions to column captions
  4341. if (getDefaultHeaderRow() != null) {
  4342. for (Column<T, ?> c : getColumns()) {
  4343. HeaderCell headerCell = getDefaultHeaderRow().getCell(c);
  4344. if (headerCell.getCellType() == GridStaticCellType.TEXT) {
  4345. String text = headerCell.getText();
  4346. c.setCaption(text == null ? "" : text);
  4347. }
  4348. }
  4349. }
  4350. }
  4351. /**
  4352. * Reads the declarative representation of a grid's data from the given
  4353. * element and stores it in the given {@link DeclarativeValueProvider}s.
  4354. * Each member in the list of value providers corresponds to a column in the
  4355. * grid.
  4356. *
  4357. * @since 8.1
  4358. *
  4359. * @param body
  4360. * the element to read data from
  4361. * @param providers
  4362. * list of {@link DeclarativeValueProvider}s to store the data of
  4363. * each column to
  4364. */
  4365. protected void readData(Element body,
  4366. List<DeclarativeValueProvider<T>> providers) {
  4367. getSelectionModel().deselectAll();
  4368. List<T> items = new ArrayList<>();
  4369. List<T> selectedItems = new ArrayList<>();
  4370. for (Element row : body.children()) {
  4371. T item = deserializeDeclarativeRepresentation(row.attr("item"));
  4372. items.add(item);
  4373. if (row.hasAttr("selected")) {
  4374. selectedItems.add(item);
  4375. }
  4376. Elements cells = row.children();
  4377. int i = 0;
  4378. for (Element cell : cells) {
  4379. providers.get(i).addValue(item, cell.html());
  4380. i++;
  4381. }
  4382. }
  4383. setItems(items);
  4384. selectedItems.forEach(getSelectionModel()::select);
  4385. }
  4386. private void writeStructure(Element design, DesignContext designContext) {
  4387. if (getColumns().isEmpty()) {
  4388. return;
  4389. }
  4390. Element tableElement = design.appendElement("table");
  4391. Element colGroup = tableElement.appendElement("colgroup");
  4392. getColumns().forEach(column -> column
  4393. .writeDesign(colGroup.appendElement("col"), designContext));
  4394. // Always write thead. Reads correctly when there no header rows
  4395. getHeader().writeDesign(tableElement.appendElement("thead"),
  4396. designContext);
  4397. if (designContext.shouldWriteData(this)) {
  4398. Element bodyElement = tableElement.appendElement("tbody");
  4399. writeData(bodyElement, designContext);
  4400. }
  4401. if (getFooter().getRowCount() > 0) {
  4402. getFooter().writeDesign(tableElement.appendElement("tfoot"),
  4403. designContext);
  4404. }
  4405. }
  4406. /**
  4407. * Writes the data contained in this grid. Used when serializing a grid to
  4408. * its declarative representation, if
  4409. * {@link DesignContext#shouldWriteData(Component)} returns {@code true} for
  4410. * the grid that is being written.
  4411. *
  4412. * @since 8.1
  4413. *
  4414. * @param body
  4415. * the body element to write the declarative representation of
  4416. * data to
  4417. * @param designContext
  4418. * the design context
  4419. *
  4420. * @since 8.1
  4421. */
  4422. protected void writeData(Element body, DesignContext designContext) {
  4423. getDataProvider().fetch(new Query<>())
  4424. .forEach(item -> writeRow(body, item, designContext));
  4425. }
  4426. private void writeRow(Element container, T item, DesignContext context) {
  4427. Element tableRow = container.appendElement("tr");
  4428. tableRow.attr("item", serializeDeclarativeRepresentation(item));
  4429. if (getSelectionModel().isSelected(item)) {
  4430. tableRow.attr("selected", true);
  4431. }
  4432. for (Column<T, ?> column : getColumns()) {
  4433. Object value = column.valueProvider.apply(item);
  4434. tableRow.appendElement("td")
  4435. .append(Optional.ofNullable(value).map(Object::toString)
  4436. .map(DesignFormatter::encodeForTextNode)
  4437. .orElse(""));
  4438. }
  4439. }
  4440. private SelectionMode getSelectionMode() {
  4441. GridSelectionModel<T> selectionModel = getSelectionModel();
  4442. SelectionMode mode = null;
  4443. if (selectionModel.getClass().equals(SingleSelectionModelImpl.class)) {
  4444. mode = SelectionMode.SINGLE;
  4445. } else if (selectionModel.getClass()
  4446. .equals(MultiSelectionModelImpl.class)) {
  4447. mode = SelectionMode.MULTI;
  4448. } else if (selectionModel.getClass().equals(NoSelectionModel.class)) {
  4449. mode = SelectionMode.NONE;
  4450. }
  4451. return mode;
  4452. }
  4453. /**
  4454. * Sets a user-defined identifier for given column.
  4455. *
  4456. * @see Column#setId(String)
  4457. *
  4458. * @param column
  4459. * the column
  4460. * @param id
  4461. * the user-defined identifier
  4462. */
  4463. protected void setColumnId(String id, Column<T, ?> column) {
  4464. if (columnIds.containsKey(id)) {
  4465. throw new IllegalArgumentException("Duplicate ID for columns");
  4466. }
  4467. columnIds.put(id, column);
  4468. }
  4469. @Override
  4470. protected Collection<String> getCustomAttributes() {
  4471. Collection<String> result = super.getCustomAttributes();
  4472. // "rename" for frozen column count
  4473. result.add("frozen-column-count");
  4474. result.add("frozen-columns");
  4475. // "rename" for height-mode
  4476. result.add("height-by-rows");
  4477. result.add("rows");
  4478. // add a selection-mode attribute
  4479. result.add("selection-mode");
  4480. return result;
  4481. }
  4482. /**
  4483. * Returns a column identified by its internal id. This id should not be
  4484. * confused with the user-defined identifier.
  4485. *
  4486. * @param columnId
  4487. * the internal id of column
  4488. * @return column identified by internal id
  4489. */
  4490. protected Column<T, ?> getColumnByInternalId(String columnId) {
  4491. return columnKeys.get(columnId);
  4492. }
  4493. /**
  4494. * Returns the internal id for given column. This id should not be confused
  4495. * with the user-defined identifier.
  4496. *
  4497. * @param column
  4498. * the column
  4499. * @return internal id of given column
  4500. */
  4501. protected String getInternalIdForColumn(Column<T, ?> column) {
  4502. return column.getInternalId();
  4503. }
  4504. private void setSortOrder(List<GridSortOrder<T>> order,
  4505. boolean userOriginated) {
  4506. Objects.requireNonNull(order, "Sort order list cannot be null");
  4507. // Update client state to display sort order.
  4508. List<String> sortColumns = new ArrayList<>();
  4509. List<SortDirection> directions = new ArrayList<>();
  4510. order.stream().forEach(sortOrder -> {
  4511. sortColumns.add(sortOrder.getSorted().getInternalId());
  4512. directions.add(sortOrder.getDirection());
  4513. });
  4514. getState().sortColumns = sortColumns.toArray(new String[0]);
  4515. getState().sortDirs = directions.toArray(new SortDirection[0]);
  4516. sortOrder.clear();
  4517. sortOrder.addAll(order);
  4518. sort(userOriginated);
  4519. }
  4520. private void sort(boolean userOriginated) {
  4521. // Set sort orders
  4522. // In-memory comparator
  4523. getDataCommunicator().setInMemorySorting(createSortingComparator(),
  4524. false);
  4525. // Back-end sort properties
  4526. List<QuerySortOrder> sortProperties = new ArrayList<>();
  4527. sortOrder.stream().map(
  4528. order -> order.getSorted().getSortOrder(order.getDirection()))
  4529. .forEach(s -> s.forEach(sortProperties::add));
  4530. getDataCommunicator().setBackEndSorting(sortProperties, true);
  4531. // Close grid editor if it's open.
  4532. if (getEditor().isOpen()) {
  4533. getEditor().cancel();
  4534. }
  4535. fireEvent(new SortEvent<>(this, new ArrayList<>(sortOrder),
  4536. userOriginated));
  4537. }
  4538. /**
  4539. * Creates a comparator for grid to sort rows.
  4540. *
  4541. * @return the comparator based on column sorting information.
  4542. */
  4543. protected SerializableComparator<T> createSortingComparator() {
  4544. /*
  4545. * thenComparing is defined to return a serializable comparator as long
  4546. * as both original comparators are also serializable
  4547. */
  4548. BinaryOperator<SerializableComparator<T>> operator = (comparator1,
  4549. comparator2) -> comparator1.thenComparing(comparator2)::compare;
  4550. return sortOrder.stream().map(
  4551. order -> order.getSorted().getComparator(order.getDirection()))
  4552. .reduce((x, y) -> 0, operator);
  4553. }
  4554. @Override
  4555. protected void internalSetDataProvider(DataProvider<T, ?> dataProvider) {
  4556. boolean newProvider = getDataProvider() != dataProvider;
  4557. super.internalSetDataProvider(dataProvider);
  4558. if (newProvider) {
  4559. Set<T> oldVisibleDetails = new HashSet<>(
  4560. detailsManager.visibleDetails);
  4561. oldVisibleDetails.forEach(item -> {
  4562. // close all old details even if the same item exists in the new
  4563. // provider
  4564. detailsManager.setDetailsVisible(item, false);
  4565. });
  4566. }
  4567. for (Column<T, ?> column : getColumns()) {
  4568. column.updateSortable();
  4569. }
  4570. }
  4571. }