Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1441 ariadna 1
<?php
2
 
3
namespace PhpOffice\PhpSpreadsheet\Reader\Gnumeric;
4
 
5
use PhpOffice\PhpSpreadsheet\Cell\Coordinate;
6
use PhpOffice\PhpSpreadsheet\Shared\Date;
7
use PhpOffice\PhpSpreadsheet\Spreadsheet;
8
use PhpOffice\PhpSpreadsheet\Style\Alignment;
9
use PhpOffice\PhpSpreadsheet\Style\Border;
10
use PhpOffice\PhpSpreadsheet\Style\Borders;
11
use PhpOffice\PhpSpreadsheet\Style\Fill;
12
use PhpOffice\PhpSpreadsheet\Style\Font;
13
use SimpleXMLElement;
14
 
15
class Styles
16
{
17
    private Spreadsheet $spreadsheet;
18
 
19
    protected bool $readDataOnly;
20
 
21
    public static array $mappings = [
22
        'borderStyle' => [
23
            '0' => Border::BORDER_NONE,
24
            '1' => Border::BORDER_THIN,
25
            '2' => Border::BORDER_MEDIUM,
26
            '3' => Border::BORDER_SLANTDASHDOT,
27
            '4' => Border::BORDER_DASHED,
28
            '5' => Border::BORDER_THICK,
29
            '6' => Border::BORDER_DOUBLE,
30
            '7' => Border::BORDER_DOTTED,
31
            '8' => Border::BORDER_MEDIUMDASHED,
32
            '9' => Border::BORDER_DASHDOT,
33
            '10' => Border::BORDER_MEDIUMDASHDOT,
34
            '11' => Border::BORDER_DASHDOTDOT,
35
            '12' => Border::BORDER_MEDIUMDASHDOTDOT,
36
            '13' => Border::BORDER_MEDIUMDASHDOTDOT,
37
        ],
38
        'fillType' => [
39
            '1' => Fill::FILL_SOLID,
40
            '2' => Fill::FILL_PATTERN_DARKGRAY,
41
            '3' => Fill::FILL_PATTERN_MEDIUMGRAY,
42
            '4' => Fill::FILL_PATTERN_LIGHTGRAY,
43
            '5' => Fill::FILL_PATTERN_GRAY125,
44
            '6' => Fill::FILL_PATTERN_GRAY0625,
45
            '7' => Fill::FILL_PATTERN_DARKHORIZONTAL, // horizontal stripe
46
            '8' => Fill::FILL_PATTERN_DARKVERTICAL, // vertical stripe
47
            '9' => Fill::FILL_PATTERN_DARKDOWN, // diagonal stripe
48
            '10' => Fill::FILL_PATTERN_DARKUP, // reverse diagonal stripe
49
            '11' => Fill::FILL_PATTERN_DARKGRID, // diagoanl crosshatch
50
            '12' => Fill::FILL_PATTERN_DARKTRELLIS, // thick diagonal crosshatch
51
            '13' => Fill::FILL_PATTERN_LIGHTHORIZONTAL,
52
            '14' => Fill::FILL_PATTERN_LIGHTVERTICAL,
53
            '15' => Fill::FILL_PATTERN_LIGHTUP,
54
            '16' => Fill::FILL_PATTERN_LIGHTDOWN,
55
            '17' => Fill::FILL_PATTERN_LIGHTGRID, // thin horizontal crosshatch
56
            '18' => Fill::FILL_PATTERN_LIGHTTRELLIS, // thin diagonal crosshatch
57
        ],
58
        'horizontal' => [
59
            '1' => Alignment::HORIZONTAL_GENERAL,
60
            '2' => Alignment::HORIZONTAL_LEFT,
61
            '4' => Alignment::HORIZONTAL_RIGHT,
62
            '8' => Alignment::HORIZONTAL_CENTER,
63
            '16' => Alignment::HORIZONTAL_CENTER_CONTINUOUS,
64
            '32' => Alignment::HORIZONTAL_JUSTIFY,
65
            '64' => Alignment::HORIZONTAL_CENTER_CONTINUOUS,
66
        ],
67
        'underline' => [
68
            '1' => Font::UNDERLINE_SINGLE,
69
            '2' => Font::UNDERLINE_DOUBLE,
70
            '3' => Font::UNDERLINE_SINGLEACCOUNTING,
71
            '4' => Font::UNDERLINE_DOUBLEACCOUNTING,
72
        ],
73
        'vertical' => [
74
            '1' => Alignment::VERTICAL_TOP,
75
            '2' => Alignment::VERTICAL_BOTTOM,
76
            '4' => Alignment::VERTICAL_CENTER,
77
            '8' => Alignment::VERTICAL_JUSTIFY,
78
        ],
79
    ];
80
 
81
    public function __construct(Spreadsheet $spreadsheet, bool $readDataOnly)
82
    {
83
        $this->spreadsheet = $spreadsheet;
84
        $this->readDataOnly = $readDataOnly;
85
    }
86
 
87
    public function read(SimpleXMLElement $sheet, int $maxRow, int $maxCol): void
88
    {
89
        if ($sheet->Styles->StyleRegion !== null) {
90
            $this->readStyles($sheet->Styles->StyleRegion, $maxRow, $maxCol);
91
        }
92
    }
93
 
94
    private function readStyles(SimpleXMLElement $styleRegion, int $maxRow, int $maxCol): void
95
    {
96
        foreach ($styleRegion as $style) {
97
            $styleAttributes = $style->attributes();
98
            if ($styleAttributes !== null && ($styleAttributes['startRow'] <= $maxRow) && ($styleAttributes['startCol'] <= $maxCol)) {
99
                $cellRange = $this->readStyleRange($styleAttributes, $maxCol, $maxRow);
100
 
101
                $styleAttributes = $style->Style->attributes();
102
 
103
                $styleArray = [];
104
                // We still set the number format mask for date/time values, even if readDataOnly is true
105
                //    so that we can identify whether a float is a float or a date value
106
                $formatCode = $styleAttributes ? (string) $styleAttributes['Format'] : null;
107
                if ($formatCode && Date::isDateTimeFormatCode($formatCode)) {
108
                    $styleArray['numberFormat']['formatCode'] = $formatCode;
109
                }
110
                if ($this->readDataOnly === false && $styleAttributes !== null) {
111
                    //    If readDataOnly is false, we set all formatting information
112
                    $styleArray['numberFormat']['formatCode'] = $formatCode;
113
                    $styleArray = $this->readStyle($styleArray, $styleAttributes, $style);
114
                }
115
                $this->spreadsheet->getActiveSheet()->getStyle($cellRange)->applyFromArray($styleArray);
116
            }
117
        }
118
    }
119
 
120
    private function addBorderDiagonal(SimpleXMLElement $srssb, array &$styleArray): void
121
    {
122
        if (isset($srssb->Diagonal, $srssb->{'Rev-Diagonal'})) {
123
            $styleArray['borders']['diagonal'] = self::parseBorderAttributes($srssb->Diagonal->attributes());
124
            $styleArray['borders']['diagonalDirection'] = Borders::DIAGONAL_BOTH;
125
        } elseif (isset($srssb->Diagonal)) {
126
            $styleArray['borders']['diagonal'] = self::parseBorderAttributes($srssb->Diagonal->attributes());
127
            $styleArray['borders']['diagonalDirection'] = Borders::DIAGONAL_UP;
128
        } elseif (isset($srssb->{'Rev-Diagonal'})) {
129
            $styleArray['borders']['diagonal'] = self::parseBorderAttributes($srssb->{'Rev-Diagonal'}->attributes());
130
            $styleArray['borders']['diagonalDirection'] = Borders::DIAGONAL_DOWN;
131
        }
132
    }
133
 
134
    private function addBorderStyle(SimpleXMLElement $srssb, array &$styleArray, string $direction): void
135
    {
136
        $ucDirection = ucfirst($direction);
137
        if (isset($srssb->$ucDirection)) {
138
            $styleArray['borders'][$direction] = self::parseBorderAttributes($srssb->$ucDirection->attributes());
139
        }
140
    }
141
 
142
    private function calcRotation(SimpleXMLElement $styleAttributes): int
143
    {
144
        $rotation = (int) $styleAttributes->Rotation;
145
        if ($rotation >= 270 && $rotation <= 360) {
146
            $rotation -= 360;
147
        }
148
        $rotation = (abs($rotation) > 90) ? 0 : $rotation;
149
 
150
        return $rotation;
151
    }
152
 
153
    private static function addStyle(array &$styleArray, string $key, string $value): void
154
    {
155
        if (array_key_exists($value, self::$mappings[$key])) {
156
            $styleArray[$key] = self::$mappings[$key][$value];
157
        }
158
    }
159
 
160
    private static function addStyle2(array &$styleArray, string $key1, string $key, string $value): void
161
    {
162
        if (array_key_exists($value, self::$mappings[$key])) {
163
            $styleArray[$key1][$key] = self::$mappings[$key][$value];
164
        }
165
    }
166
 
167
    private static function parseBorderAttributes(?SimpleXMLElement $borderAttributes): array
168
    {
169
        $styleArray = [];
170
        if ($borderAttributes !== null) {
171
            if (isset($borderAttributes['Color'])) {
172
                $styleArray['color']['rgb'] = self::parseGnumericColour($borderAttributes['Color']);
173
            }
174
 
175
            self::addStyle($styleArray, 'borderStyle', (string) $borderAttributes['Style']);
176
        }
177
 
178
        return $styleArray;
179
    }
180
 
181
    private static function parseGnumericColour(string $gnmColour): string
182
    {
183
        [$gnmR, $gnmG, $gnmB] = explode(':', $gnmColour);
184
        $gnmR = substr(str_pad($gnmR, 4, '0', STR_PAD_RIGHT), 0, 2);
185
        $gnmG = substr(str_pad($gnmG, 4, '0', STR_PAD_RIGHT), 0, 2);
186
        $gnmB = substr(str_pad($gnmB, 4, '0', STR_PAD_RIGHT), 0, 2);
187
 
188
        return $gnmR . $gnmG . $gnmB;
189
    }
190
 
191
    private function addColors(array &$styleArray, SimpleXMLElement $styleAttributes): void
192
    {
193
        $RGB = self::parseGnumericColour((string) $styleAttributes['Fore']);
194
        $styleArray['font']['color']['rgb'] = $RGB;
195
        $RGB = self::parseGnumericColour((string) $styleAttributes['Back']);
196
        $shade = (string) $styleAttributes['Shade'];
197
        if (($RGB !== '000000') || ($shade !== '0')) {
198
            $RGB2 = self::parseGnumericColour((string) $styleAttributes['PatternColor']);
199
            if ($shade === '1') {
200
                $styleArray['fill']['startColor']['rgb'] = $RGB;
201
                $styleArray['fill']['endColor']['rgb'] = $RGB2;
202
            } else {
203
                $styleArray['fill']['endColor']['rgb'] = $RGB;
204
                $styleArray['fill']['startColor']['rgb'] = $RGB2;
205
            }
206
            self::addStyle2($styleArray, 'fill', 'fillType', $shade);
207
        }
208
    }
209
 
210
    private function readStyleRange(SimpleXMLElement $styleAttributes, int $maxCol, int $maxRow): string
211
    {
212
        $startColumn = Coordinate::stringFromColumnIndex((int) $styleAttributes['startCol'] + 1);
213
        $startRow = $styleAttributes['startRow'] + 1;
214
 
215
        $endColumn = ($styleAttributes['endCol'] > $maxCol) ? $maxCol : (int) $styleAttributes['endCol'];
216
        $endColumn = Coordinate::stringFromColumnIndex($endColumn + 1);
217
 
218
        $endRow = 1 + (($styleAttributes['endRow'] > $maxRow) ? $maxRow : (int) $styleAttributes['endRow']);
219
        $cellRange = $startColumn . $startRow . ':' . $endColumn . $endRow;
220
 
221
        return $cellRange;
222
    }
223
 
224
    private function readStyle(array $styleArray, SimpleXMLElement $styleAttributes, SimpleXMLElement $style): array
225
    {
226
        self::addStyle2($styleArray, 'alignment', 'horizontal', (string) $styleAttributes['HAlign']);
227
        self::addStyle2($styleArray, 'alignment', 'vertical', (string) $styleAttributes['VAlign']);
228
        $styleArray['alignment']['wrapText'] = $styleAttributes['WrapText'] == '1';
229
        $styleArray['alignment']['textRotation'] = $this->calcRotation($styleAttributes);
230
        $styleArray['alignment']['shrinkToFit'] = $styleAttributes['ShrinkToFit'] == '1';
231
        $styleArray['alignment']['indent'] = ((int) ($styleAttributes['Indent']) > 0) ? $styleAttributes['indent'] : 0;
232
 
233
        $this->addColors($styleArray, $styleAttributes);
234
 
235
        $fontAttributes = $style->Style->Font->attributes();
236
        if ($fontAttributes !== null) {
237
            $styleArray['font']['name'] = (string) $style->Style->Font;
238
            $styleArray['font']['size'] = (int) ($fontAttributes['Unit']);
239
            $styleArray['font']['bold'] = $fontAttributes['Bold'] == '1';
240
            $styleArray['font']['italic'] = $fontAttributes['Italic'] == '1';
241
            $styleArray['font']['strikethrough'] = $fontAttributes['StrikeThrough'] == '1';
242
            self::addStyle2($styleArray, 'font', 'underline', (string) $fontAttributes['Underline']);
243
 
244
            switch ($fontAttributes['Script']) {
245
                case '1':
246
                    $styleArray['font']['superscript'] = true;
247
 
248
                    break;
249
                case '-1':
250
                    $styleArray['font']['subscript'] = true;
251
 
252
                    break;
253
            }
254
        }
255
 
256
        if (isset($style->Style->StyleBorder)) {
257
            $srssb = $style->Style->StyleBorder;
258
            $this->addBorderStyle($srssb, $styleArray, 'top');
259
            $this->addBorderStyle($srssb, $styleArray, 'bottom');
260
            $this->addBorderStyle($srssb, $styleArray, 'left');
261
            $this->addBorderStyle($srssb, $styleArray, 'right');
262
            $this->addBorderDiagonal($srssb, $styleArray);
263
        }
264
        //    TO DO
265
        /*
266
        if (isset($style->Style->HyperLink)) {
267
            $hyperlink = $style->Style->HyperLink->attributes();
268
        }
269
        */
270
 
271
        return $styleArray;
272
    }
273
}