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 <config_feature_desktop.h> 11 #include <config_options.h> 12 13 #include <memory> 14 #include <unordered_map> 15 #include <com/sun/star/accessibility/AccessibleRole.hpp> 16 17 #include <comphelper/lok.hxx> 18 #include <i18nutil/unicode.hxx> 19 #include <officecfg/Office/Common.hxx> 20 #include <osl/module.hxx> 21 #include <sal/log.hxx> 22 #include <unotools/localedatawrapper.hxx> 23 #include <unotools/resmgr.hxx> 24 #include <vcl/builder.hxx> 25 #include <vcl/toolkit/button.hxx> 26 #include <vcl/toolkit/dialog.hxx> 27 #include <vcl/edit.hxx> 28 #include <vcl/toolkit/field.hxx> 29 #include <vcl/fieldvalues.hxx> 30 #include <vcl/fmtfield.hxx> 31 #include <vcl/toolkit/fixed.hxx> 32 #include <vcl/toolkit/fixedhyper.hxx> 33 #include <vcl/headbar.hxx> 34 #include <vcl/IPrioritable.hxx> 35 #include <vcl/ivctrl.hxx> 36 #include <vcl/layout.hxx> 37 #include <vcl/toolkit/lstbox.hxx> 38 #include <vcl/menubtn.hxx> 39 #include <vcl/mnemonic.hxx> 40 #include <vcl/toolkit/prgsbar.hxx> 41 #include <vcl/scrbar.hxx> 42 #include <vcl/split.hxx> 43 #include <vcl/svapp.hxx> 44 #include <vcl/toolkit/svtabbx.hxx> 45 #include <vcl/tabctrl.hxx> 46 #include <vcl/tabpage.hxx> 47 #include <vcl/toolkit/throbber.hxx> 48 #include <vcl/toolbox.hxx> 49 #include <vcl/treelistentry.hxx> 50 #include <vcl/vclmedit.hxx> 51 #include <vcl/settings.hxx> 52 #include <slider.hxx> 53 #include <vcl/weld.hxx> 54 #include <vcl/weldutils.hxx> 55 #include <vcl/commandinfoprovider.hxx> 56 #include <iconview.hxx> 57 #include <svdata.hxx> 58 #include <bitmaps.hlst> 59 #include <messagedialog.hxx> 60 #include <OptionalBox.hxx> 61 #include <window.h> 62 #include <xmlreader/xmlreader.hxx> 63 #include <desktop/crashreport.hxx> 64 #include <calendar.hxx> 65 #include <salinst.hxx> 66 #include <strings.hrc> 67 #include <treeglue.hxx> 68 #include <tools/diagnose_ex.h> 69 #include <wizdlg.hxx> 70 #include <tools/svlibrary.h> 71 #include <jsdialog/jsdialogbuilder.hxx> 72 73 #if defined(DISABLE_DYNLOADING) || defined(LINUX) 74 #include <dlfcn.h> 75 #endif 76 77 static bool toBool(const OString &rValue) 78 { 79 return (!rValue.isEmpty() && (rValue[0] == 't' || rValue[0] == 'T' || rValue[0] == '1')); 80 } 81 82 namespace 83 { 84 OUString mapStockToImageResource(const OUString& sType) 85 { 86 if (sType == "gtk-index") 87 return SV_RESID_BITMAP_INDEX; 88 else if (sType == "gtk-refresh") 89 return SV_RESID_BITMAP_REFRESH; 90 else if (sType == "gtk-apply") 91 return IMG_APPLY; 92 else if (sType == "gtk-dialog-error") 93 return IMG_ERROR; 94 else if (sType == "gtk-add") 95 return IMG_ADD; 96 else if (sType == "gtk-remove") 97 return IMG_REMOVE; 98 else if (sType == "gtk-copy") 99 return IMG_COPY; 100 else if (sType == "gtk-paste") 101 return IMG_PASTE; 102 return OUString(); 103 } 104 105 SymbolType mapStockToSymbol(const OUString& sType) 106 { 107 SymbolType eRet = SymbolType::DONTKNOW; 108 if (sType == "gtk-media-next") 109 eRet = SymbolType::NEXT; 110 else if (sType == "gtk-media-previous") 111 eRet = SymbolType::PREV; 112 else if (sType == "gtk-media-play") 113 eRet = SymbolType::PLAY; 114 else if (sType == "gtk-media-stop") 115 eRet = SymbolType::STOP; 116 else if (sType == "gtk-goto-first") 117 eRet = SymbolType::FIRST; 118 else if (sType == "gtk-goto-last") 119 eRet = SymbolType::LAST; 120 else if (sType == "gtk-go-back") 121 eRet = SymbolType::ARROW_LEFT; 122 else if (sType == "gtk-go-forward") 123 eRet = SymbolType::ARROW_RIGHT; 124 else if (sType == "gtk-go-up") 125 eRet = SymbolType::ARROW_UP; 126 else if (sType == "gtk-go-down") 127 eRet = SymbolType::ARROW_DOWN; 128 else if (sType == "gtk-missing-image") 129 eRet = SymbolType::IMAGE; 130 else if (sType == "gtk-help") 131 eRet = SymbolType::HELP; 132 else if (sType == "gtk-close") 133 eRet = SymbolType::CLOSE; 134 else if (!mapStockToImageResource(sType).isEmpty()) 135 eRet = SymbolType::IMAGE; 136 return eRet; 137 } 138 139 void setupFromActionName(Button *pButton, VclBuilder::stringmap &rMap, const css::uno::Reference<css::frame::XFrame>& rFrame); 140 } 141 142 #if defined SAL_LOG_WARN 143 namespace 144 { 145 bool isButtonType(WindowType nType) 146 { 147 return nType == WindowType::PUSHBUTTON || 148 nType == WindowType::OKBUTTON || 149 nType == WindowType::CANCELBUTTON || 150 nType == WindowType::HELPBUTTON || 151 nType == WindowType::IMAGEBUTTON || 152 nType == WindowType::MENUBUTTON || 153 nType == WindowType::MOREBUTTON || 154 nType == WindowType::SPINBUTTON; 155 } 156 } 157 #endif 158 159 weld::Builder* Application::CreateBuilder(weld::Widget* pParent, const OUString &rUIFile, bool bMobile) 160 { 161 bool bUseJSBuilder = false; 162 163 if (bMobile) 164 { 165 if (rUIFile == "modules/swriter/ui/wordcount-mobile.ui") 166 bUseJSBuilder = true; 167 } 168 169 if (bUseJSBuilder) 170 return new JSInstanceBuilder(pParent, VclBuilderContainer::getUIRootDir(), rUIFile); 171 else 172 return ImplGetSVData()->mpDefInst->CreateBuilder(pParent, VclBuilderContainer::getUIRootDir(), rUIFile); 173 } 174 175 weld::Builder* Application::CreateInterimBuilder(vcl::Window* pParent, const OUString &rUIFile) 176 { 177 return ImplGetSVData()->mpDefInst->CreateInterimBuilder(pParent, VclBuilderContainer::getUIRootDir(), rUIFile); 178 } 179 180 weld::MessageDialog* Application::CreateMessageDialog(weld::Widget* pParent, VclMessageType eMessageType, 181 VclButtonsType eButtonType, const OUString& rPrimaryMessage, 182 bool bMobile) 183 { 184 if (bMobile) 185 return JSInstanceBuilder::CreateMessageDialog(pParent, eMessageType, eButtonType, rPrimaryMessage); 186 else 187 return ImplGetSVData()->mpDefInst->CreateMessageDialog(pParent, eMessageType, eButtonType, rPrimaryMessage); 188 } 189 190 weld::Window* Application::GetFrameWeld(const css::uno::Reference<css::awt::XWindow>& rWindow) 191 { 192 return ImplGetSVData()->mpDefInst->GetFrameWeld(rWindow); 193 } 194 195 namespace weld 196 { 197 OUString MetricSpinButton::MetricToString(FieldUnit rUnit) 198 { 199 const FieldUnitStringList& rList = ImplGetFieldUnits(); 200 // return unit's default string (ie, the first one ) 201 auto it = std::find_if( 202 rList.begin(), rList.end(), 203 [&rUnit](const std::pair<OUString, FieldUnit>& rItem) { return rItem.second == rUnit; }); 204 if (it != rList.end()) 205 return it->first; 206 207 return OUString(); 208 } 209 210 IMPL_LINK_NOARG(MetricSpinButton, spin_button_value_changed, SpinButton&, void) 211 { 212 signal_value_changed(); 213 } 214 215 IMPL_LINK(MetricSpinButton, spin_button_output, SpinButton&, rSpinButton, void) 216 { 217 OUString sNewText(format_number(rSpinButton.get_value())); 218 if (sNewText != rSpinButton.get_text()) 219 rSpinButton.set_text(sNewText); 220 } 221 222 void MetricSpinButton::update_width_chars() 223 { 224 int min, max; 225 m_xSpinButton->get_range(min, max); 226 auto width = std::max(m_xSpinButton->get_pixel_size(format_number(min)).Width(), 227 m_xSpinButton->get_pixel_size(format_number(max)).Width()); 228 int chars = ceil(width / m_xSpinButton->get_approximate_digit_width()); 229 m_xSpinButton->set_width_chars(chars); 230 } 231 232 unsigned int SpinButton::Power10(unsigned int n) 233 { 234 unsigned int nValue = 1; 235 for (unsigned int i = 0; i < n; ++i) 236 nValue *= 10; 237 return nValue; 238 } 239 240 int SpinButton::denormalize(int nValue) const 241 { 242 const int nFactor = Power10(get_digits()); 243 244 if ((nValue < (SAL_MIN_INT32 + nFactor)) || (nValue > (SAL_MAX_INT32 - nFactor))) 245 { 246 return nValue / nFactor; 247 } 248 249 const int nHalf = nFactor / 2; 250 251 if (nValue < 0) 252 return (nValue - nHalf) / nFactor; 253 return (nValue + nHalf) / nFactor; 254 } 255 256 OUString MetricSpinButton::format_number(int nValue) const 257 { 258 OUString aStr; 259 260 const LocaleDataWrapper& rLocaleData = Application::GetSettings().GetLocaleDataWrapper(); 261 262 unsigned int nDecimalDigits = m_xSpinButton->get_digits(); 263 //pawn percent off to icu to decide whether percent is separated from its number for this locale 264 if (m_eSrcUnit == FieldUnit::PERCENT) 265 { 266 double fValue = nValue; 267 fValue /= SpinButton::Power10(nDecimalDigits); 268 aStr = unicode::formatPercent(fValue, rLocaleData.getLanguageTag()); 269 } 270 else 271 { 272 aStr = rLocaleData.getNum(nValue, nDecimalDigits, true, true); 273 OUString aSuffix = MetricToString(m_eSrcUnit); 274 if (m_eSrcUnit != FieldUnit::NONE && m_eSrcUnit != FieldUnit::DEGREE && m_eSrcUnit != FieldUnit::INCH && m_eSrcUnit != FieldUnit::FOOT) 275 aStr += " "; 276 if (m_eSrcUnit == FieldUnit::INCH) 277 { 278 OUString sDoublePrime = u"\u2033"; 279 if (aSuffix != "\"" && aSuffix != sDoublePrime) 280 aStr += " "; 281 else 282 aSuffix = sDoublePrime; 283 } 284 else if (m_eSrcUnit == FieldUnit::FOOT) 285 { 286 OUString sPrime = u"\u2032"; 287 if (aSuffix != "'" && aSuffix != sPrime) 288 aStr += " "; 289 else 290 aSuffix = sPrime; 291 } 292 293 assert(m_eSrcUnit != FieldUnit::PERCENT); 294 aStr += aSuffix; 295 } 296 297 return aStr; 298 } 299 300 void MetricSpinButton::set_digits(unsigned int digits) 301 { 302 int step, page; 303 get_increments(step, page, m_eSrcUnit); 304 int value = get_value(m_eSrcUnit); 305 m_xSpinButton->set_digits(digits); 306 set_increments(step, page, m_eSrcUnit); 307 set_value(value, m_eSrcUnit); 308 update_width_chars(); 309 } 310 311 void MetricSpinButton::set_unit(FieldUnit eUnit) 312 { 313 if (eUnit != m_eSrcUnit) 314 { 315 int step, page; 316 get_increments(step, page, m_eSrcUnit); 317 int value = get_value(m_eSrcUnit); 318 m_eSrcUnit = eUnit; 319 set_increments(step, page, m_eSrcUnit); 320 set_value(value, m_eSrcUnit); 321 spin_button_output(*m_xSpinButton); 322 update_width_chars(); 323 } 324 } 325 326 int MetricSpinButton::ConvertValue(int nValue, FieldUnit eInUnit, FieldUnit eOutUnit) const 327 { 328 return vcl::ConvertValue(nValue, 0, m_xSpinButton->get_digits(), eInUnit, eOutUnit); 329 } 330 331 IMPL_LINK(MetricSpinButton, spin_button_input, int*, result, bool) 332 { 333 const LocaleDataWrapper& rLocaleData = Application::GetSettings().GetLocaleDataWrapper(); 334 double fResult(0.0); 335 bool bRet = vcl::TextToValue(get_text(), fResult, 0, m_xSpinButton->get_digits(), rLocaleData, m_eSrcUnit); 336 if (bRet) 337 { 338 if (fResult > SAL_MAX_INT32) 339 fResult = SAL_MAX_INT32; 340 else if (fResult < SAL_MIN_INT32) 341 fResult = SAL_MIN_INT32; 342 *result = fResult; 343 } 344 return bRet; 345 } 346 347 IMPL_LINK_NOARG(TimeSpinButton, spin_button_cursor_position, Entry&, void) 348 { 349 int nStartPos, nEndPos; 350 m_xSpinButton->get_selection_bounds(nStartPos, nEndPos); 351 352 const LocaleDataWrapper& rLocaleData = Application::GetSettings().GetLocaleDataWrapper(); 353 const int nTimeArea = TimeFormatter::GetTimeArea(m_eFormat, m_xSpinButton->get_text(), nEndPos, 354 rLocaleData); 355 356 int nIncrements = 1; 357 358 if (nTimeArea == 1) 359 nIncrements = 1000 * 60 * 60; 360 else if (nTimeArea == 2) 361 nIncrements = 1000 * 60; 362 else if (nTimeArea == 3) 363 nIncrements = 1000; 364 365 m_xSpinButton->set_increments(nIncrements, nIncrements * 10); 366 } 367 368 IMPL_LINK_NOARG(TimeSpinButton, spin_button_value_changed, SpinButton&, void) 369 { 370 signal_value_changed(); 371 } 372 373 IMPL_LINK(TimeSpinButton, spin_button_output, SpinButton&, rSpinButton, void) 374 { 375 int nStartPos, nEndPos; 376 rSpinButton.get_selection_bounds(nStartPos, nEndPos); 377 rSpinButton.set_text(format_number(rSpinButton.get_value())); 378 rSpinButton.set_position(nEndPos); 379 } 380 381 IMPL_LINK(TimeSpinButton, spin_button_input, int*, result, bool) 382 { 383 int nStartPos, nEndPos; 384 m_xSpinButton->get_selection_bounds(nStartPos, nEndPos); 385 386 const LocaleDataWrapper& rLocaleData = Application::GetSettings().GetLocaleDataWrapper(); 387 tools::Time aResult(0); 388 bool bRet = TimeFormatter::TextToTime(m_xSpinButton->get_text(), aResult, m_eFormat, true, rLocaleData); 389 if (bRet) 390 *result = ConvertValue(aResult); 391 return bRet; 392 } 393 394 void TimeSpinButton::update_width_chars() 395 { 396 int min, max; 397 m_xSpinButton->get_range(min, max); 398 auto width = std::max(m_xSpinButton->get_pixel_size(format_number(min)).Width(), 399 m_xSpinButton->get_pixel_size(format_number(max)).Width()); 400 int chars = ceil(width / m_xSpinButton->get_approximate_digit_width()); 401 m_xSpinButton->set_width_chars(chars); 402 } 403 404 tools::Time TimeSpinButton::ConvertValue(int nValue) 405 { 406 tools::Time aTime(0); 407 aTime.MakeTimeFromMS(nValue); 408 return aTime; 409 } 410 411 int TimeSpinButton::ConvertValue(const tools::Time& rTime) 412 { 413 return rTime.GetMSFromTime(); 414 } 415 416 OUString TimeSpinButton::format_number(int nValue) const 417 { 418 const LocaleDataWrapper& rLocaleData = Application::GetSettings().GetLocaleDataWrapper(); 419 return TimeFormatter::FormatTime(ConvertValue(nValue), m_eFormat, TimeFormat::Hour24, true, rLocaleData); 420 } 421 422 EntryTreeView::EntryTreeView(std::unique_ptr<Entry> xEntry, std::unique_ptr<TreeView> xTreeView) 423 : m_xEntry(std::move(xEntry)) 424 , m_xTreeView(std::move(xTreeView)) 425 { 426 m_xTreeView->connect_changed(LINK(this, EntryTreeView, ClickHdl)); 427 m_xEntry->connect_changed(LINK(this, EntryTreeView, ModifyHdl)); 428 } 429 430 IMPL_LINK(EntryTreeView, ClickHdl, weld::TreeView&, rView, void) 431 { 432 m_xEntry->set_text(rView.get_selected_text()); 433 m_aChangeHdl.Call(*this); 434 } 435 436 IMPL_LINK_NOARG(EntryTreeView, ModifyHdl, weld::Entry&, void) 437 { 438 m_aChangeHdl.Call(*this); 439 } 440 441 void EntryTreeView::set_height_request_by_rows(int nRows) 442 { 443 int nHeight = nRows == -1 ? -1 : m_xTreeView->get_height_rows(nRows); 444 m_xTreeView->set_size_request(m_xTreeView->get_size_request().Width(), nHeight); 445 } 446 447 size_t GetAbsPos(const weld::TreeView& rTreeView, const weld::TreeIter& rIter) 448 { 449 size_t nAbsPos = 0; 450 451 std::unique_ptr<weld::TreeIter> xEntry(rTreeView.make_iterator(&rIter)); 452 if (!rTreeView.get_iter_first(*xEntry)) 453 xEntry.reset(); 454 455 while (xEntry && rTreeView.iter_compare(*xEntry, rIter) != 0) 456 { 457 if (!rTreeView.iter_next(*xEntry)) 458 xEntry.reset(); 459 nAbsPos++; 460 } 461 462 return nAbsPos; 463 } 464 465 bool IsEntryVisible(const weld::TreeView& rTreeView, const weld::TreeIter& rIter) 466 { 467 // short circuit for the common case 468 if (rTreeView.get_iter_depth(rIter) == 0) 469 return true; 470 471 std::unique_ptr<weld::TreeIter> xEntry(rTreeView.make_iterator(&rIter)); 472 bool bRetVal = false; 473 do 474 { 475 if (rTreeView.get_iter_depth(*xEntry) == 0) 476 { 477 bRetVal = true; 478 break; 479 } 480 } while (rTreeView.iter_parent(*xEntry) && rTreeView.get_row_expanded(*xEntry)); 481 return bRetVal; 482 } 483 } 484 485 VclBuilder::VclBuilder(vcl::Window* pParent, const OUString& sUIDir, const OUString& sUIFile, 486 const OString& sID, const css::uno::Reference<css::frame::XFrame>& rFrame, 487 bool bLegacy, const NotebookBarAddonsItem* pNotebookBarAddonsItem) 488 : m_pNotebookBarAddonsItem(pNotebookBarAddonsItem 489 ? new NotebookBarAddonsItem(*pNotebookBarAddonsItem) 490 : new NotebookBarAddonsItem{}) 491 , m_sID(sID) 492 , m_sHelpRoot(OUStringToOString(sUIFile, RTL_TEXTENCODING_UTF8)) 493 , m_pStringReplace(Translate::GetReadStringHook()) 494 , m_pParent(pParent) 495 , m_bToplevelParentFound(false) 496 , m_bLegacy(bLegacy) 497 , m_pParserState(new ParserState) 498 , m_xFrame(rFrame) 499 { 500 m_bToplevelHasDeferredInit = pParent && 501 ((pParent->IsSystemWindow() && static_cast<SystemWindow*>(pParent)->isDeferredInit()) || 502 (pParent->IsDockingWindow() && static_cast<DockingWindow*>(pParent)->isDeferredInit())); 503 m_bToplevelHasDeferredProperties = m_bToplevelHasDeferredInit; 504 505 sal_Int32 nIdx = m_sHelpRoot.lastIndexOf('.'); 506 if (nIdx != -1) 507 m_sHelpRoot = m_sHelpRoot.copy(0, nIdx); 508 m_sHelpRoot += OString('/'); 509 510 OUString sUri = sUIDir + sUIFile; 511 512 try 513 { 514 xmlreader::XmlReader reader(sUri); 515 516 handleChild(pParent, reader); 517 } 518 catch (const css::uno::Exception &rExcept) 519 { 520 DBG_UNHANDLED_EXCEPTION("vcl.builder", "Unable to read .ui file"); 521 CrashReporter::addKeyValue("VclBuilderException", "Unable to read .ui file: " + rExcept.Message, CrashReporter::Write); 522 throw; 523 } 524 525 //Set Mnemonic widgets when everything has been imported 526 for (auto const& mnemonicWidget : m_pParserState->m_aMnemonicWidgetMaps) 527 { 528 FixedText *pOne = get<FixedText>(mnemonicWidget.m_sID); 529 vcl::Window *pOther = get(mnemonicWidget.m_sValue.toUtf8()); 530 SAL_WARN_IF(!pOne || !pOther, "vcl", "missing either source " << mnemonicWidget.m_sID 531 << " or target " << mnemonicWidget.m_sValue << " member of Mnemonic Widget Mapping"); 532 if (pOne && pOther) 533 pOne->set_mnemonic_widget(pOther); 534 } 535 536 //Set a11y relations and role when everything has been imported 537 for (auto const& elemAtk : m_pParserState->m_aAtkInfo) 538 { 539 vcl::Window *pSource = elemAtk.first; 540 const stringmap &rMap = elemAtk.second; 541 542 for (auto const& elemMap : rMap) 543 { 544 const OString &rType = elemMap.first; 545 const OUString &rParam = elemMap.second; 546 if (rType == "role") 547 { 548 sal_Int16 role = BuilderUtils::getRoleFromName(rParam.toUtf8()); 549 if (role != com::sun::star::accessibility::AccessibleRole::UNKNOWN) 550 pSource->SetAccessibleRole(role); 551 } 552 else 553 { 554 vcl::Window *pTarget = get(rParam.toUtf8()); 555 SAL_WARN_IF(!pTarget, "vcl", "missing parameter of a11y relation: " << rParam); 556 if (!pTarget) 557 continue; 558 if (rType == "labelled-by") 559 pSource->SetAccessibleRelationLabeledBy(pTarget); 560 else if (rType == "label-for") 561 pSource->SetAccessibleRelationLabelFor(pTarget); 562 else if (rType == "member-of") 563 pSource->SetAccessibleRelationMemberOf(pTarget); 564 else 565 { 566 SAL_WARN("vcl.builder", "unhandled a11y relation :" << rType); 567 } 568 } 569 } 570 } 571 572 //Set radiobutton groups when everything has been imported 573 for (auto const& elem : m_pParserState->m_aGroupMaps) 574 { 575 RadioButton *pOne = get<RadioButton>(elem.m_sID); 576 RadioButton *pOther = get<RadioButton>(elem.m_sValue); 577 SAL_WARN_IF(!pOne || !pOther, "vcl", "missing member of radiobutton group"); 578 if (pOne && pOther) 579 { 580 if (m_bLegacy) 581 pOne->group(*pOther); 582 else 583 { 584 pOther->group(*pOne); 585 std::stable_sort(pOther->m_xGroup->begin(), pOther->m_xGroup->end(), sortIntoBestTabTraversalOrder(this)); 586 } 587 } 588 } 589 590 //Set ComboBox models when everything has been imported 591 for (auto const& elem : m_pParserState->m_aModelMaps) 592 { 593 vcl::Window* pTarget = get(elem.m_sID); 594 ListBox *pListBoxTarget = dynamic_cast<ListBox*>(pTarget); 595 ComboBox *pComboBoxTarget = dynamic_cast<ComboBox*>(pTarget); 596 SvTabListBox *pTreeBoxTarget = dynamic_cast<SvTabListBox*>(pTarget); 597 // pStore may be empty 598 const ListStore *pStore = get_model_by_name(elem.m_sValue.toUtf8()); 599 SAL_WARN_IF(!pListBoxTarget && !pComboBoxTarget && !pTreeBoxTarget, "vcl", "missing elements of combobox"); 600 if (pListBoxTarget && pStore) 601 mungeModel(*pListBoxTarget, *pStore, elem.m_nActiveId); 602 else if (pComboBoxTarget && pStore) 603 mungeModel(*pComboBoxTarget, *pStore, elem.m_nActiveId); 604 else if (pTreeBoxTarget && pStore) 605 mungeModel(*pTreeBoxTarget, *pStore, elem.m_nActiveId); 606 } 607 608 //Set TextView buffers when everything has been imported 609 for (auto const& elem : m_pParserState->m_aTextBufferMaps) 610 { 611 VclMultiLineEdit *pTarget = get<VclMultiLineEdit>(elem.m_sID); 612 const TextBuffer *pBuffer = get_buffer_by_name(elem.m_sValue.toUtf8()); 613 SAL_WARN_IF(!pTarget || !pBuffer, "vcl", "missing elements of textview/textbuffer"); 614 if (pTarget && pBuffer) 615 mungeTextBuffer(*pTarget, *pBuffer); 616 } 617 618 //Set SpinButton adjustments when everything has been imported 619 for (auto const& elem : m_pParserState->m_aNumericFormatterAdjustmentMaps) 620 { 621 NumericFormatter *pTarget = dynamic_cast<NumericFormatter*>(get(elem.m_sID)); 622 const Adjustment *pAdjustment = get_adjustment_by_name(elem.m_sValue.toUtf8()); 623 SAL_WARN_IF(!pTarget, "vcl", "missing NumericFormatter element of spinbutton/adjustment"); 624 SAL_WARN_IF(!pAdjustment, "vcl", "missing Adjustment element of spinbutton/adjustment"); 625 if (pTarget && pAdjustment) 626 mungeAdjustment(*pTarget, *pAdjustment); 627 } 628 629 for (auto const& elem : m_pParserState->m_aFormattedFormatterAdjustmentMaps) 630 { 631 FormattedField *pTarget = dynamic_cast<FormattedField*>(get(elem.m_sID)); 632 const Adjustment *pAdjustment = get_adjustment_by_name(elem.m_sValue.toUtf8()); 633 SAL_WARN_IF(!pTarget, "vcl", "missing FormattedField element of spinbutton/adjustment"); 634 SAL_WARN_IF(!pAdjustment, "vcl", "missing Adjustment element of spinbutton/adjustment"); 635 if (pTarget && pAdjustment) 636 mungeAdjustment(*pTarget, *pAdjustment); 637 } 638 639 //Set ScrollBar adjustments when everything has been imported 640 for (auto const& elem : m_pParserState->m_aScrollAdjustmentMaps) 641 { 642 ScrollBar *pTarget = get<ScrollBar>(elem.m_sID); 643 const Adjustment *pAdjustment = get_adjustment_by_name(elem.m_sValue.toUtf8()); 644 SAL_WARN_IF(!pTarget || !pAdjustment, "vcl", "missing elements of scrollbar/adjustment"); 645 if (pTarget && pAdjustment) 646 mungeAdjustment(*pTarget, *pAdjustment); 647 } 648 649 //Set Scale(Slider) adjustments 650 for (auto const& elem : m_pParserState->m_aSliderAdjustmentMaps) 651 { 652 Slider* pTarget = dynamic_cast<Slider*>(get(elem.m_sID)); 653 const Adjustment* pAdjustment = get_adjustment_by_name(elem.m_sValue.toUtf8()); 654 SAL_WARN_IF(!pTarget || !pAdjustment, "vcl", "missing elements of scale(slider)/adjustment"); 655 if (pTarget && pAdjustment) 656 { 657 mungeAdjustment(*pTarget, *pAdjustment); 658 } 659 } 660 661 //Set size-groups when all widgets have been imported 662 for (auto const& sizeGroup : m_pParserState->m_aSizeGroups) 663 { 664 std::shared_ptr<VclSizeGroup> xGroup(std::make_shared<VclSizeGroup>()); 665 666 for (auto const& elem : sizeGroup.m_aProperties) 667 { 668 const OString &rKey = elem.first; 669 const OUString &rValue = elem.second; 670 xGroup->set_property(rKey, rValue); 671 } 672 673 for (auto const& elem : sizeGroup.m_aWidgets) 674 { 675 vcl::Window* pWindow = get(elem.getStr()); 676 pWindow->add_to_size_group(xGroup); 677 } 678 } 679 680 //Set button images when everything has been imported 681 std::set<OUString> aImagesToBeRemoved; 682 for (auto const& elem : m_pParserState->m_aButtonImageWidgetMaps) 683 { 684 PushButton *pTargetButton = nullptr; 685 RadioButton *pTargetRadio = nullptr; 686 Button *pTarget = nullptr; 687 688 if (!elem.m_bRadio) 689 { 690 pTargetButton = get<PushButton>(elem.m_sID); 691 pTarget = pTargetButton; 692 } 693 else 694 { 695 pTargetRadio = get<RadioButton>(elem.m_sID); 696 pTarget = pTargetRadio; 697 } 698 699 FixedImage *pImage = get<FixedImage>(elem.m_sValue.toUtf8()); 700 SAL_WARN_IF(!pTarget || !pImage, 701 "vcl", "missing elements of button/image/stock"); 702 if (!pTarget || !pImage) 703 continue; 704 aImagesToBeRemoved.insert(elem.m_sValue); 705 706 VclBuilder::StockMap::iterator aFind = m_pParserState->m_aStockMap.find(elem.m_sValue.toUtf8()); 707 if (aFind == m_pParserState->m_aStockMap.end()) 708 { 709 if (!elem.m_bRadio) 710 { 711 pTargetButton->SetModeImage(pImage->GetImage()); 712 if (pImage->GetStyle() & WB_SMALLSTYLE) 713 { 714 pTargetButton->SetStyle(pTargetButton->GetStyle() | WB_SMALLSTYLE); 715 Size aSz(pTargetButton->GetModeImage().GetSizePixel()); 716 aSz.AdjustWidth(6); 717 aSz.AdjustHeight(6); 718 if (pTargetButton->get_width_request() == -1) 719 pTargetButton->set_width_request(aSz.Width()); 720 if (pTargetButton->get_height_request() == -1) 721 pTargetButton->set_height_request(aSz.Height()); 722 } 723 } 724 else 725 pTargetRadio->SetModeRadioImage(pImage->GetImage()); 726 } 727 else 728 { 729 const stockinfo &rImageInfo = aFind->second; 730 SymbolType eType = mapStockToSymbol(rImageInfo.m_sStock); 731 SAL_WARN_IF(eType == SymbolType::DONTKNOW, "vcl", "missing stock image element for button"); 732 if (eType == SymbolType::DONTKNOW) 733 continue; 734 if (!elem.m_bRadio) 735 { 736 pTargetButton->SetSymbol(eType); 737 //fdo#76457 keep symbol images small e.g. tools->customize->menu 738 //but images the right size. Really the PushButton::CalcMinimumSize 739 //and PushButton::ImplDrawPushButton are the better place to handle 740 //this, but its such a train-wreck 741 if (eType != SymbolType::IMAGE) 742 pTargetButton->SetStyle(pTargetButton->GetStyle() | WB_SMALLSTYLE); 743 } 744 else 745 SAL_WARN_IF(eType != SymbolType::IMAGE, "vcl.builder", "unimplemented symbol type for radiobuttons"); 746 if (eType == SymbolType::IMAGE) 747 { 748 Image const aImage(StockImage::Yes, 749 mapStockToImageResource(rImageInfo.m_sStock)); 750 if (!elem.m_bRadio) 751 pTargetButton->SetModeImage(aImage); 752 else 753 pTargetRadio->SetModeRadioImage(aImage); 754 } 755 switch (rImageInfo.m_nSize) 756 { 757 case 1: 758 pTarget->SetSmallSymbol(); 759 break; 760 case 3: 761 // large toolbar, make bigger than normal (4) 762 pTarget->set_width_request(pTarget->GetOptimalSize().Width() * 1.5); 763 pTarget->set_height_request(pTarget->GetOptimalSize().Height() * 1.5); 764 break; 765 case 4: 766 break; 767 default: 768 SAL_WARN("vcl.builder", "unsupported image size " << rImageInfo.m_nSize); 769 break; 770 } 771 } 772 } 773 774 //There may be duplicate use of an Image, so we used a set to collect and 775 //now we can remove them from the tree after their final munge 776 for (auto const& elem : aImagesToBeRemoved) 777 { 778 delete_by_name(elem.toUtf8()); 779 } 780 781 //fill in any stock icons in surviving images 782 for (auto const& elem : m_pParserState->m_aStockMap) 783 { 784 FixedImage *pImage = get<FixedImage>(elem.first); 785 SAL_WARN_IF(!pImage, "vcl", "missing elements of image/stock: " << elem.first); 786 if (!pImage) 787 continue; 788 789 const stockinfo &rImageInfo = elem.second; 790 if (rImageInfo.m_sStock == "gtk-missing-image") 791 continue; 792 793 SymbolType eType = mapStockToSymbol(rImageInfo.m_sStock); 794 SAL_WARN_IF(eType != SymbolType::IMAGE, "vcl", "unimplemented symbol type for images"); 795 if (eType != SymbolType::IMAGE) 796 continue; 797 798 Image const aImage(StockImage::Yes, 799 mapStockToImageResource(rImageInfo.m_sStock)); 800 pImage->SetImage(aImage); 801 } 802 803 //Set button menus when everything has been imported 804 for (auto const& elem : m_pParserState->m_aButtonMenuMaps) 805 { 806 MenuButton *pTarget = get<MenuButton>(elem.m_sID); 807 PopupMenu *pMenu = get_menu(elem.m_sValue.toUtf8()); 808 SAL_WARN_IF(!pTarget || !pMenu, 809 "vcl", "missing elements of button/menu"); 810 if (!pTarget || !pMenu) 811 continue; 812 pTarget->SetPopupMenu(pMenu); 813 } 814 815 //Remove ScrollWindow parent widgets whose children in vcl implement scrolling 816 //internally. 817 for (auto const& elem : m_pParserState->m_aRedundantParentWidgets) 818 { 819 delete_by_window(elem.first); 820 } 821 822 //fdo#67378 merge the label into the disclosure button 823 for (auto const& elem : m_pParserState->m_aExpanderWidgets) 824 { 825 vcl::Window *pChild = elem->get_child(); 826 vcl::Window* pLabel = elem->GetWindow(GetWindowType::LastChild); 827 if (pLabel && pLabel != pChild && pLabel->GetType() == WindowType::FIXEDTEXT) 828 { 829 FixedText *pLabelWidget = static_cast<FixedText*>(pLabel); 830 elem->set_label(pLabelWidget->GetText()); 831 delete_by_window(pLabel); 832 } 833 } 834 835 // create message dialog message area now 836 for (auto const& elem : m_pParserState->m_aMessageDialogs) 837 elem->create_message_area(); 838 839 //drop maps, etc. that we don't need again 840 m_pParserState.reset(); 841 842 SAL_WARN_IF(!m_sID.isEmpty() && (!m_bToplevelParentFound && !get_by_name(m_sID)), "vcl.builder", 843 "Requested top level widget \"" << m_sID << "\" not found in " << sUIFile); 844 845 #if defined SAL_LOG_WARN 846 if (m_bToplevelParentFound && m_pParent->IsDialog()) 847 { 848 int nButtons = 0; 849 bool bHasDefButton = false; 850 for (auto const& child : m_aChildren) 851 { 852 if (isButtonType(child.m_pWindow->GetType())) 853 { 854 ++nButtons; 855 if (child.m_pWindow->GetStyle() & WB_DEFBUTTON) 856 { 857 bHasDefButton = true; 858 break; 859 } 860 } 861 } 862 SAL_WARN_IF(nButtons && !bHasDefButton, "vcl.builder", "No default button defined in " << sUIFile); 863 } 864 #endif 865 866 const bool bHideHelp = comphelper::LibreOfficeKit::isActive() && 867 officecfg::Office::Common::Help::HelpRootURL::get().isEmpty(); 868 if (bHideHelp) 869 { 870 if (vcl::Window *pHelpButton = get("help")) 871 pHelpButton->Hide(); 872 } 873 } 874 875 VclBuilder::~VclBuilder() 876 { 877 disposeBuilder(); 878 } 879 880 void VclBuilder::disposeBuilder() 881 { 882 for (std::vector<WinAndId>::reverse_iterator aI = m_aChildren.rbegin(), 883 aEnd = m_aChildren.rend(); aI != aEnd; ++aI) 884 { 885 aI->m_pWindow.disposeAndClear(); 886 } 887 m_aChildren.clear(); 888 889 for (std::vector<MenuAndId>::reverse_iterator aI = m_aMenus.rbegin(), 890 aEnd = m_aMenus.rend(); aI != aEnd; ++aI) 891 { 892 aI->m_pMenu.disposeAndClear(); 893 } 894 m_aMenus.clear(); 895 m_pParent.clear(); 896 } 897 898 namespace 899 { 900 bool extractDrawValue(VclBuilder::stringmap& rMap) 901 { 902 bool bDrawValue = true; 903 VclBuilder::stringmap::iterator aFind = rMap.find("draw_value"); 904 if (aFind != rMap.end()) 905 { 906 bDrawValue = toBool(aFind->second); 907 rMap.erase(aFind); 908 } 909 return bDrawValue; 910 } 911 912 OUString extractPopupMenu(VclBuilder::stringmap& rMap) 913 { 914 OUString sRet; 915 VclBuilder::stringmap::iterator aFind = rMap.find("popup"); 916 if (aFind != rMap.end()) 917 { 918 sRet = aFind->second; 919 rMap.erase(aFind); 920 } 921 return sRet; 922 } 923 924 OUString extractValuePos(VclBuilder::stringmap& rMap) 925 { 926 OUString sRet("top"); 927 VclBuilder::stringmap::iterator aFind = rMap.find("value_pos"); 928 if (aFind != rMap.end()) 929 { 930 sRet = aFind->second; 931 rMap.erase(aFind); 932 } 933 return sRet; 934 } 935 936 OUString extractTypeHint(VclBuilder::stringmap &rMap) 937 { 938 OUString sRet("normal"); 939 VclBuilder::stringmap::iterator aFind = rMap.find("type-hint"); 940 if (aFind != rMap.end()) 941 { 942 sRet = aFind->second; 943 rMap.erase(aFind); 944 } 945 return sRet; 946 } 947 948 bool extractResizable(VclBuilder::stringmap &rMap) 949 { 950 bool bResizable = true; 951 VclBuilder::stringmap::iterator aFind = rMap.find("resizable"); 952 if (aFind != rMap.end()) 953 { 954 bResizable = toBool(aFind->second); 955 rMap.erase(aFind); 956 } 957 return bResizable; 958 } 959 960 #if HAVE_FEATURE_DESKTOP 961 bool extractModal(VclBuilder::stringmap &rMap) 962 { 963 bool bModal = false; 964 VclBuilder::stringmap::iterator aFind = rMap.find("modal"); 965 if (aFind != rMap.end()) 966 { 967 bModal = toBool(aFind->second); 968 rMap.erase(aFind); 969 } 970 return bModal; 971 } 972 #endif 973 974 bool extractDecorated(VclBuilder::stringmap &rMap) 975 { 976 bool bDecorated = true; 977 VclBuilder::stringmap::iterator aFind = rMap.find("decorated"); 978 if (aFind != rMap.end()) 979 { 980 bDecorated = toBool(aFind->second); 981 rMap.erase(aFind); 982 } 983 return bDecorated; 984 } 985 986 bool extractCloseable(VclBuilder::stringmap &rMap) 987 { 988 bool bCloseable = true; 989 VclBuilder::stringmap::iterator aFind = rMap.find("deletable"); 990 if (aFind != rMap.end()) 991 { 992 bCloseable = toBool(aFind->second); 993 rMap.erase(aFind); 994 } 995 return bCloseable; 996 } 997 998 bool extractEntry(VclBuilder::stringmap &rMap) 999 { 1000 bool bHasEntry = false; 1001 VclBuilder::stringmap::iterator aFind = rMap.find("has-entry"); 1002 if (aFind != rMap.end()) 1003 { 1004 bHasEntry = toBool(aFind->second); 1005 rMap.erase(aFind); 1006 } 1007 return bHasEntry; 1008 } 1009 1010 bool extractOrientation(VclBuilder::stringmap &rMap) 1011 { 1012 bool bVertical = false; 1013 VclBuilder::stringmap::iterator aFind = rMap.find("orientation"); 1014 if (aFind != rMap.end()) 1015 { 1016 bVertical = aFind->second.equalsIgnoreAsciiCase("vertical"); 1017 rMap.erase(aFind); 1018 } 1019 return bVertical; 1020 } 1021 1022 bool extractVerticalTabPos(VclBuilder::stringmap &rMap) 1023 { 1024 bool bVertical = false; 1025 VclBuilder::stringmap::iterator aFind = rMap.find("tab-pos"); 1026 if (aFind != rMap.end()) 1027 { 1028 bVertical = aFind->second.equalsIgnoreAsciiCase("left") || 1029 aFind->second.equalsIgnoreAsciiCase("right"); 1030 rMap.erase(aFind); 1031 } 1032 return bVertical; 1033 } 1034 1035 bool extractInconsistent(VclBuilder::stringmap &rMap) 1036 { 1037 bool bInconsistent = false; 1038 VclBuilder::stringmap::iterator aFind = rMap.find("inconsistent"); 1039 if (aFind != rMap.end()) 1040 { 1041 bInconsistent = toBool(aFind->second); 1042 rMap.erase(aFind); 1043 } 1044 return bInconsistent; 1045 } 1046 1047 OUString extractIconName(VclBuilder::stringmap &rMap) 1048 { 1049 OUString sIconName; 1050 VclBuilder::stringmap::iterator aFind = rMap.find(OString("icon-name")); 1051 if (aFind != rMap.end()) 1052 { 1053 sIconName = aFind->second; 1054 rMap.erase(aFind); 1055 } 1056 return sIconName; 1057 } 1058 1059 OUString extractStockId(VclBuilder::stringmap &rMap) 1060 { 1061 OUString sIconName; 1062 VclBuilder::stringmap::iterator aFind = rMap.find(OString("stock-id")); 1063 if (aFind != rMap.end()) 1064 { 1065 sIconName = aFind->second; 1066 rMap.erase(aFind); 1067 } 1068 return sIconName; 1069 } 1070 1071 OUString getStockText(const OUString &rType) 1072 { 1073 if (rType == "gtk-ok") 1074 return VclResId(SV_BUTTONTEXT_OK); 1075 else if (rType == "gtk-cancel") 1076 return VclResId(SV_BUTTONTEXT_CANCEL); 1077 else if (rType == "gtk-help") 1078 return VclResId(SV_BUTTONTEXT_HELP); 1079 else if (rType == "gtk-close") 1080 return VclResId(SV_BUTTONTEXT_CLOSE); 1081 else if (rType == "gtk-revert-to-saved") 1082 return VclResId(SV_BUTTONTEXT_RESET); 1083 else if (rType == "gtk-add") 1084 return VclResId(SV_BUTTONTEXT_ADD); 1085 else if (rType == "gtk-delete") 1086 return VclResId(SV_BUTTONTEXT_DELETE); 1087 else if (rType == "gtk-remove") 1088 return VclResId(SV_BUTTONTEXT_REMOVE); 1089 else if (rType == "gtk-new") 1090 return VclResId(SV_BUTTONTEXT_NEW); 1091 else if (rType == "gtk-edit") 1092 return VclResId(SV_BUTTONTEXT_EDIT); 1093 else if (rType == "gtk-apply") 1094 return VclResId(SV_BUTTONTEXT_APPLY); 1095 else if (rType == "gtk-save") 1096 return VclResId(SV_BUTTONTEXT_SAVE); 1097 else if (rType == "gtk-open") 1098 return VclResId(SV_BUTTONTEXT_OPEN); 1099 else if (rType == "gtk-undo") 1100 return VclResId(SV_BUTTONTEXT_UNDO); 1101 else if (rType == "gtk-paste") 1102 return VclResId(SV_BUTTONTEXT_PASTE); 1103 else if (rType == "gtk-media-next") 1104 return VclResId(SV_BUTTONTEXT_NEXT); 1105 else if (rType == "gtk-media-previous") 1106 return VclResId(SV_BUTTONTEXT_PREV); 1107 else if (rType == "gtk-go-up") 1108 return VclResId(SV_BUTTONTEXT_GO_UP); 1109 else if (rType == "gtk-go-down") 1110 return VclResId(SV_BUTTONTEXT_GO_DOWN); 1111 else if (rType == "gtk-clear") 1112 return VclResId(SV_BUTTONTEXT_CLEAR); 1113 else if (rType == "gtk-media-play") 1114 return VclResId(SV_BUTTONTEXT_PLAY); 1115 else if (rType == "gtk-find") 1116 return VclResId(SV_BUTTONTEXT_FIND); 1117 else if (rType == "gtk-stop") 1118 return VclResId(SV_BUTTONTEXT_STOP); 1119 else if (rType == "gtk-connect") 1120 return VclResId(SV_BUTTONTEXT_CONNECT); 1121 else if (rType == "gtk-yes") 1122 return VclResId(SV_BUTTONTEXT_YES); 1123 else if (rType == "gtk-no") 1124 return VclResId(SV_BUTTONTEXT_NO); 1125 SAL_WARN("vcl.builder", "unknown stock type: " << rType); 1126 return OUString(); 1127 } 1128 1129 bool extractStock(VclBuilder::stringmap &rMap) 1130 { 1131 bool bIsStock = false; 1132 VclBuilder::stringmap::iterator aFind = rMap.find(OString("use-stock")); 1133 if (aFind != rMap.end()) 1134 { 1135 bIsStock = toBool(aFind->second); 1136 rMap.erase(aFind); 1137 } 1138 return bIsStock; 1139 } 1140 1141 WinBits extractRelief(VclBuilder::stringmap &rMap) 1142 { 1143 WinBits nBits = WB_3DLOOK; 1144 VclBuilder::stringmap::iterator aFind = rMap.find(OString("relief")); 1145 if (aFind != rMap.end()) 1146 { 1147 if (aFind->second == "half") 1148 nBits = WB_FLATBUTTON | WB_BEVELBUTTON; 1149 else if (aFind->second == "none") 1150 nBits = WB_FLATBUTTON; 1151 rMap.erase(aFind); 1152 } 1153 return nBits; 1154 } 1155 1156 OUString extractLabel(VclBuilder::stringmap &rMap) 1157 { 1158 OUString sType; 1159 VclBuilder::stringmap::iterator aFind = rMap.find(OString("label")); 1160 if (aFind != rMap.end()) 1161 { 1162 sType = aFind->second; 1163 rMap.erase(aFind); 1164 } 1165 return sType; 1166 } 1167 1168 OUString extractActionName(VclBuilder::stringmap &rMap) 1169 { 1170 OUString sActionName; 1171 VclBuilder::stringmap::iterator aFind = rMap.find(OString("action-name")); 1172 if (aFind != rMap.end()) 1173 { 1174 sActionName = aFind->second; 1175 rMap.erase(aFind); 1176 } 1177 return sActionName; 1178 } 1179 1180 bool extractVisible(VclBuilder::stringmap &rMap) 1181 { 1182 bool bRet = false; 1183 VclBuilder::stringmap::iterator aFind = rMap.find(OString("visible")); 1184 if (aFind != rMap.end()) 1185 { 1186 bRet = toBool(aFind->second); 1187 rMap.erase(aFind); 1188 } 1189 return bRet; 1190 } 1191 1192 Size extractSizeRequest(VclBuilder::stringmap &rMap) 1193 { 1194 OUString sWidthRequest("0"); 1195 OUString sHeightRequest("0"); 1196 VclBuilder::stringmap::iterator aFind = rMap.find(OString("width-request")); 1197 if (aFind != rMap.end()) 1198 { 1199 sWidthRequest = aFind->second; 1200 rMap.erase(aFind); 1201 } 1202 aFind = rMap.find("height-request"); 1203 if (aFind != rMap.end()) 1204 { 1205 sHeightRequest = aFind->second; 1206 rMap.erase(aFind); 1207 } 1208 return Size(sWidthRequest.toInt32(), sHeightRequest.toInt32()); 1209 } 1210 1211 OUString extractTooltipText(VclBuilder::stringmap &rMap) 1212 { 1213 OUString sTooltipText; 1214 VclBuilder::stringmap::iterator aFind = rMap.find(OString("tooltip-text")); 1215 if (aFind == rMap.end()) 1216 aFind = rMap.find(OString("tooltip-markup")); 1217 if (aFind != rMap.end()) 1218 { 1219 sTooltipText = aFind->second; 1220 rMap.erase(aFind); 1221 } 1222 return sTooltipText; 1223 } 1224 1225 float extractAlignment(VclBuilder::stringmap &rMap) 1226 { 1227 float f = 0.0; 1228 VclBuilder::stringmap::iterator aFind = rMap.find(OString("alignment")); 1229 if (aFind != rMap.end()) 1230 { 1231 f = aFind->second.toFloat(); 1232 rMap.erase(aFind); 1233 } 1234 return f; 1235 } 1236 1237 OUString extractTitle(VclBuilder::stringmap &rMap) 1238 { 1239 OUString sTitle; 1240 VclBuilder::stringmap::iterator aFind = rMap.find(OString("title")); 1241 if (aFind != rMap.end()) 1242 { 1243 sTitle = aFind->second; 1244 rMap.erase(aFind); 1245 } 1246 return sTitle; 1247 } 1248 1249 bool extractHeadersVisible(VclBuilder::stringmap &rMap) 1250 { 1251 bool bHeadersVisible = true; 1252 VclBuilder::stringmap::iterator aFind = rMap.find(OString("headers-visible")); 1253 if (aFind != rMap.end()) 1254 { 1255 bHeadersVisible = toBool(aFind->second); 1256 rMap.erase(aFind); 1257 } 1258 return bHeadersVisible; 1259 } 1260 1261 bool extractSortIndicator(VclBuilder::stringmap &rMap) 1262 { 1263 bool bSortIndicator = false; 1264 VclBuilder::stringmap::iterator aFind = rMap.find(OString("sort-indicator")); 1265 if (aFind != rMap.end()) 1266 { 1267 bSortIndicator = toBool(aFind->second); 1268 rMap.erase(aFind); 1269 } 1270 return bSortIndicator; 1271 } 1272 1273 bool extractClickable(VclBuilder::stringmap &rMap) 1274 { 1275 bool bClickable = false; 1276 VclBuilder::stringmap::iterator aFind = rMap.find(OString("clickable")); 1277 if (aFind != rMap.end()) 1278 { 1279 bClickable = toBool(aFind->second); 1280 rMap.erase(aFind); 1281 } 1282 return bClickable; 1283 } 1284 1285 void setupFromActionName(Button *pButton, VclBuilder::stringmap &rMap, const css::uno::Reference<css::frame::XFrame>& rFrame) 1286 { 1287 if (!rFrame.is()) 1288 return; 1289 1290 OUString aCommand(extractActionName(rMap)); 1291 if (aCommand.isEmpty()) 1292 return; 1293 1294 OUString aModuleName(vcl::CommandInfoProvider::GetModuleIdentifier(rFrame)); 1295 auto aProperties = vcl::CommandInfoProvider::GetCommandProperties(aCommand, aModuleName); 1296 OUString aLabel(vcl::CommandInfoProvider::GetLabelForCommand(aProperties)); 1297 if (!aLabel.isEmpty()) 1298 pButton->SetText(aLabel); 1299 1300 OUString aTooltip(vcl::CommandInfoProvider::GetTooltipForCommand(aCommand, aProperties, rFrame)); 1301 if (!aTooltip.isEmpty()) 1302 pButton->SetQuickHelpText(aTooltip); 1303 1304 Image aImage(vcl::CommandInfoProvider::GetImageForCommand(aCommand, rFrame)); 1305 pButton->SetModeImage(aImage); 1306 1307 pButton->SetCommandHandler(aCommand); 1308 } 1309 1310 VclPtr<Button> extractStockAndBuildPushButton(vcl::Window *pParent, VclBuilder::stringmap &rMap, bool bToggle, bool bLegacy) 1311 { 1312 WinBits nBits = WB_CLIPCHILDREN|WB_CENTER|WB_VCENTER; 1313 if (bToggle) 1314 nBits |= WB_TOGGLE; 1315 1316 nBits |= extractRelief(rMap); 1317 1318 VclPtr<Button> xWindow; 1319 1320 if (extractStock(rMap)) 1321 { 1322 OUString sType = extractLabel(rMap); 1323 if (bLegacy) 1324 { 1325 if (sType == "gtk-ok") 1326 xWindow = VclPtr<OKButton>::Create(pParent, nBits); 1327 else if (sType == "gtk-cancel") 1328 xWindow = VclPtr<CancelButton>::Create(pParent, nBits); 1329 else if (sType == "gtk-close") 1330 xWindow = VclPtr<CloseButton>::Create(pParent, nBits); 1331 else if (sType == "gtk-help") 1332 xWindow = VclPtr<HelpButton>::Create(pParent, nBits); 1333 } 1334 if (!xWindow) 1335 { 1336 xWindow = VclPtr<PushButton>::Create(pParent, nBits); 1337 xWindow->SetText(getStockText(sType)); 1338 } 1339 } 1340 1341 if (!xWindow) 1342 xWindow = VclPtr<PushButton>::Create(pParent, nBits); 1343 return xWindow; 1344 } 1345 1346 VclPtr<MenuButton> extractStockAndBuildMenuButton(vcl::Window *pParent, VclBuilder::stringmap &rMap) 1347 { 1348 WinBits nBits = WB_CLIPCHILDREN|WB_CENTER|WB_VCENTER|WB_3DLOOK; 1349 1350 nBits |= extractRelief(rMap); 1351 1352 VclPtr<MenuButton> xWindow = VclPtr<MenuButton>::Create(pParent, nBits); 1353 1354 if (extractStock(rMap)) 1355 { 1356 xWindow->SetText(getStockText(extractLabel(rMap))); 1357 } 1358 1359 return xWindow; 1360 } 1361 1362 VclPtr<Button> extractStockAndBuildMenuToggleButton(vcl::Window *pParent, VclBuilder::stringmap &rMap) 1363 { 1364 WinBits nBits = WB_CLIPCHILDREN|WB_CENTER|WB_VCENTER|WB_3DLOOK; 1365 1366 nBits |= extractRelief(rMap); 1367 1368 VclPtr<Button> xWindow = VclPtr<MenuToggleButton>::Create(pParent, nBits); 1369 1370 if (extractStock(rMap)) 1371 { 1372 xWindow->SetText(getStockText(extractLabel(rMap))); 1373 } 1374 1375 return xWindow; 1376 } 1377 1378 WinBits extractDeferredBits(VclBuilder::stringmap &rMap) 1379 { 1380 WinBits nBits = WB_3DLOOK|WB_HIDE; 1381 if (extractResizable(rMap)) 1382 nBits |= WB_SIZEABLE; 1383 if (extractCloseable(rMap)) 1384 nBits |= WB_CLOSEABLE; 1385 OUString sBorder = BuilderUtils::extractCustomProperty(rMap); 1386 if (!sBorder.isEmpty()) 1387 nBits |= WB_BORDER; 1388 if (!extractDecorated(rMap)) 1389 nBits |= WB_OWNERDRAWDECORATION; 1390 OUString sType(extractTypeHint(rMap)); 1391 if (sType == "utility") 1392 nBits |= WB_SYSTEMWINDOW | WB_DIALOGCONTROL | WB_MOVEABLE; 1393 else if (sType == "popup-menu") 1394 nBits |= WB_SYSTEMWINDOW | WB_DIALOGCONTROL | WB_POPUP; 1395 else if (sType == "dock") 1396 nBits |= WB_DOCKABLE | WB_MOVEABLE; 1397 else 1398 nBits |= WB_MOVEABLE; 1399 return nBits; 1400 } 1401 } 1402 1403 void VclBuilder::extractGroup(const OString &id, stringmap &rMap) 1404 { 1405 VclBuilder::stringmap::iterator aFind = rMap.find(OString("group")); 1406 if (aFind != rMap.end()) 1407 { 1408 OUString sID = aFind->second; 1409 sal_Int32 nDelim = sID.indexOf(':'); 1410 if (nDelim != -1) 1411 sID = sID.copy(0, nDelim); 1412 m_pParserState->m_aGroupMaps.emplace_back(id, sID.toUtf8()); 1413 rMap.erase(aFind); 1414 } 1415 } 1416 1417 void VclBuilder::connectNumericFormatterAdjustment(const OString &id, const OUString &rAdjustment) 1418 { 1419 if (!rAdjustment.isEmpty()) 1420 m_pParserState->m_aNumericFormatterAdjustmentMaps.emplace_back(id, rAdjustment); 1421 } 1422 1423 void VclBuilder::connectFormattedFormatterAdjustment(const OString &id, const OUString &rAdjustment) 1424 { 1425 if (!rAdjustment.isEmpty()) 1426 m_pParserState->m_aFormattedFormatterAdjustmentMaps.emplace_back(id, rAdjustment); 1427 } 1428 1429 bool VclBuilder::extractAdjustmentToMap(const OString& id, VclBuilder::stringmap& rMap, std::vector<WidgetAdjustmentMap>& rAdjustmentMap) 1430 { 1431 VclBuilder::stringmap::iterator aFind = rMap.find(OString("adjustment")); 1432 if (aFind != rMap.end()) 1433 { 1434 rAdjustmentMap.emplace_back(id, aFind->second); 1435 rMap.erase(aFind); 1436 return true; 1437 } 1438 return false; 1439 } 1440 1441 namespace 1442 { 1443 sal_Int32 extractActive(VclBuilder::stringmap &rMap) 1444 { 1445 sal_Int32 nActiveId = 0; 1446 VclBuilder::stringmap::iterator aFind = rMap.find(OString("active")); 1447 if (aFind != rMap.end()) 1448 { 1449 nActiveId = aFind->second.toInt32(); 1450 rMap.erase(aFind); 1451 } 1452 return nActiveId; 1453 } 1454 1455 bool extractSelectable(VclBuilder::stringmap &rMap) 1456 { 1457 bool bSelectable = false; 1458 VclBuilder::stringmap::iterator aFind = rMap.find(OString("selectable")); 1459 if (aFind != rMap.end()) 1460 { 1461 bSelectable = toBool(aFind->second); 1462 rMap.erase(aFind); 1463 } 1464 return bSelectable; 1465 } 1466 1467 OUString extractAdjustment(VclBuilder::stringmap &rMap) 1468 { 1469 OUString sAdjustment; 1470 VclBuilder::stringmap::iterator aFind = rMap.find(OString("adjustment")); 1471 if (aFind != rMap.end()) 1472 { 1473 sAdjustment= aFind->second; 1474 rMap.erase(aFind); 1475 return sAdjustment; 1476 } 1477 return sAdjustment; 1478 } 1479 1480 bool extractDrawIndicator(VclBuilder::stringmap &rMap) 1481 { 1482 bool bDrawIndicator = false; 1483 VclBuilder::stringmap::iterator aFind = rMap.find(OString("draw-indicator")); 1484 if (aFind != rMap.end()) 1485 { 1486 bDrawIndicator = toBool(aFind->second); 1487 rMap.erase(aFind); 1488 } 1489 return bDrawIndicator; 1490 } 1491 } 1492 1493 void VclBuilder::extractModel(const OString &id, stringmap &rMap) 1494 { 1495 VclBuilder::stringmap::iterator aFind = rMap.find(OString("model")); 1496 if (aFind != rMap.end()) 1497 { 1498 m_pParserState->m_aModelMaps.emplace_back(id, aFind->second, 1499 extractActive(rMap)); 1500 rMap.erase(aFind); 1501 } 1502 } 1503 1504 void VclBuilder::extractBuffer(const OString &id, stringmap &rMap) 1505 { 1506 VclBuilder::stringmap::iterator aFind = rMap.find(OString("buffer")); 1507 if (aFind != rMap.end()) 1508 { 1509 m_pParserState->m_aTextBufferMaps.emplace_back(id, aFind->second); 1510 rMap.erase(aFind); 1511 } 1512 } 1513 1514 void VclBuilder::extractStock(const OString &id, stringmap &rMap) 1515 { 1516 VclBuilder::stringmap::iterator aFind = rMap.find(OString("stock")); 1517 if (aFind != rMap.end()) 1518 { 1519 stockinfo aInfo; 1520 aInfo.m_sStock = aFind->second; 1521 rMap.erase(aFind); 1522 aFind = rMap.find(OString("icon-size")); 1523 if (aFind != rMap.end()) 1524 { 1525 aInfo.m_nSize = aFind->second.toInt32(); 1526 rMap.erase(aFind); 1527 } 1528 m_pParserState->m_aStockMap[id] = aInfo; 1529 } 1530 } 1531 1532 void VclBuilder::extractButtonImage(const OString &id, stringmap &rMap, bool bRadio) 1533 { 1534 VclBuilder::stringmap::iterator aFind = rMap.find(OString("image")); 1535 if (aFind != rMap.end()) 1536 { 1537 m_pParserState->m_aButtonImageWidgetMaps.emplace_back(id, aFind->second, bRadio); 1538 rMap.erase(aFind); 1539 } 1540 } 1541 1542 void VclBuilder::extractMnemonicWidget(const OString &rLabelID, stringmap &rMap) 1543 { 1544 VclBuilder::stringmap::iterator aFind = rMap.find(OString("mnemonic-widget")); 1545 if (aFind != rMap.end()) 1546 { 1547 OUString sID = aFind->second; 1548 sal_Int32 nDelim = sID.indexOf(':'); 1549 if (nDelim != -1) 1550 sID = sID.copy(0, nDelim); 1551 m_pParserState->m_aMnemonicWidgetMaps.emplace_back(rLabelID, sID); 1552 rMap.erase(aFind); 1553 } 1554 } 1555 1556 vcl::Window* VclBuilder::prepareWidgetOwnScrolling(vcl::Window *pParent, WinBits &rWinStyle) 1557 { 1558 //For Widgets that manage their own scrolling, if one appears as a child of 1559 //a scrolling window shoehorn that scrolling settings to this widget and 1560 //return the real parent to use 1561 if (pParent && pParent->GetType() == WindowType::SCROLLWINDOW) 1562 { 1563 WinBits nScrollBits = pParent->GetStyle(); 1564 nScrollBits &= (WB_AUTOHSCROLL|WB_HSCROLL|WB_AUTOVSCROLL|WB_VSCROLL); 1565 rWinStyle |= nScrollBits | WB_BORDER; 1566 pParent = pParent->GetParent(); 1567 } 1568 1569 return pParent; 1570 } 1571 1572 void VclBuilder::cleanupWidgetOwnScrolling(vcl::Window *pScrollParent, vcl::Window *pWindow, stringmap &rMap) 1573 { 1574 //remove the redundant scrolling parent 1575 sal_Int32 nWidthReq = pScrollParent->get_width_request(); 1576 rMap[OString("width-request")] = OUString::number(nWidthReq); 1577 sal_Int32 nHeightReq = pScrollParent->get_height_request(); 1578 rMap[OString("height-request")] = OUString::number(nHeightReq); 1579 1580 m_pParserState->m_aRedundantParentWidgets[pScrollParent] = pWindow; 1581 } 1582 1583 #ifndef DISABLE_DYNLOADING 1584 1585 extern "C" { static void thisModule() {} } 1586 1587 namespace { 1588 1589 // Don't unload the module on destruction 1590 class NoAutoUnloadModule : public osl::Module 1591 { 1592 public: 1593 ~NoAutoUnloadModule() { release(); } 1594 }; 1595 1596 } 1597 1598 typedef std::map<OUString, std::shared_ptr<NoAutoUnloadModule>> ModuleMap; 1599 static ModuleMap g_aModuleMap; 1600 1601 #if ENABLE_MERGELIBS 1602 static std::shared_ptr<NoAutoUnloadModule> g_pMergedLib = std::make_shared<NoAutoUnloadModule>(); 1603 #endif 1604 1605 #ifndef SAL_DLLPREFIX 1606 # define SAL_DLLPREFIX "" 1607 #endif 1608 1609 #endif 1610 1611 void VclBuilder::preload() 1612 { 1613 #ifndef DISABLE_DYNLOADING 1614 1615 #if ENABLE_MERGELIBS 1616 g_pMergedLib->loadRelative(&thisModule, SVLIBRARY("merged")); 1617 #else 1618 // find -name '*ui*' | xargs grep 'class=".*lo-' | 1619 // sed 's/.*class="//' | sed 's/-.*$//' | sort | uniq 1620 static const char *aWidgetLibs[] = { 1621 "sfxlo", "svtlo", "svxcorelo", "foruilo", 1622 "vcllo", "svxlo", "cuilo", "swlo", 1623 "swuilo", "sclo", "sdlo", "chartcontrollerlo", 1624 "smlo", "scuilo", "basctllo", "sduilo", 1625 "scnlo", "xsltdlglo", "pcrlo" // "dbulo" 1626 }; 1627 for (const auto & lib : aWidgetLibs) 1628 { 1629 std::unique_ptr<NoAutoUnloadModule> pModule(new NoAutoUnloadModule); 1630 OUString sModule = SAL_DLLPREFIX + OUString::createFromAscii(lib) + SAL_DLLEXTENSION; 1631 if (pModule->loadRelative(&thisModule, sModule)) 1632 g_aModuleMap.insert(std::make_pair(sModule, std::move(pModule))); 1633 } 1634 #endif // ENABLE_MERGELIBS 1635 #endif // DISABLE_DYNLOADING 1636 } 1637 1638 #if defined DISABLE_DYNLOADING && !HAVE_FEATURE_DESKTOP 1639 extern "C" VclBuilder::customMakeWidget lo_get_custom_widget_func(const char* name); 1640 #endif 1641 1642 namespace 1643 { 1644 // Takes a string like "sfxlo-SidebarToolBox" 1645 VclBuilder::customMakeWidget GetCustomMakeWidget(const OString& name) 1646 { 1647 VclBuilder::customMakeWidget pFunction = nullptr; 1648 if (sal_Int32 nDelim = name.indexOf('-'); nDelim != -1) 1649 { 1650 const OString aFunction("make" + name.copy(nDelim + 1)); 1651 const OUString sFunction(OStringToOUString(aFunction, RTL_TEXTENCODING_UTF8)); 1652 1653 #ifndef DISABLE_DYNLOADING 1654 const OUString sModule = SAL_DLLPREFIX 1655 + OStringToOUString(name.copy(0, nDelim), RTL_TEXTENCODING_UTF8) 1656 + SAL_DLLEXTENSION; 1657 ModuleMap::iterator aI = g_aModuleMap.find(sModule); 1658 if (aI == g_aModuleMap.end()) 1659 { 1660 std::shared_ptr<NoAutoUnloadModule> pModule; 1661 #if ENABLE_MERGELIBS 1662 if (!g_pMergedLib->is()) 1663 g_pMergedLib->loadRelative(&thisModule, SVLIBRARY("merged")); 1664 if ((pFunction = reinterpret_cast<VclBuilder::customMakeWidget>( 1665 g_pMergedLib->getFunctionSymbol(sFunction)))) 1666 pModule = g_pMergedLib; 1667 #endif 1668 if (!pFunction) 1669 { 1670 pModule = std::make_shared<NoAutoUnloadModule>(); 1671 bool ok = pModule->loadRelative(&thisModule, sModule); 1672 if (!ok) 1673 { 1674 #ifdef LINUX 1675 // in the case of preloading, we don't have eg. the 1676 // libcuilo.so, but still need to dlsym the symbols - 1677 // which are already in-process 1678 if (comphelper::LibreOfficeKit::isActive()) 1679 { 1680 pFunction = reinterpret_cast<VclBuilder::customMakeWidget>(dlsym(RTLD_DEFAULT, aFunction.getStr())); 1681 ok = !!pFunction; 1682 assert(ok && "couldn't even directly dlsym the sFunction (available via preload)"); 1683 } 1684 #endif 1685 assert(ok && "bad module name in .ui"); 1686 } 1687 else 1688 { 1689 pFunction = reinterpret_cast<VclBuilder::customMakeWidget>( 1690 pModule->getFunctionSymbol(sFunction)); 1691 } 1692 } 1693 g_aModuleMap.insert(std::make_pair(sModule, pModule)); 1694 } 1695 else 1696 pFunction = reinterpret_cast<VclBuilder::customMakeWidget>( 1697 aI->second->getFunctionSymbol(sFunction)); 1698 #elif !HAVE_FEATURE_DESKTOP 1699 pFunction = lo_get_custom_widget_func(sFunction.toUtf8().getStr()); 1700 SAL_WARN_IF(!pFunction, "vcl.builder", "Could not find " << sFunction); 1701 assert(pFunction); 1702 #else 1703 pFunction = reinterpret_cast<VclBuilder::customMakeWidget>( 1704 osl_getFunctionSymbol((oslModule)RTLD_DEFAULT, sFunction.pData)); 1705 #endif 1706 } 1707 return pFunction; 1708 } 1709 } 1710 1711 VclPtr<vcl::Window> VclBuilder::makeObject(vcl::Window *pParent, const OString &name, const OString &id, 1712 stringmap &rMap) 1713 { 1714 bool bIsPlaceHolder = name.isEmpty(); 1715 bool bVertical = false; 1716 1717 if (pParent && (pParent->GetType() == WindowType::TABCONTROL || 1718 pParent->GetType() == WindowType::VERTICALTABCONTROL)) 1719 { 1720 bool bTopLevel(name == "GtkDialog" || name == "GtkMessageDialog" || 1721 name == "GtkWindow" || name == "GtkPopover" || name == "GtkAssistant"); 1722 if (!bTopLevel) 1723 { 1724 if (pParent->GetType() == WindowType::TABCONTROL) 1725 { 1726 //We have to add a page 1727 //make default pageid == position 1728 TabControl *pTabControl = static_cast<TabControl*>(pParent); 1729 sal_uInt16 nNewPageCount = pTabControl->GetPageCount()+1; 1730 sal_uInt16 nNewPageId = nNewPageCount; 1731 pTabControl->InsertPage(nNewPageId, OUString()); 1732 pTabControl->SetCurPageId(nNewPageId); 1733 SAL_WARN_IF(bIsPlaceHolder, "vcl.builder", "we should have no placeholders for tabpages"); 1734 if (!bIsPlaceHolder) 1735 { 1736 VclPtrInstance<TabPage> pPage(pTabControl); 1737 pPage->Show(); 1738 1739 //Make up a name for it 1740 OString sTabPageId = get_by_window(pParent) + 1741 "-page" + 1742 OString::number(nNewPageCount); 1743 m_aChildren.emplace_back(sTabPageId, pPage, false); 1744 pPage->SetHelpId(m_sHelpRoot + sTabPageId); 1745 1746 pParent = pPage; 1747 1748 pTabControl->SetTabPage(nNewPageId, pPage); 1749 } 1750 } 1751 else 1752 { 1753 VerticalTabControl *pTabControl = static_cast<VerticalTabControl*>(pParent); 1754 SAL_WARN_IF(bIsPlaceHolder, "vcl.builder", "we should have no placeholders for tabpages"); 1755 if (!bIsPlaceHolder) 1756 pParent = pTabControl->GetPageParent(); 1757 } 1758 } 1759 } 1760 1761 if (bIsPlaceHolder || name == "GtkTreeSelection") 1762 return nullptr; 1763 1764 ToolBox *pToolBox = (pParent && pParent->GetType() == WindowType::TOOLBOX) ? static_cast<ToolBox*>(pParent) : nullptr; 1765 1766 extractButtonImage(id, rMap, name == "GtkRadioButton"); 1767 1768 VclPtr<vcl::Window> xWindow; 1769 if (name == "GtkDialog" || name == "GtkAssistant") 1770 { 1771 // WB_ALLOWMENUBAR because we don't know in advance if we will encounter 1772 // a menubar, and menubars need a BorderWindow in the toplevel, and 1773 // such border windows need to be in created during the dialog ctor 1774 WinBits nBits = WB_MOVEABLE|WB_3DLOOK|WB_ALLOWMENUBAR; 1775 if (extractResizable(rMap)) 1776 nBits |= WB_SIZEABLE; 1777 if (extractCloseable(rMap)) 1778 nBits |= WB_CLOSEABLE; 1779 Dialog::InitFlag eInit = !pParent ? Dialog::InitFlag::NoParent : Dialog::InitFlag::Default; 1780 if (name == "GtkAssistant") 1781 xWindow = VclPtr<vcl::RoadmapWizard>::Create(pParent, nBits, eInit); 1782 else 1783 xWindow = VclPtr<Dialog>::Create(pParent, nBits, eInit); 1784 #if HAVE_FEATURE_DESKTOP 1785 if (!m_bLegacy && !extractModal(rMap)) 1786 xWindow->SetType(WindowType::MODELESSDIALOG); 1787 #endif 1788 } 1789 else if (name == "GtkMessageDialog") 1790 { 1791 WinBits nBits = WB_MOVEABLE|WB_3DLOOK|WB_CLOSEABLE; 1792 if (extractResizable(rMap)) 1793 nBits |= WB_SIZEABLE; 1794 VclPtr<MessageDialog> xDialog(VclPtr<MessageDialog>::Create(pParent, nBits)); 1795 m_pParserState->m_aMessageDialogs.push_back(xDialog); 1796 xWindow = xDialog; 1797 #if defined _WIN32 1798 xWindow->set_border_width(3); 1799 #else 1800 xWindow->set_border_width(12); 1801 #endif 1802 } 1803 else if (name == "GtkBox" || name == "GtkStatusbar") 1804 { 1805 bVertical = extractOrientation(rMap); 1806 if (bVertical) 1807 xWindow = VclPtr<VclVBox>::Create(pParent); 1808 else 1809 xWindow = VclPtr<VclHBox>::Create(pParent); 1810 } 1811 else if (name == "GtkPaned") 1812 { 1813 bVertical = extractOrientation(rMap); 1814 if (bVertical) 1815 xWindow = VclPtr<VclVPaned>::Create(pParent); 1816 else 1817 xWindow = VclPtr<VclHPaned>::Create(pParent); 1818 } 1819 else if (name == "GtkHBox") 1820 xWindow = VclPtr<VclHBox>::Create(pParent); 1821 else if (name == "GtkVBox") 1822 xWindow = VclPtr<VclVBox>::Create(pParent); 1823 else if (name == "GtkButtonBox") 1824 { 1825 bVertical = extractOrientation(rMap); 1826 if (bVertical) 1827 xWindow = VclPtr<VclVButtonBox>::Create(pParent); 1828 else 1829 xWindow = VclPtr<VclHButtonBox>::Create(pParent); 1830 } 1831 else if (name == "GtkHButtonBox") 1832 xWindow = VclPtr<VclHButtonBox>::Create(pParent); 1833 else if (name == "GtkVButtonBox") 1834 xWindow = VclPtr<VclVButtonBox>::Create(pParent); 1835 else if (name == "GtkGrid") 1836 xWindow = VclPtr<VclGrid>::Create(pParent); 1837 else if (name == "GtkFrame") 1838 xWindow = VclPtr<VclFrame>::Create(pParent); 1839 else if (name == "GtkExpander") 1840 { 1841 VclPtrInstance<VclExpander> pExpander(pParent); 1842 m_pParserState->m_aExpanderWidgets.push_back(pExpander); 1843 xWindow = pExpander; 1844 } 1845 else if (name == "GtkAlignment") 1846 xWindow = VclPtr<VclAlignment>::Create(pParent); 1847 else if (name == "GtkButton" || (!m_bLegacy && name == "GtkToggleButton")) 1848 { 1849 VclPtr<Button> xButton; 1850 OUString sMenu = BuilderUtils::extractCustomProperty(rMap); 1851 if (sMenu.isEmpty()) 1852 xButton = extractStockAndBuildPushButton(pParent, rMap, name == "GtkToggleButton", m_bLegacy); 1853 else 1854 { 1855 assert(m_bLegacy && "use GtkMenuButton"); 1856 xButton = extractStockAndBuildMenuButton(pParent, rMap); 1857 m_pParserState->m_aButtonMenuMaps.emplace_back(id, sMenu); 1858 } 1859 xButton->SetImageAlign(ImageAlign::Left); //default to left 1860 setupFromActionName(xButton, rMap, m_xFrame); 1861 xWindow = xButton; 1862 } 1863 else if (name == "GtkMenuButton") 1864 { 1865 VclPtr<MenuButton> xButton = extractStockAndBuildMenuButton(pParent, rMap); 1866 OUString sMenu = extractPopupMenu(rMap); 1867 if (!sMenu.isEmpty()) 1868 m_pParserState->m_aButtonMenuMaps.emplace_back(id, sMenu); 1869 xButton->SetImageAlign(ImageAlign::Left); //default to left 1870 xButton->SetAccessibleRole(css::accessibility::AccessibleRole::BUTTON_MENU); 1871 1872 if (!extractDrawIndicator(rMap)) 1873 xButton->SetDropDown(PushButtonDropdownStyle::NONE); 1874 1875 setupFromActionName(xButton, rMap, m_xFrame); 1876 xWindow = xButton; 1877 } 1878 else if (name == "GtkToggleButton" && m_bLegacy) 1879 { 1880 VclPtr<Button> xButton; 1881 OUString sMenu = BuilderUtils::extractCustomProperty(rMap); 1882 assert(sMenu.getLength() && "not implemented yet"); 1883 xButton = extractStockAndBuildMenuToggleButton(pParent, rMap); 1884 m_pParserState->m_aButtonMenuMaps.emplace_back(id, sMenu); 1885 xButton->SetImageAlign(ImageAlign::Left); //default to left 1886 setupFromActionName(xButton, rMap, m_xFrame); 1887 xWindow = xButton; 1888 } 1889 else if (name == "GtkRadioButton") 1890 { 1891 extractGroup(id, rMap); 1892 WinBits nBits = WB_CLIPCHILDREN|WB_CENTER|WB_VCENTER|WB_3DLOOK; 1893 VclPtr<RadioButton> xButton = VclPtr<RadioButton>::Create(pParent, nBits); 1894 xButton->SetImageAlign(ImageAlign::Left); //default to left 1895 xWindow = xButton; 1896 1897 if (::extractStock(rMap)) 1898 { 1899 xWindow->SetText(getStockText(extractLabel(rMap))); 1900 } 1901 } 1902 else if (name == "GtkCheckButton") 1903 { 1904 WinBits nBits = WB_CLIPCHILDREN|WB_CENTER|WB_VCENTER|WB_3DLOOK; 1905 bool bIsTriState = extractInconsistent(rMap); 1906 VclPtr<CheckBox> xCheckBox = VclPtr<CheckBox>::Create(pParent, nBits); 1907 if (bIsTriState) 1908 { 1909 xCheckBox->EnableTriState(true); 1910 xCheckBox->SetState(TRISTATE_INDET); 1911 } 1912 xCheckBox->SetImageAlign(ImageAlign::Left); //default to left 1913 1914 xWindow = xCheckBox; 1915 1916 if (::extractStock(rMap)) 1917 { 1918 xWindow->SetText(getStockText(extractLabel(rMap))); 1919 } 1920 } 1921 else if (name == "GtkSpinButton") 1922 { 1923 OUString sAdjustment = extractAdjustment(rMap); 1924 1925 WinBits nBits = WB_CLIPCHILDREN|WB_LEFT|WB_BORDER|WB_3DLOOK|WB_SPIN|WB_REPEAT; 1926 1927 if (m_bLegacy) 1928 { 1929 connectNumericFormatterAdjustment(id, sAdjustment); 1930 xWindow = VclPtr<NumericField>::Create(pParent, nBits); 1931 } 1932 else 1933 { 1934 connectFormattedFormatterAdjustment(id, sAdjustment); 1935 VclPtrInstance<FormattedField> xField(pParent, nBits); 1936 xField->SetMinValue(0); 1937 xWindow = xField; 1938 } 1939 } 1940 else if (name == "GtkLinkButton") 1941 xWindow = VclPtr<FixedHyperlink>::Create(pParent, WB_CENTER|WB_VCENTER|WB_3DLOOK|WB_NOLABEL); 1942 else if (name == "GtkComboBox" || name == "GtkComboBoxText") 1943 { 1944 extractModel(id, rMap); 1945 1946 WinBits nBits = WB_CLIPCHILDREN|WB_LEFT|WB_VCENTER|WB_3DLOOK; 1947 1948 bool bDropdown = BuilderUtils::extractDropdown(rMap); 1949 1950 if (bDropdown) 1951 nBits |= WB_DROPDOWN; 1952 1953 if (extractEntry(rMap)) 1954 { 1955 VclPtrInstance<ComboBox> xComboBox(pParent, nBits); 1956 xComboBox->EnableAutoSize(true); 1957 xWindow = xComboBox; 1958 } 1959 else 1960 { 1961 VclPtrInstance<ListBox> xListBox(pParent, nBits|WB_SIMPLEMODE); 1962 xListBox->EnableAutoSize(true); 1963 xWindow = xListBox; 1964 } 1965 } 1966 else if (name == "VclOptionalBox") 1967 { 1968 xWindow = VclPtr<OptionalBox>::Create(pParent); 1969 } 1970 else if (name == "GtkIconView") 1971 { 1972 assert(rMap.find(OString("model")) != rMap.end() && "GtkIconView must have a model"); 1973 1974 //window we want to apply the packing props for this GtkIconView to 1975 VclPtr<vcl::Window> xWindowForPackingProps; 1976 extractModel(id, rMap); 1977 WinBits nWinStyle = WB_CLIPCHILDREN|WB_LEFT|WB_VCENTER|WB_3DLOOK; 1978 //IconView manages its own scrolling, 1979 vcl::Window *pRealParent = prepareWidgetOwnScrolling(pParent, nWinStyle); 1980 if (pRealParent != pParent) 1981 nWinStyle |= WB_BORDER; 1982 1983 VclPtr<IconView> xBox = VclPtr<IconView>::Create(pRealParent, nWinStyle); 1984 xWindowForPackingProps = xBox; 1985 1986 xWindow = xBox; 1987 xBox->SetNoAutoCurEntry(true); 1988 xBox->SetQuickSearch(true); 1989 1990 if (pRealParent != pParent) 1991 cleanupWidgetOwnScrolling(pParent, xWindowForPackingProps, rMap); 1992 } 1993 else if (name == "GtkTreeView") 1994 { 1995 if (!m_bLegacy) 1996 { 1997 assert(rMap.find(OString("model")) != rMap.end() && "GtkTreeView must have a model"); 1998 } 1999 2000 //window we want to apply the packing props for this GtkTreeView to 2001 VclPtr<vcl::Window> xWindowForPackingProps; 2002 //To-Do 2003 //a) make SvHeaderTabListBox/SvTabListBox the default target for GtkTreeView 2004 //b) remove the non-drop down mode of ListBox and convert 2005 // everything over to SvHeaderTabListBox/SvTabListBox 2006 //c) remove the users of makeSvTabListBox and makeSvTreeListBox 2007 extractModel(id, rMap); 2008 WinBits nWinStyle = WB_CLIPCHILDREN|WB_LEFT|WB_VCENTER|WB_3DLOOK; 2009 if (m_bLegacy) 2010 { 2011 OUString sBorder = BuilderUtils::extractCustomProperty(rMap); 2012 if (!sBorder.isEmpty()) 2013 nWinStyle |= WB_BORDER; 2014 } 2015 else 2016 { 2017 nWinStyle |= WB_HASBUTTONS | WB_HASBUTTONSATROOT; 2018 } 2019 //ListBox/SvHeaderTabListBox manages its own scrolling, 2020 vcl::Window *pRealParent = prepareWidgetOwnScrolling(pParent, nWinStyle); 2021 if (pRealParent != pParent) 2022 nWinStyle |= WB_BORDER; 2023 if (m_bLegacy) 2024 { 2025 xWindow = VclPtr<ListBox>::Create(pRealParent, nWinStyle | WB_SIMPLEMODE); 2026 xWindowForPackingProps = xWindow; 2027 } 2028 else 2029 { 2030 VclPtr<SvTabListBox> xBox; 2031 bool bHeadersVisible = extractHeadersVisible(rMap); 2032 if (bHeadersVisible) 2033 { 2034 VclPtr<VclVBox> xContainer = VclPtr<VclVBox>::Create(pRealParent); 2035 OString containerid(id + "-container"); 2036 xContainer->SetHelpId(m_sHelpRoot + containerid); 2037 m_aChildren.emplace_back(containerid, xContainer, true); 2038 2039 VclPtrInstance<HeaderBar> xHeader(xContainer, WB_BUTTONSTYLE | WB_BORDER | WB_TABSTOP | WB_3DLOOK); 2040 xHeader->set_width_request(0); // let the headerbar width not affect the size request 2041 OString headerid(id + "-header"); 2042 xHeader->SetHelpId(m_sHelpRoot + headerid); 2043 m_aChildren.emplace_back(headerid, xHeader, true); 2044 2045 VclPtr<LclHeaderTabListBox> xHeaderBox = VclPtr<LclHeaderTabListBox>::Create(xContainer, nWinStyle); 2046 xHeaderBox->InitHeaderBar(xHeader); 2047 xContainer->set_expand(true); 2048 xHeader->Show(); 2049 xContainer->Show(); 2050 xBox = xHeaderBox; 2051 xWindowForPackingProps = xContainer; 2052 } 2053 else 2054 { 2055 xBox = VclPtr<LclTabListBox>::Create(pRealParent, nWinStyle); 2056 xWindowForPackingProps = xBox; 2057 } 2058 xWindow = xBox; 2059 xBox->SetNoAutoCurEntry(true); 2060 xBox->SetQuickSearch(true); 2061 xBox->SetSpaceBetweenEntries(3); 2062 xBox->SetEntryHeight(16); 2063 xBox->SetHighlightRange(); // select over the whole width 2064 } 2065 if (pRealParent != pParent) 2066 cleanupWidgetOwnScrolling(pParent, xWindowForPackingProps, rMap); 2067 } 2068 else if (name == "GtkTreeViewColumn") 2069 { 2070 if (!m_bLegacy) 2071 { 2072 SvHeaderTabListBox* pTreeView = dynamic_cast<SvHeaderTabListBox*>(pParent); 2073 if (HeaderBar* pHeaderBar = pTreeView ? pTreeView->GetHeaderBar() : nullptr) 2074 { 2075 HeaderBarItemBits nBits = HeaderBarItemBits::LEFTIMAGE; 2076 if (extractClickable(rMap)) 2077 nBits |= HeaderBarItemBits::CLICKABLE; 2078 if (extractSortIndicator(rMap)) 2079 nBits |= HeaderBarItemBits::DOWNARROW; 2080 float fAlign = extractAlignment(rMap); 2081 if (fAlign == 0.0) 2082 nBits |= HeaderBarItemBits::LEFT; 2083 else if (fAlign == 1.0) 2084 nBits |= HeaderBarItemBits::RIGHT; 2085 else if (fAlign == 0.5) 2086 nBits |= HeaderBarItemBits::CENTER; 2087 auto nItemId = pHeaderBar->GetItemCount() + 1; 2088 OUString sTitle(extractTitle(rMap)); 2089 pHeaderBar->InsertItem(nItemId, sTitle, 100, nBits); 2090 } 2091 } 2092 } 2093 else if (name == "GtkLabel") 2094 { 2095 WinBits nWinStyle = WB_CENTER|WB_VCENTER|WB_3DLOOK; 2096 extractMnemonicWidget(id, rMap); 2097 if (extractSelectable(rMap)) 2098 xWindow = VclPtr<SelectableFixedText>::Create(pParent, nWinStyle); 2099 else 2100 xWindow = VclPtr<FixedText>::Create(pParent, nWinStyle); 2101 } 2102 else if (name == "GtkImage") 2103 { 2104 extractStock(id, rMap); 2105 xWindow = VclPtr<FixedImage>::Create(pParent, WB_CENTER|WB_VCENTER|WB_3DLOOK|WB_SCALE); 2106 //such parentless GtkImages are temps used to set icons on buttons 2107 //default them to hidden to stop e.g. insert->index entry flicking temp 2108 //full screen windows 2109 if (!pParent) 2110 { 2111 rMap["visible"] = "false"; 2112 } 2113 } 2114 else if (name == "GtkSeparator") 2115 { 2116 bVertical = extractOrientation(rMap); 2117 xWindow = VclPtr<FixedLine>::Create(pParent, bVertical ? WB_VERT : WB_HORZ); 2118 } 2119 else if (name == "GtkScrollbar") 2120 { 2121 extractAdjustmentToMap(id, rMap, m_pParserState->m_aScrollAdjustmentMaps); 2122 bVertical = extractOrientation(rMap); 2123 xWindow = VclPtr<ScrollBar>::Create(pParent, bVertical ? WB_VERT : WB_HORZ); 2124 } 2125 else if (name == "GtkProgressBar") 2126 { 2127 extractAdjustmentToMap(id, rMap, m_pParserState->m_aScrollAdjustmentMaps); 2128 bVertical = extractOrientation(rMap); 2129 xWindow = VclPtr<ProgressBar>::Create(pParent, bVertical ? WB_VERT : WB_HORZ); 2130 } 2131 else if (name == "GtkScrolledWindow") 2132 { 2133 xWindow = VclPtr<VclScrolledWindow>::Create(pParent); 2134 } 2135 else if (name == "GtkViewport") 2136 { 2137 xWindow = VclPtr<VclViewport>::Create(pParent); 2138 } 2139 else if (name == "GtkEventBox") 2140 { 2141 xWindow = VclPtr<VclEventBox>::Create(pParent); 2142 } 2143 else if (name == "GtkEntry") 2144 { 2145 xWindow = VclPtr<Edit>::Create(pParent, WB_LEFT|WB_VCENTER|WB_BORDER|WB_3DLOOK); 2146 BuilderUtils::ensureDefaultWidthChars(rMap); 2147 } 2148 else if (name == "GtkNotebook") 2149 { 2150 if (!extractVerticalTabPos(rMap)) 2151 xWindow = VclPtr<TabControl>::Create(pParent, WB_STDTABCONTROL|WB_3DLOOK); 2152 else 2153 xWindow = VclPtr<VerticalTabControl>::Create(pParent); 2154 } 2155 else if (name == "GtkDrawingArea") 2156 { 2157 xWindow = VclPtr<VclDrawingArea>::Create(pParent, WB_TABSTOP); 2158 } 2159 else if (name == "GtkTextView") 2160 { 2161 extractBuffer(id, rMap); 2162 2163 WinBits nWinStyle = WB_CLIPCHILDREN|WB_LEFT; 2164 //VclMultiLineEdit manages its own scrolling, 2165 vcl::Window *pRealParent = prepareWidgetOwnScrolling(pParent, nWinStyle); 2166 if (pRealParent != pParent) 2167 nWinStyle |= WB_BORDER; 2168 xWindow = VclPtr<VclMultiLineEdit>::Create(pRealParent, nWinStyle); 2169 if (pRealParent != pParent) 2170 cleanupWidgetOwnScrolling(pParent, xWindow, rMap); 2171 } 2172 else if (name == "GtkSpinner") 2173 { 2174 xWindow = VclPtr<Throbber>::Create(pParent, WB_3DLOOK); 2175 } 2176 else if (name == "GtkScale") 2177 { 2178 extractAdjustmentToMap(id, rMap, m_pParserState->m_aSliderAdjustmentMaps); 2179 bool bDrawValue = extractDrawValue(rMap); 2180 if (bDrawValue) 2181 { 2182 OUString sValuePos = extractValuePos(rMap); 2183 (void)sValuePos; 2184 } 2185 bVertical = extractOrientation(rMap); 2186 2187 WinBits nWinStyle = bVertical ? WB_VERT : WB_HORZ; 2188 2189 xWindow = VclPtr<Slider>::Create(pParent, nWinStyle); 2190 } 2191 else if (name == "GtkToolbar") 2192 { 2193 xWindow = VclPtr<ToolBox>::Create(pParent, WB_3DLOOK | WB_TABSTOP); 2194 } 2195 else if(name == "NotebookBarAddonsToolMergePoint") 2196 { 2197 customMakeWidget pFunction = GetCustomMakeWidget("sfxlo-NotebookbarToolBox"); 2198 if(pFunction != nullptr) 2199 NotebookBarAddonsMerger::MergeNotebookBarAddons(pParent, pFunction, m_xFrame, *m_pNotebookBarAddonsItem, rMap); 2200 return nullptr; 2201 } 2202 else if (name == "GtkToolButton" || name == "GtkMenuToolButton" || 2203 name == "GtkToggleToolButton" || name == "GtkRadioToolButton" || name == "GtkToolItem") 2204 { 2205 if (pToolBox) 2206 { 2207 OUString aCommand(extractActionName(rMap)); 2208 2209 sal_uInt16 nItemId = 0; 2210 ToolBoxItemBits nBits = ToolBoxItemBits::NONE; 2211 if (name == "GtkMenuToolButton") 2212 nBits |= ToolBoxItemBits::DROPDOWN; 2213 else if (name == "GtkToggleToolButton") 2214 nBits |= ToolBoxItemBits::AUTOCHECK | ToolBoxItemBits::CHECKABLE; 2215 else if (name == "GtkRadioToolButton") 2216 nBits |= ToolBoxItemBits::AUTOCHECK | ToolBoxItemBits::RADIOCHECK; 2217 2218 if (!aCommand.isEmpty() && m_xFrame.is()) 2219 { 2220 pToolBox->InsertItem(aCommand, m_xFrame, nBits, extractSizeRequest(rMap)); 2221 nItemId = pToolBox->GetItemId(aCommand); 2222 } 2223 else 2224 { 2225 nItemId = pToolBox->GetItemCount() + 1; 2226 //TODO: ImplToolItems::size_type -> sal_uInt16! 2227 pToolBox->InsertItem(nItemId, extractLabel(rMap), nBits); 2228 if (aCommand.isEmpty() && !m_bLegacy) 2229 aCommand = OUString::fromUtf8(id); 2230 pToolBox->SetItemCommand(nItemId, aCommand); 2231 } 2232 2233 pToolBox->SetHelpId(nItemId, m_sHelpRoot + id); 2234 OUString sTooltip(extractTooltipText(rMap)); 2235 if (!sTooltip.isEmpty()) 2236 pToolBox->SetQuickHelpText(nItemId, sTooltip); 2237 2238 OUString sIconName(extractIconName(rMap)); 2239 if (sIconName.isEmpty()) 2240 sIconName = mapStockToImageResource(extractStockId(rMap)); 2241 if (!sIconName.isEmpty()) 2242 pToolBox->SetItemImage(nItemId, FixedImage::loadThemeImage(sIconName)); 2243 2244 if (!extractVisible(rMap)) 2245 pToolBox->HideItem(nItemId); 2246 2247 m_pParserState->m_nLastToolbarId = nItemId; 2248 2249 return nullptr; // no widget to be created 2250 } 2251 } 2252 else if (name == "GtkSeparatorToolItem") 2253 { 2254 if (pToolBox) 2255 { 2256 pToolBox->InsertSeparator(); 2257 return nullptr; // no widget to be created 2258 } 2259 } 2260 else if (name == "GtkWindow") 2261 { 2262 WinBits nBits = extractDeferredBits(rMap); 2263 if (nBits & WB_DOCKABLE) 2264 xWindow = VclPtr<DockingWindow>::Create(pParent, nBits|WB_MOVEABLE); 2265 else 2266 xWindow = VclPtr<FloatingWindow>::Create(pParent, nBits|WB_MOVEABLE); 2267 } 2268 else if (name == "GtkPopover") 2269 { 2270 WinBits nBits = extractDeferredBits(rMap); 2271 xWindow = VclPtr<DockingWindow>::Create(pParent, nBits|WB_DOCKABLE|WB_MOVEABLE); 2272 } 2273 else if (name == "GtkCalendar") 2274 { 2275 WinBits nBits = extractDeferredBits(rMap); 2276 xWindow = VclPtr<Calendar>::Create(pParent, nBits); 2277 } 2278 else 2279 { 2280 if (customMakeWidget pFunction = GetCustomMakeWidget(name)) 2281 { 2282 pFunction(xWindow, pParent, rMap); 2283 if (xWindow->GetType() == WindowType::PUSHBUTTON) 2284 setupFromActionName(static_cast<Button*>(xWindow.get()), rMap, m_xFrame); 2285 else if (xWindow->GetType() == WindowType::MENUBUTTON) 2286 { 2287 OUString sMenu = BuilderUtils::extractCustomProperty(rMap); 2288 if (!sMenu.isEmpty()) 2289 m_pParserState->m_aButtonMenuMaps.emplace_back(id, sMenu); 2290 setupFromActionName(static_cast<Button*>(xWindow.get()), rMap, m_xFrame); 2291 } 2292 } 2293 } 2294 2295 SAL_INFO_IF(!xWindow, "vcl.builder", "probably need to implement " << name << " or add a make" << name << " function"); 2296 if (xWindow) 2297 { 2298 // child windows of disabled windows are made disabled by vcl by default, we don't want that 2299 WindowImpl *pWindowImpl = xWindow->ImplGetWindowImpl(); 2300 pWindowImpl->mbDisabled = false; 2301 2302 xWindow->SetHelpId(m_sHelpRoot + id); 2303 SAL_INFO("vcl.builder", "for name '" << name << "' and id '" << id << 2304 "', created " << xWindow.get() << " child of " << 2305 pParent << "(" << xWindow->ImplGetWindowImpl()->mpParent.get() << "/" << 2306 xWindow->ImplGetWindowImpl()->mpRealParent.get() << "/" << 2307 xWindow->ImplGetWindowImpl()->mpBorderWindow.get() << ") with helpid " << 2308 xWindow->GetHelpId()); 2309 m_aChildren.emplace_back(id, xWindow, bVertical); 2310 2311 // if the parent was a toolbox set it as an itemwindow for the latest itemid 2312 if (pToolBox) 2313 { 2314 Size aSize(xWindow->GetSizePixel()); 2315 aSize.setHeight(xWindow->get_preferred_size().Height()); 2316 xWindow->SetSizePixel(aSize); 2317 pToolBox->SetItemWindow(m_pParserState->m_nLastToolbarId, xWindow); 2318 pToolBox->SetItemExpand(m_pParserState->m_nLastToolbarId, true); 2319 } 2320 } 2321 return xWindow; 2322 } 2323 2324 namespace 2325 { 2326 //return true for window types which exist in vcl but are not themselves 2327 //represented in the .ui format, i.e. only their children exist. 2328 bool isConsideredGtkPseudo(vcl::Window const *pWindow) 2329 { 2330 return pWindow->GetType() == WindowType::TABPAGE; 2331 } 2332 } 2333 2334 //Any properties from .ui load we couldn't set because of potential virtual methods 2335 //during ctor are applied here 2336 void VclBuilder::setDeferredProperties() 2337 { 2338 if (!m_bToplevelHasDeferredProperties) 2339 return; 2340 stringmap aDeferredProperties; 2341 aDeferredProperties.swap(m_aDeferredProperties); 2342 m_bToplevelHasDeferredProperties = false; 2343 BuilderUtils::set_properties(m_pParent, aDeferredProperties); 2344 } 2345 2346 namespace BuilderUtils 2347 { 2348 void set_properties(vcl::Window *pWindow, const VclBuilder::stringmap &rProps) 2349 { 2350 for (auto const& prop : rProps) 2351 { 2352 const OString &rKey = prop.first; 2353 const OUString &rValue = prop.second; 2354 pWindow->set_property(rKey, rValue); 2355 } 2356 } 2357 2358 OUString convertMnemonicMarkup(const OUString &rIn) 2359 { 2360 OUStringBuffer aRet(rIn); 2361 for (sal_Int32 nI = 0; nI < aRet.getLength(); ++nI) 2362 { 2363 if (aRet[nI] == '_' && nI+1 < aRet.getLength()) 2364 { 2365 if (aRet[nI+1] != '_') 2366 aRet[nI] = MNEMONIC_CHAR; 2367 else 2368 aRet.remove(nI, 1); 2369 ++nI; 2370 } 2371 } 2372 return aRet.makeStringAndClear(); 2373 } 2374 2375 OUString extractCustomProperty(VclBuilder::stringmap &rMap) 2376 { 2377 OUString sCustomProperty; 2378 VclBuilder::stringmap::iterator aFind = rMap.find(OString("customproperty")); 2379 if (aFind != rMap.end()) 2380 { 2381 sCustomProperty = aFind->second; 2382 rMap.erase(aFind); 2383 } 2384 return sCustomProperty; 2385 } 2386 2387 void ensureDefaultWidthChars(VclBuilder::stringmap &rMap) 2388 { 2389 OString sWidthChars("width-chars"); 2390 VclBuilder::stringmap::iterator aFind = rMap.find(sWidthChars); 2391 if (aFind == rMap.end()) 2392 rMap[sWidthChars] = "25"; 2393 } 2394 2395 bool extractDropdown(VclBuilder::stringmap &rMap) 2396 { 2397 bool bDropdown = true; 2398 VclBuilder::stringmap::iterator aFind = rMap.find(OString("dropdown")); 2399 if (aFind != rMap.end()) 2400 { 2401 bDropdown = toBool(aFind->second); 2402 rMap.erase(aFind); 2403 } 2404 return bDropdown; 2405 } 2406 2407 void reorderWithinParent(vcl::Window &rWindow, sal_uInt16 nNewPosition) 2408 { 2409 WindowImpl *pWindowImpl = rWindow.ImplGetWindowImpl(); 2410 if (pWindowImpl->mpParent != pWindowImpl->mpRealParent) 2411 { 2412 assert(pWindowImpl->mpBorderWindow == pWindowImpl->mpParent); 2413 assert(pWindowImpl->mpBorderWindow->ImplGetWindowImpl()->mpParent == pWindowImpl->mpRealParent); 2414 reorderWithinParent(*pWindowImpl->mpBorderWindow, nNewPosition); 2415 return; 2416 } 2417 rWindow.reorderWithinParent(nNewPosition); 2418 } 2419 2420 void reorderWithinParent(std::vector<vcl::Window*>& rChilds, bool bIsButtonBox) 2421 { 2422 for (size_t i = 0; i < rChilds.size(); ++i) 2423 { 2424 reorderWithinParent(*rChilds[i], i); 2425 2426 if (!bIsButtonBox) 2427 continue; 2428 2429 //The first member of the group for legacy code needs WB_GROUP set and the 2430 //others not 2431 WinBits nBits = rChilds[i]->GetStyle(); 2432 nBits &= ~WB_GROUP; 2433 if (i == 0) 2434 nBits |= WB_GROUP; 2435 rChilds[i]->SetStyle(nBits); 2436 } 2437 } 2438 2439 sal_Int16 getRoleFromName(const OString& roleName) 2440 { 2441 using namespace com::sun::star::accessibility; 2442 2443 static const std::unordered_map<OString, sal_Int16> aAtkRoleToAccessibleRole = { 2444 /* This is in atkobject.h's AtkRole order */ 2445 { "invalid", AccessibleRole::UNKNOWN }, 2446 { "accelerator label", AccessibleRole::UNKNOWN }, 2447 { "alert", AccessibleRole::ALERT }, 2448 { "animation", AccessibleRole::UNKNOWN }, 2449 { "arrow", AccessibleRole::UNKNOWN }, 2450 { "calendar", AccessibleRole::UNKNOWN }, 2451 { "canvas", AccessibleRole::CANVAS }, 2452 { "check box", AccessibleRole::CHECK_BOX }, 2453 { "check menu item", AccessibleRole::CHECK_MENU_ITEM }, 2454 { "color chooser", AccessibleRole::COLOR_CHOOSER }, 2455 { "column header", AccessibleRole::COLUMN_HEADER }, 2456 { "combo box", AccessibleRole::COMBO_BOX }, 2457 { "date editor", AccessibleRole::DATE_EDITOR }, 2458 { "desktop icon", AccessibleRole::DESKTOP_ICON }, 2459 { "desktop frame", AccessibleRole::DESKTOP_PANE }, // ? 2460 { "dial", AccessibleRole::UNKNOWN }, 2461 { "dialog", AccessibleRole::DIALOG }, 2462 { "directory pane", AccessibleRole::DIRECTORY_PANE }, 2463 { "drawing area", AccessibleRole::UNKNOWN }, 2464 { "file chooser", AccessibleRole::FILE_CHOOSER }, 2465 { "filler", AccessibleRole::FILLER }, 2466 { "font chooser", AccessibleRole::FONT_CHOOSER }, 2467 { "frame", AccessibleRole::FRAME }, 2468 { "glass pane", AccessibleRole::GLASS_PANE }, 2469 { "html container", AccessibleRole::UNKNOWN }, 2470 { "icon", AccessibleRole::ICON }, 2471 { "image", AccessibleRole::GRAPHIC }, 2472 { "internal frame", AccessibleRole::INTERNAL_FRAME }, 2473 { "label", AccessibleRole::LABEL }, 2474 { "layered pane", AccessibleRole::LAYERED_PANE }, 2475 { "list", AccessibleRole::LIST }, 2476 { "list item", AccessibleRole::LIST_ITEM }, 2477 { "menu", AccessibleRole::MENU }, 2478 { "menu bar", AccessibleRole::MENU_BAR }, 2479 { "menu item", AccessibleRole::MENU_ITEM }, 2480 { "option pane", AccessibleRole::OPTION_PANE }, 2481 { "page tab", AccessibleRole::PAGE_TAB }, 2482 { "page tab list", AccessibleRole::PAGE_TAB_LIST }, 2483 { "panel", AccessibleRole::PANEL }, // or SHAPE or TEXT_FRAME ? 2484 { "password text", AccessibleRole::PASSWORD_TEXT }, 2485 { "popup menu", AccessibleRole::POPUP_MENU }, 2486 { "progress bar", AccessibleRole::PROGRESS_BAR }, 2487 { "push button", AccessibleRole::PUSH_BUTTON }, // or BUTTON_DROPDOWN or BUTTON_MENU 2488 { "radio button", AccessibleRole::RADIO_BUTTON }, 2489 { "radio menu item", AccessibleRole::RADIO_MENU_ITEM }, 2490 { "root pane", AccessibleRole::ROOT_PANE }, 2491 { "row header", AccessibleRole::ROW_HEADER }, 2492 { "scroll bar", AccessibleRole::SCROLL_BAR }, 2493 { "scroll pane", AccessibleRole::SCROLL_PANE }, 2494 { "separator", AccessibleRole::SEPARATOR }, 2495 { "slider", AccessibleRole::SLIDER }, 2496 { "split pane", AccessibleRole::SPLIT_PANE }, 2497 { "spin button", AccessibleRole::SPIN_BOX }, // ? 2498 { "statusbar", AccessibleRole::STATUS_BAR }, 2499 { "table", AccessibleRole::TABLE }, 2500 { "table cell", AccessibleRole::TABLE_CELL }, 2501 { "table column header", AccessibleRole::COLUMN_HEADER }, // approximate 2502 { "table row header", AccessibleRole::ROW_HEADER }, // approximate 2503 { "tear off menu item", AccessibleRole::UNKNOWN }, 2504 { "terminal", AccessibleRole::UNKNOWN }, 2505 { "text", AccessibleRole::TEXT }, 2506 { "toggle button", AccessibleRole::TOGGLE_BUTTON }, 2507 { "tool bar", AccessibleRole::TOOL_BAR }, 2508 { "tool tip", AccessibleRole::TOOL_TIP }, 2509 { "tree", AccessibleRole::TREE }, 2510 { "tree table", AccessibleRole::TREE_TABLE }, 2511 { "unknown", AccessibleRole::UNKNOWN }, 2512 { "viewport", AccessibleRole::VIEW_PORT }, 2513 { "window", AccessibleRole::WINDOW }, 2514 { "header", AccessibleRole::HEADER }, 2515 { "footer", AccessibleRole::FOOTER }, 2516 { "paragraph", AccessibleRole::PARAGRAPH }, 2517 { "ruler", AccessibleRole::RULER }, 2518 { "application", AccessibleRole::UNKNOWN }, 2519 { "autocomplete", AccessibleRole::UNKNOWN }, 2520 { "edit bar", AccessibleRole::EDIT_BAR }, 2521 { "embedded", AccessibleRole::EMBEDDED_OBJECT }, 2522 { "entry", AccessibleRole::UNKNOWN }, 2523 { "chart", AccessibleRole::CHART }, 2524 { "caption", AccessibleRole::CAPTION }, 2525 { "document frame", AccessibleRole::DOCUMENT }, 2526 { "heading", AccessibleRole::HEADING }, 2527 { "page", AccessibleRole::PAGE }, 2528 { "section", AccessibleRole::SECTION }, 2529 { "redundant object", AccessibleRole::UNKNOWN }, 2530 { "form", AccessibleRole::FORM }, 2531 { "link", AccessibleRole::HYPER_LINK }, 2532 { "input method window", AccessibleRole::UNKNOWN }, 2533 { "table row", AccessibleRole::UNKNOWN }, 2534 { "tree item", AccessibleRole::TREE_ITEM }, 2535 { "document spreadsheet", AccessibleRole::DOCUMENT_SPREADSHEET }, 2536 { "document presentation", AccessibleRole::DOCUMENT_PRESENTATION }, 2537 { "document text", AccessibleRole::DOCUMENT_TEXT }, 2538 { "document web", AccessibleRole::DOCUMENT }, // approximate 2539 { "document email", AccessibleRole::DOCUMENT }, // approximate 2540 { "comment", AccessibleRole::COMMENT }, // or NOTE or END_NOTE or FOOTNOTE or SCROLL_PANE 2541 { "list box", AccessibleRole::UNKNOWN }, 2542 { "grouping", AccessibleRole::GROUP_BOX }, 2543 { "image map", AccessibleRole::IMAGE_MAP }, 2544 { "notification", AccessibleRole::UNKNOWN }, 2545 { "info bar", AccessibleRole::UNKNOWN }, 2546 { "level bar", AccessibleRole::UNKNOWN }, 2547 { "title bar", AccessibleRole::UNKNOWN }, 2548 { "block quote", AccessibleRole::UNKNOWN }, 2549 { "audio", AccessibleRole::UNKNOWN }, 2550 { "video", AccessibleRole::UNKNOWN }, 2551 { "definition", AccessibleRole::UNKNOWN }, 2552 { "article", AccessibleRole::UNKNOWN }, 2553 { "landmark", AccessibleRole::UNKNOWN }, 2554 { "log", AccessibleRole::UNKNOWN }, 2555 { "marquee", AccessibleRole::UNKNOWN }, 2556 { "math", AccessibleRole::UNKNOWN }, 2557 { "rating", AccessibleRole::UNKNOWN }, 2558 { "timer", AccessibleRole::UNKNOWN }, 2559 { "description list", AccessibleRole::UNKNOWN }, 2560 { "description term", AccessibleRole::UNKNOWN }, 2561 { "description value", AccessibleRole::UNKNOWN }, 2562 { "static", AccessibleRole::STATIC }, 2563 { "math fraction", AccessibleRole::UNKNOWN }, 2564 { "math root", AccessibleRole::UNKNOWN }, 2565 { "subscript", AccessibleRole::UNKNOWN }, 2566 { "superscript", AccessibleRole::UNKNOWN }, 2567 { "footnote", AccessibleRole::FOOTNOTE }, 2568 }; 2569 2570 auto it = aAtkRoleToAccessibleRole.find(roleName); 2571 if (it == aAtkRoleToAccessibleRole.end()) 2572 return AccessibleRole::UNKNOWN; 2573 return it->second; 2574 } 2575 } 2576 2577 VclPtr<vcl::Window> VclBuilder::insertObject(vcl::Window *pParent, const OString &rClass, 2578 const OString &rID, stringmap &rProps, stringmap &rPango, stringmap &rAtk) 2579 { 2580 VclPtr<vcl::Window> pCurrentChild; 2581 2582 if (m_pParent && !isConsideredGtkPseudo(m_pParent) && !m_sID.isEmpty() && rID == m_sID) 2583 { 2584 pCurrentChild = m_pParent; 2585 2586 //toplevels default to resizable and apparently you can't change them 2587 //afterwards, so we need to wait until now before we can truly 2588 //initialize the dialog. 2589 if (pParent && pParent->IsSystemWindow()) 2590 { 2591 SystemWindow *pSysWin = static_cast<SystemWindow*>(pCurrentChild.get()); 2592 pSysWin->doDeferredInit(extractDeferredBits(rProps)); 2593 m_bToplevelHasDeferredInit = false; 2594 } 2595 else if (pParent && pParent->IsDockingWindow()) 2596 { 2597 DockingWindow *pDockWin = static_cast<DockingWindow*>(pCurrentChild.get()); 2598 pDockWin->doDeferredInit(extractDeferredBits(rProps)); 2599 m_bToplevelHasDeferredInit = false; 2600 } 2601 2602 if (pCurrentChild->GetHelpId().isEmpty()) 2603 { 2604 pCurrentChild->SetHelpId(m_sHelpRoot + m_sID); 2605 SAL_INFO("vcl.builder", "for toplevel dialog " << this << " " << 2606 rID << ", set helpid " << pCurrentChild->GetHelpId()); 2607 } 2608 m_bToplevelParentFound = true; 2609 } 2610 else 2611 { 2612 //if we're being inserting under a toplevel dialog whose init is 2613 //deferred due to waiting to encounter it in this .ui, and it hasn't 2614 //been seen yet, then make unattached widgets parent-less toplevels 2615 if (pParent == m_pParent.get() && m_bToplevelHasDeferredInit) 2616 pParent = nullptr; 2617 pCurrentChild = makeObject(pParent, rClass, rID, rProps); 2618 } 2619 2620 if (pCurrentChild) 2621 { 2622 pCurrentChild->set_id(OStringToOUString(rID, RTL_TEXTENCODING_UTF8)); 2623 if (pCurrentChild == m_pParent.get() && m_bToplevelHasDeferredProperties) 2624 m_aDeferredProperties = rProps; 2625 else 2626 BuilderUtils::set_properties(pCurrentChild, rProps); 2627 2628 for (auto const& elem : rPango) 2629 { 2630 const OString &rKey = elem.first; 2631 const OUString &rValue = elem.second; 2632 pCurrentChild->set_font_attribute(rKey, rValue); 2633 } 2634 2635 m_pParserState->m_aAtkInfo[pCurrentChild] = rAtk; 2636 } 2637 2638 rProps.clear(); 2639 rPango.clear(); 2640 rAtk.clear(); 2641 2642 if (!pCurrentChild) 2643 { 2644 bool bToolbarParent = (pParent && pParent->GetType() == WindowType::TOOLBOX); 2645 pCurrentChild = (m_aChildren.empty() || bToolbarParent) ? pParent : m_aChildren.back().m_pWindow.get(); 2646 } 2647 return pCurrentChild; 2648 } 2649 2650 void VclBuilder::handleTabChild(vcl::Window *pParent, xmlreader::XmlReader &reader) 2651 { 2652 std::vector<OString> sIDs; 2653 2654 int nLevel = 1; 2655 stringmap aProperties; 2656 std::vector<vcl::EnumContext::Context> context; 2657 2658 while(true) 2659 { 2660 xmlreader::Span name; 2661 int nsId; 2662 2663 xmlreader::XmlReader::Result res = reader.nextItem( 2664 xmlreader::XmlReader::Text::NONE, &name, &nsId); 2665 2666 if (res == xmlreader::XmlReader::Result::Begin) 2667 { 2668 ++nLevel; 2669 if (name == "object") 2670 { 2671 while (reader.nextAttribute(&nsId, &name)) 2672 { 2673 if (name == "id") 2674 { 2675 name = reader.getAttributeValue(false); 2676 OString sID(name.begin, name.length); 2677 sal_Int32 nDelim = sID.indexOf(':'); 2678 if (nDelim != -1) 2679 { 2680 OString sPattern = sID.copy(nDelim+1); 2681 aProperties[OString("customproperty")] = OUString::fromUtf8(sPattern); 2682 sID = sID.copy(0, nDelim); 2683 } 2684 sIDs.push_back(sID); 2685 } 2686 } 2687 } 2688 else if (name == "style") 2689 { 2690 int nPriority = 0; 2691 context = handleStyle(reader, nPriority); 2692 --nLevel; 2693 } 2694 else if (name == "property") 2695 collectProperty(reader, aProperties); 2696 } 2697 2698 if (res == xmlreader::XmlReader::Result::End) 2699 --nLevel; 2700 2701 if (!nLevel) 2702 break; 2703 2704 if (res == xmlreader::XmlReader::Result::Done) 2705 break; 2706 } 2707 2708 if (!pParent) 2709 return; 2710 2711 TabControl *pTabControl = pParent->GetType() == WindowType::TABCONTROL ? 2712 static_cast<TabControl*>(pParent) : nullptr; 2713 VerticalTabControl *pVerticalTabControl = pParent->GetType() == WindowType::VERTICALTABCONTROL ? 2714 static_cast<VerticalTabControl*>(pParent) : nullptr; 2715 assert(pTabControl || pVerticalTabControl); 2716 VclBuilder::stringmap::iterator aFind = aProperties.find(OString("label")); 2717 if (aFind != aProperties.end()) 2718 { 2719 if (pTabControl) 2720 { 2721 sal_uInt16 nPageId = pTabControl->GetCurPageId(); 2722 pTabControl->SetPageText(nPageId, aFind->second); 2723 pTabControl->SetPageName(nPageId, sIDs.back()); 2724 if (!context.empty()) 2725 { 2726 TabPage* pPage = pTabControl->GetTabPage(nPageId); 2727 pPage->SetContext(context); 2728 } 2729 } 2730 else 2731 { 2732 OUString sLabel(aFind->second); 2733 OUString sIconName(extractIconName(aProperties)); 2734 OUString sTooltip(extractTooltipText(aProperties)); 2735 pVerticalTabControl->InsertPage(sIDs.front(), sLabel, FixedImage::loadThemeImage(sIconName), sTooltip, 2736 pVerticalTabControl->GetPageParent()->GetWindow(GetWindowType::LastChild)); 2737 } 2738 } 2739 else 2740 { 2741 if (pTabControl) 2742 pTabControl->RemovePage(pTabControl->GetCurPageId()); 2743 } 2744 } 2745 2746 //so that tabbing between controls goes in a visually sensible sequence 2747 //we sort these into a best-tab-order sequence 2748 bool VclBuilder::sortIntoBestTabTraversalOrder::operator()(const vcl::Window *pA, const vcl::Window *pB) const 2749 { 2750 //sort child order within parent list by grid position 2751 sal_Int32 nTopA = pA->get_grid_top_attach(); 2752 sal_Int32 nTopB = pB->get_grid_top_attach(); 2753 if (nTopA < nTopB) 2754 return true; 2755 if (nTopA > nTopB) 2756 return false; 2757 sal_Int32 nLeftA = pA->get_grid_left_attach(); 2758 sal_Int32 nLeftB = pB->get_grid_left_attach(); 2759 if (nLeftA < nLeftB) 2760 return true; 2761 if (nLeftA > nLeftB) 2762 return false; 2763 //sort into two groups of pack start and pack end 2764 VclPackType ePackA = pA->get_pack_type(); 2765 VclPackType ePackB = pB->get_pack_type(); 2766 if (ePackA < ePackB) 2767 return true; 2768 if (ePackA > ePackB) 2769 return false; 2770 bool bVerticalContainer = m_pBuilder->get_window_packing_data(pA->GetParent()).m_bVerticalOrient; 2771 bool bPackA = pA->get_secondary(); 2772 bool bPackB = pB->get_secondary(); 2773 if (!bVerticalContainer) 2774 { 2775 //for horizontal boxes group secondaries before primaries 2776 if (bPackA > bPackB) 2777 return true; 2778 if (bPackA < bPackB) 2779 return false; 2780 } 2781 else 2782 { 2783 //for vertical boxes group secondaries after primaries 2784 if (bPackA < bPackB) 2785 return true; 2786 if (bPackA > bPackB) 2787 return false; 2788 } 2789 //honour relative box positions with pack group, (numerical order is reversed 2790 //for VclPackType::End, they are packed from the end back, but here we need 2791 //them in visual layout order so that tabbing works as expected) 2792 sal_Int32 nPackA = m_pBuilder->get_window_packing_data(pA).m_nPosition; 2793 sal_Int32 nPackB = m_pBuilder->get_window_packing_data(pB).m_nPosition; 2794 if (nPackA < nPackB) 2795 return ePackA == VclPackType::Start; 2796 if (nPackA > nPackB) 2797 return ePackA != VclPackType::Start; 2798 //sort labels of Frames before body 2799 if (pA->GetParent() == pB->GetParent()) 2800 { 2801 const VclFrame *pFrameParent = dynamic_cast<const VclFrame*>(pA->GetParent()); 2802 if (pFrameParent) 2803 { 2804 const vcl::Window *pLabel = pFrameParent->get_label_widget(); 2805 int nFramePosA = (pA == pLabel) ? 0 : 1; 2806 int nFramePosB = (pB == pLabel) ? 0 : 1; 2807 return nFramePosA < nFramePosB; 2808 } 2809 } 2810 return false; 2811 } 2812 2813 void VclBuilder::handleChild(vcl::Window *pParent, xmlreader::XmlReader &reader) 2814 { 2815 vcl::Window *pCurrentChild = nullptr; 2816 2817 xmlreader::Span name; 2818 int nsId; 2819 OString sType, sInternalChild; 2820 2821 while (reader.nextAttribute(&nsId, &name)) 2822 { 2823 if (name == "type") 2824 { 2825 name = reader.getAttributeValue(false); 2826 sType = OString(name.begin, name.length); 2827 } 2828 else if (name == "internal-child") 2829 { 2830 name = reader.getAttributeValue(false); 2831 sInternalChild = OString(name.begin, name.length); 2832 } 2833 } 2834 2835 if (sType == "tab") 2836 { 2837 handleTabChild(pParent, reader); 2838 return; 2839 } 2840 2841 int nLevel = 1; 2842 while(true) 2843 { 2844 xmlreader::XmlReader::Result res = reader.nextItem( 2845 xmlreader::XmlReader::Text::NONE, &name, &nsId); 2846 2847 if (res == xmlreader::XmlReader::Result::Begin) 2848 { 2849 if (name == "object" || name == "placeholder") 2850 { 2851 pCurrentChild = handleObject(pParent, reader).get(); 2852 2853 bool bObjectInserted = pCurrentChild && pParent != pCurrentChild; 2854 2855 if (bObjectInserted) 2856 { 2857 //Internal-children default in glade to not having their visible bits set 2858 //even though they are visible (generally anyway) 2859 if (!sInternalChild.isEmpty()) 2860 pCurrentChild->Show(); 2861 2862 //Select the first page if it's a notebook 2863 if (pCurrentChild->GetType() == WindowType::TABCONTROL) 2864 { 2865 TabControl *pTabControl = static_cast<TabControl*>(pCurrentChild); 2866 pTabControl->SetCurPageId(pTabControl->GetPageId(0)); 2867 2868 //To-Do add reorder capability to the TabControl 2869 } 2870 else 2871 { 2872 // We want to sort labels before contents of frames 2873 // for keyboard traversal, especially if there 2874 // are multiple widgets using the same mnemonic 2875 if (sType == "label") 2876 { 2877 if (VclFrame *pFrameParent = dynamic_cast<VclFrame*>(pParent)) 2878 pFrameParent->designate_label(pCurrentChild); 2879 } 2880 if (sInternalChild.startsWith("vbox") || sInternalChild.startsWith("messagedialog-vbox")) 2881 { 2882 if (Dialog *pBoxParent = dynamic_cast<Dialog*>(pParent)) 2883 pBoxParent->set_content_area(static_cast<VclBox*>(pCurrentChild)); // FIXME-VCLPTR 2884 } 2885 else if (sInternalChild.startsWith("action_area") || sInternalChild.startsWith("messagedialog-action_area")) 2886 { 2887 vcl::Window *pContentArea = pCurrentChild->GetParent(); 2888 if (Dialog *pBoxParent = dynamic_cast<Dialog*>(pContentArea ? pContentArea->GetParent() : nullptr)) 2889 { 2890 pBoxParent->set_action_area(static_cast<VclButtonBox*>(pCurrentChild)); // FIXME-VCLPTR 2891 } 2892 } 2893 2894 bool bIsButtonBox = dynamic_cast<VclButtonBox*>(pCurrentChild) != nullptr; 2895 2896 //To-Do make reorder a virtual in Window, move this foo 2897 //there and see above 2898 std::vector<vcl::Window*> aChilds; 2899 for (vcl::Window* pChild = pCurrentChild->GetWindow(GetWindowType::FirstChild); pChild; 2900 pChild = pChild->GetWindow(GetWindowType::Next)) 2901 { 2902 if (bIsButtonBox) 2903 { 2904 if (PushButton* pPushButton = dynamic_cast<PushButton*>(pChild)) 2905 pPushButton->setAction(true); 2906 } 2907 2908 aChilds.push_back(pChild); 2909 } 2910 2911 //sort child order within parent so that tabbing 2912 //between controls goes in a visually sensible sequence 2913 std::stable_sort(aChilds.begin(), aChilds.end(), sortIntoBestTabTraversalOrder(this)); 2914 BuilderUtils::reorderWithinParent(aChilds, bIsButtonBox); 2915 } 2916 } 2917 } 2918 else if (name == "packing") 2919 { 2920 handlePacking(pCurrentChild, pParent, reader); 2921 } 2922 else if (name == "interface") 2923 { 2924 while (reader.nextAttribute(&nsId, &name)) 2925 { 2926 if (name == "domain") 2927 { 2928 name = reader.getAttributeValue(false); 2929 sType = OString(name.begin, name.length); 2930 m_pParserState->m_aResLocale = Translate::Create(sType.getStr()); 2931 } 2932 } 2933 ++nLevel; 2934 } 2935 else 2936 ++nLevel; 2937 } 2938 2939 if (res == xmlreader::XmlReader::Result::End) 2940 --nLevel; 2941 2942 if (!nLevel) 2943 break; 2944 2945 if (res == xmlreader::XmlReader::Result::Done) 2946 break; 2947 } 2948 } 2949 2950 void VclBuilder::collectPangoAttribute(xmlreader::XmlReader &reader, stringmap &rMap) 2951 { 2952 xmlreader::Span span; 2953 int nsId; 2954 2955 OString sProperty; 2956 OString sValue; 2957 2958 while (reader.nextAttribute(&nsId, &span)) 2959 { 2960 if (span == "name") 2961 { 2962 span = reader.getAttributeValue(false); 2963 sProperty = OString(span.begin, span.length); 2964 } 2965 else if (span == "value") 2966 { 2967 span = reader.getAttributeValue(false); 2968 sValue = OString(span.begin, span.length); 2969 } 2970 } 2971 2972 if (!sProperty.isEmpty()) 2973 rMap[sProperty] = OUString::fromUtf8(sValue); 2974 } 2975 2976 void VclBuilder::collectAtkRelationAttribute(xmlreader::XmlReader &reader, stringmap &rMap) 2977 { 2978 xmlreader::Span span; 2979 int nsId; 2980 2981 OString sProperty; 2982 OString sValue; 2983 2984 while (reader.nextAttribute(&nsId, &span)) 2985 { 2986 if (span == "type") 2987 { 2988 span = reader.getAttributeValue(false); 2989 sProperty = OString(span.begin, span.length); 2990 } 2991 else if (span == "target") 2992 { 2993 span = reader.getAttributeValue(false); 2994 sValue = OString(span.begin, span.length); 2995 sal_Int32 nDelim = sValue.indexOf(':'); 2996 if (nDelim != -1) 2997 sValue = sValue.copy(0, nDelim); 2998 } 2999 } 3000 3001 if (!sProperty.isEmpty()) 3002 rMap[sProperty] = OUString::fromUtf8(sValue); 3003 } 3004 3005 void VclBuilder::collectAtkRoleAttribute(xmlreader::XmlReader &reader, stringmap &rMap) 3006 { 3007 xmlreader::Span span; 3008 int nsId; 3009 3010 OString sProperty; 3011 3012 while (reader.nextAttribute(&nsId, &span)) 3013 { 3014 if (span == "type") 3015 { 3016 span = reader.getAttributeValue(false); 3017 sProperty = OString(span.begin, span.length); 3018 } 3019 } 3020 3021 if (!sProperty.isEmpty()) 3022 rMap["role"] = OUString::fromUtf8(sProperty); 3023 } 3024 3025 void VclBuilder::handleRow(xmlreader::XmlReader &reader, const OString &rID) 3026 { 3027 int nLevel = 1; 3028 3029 ListStore::row aRow; 3030 3031 while(true) 3032 { 3033 xmlreader::Span name; 3034 int nsId; 3035 3036 xmlreader::XmlReader::Result res = reader.nextItem( 3037 xmlreader::XmlReader::Text::NONE, &name, &nsId); 3038 3039 if (res == xmlreader::XmlReader::Result::Done) 3040 break; 3041 3042 if (res == xmlreader::XmlReader::Result::Begin) 3043 { 3044 ++nLevel; 3045 if (name == "col") 3046 { 3047 bool bTranslated = false; 3048 sal_uInt32 nId = 0; 3049 OString sContext; 3050 3051 while (reader.nextAttribute(&nsId, &name)) 3052 { 3053 if (name == "id") 3054 { 3055 name = reader.getAttributeValue(false); 3056 nId = OString(name.begin, name.length).toInt32(); 3057 } 3058 else if (nId == 0 && name == "translatable" && reader.getAttributeValue(false) == "yes") 3059 { 3060 bTranslated = true; 3061 } 3062 else if (name == "context") 3063 { 3064 name = reader.getAttributeValue(false); 3065 sContext = OString(name.begin, name.length); 3066 } 3067 } 3068 3069 (void)reader.nextItem( 3070 xmlreader::XmlReader::Text::Raw, &name, &nsId); 3071 3072 OString sValue(name.begin, name.length); 3073 OUString sFinalValue; 3074 if (bTranslated) 3075 { 3076 if (!sContext.isEmpty()) 3077 sValue = sContext + "\004" + sValue; 3078 sFinalValue = Translate::get(sValue.getStr(), m_pParserState->m_aResLocale); 3079 } 3080 else 3081 sFinalValue = OUString::fromUtf8(sValue); 3082 3083 3084 if (aRow.size() < nId+1) 3085 aRow.resize(nId+1); 3086 aRow[nId] = sFinalValue; 3087 } 3088 } 3089 3090 if (res == xmlreader::XmlReader::Result::End) 3091 { 3092 --nLevel; 3093 } 3094 3095 if (!nLevel) 3096 break; 3097 } 3098 3099 m_pParserState->m_aModels[rID].m_aEntries.push_back(aRow); 3100 } 3101 3102 void VclBuilder::handleListStore(xmlreader::XmlReader &reader, const OString &rID, const OString &rClass) 3103 { 3104 int nLevel = 1; 3105 3106 while(true) 3107 { 3108 xmlreader::Span name; 3109 int nsId; 3110 3111 xmlreader::XmlReader::Result res = reader.nextItem( 3112 xmlreader::XmlReader::Text::NONE, &name, &nsId); 3113 3114 if (res == xmlreader::XmlReader::Result::Done) 3115 break; 3116 3117 if (res == xmlreader::XmlReader::Result::Begin) 3118 { 3119 if (name == "row") 3120 { 3121 bool bNotTreeStore = rClass != "GtkTreeStore"; 3122 if (bNotTreeStore) 3123 handleRow(reader, rID); 3124 assert(bNotTreeStore && "gtk, as the time of writing, doesn't support data in GtkTreeStore serialization"); 3125 } 3126 else 3127 ++nLevel; 3128 } 3129 3130 if (res == xmlreader::XmlReader::Result::End) 3131 { 3132 --nLevel; 3133 } 3134 3135 if (!nLevel) 3136 break; 3137 } 3138 } 3139 3140 void VclBuilder::handleAtkObject(xmlreader::XmlReader &reader, vcl::Window *pWindow) 3141 { 3142 assert(pWindow); 3143 3144 int nLevel = 1; 3145 3146 stringmap aProperties; 3147 3148 while(true) 3149 { 3150 xmlreader::Span name; 3151 int nsId; 3152 3153 xmlreader::XmlReader::Result res = reader.nextItem( 3154 xmlreader::XmlReader::Text::NONE, &name, &nsId); 3155 3156 if (res == xmlreader::XmlReader::Result::Done) 3157 break; 3158 3159 if (res == xmlreader::XmlReader::Result::Begin) 3160 { 3161 ++nLevel; 3162 if (name == "property") 3163 collectProperty(reader, aProperties); 3164 } 3165 3166 if (res == xmlreader::XmlReader::Result::End) 3167 { 3168 --nLevel; 3169 } 3170 3171 if (!nLevel) 3172 break; 3173 } 3174 3175 for (auto const& prop : aProperties) 3176 { 3177 const OString &rKey = prop.first; 3178 const OUString &rValue = prop.second; 3179 3180 if (pWindow && rKey.match("AtkObject::")) 3181 pWindow->set_property(rKey.copy(RTL_CONSTASCII_LENGTH("AtkObject::")), rValue); 3182 else 3183 SAL_WARN("vcl.builder", "unhandled atk prop: " << rKey); 3184 } 3185 } 3186 3187 std::vector<ComboBoxTextItem> VclBuilder::handleItems(xmlreader::XmlReader &reader) const 3188 { 3189 int nLevel = 1; 3190 3191 std::vector<ComboBoxTextItem> aItems; 3192 3193 while(true) 3194 { 3195 xmlreader::Span name; 3196 int nsId; 3197 3198 xmlreader::XmlReader::Result res = reader.nextItem( 3199 xmlreader::XmlReader::Text::NONE, &name, &nsId); 3200 3201 if (res == xmlreader::XmlReader::Result::Done) 3202 break; 3203 3204 if (res == xmlreader::XmlReader::Result::Begin) 3205 { 3206 ++nLevel; 3207 if (name == "item") 3208 { 3209 bool bTranslated = false; 3210 OString sContext, sId; 3211 3212 while (reader.nextAttribute(&nsId, &name)) 3213 { 3214 if (name == "translatable" && reader.getAttributeValue(false) == "yes") 3215 { 3216 bTranslated = true; 3217 } 3218 else if (name == "context") 3219 { 3220 name = reader.getAttributeValue(false); 3221 sContext = OString(name.begin, name.length); 3222 } 3223 else if (name == "id") 3224 { 3225 name = reader.getAttributeValue(false); 3226 sId = OString(name.begin, name.length); 3227 } 3228 } 3229 3230 (void)reader.nextItem( 3231 xmlreader::XmlReader::Text::Raw, &name, &nsId); 3232 3233 OString sValue(name.begin, name.length); 3234 OUString sFinalValue; 3235 if (bTranslated) 3236 { 3237 if (!sContext.isEmpty()) 3238 sValue = sContext + "\004" + sValue; 3239 sFinalValue = Translate::get(sValue.getStr(), m_pParserState->m_aResLocale); 3240 } 3241 else 3242 sFinalValue = OUString::fromUtf8(sValue); 3243 3244 if (m_pStringReplace) 3245 sFinalValue = (*m_pStringReplace)(sFinalValue); 3246 3247 aItems.emplace_back(sFinalValue, sId); 3248 } 3249 } 3250 3251 if (res == xmlreader::XmlReader::Result::End) 3252 { 3253 --nLevel; 3254 } 3255 3256 if (!nLevel) 3257 break; 3258 } 3259 3260 return aItems; 3261 } 3262 3263 VclPtr<Menu> VclBuilder::handleMenu(xmlreader::XmlReader &reader, const OString &rID, bool bMenuBar) 3264 { 3265 VclPtr<Menu> pCurrentMenu; 3266 if (bMenuBar) 3267 pCurrentMenu = VclPtr<MenuBar>::Create(); 3268 else 3269 pCurrentMenu = VclPtr<PopupMenu>::Create(); 3270 3271 int nLevel = 1; 3272 3273 stringmap aProperties; 3274 3275 while(true) 3276 { 3277 xmlreader::Span name; 3278 int nsId; 3279 3280 xmlreader::XmlReader::Result res = reader.nextItem( 3281 xmlreader::XmlReader::Text::NONE, &name, &nsId); 3282 3283 if (res == xmlreader::XmlReader::Result::Done) 3284 break; 3285 3286 if (res == xmlreader::XmlReader::Result::Begin) 3287 { 3288 if (name == "child") 3289 { 3290 handleMenuChild(pCurrentMenu, reader); 3291 } 3292 else 3293 { 3294 ++nLevel; 3295 if (name == "property") 3296 collectProperty(reader, aProperties); 3297 } 3298 } 3299 3300 if (res == xmlreader::XmlReader::Result::End) 3301 { 3302 --nLevel; 3303 } 3304 3305 if (!nLevel) 3306 break; 3307 } 3308 3309 m_aMenus.emplace_back(rID, pCurrentMenu); 3310 3311 return pCurrentMenu; 3312 } 3313 3314 void VclBuilder::handleMenuChild(Menu *pParent, xmlreader::XmlReader &reader) 3315 { 3316 xmlreader::Span name; 3317 int nsId; 3318 3319 int nLevel = 1; 3320 while(true) 3321 { 3322 xmlreader::XmlReader::Result res = reader.nextItem( 3323 xmlreader::XmlReader::Text::NONE, &name, &nsId); 3324 3325 if (res == xmlreader::XmlReader::Result::Begin) 3326 { 3327 if (name == "object" || name == "placeholder") 3328 { 3329 handleMenuObject(pParent, reader); 3330 } 3331 else 3332 ++nLevel; 3333 } 3334 3335 if (res == xmlreader::XmlReader::Result::End) 3336 --nLevel; 3337 3338 if (!nLevel) 3339 break; 3340 3341 if (res == xmlreader::XmlReader::Result::Done) 3342 break; 3343 } 3344 } 3345 3346 void VclBuilder::handleMenuObject(Menu *pParent, xmlreader::XmlReader &reader) 3347 { 3348 OString sClass; 3349 OString sID; 3350 OUString sCustomProperty; 3351 PopupMenu *pSubMenu = nullptr; 3352 3353 xmlreader::Span name; 3354 int nsId; 3355 3356 while (reader.nextAttribute(&nsId, &name)) 3357 { 3358 if (name == "class") 3359 { 3360 name = reader.getAttributeValue(false); 3361 sClass = OString(name.begin, name.length); 3362 } 3363 else if (name == "id") 3364 { 3365 name = reader.getAttributeValue(false); 3366 sID = OString(name.begin, name.length); 3367 sal_Int32 nDelim = sID.indexOf(':'); 3368 if (nDelim != -1) 3369 { 3370 sCustomProperty = OUString::fromUtf8(sID.copy(nDelim+1)); 3371 sID = sID.copy(0, nDelim); 3372 } 3373 } 3374 } 3375 3376 int nLevel = 1; 3377 3378 stringmap aProperties; 3379 accelmap aAccelerators; 3380 3381 if (!sCustomProperty.isEmpty()) 3382 aProperties[OString("customproperty")] = sCustomProperty; 3383 3384 while(true) 3385 { 3386 xmlreader::XmlReader::Result res = reader.nextItem( 3387 xmlreader::XmlReader::Text::NONE, &name, &nsId); 3388 3389 if (res == xmlreader::XmlReader::Result::Done) 3390 break; 3391 3392 if (res == xmlreader::XmlReader::Result::Begin) 3393 { 3394 if (name == "child") 3395 { 3396 size_t nChildMenuIdx = m_aMenus.size(); 3397 handleChild(nullptr, reader); 3398 assert(m_aMenus.size() > nChildMenuIdx && "menu not inserted"); 3399 pSubMenu = dynamic_cast<PopupMenu*>(m_aMenus[nChildMenuIdx].m_pMenu.get()); 3400 } 3401 else 3402 { 3403 ++nLevel; 3404 if (name == "property") 3405 collectProperty(reader, aProperties); 3406 else if (name == "accelerator") 3407 collectAccelerator(reader, aAccelerators); 3408 } 3409 } 3410 3411 if (res == xmlreader::XmlReader::Result::End) 3412 { 3413 --nLevel; 3414 } 3415 3416 if (!nLevel) 3417 break; 3418 } 3419 3420 insertMenuObject(pParent, pSubMenu, sClass, sID, aProperties, aAccelerators); 3421 } 3422 3423 void VclBuilder::handleSizeGroup(xmlreader::XmlReader &reader) 3424 { 3425 m_pParserState->m_aSizeGroups.emplace_back(); 3426 SizeGroup &rSizeGroup = m_pParserState->m_aSizeGroups.back(); 3427 3428 int nLevel = 1; 3429 3430 while(true) 3431 { 3432 xmlreader::Span name; 3433 int nsId; 3434 3435 xmlreader::XmlReader::Result res = reader.nextItem( 3436 xmlreader::XmlReader::Text::NONE, &name, &nsId); 3437 3438 if (res == xmlreader::XmlReader::Result::Done) 3439 break; 3440 3441 if (res == xmlreader::XmlReader::Result::Begin) 3442 { 3443 ++nLevel; 3444 if (name == "widget") 3445 { 3446 while (reader.nextAttribute(&nsId, &name)) 3447 { 3448 if (name == "name") 3449 { 3450 name = reader.getAttributeValue(false); 3451 OString sWidget(name.begin, name.length); 3452 sal_Int32 nDelim = sWidget.indexOf(':'); 3453 if (nDelim != -1) 3454 sWidget = sWidget.copy(0, nDelim); 3455 rSizeGroup.m_aWidgets.push_back(sWidget); 3456 } 3457 } 3458 } 3459 else 3460 { 3461 if (name == "property") 3462 collectProperty(reader, rSizeGroup.m_aProperties); 3463 } 3464 } 3465 3466 if (res == xmlreader::XmlReader::Result::End) 3467 { 3468 --nLevel; 3469 } 3470 3471 if (!nLevel) 3472 break; 3473 } 3474 } 3475 3476 namespace 3477 { 3478 vcl::KeyCode makeKeyCode(const std::pair<OString,OString> &rKey) 3479 { 3480 bool bShift = rKey.second.indexOf("GDK_SHIFT_MASK") != -1; 3481 bool bMod1 = rKey.second.indexOf("GDK_CONTROL_MASK") != -1; 3482 bool bMod2 = rKey.second.indexOf("GDK_MOD1_MASK") != -1; 3483 bool bMod3 = rKey.second.indexOf("GDK_MOD2_MASK") != -1; 3484 3485 if (rKey.first == "Insert") 3486 return vcl::KeyCode(KEY_INSERT, bShift, bMod1, bMod2, bMod3); 3487 else if (rKey.first == "Delete") 3488 return vcl::KeyCode(KEY_DELETE, bShift, bMod1, bMod2, bMod3); 3489 else if (rKey.first == "Return") 3490 return vcl::KeyCode(KEY_RETURN, bShift, bMod1, bMod2, bMod3); 3491 else if (rKey.first == "Up") 3492 return vcl::KeyCode(KEY_UP, bShift, bMod1, bMod2, bMod3); 3493 else if (rKey.first == "Down") 3494 return vcl::KeyCode(KEY_DOWN, bShift, bMod1, bMod2, bMod3); 3495 else if (rKey.first == "Left") 3496 return vcl::KeyCode(KEY_LEFT, bShift, bMod1, bMod2, bMod3); 3497 else if (rKey.first == "Right") 3498 return vcl::KeyCode(KEY_RIGHT, bShift, bMod1, bMod2, bMod3); 3499 else if (rKey.first == "asterisk") 3500 return vcl::KeyCode(KEY_MULTIPLY, bShift, bMod1, bMod2, bMod3); 3501 3502 assert (rKey.first.getLength() == 1); 3503 char cChar = rKey.first.toChar(); 3504 3505 if (cChar >= 'a' && cChar <= 'z') 3506 return vcl::KeyCode(KEY_A + (cChar - 'a'), bShift, bMod1, bMod2, bMod3); 3507 else if (cChar >= 'A' && cChar <= 'Z') 3508 return vcl::KeyCode(KEY_A + (cChar - 'A'), bShift, bMod1, bMod2, bMod3); 3509 else if (cChar >= '0' && cChar <= '9') 3510 return vcl::KeyCode(KEY_0 + (cChar - 'A'), bShift, bMod1, bMod2, bMod3); 3511 3512 return vcl::KeyCode(cChar, bShift, bMod1, bMod2, bMod3); 3513 } 3514 } 3515 3516 void VclBuilder::insertMenuObject(Menu *pParent, PopupMenu *pSubMenu, const OString &rClass, const OString &rID, 3517 stringmap &rProps, accelmap &rAccels) 3518 { 3519 sal_uInt16 nOldCount = pParent->GetItemCount(); 3520 sal_uInt16 nNewId = ++m_pParserState->m_nLastMenuItemId; 3521 3522 if(rClass == "NotebookBarAddonsMenuMergePoint") 3523 { 3524 NotebookBarAddonsMerger::MergeNotebookBarMenuAddons(pParent, nNewId, rID, *m_pNotebookBarAddonsItem); 3525 m_pParserState->m_nLastMenuItemId = pParent->GetItemCount(); 3526 } 3527 else if (rClass == "GtkMenuItem") 3528 { 3529 OUString sLabel(BuilderUtils::convertMnemonicMarkup(extractLabel(rProps))); 3530 OUString aCommand(extractActionName(rProps)); 3531 pParent->InsertItem(nNewId, sLabel, MenuItemBits::NONE , rID); 3532 pParent->SetItemCommand(nNewId, aCommand); 3533 if (pSubMenu) 3534 pParent->SetPopupMenu(nNewId, pSubMenu); 3535 } 3536 else if (rClass == "GtkCheckMenuItem") 3537 { 3538 OUString sLabel(BuilderUtils::convertMnemonicMarkup(extractLabel(rProps))); 3539 OUString aCommand(extractActionName(rProps)); 3540 pParent->InsertItem(nNewId, sLabel, MenuItemBits::CHECKABLE, rID); 3541 pParent->SetItemCommand(nNewId, aCommand); 3542 } 3543 else if (rClass == "GtkRadioMenuItem") 3544 { 3545 OUString sLabel(BuilderUtils::convertMnemonicMarkup(extractLabel(rProps))); 3546 OUString aCommand(extractActionName(rProps)); 3547 pParent->InsertItem(nNewId, sLabel, MenuItemBits::AUTOCHECK | MenuItemBits::RADIOCHECK, rID); 3548 pParent->SetItemCommand(nNewId, aCommand); 3549 } 3550 else if (rClass == "GtkSeparatorMenuItem") 3551 { 3552 pParent->InsertSeparator(rID); 3553 } 3554 3555 SAL_WARN_IF(nOldCount == pParent->GetItemCount(), "vcl.builder", "probably need to implement " << rClass); 3556 3557 if (nOldCount != pParent->GetItemCount()) 3558 { 3559 pParent->SetHelpId(nNewId, m_sHelpRoot + rID); 3560 if (!extractVisible(rProps)) 3561 pParent->HideItem(nNewId); 3562 3563 for (auto const& prop : rProps) 3564 { 3565 const OString &rKey = prop.first; 3566 const OUString &rValue = prop.second; 3567 3568 if (rKey == "tooltip-markup") 3569 pParent->SetTipHelpText(nNewId, rValue); 3570 else if (rKey == "tooltip-text") 3571 pParent->SetTipHelpText(nNewId, rValue); 3572 else 3573 SAL_INFO("vcl.builder", "unhandled property: " << rKey); 3574 } 3575 3576 for (auto const& accel : rAccels) 3577 { 3578 const OString &rSignal = accel.first; 3579 const auto &rValue = accel.second; 3580 3581 if (rSignal == "activate") 3582 pParent->SetAccelKey(nNewId, makeKeyCode(rValue)); 3583 else 3584 SAL_INFO("vcl.builder", "unhandled accelerator for: " << rSignal); 3585 } 3586 } 3587 3588 rProps.clear(); 3589 } 3590 3591 /// Insert items to a ComboBox or a ListBox. 3592 /// They have no common ancestor that would have 'InsertEntry()', so use a template. 3593 template<typename T> static bool insertItems(vcl::Window *pWindow, VclBuilder::stringmap &rMap, 3594 std::vector<std::unique_ptr<OUString>>& rUserData, 3595 const std::vector<ComboBoxTextItem> &rItems) 3596 { 3597 T *pContainer = dynamic_cast<T*>(pWindow); 3598 if (!pContainer) 3599 return false; 3600 3601 sal_uInt16 nActiveId = extractActive(rMap); 3602 for (auto const& item : rItems) 3603 { 3604 sal_Int32 nPos = pContainer->InsertEntry(item.m_sItem); 3605 if (!item.m_sId.isEmpty()) 3606 { 3607 rUserData.emplace_back(std::make_unique<OUString>(OUString::fromUtf8(item.m_sId))); 3608 pContainer->SetEntryData(nPos, rUserData.back().get()); 3609 } 3610 } 3611 if (nActiveId < rItems.size()) 3612 pContainer->SelectEntryPos(nActiveId); 3613 3614 return true; 3615 } 3616 3617 VclPtr<vcl::Window> VclBuilder::handleObject(vcl::Window *pParent, xmlreader::XmlReader &reader) 3618 { 3619 OString sClass; 3620 OString sID; 3621 OUString sCustomProperty; 3622 3623 xmlreader::Span name; 3624 int nsId; 3625 3626 while (reader.nextAttribute(&nsId, &name)) 3627 { 3628 if (name == "class") 3629 { 3630 name = reader.getAttributeValue(false); 3631 sClass = OString(name.begin, name.length); 3632 } 3633 else if (name == "id") 3634 { 3635 name = reader.getAttributeValue(false); 3636 sID = OString(name.begin, name.length); 3637 if (m_bLegacy) 3638 { 3639 sal_Int32 nDelim = sID.indexOf(':'); 3640 if (nDelim != -1) 3641 { 3642 sCustomProperty = OUString::fromUtf8(sID.copy(nDelim+1)); 3643 sID = sID.copy(0, nDelim); 3644 } 3645 } 3646 } 3647 } 3648 3649 if (sClass == "GtkListStore" || sClass == "GtkTreeStore") 3650 { 3651 handleListStore(reader, sID, sClass); 3652 return nullptr; 3653 } 3654 else if (sClass == "GtkMenu") 3655 { 3656 handleMenu(reader, sID, false); 3657 return nullptr; 3658 } 3659 else if (sClass == "GtkMenuBar") 3660 { 3661 VclPtr<Menu> xMenu = handleMenu(reader, sID, true); 3662 if (SystemWindow* pTopLevel = pParent ? pParent->GetSystemWindow() : nullptr) 3663 pTopLevel->SetMenuBar(dynamic_cast<MenuBar*>(xMenu.get())); 3664 return nullptr; 3665 } 3666 else if (sClass == "GtkSizeGroup") 3667 { 3668 handleSizeGroup(reader); 3669 return nullptr; 3670 } 3671 else if (sClass == "AtkObject") 3672 { 3673 handleAtkObject(reader, pParent); 3674 return nullptr; 3675 } 3676 3677 int nLevel = 1; 3678 3679 stringmap aProperties, aPangoAttributes; 3680 stringmap aAtkAttributes; 3681 std::vector<ComboBoxTextItem> aItems; 3682 3683 if (!sCustomProperty.isEmpty()) 3684 aProperties[OString("customproperty")] = sCustomProperty; 3685 3686 VclPtr<vcl::Window> pCurrentChild; 3687 while(true) 3688 { 3689 xmlreader::XmlReader::Result res = reader.nextItem( 3690 xmlreader::XmlReader::Text::NONE, &name, &nsId); 3691 3692 if (res == xmlreader::XmlReader::Result::Done) 3693 break; 3694 3695 if (res == xmlreader::XmlReader::Result::Begin) 3696 { 3697 if (name == "child") 3698 { 3699 if (!pCurrentChild) 3700 { 3701 pCurrentChild = insertObject(pParent, sClass, sID, 3702 aProperties, aPangoAttributes, aAtkAttributes); 3703 } 3704 handleChild(pCurrentChild, reader); 3705 } 3706 else if (name == "items") 3707 aItems = handleItems(reader); 3708 else if (name == "style") 3709 { 3710 int nPriority = 0; 3711 std::vector<vcl::EnumContext::Context> aContext = handleStyle(reader, nPriority); 3712 if (nPriority != 0) 3713 { 3714 vcl::IPrioritable* pPrioritable = dynamic_cast<vcl::IPrioritable*>(pCurrentChild.get()); 3715 SAL_WARN_IF(!pPrioritable, "vcl", "priority set for not supported item"); 3716 if (pPrioritable) 3717 pPrioritable->SetPriority(nPriority); 3718 } 3719 if (!aContext.empty()) 3720 { 3721 vcl::IContext* pContextControl = dynamic_cast<vcl::IContext*>(pCurrentChild.get()); 3722 SAL_WARN_IF(!pContextControl, "vcl", "context set for not supported item"); 3723 if (pContextControl) 3724 pContextControl->SetContext(aContext); 3725 } 3726 } 3727 else 3728 { 3729 ++nLevel; 3730 if (name == "property") 3731 collectProperty(reader, aProperties); 3732 else if (name == "attribute") 3733 collectPangoAttribute(reader, aPangoAttributes); 3734 else if (name == "relation") 3735 collectAtkRelationAttribute(reader, aAtkAttributes); 3736 else if (name == "role") 3737 collectAtkRoleAttribute(reader, aAtkAttributes); 3738 else if (name == "action-widget") 3739 handleActionWidget(reader); 3740 } 3741 } 3742 3743 if (res == xmlreader::XmlReader::Result::End) 3744 { 3745 --nLevel; 3746 } 3747 3748 if (!nLevel) 3749 break; 3750 } 3751 3752 if (sClass == "GtkAdjustment") 3753 { 3754 m_pParserState->m_aAdjustments[sID] = aProperties; 3755 return nullptr; 3756 } 3757 else if (sClass == "GtkTextBuffer") 3758 { 3759 m_pParserState->m_aTextBuffers[sID] = aProperties; 3760 return nullptr; 3761 } 3762 3763 if (!pCurrentChild) 3764 { 3765 pCurrentChild = insertObject(pParent, sClass, sID, aProperties, 3766 aPangoAttributes, aAtkAttributes); 3767 } 3768 3769 if (!aItems.empty()) 3770 { 3771 // try to fill-in the items 3772 if (!insertItems<ComboBox>(pCurrentChild, aProperties, m_aUserData, aItems)) 3773 insertItems<ListBox>(pCurrentChild, aProperties, m_aUserData, aItems); 3774 } 3775 3776 return pCurrentChild; 3777 } 3778 3779 void VclBuilder::handlePacking(vcl::Window *pCurrent, vcl::Window *pParent, xmlreader::XmlReader &reader) 3780 { 3781 xmlreader::Span name; 3782 int nsId; 3783 3784 int nLevel = 1; 3785 3786 while(true) 3787 { 3788 xmlreader::XmlReader::Result res = reader.nextItem( 3789 xmlreader::XmlReader::Text::NONE, &name, &nsId); 3790 3791 if (res == xmlreader::XmlReader::Result::Done) 3792 break; 3793 3794 if (res == xmlreader::XmlReader::Result::Begin) 3795 { 3796 ++nLevel; 3797 if (name == "property") 3798 applyPackingProperty(pCurrent, pParent, reader); 3799 } 3800 3801 if (res == xmlreader::XmlReader::Result::End) 3802 { 3803 --nLevel; 3804 } 3805 3806 if (!nLevel) 3807 break; 3808 } 3809 } 3810 3811 void VclBuilder::applyPackingProperty(vcl::Window *pCurrent, 3812 vcl::Window *pParent, 3813 xmlreader::XmlReader &reader) 3814 { 3815 if (!pCurrent) 3816 return; 3817 3818 //ToolBoxItems are not true widgets just elements 3819 //of the ToolBox itself 3820 ToolBox *pToolBoxParent = nullptr; 3821 if (pCurrent == pParent) 3822 pToolBoxParent = dynamic_cast<ToolBox*>(pParent); 3823 3824 xmlreader::Span name; 3825 int nsId; 3826 3827 if (pCurrent->GetType() == WindowType::SCROLLWINDOW) 3828 { 3829 auto aFind = m_pParserState->m_aRedundantParentWidgets.find(VclPtr<vcl::Window>(pCurrent)); 3830 if (aFind != m_pParserState->m_aRedundantParentWidgets.end()) 3831 { 3832 pCurrent = aFind->second; 3833 assert(pCurrent); 3834 } 3835 } 3836 3837 while (reader.nextAttribute(&nsId, &name)) 3838 { 3839 if (name == "name") 3840 { 3841 name = reader.getAttributeValue(false); 3842 OString sKey(name.begin, name.length); 3843 sKey = sKey.replace('_', '-'); 3844 (void)reader.nextItem( 3845 xmlreader::XmlReader::Text::Raw, &name, &nsId); 3846 OString sValue(name.begin, name.length); 3847 3848 if (sKey == "expand" || sKey == "resize") 3849 { 3850 bool bTrue = (!sValue.isEmpty() && (sValue[0] == 't' || sValue[0] == 'T' || sValue[0] == '1')); 3851 if (pToolBoxParent) 3852 pToolBoxParent->SetItemExpand(m_pParserState->m_nLastToolbarId, bTrue); 3853 else 3854 pCurrent->set_expand(bTrue); 3855 continue; 3856 } 3857 3858 if (pToolBoxParent) 3859 continue; 3860 3861 if (sKey == "fill") 3862 { 3863 bool bTrue = (!sValue.isEmpty() && (sValue[0] == 't' || sValue[0] == 'T' || sValue[0] == '1')); 3864 pCurrent->set_fill(bTrue); 3865 } 3866 else if (sKey == "pack-type") 3867 { 3868 VclPackType ePackType = (!sValue.isEmpty() && (sValue[0] == 'e' || sValue[0] == 'E')) ? VclPackType::End : VclPackType::Start; 3869 pCurrent->set_pack_type(ePackType); 3870 } 3871 else if (sKey == "left-attach") 3872 { 3873 pCurrent->set_grid_left_attach(sValue.toInt32()); 3874 } 3875 else if (sKey == "top-attach") 3876 { 3877 pCurrent->set_grid_top_attach(sValue.toInt32()); 3878 } 3879 else if (sKey == "width") 3880 { 3881 pCurrent->set_grid_width(sValue.toInt32()); 3882 } 3883 else if (sKey == "height") 3884 { 3885 pCurrent->set_grid_height(sValue.toInt32()); 3886 } 3887 else if (sKey == "padding") 3888 { 3889 pCurrent->set_padding(sValue.toInt32()); 3890 } 3891 else if (sKey == "position") 3892 { 3893 set_window_packing_position(pCurrent, sValue.toInt32()); 3894 } 3895 else if (sKey == "secondary") 3896 { 3897 pCurrent->set_secondary(toBool(sValue)); 3898 } 3899 else if (sKey == "non-homogeneous") 3900 { 3901 pCurrent->set_non_homogeneous(toBool(sValue)); 3902 } 3903 else if (sKey == "homogeneous") 3904 { 3905 pCurrent->set_non_homogeneous(!toBool(sValue)); 3906 } 3907 else 3908 { 3909 SAL_WARN("vcl.builder", "unknown packing: " << sKey); 3910 } 3911 } 3912 } 3913 } 3914 3915 std::vector<vcl::EnumContext::Context> VclBuilder::handleStyle(xmlreader::XmlReader &reader, int &nPriority) 3916 { 3917 std::vector<vcl::EnumContext::Context> aContext; 3918 3919 xmlreader::Span name; 3920 int nsId; 3921 3922 int nLevel = 1; 3923 3924 while(true) 3925 { 3926 xmlreader::XmlReader::Result res = reader.nextItem( 3927 xmlreader::XmlReader::Text::NONE, &name, &nsId); 3928 3929 if (res == xmlreader::XmlReader::Result::Done) 3930 break; 3931 3932 if (res == xmlreader::XmlReader::Result::Begin) 3933 { 3934 ++nLevel; 3935 if (name == "class") 3936 { 3937 OString classStyle = getStyleClass(reader); 3938 3939 if (classStyle.startsWith("context-")) 3940 { 3941 OString sContext = classStyle.copy(classStyle.indexOf('-') + 1); 3942 OUString sContext2(sContext.getStr(), sContext.getLength(), RTL_TEXTENCODING_UTF8); 3943 aContext.push_back(vcl::EnumContext::GetContextEnum(sContext2)); 3944 } 3945 else if (classStyle.startsWith("priority-")) 3946 { 3947 OString aPriority = classStyle.copy(classStyle.indexOf('-') + 1); 3948 OUString aPriority2(aPriority.getStr(), aPriority.getLength(), RTL_TEXTENCODING_UTF8); 3949 nPriority = aPriority2.toInt32(); 3950 } 3951 else 3952 { 3953 SAL_WARN("vcl.builder", "unknown class: " << classStyle); 3954 } 3955 } 3956 } 3957 3958 if (res == xmlreader::XmlReader::Result::End) 3959 { 3960 --nLevel; 3961 } 3962 3963 if (!nLevel) 3964 break; 3965 } 3966 3967 return aContext; 3968 } 3969 3970 OString VclBuilder::getStyleClass(xmlreader::XmlReader &reader) 3971 { 3972 xmlreader::Span name; 3973 int nsId; 3974 OString aRet; 3975 3976 while (reader.nextAttribute(&nsId, &name)) 3977 { 3978 if (name == "name") 3979 { 3980 name = reader.getAttributeValue(false); 3981 aRet = OString (name.begin, name.length); 3982 } 3983 } 3984 3985 return aRet; 3986 } 3987 3988 void VclBuilder::collectProperty(xmlreader::XmlReader &reader, stringmap &rMap) const 3989 { 3990 xmlreader::Span name; 3991 int nsId; 3992 3993 OString sProperty, sContext; 3994 3995 bool bTranslated = false; 3996 3997 while (reader.nextAttribute(&nsId, &name)) 3998 { 3999 if (name == "name") 4000 { 4001 name = reader.getAttributeValue(false); 4002 sProperty = OString(name.begin, name.length); 4003 } 4004 else if (name == "context") 4005 { 4006 name = reader.getAttributeValue(false); 4007 sContext = OString(name.begin, name.length); 4008 } 4009 else if (name == "translatable" && reader.getAttributeValue(false) == "yes") 4010 { 4011 bTranslated = true; 4012 } 4013 } 4014 4015 (void)reader.nextItem(xmlreader::XmlReader::Text::Raw, &name, &nsId); 4016 OString sValue(name.begin, name.length); 4017 OUString sFinalValue; 4018 if (bTranslated) 4019 { 4020 if (!sContext.isEmpty()) 4021 sValue = sContext + "\004" + sValue; 4022 sFinalValue = Translate::get(sValue.getStr(), m_pParserState->m_aResLocale); 4023 } 4024 else 4025 sFinalValue = OUString::fromUtf8(sValue); 4026 4027 if (!sProperty.isEmpty()) 4028 { 4029 sProperty = sProperty.replace('_', '-'); 4030 if (m_pStringReplace) 4031 sFinalValue = (*m_pStringReplace)(sFinalValue); 4032 rMap[sProperty] = sFinalValue; 4033 } 4034 } 4035 4036 void VclBuilder::handleActionWidget(xmlreader::XmlReader &reader) 4037 { 4038 xmlreader::Span name; 4039 int nsId; 4040 4041 OString sResponse; 4042 4043 while (reader.nextAttribute(&nsId, &name)) 4044 { 4045 if (name == "response") 4046 { 4047 name = reader.getAttributeValue(false); 4048 sResponse = OString(name.begin, name.length); 4049 } 4050 } 4051 4052 (void)reader.nextItem(xmlreader::XmlReader::Text::Raw, &name, &nsId); 4053 OString sID(name.begin, name.length); 4054 sal_Int32 nDelim = sID.indexOf(':'); 4055 if (nDelim != -1) 4056 sID = sID.copy(0, nDelim); 4057 set_response(sID, sResponse.toInt32()); 4058 } 4059 4060 void VclBuilder::collectAccelerator(xmlreader::XmlReader &reader, accelmap &rMap) 4061 { 4062 xmlreader::Span name; 4063 int nsId; 4064 4065 OString sProperty; 4066 OString sValue; 4067 OString sModifiers; 4068 4069 while (reader.nextAttribute(&nsId, &name)) 4070 { 4071 if (name == "key") 4072 { 4073 name = reader.getAttributeValue(false); 4074 sValue = OString(name.begin, name.length); 4075 } 4076 else if (name == "signal") 4077 { 4078 name = reader.getAttributeValue(false); 4079 sProperty = OString(name.begin, name.length); 4080 } 4081 else if (name == "modifiers") 4082 { 4083 name = reader.getAttributeValue(false); 4084 sModifiers = OString(name.begin, name.length); 4085 } 4086 } 4087 4088 if (!sProperty.isEmpty() && !sValue.isEmpty()) 4089 { 4090 rMap[sProperty] = std::make_pair(sValue, sModifiers); 4091 } 4092 } 4093 4094 vcl::Window *VclBuilder::get_widget_root() 4095 { 4096 return m_aChildren.empty() ? nullptr : m_aChildren[0].m_pWindow.get(); 4097 } 4098 4099 vcl::Window *VclBuilder::get_by_name(const OString& sID) 4100 { 4101 for (auto const& child : m_aChildren) 4102 { 4103 if (child.m_sID == sID) 4104 return child.m_pWindow; 4105 } 4106 4107 return nullptr; 4108 } 4109 4110 PopupMenu *VclBuilder::get_menu(const OString& sID) 4111 { 4112 for (auto const& menu : m_aMenus) 4113 { 4114 if (menu.m_sID == sID) 4115 return dynamic_cast<PopupMenu*>(menu.m_pMenu.get()); 4116 } 4117 4118 return nullptr; 4119 } 4120 4121 void VclBuilder::set_response(const OString& sID, short nResponse) 4122 { 4123 switch (nResponse) 4124 { 4125 case -5: 4126 nResponse = RET_OK; 4127 break; 4128 case -6: 4129 nResponse = RET_CANCEL; 4130 break; 4131 case -7: 4132 nResponse = RET_CLOSE; 4133 break; 4134 case -8: 4135 nResponse = RET_YES; 4136 break; 4137 case -9: 4138 nResponse = RET_NO; 4139 break; 4140 case -11: 4141 nResponse = RET_HELP; 4142 break; 4143 default: 4144 assert(nResponse >= 100 && "keep non-canned responses in range 100+ to avoid collision with vcl RET_*"); 4145 break; 4146 } 4147 4148 for (const auto & child : m_aChildren) 4149 { 4150 if (child.m_sID == sID) 4151 { 4152 PushButton* pPushButton = dynamic_cast<PushButton*>(child.m_pWindow.get()); 4153 assert(pPushButton); 4154 Dialog* pDialog = pPushButton->GetParentDialog(); 4155 assert(pDialog); 4156 pDialog->add_button(pPushButton, nResponse, false); 4157 return; 4158 } 4159 } 4160 4161 assert(false); 4162 } 4163 4164 void VclBuilder::delete_by_name(const OString& sID) 4165 { 4166 auto aI = std::find_if(m_aChildren.begin(), m_aChildren.end(), 4167 [&sID](WinAndId& rItem) { return rItem.m_sID == sID; }); 4168 if (aI != m_aChildren.end()) 4169 { 4170 aI->m_pWindow.disposeAndClear(); 4171 m_aChildren.erase(aI); 4172 } 4173 } 4174 4175 void VclBuilder::delete_by_window(vcl::Window *pWindow) 4176 { 4177 drop_ownership(pWindow); 4178 pWindow->disposeOnce(); 4179 } 4180 4181 void VclBuilder::drop_ownership(const vcl::Window *pWindow) 4182 { 4183 auto aI = std::find_if(m_aChildren.begin(), m_aChildren.end(), 4184 [&pWindow](WinAndId& rItem) { return rItem.m_pWindow == pWindow; }); 4185 if (aI != m_aChildren.end()) 4186 m_aChildren.erase(aI); 4187 } 4188 4189 OString VclBuilder::get_by_window(const vcl::Window *pWindow) const 4190 { 4191 for (auto const& child : m_aChildren) 4192 { 4193 if (child.m_pWindow == pWindow) 4194 return child.m_sID; 4195 } 4196 4197 return OString(); 4198 } 4199 4200 VclBuilder::PackingData VclBuilder::get_window_packing_data(const vcl::Window *pWindow) const 4201 { 4202 //We've stored the return of new Control, some of these get 4203 //border windows placed around them which are what you get 4204 //from GetChild, so scoot up a level if necessary to get the 4205 //window whose position value we have 4206 const vcl::Window *pPropHolder = pWindow->ImplGetWindow(); 4207 4208 for (auto const& child : m_aChildren) 4209 { 4210 if (child.m_pWindow == pPropHolder) 4211 return child.m_aPackingData; 4212 } 4213 4214 return PackingData(); 4215 } 4216 4217 void VclBuilder::set_window_packing_position(const vcl::Window *pWindow, sal_Int32 nPosition) 4218 { 4219 for (auto & child : m_aChildren) 4220 { 4221 if (child.m_pWindow == pWindow) 4222 child.m_aPackingData.m_nPosition = nPosition; 4223 } 4224 } 4225 4226 const VclBuilder::ListStore *VclBuilder::get_model_by_name(const OString& sID) const 4227 { 4228 std::map<OString, ListStore>::const_iterator aI = m_pParserState->m_aModels.find(sID); 4229 if (aI != m_pParserState->m_aModels.end()) 4230 return &(aI->second); 4231 return nullptr; 4232 } 4233 4234 const VclBuilder::TextBuffer *VclBuilder::get_buffer_by_name(const OString& sID) const 4235 { 4236 std::map<OString, TextBuffer>::const_iterator aI = m_pParserState->m_aTextBuffers.find(sID); 4237 if (aI != m_pParserState->m_aTextBuffers.end()) 4238 return &(aI->second); 4239 return nullptr; 4240 } 4241 4242 const VclBuilder::Adjustment *VclBuilder::get_adjustment_by_name(const OString& sID) const 4243 { 4244 std::map<OString, Adjustment>::const_iterator aI = m_pParserState->m_aAdjustments.find(sID); 4245 if (aI != m_pParserState->m_aAdjustments.end()) 4246 return &(aI->second); 4247 return nullptr; 4248 } 4249 4250 void VclBuilder::mungeModel(ComboBox &rTarget, const ListStore &rStore, sal_uInt16 nActiveId) 4251 { 4252 for (auto const& entry : rStore.m_aEntries) 4253 { 4254 const ListStore::row &rRow = entry; 4255 sal_uInt16 nEntry = rTarget.InsertEntry(rRow[0]); 4256 if (rRow.size() > 1) 4257 { 4258 if (m_bLegacy) 4259 { 4260 sal_IntPtr nValue = rRow[1].toInt32(); 4261 rTarget.SetEntryData(nEntry, reinterpret_cast<void*>(nValue)); 4262 } 4263 else 4264 { 4265 if (!rRow[1].isEmpty()) 4266 { 4267 m_aUserData.emplace_back(std::make_unique<OUString>(rRow[1])); 4268 rTarget.SetEntryData(nEntry, m_aUserData.back().get()); 4269 } 4270 } 4271 } 4272 } 4273 if (nActiveId < rStore.m_aEntries.size()) 4274 rTarget.SelectEntryPos(nActiveId); 4275 } 4276 4277 void VclBuilder::mungeModel(ListBox &rTarget, const ListStore &rStore, sal_uInt16 nActiveId) 4278 { 4279 for (auto const& entry : rStore.m_aEntries) 4280 { 4281 const ListStore::row &rRow = entry; 4282 sal_uInt16 nEntry = rTarget.InsertEntry(rRow[0]); 4283 if (rRow.size() > 1) 4284 { 4285 if (m_bLegacy) 4286 { 4287 sal_IntPtr nValue = rRow[1].toInt32(); 4288 rTarget.SetEntryData(nEntry, reinterpret_cast<void*>(nValue)); 4289 } 4290 else 4291 { 4292 if (!rRow[1].isEmpty()) 4293 { 4294 m_aUserData.emplace_back(std::make_unique<OUString>(rRow[1])); 4295 rTarget.SetEntryData(nEntry, m_aUserData.back().get()); 4296 } 4297 } 4298 } 4299 } 4300 if (nActiveId < rStore.m_aEntries.size()) 4301 rTarget.SelectEntryPos(nActiveId); 4302 } 4303 4304 void VclBuilder::mungeModel(SvTabListBox& rTarget, const ListStore &rStore, sal_uInt16 nActiveId) 4305 { 4306 for (auto const& entry : rStore.m_aEntries) 4307 { 4308 const ListStore::row &rRow = entry; 4309 auto pEntry = rTarget.InsertEntry(rRow[0]); 4310 if (rRow.size() > 1) 4311 { 4312 if (m_bLegacy) 4313 { 4314 sal_IntPtr nValue = rRow[1].toInt32(); 4315 pEntry->SetUserData(reinterpret_cast<void*>(nValue)); 4316 } 4317 else 4318 { 4319 if (!rRow[1].isEmpty()) 4320 { 4321 m_aUserData.emplace_back(std::make_unique<OUString>(rRow[1])); 4322 pEntry->SetUserData(m_aUserData.back().get()); 4323 } 4324 } 4325 } 4326 } 4327 if (nActiveId < rStore.m_aEntries.size()) 4328 { 4329 SvTreeListEntry* pEntry = rTarget.GetEntry(nullptr, nActiveId); 4330 rTarget.Select(pEntry); 4331 } 4332 } 4333 4334 void VclBuilder::mungeAdjustment(NumericFormatter &rTarget, const Adjustment &rAdjustment) 4335 { 4336 int nMul = rtl_math_pow10Exp(1, rTarget.GetDecimalDigits()); 4337 4338 for (auto const& elem : rAdjustment) 4339 { 4340 const OString &rKey = elem.first; 4341 const OUString &rValue = elem.second; 4342 4343 if (rKey == "upper") 4344 { 4345 sal_Int64 nUpper = rValue.toDouble() * nMul; 4346 rTarget.SetMax(nUpper); 4347 rTarget.SetLast(nUpper); 4348 } 4349 else if (rKey == "lower") 4350 { 4351 sal_Int64 nLower = rValue.toDouble() * nMul; 4352 rTarget.SetMin(nLower); 4353 rTarget.SetFirst(nLower); 4354 } 4355 else if (rKey == "value") 4356 { 4357 sal_Int64 nValue = rValue.toDouble() * nMul; 4358 rTarget.SetValue(nValue); 4359 } 4360 else if (rKey == "step-increment") 4361 { 4362 sal_Int64 nSpinSize = rValue.toDouble() * nMul; 4363 rTarget.SetSpinSize(nSpinSize); 4364 } 4365 else 4366 { 4367 SAL_INFO("vcl.builder", "unhandled property :" << rKey); 4368 } 4369 } 4370 } 4371 4372 void VclBuilder::mungeAdjustment(FormattedField &rTarget, const Adjustment &rAdjustment) 4373 { 4374 double nMaxValue = 0, nMinValue = 0, nValue = 0, nSpinSize = 0; 4375 4376 for (auto const& elem : rAdjustment) 4377 { 4378 const OString &rKey = elem.first; 4379 const OUString &rValue = elem.second; 4380 4381 if (rKey == "upper") 4382 nMaxValue = rValue.toDouble(); 4383 else if (rKey == "lower") 4384 nMinValue = rValue.toDouble(); 4385 else if (rKey == "value") 4386 nValue = rValue.toDouble(); 4387 else if (rKey == "step-increment") 4388 nSpinSize = rValue.toDouble(); 4389 else 4390 SAL_INFO("vcl.builder", "unhandled property :" << rKey); 4391 } 4392 4393 rTarget.SetMinValue(nMinValue); 4394 rTarget.SetMaxValue(nMaxValue); 4395 rTarget.SetValue(nValue); 4396 rTarget.SetSpinSize(nSpinSize); 4397 } 4398 4399 void VclBuilder::mungeAdjustment(ScrollBar &rTarget, const Adjustment &rAdjustment) 4400 { 4401 for (auto const& elem : rAdjustment) 4402 { 4403 const OString &rKey = elem.first; 4404 const OUString &rValue = elem.second; 4405 4406 if (rKey == "upper") 4407 rTarget.SetRangeMax(rValue.toInt32()); 4408 else if (rKey == "lower") 4409 rTarget.SetRangeMin(rValue.toInt32()); 4410 else if (rKey == "value") 4411 rTarget.SetThumbPos(rValue.toInt32()); 4412 else if (rKey == "step-increment") 4413 rTarget.SetLineSize(rValue.toInt32()); 4414 else if (rKey == "page-increment") 4415 rTarget.SetPageSize(rValue.toInt32()); 4416 else 4417 { 4418 SAL_INFO("vcl.builder", "unhandled property :" << rKey); 4419 } 4420 } 4421 } 4422 4423 void VclBuilder::mungeAdjustment(Slider& rTarget, const Adjustment& rAdjustment) 4424 { 4425 for (auto const& elem : rAdjustment) 4426 { 4427 const OString &rKey = elem.first; 4428 const OUString &rValue = elem.second; 4429 4430 if (rKey == "upper") 4431 rTarget.SetRangeMax(rValue.toInt32()); 4432 else if (rKey == "lower") 4433 rTarget.SetRangeMin(rValue.toInt32()); 4434 else if (rKey == "value") 4435 rTarget.SetThumbPos(rValue.toInt32()); 4436 else if (rKey == "step-increment") 4437 rTarget.SetLineSize(rValue.toInt32()); 4438 else if (rKey == "page-increment") 4439 rTarget.SetPageSize(rValue.toInt32()); 4440 else 4441 { 4442 SAL_INFO("vcl.builder", "unhandled property :" << rKey); 4443 } 4444 } 4445 } 4446 4447 void VclBuilder::mungeTextBuffer(VclMultiLineEdit &rTarget, const TextBuffer &rTextBuffer) 4448 { 4449 for (auto const& elem : rTextBuffer) 4450 { 4451 const OString &rKey = elem.first; 4452 const OUString &rValue = elem.second; 4453 4454 if (rKey == "text") 4455 rTarget.SetText(rValue); 4456 else 4457 { 4458 SAL_INFO("vcl.builder", "unhandled property :" << rKey); 4459 } 4460 } 4461 } 4462 4463 VclBuilder::ParserState::ParserState() 4464 : m_nLastToolbarId(0) 4465 , m_nLastMenuItemId(0) 4466 {} 4467 4468 VclBuilder::MenuAndId::MenuAndId(const OString &rId, Menu *pMenu) 4469 : m_sID(rId) 4470 , m_pMenu(pMenu) 4471 {} 4472 4473 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ 4474
