parent
eb58563b4b
commit
11b055b29f
|
@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
- Support to write merged cells in ODS format [#287](https://github.com/PHPOffice/PhpSpreadsheet/issues/287)
|
- Support to write merged cells in ODS format [#287](https://github.com/PHPOffice/PhpSpreadsheet/issues/287)
|
||||||
|
- Able to set the `topLeftCell` in freeze panes [#261](https://github.com/PHPOffice/PhpSpreadsheet/pull/261)
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
|
|
|
@ -4488,9 +4488,17 @@ class Xls extends BaseReader
|
||||||
// offset: 2; size: 2; position of horizontal split
|
// offset: 2; size: 2; position of horizontal split
|
||||||
$py = self::getUInt2d($recordData, 2);
|
$py = self::getUInt2d($recordData, 2);
|
||||||
|
|
||||||
|
// offset: 4; size: 2; top most visible row in the bottom pane
|
||||||
|
$rwTop = self::getUInt2d($recordData, 4);
|
||||||
|
|
||||||
|
// offset: 6; size: 2; first visible left column in the right pane
|
||||||
|
$colLeft = self::getUInt2d($recordData, 6);
|
||||||
|
|
||||||
if ($this->frozen) {
|
if ($this->frozen) {
|
||||||
// frozen panes
|
// frozen panes
|
||||||
$this->phpSheet->freezePane(Coordinate::stringFromColumnIndex($px + 1) . ($py + 1));
|
$cell = Coordinate::stringFromColumnIndex($px + 1) . ($py + 1);
|
||||||
|
$topLeftCell = Coordinate::stringFromColumnIndex($colLeft + 1) . ($rwTop + 1);
|
||||||
|
$this->phpSheet->freezePane($cell, $topLeftCell);
|
||||||
}
|
}
|
||||||
// unfrozen panes; split windows; not supported by PhpSpreadsheet core
|
// unfrozen panes; split windows; not supported by PhpSpreadsheet core
|
||||||
}
|
}
|
||||||
|
|
|
@ -720,22 +720,23 @@ class Xlsx extends BaseReader
|
||||||
$docSheet->setRightToLeft(self::boolean((string) $xmlSheet->sheetViews->sheetView['rightToLeft']));
|
$docSheet->setRightToLeft(self::boolean((string) $xmlSheet->sheetViews->sheetView['rightToLeft']));
|
||||||
}
|
}
|
||||||
if (isset($xmlSheet->sheetViews->sheetView->pane)) {
|
if (isset($xmlSheet->sheetViews->sheetView->pane)) {
|
||||||
if (isset($xmlSheet->sheetViews->sheetView->pane['topLeftCell'])) {
|
|
||||||
$docSheet->freezePane((string) $xmlSheet->sheetViews->sheetView->pane['topLeftCell']);
|
|
||||||
} else {
|
|
||||||
$xSplit = 0;
|
$xSplit = 0;
|
||||||
$ySplit = 0;
|
$ySplit = 0;
|
||||||
|
$topLeftCell = null;
|
||||||
|
|
||||||
if (isset($xmlSheet->sheetViews->sheetView->pane['xSplit'])) {
|
if (isset($xmlSheet->sheetViews->sheetView->pane['xSplit'])) {
|
||||||
$xSplit = 1 + (int) ($xmlSheet->sheetViews->sheetView->pane['xSplit']);
|
$xSplit = (int) ($xmlSheet->sheetViews->sheetView->pane['xSplit']);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isset($xmlSheet->sheetViews->sheetView->pane['ySplit'])) {
|
if (isset($xmlSheet->sheetViews->sheetView->pane['ySplit'])) {
|
||||||
$ySplit = 1 + (int) ($xmlSheet->sheetViews->sheetView->pane['ySplit']);
|
$ySplit = (int) ($xmlSheet->sheetViews->sheetView->pane['ySplit']);
|
||||||
}
|
}
|
||||||
|
|
||||||
$docSheet->freezePaneByColumnAndRow($xSplit + 1, $ySplit);
|
if (isset($xmlSheet->sheetViews->sheetView->pane['topLeftCell'])) {
|
||||||
|
$topLeftCell = (string) $xmlSheet->sheetViews->sheetView->pane['topLeftCell'];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$docSheet->freezePane(Coordinate::stringFromColumnIndex($xSplit + 1) . ($ySplit + 1), $topLeftCell);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isset($xmlSheet->sheetViews->sheetView->selection)) {
|
if (isset($xmlSheet->sheetViews->sheetView->selection)) {
|
||||||
|
|
|
@ -576,8 +576,14 @@ class ReferenceHelper
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update worksheet: freeze pane
|
// Update worksheet: freeze pane
|
||||||
if ($pSheet->getFreezePane() != '') {
|
if ($pSheet->getFreezePane()) {
|
||||||
$pSheet->freezePane($this->updateCellReference($pSheet->getFreezePane(), $pBefore, $pNumCols, $pNumRows));
|
$splitCell = $pSheet->getFreezePane();
|
||||||
|
$topLeftCell = $pSheet->getTopLeftCell();
|
||||||
|
|
||||||
|
$splitCell = $this->updateCellReference($splitCell, $pBefore, $pNumCols, $pNumRows);
|
||||||
|
$topLeftCell = $this->updateCellReference($topLeftCell, $pBefore, $pNumCols, $pNumRows);
|
||||||
|
|
||||||
|
$pSheet->freezePane($splitCell, $topLeftCell);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Page setup
|
// Page setup
|
||||||
|
|
|
@ -201,9 +201,16 @@ class Worksheet implements IComparable
|
||||||
/**
|
/**
|
||||||
* Freeze pane.
|
* Freeze pane.
|
||||||
*
|
*
|
||||||
* @var string
|
* @var null|string
|
||||||
*/
|
*/
|
||||||
private $freezePane = '';
|
private $freezePane;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default position of the right bottom pane.
|
||||||
|
*
|
||||||
|
* @var null|string
|
||||||
|
*/
|
||||||
|
private $topLeftCell;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Show gridlines?
|
* Show gridlines?
|
||||||
|
@ -1975,27 +1982,33 @@ class Worksheet implements IComparable
|
||||||
/**
|
/**
|
||||||
* Freeze Pane.
|
* Freeze Pane.
|
||||||
*
|
*
|
||||||
* @param string $pCell Cell (i.e. A2)
|
|
||||||
* Examples:
|
* Examples:
|
||||||
* A2 will freeze the rows above cell A2 (i.e row 1)
|
*
|
||||||
* B1 will freeze the columns to the left of cell B1 (i.e column A)
|
* - A2 will freeze the rows above cell A2 (i.e row 1)
|
||||||
* B2 will freeze the rows above and to the left of cell A2
|
* - B1 will freeze the columns to the left of cell B1 (i.e column A)
|
||||||
* (i.e row 1 and column A)
|
* - B2 will freeze the rows above and to the left of cell A2 (i.e row 1 and column A)
|
||||||
|
*
|
||||||
|
* @param null|string $cell Position of the split
|
||||||
|
* @param null|string $topLeftCell default position of the right bottom pane
|
||||||
*
|
*
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
*
|
*
|
||||||
* @return Worksheet
|
* @return Worksheet
|
||||||
*/
|
*/
|
||||||
public function freezePane($pCell)
|
public function freezePane($cell, $topLeftCell = null)
|
||||||
{
|
{
|
||||||
// Uppercase coordinate
|
if (is_string($cell) && (strpos($cell, ':') !== false || strpos($cell, ',') !== false)) {
|
||||||
$pCell = strtoupper($pCell);
|
|
||||||
if (strpos($pCell, ':') === false && strpos($pCell, ',') === false) {
|
|
||||||
$this->freezePane = $pCell;
|
|
||||||
} else {
|
|
||||||
throw new Exception('Freeze pane can not be set on a range of cells.');
|
throw new Exception('Freeze pane can not be set on a range of cells.');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($cell !== null && $topLeftCell === null) {
|
||||||
|
$coordinate = Coordinate::coordinateFromString($cell);
|
||||||
|
$topLeftCell = $coordinate[0] . ($coordinate[1] + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->freezePane = $cell;
|
||||||
|
$this->topLeftCell = $topLeftCell;
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2005,8 +2018,6 @@ class Worksheet implements IComparable
|
||||||
* @param int $columnIndex Numeric column coordinate of the cell
|
* @param int $columnIndex Numeric column coordinate of the cell
|
||||||
* @param int $row Numeric row coordinate of the cell
|
* @param int $row Numeric row coordinate of the cell
|
||||||
*
|
*
|
||||||
* @throws Exception
|
|
||||||
*
|
|
||||||
* @return Worksheet
|
* @return Worksheet
|
||||||
*/
|
*/
|
||||||
public function freezePaneByColumnAndRow($columnIndex, $row)
|
public function freezePaneByColumnAndRow($columnIndex, $row)
|
||||||
|
@ -2021,7 +2032,17 @@ class Worksheet implements IComparable
|
||||||
*/
|
*/
|
||||||
public function unfreezePane()
|
public function unfreezePane()
|
||||||
{
|
{
|
||||||
return $this->freezePane('');
|
return $this->freezePane(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the default position of the right bottom pane.
|
||||||
|
*
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public function getTopLeftCell()
|
||||||
|
{
|
||||||
|
return $this->topLeftCell;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -2622,6 +2643,7 @@ class Worksheet implements IComparable
|
||||||
// Identify the range that we need to extract from the worksheet
|
// Identify the range that we need to extract from the worksheet
|
||||||
$maxCol = $this->getHighestColumn();
|
$maxCol = $this->getHighestColumn();
|
||||||
$maxRow = $this->getHighestRow();
|
$maxRow = $this->getHighestRow();
|
||||||
|
|
||||||
// Return
|
// Return
|
||||||
return $this->rangeToArray('A1:' . $maxCol . $maxRow, $nullValue, $calculateFormulas, $formatData, $returnCellRef);
|
return $this->rangeToArray('A1:' . $maxCol . $maxRow, $nullValue, $calculateFormulas, $formatData, $returnCellRef);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1589,10 +1589,15 @@ class Worksheet extends BIFFwriter
|
||||||
private function writePanes()
|
private function writePanes()
|
||||||
{
|
{
|
||||||
$panes = [];
|
$panes = [];
|
||||||
if ($freezePane = $this->phpSheet->getFreezePane()) {
|
if ($this->phpSheet->getFreezePane()) {
|
||||||
list($column, $row) = Coordinate::coordinateFromString($freezePane);
|
list($column, $row) = Coordinate::coordinateFromString($this->phpSheet->getFreezePane());
|
||||||
$panes[0] = $row - 1;
|
$panes[0] = Coordinate::columnIndexFromString($column) - 1;
|
||||||
$panes[1] = Coordinate::columnIndexFromString($column) - 1;
|
$panes[1] = $row - 1;
|
||||||
|
|
||||||
|
list($leftMostColumn, $topRow) = Coordinate::coordinateFromString($this->phpSheet->getTopLeftCell());
|
||||||
|
//Coordinates are zero-based in xls files
|
||||||
|
$panes[2] = $topRow - 1;
|
||||||
|
$panes[3] = Coordinate::columnIndexFromString($leftMostColumn) - 1;
|
||||||
} else {
|
} else {
|
||||||
// thaw panes
|
// thaw panes
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -244,31 +244,31 @@ class Worksheet extends WriterPart
|
||||||
|
|
||||||
// Pane
|
// Pane
|
||||||
$pane = '';
|
$pane = '';
|
||||||
$topLeftCell = $pSheet->getFreezePane();
|
if ($pSheet->getFreezePane()) {
|
||||||
if (($topLeftCell != '') && ($topLeftCell != 'A1')) {
|
list($xSplit, $ySplit) = Coordinate::coordinateFromString($pSheet->getFreezePane());
|
||||||
$activeCell = $topLeftCell;
|
|
||||||
// Calculate freeze coordinates
|
|
||||||
$xSplit = $ySplit = 0;
|
|
||||||
|
|
||||||
list($xSplit, $ySplit) = Coordinate::coordinateFromString($topLeftCell);
|
|
||||||
$xSplit = Coordinate::columnIndexFromString($xSplit);
|
$xSplit = Coordinate::columnIndexFromString($xSplit);
|
||||||
|
--$xSplit;
|
||||||
|
--$ySplit;
|
||||||
|
|
||||||
|
$topLeftCell = $pSheet->getTopLeftCell();
|
||||||
|
$activeCell = $topLeftCell;
|
||||||
|
|
||||||
// pane
|
// pane
|
||||||
$pane = 'topRight';
|
$pane = 'topRight';
|
||||||
$objWriter->startElement('pane');
|
$objWriter->startElement('pane');
|
||||||
if ($xSplit > 1) {
|
if ($xSplit > 0) {
|
||||||
$objWriter->writeAttribute('xSplit', $xSplit - 1);
|
$objWriter->writeAttribute('xSplit', $xSplit);
|
||||||
}
|
}
|
||||||
if ($ySplit > 1) {
|
if ($ySplit > 0) {
|
||||||
$objWriter->writeAttribute('ySplit', $ySplit - 1);
|
$objWriter->writeAttribute('ySplit', $ySplit);
|
||||||
$pane = ($xSplit > 1) ? 'bottomRight' : 'bottomLeft';
|
$pane = ($xSplit > 0) ? 'bottomRight' : 'bottomLeft';
|
||||||
}
|
}
|
||||||
$objWriter->writeAttribute('topLeftCell', $topLeftCell);
|
$objWriter->writeAttribute('topLeftCell', $topLeftCell);
|
||||||
$objWriter->writeAttribute('activePane', $pane);
|
$objWriter->writeAttribute('activePane', $pane);
|
||||||
$objWriter->writeAttribute('state', 'frozen');
|
$objWriter->writeAttribute('state', 'frozen');
|
||||||
$objWriter->endElement();
|
$objWriter->endElement();
|
||||||
|
|
||||||
if (($xSplit > 1) && ($ySplit > 1)) {
|
if (($xSplit > 0) && ($ySplit > 0)) {
|
||||||
// Write additional selections if more than two panes (ie both an X and a Y split)
|
// Write additional selections if more than two panes (ie both an X and a Y split)
|
||||||
$objWriter->startElement('selection');
|
$objWriter->startElement('selection');
|
||||||
$objWriter->writeAttribute('pane', 'topRight');
|
$objWriter->writeAttribute('pane', 'topRight');
|
||||||
|
|
|
@ -0,0 +1,37 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace PhpOffice\PhpSpreadsheetTests\Reader;
|
||||||
|
|
||||||
|
use PhpOffice\PhpSpreadsheet\Reader\Xls as ReaderXls;
|
||||||
|
use PhpOffice\PhpSpreadsheet\Shared\File;
|
||||||
|
use PhpOffice\PhpSpreadsheet\Spreadsheet;
|
||||||
|
use PhpOffice\PhpSpreadsheet\Writer\Xls as WriterXls;
|
||||||
|
use PHPUnit_Framework_TestCase;
|
||||||
|
|
||||||
|
class XlsTest extends PHPUnit_Framework_TestCase
|
||||||
|
{
|
||||||
|
public function testFreezePane()
|
||||||
|
{
|
||||||
|
$filename = tempnam(File::sysGetTempDir(), 'phpspreadsheet');
|
||||||
|
|
||||||
|
$cellSplit = 'B2';
|
||||||
|
$topLeftCell = 'E5';
|
||||||
|
|
||||||
|
$spreadsheet = new Spreadsheet();
|
||||||
|
$active = $spreadsheet->getActiveSheet();
|
||||||
|
$active->freezePane($cellSplit, $topLeftCell);
|
||||||
|
|
||||||
|
$writer = new WriterXls($spreadsheet);
|
||||||
|
$writer->save($filename);
|
||||||
|
|
||||||
|
// Read written file
|
||||||
|
$reader = new ReaderXls();
|
||||||
|
$reloadedSpreadsheet = $reader->load($filename);
|
||||||
|
$reloadedActive = $reloadedSpreadsheet->getActiveSheet();
|
||||||
|
$actualCellSplit = $reloadedActive->getFreezePane();
|
||||||
|
$actualTopLeftCell = $reloadedActive->getTopLeftCell();
|
||||||
|
|
||||||
|
self::assertSame($cellSplit, $actualCellSplit, 'should be able to set freeze pane');
|
||||||
|
self::assertSame($topLeftCell, $actualTopLeftCell, 'should be able to set the top left cell');
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,7 +2,10 @@
|
||||||
|
|
||||||
namespace PhpOffice\PhpSpreadsheetTests\Reader;
|
namespace PhpOffice\PhpSpreadsheetTests\Reader;
|
||||||
|
|
||||||
use PhpOffice\PhpSpreadsheet\Reader\Xlsx;
|
use PhpOffice\PhpSpreadsheet\Reader\Xlsx as ReaderXlsx;
|
||||||
|
use PhpOffice\PhpSpreadsheet\Shared\File;
|
||||||
|
use PhpOffice\PhpSpreadsheet\Spreadsheet;
|
||||||
|
use PhpOffice\PhpSpreadsheet\Writer\Xlsx as WriterXlsx;
|
||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
|
|
||||||
class XlsxTest extends TestCase
|
class XlsxTest extends TestCase
|
||||||
|
@ -13,7 +16,32 @@ class XlsxTest extends TestCase
|
||||||
public function testLoadXlsxWithoutCellReference()
|
public function testLoadXlsxWithoutCellReference()
|
||||||
{
|
{
|
||||||
$filename = './data/Reader/XLSX/without_cell_reference.xlsx';
|
$filename = './data/Reader/XLSX/without_cell_reference.xlsx';
|
||||||
$reader = new Xlsx();
|
$reader = new ReaderXlsx();
|
||||||
$reader->load($filename);
|
$reader->load($filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testFreezePane()
|
||||||
|
{
|
||||||
|
$filename = tempnam(File::sysGetTempDir(), 'phpspreadsheet');
|
||||||
|
|
||||||
|
$cellSplit = 'B2';
|
||||||
|
$topLeftCell = 'E5';
|
||||||
|
|
||||||
|
$spreadsheet = new Spreadsheet();
|
||||||
|
$active = $spreadsheet->getActiveSheet();
|
||||||
|
$active->freezePane($cellSplit, $topLeftCell);
|
||||||
|
|
||||||
|
$writer = new WriterXlsx($spreadsheet);
|
||||||
|
$writer->save($filename);
|
||||||
|
|
||||||
|
// Read written file
|
||||||
|
$reader = new ReaderXlsx();
|
||||||
|
$reloadedSpreadsheet = $reader->load($filename);
|
||||||
|
$reloadedActive = $reloadedSpreadsheet->getActiveSheet();
|
||||||
|
$actualCellSplit = $reloadedActive->getFreezePane();
|
||||||
|
$actualTopLeftCell = $reloadedActive->getTopLeftCell();
|
||||||
|
|
||||||
|
self::assertSame($cellSplit, $actualCellSplit, 'should be able to set freeze pane');
|
||||||
|
self::assertSame($topLeftCell, $actualTopLeftCell, 'should be able to set the top left cell');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue