Skip to content

Commit

Permalink
Support workbook view attributes for Xlsx format
Browse files Browse the repository at this point in the history
Editing a Xlsx document using PhpSpreadsheet should preserve the workbook
view attributes of that document. For example, if the worksheet tabs are
hidden in the original document, they should remain hidden after updating.

Fixes PHPOffice#523
Fixes PHPOffice#525
  • Loading branch information
billblume authored and Frederic Delaunay committed Oct 29, 2018
1 parent 4f2b624 commit 4b71e5f
Show file tree
Hide file tree
Showing 5 changed files with 429 additions and 10 deletions.
5 changes: 4 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,14 @@ and this project adheres to [Semantic Versioning](http://semver.org/).

## [Unreleased]

- Cell formats with escaped spaces were causing incorrect date formatting - [#557](https://github.com/PHPOffice/PhpSpreadsheet/issues/557)
### Added

- Support workbook view attributes for Xlsx format - [#523](https://github.com/PHPOffice/PhpSpreadsheet/issues/523)

### Fixed

- Xlsx reader crashed when reading a file with workbook protection - [#553](https://github.com/PHPOffice/PhpSpreadsheet/pull/553)
- Cell formats with escaped spaces were causing incorrect date formatting - [#557](https://github.com/PHPOffice/PhpSpreadsheet/issues/557)

## [1.3.1] - 2018-06-12

Expand Down
67 changes: 66 additions & 1 deletion src/PhpSpreadsheet/Reader/Xlsx.php
Original file line number Diff line number Diff line change
Expand Up @@ -1988,8 +1988,10 @@ public function load($pFilename)
}

if ((!$this->readDataOnly) || (!empty($this->loadSheetsOnly))) {
$workbookView = $xmlWorkbook->bookViews->workbookView;

// active sheet index
$activeTab = (int) ($xmlWorkbook->bookViews->workbookView['activeTab']); // refers to old sheet index
$activeTab = (int) ($workbookView['activeTab']); // refers to old sheet index

// keep active sheet index if sheet is still loaded, else first sheet is set as the active
if (isset($mapSheetId[$activeTab]) && $mapSheetId[$activeTab] !== null) {
Expand All @@ -2000,6 +2002,46 @@ public function load($pFilename)
}
$excel->setActiveSheetIndex(0);
}

if (isset($workbookView['showHorizontalScroll'])) {
$showHorizontalScroll = (string) $workbookView['showHorizontalScroll'];
$excel->setShowHorizontalScroll($this->castXsdBooleanToBool($showHorizontalScroll));
}

if (isset($workbookView['showVerticalScroll'])) {
$showVerticalScroll = (string) $workbookView['showVerticalScroll'];
$excel->setShowVerticalScroll($this->castXsdBooleanToBool($showVerticalScroll));
}

if (isset($workbookView['showSheetTabs'])) {
$showSheetTabs = (string) $workbookView['showSheetTabs'];
$excel->setShowSheetTabs($this->castXsdBooleanToBool($showSheetTabs));
}

if (isset($workbookView['minimized'])) {
$minimized = (string) $workbookView['minimized'];
$excel->setMinimized($this->castXsdBooleanToBool($minimized));
}

if (isset($workbookView['autoFilterDateGrouping'])) {
$autoFilterDateGrouping = (string) $workbookView['autoFilterDateGrouping'];
$excel->setAutoFilterDateGrouping($this->castXsdBooleanToBool($autoFilterDateGrouping));
}

if (isset($workbookView['firstSheet'])) {
$firstSheet = (string) $workbookView['firstSheet'];
$excel->setFirstSheetIndex((int) $firstSheet);
}

if (isset($workbookView['visibility'])) {
$visibility = (string) $workbookView['visibility'];
$excel->setVisibility($visibility);
}

if (isset($workbookView['tabRatio'])) {
$tabRatio = (string) $workbookView['tabRatio'];
$excel->setTabRatio((int) $tabRatio);
}
}

break;
Expand Down Expand Up @@ -2490,4 +2532,27 @@ private function readPrinterSettings(Spreadsheet $excel, ZipArchive $zip, $dir,
}
unset($unparsedPrinterSettings);
}

/**
* Convert an 'xsd:boolean' XML value to a PHP boolean value.
* A valid 'xsd:boolean' XML value can be one of the following
* four values: 'true', 'false', '1', '0'. It is case sensitive.
*
* Note that just doing '(bool) $xsdBoolean' is not safe,
* since '(bool) "false"' returns true.
*
* @see https://www.w3.org/TR/xmlschema11-2/#boolean
*
* @param string $xsdBoolean An XML string value of type 'xsd:boolean'
*
* @return bool Boolean value
*/
private function castXsdBooleanToBool($xsdBoolean)
{
if ($xsdBoolean === 'false') {
return false;
}

return (bool) $xsdBoolean;
}
}
271 changes: 271 additions & 0 deletions src/PhpSpreadsheet/Spreadsheet.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,17 @@

class Spreadsheet
{
// Allowable values for workbook window visilbity
const VISIBILITY_VISIBLE = 'visible';
const VISIBILITY_HIDDEN = 'hidden';
const VISIBILITY_VERY_HIDDEN = 'veryHidden';

private static $workbookViewVisibilityValues = [
self::VISIBILITY_VISIBLE,
self::VISIBILITY_HIDDEN,
self::VISIBILITY_VERY_HIDDEN,
];

/**
* Unique ID.
*
Expand Down Expand Up @@ -123,6 +134,67 @@ class Spreadsheet
*/
private $unparsedLoadedData = [];

/**
* Controls visibility of the horizonal scroll bar in the application.
*
* @var bool
*/
private $showHorizontalScroll = true;

/**
* Controls visibility of the horizonal scroll bar in the application.
*
* @var bool
*/
private $showVerticalScroll = true;

/**
* Controls visibility of the sheet tabs in the application.
*
* @var bool
*/
private $showSheetTabs = true;

/**
* Specifies a boolean value that indicates whether the workbook window
* is minimized.
*
* @var bool
*/
private $minimized = false;

/**
* Specifies a boolean value that indicates whether to group dates
* when presenting the user with filtering optiomd in the user
* interface.
*
* @var bool
*/
private $autoFilterDateGrouping = true;

/**
* Specifies the index to the first sheet in the book view.
*
* @var int
*/
private $firstSheetIndex = 0;

/**
* Specifies the visible status of the workbook.
*
* @var string
*/
private $visibility = self::VISIBILITY_VISIBLE;

/**
* Specifies the ratio between the workbook tabs bar and the horizontal
* scroll bar. TabRatio is assumed to be out of 1000 of the horizontal
* window width.
*
* @var int
*/
private $tabRatio = 600;

/**
* The workbook has macros ?
*
Expand Down Expand Up @@ -1252,4 +1324,203 @@ public function getID()
{
return $this->uniqueID;
}

/**
* Get the visibility of the horizonal scroll bar in the application.
*
* @return bool True if horizonal scroll bar is visible
*/
public function getShowHorizontalScroll()
{
return $this->showHorizontalScroll;
}

/**
* Set the visibility of the horizonal scroll bar in the application.
*
* @param bool $showHorizontalScroll True if horizonal scroll bar is visible
*/
public function setShowHorizontalScroll($showHorizontalScroll)
{
$this->showHorizontalScroll = (bool) $showHorizontalScroll;
}

/**
* Get the visibility of the vertical scroll bar in the application.
*
* @return bool True if vertical scroll bar is visible
*/
public function getShowVerticalScroll()
{
return $this->showVerticalScroll;
}

/**
* Set the visibility of the vertical scroll bar in the application.
*
* @param bool $showVerticalScroll True if vertical scroll bar is visible
*/
public function setShowVerticalScroll($showVerticalScroll)
{
$this->showVerticalScroll = (bool) $showVerticalScroll;
}

/**
* Get the visibility of the sheet tabs in the application.
*
* @return bool True if the sheet tabs are visible
*/
public function getShowSheetTabs()
{
return $this->showSheetTabs;
}

/**
* Set the visibility of the sheet tabs in the application.
*
* @param bool $showSheetTabs True if sheet tabs are visible
*/
public function setShowSheetTabs($showSheetTabs)
{
$this->showSheetTabs = (bool) $showSheetTabs;
}

/**
* Return whether the workbook window is minimized.
*
* @return bool true if workbook window is minimized
*/
public function getMinimized()
{
return $this->minimized;
}

/**
* Set whether the workbook window is minimized.
*
* @param bool $minimized true if workbook window is minimized
*/
public function setMinimized($minimized)
{
$this->minimized = (bool) $minimized;
}

/**
* Return whether to group dates when presenting the user with
* filtering optiomd in the user interface.
*
* @return bool true if workbook window is minimized
*/
public function getAutoFilterDateGrouping()
{
return $this->autoFilterDateGrouping;
}

/**
* Set whether to group dates when presenting the user with
* filtering optiomd in the user interface.
*
* @param bool $autoFilterDateGrouping true if workbook window is minimized
*/
public function setAutoFilterDateGrouping($autoFilterDateGrouping)
{
$this->autoFilterDateGrouping = (bool) $autoFilterDateGrouping;
}

/**
* Return the first sheet in the book view.
*
* @return int First sheet in book view
*/
public function getFirstSheetIndex()
{
return $this->firstSheetIndex;
}

/**
* Set the first sheet in the book view.
*
* @param int $firstSheetIndex First sheet in book view
*
* @throws Exception if the given value is invalid
*/
public function setFirstSheetIndex($firstSheetIndex)
{
if ($firstSheetIndex >= 0) {
$this->firstSheetIndex = (int) $firstSheetIndex;
} else {
throw new Exception('First sheet index must be a positive integer.');
}
}

/**
* Return the visibility status of the workbook.
*
* This may be one of the following three values:
* - visibile
*
* @return string Visible status
*/
public function getVisibility()
{
return $this->visibility;
}

/**
* Set the visibility status of the workbook.
*
* Valid values are:
* - 'visible' (self::VISIBILITY_VISIBLE):
* Workbook window is visible
* - 'hidden' (self::VISIBILITY_HIDDEN):
* Workbook window is hidden, but can be shown by the user
* via the user interface
* - 'veryHidden' (self::VISIBILITY_VERY_HIDDEN):
* Workbook window is hidden and cannot be shown in the
* user interface.
*
* @param string $visibility visibility status of the workbook
*
* @throws Exception if the given value is invalid
*/
public function setVisibility($visibility)
{
if ($visibility === null) {
$visibility = self::VISIBILITY_VISIBLE;
}

if (in_array($visibility, self::$workbookViewVisibilityValues)) {
$this->visibility = $visibility;
} else {
throw new Exception('Invalid visibility value.');
}
}

/**
* Get the ratio between the workbook tabs bar and the horizontal scroll bar.
* TabRatio is assumed to be out of 1000 of the horizontal window width.
*
* @return int Ratio between the workbook tabs bar and the horizontal scroll bar
*/
public function getTabRatio()
{
return $this->tabRatio;
}

/**
* Set the ratio between the workbook tabs bar and the horizontal scroll bar
* TabRatio is assumed to be out of 1000 of the horizontal window width.
*
* @param int $tabRatio Ratio between the tabs bar and the horizontal scroll bar
*
* @throws Exception if the given value is invalid
*/
public function setTabRatio($tabRatio)
{
if ($tabRatio >= 0 || $tabRatio <= 1000) {
$this->tabRatio = (int) $tabRatio;
} else {
throw new Exception('Tab ratio must be between 0 and 1000.');
}
}
}
Loading

0 comments on commit 4b71e5f

Please sign in to comment.