You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

XSSFSheet.java 134KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816
  1. /* ====================================================================
  2. Licensed to the Apache Software Foundation (ASF) under one or more
  3. contributor license agreements. See the NOTICE file distributed with
  4. this work for additional information regarding copyright ownership.
  5. The ASF licenses this file to You under the Apache License, Version 2.0
  6. (the "License"); you may not use this file except in compliance with
  7. the License. You may obtain a copy of the License at
  8. http://www.apache.org/licenses/LICENSE-2.0
  9. Unless required by applicable law or agreed to in writing, software
  10. distributed under the License is distributed on an "AS IS" BASIS,
  11. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. See the License for the specific language governing permissions and
  13. limitations under the License.
  14. ==================================================================== */
  15. package org.apache.poi.xssf.usermodel;
  16. import static org.apache.poi.xssf.usermodel.helpers.XSSFPaswordHelper.setPassword;
  17. import static org.apache.poi.xssf.usermodel.helpers.XSSFPaswordHelper.validatePassword;
  18. import java.io.IOException;
  19. import java.io.InputStream;
  20. import java.io.OutputStream;
  21. import java.util.ArrayList;
  22. import java.util.Arrays;
  23. import java.util.HashMap;
  24. import java.util.Iterator;
  25. import java.util.List;
  26. import java.util.Map;
  27. import java.util.Set;
  28. import java.util.TreeMap;
  29. import javax.xml.namespace.QName;
  30. import org.apache.poi.POIXMLDocumentPart;
  31. import org.apache.poi.POIXMLException;
  32. import org.apache.poi.hssf.util.PaneInformation;
  33. import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
  34. import org.apache.poi.openxml4j.exceptions.PartAlreadyExistsException;
  35. import org.apache.poi.openxml4j.opc.PackagePart;
  36. import org.apache.poi.openxml4j.opc.PackageRelationship;
  37. import org.apache.poi.openxml4j.opc.PackageRelationshipCollection;
  38. import org.apache.poi.openxml4j.opc.TargetMode;
  39. import org.apache.poi.poifs.crypt.HashAlgorithm;
  40. import org.apache.poi.ss.SpreadsheetVersion;
  41. import org.apache.poi.ss.formula.FormulaShifter;
  42. import org.apache.poi.ss.formula.SheetNameFormatter;
  43. import org.apache.poi.ss.usermodel.*;
  44. import org.apache.poi.ss.util.AreaReference;
  45. import org.apache.poi.ss.util.CellRangeAddress;
  46. import org.apache.poi.ss.util.CellRangeAddressList;
  47. import org.apache.poi.ss.util.CellReference;
  48. import org.apache.poi.ss.util.SSCellRange;
  49. import org.apache.poi.ss.util.SheetUtil;
  50. import org.apache.poi.util.Beta;
  51. import org.apache.poi.util.Internal;
  52. import org.apache.poi.util.POILogFactory;
  53. import org.apache.poi.util.POILogger;
  54. import org.apache.poi.xssf.model.CommentsTable;
  55. import org.apache.poi.xssf.usermodel.helpers.ColumnHelper;
  56. import org.apache.poi.xssf.usermodel.helpers.XSSFRowShifter;
  57. import org.apache.xmlbeans.XmlException;
  58. import org.apache.xmlbeans.XmlOptions;
  59. import org.openxmlformats.schemas.officeDocument.x2006.relationships.STRelationshipId;
  60. import org.openxmlformats.schemas.spreadsheetml.x2006.main.*;
  61. /**
  62. * High level representation of a SpreadsheetML worksheet.
  63. *
  64. * <p>
  65. * Sheets are the central structures within a workbook, and are where a user does most of his spreadsheet work.
  66. * The most common type of sheet is the worksheet, which is represented as a grid of cells. Worksheet cells can
  67. * contain text, numbers, dates, and formulas. Cells can also be formatted.
  68. * </p>
  69. */
  70. public class XSSFSheet extends POIXMLDocumentPart implements Sheet {
  71. private static final POILogger logger = POILogFactory.getLogger(XSSFSheet.class);
  72. //TODO make the two variable below private!
  73. protected CTSheet sheet;
  74. protected CTWorksheet worksheet;
  75. private TreeMap<Integer, XSSFRow> _rows;
  76. private List<XSSFHyperlink> hyperlinks;
  77. private ColumnHelper columnHelper;
  78. private CommentsTable sheetComments;
  79. /**
  80. * cache of master shared formulas in this sheet.
  81. * Master shared formula is the first formula in a group of shared formulas is saved in the f element.
  82. */
  83. private Map<Integer, CTCellFormula> sharedFormulas;
  84. private TreeMap<String,XSSFTable> tables;
  85. private List<CellRangeAddress> arrayFormulas;
  86. private XSSFDataValidationHelper dataValidationHelper;
  87. /**
  88. * Creates new XSSFSheet - called by XSSFWorkbook to create a sheet from scratch.
  89. *
  90. * @see org.apache.poi.xssf.usermodel.XSSFWorkbook#createSheet()
  91. */
  92. protected XSSFSheet() {
  93. super();
  94. dataValidationHelper = new XSSFDataValidationHelper(this);
  95. onDocumentCreate();
  96. }
  97. /**
  98. * Creates an XSSFSheet representing the given package part and relationship.
  99. * Should only be called by XSSFWorkbook when reading in an exisiting file.
  100. *
  101. * @param part - The package part that holds xml data represenring this sheet.
  102. * @param rel - the relationship of the given package part in the underlying OPC package
  103. */
  104. protected XSSFSheet(PackagePart part, PackageRelationship rel) {
  105. super(part, rel);
  106. dataValidationHelper = new XSSFDataValidationHelper(this);
  107. }
  108. /**
  109. * Returns the parent XSSFWorkbook
  110. *
  111. * @return the parent XSSFWorkbook
  112. */
  113. @Override
  114. public XSSFWorkbook getWorkbook() {
  115. return (XSSFWorkbook)getParent();
  116. }
  117. /**
  118. * Initialize worksheet data when reading in an exisiting file.
  119. */
  120. @Override
  121. protected void onDocumentRead() {
  122. try {
  123. read(getPackagePart().getInputStream());
  124. } catch (IOException e){
  125. throw new POIXMLException(e);
  126. }
  127. }
  128. protected void read(InputStream is) throws IOException {
  129. try {
  130. worksheet = WorksheetDocument.Factory.parse(is).getWorksheet();
  131. } catch (XmlException e){
  132. throw new POIXMLException(e);
  133. }
  134. initRows(worksheet);
  135. columnHelper = new ColumnHelper(worksheet);
  136. // Look for bits we're interested in
  137. for(POIXMLDocumentPart p : getRelations()){
  138. if(p instanceof CommentsTable) {
  139. sheetComments = (CommentsTable)p;
  140. }
  141. if(p instanceof XSSFTable) {
  142. tables.put( p.getPackageRelationship().getId(), (XSSFTable)p );
  143. }
  144. if(p instanceof XSSFPivotTable) {
  145. getWorkbook().getPivotTables().add((XSSFPivotTable) p);
  146. }
  147. }
  148. // Process external hyperlinks for the sheet, if there are any
  149. initHyperlinks();
  150. }
  151. /**
  152. * Initialize worksheet data when creating a new sheet.
  153. */
  154. @Override
  155. protected void onDocumentCreate(){
  156. worksheet = newSheet();
  157. initRows(worksheet);
  158. columnHelper = new ColumnHelper(worksheet);
  159. hyperlinks = new ArrayList<XSSFHyperlink>();
  160. }
  161. @SuppressWarnings("deprecation") //YK: getXYZArray() array accessors are deprecated in xmlbeans with JDK 1.5 support
  162. private void initRows(CTWorksheet worksheetParam) {
  163. _rows = new TreeMap<Integer, XSSFRow>();
  164. tables = new TreeMap<String, XSSFTable>();
  165. sharedFormulas = new HashMap<Integer, CTCellFormula>();
  166. arrayFormulas = new ArrayList<CellRangeAddress>();
  167. for (CTRow row : worksheetParam.getSheetData().getRowArray()) {
  168. XSSFRow r = new XSSFRow(row, this);
  169. _rows.put(r.getRowNum(), r);
  170. }
  171. }
  172. /**
  173. * Read hyperlink relations, link them with CTHyperlink beans in this worksheet
  174. * and initialize the internal array of XSSFHyperlink objects
  175. */
  176. @SuppressWarnings("deprecation") //YK: getXYZArray() array accessors are deprecated in xmlbeans with JDK 1.5 support
  177. private void initHyperlinks() {
  178. hyperlinks = new ArrayList<XSSFHyperlink>();
  179. if(!worksheet.isSetHyperlinks()) return;
  180. try {
  181. PackageRelationshipCollection hyperRels =
  182. getPackagePart().getRelationshipsByType(XSSFRelation.SHEET_HYPERLINKS.getRelation());
  183. // Turn each one into a XSSFHyperlink
  184. for(CTHyperlink hyperlink : worksheet.getHyperlinks().getHyperlinkArray()) {
  185. PackageRelationship hyperRel = null;
  186. if(hyperlink.getId() != null) {
  187. hyperRel = hyperRels.getRelationshipByID(hyperlink.getId());
  188. }
  189. hyperlinks.add( new XSSFHyperlink(hyperlink, hyperRel) );
  190. }
  191. } catch (InvalidFormatException e){
  192. throw new POIXMLException(e);
  193. }
  194. }
  195. /**
  196. * Create a new CTWorksheet instance with all values set to defaults
  197. *
  198. * @return a new instance
  199. */
  200. private static CTWorksheet newSheet(){
  201. CTWorksheet worksheet = CTWorksheet.Factory.newInstance();
  202. CTSheetFormatPr ctFormat = worksheet.addNewSheetFormatPr();
  203. ctFormat.setDefaultRowHeight(15.0);
  204. CTSheetView ctView = worksheet.addNewSheetViews().addNewSheetView();
  205. ctView.setWorkbookViewId(0);
  206. worksheet.addNewDimension().setRef("A1");
  207. worksheet.addNewSheetData();
  208. CTPageMargins ctMargins = worksheet.addNewPageMargins();
  209. ctMargins.setBottom(0.75);
  210. ctMargins.setFooter(0.3);
  211. ctMargins.setHeader(0.3);
  212. ctMargins.setLeft(0.7);
  213. ctMargins.setRight(0.7);
  214. ctMargins.setTop(0.75);
  215. return worksheet;
  216. }
  217. /**
  218. * Provide access to the CTWorksheet bean holding this sheet's data
  219. *
  220. * @return the CTWorksheet bean holding this sheet's data
  221. */
  222. @Internal
  223. public CTWorksheet getCTWorksheet() {
  224. return this.worksheet;
  225. }
  226. public ColumnHelper getColumnHelper() {
  227. return columnHelper;
  228. }
  229. /**
  230. * Returns the name of this sheet
  231. *
  232. * @return the name of this sheet
  233. */
  234. @Override
  235. public String getSheetName() {
  236. return sheet.getName();
  237. }
  238. /**
  239. * Adds a merged region of cells (hence those cells form one).
  240. *
  241. * @param region (rowfrom/colfrom-rowto/colto) to merge
  242. * @return index of this region
  243. */
  244. @Override
  245. public int addMergedRegion(CellRangeAddress region) {
  246. region.validate(SpreadsheetVersion.EXCEL2007);
  247. // throw IllegalStateException if the argument CellRangeAddress intersects with
  248. // a multi-cell array formula defined in this sheet
  249. validateArrayFormulas(region);
  250. CTMergeCells ctMergeCells = worksheet.isSetMergeCells() ? worksheet.getMergeCells() : worksheet.addNewMergeCells();
  251. CTMergeCell ctMergeCell = ctMergeCells.addNewMergeCell();
  252. ctMergeCell.setRef(region.formatAsString());
  253. return ctMergeCells.sizeOfMergeCellArray();
  254. }
  255. private void validateArrayFormulas(CellRangeAddress region){
  256. int firstRow = region.getFirstRow();
  257. int firstColumn = region.getFirstColumn();
  258. int lastRow = region.getLastRow();
  259. int lastColumn = region.getLastColumn();
  260. for (int rowIn = firstRow; rowIn <= lastRow; rowIn++) {
  261. for (int colIn = firstColumn; colIn <= lastColumn; colIn++) {
  262. XSSFRow row = getRow(rowIn);
  263. if (row == null) continue;
  264. XSSFCell cell = row.getCell(colIn);
  265. if(cell == null) continue;
  266. if(cell.isPartOfArrayFormulaGroup()){
  267. CellRangeAddress arrayRange = cell.getArrayFormulaRange();
  268. if (arrayRange.getNumberOfCells() > 1 &&
  269. ( arrayRange.isInRange(region.getFirstRow(), region.getFirstColumn()) ||
  270. arrayRange.isInRange(region.getFirstRow(), region.getFirstColumn())) ){
  271. String msg = "The range " + region.formatAsString() + " intersects with a multi-cell array formula. " +
  272. "You cannot merge cells of an array.";
  273. throw new IllegalStateException(msg);
  274. }
  275. }
  276. }
  277. }
  278. }
  279. /**
  280. * Adjusts the column width to fit the contents.
  281. *
  282. * This process can be relatively slow on large sheets, so this should
  283. * normally only be called once per column, at the end of your
  284. * processing.
  285. *
  286. * @param column the column index
  287. */
  288. @Override
  289. public void autoSizeColumn(int column) {
  290. autoSizeColumn(column, false);
  291. }
  292. /**
  293. * Adjusts the column width to fit the contents.
  294. * <p>
  295. * This process can be relatively slow on large sheets, so this should
  296. * normally only be called once per column, at the end of your
  297. * processing.
  298. * </p>
  299. * You can specify whether the content of merged cells should be considered or ignored.
  300. * Default is to ignore merged cells.
  301. *
  302. * @param column the column index
  303. * @param useMergedCells whether to use the contents of merged cells when calculating the width of the column
  304. */
  305. @Override
  306. public void autoSizeColumn(int column, boolean useMergedCells) {
  307. double width = SheetUtil.getColumnWidth(this, column, useMergedCells);
  308. if (width != -1) {
  309. width *= 256;
  310. int maxColumnWidth = 255*256; // The maximum column width for an individual cell is 255 characters
  311. if (width > maxColumnWidth) {
  312. width = maxColumnWidth;
  313. }
  314. setColumnWidth(column, (int)(width));
  315. columnHelper.setColBestFit(column, true);
  316. }
  317. }
  318. /**
  319. * Create a new SpreadsheetML drawing. If this sheet already contains a drawing - return that.
  320. *
  321. * @return a SpreadsheetML drawing
  322. */
  323. @Override
  324. public XSSFDrawing createDrawingPatriarch() {
  325. XSSFDrawing drawing = null;
  326. CTDrawing ctDrawing = getCTDrawing();
  327. if(ctDrawing == null) {
  328. //drawingNumber = #drawings.size() + 1
  329. int drawingNumber = getPackagePart().getPackage().getPartsByContentType(XSSFRelation.DRAWINGS.getContentType()).size() + 1;
  330. drawing = (XSSFDrawing)createRelationship(XSSFRelation.DRAWINGS, XSSFFactory.getInstance(), drawingNumber);
  331. String relId = drawing.getPackageRelationship().getId();
  332. //add CT_Drawing element which indicates that this sheet contains drawing components built on the drawingML platform.
  333. //The relationship Id references the part containing the drawingML definitions.
  334. ctDrawing = worksheet.addNewDrawing();
  335. ctDrawing.setId(relId);
  336. } else {
  337. //search the referenced drawing in the list of the sheet's relations
  338. for(POIXMLDocumentPart p : getRelations()){
  339. if(p instanceof XSSFDrawing) {
  340. XSSFDrawing dr = (XSSFDrawing)p;
  341. String drId = dr.getPackageRelationship().getId();
  342. if(drId.equals(ctDrawing.getId())){
  343. drawing = dr;
  344. break;
  345. }
  346. break;
  347. }
  348. }
  349. if(drawing == null){
  350. logger.log(POILogger.ERROR, "Can't find drawing with id=" + ctDrawing.getId() + " in the list of the sheet's relationships");
  351. }
  352. }
  353. return drawing;
  354. }
  355. /**
  356. * Get VML drawing for this sheet (aka 'legacy' drawig)
  357. *
  358. * @param autoCreate if true, then a new VML drawing part is created
  359. *
  360. * @return the VML drawing of <code>null</code> if the drawing was not found and autoCreate=false
  361. */
  362. protected XSSFVMLDrawing getVMLDrawing(boolean autoCreate) {
  363. XSSFVMLDrawing drawing = null;
  364. CTLegacyDrawing ctDrawing = getCTLegacyDrawing();
  365. if(ctDrawing == null) {
  366. if(autoCreate) {
  367. //drawingNumber = #drawings.size() + 1
  368. int drawingNumber = getPackagePart().getPackage().getPartsByContentType(XSSFRelation.VML_DRAWINGS.getContentType()).size() + 1;
  369. drawing = (XSSFVMLDrawing)createRelationship(XSSFRelation.VML_DRAWINGS, XSSFFactory.getInstance(), drawingNumber);
  370. String relId = drawing.getPackageRelationship().getId();
  371. //add CTLegacyDrawing element which indicates that this sheet contains drawing components built on the drawingML platform.
  372. //The relationship Id references the part containing the drawing definitions.
  373. ctDrawing = worksheet.addNewLegacyDrawing();
  374. ctDrawing.setId(relId);
  375. }
  376. } else {
  377. //search the referenced drawing in the list of the sheet's relations
  378. for(POIXMLDocumentPart p : getRelations()){
  379. if(p instanceof XSSFVMLDrawing) {
  380. XSSFVMLDrawing dr = (XSSFVMLDrawing)p;
  381. String drId = dr.getPackageRelationship().getId();
  382. if(drId.equals(ctDrawing.getId())){
  383. drawing = dr;
  384. break;
  385. }
  386. break;
  387. }
  388. }
  389. if(drawing == null){
  390. logger.log(POILogger.ERROR, "Can't find VML drawing with id=" + ctDrawing.getId() + " in the list of the sheet's relationships");
  391. }
  392. }
  393. return drawing;
  394. }
  395. protected CTDrawing getCTDrawing() {
  396. return worksheet.getDrawing();
  397. }
  398. protected CTLegacyDrawing getCTLegacyDrawing() {
  399. return worksheet.getLegacyDrawing();
  400. }
  401. /**
  402. * Creates a split (freezepane). Any existing freezepane or split pane is overwritten.
  403. * @param colSplit Horizonatal position of split.
  404. * @param rowSplit Vertical position of split.
  405. */
  406. @Override
  407. public void createFreezePane(int colSplit, int rowSplit) {
  408. createFreezePane( colSplit, rowSplit, colSplit, rowSplit );
  409. }
  410. /**
  411. * Creates a split (freezepane). Any existing freezepane or split pane is overwritten.
  412. *
  413. * <p>
  414. * If both colSplit and rowSplit are zero then the existing freeze pane is removed
  415. * </p>
  416. *
  417. * @param colSplit Horizonatal position of split.
  418. * @param rowSplit Vertical position of split.
  419. * @param leftmostColumn Left column visible in right pane.
  420. * @param topRow Top row visible in bottom pane
  421. */
  422. @Override
  423. public void createFreezePane(int colSplit, int rowSplit, int leftmostColumn, int topRow) {
  424. CTSheetView ctView = getDefaultSheetView();
  425. // If both colSplit and rowSplit are zero then the existing freeze pane is removed
  426. if(colSplit == 0 && rowSplit == 0){
  427. if(ctView.isSetPane()) ctView.unsetPane();
  428. ctView.setSelectionArray(null);
  429. return;
  430. }
  431. if (!ctView.isSetPane()) {
  432. ctView.addNewPane();
  433. }
  434. CTPane pane = ctView.getPane();
  435. if (colSplit > 0) {
  436. pane.setXSplit(colSplit);
  437. } else {
  438. if(pane.isSetXSplit()) pane.unsetXSplit();
  439. }
  440. if (rowSplit > 0) {
  441. pane.setYSplit(rowSplit);
  442. } else {
  443. if(pane.isSetYSplit()) pane.unsetYSplit();
  444. }
  445. pane.setState(STPaneState.FROZEN);
  446. if (rowSplit == 0) {
  447. pane.setTopLeftCell(new CellReference(0, leftmostColumn).formatAsString());
  448. pane.setActivePane(STPane.TOP_RIGHT);
  449. } else if (colSplit == 0) {
  450. pane.setTopLeftCell(new CellReference(topRow, 0).formatAsString());
  451. pane.setActivePane(STPane.BOTTOM_LEFT);
  452. } else {
  453. pane.setTopLeftCell(new CellReference(topRow, leftmostColumn).formatAsString());
  454. pane.setActivePane(STPane.BOTTOM_RIGHT);
  455. }
  456. ctView.setSelectionArray(null);
  457. CTSelection sel = ctView.addNewSelection();
  458. sel.setPane(pane.getActivePane());
  459. }
  460. /**
  461. * Creates a new comment for this sheet. You still
  462. * need to assign it to a cell though
  463. *
  464. * @deprecated since Nov 2009 this method is not compatible with the common SS interfaces,
  465. * use {@link org.apache.poi.xssf.usermodel.XSSFDrawing#createCellComment
  466. * (org.apache.poi.ss.usermodel.ClientAnchor)} instead
  467. */
  468. @Deprecated
  469. public XSSFComment createComment() {
  470. return createDrawingPatriarch().createCellComment(new XSSFClientAnchor());
  471. }
  472. /**
  473. * Create a new row within the sheet and return the high level representation
  474. *
  475. * @param rownum row number
  476. * @return High level {@link XSSFRow} object representing a row in the sheet
  477. * @see #removeRow(org.apache.poi.ss.usermodel.Row)
  478. */
  479. @Override
  480. public XSSFRow createRow(int rownum) {
  481. CTRow ctRow;
  482. XSSFRow prev = _rows.get(rownum);
  483. if(prev != null){
  484. ctRow = prev.getCTRow();
  485. ctRow.set(CTRow.Factory.newInstance());
  486. } else {
  487. if(_rows.isEmpty() || rownum > _rows.lastKey()) {
  488. // we can append the new row at the end
  489. ctRow = worksheet.getSheetData().addNewRow();
  490. } else {
  491. // get number of rows where row index < rownum
  492. // --> this tells us where our row should go
  493. int idx = _rows.headMap(rownum).size();
  494. ctRow = worksheet.getSheetData().insertNewRow(idx);
  495. }
  496. }
  497. XSSFRow r = new XSSFRow(ctRow, this);
  498. r.setRowNum(rownum);
  499. _rows.put(rownum, r);
  500. return r;
  501. }
  502. /**
  503. * Creates a split pane. Any existing freezepane or split pane is overwritten.
  504. * @param xSplitPos Horizonatal position of split (in 1/20th of a point).
  505. * @param ySplitPos Vertical position of split (in 1/20th of a point).
  506. * @param topRow Top row visible in bottom pane
  507. * @param leftmostColumn Left column visible in right pane.
  508. * @param activePane Active pane. One of: PANE_LOWER_RIGHT,
  509. * PANE_UPPER_RIGHT, PANE_LOWER_LEFT, PANE_UPPER_LEFT
  510. * @see org.apache.poi.ss.usermodel.Sheet#PANE_LOWER_LEFT
  511. * @see org.apache.poi.ss.usermodel.Sheet#PANE_LOWER_RIGHT
  512. * @see org.apache.poi.ss.usermodel.Sheet#PANE_UPPER_LEFT
  513. * @see org.apache.poi.ss.usermodel.Sheet#PANE_UPPER_RIGHT
  514. */
  515. @Override
  516. public void createSplitPane(int xSplitPos, int ySplitPos, int leftmostColumn, int topRow, int activePane) {
  517. createFreezePane(xSplitPos, ySplitPos, leftmostColumn, topRow);
  518. getPane().setState(STPaneState.SPLIT);
  519. getPane().setActivePane(STPane.Enum.forInt(activePane));
  520. }
  521. @Override
  522. public XSSFComment getCellComment(int row, int column) {
  523. if (sheetComments == null) {
  524. return null;
  525. }
  526. String ref = new CellReference(row, column).formatAsString();
  527. CTComment ctComment = sheetComments.getCTComment(ref);
  528. if(ctComment == null) return null;
  529. XSSFVMLDrawing vml = getVMLDrawing(false);
  530. return new XSSFComment(sheetComments, ctComment,
  531. vml == null ? null : vml.findCommentShape(row, column));
  532. }
  533. public XSSFHyperlink getHyperlink(int row, int column) {
  534. String ref = new CellReference(row, column).formatAsString();
  535. for(XSSFHyperlink hyperlink : hyperlinks) {
  536. if(hyperlink.getCellRef().equals(ref)) {
  537. return hyperlink;
  538. }
  539. }
  540. return null;
  541. }
  542. /**
  543. * Vertical page break information used for print layout view, page layout view, drawing print breaks
  544. * in normal view, and for printing the worksheet.
  545. *
  546. * @return column indexes of all the vertical page breaks, never <code>null</code>
  547. */
  548. @Override
  549. @SuppressWarnings("deprecation") //YK: getXYZArray() array accessors are deprecated in xmlbeans with JDK 1.5 support
  550. public int[] getColumnBreaks() {
  551. if (!worksheet.isSetColBreaks() || worksheet.getColBreaks().sizeOfBrkArray() == 0) {
  552. return new int[0];
  553. }
  554. CTBreak[] brkArray = worksheet.getColBreaks().getBrkArray();
  555. int[] breaks = new int[brkArray.length];
  556. for (int i = 0 ; i < brkArray.length ; i++) {
  557. CTBreak brk = brkArray[i];
  558. breaks[i] = (int)brk.getId() - 1;
  559. }
  560. return breaks;
  561. }
  562. /**
  563. * Get the actual column width (in units of 1/256th of a character width )
  564. *
  565. * <p>
  566. * Note, the returned value is always gerater that {@link #getDefaultColumnWidth()} because the latter does not include margins.
  567. * Actual column width measured as the number of characters of the maximum digit width of the
  568. * numbers 0, 1, 2, ..., 9 as rendered in the normal style's font. There are 4 pixels of margin
  569. * padding (two on each side), plus 1 pixel padding for the gridlines.
  570. * </p>
  571. *
  572. * @param columnIndex - the column to set (0-based)
  573. * @return width - the width in units of 1/256th of a character width
  574. */
  575. @Override
  576. public int getColumnWidth(int columnIndex) {
  577. CTCol col = columnHelper.getColumn(columnIndex, false);
  578. double width = col == null || !col.isSetWidth() ? getDefaultColumnWidth() : col.getWidth();
  579. return (int)(width*256);
  580. }
  581. /**
  582. * Get the default column width for the sheet (if the columns do not define their own width) in
  583. * characters.
  584. * <p>
  585. * Note, this value is different from {@link #getColumnWidth(int)}. The latter is always greater and includes
  586. * 4 pixels of margin padding (two on each side), plus 1 pixel padding for the gridlines.
  587. * </p>
  588. * @return column width, default value is 8
  589. */
  590. @Override
  591. public int getDefaultColumnWidth() {
  592. CTSheetFormatPr pr = worksheet.getSheetFormatPr();
  593. return pr == null ? 8 : (int)pr.getBaseColWidth();
  594. }
  595. /**
  596. * Get the default row height for the sheet (if the rows do not define their own height) in
  597. * twips (1/20 of a point)
  598. *
  599. * @return default row height
  600. */
  601. @Override
  602. public short getDefaultRowHeight() {
  603. return (short)(getDefaultRowHeightInPoints() * 20);
  604. }
  605. /**
  606. * Get the default row height for the sheet measued in point size (if the rows do not define their own height).
  607. *
  608. * @return default row height in points
  609. */
  610. @Override
  611. public float getDefaultRowHeightInPoints() {
  612. CTSheetFormatPr pr = worksheet.getSheetFormatPr();
  613. return (float)(pr == null ? 0 : pr.getDefaultRowHeight());
  614. }
  615. private CTSheetFormatPr getSheetTypeSheetFormatPr() {
  616. return worksheet.isSetSheetFormatPr() ?
  617. worksheet.getSheetFormatPr() :
  618. worksheet.addNewSheetFormatPr();
  619. }
  620. /**
  621. * Returns the CellStyle that applies to the given
  622. * (0 based) column, or null if no style has been
  623. * set for that column
  624. */
  625. @Override
  626. public CellStyle getColumnStyle(int column) {
  627. int idx = columnHelper.getColDefaultStyle(column);
  628. return getWorkbook().getCellStyleAt((short)(idx == -1 ? 0 : idx));
  629. }
  630. /**
  631. * Sets whether the worksheet is displayed from right to left instead of from left to right.
  632. *
  633. * @param value true for right to left, false otherwise.
  634. */
  635. @Override
  636. public void setRightToLeft(boolean value)
  637. {
  638. CTSheetView view = getDefaultSheetView();
  639. view.setRightToLeft(value);
  640. }
  641. /**
  642. * Whether the text is displayed in right-to-left mode in the window
  643. *
  644. * @return whether the text is displayed in right-to-left mode in the window
  645. */
  646. @Override
  647. public boolean isRightToLeft()
  648. {
  649. CTSheetView view = getDefaultSheetView();
  650. return view == null ? false : view.getRightToLeft();
  651. }
  652. /**
  653. * Get whether to display the guts or not,
  654. * default value is true
  655. *
  656. * @return boolean - guts or no guts
  657. */
  658. @Override
  659. public boolean getDisplayGuts() {
  660. CTSheetPr sheetPr = getSheetTypeSheetPr();
  661. CTOutlinePr outlinePr = sheetPr.getOutlinePr() == null ? CTOutlinePr.Factory.newInstance() : sheetPr.getOutlinePr();
  662. return outlinePr.getShowOutlineSymbols();
  663. }
  664. /**
  665. * Set whether to display the guts or not
  666. *
  667. * @param value - guts or no guts
  668. */
  669. @Override
  670. public void setDisplayGuts(boolean value) {
  671. CTSheetPr sheetPr = getSheetTypeSheetPr();
  672. CTOutlinePr outlinePr = sheetPr.getOutlinePr() == null ? sheetPr.addNewOutlinePr() : sheetPr.getOutlinePr();
  673. outlinePr.setShowOutlineSymbols(value);
  674. }
  675. /**
  676. * Gets the flag indicating whether the window should show 0 (zero) in cells containing zero value.
  677. * When false, cells with zero value appear blank instead of showing the number zero.
  678. *
  679. * @return whether all zero values on the worksheet are displayed
  680. */
  681. @Override
  682. public boolean isDisplayZeros(){
  683. CTSheetView view = getDefaultSheetView();
  684. return view == null ? true : view.getShowZeros();
  685. }
  686. /**
  687. * Set whether the window should show 0 (zero) in cells containing zero value.
  688. * When false, cells with zero value appear blank instead of showing the number zero.
  689. *
  690. * @param value whether to display or hide all zero values on the worksheet
  691. */
  692. @Override
  693. public void setDisplayZeros(boolean value){
  694. CTSheetView view = getSheetTypeSheetView();
  695. view.setShowZeros(value);
  696. }
  697. /**
  698. * Gets the first row on the sheet
  699. *
  700. * @return the number of the first logical row on the sheet, zero based
  701. */
  702. @Override
  703. public int getFirstRowNum() {
  704. return _rows.size() == 0 ? 0 : _rows.firstKey();
  705. }
  706. /**
  707. * Flag indicating whether the Fit to Page print option is enabled.
  708. *
  709. * @return <code>true</code>
  710. */
  711. @Override
  712. public boolean getFitToPage() {
  713. CTSheetPr sheetPr = getSheetTypeSheetPr();
  714. CTPageSetUpPr psSetup = (sheetPr == null || !sheetPr.isSetPageSetUpPr()) ?
  715. CTPageSetUpPr.Factory.newInstance() : sheetPr.getPageSetUpPr();
  716. return psSetup.getFitToPage();
  717. }
  718. private CTSheetPr getSheetTypeSheetPr() {
  719. if (worksheet.getSheetPr() == null) {
  720. worksheet.setSheetPr(CTSheetPr.Factory.newInstance());
  721. }
  722. return worksheet.getSheetPr();
  723. }
  724. private CTHeaderFooter getSheetTypeHeaderFooter() {
  725. if (worksheet.getHeaderFooter() == null) {
  726. worksheet.setHeaderFooter(CTHeaderFooter.Factory.newInstance());
  727. }
  728. return worksheet.getHeaderFooter();
  729. }
  730. /**
  731. * Returns the default footer for the sheet,
  732. * creating one as needed.
  733. * You may also want to look at
  734. * {@link #getFirstFooter()},
  735. * {@link #getOddFooter()} and
  736. * {@link #getEvenFooter()}
  737. */
  738. @Override
  739. public Footer getFooter() {
  740. // The default footer is an odd footer
  741. return getOddFooter();
  742. }
  743. /**
  744. * Returns the default header for the sheet,
  745. * creating one as needed.
  746. * You may also want to look at
  747. * {@link #getFirstHeader()},
  748. * {@link #getOddHeader()} and
  749. * {@link #getEvenHeader()}
  750. */
  751. @Override
  752. public Header getHeader() {
  753. // The default header is an odd header
  754. return getOddHeader();
  755. }
  756. /**
  757. * Returns the odd footer. Used on all pages unless
  758. * other footers also present, when used on only
  759. * odd pages.
  760. */
  761. public Footer getOddFooter() {
  762. return new XSSFOddFooter(getSheetTypeHeaderFooter());
  763. }
  764. /**
  765. * Returns the even footer. Not there by default, but
  766. * when set, used on even pages.
  767. */
  768. public Footer getEvenFooter() {
  769. return new XSSFEvenFooter(getSheetTypeHeaderFooter());
  770. }
  771. /**
  772. * Returns the first page footer. Not there by
  773. * default, but when set, used on the first page.
  774. */
  775. public Footer getFirstFooter() {
  776. return new XSSFFirstFooter(getSheetTypeHeaderFooter());
  777. }
  778. /**
  779. * Returns the odd header. Used on all pages unless
  780. * other headers also present, when used on only
  781. * odd pages.
  782. */
  783. public Header getOddHeader() {
  784. return new XSSFOddHeader(getSheetTypeHeaderFooter());
  785. }
  786. /**
  787. * Returns the even header. Not there by default, but
  788. * when set, used on even pages.
  789. */
  790. public Header getEvenHeader() {
  791. return new XSSFEvenHeader(getSheetTypeHeaderFooter());
  792. }
  793. /**
  794. * Returns the first page header. Not there by
  795. * default, but when set, used on the first page.
  796. */
  797. public Header getFirstHeader() {
  798. return new XSSFFirstHeader(getSheetTypeHeaderFooter());
  799. }
  800. /**
  801. * Determine whether printed output for this sheet will be horizontally centered.
  802. */
  803. @Override
  804. public boolean getHorizontallyCenter() {
  805. CTPrintOptions opts = worksheet.getPrintOptions();
  806. return opts != null && opts.getHorizontalCentered();
  807. }
  808. @Override
  809. public int getLastRowNum() {
  810. return _rows.size() == 0 ? 0 : _rows.lastKey();
  811. }
  812. @Override
  813. public short getLeftCol() {
  814. String cellRef = worksheet.getSheetViews().getSheetViewArray(0).getTopLeftCell();
  815. if(cellRef == null) {
  816. return 0;
  817. }
  818. CellReference cellReference = new CellReference(cellRef);
  819. return cellReference.getCol();
  820. }
  821. /**
  822. * Gets the size of the margin in inches.
  823. *
  824. * @param margin which margin to get
  825. * @return the size of the margin
  826. * @see Sheet#LeftMargin
  827. * @see Sheet#RightMargin
  828. * @see Sheet#TopMargin
  829. * @see Sheet#BottomMargin
  830. * @see Sheet#HeaderMargin
  831. * @see Sheet#FooterMargin
  832. */
  833. @Override
  834. public double getMargin(short margin) {
  835. if (!worksheet.isSetPageMargins()) return 0;
  836. CTPageMargins pageMargins = worksheet.getPageMargins();
  837. switch (margin) {
  838. case LeftMargin:
  839. return pageMargins.getLeft();
  840. case RightMargin:
  841. return pageMargins.getRight();
  842. case TopMargin:
  843. return pageMargins.getTop();
  844. case BottomMargin:
  845. return pageMargins.getBottom();
  846. case HeaderMargin:
  847. return pageMargins.getHeader();
  848. case FooterMargin:
  849. return pageMargins.getFooter();
  850. default :
  851. throw new IllegalArgumentException("Unknown margin constant: " + margin);
  852. }
  853. }
  854. /**
  855. * Sets the size of the margin in inches.
  856. *
  857. * @param margin which margin to get
  858. * @param size the size of the margin
  859. * @see Sheet#LeftMargin
  860. * @see Sheet#RightMargin
  861. * @see Sheet#TopMargin
  862. * @see Sheet#BottomMargin
  863. * @see Sheet#HeaderMargin
  864. * @see Sheet#FooterMargin
  865. */
  866. @Override
  867. public void setMargin(short margin, double size) {
  868. CTPageMargins pageMargins = worksheet.isSetPageMargins() ?
  869. worksheet.getPageMargins() : worksheet.addNewPageMargins();
  870. switch (margin) {
  871. case LeftMargin:
  872. pageMargins.setLeft(size);
  873. break;
  874. case RightMargin:
  875. pageMargins.setRight(size);
  876. break;
  877. case TopMargin:
  878. pageMargins.setTop(size);
  879. break;
  880. case BottomMargin:
  881. pageMargins.setBottom(size);
  882. break;
  883. case HeaderMargin:
  884. pageMargins.setHeader(size);
  885. break;
  886. case FooterMargin:
  887. pageMargins.setFooter(size);
  888. break;
  889. default :
  890. throw new IllegalArgumentException( "Unknown margin constant: " + margin );
  891. }
  892. }
  893. /**
  894. * @return the merged region at the specified index
  895. * @throws IllegalStateException if this worksheet does not contain merged regions
  896. */
  897. @Override
  898. public CellRangeAddress getMergedRegion(int index) {
  899. CTMergeCells ctMergeCells = worksheet.getMergeCells();
  900. if(ctMergeCells == null) throw new IllegalStateException("This worksheet does not contain merged regions");
  901. CTMergeCell ctMergeCell = ctMergeCells.getMergeCellArray(index);
  902. String ref = ctMergeCell.getRef();
  903. return CellRangeAddress.valueOf(ref);
  904. }
  905. /**
  906. * Returns the number of merged regions defined in this worksheet
  907. *
  908. * @return number of merged regions in this worksheet
  909. */
  910. @Override
  911. public int getNumMergedRegions() {
  912. CTMergeCells ctMergeCells = worksheet.getMergeCells();
  913. return ctMergeCells == null ? 0 : ctMergeCells.sizeOfMergeCellArray();
  914. }
  915. public int getNumHyperlinks() {
  916. return hyperlinks.size();
  917. }
  918. /**
  919. * Returns the information regarding the currently configured pane (split or freeze).
  920. *
  921. * @return null if no pane configured, or the pane information.
  922. */
  923. @Override
  924. public PaneInformation getPaneInformation() {
  925. CTPane pane = getDefaultSheetView().getPane();
  926. // no pane configured
  927. if(pane == null) return null;
  928. CellReference cellRef = pane.isSetTopLeftCell() ? new CellReference(pane.getTopLeftCell()) : null;
  929. return new PaneInformation((short)pane.getXSplit(), (short)pane.getYSplit(),
  930. (short)(cellRef == null ? 0 : cellRef.getRow()),(cellRef == null ? 0 : cellRef.getCol()),
  931. (byte)(pane.getActivePane().intValue() - 1), pane.getState() == STPaneState.FROZEN);
  932. }
  933. /**
  934. * Returns the number of phsyically defined rows (NOT the number of rows in the sheet)
  935. *
  936. * @return the number of phsyically defined rows
  937. */
  938. @Override
  939. public int getPhysicalNumberOfRows() {
  940. return _rows.size();
  941. }
  942. /**
  943. * Gets the print setup object.
  944. *
  945. * @return The user model for the print setup object.
  946. */
  947. @Override
  948. public XSSFPrintSetup getPrintSetup() {
  949. return new XSSFPrintSetup(worksheet);
  950. }
  951. /**
  952. * Answer whether protection is enabled or disabled
  953. *
  954. * @return true => protection enabled; false => protection disabled
  955. */
  956. @Override
  957. public boolean getProtect() {
  958. return isSheetLocked();
  959. }
  960. /**
  961. * Enables sheet protection and sets the password for the sheet.
  962. * Also sets some attributes on the {@link CTSheetProtection} that correspond to
  963. * the default values used by Excel
  964. *
  965. * @param password to set for protection. Pass <code>null</code> to remove protection
  966. */
  967. @Override
  968. public void protectSheet(String password) {
  969. if (password != null) {
  970. CTSheetProtection sheetProtection = safeGetProtectionField();
  971. setSheetPassword(password, null); // defaults to xor password
  972. sheetProtection.setSheet(true);
  973. sheetProtection.setScenarios(true);
  974. sheetProtection.setObjects(true);
  975. } else {
  976. worksheet.unsetSheetProtection();
  977. }
  978. }
  979. /**
  980. * Sets the sheet password.
  981. *
  982. * @param password if null, the password will be removed
  983. * @param hashAlgo if null, the password will be set as XOR password (Excel 2010 and earlier)
  984. * otherwise the given algorithm is used for calculating the hash password (Excel 2013)
  985. */
  986. public void setSheetPassword(String password, HashAlgorithm hashAlgo) {
  987. if (password == null && !isSheetProtectionEnabled()) return;
  988. setPassword(safeGetProtectionField(), password, hashAlgo, null);
  989. }
  990. /**
  991. * Validate the password against the stored hash, the hashing method will be determined
  992. * by the existing password attributes
  993. * @return true, if the hashes match (... though original password may differ ...)
  994. */
  995. public boolean validateSheetPassword(String password) {
  996. if (!isSheetProtectionEnabled()) return (password == null);
  997. return validatePassword(safeGetProtectionField(), password, null);
  998. }
  999. /**
  1000. * Returns the logical row ( 0-based). If you ask for a row that is not
  1001. * defined you get a null. This is to say row 4 represents the fifth row on a sheet.
  1002. *
  1003. * @param rownum row to get
  1004. * @return <code>XSSFRow</code> representing the rownumber or <code>null</code> if its not defined on the sheet
  1005. */
  1006. @Override
  1007. public XSSFRow getRow(int rownum) {
  1008. return _rows.get(rownum);
  1009. }
  1010. /**
  1011. * Horizontal page break information used for print layout view, page layout view, drawing print breaks in normal
  1012. * view, and for printing the worksheet.
  1013. *
  1014. * @return row indexes of all the horizontal page breaks, never <code>null</code>
  1015. */
  1016. @Override
  1017. @SuppressWarnings("deprecation") //YK: getXYZArray() array accessors are deprecated in xmlbeans with JDK 1.5 support
  1018. public int[] getRowBreaks() {
  1019. if (!worksheet.isSetRowBreaks() || worksheet.getRowBreaks().sizeOfBrkArray() == 0) {
  1020. return new int[0];
  1021. }
  1022. CTBreak[] brkArray = worksheet.getRowBreaks().getBrkArray();
  1023. int[] breaks = new int[brkArray.length];
  1024. for (int i = 0 ; i < brkArray.length ; i++) {
  1025. CTBreak brk = brkArray[i];
  1026. breaks[i] = (int)brk.getId() - 1;
  1027. }
  1028. return breaks;
  1029. }
  1030. /**
  1031. * Flag indicating whether summary rows appear below detail in an outline, when applying an outline.
  1032. *
  1033. * <p>
  1034. * When true a summary row is inserted below the detailed data being summarized and a
  1035. * new outline level is established on that row.
  1036. * </p>
  1037. * <p>
  1038. * When false a summary row is inserted above the detailed data being summarized and a new outline level
  1039. * is established on that row.
  1040. * </p>
  1041. * @return <code>true</code> if row summaries appear below detail in the outline
  1042. */
  1043. @Override
  1044. public boolean getRowSumsBelow() {
  1045. CTSheetPr sheetPr = worksheet.getSheetPr();
  1046. CTOutlinePr outlinePr = (sheetPr != null && sheetPr.isSetOutlinePr())
  1047. ? sheetPr.getOutlinePr() : null;
  1048. return outlinePr == null || outlinePr.getSummaryBelow();
  1049. }
  1050. /**
  1051. * Flag indicating whether summary rows appear below detail in an outline, when applying an outline.
  1052. *
  1053. * <p>
  1054. * When true a summary row is inserted below the detailed data being summarized and a
  1055. * new outline level is established on that row.
  1056. * </p>
  1057. * <p>
  1058. * When false a summary row is inserted above the detailed data being summarized and a new outline level
  1059. * is established on that row.
  1060. * </p>
  1061. * @param value <code>true</code> if row summaries appear below detail in the outline
  1062. */
  1063. @Override
  1064. public void setRowSumsBelow(boolean value) {
  1065. ensureOutlinePr().setSummaryBelow(value);
  1066. }
  1067. /**
  1068. * Flag indicating whether summary columns appear to the right of detail in an outline, when applying an outline.
  1069. *
  1070. * <p>
  1071. * When true a summary column is inserted to the right of the detailed data being summarized
  1072. * and a new outline level is established on that column.
  1073. * </p>
  1074. * <p>
  1075. * When false a summary column is inserted to the left of the detailed data being
  1076. * summarized and a new outline level is established on that column.
  1077. * </p>
  1078. * @return <code>true</code> if col summaries appear right of the detail in the outline
  1079. */
  1080. @Override
  1081. public boolean getRowSumsRight() {
  1082. CTSheetPr sheetPr = worksheet.getSheetPr();
  1083. CTOutlinePr outlinePr = (sheetPr != null && sheetPr.isSetOutlinePr())
  1084. ? sheetPr.getOutlinePr() : CTOutlinePr.Factory.newInstance();
  1085. return outlinePr.getSummaryRight();
  1086. }
  1087. /**
  1088. * Flag indicating whether summary columns appear to the right of detail in an outline, when applying an outline.
  1089. *
  1090. * <p>
  1091. * When true a summary column is inserted to the right of the detailed data being summarized
  1092. * and a new outline level is established on that column.
  1093. * </p>
  1094. * <p>
  1095. * When false a summary column is inserted to the left of the detailed data being
  1096. * summarized and a new outline level is established on that column.
  1097. * </p>
  1098. * @param value <code>true</code> if col summaries appear right of the detail in the outline
  1099. */
  1100. @Override
  1101. public void setRowSumsRight(boolean value) {
  1102. ensureOutlinePr().setSummaryRight(value);
  1103. }
  1104. /**
  1105. * Ensure CTWorksheet.CTSheetPr.CTOutlinePr
  1106. */
  1107. private CTOutlinePr ensureOutlinePr(){
  1108. CTSheetPr sheetPr = worksheet.isSetSheetPr() ? worksheet.getSheetPr() : worksheet.addNewSheetPr();
  1109. return sheetPr.isSetOutlinePr() ? sheetPr.getOutlinePr() : sheetPr.addNewOutlinePr();
  1110. }
  1111. /**
  1112. * A flag indicating whether scenarios are locked when the sheet is protected.
  1113. *
  1114. * @return true => protection enabled; false => protection disabled
  1115. */
  1116. @Override
  1117. public boolean getScenarioProtect() {
  1118. return worksheet.isSetSheetProtection() && worksheet.getSheetProtection().getScenarios();
  1119. }
  1120. /**
  1121. * The top row in the visible view when the sheet is
  1122. * first viewed after opening it in a viewer
  1123. *
  1124. * @return integer indicating the rownum (0 based) of the top row
  1125. */
  1126. @Override
  1127. public short getTopRow() {
  1128. String cellRef = getSheetTypeSheetView().getTopLeftCell();
  1129. if(cellRef == null) {
  1130. return 0;
  1131. }
  1132. CellReference cellReference = new CellReference(cellRef);
  1133. return (short) cellReference.getRow();
  1134. }
  1135. /**
  1136. * Determine whether printed output for this sheet will be vertically centered.
  1137. *
  1138. * @return whether printed output for this sheet will be vertically centered.
  1139. */
  1140. @Override
  1141. public boolean getVerticallyCenter() {
  1142. CTPrintOptions opts = worksheet.getPrintOptions();
  1143. return opts != null && opts.getVerticalCentered();
  1144. }
  1145. /**
  1146. * Group between (0 based) columns
  1147. */
  1148. @Override
  1149. public void groupColumn(int fromColumn, int toColumn) {
  1150. groupColumn1Based(fromColumn+1, toColumn+1);
  1151. }
  1152. private void groupColumn1Based(int fromColumn, int toColumn) {
  1153. CTCols ctCols=worksheet.getColsArray(0);
  1154. CTCol ctCol=CTCol.Factory.newInstance();
  1155. // copy attributes, as they might be removed by merging with the new column
  1156. // TODO: check if this fix is really necessary or if the sweeping algorithm
  1157. // in addCleanColIntoCols needs to be adapted ...
  1158. CTCol fixCol_before = this.columnHelper.getColumn1Based(toColumn, false);
  1159. if (fixCol_before != null) {
  1160. fixCol_before = (CTCol)fixCol_before.copy();
  1161. }
  1162. ctCol.setMin(fromColumn);
  1163. ctCol.setMax(toColumn);
  1164. this.columnHelper.addCleanColIntoCols(ctCols, ctCol);
  1165. CTCol fixCol_after = this.columnHelper.getColumn1Based(toColumn, false);
  1166. if (fixCol_before != null && fixCol_after != null) {
  1167. this.columnHelper.setColumnAttributes(fixCol_before, fixCol_after);
  1168. }
  1169. for(int index=fromColumn;index<=toColumn;index++){
  1170. CTCol col=columnHelper.getColumn1Based(index, false);
  1171. //col must exist
  1172. short outlineLevel=col.getOutlineLevel();
  1173. col.setOutlineLevel((short)(outlineLevel+1));
  1174. index=(int)col.getMax();
  1175. }
  1176. worksheet.setColsArray(0,ctCols);
  1177. setSheetFormatPrOutlineLevelCol();
  1178. }
  1179. /**
  1180. * Do not leave the width attribute undefined (see #52186).
  1181. */
  1182. @SuppressWarnings("deprecation")
  1183. private void setColWidthAttribute(CTCols ctCols) {
  1184. for (CTCol col : ctCols.getColArray()) {
  1185. if (!col.isSetWidth()) {
  1186. col.setWidth(getDefaultColumnWidth());
  1187. col.setCustomWidth(false);
  1188. }
  1189. }
  1190. }
  1191. /**
  1192. * Tie a range of cell together so that they can be collapsed or expanded
  1193. *
  1194. * @param fromRow start row (0-based)
  1195. * @param toRow end row (0-based)
  1196. */
  1197. @Override
  1198. public void groupRow(int fromRow, int toRow) {
  1199. for (int i = fromRow; i <= toRow; i++) {
  1200. XSSFRow xrow = getRow(i);
  1201. if (xrow == null) {
  1202. xrow = createRow(i);
  1203. }
  1204. CTRow ctrow = xrow.getCTRow();
  1205. short outlineLevel = ctrow.getOutlineLevel();
  1206. ctrow.setOutlineLevel((short) (outlineLevel + 1));
  1207. }
  1208. setSheetFormatPrOutlineLevelRow();
  1209. }
  1210. private short getMaxOutlineLevelRows(){
  1211. short outlineLevel=0;
  1212. for(XSSFRow xrow : _rows.values()){
  1213. outlineLevel=xrow.getCTRow().getOutlineLevel()>outlineLevel? xrow.getCTRow().getOutlineLevel(): outlineLevel;
  1214. }
  1215. return outlineLevel;
  1216. }
  1217. @SuppressWarnings("deprecation")
  1218. private short getMaxOutlineLevelCols() {
  1219. CTCols ctCols = worksheet.getColsArray(0);
  1220. short outlineLevel = 0;
  1221. for (CTCol col : ctCols.getColArray()) {
  1222. outlineLevel = col.getOutlineLevel() > outlineLevel ? col.getOutlineLevel() : outlineLevel;
  1223. }
  1224. return outlineLevel;
  1225. }
  1226. /**
  1227. * Determines if there is a page break at the indicated column
  1228. */
  1229. @Override
  1230. public boolean isColumnBroken(int column) {
  1231. int[] colBreaks = getColumnBreaks();
  1232. for (int colBreak : colBreaks) {
  1233. if (colBreak == column) {
  1234. return true;
  1235. }
  1236. }
  1237. return false;
  1238. }
  1239. /**
  1240. * Get the hidden state for a given column.
  1241. *
  1242. * @param columnIndex - the column to set (0-based)
  1243. * @return hidden - <code>false</code> if the column is visible
  1244. */
  1245. @Override
  1246. public boolean isColumnHidden(int columnIndex) {
  1247. CTCol col = columnHelper.getColumn(columnIndex, false);
  1248. return col != null && col.getHidden();
  1249. }
  1250. /**
  1251. * Gets the flag indicating whether this sheet should display formulas.
  1252. *
  1253. * @return <code>true</code> if this sheet should display formulas.
  1254. */
  1255. @Override
  1256. public boolean isDisplayFormulas() {
  1257. return getSheetTypeSheetView().getShowFormulas();
  1258. }
  1259. /**
  1260. * Gets the flag indicating whether this sheet displays the lines
  1261. * between rows and columns to make editing and reading easier.
  1262. *
  1263. * @return <code>true</code> if this sheet displays gridlines.
  1264. * @see #isPrintGridlines() to check if printing of gridlines is turned on or off
  1265. */
  1266. @Override
  1267. public boolean isDisplayGridlines() {
  1268. return getSheetTypeSheetView().getShowGridLines();
  1269. }
  1270. /**
  1271. * Sets the flag indicating whether this sheet should display the lines
  1272. * between rows and columns to make editing and reading easier.
  1273. * To turn printing of gridlines use {@link #setPrintGridlines(boolean)}
  1274. *
  1275. *
  1276. * @param show <code>true</code> if this sheet should display gridlines.
  1277. * @see #setPrintGridlines(boolean)
  1278. */
  1279. @Override
  1280. public void setDisplayGridlines(boolean show) {
  1281. getSheetTypeSheetView().setShowGridLines(show);
  1282. }
  1283. /**
  1284. * Gets the flag indicating whether this sheet should display row and column headings.
  1285. * <p>
  1286. * Row heading are the row numbers to the side of the sheet
  1287. * </p>
  1288. * <p>
  1289. * Column heading are the letters or numbers that appear above the columns of the sheet
  1290. * </p>
  1291. *
  1292. * @return <code>true</code> if this sheet should display row and column headings.
  1293. */
  1294. @Override
  1295. public boolean isDisplayRowColHeadings() {
  1296. return getSheetTypeSheetView().getShowRowColHeaders();
  1297. }
  1298. /**
  1299. * Sets the flag indicating whether this sheet should display row and column headings.
  1300. * <p>
  1301. * Row heading are the row numbers to the side of the sheet
  1302. * </p>
  1303. * <p>
  1304. * Column heading are the letters or numbers that appear above the columns of the sheet
  1305. * </p>
  1306. *
  1307. * @param show <code>true</code> if this sheet should display row and column headings.
  1308. */
  1309. @Override
  1310. public void setDisplayRowColHeadings(boolean show) {
  1311. getSheetTypeSheetView().setShowRowColHeaders(show);
  1312. }
  1313. /**
  1314. * Returns whether gridlines are printed.
  1315. *
  1316. * @return whether gridlines are printed
  1317. */
  1318. @Override
  1319. public boolean isPrintGridlines() {
  1320. CTPrintOptions opts = worksheet.getPrintOptions();
  1321. return opts != null && opts.getGridLines();
  1322. }
  1323. /**
  1324. * Turns on or off the printing of gridlines.
  1325. *
  1326. * @param value boolean to turn on or off the printing of gridlines
  1327. */
  1328. @Override
  1329. public void setPrintGridlines(boolean value) {
  1330. CTPrintOptions opts = worksheet.isSetPrintOptions() ?
  1331. worksheet.getPrintOptions() : worksheet.addNewPrintOptions();
  1332. opts.setGridLines(value);
  1333. }
  1334. /**
  1335. * Tests if there is a page break at the indicated row
  1336. *
  1337. * @param row index of the row to test
  1338. * @return <code>true</code> if there is a page break at the indicated row
  1339. */
  1340. @Override
  1341. public boolean isRowBroken(int row) {
  1342. int[] rowBreaks = getRowBreaks();
  1343. for (int rowBreak : rowBreaks) {
  1344. if (rowBreak == row) {
  1345. return true;
  1346. }
  1347. }
  1348. return false;
  1349. }
  1350. /**
  1351. * Sets a page break at the indicated row
  1352. * Breaks occur above the specified row and left of the specified column inclusive.
  1353. *
  1354. * For example, <code>sheet.setColumnBreak(2);</code> breaks the sheet into two parts
  1355. * with columns A,B,C in the first and D,E,... in the second. Simuilar, <code>sheet.setRowBreak(2);</code>
  1356. * breaks the sheet into two parts with first three rows (rownum=1...3) in the first part
  1357. * and rows starting with rownum=4 in the second.
  1358. *
  1359. * @param row the row to break, inclusive
  1360. */
  1361. @Override
  1362. public void setRowBreak(int row) {
  1363. CTPageBreak pgBreak = worksheet.isSetRowBreaks() ? worksheet.getRowBreaks() : worksheet.addNewRowBreaks();
  1364. if (! isRowBroken(row)) {
  1365. CTBreak brk = pgBreak.addNewBrk();
  1366. brk.setId(row + 1); // this is id of the row element which is 1-based: <row r="1" ... >
  1367. brk.setMan(true);
  1368. brk.setMax(SpreadsheetVersion.EXCEL2007.getLastColumnIndex()); //end column of the break
  1369. pgBreak.setCount(pgBreak.sizeOfBrkArray());
  1370. pgBreak.setManualBreakCount(pgBreak.sizeOfBrkArray());
  1371. }
  1372. }
  1373. /**
  1374. * Removes a page break at the indicated column
  1375. */
  1376. @Override
  1377. @SuppressWarnings("deprecation") //YK: getXYZArray() array accessors are deprecated in xmlbeans with JDK 1.5 support
  1378. public void removeColumnBreak(int column) {
  1379. if (!worksheet.isSetColBreaks()) {
  1380. // no breaks
  1381. return;
  1382. }
  1383. CTPageBreak pgBreak = worksheet.getColBreaks();
  1384. CTBreak[] brkArray = pgBreak.getBrkArray();
  1385. for (int i = 0 ; i < brkArray.length ; i++) {
  1386. if (brkArray[i].getId() == (column + 1)) {
  1387. pgBreak.removeBrk(i);
  1388. }
  1389. }
  1390. }
  1391. /**
  1392. * Removes a merged region of cells (hence letting them free)
  1393. *
  1394. * @param index of the region to unmerge
  1395. */
  1396. @Override
  1397. public void removeMergedRegion(int index) {
  1398. CTMergeCells ctMergeCells = worksheet.getMergeCells();
  1399. int size = ctMergeCells.sizeOfMergeCellArray();
  1400. CTMergeCell[] mergeCellsArray = new CTMergeCell[size - 1];
  1401. for (int i = 0 ; i < size ; i++) {
  1402. if (i < index) {
  1403. mergeCellsArray[i] = ctMergeCells.getMergeCellArray(i);
  1404. }
  1405. else if (i > index) {
  1406. mergeCellsArray[i - 1] = ctMergeCells.getMergeCellArray(i);
  1407. }
  1408. }
  1409. if(mergeCellsArray.length > 0){
  1410. ctMergeCells.setMergeCellArray(mergeCellsArray);
  1411. } else{
  1412. worksheet.unsetMergeCells();
  1413. }
  1414. }
  1415. /**
  1416. * Removes a number of merged regions of cells (hence letting them free)
  1417. *
  1418. * This method can be used to bulk-remove merged regions in a way
  1419. * much faster than calling removeMergedRegion() for every single
  1420. * merged region.
  1421. *
  1422. * @param indices A set of the regions to unmerge
  1423. */
  1424. public void removeMergedRegions(Set<Integer> indices) {
  1425. CTMergeCells ctMergeCells = worksheet.getMergeCells();
  1426. int size = ctMergeCells.sizeOfMergeCellArray();
  1427. CTMergeCell[] mergeCellsArray = new CTMergeCell[size - indices.size()];
  1428. for (int i = 0, d = 0 ; i < size ; i++) {
  1429. if(!indices.contains(i)) {
  1430. mergeCellsArray[d] = ctMergeCells.getMergeCellArray(i);
  1431. d++;
  1432. }
  1433. }
  1434. if(mergeCellsArray.length > 0){
  1435. ctMergeCells.setMergeCellArray(mergeCellsArray);
  1436. } else{
  1437. worksheet.unsetMergeCells();
  1438. }
  1439. }
  1440. /**
  1441. * Remove a row from this sheet. All cells contained in the row are removed as well
  1442. *
  1443. * @param row the row to remove.
  1444. */
  1445. @Override
  1446. public void removeRow(Row row) {
  1447. if (row.getSheet() != this) {
  1448. throw new IllegalArgumentException("Specified row does not belong to this sheet");
  1449. }
  1450. // collect cells into a temporary array to avoid ConcurrentModificationException
  1451. ArrayList<XSSFCell> cellsToDelete = new ArrayList<XSSFCell>();
  1452. for(Cell cell : row) cellsToDelete.add((XSSFCell)cell);
  1453. for(XSSFCell cell : cellsToDelete) row.removeCell(cell);
  1454. int idx = _rows.headMap(row.getRowNum()).size();
  1455. _rows.remove(row.getRowNum());
  1456. worksheet.getSheetData().removeRow(idx);
  1457. }
  1458. /**
  1459. * Removes the page break at the indicated row
  1460. */
  1461. @Override
  1462. @SuppressWarnings("deprecation") //YK: getXYZArray() array accessors are deprecated in xmlbeans with JDK 1.5 support
  1463. public void removeRowBreak(int row) {
  1464. if(!worksheet.isSetRowBreaks()) {
  1465. return;
  1466. }
  1467. CTPageBreak pgBreak = worksheet.getRowBreaks();
  1468. CTBreak[] brkArray = pgBreak.getBrkArray();
  1469. for (int i = 0 ; i < brkArray.length ; i++) {
  1470. if (brkArray[i].getId() == (row + 1)) {
  1471. pgBreak.removeBrk(i);
  1472. }
  1473. }
  1474. }
  1475. /**
  1476. * Control if Excel should be asked to recalculate all formulas on this sheet
  1477. * when the workbook is opened.
  1478. *
  1479. * <p>
  1480. * Calculating the formula values with {@link org.apache.poi.ss.usermodel.FormulaEvaluator} is the
  1481. * recommended solution, but this may be used for certain cases where
  1482. * evaluation in POI is not possible.
  1483. * </p>
  1484. *
  1485. * <p>
  1486. * It is recommended to force recalcuation of formulas on workbook level using
  1487. * {@link org.apache.poi.ss.usermodel.Workbook#setForceFormulaRecalculation(boolean)}
  1488. * to ensure that all cross-worksheet formuals and external dependencies are updated.
  1489. * </p>
  1490. * @param value true if the application will perform a full recalculation of
  1491. * this worksheet values when the workbook is opened
  1492. *
  1493. * @see org.apache.poi.ss.usermodel.Workbook#setForceFormulaRecalculation(boolean)
  1494. */
  1495. @Override
  1496. public void setForceFormulaRecalculation(boolean value) {
  1497. CTCalcPr calcPr = getWorkbook().getCTWorkbook().getCalcPr();
  1498. if(worksheet.isSetSheetCalcPr()) {
  1499. // Change the current setting
  1500. CTSheetCalcPr calc = worksheet.getSheetCalcPr();
  1501. calc.setFullCalcOnLoad(value);
  1502. }
  1503. else if(value) {
  1504. // Add the Calc block and set it
  1505. CTSheetCalcPr calc = worksheet.addNewSheetCalcPr();
  1506. calc.setFullCalcOnLoad(value);
  1507. }
  1508. if(value && calcPr != null && calcPr.getCalcMode() == STCalcMode.MANUAL) {
  1509. calcPr.setCalcMode(STCalcMode.AUTO);
  1510. }
  1511. }
  1512. /**
  1513. * Whether Excel will be asked to recalculate all formulas when the
  1514. * workbook is opened.
  1515. */
  1516. @Override
  1517. public boolean getForceFormulaRecalculation() {
  1518. if(worksheet.isSetSheetCalcPr()) {
  1519. CTSheetCalcPr calc = worksheet.getSheetCalcPr();
  1520. return calc.getFullCalcOnLoad();
  1521. }
  1522. return false;
  1523. }
  1524. /**
  1525. * @return an iterator of the PHYSICAL rows. Meaning the 3rd element may not
  1526. * be the third row if say for instance the second row is undefined.
  1527. * Call getRowNum() on each row if you care which one it is.
  1528. */
  1529. @Override
  1530. @SuppressWarnings("unchecked")
  1531. public Iterator<Row> rowIterator() {
  1532. return (Iterator<Row>)(Iterator<? extends Row>) _rows.values().iterator();
  1533. }
  1534. /**
  1535. * Alias for {@link #rowIterator()} to
  1536. * allow foreach loops
  1537. */
  1538. @Override
  1539. public Iterator<Row> iterator() {
  1540. return rowIterator();
  1541. }
  1542. /**
  1543. * Flag indicating whether the sheet displays Automatic Page Breaks.
  1544. *
  1545. * @return <code>true</code> if the sheet displays Automatic Page Breaks.
  1546. */
  1547. @Override
  1548. public boolean getAutobreaks() {
  1549. CTSheetPr sheetPr = getSheetTypeSheetPr();
  1550. CTPageSetUpPr psSetup = (sheetPr == null || !sheetPr.isSetPageSetUpPr()) ?
  1551. CTPageSetUpPr.Factory.newInstance() : sheetPr.getPageSetUpPr();
  1552. return psSetup.getAutoPageBreaks();
  1553. }
  1554. /**
  1555. * Flag indicating whether the sheet displays Automatic Page Breaks.
  1556. *
  1557. * @param value <code>true</code> if the sheet displays Automatic Page Breaks.
  1558. */
  1559. @Override
  1560. public void setAutobreaks(boolean value) {
  1561. CTSheetPr sheetPr = getSheetTypeSheetPr();
  1562. CTPageSetUpPr psSetup = sheetPr.isSetPageSetUpPr() ? sheetPr.getPageSetUpPr() : sheetPr.addNewPageSetUpPr();
  1563. psSetup.setAutoPageBreaks(value);
  1564. }
  1565. /**
  1566. * Sets a page break at the indicated column.
  1567. * Breaks occur above the specified row and left of the specified column inclusive.
  1568. *
  1569. * For example, <code>sheet.setColumnBreak(2);</code> breaks the sheet into two parts
  1570. * with columns A,B,C in the first and D,E,... in the second. Simuilar, <code>sheet.setRowBreak(2);</code>
  1571. * breaks the sheet into two parts with first three rows (rownum=1...3) in the first part
  1572. * and rows starting with rownum=4 in the second.
  1573. *
  1574. * @param column the column to break, inclusive
  1575. */
  1576. @Override
  1577. public void setColumnBreak(int column) {
  1578. if (! isColumnBroken(column)) {
  1579. CTPageBreak pgBreak = worksheet.isSetColBreaks() ? worksheet.getColBreaks() : worksheet.addNewColBreaks();
  1580. CTBreak brk = pgBreak.addNewBrk();
  1581. brk.setId(column + 1); // this is id of the row element which is 1-based: <row r="1" ... >
  1582. brk.setMan(true);
  1583. brk.setMax(SpreadsheetVersion.EXCEL2007.getLastRowIndex()); //end row of the break
  1584. pgBreak.setCount(pgBreak.sizeOfBrkArray());
  1585. pgBreak.setManualBreakCount(pgBreak.sizeOfBrkArray());
  1586. }
  1587. }
  1588. @Override
  1589. public void setColumnGroupCollapsed(int columnNumber, boolean collapsed) {
  1590. if (collapsed) {
  1591. collapseColumn(columnNumber);
  1592. } else {
  1593. expandColumn(columnNumber);
  1594. }
  1595. }
  1596. private void collapseColumn(int columnNumber) {
  1597. CTCols cols = worksheet.getColsArray(0);
  1598. CTCol col = columnHelper.getColumn(columnNumber, false);
  1599. int colInfoIx = columnHelper.getIndexOfColumn(cols, col);
  1600. if (colInfoIx == -1) {
  1601. return;
  1602. }
  1603. // Find the start of the group.
  1604. int groupStartColInfoIx = findStartOfColumnOutlineGroup(colInfoIx);
  1605. CTCol columnInfo = cols.getColArray(groupStartColInfoIx);
  1606. // Hide all the columns until the end of the group
  1607. int lastColMax = setGroupHidden(groupStartColInfoIx, columnInfo
  1608. .getOutlineLevel(), true);
  1609. // write collapse field
  1610. setColumn(lastColMax + 1, null, 0, null, null, Boolean.TRUE);
  1611. }
  1612. private void setColumn(int targetColumnIx, Short xfIndex, Integer style,
  1613. Integer level, Boolean hidden, Boolean collapsed) {
  1614. CTCols cols = worksheet.getColsArray(0);
  1615. CTCol ci = null;
  1616. int k = 0;
  1617. for (k = 0; k < cols.sizeOfColArray(); k++) {
  1618. CTCol tci = cols.getColArray(k);
  1619. if (tci.getMin() >= targetColumnIx
  1620. && tci.getMax() <= targetColumnIx) {
  1621. ci = tci;
  1622. break;
  1623. }
  1624. if (tci.getMin() > targetColumnIx) {
  1625. // call column infos after k are for later columns
  1626. break; // exit now so k will be the correct insert pos
  1627. }
  1628. }
  1629. if (ci == null) {
  1630. // okay so there ISN'T a column info record that covers this column
  1631. // so lets create one!
  1632. CTCol nci = CTCol.Factory.newInstance();
  1633. nci.setMin(targetColumnIx);
  1634. nci.setMax(targetColumnIx);
  1635. unsetCollapsed(collapsed, nci);
  1636. this.columnHelper.addCleanColIntoCols(cols, nci);
  1637. return;
  1638. }
  1639. boolean styleChanged = style != null
  1640. && ci.getStyle() != style;
  1641. boolean levelChanged = level != null
  1642. && ci.getOutlineLevel() != level;
  1643. boolean hiddenChanged = hidden != null
  1644. && ci.getHidden() != hidden;
  1645. boolean collapsedChanged = collapsed != null
  1646. && ci.getCollapsed() != collapsed;
  1647. boolean columnChanged = levelChanged || hiddenChanged
  1648. || collapsedChanged || styleChanged;
  1649. if (!columnChanged) {
  1650. // do nothing...nothing changed.
  1651. return;
  1652. }
  1653. if (ci.getMin() == targetColumnIx && ci.getMax() == targetColumnIx) {
  1654. // ColumnInfo ci for a single column, the target column
  1655. unsetCollapsed(collapsed, ci);
  1656. return;
  1657. }
  1658. if (ci.getMin() == targetColumnIx || ci.getMax() == targetColumnIx) {
  1659. // The target column is at either end of the multi-column ColumnInfo
  1660. // ci
  1661. // we'll just divide the info and create a new one
  1662. if (ci.getMin() == targetColumnIx) {
  1663. ci.setMin(targetColumnIx + 1);
  1664. } else {
  1665. ci.setMax(targetColumnIx - 1);
  1666. k++; // adjust insert pos to insert after
  1667. }
  1668. CTCol nci = columnHelper.cloneCol(cols, ci);
  1669. nci.setMin(targetColumnIx);
  1670. unsetCollapsed(collapsed, nci);
  1671. this.columnHelper.addCleanColIntoCols(cols, nci);
  1672. } else {
  1673. // split to 3 records
  1674. CTCol ciStart = ci;
  1675. CTCol ciMid = columnHelper.cloneCol(cols, ci);
  1676. CTCol ciEnd = columnHelper.cloneCol(cols, ci);
  1677. int lastcolumn = (int) ci.getMax();
  1678. ciStart.setMax(targetColumnIx - 1);
  1679. ciMid.setMin(targetColumnIx);
  1680. ciMid.setMax(targetColumnIx);
  1681. unsetCollapsed(collapsed, ciMid);
  1682. this.columnHelper.addCleanColIntoCols(cols, ciMid);
  1683. ciEnd.setMin(targetColumnIx + 1);
  1684. ciEnd.setMax(lastcolumn);
  1685. this.columnHelper.addCleanColIntoCols(cols, ciEnd);
  1686. }
  1687. }
  1688. private void unsetCollapsed(boolean collapsed, CTCol ci) {
  1689. if (collapsed) {
  1690. ci.setCollapsed(collapsed);
  1691. } else {
  1692. ci.unsetCollapsed();
  1693. }
  1694. }
  1695. /**
  1696. * Sets all adjacent columns of the same outline level to the specified
  1697. * hidden status.
  1698. *
  1699. * @param pIdx
  1700. * the col info index of the start of the outline group
  1701. * @return the column index of the last column in the outline group
  1702. */
  1703. private int setGroupHidden(int pIdx, int level, boolean hidden) {
  1704. CTCols cols = worksheet.getColsArray(0);
  1705. int idx = pIdx;
  1706. CTCol columnInfo = cols.getColArray(idx);
  1707. while (idx < cols.sizeOfColArray()) {
  1708. columnInfo.setHidden(hidden);
  1709. if (idx + 1 < cols.sizeOfColArray()) {
  1710. CTCol nextColumnInfo = cols.getColArray(idx + 1);
  1711. if (!isAdjacentBefore(columnInfo, nextColumnInfo)) {
  1712. break;
  1713. }
  1714. if (nextColumnInfo.getOutlineLevel() < level) {
  1715. break;
  1716. }
  1717. columnInfo = nextColumnInfo;
  1718. }
  1719. idx++;
  1720. }
  1721. return (int) columnInfo.getMax();
  1722. }
  1723. private boolean isAdjacentBefore(CTCol col, CTCol other_col) {
  1724. return (col.getMax() == (other_col.getMin() - 1));
  1725. }
  1726. private int findStartOfColumnOutlineGroup(int pIdx) {
  1727. // Find the start of the group.
  1728. CTCols cols = worksheet.getColsArray(0);
  1729. CTCol columnInfo = cols.getColArray(pIdx);
  1730. int level = columnInfo.getOutlineLevel();
  1731. int idx = pIdx;
  1732. while (idx != 0) {
  1733. CTCol prevColumnInfo = cols.getColArray(idx - 1);
  1734. if (!isAdjacentBefore(prevColumnInfo, columnInfo)) {
  1735. break;
  1736. }
  1737. if (prevColumnInfo.getOutlineLevel() < level) {
  1738. break;
  1739. }
  1740. idx--;
  1741. columnInfo = prevColumnInfo;
  1742. }
  1743. return idx;
  1744. }
  1745. private int findEndOfColumnOutlineGroup(int colInfoIndex) {
  1746. CTCols cols = worksheet.getColsArray(0);
  1747. // Find the end of the group.
  1748. CTCol columnInfo = cols.getColArray(colInfoIndex);
  1749. int level = columnInfo.getOutlineLevel();
  1750. int idx = colInfoIndex;
  1751. while (idx < cols.sizeOfColArray() - 1) {
  1752. CTCol nextColumnInfo = cols.getColArray(idx + 1);
  1753. if (!isAdjacentBefore(columnInfo, nextColumnInfo)) {
  1754. break;
  1755. }
  1756. if (nextColumnInfo.getOutlineLevel() < level) {
  1757. break;
  1758. }
  1759. idx++;
  1760. columnInfo = nextColumnInfo;
  1761. }
  1762. return idx;
  1763. }
  1764. private void expandColumn(int columnIndex) {
  1765. CTCols cols = worksheet.getColsArray(0);
  1766. CTCol col = columnHelper.getColumn(columnIndex, false);
  1767. int colInfoIx = columnHelper.getIndexOfColumn(cols, col);
  1768. int idx = findColInfoIdx((int) col.getMax(), colInfoIx);
  1769. if (idx == -1) {
  1770. return;
  1771. }
  1772. // If it is already expanded do nothing.
  1773. if (!isColumnGroupCollapsed(idx)) {
  1774. return;
  1775. }
  1776. // Find the start/end of the group.
  1777. int startIdx = findStartOfColumnOutlineGroup(idx);
  1778. int endIdx = findEndOfColumnOutlineGroup(idx);
  1779. // expand:
  1780. // colapsed bit must be unset
  1781. // hidden bit gets unset _if_ surrounding groups are expanded you can
  1782. // determine
  1783. // this by looking at the hidden bit of the enclosing group. You will
  1784. // have
  1785. // to look at the start and the end of the current group to determine
  1786. // which
  1787. // is the enclosing group
  1788. // hidden bit only is altered for this outline level. ie. don't
  1789. // uncollapse contained groups
  1790. CTCol columnInfo = cols.getColArray(endIdx);
  1791. if (!isColumnGroupHiddenByParent(idx)) {
  1792. int outlineLevel = columnInfo.getOutlineLevel();
  1793. boolean nestedGroup = false;
  1794. for (int i = startIdx; i <= endIdx; i++) {
  1795. CTCol ci = cols.getColArray(i);
  1796. if (outlineLevel == ci.getOutlineLevel()) {
  1797. ci.unsetHidden();
  1798. if (nestedGroup) {
  1799. nestedGroup = false;
  1800. ci.setCollapsed(true);
  1801. }
  1802. } else {
  1803. nestedGroup = true;
  1804. }
  1805. }
  1806. }
  1807. // Write collapse flag (stored in a single col info record after this
  1808. // outline group)
  1809. setColumn((int) columnInfo.getMax() + 1, null, null, null,
  1810. Boolean.FALSE, Boolean.FALSE);
  1811. }
  1812. private boolean isColumnGroupHiddenByParent(int idx) {
  1813. CTCols cols = worksheet.getColsArray(0);
  1814. // Look out outline details of end
  1815. int endLevel = 0;
  1816. boolean endHidden = false;
  1817. int endOfOutlineGroupIdx = findEndOfColumnOutlineGroup(idx);
  1818. if (endOfOutlineGroupIdx < cols.sizeOfColArray()) {
  1819. CTCol nextInfo = cols.getColArray(endOfOutlineGroupIdx + 1);
  1820. if (isAdjacentBefore(cols.getColArray(endOfOutlineGroupIdx),
  1821. nextInfo)) {
  1822. endLevel = nextInfo.getOutlineLevel();
  1823. endHidden = nextInfo.getHidden();
  1824. }
  1825. }
  1826. // Look out outline details of start
  1827. int startLevel = 0;
  1828. boolean startHidden = false;
  1829. int startOfOutlineGroupIdx = findStartOfColumnOutlineGroup(idx);
  1830. if (startOfOutlineGroupIdx > 0) {
  1831. CTCol prevInfo = cols.getColArray(startOfOutlineGroupIdx - 1);
  1832. if (isAdjacentBefore(prevInfo, cols
  1833. .getColArray(startOfOutlineGroupIdx))) {
  1834. startLevel = prevInfo.getOutlineLevel();
  1835. startHidden = prevInfo.getHidden();
  1836. }
  1837. }
  1838. if (endLevel > startLevel) {
  1839. return endHidden;
  1840. }
  1841. return startHidden;
  1842. }
  1843. private int findColInfoIdx(int columnValue, int fromColInfoIdx) {
  1844. CTCols cols = worksheet.getColsArray(0);
  1845. if (columnValue < 0) {
  1846. throw new IllegalArgumentException(
  1847. "column parameter out of range: " + columnValue);
  1848. }
  1849. if (fromColInfoIdx < 0) {
  1850. throw new IllegalArgumentException(
  1851. "fromIdx parameter out of range: " + fromColInfoIdx);
  1852. }
  1853. for (int k = fromColInfoIdx; k < cols.sizeOfColArray(); k++) {
  1854. CTCol ci = cols.getColArray(k);
  1855. if (containsColumn(ci, columnValue)) {
  1856. return k;
  1857. }
  1858. if (ci.getMin() > fromColInfoIdx) {
  1859. break;
  1860. }
  1861. }
  1862. return -1;
  1863. }
  1864. private boolean containsColumn(CTCol col, int columnIndex) {
  1865. return col.getMin() <= columnIndex && columnIndex <= col.getMax();
  1866. }
  1867. /**
  1868. * 'Collapsed' state is stored in a single column col info record
  1869. * immediately after the outline group
  1870. *
  1871. * @param idx
  1872. * @return a boolean represented if the column is collapsed
  1873. */
  1874. private boolean isColumnGroupCollapsed(int idx) {
  1875. CTCols cols = worksheet.getColsArray(0);
  1876. int endOfOutlineGroupIdx = findEndOfColumnOutlineGroup(idx);
  1877. int nextColInfoIx = endOfOutlineGroupIdx + 1;
  1878. if (nextColInfoIx >= cols.sizeOfColArray()) {
  1879. return false;
  1880. }
  1881. CTCol nextColInfo = cols.getColArray(nextColInfoIx);
  1882. CTCol col = cols.getColArray(endOfOutlineGroupIdx);
  1883. if (!isAdjacentBefore(col, nextColInfo)) {
  1884. return false;
  1885. }
  1886. return nextColInfo.getCollapsed();
  1887. }
  1888. /**
  1889. * Get the visibility state for a given column.
  1890. *
  1891. * @param columnIndex - the column to get (0-based)
  1892. * @param hidden - the visiblity state of the column
  1893. */
  1894. @Override
  1895. public void setColumnHidden(int columnIndex, boolean hidden) {
  1896. columnHelper.setColHidden(columnIndex, hidden);
  1897. }
  1898. /**
  1899. * Set the width (in units of 1/256th of a character width)
  1900. *
  1901. * <p>
  1902. * The maximum column width for an individual cell is 255 characters.
  1903. * This value represents the number of characters that can be displayed
  1904. * in a cell that is formatted with the standard font (first font in the workbook).
  1905. * </p>
  1906. *
  1907. * <p>
  1908. * Character width is defined as the maximum digit width
  1909. * of the numbers <code>0, 1, 2, ... 9</code> as rendered
  1910. * using the default font (first font in the workbook).
  1911. * <br/>
  1912. * Unless you are using a very special font, the default character is '0' (zero),
  1913. * this is true for Arial (default font font in HSSF) and Calibri (default font in XSSF)
  1914. * </p>
  1915. *
  1916. * <p>
  1917. * Please note, that the width set by this method includes 4 pixels of margin padding (two on each side),
  1918. * plus 1 pixel padding for the gridlines (Section 3.3.1.12 of the OOXML spec).
  1919. * This results is a slightly less value of visible characters than passed to this method (approx. 1/2 of a character).
  1920. * </p>
  1921. * <p>
  1922. * To compute the actual number of visible characters,
  1923. * Excel uses the following formula (Section 3.3.1.12 of the OOXML spec):
  1924. * </p>
  1925. * <code>
  1926. * width = Truncate([{Number of Visible Characters} *
  1927. * {Maximum Digit Width} + {5 pixel padding}]/{Maximum Digit Width}*256)/256
  1928. * </code>
  1929. * <p>Using the Calibri font as an example, the maximum digit width of 11 point font size is 7 pixels (at 96 dpi).
  1930. * If you set a column width to be eight characters wide, e.g. <code>setColumnWidth(columnIndex, 8*256)</code>,
  1931. * then the actual value of visible characters (the value shown in Excel) is derived from the following equation:
  1932. * <code>
  1933. Truncate([numChars*7+5]/7*256)/256 = 8;
  1934. * </code>
  1935. *
  1936. * which gives <code>7.29</code>.
  1937. *
  1938. * @param columnIndex - the column to set (0-based)
  1939. * @param width - the width in units of 1/256th of a character width
  1940. * @throws IllegalArgumentException if width > 255*256 (the maximum column width in Excel is 255 characters)
  1941. */
  1942. @Override
  1943. public void setColumnWidth(int columnIndex, int width) {
  1944. if(width > 255*256) throw new IllegalArgumentException("The maximum column width for an individual cell is 255 characters.");
  1945. columnHelper.setColWidth(columnIndex, (double)width/256);
  1946. columnHelper.setCustomWidth(columnIndex, true);
  1947. }
  1948. @Override
  1949. public void setDefaultColumnStyle(int column, CellStyle style) {
  1950. columnHelper.setColDefaultStyle(column, style);
  1951. }
  1952. /**
  1953. * Specifies the number of characters of the maximum digit width of the normal style's font.
  1954. * This value does not include margin padding or extra padding for gridlines. It is only the
  1955. * number of characters.
  1956. *
  1957. * @param width the number of characters. Default value is <code>8</code>.
  1958. */
  1959. @Override
  1960. public void setDefaultColumnWidth(int width) {
  1961. getSheetTypeSheetFormatPr().setBaseColWidth(width);
  1962. }
  1963. /**
  1964. * Set the default row height for the sheet (if the rows do not define their own height) in
  1965. * twips (1/20 of a point)
  1966. *
  1967. * @param height default row height in twips (1/20 of a point)
  1968. */
  1969. @Override
  1970. public void setDefaultRowHeight(short height) {
  1971. setDefaultRowHeightInPoints((float)height / 20);
  1972. }
  1973. /**
  1974. * Sets default row height measured in point size.
  1975. *
  1976. * @param height default row height measured in point size.
  1977. */
  1978. @Override
  1979. public void setDefaultRowHeightInPoints(float height) {
  1980. CTSheetFormatPr pr = getSheetTypeSheetFormatPr();
  1981. pr.setDefaultRowHeight(height);
  1982. pr.setCustomHeight(true);
  1983. }
  1984. /**
  1985. * Sets the flag indicating whether this sheet should display formulas.
  1986. *
  1987. * @param show <code>true</code> if this sheet should display formulas.
  1988. */
  1989. @Override
  1990. public void setDisplayFormulas(boolean show) {
  1991. getSheetTypeSheetView().setShowFormulas(show);
  1992. }
  1993. private CTSheetView getSheetTypeSheetView() {
  1994. if (getDefaultSheetView() == null) {
  1995. getSheetTypeSheetViews().setSheetViewArray(0, CTSheetView.Factory.newInstance());
  1996. }
  1997. return getDefaultSheetView();
  1998. }
  1999. /**
  2000. * Flag indicating whether the Fit to Page print option is enabled.
  2001. *
  2002. * @param b <code>true</code> if the Fit to Page print option is enabled.
  2003. */
  2004. @Override
  2005. public void setFitToPage(boolean b) {
  2006. getSheetTypePageSetUpPr().setFitToPage(b);
  2007. }
  2008. /**
  2009. * Center on page horizontally when printing.
  2010. *
  2011. * @param value whether to center on page horizontally when printing.
  2012. */
  2013. @Override
  2014. public void setHorizontallyCenter(boolean value) {
  2015. CTPrintOptions opts = worksheet.isSetPrintOptions() ?
  2016. worksheet.getPrintOptions() : worksheet.addNewPrintOptions();
  2017. opts.setHorizontalCentered(value);
  2018. }
  2019. /**
  2020. * Whether the output is vertically centered on the page.
  2021. *
  2022. * @param value true to vertically center, false otherwise.
  2023. */
  2024. @Override
  2025. public void setVerticallyCenter(boolean value) {
  2026. CTPrintOptions opts = worksheet.isSetPrintOptions() ?
  2027. worksheet.getPrintOptions() : worksheet.addNewPrintOptions();
  2028. opts.setVerticalCentered(value);
  2029. }
  2030. /**
  2031. * group the row It is possible for collapsed to be false and yet still have
  2032. * the rows in question hidden. This can be achieved by having a lower
  2033. * outline level collapsed, thus hiding all the child rows. Note that in
  2034. * this case, if the lowest level were expanded, the middle level would
  2035. * remain collapsed.
  2036. *
  2037. * @param rowIndex -
  2038. * the row involved, 0 based
  2039. * @param collapse -
  2040. * boolean value for collapse
  2041. */
  2042. @Override
  2043. public void setRowGroupCollapsed(int rowIndex, boolean collapse) {
  2044. if (collapse) {
  2045. collapseRow(rowIndex);
  2046. } else {
  2047. expandRow(rowIndex);
  2048. }
  2049. }
  2050. /**
  2051. * @param rowIndex the zero based row index to collapse
  2052. */
  2053. private void collapseRow(int rowIndex) {
  2054. XSSFRow row = getRow(rowIndex);
  2055. if (row != null) {
  2056. int startRow = findStartOfRowOutlineGroup(rowIndex);
  2057. // Hide all the columns until the end of the group
  2058. int lastRow = writeHidden(row, startRow, true);
  2059. if (getRow(lastRow) != null) {
  2060. getRow(lastRow).getCTRow().setCollapsed(true);
  2061. } else {
  2062. XSSFRow newRow = createRow(lastRow);
  2063. newRow.getCTRow().setCollapsed(true);
  2064. }
  2065. }
  2066. }
  2067. /**
  2068. * @param rowIndex the zero based row index to find from
  2069. */
  2070. private int findStartOfRowOutlineGroup(int rowIndex) {
  2071. // Find the start of the group.
  2072. int level = getRow(rowIndex).getCTRow().getOutlineLevel();
  2073. int currentRow = rowIndex;
  2074. while (getRow(currentRow) != null) {
  2075. if (getRow(currentRow).getCTRow().getOutlineLevel() < level)
  2076. return currentRow + 1;
  2077. currentRow--;
  2078. }
  2079. return currentRow;
  2080. }
  2081. private int writeHidden(XSSFRow xRow, int rowIndex, boolean hidden) {
  2082. int level = xRow.getCTRow().getOutlineLevel();
  2083. for (Iterator<Row> it = rowIterator(); it.hasNext();) {
  2084. xRow = (XSSFRow) it.next();
  2085. // skip rows before the start of this group
  2086. if(xRow.getRowNum() < rowIndex) {
  2087. continue;
  2088. }
  2089. if (xRow.getCTRow().getOutlineLevel() >= level) {
  2090. xRow.getCTRow().setHidden(hidden);
  2091. rowIndex++;
  2092. }
  2093. }
  2094. return rowIndex;
  2095. }
  2096. /**
  2097. * @param rowNumber the zero based row index to expand
  2098. */
  2099. private void expandRow(int rowNumber) {
  2100. if (rowNumber == -1)
  2101. return;
  2102. XSSFRow row = getRow(rowNumber);
  2103. // If it is already expanded do nothing.
  2104. if (!row.getCTRow().isSetHidden()) {
  2105. return;
  2106. }
  2107. // Find the start of the group.
  2108. int startIdx = findStartOfRowOutlineGroup(rowNumber);
  2109. // Find the end of the group.
  2110. int endIdx = findEndOfRowOutlineGroup(rowNumber);
  2111. // expand:
  2112. // collapsed must be unset
  2113. // hidden bit gets unset _if_ surrounding groups are expanded you can
  2114. // determine
  2115. // this by looking at the hidden bit of the enclosing group. You will
  2116. // have
  2117. // to look at the start and the end of the current group to determine
  2118. // which
  2119. // is the enclosing group
  2120. // hidden bit only is altered for this outline level. ie. don't
  2121. // un-collapse contained groups
  2122. if (!isRowGroupHiddenByParent(rowNumber)) {
  2123. for (int i = startIdx; i < endIdx; i++) {
  2124. if (row.getCTRow().getOutlineLevel() == getRow(i).getCTRow()
  2125. .getOutlineLevel()) {
  2126. getRow(i).getCTRow().unsetHidden();
  2127. } else if (!isRowGroupCollapsed(i)) {
  2128. getRow(i).getCTRow().unsetHidden();
  2129. }
  2130. }
  2131. }
  2132. // Write collapse field
  2133. CTRow ctRow = getRow(endIdx).getCTRow();
  2134. // This avoids an IndexOutOfBounds if multiple nested groups are collapsed/expanded
  2135. if(ctRow.getCollapsed()) {
  2136. ctRow.unsetCollapsed();
  2137. }
  2138. }
  2139. /**
  2140. * @param row the zero based row index to find from
  2141. */
  2142. public int findEndOfRowOutlineGroup(int row) {
  2143. int level = getRow(row).getCTRow().getOutlineLevel();
  2144. int currentRow;
  2145. for (currentRow = row; currentRow < getLastRowNum(); currentRow++) {
  2146. if (getRow(currentRow) == null
  2147. || getRow(currentRow).getCTRow().getOutlineLevel() < level) {
  2148. break;
  2149. }
  2150. }
  2151. return currentRow;
  2152. }
  2153. /**
  2154. * @param row the zero based row index to find from
  2155. */
  2156. private boolean isRowGroupHiddenByParent(int row) {
  2157. // Look out outline details of end
  2158. int endLevel;
  2159. boolean endHidden;
  2160. int endOfOutlineGroupIdx = findEndOfRowOutlineGroup(row);
  2161. if (getRow(endOfOutlineGroupIdx) == null) {
  2162. endLevel = 0;
  2163. endHidden = false;
  2164. } else {
  2165. endLevel = getRow(endOfOutlineGroupIdx).getCTRow().getOutlineLevel();
  2166. endHidden = getRow(endOfOutlineGroupIdx).getCTRow().getHidden();
  2167. }
  2168. // Look out outline details of start
  2169. int startLevel;
  2170. boolean startHidden;
  2171. int startOfOutlineGroupIdx = findStartOfRowOutlineGroup(row);
  2172. if (startOfOutlineGroupIdx < 0
  2173. || getRow(startOfOutlineGroupIdx) == null) {
  2174. startLevel = 0;
  2175. startHidden = false;
  2176. } else {
  2177. startLevel = getRow(startOfOutlineGroupIdx).getCTRow()
  2178. .getOutlineLevel();
  2179. startHidden = getRow(startOfOutlineGroupIdx).getCTRow()
  2180. .getHidden();
  2181. }
  2182. if (endLevel > startLevel) {
  2183. return endHidden;
  2184. }
  2185. return startHidden;
  2186. }
  2187. /**
  2188. * @param row the zero based row index to find from
  2189. */
  2190. private boolean isRowGroupCollapsed(int row) {
  2191. int collapseRow = findEndOfRowOutlineGroup(row) + 1;
  2192. if (getRow(collapseRow) == null) {
  2193. return false;
  2194. }
  2195. return getRow(collapseRow).getCTRow().getCollapsed();
  2196. }
  2197. /**
  2198. * Sets the zoom magnication for the sheet. The zoom is expressed as a
  2199. * fraction. For example to express a zoom of 75% use 3 for the numerator
  2200. * and 4 for the denominator.
  2201. *
  2202. * @param numerator The numerator for the zoom magnification.
  2203. * @param denominator The denominator for the zoom magnification.
  2204. * @see #setZoom(int)
  2205. */
  2206. @Override
  2207. public void setZoom(int numerator, int denominator) {
  2208. int zoom = 100*numerator/denominator;
  2209. setZoom(zoom);
  2210. }
  2211. /**
  2212. * Window zoom magnification for current view representing percent values.
  2213. * Valid values range from 10 to 400. Horizontal & Vertical scale together.
  2214. *
  2215. * For example:
  2216. * <pre>
  2217. * 10 - 10%
  2218. * 20 - 20%
  2219. * ...
  2220. * 100 - 100%
  2221. * ...
  2222. * 400 - 400%
  2223. * </pre>
  2224. *
  2225. * Current view can be Normal, Page Layout, or Page Break Preview.
  2226. *
  2227. * @param scale window zoom magnification
  2228. * @throws IllegalArgumentException if scale is invalid
  2229. */
  2230. public void setZoom(int scale) {
  2231. if(scale < 10 || scale > 400) throw new IllegalArgumentException("Valid scale values range from 10 to 400");
  2232. getSheetTypeSheetView().setZoomScale(scale);
  2233. }
  2234. /**
  2235. * Shifts rows between startRow and endRow n number of rows.
  2236. * If you use a negative number, it will shift rows up.
  2237. * Code ensures that rows don't wrap around.
  2238. *
  2239. * Calls shiftRows(startRow, endRow, n, false, false);
  2240. *
  2241. * <p>
  2242. * Additionally shifts merged regions that are completely defined in these
  2243. * rows (ie. merged 2 cells on a row to be shifted).
  2244. * @param startRow the row to start shifting
  2245. * @param endRow the row to end shifting
  2246. * @param n the number of rows to shift
  2247. */
  2248. @Override
  2249. public void shiftRows(int startRow, int endRow, int n) {
  2250. shiftRows(startRow, endRow, n, false, false);
  2251. }
  2252. /**
  2253. * Shifts rows between startRow and endRow n number of rows.
  2254. * If you use a negative number, it will shift rows up.
  2255. * Code ensures that rows don't wrap around
  2256. *
  2257. * <p>
  2258. * Additionally shifts merged regions that are completely defined in these
  2259. * rows (ie. merged 2 cells on a row to be shifted).
  2260. * <p>
  2261. * @param startRow the row to start shifting
  2262. * @param endRow the row to end shifting
  2263. * @param n the number of rows to shift
  2264. * @param copyRowHeight whether to copy the row height during the shift
  2265. * @param resetOriginalRowHeight whether to set the original row's height to the default
  2266. */
  2267. @Override
  2268. @SuppressWarnings("deprecation") //YK: getXYZArray() array accessors are deprecated in xmlbeans with JDK 1.5 support
  2269. public void shiftRows(int startRow, int endRow, int n, boolean copyRowHeight, boolean resetOriginalRowHeight) {
  2270. // first remove all rows which will be overwritten
  2271. for (Iterator<Row> it = rowIterator() ; it.hasNext() ; ) {
  2272. XSSFRow row = (XSSFRow)it.next();
  2273. int rownum = row.getRowNum();
  2274. // check if we should remove this row as it will be overwritten by the data later
  2275. if (removeRow(startRow, endRow, n, rownum)) {
  2276. // remove row from worksheet.getSheetData row array
  2277. int idx = _rows.headMap(row.getRowNum()).size();
  2278. worksheet.getSheetData().removeRow(idx);
  2279. // remove row from _rows
  2280. it.remove();
  2281. }
  2282. }
  2283. // then do the actual moving and also adjust comments/rowHeight
  2284. for (Iterator<Row> it = rowIterator() ; it.hasNext() ; ) {
  2285. XSSFRow row = (XSSFRow)it.next();
  2286. int rownum = row.getRowNum();
  2287. if(sheetComments != null){
  2288. //TODO shift Note's anchor in the associated /xl/drawing/vmlDrawings#.vml
  2289. CTCommentList lst = sheetComments.getCTComments().getCommentList();
  2290. for (CTComment comment : lst.getCommentArray()) {
  2291. String oldRef = comment.getRef();
  2292. CellReference ref = new CellReference(oldRef);
  2293. if(ref.getRow() == rownum){
  2294. ref = new CellReference(rownum + n, ref.getCol());
  2295. comment.setRef(ref.formatAsString());
  2296. sheetComments.referenceUpdated(oldRef, comment);
  2297. }
  2298. }
  2299. }
  2300. if(rownum < startRow || rownum > endRow) continue;
  2301. if (!copyRowHeight) {
  2302. row.setHeight((short)-1);
  2303. }
  2304. row.shift(n);
  2305. }
  2306. XSSFRowShifter rowShifter = new XSSFRowShifter(this);
  2307. int sheetIndex = getWorkbook().getSheetIndex(this);
  2308. String sheetName = getWorkbook().getSheetName(sheetIndex);
  2309. FormulaShifter shifter = FormulaShifter.createForRowShift(
  2310. sheetIndex, sheetName, startRow, endRow, n);
  2311. rowShifter.updateNamedRanges(shifter);
  2312. rowShifter.updateFormulas(shifter);
  2313. rowShifter.shiftMerged(startRow, endRow, n);
  2314. rowShifter.updateConditionalFormatting(shifter);
  2315. //rebuild the _rows map
  2316. TreeMap<Integer, XSSFRow> map = new TreeMap<Integer, XSSFRow>();
  2317. for(XSSFRow r : _rows.values()) {
  2318. map.put(r.getRowNum(), r);
  2319. }
  2320. _rows = map;
  2321. }
  2322. /**
  2323. * Location of the top left visible cell Location of the top left visible cell in the bottom right
  2324. * pane (when in Left-to-Right mode).
  2325. *
  2326. * @param toprow the top row to show in desktop window pane
  2327. * @param leftcol the left column to show in desktop window pane
  2328. */
  2329. @Override
  2330. public void showInPane(int toprow, int leftcol) {
  2331. CellReference cellReference = new CellReference(toprow, leftcol);
  2332. String cellRef = cellReference.formatAsString();
  2333. getPane().setTopLeftCell(cellRef);
  2334. }
  2335. /**
  2336. * Location of the top left visible cell Location of the top left visible cell in the bottom right
  2337. * pane (when in Left-to-Right mode).
  2338. *
  2339. * @param toprow the top row to show in desktop window pane
  2340. * @param leftcol the left column to show in desktop window pane
  2341. *
  2342. * @deprecated Use {@link #showInPane(int, int)} as there can be more than 32767 rows.
  2343. */
  2344. @Override
  2345. @Deprecated
  2346. public void showInPane(short toprow, short leftcol) {
  2347. showInPane((int)toprow, (int)leftcol);
  2348. }
  2349. @Override
  2350. public void ungroupColumn(int fromColumn, int toColumn) {
  2351. CTCols cols = worksheet.getColsArray(0);
  2352. for (int index = fromColumn; index <= toColumn; index++) {
  2353. CTCol col = columnHelper.getColumn(index, false);
  2354. if (col != null) {
  2355. short outlineLevel = col.getOutlineLevel();
  2356. col.setOutlineLevel((short) (outlineLevel - 1));
  2357. index = (int) col.getMax();
  2358. if (col.getOutlineLevel() <= 0) {
  2359. int colIndex = columnHelper.getIndexOfColumn(cols, col);
  2360. worksheet.getColsArray(0).removeCol(colIndex);
  2361. }
  2362. }
  2363. }
  2364. worksheet.setColsArray(0, cols);
  2365. setSheetFormatPrOutlineLevelCol();
  2366. }
  2367. /**
  2368. * Ungroup a range of rows that were previously groupped
  2369. *
  2370. * @param fromRow start row (0-based)
  2371. * @param toRow end row (0-based)
  2372. */
  2373. @Override
  2374. public void ungroupRow(int fromRow, int toRow) {
  2375. for (int i = fromRow; i <= toRow; i++) {
  2376. XSSFRow xrow = getRow(i);
  2377. if (xrow != null) {
  2378. CTRow ctrow = xrow.getCTRow();
  2379. short outlinelevel = ctrow.getOutlineLevel();
  2380. ctrow.setOutlineLevel((short) (outlinelevel - 1));
  2381. //remove a row only if the row has no cell and if the outline level is 0
  2382. if (ctrow.getOutlineLevel() == 0 && xrow.getFirstCellNum() == -1) {
  2383. removeRow(xrow);
  2384. }
  2385. }
  2386. }
  2387. setSheetFormatPrOutlineLevelRow();
  2388. }
  2389. private void setSheetFormatPrOutlineLevelRow(){
  2390. short maxLevelRow=getMaxOutlineLevelRows();
  2391. getSheetTypeSheetFormatPr().setOutlineLevelRow(maxLevelRow);
  2392. }
  2393. private void setSheetFormatPrOutlineLevelCol(){
  2394. short maxLevelCol=getMaxOutlineLevelCols();
  2395. getSheetTypeSheetFormatPr().setOutlineLevelCol(maxLevelCol);
  2396. }
  2397. private CTSheetViews getSheetTypeSheetViews() {
  2398. if (worksheet.getSheetViews() == null) {
  2399. worksheet.setSheetViews(CTSheetViews.Factory.newInstance());
  2400. worksheet.getSheetViews().addNewSheetView();
  2401. }
  2402. return worksheet.getSheetViews();
  2403. }
  2404. /**
  2405. * Returns a flag indicating whether this sheet is selected.
  2406. * <p>
  2407. * When only 1 sheet is selected and active, this value should be in synch with the activeTab value.
  2408. * In case of a conflict, the Start Part setting wins and sets the active sheet tab.
  2409. * </p>
  2410. * Note: multiple sheets can be selected, but only one sheet can be active at one time.
  2411. *
  2412. * @return <code>true</code> if this sheet is selected
  2413. */
  2414. @Override
  2415. public boolean isSelected() {
  2416. CTSheetView view = getDefaultSheetView();
  2417. return view != null && view.getTabSelected();
  2418. }
  2419. /**
  2420. * Sets a flag indicating whether this sheet is selected.
  2421. *
  2422. * <p>
  2423. * When only 1 sheet is selected and active, this value should be in synch with the activeTab value.
  2424. * In case of a conflict, the Start Part setting wins and sets the active sheet tab.
  2425. * </p>
  2426. * Note: multiple sheets can be selected, but only one sheet can be active at one time.
  2427. *
  2428. * @param value <code>true</code> if this sheet is selected
  2429. */
  2430. @Override
  2431. @SuppressWarnings("deprecation") //YK: getXYZArray() array accessors are deprecated in xmlbeans with JDK 1.5 support
  2432. public void setSelected(boolean value) {
  2433. CTSheetViews views = getSheetTypeSheetViews();
  2434. for (CTSheetView view : views.getSheetViewArray()) {
  2435. view.setTabSelected(value);
  2436. }
  2437. }
  2438. /**
  2439. * Assign a cell comment to a cell region in this worksheet
  2440. *
  2441. * @param cellRef cell region
  2442. * @param comment the comment to assign
  2443. * @deprecated since Nov 2009 use {@link XSSFCell#setCellComment(org.apache.poi.ss.usermodel.Comment)} instead
  2444. */
  2445. @Deprecated
  2446. public static void setCellComment(String cellRef, XSSFComment comment) {
  2447. CellReference cellReference = new CellReference(cellRef);
  2448. comment.setRow(cellReference.getRow());
  2449. comment.setColumn(cellReference.getCol());
  2450. }
  2451. /**
  2452. * Register a hyperlink in the collection of hyperlinks on this sheet
  2453. *
  2454. * @param hyperlink the link to add
  2455. */
  2456. @Internal
  2457. public void addHyperlink(XSSFHyperlink hyperlink) {
  2458. hyperlinks.add(hyperlink);
  2459. }
  2460. /**
  2461. * Return location of the active cell, e.g. <code>A1</code>.
  2462. *
  2463. * @return the location of the active cell.
  2464. */
  2465. public String getActiveCell() {
  2466. return getSheetTypeSelection().getActiveCell();
  2467. }
  2468. /**
  2469. * Sets location of the active cell
  2470. *
  2471. * @param cellRef the location of the active cell, e.g. <code>A1</code>..
  2472. */
  2473. public void setActiveCell(String cellRef) {
  2474. CTSelection ctsel = getSheetTypeSelection();
  2475. ctsel.setActiveCell(cellRef);
  2476. ctsel.setSqref(Arrays.asList(cellRef));
  2477. }
  2478. /**
  2479. * Does this sheet have any comments on it? We need to know,
  2480. * so we can decide about writing it to disk or not
  2481. */
  2482. public boolean hasComments() {
  2483. if(sheetComments == null) { return false; }
  2484. return (sheetComments.getNumberOfComments() > 0);
  2485. }
  2486. protected int getNumberOfComments() {
  2487. if(sheetComments == null) { return 0; }
  2488. return sheetComments.getNumberOfComments();
  2489. }
  2490. private CTSelection getSheetTypeSelection() {
  2491. if (getSheetTypeSheetView().sizeOfSelectionArray() == 0) {
  2492. getSheetTypeSheetView().insertNewSelection(0);
  2493. }
  2494. return getSheetTypeSheetView().getSelectionArray(0);
  2495. }
  2496. /**
  2497. * Return the default sheet view. This is the last one if the sheet's views, according to sec. 3.3.1.83
  2498. * of the OOXML spec: "A single sheet view definition. When more than 1 sheet view is defined in the file,
  2499. * it means that when opening the workbook, each sheet view corresponds to a separate window within the
  2500. * spreadsheet application, where each window is showing the particular sheet. containing the same
  2501. * workbookViewId value, the last sheetView definition is loaded, and the others are discarded.
  2502. * When multiple windows are viewing the same sheet, multiple sheetView elements (with corresponding
  2503. * workbookView entries) are saved."
  2504. */
  2505. private CTSheetView getDefaultSheetView() {
  2506. CTSheetViews views = getSheetTypeSheetViews();
  2507. int sz = views == null ? 0 : views.sizeOfSheetViewArray();
  2508. if (sz == 0) {
  2509. return null;
  2510. }
  2511. return views.getSheetViewArray(sz - 1);
  2512. }
  2513. /**
  2514. * Returns the sheet's comments object if there is one,
  2515. * or null if not
  2516. *
  2517. * @param create create a new comments table if it does not exist
  2518. */
  2519. protected CommentsTable getCommentsTable(boolean create) {
  2520. if(sheetComments == null && create){
  2521. // Try to create a comments table with the same number as
  2522. // the sheet has (i.e. sheet 1 -> comments 1)
  2523. try {
  2524. sheetComments = (CommentsTable)createRelationship(
  2525. XSSFRelation.SHEET_COMMENTS, XSSFFactory.getInstance(), (int)sheet.getSheetId());
  2526. } catch(PartAlreadyExistsException e) {
  2527. // Technically a sheet doesn't need the same number as
  2528. // it's comments, and clearly someone has already pinched
  2529. // our number! Go for the next available one instead
  2530. sheetComments = (CommentsTable)createRelationship(
  2531. XSSFRelation.SHEET_COMMENTS, XSSFFactory.getInstance(), -1);
  2532. }
  2533. }
  2534. return sheetComments;
  2535. }
  2536. private CTPageSetUpPr getSheetTypePageSetUpPr() {
  2537. CTSheetPr sheetPr = getSheetTypeSheetPr();
  2538. return sheetPr.isSetPageSetUpPr() ? sheetPr.getPageSetUpPr() : sheetPr.addNewPageSetUpPr();
  2539. }
  2540. private boolean removeRow(int startRow, int endRow, int n, int rownum) {
  2541. // is this row in the target-window where the moved rows will land?
  2542. if (rownum >= (startRow + n) && rownum <= (endRow + n)) {
  2543. // only remove it if the current row is not part of the data that is copied
  2544. if (n > 0 && rownum > endRow) {
  2545. return true;
  2546. }
  2547. else if (n < 0 && rownum < startRow) {
  2548. return true;
  2549. }
  2550. }
  2551. return false;
  2552. }
  2553. private CTPane getPane() {
  2554. if (getDefaultSheetView().getPane() == null) {
  2555. getDefaultSheetView().addNewPane();
  2556. }
  2557. return getDefaultSheetView().getPane();
  2558. }
  2559. /**
  2560. * Return a master shared formula by index
  2561. *
  2562. * @param sid shared group index
  2563. * @return a CTCellFormula bean holding shared formula or <code>null</code> if not found
  2564. */
  2565. @Internal
  2566. public CTCellFormula getSharedFormula(int sid){
  2567. return sharedFormulas.get(sid);
  2568. }
  2569. void onReadCell(XSSFCell cell){
  2570. //collect cells holding shared formulas
  2571. CTCell ct = cell.getCTCell();
  2572. CTCellFormula f = ct.getF();
  2573. if (f != null && f.getT() == STCellFormulaType.SHARED && f.isSetRef() && f.getStringValue() != null) {
  2574. // save a detached copy to avoid XmlValueDisconnectedException,
  2575. // this may happen when the master cell of a shared formula is changed
  2576. CTCellFormula sf = (CTCellFormula)f.copy();
  2577. CellRangeAddress sfRef = CellRangeAddress.valueOf(sf.getRef());
  2578. CellReference cellRef = new CellReference(cell);
  2579. // If the shared formula range preceeds the master cell then the preceding part is discarded, e.g.
  2580. // if the cell is E60 and the shared formula range is C60:M85 then the effective range is E60:M85
  2581. // see more details in https://issues.apache.org/bugzilla/show_bug.cgi?id=51710
  2582. if(cellRef.getCol() > sfRef.getFirstColumn() || cellRef.getRow() > sfRef.getFirstRow()){
  2583. String effectiveRef = new CellRangeAddress(
  2584. Math.max(cellRef.getRow(), sfRef.getFirstRow()), sfRef.getLastRow(),
  2585. Math.max(cellRef.getCol(), sfRef.getFirstColumn()), sfRef.getLastColumn()).formatAsString();
  2586. sf.setRef(effectiveRef);
  2587. }
  2588. sharedFormulas.put((int)f.getSi(), sf);
  2589. }
  2590. if (f != null && f.getT() == STCellFormulaType.ARRAY && f.getRef() != null) {
  2591. arrayFormulas.add(CellRangeAddress.valueOf(f.getRef()));
  2592. }
  2593. }
  2594. @Override
  2595. protected void commit() throws IOException {
  2596. PackagePart part = getPackagePart();
  2597. OutputStream out = part.getOutputStream();
  2598. write(out);
  2599. out.close();
  2600. }
  2601. protected void write(OutputStream out) throws IOException {
  2602. boolean setToNull = false;
  2603. if(worksheet.sizeOfColsArray() == 1) {
  2604. CTCols col = worksheet.getColsArray(0);
  2605. if(col.sizeOfColArray() == 0) {
  2606. setToNull = true;
  2607. // this is necessary so that we do not write an empty <cols/> item into the sheet-xml in the xlsx-file
  2608. // Excel complains about a corrupted file if this shows up there!
  2609. worksheet.setColsArray(null);
  2610. } else {
  2611. setColWidthAttribute(col);
  2612. }
  2613. }
  2614. // Now re-generate our CTHyperlinks, if needed
  2615. if(hyperlinks.size() > 0) {
  2616. if(worksheet.getHyperlinks() == null) {
  2617. worksheet.addNewHyperlinks();
  2618. }
  2619. CTHyperlink[] ctHls = new CTHyperlink[hyperlinks.size()];
  2620. for(int i=0; i<ctHls.length; i++) {
  2621. // If our sheet has hyperlinks, have them add
  2622. // any relationships that they might need
  2623. XSSFHyperlink hyperlink = hyperlinks.get(i);
  2624. hyperlink.generateRelationIfNeeded(getPackagePart());
  2625. // Now grab their underling object
  2626. ctHls[i] = hyperlink.getCTHyperlink();
  2627. }
  2628. worksheet.getHyperlinks().setHyperlinkArray(ctHls);
  2629. }
  2630. for(XSSFRow row : _rows.values()){
  2631. row.onDocumentWrite();
  2632. }
  2633. XmlOptions xmlOptions = new XmlOptions(DEFAULT_XML_OPTIONS);
  2634. xmlOptions.setSaveSyntheticDocumentElement(new QName(CTWorksheet.type.getName().getNamespaceURI(), "worksheet"));
  2635. Map<String, String> map = new HashMap<String, String>();
  2636. map.put(STRelationshipId.type.getName().getNamespaceURI(), "r");
  2637. xmlOptions.setSaveSuggestedPrefixes(map);
  2638. worksheet.save(out, xmlOptions);
  2639. // Bug 52233: Ensure that we have a col-array even if write() removed it
  2640. if(setToNull) {
  2641. worksheet.addNewCols();
  2642. }
  2643. }
  2644. /**
  2645. * @return true when Autofilters are locked and the sheet is protected.
  2646. */
  2647. public boolean isAutoFilterLocked() {
  2648. if (isSheetLocked()) {
  2649. return safeGetProtectionField().getAutoFilter();
  2650. }
  2651. return false;
  2652. }
  2653. /**
  2654. * @return true when Deleting columns is locked and the sheet is protected.
  2655. */
  2656. public boolean isDeleteColumnsLocked() {
  2657. if (isSheetLocked()) {
  2658. return safeGetProtectionField().getDeleteColumns();
  2659. }
  2660. return false;
  2661. }
  2662. /**
  2663. * @return true when Deleting rows is locked and the sheet is protected.
  2664. */
  2665. public boolean isDeleteRowsLocked() {
  2666. if (isSheetLocked()) {
  2667. return safeGetProtectionField().getDeleteRows();
  2668. }
  2669. return false;
  2670. }
  2671. /**
  2672. * @return true when Formatting cells is locked and the sheet is protected.
  2673. */
  2674. public boolean isFormatCellsLocked() {
  2675. if (isSheetLocked()) {
  2676. return safeGetProtectionField().getFormatCells();
  2677. }
  2678. return false;
  2679. }
  2680. /**
  2681. * @return true when Formatting columns is locked and the sheet is protected.
  2682. */
  2683. public boolean isFormatColumnsLocked() {
  2684. if (isSheetLocked()) {
  2685. return safeGetProtectionField().getFormatColumns();
  2686. }
  2687. return false;
  2688. }
  2689. /**
  2690. * @return true when Formatting rows is locked and the sheet is protected.
  2691. */
  2692. public boolean isFormatRowsLocked() {
  2693. if (isSheetLocked()) {
  2694. return safeGetProtectionField().getFormatRows();
  2695. }
  2696. return false;
  2697. }
  2698. /**
  2699. * @return true when Inserting columns is locked and the sheet is protected.
  2700. */
  2701. public boolean isInsertColumnsLocked() {
  2702. if (isSheetLocked()) {
  2703. return safeGetProtectionField().getInsertColumns();
  2704. }
  2705. return false;
  2706. }
  2707. /**
  2708. * @return true when Inserting hyperlinks is locked and the sheet is protected.
  2709. */
  2710. public boolean isInsertHyperlinksLocked() {
  2711. if (isSheetLocked()) {
  2712. return safeGetProtectionField().getInsertHyperlinks();
  2713. }
  2714. return false;
  2715. }
  2716. /**
  2717. * @return true when Inserting rows is locked and the sheet is protected.
  2718. */
  2719. public boolean isInsertRowsLocked() {
  2720. if (isSheetLocked()) {
  2721. return safeGetProtectionField().getInsertRows();
  2722. }
  2723. return false;
  2724. }
  2725. /**
  2726. * @return true when Pivot tables are locked and the sheet is protected.
  2727. */
  2728. public boolean isPivotTablesLocked() {
  2729. if (isSheetLocked()) {
  2730. return safeGetProtectionField().getPivotTables();
  2731. }
  2732. return false;
  2733. }
  2734. /**
  2735. * @return true when Sorting is locked and the sheet is protected.
  2736. */
  2737. public boolean isSortLocked() {
  2738. if (isSheetLocked()) {
  2739. return safeGetProtectionField().getSort();
  2740. }
  2741. return false;
  2742. }
  2743. /**
  2744. * @return true when Objects are locked and the sheet is protected.
  2745. */
  2746. public boolean isObjectsLocked() {
  2747. if (isSheetLocked()) {
  2748. return safeGetProtectionField().getObjects();
  2749. }
  2750. return false;
  2751. }
  2752. /**
  2753. * @return true when Scenarios are locked and the sheet is protected.
  2754. */
  2755. public boolean isScenariosLocked() {
  2756. if (isSheetLocked()) {
  2757. return safeGetProtectionField().getScenarios();
  2758. }
  2759. return false;
  2760. }
  2761. /**
  2762. * @return true when Selection of locked cells is locked and the sheet is protected.
  2763. */
  2764. public boolean isSelectLockedCellsLocked() {
  2765. if (isSheetLocked()) {
  2766. return safeGetProtectionField().getSelectLockedCells();
  2767. }
  2768. return false;
  2769. }
  2770. /**
  2771. * @return true when Selection of unlocked cells is locked and the sheet is protected.
  2772. */
  2773. public boolean isSelectUnlockedCellsLocked() {
  2774. if (isSheetLocked()) {
  2775. return safeGetProtectionField().getSelectUnlockedCells();
  2776. }
  2777. return false;
  2778. }
  2779. /**
  2780. * @return true when Sheet is Protected.
  2781. */
  2782. public boolean isSheetLocked() {
  2783. if (worksheet.isSetSheetProtection()) {
  2784. return safeGetProtectionField().getSheet();
  2785. }
  2786. return false;
  2787. }
  2788. /**
  2789. * Enable sheet protection
  2790. */
  2791. public void enableLocking() {
  2792. safeGetProtectionField().setSheet(true);
  2793. }
  2794. /**
  2795. * Disable sheet protection
  2796. */
  2797. public void disableLocking() {
  2798. safeGetProtectionField().setSheet(false);
  2799. }
  2800. /**
  2801. * Enable Autofilters locking.
  2802. * @deprecated use {@link #lockAutoFilter(boolean)}
  2803. */
  2804. public void lockAutoFilter() {
  2805. lockAutoFilter(true);
  2806. }
  2807. /**
  2808. * Enable or disable Autofilters locking.
  2809. * This does not modify sheet protection status.
  2810. * To enforce this un-/locking, call {@link #disableLocking()} or {@link #enableLocking()}
  2811. */
  2812. public void lockAutoFilter(boolean enabled) {
  2813. safeGetProtectionField().setAutoFilter(enabled);
  2814. }
  2815. /**
  2816. * Enable Deleting columns locking.
  2817. * @deprecated use {@link #lockDeleteColumns(boolean)}
  2818. */
  2819. public void lockDeleteColumns() {
  2820. lockDeleteColumns(true);
  2821. }
  2822. /**
  2823. * Enable or disable Deleting columns locking.
  2824. * This does not modify sheet protection status.
  2825. * To enforce this un-/locking, call {@link #disableLocking()} or {@link #enableLocking()}
  2826. */
  2827. public void lockDeleteColumns(boolean enabled) {
  2828. safeGetProtectionField().setDeleteColumns(enabled);
  2829. }
  2830. /**
  2831. * Enable Deleting rows locking.
  2832. * @deprecated use {@link #lockDeleteRows(boolean)}
  2833. */
  2834. public void lockDeleteRows() {
  2835. lockDeleteRows(true);
  2836. }
  2837. /**
  2838. * Enable or disable Deleting rows locking.
  2839. * This does not modify sheet protection status.
  2840. * To enforce this un-/locking, call {@link #disableLocking()} or {@link #enableLocking()}
  2841. */
  2842. public void lockDeleteRows(boolean enabled) {
  2843. safeGetProtectionField().setDeleteRows(enabled);
  2844. }
  2845. /**
  2846. * Enable Formatting cells locking.
  2847. * @deprecated use {@link #lockFormatCells(boolean)}
  2848. */
  2849. public void lockFormatCells() {
  2850. lockFormatCells(true);
  2851. }
  2852. /**
  2853. * Enable or disable Formatting cells locking.
  2854. * This does not modify sheet protection status.
  2855. * To enforce this un-/locking, call {@link #disableLocking()} or {@link #enableLocking()}
  2856. */
  2857. public void lockFormatCells(boolean enabled) {
  2858. safeGetProtectionField().setFormatCells(enabled);
  2859. }
  2860. /**
  2861. * Enable Formatting columns locking.
  2862. * @deprecated use {@link #lockFormatColumns(boolean)}
  2863. */
  2864. public void lockFormatColumns() {
  2865. lockFormatColumns(true);
  2866. }
  2867. /**
  2868. * Enable or disable Formatting columns locking.
  2869. * This does not modify sheet protection status.
  2870. * To enforce this un-/locking, call {@link #disableLocking()} or {@link #enableLocking()}
  2871. */
  2872. public void lockFormatColumns(boolean enabled) {
  2873. safeGetProtectionField().setFormatColumns(enabled);
  2874. }
  2875. /**
  2876. * Enable Formatting rows locking.
  2877. * @deprecated use {@link #lockFormatRows(boolean)}
  2878. */
  2879. public void lockFormatRows() {
  2880. lockFormatRows(true);
  2881. }
  2882. /**
  2883. * Enable or disable Formatting rows locking.
  2884. * This does not modify sheet protection status.
  2885. * To enforce this un-/locking, call {@link #disableLocking()} or {@link #enableLocking()}
  2886. */
  2887. public void lockFormatRows(boolean enabled) {
  2888. safeGetProtectionField().setFormatRows(enabled);
  2889. }
  2890. /**
  2891. * Enable Inserting columns locking.
  2892. * @deprecated use {@link #lockInsertColumns(boolean)}
  2893. */
  2894. public void lockInsertColumns() {
  2895. lockInsertColumns(true);
  2896. }
  2897. /**
  2898. * Enable or disable Inserting columns locking.
  2899. * This does not modify sheet protection status.
  2900. * To enforce this un-/locking, call {@link #disableLocking()} or {@link #enableLocking()}
  2901. */
  2902. public void lockInsertColumns(boolean enabled) {
  2903. safeGetProtectionField().setInsertColumns(enabled);
  2904. }
  2905. /**
  2906. * Enable Inserting hyperlinks locking.
  2907. * @deprecated use {@link #lockInsertHyperlinks(boolean)}
  2908. */
  2909. public void lockInsertHyperlinks() {
  2910. lockInsertHyperlinks(true);
  2911. }
  2912. /**
  2913. * Enable or disable Inserting hyperlinks locking.
  2914. * This does not modify sheet protection status.
  2915. * To enforce this un-/locking, call {@link #disableLocking()} or {@link #enableLocking()}
  2916. */
  2917. public void lockInsertHyperlinks(boolean enabled) {
  2918. safeGetProtectionField().setInsertHyperlinks(enabled);
  2919. }
  2920. /**
  2921. * Enable Inserting rows locking.
  2922. * @deprecated use {@link #lockInsertRows(boolean)}
  2923. */
  2924. public void lockInsertRows() {
  2925. lockInsertRows(true);
  2926. }
  2927. /**
  2928. * Enable or disable Inserting rows locking.
  2929. * This does not modify sheet protection status.
  2930. * To enforce this un-/locking, call {@link #disableLocking()} or {@link #enableLocking()}
  2931. */
  2932. public void lockInsertRows(boolean enabled) {
  2933. safeGetProtectionField().setInsertRows(enabled);
  2934. }
  2935. /**
  2936. * Enable Pivot Tables locking.
  2937. * @deprecated use {@link #lockPivotTables(boolean)}
  2938. */
  2939. public void lockPivotTables() {
  2940. lockPivotTables(true);
  2941. }
  2942. /**
  2943. * Enable or disable Pivot Tables locking.
  2944. * This does not modify sheet protection status.
  2945. * To enforce this un-/locking, call {@link #disableLocking()} or {@link #enableLocking()}
  2946. */
  2947. public void lockPivotTables(boolean enabled) {
  2948. safeGetProtectionField().setPivotTables(enabled);
  2949. }
  2950. /**
  2951. * Enable Sort locking.
  2952. * @deprecated use {@link #lockSort(boolean)}
  2953. */
  2954. public void lockSort() {
  2955. lockSort(true);
  2956. }
  2957. /**
  2958. * Enable or disable Sort locking.
  2959. * This does not modify sheet protection status.
  2960. * To enforce this un-/locking, call {@link #disableLocking()} or {@link #enableLocking()}
  2961. */
  2962. public void lockSort(boolean enabled) {
  2963. safeGetProtectionField().setSort(enabled);
  2964. }
  2965. /**
  2966. * Enable Objects locking.
  2967. * @deprecated use {@link #lockObjects(boolean)}
  2968. */
  2969. public void lockObjects() {
  2970. lockObjects(true);
  2971. }
  2972. /**
  2973. * Enable or disable Objects locking.
  2974. * This does not modify sheet protection status.
  2975. * To enforce this un-/locking, call {@link #disableLocking()} or {@link #enableLocking()}
  2976. */
  2977. public void lockObjects(boolean enabled) {
  2978. safeGetProtectionField().setObjects(enabled);
  2979. }
  2980. /**
  2981. * Enable Scenarios locking.
  2982. * @deprecated use {@link #lockScenarios(boolean)}
  2983. */
  2984. public void lockScenarios() {
  2985. lockScenarios(true);
  2986. }
  2987. /**
  2988. * Enable or disable Scenarios locking.
  2989. * This does not modify sheet protection status.
  2990. * To enforce this un-/locking, call {@link #disableLocking()} or {@link #enableLocking()}
  2991. */
  2992. public void lockScenarios(boolean enabled) {
  2993. safeGetProtectionField().setScenarios(enabled);
  2994. }
  2995. /**
  2996. * Enable Selection of locked cells locking.
  2997. * @deprecated use {@link #lockSelectLockedCells(boolean)}
  2998. */
  2999. public void lockSelectLockedCells() {
  3000. lockSelectLockedCells(true);
  3001. }
  3002. /**
  3003. * Enable or disable Selection of locked cells locking.
  3004. * This does not modify sheet protection status.
  3005. * To enforce this un-/locking, call {@link #disableLocking()} or {@link #enableLocking()}
  3006. */
  3007. public void lockSelectLockedCells(boolean enabled) {
  3008. safeGetProtectionField().setSelectLockedCells(enabled);
  3009. }
  3010. /**
  3011. * Enable Selection of unlocked cells locking.
  3012. * @deprecated use {@link #lockSelectUnlockedCells(boolean)}
  3013. */
  3014. public void lockSelectUnlockedCells() {
  3015. lockSelectUnlockedCells(true);
  3016. }
  3017. /**
  3018. * Enable or disable Selection of unlocked cells locking.
  3019. * This does not modify sheet protection status.
  3020. * To enforce this un-/locking, call {@link #disableLocking()} or {@link #enableLocking()}
  3021. */
  3022. public void lockSelectUnlockedCells(boolean enabled) {
  3023. safeGetProtectionField().setSelectUnlockedCells(enabled);
  3024. }
  3025. private CTSheetProtection safeGetProtectionField() {
  3026. if (!isSheetProtectionEnabled()) {
  3027. return worksheet.addNewSheetProtection();
  3028. }
  3029. return worksheet.getSheetProtection();
  3030. }
  3031. /* package */ boolean isSheetProtectionEnabled() {
  3032. return (worksheet.isSetSheetProtection());
  3033. }
  3034. /* package */ boolean isCellInArrayFormulaContext(XSSFCell cell) {
  3035. for (CellRangeAddress range : arrayFormulas) {
  3036. if (range.isInRange(cell.getRowIndex(), cell.getColumnIndex())) {
  3037. return true;
  3038. }
  3039. }
  3040. return false;
  3041. }
  3042. /* package */ XSSFCell getFirstCellInArrayFormula(XSSFCell cell) {
  3043. for (CellRangeAddress range : arrayFormulas) {
  3044. if (range.isInRange(cell.getRowIndex(), cell.getColumnIndex())) {
  3045. return getRow(range.getFirstRow()).getCell(range.getFirstColumn());
  3046. }
  3047. }
  3048. return null;
  3049. }
  3050. /**
  3051. * Also creates cells if they don't exist
  3052. */
  3053. private CellRange<XSSFCell> getCellRange(CellRangeAddress range) {
  3054. int firstRow = range.getFirstRow();
  3055. int firstColumn = range.getFirstColumn();
  3056. int lastRow = range.getLastRow();
  3057. int lastColumn = range.getLastColumn();
  3058. int height = lastRow - firstRow + 1;
  3059. int width = lastColumn - firstColumn + 1;
  3060. List<XSSFCell> temp = new ArrayList<XSSFCell>(height*width);
  3061. for (int rowIn = firstRow; rowIn <= lastRow; rowIn++) {
  3062. for (int colIn = firstColumn; colIn <= lastColumn; colIn++) {
  3063. XSSFRow row = getRow(rowIn);
  3064. if (row == null) {
  3065. row = createRow(rowIn);
  3066. }
  3067. XSSFCell cell = row.getCell(colIn);
  3068. if (cell == null) {
  3069. cell = row.createCell(colIn);
  3070. }
  3071. temp.add(cell);
  3072. }
  3073. }
  3074. return SSCellRange.create(firstRow, firstColumn, height, width, temp, XSSFCell.class);
  3075. }
  3076. @Override
  3077. public CellRange<XSSFCell> setArrayFormula(String formula, CellRangeAddress range) {
  3078. CellRange<XSSFCell> cr = getCellRange(range);
  3079. XSSFCell mainArrayFormulaCell = cr.getTopLeftCell();
  3080. mainArrayFormulaCell.setCellArrayFormula(formula, range);
  3081. arrayFormulas.add(range);
  3082. return cr;
  3083. }
  3084. @Override
  3085. public CellRange<XSSFCell> removeArrayFormula(Cell cell) {
  3086. if (cell.getSheet() != this) {
  3087. throw new IllegalArgumentException("Specified cell does not belong to this sheet.");
  3088. }
  3089. for (CellRangeAddress range : arrayFormulas) {
  3090. if (range.isInRange(cell.getRowIndex(), cell.getColumnIndex())) {
  3091. arrayFormulas.remove(range);
  3092. CellRange<XSSFCell> cr = getCellRange(range);
  3093. for (XSSFCell c : cr) {
  3094. c.setCellType(Cell.CELL_TYPE_BLANK);
  3095. }
  3096. return cr;
  3097. }
  3098. }
  3099. String ref = ((XSSFCell)cell).getCTCell().getR();
  3100. throw new IllegalArgumentException("Cell " + ref + " is not part of an array formula.");
  3101. }
  3102. @Override
  3103. public DataValidationHelper getDataValidationHelper() {
  3104. return dataValidationHelper;
  3105. }
  3106. @SuppressWarnings("deprecation") //YK: getXYZArray() array accessors are deprecated in xmlbeans with JDK 1.5 support
  3107. public List<XSSFDataValidation> getDataValidations() {
  3108. List<XSSFDataValidation> xssfValidations = new ArrayList<XSSFDataValidation>();
  3109. CTDataValidations dataValidations = this.worksheet.getDataValidations();
  3110. if( dataValidations!=null && dataValidations.getCount() > 0 ) {
  3111. for (CTDataValidation ctDataValidation : dataValidations.getDataValidationArray()) {
  3112. CellRangeAddressList addressList = new CellRangeAddressList();
  3113. @SuppressWarnings("unchecked")
  3114. List<String> sqref = ctDataValidation.getSqref();
  3115. for (String stRef : sqref) {
  3116. String[] regions = stRef.split(" ");
  3117. for (String region : regions) {
  3118. String[] parts = region.split(":");
  3119. CellReference begin = new CellReference(parts[0]);
  3120. CellReference end = parts.length > 1 ? new CellReference(parts[1]) : begin;
  3121. CellRangeAddress cellRangeAddress = new CellRangeAddress(begin.getRow(), end.getRow(), begin.getCol(), end.getCol());
  3122. addressList.addCellRangeAddress(cellRangeAddress);
  3123. }
  3124. }
  3125. XSSFDataValidation xssfDataValidation = new XSSFDataValidation(addressList, ctDataValidation);
  3126. xssfValidations.add(xssfDataValidation);
  3127. }
  3128. }
  3129. return xssfValidations;
  3130. }
  3131. @Override
  3132. public void addValidationData(DataValidation dataValidation) {
  3133. XSSFDataValidation xssfDataValidation = (XSSFDataValidation)dataValidation;
  3134. CTDataValidations dataValidations = worksheet.getDataValidations();
  3135. if( dataValidations==null ) {
  3136. dataValidations = worksheet.addNewDataValidations();
  3137. }
  3138. int currentCount = dataValidations.sizeOfDataValidationArray();
  3139. CTDataValidation newval = dataValidations.addNewDataValidation();
  3140. newval.set(xssfDataValidation.getCtDdataValidation());
  3141. dataValidations.setCount(currentCount + 1);
  3142. }
  3143. @Override
  3144. public XSSFAutoFilter setAutoFilter(CellRangeAddress range) {
  3145. CTAutoFilter af = worksheet.getAutoFilter();
  3146. if(af == null) af = worksheet.addNewAutoFilter();
  3147. CellRangeAddress norm = new CellRangeAddress(range.getFirstRow(), range.getLastRow(),
  3148. range.getFirstColumn(), range.getLastColumn());
  3149. String ref = norm.formatAsString();
  3150. af.setRef(ref);
  3151. XSSFWorkbook wb = getWorkbook();
  3152. int sheetIndex = getWorkbook().getSheetIndex(this);
  3153. XSSFName name = wb.getBuiltInName(XSSFName.BUILTIN_FILTER_DB, sheetIndex);
  3154. if (name == null) {
  3155. name = wb.createBuiltInName(XSSFName.BUILTIN_FILTER_DB, sheetIndex);
  3156. }
  3157. name.getCTName().setHidden(true);
  3158. CellReference r1 = new CellReference(getSheetName(), range.getFirstRow(), range.getFirstColumn(), true, true);
  3159. CellReference r2 = new CellReference(null, range.getLastRow(), range.getLastColumn(), true, true);
  3160. String fmla = r1.formatAsString() + ":" + r2.formatAsString();
  3161. name.setRefersToFormula(fmla);
  3162. return new XSSFAutoFilter(this);
  3163. }
  3164. /**
  3165. * Creates a new Table, and associates it with this Sheet
  3166. */
  3167. public XSSFTable createTable() {
  3168. if(! worksheet.isSetTableParts()) {
  3169. worksheet.addNewTableParts();
  3170. }
  3171. CTTableParts tblParts = worksheet.getTableParts();
  3172. CTTablePart tbl = tblParts.addNewTablePart();
  3173. // Table numbers need to be unique in the file, not just
  3174. // unique within the sheet. Find the next one
  3175. int tableNumber = getPackagePart().getPackage().getPartsByContentType(XSSFRelation.TABLE.getContentType()).size() + 1;
  3176. XSSFTable table = (XSSFTable)createRelationship(XSSFRelation.TABLE, XSSFFactory.getInstance(), tableNumber);
  3177. tbl.setId(table.getPackageRelationship().getId());
  3178. tables.put(tbl.getId(), table);
  3179. return table;
  3180. }
  3181. /**
  3182. * Returns any tables associated with this Sheet
  3183. */
  3184. public List<XSSFTable> getTables() {
  3185. List<XSSFTable> tableList = new ArrayList<XSSFTable>(
  3186. tables.values()
  3187. );
  3188. return tableList;
  3189. }
  3190. @Override
  3191. public XSSFSheetConditionalFormatting getSheetConditionalFormatting(){
  3192. return new XSSFSheetConditionalFormatting(this);
  3193. }
  3194. /**
  3195. * Set background color of the sheet tab
  3196. *
  3197. * @param colorIndex the indexed color to set, must be a constant from {@link IndexedColors}
  3198. */
  3199. public void setTabColor(int colorIndex){
  3200. CTSheetPr pr = worksheet.getSheetPr();
  3201. if(pr == null) pr = worksheet.addNewSheetPr();
  3202. CTColor color = CTColor.Factory.newInstance();
  3203. color.setIndexed(colorIndex);
  3204. pr.setTabColor(color);
  3205. }
  3206. @Override
  3207. public CellRangeAddress getRepeatingRows() {
  3208. return getRepeatingRowsOrColums(true);
  3209. }
  3210. @Override
  3211. public CellRangeAddress getRepeatingColumns() {
  3212. return getRepeatingRowsOrColums(false);
  3213. }
  3214. @Override
  3215. public void setRepeatingRows(CellRangeAddress rowRangeRef) {
  3216. CellRangeAddress columnRangeRef = getRepeatingColumns();
  3217. setRepeatingRowsAndColumns(rowRangeRef, columnRangeRef);
  3218. }
  3219. @Override
  3220. public void setRepeatingColumns(CellRangeAddress columnRangeRef) {
  3221. CellRangeAddress rowRangeRef = getRepeatingRows();
  3222. setRepeatingRowsAndColumns(rowRangeRef, columnRangeRef);
  3223. }
  3224. private void setRepeatingRowsAndColumns(
  3225. CellRangeAddress rowDef, CellRangeAddress colDef) {
  3226. int col1 = -1;
  3227. int col2 = -1;
  3228. int row1 = -1;
  3229. int row2 = -1;
  3230. if (rowDef != null) {
  3231. row1 = rowDef.getFirstRow();
  3232. row2 = rowDef.getLastRow();
  3233. if ((row1 == -1 && row2 != -1)
  3234. || row1 < -1 || row2 < -1 || row1 > row2) {
  3235. throw new IllegalArgumentException("Invalid row range specification");
  3236. }
  3237. }
  3238. if (colDef != null) {
  3239. col1 = colDef.getFirstColumn();
  3240. col2 = colDef.getLastColumn();
  3241. if ((col1 == -1 && col2 != -1)
  3242. || col1 < -1 || col2 < -1 || col1 > col2) {
  3243. throw new IllegalArgumentException(
  3244. "Invalid column range specification");
  3245. }
  3246. }
  3247. int sheetIndex = getWorkbook().getSheetIndex(this);
  3248. boolean removeAll = rowDef == null && colDef == null;
  3249. XSSFName name = getWorkbook().getBuiltInName(
  3250. XSSFName.BUILTIN_PRINT_TITLE, sheetIndex);
  3251. if (removeAll) {
  3252. if (name != null) {
  3253. getWorkbook().removeName(name);
  3254. }
  3255. return;
  3256. }
  3257. if (name == null) {
  3258. name = getWorkbook().createBuiltInName(
  3259. XSSFName.BUILTIN_PRINT_TITLE, sheetIndex);
  3260. }
  3261. String reference = getReferenceBuiltInRecord(
  3262. name.getSheetName(), col1, col2, row1, row2);
  3263. name.setRefersToFormula(reference);
  3264. // If the print setup isn't currently defined, then add it
  3265. // in but without printer defaults
  3266. // If it's already there, leave it as-is!
  3267. if (worksheet.isSetPageSetup() && worksheet.isSetPageMargins()) {
  3268. // Everything we need is already there
  3269. } else {
  3270. // Have initial ones put in place
  3271. getPrintSetup().setValidSettings(false);
  3272. }
  3273. }
  3274. private static String getReferenceBuiltInRecord(
  3275. String sheetName, int startC, int endC, int startR, int endR) {
  3276. // Excel example for built-in title:
  3277. // 'second sheet'!$E:$F,'second sheet'!$2:$3
  3278. CellReference colRef =
  3279. new CellReference(sheetName, 0, startC, true, true);
  3280. CellReference colRef2 =
  3281. new CellReference(sheetName, 0, endC, true, true);
  3282. CellReference rowRef =
  3283. new CellReference(sheetName, startR, 0, true, true);
  3284. CellReference rowRef2 =
  3285. new CellReference(sheetName, endR, 0, true, true);
  3286. String escapedName = SheetNameFormatter.format(sheetName);
  3287. String c = "";
  3288. String r = "";
  3289. if(startC == -1 && endC == -1) {
  3290. } else {
  3291. c = escapedName + "!$" + colRef.getCellRefParts()[2]
  3292. + ":$" + colRef2.getCellRefParts()[2];
  3293. }
  3294. if (startR == -1 && endR == -1) {
  3295. } else if (!rowRef.getCellRefParts()[1].equals("0")
  3296. && !rowRef2.getCellRefParts()[1].equals("0")) {
  3297. r = escapedName + "!$" + rowRef.getCellRefParts()[1]
  3298. + ":$" + rowRef2.getCellRefParts()[1];
  3299. }
  3300. StringBuilder rng = new StringBuilder();
  3301. rng.append(c);
  3302. if(rng.length() > 0 && r.length() > 0) {
  3303. rng.append(',');
  3304. }
  3305. rng.append(r);
  3306. return rng.toString();
  3307. }
  3308. private CellRangeAddress getRepeatingRowsOrColums(boolean rows) {
  3309. int sheetIndex = getWorkbook().getSheetIndex(this);
  3310. XSSFName name = getWorkbook().getBuiltInName(
  3311. XSSFName.BUILTIN_PRINT_TITLE, sheetIndex);
  3312. if (name == null ) {
  3313. return null;
  3314. }
  3315. String refStr = name.getRefersToFormula();
  3316. if (refStr == null) {
  3317. return null;
  3318. }
  3319. String[] parts = refStr.split(",");
  3320. int maxRowIndex = SpreadsheetVersion.EXCEL2007.getLastRowIndex();
  3321. int maxColIndex = SpreadsheetVersion.EXCEL2007.getLastColumnIndex();
  3322. for (String part : parts) {
  3323. CellRangeAddress range = CellRangeAddress.valueOf(part);
  3324. if ((range.getFirstColumn() == 0
  3325. && range.getLastColumn() == maxColIndex)
  3326. || (range.getFirstColumn() == -1
  3327. && range.getLastColumn() == -1)) {
  3328. if (rows) {
  3329. return range;
  3330. }
  3331. } else if (range.getFirstRow() == 0
  3332. && range.getLastRow() == maxRowIndex
  3333. || (range.getFirstRow() == -1
  3334. && range.getLastRow() == -1)) {
  3335. if (!rows) {
  3336. return range;
  3337. }
  3338. }
  3339. }
  3340. return null;
  3341. }
  3342. /**
  3343. * Creates an empty XSSFPivotTable and sets up all its relationships
  3344. * including: pivotCacheDefinition, pivotCacheRecords
  3345. * @return returns a pivotTable
  3346. */
  3347. @Beta
  3348. private XSSFPivotTable createPivotTable() {
  3349. XSSFWorkbook wb = getWorkbook();
  3350. List<XSSFPivotTable> pivotTables = wb.getPivotTables();
  3351. int tableId = getWorkbook().getPivotTables().size()+1;
  3352. //Create relationship between pivotTable and the worksheet
  3353. XSSFPivotTable pivotTable = (XSSFPivotTable) createRelationship(XSSFRelation.PIVOT_TABLE,
  3354. XSSFFactory.getInstance(), tableId);
  3355. pivotTable.setParentSheet(this);
  3356. pivotTables.add(pivotTable);
  3357. XSSFWorkbook workbook = getWorkbook();
  3358. //Create relationship between the pivot cache defintion and the workbook
  3359. XSSFPivotCacheDefinition pivotCacheDefinition = (XSSFPivotCacheDefinition) workbook.
  3360. createRelationship(XSSFRelation.PIVOT_CACHE_DEFINITION, XSSFFactory.getInstance(), tableId);
  3361. String rId = workbook.getRelationId(pivotCacheDefinition);
  3362. //Create relationship between pivotTable and pivotCacheDefinition without creating a new instance
  3363. PackagePart pivotPackagePart = pivotTable.getPackagePart();
  3364. pivotPackagePart.addRelationship(pivotCacheDefinition.getPackagePart().getPartName(),
  3365. TargetMode.INTERNAL, XSSFRelation.PIVOT_CACHE_DEFINITION.getRelation());
  3366. pivotTable.setPivotCacheDefinition(pivotCacheDefinition);
  3367. //Create pivotCache and sets up it's relationship with the workbook
  3368. pivotTable.setPivotCache(new XSSFPivotCache(workbook.addPivotCache(rId)));
  3369. //Create relationship between pivotcacherecord and pivotcachedefinition
  3370. XSSFPivotCacheRecords pivotCacheRecords = (XSSFPivotCacheRecords) pivotCacheDefinition.
  3371. createRelationship(XSSFRelation.PIVOT_CACHE_RECORDS, XSSFFactory.getInstance(), tableId);
  3372. //Set relationships id for pivotCacheDefinition to pivotCacheRecords
  3373. pivotTable.getPivotCacheDefinition().getCTPivotCacheDefinition().setId(pivotCacheDefinition.getRelationId(pivotCacheRecords));
  3374. wb.setPivotTables(pivotTables);
  3375. return pivotTable;
  3376. }
  3377. /**
  3378. * Create a pivot table and set area of source, source sheet and a position for pivot table
  3379. * @param source Area from where data will be collected
  3380. * @param position A reference to the cell where the table will start
  3381. * @param sourceSheet The sheet where source will be collected from
  3382. * @return The pivot table
  3383. */
  3384. @Beta
  3385. public XSSFPivotTable createPivotTable(AreaReference source, CellReference position, Sheet sourceSheet){
  3386. if(source.getFirstCell().getSheetName() != null && !source.getFirstCell().getSheetName().equals(sourceSheet.getSheetName())) {
  3387. throw new IllegalArgumentException("The area is referenced in another sheet than the "
  3388. + "defined source sheet " + sourceSheet.getSheetName() + ".");
  3389. }
  3390. XSSFPivotTable pivotTable = createPivotTable();
  3391. //Creates default settings for the pivot table
  3392. pivotTable.setDefaultPivotTableDefinition();
  3393. //Set sources and references
  3394. pivotTable.createSourceReferences(source, position, sourceSheet);
  3395. //Create cachefield/s and empty SharedItems
  3396. pivotTable.getPivotCacheDefinition().createCacheFields(sourceSheet);
  3397. pivotTable.createDefaultDataColumns();
  3398. return pivotTable;
  3399. }
  3400. /**
  3401. * Create a pivot table and set area of source and a position for pivot table
  3402. * @param source Area from where data will be collected
  3403. * @param position A reference to the cell where the table will start
  3404. * @return The pivot table
  3405. */
  3406. @Beta
  3407. public XSSFPivotTable createPivotTable(AreaReference source, CellReference position){
  3408. if(source.getFirstCell().getSheetName() != null && !source.getFirstCell().getSheetName().equals(this.getSheetName())) {
  3409. return createPivotTable(source, position, getWorkbook().getSheet(source.getFirstCell().getSheetName()));
  3410. }
  3411. return createPivotTable(source, position, this);
  3412. }
  3413. /**
  3414. * Returns all the pivot tables for this Sheet
  3415. */
  3416. @Beta
  3417. public List<XSSFPivotTable> getPivotTables() {
  3418. List<XSSFPivotTable> tables = new ArrayList<XSSFPivotTable>();
  3419. for (XSSFPivotTable table : getWorkbook().getPivotTables()) {
  3420. if (table.getParent() == this) {
  3421. tables.add(table);
  3422. }
  3423. }
  3424. return tables;
  3425. }
  3426. }