diff options
34 files changed, 2219 insertions, 280 deletions
diff --git a/cui/source/dialogs/about.cxx b/cui/source/dialogs/about.cxx index a9617f7a8381..da2e4d2b4e2d 100644 --- a/cui/source/dialogs/about.cxx +++ b/cui/source/dialogs/about.cxx @@ -68,13 +68,13 @@ AboutDialog::AboutDialog(weld::Window* pParent) m_xDialog->add_button(CuiResId(RID_SVXSTR_ABOUT_WEBSITE), 102); m_xDialog->add_button(CuiResId(RID_SVXSTR_ABOUT_RELEASE_NOTES), 103); - m_pCreditsButton = m_xDialog->get_widget_for_response(101); - m_pCreditsButton->set_secondary(true); - m_pWebsiteButton = m_xDialog->get_widget_for_response(102); - m_pWebsiteButton->set_secondary(true); - m_pReleaseNotesButton = m_xDialog->get_widget_for_response(103); - m_pReleaseNotesButton->set_secondary(true); - m_pCloseButton = m_xDialog->get_widget_for_response(RET_CLOSE); + m_xCreditsButton.reset(m_xDialog->weld_widget_for_response(101)); + m_xCreditsButton->set_secondary(true); + m_xWebsiteButton.reset(m_xDialog->weld_widget_for_response(102)); + m_xWebsiteButton->set_secondary(true); + m_xReleaseNotesButton.reset(m_xDialog->weld_widget_for_response(103)); + m_xReleaseNotesButton->set_secondary(true); + m_xCloseButton.reset(m_xDialog->weld_widget_for_response(RET_CLOSE)); m_buildIdLinkString = m_xDialog->get_website_label(); @@ -88,10 +88,10 @@ AboutDialog::AboutDialog(weld::Window* pParent) m_xDialog->connect_size_allocate(LINK(this, AboutDialog, SizeAllocHdl)); // Connect all handlers - m_pCreditsButton->connect_clicked( LINK( this, AboutDialog, HandleClick ) ); - m_pWebsiteButton->connect_clicked( LINK( this, AboutDialog, HandleClick ) ); - m_pReleaseNotesButton->connect_clicked( LINK( this, AboutDialog, HandleClick ) ); - m_pCloseButton->grab_focus(); + m_xCreditsButton->connect_clicked( LINK( this, AboutDialog, HandleClick ) ); + m_xWebsiteButton->connect_clicked( LINK( this, AboutDialog, HandleClick ) ); + m_xReleaseNotesButton->connect_clicked( LINK( this, AboutDialog, HandleClick ) ); + m_xCloseButton->grab_focus(); } AboutDialog::~AboutDialog() @@ -103,14 +103,14 @@ IMPL_LINK(AboutDialog, HandleClick, weld::Button&, rButton, void) OUString sURL = ""; // Find which button was pressed and from this, get the URL to be opened - if (&rButton == m_pCreditsButton) + if (&rButton == m_xCreditsButton.get()) sURL = CuiResId(RID_SVXSTR_ABOUT_CREDITS_URL); - else if (&rButton == m_pWebsiteButton) + else if (&rButton == m_xWebsiteButton.get()) { sURL = officecfg::Office::Common::Help::StartCenter::InfoURL::get(); localizeWebserviceURI(sURL); } - else if (&rButton == m_pReleaseNotesButton) + else if (&rButton == m_xReleaseNotesButton.get()) { sURL = officecfg::Office::Common::Menus::ReleaseNotesURL::get() + "?LOvers=" + utl::ConfigManager::getProductVersion() + diff --git a/cui/source/inc/about.hxx b/cui/source/inc/about.hxx index adafb7448ef0..c51eb15433d8 100644 --- a/cui/source/inc/about.hxx +++ b/cui/source/inc/about.hxx @@ -27,18 +27,17 @@ class AboutDialog : public weld::DialogController private: std::unique_ptr<weld::Builder> m_xBuilder; std::shared_ptr<weld::AboutDialog> m_xDialog; - std::shared_ptr<weld::Container> m_xContentArea; + std::unique_ptr<weld::Container> m_xContentArea; + std::unique_ptr<weld::Button> m_xCreditsButton; + std::unique_ptr<weld::Button> m_xWebsiteButton; + std::unique_ptr<weld::Button> m_xReleaseNotesButton; + std::unique_ptr<weld::Button> m_xCloseButton; BitmapEx aLogoBitmap; BitmapEx aBackgroundBitmap; OUString m_buildIdLinkString; - weld::Button* m_pCreditsButton; - weld::Button* m_pWebsiteButton; - weld::Button* m_pReleaseNotesButton; - weld::Button* m_pCloseButton; - void SetBuildIdLink(); void SetLogo(); diff --git a/dbaccess/UIConfig_dbaccess.mk b/dbaccess/UIConfig_dbaccess.mk index eacb9eb112c2..ff79be062c22 100644 --- a/dbaccess/UIConfig_dbaccess.mk +++ b/dbaccess/UIConfig_dbaccess.mk @@ -21,6 +21,7 @@ $(eval $(call gb_UIConfig_add_uifiles,dbaccess, \ dbaccess/uiconfig/ui/colwidthdialog \ dbaccess/uiconfig/ui/connectionpage \ dbaccess/uiconfig/ui/copytablepage \ + dbaccess/uiconfig/ui/databasewizard \ dbaccess/uiconfig/ui/dbaseindexdialog \ dbaccess/uiconfig/ui/dbasepage \ dbaccess/uiconfig/ui/dbwizconnectionpage \ diff --git a/dbaccess/source/ui/dlg/adminpages.cxx b/dbaccess/source/ui/dlg/adminpages.cxx index e0599f5f1517..3672e247de5c 100644 --- a/dbaccess/source/ui/dlg/adminpages.cxx +++ b/dbaccess/source/ui/dlg/adminpages.cxx @@ -64,8 +64,10 @@ namespace dbaui , m_pAdminDialog(nullptr) , m_pItemSetHelper(nullptr) { - SetExchangeSupport(); + + Size aSize(LogicToPixel(::Size(WIZARD_PAGE_X, WIZARD_PAGE_Y), MapMode(MapUnit::MapAppFont))); + m_xContainer->set_size_request(aSize.Width(), aSize.Height()); } DeactivateRC OGenericAdministrationPage::DeactivatePage(SfxItemSet* _pSet) diff --git a/dbaccess/source/ui/dlg/dbwizsetup.cxx b/dbaccess/source/ui/dlg/dbwizsetup.cxx index 97cdfdb5e609..e878a7d611eb 100644 --- a/dbaccess/source/ui/dlg/dbwizsetup.cxx +++ b/dbaccess/source/ui/dlg/dbwizsetup.cxx @@ -99,12 +99,12 @@ using namespace ::comphelper; using namespace ::cppu; // ODbTypeWizDialogSetup -ODbTypeWizDialogSetup::ODbTypeWizDialogSetup(vcl::Window* _pParent +ODbTypeWizDialogSetup::ODbTypeWizDialogSetup(weld::Window* _pParent ,SfxItemSet const * _pItems ,const Reference< XComponentContext >& _rxORB ,const css::uno::Any& _aDataSourceName ) - :vcl::RoadmapWizard( _pParent ) + : vcl::RoadmapWizardMachine( _pParent ) , m_bIsConnectable( false) , m_sRM_IntroText( DBA_RES( STR_PAGETITLE_INTROPAGE ) ) @@ -135,14 +135,13 @@ ODbTypeWizDialogSetup::ODbTypeWizDialogSetup(vcl::Window* _pParent OSL_ENSURE(m_pCollection, "ODbTypeWizDialogSetup::ODbTypeWizDialogSetup : really need a DSN type collection !"); - m_pImpl.reset(new ODbDataSourceAdministrationHelper(_rxORB,GetFrameWeld(),_pParent ? _pParent->GetFrameWeld() : nullptr, this)); + m_pImpl.reset(new ODbDataSourceAdministrationHelper(_rxORB, m_xAssistant.get(), _pParent, this)); m_pImpl->setDataSourceOrName(_aDataSourceName); Reference< XPropertySet > xDatasource = m_pImpl->getCurrentDataSource(); m_pOutSet.reset( new SfxItemSet( *_pItems->GetPool(), _pItems->GetRanges() ) ); m_pImpl->translateProperties(xDatasource, *m_pOutSet); - SetPageSizePixel(LogicToPixel(::Size(WIZARD_PAGE_X, WIZARD_PAGE_Y), MapMode(MapUnit::MapAppFont))); defaultButton(WizardButtonFlags::NEXT); enableButtons(WizardButtonFlags::FINISH, true); enableAutomaticNextButtonState(); @@ -165,13 +164,13 @@ ODbTypeWizDialogSetup::ODbTypeWizDialogSetup(vcl::Window* _pParent aPath.push_back(PAGE_DBSETUPWIZARD_INTRO); declarePath( static_cast<PathId>(m_pCollection->size()+1), aPath); - m_pPrevPage->SetHelpId(HID_DBWIZ_PREVIOUS); - m_pNextPage->SetHelpId(HID_DBWIZ_NEXT); - m_pCancel->SetHelpId(HID_DBWIZ_CANCEL); - m_pFinish->SetHelpId(HID_DBWIZ_FINISH); - SetRoadmapInteractive( true ); + m_xPrevPage->set_help_id(HID_DBWIZ_PREVIOUS); + m_xNextPage->set_help_id(HID_DBWIZ_NEXT); + m_xCancel->set_help_id(HID_DBWIZ_CANCEL); + m_xFinish->set_help_id(HID_DBWIZ_FINISH); ActivatePage(); setTitleBase(DBA_RES(STR_DBWIZARDTITLE)); + m_xAssistant->set_current_page(0); } void ODbTypeWizDialogSetup::declareAuthDepPath( const OUString& _sURL, PathId _nPathId, const vcl::RoadmapWizardTypes::WizardPath& _rPaths) @@ -188,7 +187,7 @@ void ODbTypeWizDialogSetup::declareAuthDepPath( const OUString& _sURL, PathId _n } // call base method - ::vcl::RoadmapWizard::declarePath( _nPathId, aPath ); + ::vcl::RoadmapWizardMachine::declarePath( _nPathId, aPath ); } OUString ODbTypeWizDialogSetup::getStateDisplayName( WizardState _nState ) const @@ -256,16 +255,6 @@ OUString ODbTypeWizDialogSetup::getStateDisplayName( WizardState _nState ) const ODbTypeWizDialogSetup::~ODbTypeWizDialogSetup() { - disposeOnce(); -} - -void ODbTypeWizDialogSetup::dispose() -{ - m_pOutSet.reset(); - m_pGeneralPage.clear(); - m_pMySQLIntroPage.clear(); - m_pFinalPage.clear(); - vcl::RoadmapWizard::dispose(); } IMPL_LINK_NOARG(ODbTypeWizDialogSetup, OnTypeSelected, OGeneralPage&, void) @@ -458,10 +447,16 @@ VclPtr<TabPage> ODbTypeWizDialogSetup::createPage(WizardState _nState) { VclPtr<SfxTabPage> pFirstPage; VclPtr<OGenericAdministrationPage> pPage; + + OString sIdent(OString::number(_nState)); + weld::Container* pPageContainer = m_xAssistant->append_page(sIdent); + // TODO eventually pass DialogController as distinct argument instead of bundling into TabPageParent + TabPageParent aParent(pPageContainer, this); + switch(_nState) { case PAGE_DBSETUPWIZARD_INTRO: - pFirstPage = VclPtr<OGeneralPageWizard>::Create(this,*m_pOutSet); + pFirstPage = VclPtr<OGeneralPageWizard>::Create(aParent,*m_pOutSet); pPage = static_cast<OGenericAdministrationPage*> (pFirstPage.get()); m_pGeneralPage = static_cast<OGeneralPageWizard*>(pFirstPage.get()); m_pGeneralPage->SetTypeSelectHandler(LINK(this, ODbTypeWizDialogSetup, OnTypeSelected)); @@ -471,70 +466,70 @@ VclPtr<TabPage> ODbTypeWizDialogSetup::createPage(WizardState _nState) break; case PAGE_DBSETUPWIZARD_DBASE: - pPage = OConnectionTabPageSetup::CreateDbaseTabPage(this,*m_pOutSet); + pPage = OConnectionTabPageSetup::CreateDbaseTabPage(aParent, *m_pOutSet); break; case PAGE_DBSETUPWIZARD_ADO: - pPage = OConnectionTabPageSetup::CreateADOTabPage( this, *m_pOutSet); + pPage = OConnectionTabPageSetup::CreateADOTabPage(aParent, *m_pOutSet); break; case PAGE_DBSETUPWIZARD_TEXT: - pPage = OTextConnectionPageSetup::CreateTextTabPage(this,*m_pOutSet); + pPage = OTextConnectionPageSetup::CreateTextTabPage(aParent, *m_pOutSet); break; case PAGE_DBSETUPWIZARD_ODBC: - pPage = OConnectionTabPageSetup::CreateODBCTabPage( this, *m_pOutSet); + pPage = OConnectionTabPageSetup::CreateODBCTabPage(aParent, *m_pOutSet); break; case PAGE_DBSETUPWIZARD_JDBC: - pPage = OJDBCConnectionPageSetup::CreateJDBCTabPage( this, *m_pOutSet); + pPage = OJDBCConnectionPageSetup::CreateJDBCTabPage(aParent, *m_pOutSet); break; case PAGE_DBSETUPWIZARD_MYSQL_ODBC: m_pOutSet->Put(SfxStringItem(DSID_CONNECTURL, m_pCollection->getPrefix("sdbc:mysql:odbc:"))); - pPage = OConnectionTabPageSetup::CreateODBCTabPage( this, *m_pOutSet); + pPage = OConnectionTabPageSetup::CreateODBCTabPage(aParent, *m_pOutSet); break; case PAGE_DBSETUPWIZARD_MYSQL_JDBC: m_pOutSet->Put(SfxStringItem(DSID_CONNECTURL, m_pCollection->getPrefix("sdbc:mysql:jdbc:"))); - pPage = OGeneralSpecialJDBCConnectionPageSetup::CreateMySQLJDBCTabPage( this, *m_pOutSet); + pPage = OGeneralSpecialJDBCConnectionPageSetup::CreateMySQLJDBCTabPage(aParent, *m_pOutSet); break; case PAGE_DBSETUPWIZARD_MYSQL_NATIVE: m_pOutSet->Put(SfxStringItem(DSID_CONNECTURL, m_pCollection->getPrefix("sdbc:mysql:mysqlc:"))); - pPage = MySQLNativeSetupPage::Create( this, *m_pOutSet); + pPage = MySQLNativeSetupPage::Create(aParent, *m_pOutSet); break; case PAGE_DBSETUPWIZARD_ORACLE: - pPage = OGeneralSpecialJDBCConnectionPageSetup::CreateOracleJDBCTabPage( this, *m_pOutSet); + pPage = OGeneralSpecialJDBCConnectionPageSetup::CreateOracleJDBCTabPage(aParent, *m_pOutSet); break; case PAGE_DBSETUPWIZARD_LDAP: - pPage = OLDAPConnectionPageSetup::CreateLDAPTabPage(this,*m_pOutSet); + pPage = OLDAPConnectionPageSetup::CreateLDAPTabPage(aParent, *m_pOutSet); break; case PAGE_DBSETUPWIZARD_DOCUMENT_OR_SPREADSHEET: - pPage = OSpreadSheetConnectionPageSetup::CreateDocumentOrSpreadSheetTabPage(this,*m_pOutSet); + pPage = OSpreadSheetConnectionPageSetup::CreateDocumentOrSpreadSheetTabPage(aParent, *m_pOutSet); break; case PAGE_DBSETUPWIZARD_MSACCESS: - pPage = OConnectionTabPageSetup::CreateMSAccessTabPage(this,*m_pOutSet); + pPage = OConnectionTabPageSetup::CreateMSAccessTabPage(aParent, *m_pOutSet); break; case PAGE_DBSETUPWIZARD_MYSQL_INTRO: - m_pMySQLIntroPage = OMySQLIntroPageSetup::CreateMySQLIntroTabPage(this,*m_pOutSet); + m_pMySQLIntroPage = OMySQLIntroPageSetup::CreateMySQLIntroTabPage(aParent, *m_pOutSet); m_pMySQLIntroPage->SetClickHdl(LINK( this, ODbTypeWizDialogSetup, ImplClickHdl ) ); pPage = m_pMySQLIntroPage; break; case PAGE_DBSETUPWIZARD_AUTHENTIFICATION: - pPage = OAuthentificationPageSetup::CreateAuthentificationTabPage(this,*m_pOutSet); + pPage = OAuthentificationPageSetup::CreateAuthentificationTabPage(aParent, *m_pOutSet); break; case PAGE_DBSETUPWIZARD_USERDEFINED: - pPage = OConnectionTabPageSetup::CreateUserDefinedTabPage(this,*m_pOutSet); + pPage = OConnectionTabPageSetup::CreateUserDefinedTabPage(aParent, *m_pOutSet); break; case PAGE_DBSETUPWIZARD_FINAL: - pPage = OFinalDBPageSetup::CreateFinalDBTabPageSetup(this,*m_pOutSet); + pPage = OFinalDBPageSetup::CreateFinalDBTabPageSetup(aParent, *m_pOutSet); m_pFinalPage = static_cast<OFinalDBPageSetup*> (pPage.get()); break; } @@ -553,6 +548,8 @@ VclPtr<TabPage> ODbTypeWizDialogSetup::createPage(WizardState _nState) enableButtons( WizardButtonFlags::FINISH, _nState == PAGE_DBSETUPWIZARD_FINAL ); enableButtons( WizardButtonFlags::NEXT, _nState != PAGE_DBSETUPWIZARD_FINAL ); pPage->Show(); + + m_xAssistant->set_page_title(sIdent, getStateDisplayName(_nState)); } return pPage; } @@ -606,7 +603,7 @@ IMPL_LINK_NOARG(ODbTypeWizDialogSetup, OnSingleDocumentChosen, OGeneralPageWizar void ODbTypeWizDialogSetup::enterState(WizardState _nState) { m_sURL = dbaui::ODbDataSourceAdministrationHelper::getDatasourceType(*m_pOutSet); - RoadmapWizard::enterState(_nState); + RoadmapWizardMachine::enterState(_nState); switch(_nState) { case PAGE_DBSETUPWIZARD_INTRO: @@ -622,7 +619,7 @@ void ODbTypeWizDialogSetup::enterState(WizardState _nState) void ODbTypeWizDialogSetup::saveDatasource() { - SfxTabPage* pPage = static_cast<SfxTabPage*>(WizardDialog::GetPage(getCurrentState())); + SfxTabPage* pPage = static_cast<SfxTabPage*>(GetPage(getCurrentState())); if ( pPage ) pPage->FillItemSet(m_pOutSet.get()); } @@ -635,14 +632,13 @@ bool ODbTypeWizDialogSetup::leaveState(WizardState _nState) { resetPages(m_pImpl->getCurrentDataSource()); } - SfxTabPage* pPage = static_cast<SfxTabPage*>(WizardDialog::GetPage(_nState)); + SfxTabPage* pPage = static_cast<SfxTabPage*>(GetPage(_nState)); return pPage && pPage->DeactivatePage(m_pOutSet.get()) != DeactivateRC::KeepPage; } -void ODbTypeWizDialogSetup::setTitle(const OUString& /*_sTitle*/) +void ODbTypeWizDialogSetup::setTitle(const OUString& _sTitle) { - OSL_FAIL( "ODbTypeWizDialogSetup::setTitle: not implemented!" ); - // why? + m_xAssistant->set_title(_sTitle); } void ODbTypeWizDialogSetup::enableConfirmSettings( bool /*_bEnable*/ ) @@ -779,7 +775,7 @@ bool ODbTypeWizDialogSetup::SaveDatabaseDocument() bool bRet = false; ::sfx2::FileDialogHelper aFileDlg( ui::dialogs::TemplateDescription::FILESAVE_AUTOEXTENSION, - FileDialogFlags::NONE, GetFrameWeld()); + FileDialogFlags::NONE, m_xAssistant.get()); std::shared_ptr<const SfxFilter> pFilter = getStandardDatabaseFilter(); if ( pFilter ) { @@ -971,7 +967,7 @@ bool ODbTypeWizDialogSetup::SaveDatabaseDocument() // wants us to load could be a non-database document. Instead, we asynchronously // open the selected document. Thus, the wizard's return value is RET_CANCEL, // which means to not continue loading the database document - if ( !OWizardMachine::Finish() ) + if ( !WizardMachine::Finish() ) return false; try @@ -993,7 +989,7 @@ bool ODbTypeWizDialogSetup::SaveDatabaseDocument() skipUntil(PAGE_DBSETUPWIZARD_FINAL); } if (getCurrentState() == PAGE_DBSETUPWIZARD_FINAL) - return SaveDatabaseDocument() && OWizardMachine::onFinish(); + return SaveDatabaseDocument() && WizardMachine::onFinish(); else { enableButtons( WizardButtonFlags::FINISH, false ); diff --git a/dbaccess/source/ui/dlg/generalpage.cxx b/dbaccess/source/ui/dlg/generalpage.cxx index 2ed044a43795..5fe9655c37e9 100644 --- a/dbaccess/source/ui/dlg/generalpage.cxx +++ b/dbaccess/source/ui/dlg/generalpage.cxx @@ -239,6 +239,7 @@ namespace dbaui { implSetCurrentType( dbaccess::ODsnTypeCollection::getEmbeddedDatabase() ); sDisplayName = m_pCollection->getTypeDisplayName( m_eCurrentSelection ); + onTypeSelected(m_eCurrentSelection); } // select the correct datasource type @@ -451,6 +452,7 @@ namespace dbaui , m_xFT_EmbeddedDBLabel(m_xBuilder->weld_label("embeddeddbLabel")) , m_xEmbeddedDBType(m_xBuilder->weld_combo_box("embeddeddbList")) , m_xFT_DocListLabel(m_xBuilder->weld_label("docListLabel")) + , m_xFT_HelpText(m_xBuilder->weld_label("helpText")) , m_xLB_DocumentList(new OpenDocumentListBox(m_xBuilder->weld_combo_box("documentList"), "com.sun.star.sdb.OfficeDatabaseDocument")) , m_xPB_OpenDatabase(new OpenDocumentButton(m_xBuilder->weld_button("openDatabase"), "com.sun.star.sdb.OfficeDatabaseDocument")) , m_eOriginalCreationMode(eCreateNew) @@ -482,7 +484,7 @@ namespace dbaui // do some knittings m_xEmbeddedDBType->connect_changed(LINK(this, OGeneralPageWizard, OnEmbeddedDBTypeSelected)); - m_xRB_CreateDatabase->connect_clicked( LINK( this, OGeneralPageWizard, OnCreateDatabaseModeSelected ) ); + m_xRB_CreateDatabase->connect_clicked( LINK( this, OGeneralPageWizard, OnSetupModeSelected ) ); m_xRB_ConnectDatabase->connect_clicked( LINK( this, OGeneralPageWizard, OnSetupModeSelected ) ); m_xRB_OpenExistingDatabase->connect_clicked( LINK( this, OGeneralPageWizard, OnSetupModeSelected ) ); m_xLB_DocumentList->connect_changed( LINK( this, OGeneralPageWizard, OnDocumentSelected ) ); @@ -532,18 +534,13 @@ namespace dbaui m_xFT_DocListLabel->set_sensitive( false ); m_xLB_DocumentList->set_sensitive( false ); } - else - { - m_xDatasourceType->set_sensitive( false ); - m_xPB_OpenDatabase->set_sensitive( false ); - m_xFT_DocListLabel->set_sensitive( false ); - m_xLB_DocumentList->set_sensitive( false ); - } if (m_xLB_DocumentList->get_count()) m_xLB_DocumentList->set_active(0); m_eOriginalCreationMode = GetDatabaseCreationMode(); + + SetupModeSelected(); } OUString OGeneralPageWizard::getDatasourceName(const SfxItemSet& _rSet) @@ -620,12 +617,8 @@ namespace dbaui return m_xLB_DocumentList->GetSelectedDocumentURL(); } - IMPL_LINK_NOARG( OGeneralPageWizard, OnCreateDatabaseModeSelected, weld::Button&, void ) + void OGeneralPageWizard::EnableControls() { - m_aCreationModeHandler.Call( *this ); - - OnEmbeddedDBTypeSelected( *m_xEmbeddedDBType ); - bool bValid, bReadonly; getFlags( GetItemSet(), bValid, bReadonly ); if ( bValid && !bReadonly ) @@ -639,22 +632,21 @@ namespace dbaui } } - IMPL_LINK_NOARG( OGeneralPageWizard, OnSetupModeSelected, weld::Button&, void ) + void OGeneralPageWizard::SetupModeSelected() { m_aCreationModeHandler.Call( *this ); - OnDatasourceTypeSelected(*m_xDatasourceType); - bool bValid, bReadonly; - getFlags( GetItemSet(), bValid, bReadonly ); - if ( bValid && !bReadonly ) - { - m_xEmbeddedDBType->set_sensitive(m_xRB_CreateDatabase->get_active()); - m_xFT_EmbeddedDBLabel->set_sensitive(m_xRB_CreateDatabase->get_active()); - m_xDatasourceType->set_sensitive(m_xRB_ConnectDatabase->get_active()); - m_xPB_OpenDatabase->set_sensitive(m_xRB_OpenExistingDatabase->get_active()); - m_xFT_DocListLabel->set_sensitive(m_xRB_OpenExistingDatabase->get_active()); - m_xLB_DocumentList->set_sensitive(m_xRB_OpenExistingDatabase->get_active()); - } + if (m_xRB_CreateDatabase->get_active()) + OnEmbeddedDBTypeSelected(*m_xEmbeddedDBType); + else + OnDatasourceTypeSelected(*m_xDatasourceType); + + EnableControls(); + } + + IMPL_LINK_NOARG( OGeneralPageWizard, OnSetupModeSelected, weld::Button&, void ) + { + SetupModeSelected(); } IMPL_LINK_NOARG( OGeneralPageWizard, OnDocumentSelected, weld::ComboBox&, void ) diff --git a/dbaccess/source/ui/dlg/generalpage.hxx b/dbaccess/source/ui/dlg/generalpage.hxx index 359ed6641f82..63d8736ea38b 100644 --- a/dbaccess/source/ui/dlg/generalpage.hxx +++ b/dbaccess/source/ui/dlg/generalpage.hxx @@ -137,6 +137,7 @@ namespace dbaui std::unique_ptr<weld::ComboBox> m_xEmbeddedDBType; std::unique_ptr<weld::Label> m_xFT_DocListLabel; + std::unique_ptr<weld::Label> m_xFT_HelpText; std::unique_ptr<OpenDocumentListBox> m_xLB_DocumentList; std::unique_ptr<OpenDocumentButton> m_xPB_OpenDatabase; @@ -151,6 +152,8 @@ namespace dbaui bool m_bInitEmbeddedDBList : 1; void insertEmbeddedDBTypeEntryData( const OUString& _sType, const OUString& sDisplayName ); + void EnableControls(); + public: void SetCreationModeHandler( const Link<OGeneralPageWizard&,void>& _rHandler ) { m_aCreationModeHandler = _rHandler; } CreationMode GetDatabaseCreationMode() const; @@ -174,8 +177,9 @@ namespace dbaui OUString getEmbeddedDBName( const SfxItemSet& _rSet ); void initializeEmbeddedDBList(); + void SetupModeSelected(); + DECL_LINK( OnEmbeddedDBTypeSelected, weld::ComboBox&, void ); - DECL_LINK( OnCreateDatabaseModeSelected, weld::Button&, void ); DECL_LINK( OnSetupModeSelected, weld::Button&, void ); DECL_LINK( OnDocumentSelected, weld::ComboBox&, void ); DECL_LINK( OnOpenDocument, weld::Button&, void ); diff --git a/dbaccess/source/ui/dlg/sqlmessage.cxx b/dbaccess/source/ui/dlg/sqlmessage.cxx index f4e4204d9c4c..3bcb10c4ebcd 100644 --- a/dbaccess/source/ui/dlg/sqlmessage.cxx +++ b/dbaccess/source/ui/dlg/sqlmessage.cxx @@ -509,7 +509,7 @@ void OSQLMessageBox::impl_addDetailsButton() if ( bMoreDetailsAvailable ) { m_xDialog->add_button(Button::GetStandardText(StandardButtonType::More), RET_MORE); - m_xMoreButton.reset(m_xDialog->get_widget_for_response(RET_MORE)); + m_xMoreButton.reset(m_xDialog->weld_widget_for_response(RET_MORE)); m_xMoreButton->connect_clicked(LINK(this, OSQLMessageBox, ButtonClickHdl)); } } diff --git a/dbaccess/source/ui/inc/dbwizsetup.hxx b/dbaccess/source/ui/inc/dbwizsetup.hxx index 25001361b3f5..16969b467ee3 100644 --- a/dbaccess/source/ui/inc/dbwizsetup.hxx +++ b/dbaccess/source/ui/inc/dbwizsetup.hxx @@ -54,7 +54,7 @@ class ODbDataSourceAdministrationHelper; class OMySQLIntroPageSetup; class OFinalDBPageSetup; -class ODbTypeWizDialogSetup final : public vcl::RoadmapWizard , public IItemSetHelper, public IDatabaseSettingsDialog +class ODbTypeWizDialogSetup final : public vcl::RoadmapWizardMachine, public IItemSetHelper, public IDatabaseSettingsDialog { private: std::unique_ptr<ODbDataSourceAdministrationHelper> m_pImpl; @@ -89,13 +89,12 @@ public: /** ctor. The itemset given should have been created by <method>createItemSet</method> and should be destroyed after the dialog has been destroyed */ - ODbTypeWizDialogSetup(vcl::Window* pParent + ODbTypeWizDialogSetup(weld::Window* pParent ,SfxItemSet const * _pItems ,const css::uno::Reference< css::uno::XComponentContext >& _rxORB ,const css::uno::Any& _aDataSourceName ); virtual ~ODbTypeWizDialogSetup() override; - virtual void dispose() override; virtual const SfxItemSet* getOutputSet() const override; virtual SfxItemSet* getWriteOutputSet() override; diff --git a/dbaccess/source/ui/uno/DBTypeWizDlgSetup.cxx b/dbaccess/source/ui/uno/DBTypeWizDlgSetup.cxx index f8d021055730..8361a2325cea 100644 --- a/dbaccess/source/ui/uno/DBTypeWizDlgSetup.cxx +++ b/dbaccess/source/ui/uno/DBTypeWizDlgSetup.cxx @@ -27,7 +27,7 @@ #include <com/sun/star/sdb/XOfficeDatabaseDocument.hpp> #include <com/sun/star/sdbc/XDataSource.hpp> #include <comphelper/processfactory.hxx> -#include <toolkit/helper/vclunohelper.hxx> +#include <vcl/svapp.hxx> using namespace dbaui; @@ -108,14 +108,14 @@ Reference<XPropertySetInfo> SAL_CALL ODBTypeWizDialogSetup::getPropertySetInfo( svt::OGenericUnoDialog::Dialog ODBTypeWizDialogSetup::createDialog(const css::uno::Reference<css::awt::XWindow>& rParent) { - return svt::OGenericUnoDialog::Dialog(VclPtr<ODbTypeWizDialogSetup>::Create(VCLUnoHelper::GetWindow(rParent), m_pDatasourceItems.get(), m_aContext, m_aInitialSelection)); + return svt::OGenericUnoDialog::Dialog(std::make_unique<ODbTypeWizDialogSetup>(Application::GetFrameWeld(rParent), m_pDatasourceItems.get(), m_aContext, m_aInitialSelection)); } void ODBTypeWizDialogSetup::executedDialog(sal_Int16 _nExecutionResult) { if ( _nExecutionResult == RET_OK ) { - const ODbTypeWizDialogSetup* pDialog = static_cast<ODbTypeWizDialogSetup*>(m_aDialog.m_xVclDialog.get()); + const ODbTypeWizDialogSetup* pDialog = static_cast<ODbTypeWizDialogSetup*>(m_aDialog.m_xWeldDialog.get()); m_bOpenDatabase = pDialog->IsDatabaseDocumentToBeOpened(); m_bStartTableWizard = pDialog->IsTableWizardToBeStarted(); } diff --git a/dbaccess/uiconfig/ui/authentificationpage.ui b/dbaccess/uiconfig/ui/authentificationpage.ui index 0c1a6a44a3b0..3515cb813f6b 100644 --- a/dbaccess/uiconfig/ui/authentificationpage.ui +++ b/dbaccess/uiconfig/ui/authentificationpage.ui @@ -34,8 +34,8 @@ <property name="margin_bottom">6</property> <property name="label" translatable="yes" context="authentificationpage|helptext">Some databases require you to enter a user name.</property> <property name="wrap">True</property> - <property name="width_chars">60</property> - <property name="max_width_chars">60</property> + <property name="width_chars">72</property> + <property name="max_width_chars">72</property> <property name="xalign">0</property> </object> <packing> diff --git a/dbaccess/uiconfig/ui/databasewizard.ui b/dbaccess/uiconfig/ui/databasewizard.ui new file mode 100644 index 000000000000..5f07332a825e --- /dev/null +++ b/dbaccess/uiconfig/ui/databasewizard.ui @@ -0,0 +1,18 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Generated with glade 3.22.1 --> +<interface domain="dba"> + <requires lib="gtk+" version="3.20"/> + <object class="GtkAssistant" id="DatabaseWizard"> + <property name="can_focus">True</property> + <property name="border_width">6</property> + <property name="title" translatable="yes" context="databasewizard|DatabaseWizard">Database Wizard</property> + <property name="modal">True</property> + <property name="default_width">0</property> + <property name="default_height">0</property> + <property name="type_hint">dialog</property> + <property name="use_header_bar">0</property> + <child> + <placeholder/> + </child> + </object> +</interface> diff --git a/dbaccess/uiconfig/ui/dbasepage.ui b/dbaccess/uiconfig/ui/dbasepage.ui index dfe64734364e..244b754d48bc 100644 --- a/dbaccess/uiconfig/ui/dbasepage.ui +++ b/dbaccess/uiconfig/ui/dbasepage.ui @@ -120,8 +120,8 @@ <property name="can_focus">False</property> <property name="label" translatable="yes" context="dbasepage|specMessageLabel">Note: When deleted, and thus inactive, records are displayed, you will not be able to delete records from the data source.</property> <property name="wrap">True</property> - <property name="width_chars">60</property> - <property name="max_width_chars">60</property> + <property name="width_chars">72</property> + <property name="max_width_chars">72</property> <property name="xalign">0</property> </object> <packing> diff --git a/dbaccess/uiconfig/ui/dbwizconnectionpage.ui b/dbaccess/uiconfig/ui/dbwizconnectionpage.ui index 3d022c5307e7..81249794875d 100644 --- a/dbaccess/uiconfig/ui/dbwizconnectionpage.ui +++ b/dbaccess/uiconfig/ui/dbwizconnectionpage.ui @@ -33,7 +33,8 @@ <property name="margin_bottom">6</property> <property name="label" translatable="yes" context="dbwizconnectionpage|helptext">label</property> <property name="wrap">True</property> - <property name="max_width_chars">60</property> + <property name="width_chars">72</property> + <property name="max_width_chars">72</property> <property name="xalign">0</property> </object> <packing> @@ -46,6 +47,7 @@ <object class="GtkGrid" id="grid1"> <property name="visible">True</property> <property name="can_focus">False</property> + <property name="hexpand">True</property> <property name="row_spacing">6</property> <property name="column_spacing">12</property> <child> @@ -92,6 +94,7 @@ <object class="GtkGrid"> <property name="visible">True</property> <property name="can_focus">False</property> + <property name="hexpand">True</property> <child> <object class="GtkEntry" id="browseurl"> <property name="visible">True</property> diff --git a/dbaccess/uiconfig/ui/dbwizmysqlintropage.ui b/dbaccess/uiconfig/ui/dbwizmysqlintropage.ui index 8f1d39966b27..224f17189da2 100644 --- a/dbaccess/uiconfig/ui/dbwizmysqlintropage.ui +++ b/dbaccess/uiconfig/ui/dbwizmysqlintropage.ui @@ -23,7 +23,6 @@ <property name="visible">True</property> <property name="can_focus">False</property> <property name="top_padding">6</property> - <property name="left_padding">12</property> <child> <object class="GtkBox" id="box1"> <property name="visible">True</property> @@ -37,8 +36,8 @@ <property name="label" translatable="yes" context="dbwizmysqlintropage|label2">You can connect to a MySQL database using either ODBC or JDBC. Please contact your system administrator if you are unsure about the following settings.</property> <property name="wrap">True</property> - <property name="width_chars">100</property> - <property name="max_width_chars">100</property> + <property name="width_chars">72</property> + <property name="max_width_chars">72</property> <property name="xalign">0</property> </object> <packing> diff --git a/dbaccess/uiconfig/ui/dbwizmysqlnativepage.ui b/dbaccess/uiconfig/ui/dbwizmysqlnativepage.ui index 4eaa3ce7b4c1..5d2b38c6ecf4 100644 --- a/dbaccess/uiconfig/ui/dbwizmysqlnativepage.ui +++ b/dbaccess/uiconfig/ui/dbwizmysqlnativepage.ui @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8"?> -<!-- Generated with glade 3.18.3 --> +<!-- Generated with glade 3.22.1 --> <interface domain="dba"> <requires lib="gtk+" version="3.18"/> <object class="GtkBox" id="DBWizMysqlNativePage"> @@ -25,7 +25,6 @@ <property name="hexpand">True</property> <property name="vexpand">True</property> <property name="top_padding">6</property> - <property name="left_padding">12</property> <child> <object class="GtkBox" id="box1"> <property name="visible">True</property> @@ -37,10 +36,11 @@ <property name="visible">True</property> <property name="can_focus">False</property> <property name="halign">start</property> - <property name="xalign">0</property> <property name="label" translatable="yes" context="dbwizmysqlnativepage|helptext">Please enter the required information to connect to a MySQL database.</property> <property name="wrap">True</property> - <property name="max_width_chars">100</property> + <property name="width_chars">72</property> + <property name="max_width_chars">72</property> + <property name="xalign">0</property> </object> <packing> <property name="expand">False</property> diff --git a/dbaccess/uiconfig/ui/dbwizspreadsheetpage.ui b/dbaccess/uiconfig/ui/dbwizspreadsheetpage.ui index 2dbe3dd2eb6b..ed65d12b29dc 100644 --- a/dbaccess/uiconfig/ui/dbwizspreadsheetpage.ui +++ b/dbaccess/uiconfig/ui/dbwizspreadsheetpage.ui @@ -6,7 +6,6 @@ <property name="visible">True</property> <property name="can_focus">False</property> <property name="hexpand">True</property> - <property name="vexpand">True</property> <property name="border_width">6</property> <property name="orientation">vertical</property> <property name="spacing">12</property> @@ -24,7 +23,6 @@ <property name="hexpand">True</property> <property name="vexpand">True</property> <property name="top_padding">6</property> - <property name="left_padding">12</property> <child> <object class="GtkBox" id="box1"> <property name="visible">True</property> @@ -40,7 +38,8 @@ <property name="halign">start</property> <property name="hexpand">True</property> <property name="wrap">True</property> - <property name="max_width_chars">100</property> + <property name="width_chars">72</property> + <property name="max_width_chars">72</property> <property name="xalign">0</property> </object> <packing> @@ -100,10 +99,12 @@ <object class="GtkGrid"> <property name="visible">True</property> <property name="can_focus">False</property> + <property name="hexpand">True</property> <child> <object class="GtkEntry" id="browseurl"> <property name="visible">True</property> <property name="can_focus">True</property> + <property name="hexpand">True</property> <property name="activates_default">True</property> </object> <packing> @@ -127,6 +128,22 @@ <property name="top_attach">1</property> </packing> </child> + <child> + <object class="GtkCheckButton" id="passwordrequired"> + <property name="label" translatable="yes" context="dbwizspreadsheetpage|passwordrequired">_Password required</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">False</property> + <property name="use_underline">True</property> + <property name="xalign">0</property> + <property name="draw_indicator">True</property> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">2</property> + <property name="width">3</property> + </packing> + </child> </object> <packing> <property name="expand">True</property> @@ -154,21 +171,5 @@ <property name="position">0</property> </packing> </child> - <child> - <object class="GtkCheckButton" id="passwordrequired"> - <property name="label" translatable="yes" context="dbwizspreadsheetpage|passwordrequired">_Password required</property> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="receives_default">False</property> - <property name="use_underline">True</property> - <property name="xalign">0</property> - <property name="draw_indicator">True</property> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">True</property> - <property name="position">1</property> - </packing> - </child> </object> </interface> diff --git a/dbaccess/uiconfig/ui/dbwiztextpage.ui b/dbaccess/uiconfig/ui/dbwiztextpage.ui index bbb6600d4232..24b4e57a787f 100644 --- a/dbaccess/uiconfig/ui/dbwiztextpage.ui +++ b/dbaccess/uiconfig/ui/dbwiztextpage.ui @@ -24,7 +24,6 @@ <property name="hexpand">True</property> <property name="vexpand">True</property> <property name="top_padding">6</property> - <property name="left_padding">12</property> <child> <object class="GtkBox" id="box1"> <property name="visible">True</property> @@ -40,7 +39,8 @@ <property name="halign">start</property> <property name="hexpand">True</property> <property name="wrap">True</property> - <property name="max_width_chars">100</property> + <property name="width_chars">72</property> + <property name="max_width_chars">72</property> <property name="xalign">0</property> </object> <packing> @@ -100,10 +100,12 @@ <object class="GtkGrid"> <property name="visible">True</property> <property name="can_focus">False</property> + <property name="hexpand">True</property> <child> <object class="GtkEntry" id="browseurl"> <property name="visible">True</property> <property name="can_focus">True</property> + <property name="hexpand">True</property> </object> <packing> <property name="left_attach">1</property> @@ -158,8 +160,6 @@ <property name="visible">True</property> <property name="can_focus">False</property> <property name="hexpand">True</property> - <property name="vexpand">True</property> - <property name="border_width">6</property> <property name="orientation">vertical</property> <property name="spacing">12</property> <child> diff --git a/dbaccess/uiconfig/ui/finalpagewizard.ui b/dbaccess/uiconfig/ui/finalpagewizard.ui index 919421029fa1..8e065ea1faa0 100644 --- a/dbaccess/uiconfig/ui/finalpagewizard.ui +++ b/dbaccess/uiconfig/ui/finalpagewizard.ui @@ -2,28 +2,28 @@ <!-- Generated with glade 3.22.1 --> <interface domain="dba"> <requires lib="gtk+" version="3.18"/> - <object class="GtkBox" id="PageFinal"> - <property name="width_request">400</property> + <object class="GtkGrid" id="PageFinal"> <property name="visible">True</property> <property name="can_focus">False</property> - <property name="border_width">8</property> + <property name="hexpand">True</property> + <property name="vexpand">True</property> + <property name="border_width">6</property> <property name="orientation">vertical</property> - <property name="spacing">12</property> + <property name="row_spacing">12</property> <child> <object class="GtkLabel" id="headerText"> <property name="visible">True</property> <property name="can_focus">False</property> <property name="label" translatable="yes" context="finalpagewizard|headerText">Decide How to Proceed After Saving the Database</property> - <property name="wrap">True</property> + <property name="single_line_mode">True</property> <property name="xalign">0</property> <attributes> <attribute name="weight" value="bold"/> </attributes> </object> <packing> - <property name="expand">False</property> - <property name="fill">True</property> - <property name="position">0</property> + <property name="left_attach">0</property> + <property name="top_attach">0</property> </packing> </child> <child> @@ -42,7 +42,6 @@ <property name="can_focus">False</property> <property name="label" translatable="yes" context="finalpagewizard|helpText">Do you want the wizard to register the database in %PRODUCTNAME?</property> <property name="wrap">True</property> - <property name="wrap_mode">word-char</property> <property name="width_chars">72</property> <property name="max_width_chars">72</property> <property name="xalign">0</property> @@ -103,6 +102,7 @@ <property name="can_focus">False</property> <property name="label" translatable="yes" context="finalpagewizard|additionalText">After the database file has been saved, what do you want to do?</property> <property name="wrap">True</property> + <property name="width_chars">72</property> <property name="max_width_chars">72</property> <property name="xalign">0</property> </object> @@ -163,9 +163,8 @@ </child> </object> <packing> - <property name="expand">False</property> - <property name="fill">True</property> - <property name="position">1</property> + <property name="left_attach">0</property> + <property name="top_attach">1</property> </packing> </child> </object> diff --git a/dbaccess/uiconfig/ui/generalpagewizard.ui b/dbaccess/uiconfig/ui/generalpagewizard.ui index 8413935a4a34..32a666a71db9 100644 --- a/dbaccess/uiconfig/ui/generalpagewizard.ui +++ b/dbaccess/uiconfig/ui/generalpagewizard.ui @@ -2,34 +2,35 @@ <!-- Generated with glade 3.22.1 --> <interface domain="dba"> <requires lib="gtk+" version="3.18"/> - <object class="GtkBox" id="PageGeneral"> - <property name="width_request">400</property> + <object class="GtkGrid" id="PageGeneral"> <property name="visible">True</property> <property name="can_focus">False</property> - <property name="border_width">8</property> + <property name="hexpand">True</property> + <property name="vexpand">True</property> + <property name="border_width">6</property> <property name="orientation">vertical</property> - <property name="spacing">6</property> + <property name="row_spacing">6</property> <child> <object class="GtkLabel" id="headerText"> <property name="visible">True</property> <property name="can_focus">False</property> <property name="label" translatable="yes" context="generalpagewizard|headerText">Welcome to the %PRODUCTNAME Database Wizard</property> - <property name="wrap">True</property> + <property name="single_line_mode">True</property> <property name="xalign">0</property> <attributes> <attribute name="weight" value="bold"/> </attributes> </object> <packing> - <property name="expand">False</property> - <property name="fill">True</property> - <property name="position">0</property> + <property name="left_attach">0</property> + <property name="top_attach">0</property> </packing> </child> <child> <object class="GtkLabel" id="helpText"> <property name="visible">True</property> <property name="can_focus">False</property> + <property name="hexpand">True</property> <property name="label" translatable="yes" context="generalpagewizard|helpText">Use the Database Wizard to create a new database, open an existing database file, or connect to a database stored on a server.</property> <property name="wrap">True</property> <property name="width_chars">72</property> @@ -37,9 +38,8 @@ <property name="xalign">0</property> </object> <packing> - <property name="expand">False</property> - <property name="fill">True</property> - <property name="position">1</property> + <property name="left_attach">0</property> + <property name="top_attach">1</property> </packing> </child> <child> @@ -51,9 +51,8 @@ <property name="xalign">0</property> </object> <packing> - <property name="expand">False</property> - <property name="fill">True</property> - <property name="position">2</property> + <property name="left_attach">0</property> + <property name="top_attach">2</property> </packing> </child> <child> @@ -69,9 +68,8 @@ <property name="draw_indicator">True</property> </object> <packing> - <property name="expand">False</property> - <property name="fill">True</property> - <property name="position">3</property> + <property name="left_attach">0</property> + <property name="top_attach">3</property> </packing> </child> <child> @@ -108,9 +106,8 @@ </child> </object> <packing> - <property name="expand">False</property> - <property name="fill">True</property> - <property name="position">4</property> + <property name="left_attach">0</property> + <property name="top_attach">4</property> </packing> </child> <child> @@ -127,9 +124,8 @@ <property name="group">createDatabase</property> </object> <packing> - <property name="expand">False</property> - <property name="fill">True</property> - <property name="position">5</property> + <property name="left_attach">0</property> + <property name="top_attach">5</property> </packing> </child> <child> @@ -167,9 +163,8 @@ </child> </object> <packing> - <property name="expand">False</property> - <property name="fill">True</property> - <property name="position">6</property> + <property name="left_attach">0</property> + <property name="top_attach">6</property> </packing> </child> <child> @@ -183,9 +178,8 @@ <property name="always_show_image">True</property> </object> <packing> - <property name="expand">False</property> - <property name="fill">True</property> - <property name="position">7</property> + <property name="left_attach">0</property> + <property name="top_attach">7</property> </packing> </child> <child> @@ -202,9 +196,8 @@ <property name="group">createDatabase</property> </object> <packing> - <property name="expand">False</property> - <property name="fill">True</property> - <property name="position">8</property> + <property name="left_attach">0</property> + <property name="top_attach">8</property> </packing> </child> <child> @@ -215,9 +208,8 @@ <property name="margin_left">24</property> </object> <packing> - <property name="expand">False</property> - <property name="fill">True</property> - <property name="position">9</property> + <property name="left_attach">0</property> + <property name="top_attach">9</property> </packing> </child> <child> @@ -226,9 +218,8 @@ <property name="xalign">0</property> </object> <packing> - <property name="expand">False</property> - <property name="fill">True</property> - <property name="position">10</property> + <property name="left_attach">0</property> + <property name="top_attach">10</property> </packing> </child> </object> diff --git a/dbaccess/uiconfig/ui/jdbcconnectionpage.ui b/dbaccess/uiconfig/ui/jdbcconnectionpage.ui index 0df26ed00151..9e55d4e0e7ae 100644 --- a/dbaccess/uiconfig/ui/jdbcconnectionpage.ui +++ b/dbaccess/uiconfig/ui/jdbcconnectionpage.ui @@ -33,7 +33,8 @@ <property name="can_focus">False</property> <property name="label" translatable="yes" context="jdbcconnectionpage|helptext">Please enter the required information to connect to a JDBC database. Please contact your system administrator if you are unsure about the following settings.</property> <property name="wrap">True</property> - <property name="max_width_chars">60</property> + <property name="width_chars">72</property> + <property name="max_width_chars">72</property> <property name="xalign">0</property> </object> <packing> diff --git a/dbaccess/uiconfig/ui/ldapconnectionpage.ui b/dbaccess/uiconfig/ui/ldapconnectionpage.ui index e386c06102d2..a64373d9d43e 100644 --- a/dbaccess/uiconfig/ui/ldapconnectionpage.ui +++ b/dbaccess/uiconfig/ui/ldapconnectionpage.ui @@ -37,8 +37,8 @@ <property name="can_focus">False</property> <property name="label" translatable="yes" context="ldapconnectionpage|helpLabel">Please enter the required information to connect to an LDAP directory. Please contact your system administrator if you are unsure about the following settings.</property> <property name="wrap">True</property> - <property name="width_chars">80</property> - <property name="max_width_chars">80</property> + <property name="width_chars">72</property> + <property name="max_width_chars">72</property> <property name="xalign">0</property> </object> <packing> diff --git a/dbaccess/uiconfig/ui/specialjdbcconnectionpage.ui b/dbaccess/uiconfig/ui/specialjdbcconnectionpage.ui index 8fa89c34d21c..c63f6a2c03e4 100644 --- a/dbaccess/uiconfig/ui/specialjdbcconnectionpage.ui +++ b/dbaccess/uiconfig/ui/specialjdbcconnectionpage.ui @@ -38,8 +38,8 @@ <property name="can_focus">False</property> <property name="label" translatable="yes" context="specialjdbcconnectionpage|helpLabel">Please enter the required information to connect to a MySQL database using JDBC. Note that a JDBC driver class must be installed on your system and registered with %PRODUCTNAME. Please contact your system administrator if you are unsure about the following settings. </property> <property name="wrap">True</property> - <property name="width_chars">80</property> - <property name="max_width_chars">80</property> + <property name="width_chars">72</property> + <property name="max_width_chars">72</property> <property name="xalign">0</property> </object> <packing> @@ -133,6 +133,7 @@ <property name="visible">True</property> <property name="can_focus">True</property> <property name="hexpand">True</property> + <property name="activates_default">True</property> <property name="adjustment">adjustment1</property> </object> <packing> diff --git a/include/svtools/helpids.h b/include/svtools/helpids.h index 0c296ba613c2..ce1b29cf6cd6 100644 --- a/include/svtools/helpids.h +++ b/include/svtools/helpids.h @@ -45,9 +45,6 @@ #define HID_FILEOPEN_IMAGE_TEMPLATE "SVT_HID_FILEOPEN_IMAGE_TEMPLATE" #define HID_FILEOPEN_IMAGE_ANCHOR "SVT_HID_FILEOPEN_IMAGE_ANCHOR" -#define HID_WIZARD_NEXT "SVT_HID_WIZARD_NEXT" -#define HID_WIZARD_PREVIOUS "SVT_HID_WIZARD_PREVIOUS" - #endif /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/include/tools/wintypes.hxx b/include/tools/wintypes.hxx index 4fa4eab908f9..5bcaec41aa17 100644 --- a/include/tools/wintypes.hxx +++ b/include/tools/wintypes.hxx @@ -257,7 +257,10 @@ enum class StandardButtonType Ignore = 8, Abort = 9, Less = 10, - Count = 11, + Back = 11, + Next = 12, + Finish = 13, + Count = 14, }; // prominent place for ListBox window types diff --git a/include/vcl/roadmapwizard.hxx b/include/vcl/roadmapwizard.hxx index 6764d40f8c6e..df0632af5085 100644 --- a/include/vcl/roadmapwizard.hxx +++ b/include/vcl/roadmapwizard.hxx @@ -75,6 +75,12 @@ namespace vcl void SetRoadmapInteractive( bool _bInteractive ); + void InsertRoadmapItem(int nIndex, const OUString& rLabel, int nId, bool bEnabled); + void DeleteRoadmapItems(); + int GetCurrentRoadmapItemID() const; + void SelectRoadmapItemByID(int nId); + void SetItemSelectHdl( const Link<LinkParamNone*,void>& _rHdl ); + // returns whether a given state is enabled bool isStateEnabled( WizardState _nState ) const; @@ -213,6 +219,146 @@ namespace vcl VCL_DLLPRIVATE void impl_construct(); }; + class VCL_DLLPUBLIC RoadmapWizardMachine : public vcl::WizardMachine, public RoadmapWizardTypes + { + private: + std::unique_ptr<RoadmapWizardImpl> m_pImpl; + + public: + RoadmapWizardMachine(weld::Window* _pParent); + virtual ~RoadmapWizardMachine( ) override; + + void SetRoadmapHelpId( const OString& _rId ); + + void SetRoadmapInteractive( bool _bInteractive ); + + // returns whether a given state is enabled + bool isStateEnabled( WizardState _nState ) const; + + // WizardDialog overridables + virtual bool canAdvance() const override; + virtual void updateTravelUI() override; + + protected: + /** declares a valid path in the wizard + + The very first path which is declared is automatically activated. + + Note that all paths which are declared must have the very first state in + common. Also note that due to a restriction of the very base class (WizardDialog), + this common first state must be 0. + + You cannot declare new paths once the wizard started, so it's recommended that + you do all declarations within your derivee's constructor. + + @see activatePath + + @param _nId + the unique id you wish to give this path. This id can later on be used + to refer to the path which you just declared + */ + void declarePath( PathId _nPathId, const WizardPath& _lWizardStates); + + /** provides basic information about a state + + The given display name is used in the default implementation of getStateDisplayName, + and the given factory is used in the default implementation of createPage. + */ + void describeState( WizardState _nState, const OUString& _rStateDisplayName, RoadmapPageFactory _pPageFactory ); + + /** activates a path which has previously been declared with <member>declarePath</member> + + You can only activate paths which share the first <code>k</code> states with the path + which is previously active (if any), where <code>k</code> is the index of the + current state within the current path. + + <example> + Say you have paths, <code>(0,1,2,5)</code> and <code>(0,1,4,5)</code>. This means that after + step <code>1</code>, you either continue with state <code>2</code> or state <code>4</code>, + and after this, you finish in state <code>5</code>.<br/> + Now if the first path is active, and your current state is <code>1</code>, then you can + easily switch to the second path, since both paths start with <code>(0,1)</code>.<br/> + However, if your current state is <code>2</code>, then you can not switch to the second + path anymore. + </example> + + @param _nPathId + the id of the path. The path must have been declared (under this id) with + <member>declarePath</member> before it can be activated. + + @param _bDecideForIt + If <TRUE/>, the path will be completely activated, even if it is a conflicting path + (i.e. there is another path which shares the first <code>k</code> states with + the to-be-activated path.)<br/> + If <FALSE/>, then the new path is checked for conflicts with other paths. If such + conflicts exists, the path is not completely activated, but only up to the point + where it does <em>not</em> conflict.<br/> + With the paths in the example above, if you activate the second path (when both are + already declared), then only steps <code>0</code> and <code>1</code> are activated, + since they are common to both paths. + */ + void activatePath( PathId _nPathId, bool _bDecideForIt = false ); + + /** determine the next state to travel from the given one + + This method (which is declared in OWizardMachine and overwritten here) + ensures that traveling happens along the active path. + + @see activatePath + */ + virtual WizardState determineNextState( WizardState _nCurrentState ) const override; + + /** en- or disables a state + + In the wizard's roadmap, states to travel to can be freely chosen. To prevent + users from selecting a state which is currently not available, you can declare this + state as being disabled. + + A situation where you need this may be when you have a checkbox which, when checked + by the user, enables a page with additional settings. As long as this checkbox is + not checked, the respective state would be disabled. + + Note that in theory, you can declare multiple paths, instead of disabling states. + For instance, if you have a path where one state can be potentially disabled, then + you could declare a second path, which does not contain this state. However, the + disadvantage is that then, not the complete path would be visible in the roadmap, + but only all steps up to the point where the both paths diverge.<br/> + Another disadvantage is that the number of needed paths grows exponentially with + the number of states which can be potentially disabled. + + @see declarePath + */ + void enableState( WizardState _nState, bool _bEnable = true ); + + /** returns true if and only if the given state is known in at least one declared path + */ + bool knowsState( WizardState _nState ) const; + + // OWizardMachine overriables + virtual void enterState( WizardState _nState ) override; + + /** returns a human readable name for a given state + + There is a default implementation for this method, which returns the display name + as given in a call to describeState. If there is no description for the given state, + this is worth an assertion in a non-product build, and then an empty string is + returned. + */ + virtual OUString getStateDisplayName( WizardState _nState ) const; + + /** asks for a new label of the wizard page + + */ + void updateRoadmapItemLabel( WizardState _nState ); + + private: + DECL_DLLPRIVATE_LINK( OnRoadmapItemSelected, const OString&, bool ); + + /** updates the roadmap control to show the given path, as far as possible + (modulo conflicts with other paths) + */ + VCL_DLLPRIVATE void implUpdateRoadmap( ); + }; } // namespace vcl diff --git a/include/vcl/vclenum.hxx b/include/vcl/vclenum.hxx index 1e8f59428e3f..c7ced830da49 100644 --- a/include/vcl/vclenum.hxx +++ b/include/vcl/vclenum.hxx @@ -273,6 +273,21 @@ enum class VclPolicyType NEVER }; +enum class WizardButtonFlags : sal_Int16 +{ + NONE = 0x0000, + NEXT = 0x0001, + PREVIOUS = 0x0002, + FINISH = 0x0004, + CANCEL = 0x0008, + HELP = 0x0010, +}; + +namespace o3tl +{ + template<> struct typed_flags<WizardButtonFlags> : is_typed_flags<WizardButtonFlags, 0x001f> {}; +} + #endif // INCLUDED_VCL_VCLENUM_HXX /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/include/vcl/weld.hxx b/include/vcl/weld.hxx index 198b7a72f0d6..d4b688243c68 100644 --- a/include/vcl/weld.hxx +++ b/include/vcl/weld.hxx @@ -250,6 +250,8 @@ class VCL_DLLPUBLIC Container : virtual public Widget public: //remove and add in one go virtual void move(weld::Widget* pWidget, weld::Container* pNewParent) = 0; + //recursively unset has-default on any buttons in the widget hierarchy + virtual void recursively_unset_default_buttons() = 0; }; class VCL_DLLPUBLIC ScrolledWindow : virtual public Container @@ -423,7 +425,7 @@ public: virtual void add_button(const OUString& rText, int response, const OString& rHelpId = OString()) = 0; virtual void set_default_response(int response) = 0; - virtual Button* get_widget_for_response(int response) = 0; + virtual Button* weld_widget_for_response(int response) = 0; virtual Container* weld_content_area() = 0; // shrink the dialog down to shown just these widgets @@ -457,6 +459,30 @@ public: virtual void set_background(const css::uno::Reference<css::graphic::XGraphic>& rImage) = 0; }; +class VCL_DLLPUBLIC Assistant : virtual public Dialog +{ +protected: + Link<const OString&, bool> m_aJumpPageHdl; + + bool signal_jump_page(const OString& rIdent) { return m_aJumpPageHdl.Call(rIdent); } + +public: + virtual int get_current_page() const = 0; + virtual int get_n_pages() const = 0; + virtual OString get_page_ident(int nPage) const = 0; + virtual OString get_current_page_ident() const = 0; + virtual void set_current_page(int nPage) = 0; + virtual void set_current_page(const OString& rIdent) = 0; + // move the page rIdent to position nIndex + virtual void set_page_index(const OString& rIdent, int nIndex) = 0; + virtual void set_page_title(const OString& rIdent, const OUString& rTitle) = 0; + virtual OUString get_page_title(const OString& rIdent) const = 0; + virtual void set_page_sensitive(const OString& rIdent, bool bSensitive) = 0; + virtual weld::Container* append_page(const OString& rIdent) = 0; + + void connect_jump_page(const Link<const OString&, bool>& rLink) { m_aJumpPageHdl = rLink; } +}; + struct VCL_DLLPUBLIC ComboBoxEntry { OUString sString; @@ -1785,6 +1811,8 @@ public: virtual std::unique_ptr<AboutDialog> weld_about_dialog(const OString& id, bool bTakeOwnership = true) = 0; + virtual std::unique_ptr<Assistant> weld_assistant(const OString& id, bool bTakeOwnership = true) + = 0; virtual std::unique_ptr<Window> weld_window(const OString& id, bool bTakeOwnership = true) = 0; virtual std::unique_ptr<Widget> weld_widget(const OString& id, bool bTakeOwnership = false) = 0; virtual std::unique_ptr<Container> weld_container(const OString& id, @@ -1907,6 +1935,18 @@ public: OUString get_primary_text() const { return m_xDialog->get_primary_text(); } void set_default_response(int nResponse) { m_xDialog->set_default_response(nResponse); } }; + +class VCL_DLLPUBLIC AssistantController : public DialogController +{ +protected: + std::unique_ptr<weld::Builder> m_xBuilder; + std::unique_ptr<weld::Assistant> m_xAssistant; + +public: + AssistantController(weld::Widget* pParent, const OUString& rUIFile, const OString& rDialogId); + virtual Dialog* getDialog() override; + virtual ~AssistantController() override; +}; } #endif diff --git a/include/vcl/wizardmachine.hxx b/include/vcl/wizardmachine.hxx index 0b0afbce1576..c840af3f0745 100644 --- a/include/vcl/wizardmachine.hxx +++ b/include/vcl/wizardmachine.hxx @@ -31,20 +31,6 @@ namespace weld { class Container; } -enum class WizardButtonFlags -{ - NONE = 0x0000, - NEXT = 0x0001, - PREVIOUS = 0x0002, - FINISH = 0x0004, - CANCEL = 0x0008, - HELP = 0x0010, -}; -namespace o3tl -{ - template<> struct typed_flags<WizardButtonFlags> : is_typed_flags<WizardButtonFlags, 0x001f> {}; -} - namespace vcl { @@ -152,9 +138,6 @@ namespace vcl class VCL_DLLPUBLIC OWizardMachine : public WizardDialog, public WizardTypes { private: - // restrict access to some aspects of our base class - using WizardDialog::AddPage; - using WizardDialog::SetPage; // TabPage* GetPage( sal_uInt16 nLevel ) const { return WizardDialog::GetPage(nLevel); } // TODO: probably the complete page handling (next, previous etc.) should be prohibited ... @@ -163,7 +146,7 @@ namespace vcl // here (e.g. committing page data) depend on having full control over page traveling. // So use the travelXXX methods if you need to travel - protected: + public: VclPtr<OKButton> m_pFinish; VclPtr<CancelButton> m_pCancel; VclPtr<PushButton> m_pNextPage; @@ -358,23 +341,245 @@ namespace vcl VCL_DLLPRIVATE void implConstruct( const WizardButtonFlags _nButtonFlags ); }; + class VCL_DLLPUBLIC WizardMachine : public weld::AssistantController, public WizardTypes + { + private: + VclPtr<TabPage> m_xCurTabPage; + + WizardState m_nCurState; + ImplWizPageData* m_pFirstPage; + + protected: + std::unique_ptr<weld::Button> m_xFinish; + std::unique_ptr<weld::Button> m_xCancel; + std::unique_ptr<weld::Button> m_xNextPage; + std::unique_ptr<weld::Button> m_xPrevPage; + std::unique_ptr<weld::Button> m_xHelp; + + private: + // hold members in this structure to allow keeping compatible when members are added + std::unique_ptr<WizardMachineImplData> m_pImpl; + + public: + WizardMachine(weld::Window* _pParent, WizardButtonFlags _nButtonFlags ); + virtual ~WizardMachine() override; + + bool Finish(short nResult = RET_CANCEL); + bool ShowPage(WizardState nState); + + void AddPage( TabPage* pPage ); + void SetPage( WizardState nLevel, TabPage* pPage ); + TabPage* GetPage( WizardState eState ) const; + + /// enable (or disable) buttons + void enableButtons(WizardButtonFlags _nWizardButtonFlags, bool _bEnable); + /// set the default style for a button + void defaultButton(WizardButtonFlags _nWizardButtonFlags); + /// set the default style for a button + void defaultButton(weld::Button* _pNewDefButton); + + /// set the base of the title to use - the title of the current page is appended + void setTitleBase(const OUString& _rTitleBase); + + /// determines whether there is a next state to which we can advance + virtual bool canAdvance() const; + + /** updates the user interface which deals with traveling in the wizard + + The default implementation simply checks whether both the current page and the wizard + itself allow to advance to the next state (<code>canAdvance</code>), and enables the "Next" + button if and only if this is the case. + */ + virtual void updateTravelUI(); + + protected: + // WizardDialog overridables + virtual void ActivatePage(); + virtual bool DeactivatePage(); + + // our own overridables + + /// to override to create new pages + virtual VclPtr<TabPage> createPage(WizardState _nState) = 0; + + /// will be called when a new page is about to be displayed + virtual void enterState(WizardState _nState); + + /** will be called when the current state is about to be left for the given reason + + The base implementation in this class will simply call <member>OWizardPage::commitPage</member> + for the current page, and return whatever this call returns. + + @param _eReason + The reason why the state is to be left. + @return + <TRUE/> if and only if the page is allowed to be left + */ + virtual bool prepareLeaveCurrentState( CommitPageReason _eReason ); + + /** will be called when the given state is left + + This is the very last possibility for derived classes to veto the deactivation + of a page. + + @todo Normally, we would not need the return value here - derived classes now have + the possibility to veto page deactivations in <member>prepareLeaveCurrentState</member>. However, + changing this return type is too incompatible at the moment ... + + @return + <TRUE/> if and only if the page is allowed to be left + */ + virtual bool leaveState( WizardState _nState ); + + /** determine the next state to travel from the given one + + The default behaviour is linear traveling, overwrite this to change it + + Return WZS_INVALID_STATE to prevent traveling. + */ + virtual WizardState determineNextState( WizardState _nCurrentState ) const; + + /** called when the finish button is pressed + <p>By default, only the base class' Finish method (which is not virtual) is called</p> + */ + virtual bool onFinish(); + + /// travel to the next state + bool travelNext(); + + /// travel to the previous state + bool travelPrevious(); + + /** enables the automatic enabled/disabled state of the "Next" button + + If this is <TRUE/>, then upon entering a new state, the "Next" button will automatically be + enabled if and only if determineNextState does not return WZS_INVALID_STATE. + */ + void enableAutomaticNextButtonState(); + bool isAutomaticNextButtonStateEnabled() const; + + /** removes a page from the history. Should be called when the page is being disabled + */ + void removePageFromHistory( WizardState nToRemove ); + + /** skip a state + + The method behaves as if from the current state, <arg>_nSteps</arg> <method>travelNext</method>s were + called, but without actually creating or displaying the \EDntermediate pages. Only the + (<arg>_nSteps</arg> + 1)th page is created. + + The skipped states appear in the state history, so <method>travelPrevious</method> will make use of them. + + A very essential precondition for using this method is that your <method>determineNextState</method> + method is able to determine the next state without actually having the page of the current state. + + @see skipUntil + @see skipBackwardUntil + */ + void skip(); + + /** skips one or more states, until a given state is reached + + The method behaves as if from the current state, <method>travelNext</method>s were called + successively, until <arg>_nTargetState</arg> is reached, but without actually creating or + displaying the \EDntermediate pages. + + The skipped states appear in the state history, so <method>travelPrevious</method> will make use of them. + + @return + <TRUE/> if and only if traveling was successful + + @see skip + @see skipBackwardUntil + */ + bool skipUntil( WizardState _nTargetState ); + + /** moves back one or more states, until a given state is reached + + This method allows traveling backwards more than one state without actually showing the intermediate + states. + + For instance, if you want to travel two steps backward at a time, you could used + two travelPrevious calls, but this would <em>show</em> both pages, which is not necessary, + since you're interested in the target page only. Using <member>skipBackwardUntil</member> relieves + you of this. + + @return + <TRUE/> if and only if traveling was successful + + @see skipUntil + @see skip + */ + bool skipBackwardUntil( WizardState _nTargetState ); + + /** returns the current state of the machine + + Vulgo, this is the identifier of the current tab page :) + */ + WizardState getCurrentState() const { return m_nCurState; } + + virtual IWizardPageController* + getPageController( TabPage* _pCurrentPage ) const; + + /** retrieves a copy of the state history, i.e. all states we already visited + */ + void getStateHistory( ::std::vector< WizardState >& _out_rHistory ); + + public: + class AccessGuard + { + friend class WizardTravelSuspension; + private: + AccessGuard() { } + }; + + void suspendTraveling( AccessGuard ); + void resumeTraveling( AccessGuard ); + bool isTravelingSuspended() const; + + protected: + TabPage* GetOrCreatePage( const WizardState i_nState ); + + private: + DECL_DLLPRIVATE_LINK(OnNextPage, weld::Button&, void); + DECL_DLLPRIVATE_LINK(OnPrevPage, weld::Button&, void); + DECL_DLLPRIVATE_LINK(OnFinish, weld::Button&, void); + DECL_DLLPRIVATE_LINK(OnCancel, weld::Button&, void); + + VCL_DLLPRIVATE void implUpdateTitle(); + VCL_DLLPRIVATE void implConstruct( const WizardButtonFlags _nButtonFlags ); + }; + + /// helper class to temporarily suspend any traveling in the wizard class WizardTravelSuspension { public: - WizardTravelSuspension( OWizardMachine& _rWizard ) - :m_rWizard( _rWizard ) + WizardTravelSuspension(OWizardMachine& rWizard) + : m_pOWizard(&rWizard) + , m_pWizard(nullptr) + { + m_pOWizard->suspendTraveling(OWizardMachine::AccessGuard()); + } + + WizardTravelSuspension(WizardMachine& rWizard) + : m_pOWizard(nullptr) + , m_pWizard(&rWizard) { - m_rWizard.suspendTraveling( OWizardMachine::AccessGuard() ); + m_pWizard->suspendTraveling(WizardMachine::AccessGuard()); } ~WizardTravelSuspension() { - m_rWizard.resumeTraveling( OWizardMachine::AccessGuard() ); + if (m_pOWizard) + m_pOWizard->resumeTraveling(OWizardMachine::AccessGuard()); + if (m_pWizard) + m_pWizard->resumeTraveling(WizardMachine::AccessGuard()); } private: - OWizardMachine& m_rWizard; + VclPtr<OWizardMachine> m_pOWizard; + WizardMachine* m_pWizard; }; diff --git a/vcl/source/app/salvtables.cxx b/vcl/source/app/salvtables.cxx index 66b5e3d1bbe2..e0f3ad3f35c3 100644 --- a/vcl/source/app/salvtables.cxx +++ b/vcl/source/app/salvtables.cxx @@ -50,6 +50,7 @@ #include <vcl/menubtn.hxx> #include <vcl/prgsbar.hxx> #include <vcl/ptrstyle.hxx> +#include <vcl/roadmapwizard.hxx> #include <vcl/slider.hxx> #include <vcl/sysdata.hxx> #include <vcl/svimpbox.hxx> @@ -966,6 +967,35 @@ class SalInstanceContainer : public SalInstanceWidget, public virtual weld::Cont { private: VclPtr<vcl::Window> m_xContainer; + + void implResetDefault(const vcl::Window* _pWindow) + { + vcl::Window* pChildLoop = _pWindow->GetWindow(GetWindowType::FirstChild); + while (pChildLoop) + { + // does the window participate in the tabbing order? + if (pChildLoop->GetStyle() & WB_DIALOGCONTROL) + implResetDefault(pChildLoop); + + // is it a button? + WindowType eType = pChildLoop->GetType(); + if ( (WindowType::PUSHBUTTON == eType) + || (WindowType::OKBUTTON == eType) + || (WindowType::CANCELBUTTON == eType) + || (WindowType::HELPBUTTON == eType) + || (WindowType::IMAGEBUTTON == eType) + || (WindowType::MENUBUTTON == eType) + || (WindowType::MOREBUTTON == eType) + ) + { + pChildLoop->SetStyle(pChildLoop->GetStyle() & ~WB_DEFBUTTON); + } + + // the next one ... + pChildLoop = pChildLoop->GetWindow(GetWindowType::Next); + } + } + public: SalInstanceContainer(vcl::Window* pContainer, SalInstanceBuilder* pBuilder, bool bTakeOwnership) : SalInstanceWidget(pContainer, pBuilder, bTakeOwnership) @@ -980,6 +1010,10 @@ public: assert(!pNewParent || pNewVclParent); pVclWidget->getWidget()->SetParent(pNewVclParent ? pNewVclParent->getWidget() : nullptr); } + virtual void recursively_unset_default_buttons() override + { + implResetDefault(m_xContainer.get()); + } }; std::unique_ptr<weld::Container> SalInstanceWidget::weld_parent() const @@ -1358,7 +1392,7 @@ public: return m_xDialog->IsModalInputMode(); } - virtual weld::Button* get_widget_for_response(int nResponse) override; + virtual weld::Button* weld_widget_for_response(int nResponse) override; virtual void set_default_response(int nResponse) override { @@ -1448,6 +1482,218 @@ public: } }; +class SalInstanceAssistant : public SalInstanceDialog, public virtual weld::Assistant +{ +private: + VclPtr<vcl::RoadmapWizard> m_xWizard; + std::vector<std::unique_ptr<SalInstanceContainer>> m_aPages; + std::vector<VclPtr<TabPage>> m_aAddedPages; + std::vector<int> m_aIds; + std::vector<VclPtr<VclGrid>> m_aAddedGrids; + Idle m_aUpdateRoadmapIdle; + + int find_page(const OString& rIdent) const + { + for (size_t i = 0; i < m_aAddedPages.size(); ++i) + { + if (m_aAddedPages[i]->get_id().toUtf8() == rIdent) + return i; + } + return -1; + } + + int find_id(int nId) const + { + for (size_t i = 0; i < m_aIds.size(); ++i) + { + if (nId == m_aIds[i]) + return i; + } + return -1; + } + + DECL_LINK(OnRoadmapItemSelected, LinkParamNone*, void); + DECL_LINK(UpdateRoadmap_Hdl, Timer*, void); + +public: + SalInstanceAssistant(vcl::RoadmapWizard* pDialog, SalInstanceBuilder* pBuilder, bool bTakeOwnership) + : SalInstanceDialog(pDialog, pBuilder, bTakeOwnership) + , m_xWizard(pDialog) + { + m_xWizard->SetItemSelectHdl(LINK(this, SalInstanceAssistant, OnRoadmapItemSelected)); + + m_aUpdateRoadmapIdle.SetInvokeHandler(LINK(this, SalInstanceAssistant, UpdateRoadmap_Hdl)); + m_aUpdateRoadmapIdle.SetPriority(TaskPriority::HIGHEST); + } + + virtual int get_current_page() const override + { + return find_id(m_xWizard->GetCurLevel()); + } + + virtual int get_n_pages() const override + { + return m_aAddedPages.size(); + } + + virtual OString get_page_ident(int nPage) const override + { + return m_aAddedPages[nPage]->get_id().toUtf8(); + } + + virtual OString get_current_page_ident() const override + { + return get_page_ident(get_current_page()); + } + + virtual void set_current_page(int nPage) override + { + disable_notify_events(); + + // take the first shown page as the size for all pages + if (m_xWizard->GetPageSizePixel().Width() == 0) + { + TabPage* pPage = m_xWizard->GetPage(m_aIds[nPage]); + assert(pPage); + Size aPageSize(pPage->get_preferred_size()); + m_xWizard->SetPageSizePixel(aPageSize); + } + + m_xWizard->ShowPage(m_aIds[nPage]); + enable_notify_events(); + } + + virtual void set_current_page(const OString& rIdent) override + { + int nIndex = find_page(rIdent); + if (nIndex == -1) + return; + set_current_page(nIndex); + } + + virtual void set_page_index(const OString& rIdent, int nNewIndex) override + { + int nOldIndex = find_page(rIdent); + + if (nOldIndex == -1) + return; + + if (nOldIndex == nNewIndex) + return; + + disable_notify_events(); + + auto entry = std::move(m_aAddedPages[nOldIndex]); + m_aAddedPages.erase(m_aAddedPages.begin() + nOldIndex); + m_aAddedPages.insert(m_aAddedPages.begin() + nNewIndex, std::move(entry)); + + int nId = m_aIds[nOldIndex]; + m_aIds.erase(m_aIds.begin() + nOldIndex); + m_aIds.insert(m_aIds.begin() + nNewIndex, nId); + + m_aUpdateRoadmapIdle.Start(); + + enable_notify_events(); + } + + virtual weld::Container* append_page(const OString& rIdent) override + { + VclPtrInstance<TabPage> xPage(m_xWizard); + VclPtrInstance<VclGrid> xGrid(xPage); + xPage->set_id(OUString::fromUtf8(rIdent)); + xPage->Show(); + xGrid->set_hexpand(true); + xGrid->set_vexpand(true); + xGrid->Show(); + m_xWizard->AddPage(xPage); + m_aIds.push_back(m_aAddedPages.size()); + m_xWizard->SetPage(m_aIds.back(), xPage); + m_aAddedPages.push_back(xPage); + m_aAddedGrids.push_back(xGrid); + + m_aUpdateRoadmapIdle.Start(); + + m_aPages.emplace_back(new SalInstanceContainer(xGrid, m_pBuilder, false)); + return m_aPages.back().get(); + } + + virtual OUString get_page_title(const OString& rIdent) const override + { + int nIndex = find_page(rIdent); + if (nIndex == -1) + return OUString(); + return m_aAddedPages[nIndex]->GetText(); + } + + virtual void set_page_title(const OString& rIdent, const OUString& rTitle) override + { + int nIndex = find_page(rIdent); + if (nIndex == -1) + return; + if (m_aAddedPages[nIndex]->GetText() != rTitle) + { + disable_notify_events(); + m_aAddedPages[nIndex]->SetText(rTitle); + m_aUpdateRoadmapIdle.Start(); + enable_notify_events(); + } + } + + virtual void set_page_sensitive(const OString& rIdent, bool bSensitive) override + { + int nIndex = find_page(rIdent); + if (nIndex == -1) + return; + if (m_aAddedPages[nIndex]->IsEnabled() != bSensitive) + { + disable_notify_events(); + m_aAddedPages[nIndex]->Enable(bSensitive); + m_aUpdateRoadmapIdle.Start(); + enable_notify_events(); + } + } + + weld::Button* weld_widget_for_response(int nResponse) override; + + virtual ~SalInstanceAssistant() override + { + for (auto &rGrid : m_aAddedGrids) + rGrid.disposeAndClear(); + for (auto &rPage : m_aAddedPages) + rPage.disposeAndClear(); + } +}; + +IMPL_LINK_NOARG(SalInstanceAssistant, OnRoadmapItemSelected, LinkParamNone*, void) +{ + if (notify_events_disabled()) + return; + int nPageIndex(find_id(m_xWizard->GetCurrentRoadmapItemID())); + if (!signal_jump_page(get_page_ident(nPageIndex))) + m_xWizard->SelectRoadmapItemByID(m_xWizard->GetCurLevel()); +} + +IMPL_LINK_NOARG(SalInstanceAssistant, UpdateRoadmap_Hdl, Timer*, void) +{ + disable_notify_events(); + + m_xWizard->DeleteRoadmapItems(); + + int nPos = 0; + for (size_t i = 0; i < m_aAddedPages.size(); ++i) + { + const OUString& rLabel = m_aAddedPages[i]->GetText(); + bool bSensitive = m_aAddedPages[i]->IsEnabled(); + if (rLabel.isEmpty()) + continue; + m_xWizard->InsertRoadmapItem(nPos++, rLabel, m_aIds[i], bSensitive); + } + + m_xWizard->SelectRoadmapItemByID(m_aIds[get_current_page()]); + + enable_notify_events(); +} + class SalInstanceFrame : public SalInstanceContainer, public virtual weld::Frame { private: @@ -1978,12 +2224,30 @@ IMPL_LINK(SalInstanceButton, ClickHdl, ::Button*, pButton, void) signal_clicked(); } -weld::Button* SalInstanceDialog::get_widget_for_response(int nResponse) +weld::Button* SalInstanceDialog::weld_widget_for_response(int nResponse) { PushButton* pButton = dynamic_cast<PushButton*>(m_xDialog->get_widget_for_response(nResponse)); return pButton ? new SalInstanceButton(pButton, nullptr, false) : nullptr; } +weld::Button* SalInstanceAssistant::weld_widget_for_response(int nResponse) +{ + PushButton* pButton = nullptr; + if (nResponse == static_cast<int>(WizardButtonFlags::NEXT)) + pButton = m_xWizard->m_pNextPage; + else if (nResponse == static_cast<int>(WizardButtonFlags::PREVIOUS)) + pButton = m_xWizard->m_pPrevPage; + else if (nResponse == static_cast<int>(WizardButtonFlags::FINISH)) + pButton = m_xWizard->m_pFinish; + else if (nResponse == static_cast<int>(WizardButtonFlags::CANCEL)) + pButton = m_xWizard->m_pCancel; + else if (nResponse == static_cast<int>(WizardButtonFlags::HELP)) + pButton = m_xWizard->m_pHelp; + if (pButton) + return new SalInstanceButton(pButton, nullptr, false); + return nullptr; +} + class SalInstanceMenuButton : public SalInstanceButton, public virtual weld::MenuButton { private: @@ -5286,6 +5550,19 @@ public: return pRet; } + virtual std::unique_ptr<weld::Assistant> weld_assistant(const OString &id, bool bTakeOwnership) override + { + vcl::RoadmapWizard* pDialog = m_xBuilder->get<vcl::RoadmapWizard>(id); + std::unique_ptr<weld::Assistant> pRet(pDialog ? new SalInstanceAssistant(pDialog, this, false) : nullptr); + if (bTakeOwnership && pDialog) + { + assert(!m_aOwnedToplevel && "only one toplevel per .ui allowed"); + m_aOwnedToplevel.set(pDialog); + m_xBuilder->drop_ownership(pDialog); + } + return pRet; + } + virtual std::unique_ptr<weld::Window> weld_window(const OString &id, bool bTakeOwnership) override { SystemWindow* pWindow = m_xBuilder->get<SystemWindow>(id); @@ -5676,6 +5953,18 @@ namespace weld } } + AssistantController::AssistantController(weld::Widget* pParent, const OUString &rUIFile, const OString& rDialogId) + : m_xBuilder(Application::CreateBuilder(pParent, rUIFile)) + , m_xAssistant(m_xBuilder->weld_assistant(rDialogId)) + { + } + + Dialog* AssistantController::getDialog() { return m_xAssistant.get(); } + + AssistantController::~AssistantController() + { + } + void TriStateEnabled::ButtonToggled(weld::ToggleButton& rToggle) { if (bTriStateEnabled) diff --git a/vcl/source/control/button.cxx b/vcl/source/control/button.cxx index 8a076fadceb9..8669e655479f 100644 --- a/vcl/source/control/button.cxx +++ b/vcl/source/control/button.cxx @@ -145,6 +145,9 @@ OUString Button::GetStandardText(StandardButtonType eButton) SV_BUTTONTEXT_IGNORE, SV_BUTTONTEXT_ABORT, SV_BUTTONTEXT_LESS, + STR_WIZDLG_PREVIOUS, + STR_WIZDLG_NEXT, + STR_WIZDLG_FINISH, }; return VclResId(aResIdAry[static_cast<sal_uInt16>(eButton)]); diff --git a/vcl/source/control/roadmapwizard.cxx b/vcl/source/control/roadmapwizard.cxx index ec27bb6dae82..2d29a71aa47a 100644 --- a/vcl/source/control/roadmapwizard.cxx +++ b/vcl/source/control/roadmapwizard.cxx @@ -124,6 +124,13 @@ namespace vcl impl_construct(); } + RoadmapWizardMachine::RoadmapWizardMachine(weld::Window* pParent) + : WizardMachine(pParent, WizardButtonFlags::NEXT | WizardButtonFlags::PREVIOUS | WizardButtonFlags::FINISH | WizardButtonFlags::CANCEL | WizardButtonFlags::HELP) + , m_pImpl( new RoadmapWizardImpl ) + { + m_xAssistant->connect_jump_page(LINK(this, RoadmapWizardMachine, OnRoadmapItemSelected)); + } + void RoadmapWizard::impl_construct() { SetLeftAlignedButtonCount( 1 ); @@ -143,12 +150,15 @@ namespace vcl m_pImpl->pRoadmap->Show(); } - RoadmapWizard::~RoadmapWizard() { disposeOnce(); } + RoadmapWizardMachine::~RoadmapWizardMachine() + { + } + void RoadmapWizard::dispose() { m_pImpl.reset(); @@ -160,12 +170,15 @@ namespace vcl m_pImpl->pRoadmap->SetHelpId( _rId ); } - void RoadmapWizard::SetRoadmapInteractive( bool _bInteractive ) { m_pImpl->pRoadmap->SetRoadmapInteractive( _bInteractive ); } + void RoadmapWizardMachine::SetRoadmapInteractive( bool _bInteractive ) + { + m_pImpl->pRoadmap->SetRoadmapInteractive( _bInteractive ); + } void RoadmapWizard::declarePath( PathId _nPathId, const WizardPath& _lWizardStates) { @@ -179,6 +192,17 @@ namespace vcl implUpdateRoadmap( ); } + void RoadmapWizardMachine::declarePath( PathId _nPathId, const WizardPath& _lWizardStates) + { + + m_pImpl->aPaths.emplace( _nPathId, _lWizardStates ); + + if ( m_pImpl->aPaths.size() == 1 ) + // the very first path -> activate it + activatePath( _nPathId ); + else + implUpdateRoadmap( ); + } void RoadmapWizard::describeState( WizardState _nState, const OUString& _rStateDisplayName, RoadmapPageFactory _pPageFactory ) { @@ -187,7 +211,6 @@ namespace vcl m_pImpl->aStateDescriptors[ _nState ] = StateDescriptions::mapped_type( _rStateDisplayName, _pPageFactory ); } - void RoadmapWizard::activatePath( PathId _nPathId, bool _bDecideForIt ) { @@ -231,6 +254,47 @@ namespace vcl implUpdateRoadmap( ); } + void RoadmapWizardMachine::activatePath( PathId _nPathId, bool _bDecideForIt ) + { + if ( ( _nPathId == m_pImpl->nActivePath ) && ( _bDecideForIt == m_pImpl->bActivePathIsDefinite ) ) + // nothing to do + return; + + // does the given path exist? + Paths::const_iterator aNewPathPos = m_pImpl->aPaths.find( _nPathId ); + DBG_ASSERT( aNewPathPos != m_pImpl->aPaths.end(), "RoadmapWizard::activate: there is no such path!" ); + if ( aNewPathPos == m_pImpl->aPaths.end() ) + return; + + // determine the index of the current state in the current path + sal_Int32 nCurrentStatePathIndex = -1; + if ( m_pImpl->nActivePath != -1 ) + nCurrentStatePathIndex = m_pImpl->getStateIndexInPath( getCurrentState(), m_pImpl->nActivePath ); + + DBG_ASSERT( static_cast<sal_Int32>(aNewPathPos->second.size()) > nCurrentStatePathIndex, + "RoadmapWizard::activate: you cannot activate a path which has less states than we've already advanced!" ); + // If this asserts, this for instance means that we are already in state number, say, 5 + // of our current path, and the caller tries to activate a path which has less than 5 + // states + if ( static_cast<sal_Int32>(aNewPathPos->second.size()) <= nCurrentStatePathIndex ) + return; + + // assert that the current and the new path are equal, up to nCurrentStatePathIndex + Paths::const_iterator aActivePathPos = m_pImpl->aPaths.find( m_pImpl->nActivePath ); + if ( aActivePathPos != m_pImpl->aPaths.end() ) + { + if ( RoadmapWizardImpl::getFirstDifferentIndex( aActivePathPos->second, aNewPathPos->second ) <= nCurrentStatePathIndex ) + { + OSL_FAIL( "RoadmapWizard::activate: you cannot activate a path which conflicts with the current one *before* the current state!" ); + return; + } + } + + m_pImpl->nActivePath = _nPathId; + m_pImpl->bActivePathIsDefinite = _bDecideForIt; + + implUpdateRoadmap( ); + } void RoadmapWizard::implUpdateRoadmap( ) { @@ -337,6 +401,110 @@ namespace vcl m_pImpl->pRoadmap->SetRoadmapComplete( !bIncompletePath ); } + void RoadmapWizardMachine::implUpdateRoadmap( ) + { + + DBG_ASSERT( m_pImpl->aPaths.find( m_pImpl->nActivePath ) != m_pImpl->aPaths.end(), + "RoadmapWizard::implUpdateRoadmap: there is no such path!" ); + const WizardPath& rActivePath( m_pImpl->aPaths[ m_pImpl->nActivePath ] ); + + sal_Int32 nCurrentStatePathIndex = RoadmapWizardImpl::getStateIndexInPath( getCurrentState(), rActivePath ); + if (nCurrentStatePathIndex < 0) + return; + + // determine up to which index (in the new path) we have to display the items + RoadmapTypes::ItemIndex nUpperStepBoundary = static_cast<RoadmapTypes::ItemIndex>(rActivePath.size()); + if ( !m_pImpl->bActivePathIsDefinite ) + { + for (auto const& path : m_pImpl->aPaths) + { + if ( path.first == m_pImpl->nActivePath ) + // it's the path we are just activating -> no need to check anything + continue; + // the index from which on both paths differ + sal_Int32 nDivergenceIndex = RoadmapWizardImpl::getFirstDifferentIndex( rActivePath, path.second ); + if ( nDivergenceIndex <= nCurrentStatePathIndex ) + // they differ in an index which we have already left behind us + // -> this is no conflict anymore + continue; + + // the path conflicts with our new path -> don't activate the + // *complete* new path, but only up to the step which is unambiguous + nUpperStepBoundary = nDivergenceIndex; + } + } + + // can we advance from the current page? + bool bCurrentPageCanAdvance = true; + TabPage* pCurrentPage = GetPage( getCurrentState() ); + if ( pCurrentPage ) + { + const IWizardPageController* pController = getPageController( GetPage( getCurrentState() ) ); + OSL_ENSURE( pController != nullptr, "RoadmapWizard::implUpdateRoadmap: no controller for the current page!" ); + bCurrentPageCanAdvance = !pController || pController->canAdvance(); + } + + // now, we have to remove all items after nCurrentStatePathIndex, and insert the items from the active + // path, up to (excluding) nUpperStepBoundary + RoadmapTypes::ItemIndex nRoadmapItems = m_xAssistant->get_n_pages(); + RoadmapTypes::ItemIndex nLoopUntil = ::std::max( nUpperStepBoundary, nRoadmapItems ); + for ( RoadmapTypes::ItemIndex nItemIndex = nCurrentStatePathIndex; nItemIndex < nLoopUntil; ++nItemIndex ) + { + bool bExistentItem = ( nItemIndex < nRoadmapItems ); + bool bNeedItem = ( nItemIndex < nUpperStepBoundary ); + + bool bInsertItem = false; + if ( bExistentItem ) + { + if ( !bNeedItem ) + { + int nPages = nRoadmapItems; + for (int i = nPages - 1; i >= nItemIndex; --i) + { + m_xAssistant->set_page_title(m_xAssistant->get_page_ident(i), ""); + --nRoadmapItems; + } + break; + } + else + { + // there is an item with this index in the roadmap - does it match what is requested by + // the respective state in the active path? + RoadmapTypes::ItemId nPresentItemId = m_xAssistant->get_page_ident(nItemIndex).toInt32(); + WizardState nRequiredState = rActivePath[ nItemIndex ]; + if ( nPresentItemId != nRequiredState ) + { + m_xAssistant->set_page_title(OString::number(nPresentItemId), ""); + bInsertItem = true; + } + } + } + else + { + DBG_ASSERT( bNeedItem, "RoadmapWizard::implUpdateRoadmap: ehm - none needed, none present - why did the loop not terminate?" ); + bInsertItem = bNeedItem; + } + + WizardState nState( rActivePath[ nItemIndex ] ); + + if ( bInsertItem ) + { + GetOrCreatePage(nState); + } + + OString sIdent(OString::number(nState)); + m_xAssistant->set_page_index(sIdent, nItemIndex); + m_xAssistant->set_page_title(sIdent, getStateDisplayName(nState)); + + // if the item is *after* the current state, but the current page does not + // allow advancing, the disable the state. This relieves derived classes + // from disabling all future states just because the current state does not + // (yet) allow advancing. + const bool bUnconditionedDisable = !bCurrentPageCanAdvance && ( nItemIndex > nCurrentStatePathIndex ); + const bool bEnable = !bUnconditionedDisable && ( m_pImpl->aDisabledStates.find( nState ) == m_pImpl->aDisabledStates.end() ); + m_xAssistant->set_page_sensitive(sIdent, bEnable); + } + } WizardTypes::WizardState RoadmapWizard::determineNextState( WizardState _nCurrentState ) const { @@ -367,6 +535,33 @@ namespace vcl return aActivePathPos->second[ nNextStateIndex ]; } + WizardTypes::WizardState RoadmapWizardMachine::determineNextState( WizardState _nCurrentState ) const + { + sal_Int32 nCurrentStatePathIndex = -1; + + Paths::const_iterator aActivePathPos = m_pImpl->aPaths.find( m_pImpl->nActivePath ); + if ( aActivePathPos != m_pImpl->aPaths.end() ) + nCurrentStatePathIndex = RoadmapWizardImpl::getStateIndexInPath( _nCurrentState, aActivePathPos->second ); + + DBG_ASSERT( nCurrentStatePathIndex != -1, "RoadmapWizard::determineNextState: ehm - how can we travel if there is no (valid) active path?" ); + if ( nCurrentStatePathIndex == -1 ) + return WZS_INVALID_STATE; + + sal_Int32 nNextStateIndex = nCurrentStatePathIndex + 1; + + while ( ( nNextStateIndex < static_cast<sal_Int32>(aActivePathPos->second.size()) ) + && ( m_pImpl->aDisabledStates.find( aActivePathPos->second[ nNextStateIndex ] ) != m_pImpl->aDisabledStates.end() ) + ) + { + ++nNextStateIndex; + } + + if ( nNextStateIndex >= static_cast<sal_Int32>(aActivePathPos->second.size()) ) + // there is no next state in the current path (at least none which is enabled) + return WZS_INVALID_STATE; + + return aActivePathPos->second[ nNextStateIndex ]; + } bool RoadmapWizard::canAdvance() const { @@ -398,6 +593,35 @@ namespace vcl return *rPath.rbegin() != getCurrentState(); } + bool RoadmapWizardMachine::canAdvance() const + { + if ( !m_pImpl->bActivePathIsDefinite ) + { + // check how many paths are still allowed + const WizardPath& rActivePath( m_pImpl->aPaths[ m_pImpl->nActivePath ] ); + sal_Int32 nCurrentStatePathIndex = RoadmapWizardImpl::getStateIndexInPath( getCurrentState(), rActivePath ); + + size_t nPossiblePaths(0); + for (auto const& path : m_pImpl->aPaths) + { + // the index from which on both paths differ + sal_Int32 nDivergenceIndex = RoadmapWizardImpl::getFirstDifferentIndex( rActivePath, path.second ); + + if ( nDivergenceIndex > nCurrentStatePathIndex ) + // this path is still a possible path + nPossiblePaths += 1; + } + + // if we have more than one path which is still possible, then we assume + // to always have a next state. Though there might be scenarios where this + // is not true, but this is too sophisticated (means not really needed) right now. + if ( nPossiblePaths > 1 ) + return true; + } + + const WizardPath& rPath = m_pImpl->aPaths[ m_pImpl->nActivePath ]; + return *rPath.rbegin() != getCurrentState(); + } void RoadmapWizard::updateTravelUI() { @@ -421,6 +645,27 @@ namespace vcl implUpdateRoadmap(); } + void RoadmapWizardMachine::updateTravelUI() + { + WizardMachine::updateTravelUI(); + + // disable the "Previous" button if all states in our history are disabled + ::std::vector< WizardState > aHistory; + getStateHistory( aHistory ); + bool bHaveEnabledState = false; + for (auto const& state : aHistory) + { + if ( isStateEnabled(state) ) + { + bHaveEnabledState = true; + break; + } + } + + enableButtons( WizardButtonFlags::PREVIOUS, bHaveEnabledState ); + + implUpdateRoadmap(); + } IMPL_LINK_NOARG(RoadmapWizard, OnRoadmapItemSelected, LinkParamNone*, void) { @@ -463,10 +708,48 @@ namespace vcl m_pImpl->pRoadmap->SelectRoadmapItemByID( getCurrentState() ); } + IMPL_LINK(RoadmapWizardMachine, OnRoadmapItemSelected, const OString&, rCurItemId, bool) + { + int nCurItemId = rCurItemId.toInt32(); + + if ( nCurItemId == getCurrentState() ) + // nothing to do + return false; + + if ( isTravelingSuspended() ) + return false; + + WizardTravelSuspension aTravelGuard( *this ); + + sal_Int32 nCurrentIndex = m_pImpl->getStateIndexInPath( getCurrentState(), m_pImpl->nActivePath ); + sal_Int32 nNewIndex = m_pImpl->getStateIndexInPath( nCurItemId, m_pImpl->nActivePath ); + + DBG_ASSERT( ( nCurrentIndex != -1 ) && ( nNewIndex != -1 ), + "RoadmapWizard::OnRoadmapItemSelected: something's wrong here!" ); + if ( ( nCurrentIndex == -1 ) || ( nNewIndex == -1 ) ) + { + return false; + } + + bool bResult = true; + if ( nNewIndex > nCurrentIndex ) + { + bResult = skipUntil( static_cast<WizardState>(nCurItemId) ); + WizardState nTemp = static_cast<WizardState>(nCurItemId); + while( nTemp ) + { + if( m_pImpl->aDisabledStates.find( --nTemp ) != m_pImpl->aDisabledStates.end() ) + removePageFromHistory( nTemp ); + } + } + else + bResult = skipBackwardUntil( static_cast<WizardState>(nCurItemId) ); + + return bResult; + } void RoadmapWizard::enterState( WizardState _nState ) { - OWizardMachine::enterState( _nState ); // synchronize the roadmap @@ -474,6 +757,13 @@ namespace vcl m_pImpl->pRoadmap->SelectRoadmapItemByID( getCurrentState() ); } + void RoadmapWizardMachine::enterState( WizardState _nState ) + { + WizardMachine::enterState( _nState ); + + // synchronize the roadmap + implUpdateRoadmap(); + } OUString RoadmapWizard::getStateDisplayName( WizardState _nState ) const { @@ -488,6 +778,18 @@ namespace vcl return sDisplayName; } + OUString RoadmapWizardMachine::getStateDisplayName( WizardState _nState ) const + { + OUString sDisplayName; + + StateDescriptions::const_iterator pos = m_pImpl->aStateDescriptors.find( _nState ); + OSL_ENSURE( pos != m_pImpl->aStateDescriptors.end(), + "RoadmapWizard::getStateDisplayName: no default implementation available for this state!" ); + if ( pos != m_pImpl->aStateDescriptors.end() ) + sDisplayName = pos->second.first; + + return sDisplayName; + } VclPtr<TabPage> RoadmapWizard::createPage( WizardState _nState ) { @@ -505,7 +807,6 @@ namespace vcl return pPage; } - void RoadmapWizard::enableState( WizardState _nState, bool _bEnable ) { @@ -522,6 +823,20 @@ namespace vcl m_pImpl->pRoadmap->EnableRoadmapItem( static_cast<RoadmapTypes::ItemId>(_nState), _bEnable ); } + void RoadmapWizardMachine::enableState( WizardState _nState, bool _bEnable ) + { + // remember this (in case the state appears in the roadmap later on) + if ( _bEnable ) + m_pImpl->aDisabledStates.erase( _nState ); + else + { + m_pImpl->aDisabledStates.insert( _nState ); + removePageFromHistory( _nState ); + } + + // if the state is currently in the roadmap, reflect it's new status + m_xAssistant->set_page_sensitive(OString::number(_nState), _bEnable); + } bool RoadmapWizard::knowsState( WizardState i_nState ) const { @@ -541,6 +856,11 @@ namespace vcl return m_pImpl->aDisabledStates.find( _nState ) == m_pImpl->aDisabledStates.end(); } + bool RoadmapWizardMachine::isStateEnabled( WizardState _nState ) const + { + return m_pImpl->aDisabledStates.find( _nState ) == m_pImpl->aDisabledStates.end(); + } + void RoadmapWizard::updateRoadmapItemLabel( WizardState _nState ) { const WizardPath& rActivePath( m_pImpl->aPaths[ m_pImpl->nActivePath ] ); @@ -569,6 +889,32 @@ namespace vcl } } + void RoadmapWizard::InsertRoadmapItem(int nItemIndex, const OUString& rText, int nItemId, bool bEnable) + { + m_pImpl->pRoadmap->InsertRoadmapItem(nItemIndex, rText, nItemId, bEnable); + } + + void RoadmapWizard::SelectRoadmapItemByID(int nItemId) + { + m_pImpl->pRoadmap->SelectRoadmapItemByID(nItemId); + } + + void RoadmapWizard::DeleteRoadmapItems() + { + while (m_pImpl->pRoadmap->GetItemCount()) + m_pImpl->pRoadmap->DeleteRoadmapItem(0); + } + + void RoadmapWizard::SetItemSelectHdl( const Link<LinkParamNone*,void>& _rHdl ) + { + m_pImpl->pRoadmap->SetItemSelectHdl(_rHdl); + } + + int RoadmapWizard::GetCurrentRoadmapItemID() const + { + return m_pImpl->pRoadmap->GetCurrentRoadmapItemID(); + } + } // namespace vcl /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/control/wizardmachine.cxx b/vcl/source/control/wizardmachine.cxx index f42c509bff37..8a1a92a707f2 100644 --- a/vcl/source/control/wizardmachine.cxx +++ b/vcl/source/control/wizardmachine.cxx @@ -18,7 +18,6 @@ */ #include <vcl/wizardmachine.hxx> -#include <svtools/helpids.h> #include <tools/debug.hxx> #include <tools/diagnose_ex.h> #include <vcl/svapp.hxx> @@ -26,6 +25,15 @@ #include <svdata.hxx> #include <stack> +#define HID_WIZARD_NEXT "SVT_HID_WIZARD_NEXT" +#define HID_WIZARD_PREVIOUS "SVT_HID_WIZARD_PREVIOUS" + +struct ImplWizPageData +{ + ImplWizPageData* mpNext; + VclPtr<TabPage> mpPage; +}; + namespace vcl { //= WizardPageImplData @@ -360,14 +368,13 @@ namespace vcl m_pCancel->Enable(_bEnable); } - void OWizardMachine::enterState(WizardState _nState) { // tell the page IWizardPageController* pController = getPageController( GetPage( _nState ) ); - OSL_ENSURE( pController, "OWizardMachine::enterState: no controller for the given page!" ); - if ( pController ) - pController->initializePage(); + if (!pController) + return; + pController->initializePage(); if ( isAutomaticNextButtonStateEnabled() ) enableButtons( WizardButtonFlags::NEXT, canAdvance() ); @@ -378,7 +385,6 @@ namespace vcl implUpdateTitle(); } - bool OWizardMachine::leaveState(WizardState) { // no need to ask the page here. @@ -522,7 +528,6 @@ namespace vcl // all fine } - bool OWizardMachine::travelNext() { // allowed to leave the current page? @@ -679,7 +684,586 @@ namespace vcl m_pImpl->m_bTravelingSuspended = false; } + WizardMachine::WizardMachine(weld::Window* pParent, WizardButtonFlags nButtonFlags) + : AssistantController(pParent, "dbaccess/ui/databasewizard.ui", "DatabaseWizard") + , m_nCurState(0) + , m_pFirstPage(nullptr) + , m_xFinish(m_xAssistant->weld_widget_for_response(static_cast<int>(WizardButtonFlags::FINISH))) + , m_xCancel(m_xAssistant->weld_widget_for_response(static_cast<int>(WizardButtonFlags::CANCEL))) + , m_xNextPage(m_xAssistant->weld_widget_for_response(static_cast<int>(WizardButtonFlags::NEXT))) + , m_xPrevPage(m_xAssistant->weld_widget_for_response(static_cast<int>(WizardButtonFlags::PREVIOUS))) + , m_xHelp(m_xAssistant->weld_widget_for_response(static_cast<int>(WizardButtonFlags::HELP))) + , m_pImpl(new WizardMachineImplData) + { + implConstruct(nButtonFlags); + } + + void WizardMachine::implConstruct(const WizardButtonFlags nButtonFlags) + { + m_pImpl->sTitleBase = m_xAssistant->get_title(); + + // create the buttons according to the wizard button flags + // the help button + if (nButtonFlags & WizardButtonFlags::HELP) + { + m_xHelp->show(); + } + + // the previous button + if (nButtonFlags & WizardButtonFlags::PREVIOUS) + { + m_xPrevPage->set_help_id( HID_WIZARD_PREVIOUS ); + m_xPrevPage->show(); + + m_xPrevPage->connect_clicked( LINK( this, WizardMachine, OnPrevPage ) ); + } + + // the next button + if (nButtonFlags & WizardButtonFlags::NEXT) + { + m_xNextPage->set_help_id( HID_WIZARD_NEXT ); + m_xNextPage->show(); + + m_xNextPage->connect_clicked( LINK( this, WizardMachine, OnNextPage ) ); + } + + // the finish button + if (nButtonFlags & WizardButtonFlags::FINISH) + { + m_xFinish->show(); + + m_xFinish->connect_clicked( LINK( this, WizardMachine, OnFinish ) ); + } + + // the cancel button + if (nButtonFlags & WizardButtonFlags::CANCEL) + { + m_xCancel->show(); + m_xCancel->connect_clicked( LINK( this, WizardMachine, OnCancel ) ); + } + } + + WizardMachine::~WizardMachine() + { + if (m_pImpl) + { + for (WizardState i = 0; i < m_pImpl->nFirstUnknownPage; ++i) + { + TabPage *pPage = GetPage(i); + if (pPage) + pPage->disposeOnce(); + } + m_pImpl.reset(); + } + } + + void WizardMachine::implUpdateTitle() + { + OUString sCompleteTitle(m_pImpl->sTitleBase); + + // append the page title + TabPage* pCurrentPage = GetPage(getCurrentState()); + if ( pCurrentPage && !pCurrentPage->GetText().isEmpty() ) + { + sCompleteTitle += " - " + pCurrentPage->GetText(); + } + + m_xAssistant->set_title(sCompleteTitle); + } + + void WizardMachine::setTitleBase(const OUString& _rTitleBase) + { + m_pImpl->sTitleBase = _rTitleBase; + implUpdateTitle(); + } + + TabPage* WizardMachine::GetOrCreatePage( const WizardState i_nState ) + { + if ( nullptr == GetPage( i_nState ) ) + { + VclPtr<TabPage> pNewPage = createPage( i_nState ); + DBG_ASSERT( pNewPage, "WizardMachine::GetOrCreatePage: invalid new page (NULL)!" ); + + // fill up the page sequence of our base class (with dummies) + while ( m_pImpl->nFirstUnknownPage < i_nState ) + { + AddPage( nullptr ); + ++m_pImpl->nFirstUnknownPage; + } + + if ( m_pImpl->nFirstUnknownPage == i_nState ) + { + // encountered this page number the first time + AddPage( pNewPage ); + ++m_pImpl->nFirstUnknownPage; + } + else + // already had this page - just change it + SetPage( i_nState, pNewPage ); + } + return GetPage( i_nState ); + } + + void WizardMachine::ActivatePage() + { + WizardState nCurrentLevel = m_nCurState; + GetOrCreatePage( nCurrentLevel ); + + enterState( nCurrentLevel ); + } + + bool WizardMachine::DeactivatePage() + { + WizardState nCurrentState = getCurrentState(); + return leaveState(nCurrentState); + } + + void WizardMachine::defaultButton(WizardButtonFlags _nWizardButtonFlags) + { + // the new default button + weld::Button* pNewDefButton = nullptr; + if (_nWizardButtonFlags & WizardButtonFlags::FINISH) + pNewDefButton = m_xFinish.get(); + if (_nWizardButtonFlags & WizardButtonFlags::NEXT) + pNewDefButton = m_xNextPage.get(); + if (_nWizardButtonFlags & WizardButtonFlags::PREVIOUS) + pNewDefButton = m_xPrevPage.get(); + if (_nWizardButtonFlags & WizardButtonFlags::HELP) + pNewDefButton = m_xHelp.get(); + if (_nWizardButtonFlags & WizardButtonFlags::CANCEL) + pNewDefButton = m_xCancel.get(); + + if ( pNewDefButton ) + defaultButton( pNewDefButton ); + else + m_xAssistant->recursively_unset_default_buttons(); + } + void WizardMachine::defaultButton(weld::Button* _pNewDefButton) + { + // loop through all (direct and indirect) descendants which participate in our tabbing order, and + // reset the WB_DEFBUTTON for every window which is a button + m_xAssistant->recursively_unset_default_buttons(); + + // set its new style + if (_pNewDefButton) + _pNewDefButton->set_has_default(true); + } + + void WizardMachine::enableButtons(WizardButtonFlags _nWizardButtonFlags, bool _bEnable) + { + if (_nWizardButtonFlags & WizardButtonFlags::FINISH) + m_xFinish->set_sensitive(_bEnable); + if (_nWizardButtonFlags & WizardButtonFlags::NEXT) + m_xNextPage->set_sensitive(_bEnable); + if (_nWizardButtonFlags & WizardButtonFlags::PREVIOUS) + m_xPrevPage->set_sensitive(_bEnable); + if (_nWizardButtonFlags & WizardButtonFlags::HELP) + m_xHelp->set_sensitive(_bEnable); + if (_nWizardButtonFlags & WizardButtonFlags::CANCEL) + m_xCancel->set_sensitive(_bEnable); + } + + void WizardMachine::enterState(WizardState _nState) + { + // tell the page + IWizardPageController* pController = getPageController( GetPage( _nState ) ); + OSL_ENSURE( pController, "WizardMachine::enterState: no controller for the given page!" ); + if ( pController ) + pController->initializePage(); + + if ( isAutomaticNextButtonStateEnabled() ) + enableButtons( WizardButtonFlags::NEXT, canAdvance() ); + + enableButtons( WizardButtonFlags::PREVIOUS, !m_pImpl->aStateHistory.empty() ); + + // set the new title - it depends on the current page (i.e. state) + implUpdateTitle(); + } + + bool WizardMachine::leaveState(WizardState) + { + // no need to ask the page here. + // If we reach this point, we already gave the current page the chance to commit it's data, + // and it was allowed to commit it's data + + return true; + } + + bool WizardMachine::onFinish() + { + return Finish( RET_OK ); + } + + IMPL_LINK_NOARG(WizardMachine, OnFinish, weld::Button&, void) + { + if ( isTravelingSuspended() ) + return; + WizardTravelSuspension aTravelGuard( *this ); + if ( !prepareLeaveCurrentState( eFinish ) ) + { + return; + } + onFinish(); + } + + IMPL_LINK_NOARG(WizardMachine, OnCancel, weld::Button&, void) + { + m_xAssistant->response(static_cast<int>(WizardButtonFlags::CANCEL)); + } + + WizardMachine::WizardState WizardMachine::determineNextState( WizardState _nCurrentState ) const + { + return _nCurrentState + 1; + } + + bool WizardMachine::prepareLeaveCurrentState( CommitPageReason _eReason ) + { + IWizardPageController* pController = getPageController( GetPage( getCurrentState() ) ); + ENSURE_OR_RETURN( pController != nullptr, "WizardMachine::prepareLeaveCurrentState: no controller for the current page!", true ); + return pController->commitPage( _eReason ); + } + + + bool WizardMachine::skipBackwardUntil( WizardState _nTargetState ) + { + // allowed to leave the current page? + if ( !prepareLeaveCurrentState( eTravelBackward ) ) + return false; + + // don't travel directly on m_pImpl->aStateHistory, in case something goes wrong + ::std::stack< WizardState > aTravelVirtually = m_pImpl->aStateHistory; + ::std::stack< WizardState > aOldStateHistory = m_pImpl->aStateHistory; + + WizardState nCurrentRollbackState = getCurrentState(); + while ( nCurrentRollbackState != _nTargetState ) + { + DBG_ASSERT( !aTravelVirtually.empty(), "WizardMachine::skipBackwardUntil: this target state does not exist in the history!" ); + nCurrentRollbackState = aTravelVirtually.top(); + aTravelVirtually.pop(); + } + m_pImpl->aStateHistory = aTravelVirtually; + if ( !ShowPage( _nTargetState ) ) + { + m_pImpl->aStateHistory = aOldStateHistory; + return false; + } + return true; + } + + + bool WizardMachine::skipUntil( WizardState _nTargetState ) + { + WizardState nCurrentState = getCurrentState(); + + // allowed to leave the current page? + if ( !prepareLeaveCurrentState( nCurrentState < _nTargetState ? eTravelForward : eTravelBackward ) ) + return false; + + // don't travel directly on m_pImpl->aStateHistory, in case something goes wrong + ::std::stack< WizardState > aTravelVirtually = m_pImpl->aStateHistory; + ::std::stack< WizardState > aOldStateHistory = m_pImpl->aStateHistory; + while ( nCurrentState != _nTargetState ) + { + WizardState nNextState = determineNextState( nCurrentState ); + if ( WZS_INVALID_STATE == nNextState ) + { + OSL_FAIL( "WizardMachine::skipUntil: the given target state does not exist!" ); + return false; + } + + // remember the skipped state in the history + aTravelVirtually.push( nCurrentState ); + + // get the next state + nCurrentState = nNextState; + } + m_pImpl->aStateHistory = aTravelVirtually; + // show the target page + if ( !ShowPage( nCurrentState ) ) + { + // argh! prepareLeaveCurrentPage succeeded, determineNextState succeeded, + // but ShowPage doesn't? Somebody behaves very strange here .... + OSL_FAIL( "WizardMachine::skipUntil: very unpolite ...." ); + m_pImpl->aStateHistory = aOldStateHistory; + return false; + } + return true; + } + + + void WizardMachine::skip() + { + // allowed to leave the current page? + if ( !prepareLeaveCurrentState( eTravelForward ) ) + return; + + WizardState nCurrentState = getCurrentState(); + WizardState nNextState = determineNextState(nCurrentState); + + if (WZS_INVALID_STATE == nNextState) + return; + + // remember the skipped state in the history + m_pImpl->aStateHistory.push(nCurrentState); + + // get the next state + nCurrentState = nNextState; + + // show the (n+1)th page + if (!ShowPage(nCurrentState)) + { + // TODO: this leaves us in a state where we have no current page and an inconsistent state history. + // Perhaps we should rollback the skipping here .... + OSL_FAIL("WizardMachine::skip: very unpolite ...."); + // if somebody does a skip and then does not allow to leave ... + // (can't be a commit error, as we've already committed the current page. So if ShowPage fails here, + // somebody behaves really strange ...) + return; + } + + // all fine + } + + bool WizardMachine::travelNext() + { + // allowed to leave the current page? + if ( !prepareLeaveCurrentState( eTravelForward ) ) + return false; + + // determine the next state to travel to + WizardState nCurrentState = getCurrentState(); + WizardState nNextState = determineNextState(nCurrentState); + if (WZS_INVALID_STATE == nNextState) + return false; + + // the state history is used by the enterState method + // all fine + m_pImpl->aStateHistory.push(nCurrentState); + if (!ShowPage(nNextState)) + { + m_pImpl->aStateHistory.pop(); + return false; + } + + return true; + } + + bool WizardMachine::ShowPage(WizardState nState) + { + if (DeactivatePage()) + { + TabPage* pOldTabPage = m_xCurTabPage; + + m_nCurState = nState; + ActivatePage(); + + if (pOldTabPage) + pOldTabPage->DeactivatePage(); + + m_xAssistant->set_current_page(OString::number(nState)); + + m_xCurTabPage = GetPage(m_nCurState); + m_xCurTabPage->ActivatePage(); + + return true; + } + return false; + } + + bool WizardMachine::travelPrevious() + { + DBG_ASSERT(!m_pImpl->aStateHistory.empty(), "WizardMachine::travelPrevious: have no previous page!"); + + // allowed to leave the current page? + if ( !prepareLeaveCurrentState( eTravelBackward ) ) + return false; + + // the next state to switch to + WizardState nPreviousState = m_pImpl->aStateHistory.top(); + + // the state history is used by the enterState method + m_pImpl->aStateHistory.pop(); + // show this page + if (!ShowPage(nPreviousState)) + { + m_pImpl->aStateHistory.push(nPreviousState); + return false; + } + + // all fine + return true; + } + + + void WizardMachine::removePageFromHistory( WizardState nToRemove ) + { + + ::std::stack< WizardState > aTemp; + while(!m_pImpl->aStateHistory.empty()) + { + WizardState nPreviousState = m_pImpl->aStateHistory.top(); + m_pImpl->aStateHistory.pop(); + if(nPreviousState != nToRemove) + aTemp.push( nPreviousState ); + else + break; + } + while(!aTemp.empty()) + { + m_pImpl->aStateHistory.push( aTemp.top() ); + aTemp.pop(); + } + } + + + void WizardMachine::enableAutomaticNextButtonState() + { + m_pImpl->m_bAutoNextButtonState = true; + } + + + bool WizardMachine::isAutomaticNextButtonStateEnabled() const + { + return m_pImpl->m_bAutoNextButtonState; + } + + IMPL_LINK_NOARG(WizardMachine, OnPrevPage, weld::Button&, void) + { + if ( isTravelingSuspended() ) + return; + WizardTravelSuspension aTravelGuard( *this ); + travelPrevious(); + } + + IMPL_LINK_NOARG(WizardMachine, OnNextPage, weld::Button&, void) + { + if ( isTravelingSuspended() ) + return; + WizardTravelSuspension aTravelGuard( *this ); + travelNext(); + } + + IWizardPageController* WizardMachine::getPageController( TabPage* _pCurrentPage ) const + { + IWizardPageController* pController = dynamic_cast< IWizardPageController* >( _pCurrentPage ); + return pController; + } + + + void WizardMachine::getStateHistory( ::std::vector< WizardState >& _out_rHistory ) + { + ::std::stack< WizardState > aHistoryCopy( m_pImpl->aStateHistory ); + while ( !aHistoryCopy.empty() ) + { + _out_rHistory.push_back( aHistoryCopy.top() ); + aHistoryCopy.pop(); + } + } + + + bool WizardMachine::canAdvance() const + { + return WZS_INVALID_STATE != determineNextState( getCurrentState() ); + } + + + void WizardMachine::updateTravelUI() + { + const IWizardPageController* pController = getPageController( GetPage( getCurrentState() ) ); + OSL_ENSURE( pController != nullptr, "RoadmapWizard::updateTravelUI: no controller for the current page!" ); + + bool bCanAdvance = + ( !pController || pController->canAdvance() ) // the current page allows to advance + && canAdvance(); // the dialog as a whole allows to advance + enableButtons( WizardButtonFlags::NEXT, bCanAdvance ); + } + + + bool WizardMachine::isTravelingSuspended() const + { + return m_pImpl->m_bTravelingSuspended; + } + + + void WizardMachine::suspendTraveling( AccessGuard ) + { + DBG_ASSERT( !m_pImpl->m_bTravelingSuspended, "WizardMachine::suspendTraveling: already suspended!" ); + m_pImpl->m_bTravelingSuspended = true; + } + + void WizardMachine::resumeTraveling( AccessGuard ) + { + DBG_ASSERT( m_pImpl->m_bTravelingSuspended, "WizardMachine::resumeTraveling: nothing to resume!" ); + m_pImpl->m_bTravelingSuspended = false; + } + + bool WizardMachine::Finish(short nResult) + { + if ( DeactivatePage() ) + { + if (m_xCurTabPage) + m_xCurTabPage->DeactivatePage(); + + m_xAssistant->response(nResult); + return true; + } + else + return false; + } + + void WizardMachine::AddPage( TabPage* pPage ) + { + ImplWizPageData* pNewPageData = new ImplWizPageData; + pNewPageData->mpNext = nullptr; + pNewPageData->mpPage = pPage; + + if ( !m_pFirstPage ) + m_pFirstPage = pNewPageData; + else + { + ImplWizPageData* pPageData = m_pFirstPage; + while ( pPageData->mpNext ) + pPageData = pPageData->mpNext; + pPageData->mpNext = pNewPageData; + } + } + + void WizardMachine::SetPage(WizardState nLevel, TabPage* pPage) + { + sal_uInt16 nTempLevel = 0; + ImplWizPageData* pPageData = m_pFirstPage; + while ( pPageData ) + { + if ( (nTempLevel == nLevel) || !pPageData->mpNext ) + break; + + nTempLevel++; + pPageData = pPageData->mpNext; + } + + if ( pPageData ) + { + if ( pPageData->mpPage == m_xCurTabPage ) + m_xCurTabPage = nullptr; + pPageData->mpPage = pPage; + } + } + + TabPage* WizardMachine::GetPage(WizardState nLevel) const + { + sal_uInt16 nTempLevel = 0; + + for (ImplWizPageData* pPageData = m_pFirstPage; pPageData; + pPageData = pPageData->mpNext) + { + if ( nTempLevel == nLevel ) + return pPageData->mpPage; + nTempLevel++; + } + + return nullptr; + } } // namespace svt diff --git a/vcl/unx/gtk3/gtk3gtkinst.cxx b/vcl/unx/gtk3/gtk3gtkinst.cxx index 10e3331ee355..45f6ae5a9813 100644 --- a/vcl/unx/gtk3/gtk3gtkinst.cxx +++ b/vcl/unx/gtk3/gtk3gtkinst.cxx @@ -38,6 +38,7 @@ #include <unotools/resmgr.hxx> #include <unx/gstsink.hxx> #include <vcl/ImageTree.hxx> +#include <vcl/button.hxx> #include <vcl/i18nhelp.hxx> #include <vcl/quickselectionengine.hxx> #include <vcl/mnemonic.hxx> @@ -2619,6 +2620,15 @@ class GtkInstanceContainer : public GtkInstanceWidget, public virtual weld::Cont { private: GtkContainer* m_pContainer; + + static void implResetDefault(GtkWidget *pWidget, gpointer user_data) + { + if (GTK_IS_BUTTON(pWidget)) + g_object_set(G_OBJECT(pWidget), "has-default", false, nullptr); + if (GTK_IS_CONTAINER(pWidget)) + gtk_container_forall(GTK_CONTAINER(pWidget), implResetDefault, user_data); + } + public: GtkInstanceContainer(GtkContainer* pContainer, GtkInstanceBuilder* pBuilder, bool bTakeOwnership) : GtkInstanceWidget(GTK_WIDGET(pContainer), pBuilder, bTakeOwnership) @@ -2642,6 +2652,11 @@ public: gtk_container_add(pNewGtkParent->getContainer(), pChild); g_object_unref(pChild); } + + virtual void recursively_unset_default_buttons() override + { + implResetDefault(GTK_WIDGET(m_pContainer), nullptr); + } }; std::unique_ptr<weld::Container> GtkInstanceWidget::weld_parent() const @@ -2964,21 +2979,21 @@ class GtkInstanceDialog; struct DialogRunner { - GtkDialog *m_pDialog; + GtkWindow* m_pDialog; GtkInstanceDialog *m_pInstance; gint m_nResponseId; GMainLoop *m_pLoop; VclPtr<vcl::Window> m_xFrameWindow; int m_nModalDepth; - DialogRunner(GtkDialog* pDialog, GtkInstanceDialog* pInstance) + DialogRunner(GtkWindow* pDialog, GtkInstanceDialog* pInstance) : m_pDialog(pDialog) , m_pInstance(pInstance) , m_nResponseId(GTK_RESPONSE_NONE) , m_pLoop(nullptr) , m_nModalDepth(0) { - GtkWindow* pParent = gtk_window_get_transient_for(GTK_WINDOW(m_pDialog)); + GtkWindow* pParent = gtk_window_get_transient_for(m_pDialog); GtkSalFrame* pFrame = pParent ? GtkSalFrame::getFromWindow(pParent) : nullptr; m_xFrameWindow = pFrame ? pFrame->GetWindow() : nullptr; } @@ -2995,6 +3010,7 @@ struct DialogRunner } static void signal_response(GtkDialog*, gint nResponseId, gpointer data); + static void signal_cancel(GtkDialog*, gpointer data); static gboolean signal_delete(GtkDialog*, GdkEventAny*, gpointer data) { @@ -3038,14 +3054,15 @@ struct DialogRunner inc_modal_count(); - bool bWasModal = gtk_window_get_modal(GTK_WINDOW(m_pDialog)); + bool bWasModal = gtk_window_get_modal(m_pDialog); if (!bWasModal) - gtk_window_set_modal(GTK_WINDOW(m_pDialog), true); + gtk_window_set_modal(m_pDialog, true); if (!gtk_widget_get_visible(GTK_WIDGET(m_pDialog))) gtk_widget_show(GTK_WIDGET(m_pDialog)); - gulong nSignalResponseId = g_signal_connect(m_pDialog, "response", G_CALLBACK(signal_response), this); + gulong nSignalResponseId = GTK_IS_DIALOG(m_pDialog) ? g_signal_connect(m_pDialog, "response", G_CALLBACK(signal_response), this) : 0; + gulong nSignalCancelId = GTK_IS_ASSISTANT(m_pDialog) ? g_signal_connect(m_pDialog, "cancel", G_CALLBACK(signal_cancel), this) : 0; gulong nSignalDeleteId = g_signal_connect(m_pDialog, "delete-event", G_CALLBACK(signal_delete), this); gulong nSignalDestroyId = g_signal_connect(m_pDialog, "destroy", G_CALLBACK(signal_destroy), this); @@ -3061,9 +3078,12 @@ struct DialogRunner m_pLoop = nullptr; if (!bWasModal) - gtk_window_set_modal(GTK_WINDOW(m_pDialog), false); + gtk_window_set_modal(m_pDialog, false); - g_signal_handler_disconnect(m_pDialog, nSignalResponseId); + if (nSignalResponseId) + g_signal_handler_disconnect(m_pDialog, nSignalResponseId); + if (nSignalCancelId) + g_signal_handler_disconnect(m_pDialog, nSignalCancelId); g_signal_handler_disconnect(m_pDialog, nSignalDeleteId); g_signal_handler_disconnect(m_pDialog, nSignalDestroyId); @@ -3125,7 +3145,7 @@ class GtkInstanceButton; class GtkInstanceDialog : public GtkInstanceWindow, public virtual weld::Dialog { private: - GtkDialog* m_pDialog; + GtkWindow* m_pDialog; DialogRunner m_aDialogRun; std::shared_ptr<weld::DialogController> m_xDialogController; // Used to keep ourself alive during a runAsync(when doing runAsync without a DialogController) @@ -3164,7 +3184,7 @@ private: return true; /* Do not destroy */ } - static int GtkToVcl(int ret) + virtual int GtkToVcl(int ret) { if (ret == GTK_RESPONSE_OK) ret = RET_OK; @@ -3181,11 +3201,28 @@ private: return ret; } + virtual int VclToGtk(int nResponse) + { + if (nResponse == RET_OK) + return GTK_RESPONSE_OK; + else if (nResponse == RET_CANCEL) + return GTK_RESPONSE_CANCEL; + else if (nResponse == RET_CLOSE) + return GTK_RESPONSE_CLOSE; + else if (nResponse == RET_YES) + return GTK_RESPONSE_YES; + else if (nResponse == RET_NO) + return GTK_RESPONSE_NO; + else if (nResponse == RET_HELP) + return GTK_RESPONSE_HELP; + return nResponse; + } + void asyncresponse(gint ret); public: - GtkInstanceDialog(GtkDialog* pDialog, GtkInstanceBuilder* pBuilder, bool bTakeOwnership) - : GtkInstanceWindow(GTK_WINDOW(pDialog), pBuilder, bTakeOwnership) + GtkInstanceDialog(GtkWindow* pDialog, GtkInstanceBuilder* pBuilder, bool bTakeOwnership) + : GtkInstanceWindow(pDialog, pBuilder, bTakeOwnership) , m_pDialog(pDialog) , m_aDialogRun(pDialog, this) , m_nCloseSignalId(g_signal_connect(m_pDialog, "close", G_CALLBACK(signalClose), this)) @@ -3243,7 +3280,8 @@ public: { if (gtk_widget_get_visible(m_pWidget)) return; - sort_native_button_order(GTK_BOX(gtk_dialog_get_action_area(m_pDialog))); + if (GTK_IS_DIALOG(m_pDialog)) + sort_native_button_order(GTK_BOX(gtk_dialog_get_action_area(GTK_DIALOG(m_pDialog)))); gtk_widget_show(m_pWidget); } @@ -3272,42 +3310,30 @@ public: } } - static int VclToGtk(int nResponse) - { - if (nResponse == RET_OK) - return GTK_RESPONSE_OK; - else if (nResponse == RET_CANCEL) - return GTK_RESPONSE_CANCEL; - else if (nResponse == RET_CLOSE) - return GTK_RESPONSE_CLOSE; - else if (nResponse == RET_YES) - return GTK_RESPONSE_YES; - else if (nResponse == RET_NO) - return GTK_RESPONSE_NO; - else if (nResponse == RET_HELP) - return GTK_RESPONSE_HELP; - return nResponse; - } - virtual void response(int nResponse) override; virtual void add_button(const OUString& rText, int nResponse, const OString& rHelpId) override { - GtkWidget* pWidget = gtk_dialog_add_button(m_pDialog, MapToGtkAccelerator(rText).getStr(), VclToGtk(nResponse)); + GtkWidget* pWidget = gtk_dialog_add_button(GTK_DIALOG(m_pDialog), MapToGtkAccelerator(rText).getStr(), VclToGtk(nResponse)); if (!rHelpId.isEmpty()) ::set_help_id(pWidget, rHelpId); } virtual void set_default_response(int nResponse) override { - gtk_dialog_set_default_response(m_pDialog, VclToGtk(nResponse)); + gtk_dialog_set_default_response(GTK_DIALOG(m_pDialog), VclToGtk(nResponse)); } - virtual weld::Button* get_widget_for_response(int nResponse) override; + virtual GtkButton* get_widget_for_response(int nGtkResponse) + { + return GTK_BUTTON(gtk_dialog_get_widget_for_response(GTK_DIALOG(m_pDialog), nGtkResponse)); + } + + virtual weld::Button* weld_widget_for_response(int nVclResponse) override; virtual Container* weld_content_area() override { - return new GtkInstanceContainer(GTK_CONTAINER(gtk_dialog_get_content_area(m_pDialog)), m_pBuilder, false); + return new GtkInstanceContainer(GTK_CONTAINER(gtk_dialog_get_content_area(GTK_DIALOG(m_pDialog))), m_pBuilder, false); } virtual void collapse(weld::Widget* pEdit, weld::Widget* pButton) override @@ -3327,7 +3353,7 @@ public: //mark widgets we want to be visible, starting with pRefEdit //and all its direct parents. winset aVisibleWidgets; - GtkWidget *pContentArea = gtk_dialog_get_content_area(m_pDialog); + GtkWidget *pContentArea = gtk_dialog_get_content_area(GTK_DIALOG(m_pDialog)); for (GtkWidget *pCandidate = pRefEdit; pCandidate && pCandidate != pContentArea && gtk_widget_get_visible(pCandidate); pCandidate = gtk_widget_get_parent(pCandidate)) @@ -3350,7 +3376,7 @@ public: gtk_widget_set_size_request(pRefEdit, m_nOldEditWidth, -1); m_nOldBorderWidth = gtk_container_get_border_width(GTK_CONTAINER(m_pDialog)); gtk_container_set_border_width(GTK_CONTAINER(m_pDialog), 0); - if (GtkWidget* pActionArea = gtk_dialog_get_action_area(m_pDialog)) + if (GtkWidget* pActionArea = gtk_dialog_get_action_area(GTK_DIALOG(m_pDialog))) gtk_widget_hide(pActionArea); // calc's insert->function is springing back to its original size if the ref-button @@ -3385,7 +3411,7 @@ public: gtk_widget_set_size_request(m_pRefEdit, m_nOldEditWidthReq, -1); m_pRefEdit = nullptr; gtk_container_set_border_width(GTK_CONTAINER(m_pDialog), m_nOldBorderWidth); - if (GtkWidget* pActionArea = gtk_dialog_get_action_area(m_pDialog)) + if (GtkWidget* pActionArea = gtk_dialog_get_action_area(GTK_DIALOG(m_pDialog))) gtk_widget_show(pActionArea); resize_to_request(); present(); @@ -3430,13 +3456,21 @@ void DialogRunner::signal_response(GtkDialog*, gint nResponseId, gpointer data) pThis->loop_quit(); } +void DialogRunner::signal_cancel(GtkDialog*, gpointer data) +{ + DialogRunner* pThis = static_cast<DialogRunner*>(data); + + // make esc in an assistant act as if cancel button was pressed + pThis->m_pInstance->close(false); +} + class GtkInstanceMessageDialog : public GtkInstanceDialog, public virtual weld::MessageDialog { private: GtkMessageDialog* m_pMessageDialog; public: GtkInstanceMessageDialog(GtkMessageDialog* pMessageDialog, GtkInstanceBuilder* pBuilder, bool bTakeOwnership) - : GtkInstanceDialog(GTK_DIALOG(pMessageDialog), pBuilder, bTakeOwnership) + : GtkInstanceDialog(GTK_WINDOW(pMessageDialog), pBuilder, bTakeOwnership) , m_pMessageDialog(pMessageDialog) { } @@ -3475,7 +3509,7 @@ private: std::unique_ptr<utl::TempFile> mxBackgroundImage; public: GtkInstanceAboutDialog(GtkAboutDialog* pAboutDialog, GtkInstanceBuilder* pBuilder, bool bTakeOwnership) - : GtkInstanceDialog(GTK_DIALOG(pAboutDialog), pBuilder, bTakeOwnership) + : GtkInstanceDialog(GTK_WINDOW(pAboutDialog), pBuilder, bTakeOwnership) , m_pAboutDialog(pAboutDialog) , m_pCssProvider(nullptr) { @@ -3564,6 +3598,260 @@ public: } }; +class GtkInstanceAssistant : public GtkInstanceDialog, public virtual weld::Assistant +{ +private: + GtkAssistant* m_pAssistant; + GtkWidget* m_pSidebar; + GtkButtonBox* m_pButtonBox; + GtkButton* m_pHelp; + GtkButton* m_pBack; + GtkButton* m_pNext; + GtkButton* m_pFinish; + GtkButton* m_pCancel; + std::vector<std::unique_ptr<GtkInstanceContainer>> m_aPages; + + int find_page(const OString& rIdent) const + { + int nPages = gtk_assistant_get_n_pages(m_pAssistant); + for (int i = 0; i < nPages; ++i) + { + GtkWidget* pPage = gtk_assistant_get_nth_page(m_pAssistant, i); + const gchar* pStr = gtk_buildable_get_name(GTK_BUILDABLE(pPage)); + if (g_strcmp0(pStr, rIdent.getStr()) == 0) + return i; + } + return -1; + } + + virtual int GtkToVcl(int ret) override + { + if (ret == GTK_RESPONSE_OK) + ret = static_cast<int>(WizardButtonFlags::FINISH); + else if (ret == GTK_RESPONSE_CANCEL) + ret = static_cast<int>(WizardButtonFlags::CANCEL); + else if (ret == GTK_RESPONSE_DELETE_EVENT) + ret = static_cast<int>(WizardButtonFlags::CANCEL); + else if (ret == GTK_RESPONSE_CLOSE) + ret = static_cast<int>(WizardButtonFlags::CANCEL); + else if (ret == GTK_RESPONSE_ACCEPT) + ret = static_cast<int>(WizardButtonFlags::NEXT); + else if (ret == GTK_RESPONSE_REJECT) + ret = static_cast<int>(WizardButtonFlags::PREVIOUS); + else if (ret == GTK_RESPONSE_HELP) + ret = static_cast<int>(WizardButtonFlags::HELP); + return ret; + } + + virtual int VclToGtk(int nResponse) override + { + if (nResponse == static_cast<int>(WizardButtonFlags::NEXT)) + return GTK_RESPONSE_ACCEPT; + if (nResponse == static_cast<int>(WizardButtonFlags::PREVIOUS)) + return GTK_RESPONSE_REJECT; + else if (nResponse == static_cast<int>(WizardButtonFlags::FINISH)) + return GTK_RESPONSE_OK; + else if (nResponse == static_cast<int>(WizardButtonFlags::CANCEL)) + return GTK_RESPONSE_CANCEL; + else if (nResponse == static_cast<int>(WizardButtonFlags::HELP)) + return GTK_RESPONSE_HELP; + return nResponse; + } + + static void wrap_sidebar_label(GtkWidget *pWidget, gpointer /*user_data*/) + { + if (GTK_IS_LABEL(pWidget)) + { + gtk_label_set_line_wrap(GTK_LABEL(pWidget), true); + gtk_label_set_width_chars(GTK_LABEL(pWidget), 22); + gtk_label_set_max_width_chars(GTK_LABEL(pWidget), 22); + } + } + + static void find_sidebar(GtkWidget *pWidget, gpointer user_data) + { + if (g_strcmp0(gtk_buildable_get_name(GTK_BUILDABLE(pWidget)), "sidebar") == 0) + { + GtkWidget **ppSidebar = static_cast<GtkWidget**>(user_data); + *ppSidebar = pWidget; + } + if (GTK_IS_CONTAINER(pWidget)) + gtk_container_forall(GTK_CONTAINER(pWidget), find_sidebar, user_data); + } + +public: + GtkInstanceAssistant(GtkAssistant* pAssistant, GtkInstanceBuilder* pBuilder, bool bTakeOwnership) + : GtkInstanceDialog(GTK_WINDOW(pAssistant), pBuilder, bTakeOwnership) + , m_pAssistant(pAssistant) + , m_pSidebar(nullptr) + { + m_pButtonBox = GTK_BUTTON_BOX(gtk_button_box_new(GTK_ORIENTATION_HORIZONTAL)); + gtk_button_box_set_layout(m_pButtonBox, GTK_BUTTONBOX_END); + gtk_box_set_spacing(GTK_BOX(m_pButtonBox), 6); + + m_pBack = GTK_BUTTON(gtk_button_new_with_mnemonic(MapToGtkAccelerator(Button::GetStandardText(StandardButtonType::Back)).getStr())); + gtk_widget_set_can_default(GTK_WIDGET(m_pBack), true); + gtk_buildable_set_name(GTK_BUILDABLE(m_pBack), "previous"); + gtk_box_pack_end(GTK_BOX(m_pButtonBox), GTK_WIDGET(m_pBack), false, false, 0); + + m_pNext = GTK_BUTTON(gtk_button_new_with_mnemonic(MapToGtkAccelerator(Button::GetStandardText(StandardButtonType::Next)).getStr())); + gtk_widget_set_can_default(GTK_WIDGET(m_pNext), true); + gtk_buildable_set_name(GTK_BUILDABLE(m_pNext), "next"); + gtk_box_pack_end(GTK_BOX(m_pButtonBox), GTK_WIDGET(m_pNext), false, false, 0); + + m_pCancel = GTK_BUTTON(gtk_button_new_with_mnemonic(MapToGtkAccelerator(Button::GetStandardText(StandardButtonType::Cancel)).getStr())); + gtk_widget_set_can_default(GTK_WIDGET(m_pCancel), true); + gtk_box_pack_end(GTK_BOX(m_pButtonBox), GTK_WIDGET(m_pCancel), false, false, 0); + + m_pFinish = GTK_BUTTON(gtk_button_new_with_mnemonic(MapToGtkAccelerator(Button::GetStandardText(StandardButtonType::Finish)).getStr())); + gtk_widget_set_can_default(GTK_WIDGET(m_pFinish), true); + gtk_buildable_set_name(GTK_BUILDABLE(m_pFinish), "finish"); + gtk_box_pack_end(GTK_BOX(m_pButtonBox), GTK_WIDGET(m_pFinish), false, false, 0); + + m_pHelp = GTK_BUTTON(gtk_button_new_with_mnemonic(MapToGtkAccelerator(Button::GetStandardText(StandardButtonType::Help)).getStr())); + gtk_widget_set_can_default(GTK_WIDGET(m_pHelp), true); + gtk_box_pack_end(GTK_BOX(m_pButtonBox), GTK_WIDGET(m_pHelp), false, false, 0); + + gtk_assistant_add_action_widget(pAssistant, GTK_WIDGET(m_pButtonBox)); + gtk_button_box_set_child_secondary(m_pButtonBox, GTK_WIDGET(m_pHelp), true); + gtk_widget_set_hexpand(GTK_WIDGET(m_pButtonBox), true); + + GtkWidget* pParent = gtk_widget_get_parent(GTK_WIDGET(m_pButtonBox)); + gtk_container_child_set(GTK_CONTAINER(pParent), GTK_WIDGET(m_pButtonBox), "expand", true, "fill", true, nullptr); + gtk_widget_set_halign(pParent, GTK_ALIGN_FILL); + + // Hide the built-in ones early so we get a nice optimal size for the width without + // including the unused contents + GList* pChildren = gtk_container_get_children(GTK_CONTAINER(pParent)); + for (GList* pChild = g_list_first(pChildren); pChild; pChild = g_list_next(pChild)) + { + GtkWidget* pWidget = static_cast<GtkWidget*>(pChild->data); + gtk_widget_hide(pWidget); + } + g_list_free(pChildren); + + gtk_widget_show_all(GTK_WIDGET(m_pButtonBox)); + + find_sidebar(GTK_WIDGET(m_pAssistant), &m_pSidebar); + } + + virtual int get_current_page() const override + { + return gtk_assistant_get_current_page(m_pAssistant); + } + + virtual int get_n_pages() const override + { + return gtk_assistant_get_n_pages(m_pAssistant); + } + + virtual OString get_page_ident(int nPage) const override + { + const GtkWidget* pWidget = gtk_assistant_get_nth_page(m_pAssistant, nPage); + const gchar* pStr = gtk_buildable_get_name(GTK_BUILDABLE(pWidget)); + return OString(pStr, pStr ? strlen(pStr) : 0); + } + + virtual OString get_current_page_ident() const override + { + return get_page_ident(get_current_page()); + } + + virtual void set_current_page(int nPage) override + { + gtk_assistant_set_current_page(m_pAssistant, nPage); + } + + virtual void set_current_page(const OString& rIdent) override + { + int nPage = find_page(rIdent); + if (nPage == -1) + return; + set_current_page(nPage); + } + + virtual void set_page_title(const OString& rIdent, const OUString& rTitle) override + { + int nIndex = find_page(rIdent); + if (nIndex == -1) + return; + GtkWidget* pPage = gtk_assistant_get_nth_page(m_pAssistant, nIndex); + gtk_assistant_set_page_title(m_pAssistant, pPage, + OUStringToOString(rTitle, RTL_TEXTENCODING_UTF8).getStr()); + gtk_container_forall(GTK_CONTAINER(m_pSidebar), wrap_sidebar_label, nullptr); + } + + virtual OUString get_page_title(const OString& rIdent) const override + { + int nIndex = find_page(rIdent); + if (nIndex == -1) + return OUString(); + GtkWidget* pPage = gtk_assistant_get_nth_page(m_pAssistant, nIndex); + const gchar* pStr = gtk_assistant_get_page_title(m_pAssistant, pPage); + return OUString(pStr, pStr ? strlen(pStr) : 0, RTL_TEXTENCODING_UTF8); + } + + virtual void set_page_sensitive(const OString& /*rIdent*/, bool /*bSensitive*/) override + { + // seeing as the GtkAssistant doesn't have clickable roadmap entries + // sensitive vs insensitive is moot + } + + virtual void set_page_index(const OString& rIdent, int nNewIndex) override + { + int nOldIndex = find_page(rIdent); + if (nOldIndex == -1) + return; + + if (nOldIndex == nNewIndex) + return; + + GtkWidget* pPage = gtk_assistant_get_nth_page(m_pAssistant, nOldIndex); + + g_object_ref(pPage); + OString sTitle(gtk_assistant_get_page_title(m_pAssistant, pPage)); + gtk_assistant_remove_page(m_pAssistant, nOldIndex); + gtk_assistant_insert_page(m_pAssistant, pPage, nNewIndex); + gtk_assistant_set_page_type(m_pAssistant, pPage, GTK_ASSISTANT_PAGE_CUSTOM); + gtk_assistant_set_page_title(m_pAssistant, pPage, sTitle.getStr()); + gtk_container_forall(GTK_CONTAINER(m_pSidebar), wrap_sidebar_label, nullptr); + g_object_unref(pPage); + } + + virtual weld::Container* append_page(const OString& rIdent) override + { + disable_notify_events(); + + GtkWidget *pChild = gtk_grid_new(); + gtk_buildable_set_name(GTK_BUILDABLE(pChild), rIdent.getStr()); + gtk_assistant_append_page(m_pAssistant, pChild); + gtk_assistant_set_page_type(m_pAssistant, pChild, GTK_ASSISTANT_PAGE_CUSTOM); + gtk_widget_show(pChild); + + enable_notify_events(); + + m_aPages.emplace_back(new GtkInstanceContainer(GTK_CONTAINER(pChild), m_pBuilder, false)); + + return m_aPages.back().get(); + } + + virtual GtkButton* get_widget_for_response(int nGtkResponse) override + { + GtkButton* pButton = nullptr; + if (nGtkResponse == GTK_RESPONSE_ACCEPT) + pButton = m_pNext; + else if (nGtkResponse == GTK_RESPONSE_REJECT) + pButton = m_pBack; + else if (nGtkResponse == GTK_RESPONSE_OK) + pButton = m_pFinish; + else if (nGtkResponse == GTK_RESPONSE_CANCEL) + pButton = m_pCancel; + else if (nGtkResponse == GTK_RESPONSE_HELP) + pButton = m_pHelp; + return pButton; + } +}; + class GtkInstanceFrame : public GtkInstanceContainer, public virtual weld::Frame { private: @@ -4869,7 +5157,8 @@ void GtkInstanceDialog::asyncresponse(gint ret) int GtkInstanceDialog::run() { - sort_native_button_order(GTK_BOX(gtk_dialog_get_action_area(m_pDialog))); + if (GTK_IS_DIALOG(m_pDialog)) + sort_native_button_order(GTK_BOX(gtk_dialog_get_action_area(GTK_DIALOG(m_pDialog)))); int ret; while (true) { @@ -4887,9 +5176,9 @@ int GtkInstanceDialog::run() return GtkToVcl(ret); } -weld::Button* GtkInstanceDialog::get_widget_for_response(int nResponse) +weld::Button* GtkInstanceDialog::weld_widget_for_response(int nVclResponse) { - GtkButton* pButton = GTK_BUTTON(gtk_dialog_get_widget_for_response(m_pDialog, VclToGtk(nResponse))); + GtkButton* pButton = get_widget_for_response(VclToGtk(nVclResponse)); if (!pButton) return nullptr; return new GtkInstanceButton(pButton, m_pBuilder, false); @@ -4897,15 +5186,22 @@ weld::Button* GtkInstanceDialog::get_widget_for_response(int nResponse) void GtkInstanceDialog::response(int nResponse) { + int nGtkResponse = VclToGtk(nResponse); //unblock this response now when activated through code - if (GtkWidget* pWidget = gtk_dialog_get_widget_for_response(m_pDialog, VclToGtk(nResponse))) + if (GtkButton* pWidget = get_widget_for_response(nGtkResponse)) { void* pData = g_object_get_data(G_OBJECT(pWidget), "g-lo-GtkInstanceButton"); GtkInstanceButton* pButton = static_cast<GtkInstanceButton*>(pData); if (pButton) pButton->clear_click_handler(); } - gtk_dialog_response(m_pDialog, VclToGtk(nResponse)); + if (GTK_IS_DIALOG(m_pDialog)) + gtk_dialog_response(GTK_DIALOG(m_pDialog), nGtkResponse); + else if (GTK_IS_ASSISTANT(m_pDialog)) + { + m_aDialogRun.m_nResponseId = nGtkResponse; + m_aDialogRun.loop_quit(); + } } void GtkInstanceDialog::close(bool bCloseSignal) @@ -4928,7 +5224,7 @@ GtkInstanceButton* GtkInstanceDialog::has_click_handler(int nResponse) GtkInstanceButton* pButton = nullptr; // e.g. map GTK_RESPONSE_DELETE_EVENT to GTK_RESPONSE_CANCEL nResponse = VclToGtk(GtkToVcl(nResponse)); - if (GtkWidget* pWidget = gtk_dialog_get_widget_for_response(m_pDialog, nResponse)) + if (GtkButton* pWidget = get_widget_for_response(nResponse)) { void* pData = g_object_get_data(G_OBJECT(pWidget), "g-lo-GtkInstanceButton"); pButton = static_cast<GtkInstanceButton*>(pData); @@ -10368,7 +10664,7 @@ private: set_help_id(pWidget, sHelpId); //hook up for extended help const ImplSVData* pSVData = ImplGetSVData(); - if (pSVData->maHelpData.mbBalloonHelp && !GTK_IS_DIALOG(pWidget)) + if (pSVData->maHelpData.mbBalloonHelp && !GTK_IS_DIALOG(pWidget) && !GTK_IS_ASSISTANT(pWidget)) { gtk_widget_set_has_tooltip(pWidget, true); g_signal_connect(pWidget, "query-tooltip", G_CALLBACK(signalTooltipQuery), nullptr); @@ -10602,6 +10898,15 @@ public: return std::make_unique<GtkInstanceAboutDialog>(pAboutDialog, this, bTakeOwnership); } + virtual std::unique_ptr<weld::Assistant> weld_assistant(const OString &id, bool bTakeOwnership) override + { + GtkAssistant* pAssistant = GTK_ASSISTANT(gtk_builder_get_object(m_pBuilder, id.getStr())); + if (!pAssistant) + return nullptr; + gtk_window_set_transient_for(GTK_WINDOW(pAssistant), GTK_WINDOW(gtk_widget_get_toplevel(m_pParentWidget))); + return std::make_unique<GtkInstanceAssistant>(pAssistant, this, bTakeOwnership); + } + virtual std::unique_ptr<weld::Dialog> weld_dialog(const OString &id, bool bTakeOwnership) override { GtkDialog* pDialog = GTK_DIALOG(gtk_builder_get_object(m_pBuilder, id.getStr())); @@ -10609,7 +10914,7 @@ public: return nullptr; if (m_pParentWidget) gtk_window_set_transient_for(GTK_WINDOW(pDialog), GTK_WINDOW(gtk_widget_get_toplevel(m_pParentWidget))); - return std::make_unique<GtkInstanceDialog>(pDialog, this, bTakeOwnership); + return std::make_unique<GtkInstanceDialog>(GTK_WINDOW(pDialog), this, bTakeOwnership); } virtual std::unique_ptr<weld::Window> weld_window(const OString &id, bool bTakeOwnership) override |