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 10 #include "optaboutconfig.hxx" 11 12 #include <comphelper/processfactory.hxx> 13 #include <comphelper/sequence.hxx> 14 #include <com/sun/star/configuration/theDefaultProvider.hpp> 15 #include <com/sun/star/lang/XMultiServiceFactory.hpp> 16 #include <com/sun/star/beans/NamedValue.hpp> 17 #include <com/sun/star/container/XNameAccess.hpp> 18 #include <com/sun/star/container/XNameReplace.hpp> 19 #include <com/sun/star/container/XHierarchicalName.hpp> 20 #include <com/sun/star/util/XChangesBatch.hpp> 21 #include <com/sun/star/util/SearchFlags.hpp> 22 #include <com/sun/star/util/SearchAlgorithms2.hpp> 23 #include <unotools/textsearch.hxx> 24 #include <vcl/event.hxx> 25 #include <sal/log.hxx> 26 #include <tools/diagnose_ex.h> 27 28 #include <memory> 29 #include <vector> 30 #include <iostream> 31 32 using namespace ::com::sun::star; 33 using namespace com::sun::star::uno; 34 using namespace com::sun::star::container; 35 36 #define SHORT_LEN_LIMIT 7 37 #define LONG_LEN_LIMIT 11 38 #define HYPER_LEN_LIMIT 20 39 40 struct Prop_Impl 41 { 42 OUString Name; 43 OUString Property; 44 Any Value; 45 46 Prop_Impl( const OUString& sName, const OUString& sProperty, const Any& aValue ) 47 : Name( sName ) 48 , Property( sProperty ) 49 , Value( aValue ) 50 {} 51 }; 52 53 struct UserData 54 { 55 bool bIsPropertyPath; 56 OUString sPropertyPath; 57 int aLineage; 58 Reference<XNameAccess> aXNameAccess; 59 60 explicit UserData( OUString const & rPropertyPath ) 61 : bIsPropertyPath( true ) 62 , sPropertyPath(rPropertyPath) 63 , aLineage(0) 64 {} 65 66 explicit UserData( Reference<XNameAccess> const & rXNameAccess, int rIndex ) 67 : bIsPropertyPath( false ) 68 , aLineage(rIndex) 69 , aXNameAccess( rXNameAccess ) 70 {} 71 }; 72 73 IMPL_LINK(CuiAboutConfigValueDialog, KeyInputHdl, const KeyEvent&, rKeyEvent, bool) 74 { 75 bool bValid = false; 76 bool bNonSpace = rKeyEvent.GetKeyCode().GetCode() != KEY_SPACE; 77 if (m_bNumericOnly && bNonSpace ) 78 { 79 const vcl::KeyCode& rKeyCode = rKeyEvent.GetKeyCode(); 80 sal_uInt16 nGroup = rKeyCode.GetGroup(); 81 sal_uInt16 nKey = rKeyCode.GetCode(); 82 83 switch ( nGroup ) { 84 case KEYGROUP_NUM : 85 case KEYGROUP_CURSOR : 86 { 87 bValid = true; 88 break; 89 } 90 91 case KEYGROUP_MISC : 92 { 93 switch ( nKey ) { 94 case KEY_SUBTRACT : 95 case KEY_COMMA : 96 case KEY_POINT : 97 { 98 bValid = true; 99 break; 100 } 101 102 default : 103 { 104 if( nKey < KEY_ADD || nKey > KEY_EQUAL ) 105 bValid = true; 106 break; 107 } 108 } 109 break; 110 } 111 112 default : 113 { 114 bValid = false; 115 break; 116 } 117 } 118 119 //Select all, Copy, Paste, Cut, Undo Keys 120 if ( !bValid && ( rKeyCode.IsMod1() && ( 121 KEY_A == nKey || KEY_C == nKey || KEY_V == nKey || KEY_X == nKey || KEY_Z == nKey ) ) ) 122 bValid = true; 123 } 124 else 125 bValid = true; 126 127 //if value return true to claim that it has been handled 128 return !bValid; 129 } 130 131 CuiAboutConfigTabPage::CuiAboutConfigTabPage(weld::Window* pParent) 132 : GenericDialogController(pParent, "cui/ui/aboutconfigdialog.ui", "AboutConfig") 133 , m_xResetBtn(m_xBuilder->weld_button("reset")) 134 , m_xEditBtn(m_xBuilder->weld_button("edit")) 135 , m_xSearchBtn(m_xBuilder->weld_button("searchButton")) 136 , m_xSearchEdit(m_xBuilder->weld_entry("searchEntry")) 137 , m_xPrefBox(m_xBuilder->weld_tree_view("preferences")) 138 , m_xScratchIter(m_xPrefBox->make_iterator()) 139 , m_vectorOfModified() 140 , m_bSorted(false) 141 { 142 m_xPrefBox->set_size_request(m_xPrefBox->get_approximate_digit_width() * 100, 143 m_xPrefBox->get_height_rows(28)); 144 m_xPrefBox->connect_column_clicked(LINK(this, CuiAboutConfigTabPage, HeaderBarClick)); 145 146 m_xEditBtn->connect_clicked(LINK( this, CuiAboutConfigTabPage, StandardHdl_Impl)); 147 m_xResetBtn->connect_clicked(LINK( this, CuiAboutConfigTabPage, ResetBtnHdl_Impl)); 148 m_xPrefBox->connect_row_activated(LINK(this, CuiAboutConfigTabPage, DoubleClickHdl_Impl)); 149 m_xPrefBox->connect_expanding(LINK(this, CuiAboutConfigTabPage, ExpandingHdl_Impl)); 150 m_xSearchBtn->connect_clicked(LINK(this, CuiAboutConfigTabPage, SearchHdl_Impl)); 151 152 m_options.AlgorithmType2 = util::SearchAlgorithms2::ABSOLUTE; 153 m_options.transliterateFlags |= TransliterationFlags::IGNORE_CASE; 154 m_options.searchFlag |= (util::SearchFlags::REG_NOT_BEGINOFLINE | 155 util::SearchFlags::REG_NOT_ENDOFLINE); 156 157 float fWidth = m_xPrefBox->get_approximate_digit_width(); 158 std::vector<int> aWidths; 159 aWidths.push_back(fWidth * 65); 160 aWidths.push_back(fWidth * 20); 161 aWidths.push_back(fWidth * 8); 162 m_xPrefBox->set_column_fixed_widths(aWidths); 163 } 164 165 IMPL_LINK(CuiAboutConfigTabPage, HeaderBarClick, int, nColumn, void) 166 { 167 if (!m_bSorted) 168 { 169 m_xPrefBox->make_sorted(); 170 m_bSorted = true; 171 } 172 173 bool bSortAtoZ = m_xPrefBox->get_sort_order(); 174 175 //set new arrow positions in headerbar 176 if (nColumn == m_xPrefBox->get_sort_column()) 177 { 178 bSortAtoZ = !bSortAtoZ; 179 m_xPrefBox->set_sort_order(bSortAtoZ); 180 } 181 else 182 { 183 m_xPrefBox->set_sort_indicator(TRISTATE_INDET, m_xPrefBox->get_sort_column()); 184 m_xPrefBox->set_sort_column(nColumn); 185 } 186 187 if (nColumn != -1) 188 { 189 //sort lists 190 m_xPrefBox->set_sort_indicator(bSortAtoZ ? TRISTATE_TRUE : TRISTATE_FALSE, nColumn); 191 } 192 } 193 194 CuiAboutConfigTabPage::~CuiAboutConfigTabPage() 195 { 196 } 197 198 void CuiAboutConfigTabPage::InsertEntry(const OUString& rPropertyPath, const OUString& rProp, const OUString& rStatus, 199 const OUString& rType, const OUString& rValue, const weld::TreeIter* pParentEntry, 200 bool bInsertToPrefBox) 201 { 202 m_vectorUserData.push_back(std::make_unique<UserData>(rPropertyPath)); 203 if (bInsertToPrefBox) 204 { 205 OUString sId(OUString::number(reinterpret_cast<sal_Int64>(m_vectorUserData.back().get()))); 206 m_xPrefBox->insert(pParentEntry, -1, &rProp, &sId, nullptr, nullptr, nullptr, false, m_xScratchIter.get()); 207 m_xPrefBox->set_text(*m_xScratchIter, rStatus, 1); 208 m_xPrefBox->set_text(*m_xScratchIter, rType, 2); 209 m_xPrefBox->set_text(*m_xScratchIter, rValue, 3); 210 } 211 else 212 { 213 m_prefBoxEntries.push_back({rProp, rStatus, rType, rValue, m_vectorUserData.back().get()}); 214 } 215 } 216 217 void CuiAboutConfigTabPage::Reset() 218 { 219 weld::WaitObject aWait(m_xDialog.get()); 220 221 m_xPrefBox->clear(); 222 m_vectorOfModified.clear(); 223 if (m_bSorted) 224 { 225 m_xPrefBox->set_sort_indicator(TRISTATE_INDET, m_xPrefBox->get_sort_column()); 226 m_xPrefBox->make_unsorted(); 227 m_bSorted = false; 228 } 229 m_prefBoxEntries.clear(); 230 m_modifiedPrefBoxEntries.clear(); 231 232 m_xPrefBox->freeze(); 233 Reference< XNameAccess > xConfigAccess = getConfigAccess( "/", false ); 234 //Load all XNameAccess to m_prefBoxEntries 235 FillItems( xConfigAccess, nullptr, 0, true ); 236 //Load xConfigAccess' children to m_prefBox 237 FillItems( xConfigAccess ); 238 m_xPrefBox->thaw(); 239 } 240 241 void CuiAboutConfigTabPage::FillItemSet() 242 { 243 std::vector< std::shared_ptr< Prop_Impl > >::iterator pIter; 244 for( pIter = m_vectorOfModified.begin() ; pIter != m_vectorOfModified.end(); ++pIter ) 245 { 246 Reference< XNameAccess > xUpdateAccess = getConfigAccess( (*pIter)->Name , true ); 247 Reference< XNameReplace > xNameReplace( xUpdateAccess, UNO_QUERY_THROW ); 248 249 xNameReplace->replaceByName( (*pIter)->Property, (*pIter)->Value ); 250 251 Reference< util::XChangesBatch > xChangesBatch( xUpdateAccess, UNO_QUERY_THROW ); 252 xChangesBatch->commitChanges(); 253 } 254 } 255 256 void CuiAboutConfigTabPage::FillItems(const Reference< XNameAccess >& xNameAccess, const weld::TreeIter* pParentEntry, 257 int lineage, bool bLoadAll) 258 { 259 OUString sPath = Reference< XHierarchicalName >( 260 xNameAccess, uno::UNO_QUERY_THROW )->getHierarchicalName(); 261 uno::Sequence< OUString > seqItems = xNameAccess->getElementNames(); 262 for( sal_Int32 i = 0; i < seqItems.getLength(); ++i ) 263 { 264 Any aNode = xNameAccess->getByName( seqItems[i] ); 265 266 bool bNotLeaf = false; 267 268 Reference< XNameAccess > xNextNameAccess; 269 try 270 { 271 xNextNameAccess.set(aNode, uno::UNO_QUERY); 272 bNotLeaf = xNextNameAccess.is(); 273 } 274 catch (const RuntimeException&) 275 { 276 TOOLS_WARN_EXCEPTION( "cui.options", "CuiAboutConfigTabPage"); 277 } 278 279 if (bNotLeaf) 280 { 281 if(bLoadAll) 282 FillItems(xNextNameAccess, nullptr, lineage + 1, true); 283 else 284 { 285 // not leaf node 286 m_vectorUserData.push_back(std::make_unique<UserData>(xNextNameAccess, lineage + 1)); 287 OUString sId(OUString::number(reinterpret_cast<sal_Int64>(m_vectorUserData.back().get()))); 288 289 m_xPrefBox->insert(pParentEntry, -1, &seqItems[i], &sId, nullptr, nullptr, nullptr, true, m_xScratchIter.get()); 290 //It is needed, without this the selection line will be truncated. 291 m_xPrefBox->set_text(*m_xScratchIter, "", 1); 292 m_xPrefBox->set_text(*m_xScratchIter, "", 2); 293 m_xPrefBox->set_text(*m_xScratchIter, "", 3); 294 } 295 } 296 else 297 { 298 // leaf node 299 OUString sPropertyName = seqItems[i]; 300 auto it = std::find_if(m_modifiedPrefBoxEntries.begin(), m_modifiedPrefBoxEntries.end(), 301 [&sPath, &sPropertyName](const prefBoxEntry& rEntry) -> bool 302 { 303 return rEntry.pUserData->sPropertyPath == sPath 304 && rEntry.sStatus == sPropertyName; 305 } 306 ); 307 308 OUString sType = aNode.getValueTypeName(); 309 OUStringBuffer sValue; 310 311 if (it != m_modifiedPrefBoxEntries.end()) 312 sValue = it->sValue; 313 else 314 { 315 switch( aNode.getValueType().getTypeClass() ) 316 { 317 case css::uno::TypeClass_VOID: 318 break; 319 320 case css::uno::TypeClass_BOOLEAN: 321 sValue = OUString::boolean( aNode.get<bool>() ); 322 break; 323 324 case css::uno::TypeClass_SHORT: 325 case css::uno::TypeClass_LONG: 326 case css::uno::TypeClass_HYPER: 327 sValue = OUString::number( aNode.get<sal_Int64>() ); 328 break; 329 330 case css::uno::TypeClass_DOUBLE: 331 sValue = OUString::number( aNode.get<double>() ); 332 break; 333 334 case css::uno::TypeClass_STRING: 335 sValue = aNode.get<OUString>(); 336 break; 337 338 case css::uno::TypeClass_SEQUENCE: 339 if( sType == "[]boolean" ) 340 { 341 uno::Sequence<sal_Bool> seq = aNode.get< uno::Sequence<sal_Bool> >(); 342 for( sal_Int32 j = 0; j != seq.getLength(); ++j ) 343 { 344 if( j != 0 ) 345 { 346 sValue.append(","); 347 } 348 sValue.append(OUString::boolean( seq[j] )); 349 } 350 } 351 else if( sType == "[]byte" ) 352 { 353 uno::Sequence<sal_Int8> seq = aNode.get< uno::Sequence<sal_Int8> >(); 354 for( sal_Int32 j = 0; j != seq.getLength(); ++j ) 355 { 356 OUString s = OUString::number( 357 static_cast<sal_uInt8>(seq[j]), 16 ); 358 if( s.getLength() == 1 ) 359 { 360 sValue.append("0"); 361 } 362 sValue.append(s.toAsciiUpperCase()); 363 } 364 } 365 else if( sType == "[][]byte" ) 366 { 367 uno::Sequence< uno::Sequence<sal_Int8> > seq = aNode.get< uno::Sequence< uno::Sequence<sal_Int8> > >(); 368 for( sal_Int32 j = 0; j != seq.getLength(); ++j ) 369 { 370 if( j != 0 ) 371 { 372 sValue.append(","); 373 } 374 for( sal_Int32 k = 0; k != seq[j].getLength(); ++k ) 375 { 376 OUString s = OUString::number( 377 static_cast<sal_uInt8>(seq[j][k]), 16 ); 378 if( s.getLength() == 1 ) 379 { 380 sValue.append("0"); 381 } 382 sValue.append(s.toAsciiUpperCase()); 383 } 384 } 385 } 386 else if( sType == "[]short" ) 387 { 388 uno::Sequence<sal_Int16> seq = aNode.get< uno::Sequence<sal_Int16> >(); 389 for( sal_Int32 j = 0; j != seq.getLength(); ++j ) 390 { 391 if( j != 0 ) 392 { 393 sValue.append(","); 394 } 395 sValue.append(OUString::number( seq[j] )); 396 } 397 } 398 else if( sType == "[]long" ) 399 { 400 uno::Sequence<sal_Int32> seq = aNode.get< uno::Sequence<sal_Int32> >(); 401 for( sal_Int32 j = 0; j != seq.getLength(); ++j ) 402 { 403 if( j != 0 ) 404 { 405 sValue.append(","); 406 } 407 sValue.append(OUString::number( seq[j] )); 408 } 409 } 410 else if( sType == "[]hyper" ) 411 { 412 uno::Sequence<sal_Int64> seq = aNode.get< uno::Sequence<sal_Int64> >(); 413 for( sal_Int32 j = 0; j != seq.getLength(); ++j ) 414 { 415 if( j != 0 ) 416 { 417 sValue.append(","); 418 } 419 sValue.append(OUString::number( seq[j] )); 420 } 421 } 422 else if( sType == "[]double" ) 423 { 424 uno::Sequence<double> seq = aNode.get< uno::Sequence<double> >(); 425 for( sal_Int32 j = 0; j != seq.getLength(); ++j ) 426 { 427 if( j != 0 ) 428 { 429 sValue.append(","); 430 } 431 sValue.append(OUString::number( seq[j] )); 432 } 433 } 434 else if( sType == "[]string" ) 435 { 436 uno::Sequence<OUString> seq = aNode.get< uno::Sequence<OUString> >(); 437 for( sal_Int32 j = 0; j != seq.getLength(); ++j ) 438 { 439 if( j != 0 ) 440 { 441 sValue.append(","); 442 } 443 sValue.append(seq[j]); 444 } 445 } 446 else 447 { 448 SAL_WARN( 449 "cui.options", 450 "path \"" << sPath << "\" member " << seqItems[i] 451 << " of unsupported type " << sType); 452 } 453 break; 454 455 default: 456 SAL_WARN( 457 "cui.options", 458 "path \"" << sPath << "\" member " << seqItems[i] 459 << " of unsupported type " << sType); 460 break; 461 } 462 } 463 464 //Short name 465 int index = 0; 466 for(int j = 1; j < lineage; ++j) 467 index = sPath.indexOf("/", index + 1); 468 469 InsertEntry(sPath, sPath.copy(index+1), seqItems[i], sType, sValue.makeStringAndClear(), pParentEntry, !bLoadAll); 470 } 471 } 472 } 473 474 Reference< XNameAccess > CuiAboutConfigTabPage::getConfigAccess( const OUString& sNodePath, bool bUpdate ) 475 { 476 uno::Reference< uno::XComponentContext > xContext( ::comphelper::getProcessComponentContext() ); 477 478 uno::Reference< lang::XMultiServiceFactory > xConfigProvider( 479 css::configuration::theDefaultProvider::get( xContext ) ); 480 481 beans::NamedValue aProperty; 482 aProperty.Name = "nodepath"; 483 aProperty.Value <<= sNodePath; 484 485 uno::Sequence< uno::Any > aArgumentList( 1 ); 486 aArgumentList[0] <<= aProperty; 487 488 OUString sAccessString; 489 490 if( bUpdate ) 491 sAccessString = "com.sun.star.configuration.ConfigurationUpdateAccess"; 492 else 493 sAccessString = "com.sun.star.configuration.ConfigurationAccess"; 494 495 uno::Reference< container::XNameAccess > xNameAccess( 496 xConfigProvider->createInstanceWithArguments( 497 sAccessString, aArgumentList ), 498 uno::UNO_QUERY_THROW ); 499 500 return xNameAccess; 501 } 502 503 void CuiAboutConfigTabPage::AddToModifiedVector( const std::shared_ptr< Prop_Impl >& rProp ) 504 { 505 bool isModifiedBefore = false; 506 //Check if value modified before 507 for(std::shared_ptr<Prop_Impl> & nInd : m_vectorOfModified) 508 { 509 if( rProp->Name == nInd->Name && rProp->Property == nInd->Property ) 510 { 511 //property modified before. Assign reference to the modified value 512 //do your changes on this object. They will be saved later. 513 nInd = rProp; 514 isModifiedBefore = true; 515 break; 516 } 517 } 518 519 if( !isModifiedBefore ) 520 m_vectorOfModified.push_back( rProp ); 521 //property is not modified before 522 } 523 524 std::vector< OUString > CuiAboutConfigTabPage::commaStringToSequence( const OUString& rCommaSepString ) 525 { 526 std::vector<OUString> tempVector; 527 528 sal_Int32 index = 0; 529 do 530 { 531 OUString word = rCommaSepString.getToken(0, u',', index); 532 word = word.trim(); 533 if( !word.isEmpty()) 534 tempVector.push_back(word); 535 }while( index >= 0 ); 536 return tempVector; 537 } 538 539 CuiAboutConfigValueDialog::CuiAboutConfigValueDialog(weld::Window* pWindow, 540 const OUString& rValue, 541 int limit) 542 : GenericDialogController(pWindow, "cui/ui/aboutconfigvaluedialog.ui", "AboutConfigValueDialog") 543 , m_bNumericOnly(limit != 0) 544 , m_xEDValue(m_xBuilder->weld_entry("valuebox")) 545 { 546 if (limit) 547 m_xEDValue->set_max_length(limit); 548 m_xEDValue->set_text(rValue); 549 m_xEDValue->connect_key_press(LINK(this, CuiAboutConfigValueDialog, KeyInputHdl)); 550 } 551 552 CuiAboutConfigValueDialog::~CuiAboutConfigValueDialog() 553 { 554 } 555 556 IMPL_LINK_NOARG( CuiAboutConfigTabPage, ResetBtnHdl_Impl, weld::Button&, void ) 557 { 558 Reset(); 559 } 560 561 IMPL_LINK_NOARG(CuiAboutConfigTabPage, DoubleClickHdl_Impl, weld::TreeView&, bool) 562 { 563 StandardHdl_Impl(*m_xEditBtn); 564 return true; 565 } 566 567 IMPL_LINK_NOARG( CuiAboutConfigTabPage, StandardHdl_Impl, weld::Button&, void ) 568 { 569 if (!m_xPrefBox->get_selected(m_xScratchIter.get())) 570 return; 571 572 UserData *pUserData = reinterpret_cast<UserData*>(m_xPrefBox->get_id(*m_xScratchIter).toInt64()); 573 if (pUserData && pUserData->bIsPropertyPath) 574 { 575 //if selection is a node 576 OUString sPropertyName = m_xPrefBox->get_text(*m_xScratchIter, 1); 577 OUString sPropertyType = m_xPrefBox->get_text(*m_xScratchIter, 2); 578 OUString sPropertyValue = m_xPrefBox->get_text(*m_xScratchIter, 3); 579 580 auto pProperty = std::make_shared<Prop_Impl>( pUserData->sPropertyPath, sPropertyName, Any( sPropertyValue ) ); 581 bool bSaveChanges = false; 582 583 bool bOpenDialog = true; 584 OUString sDialogValue; 585 OUString sNewValue; 586 587 if( sPropertyType == "boolean" ) 588 { 589 bool bValue; 590 if( sPropertyValue == "true" ) 591 { 592 sDialogValue = "false"; 593 bValue = false; 594 } 595 else 596 { 597 sDialogValue = "true"; 598 bValue = true; 599 } 600 601 pProperty->Value <<= bValue; 602 bOpenDialog = false; 603 bSaveChanges = true; 604 } 605 else if ( sPropertyType == "void" ) 606 { 607 bOpenDialog = false; 608 } 609 else 610 { 611 sDialogValue = sPropertyValue; 612 bOpenDialog = true; 613 } 614 615 try 616 { 617 if( bOpenDialog ) 618 { 619 //Cosmetic length limit for integer values. 620 int limit=0; 621 if( sPropertyType == "short" ) 622 limit = SHORT_LEN_LIMIT; 623 else if( sPropertyType == "long" ) 624 limit = LONG_LEN_LIMIT; 625 else if( sPropertyType == "hyper" ) 626 limit = HYPER_LEN_LIMIT; 627 628 CuiAboutConfigValueDialog aValueDialog(m_xDialog.get(), sDialogValue, limit); 629 630 if (aValueDialog.run() == RET_OK ) 631 { 632 sNewValue = aValueDialog.getValue(); 633 bSaveChanges = true; 634 if ( sPropertyType == "short") 635 { 636 sal_Int16 nShort; 637 sal_Int32 nNumb = sNewValue.toInt32(); 638 639 //if the value is 0 and length is not 1, there is something wrong 640 if( ( nNumb==0 && sNewValue.getLength()!=1 ) || nNumb > SAL_MAX_INT16 || nNumb < SAL_MIN_INT16) 641 throw uno::Exception("out of range short", nullptr); 642 nShort = static_cast<sal_Int16>(nNumb); 643 pProperty->Value <<= nShort; 644 } 645 else if( sPropertyType == "long" ) 646 { 647 sal_Int32 nLong = sNewValue.toInt32(); 648 if( nLong==0 && sNewValue.getLength()!=1) 649 throw uno::Exception("out of range long", nullptr); 650 pProperty->Value <<= nLong; 651 } 652 else if( sPropertyType == "hyper") 653 { 654 sal_Int64 nHyper = sNewValue.toInt64(); 655 if( nHyper==0 && sNewValue.getLength()!=1) 656 throw uno::Exception("out of range hyper", nullptr); 657 pProperty->Value <<= nHyper; 658 } 659 else if( sPropertyType == "double") 660 { 661 double nDoub = sNewValue.toDouble(); 662 if( nDoub ==0 && sNewValue.getLength()!=1) 663 throw uno::Exception("out of range double", nullptr); 664 pProperty->Value <<= nDoub; 665 } 666 else if( sPropertyType == "float") 667 { 668 float nFloat = sNewValue.toFloat(); 669 if( nFloat ==0 && sNewValue.getLength()!=1) 670 throw uno::Exception("out of range float", nullptr); 671 pProperty->Value <<= nFloat; 672 } 673 else if( sPropertyType == "string" ) 674 { 675 pProperty->Value <<= sNewValue; 676 } 677 else if( sPropertyType == "[]short" ) 678 { 679 //create string sequence from comma separated string 680 //uno::Sequence< OUString > seqStr; 681 std::vector< OUString > seqStr = commaStringToSequence( sNewValue ); 682 683 //create appropriate sequence with same size as string sequence 684 uno::Sequence< sal_Int16 > seqShort( seqStr.size() ); 685 //convert all strings to appropriate type 686 for( size_t i = 0; i < seqStr.size(); ++i ) 687 { 688 seqShort[i] = static_cast<sal_Int16>(seqStr[i].toInt32()); 689 } 690 pProperty->Value <<= seqShort; 691 } 692 else if( sPropertyType == "[]long" ) 693 { 694 std::vector< OUString > seqStrLong = commaStringToSequence( sNewValue ); 695 696 uno::Sequence< sal_Int32 > seqLong( seqStrLong.size() ); 697 for( size_t i = 0; i < seqStrLong.size(); ++i ) 698 { 699 seqLong[i] = seqStrLong[i].toInt32(); 700 } 701 pProperty->Value <<= seqLong; 702 } 703 else if( sPropertyType == "[]hyper" ) 704 { 705 std::vector< OUString > seqStrHyper = commaStringToSequence( sNewValue ); 706 uno::Sequence< sal_Int64 > seqHyper( seqStrHyper.size() ); 707 for( size_t i = 0; i < seqStrHyper.size(); ++i ) 708 { 709 seqHyper[i] = seqStrHyper[i].toInt64(); 710 } 711 pProperty->Value <<= seqHyper; 712 } 713 else if( sPropertyType == "[]double" ) 714 { 715 std::vector< OUString > seqStrDoub = commaStringToSequence( sNewValue ); 716 uno::Sequence< double > seqDoub( seqStrDoub.size() ); 717 for( size_t i = 0; i < seqStrDoub.size(); ++i ) 718 { 719 seqDoub[i] = seqStrDoub[i].toDouble(); 720 } 721 pProperty->Value <<= seqDoub; 722 } 723 else if( sPropertyType == "[]float" ) 724 { 725 std::vector< OUString > seqStrFloat = commaStringToSequence( sNewValue ); 726 uno::Sequence< sal_Int16 > seqFloat( seqStrFloat.size() ); 727 for( size_t i = 0; i < seqStrFloat.size(); ++i ) 728 { 729 seqFloat[i] = seqStrFloat[i].toFloat(); 730 } 731 pProperty->Value <<= seqFloat; 732 } 733 else if( sPropertyType == "[]string" ) 734 { 735 pProperty->Value <<= comphelper::containerToSequence( commaStringToSequence( sNewValue )); 736 } 737 else //unknown 738 throw uno::Exception("unknown property type " + sPropertyType, nullptr); 739 740 sDialogValue = sNewValue; 741 } 742 } 743 744 if(bSaveChanges) 745 { 746 AddToModifiedVector( pProperty ); 747 748 //update listbox value. 749 m_xPrefBox->set_text(*m_xScratchIter, sDialogValue, 3); 750 //update m_prefBoxEntries 751 auto it = std::find_if(m_prefBoxEntries.begin(), m_prefBoxEntries.end(), 752 [&pUserData, &sPropertyName](const prefBoxEntry& rEntry) -> bool 753 { 754 return rEntry.pUserData->sPropertyPath == pUserData->sPropertyPath 755 && rEntry.sStatus == sPropertyName; 756 } 757 ); 758 if (it != m_prefBoxEntries.end()) 759 { 760 it->sValue = sDialogValue; 761 762 auto modifiedIt = std::find_if( 763 m_modifiedPrefBoxEntries.begin(), m_modifiedPrefBoxEntries.end(), 764 [&pUserData, &sPropertyName](const prefBoxEntry& rEntry) -> bool 765 { 766 return rEntry.pUserData->sPropertyPath == pUserData->sPropertyPath 767 && rEntry.sStatus == sPropertyName; 768 } 769 ); 770 771 if (modifiedIt != m_modifiedPrefBoxEntries.end()) 772 { 773 modifiedIt->sValue = sDialogValue; 774 } 775 else 776 { 777 m_modifiedPrefBoxEntries.push_back(*it); 778 } 779 } 780 } 781 } 782 catch( uno::Exception& ) 783 { 784 } 785 } 786 } 787 788 IMPL_LINK_NOARG( CuiAboutConfigTabPage, SearchHdl_Impl, weld::Button&, void) 789 { 790 weld::WaitObject aWait(m_xDialog.get()); 791 792 m_xPrefBox->clear(); 793 m_xPrefBox->freeze(); 794 795 if (m_bSorted) 796 m_xPrefBox->make_unsorted(); 797 798 if (m_xSearchEdit->get_text().isEmpty()) 799 { 800 m_xPrefBox->clear(); 801 Reference< XNameAccess > xConfigAccess = getConfigAccess( "/", false ); 802 FillItems( xConfigAccess ); 803 } 804 else 805 { 806 m_options.searchString = m_xSearchEdit->get_text(); 807 utl::TextSearch textSearch( m_options ); 808 for (auto const& it : m_prefBoxEntries) 809 { 810 sal_Int32 endPos, startPos = 0; 811 812 for(size_t i = 0; i < 5; ++i) 813 { 814 OUString scrTxt; 815 816 if (i == 0) 817 scrTxt = it.pUserData->sPropertyPath; 818 else if (i == 1) 819 scrTxt = it.sProp; 820 else if (i == 2) 821 scrTxt = it.sStatus; 822 else if (i == 3) 823 scrTxt = it.sType; 824 else if (i == 4) 825 scrTxt = it.sValue; 826 827 endPos = scrTxt.getLength(); 828 if (textSearch.SearchForward(scrTxt, &startPos, &endPos)) 829 { 830 InsertEntry(it); 831 break; 832 } 833 } 834 } 835 } 836 837 m_xPrefBox->thaw(); 838 if (m_bSorted) 839 m_xPrefBox->make_sorted(); 840 841 m_xPrefBox->all_foreach([this](weld::TreeIter& rEntry) { 842 m_xPrefBox->expand_row(rEntry); 843 return false; 844 }); 845 } 846 847 void CuiAboutConfigTabPage::InsertEntry(const prefBoxEntry& rEntry) 848 { 849 OUString sPathWithProperty = rEntry.pUserData->sPropertyPath; 850 sal_Int32 index = sPathWithProperty.lastIndexOf(rEntry.sProp); 851 OUString sPath = sPathWithProperty.copy(0, index); 852 index = 0; 853 std::unique_ptr<weld::TreeIter> xParentEntry(m_xPrefBox->make_iterator()); 854 std::unique_ptr<weld::TreeIter> xGrandParentEntry; 855 856 do 857 { 858 int prevIndex = index; 859 index = sPath.indexOf("/", index+1); 860 // deal with no parent case (tdf#107811) 861 if (index < 0) 862 { 863 OUString sId(OUString::number(reinterpret_cast<sal_Int64>(rEntry.pUserData))); 864 m_xPrefBox->insert(nullptr, -1, &rEntry.sProp, &sId, nullptr, nullptr, nullptr, false, m_xScratchIter.get()); 865 m_xPrefBox->set_text(*m_xScratchIter, rEntry.sStatus, 1); 866 m_xPrefBox->set_text(*m_xScratchIter, rEntry.sType, 2); 867 m_xPrefBox->set_text(*m_xScratchIter, rEntry.sValue, 3); 868 return; 869 } 870 OUString sParentName = sPath.copy(prevIndex+1, index - prevIndex - 1); 871 872 bool hasEntry = false; 873 bool bStartOk; 874 875 if (!xGrandParentEntry) 876 bStartOk = m_xPrefBox->get_iter_first(*xParentEntry); 877 else 878 { 879 m_xPrefBox->copy_iterator(*xGrandParentEntry, *xParentEntry); 880 bStartOk = m_xPrefBox->iter_children(*xParentEntry); 881 } 882 883 if (bStartOk) 884 { 885 do 886 { 887 if (m_xPrefBox->get_text(*xParentEntry, 0) == sParentName) 888 { 889 hasEntry = true; 890 break; 891 } 892 } while (m_xPrefBox->iter_next_sibling(*xParentEntry)); 893 } 894 895 if (!hasEntry) 896 { 897 m_xPrefBox->insert(xGrandParentEntry.get(), -1, &sParentName, nullptr, nullptr, nullptr, nullptr, false, xParentEntry.get()); 898 //It is needed, without this the selection line will be truncated. 899 m_xPrefBox->set_text(*xParentEntry, "", 1); 900 m_xPrefBox->set_text(*xParentEntry, "", 2); 901 m_xPrefBox->set_text(*xParentEntry, "", 3); 902 } 903 904 xGrandParentEntry = m_xPrefBox->make_iterator(xParentEntry.get()); 905 } while(index < sPath.getLength() - 1); 906 907 OUString sId(OUString::number(reinterpret_cast<sal_Int64>(rEntry.pUserData))); 908 m_xPrefBox->insert(xParentEntry.get(), -1, &rEntry.sProp, &sId, nullptr, nullptr, nullptr, false, m_xScratchIter.get()); 909 m_xPrefBox->set_text(*m_xScratchIter, rEntry.sStatus, 1); 910 m_xPrefBox->set_text(*m_xScratchIter, rEntry.sType, 2); 911 m_xPrefBox->set_text(*m_xScratchIter, rEntry.sValue, 3); 912 } 913 914 IMPL_LINK(CuiAboutConfigTabPage, ExpandingHdl_Impl, const weld::TreeIter&, rEntry, bool) 915 { 916 if (m_xPrefBox->iter_has_child(rEntry)) 917 return true; 918 UserData *pUserData = reinterpret_cast<UserData*>(m_xPrefBox->get_id(rEntry).toInt64()); 919 if (pUserData && !pUserData->bIsPropertyPath) 920 { 921 assert(pUserData->aXNameAccess.is()); 922 FillItems(pUserData->aXNameAccess, &rEntry, pUserData->aLineage); 923 } 924 return true; 925 } 926 927 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ 928
