Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 : #include "tabprotection.hxx"
21 : #include <svl/PasswordHelper.hxx>
22 : #include <comphelper/docpasswordhelper.hxx>
23 : #include "document.hxx"
24 :
25 : #include <vector>
26 :
27 : #define DEBUG_TAB_PROTECTION 0
28 :
29 : #define URI_SHA1 "http://www.w3.org/2000/09/xmldsig#sha1"
30 : #define URI_XLS_LEGACY "http://docs.oasis-open.org/office/ns/table/legacy-hash-excel"
31 :
32 : using namespace ::com::sun::star;
33 : using ::com::sun::star::uno::Sequence;
34 : using ::std::vector;
35 :
36 52 : bool ScPassHashHelper::needsPassHashRegen(const ScDocument& rDoc, ScPasswordHash eHash1, ScPasswordHash eHash2)
37 : {
38 52 : if (rDoc.IsDocProtected())
39 : {
40 0 : const ScDocProtection* p = rDoc.GetDocProtection();
41 0 : if (!p->isPasswordEmpty() && !p->hasPasswordHash(eHash1, eHash2))
42 0 : return true;
43 : }
44 :
45 52 : SCTAB nTabCount = rDoc.GetTableCount();
46 112 : for (SCTAB i = 0; i < nTabCount; ++i)
47 : {
48 60 : const ScTableProtection* p = rDoc.GetTabProtection(i);
49 60 : if (!p || !p->isProtected())
50 : // Sheet not protected. Skip it.
51 58 : continue;
52 :
53 2 : if (!p->isPasswordEmpty() && !p->hasPasswordHash(eHash1, eHash2))
54 0 : return true;
55 : }
56 :
57 52 : return false;
58 : }
59 :
60 0 : OUString ScPassHashHelper::getHashURI(ScPasswordHash eHash)
61 : {
62 0 : switch (eHash)
63 : {
64 : case PASSHASH_SHA1:
65 0 : return OUString(URI_SHA1);
66 : case PASSHASH_XL:
67 0 : return OUString(URI_XLS_LEGACY);
68 : case PASSHASH_UNSPECIFIED:
69 : default:
70 : ;
71 : }
72 0 : return OUString();
73 : }
74 :
75 0 : ScPasswordHash ScPassHashHelper::getHashTypeFromURI(const OUString& rURI)
76 : {
77 0 : if ( rURI == URI_SHA1 )
78 0 : return PASSHASH_SHA1;
79 0 : else if ( rURI == URI_XLS_LEGACY )
80 0 : return PASSHASH_XL;
81 0 : return PASSHASH_UNSPECIFIED;
82 : }
83 :
84 86 : ScPassHashProtectable::~ScPassHashProtectable()
85 : {
86 86 : }
87 :
88 86 : class ScTableProtectionImpl
89 : {
90 : public:
91 : static Sequence<sal_Int8> hashPassword(const OUString& aPassText, ScPasswordHash eHash = PASSHASH_SHA1);
92 : static Sequence<sal_Int8> hashPassword(const Sequence<sal_Int8>& rPassHash, ScPasswordHash eHash = PASSHASH_SHA1);
93 :
94 : explicit ScTableProtectionImpl(SCSIZE nOptSize);
95 : explicit ScTableProtectionImpl(const ScTableProtectionImpl& r);
96 :
97 24 : bool isProtected() const { return mbProtected;}
98 : bool isProtectedWithPass() const;
99 : void setProtected(bool bProtected);
100 :
101 2 : bool isPasswordEmpty() const { return mbEmptyPass;}
102 : bool hasPasswordHash(ScPasswordHash eHash, ScPasswordHash eHash2 = PASSHASH_UNSPECIFIED) const;
103 : void setPassword(const OUString& aPassText);
104 : ::com::sun::star::uno::Sequence<sal_Int8> getPasswordHash(
105 : ScPasswordHash eHash, ScPasswordHash eHash2 = PASSHASH_UNSPECIFIED) const;
106 : void setPasswordHash(
107 : const ::com::sun::star::uno::Sequence<sal_Int8>& aPassword,
108 : ScPasswordHash eHash = PASSHASH_SHA1, ScPasswordHash eHash2 = PASSHASH_UNSPECIFIED);
109 : bool verifyPassword(const OUString& aPassText) const;
110 :
111 : bool isOptionEnabled(SCSIZE nOptId) const;
112 : void setOption(SCSIZE nOptId, bool bEnabled);
113 :
114 : void setEnhancedProtection( const ::std::vector< ScEnhancedProtection > & rProt );
115 2 : const ::std::vector< ScEnhancedProtection > & getEnhancedProtection() const { return maEnhancedProtection;}
116 : bool updateReference( UpdateRefMode, ScDocument*, const ScRange& rWhere, SCsCOL nDx, SCsROW nDy, SCsTAB nDz );
117 : bool isBlockEditable( const ScRange& rRange ) const;
118 : bool isSelectionEditable( const ScRangeList& rRangeList ) const;
119 :
120 : private:
121 : OUString maPassText;
122 : ::com::sun::star::uno::Sequence<sal_Int8> maPassHash;
123 : ::std::vector<bool> maOptions;
124 : bool mbEmptyPass;
125 : bool mbProtected;
126 : ScPasswordHash meHash1;
127 : ScPasswordHash meHash2;
128 : ::std::vector< ScEnhancedProtection > maEnhancedProtection;
129 : };
130 :
131 0 : Sequence<sal_Int8> ScTableProtectionImpl::hashPassword(const OUString& aPassText, ScPasswordHash eHash)
132 : {
133 0 : Sequence<sal_Int8> aHash;
134 0 : switch (eHash)
135 : {
136 : case PASSHASH_XL:
137 0 : aHash = ::comphelper::DocPasswordHelper::GetXLHashAsSequence( aPassText, RTL_TEXTENCODING_UTF8 );
138 0 : break;
139 : case PASSHASH_SHA1:
140 0 : SvPasswordHelper::GetHashPassword(aHash, aPassText);
141 0 : break;
142 : default:
143 : ;
144 : }
145 0 : return aHash;
146 : }
147 :
148 0 : Sequence<sal_Int8> ScTableProtectionImpl::hashPassword(
149 : const Sequence<sal_Int8>& rPassHash, ScPasswordHash eHash)
150 : {
151 0 : if (!rPassHash.getLength() || eHash == PASSHASH_UNSPECIFIED)
152 0 : return rPassHash;
153 :
154 : // TODO: Right now, we only support double-hash by SHA1.
155 0 : if (eHash == PASSHASH_SHA1)
156 : {
157 0 : vector<sal_Char> aChars;
158 0 : sal_Int32 n = rPassHash.getLength();
159 0 : aChars.reserve(n);
160 0 : for (sal_Int32 i = 0; i < n; ++i)
161 0 : aChars.push_back(static_cast<sal_Char>(rPassHash[i]));
162 :
163 0 : Sequence<sal_Int8> aNewHash;
164 0 : SvPasswordHelper::GetHashPassword(aNewHash, &aChars[0], aChars.size());
165 0 : return aNewHash;
166 : }
167 :
168 0 : return rPassHash;
169 : }
170 :
171 40 : ScTableProtectionImpl::ScTableProtectionImpl(SCSIZE nOptSize) :
172 : maOptions(nOptSize),
173 : mbEmptyPass(true),
174 : mbProtected(false),
175 : meHash1(PASSHASH_SHA1),
176 40 : meHash2(PASSHASH_UNSPECIFIED)
177 : {
178 40 : }
179 :
180 46 : ScTableProtectionImpl::ScTableProtectionImpl(const ScTableProtectionImpl& r) :
181 : maPassText(r.maPassText),
182 : maPassHash(r.maPassHash),
183 : maOptions(r.maOptions),
184 : mbEmptyPass(r.mbEmptyPass),
185 : mbProtected(r.mbProtected),
186 : meHash1(r.meHash1),
187 : meHash2(r.meHash2),
188 46 : maEnhancedProtection(r.maEnhancedProtection)
189 : {
190 46 : }
191 :
192 0 : bool ScTableProtectionImpl::isProtectedWithPass() const
193 : {
194 0 : if (!mbProtected)
195 0 : return false;
196 :
197 0 : return !maPassText.isEmpty() || maPassHash.getLength();
198 : }
199 :
200 44 : void ScTableProtectionImpl::setProtected(bool bProtected)
201 : {
202 44 : mbProtected = bProtected;
203 : // We need to keep the old password even when the protection is off. So,
204 : // don't erase the password data here.
205 44 : }
206 :
207 2 : void ScTableProtectionImpl::setPassword(const OUString& aPassText)
208 : {
209 : // We can't hash it here because we don't know whether this document will
210 : // get saved to Excel or ODF, depending on which we will need to use a
211 : // different hashing algorithm. One alternative is to hash it using all
212 : // hash algorithms that we support, and store them all.
213 :
214 2 : maPassText = aPassText;
215 2 : mbEmptyPass = aPassText.isEmpty();
216 2 : if (mbEmptyPass)
217 : {
218 0 : maPassHash = Sequence<sal_Int8>();
219 : }
220 2 : }
221 :
222 2 : bool ScTableProtectionImpl::hasPasswordHash(ScPasswordHash eHash, ScPasswordHash eHash2) const
223 : {
224 2 : if (mbEmptyPass)
225 2 : return true;
226 :
227 0 : if (!maPassText.isEmpty())
228 0 : return true;
229 :
230 0 : if (meHash1 == eHash)
231 : {
232 0 : if (meHash2 == PASSHASH_UNSPECIFIED)
233 : // single hash.
234 0 : return true;
235 :
236 0 : return meHash2 == eHash2;
237 : }
238 :
239 0 : return false;
240 : }
241 :
242 6 : Sequence<sal_Int8> ScTableProtectionImpl::getPasswordHash(
243 : ScPasswordHash eHash, ScPasswordHash eHash2) const
244 : {
245 6 : Sequence<sal_Int8> aPassHash;
246 :
247 6 : if (mbEmptyPass)
248 : // Flaged as empty.
249 2 : return aPassHash;
250 :
251 4 : if (!maPassText.isEmpty())
252 : {
253 : // Cleartext password exists. Hash it.
254 0 : aPassHash = hashPassword(maPassText, eHash);
255 0 : if (eHash2 != PASSHASH_UNSPECIFIED)
256 : // Double-hash it.
257 0 : aPassHash = hashPassword(aPassHash, eHash2);
258 :
259 0 : return aPassHash;
260 : }
261 : else
262 : {
263 : // No clear text password. Check if we have a hash value of the right hash type.
264 4 : if (meHash1 == eHash)
265 : {
266 4 : aPassHash = maPassHash;
267 :
268 4 : if (meHash2 == eHash2)
269 : // Matching double-hash requested.
270 4 : return aPassHash;
271 0 : else if (meHash2 == PASSHASH_UNSPECIFIED)
272 : // primary hashing type match. Double hash it by the requested
273 : // double-hash type.
274 0 : return hashPassword(aPassHash, eHash2);
275 : }
276 : }
277 :
278 : // failed.
279 0 : return Sequence<sal_Int8>();
280 : }
281 :
282 8 : void ScTableProtectionImpl::setPasswordHash(
283 : const uno::Sequence<sal_Int8>& aPassword, ScPasswordHash eHash, ScPasswordHash eHash2)
284 : {
285 8 : sal_Int32 nLen = aPassword.getLength();
286 8 : mbEmptyPass = nLen <= 0;
287 8 : meHash1 = eHash;
288 8 : meHash2 = eHash2;
289 8 : maPassHash = aPassword;
290 :
291 : #if DEBUG_TAB_PROTECTION
292 : for (sal_Int32 i = 0; i < nLen; ++i)
293 : printf("%2.2X ", static_cast<sal_uInt8>(aPassword[i]));
294 : printf("\n");
295 : #endif
296 8 : }
297 :
298 4 : bool ScTableProtectionImpl::verifyPassword(const OUString& aPassText) const
299 : {
300 : #if DEBUG_TAB_PROTECTION
301 : fprintf(stdout, "ScTableProtectionImpl::verifyPassword: input = '%s'\n",
302 : OUStringToOString(OUString(aPassText), RTL_TEXTENCODING_UTF8).getStr());
303 : #endif
304 :
305 4 : if (mbEmptyPass)
306 0 : return aPassText.isEmpty();
307 :
308 4 : if (!maPassText.isEmpty())
309 : // Clear text password exists, and this one takes precedence.
310 4 : return aPassText == maPassText;
311 :
312 0 : Sequence<sal_Int8> aHash = hashPassword(aPassText, meHash1);
313 0 : aHash = hashPassword(aHash, meHash2);
314 :
315 : #if DEBUG_TAB_PROTECTION
316 : fprintf(stdout, "ScTableProtectionImpl::verifyPassword: hash = ");
317 : for (sal_Int32 i = 0; i < aHash.getLength(); ++i)
318 : printf("%2.2X ", static_cast<sal_uInt8>(aHash[i]));
319 : printf("\n");
320 : #endif
321 :
322 0 : return aHash == maPassHash;
323 : }
324 :
325 46 : bool ScTableProtectionImpl::isOptionEnabled(SCSIZE nOptId) const
326 : {
327 46 : if ( maOptions.size() <= static_cast<size_t>(nOptId) )
328 : {
329 : OSL_FAIL("ScTableProtectionImpl::isOptionEnabled: wrong size");
330 0 : return false;
331 : }
332 :
333 46 : return maOptions[nOptId];
334 : }
335 :
336 572 : void ScTableProtectionImpl::setOption(SCSIZE nOptId, bool bEnabled)
337 : {
338 572 : if ( maOptions.size() <= static_cast<size_t>(nOptId) )
339 : {
340 : OSL_FAIL("ScTableProtectionImpl::setOption: wrong size");
341 572 : return;
342 : }
343 :
344 572 : maOptions[nOptId] = bEnabled;
345 : }
346 :
347 32 : void ScTableProtectionImpl::setEnhancedProtection( const ::std::vector< ScEnhancedProtection > & rProt )
348 : {
349 32 : maEnhancedProtection = rProt;
350 32 : }
351 :
352 0 : bool ScTableProtectionImpl::updateReference( UpdateRefMode eMode, ScDocument* pDoc,
353 : const ScRange& rWhere, SCsCOL nDx, SCsROW nDy, SCsTAB nDz )
354 : {
355 0 : bool bChanged = false;
356 0 : for (::std::vector<ScEnhancedProtection>::iterator it(maEnhancedProtection.begin());
357 0 : it != maEnhancedProtection.end(); ++it)
358 : {
359 0 : if ((*it).maRangeList.Is())
360 0 : bChanged |= (*it).maRangeList->UpdateReference( eMode, pDoc, rWhere, nDx, nDy, nDz);
361 : }
362 0 : return bChanged;
363 : }
364 :
365 36 : bool ScTableProtectionImpl::isBlockEditable( const ScRange& rRange ) const
366 : {
367 : /* TODO: ask for password (and remember) if a password was set for
368 : * a matching range and no matching range without password was encountered.
369 : * Would need another return type than boolean to reflect
370 : * "password required for a specific protection". */
371 :
372 : // No protection exception or overriding permission to edit if empty.
373 36 : if (maEnhancedProtection.empty())
374 0 : return false;
375 :
376 : // No security descriptor in an enhanced protection means the ranges of
377 : // that protection are editable. If there is any security descriptor
378 : // present we assume the permission to edit is not granted. Until we
379 : // actually can evaluate the descriptors..
380 :
381 232 : for (::std::vector<ScEnhancedProtection>::const_iterator it(maEnhancedProtection.begin()),
382 36 : itEnd(maEnhancedProtection.end()); it != itEnd; ++it)
383 : {
384 168 : if (!(*it).hasSecurityDescriptor() && (*it).maRangeList.Is())
385 : {
386 96 : if ((*it).maRangeList->In( rRange))
387 : {
388 : // Range is editable if no password is assigned.
389 12 : if (!(*it).hasPassword())
390 8 : return true;
391 : }
392 : }
393 : }
394 :
395 : // For a single address, a simple check with single ranges was sufficient.
396 28 : if (rRange.aStart == rRange.aEnd)
397 16 : return false;
398 :
399 : // Test also for cases where rRange is encompassed by a union of two or
400 : // more ranges of the list. The original ranges are not necessarily joined.
401 84 : for (::std::vector<ScEnhancedProtection>::const_iterator it(maEnhancedProtection.begin()),
402 12 : itEnd(maEnhancedProtection.end()); it != itEnd; ++it)
403 : {
404 60 : if (!(*it).hasSecurityDescriptor() && (*it).maRangeList.Is())
405 : {
406 36 : ScRangeList aList( (*it).maRangeList->GetIntersectedRange( rRange));
407 36 : if (aList.size() == 1 && *aList[0] == rRange)
408 : {
409 : // Range is editable if no password is assigned.
410 0 : if (!(*it).hasPassword())
411 0 : return true;
412 36 : }
413 : }
414 : }
415 :
416 : // Ranges may even be distributed over different protection records, for
417 : // example if they are assigned different names, and can have different
418 : // passwords. Combine the ones that can be edited.
419 : /* TODO: once we handle passwords, remember a successful unlock at
420 : * ScEnhancedProtection so we can use that here. */
421 12 : ScRangeList aRangeList;
422 84 : for (::std::vector<ScEnhancedProtection>::const_iterator it(maEnhancedProtection.begin()),
423 12 : itEnd(maEnhancedProtection.end()); it != itEnd; ++it)
424 : {
425 60 : if (!(*it).hasSecurityDescriptor() && (*it).maRangeList.Is())
426 : {
427 : // Ranges are editable if no password is assigned.
428 36 : if (!(*it).hasPassword())
429 : {
430 24 : const ScRangeList& rRanges = *(*it).maRangeList;
431 24 : size_t nRanges = rRanges.size();
432 48 : for (size_t i=0; i < nRanges; ++i)
433 : {
434 24 : aRangeList.Append( *rRanges[i]);
435 : }
436 : }
437 : }
438 : }
439 24 : ScRangeList aResultList( aRangeList.GetIntersectedRange( rRange));
440 12 : if (aResultList.size() == 1 && *aResultList[0] == rRange)
441 4 : return true;
442 :
443 20 : return false;
444 : }
445 :
446 0 : bool ScTableProtectionImpl::isSelectionEditable( const ScRangeList& rRangeList ) const
447 : {
448 0 : if (rRangeList.empty())
449 0 : return false;
450 :
451 0 : for (size_t i=0, nRanges = rRangeList.size(); i < nRanges; ++i)
452 : {
453 0 : if (!isBlockEditable( *rRangeList[i]))
454 0 : return false;
455 : }
456 0 : return true;
457 : }
458 :
459 4 : ScDocProtection::ScDocProtection() :
460 4 : mpImpl(new ScTableProtectionImpl(static_cast<SCSIZE>(ScDocProtection::NONE)))
461 : {
462 4 : }
463 :
464 10 : ScDocProtection::ScDocProtection(const ScDocProtection& r) :
465 : ScPassHashProtectable(),
466 10 : mpImpl(new ScTableProtectionImpl(*r.mpImpl))
467 : {
468 10 : }
469 :
470 26 : ScDocProtection::~ScDocProtection()
471 : {
472 26 : }
473 :
474 12 : bool ScDocProtection::isProtected() const
475 : {
476 12 : return mpImpl->isProtected();
477 : }
478 :
479 0 : bool ScDocProtection::isProtectedWithPass() const
480 : {
481 0 : return mpImpl->isProtectedWithPass();
482 : }
483 :
484 8 : void ScDocProtection::setProtected(bool bProtected)
485 : {
486 8 : mpImpl->setProtected(bProtected);
487 :
488 : // Currently Calc doesn't support document protection options. So, let's
489 : // assume that when the document is protected, its structure is protected.
490 : // We need to do this for Excel export.
491 8 : mpImpl->setOption(ScDocProtection::STRUCTURE, bProtected);
492 8 : }
493 :
494 0 : bool ScDocProtection::isPasswordEmpty() const
495 : {
496 0 : return mpImpl->isPasswordEmpty();
497 : }
498 :
499 0 : bool ScDocProtection::hasPasswordHash(ScPasswordHash eHash, ScPasswordHash eHash2) const
500 : {
501 0 : return mpImpl->hasPasswordHash(eHash, eHash2);
502 : }
503 :
504 2 : void ScDocProtection::setPassword(const OUString& aPassText)
505 : {
506 2 : mpImpl->setPassword(aPassText);
507 2 : }
508 :
509 0 : uno::Sequence<sal_Int8> ScDocProtection::getPasswordHash(ScPasswordHash eHash, ScPasswordHash eHash2) const
510 : {
511 0 : return mpImpl->getPasswordHash(eHash, eHash2);
512 : }
513 :
514 0 : void ScDocProtection::setPasswordHash(
515 : const uno::Sequence<sal_Int8>& aPassword, ScPasswordHash eHash, ScPasswordHash eHash2)
516 : {
517 0 : mpImpl->setPasswordHash(aPassword, eHash, eHash2);
518 0 : }
519 :
520 4 : bool ScDocProtection::verifyPassword(const OUString& aPassText) const
521 : {
522 4 : return mpImpl->verifyPassword(aPassText);
523 : }
524 :
525 0 : bool ScDocProtection::isOptionEnabled(Option eOption) const
526 : {
527 0 : return mpImpl->isOptionEnabled(eOption);
528 : }
529 :
530 4 : void ScDocProtection::setOption(Option eOption, bool bEnabled)
531 : {
532 4 : mpImpl->setOption(eOption, bEnabled);
533 4 : }
534 :
535 36 : ScTableProtection::ScTableProtection() :
536 36 : mpImpl(new ScTableProtectionImpl(static_cast<SCSIZE>(ScTableProtection::NONE)))
537 : {
538 : // Set default values for the options.
539 36 : mpImpl->setOption(SELECT_LOCKED_CELLS, true);
540 36 : mpImpl->setOption(SELECT_UNLOCKED_CELLS, true);
541 36 : }
542 :
543 36 : ScTableProtection::ScTableProtection(const ScTableProtection& r) :
544 : ScPassHashProtectable(),
545 36 : mpImpl(new ScTableProtectionImpl(*r.mpImpl))
546 : {
547 36 : }
548 :
549 136 : ScTableProtection::~ScTableProtection()
550 : {
551 136 : }
552 :
553 12 : bool ScTableProtection::isProtected() const
554 : {
555 12 : return mpImpl->isProtected();
556 : }
557 :
558 0 : bool ScTableProtection::isProtectedWithPass() const
559 : {
560 0 : return mpImpl->isProtectedWithPass();
561 : }
562 :
563 36 : void ScTableProtection::setProtected(bool bProtected)
564 : {
565 36 : mpImpl->setProtected(bProtected);
566 36 : }
567 :
568 2 : bool ScTableProtection::isPasswordEmpty() const
569 : {
570 2 : return mpImpl->isPasswordEmpty();
571 : }
572 :
573 2 : bool ScTableProtection::hasPasswordHash(ScPasswordHash eHash, ScPasswordHash eHash2) const
574 : {
575 2 : return mpImpl->hasPasswordHash(eHash, eHash2);
576 : }
577 :
578 0 : void ScTableProtection::setPassword(const OUString& aPassText)
579 : {
580 0 : mpImpl->setPassword(aPassText);
581 0 : }
582 :
583 6 : Sequence<sal_Int8> ScTableProtection::getPasswordHash(ScPasswordHash eHash, ScPasswordHash eHash2) const
584 : {
585 6 : return mpImpl->getPasswordHash(eHash, eHash2);
586 : }
587 :
588 8 : void ScTableProtection::setPasswordHash(
589 : const uno::Sequence<sal_Int8>& aPassword, ScPasswordHash eHash, ScPasswordHash eHash2)
590 : {
591 8 : mpImpl->setPasswordHash(aPassword, eHash, eHash2);
592 8 : }
593 :
594 0 : bool ScTableProtection::verifyPassword(const OUString& aPassText) const
595 : {
596 0 : return mpImpl->verifyPassword(aPassText);
597 : }
598 :
599 46 : bool ScTableProtection::isOptionEnabled(Option eOption) const
600 : {
601 46 : return mpImpl->isOptionEnabled(eOption);
602 : }
603 :
604 488 : void ScTableProtection::setOption(Option eOption, bool bEnabled)
605 : {
606 488 : mpImpl->setOption(eOption, bEnabled);
607 488 : }
608 :
609 32 : void ScTableProtection::setEnhancedProtection( const ::std::vector< ScEnhancedProtection > & rProt )
610 : {
611 32 : mpImpl->setEnhancedProtection(rProt);
612 32 : }
613 :
614 2 : const ::std::vector< ScEnhancedProtection > & ScTableProtection::getEnhancedProtection() const
615 : {
616 2 : return mpImpl->getEnhancedProtection();
617 : }
618 :
619 0 : bool ScTableProtection::updateReference( UpdateRefMode eMode, ScDocument* pDoc, const ScRange& rWhere,
620 : SCsCOL nDx, SCsROW nDy, SCsTAB nDz )
621 : {
622 0 : return mpImpl->updateReference( eMode, pDoc, rWhere, nDx, nDy, nDz);
623 : }
624 :
625 36 : bool ScTableProtection::isBlockEditable( const ScRange& rRange ) const
626 : {
627 36 : return mpImpl->isBlockEditable( rRange);
628 : }
629 :
630 0 : bool ScTableProtection::isSelectionEditable( const ScRangeList& rRangeList ) const
631 : {
632 0 : return mpImpl->isSelectionEditable( rRangeList);
633 228 : }
634 :
635 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|