worksheet.cpp 33 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355
  1. // Copyright (c) 2014-2021 Thomas Fussell
  2. // Copyright (c) 2010-2015 openpyxl
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to deal
  6. // in the Software without restriction, including without limitation the rights
  7. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  8. // copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  19. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  20. // THE SOFTWARE
  21. //
  22. // @license: http://www.opensource.org/licenses/mit-license.php
  23. // @author: see AUTHORS file
  24. #include <algorithm>
  25. #include <cmath>
  26. #include <limits>
  27. #include <xlnt/cell/cell.hpp>
  28. #include <xlnt/cell/cell_reference.hpp>
  29. #include <xlnt/cell/index_types.hpp>
  30. #include <xlnt/packaging/relationship.hpp>
  31. #include <xlnt/utils/date.hpp>
  32. #include <xlnt/utils/datetime.hpp>
  33. #include <xlnt/utils/exceptions.hpp>
  34. #include <xlnt/utils/numeric.hpp>
  35. #include <xlnt/workbook/named_range.hpp>
  36. #include <xlnt/workbook/workbook.hpp>
  37. #include <xlnt/workbook/worksheet_iterator.hpp>
  38. #include <xlnt/worksheet/cell_iterator.hpp>
  39. #include <xlnt/worksheet/column_properties.hpp>
  40. #include <xlnt/worksheet/header_footer.hpp>
  41. #include <xlnt/worksheet/range.hpp>
  42. #include <xlnt/worksheet/range_iterator.hpp>
  43. #include <xlnt/worksheet/range_reference.hpp>
  44. #include <xlnt/worksheet/row_properties.hpp>
  45. #include <xlnt/worksheet/worksheet.hpp>
  46. #include <detail/constants.hpp>
  47. #include <detail/default_case.hpp>
  48. #include <detail/implementations/cell_impl.hpp>
  49. #include <detail/implementations/workbook_impl.hpp>
  50. #include <detail/implementations/worksheet_impl.hpp>
  51. #include <detail/unicode.hpp>
  52. namespace {
  53. int points_to_pixels(double points, double dpi)
  54. {
  55. return static_cast<int>(std::ceil(points * dpi / 72));
  56. }
  57. } // namespace
  58. namespace xlnt {
  59. worksheet::worksheet()
  60. : d_(nullptr)
  61. {
  62. }
  63. worksheet::worksheet(detail::worksheet_impl *d)
  64. : d_(d)
  65. {
  66. }
  67. worksheet::worksheet(const worksheet &rhs)
  68. : d_(rhs.d_)
  69. {
  70. }
  71. bool worksheet::has_frozen_panes() const
  72. {
  73. return !d_->views_.empty() && d_->views_.front().has_pane()
  74. && (d_->views_.front().pane().state == pane_state::frozen
  75. || d_->views_.front().pane().state == pane_state::frozen_split);
  76. }
  77. void worksheet::create_named_range(const std::string &name, const std::string &reference_string)
  78. {
  79. create_named_range(name, range_reference(reference_string));
  80. }
  81. void worksheet::create_named_range(const std::string &name, const range_reference &reference)
  82. {
  83. try
  84. {
  85. auto temp = cell_reference::split_reference(name);
  86. // name is a valid reference, make sure it's outside the allowed range
  87. if (column_t(temp.first).index <= column_t("XFD").index && temp.second <= 1048576)
  88. {
  89. throw invalid_parameter(); //("named range name must be outside the range A1-XFD1048576");
  90. }
  91. }
  92. catch (xlnt::invalid_cell_reference &)
  93. {
  94. // name is not a valid reference, that's good
  95. }
  96. std::vector<named_range::target> targets;
  97. targets.push_back({*this, reference});
  98. d_->named_ranges_[name] = xlnt::named_range(name, targets);
  99. }
  100. cell worksheet::operator[](const cell_reference &ref)
  101. {
  102. return cell(ref);
  103. }
  104. std::vector<range_reference> worksheet::merged_ranges() const
  105. {
  106. return d_->merged_cells_;
  107. }
  108. bool worksheet::has_page_margins() const
  109. {
  110. return d_->page_margins_.is_set();
  111. }
  112. bool worksheet::has_page_setup() const
  113. {
  114. return d_->page_setup_.is_set();
  115. }
  116. page_margins worksheet::page_margins() const
  117. {
  118. return d_->page_margins_.get();
  119. }
  120. void worksheet::page_margins(const class page_margins &margins)
  121. {
  122. d_->page_margins_ = margins;
  123. }
  124. void worksheet::auto_filter(const std::string &reference_string)
  125. {
  126. auto_filter(range_reference(reference_string));
  127. }
  128. void worksheet::auto_filter(const range_reference &reference)
  129. {
  130. d_->auto_filter_ = reference;
  131. }
  132. void worksheet::auto_filter(const xlnt::range &range)
  133. {
  134. auto_filter(range.reference());
  135. }
  136. range_reference worksheet::auto_filter() const
  137. {
  138. return d_->auto_filter_.get();
  139. }
  140. bool worksheet::has_auto_filter() const
  141. {
  142. return d_->auto_filter_.is_set();
  143. }
  144. void worksheet::clear_auto_filter()
  145. {
  146. d_->auto_filter_.clear();
  147. }
  148. void worksheet::page_setup(const struct page_setup &setup)
  149. {
  150. d_->page_setup_ = setup;
  151. }
  152. page_setup worksheet::page_setup() const
  153. {
  154. if (!has_page_setup())
  155. {
  156. throw invalid_attribute();
  157. }
  158. return d_->page_setup_.get();
  159. }
  160. workbook &worksheet::workbook()
  161. {
  162. return *d_->parent_;
  163. }
  164. const workbook &worksheet::workbook() const
  165. {
  166. return *d_->parent_;
  167. }
  168. void worksheet::garbage_collect()
  169. {
  170. auto cell_iter = d_->cell_map_.begin();
  171. while (cell_iter != d_->cell_map_.end())
  172. {
  173. if (xlnt::cell(&cell_iter->second).garbage_collectible())
  174. {
  175. cell_iter = d_->cell_map_.erase(cell_iter);
  176. }
  177. else
  178. {
  179. ++cell_iter;
  180. }
  181. }
  182. }
  183. void worksheet::id(std::size_t id)
  184. {
  185. d_->id_ = id;
  186. }
  187. std::size_t worksheet::id() const
  188. {
  189. return d_->id_;
  190. }
  191. std::string worksheet::title() const
  192. {
  193. return d_->title_;
  194. }
  195. void worksheet::title(const std::string &title)
  196. {
  197. // do no work if we don't need to
  198. if (d_->title_ == title)
  199. {
  200. return;
  201. }
  202. // excel limits worksheet titles to 31 characters
  203. if (title.empty() || detail::string_length(title) > 31)
  204. {
  205. throw invalid_sheet_title(title);
  206. }
  207. // invalid characters in a worksheet name
  208. if (title.find_first_of("*:/\\?[]") != std::string::npos)
  209. {
  210. throw invalid_sheet_title(title);
  211. }
  212. // try and insert the new name into the worksheets map
  213. // if the insert fails, we have a duplicate sheet name
  214. auto insert_result = workbook().d_->sheet_title_rel_id_map_.insert(
  215. std::make_pair(title, workbook().d_->sheet_title_rel_id_map_[d_->title_]));
  216. if (!insert_result.second) // insert failed, duplication detected
  217. {
  218. throw invalid_sheet_title(title);
  219. }
  220. // if the insert succeeded (i.e. wasn't a duplicate sheet name)
  221. // update the worksheet title and remove the old relation
  222. workbook().d_->sheet_title_rel_id_map_.erase(d_->title_);
  223. d_->title_ = title;
  224. workbook().update_sheet_properties();
  225. }
  226. cell_reference worksheet::frozen_panes() const
  227. {
  228. if (!has_frozen_panes())
  229. {
  230. throw xlnt::invalid_attribute();
  231. }
  232. return d_->views_.front().pane().top_left_cell.get();
  233. }
  234. void worksheet::freeze_panes(xlnt::cell top_left_cell)
  235. {
  236. freeze_panes(top_left_cell.reference());
  237. }
  238. void worksheet::freeze_panes(const cell_reference &ref)
  239. {
  240. if (ref == "A1")
  241. {
  242. unfreeze_panes();
  243. return;
  244. }
  245. if (!has_view())
  246. {
  247. d_->views_.push_back(sheet_view());
  248. }
  249. auto &primary_view = d_->views_.front();
  250. if (!primary_view.has_pane())
  251. {
  252. primary_view.pane(pane());
  253. }
  254. primary_view.pane().top_left_cell = ref;
  255. primary_view.pane().state = pane_state::frozen;
  256. primary_view.clear_selections();
  257. if (ref.column() == "A") // no column is frozen
  258. {
  259. primary_view.add_selection(selection(pane_corner::bottom_left, ref));
  260. primary_view.pane().active_pane = pane_corner::bottom_left;
  261. primary_view.pane().y_split = ref.row() - 1;
  262. }
  263. else if (ref.row() == 1) // no row is frozen
  264. {
  265. primary_view.add_selection(selection(pane_corner::top_right, ref));
  266. primary_view.pane().active_pane = pane_corner::top_right;
  267. primary_view.pane().x_split = ref.column_index() - 1;
  268. }
  269. else // column and row is frozen
  270. {
  271. primary_view.add_selection(selection(pane_corner::top_right, cell_reference(ref.column(), 1)));
  272. primary_view.add_selection(selection(pane_corner::bottom_left, cell_reference(1, ref.row())));
  273. primary_view.add_selection(selection(pane_corner::bottom_right, ref));
  274. primary_view.pane().active_pane = pane_corner::bottom_right;
  275. primary_view.pane().x_split = ref.column_index() - 1;
  276. primary_view.pane().y_split = ref.row() - 1;
  277. }
  278. }
  279. void worksheet::unfreeze_panes()
  280. {
  281. if (!has_view()) return;
  282. auto &primary_view = d_->views_.front();
  283. primary_view.clear_selections();
  284. primary_view.clear_pane();
  285. }
  286. void worksheet::active_cell(const cell_reference &ref)
  287. {
  288. if (!has_view())
  289. {
  290. d_->views_.push_back(sheet_view());
  291. }
  292. auto &primary_view = d_->views_.front();
  293. if (!primary_view.has_selections())
  294. {
  295. primary_view.add_selection(selection(pane_corner::bottom_right, ref));
  296. }
  297. else
  298. {
  299. primary_view.selection(0).active_cell(ref);
  300. }
  301. }
  302. bool worksheet::has_active_cell() const
  303. {
  304. if (!has_view()) return false;
  305. auto &primary_view = d_->views_.front();
  306. if (!primary_view.has_selections()) return false;
  307. auto primary_selection = primary_view.selection(0);
  308. return primary_selection.has_active_cell();
  309. }
  310. cell_reference worksheet::active_cell() const
  311. {
  312. if (!has_view())
  313. {
  314. throw xlnt::exception("Worksheet has no view.");
  315. }
  316. auto &primary_view = d_->views_.front();
  317. if (!primary_view.has_selections())
  318. {
  319. throw xlnt::exception("Default worksheet view has no selections.");
  320. }
  321. return primary_view.selection(0).active_cell();
  322. }
  323. cell worksheet::cell(const cell_reference &reference)
  324. {
  325. auto match = d_->cell_map_.find(reference);
  326. if (match == d_->cell_map_.end())
  327. {
  328. auto impl = detail::cell_impl();
  329. impl.parent_ = d_;
  330. impl.column_ = reference.column_index();
  331. impl.row_ = reference.row();
  332. match = d_->cell_map_.emplace(reference, impl).first;
  333. }
  334. return xlnt::cell(&match->second);
  335. }
  336. const cell worksheet::cell(const cell_reference &reference) const
  337. {
  338. return xlnt::cell(&d_->cell_map_.at(reference));
  339. }
  340. cell worksheet::cell(xlnt::column_t column, row_t row)
  341. {
  342. return cell(cell_reference(column, row));
  343. }
  344. const cell worksheet::cell(xlnt::column_t column, row_t row) const
  345. {
  346. return cell(cell_reference(column, row));
  347. }
  348. bool worksheet::has_cell(const cell_reference &reference) const
  349. {
  350. const auto cell = d_->cell_map_.find(reference);
  351. return cell != d_->cell_map_.cend();
  352. }
  353. bool worksheet::has_row_properties(row_t row) const
  354. {
  355. return d_->row_properties_.find(row) != d_->row_properties_.end();
  356. }
  357. range worksheet::named_range(const std::string &name)
  358. {
  359. if (!workbook().has_named_range(name))
  360. {
  361. throw key_not_found();
  362. }
  363. if (!has_named_range(name))
  364. {
  365. throw key_not_found();
  366. }
  367. return range(d_->named_ranges_[name].targets()[0].second);
  368. }
  369. const range worksheet::named_range(const std::string &name) const
  370. {
  371. if (!workbook().has_named_range(name))
  372. {
  373. throw key_not_found();
  374. }
  375. if (!has_named_range(name))
  376. {
  377. throw key_not_found();
  378. }
  379. return range(d_->named_ranges_[name].targets()[0].second);
  380. }
  381. column_t worksheet::lowest_column() const
  382. {
  383. if (d_->cell_map_.empty())
  384. {
  385. return constants::min_column();
  386. }
  387. auto lowest = constants::max_column();
  388. for (auto &cell : d_->cell_map_)
  389. {
  390. lowest = std::min(lowest, cell.first.column());
  391. }
  392. return lowest;
  393. }
  394. column_t worksheet::lowest_column_or_props() const
  395. {
  396. auto lowest = lowest_column();
  397. if (d_->cell_map_.empty() && !d_->column_properties_.empty())
  398. {
  399. lowest = d_->column_properties_.begin()->first;
  400. }
  401. for (auto &props : d_->column_properties_)
  402. {
  403. lowest = std::min(lowest, props.first);
  404. }
  405. return lowest;
  406. }
  407. row_t worksheet::lowest_row() const
  408. {
  409. if (d_->cell_map_.empty())
  410. {
  411. return constants::min_row();
  412. }
  413. auto lowest = constants::max_row();
  414. for (auto &cell : d_->cell_map_)
  415. {
  416. lowest = std::min(lowest, cell.first.row());
  417. }
  418. return lowest;
  419. }
  420. row_t worksheet::lowest_row_or_props() const
  421. {
  422. auto lowest = lowest_row();
  423. if (d_->cell_map_.empty() && !d_->row_properties_.empty())
  424. {
  425. lowest = d_->row_properties_.begin()->first;
  426. }
  427. for (auto &props : d_->row_properties_)
  428. {
  429. lowest = std::min(lowest, props.first);
  430. }
  431. return lowest;
  432. }
  433. row_t worksheet::highest_row() const
  434. {
  435. auto highest = constants::min_row();
  436. for (auto &cell : d_->cell_map_)
  437. {
  438. highest = std::max(highest, cell.first.row());
  439. }
  440. return highest;
  441. }
  442. row_t worksheet::highest_row_or_props() const
  443. {
  444. auto highest = highest_row();
  445. if (d_->cell_map_.empty() && !d_->row_properties_.empty())
  446. {
  447. highest = d_->row_properties_.begin()->first;
  448. }
  449. for (auto &props : d_->row_properties_)
  450. {
  451. highest = std::max(highest, props.first);
  452. }
  453. return highest;
  454. }
  455. column_t worksheet::highest_column() const
  456. {
  457. auto highest = constants::min_column();
  458. for (auto &cell : d_->cell_map_)
  459. {
  460. highest = std::max(highest, cell.first.column());
  461. }
  462. return highest;
  463. }
  464. column_t worksheet::highest_column_or_props() const
  465. {
  466. auto highest = highest_column();
  467. if (d_->cell_map_.empty() && !d_->column_properties_.empty())
  468. {
  469. highest = d_->column_properties_.begin()->first;
  470. }
  471. for (auto &props : d_->column_properties_)
  472. {
  473. highest = std::max(highest, props.first);
  474. }
  475. return highest;
  476. }
  477. range_reference worksheet::calculate_dimension(bool skip_null) const
  478. {
  479. // partially optimised version of:
  480. // return range_reference(lowest_column(), lowest_row_or_props(),
  481. // highest_column(), highest_row_or_props());
  482. //
  483. if (d_->cell_map_.empty() && d_->row_properties_.empty())
  484. {
  485. return range_reference(constants::min_column(), constants::min_row(),
  486. constants::min_column(), constants::min_row());
  487. }
  488. // if skip_null = false, min row = min_row() and min column = min_column()
  489. // in order to include first empty rows and columns
  490. row_t min_row_prop = skip_null? constants::max_row() : constants::min_row();
  491. row_t max_row_prop = constants::min_row();
  492. for (const auto &row_prop : d_->row_properties_)
  493. {
  494. if(skip_null){
  495. min_row_prop = std::min(min_row_prop, row_prop.first);
  496. }
  497. max_row_prop = std::max(max_row_prop, row_prop.first);
  498. }
  499. if (d_->cell_map_.empty())
  500. {
  501. return range_reference(constants::min_column(), min_row_prop,
  502. constants::min_column(), max_row_prop);
  503. }
  504. // find min and max row/column in cell map
  505. column_t min_col = skip_null? constants::max_column() : constants::min_column();
  506. column_t max_col = constants::min_column();
  507. row_t min_row = min_row_prop;
  508. row_t max_row = max_row_prop;
  509. for (auto &c : d_->cell_map_)
  510. {
  511. if(skip_null){
  512. min_col = std::min(min_col, c.second.column_);
  513. min_row = std::min(min_row, c.second.row_);
  514. }
  515. max_col = std::max(max_col, c.second.column_);
  516. max_row = std::max(max_row, c.second.row_);
  517. }
  518. return range_reference(min_col, min_row, max_col, max_row);
  519. }
  520. range worksheet::range(const std::string &reference_string)
  521. {
  522. if (has_named_range(reference_string))
  523. {
  524. return named_range(reference_string);
  525. }
  526. return range(range_reference(reference_string));
  527. }
  528. const range worksheet::range(const std::string &reference_string) const
  529. {
  530. if (has_named_range(reference_string))
  531. {
  532. return named_range(reference_string);
  533. }
  534. return range(range_reference(reference_string));
  535. }
  536. range worksheet::range(const range_reference &reference)
  537. {
  538. return xlnt::range(*this, reference);
  539. }
  540. const range worksheet::range(const range_reference &reference) const
  541. {
  542. return xlnt::range(*this, reference);
  543. }
  544. void worksheet::merge_cells(const std::string &reference_string)
  545. {
  546. merge_cells(range_reference(reference_string));
  547. }
  548. void worksheet::unmerge_cells(const std::string &reference_string)
  549. {
  550. unmerge_cells(range_reference(reference_string));
  551. }
  552. void worksheet::merge_cells(const range_reference &reference)
  553. {
  554. d_->merged_cells_.push_back(reference);
  555. bool first = true;
  556. for (auto row : range(reference))
  557. {
  558. for (auto cell : row)
  559. {
  560. cell.merged(true);
  561. if (!first)
  562. {
  563. if (cell.data_type() == cell::type::shared_string)
  564. {
  565. cell.value("");
  566. }
  567. else
  568. {
  569. cell.clear_value();
  570. }
  571. }
  572. first = false;
  573. }
  574. }
  575. }
  576. void worksheet::unmerge_cells(const range_reference &reference)
  577. {
  578. auto match = std::find(d_->merged_cells_.begin(), d_->merged_cells_.end(), reference);
  579. if (match == d_->merged_cells_.end())
  580. {
  581. throw invalid_parameter();
  582. }
  583. d_->merged_cells_.erase(match);
  584. for (auto row : range(reference))
  585. {
  586. for (auto cell : row)
  587. {
  588. cell.merged(false);
  589. }
  590. }
  591. }
  592. row_t worksheet::next_row() const
  593. {
  594. auto row = highest_row() + 1;
  595. if (row == 2 && d_->cell_map_.size() == 0)
  596. {
  597. row = 1;
  598. }
  599. return row;
  600. }
  601. xlnt::range worksheet::rows(bool skip_null)
  602. {
  603. return xlnt::range(*this, calculate_dimension(skip_null), major_order::row, skip_null);
  604. }
  605. const xlnt::range worksheet::rows(bool skip_null) const
  606. {
  607. return xlnt::range(*this, calculate_dimension(skip_null), major_order::row, skip_null);
  608. }
  609. xlnt::range worksheet::columns(bool skip_null)
  610. {
  611. return xlnt::range(*this, calculate_dimension(skip_null), major_order::column, skip_null);
  612. }
  613. const xlnt::range worksheet::columns(bool skip_null) const
  614. {
  615. return xlnt::range(*this, calculate_dimension(skip_null), major_order::column, skip_null);
  616. }
  617. /*
  618. //TODO: finish implementing cell_iterator wrapping before uncommenting
  619. cell_vector worksheet::cells(bool skip_null)
  620. {
  621. const auto dimension = calculate_dimension();
  622. return cell_vector(*this, dimension.top_left(), dimension, major_order::row, skip_null, true);
  623. }
  624. const cell_vector worksheet::cells(bool skip_null) const
  625. {
  626. const auto dimension = calculate_dimension();
  627. return cell_vector(*this, dimension.top_left(), dimension, major_order::row, skip_null, true);
  628. }
  629. */
  630. void worksheet::clear_cell(const cell_reference &ref)
  631. {
  632. d_->cell_map_.erase(ref);
  633. // TODO: garbage collect newly unreferenced resources such as styles?
  634. }
  635. void worksheet::clear_row(row_t row)
  636. {
  637. for (auto it = d_->cell_map_.begin(); it != d_->cell_map_.end();)
  638. {
  639. if (it->first.row() == row)
  640. {
  641. it = d_->cell_map_.erase(it);
  642. }
  643. else
  644. {
  645. ++it;
  646. }
  647. }
  648. d_->row_properties_.erase(row);
  649. // TODO: garbage collect newly unreferenced resources such as styles?
  650. }
  651. void worksheet::insert_rows(row_t row, std::uint32_t amount)
  652. {
  653. move_cells(row, amount, row_or_col_t::row);
  654. }
  655. void worksheet::insert_columns(column_t column, std::uint32_t amount)
  656. {
  657. move_cells(column.index, amount, row_or_col_t::column);
  658. }
  659. void worksheet::delete_rows(row_t row, std::uint32_t amount)
  660. {
  661. move_cells(row + amount, amount, row_or_col_t::row, true);
  662. }
  663. void worksheet::delete_columns(column_t column, std::uint32_t amount)
  664. {
  665. move_cells(column.index + amount, amount, row_or_col_t::column, true);
  666. }
  667. void worksheet::move_cells(std::uint32_t min_index, std::uint32_t amount, row_or_col_t row_or_col, bool reverse)
  668. {
  669. if (reverse && amount > min_index)
  670. {
  671. throw xlnt::invalid_parameter();
  672. }
  673. if ((!reverse && row_or_col == row_or_col_t::row && min_index > constants::max_row() - amount) || (!reverse && row_or_col == row_or_col_t::column && min_index > constants::max_column() - amount))
  674. {
  675. throw xlnt::exception("Cannot move cells as they would be outside the maximum bounds of the spreadsheet");
  676. }
  677. std::vector<detail::cell_impl> cells_to_move;
  678. auto cell_iter = d_->cell_map_.cbegin();
  679. while (cell_iter != d_->cell_map_.cend())
  680. {
  681. std::uint32_t current_index;
  682. switch (row_or_col)
  683. {
  684. case row_or_col_t::row:
  685. current_index = cell_iter->first.row();
  686. break;
  687. case row_or_col_t::column:
  688. current_index = cell_iter->first.column().index;
  689. break;
  690. default:
  691. throw xlnt::unhandled_switch_case();
  692. }
  693. if (current_index >= min_index) // extract cells to be moved
  694. {
  695. auto cell = cell_iter->second;
  696. if (row_or_col == row_or_col_t::row)
  697. {
  698. cell.row_ = reverse ? cell.row_ - amount : cell.row_ + amount;
  699. }
  700. else if (row_or_col == row_or_col_t::column)
  701. {
  702. cell.column_ = reverse ? cell.column_.index - amount : cell.column_.index + amount;
  703. }
  704. cells_to_move.push_back(cell);
  705. cell_iter = d_->cell_map_.erase(cell_iter);
  706. }
  707. else if (reverse && current_index >= min_index - amount) // delete destination cells
  708. {
  709. cell_iter = d_->cell_map_.erase(cell_iter);
  710. }
  711. else // skip other cells
  712. {
  713. ++cell_iter;
  714. }
  715. }
  716. for (auto &cell : cells_to_move)
  717. {
  718. d_->cell_map_[cell_reference(cell.column_, cell.row_)] = cell;
  719. }
  720. if (row_or_col == row_or_col_t::row)
  721. {
  722. std::vector<std::pair<row_t, xlnt::row_properties>> properties_to_move;
  723. auto row_prop_iter = d_->row_properties_.cbegin();
  724. while (row_prop_iter != d_->row_properties_.cend())
  725. {
  726. auto current_row = row_prop_iter->first;
  727. if (current_row >= min_index) // extract properties that need to be moved
  728. {
  729. auto tmp_row = reverse ? current_row - amount : current_row + amount;
  730. properties_to_move.push_back({tmp_row, row_prop_iter->second});
  731. row_prop_iter = d_->row_properties_.erase(row_prop_iter);
  732. }
  733. else if (reverse && current_row >= min_index - amount) // clear properties of destination when in reverse
  734. {
  735. row_prop_iter = d_->row_properties_.erase(row_prop_iter);
  736. }
  737. else // skip the rest
  738. {
  739. ++row_prop_iter;
  740. }
  741. }
  742. for (const auto &prop : properties_to_move)
  743. {
  744. add_row_properties(prop.first, prop.second);
  745. }
  746. }
  747. else if (row_or_col == row_or_col_t::column)
  748. {
  749. std::vector<std::pair<column_t, xlnt::column_properties>> properties_to_move;
  750. auto col_prop_iter = d_->column_properties_.cbegin();
  751. while (col_prop_iter != d_->column_properties_.cend())
  752. {
  753. auto current_col = col_prop_iter->first.index;
  754. if (current_col >= min_index) // extract properties that need to be moved
  755. {
  756. auto tmp_column = column_t(reverse ? current_col - amount : current_col + amount);
  757. properties_to_move.push_back({tmp_column, col_prop_iter->second});
  758. col_prop_iter = d_->column_properties_.erase(col_prop_iter);
  759. }
  760. else if (reverse && current_col >= min_index - amount) // clear properties of destination when in reverse
  761. {
  762. col_prop_iter = d_->column_properties_.erase(col_prop_iter);
  763. }
  764. else // skip the rest
  765. {
  766. ++col_prop_iter;
  767. }
  768. }
  769. for (auto &prop : properties_to_move)
  770. {
  771. add_column_properties(prop.first, prop.second);
  772. }
  773. }
  774. // adjust merged cells
  775. auto shift_reference = [min_index, amount, row_or_col, reverse](cell_reference &ref) {
  776. auto index = row_or_col == row_or_col_t::row ? ref.row() : ref.column_index();
  777. if (index >= min_index)
  778. {
  779. auto new_index = reverse ? index - amount : index + amount;
  780. if (row_or_col == row_or_col_t::row)
  781. {
  782. ref.row(new_index);
  783. }
  784. else if (row_or_col == row_or_col_t::column)
  785. {
  786. ref.column_index(new_index);
  787. }
  788. }
  789. };
  790. for (auto merged_cell = d_->merged_cells_.begin(); merged_cell != d_->merged_cells_.end(); ++merged_cell)
  791. {
  792. cell_reference new_top_left = merged_cell->top_left();
  793. shift_reference(new_top_left);
  794. cell_reference new_bottom_right = merged_cell->bottom_right();
  795. shift_reference(new_bottom_right);
  796. range_reference new_range{new_top_left, new_bottom_right};
  797. if (*merged_cell != new_range)
  798. {
  799. *merged_cell = new_range;
  800. }
  801. }
  802. }
  803. bool worksheet::operator==(const worksheet &other) const
  804. {
  805. return compare(other, true);
  806. }
  807. bool worksheet::compare(const worksheet &other, bool reference) const
  808. {
  809. if (reference)
  810. {
  811. return d_ == other.d_;
  812. }
  813. if (d_->parent_ != other.d_->parent_) return false;
  814. for (auto &cell : d_->cell_map_)
  815. {
  816. if (other.d_->cell_map_.find(cell.first) == other.d_->cell_map_.end())
  817. {
  818. return false;
  819. }
  820. xlnt::cell this_cell(&cell.second);
  821. xlnt::cell other_cell(&other.d_->cell_map_[cell.first]);
  822. if (this_cell.data_type() != other_cell.data_type())
  823. {
  824. return false;
  825. }
  826. if (this_cell.data_type() == xlnt::cell::type::number
  827. && !detail::float_equals(this_cell.value<double>(), other_cell.value<double>()))
  828. {
  829. return false;
  830. }
  831. }
  832. // todo: missing some comparisons
  833. if (d_->auto_filter_ == other.d_->auto_filter_ && d_->views_ == other.d_->views_
  834. && d_->merged_cells_ == other.d_->merged_cells_)
  835. {
  836. return true;
  837. }
  838. return false;
  839. }
  840. bool worksheet::operator!=(const worksheet &other) const
  841. {
  842. return !(*this == other);
  843. }
  844. bool worksheet::operator==(std::nullptr_t) const
  845. {
  846. return d_ == nullptr;
  847. }
  848. bool worksheet::operator!=(std::nullptr_t) const
  849. {
  850. return d_ != nullptr;
  851. }
  852. void worksheet::operator=(const worksheet &other)
  853. {
  854. d_ = other.d_;
  855. }
  856. const cell worksheet::operator[](const cell_reference &ref) const
  857. {
  858. return cell(ref);
  859. }
  860. bool worksheet::has_named_range(const std::string &name) const
  861. {
  862. return d_->named_ranges_.find(name) != d_->named_ranges_.end();
  863. }
  864. void worksheet::remove_named_range(const std::string &name)
  865. {
  866. if (!has_named_range(name))
  867. {
  868. throw key_not_found();
  869. }
  870. d_->named_ranges_.erase(name);
  871. }
  872. void worksheet::reserve(std::size_t n)
  873. {
  874. d_->cell_map_.reserve(n);
  875. }
  876. class header_footer worksheet::header_footer() const
  877. {
  878. return d_->header_footer_.get();
  879. }
  880. cell_reference worksheet::point_pos(int left, int top) const
  881. {
  882. column_t current_column = 1;
  883. row_t current_row = 1;
  884. double left_pos = 0;
  885. double top_pos = 0;
  886. while (left_pos <= left)
  887. {
  888. left_pos += column_width(current_column++);
  889. }
  890. while (top_pos <= top)
  891. {
  892. top_pos += row_height(current_row++);
  893. }
  894. return {current_column - 1, current_row - 1};
  895. }
  896. void worksheet::sheet_state(xlnt::sheet_state state)
  897. {
  898. page_setup().sheet_state(state);
  899. }
  900. sheet_state worksheet::sheet_state() const
  901. {
  902. return page_setup().sheet_state();
  903. }
  904. void worksheet::add_column_properties(column_t column, const xlnt::column_properties &props)
  905. {
  906. d_->column_properties_[column] = props;
  907. }
  908. bool worksheet::has_column_properties(column_t column) const
  909. {
  910. return d_->column_properties_.find(column) != d_->column_properties_.end();
  911. }
  912. column_properties &worksheet::column_properties(column_t column)
  913. {
  914. return d_->column_properties_[column];
  915. }
  916. const column_properties &worksheet::column_properties(column_t column) const
  917. {
  918. return d_->column_properties_.at(column);
  919. }
  920. row_properties &worksheet::row_properties(row_t row)
  921. {
  922. return d_->row_properties_[row];
  923. }
  924. const row_properties &worksheet::row_properties(row_t row) const
  925. {
  926. return d_->row_properties_.at(row);
  927. }
  928. void worksheet::add_row_properties(row_t row, const xlnt::row_properties &props)
  929. {
  930. d_->row_properties_[row] = props;
  931. }
  932. worksheet::iterator worksheet::begin()
  933. {
  934. return rows().begin();
  935. }
  936. worksheet::iterator worksheet::end()
  937. {
  938. return rows().end();
  939. }
  940. worksheet::const_iterator worksheet::cbegin() const
  941. {
  942. return rows().cbegin();
  943. }
  944. worksheet::const_iterator worksheet::cend() const
  945. {
  946. return rows().cend();
  947. }
  948. worksheet::const_iterator worksheet::begin() const
  949. {
  950. return cbegin();
  951. }
  952. worksheet::const_iterator worksheet::end() const
  953. {
  954. return cend();
  955. }
  956. void worksheet::print_title_rows(row_t start, row_t end)
  957. {
  958. d_->print_title_rows_ = std::make_pair(start, end);
  959. }
  960. optional<std::pair<row_t, row_t>> worksheet::print_title_rows() const
  961. {
  962. return d_->print_title_rows_;
  963. }
  964. void worksheet::print_title_cols(column_t start, column_t end)
  965. {
  966. d_->print_title_cols_ = std::make_pair(start, end);
  967. }
  968. optional<std::pair<column_t, column_t>> worksheet::print_title_cols() const
  969. {
  970. return d_->print_title_cols_;
  971. }
  972. bool worksheet::has_print_titles() const
  973. {
  974. return d_->print_title_cols_.is_set() || d_->print_title_rows_.is_set();
  975. }
  976. void worksheet::clear_print_titles()
  977. {
  978. d_->print_title_rows_.clear();
  979. d_->print_title_cols_.clear();
  980. }
  981. void worksheet::print_area(const std::string &print_area)
  982. {
  983. d_->print_area_ = range_reference::make_absolute(range_reference(print_area));
  984. }
  985. range_reference worksheet::print_area() const
  986. {
  987. return d_->print_area_.get();
  988. }
  989. bool worksheet::has_print_area() const
  990. {
  991. return d_->print_area_.is_set();
  992. }
  993. void worksheet::clear_print_area()
  994. {
  995. return d_->print_area_.clear();
  996. }
  997. bool worksheet::has_view() const
  998. {
  999. return !d_->views_.empty();
  1000. }
  1001. sheet_view &worksheet::view(std::size_t index) const
  1002. {
  1003. return d_->views_.at(index);
  1004. }
  1005. void worksheet::add_view(const sheet_view &new_view)
  1006. {
  1007. d_->views_.push_back(new_view);
  1008. }
  1009. void worksheet::register_comments_in_manifest()
  1010. {
  1011. workbook().register_worksheet_part(*this, relationship_type::comments);
  1012. }
  1013. void worksheet::register_calc_chain_in_manifest()
  1014. {
  1015. workbook().register_workbook_part(relationship_type::calculation_chain);
  1016. }
  1017. bool worksheet::has_phonetic_properties() const
  1018. {
  1019. return d_->phonetic_properties_.is_set();
  1020. }
  1021. const phonetic_pr &worksheet::phonetic_properties() const
  1022. {
  1023. return d_->phonetic_properties_.get();
  1024. }
  1025. void worksheet::phonetic_properties(const phonetic_pr &phonetic_props)
  1026. {
  1027. d_->phonetic_properties_.set(phonetic_props);
  1028. }
  1029. bool worksheet::has_header_footer() const
  1030. {
  1031. return d_->header_footer_.is_set();
  1032. }
  1033. void worksheet::header_footer(const class header_footer &hf)
  1034. {
  1035. d_->header_footer_ = hf;
  1036. }
  1037. void worksheet::clear_page_breaks()
  1038. {
  1039. d_->row_breaks_.clear();
  1040. d_->column_breaks_.clear();
  1041. }
  1042. void worksheet::page_break_at_row(row_t row)
  1043. {
  1044. d_->row_breaks_.push_back(row);
  1045. }
  1046. const std::vector<row_t> &worksheet::page_break_rows() const
  1047. {
  1048. return d_->row_breaks_;
  1049. }
  1050. void worksheet::page_break_at_column(xlnt::column_t column)
  1051. {
  1052. d_->column_breaks_.push_back(column);
  1053. }
  1054. const std::vector<column_t> &worksheet::page_break_columns() const
  1055. {
  1056. return d_->column_breaks_;
  1057. }
  1058. double worksheet::column_width(column_t column) const
  1059. {
  1060. static const auto DefaultColumnWidth = 51.85;
  1061. if (has_column_properties(column))
  1062. {
  1063. return column_properties(column).width.get();
  1064. }
  1065. else
  1066. {
  1067. return points_to_pixels(DefaultColumnWidth, 96.0);
  1068. }
  1069. }
  1070. double worksheet::row_height(row_t row) const
  1071. {
  1072. static const auto DefaultRowHeight = 15.0;
  1073. if (has_row_properties(row) && row_properties(row).height.is_set())
  1074. {
  1075. return row_properties(row).height.get();
  1076. }
  1077. else
  1078. {
  1079. return points_to_pixels(DefaultRowHeight, 96.0);
  1080. }
  1081. }
  1082. void worksheet::garbage_collect_formulae()
  1083. {
  1084. workbook().garbage_collect_formulae();
  1085. }
  1086. void worksheet::parent(xlnt::workbook &wb)
  1087. {
  1088. d_->parent_ = &wb;
  1089. }
  1090. conditional_format worksheet::conditional_format(const range_reference &ref, const condition &when)
  1091. {
  1092. return workbook().d_->stylesheet_.get().add_conditional_format_rule(d_, ref, when);
  1093. }
  1094. path worksheet::path() const
  1095. {
  1096. auto rel = referring_relationship();
  1097. return xlnt::path(rel.source().path().parent().append(rel.target().path()));
  1098. }
  1099. relationship worksheet::referring_relationship() const
  1100. {
  1101. auto &manifest = workbook().manifest();
  1102. auto wb_rel = manifest.relationship(xlnt::path("/"),
  1103. relationship_type::office_document);
  1104. auto ws_rel = manifest.relationship(wb_rel.target().path(),
  1105. workbook().d_->sheet_title_rel_id_map_.at(title()));
  1106. return ws_rel;
  1107. }
  1108. sheet_format_properties worksheet::format_properties() const
  1109. {
  1110. return d_->format_properties_;
  1111. }
  1112. void worksheet::format_properties(const sheet_format_properties &properties)
  1113. {
  1114. d_->format_properties_ = properties;
  1115. }
  1116. bool worksheet::has_drawing() const
  1117. {
  1118. return d_->drawing_.is_set();
  1119. }
  1120. bool worksheet::is_empty() const
  1121. {
  1122. return d_->cell_map_.empty();
  1123. }
  1124. } // namespace xlnt